Repository navigation
fix(auth): keep static file cache policy for signed-in users, and skip the Worker for hashed chunks - #552
Merged
Conversation
Static files that the Worker serves from ASSETS ran inside the auth middleware, which copied the session lookup's `no-store` and `pragma: no-cache` onto them for any request with a cookie, Authorization or CF Access header. Browsers then refetched hashed JS and CSS on every navigation once a user signed in. The Pages, SSR and asset-only fallbacks now record the Cache-Control of the file they served on the Hono context. When the final response is still that file (success status, same Cache-Control, no added Set-Cookie), the auth middleware keeps the file's own policy and only makes it private for credentialed requests, e.g. `private, max-age=31536000, immutable`. A session cookie refresh on the same request still gets `private, no-store`. Pages, API routes, and files whose headers user middleware changed keep today's behaviour. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…native builds Every request for a fingerprinted chunk started the Worker, ran the auth middleware and, for signed-in users, a session read, only to copy the asset response. Native Cloudflare builds now patch the built wrangler.json to `run_worker_first: ['/**', '!/<assetsDir>/*']` and write a Void-generated `_headers` that lists each manifest-proven chunk with `public, max-age=31536000, immutable`, so the asset layer keeps today's cache policy. This applies only when every condition holds: no global middleware, no header/redirect/rewrite/fallback rules, no public `_headers`/`_redirects`, no route, page, WebSocket, prerender or revalidate pattern that reaches the assets folder, base '/', 1-100 hashed chunks, no user `_headers` in the client output, and not a managed build. Otherwise the output is unchanged, and a stale generated `_headers` is removed. The pinned-secrets version upload sends the generated `_headers` as a `_headers` text/plain module, as the Workers versions API and cf expect. User-authored `_headers` files are still not sent on that path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A middleware that swaps c.res after next() keeps the file's Cache-Control and ETag, so the auth middleware still saw an unchanged file and gave the new body a cacheable private policy. Record the body stream with the marker and require the final response to keep it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Cloudflare Vite plugin writes the built wrangler.json as compact JSON with no trailing newline, so the indent and newline branches never ran. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
resolveAssetWorkerBypass now returns the final run_worker_first and the _headers text, so the plugin no longer repeats its checks through two exported helpers whose null results could not happen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A negative run_worker_first rule sends every matching request to the asset layer, misses included, so '!/assets/*' took SSR rendering, the SPA shell, the custom 404 page and the /assets redirect away from paths under the assets folder. Emit one negative rule per immutable file instead, which caps the bypass at 99 files. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rebuilds In vite build --watch a client-only rebuild empties dist/client but keeps the Worker's wrangler.json, which still held the earlier bypass rule. The plan then saw no lone '/**' and wrote nothing, leaving hashed chunks out of the Worker with no immutable _headers. Treat the earlier rule as '/**', and write '/**' back when the rebuild cannot use the bypass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add plugin-level cases for a route and a page under the assets folder, redirect and fallback rules, a public _redirects file, and revalidate and prerender paths under the folder. Each fails when its fact is dropped. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e Worker Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ves them Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🚀 Deploying Preview to Cloudflare 🚀Preview URL: https://fix-static-asset-cache-policy-void-cloud.voidzero-docs.workers.dev (commit 803a53b)This URL reflects your latest Preview deploymentPreview Deployments by commit
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Signed-in users never cached JS or CSS, and every static file request started the Worker. A Codiff app on Void ran into this and worked around it with a post-build script. This PR fixes it in Void.
What was wrong
The Worker also ran for every file, and for signed-in users each file cost one session read (D1).
Changes
1. Static files keep their own cache policy (all targets,
runtime/)public, …, immutableno-storeprivate, max-age=31536000, immutableno-storeprivate, no-storeno-storeASSETS(static-asset-marker.ts).next(), the response is handled like a route again (no-store).private, notpublic: user middleware may gate files on the session, so a shared cache must never keep one.2. Hashed chunks skip the Worker (native
void deploy --platform cloudflareonly)_headers/_redirects; no route, page, WebSocket, prerender or revalidate pattern that can reach the assets folder; base/; 1–99 hashed chunks; not a managed (dispatch) build./assets/*. Misses, client routes like/assets/42, and custom 404 pages still reach the Worker._headersas atext/plainmodule, as cf does. User-written_headershandling is unchanged._headersandrun_worker_firstin step. A stale generated_headersis removed.Not in this PR
cookieCacheby default (changes how quickly a revoked session stops working)Verification
asset-worker-bypass,client-asset-manifest,plugin-routingbypass wiring,cf-version-runner_headersmodule,auth-middleware(incl. swapped body),auth-isr-cache-policywith real better-auth against each fallback (incl. 304),routing-runtimemarker, Miniflare bypass test (Worker does not run),ssr-playgroundbuild output.vp run check: 33/33vp test run: 732 files, 14403 tests passed, 0 failedprivate, …and neverno-storeon files🤖 Generated with Claude Code