From 7c287f978d858041d635f09348f04fbe5ec7c030 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 11:50:31 +0200 Subject: [PATCH 01/12] wip --- packages/nextjs/src/app-router/server/auth.ts | 17 +++++++- .../nextjs/src/app-router/server/utils.ts | 2 +- packages/nextjs/src/server/createGetAuth.ts | 17 +++++++- packages/nextjs/src/server/errors.ts | 4 +- packages/nextjs/src/server/keyless-node.ts | 42 ++++++++++++++++++- 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 403dbf2710c..270e61a43f9 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -10,6 +10,7 @@ import type { AuthProtect } from '../../server/protect'; import { createProtect } from '../../server/protect'; import { decryptClerkRequestData } from '../../server/utils'; import { buildRequestLike } from './utils'; +// import { canUseKeyless } from '../../utils/feature-flags'; type Auth = AuthObject & { redirectToSignIn: RedirectFun> }; @@ -22,9 +23,21 @@ export const auth: AuthFn = async () => { require('server-only'); const request = await buildRequestLike(); - const authObject = createGetAuth({ + + // const isSrcAppDir = async () => { + // if (!canUseKeyless) { + // return ''; + // } + // + // const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.isSrcAppDir()).catch(() => false); + // return `- Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts\n`; + // }; + const authObject = await createGetAuth({ debugLoggerName: 'auth()', - noAuthStatusMessage: authAuthHeaderMissing(), + noAuthStatusMessage: authAuthHeaderMissing( + 'auth', + // , await isSrcAppDir() + ), })(request); const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl'); diff --git a/packages/nextjs/src/app-router/server/utils.ts b/packages/nextjs/src/app-router/server/utils.ts index 490166d3027..1c6e24a38f4 100644 --- a/packages/nextjs/src/app-router/server/utils.ts +++ b/packages/nextjs/src/app-router/server/utils.ts @@ -34,7 +34,7 @@ export async function buildRequestLike(): Promise { } throw new Error( - `Clerk: auth() and currentUser() are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, + `Clerk: auth(), currentUser() and clerkClient(), are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, ); } } diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 1f6106faeb9..ecefb80a8af 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -18,17 +18,30 @@ export const createGetAuth = ({ noAuthStatusMessage: string; }) => withLogger(debugLoggerName, logger => { - return (req: RequestLike, opts?: { secretKey?: string }): AuthObject => { + return async (req: RequestLike, opts?: { secretKey?: string }): Promise => { if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { logger.enable(); } - assertAuthStatus(req, noAuthStatusMessage); + // if (!detectClerkMiddleware(req)) { + // if (canUseKeyless) { + // const errorMessage = await import('./keyless-node.js').then(m => m.suggestMiddlewareLocation()); + // if (errorMessage) { + // throw new Error(errorMessage); + // } else { + // assertAuthStatus(req, noAuthStatusMessage); + // } + // } else { + // assertAuthStatus(req, noAuthStatusMessage); + // } + // } + assertAuthStatus(req, noAuthStatusMessage); return getAuthDataFromRequest(req, { ...opts, logger }); }; }); +// Did this break ? export const getAuth = createGetAuth({ debugLoggerName: 'getAuth()', noAuthStatusMessage: getAuthAuthHeaderMissing(), diff --git a/packages/nextjs/src/server/errors.ts b/packages/nextjs/src/server/errors.ts index c519771a7ee..6797d96f68c 100644 --- a/packages/nextjs/src/server/errors.ts +++ b/packages/nextjs/src/server/errors.ts @@ -20,9 +20,9 @@ Check if signInUrl is missing from your configuration or if it is not an absolut export const getAuthAuthHeaderMissing = () => authAuthHeaderMissing('getAuth'); -export const authAuthHeaderMissing = (helperName = 'auth') => +export const authAuthHeaderMissing = (helperName = 'auth', firstStep = '') => `Clerk: ${helperName}() was called but Clerk can't detect usage of clerkMiddleware(). Please ensure the following: -- clerkMiddleware() is used in your Next.js Middleware. +${firstStep}- clerkMiddleware() is used in your Next.js Middleware. - Your Middleware matcher is configured to match this route or page. - If you are using the src directory, make sure the Middleware file is inside of it. diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index 9b5a4b74686..f6d3ef4c25a 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -209,4 +209,44 @@ function removeKeyless() { unlockFileWriting(); } -export { createOrReadKeyless, removeKeyless }; +function isSrcAppDir() { + const { existsSync } = safeNodeRuntimeFs(); + const path = safeNodeRuntimePath(); + + const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); + + return !!existsSync(projectWithAppSrc); +} + +function suggestMiddlewareLocation() { + const { existsSync } = safeNodeRuntimeFs(); + const path = safeNodeRuntimePath(); + + const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); + const projectWithApp = path.join(process.cwd(), 'app'); + + if (existsSync(projectWithAppSrc)) { + if (existsSync(path.join(projectWithAppSrc, 'middleware.ts'))) { + return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /src/app/middleware.ts`; + } + + if (existsSync(path.join(process.cwd(), 'middleware.ts'))) { + return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /middleware.ts`; + } + + // default error + return undefined; + } + + if (existsSync(projectWithApp)) { + if (existsSync(path.join(projectWithApp, 'middleware.ts'))) { + return `Clerk: Move your middleware file to /middleware.ts. Currently located at /app/middleware.ts`; + } + // default error + return undefined; + } + + return undefined; +} + +export { createOrReadKeyless, removeKeyless, suggestMiddlewareLocation, isSrcAppDir }; From af2d82a69bd79686bfb8bb752ef98e3e82b34db0 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 11:51:07 +0200 Subject: [PATCH 02/12] Revert "wip" This reverts commit 7c287f978d858041d635f09348f04fbe5ec7c030. --- packages/nextjs/src/app-router/server/auth.ts | 17 +------- .../nextjs/src/app-router/server/utils.ts | 2 +- packages/nextjs/src/server/createGetAuth.ts | 17 +------- packages/nextjs/src/server/errors.ts | 4 +- packages/nextjs/src/server/keyless-node.ts | 42 +------------------ 5 files changed, 8 insertions(+), 74 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 270e61a43f9..403dbf2710c 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -10,7 +10,6 @@ import type { AuthProtect } from '../../server/protect'; import { createProtect } from '../../server/protect'; import { decryptClerkRequestData } from '../../server/utils'; import { buildRequestLike } from './utils'; -// import { canUseKeyless } from '../../utils/feature-flags'; type Auth = AuthObject & { redirectToSignIn: RedirectFun> }; @@ -23,21 +22,9 @@ export const auth: AuthFn = async () => { require('server-only'); const request = await buildRequestLike(); - - // const isSrcAppDir = async () => { - // if (!canUseKeyless) { - // return ''; - // } - // - // const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.isSrcAppDir()).catch(() => false); - // return `- Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts\n`; - // }; - const authObject = await createGetAuth({ + const authObject = createGetAuth({ debugLoggerName: 'auth()', - noAuthStatusMessage: authAuthHeaderMissing( - 'auth', - // , await isSrcAppDir() - ), + noAuthStatusMessage: authAuthHeaderMissing(), })(request); const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl'); diff --git a/packages/nextjs/src/app-router/server/utils.ts b/packages/nextjs/src/app-router/server/utils.ts index 1c6e24a38f4..490166d3027 100644 --- a/packages/nextjs/src/app-router/server/utils.ts +++ b/packages/nextjs/src/app-router/server/utils.ts @@ -34,7 +34,7 @@ export async function buildRequestLike(): Promise { } throw new Error( - `Clerk: auth(), currentUser() and clerkClient(), are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, + `Clerk: auth() and currentUser() are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, ); } } diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index ecefb80a8af..1f6106faeb9 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -18,30 +18,17 @@ export const createGetAuth = ({ noAuthStatusMessage: string; }) => withLogger(debugLoggerName, logger => { - return async (req: RequestLike, opts?: { secretKey?: string }): Promise => { + return (req: RequestLike, opts?: { secretKey?: string }): AuthObject => { if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { logger.enable(); } - // if (!detectClerkMiddleware(req)) { - // if (canUseKeyless) { - // const errorMessage = await import('./keyless-node.js').then(m => m.suggestMiddlewareLocation()); - // if (errorMessage) { - // throw new Error(errorMessage); - // } else { - // assertAuthStatus(req, noAuthStatusMessage); - // } - // } else { - // assertAuthStatus(req, noAuthStatusMessage); - // } - // } - assertAuthStatus(req, noAuthStatusMessage); + return getAuthDataFromRequest(req, { ...opts, logger }); }; }); -// Did this break ? export const getAuth = createGetAuth({ debugLoggerName: 'getAuth()', noAuthStatusMessage: getAuthAuthHeaderMissing(), diff --git a/packages/nextjs/src/server/errors.ts b/packages/nextjs/src/server/errors.ts index 6797d96f68c..c519771a7ee 100644 --- a/packages/nextjs/src/server/errors.ts +++ b/packages/nextjs/src/server/errors.ts @@ -20,9 +20,9 @@ Check if signInUrl is missing from your configuration or if it is not an absolut export const getAuthAuthHeaderMissing = () => authAuthHeaderMissing('getAuth'); -export const authAuthHeaderMissing = (helperName = 'auth', firstStep = '') => +export const authAuthHeaderMissing = (helperName = 'auth') => `Clerk: ${helperName}() was called but Clerk can't detect usage of clerkMiddleware(). Please ensure the following: -${firstStep}- clerkMiddleware() is used in your Next.js Middleware. +- clerkMiddleware() is used in your Next.js Middleware. - Your Middleware matcher is configured to match this route or page. - If you are using the src directory, make sure the Middleware file is inside of it. diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index f6d3ef4c25a..9b5a4b74686 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -209,44 +209,4 @@ function removeKeyless() { unlockFileWriting(); } -function isSrcAppDir() { - const { existsSync } = safeNodeRuntimeFs(); - const path = safeNodeRuntimePath(); - - const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); - - return !!existsSync(projectWithAppSrc); -} - -function suggestMiddlewareLocation() { - const { existsSync } = safeNodeRuntimeFs(); - const path = safeNodeRuntimePath(); - - const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); - const projectWithApp = path.join(process.cwd(), 'app'); - - if (existsSync(projectWithAppSrc)) { - if (existsSync(path.join(projectWithAppSrc, 'middleware.ts'))) { - return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /src/app/middleware.ts`; - } - - if (existsSync(path.join(process.cwd(), 'middleware.ts'))) { - return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /middleware.ts`; - } - - // default error - return undefined; - } - - if (existsSync(projectWithApp)) { - if (existsSync(path.join(projectWithApp, 'middleware.ts'))) { - return `Clerk: Move your middleware file to /middleware.ts. Currently located at /app/middleware.ts`; - } - // default error - return undefined; - } - - return undefined; -} - -export { createOrReadKeyless, removeKeyless, suggestMiddlewareLocation, isSrcAppDir }; +export { createOrReadKeyless, removeKeyless }; From 807566796ed02155eb7a2db5b3059a7c34f24c65 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 12:00:12 +0200 Subject: [PATCH 03/12] Revert "Revert "wip"" This reverts commit af2d82a69bd79686bfb8bb752ef98e3e82b34db0. --- packages/nextjs/src/app-router/server/auth.ts | 17 +++++++- .../nextjs/src/app-router/server/utils.ts | 2 +- packages/nextjs/src/server/createGetAuth.ts | 17 +++++++- packages/nextjs/src/server/errors.ts | 4 +- packages/nextjs/src/server/keyless-node.ts | 42 ++++++++++++++++++- 5 files changed, 74 insertions(+), 8 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 403dbf2710c..270e61a43f9 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -10,6 +10,7 @@ import type { AuthProtect } from '../../server/protect'; import { createProtect } from '../../server/protect'; import { decryptClerkRequestData } from '../../server/utils'; import { buildRequestLike } from './utils'; +// import { canUseKeyless } from '../../utils/feature-flags'; type Auth = AuthObject & { redirectToSignIn: RedirectFun> }; @@ -22,9 +23,21 @@ export const auth: AuthFn = async () => { require('server-only'); const request = await buildRequestLike(); - const authObject = createGetAuth({ + + // const isSrcAppDir = async () => { + // if (!canUseKeyless) { + // return ''; + // } + // + // const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.isSrcAppDir()).catch(() => false); + // return `- Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts\n`; + // }; + const authObject = await createGetAuth({ debugLoggerName: 'auth()', - noAuthStatusMessage: authAuthHeaderMissing(), + noAuthStatusMessage: authAuthHeaderMissing( + 'auth', + // , await isSrcAppDir() + ), })(request); const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl'); diff --git a/packages/nextjs/src/app-router/server/utils.ts b/packages/nextjs/src/app-router/server/utils.ts index 490166d3027..1c6e24a38f4 100644 --- a/packages/nextjs/src/app-router/server/utils.ts +++ b/packages/nextjs/src/app-router/server/utils.ts @@ -34,7 +34,7 @@ export async function buildRequestLike(): Promise { } throw new Error( - `Clerk: auth() and currentUser() are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, + `Clerk: auth(), currentUser() and clerkClient(), are only supported in App Router (/app directory).\nIf you're using /pages, try getAuth() instead.\nOriginal error: ${e}`, ); } } diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 1f6106faeb9..ecefb80a8af 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -18,17 +18,30 @@ export const createGetAuth = ({ noAuthStatusMessage: string; }) => withLogger(debugLoggerName, logger => { - return (req: RequestLike, opts?: { secretKey?: string }): AuthObject => { + return async (req: RequestLike, opts?: { secretKey?: string }): Promise => { if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { logger.enable(); } - assertAuthStatus(req, noAuthStatusMessage); + // if (!detectClerkMiddleware(req)) { + // if (canUseKeyless) { + // const errorMessage = await import('./keyless-node.js').then(m => m.suggestMiddlewareLocation()); + // if (errorMessage) { + // throw new Error(errorMessage); + // } else { + // assertAuthStatus(req, noAuthStatusMessage); + // } + // } else { + // assertAuthStatus(req, noAuthStatusMessage); + // } + // } + assertAuthStatus(req, noAuthStatusMessage); return getAuthDataFromRequest(req, { ...opts, logger }); }; }); +// Did this break ? export const getAuth = createGetAuth({ debugLoggerName: 'getAuth()', noAuthStatusMessage: getAuthAuthHeaderMissing(), diff --git a/packages/nextjs/src/server/errors.ts b/packages/nextjs/src/server/errors.ts index c519771a7ee..6797d96f68c 100644 --- a/packages/nextjs/src/server/errors.ts +++ b/packages/nextjs/src/server/errors.ts @@ -20,9 +20,9 @@ Check if signInUrl is missing from your configuration or if it is not an absolut export const getAuthAuthHeaderMissing = () => authAuthHeaderMissing('getAuth'); -export const authAuthHeaderMissing = (helperName = 'auth') => +export const authAuthHeaderMissing = (helperName = 'auth', firstStep = '') => `Clerk: ${helperName}() was called but Clerk can't detect usage of clerkMiddleware(). Please ensure the following: -- clerkMiddleware() is used in your Next.js Middleware. +${firstStep}- clerkMiddleware() is used in your Next.js Middleware. - Your Middleware matcher is configured to match this route or page. - If you are using the src directory, make sure the Middleware file is inside of it. diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index 9b5a4b74686..f6d3ef4c25a 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -209,4 +209,44 @@ function removeKeyless() { unlockFileWriting(); } -export { createOrReadKeyless, removeKeyless }; +function isSrcAppDir() { + const { existsSync } = safeNodeRuntimeFs(); + const path = safeNodeRuntimePath(); + + const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); + + return !!existsSync(projectWithAppSrc); +} + +function suggestMiddlewareLocation() { + const { existsSync } = safeNodeRuntimeFs(); + const path = safeNodeRuntimePath(); + + const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); + const projectWithApp = path.join(process.cwd(), 'app'); + + if (existsSync(projectWithAppSrc)) { + if (existsSync(path.join(projectWithAppSrc, 'middleware.ts'))) { + return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /src/app/middleware.ts`; + } + + if (existsSync(path.join(process.cwd(), 'middleware.ts'))) { + return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /middleware.ts`; + } + + // default error + return undefined; + } + + if (existsSync(projectWithApp)) { + if (existsSync(path.join(projectWithApp, 'middleware.ts'))) { + return `Clerk: Move your middleware file to /middleware.ts. Currently located at /app/middleware.ts`; + } + // default error + return undefined; + } + + return undefined; +} + +export { createOrReadKeyless, removeKeyless, suggestMiddlewareLocation, isSrcAppDir }; From 040628cda70d5e52ed7c142d147bb6e96f1e51f6 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 13:12:35 +0200 Subject: [PATCH 04/12] feat(nextjs): Hint correct middleware location when missing clerkMiddleware --- .changeset/fuzzy-rockets-smash.md | 5 +++ .../src/app-router/server/ClerkProvider.tsx | 10 +----- packages/nextjs/src/app-router/server/auth.ts | 27 ++++++++------- packages/nextjs/src/server/createGetAuth.ts | 34 +++++++++++-------- packages/nextjs/src/server/errors.ts | 4 +-- packages/nextjs/src/server/keyless-node.ts | 4 +-- 6 files changed, 43 insertions(+), 41 deletions(-) create mode 100644 .changeset/fuzzy-rockets-smash.md diff --git a/.changeset/fuzzy-rockets-smash.md b/.changeset/fuzzy-rockets-smash.md new file mode 100644 index 00000000000..30425d20309 --- /dev/null +++ b/.changeset/fuzzy-rockets-smash.md @@ -0,0 +1,5 @@ +--- +'@clerk/nextjs': patch +--- + +Improve error messages when clerkMiddleware is missing by suggesting the correct path to place the middleware.ts file. diff --git a/packages/nextjs/src/app-router/server/ClerkProvider.tsx b/packages/nextjs/src/app-router/server/ClerkProvider.tsx index 7748f06fa6a..f6546929cbe 100644 --- a/packages/nextjs/src/app-router/server/ClerkProvider.tsx +++ b/packages/nextjs/src/app-router/server/ClerkProvider.tsx @@ -8,6 +8,7 @@ import { safeParseClerkFile } from '../../server/keyless-node'; import type { NextClerkProviderProps } from '../../types'; import { canUseKeyless } from '../../utils/feature-flags'; import { mergeNextClerkPropsWithEnv } from '../../utils/mergeNextClerkPropsWithEnv'; +import { onlyTry } from '../../utils/only-try'; import { isNext13 } from '../../utils/sdk-versions'; import { ClientClerkProvider } from '../client/ClerkProvider'; import { deleteKeylessAction } from '../keyless-actions'; @@ -24,15 +25,6 @@ const getNonceFromCSPHeader = React.cache(async function getNonceFromCSPHeader() return getScriptNonceFromHeader((await headers()).get('Content-Security-Policy') || '') || ''; }); -/** Discards errors thrown by attempted code */ -const onlyTry = (cb: () => unknown) => { - try { - cb(); - } catch (e) { - // ignore - } -}; - export async function ClerkProvider( props: Without, ) { diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 270e61a43f9..8afac8607cd 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -9,8 +9,8 @@ import { getAuthKeyFromRequest, getHeader } from '../../server/headers-utils'; import type { AuthProtect } from '../../server/protect'; import { createProtect } from '../../server/protect'; import { decryptClerkRequestData } from '../../server/utils'; +import { isNextWithUnstableServerActions } from '../../utils/sdk-versions'; import { buildRequestLike } from './utils'; -// import { canUseKeyless } from '../../utils/feature-flags'; type Auth = AuthObject & { redirectToSignIn: RedirectFun> }; @@ -24,20 +24,21 @@ export const auth: AuthFn = async () => { const request = await buildRequestLike(); - // const isSrcAppDir = async () => { - // if (!canUseKeyless) { - // return ''; - // } - // - // const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.isSrcAppDir()).catch(() => false); - // return `- Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts\n`; - // }; + const stepsBasedOnSrcDirectory = async () => { + if (isNextWithUnstableServerActions) { + return []; + } + + try { + const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.hasSrcAppDir()); + return [`Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts`]; + } catch { + return []; + } + }; const authObject = await createGetAuth({ debugLoggerName: 'auth()', - noAuthStatusMessage: authAuthHeaderMissing( - 'auth', - // , await isSrcAppDir() - ), + noAuthStatusMessage: authAuthHeaderMissing('auth', await stepsBasedOnSrcDirectory()), })(request); const clerkUrl = getAuthKeyFromRequest(request, 'ClerkUrl'); diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index ecefb80a8af..f4a0d5446c7 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -4,9 +4,10 @@ import { decodeJwt } from '@clerk/backend/jwt'; import { isTruthy } from '@clerk/shared/underscore'; import { withLogger } from '../utils/debugLogger'; +import { isNextWithUnstableServerActions } from '../utils/sdk-versions'; import { getAuthDataFromRequest } from './data/getAuthDataFromRequest'; import { getAuthAuthHeaderMissing } from './errors'; -import { getHeader } from './headers-utils'; +import { detectClerkMiddleware, getHeader } from './headers-utils'; import type { RequestLike } from './types'; import { assertAuthStatus, getCookie } from './utils'; @@ -23,20 +24,23 @@ export const createGetAuth = ({ logger.enable(); } - // if (!detectClerkMiddleware(req)) { - // if (canUseKeyless) { - // const errorMessage = await import('./keyless-node.js').then(m => m.suggestMiddlewareLocation()); - // if (errorMessage) { - // throw new Error(errorMessage); - // } else { - // assertAuthStatus(req, noAuthStatusMessage); - // } - // } else { - // assertAuthStatus(req, noAuthStatusMessage); - // } - // } - - assertAuthStatus(req, noAuthStatusMessage); + if (!detectClerkMiddleware(req)) { + // Keep the same behaviour for versions that may have issues with bundling `node:fs` + if (isNextWithUnstableServerActions) { + assertAuthStatus(req, noAuthStatusMessage); + } + + const missConfiguredMiddlewareLocation = await import('./keyless-node.js') + .then(m => m.suggestMiddlewareLocation()) + .catch(() => undefined); + + if (missConfiguredMiddlewareLocation) { + throw new Error(missConfiguredMiddlewareLocation); + } + + assertAuthStatus(req, noAuthStatusMessage); + } + return getAuthDataFromRequest(req, { ...opts, logger }); }; }); diff --git a/packages/nextjs/src/server/errors.ts b/packages/nextjs/src/server/errors.ts index 6797d96f68c..af315b2df69 100644 --- a/packages/nextjs/src/server/errors.ts +++ b/packages/nextjs/src/server/errors.ts @@ -20,9 +20,9 @@ Check if signInUrl is missing from your configuration or if it is not an absolut export const getAuthAuthHeaderMissing = () => authAuthHeaderMissing('getAuth'); -export const authAuthHeaderMissing = (helperName = 'auth', firstStep = '') => +export const authAuthHeaderMissing = (helperName = 'auth', prefixSteps?: string[]) => `Clerk: ${helperName}() was called but Clerk can't detect usage of clerkMiddleware(). Please ensure the following: -${firstStep}- clerkMiddleware() is used in your Next.js Middleware. +- ${prefixSteps ? [...prefixSteps, ''].join('\n- ') : ' '}clerkMiddleware() is used in your Next.js Middleware. - Your Middleware matcher is configured to match this route or page. - If you are using the src directory, make sure the Middleware file is inside of it. diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index f6d3ef4c25a..06b325fde61 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -209,7 +209,7 @@ function removeKeyless() { unlockFileWriting(); } -function isSrcAppDir() { +function hasSrcAppDir() { const { existsSync } = safeNodeRuntimeFs(); const path = safeNodeRuntimePath(); @@ -249,4 +249,4 @@ function suggestMiddlewareLocation() { return undefined; } -export { createOrReadKeyless, removeKeyless, suggestMiddlewareLocation, isSrcAppDir }; +export { createOrReadKeyless, removeKeyless, suggestMiddlewareLocation, hasSrcAppDir }; From 4da1637856c6cc83ffb3715f2eb21a07a9a8df42 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 13:27:51 +0200 Subject: [PATCH 05/12] missed file --- packages/nextjs/src/utils/only-try.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 packages/nextjs/src/utils/only-try.ts diff --git a/packages/nextjs/src/utils/only-try.ts b/packages/nextjs/src/utils/only-try.ts new file mode 100644 index 00000000000..22eb40aaafa --- /dev/null +++ b/packages/nextjs/src/utils/only-try.ts @@ -0,0 +1,12 @@ +/** + * Discards errors thrown by attempted code + */ +const onlyTry = (cb: () => unknown) => { + try { + cb(); + } catch (e) { + // ignore + } +}; + +export { onlyTry }; From d1d82f8ff74238ebe57591709bc7f708eebb781a Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 23 Jan 2025 14:09:42 +0200 Subject: [PATCH 06/12] prevent breaking sync getAuth() --- packages/nextjs/src/app-router/server/auth.ts | 4 +- .../server/__tests__/createGetAuth.test.ts | 4 +- packages/nextjs/src/server/createGetAuth.ts | 76 ++++++++++++++----- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 8afac8607cd..628cbc4dd54 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -3,7 +3,7 @@ import { constants, createClerkRequest, createRedirect, type RedirectFun } from import { notFound, redirect } from 'next/navigation'; import { PUBLISHABLE_KEY, SIGN_IN_URL, SIGN_UP_URL } from '../../server/constants'; -import { createGetAuth } from '../../server/createGetAuth'; +import { createGetAuthAsync } from '../../server/createGetAuth'; import { authAuthHeaderMissing } from '../../server/errors'; import { getAuthKeyFromRequest, getHeader } from '../../server/headers-utils'; import type { AuthProtect } from '../../server/protect'; @@ -36,7 +36,7 @@ export const auth: AuthFn = async () => { return []; } }; - const authObject = await createGetAuth({ + const authObject = await createGetAuthAsync({ debugLoggerName: 'auth()', noAuthStatusMessage: authAuthHeaderMissing('auth', await stepsBasedOnSrcDirectory()), })(request); diff --git a/packages/nextjs/src/server/__tests__/createGetAuth.test.ts b/packages/nextjs/src/server/__tests__/createGetAuth.test.ts index e881ab7368b..d9f4493481b 100644 --- a/packages/nextjs/src/server/__tests__/createGetAuth.test.ts +++ b/packages/nextjs/src/server/__tests__/createGetAuth.test.ts @@ -3,7 +3,7 @@ import hmacSHA1 from 'crypto-js/hmac-sha1'; import { NextRequest } from 'next/server'; import { describe, expect, it } from 'vitest'; -import { createGetAuth, getAuth } from '../createGetAuth'; +import { createGetAuthSync, getAuth } from '../createGetAuth'; const mockSecretKey = 'sk_test_mock'; @@ -16,7 +16,7 @@ const mockTokenSignature = hmacSHA1(mockToken, 'sk_test_mock').toString(); describe('createGetAuth(opts)', () => { it('returns a getAuth function', () => { - expect(createGetAuth({ debugLoggerName: 'test', noAuthStatusMessage: 'test' })).toBeInstanceOf(Function); + expect(createGetAuthSync({ debugLoggerName: 'test', noAuthStatusMessage: 'test' })).toBeInstanceOf(Function); }); }); diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index f4a0d5446c7..dbda3f8e82e 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -1,33 +1,61 @@ import type { AuthObject } from '@clerk/backend'; import { constants } from '@clerk/backend/internal'; -import { decodeJwt } from '@clerk/backend/jwt'; import { isTruthy } from '@clerk/shared/underscore'; -import { withLogger } from '../utils/debugLogger'; +import { type LoggerNoCommit, withLogger } from '../utils/debugLogger'; import { isNextWithUnstableServerActions } from '../utils/sdk-versions'; import { getAuthDataFromRequest } from './data/getAuthDataFromRequest'; import { getAuthAuthHeaderMissing } from './errors'; import { detectClerkMiddleware, getHeader } from './headers-utils'; import type { RequestLike } from './types'; -import { assertAuthStatus, getCookie } from './utils'; +import { assertAuthStatus } from './utils'; -export const createGetAuth = ({ - noAuthStatusMessage, +// Utility type to determine if a type is a Promise +type IsPromise = T extends Promise ? true : false; + +const createGetAuth = < + TTransformer extends (param: { + options: { secretKey?: string }; + logger: LoggerNoCommit; + request: RequestLike; + }) => AuthObject | Promise, +>({ debugLoggerName, + transformer, }: { debugLoggerName: string; - noAuthStatusMessage: string; + transformer: TTransformer; }) => withLogger(debugLoggerName, logger => { - return async (req: RequestLike, opts?: { secretKey?: string }): Promise => { + return (req: RequestLike, opts?: { secretKey?: string }) => { if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { logger.enable(); } - if (!detectClerkMiddleware(req)) { + return transformer({ + request: req, + options: { ...opts }, + logger, + }) as unknown as IsPromise> extends true + ? Promise>> + : ReturnType; + }; + }); + +export const createGetAuthAsync = ({ + debugLoggerName, + noAuthStatusMessage, +}: { + debugLoggerName: string; + noAuthStatusMessage: string; +}) => + createGetAuth({ + debugLoggerName: debugLoggerName, + transformer: async ({ request, options, logger }) => { + if (!detectClerkMiddleware(request)) { // Keep the same behaviour for versions that may have issues with bundling `node:fs` if (isNextWithUnstableServerActions) { - assertAuthStatus(req, noAuthStatusMessage); + assertAuthStatus(request, noAuthStatusMessage); } const missConfiguredMiddlewareLocation = await import('./keyless-node.js') @@ -38,21 +66,29 @@ export const createGetAuth = ({ throw new Error(missConfiguredMiddlewareLocation); } - assertAuthStatus(req, noAuthStatusMessage); + assertAuthStatus(request, noAuthStatusMessage); } - return getAuthDataFromRequest(req, { ...opts, logger }); - }; + return getAuthDataFromRequest(request, { ...options, logger }); + }, }); -// Did this break ? -export const getAuth = createGetAuth({ +export const createGetAuthSync = ({ + debugLoggerName, + noAuthStatusMessage, +}: { + debugLoggerName: string; + noAuthStatusMessage: string; +}) => + createGetAuth({ + debugLoggerName: debugLoggerName, + transformer: ({ request, options, logger }) => { + assertAuthStatus(request, noAuthStatusMessage); + return getAuthDataFromRequest(request, { ...options, logger }); + }, + }); + +export const getAuth = createGetAuthSync({ debugLoggerName: 'getAuth()', noAuthStatusMessage: getAuthAuthHeaderMissing(), }); - -export const parseJwt = (req: RequestLike) => { - const cookieToken = getCookie(req, constants.Cookies.Session); - const headerToken = getHeader(req, 'authorization')?.replace('Bearer ', ''); - return decodeJwt(cookieToken || headerToken || ''); -}; From fd8bc74bb7e5cb9a512ce42047dc7a34bf26b0e8 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 24 Jan 2025 17:54:00 +0200 Subject: [PATCH 07/12] replace root with `./` --- packages/nextjs/src/app-router/server/auth.ts | 2 +- packages/nextjs/src/server/keyless-node.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 628cbc4dd54..0dd77f71138 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -31,7 +31,7 @@ export const auth: AuthFn = async () => { try { const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.hasSrcAppDir()); - return [`Your Middleware exists at /${isSrcAppDir ? 'src/' : ''}middleware.ts`]; + return [`Your Middleware exists at ./${isSrcAppDir ? 'src/' : ''}middleware.ts`]; } catch { return []; } diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index 06b325fde61..6f65c7b5118 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -219,6 +219,11 @@ function hasSrcAppDir() { } function suggestMiddlewareLocation() { + const suggestionMessage = (to?: 'src/', from?: 'src/app/' | 'app/') => { + const _to = to || ''; + const _from = from || ''; + return `Clerk: Move your middleware file to ./${_to}middleware.ts. Currently located at ./${_from}middleware.ts`; + }; const { existsSync } = safeNodeRuntimeFs(); const path = safeNodeRuntimePath(); @@ -227,11 +232,11 @@ function suggestMiddlewareLocation() { if (existsSync(projectWithAppSrc)) { if (existsSync(path.join(projectWithAppSrc, 'middleware.ts'))) { - return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /src/app/middleware.ts`; + return suggestionMessage('src/', 'src/app/'); } if (existsSync(path.join(process.cwd(), 'middleware.ts'))) { - return `Clerk: Move your middleware file to /src/middleware.ts. Currently located at /middleware.ts`; + return suggestionMessage('src/'); } // default error @@ -240,7 +245,7 @@ function suggestMiddlewareLocation() { if (existsSync(projectWithApp)) { if (existsSync(path.join(projectWithApp, 'middleware.ts'))) { - return `Clerk: Move your middleware file to /middleware.ts. Currently located at /app/middleware.ts`; + return suggestionMessage(undefined, 'app/'); } // default error return undefined; From 4dad459ad1e058d6d4a2291102ee2d8fa0bb3405 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 24 Jan 2025 19:05:58 +0200 Subject: [PATCH 08/12] fix lint errors --- packages/nextjs/src/app-router/server/auth.ts | 1 + packages/nextjs/src/server/createGetAuth.ts | 1 + packages/nextjs/src/utils/only-try.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 231e6ecf220..7fa040ce1dc 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -31,6 +31,7 @@ export const auth: AuthFn = async () => { } try { + // eslint-disable-next-line import/no-unresolved const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.hasSrcAppDir()); return [`Your Middleware exists at ./${isSrcAppDir ? 'src/' : ''}middleware.ts`]; } catch { diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index dbda3f8e82e..6375cff3afa 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -58,6 +58,7 @@ export const createGetAuthAsync = ({ assertAuthStatus(request, noAuthStatusMessage); } + // eslint-disable-next-line import/no-unresolved const missConfiguredMiddlewareLocation = await import('./keyless-node.js') .then(m => m.suggestMiddlewareLocation()) .catch(() => undefined); diff --git a/packages/nextjs/src/utils/only-try.ts b/packages/nextjs/src/utils/only-try.ts index 22eb40aaafa..5f8c62e87f8 100644 --- a/packages/nextjs/src/utils/only-try.ts +++ b/packages/nextjs/src/utils/only-try.ts @@ -4,7 +4,7 @@ const onlyTry = (cb: () => unknown) => { try { cb(); - } catch (e) { + } catch { // ignore } }; From 85a7694022d5f4154efcdf5f578d137011fda617 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 27 Jan 2025 14:27:44 +0200 Subject: [PATCH 09/12] Apply suggestions from code review Co-authored-by: Stefanos Anagnostou Co-authored-by: Nikos Douvlis --- .changeset/fuzzy-rockets-smash.md | 2 +- packages/nextjs/src/server/keyless-node.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/fuzzy-rockets-smash.md b/.changeset/fuzzy-rockets-smash.md index 30425d20309..9fa92bda846 100644 --- a/.changeset/fuzzy-rockets-smash.md +++ b/.changeset/fuzzy-rockets-smash.md @@ -2,4 +2,4 @@ '@clerk/nextjs': patch --- -Improve error messages when clerkMiddleware is missing by suggesting the correct path to place the middleware.ts file. +Improve error messages when `clerkMiddleware` is missing by suggesting the correct path to place the `middleware.ts` file. diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index d964529c3e9..d64aa561a46 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -222,7 +222,7 @@ function suggestMiddlewareLocation() { const suggestionMessage = (to?: 'src/', from?: 'src/app/' | 'app/') => { const _to = to || ''; const _from = from || ''; - return `Clerk: Move your middleware file to ./${_to}middleware.ts. Currently located at ./${_from}middleware.ts`; + return `Clerk: Move your middleware file to ./${to || ''}middleware.ts. Currently located at ./${from || ''}middleware.ts`; }; const { existsSync } = safeNodeRuntimeFs(); const path = safeNodeRuntimePath(); From 88768ab75dbd3a08b0e05f205d32ed7e4a830ec4 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 27 Jan 2025 15:05:22 +0200 Subject: [PATCH 10/12] address review comments --- packages/nextjs/src/app-router/server/auth.ts | 4 +- packages/nextjs/src/server/createGetAuth.ts | 70 ++++++------------- packages/nextjs/src/server/keyless-node.ts | 20 +++--- 3 files changed, 33 insertions(+), 61 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 7fa040ce1dc..0614f244882 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -3,7 +3,7 @@ import { constants, createClerkRequest, createRedirect, type RedirectFun } from import { notFound, redirect } from 'next/navigation'; import { PUBLISHABLE_KEY, SIGN_IN_URL, SIGN_UP_URL } from '../../server/constants'; -import { createGetAuthAsync } from '../../server/createGetAuth'; +import { createAsyncGetAuth } from '../../server/createGetAuth'; import { authAuthHeaderMissing } from '../../server/errors'; import { getAuthKeyFromRequest, getHeader } from '../../server/headers-utils'; import type { AuthProtect } from '../../server/protect'; @@ -38,7 +38,7 @@ export const auth: AuthFn = async () => { return []; } }; - const authObject = await createGetAuthAsync({ + const authObject = await createAsyncGetAuth({ debugLoggerName: 'auth()', noAuthStatusMessage: authAuthHeaderMissing('auth', await stepsBasedOnSrcDirectory()), })(request); diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 6375cff3afa..3a4f3b09557 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -1,8 +1,7 @@ -import type { AuthObject } from '@clerk/backend'; import { constants } from '@clerk/backend/internal'; import { isTruthy } from '@clerk/shared/underscore'; -import { type LoggerNoCommit, withLogger } from '../utils/debugLogger'; +import { withLogger } from '../utils/debugLogger'; import { isNextWithUnstableServerActions } from '../utils/sdk-versions'; import { getAuthDataFromRequest } from './data/getAuthDataFromRequest'; import { getAuthAuthHeaderMissing } from './errors'; @@ -10,52 +9,23 @@ import { detectClerkMiddleware, getHeader } from './headers-utils'; import type { RequestLike } from './types'; import { assertAuthStatus } from './utils'; -// Utility type to determine if a type is a Promise -type IsPromise = T extends Promise ? true : false; - -const createGetAuth = < - TTransformer extends (param: { - options: { secretKey?: string }; - logger: LoggerNoCommit; - request: RequestLike; - }) => AuthObject | Promise, ->({ +export const createAsyncGetAuth = ({ debugLoggerName, - transformer, + noAuthStatusMessage, }: { debugLoggerName: string; - transformer: TTransformer; + noAuthStatusMessage: string; }) => withLogger(debugLoggerName, logger => { - return (req: RequestLike, opts?: { secretKey?: string }) => { + return async (req: RequestLike, opts?: { secretKey?: string }) => { if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { logger.enable(); } - return transformer({ - request: req, - options: { ...opts }, - logger, - }) as unknown as IsPromise> extends true - ? Promise>> - : ReturnType; - }; - }); - -export const createGetAuthAsync = ({ - debugLoggerName, - noAuthStatusMessage, -}: { - debugLoggerName: string; - noAuthStatusMessage: string; -}) => - createGetAuth({ - debugLoggerName: debugLoggerName, - transformer: async ({ request, options, logger }) => { - if (!detectClerkMiddleware(request)) { + if (!detectClerkMiddleware(req)) { // Keep the same behaviour for versions that may have issues with bundling `node:fs` if (isNextWithUnstableServerActions) { - assertAuthStatus(request, noAuthStatusMessage); + assertAuthStatus(req, noAuthStatusMessage); } // eslint-disable-next-line import/no-unresolved @@ -67,29 +37,33 @@ export const createGetAuthAsync = ({ throw new Error(missConfiguredMiddlewareLocation); } - assertAuthStatus(request, noAuthStatusMessage); + // still throw there is no suggested move location + assertAuthStatus(req, noAuthStatusMessage); } - return getAuthDataFromRequest(request, { ...options, logger }); - }, + return getAuthDataFromRequest(req, { ...opts, logger }); + }; }); -export const createGetAuthSync = ({ +export const createSyncGetAuth = ({ debugLoggerName, noAuthStatusMessage, }: { debugLoggerName: string; noAuthStatusMessage: string; }) => - createGetAuth({ - debugLoggerName: debugLoggerName, - transformer: ({ request, options, logger }) => { - assertAuthStatus(request, noAuthStatusMessage); - return getAuthDataFromRequest(request, { ...options, logger }); - }, + withLogger(debugLoggerName, logger => { + return (req: RequestLike, opts?: { secretKey?: string }) => { + if (isTruthy(getHeader(req, constants.Headers.EnableDebug))) { + logger.enable(); + } + + assertAuthStatus(req, noAuthStatusMessage); + return getAuthDataFromRequest(req, { ...opts, logger }); + }; }); -export const getAuth = createGetAuthSync({ +export const getAuth = createSyncGetAuth({ debugLoggerName: 'getAuth()', noAuthStatusMessage: getAuthAuthHeaderMissing(), }); diff --git a/packages/nextjs/src/server/keyless-node.ts b/packages/nextjs/src/server/keyless-node.ts index d64aa561a46..f83f88028f2 100644 --- a/packages/nextjs/src/server/keyless-node.ts +++ b/packages/nextjs/src/server/keyless-node.ts @@ -219,19 +219,17 @@ function hasSrcAppDir() { } function suggestMiddlewareLocation() { - const suggestionMessage = (to?: 'src/', from?: 'src/app/' | 'app/') => { - const _to = to || ''; - const _from = from || ''; - return `Clerk: Move your middleware file to ./${to || ''}middleware.ts. Currently located at ./${from || ''}middleware.ts`; - }; + const suggestionMessage = (to?: 'src/', from?: 'src/app/' | 'app/') => + `Clerk: Move your middleware file to ./${to || ''}middleware.ts. Currently located at ./${from || ''}middleware.ts`; + const { existsSync } = safeNodeRuntimeFs(); const path = safeNodeRuntimePath(); - const projectWithAppSrc = path.join(process.cwd(), 'src', 'app'); - const projectWithApp = path.join(process.cwd(), 'app'); + const projectWithAppSrcPath = path.join(process.cwd(), 'src', 'app'); + const projectWithAppPath = path.join(process.cwd(), 'app'); - if (existsSync(projectWithAppSrc)) { - if (existsSync(path.join(projectWithAppSrc, 'middleware.ts'))) { + if (existsSync(projectWithAppSrcPath)) { + if (existsSync(path.join(projectWithAppSrcPath, 'middleware.ts'))) { return suggestionMessage('src/', 'src/app/'); } @@ -243,8 +241,8 @@ function suggestMiddlewareLocation() { return undefined; } - if (existsSync(projectWithApp)) { - if (existsSync(path.join(projectWithApp, 'middleware.ts'))) { + if (existsSync(projectWithAppPath)) { + if (existsSync(path.join(projectWithAppPath, 'middleware.ts'))) { return suggestionMessage(undefined, 'app/'); } // default error From 09795c3c884146c5c45d3c982a63f51a54ccb60f Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 27 Jan 2025 15:10:22 +0200 Subject: [PATCH 11/12] fix tests --- packages/nextjs/src/server/__tests__/createGetAuth.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/server/__tests__/createGetAuth.test.ts b/packages/nextjs/src/server/__tests__/createGetAuth.test.ts index d9f4493481b..56a9e99bd12 100644 --- a/packages/nextjs/src/server/__tests__/createGetAuth.test.ts +++ b/packages/nextjs/src/server/__tests__/createGetAuth.test.ts @@ -3,7 +3,7 @@ import hmacSHA1 from 'crypto-js/hmac-sha1'; import { NextRequest } from 'next/server'; import { describe, expect, it } from 'vitest'; -import { createGetAuthSync, getAuth } from '../createGetAuth'; +import { createSyncGetAuth, getAuth } from '../createGetAuth'; const mockSecretKey = 'sk_test_mock'; @@ -16,7 +16,7 @@ const mockTokenSignature = hmacSHA1(mockToken, 'sk_test_mock').toString(); describe('createGetAuth(opts)', () => { it('returns a getAuth function', () => { - expect(createGetAuthSync({ debugLoggerName: 'test', noAuthStatusMessage: 'test' })).toBeInstanceOf(Function); + expect(createSyncGetAuth({ debugLoggerName: 'test', noAuthStatusMessage: 'test' })).toBeInstanceOf(Function); }); }); From 47d3f314f9f66dfc61db2bff511312c10a156bcd Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 27 Jan 2025 15:18:13 +0200 Subject: [PATCH 12/12] remove eslint rules --- packages/nextjs/src/app-router/server/auth.ts | 3 ++- packages/nextjs/src/server/createGetAuth.ts | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index adf81ff8e90..e090b849adb 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -26,8 +26,10 @@ type Auth = AuthObject & { */ redirectToSignIn: RedirectFun>; }; + export interface AuthFn { (): Promise; + /** * `auth` includes a single property, the `protect()` method, which you can use in two ways: * - to check if a user is authenticated (signed in) @@ -68,7 +70,6 @@ export const auth: AuthFn = async () => { } try { - // eslint-disable-next-line import/no-unresolved const isSrcAppDir = await import('../../server/keyless-node.js').then(m => m.hasSrcAppDir()); return [`Your Middleware exists at ./${isSrcAppDir ? 'src/' : ''}middleware.ts`]; } catch { diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 059dc0b6382..7e6caeb0f12 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -28,7 +28,6 @@ export const createAsyncGetAuth = ({ assertAuthStatus(req, noAuthStatusMessage); } - // eslint-disable-next-line import/no-unresolved const missConfiguredMiddlewareLocation = await import('./keyless-node.js') .then(m => m.suggestMiddlewareLocation()) .catch(() => undefined);