@doswiftly/storefront-sdk 22.3.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 +40 -0
- package/README.md +26 -4
- package/dist/core/client/cache-eligibility.d.ts +61 -0
- package/dist/core/client/cache-eligibility.d.ts.map +1 -0
- package/dist/core/client/cache-eligibility.js +80 -0
- package/dist/core/client/create-client.d.ts.map +1 -1
- package/dist/core/client/create-client.js +23 -1
- package/dist/core/client/execute.d.ts.map +1 -1
- package/dist/core/client/execute.js +114 -23
- package/dist/core/client/types.d.ts +37 -4
- package/dist/core/client/types.d.ts.map +1 -1
- package/dist/core/client/types.js +3 -3
- package/dist/core/generated/operation-types.d.ts +15 -0
- package/dist/core/generated/operation-types.d.ts.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/operations/cart.d.ts.map +1 -1
- package/dist/core/operations/cart.js +10 -0
- package/dist/react/components/PriceDisplay.d.ts +12 -3
- package/dist/react/components/PriceDisplay.d.ts.map +1 -1
- package/dist/react/components/PriceDisplay.js +8 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
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
|
+
|
|
35
|
+
## 22.4.0
|
|
36
|
+
|
|
37
|
+
### Minor Changes
|
|
38
|
+
|
|
39
|
+
- 848a3fe: Expose payment consents on `PaymentMethod`. The fragment now selects `acknowledgements` — consent statements a buyer can affirm before paying, each with linked documents — so storefronts can render the consent checkboxes and echo accepted codes back in `PaymentCreateInput.acknowledgements`.
|
|
40
|
+
- ecf919f: `<PriceDisplay>` now accepts an optional `locale` prop, forwarded to both the current price and the strikethrough compare-at price. Pass it (e.g. `locale="pl-PL"`) for deterministic, environment-independent formatting — bringing `<PriceDisplay>` in line with the `locale` prop already on `<Money>`. When omitted, behaviour is unchanged (the runtime default locale is used).
|
|
41
|
+
- be11ed6: Add a cacheable `GET` transport for public reads. When a document carries a persisted-document id (`TypedDocumentString.__meta__.hash`), a public cacheable query is sent as a `GET` with only the id — so a shared CDN can cache it — with the shop, currency and language in the URL and no credentials attached; an unrecognised id transparently replays as a `POST`. Mutations and any request without a document id keep the existing `POST` behaviour, so current behaviour is unchanged until document ids are present.
|
|
42
|
+
|
|
3
43
|
## 22.3.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -718,11 +718,11 @@ your CSS approach. Available from `@doswiftly/storefront-sdk/react`:
|
|
|
718
718
|
|
|
719
719
|
| Component | Purpose |
|
|
720
720
|
|-----------|---------|
|
|
721
|
-
| `<Money amount currency
|
|
721
|
+
| `<Money amount currency locale?>` | Locale-formatted price string from minor units |
|
|
722
722
|
| `<Image data sizes priority>` | `<img>` with thumbhash blur placeholder + sane defaults |
|
|
723
723
|
| `<CartCount count label>` | Aria-live cart item count |
|
|
724
724
|
| `<AddToCartButton variantId quantity>` | Button wired to `useCartManager().addItem` (loading state + a11y error surfacing) |
|
|
725
|
-
| `<PriceDisplay price compareAtPrice currency
|
|
725
|
+
| `<PriceDisplay price compareAtPrice currency locale?>` | Price + optional strikethrough sale price |
|
|
726
726
|
| `<CartTotals subtotal tax shipping discount total currency>` | Cart financial breakdown `<dl>` |
|
|
727
727
|
| `<PaymentInstrumentTile instrument>` | One selectable payment instrument (card brand, wallet, bank) |
|
|
728
728
|
| `<PaymentInstrumentSection method>` | Instrument group for a payment method (renders tiles) |
|
|
@@ -730,8 +730,8 @@ your CSS approach. Available from `@doswiftly/storefront-sdk/react`:
|
|
|
730
730
|
```tsx
|
|
731
731
|
import { Money, PriceDisplay, CartCount } from '@doswiftly/storefront-sdk/react';
|
|
732
732
|
|
|
733
|
-
<Money amount={9990} currency="PLN" /> {/* "99,90 zł" */}
|
|
734
|
-
<PriceDisplay price={7990} compareAtPrice={9990} currency="PLN" />
|
|
733
|
+
<Money amount={9990} currency="PLN" locale="pl-PL" /> {/* "99,90 zł" */}
|
|
734
|
+
<PriceDisplay price={7990} compareAtPrice={9990} currency="PLN" locale="pl-PL" />
|
|
735
735
|
<CartCount count={3} label="items" />
|
|
736
736
|
```
|
|
737
737
|
|
|
@@ -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,
|
|
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,16 +47,37 @@ export function createStorefrontClient(config) {
|
|
|
47
47
|
return compiledPipeline;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* Resolve query string from
|
|
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
|
+
/**
|
|
56
|
+
* Persisted-document id carried by codegen on `__meta__.hash`.
|
|
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.
|
|
62
|
+
*/
|
|
63
|
+
function resolveDocumentId(document) {
|
|
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;
|
|
74
|
+
}
|
|
55
75
|
/**
|
|
56
76
|
* Core request execution — shared by query() and mutate().
|
|
57
77
|
*/
|
|
58
78
|
async function request(document, variables, isMutation = false, cache) {
|
|
59
79
|
const query = resolveQuery(document);
|
|
80
|
+
const documentId = resolveDocumentId(document);
|
|
60
81
|
const operationName = getOperationName(query);
|
|
61
82
|
const pipeline = getPipeline();
|
|
62
83
|
const headers = {
|
|
@@ -73,6 +94,7 @@ export function createStorefrontClient(config) {
|
|
|
73
94
|
headers,
|
|
74
95
|
isMutation,
|
|
75
96
|
cache,
|
|
97
|
+
documentId,
|
|
76
98
|
};
|
|
77
99
|
// Dedupe queries (not mutations) in the same tick
|
|
78
100
|
const executeFn = () => pipeline(graphqlRequest);
|
|
@@ -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;
|
|
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,6 +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 { isPublicReadEligible, VARIANCE_AXIS_PARAMS } from './cache-eligibility';
|
|
7
8
|
const DEFAULT_LOG = (event) => {
|
|
8
9
|
// Header on a separate line so the data dump below renders untruncated in
|
|
9
10
|
// both terminals and DevTools.
|
|
@@ -151,45 +152,135 @@ function extractUserErrors(data) {
|
|
|
151
152
|
}
|
|
152
153
|
return flat;
|
|
153
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Default POST transport — the full query travels in the body and cookies are sent.
|
|
157
|
+
* Every request that is not a cacheable public read uses this (unchanged contract).
|
|
158
|
+
*/
|
|
159
|
+
function buildPostRequest(endpoint, request) {
|
|
160
|
+
const body = { query: request.query };
|
|
161
|
+
if (request.variables && Object.keys(request.variables).length > 0) {
|
|
162
|
+
body.variables = request.variables;
|
|
163
|
+
}
|
|
164
|
+
if (request.operationName) {
|
|
165
|
+
body.operationName = request.operationName;
|
|
166
|
+
}
|
|
167
|
+
return [
|
|
168
|
+
endpoint,
|
|
169
|
+
{
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: {
|
|
172
|
+
'Content-Type': 'application/json',
|
|
173
|
+
Accept: 'application/json',
|
|
174
|
+
...request.headers,
|
|
175
|
+
},
|
|
176
|
+
body: JSON.stringify(body),
|
|
177
|
+
signal: request.signal,
|
|
178
|
+
// Include httpOnly cookies (e.g. customerAccessToken auth) on cross-origin
|
|
179
|
+
// requests. Required when the storefront runs on a domain different from the
|
|
180
|
+
// backend GraphQL endpoint — same-origin browsers send cookies regardless,
|
|
181
|
+
// but cross-origin needs `credentials: 'include'` paired with the backend's
|
|
182
|
+
// `Access-Control-Allow-Credentials: true` (already configured).
|
|
183
|
+
credentials: 'include',
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Cacheable GET transport for public reads with a known `documentId`. Only the id
|
|
189
|
+
* travels (the backend resolves it to the full query from its allowlist), the variance
|
|
190
|
+
* axes ride in the URL so a shared edge cache keys correctly, and no credentials are
|
|
191
|
+
* sent so the response stays shareable across visitors.
|
|
192
|
+
*/
|
|
193
|
+
function buildTrustedGetRequest(endpoint, request) {
|
|
194
|
+
const url = new URL(endpoint);
|
|
195
|
+
url.searchParams.set('documentId', request.documentId);
|
|
196
|
+
if (request.operationName && request.operationName !== 'anonymous') {
|
|
197
|
+
url.searchParams.set('operationName', request.operationName);
|
|
198
|
+
}
|
|
199
|
+
if (request.variables && Object.keys(request.variables).length > 0) {
|
|
200
|
+
url.searchParams.set('variables', JSON.stringify(request.variables));
|
|
201
|
+
}
|
|
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()];
|
|
212
|
+
if (value)
|
|
213
|
+
url.searchParams.set(param, value);
|
|
214
|
+
}
|
|
215
|
+
const headers = { ...request.headers };
|
|
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.
|
|
220
|
+
delete headers.Authorization;
|
|
221
|
+
delete headers.authorization;
|
|
222
|
+
delete headers.Cookie;
|
|
223
|
+
delete headers.cookie;
|
|
224
|
+
headers.Accept = 'application/json';
|
|
225
|
+
// Force a CORS preflight so the backend CSRF prevention admits the GET.
|
|
226
|
+
headers['apollo-require-preflight'] = 'true';
|
|
227
|
+
return [url.toString(), { method: 'GET', headers, signal: request.signal, credentials: 'omit' }];
|
|
228
|
+
}
|
|
154
229
|
/**
|
|
155
230
|
* Create the innermost execute function for the middleware pipeline.
|
|
156
231
|
*/
|
|
157
232
|
export function createExecute(config) {
|
|
158
233
|
const { endpoint, fetch: fetchFn, debug } = config;
|
|
159
234
|
return async function execute(request) {
|
|
160
|
-
const { query, variables, headers,
|
|
235
|
+
const { query, variables, headers, operationName, cache, documentId } = request;
|
|
161
236
|
const startedAt = debug?.timing ? Date.now() : 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';
|
|
162
245
|
if (debug) {
|
|
163
|
-
const requestData = { variables };
|
|
246
|
+
const requestData = { variables, method: useTrustedGet ? 'GET' : 'POST' };
|
|
247
|
+
if (useTrustedGet)
|
|
248
|
+
requestData.documentId = documentId;
|
|
164
249
|
if (debug.request)
|
|
165
250
|
requestData.query = query;
|
|
166
251
|
if (debug.headers)
|
|
167
252
|
requestData.headers = redactRequestHeaders(headers);
|
|
168
253
|
debug.log({ phase: 'request', operationName, data: requestData });
|
|
169
254
|
}
|
|
170
|
-
|
|
171
|
-
if (
|
|
172
|
-
|
|
255
|
+
let response;
|
|
256
|
+
if (useTrustedGet) {
|
|
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);
|
|
278
|
+
}
|
|
173
279
|
}
|
|
174
|
-
|
|
175
|
-
|
|
280
|
+
else {
|
|
281
|
+
const [postUrl, postInit] = buildPostRequest(endpoint, request);
|
|
282
|
+
response = await fetchFn(postUrl, postInit);
|
|
176
283
|
}
|
|
177
|
-
const response = await fetchFn(endpoint, {
|
|
178
|
-
method: 'POST',
|
|
179
|
-
headers: {
|
|
180
|
-
'Content-Type': 'application/json',
|
|
181
|
-
Accept: 'application/json',
|
|
182
|
-
...headers,
|
|
183
|
-
},
|
|
184
|
-
body: JSON.stringify(body),
|
|
185
|
-
signal,
|
|
186
|
-
// Include httpOnly cookies (e.g. customerAccessToken auth) on cross-origin
|
|
187
|
-
// requests. Required when the storefront runs on a domain different from the
|
|
188
|
-
// backend GraphQL endpoint — same-origin browsers send cookies regardless,
|
|
189
|
-
// but cross-origin needs `credentials: 'include'` paired with the backend's
|
|
190
|
-
// `Access-Control-Allow-Credentials: true` (already configured).
|
|
191
|
-
credentials: 'include',
|
|
192
|
-
});
|
|
193
284
|
const json = await response.json();
|
|
194
285
|
if (debug) {
|
|
195
286
|
const responseData = {
|
|
@@ -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;
|
|
@@ -35,6 +61,12 @@ export interface GraphQLRequest {
|
|
|
35
61
|
isMutation: boolean;
|
|
36
62
|
/** Cache strategy override */
|
|
37
63
|
cache?: CacheStrategy;
|
|
64
|
+
/**
|
|
65
|
+
* Persisted-document id (`sha256:<hex>`), carried by `TypedDocumentString.__meta__.hash`.
|
|
66
|
+
* When present on a cacheable public read, the transport sends only this id over GET
|
|
67
|
+
* (instead of the full query) so a shared edge cache can serve the response. Absent → POST.
|
|
68
|
+
*/
|
|
69
|
+
documentId?: string;
|
|
38
70
|
}
|
|
39
71
|
export interface GraphQLResponse<T = unknown> {
|
|
40
72
|
/** Parsed response data */
|
|
@@ -205,15 +237,16 @@ export interface StorefrontClient {
|
|
|
205
237
|
/**
|
|
206
238
|
* Execute a typed GraphQL query.
|
|
207
239
|
*
|
|
208
|
-
* Accepts
|
|
240
|
+
* Accepts any typed document (the SDK's `TypedDocumentString` or a
|
|
241
|
+
* graphql-codegen client-preset document) or a plain string.
|
|
209
242
|
*/
|
|
210
|
-
query<T = unknown, V = Record<string, unknown>>(document:
|
|
243
|
+
query<T = unknown, V = Record<string, unknown>>(document: TypedDocumentLike<T, V> | string, variables?: V, cache?: CacheStrategy): Promise<T>;
|
|
211
244
|
/**
|
|
212
245
|
* Execute a typed GraphQL mutation.
|
|
213
246
|
*
|
|
214
247
|
* Mutations are never cached and never retried by retry middleware.
|
|
215
248
|
*/
|
|
216
|
-
mutate<T = unknown, V = Record<string, unknown>>(document:
|
|
249
|
+
mutate<T = unknown, V = Record<string, unknown>>(document: TypedDocumentLike<T, V> | string, variables?: V): Promise<T>;
|
|
217
250
|
/**
|
|
218
251
|
* Add middleware to the pipeline (imperative API).
|
|
219
252
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/client/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/client/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -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__;
|
|
@@ -3940,12 +3940,18 @@ export type AvailablePaymentMethodsQuery = {
|
|
|
3940
3940
|
instruments?: Maybe<Array<(Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
3941
3941
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
3942
3942
|
})>>;
|
|
3943
|
+
acknowledgements: Array<(Pick<PaymentAcknowledgement, 'code' | 'enforcement' | 'statement'> & {
|
|
3944
|
+
documents: Array<Pick<PaymentAcknowledgementDocument, 'token' | 'kind' | 'url'>>;
|
|
3945
|
+
})>;
|
|
3943
3946
|
})>;
|
|
3944
3947
|
defaultMethod?: Maybe<(Pick<PaymentMethod, 'id' | 'name' | 'provider' | 'type' | 'description' | 'isDefault' | 'supportedCurrencies' | 'position' | 'providersAvailable' | 'preferredProvider' | 'available' | 'unavailableReason'> & {
|
|
3945
3948
|
icon?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
3946
3949
|
instruments?: Maybe<Array<(Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
3947
3950
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
3948
3951
|
})>>;
|
|
3952
|
+
acknowledgements: Array<(Pick<PaymentAcknowledgement, 'code' | 'enforcement' | 'statement'> & {
|
|
3953
|
+
documents: Array<Pick<PaymentAcknowledgementDocument, 'token' | 'kind' | 'url'>>;
|
|
3954
|
+
})>;
|
|
3949
3955
|
})>;
|
|
3950
3956
|
};
|
|
3951
3957
|
};
|
|
@@ -5393,12 +5399,18 @@ export type AvailablePaymentMethodsFragment = {
|
|
|
5393
5399
|
instruments?: Maybe<Array<(Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
5394
5400
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
5395
5401
|
})>>;
|
|
5402
|
+
acknowledgements: Array<(Pick<PaymentAcknowledgement, 'code' | 'enforcement' | 'statement'> & {
|
|
5403
|
+
documents: Array<Pick<PaymentAcknowledgementDocument, 'token' | 'kind' | 'url'>>;
|
|
5404
|
+
})>;
|
|
5396
5405
|
})>;
|
|
5397
5406
|
defaultMethod?: Maybe<(Pick<PaymentMethod, 'id' | 'name' | 'provider' | 'type' | 'description' | 'isDefault' | 'supportedCurrencies' | 'position' | 'providersAvailable' | 'preferredProvider' | 'available' | 'unavailableReason'> & {
|
|
5398
5407
|
icon?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
5399
5408
|
instruments?: Maybe<Array<(Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
5400
5409
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
5401
5410
|
})>>;
|
|
5411
|
+
acknowledgements: Array<(Pick<PaymentAcknowledgement, 'code' | 'enforcement' | 'statement'> & {
|
|
5412
|
+
documents: Array<Pick<PaymentAcknowledgementDocument, 'token' | 'kind' | 'url'>>;
|
|
5413
|
+
})>;
|
|
5402
5414
|
})>;
|
|
5403
5415
|
};
|
|
5404
5416
|
export type PaymentMethodFragment = (Pick<PaymentMethod, 'id' | 'name' | 'provider' | 'type' | 'description' | 'isDefault' | 'supportedCurrencies' | 'position' | 'providersAvailable' | 'preferredProvider' | 'available' | 'unavailableReason'> & {
|
|
@@ -5406,6 +5418,9 @@ export type PaymentMethodFragment = (Pick<PaymentMethod, 'id' | 'name' | 'provid
|
|
|
5406
5418
|
instruments?: Maybe<Array<(Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
5407
5419
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|
|
5408
5420
|
})>>;
|
|
5421
|
+
acknowledgements: Array<(Pick<PaymentAcknowledgement, 'code' | 'enforcement' | 'statement'> & {
|
|
5422
|
+
documents: Array<Pick<PaymentAcknowledgementDocument, 'token' | 'kind' | 'url'>>;
|
|
5423
|
+
})>;
|
|
5409
5424
|
});
|
|
5410
5425
|
export type PaymentInstrumentFragment = (Pick<PaymentInstrument, 'provider' | 'code' | 'type' | 'displayName' | 'displayHint' | 'enabled'> & {
|
|
5411
5426
|
brandImage?: Maybe<Pick<Image, 'id' | 'url' | 'altText' | 'width' | 'height' | 'thumbhash'>>;
|