@doswiftly/storefront-operations 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/AGENTS.md +1 -1
- package/CHANGELOG.md +130 -0
- package/fragments.graphql +5 -0
- package/llms-full.txt +6 -1
- package/operations.json +2 -2
- package/package.json +1 -1
- package/schema.graphql +21 -0
package/AGENTS.md
CHANGED
|
@@ -27,7 +27,7 @@ consumer's `codegen.ts` references this package's `.graphql` files as
|
|
|
27
27
|
live in the consumer's repo.
|
|
28
28
|
|
|
29
29
|
<!-- AUTOGEN:STATS:BEGIN — auto-regenerated, do not edit by hand -->
|
|
30
|
-
- **Schema version**: 16.
|
|
30
|
+
- **Schema version**: 16.1.0
|
|
31
31
|
- **Queries**: 52
|
|
32
32
|
- **Mutations**: 40
|
|
33
33
|
- **Fragments**: 102
|
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
|
package/fragments.graphql
CHANGED
|
@@ -427,6 +427,11 @@ fragment CartLine on CartLine {
|
|
|
427
427
|
productHandle
|
|
428
428
|
productType
|
|
429
429
|
requiresShipping
|
|
430
|
+
giftCardRecipient {
|
|
431
|
+
recipientEmail
|
|
432
|
+
recipientName
|
|
433
|
+
message
|
|
434
|
+
}
|
|
430
435
|
}
|
|
431
436
|
|
|
432
437
|
# Buyer identity associated with the cart. Note: only `customerId` is currently persisted server-side; `email`, `phone`, `countryCode` are accepted in the input but ignored.
|
package/llms-full.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DoSwiftly Storefront Operations — Full Reference
|
|
2
2
|
|
|
3
|
-
> Schema version: **16.
|
|
3
|
+
> Schema version: **16.1.0**
|
|
4
4
|
> 52 queries · 40 mutations · 102 fragments
|
|
5
5
|
|
|
6
6
|
Auto-generated from `.graphql` source files. Do not edit by hand — this file is
|
|
@@ -3052,6 +3052,11 @@ fragment CartLine on CartLine {
|
|
|
3052
3052
|
productHandle
|
|
3053
3053
|
productType
|
|
3054
3054
|
requiresShipping
|
|
3055
|
+
giftCardRecipient {
|
|
3056
|
+
recipientEmail
|
|
3057
|
+
recipientName
|
|
3058
|
+
message
|
|
3059
|
+
}
|
|
3055
3060
|
}
|
|
3056
3061
|
```
|
|
3057
3062
|
|
package/operations.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion": "16.
|
|
2
|
+
"schemaVersion": "16.1.0",
|
|
3
3
|
"queries": [
|
|
4
4
|
{
|
|
5
5
|
"name": "Shop",
|
|
@@ -2124,7 +2124,7 @@
|
|
|
2124
2124
|
"CartLineCost",
|
|
2125
2125
|
"ProductVariant"
|
|
2126
2126
|
],
|
|
2127
|
-
"body": "fragment CartLine on CartLine {\n id\n quantity\n variant {\n ...ProductVariant\n }\n cost {\n ...CartLineCost\n }\n attributes {\n key\n value\n }\n attributeSelections {\n ...AttributeSelection\n }\n productId\n productTitle\n productHandle\n productType\n requiresShipping\n}",
|
|
2127
|
+
"body": "fragment CartLine on CartLine {\n id\n quantity\n variant {\n ...ProductVariant\n }\n cost {\n ...CartLineCost\n }\n attributes {\n key\n value\n }\n attributeSelections {\n ...AttributeSelection\n }\n productId\n productTitle\n productHandle\n productType\n requiresShipping\n giftCardRecipient {\n recipientEmail\n recipientName\n message\n }\n}",
|
|
2128
2128
|
"onType": "CartLine"
|
|
2129
2129
|
},
|
|
2130
2130
|
{
|
package/package.json
CHANGED
package/schema.graphql
CHANGED
|
@@ -1360,6 +1360,11 @@ type CartLine {
|
|
|
1360
1360
|
"""
|
|
1361
1361
|
cost: CartLineCost!
|
|
1362
1362
|
|
|
1363
|
+
"""
|
|
1364
|
+
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.
|
|
1365
|
+
"""
|
|
1366
|
+
giftCardRecipient: GiftCardLineRecipient
|
|
1367
|
+
|
|
1363
1368
|
"""
|
|
1364
1369
|
Stable line identifier. Use it to address the line in `cartUpdateLines` / `cartRemoveLines`.
|
|
1365
1370
|
"""
|
|
@@ -3025,6 +3030,22 @@ enum GiftCardErrorCode {
|
|
|
3025
3030
|
NOT_FOUND
|
|
3026
3031
|
}
|
|
3027
3032
|
|
|
3033
|
+
"""
|
|
3034
|
+
Recipient details attached to a `GIFT_CARD` line — set with `cartUpdateGiftCardRecipient`. All fields are nullable individually so a partial set (e.g. email only) is representable.
|
|
3035
|
+
"""
|
|
3036
|
+
type GiftCardLineRecipient {
|
|
3037
|
+
"""Personalised message included with the gift card."""
|
|
3038
|
+
message: String
|
|
3039
|
+
|
|
3040
|
+
"""
|
|
3041
|
+
Recipient email — where the gift card code will be delivered on order completion.
|
|
3042
|
+
"""
|
|
3043
|
+
recipientEmail: String
|
|
3044
|
+
|
|
3045
|
+
"""Recipient display name shown in the gift card email."""
|
|
3046
|
+
recipientName: String
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3028
3049
|
"""Gift card status"""
|
|
3029
3050
|
enum GiftCardStatus {
|
|
3030
3051
|
ACTIVE
|