Skip to content

fix(vtex): merge headers Headers-aware so init.headers Cookie survives#53

Merged
vibe-dex merged 1 commit into
mainfrom
fix/headers-aware-cookie-merge
May 19, 2026
Merged

fix(vtex): merge headers Headers-aware so init.headers Cookie survives#53
vibe-dex merged 1 commit into
mainfrom
fix/headers-aware-cookie-merge

Conversation

@vibe-dex
Copy link
Copy Markdown
Contributor

@vibe-dex vibe-dex commented May 19, 2026

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.headers as a Headers instance (as createVtexCheckoutProxy does since 1.15.0 — routing through getVtexFetch() for tracing), the framework's per-call header merge silently dropped the caller's cookies:

headers: {
  ...authHeaders(),
  ...(segmentCookie ? { cookie: segmentCookie } : {}),
  ...init?.headers,   // ← `new Headers({...})` spreads to `{}`
}

A Headers instance 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 — introduce mergeHeaders(auth, segmentCookie, callerHeaders), backed by the Headers constructor, which absorbs every HeadersInit shape (Headers, string[][], Record) correctly. Use it from vtexFetchResponse and vtexCachedFetch.
  • vtex/client.ts — hoist vtex_segment cookie injection into vtexCachedFetch and intelligentSearch. Closes the gap that previously forced consumers to wrap setVtexFetch with their own (often Headers-unsafe) injectors. "Caller wins" precedence preserved via hasCookieHeader.
  • vtex/__tests__/client-segment-cookie.test.ts — regression test for the Headers-init path (the exact shape createVtexCheckoutProxy passes), plus full describe blocks for the new vtexCachedFetch and intelligentSearch injection paths. 12 tests covering this surface; 418/418 in the full suite.

Test plan

  • npm test — 33 files, 418/418 pass
  • npx tsc --noEmit — clean

Risk

Low. The refactor strictly widens what init.headers shapes are tolerated; the new helper returns a Headers instance instead of a plain object, but both Workers and Node accept either as HeadersInit. 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.

@vibe-dex vibe-dex requested a review from a team May 19, 2026 20:50
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>
@vibe-dex vibe-dex force-pushed the fix/headers-aware-cookie-merge branch from 732ebb9 to e87bc5a Compare May 19, 2026 20:53
@vibe-dex vibe-dex merged commit c80e5ad into main May 19, 2026
1 check passed
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

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

Comment thread vtex/client.ts
// 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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>
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