diff --git a/.changeset/nasty-meals-call.md b/.changeset/nasty-meals-call.md new file mode 100644 index 00000000000..06fd236c8fd --- /dev/null +++ b/.changeset/nasty-meals-call.md @@ -0,0 +1,5 @@ +--- +"@clerk/nextjs": minor +--- + +Replace `next/headers` with `ezheaders` diff --git a/package-lock.json b/package-lock.json index 0a8a854f6bd..440395f9c04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -499,9 +499,9 @@ } }, "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", - "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -554,12 +554,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", - "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.0", + "@babel/parser": "^7.26.2", "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", @@ -919,9 +919,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", - "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "license": "MIT", "dependencies": { "@babel/types": "^7.26.0" @@ -10110,7 +10110,7 @@ }, "node_modules/@playwright/test": { "version": "1.44.1", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "playwright": "1.44.1" @@ -19964,7 +19964,6 @@ }, "node_modules/busboy": { "version": "1.6.0", - "dev": true, "dependencies": { "streamsearch": "^1.1.0" }, @@ -37508,7 +37507,7 @@ }, "node_modules/playwright": { "version": "1.44.1", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "playwright-core": "1.44.1" @@ -37525,7 +37524,7 @@ }, "node_modules/playwright-core": { "version": "1.44.1", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -41081,7 +41080,6 @@ }, "node_modules/streamsearch": { "version": "1.1.0", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -41394,7 +41392,6 @@ }, "node_modules/styled-jsx": { "version": "5.1.1", - "dev": true, "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -48543,6 +48540,7 @@ "@clerk/shared": "2.10.1", "@clerk/types": "4.28.0", "crypto-js": "4.2.0", + "ezheaders": "0.1.0", "server-only": "0.0.1", "tslib": "2.4.1" }, @@ -48566,7 +48564,6 @@ }, "packages/nextjs/node_modules/@next/env": { "version": "14.2.4", - "dev": true, "license": "MIT" }, "packages/nextjs/node_modules/@next/swc-darwin-arm64": { @@ -48574,7 +48571,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -48591,7 +48587,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -48607,7 +48602,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -48623,7 +48617,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -48639,7 +48632,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -48655,7 +48647,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -48671,7 +48662,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -48687,7 +48677,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -48703,7 +48692,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -48712,9 +48700,16 @@ "node": ">= 10" } }, + "packages/nextjs/node_modules/ezheaders": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ezheaders/-/ezheaders-0.1.0.tgz", + "integrity": "sha512-U0wdCs2dS+IzFuxyHGyw1aWhiunW22sGqnyH4yQsovkgqUvO4YSbzQ5BQzV6HY4oFlNnK+TbFGJj8rvvX5aN7w==", + "peerDependencies": { + "next": "^13.5.4 || ^14 || ^15" + } + }, "packages/nextjs/node_modules/next": { "version": "14.2.4", - "dev": true, "license": "MIT", "dependencies": { "@next/env": "14.2.4", @@ -48763,7 +48758,6 @@ }, "packages/nextjs/node_modules/postcss": { "version": "8.4.31", - "dev": true, "funding": [ { "type": "opencollective", diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 89137164ee8..df6fc2e9a92 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -72,6 +72,7 @@ "@clerk/shared": "2.10.1", "@clerk/types": "4.28.0", "crypto-js": "4.2.0", + "ezheaders": "0.1.0", "server-only": "0.0.1", "tslib": "2.4.1" }, diff --git a/packages/nextjs/src/app-router/server-actions.ts b/packages/nextjs/src/app-router/server-actions.ts index caecdf189d8..f5e883fb257 100644 --- a/packages/nextjs/src/app-router/server-actions.ts +++ b/packages/nextjs/src/app-router/server-actions.ts @@ -1,11 +1,11 @@ 'use server'; -import { cookies } from 'next/headers'; +import { cookie } from 'ezheaders'; // This function needs to be async as we'd like to support next versions in the range of [14.1.2,14.2.0) // These versions required 'use server' files to export async methods only. This check was later relaxed // and the async is no longer required in newer next versions. // ref: https://github.com/vercel/next.js/pull/62821 -export async function invalidateCacheAction() { - void (await cookies()).delete(`__clerk_invalidate_cache_cookie_${Date.now()}`); +export async function invalidateCacheAction(): Promise { + await cookie(`__clerk_invalidate_cache_cookie_${Date.now()}`, ''); } diff --git a/packages/nextjs/src/app-router/server/ClerkProvider.tsx b/packages/nextjs/src/app-router/server/ClerkProvider.tsx index b8c7dbd4f93..c7a17da813a 100644 --- a/packages/nextjs/src/app-router/server/ClerkProvider.tsx +++ b/packages/nextjs/src/app-router/server/ClerkProvider.tsx @@ -1,6 +1,6 @@ import type { AuthObject } from '@clerk/backend'; import type { InitialState, Without } from '@clerk/types'; -import { headers } from 'next/headers'; +import { header } from 'ezheaders'; import nextPkg from 'next/package.json'; import React from 'react'; @@ -21,7 +21,7 @@ const getDynamicClerkState = React.cache(async function getDynamicClerkState() { }); const getNonceFromCSPHeader = React.cache(async function getNonceFromCSPHeader() { - return getScriptNonceFromHeader((await headers()).get('Content-Security-Policy') || '') || ''; + return getScriptNonceFromHeader((await header('Content-Security-Policy')) || '') || ''; }); export async function ClerkProvider( diff --git a/packages/nextjs/src/app-router/server/utils.ts b/packages/nextjs/src/app-router/server/utils.ts index d831c4fdaaa..ae1f70d9f11 100644 --- a/packages/nextjs/src/app-router/server/utils.ts +++ b/packages/nextjs/src/app-router/server/utils.ts @@ -23,9 +23,8 @@ export async function buildRequestLike() { try { // Dynamically import next/headers, otherwise Next12 apps will break // @ts-ignore: Cannot find module 'next/headers' or its corresponding type declarations.ts(2307) - const { headers } = await import('next/headers'); - const resolvedHeaders = await headers(); - return new NextRequest('https://placeholder.com', { headers: resolvedHeaders }); + const { getHeaders } = await import('ezheaders'); + return new NextRequest('https://placeholder.com', { headers: await getHeaders() }); } catch (e: any) { // rethrow the error when react throws a prerendering bailout // https://nextjs.org/docs/messages/ppr-caught-error diff --git a/playground/app-router/package.json b/playground/app-router/package.json index 243077e36d6..b5375a012b0 100644 --- a/playground/app-router/package.json +++ b/playground/app-router/package.json @@ -23,6 +23,7 @@ "next": "^14.2.4", "react": "18.2.0", "react-dom": "18.2.0", - "typescript": "5.0.4" + "typescript": "5.0.4", + "ezheaders": "^0.0.3" } } diff --git a/playground/app-router/src/app/protected/page.tsx b/playground/app-router/src/app/protected/page.tsx index dbf53f5c6c9..ff3a74f16fd 100644 --- a/playground/app-router/src/app/protected/page.tsx +++ b/playground/app-router/src/app/protected/page.tsx @@ -1,14 +1,14 @@ -import { useAuth, ClerkLoaded, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'; +import { ClerkLoaded, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'; +import { auth } from '@clerk/nextjs/server'; import React from 'react'; import { ClientSideWrapper } from '@/app/protected/ClientSideWrapper'; -import { headers } from 'next/headers'; +import { header } from 'ezheaders'; export default async function Page() { - const { userId } = useAuth(); - const resolvedHeaders = await headers().get('x-clerk-debug'); + const { userId } = await auth(); + const xClerkDebug = await header('x-clerk-debug'); - console.log('Auth run in /protected', userId, resolvedHeaders.get('x-clerk-debug'), resolvedHeaders.keys()); - // console.log(auth()); + console.log('Auth run in /protected', userId, xClerkDebug); return (

Protected page