Skip to content

Conversation

wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Aug 28, 2025

Description

This PR introduces clerkMiddleware(), which is based on the new React Router middleware. It authenticates once per request and enables streaming in the root loader.

DX guide for more info

Deprecation

  • Using rootAuthLoader without middleware will be removed in the next major.
  • /api.server and /ssr.server module exports is deprecated in favor of @clerk/react-router/server and will be removed in the next major.

Migration

Migration is easy; they'll just need to export a middleware in their root route alongside the rootAuthLoader:

Before:

import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'

export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args)

After:

import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'

export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]

export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args)

Even though this change is backwards compatible, we want a major bump since we bumped the minimum required React Router versions to ^7.9.0 for stable Middleware and Context APIs.

Tests

Added unit and integration tests that covers both legacy (rootAuthLoader only) and with middleware flows.

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
    • Introduces React Router middleware for improved performance and data streaming.
    • Adds a new “server” entrypoint with getAuth, clerkMiddleware, and clerkClient.
  • Deprecations
    • Deprecates @clerk/react-router/ssr.server and /api.server imports; warns at runtime.
    • Using rootAuthLoader without middleware is deprecated; migration guidance included.
  • Templates
    • Upgrades React Router templates (v7.9) and React (to 19 in node template); enables v8_middleware.
    • Adjusts protected route loader data shape for simpler consumption.
  • Tests
    • Adds unit and integration tests for middleware and pre-middleware flows.
  • Chores
    • Dependency updates and script switch to pnpm; removes Clerk from certain templates.

Copy link

changeset-bot bot commented Aug 28, 2025

🦋 Changeset detected

Latest commit: d94a79c

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 19, 2025 3:12pm

Copy link
Contributor

coderabbitai bot commented Aug 28, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

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

Walkthrough

Introduces a new server middleware-based auth flow for @clerk/react-router, adds a server subpath export, and updates types/APIs to support middleware contexts. Deprecates SSR import paths, adds deprecation warnings, and removes legacy SSR implementations. Updates integration templates, configs, and tests accordingly, with various dependency version bumps.

Changes

Cohort / File(s) Summary
Docs & Changeset
\.changeset/quiet-bats-protect.md
Adds changeset documenting major changes: new React Router middleware via clerkMiddleware(), deprecations, migration guidance, and streaming example.
Server API & Middleware
packages/react-router/package.json, packages/react-router/src/server/index.ts, packages/react-router/src/server/clerkMiddleware.ts, packages/react-router/src/server/getAuth.ts, packages/react-router/src/server/clerkClient.ts, packages/react-router/src/server/loadOptions.ts, packages/react-router/src/server/types.ts, packages/react-router/src/server/legacyAuthenticateRequest.ts, packages/react-router/src/server/utils.ts
Adds public ./server export and types mapping; introduces clerkMiddleware, contexts, getAuth, and clerkClient; reworks option loading types and data args; renames authenticateRequest to legacyAuthenticateRequest using new client factory; adds middleware opt-in detection and conditional header injection; updates peer/dev deps for react-router.
SSR Deprecation & Migration
packages/react-router/src/ssr/index.ts, packages/react-router/src/ssr/getAuth.ts, packages/react-router/src/ssr/rootAuthLoader.ts, packages/react-router/src/utils/errors.ts, packages/react-router/src/api/index.ts
Removes SSR getAuth and rootAuthLoader implementations; SSR index now re-exports from server and logs a one-time deprecation warning; updates error/migration messages and adds middlewareMigrationWarning; adds API deprecation warnOnce for api.server.
Tests
packages/react-router/src/server/__tests__/getAuth.test.ts, packages/react-router/src/server/__tests__/clerkMiddleware.test.ts, packages/react-router/src/__tests__/exports.test.ts, integration/tests/react-router/basic.test.ts, integration/tests/react-router/pre-middleware.test.ts
Adds unit tests for middleware and getAuth; updates export tests to cover server and SSR deprecation; adjusts test label; adds E2E pre-middleware test wiring SSR auth and flows.
Integration Templates (React Router Node/Library)
integration/templates/react-router-node/package.json, integration/templates/react-router-library/package.json, integration/templates/react-router-node/react-router.config.ts, integration/templates/react-router-node/app/root.tsx, integration/templates/react-router-node/app/routes/protected.tsx
Removes @clerk/react-router deps from templates; upgrades react, react-dom, react-router, router toolchain, and build tools; enables future.v8_middleware and unstable_optimizeDeps; adds commented middleware placeholder; adjusts protected route loader data shape and UI.
Tooling & Scripts
package.json, integration/presets/utils.ts
Switches integration test script to pnpm invocation; minor refactor of conditional return in preset utility without functional change.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant RR as React Router
  participant MW as clerkMiddleware
  participant CC as ClerkClient
  participant LD as Loader/getAuth

  U->>RR: HTTP Request
  RR->>MW: Invoke middleware chain
  MW->>CC: authenticateRequest(patched request, options)
  alt Redirect (Location header)
    MW-->>RR: 307 Redirect with Clerk headers
    RR-->>U: Redirect response
  else Handshake without redirect
    MW-->>RR: Error (handshake status)
  else Auth state available
    MW->>RR: Set contexts (requestState, authFn)
    MW-->>RR: next()
    RR->>LD: Route loader executes
    opt getAuth called
      LD->>RR: Check authFnContext
      alt Context present
        RR-->>LD: authFn provides authObject
      else Legacy path
        LD->>CC: legacyAuthenticateRequest()
        CC-->>LD: requestState.toAuth()
      end
      LD-->>RR: Loader returns data/Response
    end
    RR-->>U: Response (with propagated Clerk headers)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

In burrows of bytes, I hop with glee,
A middleware trail for auth decree.
Contexts set, one hop, not two—
No double checks, just streaming through.
Old SSR paths fade from sight,
New routes twinkle in server light.
Thump-thump—ships tonight! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning I found changes that appear outside the core middleware/context objectives: switching the integration test invocation from npm to pnpm in the repo-level package.json and broad dependency upgrades in integration/templates/react-router-node/package.json (notably bumping react/react-dom to ^19.1.0 and large Vite/devDependency updates) plus unrelated devDependency bumps in integration templates; these edits materially widen the PR surface and may introduce CI or compatibility risk not justified in the PR description. Either remove or separate the package-manager switch and large dependency bumps into a follow-up PR, or add clear justification and CI validation in this PR showing those upgrades are required for the middleware change and do not break integrations.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat(react-router): Introduce middleware and context" concisely and accurately captures the primary change — adding middleware (clerkMiddleware) and associated React Router contexts — and is focused, specific, and free of extraneous noise, so it communicates the main intent to a reviewer scanning history.
Linked Issues Check ✅ Passed The changes directly implement the middleware/context solution requested in USER-3317 by adding clerkMiddleware, authFnContext/requestStateContext, and updating getAuth to prefer middleware-provided auth (avoiding duplicate authenticateRequest calls), and they address USER-3141 by enabling downstream reuse of authentication state while keeping a legacy fallback; the PR also adds unit and integration tests and migration warnings/deprecation notices that align with the stated objectives. For USER-2693 the PR surfaces middleware-based streaming examples and moves server-side auth wiring toward an authLoader pattern that enables promise/streaming scenarios, though an explicit end-to-end test demonstrating a promise-returning root loader would make the claim fully verifiable.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Comment @coderabbitai help to get the list of available commands and usage tips.

@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: d94a79c

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.

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.

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.

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.

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

🧹 Nitpick comments (4)
.changeset/quiet-bats-protect.md (4)

7-8: Deprecation phrasing conflicts with an immediate major bump — clarify timeline.

You’re shipping a major now while saying removal happens “in the next major.” Reword to avoid ambiguity.

Apply this edit:

-Usage of `rootAuthLoader` without the `clerkMiddleware()` installed is now deprecated and will be removed in the next major version.
+Usage of `rootAuthLoader` without `clerkMiddleware()` is deprecated in this release and scheduled for removal in a subsequent major version. Migrate to `clerkMiddleware()` + `rootAuthLoader` now.

5-5: Call out all breaking requirements and deprecations up front.

Add bullets for the minimum React Router version and deprecated import paths to align with the PR description.

Apply this insertion after the introductory sentence:

 Introduce [React Router middleware](https://reactrouter.com/how-to/middleware) support with `clerkMiddleware()` for improved performance and streaming capabilities.
+
+Breaking changes and deprecations:
+- Requires React Router >= 7.9.0 (relies on the stable Middleware and Context APIs).
+- `@clerk/react-router/ssr.server` and `@clerk/react-router/api.server` are deprecated in favor of `@clerk/react-router/server` and will be removed in a future major.

21-28: Add missing type import in the config snippet.

Without importing Config, the satisfies Config line is incomplete.

Apply this tweak:

 ```ts
-// react-router.config.ts
+// react-router.config.ts
+import type { Config } from '@react-router/dev/config';
 
 export default {
   future: {
     v8_middleware: true,
   },
 } satisfies Config;

---

`40-54`: **Optional doc polish: mention promise streaming support explicitly.**

Add one sentence clarifying that `rootAuthLoader` may return promises when middleware is enabled (RR >=7.9), matching the objective USER-2693.

Proposed addition right above the example:

```diff
 **Streaming Support (with middleware):**
+When using React Router >=7.9 with `clerkMiddleware()`, your `rootAuthLoader` can return promises to enable streaming responses.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 041c9d4 and cab78e7.

📒 Files selected for processing (1)
  • .changeset/quiet-bats-protect.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/**

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Automated releases must use Changesets.

Files:

  • .changeset/quiet-bats-protect.md
⏰ 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). (28)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • 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)
.changeset/quiet-bats-protect.md (1)

1-3: Frontmatter fixed — good to release.

The changeset frontmatter is now valid and marks a major bump for @clerk/react-router.

Before merging, confirm whether any sibling packages (templates/integrations) also require bumps or dependent releases in the same batch so the release notes remain coherent.

Comment on lines +30 to +38
2. Use the middleware in your app:

```tsx
import { clerkMiddleware, rootAuthLoader } from '@clerk/react-router/server'

export const middleware: Route.MiddlewareFunction[] = [clerkMiddleware()]

export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args)
```
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

🧩 Analysis chain

Verify stable API names: middleware key, Route.MiddlewareFunction, and future.v8_middleware.

These names depend on the exact React Router version. Your PR text says “stable APIs” on >=7.9.0; if consumers are below that, they may still need unstable_middleware. Keep the snippet as-is if we’re hard-requiring 7.9+, but let’s double-check the flag and type names.


🌐 Web query:

For React Router v7.9.0 and later:
- Is the feature flag name `future.v8_middleware` correct for enabling middleware on the Node adapter?
- Is the route export key `middleware` (not `unstable_middleware`) the correct stable name?
- Is the type `Route.MiddlewareFunction` the correct stable type name?

💡 Result:

Short answers:

  • No. The runtime feature flag to enable middleware is future.unstable_middleware (not future.v8_middleware). [1][2]
  • No. The stable route export in the docs remains unstable_middleware (the docs show export const unstable_middleware = …). [1]
  • No. The documented type is Route.unstable_MiddlewareFunction (not Route.MiddlewareFunction). [1][3]

Sources:

  1. React Router Middleware docs (shows future.unstable_middleware, export unstable_middleware, and Route.unstable_MiddlewareFunction examples). [turn0search0].
  2. React Router changelog (v7.9.1 notes about internal Future interface naming fixes). [turn0search1].
  3. Route Module docs / examples showing unstable_middleware usage. [turn0search2].

Use documented unstable middleware names (fix snippet + PR text)

File: .changeset/quiet-bats-protect.md (lines 30–38)

  • Replace future.v8_middleware → future.unstable_middleware (runtime flag).
  • Replace export const middleware → export const unstable_middleware (route export).
  • Use Route.unstable_MiddlewareFunction (type) instead of Route.MiddlewareFunction.
  • Either update the snippet to use these unstable names, or change the PR to require and cite the exact React Router version that actually exposes stable middleware names and verify those names.
🤖 Prompt for AI Agents
In .changeset/quiet-bats-protect.md around lines 30–38, the provided snippet
uses stable middleware names that aren’t available; update the snippet and PR
text to use the unstable names: change the runtime flag future.v8_middleware to
future.unstable_middleware, change the route export from export const middleware
to export const unstable_middleware, and use the
Route.unstable_MiddlewareFunction type instead of Route.MiddlewareFunction;
alternatively, if you want to keep the stable names, update the PR to explicitly
require and cite the exact React Router version that exposes those stable
middleware names and verify the names in the documentation.

@wobsoriano
Copy link
Member Author

!snapshot

@clerk-cookie
Copy link
Collaborator

Hey @wobsoriano - the snapshot version command generated the following package versions:

Package Version
@clerk/agent-toolkit 0.1.34-snapshot.v20250917224107
@clerk/astro 2.13.2-snapshot.v20250917224107
@clerk/backend 2.15.0-snapshot.v20250917224107
@clerk/chrome-extension 2.6.2-snapshot.v20250917224107
@clerk/clerk-js 5.94.1-snapshot.v20250917224107
@clerk/elements 0.23.65-snapshot.v20250917224107
@clerk/clerk-expo 2.15.2-snapshot.v20250917224107
@clerk/expo-passkeys 0.4.2-snapshot.v20250917224107
@clerk/express 1.7.33-snapshot.v20250917224107
@clerk/fastify 2.4.33-snapshot.v20250917224107
@clerk/localizations 3.25.3-snapshot.v20250917224107
@clerk/nextjs 6.32.2-snapshot.v20250917224107
@clerk/nuxt 1.9.0-snapshot.v20250917224107
@clerk/clerk-react 5.48.1-snapshot.v20250917224107
@clerk/react-router 2.0.0-snapshot.v20250917224107
@clerk/remix 4.12.2-snapshot.v20250917224107
@clerk/shared 3.26.1-snapshot.v20250917224107
@clerk/tanstack-react-start 0.24.2-snapshot.v20250917224107
@clerk/testing 1.12.8-snapshot.v20250917224107
@clerk/themes 2.4.21-snapshot.v20250917224107
@clerk/types 4.87.1-snapshot.v20250917224107
@clerk/vue 1.13.3-snapshot.v20250917224107

Tip: Use the snippet copy button below to quickly install the required packages.
@clerk/agent-toolkit

npm i @clerk/[email protected] --save-exact

@clerk/astro

npm i @clerk/[email protected] --save-exact

@clerk/backend

npm i @clerk/[email protected] --save-exact

@clerk/chrome-extension

npm i @clerk/[email protected] --save-exact

@clerk/clerk-js

npm i @clerk/[email protected] --save-exact

@clerk/elements

npm i @clerk/[email protected] --save-exact

@clerk/clerk-expo

npm i @clerk/[email protected] --save-exact

@clerk/expo-passkeys

npm i @clerk/[email protected] --save-exact

@clerk/express

npm i @clerk/[email protected] --save-exact

@clerk/fastify

npm i @clerk/[email protected] --save-exact

@clerk/localizations

npm i @clerk/[email protected] --save-exact

@clerk/nextjs

npm i @clerk/[email protected] --save-exact

@clerk/nuxt

npm i @clerk/[email protected] --save-exact

@clerk/clerk-react

npm i @clerk/[email protected] --save-exact

@clerk/react-router

npm i @clerk/[email protected] --save-exact

@clerk/remix

npm i @clerk/[email protected] --save-exact

@clerk/shared

npm i @clerk/[email protected] --save-exact

@clerk/tanstack-react-start

npm i @clerk/[email protected] --save-exact

@clerk/testing

npm i @clerk/[email protected] --save-exact

@clerk/themes

npm i @clerk/[email protected] --save-exact

@clerk/types

npm i @clerk/[email protected] --save-exact

@clerk/vue

npm i @clerk/[email protected] --save-exact

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

♻️ Duplicate comments (1)
integration/templates/react-router-node/app/routes/protected.tsx (1)

6-11: Return typed JSON with no-store, handle missing/deleted users, don’t assume an email exists.

Add defensive fetch + primary email selection, avoid caching PII, and provide an explicit return type for the public loader. This mirrors prior feedback.

-export async function loader(args: Route.LoaderArgs) {
+/** Loader for the protected route. Returns minimal, non-PII-cached user info. */
+export async function loader(args: Route.LoaderArgs): Promise<Response> {
   const { userId } = await getAuth(args);
 
   if (!userId) {
     return redirect('/sign-in');
   }
 
-  const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser(userId);
-
-  return {
-    firstName: user.firstName,
-    emailAddress: user.emailAddresses[0].emailAddress,
-  };
+  try {
+    const user = await clerkClient.users.getUser(userId);
+    const primaryEmail =
+      user.emailAddresses?.find(e => e.id === user.primaryEmailAddressId) ??
+      user.emailAddresses?.[0];
+    return json<{ firstName: string | null; emailAddress: string | null }>(
+      {
+        firstName: user.firstName ?? null,
+        emailAddress: primaryEmail?.emailAddress ?? null,
+      },
+      { headers: { 'Cache-Control': 'private, no-store' } },
+    );
+  } catch (_err: unknown) {
+    // User may be deleted or token invalid; force re-auth.
+    return redirect('/sign-in');
+  }
 }

Also applies to: 15-18

🧹 Nitpick comments (2)
integration/templates/react-router-node/app/routes/protected.tsx (2)

21-29: Null-safe render and explicit component return type.

Guard against nulls from the loader and declare the return type.

-export default function Profile({ loaderData }: Route.ComponentProps) {
+/** Protected profile page. */
+export default function Profile({ loaderData }: Route.ComponentProps): JSX.Element {
   return (
     <div>
       <h1>Protected</h1>
       <UserProfile />
       <ul>
-        <li>First name: {loaderData.firstName}</li>
-        <li>Email: {loaderData.emailAddress}</li>
+        <li>First name: {loaderData.firstName ?? '—'}</li>
+        <li>Email: {loaderData.emailAddress ?? '—'}</li>
       </ul>
     </div>
   );
 }

33-33: Add a route-level ErrorBoundary for better DX.

Optional but recommended per guidelines.

+export function ErrorBoundary(): JSX.Element {
+  // eslint-disable-next-line @typescript-eslint/consistent-type-imports
+  const { isRouteErrorResponse, useRouteError } = require('react-router') as typeof import('react-router');
+  const err = useRouteError();
+  if (isRouteErrorResponse(err)) {
+    return (
+      <div role="alert">
+        <h1>Something went wrong</h1>
+        <p>
+          {err.status} {err.statusText}
+        </p>
+      </div>
+    );
+  }
+  return (
+    <div role="alert">
+      <h1>Unexpected error</h1>
+      <pre>{String(err)}</pre>
+    </div>
+  );
+}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 ae32a9a and 37a6dbd.

📒 Files selected for processing (2)
  • integration/templates/react-router-node/app/root.tsx (1 hunks)
  • integration/templates/react-router-node/app/routes/protected.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • integration/templates/react-router-node/app/root.tsx
🧰 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:

  • integration/templates/react-router-node/app/routes/protected.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/templates/react-router-node/app/routes/protected.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/templates/react-router-node/app/routes/protected.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/routes/protected.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/routes/protected.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/app/routes/protected.tsx
**/*.{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/routes/protected.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/routes/protected.tsx
⏰ 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). (27)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
integration/templates/react-router-node/app/routes/protected.tsx (1)

1-4: Do not migrate to @clerk/react-router/server — the suggested exports are not available.

The targeted version does not export both clerkClient and getAuth from @clerk/react-router/server, and @clerk/react-router/ssr.server is not marked deprecated. Keep using getAuth from @clerk/react-router/ssr.server and your existing server-side client pattern (e.g., createClerkClient / api.server) instead of switching to clerkClient. Import json from react-router if you need typed responses.

File: integration/templates/react-router-node/app/routes/protected.tsx (lines 1–4)

Likely an incorrect or invalid review comment.

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 (2)
integration/templates/react-router-node/app/root.tsx (1)

6-6: Ensure the router opts into middleware; export alone won’t activate it.

Double‑check the router config enables the middleware feature flag, otherwise rootAuthLoader will fall back to legacy behavior and warn.

#!/bin/bash
# Search template for a middleware opt‑in flag in router config
rg -nP -C3 '(future\s*:\s*\{[^}]*\b(unstable_)?middleware\s*:\s*true)' integration/templates/react-router-node -g '!**/dist/**'

# Also scan common router config files
fd -H 'react-router*.{js,ts}' integration/templates/react-router-node | xargs -I{} rg -n 'middleware' {}
integration/templates/react-router-node/package.json (1)

9-9: Switch typecheck to plain tsc --noEmit; --build requires composite projects.

This template doesn’t declare "composite": true; tsc --build commonly fails.

-    "typecheck": "react-router typegen && tsc --build --noEmit"
+    "typecheck": "react-router typegen && tsc --noEmit"
🧹 Nitpick comments (1)
integration/templates/react-router-node/app/root.tsx (1)

8-8: Add an explicit return type for the public loader.

Keep API surfaces explicit per guidelines.

-export const loader = (args: Route.LoaderArgs) => rootAuthLoader(args);
+export const loader: Route.LoaderFunction = (args) => rootAuthLoader(args);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 7d1c5bc and 74f4f36.

📒 Files selected for processing (3)
  • integration/templates/react-router-node/app/root.tsx (1 hunks)
  • integration/templates/react-router-node/app/routes/protected.tsx (3 hunks)
  • integration/templates/react-router-node/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • integration/templates/react-router-node/app/routes/protected.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{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/package.json
  • 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/package.json
  • 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/package.json
  • integration/templates/react-router-node/app/root.tsx
**/*.{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
**/*.{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
**/*.{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
**/*.{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
**/*.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/templates/react-router-node/app/root.tsx (2)
packages/react-router/src/server/clerkMiddleware.ts (1)
  • clerkMiddleware (33-77)
packages/react-router/src/server/rootAuthLoader.ts (1)
  • rootAuthLoader (118-139)
⏰ 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). (25)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Publish with pkg-pr-new
  • 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: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
integration/templates/react-router-node/package.json (1)

12-19: Deps bump aligns with the new middleware/context requirements.

@clerk/react-router snapshot and React Router 7.9.x look consistent here.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
integration/templates/react-router-node/app/routes/protected.tsx (1)

3-4: Use new server entrypoint and preconfigured client; avoid deprecated imports and manual secret wiring.

Replace deprecated /ssr.server and /api.server imports with @clerk/react-router/server and use the preconfigured clerkClient instead of constructing one with the secret key.

-import { getAuth } from '@clerk/react-router/ssr.server';
-import { createClerkClient } from '@clerk/react-router/api.server';
+import { getAuth, clerkClient } from '@clerk/react-router/server';
-  const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser(userId);
+  const user = await clerkClient.users.getUser(userId);

Location: integration/templates/react-router-node/app/routes/protected.tsx — preconfigured clerkClient available at packages/react-router/src/server/clerkClient.ts.

♻️ Duplicate comments (4)
integration/templates/react-router-node/package.json (2)

9-9: Switch typecheck off “--build”; duplicate of prior feedback.
tsc --build needs "composite": true; this template typically isn’t composite.

-    "typecheck": "react-router typegen && tsc --build --noEmit"
+    "typecheck": "react-router typegen && tsc --noEmit"

11-18: Missing required dependency: @clerk/react-router.
This is a Clerk quickstart; installs will fail without it.

Apply (use one of the versions per your release workflow):

   "dependencies": {
+    "@clerk/react-router": "workspace:*",
     "@react-router/node": "^7.9.1",
     "@react-router/serve": "^7.9.1",
     "isbot": "^5.1.17",
     "react": "^19.1.0",
     "react-dom": "^19.1.0",
     "react-router": "^7.9.1"
   },

If publishing outside the monorepo, prefer:

-    "@clerk/react-router": "workspace:*",
+    "@clerk/react-router": "^2.0.0"
integration/templates/react-router-node/app/routes/protected.tsx (2)

5-5: Types path mismatch for generated Route types.

Use the protected types file to match this route’s filename.

-import type { Route } from './+types/profile';
+import type { Route } from './+types/protected';

16-19: Return typed JSON, set no-store for PII, and null‑safe email selection.

Avoid caching personalized data and don’t assume an email exists; prefer the primary email with a safe fallback.

-  return {
-    firstName: user.firstName,
-    emailAddress: user.emailAddresses[0].emailAddress,
-  };
+  const primaryEmail =
+    user.emailAddresses?.find(e => e.id === user.primaryEmailAddressId) ??
+    user.emailAddresses?.[0];
+  return json<{ firstName: string | null; emailAddress: string | null }>(
+    {
+      firstName: user.firstName ?? null,
+      emailAddress: primaryEmail?.emailAddress ?? null,
+    },
+    { headers: { 'Cache-Control': 'private, no-store' } },
+  );

Add the missing import:

import { json, redirect } from 'react-router';

(Optional) Wrap the fetch in a try/catch to handle deleted users/invalid tokens by redirecting to sign-in.

🧹 Nitpick comments (2)
integration/templates/react-router-node/package.json (1)

25-26: Vite 7 requires modern Node — add an engines guard.
Prevent CI/user mismatches by declaring Node range.

Apply:

 {
   "name": "clerk-react-router-quickstart",
   "private": true,
   "type": "module",
+  "engines": {
+    "node": ">=18.0.0"
+  },
   "scripts": {
integration/templates/react-router-node/app/routes/protected.tsx (1)

28-29: Render fallbacks for possibly null loaderData fields.

Prevents “cannot read” UI glitches when values are absent.

-        <li>First name: {loaderData.firstName}</li>
-        <li>Email: {loaderData.emailAddress}</li>
+        <li>First name: {loaderData.firstName ?? '—'}</li>
+        <li>Email: {loaderData.emailAddress ?? '—'}</li>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • 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 74f4f36 and d718198.

📒 Files selected for processing (3)
  • integration/templates/react-router-node/app/root.tsx (1 hunks)
  • integration/templates/react-router-node/app/routes/protected.tsx (2 hunks)
  • integration/templates/react-router-node/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • integration/templates/react-router-node/app/root.tsx
🧰 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:

  • integration/templates/react-router-node/app/routes/protected.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/templates/react-router-node/app/routes/protected.tsx
  • integration/templates/react-router-node/package.json
**/*.{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/routes/protected.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/routes/protected.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/routes/protected.tsx
  • integration/templates/react-router-node/package.json
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/routes/protected.tsx
  • integration/templates/react-router-node/package.json
**/*.{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/routes/protected.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/routes/protected.tsx
⏰ 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). (28)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (custom, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (machine, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Unit Tests (18, --filter=@clerk/astro --filter=@clerk/backend --filter=@clerk/express --filter=@c...
  • GitHub Check: Unit Tests (22, **)
  • GitHub Check: Static analysis
  • GitHub Check: Publish with pkg-pr-new
  • 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 (3)
integration/templates/react-router-node/package.json (3)

12-13: Router core/server bumped to ^7.9.1 — aligned with new minimum.
Looks good and matches the middleware/context requirement.


15-17: React 19 upgrade acknowledged.
Deps are consistent (react/react-dom 19, router 7.9).


20-23: Dev/tooling versions aligned to 7.9 + React 19 types.
No issues spotted.

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.

3 participants