Skip to content

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Dec 11, 2025

fixes #6065

Summary by CodeRabbit

  • Refactor

    • Consistent internal URL handling across router packages to improve navigation and redirect behavior.
    • Added a central helper to reliably derive link hrefs for navigation flows.
  • Bug Fixes

    • Link components (React, Solid, Vue) now generate correct href strings for navigation and external detection.
    • Server-side redirect behavior verified to respect base paths in Location headers.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 11, 2025

Walkthrough

The PR changes ParsedLocation.url from a string to a URL object in router-core, updates router logic to propagate and consume URL objects, and updates framework link components and tests to read .href from those URL objects.

Changes

Cohort / File(s) Summary
Router core type definition
packages/router-core/src/location.ts
ParsedLocation.url changed from string to URL; JSDoc for publicHref adjusted.
Router core location handling
packages/router-core/src/router.ts
parse/build/redirect/commit flows now store and compare URL objects; getParsedLocationHref(location) helper added to produce safe href strings (origin stripping/normalization) and used throughout.
Framework link components
packages/react-router/src/link.tsx, packages/solid-router/src/link.tsx, packages/vue-router/src/link.tsx
Link hooks/components now extract href via .href from ParsedLocation.url (e.g., maskedLocation.url.href, nextLocation.url.href) instead of using the url field directly.
Tests
packages/react-router/tests/*.tsx, packages/solid-router/tests/*.tsx, e2e/*/custom-basepath/tests/navigation.spec.ts
Tests updated to expect URL objects or to access .href (e.g., assert on location.url.href); e2e navigation specs add explicit Location header checks for redirects.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to router.ts changes (parsing, redirects, rewrites) and correctness of getParsedLocationHref.
  • Verify all call sites and tests correctly treat ParsedLocation.url as URL (not string).
  • Confirm no remaining assumptions about location.url being a string (serialization, comparisons, logging).

Possibly related PRs

Suggested reviewers

  • birkskyum
  • nlynzaad
  • SeanCassiere

Poem

🐰 A hop, a sniff, a tiny cheer,

URLs now wear jackets clear,
.href I fetch with gentle paw,
Router paths align—oh law!
Hops of joy across the code so dear 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: converting from string href comparisons to URL object comparisons for determining server redirect logic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-rewrite-redirect

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

@nx-cloud
Copy link

nx-cloud bot commented Dec 11, 2025

View your CI Pipeline Execution ↗ for commit 6a00d7b

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 12m 14s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 42s View ↗

☁️ Nx Cloud last updated this comment at 2025-12-12 19:20:19 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 11, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6072

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@6072

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6072

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6072

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6072

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6072

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6072

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6072

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6072

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6072

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6072

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6072

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6072

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6072

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6072

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6072

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6072

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6072

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6072

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6072

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@6072

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6072

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6072

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6072

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6072

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6072

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6072

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6072

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6072

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6072

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6072

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6072

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6072

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6072

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6072

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6072

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6072

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6072

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6072

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6072

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6072

commit: 6a00d7b

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 (1)
packages/router-core/src/location.ts (1)

41-43: Documentation change removes rewrite context.

The updated JSDoc for publicHref no longer mentions "before any rewrites", which was helpful context for understanding the distinction between publicHref and href. Consider preserving this clarification to help developers understand when rewrite transformations have been applied.

Apply this diff to restore the rewrite context:

  /**
   * @private
-  * @description The public href of the location.
+  * @description The public href of the location before any rewrite transformations.
   * If a rewrite is applied, the `href` property will be the rewritten URL.
   */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcce02c and 3b9b4c7.

📒 Files selected for processing (5)
  • packages/react-router/src/link.tsx (1 hunks)
  • packages/router-core/src/location.ts (1 hunks)
  • packages/router-core/src/router.ts (5 hunks)
  • packages/solid-router/src/link.tsx (1 hunks)
  • packages/vue-router/src/link.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode with extensive type safety for all code

Files:

  • packages/solid-router/src/link.tsx
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
  • packages/router-core/src/location.ts
  • packages/vue-router/src/link.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Implement ESLint rules for router best practices using the ESLint plugin router

Files:

  • packages/solid-router/src/link.tsx
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
  • packages/router-core/src/location.ts
  • packages/vue-router/src/link.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/solid-router/src/link.tsx
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
  • packages/router-core/src/location.ts
  • packages/vue-router/src/link.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
⏰ 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). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (10)
packages/router-core/src/location.ts (1)

50-50: Type change from string to URL object is correct.

The change from url: string to url: URL aligns with the PR objective to store URLs as objects rather than strings. Since this field is marked @private, the breaking change impact is contained to internal usage.

packages/router-core/src/router.ts (6)

1184-1184: URL object storage is correctly implemented.

Storing the URL object directly in the parsed location enables more robust URL manipulation and comparison throughout the router lifecycle.


1768-1768: Rewritten URL stored as object for consistency.

Storing the rewritten URL as a URL object maintains consistency with the parseLocation output and enables uniform handling across navigation flows.


2003-2003: Correct href extraction from URL object.

Accessing location.url.href properly extracts the string href from the URL object for document navigation.


2385-2391: The getParsedLocationHref helper correctly implements origin stripping.

The helper extracts the href from the URL object and strips the router's origin when they differ. This aligns with the learning that origin stripping is intentional for same-origin redirects while preserving full URLs for cross-origin cases.

Implementation is correct and consistent with the existing resolveRedirect pattern.

Based on learnings, this method correctly preserves the router's origin-stripping behavior for same-origin redirects.


2396-2396: Correct usage of the new helper in redirect resolution.

Using getParsedLocationHref ensures the redirect location header contains the properly normalized href with origin handling applied.


2060-2066: The condition logic is correct and intentional.

The OR logic appropriately handles both scenarios independently:

  1. publicHref mismatch — Detects when the rewrite function changes the pathname, search, or hash (visible URL changes)
  2. origin mismatch — Detects when the rewrite function returns a URL with a different origin (e.g., via rewrite.input() returning 'https://other-origin.com/path')

Both conditions warrant a server-side redirect independently. The rewrite function can modify the origin by returning a new URL string or object with a different origin, so the origin check is not redundant. This design ensures the server correctly handles cases where URL rewriting affects either the path or the origin.

packages/react-router/src/link.tsx (1)

130-143: Href extraction correctly adapted to URL objects.

The change properly extracts string hrefs from the new URL objects (maskedLocation.url.href and next.url.href) while preserving the existing external link detection and origin handling logic.

packages/vue-router/src/link.tsx (1)

433-437: Href extraction correctly adapted for Vue.

The implementation consistently extracts string hrefs from URL objects, matching the pattern used in the React implementation. The optional chaining on line 436 safely handles cases where nextLocation might be undefined.

packages/solid-router/src/link.tsx (1)

142-145: Href extraction correctly adapted for SolidJS.

The implementation properly extracts string hrefs from URL objects using the SolidJS reactive pattern (next().url.href), maintaining consistency with the React and Vue implementations.

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 (2)
packages/router-core/src/router.ts (2)

1842-1930: Don’t leak URL instances into history state via maskedLocation (can break pushState).
You’re stripping next.url, but ...maskedLocation reintroduces maskedLocation.url into nextHistory (and then into __tempLocation). If URL isn’t structured-cloneable in some targets, this can throw at runtime.

-      if (maskedLocation) {
+      if (maskedLocation) {
+        // Omit `url` from maskedLocation before putting it into history/state payloads
+        // (URL may not be structured-cloneable everywhere)
+        // eslint-disable-next-line prefer-const
+        let { url: _maskedUrl, ...maskedLocationForHistory } = maskedLocation as any
+
         nextHistory = {
-          ...maskedLocation,
+          ...maskedLocationForHistory,
           state: {
-            ...maskedLocation.state,
+            ...maskedLocationForHistory.state,
             __tempKey: undefined,
             __tempLocation: {
               ...nextHistory,
               search: nextHistory.searchStr,
               state: {
                 ...nextHistory.state,
                 __tempKey: undefined!,
                 __tempLocation: undefined!,
                 __TSR_key: undefined!,
                 key: undefined!, // TODO: Remove in v2 - use __TSR_key instead
               },
             },
           },
         }

2399-2410: resolveRedirect must set redirect.options.href to the same value as the Location header (breaks cross-origin redirects otherwise).
Right now the header uses getParsedLocationHref(location) but redirect.options.href is set to location.href (internal, origin-less). On the client, catch (redirect) spreads redirect.options into navigate(), so cross-origin redirects won’t become reloadDocument navigations.

   resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
     if (!redirect.options.href) {
       const location = this.buildLocation(redirect.options)
       const href = this.getParsedLocationHref(location)
-      redirect.options.href = location.href
+      // Keep options.href consistent with the Location header so client-side
+      // redirect handling can correctly detect absolute/cross-origin navigations.
+      redirect.options.href = href
       redirect.headers.set('Location', href)
     }
🧹 Nitpick comments (6)
e2e/solid-start/custom-basepath/tests/navigation.spec.ts (1)

63-77: Prefer APIResponse.headerValue('location') + avoid await ... .then(...) in tests.
This keeps the test runtime-independent (no reliance on global Headers) and improves readability/debuggability.

   // do not follow redirects since we want to test the Location header
   // first go to the route WITHOUT the base path, this will just add the base path
-  await page.request
-    .get('/redirect/throw-it', { maxRedirects: 0 })
-    .then((res) => {
-      const headers = new Headers(res.headers())
-      expect(headers.get('location')).toBe('/custom/basepath/redirect/throw-it')
-    })
+  const res1 = await page.request.get('/redirect/throw-it', { maxRedirects: 0 })
+  expect(res1.headerValue('location')).toBe('/custom/basepath/redirect/throw-it')

   // now go to the route WITH the base path, this will redirect to the final destination
-  await page.request
-    .get('/custom/basepath/redirect/throw-it', { maxRedirects: 0 })
-    .then((res) => {
-      const headers = new Headers(res.headers())
-      expect(headers.get('location')).toBe('/custom/basepath/posts/1')
-    })
+  const res2 = await page.request.get('/custom/basepath/redirect/throw-it', {
+    maxRedirects: 0,
+  })
+  expect(res2.headerValue('location')).toBe('/custom/basepath/posts/1')
packages/react-router/src/link.tsx (1)

126-143: Update looks correct for ParsedLocation.url: URL migration; consider guarding/typing maskedLocation.url as always-present.
The switch to next.*.url.href aligns with the new location shape and keeps origin-stripping logic intact.

packages/react-router/tests/redirect.test.tsx (1)

358-376: Avoid deep toEqual on URL instances; assert on .href or expect.any(URL) instead.
This expectation may be brittle depending on how the test runner compares URL objects.

-      expect(currentRedirect.options).toEqual({
+      expect(currentRedirect.options).toEqual({
         _fromLocation: {
@@
-          url: new URL('http://localhost/'),
+          url: expect.any(URL),
         },
@@
       })
+      expect(currentRedirect.options._fromLocation!.url.href).toBe('http://localhost/')
packages/solid-router/tests/redirect.test.tsx (1)

352-370: Avoid deep toEqual on URL instances; assert on .href or expect.any(URL) instead.

       expect(currentRedirect.options).toEqual({
         _fromLocation: {
           publicHref: '/',
-          url: new URL('http://localhost/'),
+          url: expect.any(URL),
           hash: '',
           href: '/',
@@
         },
@@
       })
+      expect(currentRedirect.options._fromLocation!.url.href).toBe('http://localhost/')
packages/router-core/src/location.ts (1)

40-51: Docs/type change is fine, but call out serialization constraints for url: URL.
Since ParsedLocation is widely consumed, it’s worth explicitly noting (in docs) that url is not JSON-serializable and may be unsafe to store in history/state payloads.

packages/react-router/tests/router.test.tsx (1)

345-467: Test updates to location.url.href are consistent; consider removing redundant new URL(location.url) usage.
Using router.state.location.url.pathname is clearer now that url is already a URL.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b9b4c7 and 6a00d7b.

📒 Files selected for processing (10)
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts (1 hunks)
  • e2e/solid-start/custom-basepath/tests/navigation.spec.ts (1 hunks)
  • packages/react-router/src/link.tsx (1 hunks)
  • packages/react-router/tests/redirect.test.tsx (1 hunks)
  • packages/react-router/tests/router.test.tsx (13 hunks)
  • packages/router-core/src/location.ts (1 hunks)
  • packages/router-core/src/router.ts (6 hunks)
  • packages/solid-router/src/link.tsx (1 hunks)
  • packages/solid-router/tests/redirect.test.tsx (1 hunks)
  • packages/vue-router/src/link.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/solid-router/src/link.tsx
  • packages/vue-router/src/link.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode with extensive type safety for all code

Files:

  • packages/react-router/tests/redirect.test.tsx
  • packages/react-router/tests/router.test.tsx
  • e2e/solid-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/location.ts
  • packages/solid-router/tests/redirect.test.tsx
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Implement ESLint rules for router best practices using the ESLint plugin router

Files:

  • packages/react-router/tests/redirect.test.tsx
  • packages/react-router/tests/router.test.tsx
  • e2e/solid-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/location.ts
  • packages/solid-router/tests/redirect.test.tsx
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/react-router/tests/redirect.test.tsx
  • packages/react-router/tests/router.test.tsx
  • e2e/solid-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/location.ts
  • packages/solid-router/tests/redirect.test.tsx
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
  • packages/router-core/src/router.ts
  • packages/react-router/src/link.tsx
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/react-router/tests/redirect.test.tsx
  • packages/react-router/tests/router.test.tsx
  • e2e/solid-start/custom-basepath/tests/navigation.spec.ts
  • packages/solid-router/tests/redirect.test.tsx
  • e2e/react-start/custom-basepath/tests/navigation.spec.ts
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router

Applied to files:

  • packages/react-router/tests/router.test.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). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (2)
e2e/react-start/custom-basepath/tests/navigation.spec.ts (1)

63-77: LGTM! Excellent redirect header verification.

The two-step header verification properly tests the basepath redirect logic:

  1. Requesting without basepath correctly expects a redirect to add it
  2. Requesting with basepath correctly expects a redirect to the final destination

This provides good coverage for the URL comparison fix and ensures the server correctly handles basepath application during redirects.

packages/router-core/src/router.ts (1)

2054-2073: Server redirect decision change matches the PR objective; looks good.
Comparing publicHref (actual) vs nextLocation.publicHref (post-output-rewrite) plus origin mismatch is the right signal for “server must redirect”.

@schiller-manuel schiller-manuel merged commit 20aac85 into main Dec 12, 2025
6 checks passed
@schiller-manuel schiller-manuel deleted the fix-rewrite-redirect branch December 12, 2025 19:29
@coderabbitai coderabbitai bot mentioned this pull request Dec 24, 2025
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.

Infinite redirect when we refresh a rewrited subdomain route with a search param

2 participants