-
Notifications
You must be signed in to change notification settings - Fork 381
feat(react-router): [WIP] Introduce middleware #6660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 5fd6ef8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughAdds middleware-based Clerk authentication to the React Router SDK: new clerkMiddleware, middleware-aware getAuth and rootAuthLoader (with legacy fallback and streaming), server exports/types, tests, template/config updates, and a migration warning/example. No public signatures were removed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant RR as React Router
participant MW as clerkMiddleware
participant CL as Clerk Backend
participant LD as rootAuthLoader
participant H as Route Handler
rect rgb(245,250,255)
U->>RR: HTTP Request
RR->>MW: invoke middleware(args)
MW->>CL: authenticateRequest(patched request)
end
alt Redirect required
CL-->>MW: RequestState w/ Location
MW-->>RR: 307 Redirect (propagate headers)
RR-->>U: Redirect response
else Auth evaluated
CL-->>MW: RequestState
MW->>RR: next() (contexts set)
RR->>LD: call rootAuthLoader(args)
alt Middleware present
LD->>H: call handler with auth in args (streaming allowed)
H-->>LD: Response | Data | Object | null
LD-->>RR: merged result (inject/merge clerkState)
else Legacy path
LD->>CL: legacyAuthenticateRequest(...)
CL-->>LD: RequestState
LD-->>RR: Response with injected clerkState (includeClerkHeaders)
end
RR-->>U: Final response
end
sequenceDiagram
participant LD as rootAuthLoader
participant Ctx as Middleware Context
participant LG as legacyAuthenticateRequest
note right of Ctx #e8f7ff: checks for requestState and authFn
LD->>Ctx: check requestState
alt With middleware
Ctx-->>LD: requestState available
LD->>LD: processRootAuthLoader(handler?) => merge/stream or inject
else Without middleware
Ctx-->>LD: null
LD->>LG: authenticate (legacy flow)
LG-->>LD: requestState
LD->>LD: processRootAuthLoader(handler?, includeClerkHeaders=true)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
✨ Finishing Touches🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
@clerk/agent-toolkit
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/elements
@clerk/clerk-expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/clerk-react
@clerk/react-router
@clerk/remix
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/themes
@clerk/types
@clerk/upgrade
@clerk/vue
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/react-router/src/server/types.ts (1)
15-40
: Avoid defaulting generics to any in public types (outside selected range included below)Current defaults elsewhere use “= any”, which weakens consumer DX. Prefer a concrete default or unknown and narrow.
Outside this hunk, update generic defaults:
- export type LoaderFunctionArgsWithAuth<Options extends RootAuthLoaderOptions = any> = LoaderFunctionArgs & { + export type LoaderFunctionArgsWithAuth<Options extends RootAuthLoaderOptions = RootAuthLoaderOptions> = LoaderFunctionArgs & { request: RequestWithAuth<Options>; }; - export type RequestWithAuth<Options extends RootAuthLoaderOptions = any> = LoaderFunctionArgs['request'] & { + export type RequestWithAuth<Options extends RootAuthLoaderOptions = RootAuthLoaderOptions> = LoaderFunctionArgs['request'] & { auth: Omit<SignedInAuthObject | SignedOutAuthObject, 'session' | 'user' | 'organization'>; } & (Options extends { loadSession: true } ? { session: Session | null } : object) & (Options extends { loadUser: true } ? { user: User | null } : object) & (Options extends { loadOrganization: true } ? { organization: Organization | null } : object);packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
16-34
: Bug: acceptsToken is dropped; pass it through to authenticateRequestacceptsToken from opts isn’t forwarded, changing auth source semantics. Include it in the options passed to authenticateRequest.
Apply this diff:
- const { audience, authorizedParties } = opts; + const { audience, authorizedParties, acceptsToken } = opts; @@ - const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), { + const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), { @@ - afterSignUpUrl, + afterSignUpUrl, + acceptsToken, });
🧹 Nitpick comments (19)
packages/react-router/src/utils/errors.ts (1)
120-124
: Tighten wording/quotes in warningMinor polish: drop the leading single quote before "clerkMiddleware()".
Apply:
-export const middlewareMigrationWarning = createErrorMessage(` -'"clerkMiddleware()" not detected. +export const middlewareMigrationWarning = createErrorMessage(` +"clerkMiddleware()" not detected.packages/react-router/src/server/types.ts (2)
15-40
: Document signInUrl/signUpUrl and generalize env-var notes; options shape looks goodAdd JSDoc for signInUrl/signUpUrl and avoid Vite-specific wording so docs match Node/Workers too.
export type ClerkMiddlewareOptions = { /** - * Used to override the default VITE_CLERK_PUBLISHABLE_KEY env variable if needed. + * Overrides the default publishable key resolved from env/context + * (e.g. CLERK_PUBLISHABLE_KEY, VITE_CLERK_PUBLISHABLE_KEY, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY). */ publishableKey?: string; /** - * Used to override the CLERK_JWT_KEY env variable if needed. + * Overrides the JWT key resolved from env/context (CLERK_JWT_KEY). */ jwtKey?: string; /** - * Used to override the CLERK_SECRET_KEY env variable if needed. + * Overrides the secret key resolved from env/context (CLERK_SECRET_KEY). */ secretKey?: string; /** - * Used to override the CLERK_MACHINE_SECRET_KEY env variable if needed. + * Overrides the machine secret key resolved from env/context (CLERK_MACHINE_SECRET_KEY). */ machineSecretKey?: string; + /** + * Absolute URL to your Sign In route. If omitted, resolved from env/context. + */ signInUrl?: string; + /** + * Absolute URL to your Sign Up route. If omitted, resolved from env/context. + */ signUpUrl?: string; } & Pick<VerifyTokenOptions, 'audience' | 'authorizedParties'> & MultiDomainAndOrProxy & SignInForceRedirectUrl & SignInFallbackRedirectUrl & SignUpForceRedirectUrl & SignUpFallbackRedirectUrl & LegacyRedirectProps;Additionally, consider tightening the public docs for audience/authorizedParties by linking to VerifyTokenOptions.
42-55
: Deprecation guidance is good; add “since” and planned removal versionClarify migration timing for loadUser/loadSession/loadOrganization to set expectations.
export type RootAuthLoaderOptions = ClerkMiddlewareOptions & { /** - * @deprecated Use [session token claims](https://clerk.com/docs/backend-requests/making/custom-session-token) instead. + * @deprecated Since vX.Y. Use custom session token claims instead. + * Will be removed in vZ.0. */ loadUser?: boolean; /** - * @deprecated Use [session token claims](https://clerk.com/docs/backend-requests/making/custom-session-token) instead. + * @deprecated Since vX.Y. Use custom session token claims instead. + * Will be removed in vZ.0. */ loadSession?: boolean; /** - * @deprecated Use [session token claims](https://clerk.com/docs/backend-requests/making/custom-session-token) instead. + * @deprecated Since vX.Y. Use custom session token claims instead. + * Will be removed in vZ.0. */ loadOrganization?: boolean; };If you have the timeline, replace X.Y/Z.0 accordingly.
packages/react-router/src/server/clerkClient.ts (2)
5-21
: Consider memoizing the client per resolved optionsIf loadOptions resolves to the same values across requests, caching avoids re-instantiation. Key by a stable JSON of options that affect the client (apiUrl, secretKey, jwtKey, proxyUrl, isSatellite, domain, publishableKey, machineSecretKey).
5-21
: Add explicit return type for clerkClient
- Import ClerkClient from
@clerk/backend
and annotateclerkClient
’s return type asClerkClient
.integration/tests/react-router/basic.test.ts (1)
92-102
: Prefer test IDs over text to reduce flakiness; consider unskipping when stableText-based assertions on “Loading...” and content can be brittle. Use data-testid hooks and extend timeout if CI is slow. Unskip when streaming is supported on all targets.
-test.skip('streaming with Suspense works with rootAuthLoader', async ({ page, context }) => { +test.skip('streaming with Suspense works with rootAuthLoader', async ({ page, context }) => { @@ - await expect(u.page.getByText('Loading...')).toBeVisible(); + await expect(u.page.getByTestId('non-critical-loading')).toBeVisible(); @@ - await expect(u.page.getByText('Non critical value: non-critical')).toBeVisible({ timeout: 3000 }); - await expect(u.page.getByText('Loading...')).toBeHidden(); + await expect(u.page.getByTestId('non-critical-value')).toHaveText('Non critical value: non-critical', { timeout: 5000 }); + await expect(u.page.getByTestId('non-critical-loading')).toBeHidden();Add the corresponding data-testid attributes in the app under test.
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts (1)
47-66
: Add expectations on returned value shape to increase coverageVerify that the handler is invoked and the data path returns expected structure, and that headers are preserved when legacy path returns a redirect-less signed-in state.
- await rootAuthLoader(args, () => ({ data: 'test' })); + const res = (await rootAuthLoader(args, () => ({ data: 'test' }))) as any; + expect(res).toMatchObject({ data: 'test' });For the legacy path case, also assert the mocked headers/status propagate if applicable.
packages/react-router/src/server/index.ts (1)
1-4
: Avoidexport *
barrel; prefer explicit, tree-shakable exports to reduce circular-deps riskRe-exporting the entire backend surface from an index barrel can hinder tree-shaking and increase the chance of cycles. Prefer explicit named re-exports and separate type-only re-exports.
Please confirm no circular import graph is introduced by this star export (common with index barrels). If needed, I can generate a script to map the import graph.
packages/react-router/src/server/__tests__/getAuth.test.ts (3)
18-21
: Clean up env after testsUnset CLERK_SECRET_KEY post-test to avoid cross-test leakage.
Apply:
-import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; beforeEach(() => { vi.clearAllMocks(); process.env.CLERK_SECRET_KEY = 'sk_test_...'; }); +afterEach(() => { + delete process.env.CLERK_SECRET_KEY; +});
36-39
: Assert return value for stronger signalAlso verify the returned auth object.
- await getAuth(args); - - expect(legacyAuthenticateRequest).not.toHaveBeenCalled(); + const res = await getAuth(args); + expect(res.userId).toBe('user_xxx'); + expect(legacyAuthenticateRequest).not.toHaveBeenCalled();
51-54
: Assert return value in legacy pathTighten the expectation to ensure getAuth returns the expected shape.
- await getAuth(args); - - expect(legacyAuthenticateRequest).toHaveBeenCalled(); + const res = await getAuth(args); + expect(res.userId).toBe('user_xxx'); + expect(legacyAuthenticateRequest).toHaveBeenCalled();packages/react-router/src/server/utils.ts (1)
47-47
: Guard redirects/non-JSON responses to prevent.json()
errorsIf
response
is a redirect or not JSON,await clone.json()
will throw. Early-return redirects and consider tolerant parse.Outside selected lines, suggested pattern:
if (isRedirect(response)) { return response; } let data: unknown = {}; try { data = await clone.json(); } catch { // keep empty object if body is not JSON }integration/templates/react-router-node/app/root.tsx (2)
7-8
: Document middleware exportAdd a brief JSDoc so users know where to customize Clerk middleware options.
/** Configure Clerk middleware for this route */ export const unstable_middleware: Route.unstable_MiddlewareFunction[] = [clerkMiddleware()];
10-14
: Make deferred promise abortable to respect navigation cancellationTie the promise to
args.request.signal
to avoid leaked timers and spurious work.- const nonCriticalData = new Promise(res => setTimeout(() => res('non-critical'), 1000)); + const nonCriticalData = new Promise<string>((res, rej) => { + const id = setTimeout(() => res('non-critical'), 1000); + const onAbort = () => { + clearTimeout(id); + rej(new DOMException('Aborted', 'AbortError')); + }; + args.request.signal.addEventListener('abort', onAbort, { once: true }); + });packages/react-router/src/server/loadOptions.ts (1)
14-17
: Unify arg types across server APIs
loadOptions
now takesDataFunctionArgs
; callers likegetAuth
may still be typed withLoaderFunctionArgs
. ExportDataFunctionArgs
from a centraltypes.ts
and use it consistently to avoid drift.integration/tests/react-router/pre-middleware.test.ts (1)
8-12
: Parallel mode with shared app/user — confirm no flakinessRunning tests in parallel while sharing a single app instance and user can cause intermittent failures if routes mutate shared state. If you’ve seen flakes, switch this suite to serial or provision per-test users.
packages/react-router/src/server/clerkMiddleware.ts (1)
15-15
: Avoid any in public typesUse unknown instead of any for RequestState generic.
-export const requestStateContext = unstable_createContext<RequestState<any> | null>(null); +export const requestStateContext = unstable_createContext<RequestState<unknown> | null>(null);packages/react-router/src/server/rootAuthLoader.ts (2)
46-49
: Avoid any in callback typePrefer unknown for RootAuthLoaderCallback generic.
- handler?: RootAuthLoaderCallback<any>, + handler?: RootAuthLoaderCallback<unknown>,
60-64
: Avoid any in LoaderFunctionArgsWithAuth castUse unknown to prevent unsafe widening.
- } as LoaderFunctionArgsWithAuth<any>; + } as LoaderFunctionArgsWithAuth<unknown>;
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (23)
.changeset/quiet-bats-protect.md
(1 hunks)integration/templates/react-router-library/package.json
(1 hunks)integration/templates/react-router-node/app/root.tsx
(2 hunks)integration/templates/react-router-node/package.json
(1 hunks)integration/templates/react-router-node/react-router.config.ts
(1 hunks)integration/tests/react-router/basic.test.ts
(2 hunks)integration/tests/react-router/pre-middleware.test.ts
(1 hunks)packages/react-router/package.json
(3 hunks)packages/react-router/src/server/__tests__/getAuth.test.ts
(1 hunks)packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
(1 hunks)packages/react-router/src/server/clerkClient.ts
(1 hunks)packages/react-router/src/server/clerkMiddleware.ts
(1 hunks)packages/react-router/src/server/getAuth.ts
(1 hunks)packages/react-router/src/server/index.ts
(1 hunks)packages/react-router/src/server/legacyAuthenticateRequest.ts
(2 hunks)packages/react-router/src/server/loadOptions.ts
(1 hunks)packages/react-router/src/server/rootAuthLoader.ts
(1 hunks)packages/react-router/src/server/types.ts
(3 hunks)packages/react-router/src/server/utils.ts
(2 hunks)packages/react-router/src/ssr/getAuth.ts
(0 hunks)packages/react-router/src/ssr/index.ts
(1 hunks)packages/react-router/src/ssr/rootAuthLoader.ts
(0 hunks)packages/react-router/src/utils/errors.ts
(1 hunks)
💤 Files with no reviewable changes (2)
- packages/react-router/src/ssr/getAuth.ts
- packages/react-router/src/ssr/rootAuthLoader.ts
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/src/server/clerkClient.ts
integration/templates/react-router-node/react-router.config.ts
packages/react-router/src/server/loadOptions.ts
integration/tests/react-router/basic.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
integration/tests/react-router/pre-middleware.test.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
integration/templates/react-router-node/app/root.tsx
packages/react-router/src/server/legacyAuthenticateRequest.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/package.json
packages/react-router/src/server/clerkClient.ts
integration/templates/react-router-node/react-router.config.ts
packages/react-router/src/server/loadOptions.ts
integration/tests/react-router/basic.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
integration/templates/react-router-node/package.json
integration/templates/react-router-library/package.json
integration/tests/react-router/pre-middleware.test.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
integration/templates/react-router-node/app/root.tsx
packages/react-router/src/server/legacyAuthenticateRequest.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/src/server/clerkClient.ts
packages/react-router/src/server/loadOptions.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
packages/react-router/src/server/legacyAuthenticateRequest.ts
packages/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Packages should export TypeScript types alongside runtime code
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/src/server/clerkClient.ts
packages/react-router/src/server/loadOptions.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
packages/react-router/src/server/legacyAuthenticateRequest.ts
packages/**/index.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use tree-shaking friendly exports
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/ssr/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/src/server/clerkClient.ts
integration/templates/react-router-node/react-router.config.ts
packages/react-router/src/server/loadOptions.ts
integration/tests/react-router/basic.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
integration/tests/react-router/pre-middleware.test.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
integration/templates/react-router-node/app/root.tsx
packages/react-router/src/server/legacyAuthenticateRequest.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/ssr/index.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/react-router/src/server/clerkClient.ts
integration/templates/react-router-node/react-router.config.ts
packages/react-router/src/server/loadOptions.ts
integration/tests/react-router/basic.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/utils/errors.ts
packages/react-router/src/server/getAuth.ts
integration/tests/react-router/pre-middleware.test.ts
packages/react-router/src/server/utils.ts
packages/react-router/src/server/types.ts
integration/templates/react-router-node/app/root.tsx
packages/react-router/src/server/legacyAuthenticateRequest.ts
**/index.ts
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
Use index.ts files for clean imports but avoid deep barrel exports
Avoid barrel files (index.ts re-exports) as they can cause circular dependencies
Files:
packages/react-router/src/server/index.ts
packages/react-router/src/ssr/index.ts
.changeset/**
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Automated releases must use Changesets.
Files:
.changeset/quiet-bats-protect.md
packages/**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Unit tests should use Jest or Vitest as the test runner.
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)
**/__tests__/**/*.{ts,tsx}
: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/*/package.json
📄 CodeRabbit inference engine (.cursor/rules/global.mdc)
All publishable packages should be placed under the packages/ directory
packages/*/package.json
: All publishable packages must be located in the 'packages/' directory.
All packages must be published under the @clerk namespace on npm.
Semantic versioning must be used across all packages.
Files:
packages/react-router/package.json
integration/**
📄 CodeRabbit inference engine (.cursor/rules/global.mdc)
Framework integration templates and E2E tests should be placed under the integration/ directory
Files:
integration/templates/react-router-node/react-router.config.ts
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/package.json
integration/templates/react-router-library/package.json
integration/tests/react-router/pre-middleware.test.ts
integration/templates/react-router-node/app/root.tsx
integration/**/*
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
End-to-end tests and integration templates must be located in the 'integration/' directory.
Files:
integration/templates/react-router-node/react-router.config.ts
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/package.json
integration/templates/react-router-library/package.json
integration/tests/react-router/pre-middleware.test.ts
integration/templates/react-router-node/app/root.tsx
integration/**/*.{test,spec}.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Integration tests should use Playwright.
Files:
integration/tests/react-router/basic.test.ts
integration/tests/react-router/pre-middleware.test.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{jsx,tsx}
: Use error boundaries in React components
Minimize re-renders in React components
**/*.{jsx,tsx}
: Always use functional components with hooks instead of class components
Follow PascalCase naming for components:UserProfile
,NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...
Files:
integration/templates/react-router-node/app/root.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
**/*.tsx
: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering
Files:
integration/templates/react-router-node/app/root.tsx
🧬 Code graph analysis (12)
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts (4)
packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/server/rootAuthLoader.ts (1)
rootAuthLoader
(116-136)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)packages/react-router/src/utils/errors.ts (1)
middlewareMigrationWarning
(120-124)
packages/react-router/src/server/__tests__/getAuth.test.ts (3)
packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/server/getAuth.ts (1)
getAuth
(16-45)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)
packages/react-router/src/server/clerkMiddleware.ts (6)
packages/types/src/session.ts (1)
PendingSessionOptions
(34-40)packages/react-router/src/server/types.ts (1)
ClerkMiddlewareOptions
(15-40)packages/react-router/src/server/utils.ts (1)
patchRequest
(118-133)packages/react-router/src/server/loadOptions.ts (1)
loadOptions
(16-90)packages/react-router/src/server/clerkClient.ts (1)
clerkClient
(5-21)packages/shared/src/netlifyCacheHandler.ts (1)
handleNetlifyCacheInDevInstance
(43-65)
packages/react-router/src/server/clerkClient.ts (1)
packages/react-router/src/server/loadOptions.ts (2)
DataFunctionArgs
(14-14)loadOptions
(16-90)
packages/react-router/src/server/loadOptions.ts (1)
packages/react-router/src/server/types.ts (1)
ClerkMiddlewareOptions
(15-40)
integration/tests/react-router/basic.test.ts (1)
integration/testUtils/index.ts (1)
createTestUtils
(24-86)
packages/react-router/src/server/rootAuthLoader.ts (6)
packages/react-router/src/server/types.ts (4)
RootAuthLoaderOptions
(42-55)RootAuthLoaderCallback
(64-66)LoaderFunctionReturn
(83-83)LoaderFunctionArgsWithAuth
(85-87)packages/react-router/src/server/clerkMiddleware.ts (2)
authFnContext
(14-14)requestStateContext
(15-15)packages/react-router/src/server/utils.ts (5)
getResponseClerkState
(72-99)isResponse
(8-16)isRedirect
(29-31)injectRequestStateIntoResponse
(43-65)isDataWithResponseInit
(18-27)packages/react-router/src/utils/errors.ts (2)
invalidRootLoaderCallbackReturn
(51-73)middlewareMigrationWarning
(120-124)packages/react-router/src/server/loadOptions.ts (1)
loadOptions
(16-90)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)
packages/react-router/src/server/getAuth.ts (7)
packages/nextjs/src/server/createGetAuth.ts (1)
GetAuthOptions
(18-20)packages/types/src/session.ts (1)
PendingSessionOptions
(34-40)packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/utils/errors.ts (1)
noLoaderArgsPassedInGetAuth
(40-49)packages/react-router/src/server/clerkMiddleware.ts (1)
authFnContext
(14-14)packages/react-router/src/server/loadOptions.ts (1)
loadOptions
(16-90)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)
integration/tests/react-router/pre-middleware.test.ts (3)
integration/models/application.ts (1)
Application
(7-7)integration/presets/index.ts (1)
appConfigs
(14-30)integration/testUtils/index.ts (1)
createTestUtils
(24-86)
packages/react-router/src/server/types.ts (2)
packages/types/src/multiDomain.ts (1)
MultiDomainAndOrProxy
(11-35)packages/types/src/redirects.ts (5)
SignInForceRedirectUrl
(128-133)SignInFallbackRedirectUrl
(120-126)SignUpForceRedirectUrl
(105-110)SignUpFallbackRedirectUrl
(112-118)LegacyRedirectProps
(21-34)
integration/templates/react-router-node/app/root.tsx (3)
packages/react-router/src/server/clerkMiddleware.ts (1)
clerkMiddleware
(17-61)playground/react-router/app/root.tsx (1)
loader
(15-17)packages/react-router/src/server/rootAuthLoader.ts (1)
rootAuthLoader
(116-136)
packages/react-router/src/server/legacyAuthenticateRequest.ts (2)
packages/react-router/src/server/clerkClient.ts (1)
clerkClient
(5-21)packages/react-router/src/server/utils.ts (1)
patchRequest
(118-133)
🪛 LanguageTool
.changeset/quiet-bats-protect.md
[grammar] ~1-~1: Hier könnte ein Fehler sein.
Context: --- ---
(QB_NEW_DE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: Build Packages
- GitHub Check: semgrep/ci
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (13)
.changeset/quiet-bats-protect.md (1)
1-2
: Verify affected packages and bump levels before merging. Automatic detection failed due to a missing merge base; please manually ensure every publishable package touched by this PR that exposes new middleware APIs is bumped (minor for new APIs, major for breaking changes).integration/templates/react-router-node/react-router.config.ts (1)
7-9
: unstable_middleware export verified
The export const unstable_middleware is defined in integration/templates/react-router-node/app/root.tsx, matching the future.unstable_middleware flag requirement.packages/react-router/package.json (4)
33-36
: Server subpath export: LGTM
62-64
: typesVersions for server: LGTM
102-102
: Dev dependency bump to 7.8.2: LGTM
107-107
: Peer dependency bump to ^7.8.2: LGTMintegration/templates/react-router-node/package.json (2)
12-13
: RR tooling aligned to ^7.8.2: LGTM
20-20
: Dev tooling aligned to ^7.8.2: LGTMpackages/react-router/src/ssr/index.ts (1)
1-2
: LGTM: explicit named re-exportsExplicit server re-exports improve tree-shaking and clarity. Ensure docs reflect the new import paths.
integration/tests/react-router/basic.test.ts (1)
8-8
: Test title updated — OKTitle reflects middleware path; no action needed.
packages/react-router/src/server/loadOptions.ts (1)
7-7
: Confirm react-router peerDependency covers unstable_MiddlewareFunction
Hard-couples to the unstable APIunstable_MiddlewareFunction
. Verify your package.json peerDependency range includes a React Router version that exports this type and update any project templates to pin a compatible version.integration/tests/react-router/pre-middleware.test.ts (1)
19-24
: Verify Meta/Links imports are valid for this templateAre Meta, Links, Scripts, ScrollRestoration exported from 'react-router' in the react-router-node template? If not, adjust imports (e.g., the framework-specific entry) to avoid build errors.
packages/react-router/src/server/rootAuthLoader.ts (1)
116-136
: LGTM: Middleware vs legacy routing is cleanly splitThe rootAuthLoader flow correctly prefers middleware, warns once when missing, and handles injection/redirect semantics appropriately.
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"react-router": "^7.1.2" | ||
"react-router": "^7.8.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Align React Router versions across templates
This template uses react-router ^7.8.2. The Node template still lists ^7.1.2; please align to avoid integration drift.
Run to find mismatches:
🏁 Script executed:
#!/bin/bash
rg -n --type=json -C1 '"react-router":\s*"\^7\.[^"]+"' integration
Length of output: 540
Align React Router versions across templates
In integration/templates/react-router-node/package.json
, react-router
is pinned to ^7.1.2
, while in integration/templates/react-router-library/package.json
it’s ^7.8.2
. Update the Node template to ^7.8.2
to keep both in sync.
🤖 Prompt for AI Agents
In integration/templates/react-router-node/package.json around the react-router
dependency line (mirror of line 14 in the library template), update the
"react-router" version from "^7.1.2" to "^7.8.2" so both templates use the same
pinned version; edit the dependency entry to "^7.8.2" and save.
"@react-router/node": "^7.1.2", | ||
"@react-router/serve": "^7.1.2", | ||
"@react-router/node": "^7.8.2", | ||
"@react-router/serve": "^7.8.2", | ||
"isbot": "^5.1.17", | ||
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"react-router": "^7.1.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Bump core react-router to ^7.8.2 for consistency
Tooling is at 7.8.x but core is ^7.1.2, which can cause type/runtime mismatches.
Apply:
- "react-router": "^7.1.2"
+ "react-router": "^7.8.2"
Confirm no stragglers:
🏁 Script executed:
#!/bin/bash
rg -n --type=json -C1 '"react-router":\s*"\^7\.[^"]+"' integration/templates
Length of output: 550
Bump react-router in the node template to ^7.8.2
integration/templates/react-router-node/package.json line 17
- "react-router": "^7.1.2"
+ "react-router": "^7.8.2"
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
"react-router": "^7.1.2" | |
"react-router": "^7.8.2" |
🤖 Prompt for AI Agents
In integration/templates/react-router-node/package.json around line 17, the
react-router dependency is pinned to "^7.1.2"; update that dependency string to
"^7.8.2" to apply the requested bump, then run npm install (or update your
lockfile) to refresh node_modules and the package-lock.json/yarn.lock
accordingly.
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
Outdated
Show resolved
Hide resolved
const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), { | ||
apiUrl, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Align client config with overrides to avoid mismatched secrets/domains
clerkClient(args) internally calls loadOptions(args) without overrides, which can diverge from opts (e.g., overridden secretKey/domain). Prefer passing overrides into the client factory.
Proposed changes (outside this file for completeness):
- packages/react-router/src/server/clerkClient.ts
-export const clerkClient = (args: DataFunctionArgs) => {
- const options = loadOptions(args);
+export const clerkClient = (args: DataFunctionArgs, overrides?: ClerkMiddlewareOptions) => {
+ const options = loadOptions(args, overrides);
@@
return createClerkClient({
apiUrl,
secretKey,
jwtKey,
proxyUrl,
isSatellite,
domain,
publishableKey,
machineSecretKey,
userAgent: `${PACKAGE_NAME}@${PACKAGE_VERSION}`,
});
};
- packages/react-router/src/server/legacyAuthenticateRequest.ts
- const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), {
+ const requestState = await clerkClient(args, opts).authenticateRequest(patchRequest(request), {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), { | |
apiUrl, | |
const requestState = await clerkClient(args, opts).authenticateRequest( | |
patchRequest(request), | |
{ | |
apiUrl, | |
// …other opts… | |
} | |
); |
🤖 Prompt for AI Agents
In packages/react-router/src/server/legacyAuthenticateRequest.ts around lines
19-20, the call clerkClient(args) creates a client that ignores the current
overrides (opts) causing mismatched secrets/domains; update the call to pass the
same overrides into the client factory (e.g., clerkClient(args, opts) or
clerkClient({ ...args, ...opts }) depending on the factory signature) so the
client is constructed with the same overridden config before calling
authenticateRequest.
// Only add Clerk headers if requested (for legacy mode) | ||
if (includeClerkHeaders) { | ||
headers.forEach((value, key) => { | ||
clone.headers.append(key, value); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use set
instead of append
to avoid duplicate Clerk headers
Appending can create duplicated observability headers across multiple injections. Overwrite instead.
- if (includeClerkHeaders) {
- headers.forEach((value, key) => {
- clone.headers.append(key, value);
- });
- }
+ if (includeClerkHeaders) {
+ headers.forEach((value, key) => {
+ clone.headers.set(key, value);
+ });
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Only add Clerk headers if requested (for legacy mode) | |
if (includeClerkHeaders) { | |
headers.forEach((value, key) => { | |
clone.headers.append(key, value); | |
}); | |
} | |
// Only add Clerk headers if requested (for legacy mode) | |
if (includeClerkHeaders) { | |
headers.forEach((value, key) => { | |
clone.headers.set(key, value); | |
}); | |
} |
🤖 Prompt for AI Agents
In packages/react-router/src/server/utils.ts around lines 57 to 62, the code
appends Clerk headers which can produce duplicate observability headers on
multiple injections; replace clone.headers.append(key, value) with
clone.headers.set(key, value) so headers are overwritten instead of duplicated,
ensuring each header key is unique and preventing repeated values.
const middlewareMigrationExample = `In the next major release, an error will be thrown if the middleware is not installed. | ||
|
||
Example: | ||
|
||
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/ssr.server' | ||
import { ClerkProvider } from '@clerk/react-router' | ||
|
||
export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] | ||
|
||
export async function loader(args: Route.LoaderArgs) { | ||
return rootAuthLoader(args) | ||
} | ||
|
||
export default function App({ loaderData }: Route.ComponentProps) { | ||
return ( | ||
<ClerkProvider loaderData={loaderData}> | ||
<Outlet /> | ||
</ClerkProvider> | ||
) | ||
} | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Augment example to show enabling the flag in react-router.config.ts
Add a short snippet so users don’t miss the required config.
Apply:
const middlewareMigrationExample = `In the next major release, an error will be thrown if the middleware is not installed.
Example:
+// react-router.config.ts
+import type { Config } from '@react-router/dev/config'
+export default {
+ ssr: true,
+ future: { unstable_middleware: true },
+} satisfies Config
+
-import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/ssr.server'
+import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'
import { ClerkProvider } from '@clerk/react-router'
-export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]
+export const unstable_middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]
export async function loader(args: Route.LoaderArgs) {
return rootAuthLoader(args)
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const middlewareMigrationExample = `In the next major release, an error will be thrown if the middleware is not installed. | |
Example: | |
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/ssr.server' | |
import { ClerkProvider } from '@clerk/react-router' | |
export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] | |
export async function loader(args: Route.LoaderArgs) { | |
return rootAuthLoader(args) | |
} | |
export default function App({ loaderData }: Route.ComponentProps) { | |
return ( | |
<ClerkProvider loaderData={loaderData}> | |
<Outlet /> | |
</ClerkProvider> | |
) | |
} | |
`; | |
const middlewareMigrationExample = `In the next major release, an error will be thrown if the middleware is not installed. | |
Example: | |
// react-router.config.ts | |
import type { Config } from '@react-router/dev/config' | |
export default { | |
ssr: true, | |
future: { unstable_middleware: true }, | |
} satisfies Config | |
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server' | |
import { ClerkProvider } from '@clerk/react-router' | |
export const unstable_middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] | |
export async function loader(args: Route.LoaderArgs) { | |
return rootAuthLoader(args) | |
} | |
export default function App({ loaderData }: Route.ComponentProps) { | |
return ( | |
<ClerkProvider loaderData={loaderData}> | |
<Outlet /> | |
</ClerkProvider> | |
) | |
} | |
`; |
🤖 Prompt for AI Agents
In packages/react-router/src/utils/errors.ts around lines 98 to 118, the
middlewareMigrationExample string is missing a short snippet that shows how to
enable the required flag in react-router.config.ts; update the example text to
append a minimal react-router.config.ts snippet that demonstrates setting the
middleware-enablement flag (e.g., export default { experimental: {
clerkMiddleware: true } } or whichever project config key is used) and ensure
the wording clarifies this flag is required so users won't miss it; keep the
snippet short, consistent with the existing example style, and escape backticks
appropriately inside the template literal.
export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the unstable_middleware export name
With the future flag, React Router expects unstable_middleware. The current example shows middleware, which will be ignored.
Apply:
-export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]
+export const unstable_middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] | |
export const unstable_middleware: Route.MiddlewareFunction[] = [clerkMiddleware()] |
🤖 Prompt for AI Agents
In packages/react-router/src/utils/errors.ts around lines 105 to 106, the file
currently exports the middleware under the name "middleware" which React Router
will ignore when using the future flag; rename the export to unstable_middleware
and ensure the exported value and its type remain the same (export the same
array of Route.MiddlewareFunction containing clerkMiddleware()) so the framework
picks it up correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (3)
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts (1)
39-48
: Good: spying on logger.warnOnce (not console.warn) matches implementationThis addresses the prior review and decouples tests from logger internals.
packages/react-router/src/server/clerkMiddleware.ts (2)
61-65
: Avoid duplicating non-Set-Cookie headers: set vs appendAppending all headers can create duplicates. Append Set-Cookie; set others.
- if (requestState.headers) { - requestState.headers.forEach((value, key) => { - response.headers.append(key, value); - }); - } + if (requestState.headers) { + for (const [key, value] of requestState.headers.entries()) { + if (key.toLowerCase() === 'set-cookie') { + response.headers.append(key, value); + } else { + response.headers.set(key, value); + } + } + }
17-24
: Expand/correct JSDoc and usage examplePublic API needs comprehensive JSDoc. The example is syntactically incorrect; it should assign an array.
/** - * Middleware that integrates Clerk authentication into your React Router application. - * It checks the request's cookies and headers for a session JWT and, if found, - * attaches the Auth object to a context. - * - * @example - * export const middleware: Route.MiddlewareFunction[clerkMiddleware()] + * Integrates Clerk authentication into a React Router app. + * Authenticates the incoming request (cookies/headers), stores the RequestState + * and an auth() function in contexts for downstream loaders/actions, and + * propagates Clerk headers on the way out. + * + * @param options - Clerk middleware options (keys, domain/proxy, redirect URLs, audience/authorizedParties). + * @returns A React Router middleware function. + * + * @example + * export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]; */
🧹 Nitpick comments (7)
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts (3)
82-85
: Remove long timers in tests to prevent slow/flaky runsUsing setTimeout(5000) needlessly slows tests. A resolved promise is enough to verify serialization to {}.
- const nonCriticalData = new Promise(res => setTimeout(() => res('non-critical'), 5000)); + const nonCriticalData = Promise.resolve('non-critical');Apply the same change in the legacy-path test.
Also applies to: 159-161
71-79
: Add a test for redirect pass-throughprocessRootAuthLoader returns unmodified redirect Responses. Add a case where the handler returns new Response(null, { status: 302, headers: { Location: '/login' } }) and assert it’s returned as-is and not decorated.
I can draft the test if you want.
111-119
: Tighten spy typing for logger.warnOnceUse SpyInstance for accurate typing of arguments and return type.
-import type { MockInstance } from 'vitest'; +import type { SpyInstance } from 'vitest'; @@ - let warnOnceSpy: MockInstance<(msg: string) => void>; + let warnOnceSpy: SpyInstance<[string], void>;packages/react-router/src/server/clerkMiddleware.ts (1)
31-39
: Consider making acceptsToken configurable (default to 'any')Expose acceptsToken in ClerkMiddlewareOptions for advanced deployments that want to restrict token sources.
I can propose the types and a backwards-compatible default if you want this.
packages/react-router/src/server/rootAuthLoader.ts (3)
59-66
: Don’t mutate the original Request when adding authObject.assign mutates args.request. Prefer a shallow wrapper to avoid side effects on other code that uses the same Request.
- const argsWithAuth = { - ...args, - request: Object.assign(args.request, { auth: requestState.toAuth() }), - } as LoaderFunctionArgsWithAuth<any>; + const requestWithAuth = Object.create(args.request, { + auth: { value: requestState.toAuth(), enumerable: false, configurable: true }, + }); + const argsWithAuth = { ...args, request: requestWithAuth } as LoaderFunctionArgsWithAuth<any>;
67-79
: Robustness: narrow catch blocks to JSON parsing onlyThe catch will also swallow unrelated errors. Limit the try/catch to the JSON injection path.
- if (isResponse(handlerResult)) { - try { - if (isRedirect(handlerResult)) { - return handlerResult; - } - return injectRequestStateIntoResponse(handlerResult, requestState, args.context, includeClerkHeaders); - } catch { - throw new Error(invalidRootLoaderCallbackReturn); - } - } + if (isResponse(handlerResult)) { + if (isRedirect(handlerResult)) { + return handlerResult; + } + try { + return injectRequestStateIntoResponse(handlerResult, requestState, args.context, includeClerkHeaders); + } catch { + throw new Error(invalidRootLoaderCallbackReturn); + } + }
96-105
: Confirm intentional return shape for “no handler” (middleware path)Returning a plain object with clerkState (not a Response) enables streaming, which is good. Ensure docs explicitly call out the differing return types between middleware and legacy paths to set developer expectations.
I can add a short note to the reference docs and examples.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
(1 hunks)packages/react-router/src/server/clerkMiddleware.ts
(1 hunks)packages/react-router/src/server/rootAuthLoader.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Packages should export TypeScript types alongside runtime code
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Unit tests should use Jest or Vitest as the test runner.
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
packages/react-router/src/server/rootAuthLoader.ts
packages/react-router/src/server/clerkMiddleware.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)
**/__tests__/**/*.{ts,tsx}
: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces
Files:
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: wobsoriano
PR: clerk/javascript#6653
File: integration/tests/react-router/pre-middleware.test.ts:20-20
Timestamp: 2025-08-28T14:52:55.884Z
Learning: In the clerk/react-router package migration, the legacy `clerk/react-router/ssr.server` entrypoint is being maintained for backward compatibility while users are guided to migrate to `clerk/react-router/server` through deprecation notices.
🧬 Code graph analysis (3)
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts (4)
packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/server/rootAuthLoader.ts (1)
rootAuthLoader
(117-137)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)packages/react-router/src/utils/errors.ts (1)
middlewareMigrationWarning
(120-124)
packages/react-router/src/server/rootAuthLoader.ts (6)
packages/react-router/src/server/types.ts (4)
RootAuthLoaderOptions
(42-55)RootAuthLoaderCallback
(64-66)LoaderFunctionReturn
(83-83)LoaderFunctionArgsWithAuth
(85-87)packages/react-router/src/server/clerkMiddleware.ts (2)
authFnContext
(14-14)requestStateContext
(15-15)packages/react-router/src/server/utils.ts (5)
getResponseClerkState
(72-99)isResponse
(8-16)isRedirect
(29-31)injectRequestStateIntoResponse
(43-65)isDataWithResponseInit
(18-27)packages/react-router/src/utils/errors.ts (2)
invalidRootLoaderCallbackReturn
(51-73)middlewareMigrationWarning
(120-124)packages/react-router/src/server/loadOptions.ts (1)
loadOptions
(16-90)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)
packages/react-router/src/server/clerkMiddleware.ts (6)
packages/types/src/session.ts (1)
PendingSessionOptions
(34-40)packages/react-router/src/server/types.ts (1)
ClerkMiddlewareOptions
(15-40)packages/react-router/src/server/utils.ts (1)
patchRequest
(118-133)packages/react-router/src/server/loadOptions.ts (1)
loadOptions
(16-90)packages/react-router/src/server/clerkClient.ts (1)
clerkClient
(5-21)packages/shared/src/netlifyCacheHandler.ts (1)
handleNetlifyCacheInDevInstance
(43-65)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/react-router/src/server/rootAuthLoader.ts (1)
155-169
: Good backward compatibility in legacy pathLoading options, authenticating, decorating request, and reusing the same processor keeps behavior consistent while guiding migration.
packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
integration/tests/react-router/basic.test.ts (1)
92-102
: Harden the streaming test against CI flakiness.
Increase timeout headroom and wait for app URL before assertions to avoid races on slow bots.Apply this diff:
test('streaming with Suspense works with rootAuthLoader', async ({ page, context }) => { const u = createTestUtils({ app, page, context }); - await u.page.goToRelative('/'); + await u.page.goToRelative('/'); + await u.page.waitForAppUrl('/'); await expect(u.page.getByText('Loading...')).toBeVisible(); // Wait for the streaming content to resolve (5 second delay + buffer) - await expect(u.page.getByText('Non critical value: non-critical')).toBeVisible({ timeout: 8000 }); + await expect(u.page.getByText('Non critical value: non-critical')).toBeVisible({ timeout: 15000 }); await expect(u.page.getByText('Loading...')).toBeHidden(); });integration/templates/react-router-node/app/root.tsx (4)
7-7
: Document the middleware export and intent.
Since this is a template entrypoint, add a brief JSDoc so integrators know where to customize.Apply this diff:
+/** + * Route middleware chain. Customize by adding your own handlers before/after Clerk. + * Requires React Router `future.unstable_middleware` to be enabled in the router config. + */ export const unstable_middleware: Route.unstable_MiddlewareFunction[] = [clerkMiddleware()];
9-15
: Abort-aware delayed promise to avoid leaking timers on navigation.
Tie the timeout to the request’s abort signal so timers are cleared when the loader is canceled.Apply this diff:
export async function loader(args: Route.LoaderArgs) { - const nonCriticalData = new Promise(res => setTimeout(() => res('non-critical'), 5000)); + const controller = new AbortController(); + const nonCriticalData: Promise<string> = new Promise(res => { + const id = setTimeout(() => res('non-critical'), 5000); + const cleanup = () => clearTimeout(id); + args.request.signal.addEventListener('abort', cleanup, { once: true }); + controller.signal.addEventListener('abort', cleanup, { once: true }); + }); return rootAuthLoader(args, () => ({ nonCriticalData, })); }
12-14
: Add minimal type clarity for loader data.
Make the awaited value explicit for downstream inference without over-specifying the loader’s return type.Apply this diff:
- return rootAuthLoader(args, () => ({ - nonCriticalData, - })); + return rootAuthLoader(args, () => ({ + nonCriticalData: nonCriticalData as Promise<string>, + }));
43-45
: Type the Await render arg and improve a11y of the fallback.
Explicit type avoids unknown, and role/aria-live improves SR experience.Apply this diff:
- <React.Suspense fallback={<div>Loading...</div>}> - <Await resolve={loaderData.nonCriticalData}>{value => <h3>Non critical value: {value}</h3>}</Await> + <React.Suspense fallback={<div role="status" aria-live="polite">Loading...</div>}> + <Await resolve={loaderData.nonCriticalData}> + {(value: string) => <h3>Non critical value: {value}</h3>} + </Await> </React.Suspense>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
integration/templates/react-router-node/app/root.tsx
(2 hunks)integration/tests/react-router/basic.test.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
integration/**
📄 CodeRabbit inference engine (.cursor/rules/global.mdc)
Framework integration templates and E2E tests should be placed under the integration/ directory
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
integration/**/*
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
End-to-end tests and integration templates must be located in the 'integration/' directory.
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
integration/**/*.{test,spec}.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Integration tests should use Playwright.
Files:
integration/tests/react-router/basic.test.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
integration/tests/react-router/basic.test.ts
integration/templates/react-router-node/app/root.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{jsx,tsx}
: Use error boundaries in React components
Minimize re-renders in React components
**/*.{jsx,tsx}
: Always use functional components with hooks instead of class components
Follow PascalCase naming for components:UserProfile
,NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...
Files:
integration/templates/react-router-node/app/root.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
**/*.tsx
: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering
Files:
integration/templates/react-router-node/app/root.tsx
🧬 Code graph analysis (1)
integration/tests/react-router/basic.test.ts (1)
integration/testUtils/index.ts (1)
createTestUtils
(24-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
- GitHub Check: Integration Tests (machine, chrome)
- GitHub Check: Integration Tests (nuxt, chrome)
- GitHub Check: Integration Tests (astro, chrome)
- GitHub Check: Integration Tests (nextjs, chrome, 15)
- GitHub Check: Integration Tests (billing, chrome)
- GitHub Check: Integration Tests (tanstack-react-router, chrome)
- GitHub Check: Integration Tests (vue, chrome)
- GitHub Check: Integration Tests (expo-web, chrome)
- GitHub Check: Integration Tests (nextjs, chrome, 14)
- GitHub Check: Integration Tests (localhost, chrome)
- GitHub Check: Integration Tests (ap-flows, chrome)
- GitHub Check: Integration Tests (react-router, chrome)
- GitHub Check: Integration Tests (tanstack-react-start, chrome)
- GitHub Check: Integration Tests (elements, chrome)
- GitHub Check: Integration Tests (sessions, chrome)
- GitHub Check: Integration Tests (express, chrome)
- GitHub Check: Integration Tests (generic, chrome)
- GitHub Check: Integration Tests (quickstart, chrome)
- GitHub Check: Publish with pkg-pr-new
- GitHub Check: Static analysis
- GitHub Check: Unit Tests (22, **)
- GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
- GitHub Check: semgrep/ci
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
integration/tests/react-router/basic.test.ts (2)
8-8
: Suite title change is clear and scoped.
Accurately reflects middleware focus. No action needed.
92-102
: No changes needed:unstable_middleware
is already enabled
Confirmedunstable_middleware: true
inintegration/templates/react-router-node/react-router.config.ts
.integration/templates/react-router-node/app/root.tsx (1)
1-3
: Imports are correct for react-router v7.1.2
Await, Links, Meta, Scripts, ScrollRestoration and isRouteErrorResponse are all exported by the core react-router package in the v7 release line—no change needed.
import type { Route } from './+types/root'; | ||
|
||
export const unstable_middleware: Route.unstable_MiddlewareFunction[] = [clerkMiddleware()]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Ensure router config enables middleware feature.
The export alone isn’t sufficient; the router must opt-in via future.unstable_middleware.
Run to confirm:
🏁 Script executed:
#!/bin/bash
rg -nP -C3 'future\s*:\s*\{[^}]*unstable_middleware\s*:\s*true' integration/templates/react-router-node -g '!**/dist/**'
Length of output: 122
Enable middleware in router config: In integration/templates/react-router-node/app/root.tsx, update your router instantiation (e.g. createBrowserRouter or createRoutesFromElements) to include
future: { unstable_middleware: true }
Exporting the middleware alone won’t activate it without this opt-in.
🤖 Prompt for AI Agents
In integration/templates/react-router-node/app/root.tsx around line 7, exporting
unstable_middleware alone won’t enable it; update the router instantiation
(where createBrowserRouter or createRoutesFromElements is called) to pass the
future opt-in by adding the option future: { unstable_middleware: true } so the
exported middleware is actually activated by the router.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
integration/templates/react-router-node/app/root.tsx (1)
7-8
: Ensure router feature flag is enabled.Exporting
unstable_middleware
isn’t enough; the router must opt-in withfuture.unstable_middleware: true
. Please confirm it’s set in this template’s router config.#!/bin/bash # Verify the feature flag is enabled somewhere under the template rg -nP -C3 'future\s*:\s*\{[^}]*unstable_middleware\s*:\s*true' integration/templates/react-router-node -g '!**/dist/**'
🧹 Nitpick comments (5)
.changeset/quiet-bats-protect.md (1)
32-48
: Keep streaming timings consistent with the template/tests.The example uses a 5s delay while the template currently uses 10s and the test waits less by default. Standardize to 5s here and in the template to avoid flaky tests and long waits.
If you prefer 10s in the template, update the test’s expectation timeouts accordingly (see my test comment).
integration/templates/react-router-node/app/root.tsx (4)
17-36
: Add explicit return types for public components.Keep TS surfaces explicit.
-export function Layout({ children }: { children: React.ReactNode }) { +export function Layout({ children }: { children: React.ReactNode }): JSX.Element {
38-49
: Add explicit return type for App.-export default function App({ loaderData }: Route.ComponentProps) { +export default function App({ loaderData }: Route.ComponentProps): JSX.Element {
51-76
: Add explicit return type for ErrorBoundary.-export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { +export function ErrorBoundary({ error }: Route.ErrorBoundaryProps): JSX.Element {
43-46
: Optional: Provide an error fallback for Await.Helps surface loader promise errors in dev.
- <React.Suspense fallback={<div>Loading...</div>}> - <Await resolve={loaderData.nonCriticalData}>{value => <h3>Non critical value: {value}</h3>}</Await> - </React.Suspense> + <React.Suspense fallback={<div>Loading...</div>}> + <Await + resolve={loaderData.nonCriticalData} + errorElement={<div>Failed to load non-critical data.</div>} + > + {value => <h3>Non critical value: {value}</h3>} + </Await> + </React.Suspense>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
.changeset/quiet-bats-protect.md
(1 hunks)integration/templates/react-router-node/app/root.tsx
(2 hunks)integration/tests/react-router/basic.test.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
.changeset/**
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Automated releases must use Changesets.
Files:
.changeset/quiet-bats-protect.md
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{jsx,tsx}
: Use error boundaries in React components
Minimize re-renders in React components
**/*.{jsx,tsx}
: Always use functional components with hooks instead of class components
Follow PascalCase naming for components:UserProfile
,NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...
Files:
integration/templates/react-router-node/app/root.tsx
integration/**
📄 CodeRabbit inference engine (.cursor/rules/global.mdc)
Framework integration templates and E2E tests should be placed under the integration/ directory
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
integration/**/*
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
End-to-end tests and integration templates must be located in the 'integration/' directory.
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
integration/templates/react-router-node/app/root.tsx
integration/tests/react-router/basic.test.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/react.mdc)
**/*.tsx
: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering
Files:
integration/templates/react-router-node/app/root.tsx
integration/**/*.{test,spec}.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Integration tests should use Playwright.
Files:
integration/tests/react-router/basic.test.ts
🧬 Code graph analysis (2)
integration/templates/react-router-node/app/root.tsx (1)
packages/react-router/src/server/clerkMiddleware.ts (1)
clerkMiddleware
(25-69)
integration/tests/react-router/basic.test.ts (1)
integration/testUtils/index.ts (1)
createTestUtils
(24-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (21)
- GitHub Check: Integration Tests (machine, chrome)
- GitHub Check: Integration Tests (vue, chrome)
- GitHub Check: Integration Tests (nuxt, chrome)
- GitHub Check: Integration Tests (nextjs, chrome, 14)
- GitHub Check: Integration Tests (tanstack-react-router, chrome)
- GitHub Check: Integration Tests (sessions, chrome)
- GitHub Check: Integration Tests (nextjs, chrome, 15)
- GitHub Check: Integration Tests (quickstart, chrome)
- GitHub Check: Integration Tests (react-router, chrome)
- GitHub Check: Integration Tests (billing, chrome)
- GitHub Check: Integration Tests (localhost, chrome)
- GitHub Check: Integration Tests (astro, chrome)
- GitHub Check: Integration Tests (tanstack-react-start, chrome)
- GitHub Check: Integration Tests (expo-web, chrome)
- GitHub Check: Integration Tests (ap-flows, chrome)
- GitHub Check: Integration Tests (elements, chrome)
- GitHub Check: Integration Tests (generic, chrome)
- GitHub Check: Integration Tests (express, chrome)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: semgrep-cloud-platform/scan
- GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
.changeset/quiet-bats-protect.md (1)
1-3
: Frontmatter looks correct for a breaking release.The package key and bump type are valid for Changesets.
integration/templates/react-router-node/app/root.tsx (1)
1-3
: Imports and server entrypoints look good.
Introduce [React Router middleware](https://reactrouter.com/how-to/middleware) support with `clerkMiddleware()` for improved performance and streaming capabilities. | ||
|
||
Usage of `rootAuthLoader` without the `clerkMiddleware()` installed is now deprecated and will be removed in the next major version. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Docs mismatch: example uses stable middleware
, code exports unstable_middleware
.
Your integration template exports unstable_middleware: Route.unstable_MiddlewareFunction[]
, but the changeset shows middleware: Route.MiddlewareFunction[]
. Align the docs to the current API and call out the feature flag requirement.
Apply this diff to the example block below to match the current API:
-import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'
+import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'
-export const middleware: Route.MiddlewareFunction[] = [
- clerkMiddleware()
-]
+export const unstable_middleware: Route.unstable_MiddlewareFunction[] = [clerkMiddleware()]
Also add a short note after the snippet:
+Note: React Router v7 requires enabling the feature flag in your router config:
+`future: { unstable_middleware: true }`.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
Introduce [React Router middleware](https://reactrouter.com/how-to/middleware) support with `clerkMiddleware()` for improved performance and streaming capabilities. | |
Usage of `rootAuthLoader` without the `clerkMiddleware()` installed is now deprecated and will be removed in the next major version. |
🤖 Prompt for AI Agents
In .changeset/quiet-bats-protect.md around lines 5 to 8, the docs example
exports unstable_middleware while the changeset text and current API use
middleware and require the feature flag; update the example to export
middleware: Route.MiddlewareFunction[] (or keep unstable_middleware if the
library still exposes it but then update the changeset to show
unstable_middleware) so code and docs match, and add a short note after the
snippet stating that this feature requires enabling the React Router middleware
feature flag (include the exact flag name used by the library). Ensure the
snippet and note explicitly reference the API name and feature flag
consistently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
packages/react-router/src/server/__tests__/getAuth.test.ts (6)
23-26
: Prevent env leakage across test suite by restoring CLERK_SECRET_KEYCapture the previous value and restore it after the suite to avoid cross-test contamination.
-import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'; describe('getAuth', () => { beforeEach(() => { vi.clearAllMocks(); - process.env.CLERK_SECRET_KEY = 'sk_test_...'; + prevSecretKey = process.env.CLERK_SECRET_KEY; + process.env.CLERK_SECRET_KEY = 'sk_test_...'; }); + + let prevSecretKey: string | undefined; + afterAll(() => { + if (prevSecretKey === undefined) { + delete process.env.CLERK_SECRET_KEY; + } else { + process.env.CLERK_SECRET_KEY = prevSecretKey; + } + });Also applies to: 3-3
43-47
: Tighten type-safety of args and avoid broad type assertionsUse the satisfies operator and include params to conform to LoaderFunctionArgs without an unsafe cast.
- const args = { - context: mockContext, - request: new Request('http://clerk.com'), - } as LoaderFunctionArgs; + const args = { + context: mockContext, + request: new Request('http://clerk.com'), + params: {} as any, + } satisfies LoaderFunctionArgs;- const args = { - context: mockContext, - request: new Request('http://clerk.com'), - } as LoaderFunctionArgs; + const args = { + context: mockContext, + request: new Request('http://clerk.com'), + params: {} as any, + } satisfies LoaderFunctionArgs;Also applies to: 60-63
29-41
: Remove unused mock fieldmockContext.set is never used in this suite.
- }), - set: vi.fn(), + }),
48-53
: Add an assertion that middleware context was queriedThis makes the control-flow intent explicit.
const auth = await getAuth(args); + expect(mockContext.get).toHaveBeenCalledWith(authFnContext); expect(legacyAuthenticateRequest).not.toHaveBeenCalled();
65-69
: Assert legacyAuthenticateRequest is called with acceptsToken: 'any'Verifies the fallback path sets the expected option.
const auth = await getAuth(args); - expect(legacyAuthenticateRequest).toHaveBeenCalled(); + expect(legacyAuthenticateRequest).toHaveBeenCalledWith( + args, + expect.objectContaining({ acceptsToken: 'any' }), + ); expect(auth.userId).toBe('user_xxx'); expect(auth.tokenType).toBe('session_token');
71-71
: Add a negative test for missing argsCovers the explicit error branch in getAuth for better safety.
it('should call legacyAuthenticateRequest when middleware context is missing', async () => { const mockContext = { get: vi.fn().mockReturnValue(null), }; const args = { context: mockContext, request: new Request('http://clerk.com'), } as LoaderFunctionArgs; const auth = await getAuth(args); expect(legacyAuthenticateRequest).toHaveBeenCalled(); expect(auth.userId).toBe('user_xxx'); expect(auth.tokenType).toBe('session_token'); }); + + it('throws when called without args', async () => { + // @ts-expect-error - validating runtime guard + await expect(getAuth()).rejects.toThrowError(); + }); });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
.changeset/quiet-bats-protect.md
(1 hunks)integration/templates/react-router-node/app/root.tsx
(1 hunks)integration/tests/react-router/basic.test.ts
(1 hunks)packages/react-router/src/server/__tests__/getAuth.test.ts
(1 hunks)packages/react-router/src/server/__tests__/rootAuthLoader.test.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- integration/tests/react-router/basic.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- integration/templates/react-router-node/app/root.tsx
- .changeset/quiet-bats-protect.md
- packages/react-router/src/server/tests/rootAuthLoader.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Packages should export TypeScript types alongside runtime code
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Unit tests should use Jest or Vitest as the test runner.
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)
**/__tests__/**/*.{ts,tsx}
: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces
Files:
packages/react-router/src/server/__tests__/getAuth.test.ts
🧬 Code graph analysis (1)
packages/react-router/src/server/__tests__/getAuth.test.ts (4)
packages/react-router/src/server/clerkMiddleware.ts (1)
authFnContext
(14-14)packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/server/getAuth.ts (1)
getAuth
(16-45)packages/react-router/src/server/legacyAuthenticateRequest.ts (1)
legacyAuthenticateRequest
(9-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build Packages
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
packages/react-router/src/server/__tests__/getAuth.test.ts (1)
28-53
: Good coverage of both middleware and legacy pathsThis test correctly verifies the short-circuit when middleware context is present and asserts the normalized tokenType. Looks solid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (7)
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts (7)
11-16
: Stabilize module mocks with explicit factoriesRelying on auto-mocking can be brittle with ESM. Declare mock factories so
clerkClient
andloadOptions
are guaranteedvi.fn()
and typed.-vi.mock('../clerkClient'); -vi.mock('../loadOptions'); +vi.mock('../clerkClient', () => ({ clerkClient: vi.fn() })); +vi.mock('../loadOptions', () => ({ loadOptions: vi.fn() }));
23-26
: Restore env after each test to prevent cross-test leakage
process.env.CLERK_SECRET_KEY
is mutated but never restored. Capture and restore to avoid side effects.-import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ +const prevSecret = process.env.CLERK_SECRET_KEY; beforeEach(() => { vi.clearAllMocks(); process.env.CLERK_SECRET_KEY = 'sk_test_...'; }); +afterEach(() => { + process.env.CLERK_SECRET_KEY = prevSecret; +});
66-75
: Assert the exact request object passed to authenticateRequestStrengthen the assertion by checking the first argument is the same
Request
instance.- expect(mockAuthenticateRequest).toHaveBeenCalledWith(expect.any(Object), { + expect(mockAuthenticateRequest).toHaveBeenCalledWith(args.request, { audience: '', authorizedParties: [], signInUrl: '', signUpUrl: '', afterSignInUrl: '', afterSignUpUrl: '', acceptsToken: 'any', });
76-82
: Verify context is set before calling next and that auth factory delegates to requestState.toAuthAdds ordering and delegation checks to catch regressions.
expect(mockContext.set).toHaveBeenCalledWith(authFnContext, expect.any(Function)); expect(mockContext.set).toHaveBeenCalledWith(requestStateContext, mockRequestState); expect(mockNext).toHaveBeenCalled(); expect(result).toBe(mockResponse); + + // Context must be set before invoking next + const lastSetOrder = Math.max(...mockContext.set.mock.invocationCallOrder); + const nextOrder = mockNext.mock.invocationCallOrder[0]; + expect(lastSetOrder).toBeLessThan(nextOrder); + + // The auth factory should delegate to requestState.toAuth with provided options + const [, authFactory] = mockContext.set.mock.calls.find(([ctx]) => ctx === authFnContext)!; + const pendingOptions = { fromTest: true } as any; + (authFactory as (opts?: any) => unknown)(pendingOptions); + expect(mockRequestState.toAuth).toHaveBeenCalledWith(pendingOptions);
84-117
: Also assert that clerkClient is constructed with derived optionsWe already check
loadOptions(args, options)
is called; ensureclerkClient
receives those derived options too.await middleware(args, mockNext); expect(mockLoadOptions).toHaveBeenCalledWith(args, options); + expect(mockClerkClient).toHaveBeenCalledTimes(1); + expect(mockClerkClient).toHaveBeenCalledWith( + expect.objectContaining({ secretKey: 'sk_test_...', publishableKey: 'pk_test_...' }) + );
119-149
: Add coverage for includeClerkHeaders=false (headers not appended)Current test covers positive path. Add a negative test to prevent accidental header injection when disabled.
// Append this new test at the end of the suite it('should not append request state headers when includeClerkHeaders is false', async () => { const mockRequestState = { status: AuthStatus.SignedIn, headers: new Headers({ 'x-clerk-auth-status': 'signed-in', 'x-clerk-auth-reason': 'auth-reason', 'x-clerk-auth-message': 'auth-message', }), toAuth: vi.fn().mockReturnValue({ userId: 'user_xxx' }), }; const mockAuthenticateRequest = vi.fn().mockResolvedValue(mockRequestState); mockClerkClient.mockReturnValue({ authenticateRequest: mockAuthenticateRequest } as unknown as ClerkClient); const middleware = clerkMiddleware({ includeClerkHeaders: false } as any); const args = { request: new Request('http://clerk.com'), context: mockContext, } as LoaderFunctionArgs; const mockResponse = new Response('OK'); mockNext.mockResolvedValue(mockResponse); const result = (await middleware(args, mockNext)) as Response; expect(result.headers.get('x-clerk-auth-status')).toBeNull(); expect(result.headers.get('x-clerk-auth-reason')).toBeNull(); expect(result.headers.get('x-clerk-auth-message')).toBeNull(); });
2-2
: Avoid importing internals unless requiredUsing
@clerk/backend/internal
in tests increases coupling. If feasible, avoidTokenType
(it isn’t asserted) or import via public API.-import { AuthStatus, TokenType } from '@clerk/backend/internal'; +import { AuthStatus } from '@clerk/backend/internal';And drop
tokenType
from thetoAuth
return objects in tests.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
**/*.{js,jsx,ts,tsx}
: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use Prettier for consistent code formatting
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
packages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
TypeScript is required for all packages
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
packages/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Packages should export TypeScript types alongside runtime code
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development.mdc)
Use proper TypeScript error types
**/*.{ts,tsx}
: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoidany
type - preferunknown
when type is uncertain, then narrow with type guards
Useinterface
for object shapes that might be extended
Usetype
for unions, primitives, and computed types
Preferreadonly
properties for immutable data structures
Useprivate
for internal implementation details
Useprotected
for inheritance hierarchies
Usepublic
explicitly for clarity in public APIs
Preferreadonly
for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Useconst assertions
for literal types:as const
Usesatisfies
operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports:import type { ... } from ...
Noany
types without justification
Proper error handling with typed errors
Consistent use ofreadonly
for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
packages/**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Unit tests should use Jest or Vitest as the test runner.
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)
Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
**/__tests__/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)
**/__tests__/**/*.{ts,tsx}
: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces
Files:
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts
🧬 Code graph analysis (1)
packages/react-router/src/server/__tests__/clerkMiddleware.test.ts (3)
packages/backend/src/index.ts (1)
ClerkClient
(24-27)packages/remix/src/ssr/types.ts (1)
LoaderFunctionArgs
(68-68)packages/react-router/src/server/clerkMiddleware.ts (2)
authFnContext
(14-14)requestStateContext
(15-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: Integration Tests (machine, chrome)
- GitHub Check: Integration Tests (tanstack-react-router, chrome)
- GitHub Check: Integration Tests (elements, chrome)
- GitHub Check: Integration Tests (astro, chrome)
- GitHub Check: Integration Tests (localhost, chrome)
- GitHub Check: Integration Tests (generic, chrome)
- GitHub Check: Integration Tests (express, chrome)
- GitHub Check: Integration Tests (quickstart, chrome)
- GitHub Check: Unit Tests (22, **)
- GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
- GitHub Check: Static analysis
- GitHub Check: Formatting | Dedupe | Changeset
- GitHub Check: semgrep/ci
- GitHub Check: Analyze (javascript-typescript)
Description
Resolves USER-3317, USER-3141 and USER-2693
Checklist
pnpm test
runs as expected.pnpm build
runs as expected.Type of change
Summary by CodeRabbit
New Features
Bug Fixes / Behavior
Tests
Chores
Documentation