diff --git a/src/sdk/workerEntry.ts b/src/sdk/workerEntry.ts index d9df220a..ccc44369 100644 --- a/src/sdk/workerEntry.ts +++ b/src/sdk/workerEntry.ts @@ -662,7 +662,7 @@ export function createDecoWorkerEntry( admin, detectProfile: customDetect, deviceSpecificKeys = true, - buildSegment, + buildSegment: rawBuildSegment, purgeTokenEnv = "PURGE_TOKEN", bypassPaths, extraBypassPaths = [], @@ -678,6 +678,31 @@ export function createDecoWorkerEntry( cdnCacheControl: cdnCacheControlOpt = "no-store", } = options; + // Backfill `regionId` from Cloudflare geo when the consumer's buildSegment + // doesn't set one. Without this, sites using website/matchers/location.ts + // get a single cached response per device that leaks across regions: the + // first visitor's resolved variant gets served to everyone. With this, + // existing sites get region-segmented cache "for free" on bump — no + // worker-entry.ts edit required. + function readRegionFromRequest(request: Request): string | undefined { + // Trust the Cloudflare-injected `request.cf` first — it can't be spoofed + // by clients. Fall back to the `cf-region-code` header for environments + // that surface geo only via headers (e.g. tests, non-CF proxies). + const cf = (request as unknown as { cf?: { regionCode?: string } }).cf; + if (cf?.regionCode) return cf.regionCode; + const fromHeader = request.headers.get("cf-region-code"); + return fromHeader || undefined; + } + + const buildSegment = rawBuildSegment + ? (request: Request): SegmentKey => { + const seg = rawBuildSegment(request); + if (seg.regionId) return seg; + const region = readRegionFromRequest(request); + return region ? { ...seg, regionId: region } : seg; + } + : undefined; + const safeCookieSet = new Set(safeCookiesOpt); // Build the final security headers map (merged defaults + custom + CSP)