From 411c05a9d6c3c4685d3ef11f334c588b5c1de801 Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Mon, 29 Jun 2026 00:40:42 +0300 Subject: [PATCH] fix(client): add /l vanity route to SW denylist; name failed offline steps (F2, F3) F2: navigateFallbackDenylist was missing the server's `l/:alias` vanity short-link, so a top-nav to /l/ after SW registration got the index.html app shell (which has no /l route) and dead-ended on Error404 instead of the server's 302 redirect. Add /^\/l(\/|$)/ mirroring main.ts. F3: the partial-failure branch of "make page available offline" showed a bare generic toast; include result.failed step labels in the message per AGENTS.md (errors must be specific), matching the catch-branch below it. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../tree/components/space-tree-node-menu.tsx | 5 +++-- apps/client/vite.config.ts | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/client/src/features/page/tree/components/space-tree-node-menu.tsx b/apps/client/src/features/page/tree/components/space-tree-node-menu.tsx index 8df209fb..997955ed 100644 --- a/apps/client/src/features/page/tree/components/space-tree-node-menu.tsx +++ b/apps/client/src/features/page/tree/components/space-tree-node-menu.tsx @@ -98,9 +98,10 @@ export function NodeMenu({ node, canEdit }: NodeMenuProps) { } else { // Partial warm — the page may still be partly usable offline, but some // queries failed to cache, so surface it as an error rather than a - // silent success. + // silent success. Name the failed step(s) (AGENTS.md: errors must be + // specific, never a bare generic string); `result.failed` carries them. notifications.show({ - message: t("Failed to make page available offline"), + message: `${t("Failed to make page available offline")}: ${result.failed.join(", ")}`, color: "red", }); } diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index b9a9ee80..397bd9a8 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -68,18 +68,22 @@ export default defineConfig(({ mode }) => { // segments are consistently excluded from the SPA fallback, mirroring // the runtimeCaching urlPattern regexes below. // - // `/share`, `/mcp`, and `/robots.txt` mirror the server static-serve - // exclude list (apps/server/src/main.ts setGlobalPrefix `exclude`): - // robots.txt, the SEO/OG/analytics-injected public share HTML, and the - // embedded MCP endpoint are served by server controllers, so the SW must - // never shadow them with the precached index.html app shell (doing so - // would break SEO and MCP). + // `/share`, `/mcp`, `/l`, and `/robots.txt` mirror the server + // static-serve exclude list (apps/server/src/main.ts setGlobalPrefix + // `exclude`): robots.txt, the SEO/OG/analytics-injected public share + // HTML, the embedded MCP endpoint, and the `l/:alias` vanity short-link + // (a server 302 to a share page) are served by server controllers, so + // the SW must never shadow them with the precached index.html app shell. + // For `/l/:alias` the client router has NO matching route, so serving + // the app shell would dead-end on Error404 and break the public link; + // it must reach the server to perform the redirect. navigateFallbackDenylist: [ /^\/api(\/|$)/, /^\/collab(\/|$)/, /^\/socket\.io(\/|$)/, /^\/share(\/|$)/, /^\/mcp(\/|$)/, + /^\/l(\/|$)/, /^\/robots\.txt$/, ], cleanupOutdatedCaches: true,