@doswiftly/storefront-sdk 16.0.0 → 16.1.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 +130 -0
- package/dist/core/cart/cart-recovery.d.ts +63 -0
- package/dist/core/cart/cart-recovery.d.ts.map +1 -1
- package/dist/core/cart/cart-recovery.js +91 -8
- package/dist/core/generated/operation-types.d.ts +28 -0
- package/dist/core/generated/operation-types.d.ts.map +1 -1
- package/dist/core/operations/cart.d.ts.map +1 -1
- package/dist/core/operations/cart.js +5 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,135 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 16.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1e6062e: Read the gift card recipient back from the cart.
|
|
8
|
+
|
|
9
|
+
`cartUpdateGiftCardRecipient` already persisted the recipient (email, name,
|
|
10
|
+
personalised message) on a gift card line — but the `CartLine` type didn't
|
|
11
|
+
expose any field to read it. Storefronts that render the checkout server-side
|
|
12
|
+
(SSR, deep link, "back to cart" navigation) had no way to know that the buyer
|
|
13
|
+
had already filled in the recipient form on a previous visit. The recipient
|
|
14
|
+
dialog opened blank, like nothing had been saved.
|
|
15
|
+
|
|
16
|
+
**New field** — `CartLine.giftCardRecipient: GiftCardLineRecipient`
|
|
17
|
+
|
|
18
|
+
```graphql
|
|
19
|
+
type GiftCardLineRecipient {
|
|
20
|
+
recipientEmail: String
|
|
21
|
+
recipientName: String
|
|
22
|
+
message: String
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
All three fields are individually nullable so a partial set (email only, no
|
|
27
|
+
name or message) is representable as-is. The field on `CartLine` itself is
|
|
28
|
+
nullable — `null` means the buyer has not set a recipient yet, in which case
|
|
29
|
+
the gift card is delivered to the order `customerEmail` on completion.
|
|
30
|
+
|
|
31
|
+
`null` is also what you get for any non-gift-card line — there is no risk of
|
|
32
|
+
the field reporting a stale recipient from a previous line at the same index.
|
|
33
|
+
|
|
34
|
+
**Use it to seed your form**
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
const cart = await cartClient.get(cartId);
|
|
38
|
+
const giftLine = cart?.lines.edges.find(
|
|
39
|
+
(e) => e.node.productType === "GIFT_CARD",
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
<GiftRecipientForm
|
|
43
|
+
defaultValues={
|
|
44
|
+
giftLine?.node.giftCardRecipient ?? {
|
|
45
|
+
recipientEmail: "",
|
|
46
|
+
recipientName: "",
|
|
47
|
+
message: "",
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
onSubmit={(values) =>
|
|
51
|
+
cartClient.updateGiftCardRecipient(cartId, giftLine!.node.id, values)
|
|
52
|
+
}
|
|
53
|
+
/>;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Migration**
|
|
57
|
+
|
|
58
|
+
Additive change — no rename, no signature change. The `CartLine` fragment
|
|
59
|
+
shipped by the SDK already includes the new field after this release, so
|
|
60
|
+
upgrading immediately unlocks the read path. No client code changes required
|
|
61
|
+
to keep existing flows working.
|
|
62
|
+
|
|
63
|
+
- ac2e306: Distinguish recoverable session loss from permanent cart denial.
|
|
64
|
+
|
|
65
|
+
Adds a new `CART_UNAUTHENTICATED` code to the cart error envelope. Until now,
|
|
66
|
+
both "your sign-in expired" and "this cart belongs to someone else" surfaced
|
|
67
|
+
as `CART_FORBIDDEN`, so a storefront had no way to know whether to send the
|
|
68
|
+
buyer to `/login` (recoverable) or to drop the cart cookie (permanent).
|
|
69
|
+
After the typical ~24h session TTL, the buyer would silently lose their
|
|
70
|
+
checkout state instead of being prompted to re-authenticate.
|
|
71
|
+
|
|
72
|
+
**New code** — `CART_UNAUTHENTICATED`
|
|
73
|
+
|
|
74
|
+
| Condition | Code | Recovery |
|
|
75
|
+
| ------------------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------- |
|
|
76
|
+
| Anonymous request **or** expired/invalid session on a cart that belongs to a customer | `CART_UNAUTHENTICATED` | Re-authenticate. Cart is preserved (`cart-id` cookie kept). |
|
|
77
|
+
| Authenticated as a **different** customer than the cart owner | `CART_FORBIDDEN` (unchanged) | Drop the cart cookie and start over. |
|
|
78
|
+
|
|
79
|
+
The cart resource itself is intact in the `CART_UNAUTHENTICATED` case — the
|
|
80
|
+
buyer's saved address, line items, discount codes, and gift cards return as
|
|
81
|
+
soon as they sign in.
|
|
82
|
+
|
|
83
|
+
**New SDK signal** — `runner.onSessionExpired(...)`
|
|
84
|
+
|
|
85
|
+
The recovery runner now exposes a separate event for session loss, distinct
|
|
86
|
+
from `onExpired` (which is for cart-resource lifecycle: cart not found, cart
|
|
87
|
+
already completed). Subscribe once at the provider level and route the buyer
|
|
88
|
+
to `/login` with a `return_to` parameter; the cart cookie stays put.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
// app/providers.tsx
|
|
92
|
+
const unsubExpired = runner.onExpired(() => {
|
|
93
|
+
// cart resource gone — start fresh
|
|
94
|
+
router.push("/cart/new");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const unsubSession = runner.onSessionExpired(() => {
|
|
98
|
+
// session gone, cart preserved — sign back in
|
|
99
|
+
router.push(`/login?return_to=${encodeURIComponent(location.pathname)}`);
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The session branch throws `CartSessionRequiredError` (re-exported alongside
|
|
104
|
+
`CartRecoveryNotPossibleError`) and does **not** invoke `recreateAndRun` —
|
|
105
|
+
recreating the cart on a stale session would discard the buyer's progress.
|
|
106
|
+
|
|
107
|
+
**Imperative handling**
|
|
108
|
+
|
|
109
|
+
If you handle mutation errors directly (Server Action, custom hook), add one
|
|
110
|
+
case to your existing switch:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
switch (err.userErrors[0]?.code) {
|
|
114
|
+
case "CART_UNAUTHENTICATED":
|
|
115
|
+
redirect(`/login?return_to=${encodeURIComponent("/checkout")}`);
|
|
116
|
+
break;
|
|
117
|
+
case "CART_FORBIDDEN":
|
|
118
|
+
cookies().delete("cart-id");
|
|
119
|
+
redirect("/cart/expired");
|
|
120
|
+
break;
|
|
121
|
+
// ...existing cases for CART_NOT_FOUND / ALREADY_COMPLETED
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Migration**
|
|
126
|
+
|
|
127
|
+
Additive change — no rename, no signature change. Existing `case 'CART_FORBIDDEN'`
|
|
128
|
+
branches keep working as before. Opt in to the new code at your own pace; until
|
|
129
|
+
you add the case, anonymous and cross-customer denials fall into your existing
|
|
130
|
+
default branch (one will be recoverable, one will not — adding the case lets
|
|
131
|
+
you distinguish them).
|
|
132
|
+
|
|
3
133
|
## 16.0.0
|
|
4
134
|
|
|
5
135
|
### Major Changes
|
|
@@ -55,6 +55,54 @@ export type CartRecoverableErrorCode = (typeof CART_RECOVERABLE_ERROR_CODES)[num
|
|
|
55
55
|
* `StorefrontError` carries at least one userError with a recoverable code.
|
|
56
56
|
*/
|
|
57
57
|
export declare function isCartRecoverableError(err: unknown): err is StorefrontError;
|
|
58
|
+
/**
|
|
59
|
+
* Cart error codes that signal a missing or invalid auth context on a
|
|
60
|
+
* customer-owned cart — distinct from cart-resource recovery
|
|
61
|
+
* (`CART_RECOVERABLE_ERROR_CODES`).
|
|
62
|
+
*
|
|
63
|
+
* - `CART_UNAUTHENTICATED` — anonymous request OR present-but-invalid token
|
|
64
|
+
* (expired JWT, malformed). The cart resource is intact and reachable
|
|
65
|
+
* again after re-auth.
|
|
66
|
+
*
|
|
67
|
+
* Storefronts SHOULD preserve the `cart-id` cookie when handling these
|
|
68
|
+
* codes and prompt sign-in — the same cart resumes after a successful login.
|
|
69
|
+
*/
|
|
70
|
+
export declare const CART_SESSION_ERROR_CODES: readonly ["CART_UNAUTHENTICATED"];
|
|
71
|
+
export type CartSessionErrorCode = (typeof CART_SESSION_ERROR_CODES)[number];
|
|
72
|
+
/**
|
|
73
|
+
* Type-safe predicate for "this error means the session is gone, but the
|
|
74
|
+
* cart resource is intact". Distinct from `isCartRecoverableError`
|
|
75
|
+
* (cart-resource recovery) — `isCartSessionError` matches auth-recoverable
|
|
76
|
+
* codes that should trigger re-auth flow, NOT cart cookie cleanup.
|
|
77
|
+
*
|
|
78
|
+
* Inspects `err.userErrors[].code` (structured field) — never matches against
|
|
79
|
+
* `err.message` (locale-dependent, non-stable).
|
|
80
|
+
*/
|
|
81
|
+
export declare function isCartSessionError(err: unknown): err is StorefrontError;
|
|
82
|
+
/**
|
|
83
|
+
* Event fired when the runner observes a session error (`CART_UNAUTHENTICATED`).
|
|
84
|
+
* Cart-id cookie is NOT cleared — the cart resource is intact and the buyer
|
|
85
|
+
* should be prompted to re-authenticate; after a successful login the same
|
|
86
|
+
* cart resumes.
|
|
87
|
+
*/
|
|
88
|
+
export interface CartSessionExpiredEvent {
|
|
89
|
+
/** Cart id from the cookie at the time of the failure (null when no cart was set). */
|
|
90
|
+
oldCartId: string | null;
|
|
91
|
+
/** Operation name from `CartRecoveryOperation.name` if provided, otherwise 'unknown'. */
|
|
92
|
+
operation: string;
|
|
93
|
+
/** Original `StorefrontError` carrying the `CART_UNAUTHENTICATED` userError. */
|
|
94
|
+
cause: unknown;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Thrown when a cart operation fails with a session error
|
|
98
|
+
* (`CART_UNAUTHENTICATED`). Distinct from `CartRecoveryNotPossibleError`
|
|
99
|
+
* (cart-resource issue) — storefronts should redirect to a sign-in flow
|
|
100
|
+
* and retry the operation after re-auth.
|
|
101
|
+
*/
|
|
102
|
+
export declare class CartSessionRequiredError extends Error {
|
|
103
|
+
readonly cause: unknown;
|
|
104
|
+
constructor(cause: unknown, message?: string);
|
|
105
|
+
}
|
|
58
106
|
/**
|
|
59
107
|
* Cookie I/O port. Caller's responsibility — core never touches `document.cookie`.
|
|
60
108
|
*
|
|
@@ -137,6 +185,14 @@ export interface ExecuteWithCartRecoveryOptions<T> {
|
|
|
137
185
|
cookieMaxAge?: number;
|
|
138
186
|
/** Optional listener fired before the runner throws `CartRecoveryNotPossibleError`. */
|
|
139
187
|
onExpired?: (event: CartExpiredEvent) => void;
|
|
188
|
+
/**
|
|
189
|
+
* Optional listener fired before the runner throws
|
|
190
|
+
* `CartSessionRequiredError`. Distinct from `onExpired` — the cart
|
|
191
|
+
* resource is intact, but the session/auth context is missing or invalid.
|
|
192
|
+
* Storefront should redirect to sign-in and retry the operation after
|
|
193
|
+
* re-auth; the same cart resumes.
|
|
194
|
+
*/
|
|
195
|
+
onSessionExpired?: (event: CartSessionExpiredEvent) => void;
|
|
140
196
|
}
|
|
141
197
|
/**
|
|
142
198
|
* Runs an operation against the current cart, recovering once on
|
|
@@ -158,6 +214,13 @@ export interface CartRecoveryRunner {
|
|
|
158
214
|
* fails. Returns an unsubscribe function. Multiple subscribers are supported.
|
|
159
215
|
*/
|
|
160
216
|
onExpired(listener: (event: CartExpiredEvent) => void): () => void;
|
|
217
|
+
/**
|
|
218
|
+
* Subscribe to `session-expired` events fired when the runner observes a
|
|
219
|
+
* `CART_UNAUTHENTICATED` userError (cart resource intact, re-auth required).
|
|
220
|
+
* The cart-id cookie is preserved so the same cart resumes after a successful
|
|
221
|
+
* sign-in. Returns an unsubscribe function. Multiple subscribers are supported.
|
|
222
|
+
*/
|
|
223
|
+
onSessionExpired(listener: (event: CartSessionExpiredEvent) => void): () => void;
|
|
161
224
|
/** Underlying cart client (for advanced flows / read-only helpers). */
|
|
162
225
|
readonly cartClient: CartClient;
|
|
163
226
|
/** Underlying cookie store (for advanced flows). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-recovery.d.ts","sourceRoot":"","sources":["../../../src/core/cart/cart-recovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAMrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,kDAAmD,CAAC;AAE7F,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAQrF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,eAAe,CAM3E;AAMD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,GAAG,IAAI,MAAM,GAAG,IAAI,CAAC;IACrB,qFAAqF;IACrF,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzD,6EAA6E;IAC7E,KAAK,IAAI,IAAI,CAAC;CACf;AAMD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,4CAA4C;IAC5C,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,MAAM,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAChF,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,MAAM,yBAAyB,GACjC,iBAAiB,GACjB,iBAAiB,GACjB,mBAAmB,CAAC;AAExB;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBAEZ,MAAM,EAAE,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM;CAMhF;AAaD,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,MAAM,EAAE,yBAAyB,CAAC;IAClC,4FAA4F;IAC5F,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,KAAK,EAAE,OAAO,CAAC;CAChB;AAmCD,MAAM,WAAW,8BAA8B,CAAC,CAAC;IAC/C,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACpC,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"cart-recovery.d.ts","sourceRoot":"","sources":["../../../src/core/cart/cart-recovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,6 +65,53 @@ export function isCartRecoverableError(err) {
|
|
|
65
65
|
return false;
|
|
66
66
|
return err.userErrors.some((ue) => typeof ue.code === 'string' && RECOVERABLE_CODE_SET.has(ue.code));
|
|
67
67
|
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Session error codes — auth-recoverable, distinct from cart-resource recovery
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/**
|
|
72
|
+
* Cart error codes that signal a missing or invalid auth context on a
|
|
73
|
+
* customer-owned cart — distinct from cart-resource recovery
|
|
74
|
+
* (`CART_RECOVERABLE_ERROR_CODES`).
|
|
75
|
+
*
|
|
76
|
+
* - `CART_UNAUTHENTICATED` — anonymous request OR present-but-invalid token
|
|
77
|
+
* (expired JWT, malformed). The cart resource is intact and reachable
|
|
78
|
+
* again after re-auth.
|
|
79
|
+
*
|
|
80
|
+
* Storefronts SHOULD preserve the `cart-id` cookie when handling these
|
|
81
|
+
* codes and prompt sign-in — the same cart resumes after a successful login.
|
|
82
|
+
*/
|
|
83
|
+
export const CART_SESSION_ERROR_CODES = ['CART_UNAUTHENTICATED'];
|
|
84
|
+
const SESSION_CODE_SET = new Set(CART_SESSION_ERROR_CODES);
|
|
85
|
+
/**
|
|
86
|
+
* Type-safe predicate for "this error means the session is gone, but the
|
|
87
|
+
* cart resource is intact". Distinct from `isCartRecoverableError`
|
|
88
|
+
* (cart-resource recovery) — `isCartSessionError` matches auth-recoverable
|
|
89
|
+
* codes that should trigger re-auth flow, NOT cart cookie cleanup.
|
|
90
|
+
*
|
|
91
|
+
* Inspects `err.userErrors[].code` (structured field) — never matches against
|
|
92
|
+
* `err.message` (locale-dependent, non-stable).
|
|
93
|
+
*/
|
|
94
|
+
export function isCartSessionError(err) {
|
|
95
|
+
if (!(err instanceof StorefrontError))
|
|
96
|
+
return false;
|
|
97
|
+
if (err.userErrors.length === 0)
|
|
98
|
+
return false;
|
|
99
|
+
return err.userErrors.some((ue) => typeof ue.code === 'string' && SESSION_CODE_SET.has(ue.code));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Thrown when a cart operation fails with a session error
|
|
103
|
+
* (`CART_UNAUTHENTICATED`). Distinct from `CartRecoveryNotPossibleError`
|
|
104
|
+
* (cart-resource issue) — storefronts should redirect to a sign-in flow
|
|
105
|
+
* and retry the operation after re-auth.
|
|
106
|
+
*/
|
|
107
|
+
export class CartSessionRequiredError extends Error {
|
|
108
|
+
cause;
|
|
109
|
+
constructor(cause, message) {
|
|
110
|
+
super(message ?? 'Session required — please sign in to continue', { cause });
|
|
111
|
+
this.name = 'CartSessionRequiredError';
|
|
112
|
+
this.cause = cause;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
68
115
|
/**
|
|
69
116
|
* Thrown when an operation hits a recoverable cart error but recovery is not
|
|
70
117
|
* possible (no `recreateAndRun`, or recovery itself failed). UI should clear
|
|
@@ -109,7 +156,7 @@ async function acquireCartId(coord, factory) {
|
|
|
109
156
|
* consumers can wire this directly without the runner factory.
|
|
110
157
|
*/
|
|
111
158
|
export async function executeWithCartRecovery(opts) {
|
|
112
|
-
const { cartClient, cookieStore, operation, ensureCart, cookieMaxAge, onExpired } = opts;
|
|
159
|
+
const { cartClient, cookieStore, operation, ensureCart, cookieMaxAge, onExpired, onSessionExpired } = opts;
|
|
113
160
|
const coord = opts.recoveryCoordinator ?? createCoordinator();
|
|
114
161
|
const opName = operation.name ?? 'unknown';
|
|
115
162
|
// Phase 0 — ensure cart exists (cookie may be empty on first interaction).
|
|
@@ -126,6 +173,17 @@ export async function executeWithCartRecovery(opts) {
|
|
|
126
173
|
return await operation.run(cartId);
|
|
127
174
|
}
|
|
128
175
|
catch (err) {
|
|
176
|
+
// Session loss — cart resource intact, re-auth needed. Preserve cookie
|
|
177
|
+
// so the same cart resumes after a successful login.
|
|
178
|
+
if (isCartSessionError(err)) {
|
|
179
|
+
const sessionEvent = {
|
|
180
|
+
oldCartId: cartId,
|
|
181
|
+
operation: opName,
|
|
182
|
+
cause: err,
|
|
183
|
+
};
|
|
184
|
+
onSessionExpired?.(sessionEvent);
|
|
185
|
+
throw new CartSessionRequiredError(err);
|
|
186
|
+
}
|
|
129
187
|
if (!isCartRecoverableError(err))
|
|
130
188
|
throw err;
|
|
131
189
|
const oldCartId = cartId;
|
|
@@ -181,9 +239,20 @@ export async function executeWithCartRecovery(opts) {
|
|
|
181
239
|
export function createCartRecoveryRunner(options) {
|
|
182
240
|
const { cartClient, cookieStore, ensureCart, cookieMaxAge } = options;
|
|
183
241
|
const coordinator = createCoordinator();
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
242
|
+
const expiredListeners = new Set();
|
|
243
|
+
const sessionListeners = new Set();
|
|
244
|
+
function emitExpired(event) {
|
|
245
|
+
for (const listener of expiredListeners) {
|
|
246
|
+
try {
|
|
247
|
+
listener(event);
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// Listeners must not break recovery flow — swallow listener exceptions.
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function emitSessionExpired(event) {
|
|
255
|
+
for (const listener of sessionListeners) {
|
|
187
256
|
try {
|
|
188
257
|
listener(event);
|
|
189
258
|
}
|
|
@@ -203,7 +272,8 @@ export function createCartRecoveryRunner(options) {
|
|
|
203
272
|
ensureCart,
|
|
204
273
|
cookieMaxAge,
|
|
205
274
|
recoveryCoordinator: coordinator,
|
|
206
|
-
onExpired:
|
|
275
|
+
onExpired: emitExpired,
|
|
276
|
+
onSessionExpired: emitSessionExpired,
|
|
207
277
|
};
|
|
208
278
|
return executeWithCartRecovery(internalOpts);
|
|
209
279
|
},
|
|
@@ -215,9 +285,18 @@ export function createCartRecoveryRunner(options) {
|
|
|
215
285
|
return await cartClient.get(cartId);
|
|
216
286
|
}
|
|
217
287
|
catch (err) {
|
|
288
|
+
if (isCartSessionError(err)) {
|
|
289
|
+
// Cart resource intact — re-auth required. Preserve cookie.
|
|
290
|
+
emitSessionExpired({
|
|
291
|
+
oldCartId: cartId,
|
|
292
|
+
operation: 'getCart',
|
|
293
|
+
cause: err,
|
|
294
|
+
});
|
|
295
|
+
throw new CartSessionRequiredError(err);
|
|
296
|
+
}
|
|
218
297
|
if (isCartRecoverableError(err)) {
|
|
219
298
|
cookieStore.clear();
|
|
220
|
-
|
|
299
|
+
emitExpired({
|
|
221
300
|
reason: 'state-dependent',
|
|
222
301
|
oldCartId: cartId,
|
|
223
302
|
operation: 'getCart',
|
|
@@ -229,8 +308,12 @@ export function createCartRecoveryRunner(options) {
|
|
|
229
308
|
}
|
|
230
309
|
},
|
|
231
310
|
onExpired(listener) {
|
|
232
|
-
|
|
233
|
-
return () =>
|
|
311
|
+
expiredListeners.add(listener);
|
|
312
|
+
return () => expiredListeners.delete(listener);
|
|
313
|
+
},
|
|
314
|
+
onSessionExpired(listener) {
|
|
315
|
+
sessionListeners.add(listener);
|
|
316
|
+
return () => sessionListeners.delete(listener);
|
|
234
317
|
},
|
|
235
318
|
};
|
|
236
319
|
}
|
|
@@ -710,6 +710,8 @@ export type CartLine = {
|
|
|
710
710
|
attributes: Array<Attribute>;
|
|
711
711
|
/** Per-line cost breakdown (unit price, subtotal, total, optional compare-at). */
|
|
712
712
|
cost: CartLineCost;
|
|
713
|
+
/** Recipient details captured for a `GIFT_CARD` line via `cartUpdateGiftCardRecipient`. Null for non-gift-card lines or when no recipient has been set yet — in that case the gift card is delivered to the order `customerEmail` on completion. Use to initialise the "gift recipient" form from cart state on SSR / page reload / deep link instead of keeping it in client-only state. */
|
|
714
|
+
giftCardRecipient?: Maybe<GiftCardLineRecipient>;
|
|
713
715
|
/** Stable line identifier. Use it to address the line in `cartUpdateLines` / `cartRemoveLines`. */
|
|
714
716
|
id: Scalars['ID']['output'];
|
|
715
717
|
/** URL handle (slug) of the parent product — link target for the cart drawer (denormalised). */
|
|
@@ -1413,6 +1415,14 @@ export type GiftCardError = {
|
|
|
1413
1415
|
message: Scalars['String']['output'];
|
|
1414
1416
|
};
|
|
1415
1417
|
export type GiftCardErrorCode = 'ALREADY_USED' | 'CURRENCY_MISMATCH' | 'DISABLED' | 'EXPIRED' | 'INSUFFICIENT_BALANCE' | 'INVALID_CODE_FORMAT' | 'NOT_FOUND';
|
|
1418
|
+
export type GiftCardLineRecipient = {
|
|
1419
|
+
/** Personalised message included with the gift card. */
|
|
1420
|
+
message?: Maybe<Scalars['String']['output']>;
|
|
1421
|
+
/** Recipient email — where the gift card code will be delivered on order completion. */
|
|
1422
|
+
recipientEmail?: Maybe<Scalars['String']['output']>;
|
|
1423
|
+
/** Recipient display name shown in the gift card email. */
|
|
1424
|
+
recipientName?: Maybe<Scalars['String']['output']>;
|
|
1425
|
+
};
|
|
1416
1426
|
export type GiftCardStatus = 'ACTIVE' | 'DISABLED' | 'EXPIRED' | 'USED';
|
|
1417
1427
|
export type GiftCardValidatePayload = {
|
|
1418
1428
|
/** User errors */
|
|
@@ -3237,6 +3247,7 @@ export type CartAddLinesMutation = {
|
|
|
3237
3247
|
};
|
|
3238
3248
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3239
3249
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3250
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3240
3251
|
})>;
|
|
3241
3252
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3242
3253
|
});
|
|
@@ -3298,6 +3309,7 @@ export type CartApplyGiftCardMutation = {
|
|
|
3298
3309
|
};
|
|
3299
3310
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3300
3311
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3312
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3301
3313
|
})>;
|
|
3302
3314
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3303
3315
|
});
|
|
@@ -3405,6 +3417,7 @@ export type CartCreateMutation = {
|
|
|
3405
3417
|
};
|
|
3406
3418
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3407
3419
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3420
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3408
3421
|
})>;
|
|
3409
3422
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3410
3423
|
});
|
|
@@ -3467,6 +3480,7 @@ export type CartDiscountCodesUpdateMutation = {
|
|
|
3467
3480
|
};
|
|
3468
3481
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3469
3482
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3483
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3470
3484
|
})>;
|
|
3471
3485
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3472
3486
|
});
|
|
@@ -3527,6 +3541,7 @@ export type CartQuery = {
|
|
|
3527
3541
|
};
|
|
3528
3542
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3529
3543
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3544
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3530
3545
|
})>;
|
|
3531
3546
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3532
3547
|
});
|
|
@@ -3585,6 +3600,7 @@ export type CartRemoveGiftCardMutation = {
|
|
|
3585
3600
|
};
|
|
3586
3601
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3587
3602
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3603
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3588
3604
|
})>;
|
|
3589
3605
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3590
3606
|
});
|
|
@@ -3647,6 +3663,7 @@ export type CartRemoveLinesMutation = {
|
|
|
3647
3663
|
};
|
|
3648
3664
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3649
3665
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3666
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3650
3667
|
})>;
|
|
3651
3668
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3652
3669
|
});
|
|
@@ -3708,6 +3725,7 @@ export type CartSelectPaymentMethodMutation = {
|
|
|
3708
3725
|
};
|
|
3709
3726
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3710
3727
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3728
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3711
3729
|
})>;
|
|
3712
3730
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3713
3731
|
});
|
|
@@ -3769,6 +3787,7 @@ export type CartSelectShippingMethodMutation = {
|
|
|
3769
3787
|
};
|
|
3770
3788
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3771
3789
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3790
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3772
3791
|
})>;
|
|
3773
3792
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3774
3793
|
});
|
|
@@ -3830,6 +3849,7 @@ export type CartSetBillingAddressMutation = {
|
|
|
3830
3849
|
};
|
|
3831
3850
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3832
3851
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3852
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3833
3853
|
})>;
|
|
3834
3854
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3835
3855
|
});
|
|
@@ -3891,6 +3911,7 @@ export type CartSetShippingAddressMutation = {
|
|
|
3891
3911
|
};
|
|
3892
3912
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3893
3913
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3914
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3894
3915
|
})>;
|
|
3895
3916
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3896
3917
|
});
|
|
@@ -3953,6 +3974,7 @@ export type CartUpdateAttributesMutation = {
|
|
|
3953
3974
|
};
|
|
3954
3975
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
3955
3976
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
3977
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
3956
3978
|
})>;
|
|
3957
3979
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
3958
3980
|
});
|
|
@@ -4015,6 +4037,7 @@ export type CartUpdateBuyerIdentityMutation = {
|
|
|
4015
4037
|
};
|
|
4016
4038
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4017
4039
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4040
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4018
4041
|
})>;
|
|
4019
4042
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
4020
4043
|
});
|
|
@@ -4076,6 +4099,7 @@ export type CartUpdateGiftCardRecipientMutation = {
|
|
|
4076
4099
|
};
|
|
4077
4100
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4078
4101
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4102
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4079
4103
|
})>;
|
|
4080
4104
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
4081
4105
|
});
|
|
@@ -4138,6 +4162,7 @@ export type CartUpdateLinesMutation = {
|
|
|
4138
4162
|
};
|
|
4139
4163
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4140
4164
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4165
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4141
4166
|
})>;
|
|
4142
4167
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
4143
4168
|
});
|
|
@@ -4200,6 +4225,7 @@ export type CartUpdateNoteMutation = {
|
|
|
4200
4225
|
};
|
|
4201
4226
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4202
4227
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4228
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4203
4229
|
})>;
|
|
4204
4230
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
4205
4231
|
});
|
|
@@ -4360,6 +4386,7 @@ export type CartFragment = (Pick<Cart, 'id' | 'checkoutUrl' | 'totalQuantity' |
|
|
|
4360
4386
|
};
|
|
4361
4387
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4362
4388
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4389
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4363
4390
|
})>;
|
|
4364
4391
|
pageInfo: Pick<PageInfo, 'hasNextPage' | 'hasPreviousPage' | 'startCursor' | 'endCursor'>;
|
|
4365
4392
|
});
|
|
@@ -4410,6 +4437,7 @@ export type CartLineFragment = (Pick<CartLine, 'id' | 'quantity' | 'productId' |
|
|
|
4410
4437
|
};
|
|
4411
4438
|
attributes: Array<Pick<Attribute, 'key' | 'value'>>;
|
|
4412
4439
|
attributeSelections: Array<Pick<AttributeSelection, 'attributeDefinitionId' | 'attributeName' | 'type' | 'fillingMode' | 'billingMode' | 'optionId' | 'optionLabel' | 'optionIds' | 'textValue' | 'surchargeAmount' | 'surchargeType' | 'taxClassId' | 'linkedVariantId'>>;
|
|
4440
|
+
giftCardRecipient?: Maybe<Pick<GiftCardLineRecipient, 'recipientEmail' | 'recipientName' | 'message'>>;
|
|
4413
4441
|
});
|
|
4414
4442
|
export type CartLineCostFragment = {
|
|
4415
4443
|
pricePerUnit: Pick<Money, 'amount' | 'currencyCode'>;
|