@doswiftly/storefront-sdk 22.9.0 → 22.10.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 +20 -0
- package/README.md +13 -6
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/middleware/cart-secret.d.ts +36 -8
- package/dist/core/middleware/cart-secret.d.ts.map +1 -1
- package/dist/core/middleware/cart-secret.js +46 -12
- package/dist/react/providers/storefront-client-provider.d.ts.map +1 -1
- package/dist/react/providers/storefront-client-provider.js +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 22.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3961ca4: Attach the cart access secret (`x-cart-secret`) only to cart operations.
|
|
8
|
+
|
|
9
|
+
Previously the header was sent on every request whenever a cart cookie was
|
|
10
|
+
present, which kept public catalog reads (products, search, recommendations,
|
|
11
|
+
payment methods) off the shared response cache for any visitor who had a cart.
|
|
12
|
+
The secret is now attached only to cart-scoped operations, so those public
|
|
13
|
+
reads become cacheable again — faster responses, with no change needed in your
|
|
14
|
+
code.
|
|
15
|
+
|
|
16
|
+
A new `isCartScopedOperation` helper is exported, and `cartSecretMiddleware` /
|
|
17
|
+
`serverCartSecretMiddleware` accept an optional classifier as their second
|
|
18
|
+
argument. Cart operations are recognised by a `Cart` operation-name prefix. If
|
|
19
|
+
you issue custom cart queries through the SDK, name them with a `Cart` prefix,
|
|
20
|
+
or pass your own classifier:
|
|
21
|
+
`cartSecretMiddleware(getSecret, (operationName) => ...)`.
|
|
22
|
+
|
|
3
23
|
## 22.9.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ const client = createStorefrontClient({
|
|
|
197
197
|
apiUrl: 'https://api.doswiftly.pl',
|
|
198
198
|
shopSlug: 'my-shop',
|
|
199
199
|
middleware: [
|
|
200
|
-
cartSecretMiddleware(() => cartSecret), // lazy getter
|
|
200
|
+
cartSecretMiddleware(() => cartSecret), // lazy getter; secret rides cart ops only
|
|
201
201
|
retryMiddleware({ maxRetries: 2 }),
|
|
202
202
|
timeoutMiddleware({ timeout: 5000 }),
|
|
203
203
|
errorMiddleware(), // ALWAYS LAST
|
|
@@ -425,17 +425,24 @@ Cart access is authorized by **possession of a secret**, not by the customer
|
|
|
425
425
|
session. The `cart-id` cookie stores a composite value `"<cartId>.<secret>"`
|
|
426
426
|
(30 days, SSR/edge-visible, not httpOnly — the cart carries no payment data).
|
|
427
427
|
`CartClient.create()` and `recoveryRedeem()` reveal the secret **once**; the SDK
|
|
428
|
-
persists it into the cookie for you.
|
|
429
|
-
the `x-cart-secret` header via middleware
|
|
428
|
+
persists it into the cookie for you. **Cart operations** then carry the secret in
|
|
429
|
+
the `x-cart-secret` header via middleware — public reads (product listings,
|
|
430
|
+
search, recommendations, payment methods) do **not**, so they stay eligible for
|
|
431
|
+
the shared cache even when the visitor has a cart:
|
|
430
432
|
|
|
431
433
|
- **Browser**: `StorefrontProvider` wires `cartSecretMiddleware` automatically —
|
|
432
|
-
the secret is read lazily from the cookie
|
|
433
|
-
secret is picked up without rebuilding the client.
|
|
434
|
+
the secret is read lazily from the cookie and attached only to cart
|
|
435
|
+
operations, so a rotated secret is picked up without rebuilding the client.
|
|
434
436
|
- **Server (SSR/edge)**: prepend `serverCartSecretMiddleware(await readCartCredentials())`
|
|
435
437
|
to your server client — see [Server-side](#server-side-reactserver).
|
|
436
438
|
- **Custom runtimes**: `cartSecretMiddleware(() => secret)` + the
|
|
437
439
|
`parseCartCookieValue` / `formatCartCookieValue` helpers.
|
|
438
440
|
|
|
441
|
+
Cart operations are recognised by a `Cart` operation-name prefix
|
|
442
|
+
(`isCartScopedOperation`). If you issue custom cart queries, name them with a
|
|
443
|
+
`Cart` prefix, or pass your own classifier as the second argument:
|
|
444
|
+
`cartSecretMiddleware(getSecret, (operationName) => ...)`.
|
|
445
|
+
|
|
439
446
|
A cookie without the secret half (or a stale capability) makes the cart
|
|
440
447
|
unreachable — mutations reject with `CART_NOT_FOUND` and the standard recovery
|
|
441
448
|
flow recreates a fresh cart.
|
|
@@ -806,7 +813,7 @@ replay; a 401 on a mutation fires the `session-expired` signal instead.
|
|
|
806
813
|
```typescript
|
|
807
814
|
import {
|
|
808
815
|
authMiddleware, // Authorization: Bearer <token> (lazy getter)
|
|
809
|
-
cartSecretMiddleware, // x-cart-secret header (
|
|
816
|
+
cartSecretMiddleware, // x-cart-secret header (cart operations only)
|
|
810
817
|
currencyMiddleware, // X-Preferred-Currency header
|
|
811
818
|
languageMiddleware, // X-Language header (skipped when null — intentional)
|
|
812
819
|
botProtectionMiddleware, // challenge token for protected mutations only
|
package/dist/core/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export type { StorefrontClient, StorefrontClientConfig, Middleware, ExecuteFn, G
|
|
|
39
39
|
export { createRemoteDebugTransport } from './client/remote-debug-transport';
|
|
40
40
|
export type { RemoteDebugTransport, RemoteDebugTransportConfig } from './client/remote-debug-transport';
|
|
41
41
|
export { authMiddleware } from './middleware/auth';
|
|
42
|
-
export { cartSecretMiddleware, serverCartSecretMiddleware, CART_SECRET_HEADER, } from './middleware/cart-secret';
|
|
42
|
+
export { cartSecretMiddleware, serverCartSecretMiddleware, isCartScopedOperation, CART_SECRET_HEADER, } from './middleware/cart-secret';
|
|
43
43
|
export { currencyMiddleware } from './middleware/currency';
|
|
44
44
|
export { languageMiddleware } from './middleware/language';
|
|
45
45
|
export { forwardedIpMiddleware, forwardedIpSignedMessage, FORWARDED_IP_HEADER, FORWARDED_IP_TS_HEADER, FORWARDED_IP_SIG_HEADER, type ForwardedIpMiddlewareOptions, } from './middleware/forwarded-ip';
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
|
package/dist/core/index.js
CHANGED
|
@@ -42,7 +42,7 @@ export { isPublicReadEligible, IDENTITY_HEADERS, VARIANCE_AXIS_HEADERS, VARIANCE
|
|
|
42
42
|
export { createRemoteDebugTransport } from './client/remote-debug-transport';
|
|
43
43
|
// Middleware
|
|
44
44
|
export { authMiddleware } from './middleware/auth';
|
|
45
|
-
export { cartSecretMiddleware, serverCartSecretMiddleware, CART_SECRET_HEADER, } from './middleware/cart-secret';
|
|
45
|
+
export { cartSecretMiddleware, serverCartSecretMiddleware, isCartScopedOperation, CART_SECRET_HEADER, } from './middleware/cart-secret';
|
|
46
46
|
export { currencyMiddleware } from './middleware/currency';
|
|
47
47
|
export { languageMiddleware } from './middleware/language';
|
|
48
48
|
export { forwardedIpMiddleware, forwardedIpSignedMessage, FORWARDED_IP_HEADER, FORWARDED_IP_TS_HEADER, FORWARDED_IP_SIG_HEADER, } from './middleware/forwarded-ip';
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* cart access secret. Possession of the secret is what authorizes cart
|
|
4
4
|
* operations; the cart id alone is not enough.
|
|
5
5
|
*
|
|
6
|
+
* The header is attached **only to cart operations** (classified by
|
|
7
|
+
* {@link isCartScopedOperation} — operation names with a `Cart` prefix). Public
|
|
8
|
+
* reads such as product listings, search and recommendations never carry the
|
|
9
|
+
* secret, so they stay eligible for the shared response cache even when the
|
|
10
|
+
* visitor already has a cart. Pass a custom classifier as the second argument
|
|
11
|
+
* to override which operations are treated as cart-scoped.
|
|
12
|
+
*
|
|
6
13
|
* Two variants share one header contract:
|
|
7
14
|
*
|
|
8
15
|
* - **Client** (`cartSecretMiddleware`) resolves the secret lazily on every
|
|
@@ -27,17 +34,38 @@ import type { CartCredentials } from '../cart/cookie-config';
|
|
|
27
34
|
/** Request header carrying the cart access secret. */
|
|
28
35
|
export declare const CART_SECRET_HEADER = "x-cart-secret";
|
|
29
36
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
37
|
+
* Default classifier deciding whether an operation should carry the cart access
|
|
38
|
+
* secret. Cart operations are named with a `Cart` prefix (`Cart`, `CartAddLines`,
|
|
39
|
+
* `CartComplete`, `CartAvailableShippingMethods`, …). Three operations are
|
|
40
|
+
* deliberately excluded because none of them is bound to a specific cart, so the
|
|
41
|
+
* secret would be meaningless on them:
|
|
42
|
+
* - `AvailablePaymentMethods` — a shop-level read (cacheable);
|
|
43
|
+
* - `OrderByToken` — a guest order lookup authorized by an opaque order token
|
|
44
|
+
* (not cacheable — served `no-store`);
|
|
45
|
+
* - `PaymentCreate` — a mutation operating on an order.
|
|
46
|
+
*
|
|
47
|
+
* Withholding the secret keeps the cacheable shop-level read in the shared cache
|
|
48
|
+
* (carrying the secret would mark it identity-bearing and push it off); for the
|
|
49
|
+
* order operations it simply avoids sending a credential they never read.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isCartScopedOperation(operationName: string | undefined): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Client cart-secret middleware. The header is sent only for cart-scoped
|
|
54
|
+
* operations (`isCartScoped`, default {@link isCartScopedOperation}); public
|
|
55
|
+
* reads stay cacheable and never touch the cookie. For a cart operation,
|
|
56
|
+
* `getSecret` is read fresh on each request so a rotated secret (recovery
|
|
57
|
+
* redeem) is picked up without rebuilding the pipeline. No header is sent when
|
|
58
|
+
* the secret is absent (legacy plain-id cookie) — the backend then treats the
|
|
59
|
+
* cart as unreachable and the SDK recreates one.
|
|
34
60
|
*/
|
|
35
|
-
export declare function cartSecretMiddleware(getSecret: () => string | null | undefined): Middleware;
|
|
61
|
+
export declare function cartSecretMiddleware(getSecret: () => string | null | undefined, isCartScoped?: (operationName: string | undefined) => boolean): Middleware;
|
|
36
62
|
/**
|
|
37
63
|
* Server cart-secret middleware. Takes the credentials already read from the
|
|
38
64
|
* request cookies (`readCartCredentials`) — prepend it to a server client so
|
|
39
|
-
* SSR / edge cart reads carry the secret.
|
|
40
|
-
*
|
|
65
|
+
* SSR / edge cart reads carry the secret. As with the client variant, the
|
|
66
|
+
* header is sent only for cart-scoped operations (`isCartScoped`, default
|
|
67
|
+
* {@link isCartScopedOperation}). No header is sent when credentials are null or
|
|
68
|
+
* carry no secret.
|
|
41
69
|
*/
|
|
42
|
-
export declare function serverCartSecretMiddleware(credentials: CartCredentials | null): Middleware;
|
|
70
|
+
export declare function serverCartSecretMiddleware(credentials: CartCredentials | null, isCartScoped?: (operationName: string | undefined) => boolean): Middleware;
|
|
43
71
|
//# sourceMappingURL=cart-secret.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-secret.d.ts","sourceRoot":"","sources":["../../../src/core/middleware/cart-secret.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cart-secret.d.ts","sourceRoot":"","sources":["../../../src/core/middleware/cart-secret.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAC1C,YAAY,GAAE,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,KAAK,OAA+B,GACnF,UAAU,CAYZ;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,eAAe,GAAG,IAAI,EACnC,YAAY,GAAE,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,KAAK,OAA+B,GACnF,UAAU,CAOZ"}
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
* cart access secret. Possession of the secret is what authorizes cart
|
|
4
4
|
* operations; the cart id alone is not enough.
|
|
5
5
|
*
|
|
6
|
+
* The header is attached **only to cart operations** (classified by
|
|
7
|
+
* {@link isCartScopedOperation} — operation names with a `Cart` prefix). Public
|
|
8
|
+
* reads such as product listings, search and recommendations never carry the
|
|
9
|
+
* secret, so they stay eligible for the shared response cache even when the
|
|
10
|
+
* visitor already has a cart. Pass a custom classifier as the second argument
|
|
11
|
+
* to override which operations are treated as cart-scoped.
|
|
12
|
+
*
|
|
6
13
|
* Two variants share one header contract:
|
|
7
14
|
*
|
|
8
15
|
* - **Client** (`cartSecretMiddleware`) resolves the secret lazily on every
|
|
@@ -25,16 +32,41 @@
|
|
|
25
32
|
/** Request header carrying the cart access secret. */
|
|
26
33
|
export const CART_SECRET_HEADER = 'x-cart-secret';
|
|
27
34
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
35
|
+
* Default classifier deciding whether an operation should carry the cart access
|
|
36
|
+
* secret. Cart operations are named with a `Cart` prefix (`Cart`, `CartAddLines`,
|
|
37
|
+
* `CartComplete`, `CartAvailableShippingMethods`, …). Three operations are
|
|
38
|
+
* deliberately excluded because none of them is bound to a specific cart, so the
|
|
39
|
+
* secret would be meaningless on them:
|
|
40
|
+
* - `AvailablePaymentMethods` — a shop-level read (cacheable);
|
|
41
|
+
* - `OrderByToken` — a guest order lookup authorized by an opaque order token
|
|
42
|
+
* (not cacheable — served `no-store`);
|
|
43
|
+
* - `PaymentCreate` — a mutation operating on an order.
|
|
44
|
+
*
|
|
45
|
+
* Withholding the secret keeps the cacheable shop-level read in the shared cache
|
|
46
|
+
* (carrying the secret would mark it identity-bearing and push it off); for the
|
|
47
|
+
* order operations it simply avoids sending a credential they never read.
|
|
48
|
+
*/
|
|
49
|
+
export function isCartScopedOperation(operationName) {
|
|
50
|
+
return typeof operationName === 'string' && operationName.startsWith('Cart');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Client cart-secret middleware. The header is sent only for cart-scoped
|
|
54
|
+
* operations (`isCartScoped`, default {@link isCartScopedOperation}); public
|
|
55
|
+
* reads stay cacheable and never touch the cookie. For a cart operation,
|
|
56
|
+
* `getSecret` is read fresh on each request so a rotated secret (recovery
|
|
57
|
+
* redeem) is picked up without rebuilding the pipeline. No header is sent when
|
|
58
|
+
* the secret is absent (legacy plain-id cookie) — the backend then treats the
|
|
59
|
+
* cart as unreachable and the SDK recreates one.
|
|
32
60
|
*/
|
|
33
|
-
export function cartSecretMiddleware(getSecret) {
|
|
61
|
+
export function cartSecretMiddleware(getSecret, isCartScoped = isCartScopedOperation) {
|
|
34
62
|
return (request, next) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
// Gate on the cheap operation-name check first so public reads (the
|
|
64
|
+
// high-volume path) skip the secret getter (a cookie read) entirely.
|
|
65
|
+
if (isCartScoped(request.operationName)) {
|
|
66
|
+
const secret = getSecret();
|
|
67
|
+
if (secret) {
|
|
68
|
+
request.headers[CART_SECRET_HEADER] = secret;
|
|
69
|
+
}
|
|
38
70
|
}
|
|
39
71
|
return next(request);
|
|
40
72
|
};
|
|
@@ -42,12 +74,14 @@ export function cartSecretMiddleware(getSecret) {
|
|
|
42
74
|
/**
|
|
43
75
|
* Server cart-secret middleware. Takes the credentials already read from the
|
|
44
76
|
* request cookies (`readCartCredentials`) — prepend it to a server client so
|
|
45
|
-
* SSR / edge cart reads carry the secret.
|
|
46
|
-
*
|
|
77
|
+
* SSR / edge cart reads carry the secret. As with the client variant, the
|
|
78
|
+
* header is sent only for cart-scoped operations (`isCartScoped`, default
|
|
79
|
+
* {@link isCartScopedOperation}). No header is sent when credentials are null or
|
|
80
|
+
* carry no secret.
|
|
47
81
|
*/
|
|
48
|
-
export function serverCartSecretMiddleware(credentials) {
|
|
82
|
+
export function serverCartSecretMiddleware(credentials, isCartScoped = isCartScopedOperation) {
|
|
49
83
|
return (request, next) => {
|
|
50
|
-
if (credentials?.cartSecret) {
|
|
84
|
+
if (credentials?.cartSecret && isCartScoped(request.operationName)) {
|
|
51
85
|
request.headers[CART_SECRET_HEADER] = credentials.cartSecret;
|
|
52
86
|
}
|
|
53
87
|
return next(request);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storefront-client-provider.d.ts","sourceRoot":"","sources":["../../../src/react/providers/storefront-client-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAA6C,MAAM,OAAO,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAOzD,OAAO,EAA2B,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAKhH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;CACxB;AAID,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,sBAAsB,CAAC;IAC/B;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,oEAAoE;IACpE,aAAa,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAClD,+DAA+D;IAC/D,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,4HAA4H;IAC5H,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,MAAM,EACN,UAAU,EAAE,gBAAqB,EACjC,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,YAAY,GACb,EAAE,6BAA6B,
|
|
1
|
+
{"version":3,"file":"storefront-client-provider.d.ts","sourceRoot":"","sources":["../../../src/react/providers/storefront-client-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAA6C,MAAM,OAAO,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAOzD,OAAO,EAA2B,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAKhH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;CACxB;AAID,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,sBAAsB,CAAC;IAC/B;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,oEAAoE;IACpE,aAAa,CAAC,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAClD,+DAA+D;IAC/D,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,4HAA4H;IAC5H,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,MAAM,EACN,UAAU,EAAE,gBAAqB,EACjC,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,YAAY,GACb,EAAE,6BAA6B,2CAiF/B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,4BAA4B,CAMzE"}
|
|
@@ -13,7 +13,7 @@ import { createStorefrontClient } from '../../core/client/create-client';
|
|
|
13
13
|
import { CartClient } from '../../core/cart/cart-client';
|
|
14
14
|
import { AuthClient } from '../../core/auth/auth-client';
|
|
15
15
|
import { authMiddleware } from '../../core/middleware/auth';
|
|
16
|
-
import { cartSecretMiddleware } from '../../core/middleware/cart-secret';
|
|
16
|
+
import { cartSecretMiddleware, isCartScopedOperation } from '../../core/middleware/cart-secret';
|
|
17
17
|
import { CART_COOKIE_NAME, parseCartCookieValue } from '../../core/cart/cookie-config';
|
|
18
18
|
import { getCookie } from '../cookies';
|
|
19
19
|
import { currencyMiddleware } from '../../core/middleware/currency';
|
|
@@ -67,7 +67,9 @@ export function StorefrontClientProvider({ children, config, middleware: customM
|
|
|
67
67
|
authMiddleware(() => authStore.getState().accessToken),
|
|
68
68
|
// Cart access secret — read lazily from the composite cart-id cookie so
|
|
69
69
|
// a rotated secret (recovery redeem) is picked up without rebuilding.
|
|
70
|
-
|
|
70
|
+
// Attached only to cart operations (passed explicitly for clarity; it is
|
|
71
|
+
// the default) so public reads stay cacheable when a cart exists.
|
|
72
|
+
cartSecretMiddleware(() => parseCartCookieValue(getCookie(CART_COOKIE_NAME))?.cartSecret ?? null, isCartScopedOperation),
|
|
71
73
|
currencyMiddleware(() => currencyStore.getState().currency),
|
|
72
74
|
languageMiddleware(() => languageStore.getState().language),
|
|
73
75
|
// Bot protection (if configured)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doswiftly/storefront-sdk",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.10.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,
|