From df90b867e323d1a6d58152922ecfed3dd7666f42 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Thu, 9 Oct 2025 11:41:26 -0300 Subject: [PATCH 1/7] fix: restore backward compatibility for header constants - Re-export legacy `*_HEADER` named exports (e.g., TENANT_HEADER, REQUEST_ID_HEADER, etc.) as deprecated aliases of `HeaderKeys.*` - Preserves public API without a major bump while guiding migration via @deprecated JSDoc --- src/constants.ts | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/constants.ts b/src/constants.ts index 38f4c7630..cab1e5ba8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -64,6 +64,90 @@ export const AttributeKeys = { VTEX_IO_APP_AUTHOR_TYPE: ATTR_VTEX_IO_APP_AUTHOR_TYPE, } +/** @deprecated Use HeaderKeys.CACHE_CONTROL instead */ +export const CACHE_CONTROL_HEADER = HeaderKeys.CACHE_CONTROL + +/** @deprecated Use HeaderKeys.SEGMENT instead */ +export const SEGMENT_HEADER = HeaderKeys.SEGMENT + +/** @deprecated Use HeaderKeys.SESSION instead */ +export const SESSION_HEADER = HeaderKeys.SESSION + +/** @deprecated Use HeaderKeys.PRODUCT instead */ +export const PRODUCT_HEADER = HeaderKeys.PRODUCT + +/** @deprecated Use HeaderKeys.LOCALE instead */ +export const LOCALE_HEADER = HeaderKeys.LOCALE + +/** @deprecated Use HeaderKeys.FORWARDED_HOST instead */ +export const FORWARDED_HOST_HEADER = HeaderKeys.FORWARDED_HOST + +/** @deprecated Use HeaderKeys.TENANT instead */ +export const TENANT_HEADER = HeaderKeys.TENANT + +/** @deprecated Use HeaderKeys.BINDING instead */ +export const BINDING_HEADER = HeaderKeys.BINDING + +/** @deprecated Use HeaderKeys.META instead */ +export const META_HEADER = HeaderKeys.META + +/** @deprecated Use HeaderKeys.META_BUCKET instead */ +export const META_HEADER_BUCKET = HeaderKeys.META_BUCKET + +/** @deprecated Use HeaderKeys.ETAG instead */ +export const ETAG_HEADER = HeaderKeys.ETAG + +/** @deprecated Use HeaderKeys.ACCOUNT instead */ +export const ACCOUNT_HEADER = HeaderKeys.ACCOUNT + +/** @deprecated Use HeaderKeys.CREDENTIAL instead */ +export const CREDENTIAL_HEADER = HeaderKeys.CREDENTIAL + +/** @deprecated Use HeaderKeys.REQUEST_ID instead */ +export const REQUEST_ID_HEADER = HeaderKeys.REQUEST_ID + +/** @deprecated Use HeaderKeys.ROUTER_CACHE instead */ +export const ROUTER_CACHE_HEADER = HeaderKeys.ROUTER_CACHE + +/** @deprecated Use HeaderKeys.OPERATION_ID instead */ +export const OPERATION_ID_HEADER = HeaderKeys.OPERATION_ID + +/** @deprecated Use HeaderKeys.PLATFORM instead */ +export const PLATFORM_HEADER = HeaderKeys.PLATFORM + +/** @deprecated Use HeaderKeys.WORKSPACE_IS_PRODUCTION instead */ +export const WORKSPACE_IS_PRODUCTION_HEADER = HeaderKeys.WORKSPACE_IS_PRODUCTION + +/** @deprecated Use HeaderKeys.WORKSPACE instead */ +export const WORKSPACE_HEADER = HeaderKeys.WORKSPACE + +/** @deprecated Use HeaderKeys.EVENT_KEY instead */ +export const EVENT_KEY_HEADER = HeaderKeys.EVENT_KEY + +/** @deprecated Use HeaderKeys.EVENT_SENDER instead */ +export const EVENT_SENDER_HEADER = HeaderKeys.EVENT_SENDER + +/** @deprecated Use HeaderKeys.EVENT_SUBJECT instead */ +export const EVENT_SUBJECT_HEADER = HeaderKeys.EVENT_SUBJECT + +/** @deprecated Use HeaderKeys.EVENT_HANDLER_ID instead */ +export const EVENT_HANDLER_ID_HEADER = HeaderKeys.EVENT_HANDLER_ID + +/** @deprecated Use HeaderKeys.COLOSSUS_ROUTE_DECLARER instead */ +export const COLOSSUS_ROUTE_DECLARER_HEADER = HeaderKeys.COLOSSUS_ROUTE_DECLARER + +/** @deprecated Use HeaderKeys.COLOSSUS_ROUTE_ID instead */ +export const COLOSSUS_ROUTE_ID_HEADER = HeaderKeys.COLOSSUS_ROUTE_ID + +/** @deprecated Use HeaderKeys.COLOSSUS_PARAMS instead */ +export const COLOSSUS_PARAMS_HEADER = HeaderKeys.COLOSSUS_PARAMS + +/** @deprecated Use HeaderKeys.TRACE_ID instead */ +export const TRACE_ID_HEADER = HeaderKeys.TRACE_ID + +/** @deprecated Use HeaderKeys.PROVIDER instead */ +export const PROVIDER_HEADER = HeaderKeys.PROVIDER + export type VaryHeaders = typeof HeaderKeys.SEGMENT | typeof HeaderKeys.SESSION | typeof HeaderKeys.PRODUCT | typeof HeaderKeys.LOCALE export const BODY_HASH = '__graphqlBodyHash' From e19ed3fef8e894434ebfde7120cd2e1fb8c27a2e Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Thu, 9 Oct 2025 11:45:07 -0300 Subject: [PATCH 2/7] test: add back-compatible coverage for header constants - Assert deprecated `*_HEADER` exports exist and mirror `HeaderKeys.*` - Add checks for critical VTEX headers and expected string values --- src/constants.test.ts | 112 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/src/constants.test.ts b/src/constants.test.ts index 522acfb10..9a4a8c1f9 100644 --- a/src/constants.test.ts +++ b/src/constants.test.ts @@ -20,7 +20,36 @@ import { PRODUCTION, INSPECT_DEBUGGER_PORT, cancellableMethods, - LOG_CLIENT_INIT_TIMEOUT_MS + LOG_CLIENT_INIT_TIMEOUT_MS, + // Backward-compatible individual header constants + CACHE_CONTROL_HEADER, + SEGMENT_HEADER, + SESSION_HEADER, + PRODUCT_HEADER, + LOCALE_HEADER, + FORWARDED_HOST_HEADER, + TENANT_HEADER, + BINDING_HEADER, + META_HEADER, + META_HEADER_BUCKET, + ETAG_HEADER, + ACCOUNT_HEADER, + CREDENTIAL_HEADER, + REQUEST_ID_HEADER, + ROUTER_CACHE_HEADER, + OPERATION_ID_HEADER, + PLATFORM_HEADER, + WORKSPACE_IS_PRODUCTION_HEADER, + WORKSPACE_HEADER, + EVENT_KEY_HEADER, + EVENT_SENDER_HEADER, + EVENT_SUBJECT_HEADER, + EVENT_HANDLER_ID_HEADER, + COLOSSUS_ROUTE_DECLARER_HEADER, + COLOSSUS_ROUTE_ID_HEADER, + COLOSSUS_PARAMS_HEADER, + TRACE_ID_HEADER, + PROVIDER_HEADER } from './constants' describe('constants', () => { @@ -426,5 +455,86 @@ describe('constants', () => { expect(APP).toHaveProperty(prop) }) }) + + describe('Individual header constants (deprecated)', () => { + test('all individual header constants should be defined', () => { + expect(CACHE_CONTROL_HEADER).toBeDefined() + expect(SEGMENT_HEADER).toBeDefined() + expect(SESSION_HEADER).toBeDefined() + expect(PRODUCT_HEADER).toBeDefined() + expect(LOCALE_HEADER).toBeDefined() + expect(FORWARDED_HOST_HEADER).toBeDefined() + expect(TENANT_HEADER).toBeDefined() + expect(BINDING_HEADER).toBeDefined() + expect(META_HEADER).toBeDefined() + expect(META_HEADER_BUCKET).toBeDefined() + expect(ETAG_HEADER).toBeDefined() + expect(ACCOUNT_HEADER).toBeDefined() + expect(CREDENTIAL_HEADER).toBeDefined() + expect(REQUEST_ID_HEADER).toBeDefined() + expect(ROUTER_CACHE_HEADER).toBeDefined() + expect(OPERATION_ID_HEADER).toBeDefined() + expect(PLATFORM_HEADER).toBeDefined() + expect(WORKSPACE_IS_PRODUCTION_HEADER).toBeDefined() + expect(WORKSPACE_HEADER).toBeDefined() + expect(EVENT_KEY_HEADER).toBeDefined() + expect(EVENT_SENDER_HEADER).toBeDefined() + expect(EVENT_SUBJECT_HEADER).toBeDefined() + expect(EVENT_HANDLER_ID_HEADER).toBeDefined() + expect(COLOSSUS_ROUTE_DECLARER_HEADER).toBeDefined() + expect(COLOSSUS_ROUTE_ID_HEADER).toBeDefined() + expect(COLOSSUS_PARAMS_HEADER).toBeDefined() + expect(TRACE_ID_HEADER).toBeDefined() + expect(PROVIDER_HEADER).toBeDefined() + }) + + test('individual constants should equal HeaderKeys values', () => { + expect(CACHE_CONTROL_HEADER).toBe(HeaderKeys.CACHE_CONTROL) + expect(SEGMENT_HEADER).toBe(HeaderKeys.SEGMENT) + expect(SESSION_HEADER).toBe(HeaderKeys.SESSION) + expect(PRODUCT_HEADER).toBe(HeaderKeys.PRODUCT) + expect(LOCALE_HEADER).toBe(HeaderKeys.LOCALE) + expect(FORWARDED_HOST_HEADER).toBe(HeaderKeys.FORWARDED_HOST) + expect(TENANT_HEADER).toBe(HeaderKeys.TENANT) + expect(BINDING_HEADER).toBe(HeaderKeys.BINDING) + expect(META_HEADER).toBe(HeaderKeys.META) + expect(META_HEADER_BUCKET).toBe(HeaderKeys.META_BUCKET) + expect(ETAG_HEADER).toBe(HeaderKeys.ETAG) + expect(ACCOUNT_HEADER).toBe(HeaderKeys.ACCOUNT) + expect(CREDENTIAL_HEADER).toBe(HeaderKeys.CREDENTIAL) + expect(REQUEST_ID_HEADER).toBe(HeaderKeys.REQUEST_ID) + expect(ROUTER_CACHE_HEADER).toBe(HeaderKeys.ROUTER_CACHE) + expect(OPERATION_ID_HEADER).toBe(HeaderKeys.OPERATION_ID) + expect(PLATFORM_HEADER).toBe(HeaderKeys.PLATFORM) + expect(WORKSPACE_IS_PRODUCTION_HEADER).toBe(HeaderKeys.WORKSPACE_IS_PRODUCTION) + expect(WORKSPACE_HEADER).toBe(HeaderKeys.WORKSPACE) + expect(EVENT_KEY_HEADER).toBe(HeaderKeys.EVENT_KEY) + expect(EVENT_SENDER_HEADER).toBe(HeaderKeys.EVENT_SENDER) + expect(EVENT_SUBJECT_HEADER).toBe(HeaderKeys.EVENT_SUBJECT) + expect(EVENT_HANDLER_ID_HEADER).toBe(HeaderKeys.EVENT_HANDLER_ID) + expect(COLOSSUS_ROUTE_DECLARER_HEADER).toBe(HeaderKeys.COLOSSUS_ROUTE_DECLARER) + expect(COLOSSUS_ROUTE_ID_HEADER).toBe(HeaderKeys.COLOSSUS_ROUTE_ID) + expect(COLOSSUS_PARAMS_HEADER).toBe(HeaderKeys.COLOSSUS_PARAMS) + expect(TRACE_ID_HEADER).toBe(HeaderKeys.TRACE_ID) + expect(PROVIDER_HEADER).toBe(HeaderKeys.PROVIDER) + }) + + test('critical individual constants should have expected string values', () => { + expect(TENANT_HEADER).toBe('x-vtex-tenant') + expect(BINDING_HEADER).toBe('x-vtex-binding') + expect(LOCALE_HEADER).toBe('x-vtex-locale') + expect(SEGMENT_HEADER).toBe('x-vtex-segment') + expect(SESSION_HEADER).toBe('x-vtex-session') + expect(ACCOUNT_HEADER).toBe('x-vtex-account') + expect(WORKSPACE_HEADER).toBe('x-vtex-workspace') + }) + + test('individual constants should be strings', () => { + expect(typeof TENANT_HEADER).toBe('string') + expect(typeof BINDING_HEADER).toBe('string') + expect(typeof LOCALE_HEADER).toBe('string') + expect(typeof SEGMENT_HEADER).toBe('string') + }) + }) }) }) From b16aa8e44e7bd84a877f310124760b0bf42c4bea Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Thu, 9 Oct 2025 11:48:52 -0300 Subject: [PATCH 3/7] chore: bump version to 7.2.4-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c6124abb..30fdb6403 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "7.2.3", + "version": "7.2.4-beta.0", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts", From b15c7cc4fd2ab2d0e6a67bdf1183c1ecac47225a Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Mon, 13 Oct 2025 15:19:41 -0300 Subject: [PATCH 4/7] test: enhance coverage for header constants usage - Add tests to verify constants can be used as object keys without runtime errors - Ensure destructuring from module exports works correctly - Validate compatibility of constants with VaryHeaders type - Simulate realistic scenarios for header key usage in IO apps --- src/constants.test.ts | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/src/constants.test.ts b/src/constants.test.ts index 9a4a8c1f9..05e036c7c 100644 --- a/src/constants.test.ts +++ b/src/constants.test.ts @@ -535,6 +535,138 @@ describe('constants', () => { expect(typeof LOCALE_HEADER).toBe('string') expect(typeof SEGMENT_HEADER).toBe('string') }) + + test('constants can be used as object keys without runtime errors', () => { + // This is how IO apps use them in practice + const headers = { + [TENANT_HEADER]: 'example-value', + [BINDING_HEADER]: 'example-binding', + [LOCALE_HEADER]: 'en-US', + [SEGMENT_HEADER]: 'segment-token', + [SESSION_HEADER]: 'session-token', + [ACCOUNT_HEADER]: 'account-name', + [WORKSPACE_HEADER]: 'master' + } + + expect(headers['x-vtex-tenant']).toBe('example-value') + expect(headers['x-vtex-binding']).toBe('example-binding') + expect(headers['x-vtex-locale']).toBe('en-US') + expect(headers['x-vtex-segment']).toBe('segment-token') + expect(Object.keys(headers)).toHaveLength(7) + + // Verify no undefined keys were created + Object.keys(headers).forEach(key => { + expect(key).not.toBe('undefined') + expect(headers[key]).toBeDefined() + }) + }) + + test('constants can be destructured from module exports', () => { + // Simulates: import { TENANT_HEADER, BINDING_HEADER } from '@vtex/api' + const constants = require('./constants') + const { + TENANT_HEADER: tenant, + BINDING_HEADER: binding, + LOCALE_HEADER: locale, + SEGMENT_HEADER: segment + } = constants + + expect(tenant).toBeDefined() + expect(binding).toBeDefined() + expect(locale).toBeDefined() + expect(segment).toBeDefined() + + expect(tenant).toBe('x-vtex-tenant') + expect(binding).toBe('x-vtex-binding') + expect(locale).toBe('x-vtex-locale') + expect(segment).toBe('x-vtex-segment') + + // Ensure they're not undefined + expect(tenant).not.toBe(undefined) + expect(binding).not.toBe(undefined) + }) + + test('individual constants are compatible with VaryHeaders type', () => { + // VaryHeaders type uses HeaderKeys internally, but should accept old constants + const varyHeaderValues: string[] = [SEGMENT_HEADER, SESSION_HEADER, PRODUCT_HEADER, LOCALE_HEADER] + + varyHeaderValues.forEach(header => { + expect(typeof header).toBe('string') + expect(header.length).toBeGreaterThan(0) + // VTEX headers follow x-vtex- pattern, except standard headers like cache-control + expect(header).toMatch(/^x-vtex-|^cache-control$|^etag$/) + }) + + // Verify they match the type definition (HeaderKeys values) + const expectedVaryHeaders = [ + HeaderKeys.SEGMENT, + HeaderKeys.SESSION, + HeaderKeys.PRODUCT, + HeaderKeys.LOCALE + ] + + expect(varyHeaderValues).toEqual(expectedVaryHeaders) + + // Ensure VaryHeaders type inference works + expect(SEGMENT_HEADER).toBe(HeaderKeys.SEGMENT) + expect(SESSION_HEADER).toBe(HeaderKeys.SESSION) + expect(PRODUCT_HEADER).toBe(HeaderKeys.PRODUCT) + expect(LOCALE_HEADER).toBe(HeaderKeys.LOCALE) + }) + + test('constants work correctly as header keys in realistic scenarios', () => { + // Simulates IO apps usage patterns + const mockBinding = { locale: 'en-US', currency: 'USD' } + const mockTenant = { locale: 'pt-BR' } + const mockSegmentToken = 'eyJjYW1wYWlnbnMiOm51bGx9' + const mockSessionToken = 'session-abc-123' + + // Pattern 1: Building headers object + const requestHeaders = { + [BINDING_HEADER]: JSON.stringify(mockBinding), + [TENANT_HEADER]: mockTenant.locale, + [LOCALE_HEADER]: 'en-US', + [SEGMENT_HEADER]: mockSegmentToken, + [SESSION_HEADER]: mockSessionToken, + [ACCOUNT_HEADER]: 'vtexstore', + [WORKSPACE_HEADER]: 'master' + } + + expect(requestHeaders['x-vtex-binding']).toBe(JSON.stringify(mockBinding)) + expect(requestHeaders['x-vtex-tenant']).toBe('pt-BR') + expect(requestHeaders['x-vtex-locale']).toBe('en-US') + expect(requestHeaders['x-vtex-segment']).toBe(mockSegmentToken) + expect(requestHeaders['x-vtex-session']).toBe(mockSessionToken) + + // Pattern 2: Conditional header setting + const conditionalHeaders: Record = {} + if (mockSegmentToken) { + conditionalHeaders[SEGMENT_HEADER] = mockSegmentToken + } + if (mockSessionToken) { + conditionalHeaders[SESSION_HEADER] = mockSessionToken + } + + expect(conditionalHeaders['x-vtex-segment']).toBe(mockSegmentToken) + expect(conditionalHeaders['x-vtex-session']).toBe(mockSessionToken) + expect(Object.keys(conditionalHeaders)).toHaveLength(2) + + // Pattern 3: Reading from headers object + const incomingHeaders = { + 'x-vtex-tenant': 'es-AR', + 'x-vtex-binding': '{"locale":"es-AR"}', + 'x-vtex-account': 'mystore' + } + + expect(incomingHeaders[TENANT_HEADER]).toBe('es-AR') + expect(incomingHeaders[BINDING_HEADER]).toBe('{"locale":"es-AR"}') + expect(incomingHeaders[ACCOUNT_HEADER]).toBe('mystore') + + // Verify no undefined keys in any pattern + expect(TENANT_HEADER).not.toBe('undefined') + expect(BINDING_HEADER).not.toBe('undefined') + expect(SEGMENT_HEADER).not.toBe('undefined') + }) }) }) }) From b465d5996b38ef5f33f65775afd95e9d1fb9d43b Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Mon, 13 Oct 2025 18:09:19 -0300 Subject: [PATCH 5/7] test: specify type for incomingHeaders in constants tests - Update the type of incomingHeaders to Record for better type safety --- src/constants.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.test.ts b/src/constants.test.ts index 05e036c7c..c4bc3096c 100644 --- a/src/constants.test.ts +++ b/src/constants.test.ts @@ -652,7 +652,7 @@ describe('constants', () => { expect(Object.keys(conditionalHeaders)).toHaveLength(2) // Pattern 3: Reading from headers object - const incomingHeaders = { + const incomingHeaders: Record = { 'x-vtex-tenant': 'es-AR', 'x-vtex-binding': '{"locale":"es-AR"}', 'x-vtex-account': 'mystore' From dfd3369b325103f6a89bb8093a567c4680ee4aa4 Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Mon, 13 Oct 2025 18:10:11 -0300 Subject: [PATCH 6/7] ci: remove dependency on lint job for test execution --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42ff68521..f28d7dcb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,6 @@ jobs: - run: yarn run lint test: - needs: [lint] runs-on: ${{ matrix.os }} strategy: fail-fast: true From bb4d8b702dc1dc3acf03e7bcf1667da5bd9ad09e Mon Sep 17 00:00:00 2001 From: Daniyel Rocha Date: Wed, 15 Oct 2025 10:34:52 -0300 Subject: [PATCH 7/7] chore: release v7.2.4 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b030f81..9e5a8727f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [7.2.4] - 2025-10-15 +### Fix +- Restores backward compatibility for individual header constant exports + ## [7.2.3] - 2025-10-08 ### Fix - Separate console and diagnostics client logging formats diff --git a/package.json b/package.json index 30fdb6403..e16f675ab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vtex/api", - "version": "7.2.4-beta.0", + "version": "7.2.4", "description": "VTEX I/O API client", "main": "lib/index.js", "typings": "lib/index.d.ts",