@doswiftly/storefront-sdk 22.4.0 → 22.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 22.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3d5f1d3: Public reads now use the cacheable `GET` transport **by default** — you no longer opt in per query with `cacheLong()`. A non-mutation query that carries a persisted-document id and no signed-in identity is sent as a shared, credential-less `GET` so a CDN can cache it; a request carrying an `Authorization` bearer or a cart secret automatically stays on `POST` with credentials, so personalised reads are never shared. The server decides whether a result is actually cacheable via its `Cache-Control` response — the client only chooses the transport. Opt a specific persisted read out of the shared cache with `cachePrivate()` or `cacheNone()` (forces `POST`). Mutations and any request without a document id keep the existing `POST` behaviour, so current behaviour is unchanged until document ids are present.
8
+
9
+ ```ts
10
+ // Cacheable GET automatically (anonymous visitor) — no cacheLong() needed:
11
+ const products = await client.query(ProductsQuery, { first: 20 });
12
+
13
+ // Keep a persisted read per-user (forces POST):
14
+ const account = await client.query(MyAccountQuery, {}, cachePrivate());
15
+ ```
16
+
17
+ - 7664b81: Added a ready GraphQL codegen recipe for edge-cacheable reads. Import `createCodegenConfig` from `@doswiftly/storefront-operations/codegen` and `export default` it from your `codegen.ts` — it points the client preset at the bundled schema and emits persisted documents whose `documentId` matches the Storefront API's `sha256:<hex>` contract, so public reads resolve server-side and can be cached at the edge.
18
+
19
+ You write operations with the generated `gql(...)` tag. They compile to lightweight typed strings (no `graphql` package at runtime) that the SDK's `query` / `mutate` accept directly, custom scalars are mapped to precision-safe TypeScript types (money and 64-bit integers as strings), and fragment fields are read directly with no unmasking helper. If your project already imports a `gql` from another GraphQL client, override the tag name: `createCodegenConfig({ gqlTagName: 'graphql' })`. Requires `@graphql-codegen/cli`, `@graphql-codegen/client-preset@^4` and `graphql@^16` as devDependencies (the preset doesn't support `graphql` v17 yet — fragment operations fail to generate). See the README "Edge-cacheable reads" section. `@doswiftly/storefront-sdk` accepts these generated documents directly in `query` / `mutate`, and its cacheable `GET` transport degrades to a `POST` on any non-success response.
20
+
21
+ Author operations with the generated tag — codegen emits each as a typed document carrying its `documentId`:
22
+
23
+ ```ts
24
+ import { gql } from "./gql";
25
+
26
+ export const ProductsQuery = gql(`
27
+ query Products($first: Int) {
28
+ products(first: $first) {
29
+ nodes { id handle title }
30
+ }
31
+ }
32
+ `);
33
+ ```
34
+
3
35
  ## 22.4.0
4
36
 
5
37
  ### Minor Changes
package/README.md CHANGED
@@ -1122,6 +1122,28 @@ cacheCustom({ maxAge: 300, swr: 600 }) // 5min + 10min swr
1122
1122
  const data = await client.query(ProductQuery, { handle }, cacheLong());
1123
1123
  ```
1124
1124
 
1125
+ ### Edge caching is the default for public reads
1126
+
1127
+ When an operation is generated with a persisted-document id (the recipe in
1128
+ `@doswiftly/storefront-operations` does this), a non-mutation read with no
1129
+ signed-in identity is sent as a **cacheable `GET`** automatically — you do not
1130
+ need to pass `cacheLong()`. A shared CDN can then serve it, and the server
1131
+ decides whether the result is actually cacheable via its `Cache-Control`
1132
+ response. Requests carrying an identity (an `Authorization` bearer or a cart
1133
+ secret) stay on `POST` with credentials, so personalised reads are never shared.
1134
+
1135
+ The cache strategies above are now **tuning / opt-out** rather than the on
1136
+ switch: pass `cachePrivate()` or `cacheNone()` to keep a persisted read per-user
1137
+ (forces `POST`), or `cacheLong({ tags })` to attach Next.js revalidation tags.
1138
+
1139
+ ```typescript
1140
+ // Cacheable GET automatically — no strategy argument needed:
1141
+ const products = await client.query(ProductsQuery, { first: 20 });
1142
+
1143
+ // Keep a persisted read per-user (forces POST):
1144
+ const account = await client.query(MyAccountQuery, {}, cachePrivate());
1145
+ ```
1146
+
1125
1147
  ## GraphQL schema for codegen
1126
1148
 
1127
1149
  The GraphQL SDL ships in the linked `@doswiftly/storefront-operations` package
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cacheable-public-read eligibility — the platform-default rule deciding whether
3
+ * a query may travel over the shared, credential-less cacheable GET transport
4
+ * instead of POST. No per-query `cacheLong()` opt-in is required: a non-mutation
5
+ * persisted read with no identity is eligible by default.
6
+ *
7
+ * Mirror of the backend storefront-cache header SSOT
8
+ * (`commerce/storefront-graphql/cache/cache-headers.ts`). The published SDK
9
+ * cannot import the private backend, so the contract is duplicated here
10
+ * intentionally — the same rationale as `LANGUAGE_HEADER_NAME`. A drift test
11
+ * (`cache-eligibility.drift.test.ts`, run against the backend source) keeps the
12
+ * two in sync:
13
+ * - {@link IDENTITY_HEADERS} must be a **superset** of the backend's (missing one
14
+ * → the SDK sends a credential-less GET that strips the identity → wrong data).
15
+ * - {@link VARIANCE_AXIS_HEADERS} must **equal** the backend's (a missing axis
16
+ * collapses two shops / currencies / languages onto one shared edge entry →
17
+ * cross-tenant / wrong-variant leak; an extra axis fragments the cache).
18
+ *
19
+ * The SDK does NOT classify operations as cacheable (PUBLIC_READ vs USER_SCOPED) —
20
+ * that stays the backend's sole authority. It resolves the documentId, classifies
21
+ * the operation fail-closed and emits `Cache-Control: public|private`; the SDK
22
+ * only chooses the *transport*. Do NOT add a PUBLIC_READ allow-list here — it
23
+ * would duplicate the backend registry and drift.
24
+ *
25
+ * Identity manifests as a header by the time a request reaches the transport:
26
+ * `authMiddleware` adds `Authorization` whenever a customer is signed in (the
27
+ * token lives in memory, seeded server-side or rehydrated client-side), and
28
+ * `cartSecretMiddleware` adds `x-cart-secret`. The backend's additional
29
+ * cookie / `@inContext` identity checks are upstream signals the SDK has already
30
+ * converted to one of these headers — so the header gate is sufficient.
31
+ */
32
+ import type { GraphQLRequest } from './types';
33
+ /** Shop-routing header the client always sends; also a cache variance axis. */
34
+ export declare const SHOP_SLUG_HEADER = "X-Shop-Slug";
35
+ /**
36
+ * Header-level identity signals. Their presence keeps a request on POST (with
37
+ * credentials) instead of the shared cacheable GET. Mirror of backend
38
+ * `IDENTITY_HEADERS`; compared case-insensitively.
39
+ */
40
+ export declare const IDENTITY_HEADERS: readonly ["authorization", "x-cart-secret"];
41
+ /**
42
+ * Cache variance axes as `[requestHeaderName, getUrlParam]`. The backend keys its
43
+ * L1 cache on the resolved `{tenant, currency, language}`; the SDK copies the same
44
+ * axes into the GET URL so a shared edge cache keys correctly (it keys on the URL,
45
+ * not on request headers). Consumed by `buildTrustedGetRequest`.
46
+ */
47
+ export declare const VARIANCE_AXIS_PARAMS: readonly [readonly ["X-Shop-Slug", "__shop"], readonly ["X-Preferred-Currency", "__currency"], readonly ["X-Language", "__language"]];
48
+ /**
49
+ * Lowercase variance header names — the contract compared against the backend
50
+ * `VARIANCE_HEADERS` SSOT by the drift test. Derived from {@link VARIANCE_AXIS_PARAMS}
51
+ * so there is one list in the SDK.
52
+ */
53
+ export declare const VARIANCE_AXIS_HEADERS: readonly string[];
54
+ /**
55
+ * Whether a request may use the cacheable GET transport (transport safety only —
56
+ * the backend decides actual cacheability via `Cache-Control`). Eligible when it
57
+ * is a non-mutation persisted read carrying no identity. The explicit cache
58
+ * opt-outs (`cachePrivate()` / `cacheNone()`) are applied by the caller.
59
+ */
60
+ export declare function isPublicReadEligible(request: GraphQLRequest): boolean;
61
+ //# sourceMappingURL=cache-eligibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-eligibility.d.ts","sourceRoot":"","sources":["../../../src/core/client/cache-eligibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAI9C,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6CAA8C,CAAC;AAE5E;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,uIAIvB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAElD,CAAC;AAYF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAIrE"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Cacheable-public-read eligibility — the platform-default rule deciding whether
3
+ * a query may travel over the shared, credential-less cacheable GET transport
4
+ * instead of POST. No per-query `cacheLong()` opt-in is required: a non-mutation
5
+ * persisted read with no identity is eligible by default.
6
+ *
7
+ * Mirror of the backend storefront-cache header SSOT
8
+ * (`commerce/storefront-graphql/cache/cache-headers.ts`). The published SDK
9
+ * cannot import the private backend, so the contract is duplicated here
10
+ * intentionally — the same rationale as `LANGUAGE_HEADER_NAME`. A drift test
11
+ * (`cache-eligibility.drift.test.ts`, run against the backend source) keeps the
12
+ * two in sync:
13
+ * - {@link IDENTITY_HEADERS} must be a **superset** of the backend's (missing one
14
+ * → the SDK sends a credential-less GET that strips the identity → wrong data).
15
+ * - {@link VARIANCE_AXIS_HEADERS} must **equal** the backend's (a missing axis
16
+ * collapses two shops / currencies / languages onto one shared edge entry →
17
+ * cross-tenant / wrong-variant leak; an extra axis fragments the cache).
18
+ *
19
+ * The SDK does NOT classify operations as cacheable (PUBLIC_READ vs USER_SCOPED) —
20
+ * that stays the backend's sole authority. It resolves the documentId, classifies
21
+ * the operation fail-closed and emits `Cache-Control: public|private`; the SDK
22
+ * only chooses the *transport*. Do NOT add a PUBLIC_READ allow-list here — it
23
+ * would duplicate the backend registry and drift.
24
+ *
25
+ * Identity manifests as a header by the time a request reaches the transport:
26
+ * `authMiddleware` adds `Authorization` whenever a customer is signed in (the
27
+ * token lives in memory, seeded server-side or rehydrated client-side), and
28
+ * `cartSecretMiddleware` adds `x-cart-secret`. The backend's additional
29
+ * cookie / `@inContext` identity checks are upstream signals the SDK has already
30
+ * converted to one of these headers — so the header gate is sufficient.
31
+ */
32
+ import { CURRENCY_HEADER_NAME } from '../currency/cookie-config';
33
+ import { LANGUAGE_HEADER_NAME } from '../language/cookie-config';
34
+ /** Shop-routing header the client always sends; also a cache variance axis. */
35
+ export const SHOP_SLUG_HEADER = 'X-Shop-Slug';
36
+ /**
37
+ * Header-level identity signals. Their presence keeps a request on POST (with
38
+ * credentials) instead of the shared cacheable GET. Mirror of backend
39
+ * `IDENTITY_HEADERS`; compared case-insensitively.
40
+ */
41
+ export const IDENTITY_HEADERS = ['authorization', 'x-cart-secret'];
42
+ /**
43
+ * Cache variance axes as `[requestHeaderName, getUrlParam]`. The backend keys its
44
+ * L1 cache on the resolved `{tenant, currency, language}`; the SDK copies the same
45
+ * axes into the GET URL so a shared edge cache keys correctly (it keys on the URL,
46
+ * not on request headers). Consumed by `buildTrustedGetRequest`.
47
+ */
48
+ export const VARIANCE_AXIS_PARAMS = [
49
+ [SHOP_SLUG_HEADER, '__shop'],
50
+ [CURRENCY_HEADER_NAME, '__currency'],
51
+ [LANGUAGE_HEADER_NAME, '__language'],
52
+ ];
53
+ /**
54
+ * Lowercase variance header names — the contract compared against the backend
55
+ * `VARIANCE_HEADERS` SSOT by the drift test. Derived from {@link VARIANCE_AXIS_PARAMS}
56
+ * so there is one list in the SDK.
57
+ */
58
+ export const VARIANCE_AXIS_HEADERS = VARIANCE_AXIS_PARAMS.map(([header]) => header.toLowerCase());
59
+ const IDENTITY_HEADER_SET = new Set(IDENTITY_HEADERS);
60
+ /** True when any identity header is present (case-insensitive). */
61
+ function hasIdentityHeader(headers) {
62
+ for (const [name, value] of Object.entries(headers)) {
63
+ if (value && IDENTITY_HEADER_SET.has(name.toLowerCase()))
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ /**
69
+ * Whether a request may use the cacheable GET transport (transport safety only —
70
+ * the backend decides actual cacheability via `Cache-Control`). Eligible when it
71
+ * is a non-mutation persisted read carrying no identity. The explicit cache
72
+ * opt-outs (`cachePrivate()` / `cacheNone()`) are applied by the caller.
73
+ */
74
+ export function isPublicReadEligible(request) {
75
+ if (request.isMutation)
76
+ return false;
77
+ if (typeof request.documentId !== 'string' || request.documentId.length === 0)
78
+ return false;
79
+ return !hasIdentityHeader(request.headers);
80
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"create-client.d.ts","sourceRoot":"","sources":["../../../src/core/client/create-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAKjB,MAAM,SAAS,CAAC;AAQjB,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CA0HvF"}
1
+ {"version":3,"file":"create-client.d.ts","sourceRoot":"","sources":["../../../src/core/client/create-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAKjB,MAAM,SAAS,CAAC;AAQjB,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CAmIvF"}
@@ -47,17 +47,30 @@ export function createStorefrontClient(config) {
47
47
  return compiledPipeline;
48
48
  }
49
49
  /**
50
- * Resolve query string from TypedDocumentString or plain string.
50
+ * Resolve query string from a typed document or plain string.
51
51
  */
52
52
  function resolveQuery(document) {
53
53
  return typeof document === 'string' ? document : document.toString();
54
54
  }
55
55
  /**
56
- * Persisted-document id carried by codegen on `TypedDocumentString.__meta__.hash`.
56
+ * Persisted-document id carried by codegen on `__meta__.hash`.
57
57
  * Plain strings (and documents without a populated hash) have none → POST transport.
58
+ *
59
+ * `__meta__` is optional codegen metadata, not part of the public document
60
+ * contract (`TypedDocumentLike`), so it is read defensively via narrowing — no
61
+ * cast, no assumption that any given document carries it.
58
62
  */
59
63
  function resolveDocumentId(document) {
60
- return typeof document === 'string' ? undefined : document.__meta__?.hash;
64
+ if (typeof document === 'string')
65
+ return undefined;
66
+ if (!('__meta__' in document))
67
+ return undefined;
68
+ const meta = document.__meta__;
69
+ if (typeof meta !== 'object' || meta === null)
70
+ return undefined;
71
+ if (!('hash' in meta) || typeof meta.hash !== 'string')
72
+ return undefined;
73
+ return meta.hash;
61
74
  }
62
75
  /**
63
76
  * Core request execution — shared by query() and mutate().
@@ -1 +1 @@
1
- {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/core/client/execute.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EAEZ,cAAc,EACd,eAAe,EAChB,MAAM,SAAS,CAAC;AAIjB,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC/B;;;;OAIG;IACH,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAClC;AAsCD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,GACpD,oBAAoB,GAAG,IAAI,CAiB7B;AA4KD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,IAGnB,SAAS,cAAc,KAAG,OAAO,CAAC,eAAe,CAAC,CAwEjF"}
1
+ {"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/core/client/execute.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EAEZ,cAAc,EACd,eAAe,EAChB,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC/B;;;;OAIG;IACH,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAClC;AAsCD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,GACpD,oBAAoB,GAAG,IAAI,CAiB7B;AAqKD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,IAGnB,SAAS,cAAc,KAAG,OAAO,CAAC,eAAe,CAAC,CAqFjF"}
@@ -4,8 +4,7 @@
4
4
  * Sends GraphQL POST request, parses response, returns typed GraphQLResponse.
5
5
  * Error normalization is handled by error middleware, NOT here.
6
6
  */
7
- import { CURRENCY_HEADER_NAME } from '../currency/cookie-config';
8
- import { LANGUAGE_HEADER_NAME } from '../language/cookie-config';
7
+ import { isPublicReadEligible, VARIANCE_AXIS_PARAMS } from './cache-eligibility';
9
8
  const DEFAULT_LOG = (event) => {
10
9
  // Header on a separate line so the data dump below renders untruncated in
11
10
  // both terminals and DevTools.
@@ -153,21 +152,6 @@ function extractUserErrors(data) {
153
152
  }
154
153
  return flat;
155
154
  }
156
- /** Backend signal that a `documentId` is not in the allowlist → replay as POST. */
157
- const TRUSTED_DOC_NOT_FOUND = 'TRUSTED_DOCUMENT_NOT_FOUND';
158
- /** Shop-routing header the client always sends; lifted into the GET cache key below. */
159
- const SHOP_SLUG_HEADER = 'X-Shop-Slug';
160
- /**
161
- * Variance axes mirrored from request headers into the GET query string. A shared
162
- * edge cache keys on the URL, not on request headers — without these in the URL two
163
- * shops / currencies / languages would collide on one cache entry. The backend still
164
- * reads the values from the headers; the URL copy exists only to split the cache key.
165
- */
166
- const AXIS_URL_PARAMS = [
167
- [SHOP_SLUG_HEADER, '__shop'],
168
- [CURRENCY_HEADER_NAME, '__currency'],
169
- [LANGUAGE_HEADER_NAME, '__language'],
170
- ];
171
155
  /**
172
156
  * Default POST transport — the full query travels in the body and cookies are sent.
173
157
  * Every request that is not a cacheable public read uses this (unchanged contract).
@@ -215,16 +199,28 @@ function buildTrustedGetRequest(endpoint, request) {
215
199
  if (request.variables && Object.keys(request.variables).length > 0) {
216
200
  url.searchParams.set('variables', JSON.stringify(request.variables));
217
201
  }
218
- for (const [headerName, param] of AXIS_URL_PARAMS) {
219
- const value = request.headers[headerName];
202
+ // Case-insensitive lookup for the variance axes: request header casing is not guaranteed
203
+ // (middleware/proxies may normalise), and the identity gate is already case-insensitive.
204
+ // A casing mismatch here would drop an axis from the URL — and the shared edge keys on the
205
+ // URL only, so two shops/currencies/languages would collapse onto one entry (cross-tenant /
206
+ // wrong-variant leak). Build one lowercased view, then look up each axis by lowercase name.
207
+ const lowerHeaders = {};
208
+ for (const [name, value] of Object.entries(request.headers))
209
+ lowerHeaders[name.toLowerCase()] = value;
210
+ for (const [headerName, param] of VARIANCE_AXIS_PARAMS) {
211
+ const value = lowerHeaders[headerName.toLowerCase()];
220
212
  if (value)
221
213
  url.searchParams.set(param, value);
222
214
  }
223
215
  const headers = { ...request.headers };
224
- // Public read = customer-agnostic → never carry the bearer token (`omit` also drops
225
- // cookies), so the cached response can be served to any visitor.
216
+ // Public read = customer-agnostic → the GET must carry NO credentials, so the cached
217
+ // response can be served to any visitor. `credentials: 'omit'` drops the browser cookie jar,
218
+ // but NOT an explicitly-set Cookie header (e.g. forwarded on SSR) — strip it (and the bearer
219
+ // token) by hand so the request is truly credential-less and can never personalise the body.
226
220
  delete headers.Authorization;
227
221
  delete headers.authorization;
222
+ delete headers.Cookie;
223
+ delete headers.cookie;
228
224
  headers.Accept = 'application/json';
229
225
  // Force a CORS preflight so the backend CSRF prevention admits the GET.
230
226
  headers['apollo-require-preflight'] = 'true';
@@ -236,11 +232,16 @@ function buildTrustedGetRequest(endpoint, request) {
236
232
  export function createExecute(config) {
237
233
  const { endpoint, fetch: fetchFn, debug } = config;
238
234
  return async function execute(request) {
239
- const { query, variables, headers, operationName, isMutation, cache, documentId } = request;
235
+ const { query, variables, headers, operationName, cache, documentId } = request;
240
236
  const startedAt = debug?.timing ? Date.now() : 0;
241
- // Cacheable public reads with a resolvable persisted document go over GET so a
242
- // shared edge cache can serve them; everything else stays POST.
243
- const useTrustedGet = !isMutation && cache?.mode === 'public' && typeof documentId === 'string' && documentId.length > 0;
237
+ // Platform default: a non-mutation persisted read with no identity goes over the
238
+ // shared cacheable GET so an edge cache can serve it no per-query `cacheLong()`
239
+ // opt-in needed. The caller can still opt OUT with `cachePrivate()` / `cacheNone()`
240
+ // for a persisted read it wants kept per-user. Whether the result is ACTUALLY
241
+ // cached is the backend's call (it classifies the operation and emits
242
+ // `Cache-Control`); the SDK never classifies operations here — adding a PUBLIC_READ
243
+ // list would duplicate the backend registry and drift.
244
+ const useTrustedGet = isPublicReadEligible(request) && cache?.mode !== 'private' && cache?.mode !== 'no-store';
244
245
  if (debug) {
245
246
  const requestData = { variables, method: useTrustedGet ? 'GET' : 'POST' };
246
247
  if (useTrustedGet)
@@ -253,16 +254,27 @@ export function createExecute(config) {
253
254
  }
254
255
  let response;
255
256
  if (useTrustedGet) {
256
- const [getUrl, getInit] = buildTrustedGetRequest(endpoint, request);
257
- response = await fetchFn(getUrl, getInit);
258
- // Unknown documentId (custom selection or manifest skew) replay as POST with
259
- // the full query. The backend never executes a document it cannot resolve.
260
- if (response.status === 400) {
261
- const fallback = (await response.clone().json().catch(() => null));
262
- if (fallback?.error === TRUSTED_DOC_NOT_FOUND) {
263
- const [postUrl, postInit] = buildPostRequest(endpoint, request);
264
- response = await fetchFn(postUrl, postInit);
265
- }
257
+ // The cacheable GET is only an optimization for a shared edge cache — it must NEVER
258
+ // break a read. Use it only on a clean 2xx; degrade to a full-query POST on ANY other
259
+ // outcome: the GET transport throwing (network / CORS / aborted), an opaque or blocked
260
+ // response (`status` 0, `ok` false), an unknown documentId surfaced as 400, a 5xx, etc.
261
+ // The full query travels in the POST body, so the backend always resolves it.
262
+ let getResponse = null;
263
+ try {
264
+ const [getUrl, getInit] = buildTrustedGetRequest(endpoint, request);
265
+ const candidate = await fetchFn(getUrl, getInit);
266
+ if (candidate.ok)
267
+ getResponse = candidate;
268
+ }
269
+ catch {
270
+ // network / CORS / aborted GET — fall through to the safe POST below
271
+ }
272
+ if (getResponse) {
273
+ response = getResponse;
274
+ }
275
+ else {
276
+ const [postUrl, postInit] = buildPostRequest(endpoint, request);
277
+ response = await fetchFn(postUrl, postInit);
266
278
  }
267
279
  }
268
280
  else {
@@ -3,13 +3,39 @@
3
3
  *
4
4
  * Framework-agnostic — no React, no Zustand, 0 runtime dependencies.
5
5
  */
6
+ /**
7
+ * Structural contract for a typed GraphQL document accepted by `query` / `mutate`.
8
+ *
9
+ * A document carries its result type (`TResult`) and variables type (`TVariables`)
10
+ * at the type level via the phantom `__apiType` brand (never called at runtime) and
11
+ * stringifies to the GraphQL operation text. This is the parameter type the client
12
+ * exposes — deliberately a *structural interface*, not a concrete class, so it is
13
+ * satisfied by:
14
+ * - the SDK's own {@link TypedDocumentString} class, and
15
+ * - the class graphql-codegen's client-preset emits in a consumer project
16
+ * (which declares a `private` field and would otherwise be nominally
17
+ * incompatible with a class-typed parameter — private members only block
18
+ * class-to-class assignment, never class-to-interface).
19
+ *
20
+ * Inference is preserved either way: `client.query(doc, vars)` infers both the
21
+ * result and the variables shape from the document.
22
+ */
23
+ export interface TypedDocumentLike<TResult = unknown, TVariables = unknown> {
24
+ /** Type-level brand carrying result & variable types — never called at runtime. */
25
+ __apiType?: (variables: TVariables) => TResult;
26
+ /** Stringifies to the GraphQL operation text. */
27
+ toString(): string;
28
+ }
6
29
  /**
7
30
  * A branded string carrying result & variable types.
8
31
  * Produced by graphql-codegen client-preset with `documentMode: 'string'`.
9
32
  *
10
33
  * SDK also accepts plain strings — TypedDocumentString is purely for DX.
34
+ *
35
+ * Structurally satisfies {@link TypedDocumentLike}, the type accepted by
36
+ * `query` / `mutate`.
11
37
  */
12
- export declare class TypedDocumentString<TResult = unknown, TVariables = unknown> extends String {
38
+ export declare class TypedDocumentString<TResult = unknown, TVariables = unknown> extends String implements TypedDocumentLike<TResult, TVariables> {
13
39
  __meta__?: {
14
40
  hash: string;
15
41
  } | undefined;
@@ -211,15 +237,16 @@ export interface StorefrontClient {
211
237
  /**
212
238
  * Execute a typed GraphQL query.
213
239
  *
214
- * Accepts TypedDocumentString (from codegen) or plain string.
240
+ * Accepts any typed document (the SDK's `TypedDocumentString` or a
241
+ * graphql-codegen client-preset document) or a plain string.
215
242
  */
216
- query<T = unknown, V = Record<string, unknown>>(document: TypedDocumentString<T, V> | string, variables?: V, cache?: CacheStrategy): Promise<T>;
243
+ query<T = unknown, V = Record<string, unknown>>(document: TypedDocumentLike<T, V> | string, variables?: V, cache?: CacheStrategy): Promise<T>;
217
244
  /**
218
245
  * Execute a typed GraphQL mutation.
219
246
  *
220
247
  * Mutations are never cached and never retried by retry middleware.
221
248
  */
222
- mutate<T = unknown, V = Record<string, unknown>>(document: TypedDocumentString<T, V> | string, variables?: V): Promise<T>;
249
+ mutate<T = unknown, V = Record<string, unknown>>(document: TypedDocumentLike<T, V> | string, variables?: V): Promise<T>;
223
250
  /**
224
251
  * Add middleware to the pipeline (imperative API).
225
252
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/client/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;GAKG;AACH,qBAAa,mBAAmB,CAAC,OAAO,GAAG,OAAO,EAAE,UAAU,GAAG,OAAO,CAAE,SAAQ,MAAM;IAIpD,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAH7D,+CAA+C;IAC/C,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;gBAEnC,KAAK,EAAE,MAAM,EAAS,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,YAAA;IAIpD,QAAQ,IAAI,MAAM;CAG5B;AAMD,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,2BAA2B;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,8BAA8B;IAC9B,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAMD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAMhG,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB;IACjB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AAMzC;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,2GAA2G;IAC3G,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wGAAwG;IACxG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gKAAgK;IAChK,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sIAAsI;IACtI,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2JAA2J;IAC3J,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,eAAe,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IACzC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,0BAA0B;IAC1B,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;CAC5C;AAMD,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5C,QAAQ,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAC5C,SAAS,CAAC,EAAE,CAAC,EACb,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;;OAIG;IACH,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,QAAQ,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAC5C,SAAS,CAAC,EAAE,CAAC,GACZ,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;;OAIG;IACH,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CACnC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/client/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,iBAAiB,CAAC,OAAO,GAAG,OAAO,EAAE,UAAU,GAAG,OAAO;IACxE,mFAAmF;IACnF,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;IAC/C,iDAAiD;IACjD,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAmB,CAAC,OAAO,GAAG,OAAO,EAAE,UAAU,GAAG,OAAO,CACtE,SAAQ,MACR,YAAW,iBAAiB,CAAC,OAAO,EAAE,UAAU,CAAC;IAKf,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAH7D,+CAA+C;IAC/C,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;gBAEnC,KAAK,EAAE,MAAM,EAAS,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,YAAA;IAIpD,QAAQ,IAAI,MAAM;CAG5B;AAMD,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,iDAAiD;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,2BAA2B;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,8BAA8B;IAC9B,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAMD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAMhG,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB;IACjB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AAMzC;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,2GAA2G;IAC3G,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wGAAwG;IACxG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gKAAgK;IAChK,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sIAAsI;IACtI,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2JAA2J;IAC3J,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,kBAAkB,GAAG,eAAe,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IACzC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,0BAA0B;IAC1B,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;CAC5C;AAMD,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5C,QAAQ,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAC1C,SAAS,CAAC,EAAE,CAAC,EACb,KAAK,CAAC,EAAE,aAAa,GACpB,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;;OAIG;IACH,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7C,QAAQ,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAC1C,SAAS,CAAC,EAAE,CAAC,GACZ,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd;;;;OAIG;IACH,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CACnC"}
@@ -3,14 +3,14 @@
3
3
  *
4
4
  * Framework-agnostic — no React, no Zustand, 0 runtime dependencies.
5
5
  */
6
- // ---------------------------------------------------------------------------
7
- // TypedDocumentString (graphql-codegen client-preset pattern)
8
- // ---------------------------------------------------------------------------
9
6
  /**
10
7
  * A branded string carrying result & variable types.
11
8
  * Produced by graphql-codegen client-preset with `documentMode: 'string'`.
12
9
  *
13
10
  * SDK also accepts plain strings — TypedDocumentString is purely for DX.
11
+ *
12
+ * Structurally satisfies {@link TypedDocumentLike}, the type accepted by
13
+ * `query` / `mutate`.
14
14
  */
15
15
  export class TypedDocumentString extends String {
16
16
  __meta__;
@@ -34,7 +34,8 @@
34
34
  * ```
35
35
  */
36
36
  export { createStorefrontClient } from './client/create-client';
37
- export type { StorefrontClient, StorefrontClientConfig, Middleware, ExecuteFn, GraphQLRequest, GraphQLResponse, GraphQLErrorInfo, UserError, CacheStrategy, CacheOptions, TypedDocumentString, DebugOptions, DebugEvent, RemoteDebugOptions, RemoteDebugSink, } from './client/types';
37
+ export { isPublicReadEligible, IDENTITY_HEADERS, VARIANCE_AXIS_HEADERS, VARIANCE_AXIS_PARAMS, SHOP_SLUG_HEADER, } from './client/cache-eligibility';
38
+ export type { StorefrontClient, StorefrontClientConfig, Middleware, ExecuteFn, GraphQLRequest, GraphQLResponse, GraphQLErrorInfo, UserError, CacheStrategy, CacheOptions, TypedDocumentString, TypedDocumentLike, DebugOptions, DebugEvent, RemoteDebugOptions, RemoteDebugSink, } from './client/types';
38
39
  export { createRemoteDebugTransport } from './client/remote-debug-transport';
39
40
  export type { RemoteDebugTransport, RemoteDebugTransportConfig } from './client/remote-debug-transport';
40
41
  export { authMiddleware } from './middleware/auth';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,UAAU,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,YAAY,EAAE,oBAAoB,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAGxG,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,4BAA4B,GAClC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EAChC,KAAK,8BAA8B,EACnC,KAAK,YAAY,GAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAG9F,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAGjF,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,0BAA0B,EAC1B,KAAK,cAAc,GACpB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,4BAA4B,EAC5B,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAEV,IAAI,EACJ,QAAQ,EACR,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,kBAAkB,EAClB,YAAY,EACZ,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,KAAK,EACL,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,EACL,cAAc,EAGd,aAAa,EACb,uBAAuB,EACvB,uBAAuB,EACvB,+BAA+B,EAC/B,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,WAAW,EAEX,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,gBAAgB,EAChB,2BAA2B,EAC3B,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAGhB,gBAAgB,EAEhB,wBAAwB,EACxB,YAAY,EACZ,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,UAAU,EACV,eAAe,EACf,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACnG,YAAY,EACV,QAAQ,EACR,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,2BAA2B,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,UAAU,GAChB,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,0BAA0B,EAC1B,8BAA8B,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAG/G,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAG/G,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGzE,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,6BAA6B,GAC9B,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAG/E,OAAO,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGlF,OAAO,EAAE,KAAK,SAAS,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,8 @@
35
35
  */
36
36
  // Client factory
37
37
  export { createStorefrontClient } from './client/create-client';
38
+ // Cacheable-public-read eligibility (platform-default GET transport)
39
+ export { isPublicReadEligible, IDENTITY_HEADERS, VARIANCE_AXIS_HEADERS, VARIANCE_AXIS_PARAMS, SHOP_SLUG_HEADER, } from './client/cache-eligibility';
38
40
  // Remote debug transport — build one and share it across the client + cookie stores
39
41
  // (`debug: { remote: transport }`) for a single debug channel / sessionId.
40
42
  export { createRemoteDebugTransport } from './client/remote-debug-transport';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doswiftly/storefront-sdk",
3
- "version": "22.4.0",
3
+ "version": "22.5.0",
4
4
  "description": "Storefront runtime SDK for DoSwiftly Commerce — layered transport, middleware pipeline, React providers, Zustand stores, cache strategies. 0 runtime dependencies in core.",
5
5
  "type": "module",
6
6
  "sideEffects": false,