Skip to content
Merged
5 changes: 5 additions & 0 deletions .changeset/nasty-meals-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/nextjs": minor
---

Replace `next/headers` with `ezheaders`
50 changes: 22 additions & 28 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/nextjs/src/app-router/server-actions.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
await cookie(`__clerk_invalidate_cache_cookie_${Date.now()}`, '');
}
4 changes: 2 additions & 2 deletions packages/nextjs/src/app-router/server/ClerkProvider.tsx
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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(
Expand Down
5 changes: 2 additions & 3 deletions packages/nextjs/src/app-router/server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion playground/app-router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
12 changes: 6 additions & 6 deletions playground/app-router/src/app/protected/page.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<h1>Protected page</h1>
Expand Down
Loading