Skip to content

Conversation

wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Aug 28, 2025

Description

Resolves USER-3317, USER-3141 and USER-2693

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Server-side middleware support for authentication in React Router apps and streaming-safe loader responses; new server API entry for server-side auth.
  • Bug Fixes / Behavior

    • Maintains legacy fallback while deprecating the old SSR-only loader import; reduces when auth headers are injected to improve responses.
  • Tests

    • Adds unit and end-to-end tests covering middleware, legacy flows, redirects, and streaming.
  • Chores

    • Upgrades React Router across templates and updates package exports.
  • Documentation

    • Adds migration guidance, warnings, and examples for moving to middleware.

Copy link

changeset-bot bot commented Aug 28, 2025

🦋 Changeset detected

Latest commit: 5fd6ef8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@clerk/react-router Major

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

Copy link

vercel bot commented Aug 28, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Sep 2, 2025 10:59pm

Copy link
Contributor

coderabbitai bot commented Aug 28, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds 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

Cohort / File(s) Summary
Meta: Changeset
\.changeset/quiet-bats-protect.md
Adds a changeset marking a major release and documents middleware migration, streaming examples, and migration guidance (changelog/docs only).
Templates: React Router Library
integration/templates/react-router-library/package.json
Removes @clerk/react-router dependency and upgrades react-router to ^7.8.2.
Templates: React Router Node app
integration/templates/react-router-node/app/root.tsx, integration/templates/react-router-node/react-router.config.ts, integration/templates/react-router-node/package.json
root.tsx now imports clerkMiddleware, exports unstable_middleware = [clerkMiddleware()]; enables future.unstable_middleware in config; updates @react-router/* versions and removes @clerk/react-router dep.
Integration tests: React Router
integration/tests/react-router/basic.test.ts, integration/tests/react-router/pre-middleware.test.ts
Updates test label and adds pre-middleware E2E suite exercising SSR auth flows, sign-in/redirects, streaming/loader wiring, and cleanup.
Package export surface
packages/react-router/package.json
Adds a ./server subpath export and types mapping; bumps dev/peer react-router to ^7.8.2.
Server: Public API entry
packages/react-router/src/server/index.ts
New server index re-exporting @clerk/backend and server utilities (clerkMiddleware, rootAuthLoader, getAuth).
Server: Middleware and auth flow
packages/react-router/src/server/clerkMiddleware.ts, packages/react-router/src/server/getAuth.ts, packages/react-router/src/server/rootAuthLoader.ts, packages/react-router/src/server/clerkClient.ts
Adds clerkMiddleware (contexts, single authenticateRequest, redirect handling, context propagation), middleware-aware getAuth, streaming-capable rootAuthLoader with legacy fallback, and a clerkClient factory.
Server: Legacy and utilities
packages/react-router/src/server/legacyAuthenticateRequest.ts, packages/react-router/src/server/loadOptions.ts, packages/react-router/src/server/utils.ts, packages/react-router/src/server/types.ts
Renames authenticateRequestlegacyAuthenticateRequest (now uses local clerkClient), introduces DataFunctionArgs and ClerkMiddlewareOptions, and makes header injection optional for legacy mode.
Server: Tests
packages/react-router/src/server/__tests__/*
Adds unit tests for clerkMiddleware, getAuth, and rootAuthLoader covering middleware vs legacy flows, callback return types, header propagation, and migration warnings.
SSR: Deletions and re-exports
packages/react-router/src/ssr/getAuth.ts, packages/react-router/src/ssr/rootAuthLoader.ts, packages/react-router/src/ssr/index.ts
Removes SSR-specific implementations and re-exports server implementations from SSR index.
Errors and messaging
packages/react-router/src/utils/errors.ts
Adds middlewareMigrationWarning with a migration example guiding users to wire clerkMiddleware + rootAuthLoader.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective (issue#) Addressed Explanation
Implement middleware feature; authenticate once and share via context (USER-3317)
Reduce machine verification calls by reusing middleware auth in getAuth (USER-3141)
Support returning promises from rootAuthLoader / streaming (USER-2693)

"I hop through routes where headers gleam,
Middleware hums — a tidy stream.
I stash the state and pass the key,
Stream the bits, let loaders be.
A rabbit cheers: auth whole and free. 🥕"

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rob/user-3317-bu

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@wobsoriano wobsoriano changed the title feat(react-router): Introduce middleware feat(react-router): [WIP] Introduce middleware Aug 28, 2025
Copy link

pkg-pr-new bot commented Aug 28, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@6660

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@6660

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@6660

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@6660

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@6660

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@6660

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@6660

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@6660

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@6660

@clerk/express

npm i https://pkg.pr.new/@clerk/express@6660

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@6660

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@6660

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@6660

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@6660

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@6660

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@6660

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@6660

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@6660

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@6660

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@6660

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@6660

@clerk/types

npm i https://pkg.pr.new/@clerk/types@6660

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@6660

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@6660

commit: 5df2647

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 authenticateRequest

acceptsToken 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 warning

Minor 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 good

Add 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 version

Clarify 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 options

If 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 annotate clerkClient’s return type as ClerkClient.
integration/tests/react-router/basic.test.ts (1)

92-102: Prefer test IDs over text to reduce flakiness; consider unskipping when stable

Text-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 coverage

Verify 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: Avoid export * barrel; prefer explicit, tree-shakable exports to reduce circular-deps risk

Re-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 tests

Unset 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 signal

Also 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 path

Tighten 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() errors

If 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 export

Add 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 cancellation

Tie 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 takes DataFunctionArgs; callers like getAuth may still be typed with LoaderFunctionArgs. Export DataFunctionArgs from a central types.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 flakiness

Running 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 types

Use 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 type

Prefer unknown for RootAuthLoaderCallback generic.

-  handler?: RootAuthLoaderCallback<any>,
+  handler?: RootAuthLoaderCallback<unknown>,

60-64: Avoid any in LoaderFunctionArgsWithAuth cast

Use 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 2a82737 and 55d3572.

⛔ 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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: LGTM

integration/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: LGTM

packages/react-router/src/ssr/index.ts (1)

1-2: LGTM: explicit named re-exports

Explicit 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 — OK

Title 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 API unstable_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 template

Are 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 split

The 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"
Copy link
Contributor

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"
Copy link
Contributor

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.

Suggested change
"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.

Comment on lines +19 to 20
const requestState = await clerkClient(args).authenticateRequest(patchRequest(request), {
apiUrl,
Copy link
Contributor

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):

  1. 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}`,
   });
 };
  1. 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.

Suggested change
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.

Comment on lines +57 to +62
// Only add Clerk headers if requested (for legacy mode)
if (includeClerkHeaders) {
headers.forEach((value, key) => {
clone.headers.append(key, value);
});
}
Copy link
Contributor

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.

Suggested change
// 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.

Comment on lines 98 to 118
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>
)
}
`;
Copy link
Contributor

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.

Suggested change
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.

Comment on lines +105 to +106
export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 implementation

This 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 append

Appending 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 example

Public 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 runs

Using 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-through

processRootAuthLoader 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.warnOnce

Use 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 auth

Object.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 only

The 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 55d3572 and 7e07dca.

📒 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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 path

Loading options, authenticating, decorating request, and reusing the same processor keeps behavior consistent while guiding migration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 7e07dca and b8f9998.

📒 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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
Confirmed unstable_middleware: true in integration/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()];
Copy link
Contributor

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 with future.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.

📥 Commits

Reviewing files that changed from the base of the PR and between b8f9998 and be2d0b0.

📒 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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.

Comment on lines +5 to +8
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.

Copy link
Contributor

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.

Suggested change
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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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_KEY

Capture 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 assertions

Use 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 field

mockContext.set is never used in this suite.

-      }),
-      set: vi.fn(),
+      }),

48-53: Add an assertion that middleware context was queried

This 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 args

Covers 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.

📥 Commits

Reviewing files that changed from the base of the PR and between be2d0b0 and 6ed6edd.

📒 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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 paths

This test correctly verifies the short-circuit when middleware context is present and asserts the normalized tokenType. Looks solid.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 factories

Relying on auto-mocking can be brittle with ESM. Declare mock factories so clerkClient and loadOptions are guaranteed vi.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 authenticateRequest

Strengthen 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.toAuth

Adds 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 options

We already check loadOptions(args, options) is called; ensure clerkClient 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 required

Using @clerk/backend/internal in tests increases coupling. If feasible, avoid TokenType (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 the toAuth 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 6ed6edd and db4ca90.

📒 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
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly 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
Use const assertions for literal types: as const
Use satisfies 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 ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly 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)

@wobsoriano wobsoriano marked this pull request as draft August 30, 2025 18:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants