diff --git a/.github/workflows/prerelease.yaml b/.github/workflows/prerelease.yaml new file mode 100644 index 00000000..b4a450e0 --- /dev/null +++ b/.github/workflows/prerelease.yaml @@ -0,0 +1,43 @@ +name: Tests +on: + pull_request: + branches: + - main + +jobs: + prerelease: + outputs: + version: ${{ steps.version.outputs.version }} + name: Pre release + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + + - name: Get version + id: version + run: echo "::set-output name=version::v0.0.0-ci.${GITHUB_SHA}-$(date +%Y%m%d%H%M%S)" + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: Install pnpm + run: npm install -g pnpm + + - name: Set version + run: | + echo $(jq --arg v "${{ steps.version.outputs.version }}" '(.version) = $v' package.json) > package.json + + - name: Install Dependencies + run: pnpm install + + - name: Build + run: pnpm run build + + - name: Set NPM_TOKEN + run: npm config set //registry.npmjs.org/:_authToken=${{secrets.NPM_TOKEN}} + + - name: Publish ci version + run: npm publish --tag=ci --verbose diff --git a/rome.json b/biome.json similarity index 97% rename from rome.json rename to biome.json index 27cea57c..e70ea365 100644 --- a/rome.json +++ b/biome.json @@ -23,7 +23,6 @@ }, "formatter": { "indentStyle": "space", - "indentSize": 2, "enabled": true, "lineWidth": 100, "ignore": ["node_modules", ".next", "dist", ".nuxt", ".contentlayer"] diff --git a/examples/nextjs/app/serverless/route.ts b/examples/nextjs/app/serverless/route.ts new file mode 100644 index 00000000..a3c59d1a --- /dev/null +++ b/examples/nextjs/app/serverless/route.ts @@ -0,0 +1,11 @@ +import { verifySignatureAppRouter } from "@upstash/qstash/dist/nextjs"; +import { NextRequest, NextResponse } from "next/server"; + +async function handler(_req: NextRequest) { + // simulate work + await new Promise((r) => setTimeout(r, 1000)); + + console.log("Success"); + return NextResponse.json({ name: "John Doe Serverless" }); +} +export const POST = verifySignatureAppRouter(handler); diff --git a/package.json b/package.json index 2f2175ec..a38dc8c1 100644 --- a/package.json +++ b/package.json @@ -30,21 +30,25 @@ "fmt": "pnpm rome check . --apply-unsafe && pnpm rome format . --write" }, "devDependencies": { - "@types/crypto-js": "^4.1.1", + "@biomejs/biome": "^1.3.3", + "@types/crypto-js": "^4.2.0", "@types/node": "^20.5.7", - "next": "^13.4.19", - "rome": "12.1.3", + "next": "^14.0.2", "tsup": "^7.2.0", "typescript": "^5.2.2" }, "dependencies": { - "crypto-js": "^4.1.1", + "crypto-js": "^4.2.0", "jose": "^4.14.4" }, "typesVersions": { "*": { - ".": ["./dist/index.d.ts"], - "nextjs": ["./dist/nextjs.d.ts"] + ".": [ + "./dist/index.d.ts" + ], + "nextjs": [ + "./dist/nextjs.d.ts" + ] } } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b620b37..bbb784aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,25 +6,25 @@ settings: dependencies: crypto-js: - specifier: ^4.1.1 - version: 4.1.1 + specifier: ^4.2.0 + version: 4.2.0 jose: specifier: ^4.14.4 version: 4.14.4 devDependencies: + '@biomejs/biome': + specifier: ^1.3.3 + version: 1.3.3 '@types/crypto-js': - specifier: ^4.1.1 - version: 4.1.1 + specifier: ^4.2.0 + version: 4.2.1 '@types/node': specifier: ^20.5.7 version: 20.5.7 next: - specifier: ^13.4.19 - version: 13.4.19(react-dom@18.2.0)(react@18.2.0) - rome: - specifier: 12.1.3 - version: 12.1.3 + specifier: ^14.0.2 + version: 14.0.2(react-dom@18.2.0)(react@18.2.0) tsup: specifier: ^7.2.0 version: 7.2.0(typescript@5.2.2) @@ -34,6 +34,74 @@ devDependencies: packages: + /@biomejs/biome@1.3.3: + resolution: {integrity: sha512-vTJn7RBzLWIabUuUIoEopO860YyBrbPEu4Pztfd28jRU5QD074hKZ9IQs24pFO6A2R296gaeYmN62f4u7pUruQ==} + engines: {node: '>=14.*'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.3.3 + '@biomejs/cli-darwin-x64': 1.3.3 + '@biomejs/cli-linux-arm64': 1.3.3 + '@biomejs/cli-linux-x64': 1.3.3 + '@biomejs/cli-win32-arm64': 1.3.3 + '@biomejs/cli-win32-x64': 1.3.3 + dev: true + + /@biomejs/cli-darwin-arm64@1.3.3: + resolution: {integrity: sha512-2X87ZfbmWwe4NGukrUvnoYdI//muSgjNUCAHJ2DO+kS1sB7kDy1s6PN/IYyTJuqRcJtDuOnSpaUDE7KxR1YhtA==} + engines: {node: '>=14.*'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@biomejs/cli-darwin-x64@1.3.3: + resolution: {integrity: sha512-t+7DWTCbSgHOBcPsGKuwS1qh1z9zbXFK8i8ktE18yW7iF/W0zI62k44fYqYeFJKlb0Q08aqUvez3L+AQJFsn+w==} + engines: {node: '>=14.*'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@biomejs/cli-linux-arm64@1.3.3: + resolution: {integrity: sha512-D8CvXaB8lkXXBQ6B3n0MXSSZFiE60+aNHorBLimVTtKiMod8QvAP425oQFZFul5wMXZqPLGTKFjXbAi/rvnc1A==} + engines: {node: '>=14.*'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@biomejs/cli-linux-x64@1.3.3: + resolution: {integrity: sha512-bqB05fwJnRZwRlcm/BS/s4qPickqiXZkiU/nOYvHApfsPeqgSHgv5HWoBYuSUjgqBbX3XZJArsC5dCcVW7vAJw==} + engines: {node: '>=14.*'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@biomejs/cli-win32-arm64@1.3.3: + resolution: {integrity: sha512-muFOjAv1ONMfaJDlo4Ds+Qb9lkdSLM2XaxOe3AJPejSq3Vi0aRr51ZnE02BofMnL2sVsOA9cO54wibsuTcopbw==} + engines: {node: '>=14.*'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@biomejs/cli-win32-x64@1.3.3: + resolution: {integrity: sha512-PMkMhS4smmmTMflxuZUx3REFSazEL9xsGscvZO1dKWI4ET23la+KxEM4TlSpjOyO66UerqSkuUlZecn0QhD63A==} + engines: {node: '>=14.*'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -262,12 +330,12 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /@next/env@13.4.19: - resolution: {integrity: sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ==} + /@next/env@14.0.2: + resolution: {integrity: sha512-HAW1sljizEaduEOes/m84oUqeIDAUYBR1CDwu2tobNlNDFP3cSm9d6QsOsGeNlIppU1p/p1+bWbYCbvwjFiceA==} dev: true - /@next/swc-darwin-arm64@13.4.19: - resolution: {integrity: sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ==} + /@next/swc-darwin-arm64@14.0.2: + resolution: {integrity: sha512-i+jQY0fOb8L5gvGvojWyZMfQoQtDVB2kYe7fufOEiST6sicvzI2W5/EXo4lX5bLUjapHKe+nFxuVv7BA+Pd7LQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -275,8 +343,8 @@ packages: dev: true optional: true - /@next/swc-darwin-x64@13.4.19: - resolution: {integrity: sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw==} + /@next/swc-darwin-x64@14.0.2: + resolution: {integrity: sha512-zRCAO0d2hW6gBEa4wJaLn+gY8qtIqD3gYd9NjruuN98OCI6YyelmhWVVLlREjS7RYrm9OUQIp/iVJFeB6kP1hg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -284,8 +352,8 @@ packages: dev: true optional: true - /@next/swc-linux-arm64-gnu@13.4.19: - resolution: {integrity: sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg==} + /@next/swc-linux-arm64-gnu@14.0.2: + resolution: {integrity: sha512-tSJmiaon8YaKsVhi7GgRizZoV0N1Sx5+i+hFTrCKKQN7s3tuqW0Rov+RYdPhAv/pJl4qiG+XfSX4eJXqpNg3dA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -293,8 +361,8 @@ packages: dev: true optional: true - /@next/swc-linux-arm64-musl@13.4.19: - resolution: {integrity: sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA==} + /@next/swc-linux-arm64-musl@14.0.2: + resolution: {integrity: sha512-dXJLMSEOwqJKcag1BeX1C+ekdPPJ9yXbWIt3nAadhbLx5CjACoB2NQj9Xcqu2tmdr5L6m34fR+fjGPs+ZVPLzA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -302,8 +370,8 @@ packages: dev: true optional: true - /@next/swc-linux-x64-gnu@13.4.19: - resolution: {integrity: sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g==} + /@next/swc-linux-x64-gnu@14.0.2: + resolution: {integrity: sha512-WC9KAPSowj6as76P3vf1J3mf2QTm3Wv3FBzQi7UJ+dxWjK3MhHVWsWUo24AnmHx9qDcEtHM58okgZkXVqeLB+Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -311,8 +379,8 @@ packages: dev: true optional: true - /@next/swc-linux-x64-musl@13.4.19: - resolution: {integrity: sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q==} + /@next/swc-linux-x64-musl@14.0.2: + resolution: {integrity: sha512-KSSAwvUcjtdZY4zJFa2f5VNJIwuEVnOSlqYqbQIawREJA+gUI6egeiRu290pXioQXnQHYYdXmnVNZ4M+VMB7KQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -320,8 +388,8 @@ packages: dev: true optional: true - /@next/swc-win32-arm64-msvc@13.4.19: - resolution: {integrity: sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw==} + /@next/swc-win32-arm64-msvc@14.0.2: + resolution: {integrity: sha512-2/O0F1SqJ0bD3zqNuYge0ok7OEWCQwk55RPheDYD0va5ij7kYwrFkq5ycCRN0TLjLfxSF6xI5NM6nC5ux7svEQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -329,8 +397,8 @@ packages: dev: true optional: true - /@next/swc-win32-ia32-msvc@13.4.19: - resolution: {integrity: sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA==} + /@next/swc-win32-ia32-msvc@14.0.2: + resolution: {integrity: sha512-vJI/x70Id0oN4Bq/R6byBqV1/NS5Dl31zC+lowO8SDu1fHmUxoAdILZR5X/sKbiJpuvKcCrwbYgJU8FF/Gh50Q==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -338,8 +406,8 @@ packages: dev: true optional: true - /@next/swc-win32-x64-msvc@13.4.19: - resolution: {integrity: sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw==} + /@next/swc-win32-x64-msvc@14.0.2: + resolution: {integrity: sha512-Ut4LXIUvC5m8pHTe2j0vq/YDnTEyq6RSR9vHYPqnELrDapPhLNz9Od/L5Ow3J8RNDWpEnfCiQXuVdfjlNEJ7ug==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -368,62 +436,14 @@ packages: fastq: 1.15.0 dev: true - /@rometools/cli-darwin-arm64@12.1.3: - resolution: {integrity: sha512-AmFTUDYjBuEGQp/Wwps+2cqUr+qhR7gyXAUnkL5psCuNCz3807TrUq/ecOoct5MIavGJTH6R4aaSL6+f+VlBEg==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rometools/cli-darwin-x64@12.1.3: - resolution: {integrity: sha512-k8MbWna8q4LRlb005N2X+JS1UQ+s3ZLBBvwk4fP8TBxlAJXUz17jLLu/Fi+7DTTEmMhM84TWj4FDKW+rNar28g==} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@rometools/cli-linux-arm64@12.1.3: - resolution: {integrity: sha512-X/uLhJ2/FNA3nu5TiyeNPqiD3OZoFfNfRvw6a3ut0jEREPvEn72NI7WPijH/gxSz55znfQ7UQ6iM4DZumUknJg==} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rometools/cli-linux-x64@12.1.3: - resolution: {integrity: sha512-csP17q1eWiUXx9z6Jr/JJPibkplyKIwiWPYNzvPCGE8pHlKhwZj3YHRuu7Dm/4EOqx0XFIuqqWZUYm9bkIC8xg==} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@rometools/cli-win32-arm64@12.1.3: - resolution: {integrity: sha512-RymHWeod57EBOJY4P636CgUwYA6BQdkQjh56XKk4pLEHO6X1bFyMet2XL7KlHw5qOTalzuzf5jJqUs+vf3jdXQ==} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@rometools/cli-win32-x64@12.1.3: - resolution: {integrity: sha512-yHSKYidqJMV9nADqg78GYA+cZ0hS1twANAjiFibQdXj9aGzD+s/IzIFEIi/U/OBLvWYg/SCw0QVozi2vTlKFDQ==} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@swc/helpers@0.5.1: - resolution: {integrity: sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==} + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: tslib: 2.6.2 dev: true - /@types/crypto-js@4.1.1: - resolution: {integrity: sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==} + /@types/crypto-js@4.2.1: + resolution: {integrity: sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==} dev: true /@types/node@20.5.7: @@ -533,8 +553,8 @@ packages: which: 2.0.2 dev: true - /crypto-js@4.1.1: - resolution: {integrity: sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==} + /crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} dev: false /debug@4.3.4: @@ -818,9 +838,9 @@ packages: hasBin: true dev: true - /next@13.4.19(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==} - engines: {node: '>=16.8.0'} + /next@14.0.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-jsAU2CkYS40GaQYOiLl9m93RTv2DA/tTJ0NRlmZIBIL87YwQ/xR8k796z7IqgM3jydI8G25dXvyYMC9VDIevIg==} + engines: {node: '>=18.17.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -833,26 +853,25 @@ packages: sass: optional: true dependencies: - '@next/env': 13.4.19 - '@swc/helpers': 0.5.1 + '@next/env': 14.0.2 + '@swc/helpers': 0.5.2 busboy: 1.6.0 caniuse-lite: 1.0.30001524 - postcss: 8.4.14 + postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(react@18.2.0) watchpack: 2.4.0 - zod: 3.21.4 optionalDependencies: - '@next/swc-darwin-arm64': 13.4.19 - '@next/swc-darwin-x64': 13.4.19 - '@next/swc-linux-arm64-gnu': 13.4.19 - '@next/swc-linux-arm64-musl': 13.4.19 - '@next/swc-linux-x64-gnu': 13.4.19 - '@next/swc-linux-x64-musl': 13.4.19 - '@next/swc-win32-arm64-msvc': 13.4.19 - '@next/swc-win32-ia32-msvc': 13.4.19 - '@next/swc-win32-x64-msvc': 13.4.19 + '@next/swc-darwin-arm64': 14.0.2 + '@next/swc-darwin-x64': 14.0.2 + '@next/swc-linux-arm64-gnu': 14.0.2 + '@next/swc-linux-arm64-musl': 14.0.2 + '@next/swc-linux-x64-gnu': 14.0.2 + '@next/swc-linux-x64-musl': 14.0.2 + '@next/swc-win32-arm64-msvc': 14.0.2 + '@next/swc-win32-ia32-msvc': 14.0.2 + '@next/swc-win32-x64-msvc': 14.0.2 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -933,8 +952,8 @@ packages: yaml: 2.3.1 dev: true - /postcss@8.4.14: - resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.6 @@ -993,20 +1012,6 @@ packages: fsevents: 2.3.3 dev: true - /rome@12.1.3: - resolution: {integrity: sha512-e+ff72hxDpe/t5/Us7YRBVw3PBET7SeczTQNn6tvrWdrCaAw3qOukQQ+tDCkyFtS4yGsnhjrJbm43ctNbz27Yg==} - engines: {node: '>=14.*'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@rometools/cli-darwin-arm64': 12.1.3 - '@rometools/cli-darwin-x64': 12.1.3 - '@rometools/cli-linux-arm64': 12.1.3 - '@rometools/cli-linux-x64': 12.1.3 - '@rometools/cli-win32-arm64': 12.1.3 - '@rometools/cli-win32-x64': 12.1.3 - dev: true - /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -1210,7 +1215,3 @@ packages: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} engines: {node: '>= 14'} dev: true - - /zod@3.21.4: - resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} - dev: true diff --git a/src/nextjs.ts b/src/nextjs.ts index 48daa13e..72cb7e19 100644 --- a/src/nextjs.ts +++ b/src/nextjs.ts @@ -23,18 +23,18 @@ export type VerifySignatureConfig = { export function verifySignature( handler: NextApiHandler, - config?: VerifySignatureConfig, + config?: VerifySignatureConfig ): NextApiHandler { 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", + "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", + "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY" ); } const receiver = new Receiver({ @@ -90,18 +90,18 @@ export function verifySignature( export function verifySignatureEdge( handler: (req: NextRequest, nfe?: NextFetchEvent) => NextResponse | Promise, - config?: VerifySignatureConfig, + config?: VerifySignatureConfig ) { 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", + "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", + "nextSigningKey is required, either in the config or as env variable QSTASH_NEXT_SIGNING_KEY" ); } const receiver = new Receiver({ @@ -132,18 +132,58 @@ export function verifySignatureEdge( return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 }); } - let parsedBody: unknown = undefined; + return handler(reqClone, nfe); + }; +} - try { - if (req.headers.get("content-type") === "application/json") { - parsedBody = JSON.parse(body); - } else { - parsedBody = body; - } - } catch { - parsedBody = body; +type VerifySignatureAppRouterResponse = NextResponse | Promise; + +export function verifySignatureAppRouter( + handler: + | ((req: Request) => VerifySignatureAppRouterResponse) + | ((req: NextRequest) => VerifySignatureAppRouterResponse), + config?: VerifySignatureConfig +) { + 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 (req: NextRequest | Request) => { + const reqClone = req.clone() as NextRequest; + // @ts-ignore This can throw errors during vercel build + const signature = req.headers.get("upstash-signature"); + if (!signature) { + return new NextResponse(new TextEncoder().encode("`Upstash-Signature` header is missing"), { + status: 403, + }); + } + if (typeof signature !== "string") { + throw new Error("`Upstash-Signature` header is not a string"); } - return handler(reqClone, nfe); + const body = await req.text(); + const isValid = await receiver.verify({ + signature, + body, + clockTolerance: config?.clockTolerance, + }); + if (!isValid) { + return new NextResponse(new TextEncoder().encode("invalid signature"), { status: 403 }); + } + + return handler(reqClone); }; }