fix: hard page reloads on family routes — RSC .txt payloads were wildcard-rewritten

Client navigation to an exported route fetches its RSC payload
(<route>/index.txt). The legacy-path wildcards (/admin/backups/* etc.)
matched those .txt paths and served the detail HTML instead — the Next
router cannot parse HTML as a flight payload and falls back to a hard
full-page navigation, resetting all client state (visible as the sidebar
collapsing on every Backups/Customs-Archive navigation).

Exact self-rewrites for all nine exported index.txt files now precede the
wildcards; the swaConfig guard pins txt-before-wildcard for every family.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-07-29 02:48:08 +02:00
parent ffe88a47c6
commit 5e9876bc5f
2 changed files with 24 additions and 0 deletions
@@ -21,6 +21,16 @@
{ "route": "/changelog", "redirect": "https://docs.autopilotmonitor.com/changelog/platform-changelog", "statusCode": 301 },
{ "route": "/roadmap", "redirect": "/", "statusCode": 302 },
{ "route": "/sessions/index.txt", "rewrite": "/sessions/index.txt" },
{ "route": "/sessions/inspector/index.txt", "rewrite": "/sessions/inspector/index.txt" },
{ "route": "/diagnosis/index.txt", "rewrite": "/diagnosis/index.txt" },
{ "route": "/apps/index.txt", "rewrite": "/apps/index.txt" },
{ "route": "/apps/detail/index.txt", "rewrite": "/apps/detail/index.txt" },
{ "route": "/admin/backups/index.txt", "rewrite": "/admin/backups/index.txt" },
{ "route": "/admin/backups/detail/index.txt", "rewrite": "/admin/backups/detail/index.txt" },
{ "route": "/admin/customs-archive/index.txt", "rewrite": "/admin/customs-archive/index.txt" },
{ "route": "/admin/customs-archive/detail/index.txt", "rewrite": "/admin/customs-archive/detail/index.txt" },
{ "route": "/sessions", "rewrite": "/sessions/index.html" },
{ "route": "/sessions/inspector", "rewrite": "/sessions/inspector/index.html" },
{ "route": "/sessions/*", "rewrite": "/sessions/index.html" },
@@ -87,7 +87,21 @@ describe("staticwebapp.config.json guard", () => {
// trailingSlash:auto normalizes /apps to /apps/, which the /apps/* wildcard
// matches — without the exact entry the list page serves the DETAIL html
// (production incident 2026-07-29: /apps rendered the app-detail view).
// The exported RSC payloads (<route>/index.txt) equally need exact
// self-rewrites before the wildcard: client navigation fetches them, and a
// wildcard-rewritten HTML response makes the Next router fall back to a
// HARD page load (production incident 2026-07-29: sidebar state reset on
// every /admin/backups navigation).
const pairs: Array<[string, string]> = [
["/sessions/index.txt", "/sessions/*"],
["/sessions/inspector/index.txt", "/sessions/*"],
["/diagnosis/index.txt", "/diagnosis/*"],
["/apps/index.txt", "/apps/*"],
["/apps/detail/index.txt", "/apps/*"],
["/admin/backups/index.txt", "/admin/backups/*"],
["/admin/backups/detail/index.txt", "/admin/backups/*"],
["/admin/customs-archive/index.txt", "/admin/customs-archive/*"],
["/admin/customs-archive/detail/index.txt", "/admin/customs-archive/*"],
["/sessions", "/sessions/*"],
["/sessions/inspector", "/sessions/*"],
["/diagnosis", "/diagnosis/*"],