Skip to content

Commit 8d4b254

Browse files
jorgemoyaclaude
andcommitted
feat(core): add locale parameter to client.fetch() and harden beforeRequest
Add optional locale parameter to client.fetch() for use in cached contexts. Wrap headers() call in beforeRequest with try/catch so it gracefully degrades inside unstable_cache. No changes to getChannelId or beforeRequest callback signatures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a8dd99e commit 8d4b254

4 files changed

Lines changed: 23 additions & 5 deletions

File tree

.changeset/locale-param-client.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-client": minor
3+
---
4+
5+
Add optional `locale` parameter to `client.fetch()`. This allows locale to be passed explicitly for use in cached contexts where `getLocale()` is unavailable.

.changeset/locale-param-core.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@bigcommerce/catalyst-core": minor
3+
---
4+
5+
Wrap IP forwarding headers (`X-Forwarded-For`, `True-Client-IP`) in try/catch for safety inside `unstable_cache` contexts where `headers()` is unavailable.

core/client/index.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,16 @@ export const client = createClient({
5353
const locale = await getLocale();
5454

5555
if (fetchOptions?.cache && ['no-store', 'no-cache'].includes(fetchOptions.cache)) {
56-
const { headers } = await import('next/headers');
57-
const ipAddress = (await headers()).get('X-Forwarded-For');
56+
try {
57+
const { headers } = await import('next/headers');
58+
const ipAddress = (await headers()).get('X-Forwarded-For');
5859

59-
if (ipAddress) {
60-
requestHeaders['X-Forwarded-For'] = ipAddress;
61-
requestHeaders['True-Client-IP'] = ipAddress;
60+
if (ipAddress) {
61+
requestHeaders['X-Forwarded-For'] = ipAddress;
62+
requestHeaders['True-Client-IP'] = ipAddress;
63+
}
64+
} catch {
65+
// headers() is unavailable inside unstable_cache / 'use cache' contexts
6266
}
6367
}
6468

packages/client/src/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Client<FetcherRequestInit extends RequestInit = RequestInit> {
8585
customerAccessToken?: string;
8686
fetchOptions?: FetcherRequestInit;
8787
channelId?: string;
88+
locale?: string;
8889
errorPolicy?: GraphQLErrorPolicy;
8990
validateCustomerAccessToken?: boolean;
9091
}): Promise<BigCommerceResponse<TResult>>;
@@ -96,6 +97,7 @@ class Client<FetcherRequestInit extends RequestInit = RequestInit> {
9697
customerAccessToken?: string;
9798
fetchOptions?: FetcherRequestInit;
9899
channelId?: string;
100+
locale?: string;
99101
errorPolicy?: GraphQLErrorPolicy;
100102
validateCustomerAccessToken?: boolean;
101103
}): Promise<BigCommerceResponse<TResult>>;
@@ -106,6 +108,7 @@ class Client<FetcherRequestInit extends RequestInit = RequestInit> {
106108
customerAccessToken,
107109
fetchOptions = {} as FetcherRequestInit,
108110
channelId,
111+
locale: _locale, // eslint-disable-line @typescript-eslint/no-unused-vars
109112
errorPolicy = 'none',
110113
validateCustomerAccessToken = true,
111114
}: {
@@ -114,6 +117,7 @@ class Client<FetcherRequestInit extends RequestInit = RequestInit> {
114117
customerAccessToken?: string;
115118
fetchOptions?: FetcherRequestInit;
116119
channelId?: string;
120+
locale?: string;
117121
errorPolicy?: GraphQLErrorPolicy;
118122
validateCustomerAccessToken?: boolean;
119123
}): Promise<BigCommerceResponse<TResult>> {

0 commit comments

Comments
 (0)