From a42ededea3d9b5b7b15c01f07b3868b52e784fb4 Mon Sep 17 00:00:00 2001
From: Chadwick Maycumber <36460656+cmaycumber@users.noreply.github.com>
Date: Sat, 9 Nov 2024 19:32:01 -0500
Subject: [PATCH] Added support for NextJS 15
---
CHANGELOG.md | 7 +
docs/pages/authz/nextjs.mdx | 12 +-
docs/pages/index.mdx | 2 +-
docs/pages/setup.mdx | 2 +-
package-lock.json | 672 +++++++++++++++++++++++----
package.json | 9 +-
src/nextjs/server/cookies.ts | 36 +-
src/nextjs/server/index.tsx | 39 +-
src/nextjs/server/invalidateCache.ts | 4 +-
src/nextjs/server/proxy.ts | 13 +-
src/nextjs/server/request.ts | 14 +-
src/nextjs/server/utils.ts | 8 +-
test-nextjs/app/product/page.tsx | 2 +-
test-nextjs/middleware.ts | 6 +-
14 files changed, 681 insertions(+), 145 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e7e3ba..85e539b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## Unreleased
+
+- BREAKING: `convexAuthNextjsToken()` and `isAuthenticatedNextjs()` now return
+ promises so must be `await`ed.
+- Support for Next.js 15.
+- Update convex peer dependency to ^1.17.0
+
## 0.0.74
- Fix to header propagation in Next.js middleware
diff --git a/docs/pages/authz/nextjs.mdx b/docs/pages/authz/nextjs.mdx
index aacd4ce..3e84a6b 100644
--- a/docs/pages/authz/nextjs.mdx
+++ b/docs/pages/authz/nextjs.mdx
@@ -1,12 +1,10 @@
import { Callout } from "nextra/components";
-# Server-side authentication in Next.js 14
+# Server-side authentication in Next.js
You can set up your Next.js App Router app to have access to the authentication
state on the server.
-Next.js 15 is not supported yet.
-
## Setup
Make sure your React providers and middleware are
@@ -28,10 +26,10 @@ const isSignInPage = createRouteMatcher(["/signin"]);
const isProtectedRoute = createRouteMatcher(["/product(.*)"]);
export default convexAuthNextjsMiddleware((request, { convexAuth }) => {
- if (isSignInPage(request) && convexAuth.isAuthenticated()) {
+ if (isSignInPage(request) && (await convexAuth.isAuthenticated())) {
return nextjsMiddlewareRedirect(request, "/product");
}
- if (isProtectedRoute(request) && !convexAuth.isAuthenticated()) {
+ if (isProtectedRoute(request) && !(await convexAuth.isAuthenticated())) {
return nextjsMiddlewareRedirect(request, "/signin");
}
});
@@ -113,7 +111,7 @@ export async function TasksWrapper() {
const preloadedTasks = await preloadQuery(
api.tasks.list,
{ list: "default" },
- { token: convexAuthNextjsToken() },
+ { token: await convexAuthNextjsToken() },
);
return ;
}
@@ -143,7 +141,7 @@ export default async function PureServerPage() {
{
text: formData.get("text") as string,
},
- { token: convexAuthNextjsToken() },
+ { token: await convexAuthNextjsToken() },
);
revalidatePath("/example");
}
diff --git a/docs/pages/index.mdx b/docs/pages/index.mdx
index 40bbab4..0bbf584 100644
--- a/docs/pages/index.mdx
+++ b/docs/pages/index.mdx
@@ -6,7 +6,7 @@ without needing an authentication service or even a hosting server. Your
application can be:
- a React SPA served from a CDN
-- a full-stack Next.js 14 app
+- a full-stack Next.js app
- a React Native mobile app
**NOTE:** Convex Auth is in beta. Please share any feedback you have on
diff --git a/docs/pages/setup.mdx b/docs/pages/setup.mdx
index 18c0842..a0c31d0 100644
--- a/docs/pages/setup.mdx
+++ b/docs/pages/setup.mdx
@@ -18,7 +18,7 @@ and choose `React (Vite)` and then `Convex Auth`.
-**NOTE:** Convex Auth support for Next.js with server-side authentication (SSA) is experimental. Only Next.js 14 is currently supported, Next.js 15 is coming soon.
+**NOTE:** Convex Auth support for Next.js with server-side authentication (SSA) is experimental.
To start a new project from scratch with Convex and Convex Auth, run
diff --git a/package-lock.json b/package-lock.json
index ca603b3..e55e224 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,7 +33,7 @@
"dotenv": "^16.4.5",
"eslint": "8.49.0",
"inquirer": "^9.2.22",
- "next": "^14.2.5",
+ "next": "^15.0.3",
"npm-run-all": "^4.1.5",
"react-dom": "^18.3.1",
"shelljs": "^0.8.5",
@@ -45,12 +45,9 @@
"peerDependencies": {
"@auth/core": "^0.36.0",
"convex": "^1.14.4",
- "react": "^18.2.0"
+ "react": "^18.2.0 || ^19.0.0-0"
},
"peerDependenciesMeta": {
- "next": {
- "optional": true
- },
"react": {
"optional": true
}
@@ -645,6 +642,397 @@
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-wasm32/node_modules/@emnapi/runtime": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz",
+ "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@inquirer/figures": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.2.tgz",
@@ -823,19 +1211,21 @@
}
},
"node_modules/@next/env": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz",
- "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==",
- "dev": true
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.0.3.tgz",
+ "integrity": "sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz",
- "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz",
+ "integrity": "sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -845,13 +1235,14 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz",
- "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz",
+ "integrity": "sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -861,13 +1252,14 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz",
- "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz",
+ "integrity": "sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -877,13 +1269,14 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz",
- "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz",
+ "integrity": "sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -893,13 +1286,14 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz",
- "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz",
+ "integrity": "sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -909,13 +1303,14 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz",
- "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz",
+ "integrity": "sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -925,29 +1320,14 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz",
- "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz",
+ "integrity": "sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==",
"cpu": [
"arm64"
],
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz",
- "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -957,13 +1337,14 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz",
- "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz",
+ "integrity": "sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1722,15 +2103,16 @@
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
- "dev": true
+ "dev": true,
+ "license": "Apache-2.0"
},
"node_modules/@swc/helpers": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
- "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz",
+ "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@swc/counter": "^0.1.3",
"tslib": "^2.4.0"
}
},
@@ -2645,7 +3027,8 @@
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/clone": {
"version": "1.0.4",
@@ -2656,6 +3039,21 @@
"node": ">=0.8"
}
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -2671,6 +3069,40 @@
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/color/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/commander": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
@@ -2906,6 +3338,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
@@ -4820,41 +5263,43 @@
"dev": true
},
"node_modules/next": {
- "version": "14.2.5",
- "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz",
- "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==",
+ "version": "15.0.3",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.0.3.tgz",
+ "integrity": "sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@next/env": "14.2.5",
- "@swc/helpers": "0.5.5",
+ "@next/env": "15.0.3",
+ "@swc/counter": "0.1.3",
+ "@swc/helpers": "0.5.13",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
- "graceful-fs": "^4.2.11",
"postcss": "8.4.31",
- "styled-jsx": "5.1.1"
+ "styled-jsx": "5.1.6"
},
"bin": {
"next": "dist/bin/next"
},
"engines": {
- "node": ">=18.17.0"
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.2.5",
- "@next/swc-darwin-x64": "14.2.5",
- "@next/swc-linux-arm64-gnu": "14.2.5",
- "@next/swc-linux-arm64-musl": "14.2.5",
- "@next/swc-linux-x64-gnu": "14.2.5",
- "@next/swc-linux-x64-musl": "14.2.5",
- "@next/swc-win32-arm64-msvc": "14.2.5",
- "@next/swc-win32-ia32-msvc": "14.2.5",
- "@next/swc-win32-x64-msvc": "14.2.5"
+ "@next/swc-darwin-arm64": "15.0.3",
+ "@next/swc-darwin-x64": "15.0.3",
+ "@next/swc-linux-arm64-gnu": "15.0.3",
+ "@next/swc-linux-arm64-musl": "15.0.3",
+ "@next/swc-linux-x64-gnu": "15.0.3",
+ "@next/swc-linux-x64-musl": "15.0.3",
+ "@next/swc-win32-arm64-msvc": "15.0.3",
+ "@next/swc-win32-x64-msvc": "15.0.3",
+ "sharp": "^0.33.5"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
"@playwright/test": "^1.41.2",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-66855b96-20241106",
+ "react-dom": "^18.2.0 || 19.0.0-rc-66855b96-20241106",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
@@ -4864,6 +5309,9 @@
"@playwright/test": {
"optional": true
},
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
"sass": {
"optional": true
}
@@ -5962,10 +6410,11 @@
}
},
"node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -6010,6 +6459,47 @@
"node": ">= 0.4"
}
},
+ "node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -6087,6 +6577,25 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -6375,10 +6884,11 @@
"dev": true
},
"node_modules/styled-jsx": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
- "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"client-only": "0.0.1"
},
@@ -6386,7 +6896,7 @@
"node": ">= 12.0.0"
},
"peerDependencies": {
- "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
diff --git a/package.json b/package.json
index c4ea042..7ea90c5 100644
--- a/package.json
+++ b/package.json
@@ -73,15 +73,12 @@
},
"peerDependencies": {
"@auth/core": "^0.36.0",
- "convex": "^1.14.4",
- "react": "^18.2.0"
+ "convex": "^1.17.0",
+ "react": "^18.2.0 || ^19.0.0-0"
},
"peerDependenciesMeta": {
"react": {
"optional": true
- },
- "next": {
- "optional": true
}
},
"@comment devDependencies": [
@@ -100,7 +97,7 @@
"dotenv": "^16.4.5",
"eslint": "8.49.0",
"inquirer": "^9.2.22",
- "next": "^14.2.5",
+ "next": "^15.0.3",
"npm-run-all": "^4.1.5",
"react-dom": "^18.3.1",
"shelljs": "^0.8.5",
diff --git a/src/nextjs/server/cookies.ts b/src/nextjs/server/cookies.ts
index 4efbd04..651e34c 100644
--- a/src/nextjs/server/cookies.ts
+++ b/src/nextjs/server/cookies.ts
@@ -1,31 +1,46 @@
-import { cookies, headers } from "next/headers";
+import { cookies as nextCookies, headers as nextHeaders } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import * as utils from "../../server/utils.js";
-export function getRequestCookies() {
+/**
+ * Before Next.js 15 introduced Async Request APIs https://nextjs.org/blog/next-15#async-request-apis-breaking-change
+ * many APIs were sync. Add this return type to help us stay compatible with Next.js 14.
+ */
+type RememberNext14 any> = F extends (
+ ...args: infer Args
+) => infer Return
+ ? (...args: Args) => Return | Awaited
+ : never;
+
+const cookies = nextCookies as RememberNext14;
+const headers = nextHeaders as RememberNext14;
+
+export async function getRequestCookies() {
// maxAge doesn't matter for request cookies since they're only relevant for the
// length of the request
- return getCookieStore(headers(), cookies(), { maxAge: null });
+ return getCookieStore(await headers(), await cookies(), {
+ maxAge: null,
+ });
}
-export function getRequestCookiesInMiddleware(request: NextRequest) {
+export async function getRequestCookiesInMiddleware(request: NextRequest) {
// maxAge doesn't matter for request cookies since they're only relevant for the
// length of the request
- return getCookieStore(headers(), request.cookies, { maxAge: null });
+ return getCookieStore(await headers(), request.cookies, { maxAge: null });
}
-export function getResponseCookies(
+export async function getResponseCookies(
response: NextResponse,
cookieConfig: {
maxAge: number | null;
},
) {
- return getCookieStore(headers(), response.cookies, cookieConfig);
+ return getCookieStore(await headers(), response.cookies, cookieConfig);
}
function getCookieStore(
- requestHeaders: ReturnType,
- requestCookies: ReturnType,
+ requestHeaders: Awaited>,
+ requestCookies: Awaited>,
cookieConfig: {
maxAge: number | null;
},
@@ -45,8 +60,9 @@ function getCookieStore(
refreshToken: string | null;
verifier: string | null;
};
+
function getCookieStore(
- requestHeaders: ReturnType,
+ requestHeaders: Awaited>,
responseCookies: NextResponse["cookies"] | NextRequest["cookies"],
cookieConfig: {
maxAge: number | null;
diff --git a/src/nextjs/server/index.tsx b/src/nextjs/server/index.tsx
index 3ae7ad3..23adf3e 100644
--- a/src/nextjs/server/index.tsx
+++ b/src/nextjs/server/index.tsx
@@ -24,7 +24,7 @@ import {
/**
* Wrap your app with this provider in your root `layout.tsx`.
*/
-export function ConvexAuthNextjsServerProvider(props: {
+export async function ConvexAuthNextjsServerProvider(props: {
/**
* You can customize the route path that handles authentication
* actions via this prop and the `apiRoute` option to `convexAuthNextjsMiddleWare`.
@@ -61,9 +61,10 @@ export function ConvexAuthNextjsServerProvider(props: {
children: ReactNode;
}) {
const { apiRoute, storage, storageNamespace, verbose, children } = props;
+ const serverState = await convexAuthNextjsServerState();
return (
{
- * if (!convexAuth.isAuthenticated()) {
+ * if (!(await convexAuth.isAuthenticated())) {
* return nextjsMiddlewareRedirect(request, "/login");
* }
* };
@@ -110,8 +111,8 @@ export function isAuthenticatedNextjs() {
* ```
*/
export type ConvexAuthNextjsMiddlewareContext = {
- getToken: () => string | undefined;
- isAuthenticated: () => boolean;
+ getToken: () => Promise;
+ isAuthenticated: () => Promise;
};
/**
@@ -207,7 +208,7 @@ export function convexAuthNextjsMiddleware(
authResult.refreshTokens !== undefined
) {
logVerbose(`Forwarding cookies to request`, verbose);
- setAuthCookiesInMiddleware(request, authResult.refreshTokens);
+ await setAuthCookiesInMiddleware(request, authResult.refreshTokens);
}
if (handler === undefined) {
logVerbose(`No custom handler`, verbose);
@@ -223,12 +224,12 @@ export function convexAuthNextjsMiddleware(
(await handler(request, {
event,
convexAuth: {
- getToken: () => {
- const cookies = getRequestCookiesInMiddleware(request);
+ getToken: async () => {
+ const cookies = await getRequestCookiesInMiddleware(request);
return cookies.token ?? undefined;
},
- isAuthenticated: () => {
- const cookies = getRequestCookiesInMiddleware(request);
+ isAuthenticated: async () => {
+ const cookies = await getRequestCookiesInMiddleware(request);
return (cookies.token ?? undefined) !== undefined;
},
},
@@ -246,7 +247,11 @@ export function convexAuthNextjsMiddleware(
authResult.refreshTokens !== undefined
) {
const nextResponse = NextResponse.next(response);
- setAuthCookies(nextResponse, authResult.refreshTokens, cookieConfig);
+ await setAuthCookies(
+ nextResponse,
+ authResult.refreshTokens,
+ cookieConfig,
+ );
return nextResponse;
}
@@ -279,8 +284,8 @@ export function nextjsMiddlewareRedirect(
return NextResponse.redirect(url);
}
-function convexAuthNextjsServerState(): ConvexAuthServerState {
- const { token } = getRequestCookies();
+async function convexAuthNextjsServerState(): Promise {
+ const { token } = await getRequestCookies();
return {
// The server doesn't share the refresh token with the client
// for added security - the client has to use the server
diff --git a/src/nextjs/server/invalidateCache.ts b/src/nextjs/server/invalidateCache.ts
index ab522c9..7f1a48f 100644
--- a/src/nextjs/server/invalidateCache.ts
+++ b/src/nextjs/server/invalidateCache.ts
@@ -5,6 +5,8 @@ import { cookies } from "next/headers";
export async function invalidateCache() {
// Dummy cookie, just to set the header which will invalidate
// the client Router Cache.
- cookies().delete(`__convexAuthCookieForRouterCacheInvalidation${Date.now()}`);
+ (await cookies()).delete(
+ `__convexAuthCookieForRouterCacheInvalidation${Date.now()}`,
+ );
return null;
}
diff --git a/src/nextjs/server/proxy.ts b/src/nextjs/server/proxy.ts
index 81d0038..c664ad3 100644
--- a/src/nextjs/server/proxy.ts
+++ b/src/nextjs/server/proxy.ts
@@ -37,7 +37,7 @@ export async function proxyAuthActionToConvex(
if (action === "auth:signIn" && args.refreshToken !== undefined) {
// The client has a dummy refreshToken, the real one is only
// stored in cookies.
- const refreshToken = getRequestCookies().refreshToken;
+ const refreshToken = (await getRequestCookies()).refreshToken;
if (refreshToken === null) {
console.error(
"Convex Auth: Unexpected missing refreshToken cookie during client refresh",
@@ -49,7 +49,7 @@ export async function proxyAuthActionToConvex(
// Make sure the proxy is authenticated if the client is,
// important for signOut and any other logic working
// with existing sessions.
- token = getRequestCookies().token ?? undefined;
+ token = (await getRequestCookies()).token ?? undefined;
}
logVerbose(
`Fetching action ${action} with args ${JSON.stringify({
@@ -77,13 +77,14 @@ export async function proxyAuthActionToConvex(
console.error(error);
logVerbose(`Clearing auth cookies`, verbose);
const response = jsonResponse(null);
- setAuthCookies(response, null, cookieConfig);
+ await setAuthCookies(response, null, cookieConfig);
return response;
}
if (result.redirect !== undefined) {
const { redirect } = result;
const response = jsonResponse({ redirect });
- getResponseCookies(response, cookieConfig).verifier = result.verifier!;
+ (await getResponseCookies(response, cookieConfig)).verifier =
+ result.verifier!;
logVerbose(`Redirecting to ${redirect}`, verbose);
return response;
} else if (result.tokens !== undefined) {
@@ -102,7 +103,7 @@ export async function proxyAuthActionToConvex(
? { token: result.tokens.token, refreshToken: "dummy" }
: null,
});
- setAuthCookies(response, result.tokens, cookieConfig);
+ await setAuthCookies(response, result.tokens, cookieConfig);
return response;
}
return jsonResponse(result);
@@ -118,7 +119,7 @@ export async function proxyAuthActionToConvex(
}
logVerbose(`Clearing auth cookies`, verbose);
const response = jsonResponse(null);
- setAuthCookies(response, null, cookieConfig);
+ await setAuthCookies(response, null, cookieConfig);
return response;
}
}
diff --git a/src/nextjs/server/request.ts b/src/nextjs/server/request.ts
index 537793e..548c953 100644
--- a/src/nextjs/server/request.ts
+++ b/src/nextjs/server/request.ts
@@ -20,7 +20,7 @@ export async function handleAuthenticationInRequest(
const requestUrl = new URL(request.url);
// Validate CORS
- validateCors(request);
+ await validateCors(request);
// Refresh tokens if necessary
const refreshTokens = await getRefreshedTokens(verbose);
@@ -33,7 +33,7 @@ export async function handleAuthenticationInRequest(
request.headers.get("accept")?.includes("text/html")
) {
logVerbose(`Handling code exchange for OAuth or magic link`, verbose);
- const verifier = getRequestCookies().verifier ?? undefined;
+ const verifier = (await getRequestCookies()).verifier ?? undefined;
const redirectUrl = new URL(requestUrl);
redirectUrl.searchParams.delete("code");
try {
@@ -45,7 +45,7 @@ export async function handleAuthenticationInRequest(
throw new Error("Invalid `signIn` action result for code exchange");
}
const response = NextResponse.redirect(redirectUrl);
- setAuthCookies(response, result.tokens, cookieConfig);
+ await setAuthCookies(response, result.tokens, cookieConfig);
logVerbose(
`Successfully validated code, redirecting to ${redirectUrl.toString()} with auth cookies`,
verbose,
@@ -58,7 +58,7 @@ export async function handleAuthenticationInRequest(
verbose,
);
const response = NextResponse.redirect(redirectUrl);
- setAuthCookies(response, null, cookieConfig);
+ await setAuthCookies(response, null, cookieConfig);
return { kind: "redirect", response };
}
}
@@ -68,9 +68,9 @@ export async function handleAuthenticationInRequest(
// If this is a cross-origin request with `Origin` header set
// do not allow the app to read auth cookies.
-function validateCors(request: NextRequest) {
+async function validateCors(request: NextRequest) {
if (isCorsRequest(request)) {
- const cookies = getRequestCookiesInMiddleware(request);
+ const cookies = await getRequestCookiesInMiddleware(request);
cookies.token = null;
cookies.refreshToken = null;
cookies.verifier = null;
@@ -81,7 +81,7 @@ const REQUIRED_TOKEN_LIFETIME_MS = 60_000; // 1 minute
const MINIMUM_REQUIRED_TOKEN_LIFETIME_MS = 10_000; // 10 seconds
async function getRefreshedTokens(verbose: boolean) {
- const cookies = getRequestCookies();
+ const cookies = await getRequestCookies();
const { token, refreshToken } = cookies;
if (refreshToken === null && token === null) {
logVerbose(`No tokens to refresh, returning undefined`, verbose);
diff --git a/src/nextjs/server/utils.ts b/src/nextjs/server/utils.ts
index 505e485..cff2fc5 100644
--- a/src/nextjs/server/utils.ts
+++ b/src/nextjs/server/utils.ts
@@ -10,14 +10,14 @@ export function jsonResponse(body: any) {
});
}
-export function setAuthCookies(
+export async function setAuthCookies(
response: NextResponse,
tokens: { token: string; refreshToken: string } | null,
cookieConfig: {
maxAge: number | null;
},
) {
- const responseCookies = getResponseCookies(response, cookieConfig);
+ const responseCookies = await getResponseCookies(response, cookieConfig);
if (tokens === null) {
responseCookies.token = null;
responseCookies.refreshToken = null;
@@ -34,11 +34,11 @@ export function setAuthCookies(
* @param request
* @param tokens
*/
-export function setAuthCookiesInMiddleware(
+export async function setAuthCookiesInMiddleware(
request: NextRequest,
tokens: { token: string; refreshToken: string } | null,
) {
- const requestCookies = getRequestCookiesInMiddleware(request);
+ const requestCookies = await getRequestCookiesInMiddleware(request);
if (tokens === null) {
requestCookies.token = null;
requestCookies.refreshToken = null;
diff --git a/test-nextjs/app/product/page.tsx b/test-nextjs/app/product/page.tsx
index 73e37e3..c47bf0d 100644
--- a/test-nextjs/app/product/page.tsx
+++ b/test-nextjs/app/product/page.tsx
@@ -9,7 +9,7 @@ export default async function ProductPage() {
const viewer = await fetchQuery(
api.users.viewer,
{},
- { token: convexAuthNextjsToken() },
+ { token: await convexAuthNextjsToken() },
);
return (
diff --git a/test-nextjs/middleware.ts b/test-nextjs/middleware.ts
index 288e66f..770be7e 100644
--- a/test-nextjs/middleware.ts
+++ b/test-nextjs/middleware.ts
@@ -7,11 +7,11 @@ import {
const isSignInPage = createRouteMatcher(["/signin"]);
const isProtectedRoute = createRouteMatcher(["/product(.*)"]);
-export default convexAuthNextjsMiddleware((request, { convexAuth }) => {
- if (isSignInPage(request) && convexAuth.isAuthenticated()) {
+export default convexAuthNextjsMiddleware(async (request, { convexAuth }) => {
+ if (isSignInPage(request) && (await convexAuth.isAuthenticated())) {
return nextjsMiddlewareRedirect(request, "/product");
}
- if (isProtectedRoute(request) && !convexAuth.isAuthenticated()) {
+ if (isProtectedRoute(request) && !(await convexAuth.isAuthenticated())) {
return nextjsMiddlewareRedirect(request, "/signin");
}
});