Skip to content

fix(pwa): do not intercept navigations so Chrome can retry HTTP/2 - #12767

Merged
diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.51from
HouMinXi:fix/dashboard-stale-tab-refresh
Sep 7, 2026
Merged

diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.51from
HouMinXi:fix/dashboard-stale-tab-refresh

Conversation

@HouMinXi

@HouMinXi HouMinXi commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Bug

A Chrome tab left on /dashboard/quota eventually fails to reload. F5 times out. A new tab on the same origin loads immediately. curl against the origin stays 200.

Seen on both a LAN HTTPS origin (TCP 20128, no UDP) and a Cloudflare-fronted hostname.

Cause

Two things stack:

  1. Caddy 2.11 defaults to protocols = [h1 h2 h3] and sends Alt-Svc: h3=":<port>"; ma=2592000. If the process only publishes TCP, that advertisement is a lie. Chrome caches it for 30 days and retries QUIC on F5. UDP never answers.
  2. public/sw.js called event.respondWith on mode:navigate for /dashboard/*. On a dead QUIC socket the worker's fetch() hangs or errors, and Response.error() aborts the document load. Chrome never gets to fall back to HTTP/2 on that tab. A new tab opens a fresh TCP handshake, so it works.

This PR only changes the service worker. The Caddy protocols h1 h2 + header Alt-Svc "clear" fix belongs in the reverse-proxy config, not here.

pathname.startsWith("/dashboard") also matched /dashboardfoo. Second commit requires a path-segment boundary.

Change

  • Navigations: do not call respondWith. The browser owns the document load and the H3→H2 retry.
  • Cache name omniroute-pwa-v2 → omniroute-pwa-v3 so existing clients drop the old worker.
  • pathIsExcluded: strip a trailing slash, then exact match or ${base}/.
  • Static assets (style / script / image / font) stay cache-first.

No custom offline HTML for navigations. Serving a stale shell from the worker is what hung F5. Offline dashboard is a follow-up.

Tests

node --import tsx/esm --test tests/unit/service-worker-navigation-fallback.test.ts

4/4 pass. Naive startsWith injection fails /dashboardfoo; restore is green. node --check public/sw.js is clean. CI shards also ran the four #11779 / #5165 cases green.

After merge + deploy: F5 a stale tab on /dashboard/quota without opening a new one. If the tab is still on v2, unregister the worker in DevTools or wait for v3 to activate.

WAN h3=":443" from Cloudflare is a real listener. Leave it.

⚠️ base-red inherited

This PR does not touch open-sse/executors/glm.ts, changelog.d/fixes/reset-aware-model-family.md, stryker.conf.json, or the sanitizer / stream-boundary tests that failed on CI. Those gates are already red on release/v3.8.51 (same changelog fragment on sibling #12733; glm TS2554 baseline 0→1; mutation list missing tests/unit/reset-aware-request-scope-12600.test.ts). Not fixing them here.

@HouMinXi
HouMinXi force-pushed the fix/dashboard-stale-tab-refresh branch from 22bda89 to 9e4b046 Compare September 5, 2026 14:34
@HouMinXi

HouMinXi commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto upstream/release/v3.8.51 @ 9d1a896c6 (#12670).

range-diff every unique commit =. All rewritten commits GPG G. behind=0 vs tip.

Own tests re-run on the new base. --force-with-lease to the previous fork SHA.

⚠️ base-red inherited: #12732 (FQG / unit shards / changelog-integrity / glm arity until #12770 lands). Files this PR does not touch.

@HouMinXi

HouMinXi commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto release/v3.8.51 tip f9a1cc8a9 (#12682 / #12691 / #12834).

9e4b046b1 → c4381e5fe. range-diff 2 commits =. GPG G. No file overlap with the three landed commits.

Chrome cached Alt-Svc h3=":20128" (ma=2592000) from Caddy's default
protocol list. UDP 20128 is unpublished, so a long-lived tab's refresh
hit a dead QUIC socket. The service worker then respondWith()'d
Response.error() and Chrome never retried HTTP/2. A new tab worked
because it opened a fresh TCP connection.

Leave navigations to the browser. Bump the PWA cache to v3 so existing
workers update.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
startsWith("/dashboard") also matched /dashboardfoo. Strip a trailing
slash from each prefix, then require exact equality or `${base}/`.

Tested: 4/4 SW unit tests pass. Naive startsWith injection fails the
/dashboardfoo case; restore is green again.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
@HouMinXi
HouMinXi force-pushed the fix/dashboard-stale-tab-refresh branch from c4381e5 to ff0f718 Compare September 7, 2026 02:35
@HouMinXi

HouMinXi commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto upstream/release/v3.8.51 b345c7f6c (#12870 OpenCode v2 plugin).

  • c4381e5fea3 → ff0f718fcff
  • range-diff identity (eq=2); all commits GPG G
  • 2 unique commit(s) ahead, 0 behind
  • --force-with-lease to HouMinXi:fix/dashboard-stale-tab-refresh

@diegosouzapw
diegosouzapw merged commit 6d6b602 into cheaper-inference:release/v3.8.51 Sep 7, 2026
8 of 16 checks passed
@HouMinXi
HouMinXi deleted the fix/dashboard-stale-tab-refresh branch September 7, 2026 13:27
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…eaper-inference#12767)

Validado numa worktree combinada com as 16 PRs desta leva sobre `release/v3.8.51`: typecheck:core limpo, check-file-size e check-changelog-integrity OK, complexity 2788/3218 e cognitive 1261/1437 (ambos sob a baseline), ESLint 0 erros nos 152 arquivos alterados, 771 testes unitários focados, 49 de integração e a suíte vitest:ui completa (2149) verdes.

A separação entre o que é do service worker e o que é do Caddy está certa e é o que torna a PR mergeável: o `respondWith` em navegação é defeito nosso, o `Alt-Svc` mentindo h3 é config de proxy reverso e não tem o que fazer aqui.

O `/dashboardfoo` casando com `startsWith("/dashboard")` é um achado à parte, e o bump de cache v2→v3 é o que faz o worker antigo sair do ar nos clientes que já estão presos.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants