@doswiftly/storefront-operations 13.0.0 → 14.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/schema.graphql CHANGED
@@ -63,7 +63,9 @@ type AttributeDefinition {
63
63
  """Attribute ID"""
64
64
  id: ID!
65
65
 
66
- """Whether attribute is filterable"""
66
+ """
67
+ Whether attribute is filterable (admin toggle). For storefront UI rendering signal use `isUsableAsFilter` (computed).
68
+ """
67
69
  isFilterable: Boolean!
68
70
 
69
71
  """Whether attribute is visible on product pages"""
@@ -140,6 +142,34 @@ type AttributeFilterValue {
140
142
  value: String!
141
143
  }
142
144
 
145
+ """Paginated + searchable attribute options (Relay Connection)"""
146
+ type AttributeFilterValueConnection {
147
+ """Paginated edges z cursorami"""
148
+ edges: [AttributeFilterValueEdge!]!
149
+
150
+ """Shortcut: edges.map(e => e.node)"""
151
+ nodes: [AttributeFilterValue!]!
152
+
153
+ """Relay pagination info (hasNextPage, hasPreviousPage, cursors)"""
154
+ pageInfo: PageInfo!
155
+
156
+ """
157
+ Total number of attribute options matching the filter (po zastosowaniu search + context). NIE zmienia się przy paginacji — pokazuje pełną liczbę dla counter UI.
158
+ """
159
+ totalCount: Int!
160
+ }
161
+
162
+ """Edge w AttributeFilterValueConnection (Relay spec)"""
163
+ type AttributeFilterValueEdge {
164
+ """
165
+ Opaque pagination cursor (base64-encoded). Echo as `after` for next page.
166
+ """
167
+ cursor: String!
168
+
169
+ """Attribute filter value (option + product count + swatch)"""
170
+ node: AttributeFilterValue!
171
+ }
172
+
143
173
  """Attribute input"""
144
174
  input AttributeInput {
145
175
  """Attribute key"""
@@ -157,6 +187,37 @@ enum AttributeOptionSurchargeType {
157
187
  PERCENT
158
188
  }
159
189
 
190
+ """Input dla attributeOptionsSearch query"""
191
+ input AttributeOptionsSearchInput {
192
+ """Opaque cursor z pageInfo.endCursor poprzedniej strony"""
193
+ after: String
194
+
195
+ """
196
+ Produktowy kontekst (categoryId/collectionId/searchQuery/currentFilters) dla accurate productCount. Exclude-self: gdy currentFilters zawiera ten sam atrybut, jest pomijany.
197
+ """
198
+ contextInput: AvailableFiltersInput
199
+
200
+ """Liczba zwracanych opcji (default 50, max 100)"""
201
+ first: Int
202
+
203
+ """Attribute handle (URL-friendly identifier, np. "licencja")"""
204
+ handle: String!
205
+
206
+ """Wyszukiwanie po value/label (case-insensitive ILIKE, max 100 znaków)"""
207
+ search: String
208
+
209
+ """
210
+ Sort — COUNT_DESC default (most popular first), LABEL_ASC dla alphabetical
211
+ """
212
+ sort: AttributeOptionsSearchSort
213
+ }
214
+
215
+ """Sort order for attributeOptionsSearch results"""
216
+ enum AttributeOptionsSearchSort {
217
+ COUNT_DESC
218
+ LABEL_ASC
219
+ }
220
+
160
221
  """Min/max bounds for numeric attributes"""
161
222
  type AttributeRangeBounds {
162
223
  """Currency code for CURRENCY type"""
@@ -271,7 +332,7 @@ type AvailableFilters {
271
332
  availableCount: Int!
272
333
 
273
334
  """
274
- Faza 3 (2026-05-17): canonical Brand entities z product counts w current context. Storefront UI renderuje checkbox list / dropdown z logo per brand. Klik → `filters: [{brand: {slug}}]`. Tylko brandy z >0 produktów w current product set + isActive=true.
335
+ Faza 3 (2026-05-17): canonical Brand entities z product counts w current context. Storefront UI renderuje checkbox list / dropdown z logo per brand. Klik → `filters: [{brand: {handle}}]`. Tylko brandy z >0 produktów w current product set + isActive=true.
275
336
  """
276
337
  brands: [BrandFilterValue!]
277
338
 
@@ -431,6 +492,9 @@ type BlogCategory {
431
492
  """Category description"""
432
493
  description: String
433
494
 
495
+ """URL-friendly handle"""
496
+ handle: String!
497
+
434
498
  """Category ID"""
435
499
  id: ID!
436
500
 
@@ -445,9 +509,6 @@ type BlogCategory {
445
509
 
446
510
  """SEO metadata"""
447
511
  seo: SEO
448
-
449
- """URL-friendly slug"""
450
- slug: String!
451
512
  }
452
513
 
453
514
  """Blog post"""
@@ -479,6 +540,9 @@ type BlogPost {
479
540
  """Featured image"""
480
541
  featuredImage: Image
481
542
 
543
+ """URL-friendly handle"""
544
+ handle: String!
545
+
482
546
  """Post ID"""
483
547
  id: ID!
484
548
 
@@ -494,9 +558,6 @@ type BlogPost {
494
558
  """SEO metadata"""
495
559
  seo: SEO
496
560
 
497
- """URL-friendly slug"""
498
- slug: String!
499
-
500
561
  """Post status"""
501
562
  status: BlogPostStatus!
502
563
 
@@ -552,6 +613,9 @@ enum BlogPostStatus {
552
613
 
553
614
  """Blog tag"""
554
615
  type BlogTag {
616
+ """URL-friendly handle"""
617
+ handle: String!
618
+
555
619
  """Tag ID"""
556
620
  id: ID!
557
621
 
@@ -560,9 +624,6 @@ type BlogTag {
560
624
 
561
625
  """Number of posts with this tag"""
562
626
  postCount: Int!
563
-
564
- """URL-friendly slug"""
565
- slug: String!
566
627
  }
567
628
 
568
629
  """Bot protection configuration (platform-level)"""
@@ -589,25 +650,21 @@ type BotProtectionProviderInfo {
589
650
  siteKey: String!
590
651
  }
591
652
 
592
- """Shop brand metadata (logo, colors, slogan)"""
653
+ """
654
+ Canonical product brand entity (np. Funko, Nike). Distinct od ShopBrand (shop branding metadata).
655
+ """
593
656
  type Brand {
594
- """Primary + secondary brand colors"""
595
- colors: BrandColors
596
-
597
- """Cover image / hero banner"""
598
- coverImage: Image
599
-
600
- """Primary logo"""
601
- logo: Image
657
+ """URL-friendly handle (e.g. "funko" → /brands/funko). Stable per-shop."""
658
+ handle: String!
602
659
 
603
- """Short brand description"""
604
- shortDescription: String
660
+ """Brand unique identifier"""
661
+ id: ID!
605
662
 
606
- """Marketing slogan / tagline"""
607
- slogan: String
663
+ """Brand logo URL (CDN-served, storefront-rendered)"""
664
+ logo: String
608
665
 
609
- """Square logo variant (favicons, app tiles)"""
610
- squareLogo: Image
666
+ """Brand display name (e.g. "Funko", "Nintendo")"""
667
+ name: String!
611
668
  }
612
669
 
613
670
  """Single brand color group (background + foreground hex)"""
@@ -627,17 +684,20 @@ type BrandColors {
627
684
 
628
685
  """Filter products po brand (canonical entity)"""
629
686
  input BrandFilter {
630
- """Brand ID — exact UUID match"""
631
- id: ID
632
-
633
687
  """
634
- Brand slug — URL-friendly identifier. Preferowany over `id` dla storefront refetch (stable po URL share).
688
+ Brand handle — URL-friendly identifier. Preferowany over `id` dla storefront refetch (stable po URL share).
635
689
  """
636
- slug: String
690
+ handle: String
691
+
692
+ """Brand ID — exact UUID match"""
693
+ id: ID
637
694
  }
638
695
 
639
696
  """Brand filter value z product count"""
640
697
  type BrandFilterValue {
698
+ """Brand handle (refetch payload — paste w ProductFilter.brand.handle)"""
699
+ handle: String!
700
+
641
701
  """Brand ID"""
642
702
  id: ID!
643
703
 
@@ -649,26 +709,6 @@ type BrandFilterValue {
649
709
 
650
710
  """Liczba produktów z tym brandem w current product set"""
651
711
  productCount: Int!
652
-
653
- """Brand slug (refetch payload — paste w ProductFilter.brand.slug)"""
654
- slug: String!
655
- }
656
-
657
- """
658
- Brand summary — minimalna projekcja dla storefront catalog + filter rendering
659
- """
660
- type BrandSummary {
661
- """Brand unique identifier"""
662
- id: ID!
663
-
664
- """Brand logo URL (CDN-served, storefront-rendered)"""
665
- logo: String
666
-
667
- """Brand display name (e.g. "Funko", "Nintendo")"""
668
- name: String!
669
-
670
- """URL-friendly slug — używane dla future /marka/[slug] landing pages"""
671
- slug: String!
672
712
  }
673
713
 
674
714
  """Business hours for a day"""
@@ -776,6 +816,11 @@ type Cart implements Node {
776
816
  """Available payment methods dla tego cart (shop-configured providers)"""
777
817
  availablePaymentMethods: [PaymentMethod!]!
778
818
 
819
+ """
820
+ Cart-aware shipping methods discovery. Returns empty methods + DIGITAL_ONLY_NO_SHIPPING user error when the cart contains only non-physical items (digital, gift card, service, subscription). Physical / mixed carts get the same method computation as the standalone `availableShippingMethods` query but with subtotal and weight pulled from the cart aggregate.
821
+ """
822
+ availableShippingMethods(address: ShippingAddressInput!): AvailableShippingMethodsPayload!
823
+
779
824
  """
780
825
  Billing address ustawiony przez cartSetBillingAddress (jeśli różny od shipping)
781
826
  """
@@ -821,6 +866,11 @@ type Cart implements Node {
821
866
  """Product recommendations based on cart contents"""
822
867
  recommendations(first: Int = 4): CartRecommendations
823
868
 
869
+ """
870
+ True if any line in the cart requires physical shipping. False when every line is non-physical (digital, gift card, service, subscription). Use as the single signal to render or skip the shipping picker in checkout.
871
+ """
872
+ requiresShipping: Boolean!
873
+
824
874
  """Selected payment method (PayU/Stripe/COD/etc.)"""
825
875
  selectedPaymentMethod: PaymentMethod
826
876
 
@@ -1139,6 +1189,11 @@ type CartLine {
1139
1189
  """Quantity of this item"""
1140
1190
  quantity: Int!
1141
1191
 
1192
+ """
1193
+ True if this line item requires physical shipping (productType=PHYSICAL). False for digital, gift card, service, and subscription items. Use to skip the shipping step in checkout when every line is non-physical.
1194
+ """
1195
+ requiresShipping: Boolean!
1196
+
1142
1197
  """Product variant being purchased"""
1143
1198
  variant: ProductVariant!
1144
1199
  }
@@ -1491,6 +1546,7 @@ enum CartWarningCode {
1491
1546
  MERCHANDISE_NOT_AVAILABLE
1492
1547
  MERCHANDISE_NOT_ENOUGH_STOCK
1493
1548
  PAYMENTS_AMOUNT_REGION_MISMATCH
1549
+ SHIPPING_METHOD_AUTO_CLEARED
1494
1550
  }
1495
1551
 
1496
1552
  """Product category - hierarchical organization"""
@@ -1501,6 +1557,11 @@ type Category {
1501
1557
  """Category description"""
1502
1558
  description: String
1503
1559
 
1560
+ """
1561
+ URL-friendly handle (e.g. "electronics" -> /categories/electronics). Stable per-shop.
1562
+ """
1563
+ handle: String!
1564
+
1504
1565
  """Unique identifier"""
1505
1566
  id: ID!
1506
1567
 
@@ -1528,9 +1589,6 @@ type Category {
1528
1589
  """SEO metadata"""
1529
1590
  seo: SEO
1530
1591
 
1531
- """URL-friendly slug"""
1532
- slug: String!
1533
-
1534
1592
  """Sort order within parent"""
1535
1593
  sortOrder: Int!
1536
1594
  }
@@ -1567,6 +1625,9 @@ input CategoryFilter {
1567
1625
 
1568
1626
  """Category filter option"""
1569
1627
  type CategoryFilterOption {
1628
+ """URL-friendly handle"""
1629
+ handle: String!
1630
+
1570
1631
  """Category ID"""
1571
1632
  id: ID!
1572
1633
 
@@ -1581,9 +1642,6 @@ type CategoryFilterOption {
1581
1642
 
1582
1643
  """Number of products in this category"""
1583
1644
  productCount: Int!
1584
-
1585
- """URL-friendly slug"""
1586
- slug: String!
1587
1645
  }
1588
1646
 
1589
1647
  """Collection - curated group of products"""
@@ -3015,6 +3073,9 @@ type LoyaltyReward {
3015
3073
  """Discount percentage (if discount type)"""
3016
3074
  discountPercent: Float
3017
3075
 
3076
+ """URL-friendly handle"""
3077
+ handle: String!
3078
+
3018
3079
  """Reward ID"""
3019
3080
  id: ID!
3020
3081
 
@@ -3033,9 +3094,6 @@ type LoyaltyReward {
3033
3094
  """Redemptions remaining (null = unlimited)"""
3034
3095
  redemptionsRemaining: Int
3035
3096
 
3036
- """URL-friendly slug"""
3037
- slug: String!
3038
-
3039
3097
  """Minimum tier required"""
3040
3098
  tierRequired: LoyaltyTier
3041
3099
 
@@ -3348,16 +3406,17 @@ type MenuItem {
3348
3406
  type: MenuItemType!
3349
3407
 
3350
3408
  """
3351
- Resolved URL path computed server-side (e.g., /categories/funko, /products/toy-1, /pages/about, /collections/sale). Static types resolve to /, /search, /products, /blog. HTTP type returns the manually stored URL. Null only when type is a resource link (CATEGORY/COLLECTION/PAGE/PRODUCT) and the resource was deleted.
3409
+ Pre-resolved URL path computed server-side using a standard route convention: /categories/<handle>, /collections/<handle>, /pages/<handle>, /products/<handle>, /brands/<handle>. Static types resolve to /, /search, /products, /blog. HTTP returns the manually stored URL. Null when type is a resource link and the underlying resource was deleted. If your storefront uses non-standard routing (e.g. single-segment /<handle>), prefer reading the `resource` field instead and build URLs yourself from `resource.__typename` + `handle`.
3352
3410
  """
3353
3411
  url: URL
3354
3412
  }
3355
3413
 
3356
- union MenuItemResource = Category | Collection | Product | ShopPage
3414
+ union MenuItemResource = Brand | Category | Collection | Product | ShopPage
3357
3415
 
3358
3416
  """Menu item link type"""
3359
3417
  enum MenuItemType {
3360
3418
  BLOG
3419
+ BRAND
3361
3420
  CATALOG
3362
3421
  CATEGORY
3363
3422
  COLLECTION
@@ -3994,7 +4053,7 @@ type Product implements Node {
3994
4053
  """
3995
4054
  Canonical brand entity (Faza 3, 2026-05-17). Resolved via DataLoader (N+1 safe dla list queries). Null gdy product nie ma przypisanego brand_id.
3996
4055
  """
3997
- brand: BrandSummary
4056
+ brand: Brand
3998
4057
 
3999
4058
  """
4000
4059
  Wszystkie kategorie do których produkt należy (M2M przez ProductCategory junction). Posortowane po junction.sortOrder ASC. Empty list gdy produkt nie jest w żadnej kategorii.
@@ -4108,6 +4167,9 @@ type ProductAttributeDefinition {
4108
4167
  """Filling mode — MERCHANT | CUSTOMER | BOTH"""
4109
4168
  fillingMode: AttributeFillingMode!
4110
4169
 
4170
+ """URL-friendly handle"""
4171
+ handle: String!
4172
+
4111
4173
  """Definition ID"""
4112
4174
  id: ID!
4113
4175
 
@@ -4134,9 +4196,6 @@ type ProductAttributeDefinition {
4134
4196
  """
4135
4197
  scopeProductId: ID
4136
4198
 
4137
- """URL-friendly slug"""
4138
- slug: String!
4139
-
4140
4199
  """Tax class ID; null = inherit from variant"""
4141
4200
  taxClassId: ID
4142
4201
 
@@ -4522,6 +4581,11 @@ type Query {
4522
4581
  """List of all currencies supported by the system (ECB rates)"""
4523
4582
  allSupportedCurrencies: [Currency!]!
4524
4583
 
4584
+ """
4585
+ Paginated + searchable attribute options dla drill-into filter UI (np. dropdown z 800 licencjami + search input). Honors product context z exclude-self per attribute. Sort: COUNT_DESC default (most popular first), LABEL_ASC dla alfabetycznego z polskim collation.
4586
+ """
4587
+ attributeOptionsSearch(input: AttributeOptionsSearchInput!): AttributeFilterValueConnection!
4588
+
4525
4589
  """Get available payment methods"""
4526
4590
  availablePaymentMethods: AvailablePaymentMethods!
4527
4591
 
@@ -4539,11 +4603,11 @@ type Query {
4539
4603
 
4540
4604
  """Get single blog post"""
4541
4605
  blogPost(
4606
+ """Post handle"""
4607
+ handle: String
4608
+
4542
4609
  """Post ID"""
4543
4610
  id: ID
4544
-
4545
- """Post slug"""
4546
- slug: String
4547
4611
  ): BlogPost
4548
4612
 
4549
4613
  """List blog posts"""
@@ -4554,8 +4618,8 @@ type Query {
4554
4618
  """Filter by author ID"""
4555
4619
  authorId: String
4556
4620
 
4557
- """Filter by category slug"""
4558
- categorySlug: String
4621
+ """Filter by category handle"""
4622
+ categoryHandle: String
4559
4623
 
4560
4624
  """Filter featured posts only"""
4561
4625
  featured: Boolean
@@ -4569,8 +4633,8 @@ type Query {
4569
4633
  """Sort key"""
4570
4634
  sortKey: BlogPostSortKey = PUBLISHED_AT
4571
4635
 
4572
- """Filter by tag slug"""
4573
- tagSlug: String
4636
+ """Filter by tag handle"""
4637
+ tagHandle: String
4574
4638
  ): BlogPostConnection!
4575
4639
 
4576
4640
  """List blog tags"""
@@ -4609,11 +4673,11 @@ type Query {
4609
4673
 
4610
4674
  """Get category by ID or slug"""
4611
4675
  category(
4676
+ """Category handle (URL-friendly)"""
4677
+ handle: String
4678
+
4612
4679
  """Category ID"""
4613
4680
  id: ID
4614
-
4615
- """Category slug"""
4616
- slug: String
4617
4681
  ): Category
4618
4682
 
4619
4683
  """Get single collection"""
@@ -5547,8 +5611,10 @@ type Shop {
5547
5611
  """Bot protection configuration (platform-level)"""
5548
5612
  botProtection: BotProtectionInfo
5549
5613
 
5550
- """Industry-standard brand metadata (logo + slogan + colors)"""
5551
- brand: Brand
5614
+ """
5615
+ Shop brand metadata (logo + slogan + colors). Tenant-scoped (vs canonical product `Brand` entity used in `Product.brand`).
5616
+ """
5617
+ brand: ShopBrand
5552
5618
 
5553
5619
  """Complete branding configuration"""
5554
5620
  branding: ShopBranding
@@ -5655,6 +5721,27 @@ type ShopAddress {
5655
5721
  streetLine2: String
5656
5722
  }
5657
5723
 
5724
+ """Shop brand metadata (logo, colors, slogan)"""
5725
+ type ShopBrand {
5726
+ """Primary + secondary brand colors"""
5727
+ colors: BrandColors
5728
+
5729
+ """Cover image / hero banner"""
5730
+ coverImage: Image
5731
+
5732
+ """Primary logo"""
5733
+ logo: Image
5734
+
5735
+ """Short brand description"""
5736
+ shortDescription: String
5737
+
5738
+ """Marketing slogan / tagline"""
5739
+ slogan: String
5740
+
5741
+ """Square logo variant (favicons, app tiles)"""
5742
+ squareLogo: Image
5743
+ }
5744
+
5658
5745
  """Shop branding configuration"""
5659
5746
  type ShopBranding {
5660
5747
  """Brand colors"""