@doswiftly/storefront-sdk 11.5.0 → 13.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/CHANGELOG.md CHANGED
@@ -1,5 +1,214 @@
1
1
  # Changelog
2
2
 
3
+ ## 13.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 783ce01: Faceted aggregation accuracy + DX naming consolidation w `productFilters` API. Plus boolean facet count dla "availableForSale" + payload cleanup w Cart query.
8
+
9
+ ## BREAKING — `AvailableFilters.matchCount` removed → `totalCount`
10
+
11
+ Pole `matchCount` zostało usunięte. Użyj `totalCount` — semantyka identyczna (produkty w current context PRZED zaaplikowaniem faceted filters), nazwa zaligned z `ProductConnection.totalCount` (Relay Connection spec).
12
+
13
+ **Migration** (1:1 rename):
14
+
15
+ ```graphql
16
+ # PRZED
17
+ query Listing {
18
+ productFilters {
19
+ matchCount # ❌ removed
20
+ activeCount
21
+ }
22
+ }
23
+
24
+ # PO
25
+ query Listing {
26
+ productFilters {
27
+ totalCount # ✅ same semantics, Relay-aligned
28
+ activeCount
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## BREAKING — `ProductFilter.available: true` semantics
34
+
35
+ Filter teraz includuje untracked produkty (gift cards, digital, made-to-order — wszystko z `trackQuantity = false`). Semantyka zgodna z `Product.isAvailable` resolver — single source of truth dla "co jest sellable".
36
+
37
+ **Pre-fix**: `available: true` zwracał tylko produkty z fizycznym stockiem (`available > 0`), wykluczał untracked. Storefront widział "Dostępne (3)" w sidebar (computed via `isAvailable`), po kliku dostawał 2 produkty (SQL filter różny).
38
+
39
+ **Post-fix**: oba źródła zwracają to samo.
40
+
41
+ Jeśli polegałeś na exclusion untracked przez `available: true` (np. żeby ukryć gift cards) — użyj `ProductFilter.type` lub osobnej logiki klienckiej.
42
+
43
+ ## NEW — `AvailableFilters.availableCount: Int!`
44
+
45
+ Nowy boolean facet count — liczba produktów spełniających `Product.isAvailable` w current context. Storefront UI renderuje "Dostępne (N)" w sidebar facet panel.
46
+
47
+ Exclude-self: gdy `AvailableFiltersInput.available` jest provided w `currentFilters`, `availableCount` IGNORUJE ten filter (pokazuje "ile produktów ten facet odsłoni gdy włączysz") — inne facets aplikują go normalnie.
48
+
49
+ ## NEW — `AvailableFiltersInput.available: Boolean`
50
+
51
+ Storefront może passować obecny `available` filter context do `productFilters` query — wymagane dla exclude-self semantyki. Pomiń (null/undefined) gdy filtr "Dostępne" nie jest aktywny w UI.
52
+
53
+ ## IMPROVEMENT — Faceted count accuracy (`productCount` mismatch eliminated)
54
+
55
+ Per-attribute / per-brand / per-category `productCount` teraz używa exclude-self aggregation pattern. Facet count MATCHUJE `products(filters).totalCount` gdy storefront aplikuje facet jako filter.
56
+
57
+ **Pre-fix**: `productFilters({categoryId, available: true}).attributes[producent].filterValues[Funko].productCount = 4` (ignoring `available`), `products({categoryId, available: true, attributes: [Funko]}).totalCount = 3` (3 sellable + 1 OOS Funko). Storefront pokazywał "Funko (4)", user dostawał 3 — utracone zaufanie do countów.
58
+
59
+ **Post-fix**: oba zwracają 3. Facet ignoruje WYŁĄCZNIE swój wymiar w `currentFilters`, aplikuje pozostałe + `available` + context (categoryId/collectionId/searchQuery).
60
+
61
+ ## IMPROVEMENT — Cart query payload size
62
+
63
+ `Cart.lines` query w SDK używał obu form (`edges + nodes`) z których konsumowane były wyłącznie `nodes`. Backend serializował `CartLine` fragment 2× per request. Usunięcie duplikatu — redukcja payload typowo 5-20KB per cart request (proportional do liczby pozycji).
64
+
65
+ Brak API change widzialnej dla consumer — SDK używa `cart.lines.nodes` jak wcześniej. Internal SDK improvement.
66
+
67
+ ## Example: end-to-end facet sidebar query (post-rename)
68
+
69
+ ```graphql
70
+ query ProductListing($input: AvailableFiltersInput) {
71
+ productFilters(input: $input) {
72
+ totalCount # ile produktów w current context (przed faceted filters)
73
+ availableCount # ile sellable (boolean facet, exclude-self)
74
+ activeCount # input.currentFilters.length
75
+ attributes {
76
+ handle
77
+ filterValues {
78
+ value
79
+ productCount
80
+ } # per-value facet count (exclude-self per attrDef)
81
+ }
82
+ brands {
83
+ slug
84
+ name
85
+ productCount
86
+ } # per-brand facet count
87
+ categories {
88
+ slug
89
+ name
90
+ productCount
91
+ } # per-category facet count
92
+ priceRange {
93
+ min {
94
+ amount
95
+ currencyCode
96
+ }
97
+ max {
98
+ amount
99
+ currencyCode
100
+ }
101
+ }
102
+ }
103
+
104
+ products(
105
+ filters: [
106
+ { available: true }
107
+ { attributes: [{ attributeId: "producent", values: ["Funko"] }] }
108
+ ]
109
+ ) {
110
+ totalCount
111
+ nodes {
112
+ id
113
+ title
114
+ isAvailable
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ Gdy storefront aplikuje "Dostępne + Producent=Funko" jako filter w UI:
121
+
122
+ ```graphql
123
+ variables: {
124
+ input: {
125
+ available: true,
126
+ currentFilters: [{ attributeId: "producent", values: ["Funko"] }]
127
+ }
128
+ }
129
+ ```
130
+
131
+ - `availableCount` = liczba sellable Funko w context (ignoring `input.available`, applying `producent: Funko`)
132
+ - `attributes[producent].filterValues[Funko].productCount` = liczba sellable produktów (ignoring `producent`, applying `available: true`) = `products(filters).totalCount`
133
+
134
+ ### Minor Changes
135
+
136
+ - e64cfc5: Brand entity available in Storefront API: filter products by canonical brand + read brand details per product.
137
+
138
+ **What's new in Storefront API**
139
+ - **`Product.brand: BrandSummary`** — every product now exposes its canonical brand (when assigned). Returns `{ id, name, slug, logo }` or `null` if the product has no brand. Resolved via DataLoader so listing 50 products incurs at most 1 brand query (no N+1).
140
+ - **`ProductFilter.brand: BrandFilter`** — new filter input accepting either `{ id: "uuid" }` or `{ slug: "funko" }`. Multiple `brand` entries in `filters[]` use OR semantics. Combine with other filters (price, tags, attributes) using AND across different field names.
141
+ - **`AvailableFilters.brands: [BrandFilterValue!]!`** — `productFilters` query now returns aggregated brands present in the current product set, each with `productCount`. Build a brand facet (checkbox list or dropdown with logo) directly from this response. Only active brands with at least one product in context are included.
142
+
143
+ **Example: brand facet + filter on a listing page**
144
+
145
+ ```graphql
146
+ query Listing {
147
+ productFilters {
148
+ brands {
149
+ id
150
+ name
151
+ slug
152
+ logo
153
+ productCount
154
+ }
155
+ }
156
+ products(filters: [{ brand: { slug: "funko" } }]) {
157
+ totalCount
158
+ nodes {
159
+ id
160
+ title
161
+ brand {
162
+ name
163
+ slug
164
+ logo
165
+ }
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ **Migration**
172
+ - Existing `Product.vendor: String` (legacy free-text) remains supported. New brand-based filtering uses `ProductFilter.brand` instead of `productVendor`.
173
+ - No breaking changes. All new fields are nullable / optional — queries written before this release continue to work.
174
+
175
+ **SDK**
176
+
177
+ Regenerated types include `BrandSummary`, `BrandFilter`, `BrandFilterValue`, and `Product.brand`. Import them from `@doswiftly/storefront-operations` schema types.
178
+
179
+ ## 12.0.0
180
+
181
+ ### Major Changes
182
+
183
+ - 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.
184
+
185
+ ### Why removed
186
+
187
+ 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.
188
+
189
+ ### New model — storefront-driven recipient mode
190
+
191
+ Common e-commerce convention for gift card flow:
192
+ 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.
193
+ 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.
194
+
195
+ 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.
196
+
197
+ ### Migration
198
+
199
+ If your storefront was reading `Product.requiresRecipientInfo` to conditionally show a recipient form, replace the gate with a simple product type check:
200
+
201
+ ```diff
202
+ - {product.requiresRecipientInfo && (
203
+ + {product.type === 'GIFT_CARD' && (
204
+ <GiftRecipientForm cartId={cartId} lineItemId={lineItemId} />
205
+ )}
206
+ ```
207
+
208
+ If you were not reading the field, no storefront changes are required — the fallback ensures gift card delivery works out of the box.
209
+
210
+ 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.
211
+
3
212
  ## 11.5.0
4
213
 
5
214
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../../src/core/operations/cart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAwSH,eAAO,MAAM,UAAU,QAOrB,CAAC;AAMH,eAAO,MAAM,WAAW,QAWtB,CAAC;AAEH,eAAO,MAAM,cAAc,QAWzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAW3B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAMH,eAAO,MAAM,yBAAyB,QAWpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAWnC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAWtC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAW/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAWhC,CAAC;AAEH,eAAO,MAAM,+BAA+B,QAW1C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,QAWxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAoBtC,CAAC"}
1
+ {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../../src/core/operations/cart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoSH,eAAO,MAAM,UAAU,QAOrB,CAAC;AAMH,eAAO,MAAM,WAAW,QAWtB,CAAC;AAEH,eAAO,MAAM,cAAc,QAWzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAW3B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAMH,eAAO,MAAM,yBAAyB,QAWpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAWnC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAWtC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAW/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAWhC,CAAC;AAEH,eAAO,MAAM,+BAA+B,QAW1C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,QAWxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAoBtC,CAAC"}
@@ -191,10 +191,6 @@ const CART_FRAGMENT = `
191
191
  totalQuantity
192
192
  cost { ...CartCost }
193
193
  lines(first: 100) {
194
- edges {
195
- cursor
196
- node { ... on CartLine { ...CartLine } }
197
- }
198
194
  nodes { ... on CartLine { ...CartLine } }
199
195
  pageInfo { ...PageInfo }
200
196
  totalCount
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doswiftly/storefront-sdk",
3
- "version": "11.5.0",
3
+ "version": "13.0.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,