fix(vtex): merge headers Headers-aware so init.headers Cookie survives#53
Merged
Conversation
When a forwarder builds `init` with `headers: new Headers(...)` and
that init flows through `getVtexFetch()` (as `createVtexCheckoutProxy`
does since 1.15.0), the framework's own header-merge logic silently
dropped the cookies. The naive `{ ...authHeaders, ...init?.headers }`
spread collapses a `Headers` instance to `{}` (Headers has no own
enumerable entries), wiping the browser's full Cookie header on its
way to VTEX.
Fix: funnel all per-call header merges through a `mergeHeaders` helper
backed by the `Headers` constructor, which correctly absorbs every
`HeadersInit` shape (Headers / string[][] / Record). Apply the same
treatment to `vtexCachedFetch` and `intelligentSearch` so their
`_fetch` callsites get vtex_segment forwarding too — covering the
last gaps that previously forced sites to wrap `setVtexFetch` with
their own (often Headers-unsafe) cookie injectors.
Regression test asserts an existing `Cookie` header on a `Headers`-
typed init survives the full vtexFetchResponse path verbatim. Two
new describe blocks exercise the cached-GET and IS paths.
418/418 tests pass; typecheck clean.
Co-authored-by: Cursor <cursoragent@cursor.com>
732ebb9 to
e87bc5a
Compare
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="vtex/client.ts">
<violation number="1" location="vtex/client.ts:321">
P1: `vtexCachedFetch` now varies upstream responses by segment cookie, but cache keys still ignore that cookie. This can serve another region's cached response for the same URL.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // unsafe and clobbered the proxy's full Cookie header). Inline here | ||
| // keeps the surface small; if a third callsite appears we extract a | ||
| // shared helper. | ||
| const segmentCookie = !hasCookieHeader(init?.headers) ? getSegmentCookieHeader() : null; |
There was a problem hiding this comment.
P1: vtexCachedFetch now varies upstream responses by segment cookie, but cache keys still ignore that cookie. This can serve another region's cached response for the same URL.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vtex/client.ts, line 321:
<comment>`vtexCachedFetch` now varies upstream responses by segment cookie, but cache keys still ignore that cookie. This can serve another region's cached response for the same URL.</comment>
<file context>
@@ -282,12 +309,23 @@ export async function vtexCachedFetch<T>(
+ // unsafe and clobbered the proxy's full Cookie header). Inline here
+ // keeps the surface small; if a third callsite appears we extract a
+ // shared helper.
+ const segmentCookie = !hasCookieHeader(init?.headers) ? getSegmentCookieHeader() : null;
+
return fetchWithCache<T>(
</file context>
vibe-dex
added a commit
that referenced
this pull request
May 19, 2026
The publish-failure chain that started May 19 produced two orphan git tags (v1.15.2 and v1.15.3) without matching npm versions or GitHub Releases, so subsequent runs saw them as already-released and skipped the publish. The orphan tags are now deleted; this empty fix commit exists to land a Conventional Commit type that triggers semantic-release to attempt the publish again on the byte-identical-to-3e0ee95 config. The actual fix being released is the cookie-merge fix from PR #53. Co-authored-by: Cursor <cursoragent@cursor.com>
4 tasks
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.
Summary
Closes a latent failure mode in the framework's outbound header merging that any forwarder relying on browser-supplied cookies can trigger.
The bug
When a caller builds
init.headersas aHeadersinstance (ascreateVtexCheckoutProxydoes since 1.15.0 — routing throughgetVtexFetch()for tracing), the framework's per-call header merge silently dropped the caller's cookies:A
Headersinstance has no own enumerable entries, so the spread collapses to{}— wiping every header the caller set on the Headers object, cookies included. The downstream service receives an effectively cookieless request even though the proxy was forwarding a fully-populated browser request.Changes
vtex/client.ts— introducemergeHeaders(auth, segmentCookie, callerHeaders), backed by theHeadersconstructor, which absorbs everyHeadersInitshape (Headers,string[][],Record) correctly. Use it fromvtexFetchResponseandvtexCachedFetch.vtex/client.ts— hoistvtex_segmentcookie injection intovtexCachedFetchandintelligentSearch. Closes the gap that previously forced consumers to wrapsetVtexFetchwith their own (often Headers-unsafe) injectors. "Caller wins" precedence preserved viahasCookieHeader.vtex/__tests__/client-segment-cookie.test.ts— regression test for the Headers-init path (the exact shapecreateVtexCheckoutProxypasses), plus full describe blocks for the newvtexCachedFetchandintelligentSearchinjection paths. 12 tests covering this surface; 418/418 in the full suite.Test plan
npm test— 33 files, 418/418 passnpx tsc --noEmit— cleanRisk
Low. The refactor strictly widens what
init.headersshapes are tolerated; the new helper returns aHeadersinstance instead of a plain object, but both Workers and Node accept either asHeadersInit. The two new injection sites (vtexCachedFetch,intelligentSearch) are gated on "caller didn't supply a cookie", so they're no-ops for any callsite that already passes one explicitly.