Skip to content

feat(workerEntry): backfill regionId in segment from cf-region-code - #210

Merged
JonasJesus42 merged 2 commits into
mainfrom
feat/worker-entry-auto-region-segment
Jun 1, 2026
Merged

feat(workerEntry): backfill regionId in segment from cf-region-code#210
JonasJesus42 merged 2 commits into
mainfrom
feat/worker-entry-auto-region-segment

Conversation

@JonasJesus42

@JonasJesus42 JonasJesus42 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #209. Makes the location-matcher fix work for existing storefronts without any worker-entry edit — they only need to bump the package.

Today, after #209 merged, sites still hit a cache contamination bug:

  1. Visitor in RJ opens / → matcher resolves the RJ variant correctly → response cached with key desktop
  2. Visitor in SP opens / → cache HIT on same desktop key → receives the RJ variant
  3. No one in SP sees the right variant until TTL expires

The matcher is correct, but the cache key doesn't include region. To fix that today, every storefront has to edit src/worker-entry.ts:

 buildSegment: (request) => {
   const vtx = extractVtexContext(request);
+  const cf = (request as unknown as { cf?: { regionCode?: string } }).cf;
+  const geoRegion = request.headers.get("cf-region-code") ?? cf?.regionCode ?? "";
   return {
     device: ...,
     ...
-    regionId: (vtx as any).regionId ?? undefined,
+    regionId: (vtx as any).regionId ?? (geoRegion || undefined),
   };
 },

That's friction at every storefront. This PR moves the backfill into createDecoWorkerEntry so the bump alone is enough.

Change

createDecoWorkerEntry now wraps the consumer's buildSegment. If the returned segment is missing regionId, the framework injects it from cf-region-code (header first, then request.cf).

const buildSegment = rawBuildSegment
  ? (request) => {
      const seg = rawBuildSegment(request);
      if (seg.regionId) return seg;
      const region = readRegionFromRequest(request);
      return region ? { ...seg, regionId: region } : seg;
    }
  : undefined;

Compatibility

  • Sites that set regionId explicitly (e.g. VTEX regionalization) → unchanged. Wrapper is a no-op when seg.regionId is truthy.
  • Sites that don't pass buildSegment at all → unchanged. Backfill only applies when the consumer opted in to segmentation.
  • Sites that previously returned regionId: undefined → now get it from CF. The cache key gains a r=<region> segment. One-time cache miss spike on first deploy after the bump, then stable.

Why split from #209

#209 was the matcher logic + migration template default. This is a separate, narrowly-scoped runtime change to workerEntry. Keeping it separate makes it easier to revert if any site sees an unexpected regression.

Test plan

Refs #209

🤖 Generated with Claude Code


Summary by cubic

Automatically backfills segment.regionId from Cloudflare geo inside createDecoWorkerEntry, preferring request.cf.regionCode and falling back to cf-region-code. Cache keys become region-aware without editing storefront worker-entry.ts, preventing cross-region cache contamination. Bumping @decocms/start is enough.

  • Bug Fixes
    • Wraps consumer buildSegment; if regionId is missing, sets it from request.cf.regionCode first, then cf-region-code header.
    • No-op when regionId is already set or when no buildSegment is provided.
    • One-time cache miss spike expected as the key now includes region.

Written for commit 044724c. Summary will update on new commits.

Review in cubic

Follow-up to #209. Without this, existing sites still need a manual
edit to their worker-entry.ts's buildSegment to include
`regionId: cf-region-code` — otherwise the cache key stays
region-agnostic and a RJ-cached response gets served to SP visitors,
defeating the matcher fix.

createDecoWorkerEntry now wraps the consumer's buildSegment so that,
if the returned segment doesn't include regionId, the framework
backfills it from `cf-region-code` (header preferred, then
`request.cf`). Sites that already set regionId explicitly (e.g. via
VTEX regionalization) are unaffected — the wrapper is a no-op when
seg.regionId is truthy. Sites without buildSegment also unaffected.

Net effect: bumping @decocms/start to this release is enough to make
the website/matchers/location.ts matcher work end-to-end. No
worker-entry.ts edit required for existing storefronts.

The bump does invalidate existing cache entries on first deploy (cache
key now includes r=<region>), but that's a one-time miss spike, not a
correctness issue.
@JonasJesus42
JonasJesus42 requested a review from a team June 1, 2026 17:25

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/sdk/workerEntry.ts Outdated
…ader

Addresses cubic P1 (confidence 6) on PR #210 — defense in depth against
cache-key spoofing. CF strips inbound cf-* headers in standard
deployments, so this is only exploitable behind a custom proxy, but
reading request.cf first removes the concern entirely.

Header stays as a fallback for environments without a populated cf
object (tests, non-CF proxies).
@JonasJesus42
JonasJesus42 merged commit d59eb7e into main Jun 1, 2026
1 check passed
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 6.4.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant