Skip to content

fix(cloudflare): verify Worker version IDs during CDN warmup - #3072

Merged
james-elicx merged 9 commits into
codex/rsc-prewarm-promotion-delay-rangefrom
codex/rsc-prewarm-revalidate-stale-builds
Aug 24, 2026
Merged

fix(cloudflare): verify Worker version IDs during CDN warmup#3072
james-elicx merged 9 commits into
codex/rsc-prewarm-promotion-delay-rangefrom
codex/rsc-prewarm-revalidate-stale-builds

Conversation

@james-elicx

@james-elicx james-elicx commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

  • keep initial and retried CDN warm requests browser-cache-identical; retries do not add Cache-Control: no-cache or Pragma: no-cache
  • send a vinext-owned X-Vinext-Expected-Worker-Version assertion alongside Cloudflare's version override during staged warmup
  • add a provider-neutral CdnCacheAdapter.validateRequest(request) hook which App and Pages Worker entries invoke before application routing
  • make the Cloudflare adapter compare the vinext assertion with the executing Worker's version metadata binding
  • return a non-cacheable HTTP 503 when the expected and executing versions differ or the configured metadata binding is missing, allowing the warmup retry flow to retry without populating cache
  • ignore ordinary/downstream-only Cloudflare-Workers-Version-Overrides dictionaries that do not carry vinext's assertion
  • make warmup fail closed by default and remove --warm-cdn-strict
  • add --dangerously-promote-on-cdn-warm-error as the explicit escape hatch which may promote after failed staged readiness/warmup and retry unresolved paths after promotion
  • default the metadata binding to CF_VERSION_METADATA, customizable with cdnAdapter({ versionMetadataBinding: "CUSTOM_VERSION" })
  • scaffold and repair the top-level version_metadata during vinext init --platform=cloudflare, preserving custom binding names; Wrangler named environments remain user-managed and must repeat this non-inheritable binding
  • retain deferred retries, retry progress, readiness controls, promotion controls, and browser-identical canonical warm requests

Runtime flow

  1. The deploy command sends Cloudflare-Workers-Version-Overrides and X-Vinext-Expected-Worker-Version with the uploaded version ID.
  2. Core passes the untouched request to the configured CDN adapter without interpreting provider headers or bindings.
  3. The Cloudflare adapter compares the expected version with env[versionMetadataBinding].id.
  4. A mismatch returns 503 with Cache-Control: no-store, preventing the wrong Worker invocation from rendering or populating cache.
  5. The warmer retries the same canonical URL with the same request headers.
  6. Without the dangerous escape hatch, any unverifiable readiness or failed warm request leaves the uploaded version staged instead of promoting it.

Ordinary requests and version-override dictionaries intended only for downstream Workers are unaffected.

Configuration

Default init output:

"version_metadata": { "binding": "CF_VERSION_METADATA" }

Custom binding:

cdnAdapter({ versionMetadataBinding: "CUSTOM_VERSION" })
"version_metadata": { "binding": "CUSTOM_VERSION" }

Wrangler does not inherit version_metadata into named environments. Repeat the same binding under every env.<name> used for CDN warmup.

Dangerous fallback:

vinext-cloudflare deploy --experimental-warm-cdn-cache --dangerously-promote-on-cdn-warm-error

Regression coverage

  • matching/mismatched version assertions and missing metadata bindings
  • downstream-only override dictionaries continue normally
  • vinext assertions without Cloudflare overrides fail closed
  • default partial warmup failure does not promote
  • dangerous readiness failure promotes and retries after promotion
  • App and Pages Worker entries validate after adapter registration and before routing
  • init generation, repair, custom binding alignment, and idempotency
  • 4,528-request retry regression keeps initial and retry request headers identical
  • deployed Cloudflare E2E checks downstream-only override handling, mismatch rejection, and prewarmed HTML/RSC browser reuse

Validation

  • 635 focused adapter, warmup, deploy, cache, and init tests passed
  • vp check passed with no formatting, lint, or type errors
  • vp run vinext#build
  • vp run @vinext/cloudflare#build
  • vp run workers-cache#build; emitted Worker contains the version assertion validator and version metadata binding

This is Cloudflare deployment and cache orchestration; there is no equivalent Next.js behavior to port.

Stacked on #3057.

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3072
npm i https://pkg.pr.new/create-vinext-app@3072
npm i https://pkg.pr.new/@vinext/types@3072
npm i https://pkg.pr.new/vinext@3072

commit: b9ed953

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared b9ed953 against base 59d7cb2 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 1 regressed · 5 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 142.2 KB 142.3 KB ⚫ +0.1%
Client entry size (gzip) vinext 129.5 KB 129.5 KB ⚫ +0.1%
Dev server cold start vinext 3.08 s 3.17 s 🔴 +2.9%
Production build time vinext 3.34 s 3.35 s ⚫ +0.4%
RSC entry closure size (gzip) vinext 116.1 KB 116.2 KB ⚫ +0.0%
Server bundle size (gzip) vinext 197.7 KB 197.7 KB ⚫ -0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@github-actions

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
workers-cache preview production
web preview production

@james-elicx james-elicx changed the title fix(cloudflare): revalidate stale CDN warmup retries fix(cloudflare): validate staged CDN warmup routing Aug 24, 2026
@james-elicx james-elicx changed the title fix(cloudflare): validate staged CDN warmup routing fix(cloudflare): verify Worker version IDs during CDN warmup Aug 24, 2026
@james-elicx
james-elicx marked this pull request as ready for review August 24, 2026 21:32
@james-elicx
james-elicx marked this pull request as draft August 24, 2026 21:33
@james-elicx
james-elicx marked this pull request as ready for review August 24, 2026 21:37
@james-elicx
james-elicx marked this pull request as draft August 24, 2026 22:02
stack merge was automatically disabled August 24, 2026 22:02

Pull request was converted to draft

@james-elicx
james-elicx marked this pull request as ready for review August 24, 2026 22:02
@james-elicx
james-elicx merged commit 4146d69 into main Aug 24, 2026
82 of 83 checks passed
@james-elicx
james-elicx deleted the codex/rsc-prewarm-revalidate-stale-builds branch August 24, 2026 22:03
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.

1 participant