@doswiftly/storefront-operations 11.4.0 → 12.0.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 +81 -0
- package/fragments.graphql +0 -1
- package/llms-full.txt +1 -2
- package/operations.json +2 -2
- package/package.json +1 -1
- package/schema.graphql +0 -3
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**:
|
|
30
|
+
- **Schema version**: 12.0.0
|
|
31
31
|
- **Queries**: 49
|
|
32
32
|
- **Mutations**: 40
|
|
33
33
|
- **Fragments**: 100
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,86 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 12.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 2ff6b16: **BREAKING**: `Product.requiresRecipientInfo` field has been removed from the storefront GraphQL schema. Every paid gift card line now guarantees email delivery — to the recipient when your storefront captured one, otherwise to the buyer as fallback.
|
|
8
|
+
|
|
9
|
+
### Why removed
|
|
10
|
+
|
|
11
|
+
The field exposed a per-product merchant toggle intended to gate whether your storefront should collect gift card recipient info (email, name, message) at checkout. In practice the toggle did not change actual delivery behaviour — every storefront ended up deciding on its own whether to render a recipient form, and the platform sent emails based solely on whether per-line recipient data was present. Merchants saw an admin control that had no effect downstream, so it has been removed in favour of an explicit storefront-driven model.
|
|
12
|
+
|
|
13
|
+
### New model — storefront-driven recipient mode
|
|
14
|
+
|
|
15
|
+
Common e-commerce convention for gift card flow:
|
|
16
|
+
1. **Your storefront opts in**: render a recipient form on PDP / cart drawer for any cart line where `product.type === 'GIFT_CARD'`. Call `cartUpdateGiftCardRecipient({ cartId, lineItemId, recipientEmail, recipientName?, message? })` per line where the buyer fills it in.
|
|
17
|
+
2. **Your storefront opts out**: skip the mutation entirely. Gift cards still ship — the platform emails the code to the buyer (the same email used at checkout) as a fallback.
|
|
18
|
+
|
|
19
|
+
Every paid gift card is now guaranteed to land in someone's inbox — either the explicit recipient (when collected) or the buyer (fallback). Previously, missing recipient data caused a silent email skip, leaving customers without their codes.
|
|
20
|
+
|
|
21
|
+
### Migration
|
|
22
|
+
|
|
23
|
+
If your storefront was reading `Product.requiresRecipientInfo` to conditionally show a recipient form, replace the gate with a simple product type check:
|
|
24
|
+
|
|
25
|
+
```diff
|
|
26
|
+
- {product.requiresRecipientInfo && (
|
|
27
|
+
+ {product.type === 'GIFT_CARD' && (
|
|
28
|
+
<GiftRecipientForm cartId={cartId} lineItemId={lineItemId} />
|
|
29
|
+
)}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If you were not reading the field, no storefront changes are required — the fallback ensures gift card delivery works out of the box.
|
|
33
|
+
|
|
34
|
+
See [cart docs — Karty podarunkowe — dostawa kodu](https://docs.doswiftly.pl/storefront-developer/sdk/cart#karty-podarunkowe--dostawa-kodu) for the full delivery semantics, a cart-structuring table (one gift card for self vs N gift cards for N recipients), and a recipient form example.
|
|
35
|
+
|
|
36
|
+
## 11.5.0
|
|
37
|
+
|
|
38
|
+
### Minor Changes
|
|
39
|
+
|
|
40
|
+
- 190fd9d: Version sync with `@doswiftly/storefront-sdk` (linked release pair). No operations file changes — `OrderByToken` query and `Order.accessToken` field were shipped in the previous version (11.4.0); this bump keeps the operations package version aligned with the SDK release that now selects `accessToken` in its built-in `Order` fragment for `cartComplete`.
|
|
41
|
+
|
|
42
|
+
If you already use `@doswiftly/storefront-operations` for codegen, no regeneration is required (`queries.graphql` and `fragments.graphql` are unchanged). The companion `@doswiftly/storefront-sdk` upgrade is where the actual behavior change lands (see that changelog entry).
|
|
43
|
+
|
|
44
|
+
- e6c80ce: Auth route handlers (`createSetTokenHandler`, `createClearTokenHandler`, `createWhoamiHandler`) now accept an optional `isTrustedOrigin` predicate. This unblocks the BFF auth flow when the storefront runs behind a reverse proxy (DoSwiftly hosting, Vercel, custom edge proxy) that rewrites or strips the `Host` header — since 11.3.0 the strict `Origin host = Host` comparison returned 403 for every login, logout, and page-load hydration in that topology, leaving the auth cookie unset and every auth-gated route redirecting to login.
|
|
45
|
+
|
|
46
|
+
### Fix
|
|
47
|
+
|
|
48
|
+
Each handler accepts a new `isTrustedOrigin` callback:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
type OriginValidator = (ctx: {
|
|
52
|
+
origin: string;
|
|
53
|
+
originHost: string;
|
|
54
|
+
request: Request;
|
|
55
|
+
}) => boolean | Promise<boolean>;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
When the predicate returns truthy the strict `Origin host = Host header` comparison is bypassed; when it returns falsy (or is not configured) the existing strict check applies. A thrown predicate fails closed — the error is logged and the strict check applies as if the predicate returned `false`.
|
|
59
|
+
|
|
60
|
+
Two pre-built predicates are exported:
|
|
61
|
+
- `trustedForwardedHostValidator` — passes when `Origin host` equals `X-Forwarded-Host` (falling back to `X-Original-Host`). Use this when a reverse proxy you control sets one of those headers per request. The DoSwiftly hosting platform and Vercel both qualify.
|
|
62
|
+
- `originAllowlistValidator(['https://shop.example.com', 'other-shop.example'])` — passes when `Origin` matches an entry in a static list. Useful when one storefront is hosted on multiple hostnames (custom apex + platform subdomain) and you do not want to depend on forwarded-host headers.
|
|
63
|
+
|
|
64
|
+
### Upgrade impact
|
|
65
|
+
- New storefronts scaffolded via `doswiftly init` ship with `isTrustedOrigin: trustedForwardedHostValidator` configured by default.
|
|
66
|
+
- Existing storefronts using the SDK behind a reverse proxy need a 3-line change to each route handler under `app/api/auth/`:
|
|
67
|
+
```ts
|
|
68
|
+
import {
|
|
69
|
+
createSetTokenHandler,
|
|
70
|
+
trustedForwardedHostValidator,
|
|
71
|
+
} from "@doswiftly/storefront-sdk";
|
|
72
|
+
export const POST = createSetTokenHandler({
|
|
73
|
+
isTrustedOrigin: trustedForwardedHostValidator,
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
- Storefronts deployed without a reverse proxy (single-tier hosting where the Next.js process receives traffic directly) need no changes — the default strict check still works because the Host header arrives intact.
|
|
77
|
+
|
|
78
|
+
### Security
|
|
79
|
+
|
|
80
|
+
The predicate is invoked AFTER the Origin header is parsed (rejecting malformed origins) and BEFORE the strict Host comparison. Forwarded-host validation is safe because the trusted intermediary overwrites those headers on every inbound request (`headers.set(...)`, not `append`), so an attacker cannot forge them via a browser `fetch()` — browsers cannot set `X-Forwarded-*` from JavaScript (they are forbidden request headers per the fetch spec).
|
|
81
|
+
|
|
82
|
+
Defense-in-depth layers continue to apply: CORS preflight at the backend, `SameSite=Lax` on the auth cookie, `HttpOnly` + `Secure` cookie attributes, and the strict Origin URL parse (still rejects malformed origin and the `?host=trusted` query-string bypass).
|
|
83
|
+
|
|
3
84
|
## 11.4.0
|
|
4
85
|
|
|
5
86
|
### Minor Changes
|
package/fragments.graphql
CHANGED
package/llms-full.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DoSwiftly Storefront Operations — Full Reference
|
|
2
2
|
|
|
3
|
-
> Schema version: **
|
|
3
|
+
> Schema version: **12.0.0**
|
|
4
4
|
> 49 queries · 40 mutations · 100 fragments
|
|
5
5
|
|
|
6
6
|
Auto-generated from `.graphql` source files. Do not edit by hand — this file is
|
|
@@ -2602,7 +2602,6 @@ fragment ProductBase on Product {
|
|
|
2602
2602
|
descriptionHtml
|
|
2603
2603
|
stockTotal
|
|
2604
2604
|
type
|
|
2605
|
-
requiresRecipientInfo
|
|
2606
2605
|
visibility
|
|
2607
2606
|
attributeSetId
|
|
2608
2607
|
createdAt
|
package/operations.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion": "
|
|
2
|
+
"schemaVersion": "12.0.0",
|
|
3
3
|
"queries": [
|
|
4
4
|
{
|
|
5
5
|
"name": "Shop",
|
|
@@ -1932,7 +1932,7 @@
|
|
|
1932
1932
|
"fragmentRefs": [
|
|
1933
1933
|
"ProductCard"
|
|
1934
1934
|
],
|
|
1935
|
-
"body": "fragment ProductBase on Product {\n ...ProductCard\n description\n descriptionHtml\n stockTotal\n type\n
|
|
1935
|
+
"body": "fragment ProductBase on Product {\n ...ProductCard\n description\n descriptionHtml\n stockTotal\n type\n visibility\n attributeSetId\n createdAt\n updatedAt\n}",
|
|
1936
1936
|
"onType": "Product"
|
|
1937
1937
|
},
|
|
1938
1938
|
{
|
package/package.json
CHANGED
package/schema.graphql
CHANGED
|
@@ -4083,9 +4083,6 @@ type Product implements Node {
|
|
|
4083
4083
|
"""Similar products recommendations"""
|
|
4084
4084
|
recommendations(first: Int = 4): ProductRecommendations
|
|
4085
4085
|
|
|
4086
|
-
"""Whether storefront checkout requires recipient data for this product"""
|
|
4087
|
-
requiresRecipientInfo: Boolean!
|
|
4088
|
-
|
|
4089
4086
|
"""Number of reviews"""
|
|
4090
4087
|
reviewCount: Int
|
|
4091
4088
|
|