@doswiftly/storefront-operations 13.1.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/llms-full.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # DoSwiftly Storefront Operations — Full Reference
2
2
 
3
- > Schema version: **13.1.0**
3
+ > Schema version: **14.0.0**
4
4
  > 50 queries · 40 mutations · 100 fragments
5
5
 
6
6
  Auto-generated from `.graphql` source files. Do not edit by hand — this file is
@@ -41,7 +41,7 @@ query Shop {
41
41
 
42
42
  **Section**: Products
43
43
 
44
- **Description**: Fetches a single product by `id` or `handle` (URL slug). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).
44
+ **Description**: Fetches a single product by `id` or `handle` (URL-friendly identifier). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).
45
45
 
46
46
  **Variables**:
47
47
  - `$id`: `ID`
@@ -274,18 +274,18 @@ query Collections($first: Int = 20, $after: String, $query: String, $sortKey: Co
274
274
 
275
275
  **Section**: Categories
276
276
 
277
- **Description**: Fetches a single category by `id` or `slug` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.
277
+ **Description**: Fetches a single category by `id` or `handle` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.
278
278
 
279
279
  **Variables**:
280
280
  - `$id`: `ID`
281
- - `$slug`: `String`
281
+ - `$handle`: `String`
282
282
 
283
283
  **Fragments used**: `Category`
284
284
 
285
285
  **GraphQL**:
286
286
  ```graphql
287
- query Category($id: ID, $slug: String) {
288
- category(id: $id, slug: $slug) {
287
+ query Category($id: ID, $handle: String) {
288
+ category(id: $id, handle: $handle) {
289
289
  ...Category
290
290
  parent {
291
291
  ...Category
@@ -1018,13 +1018,13 @@ query WishlistById($id: ID!) {
1018
1018
 
1019
1019
  **Section**: Blog
1020
1020
 
1021
- **Description**: Paginated list of published blog posts. Filter by `categorySlug`, `tagSlug`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.
1021
+ **Description**: Paginated list of published blog posts. Filter by `categoryHandle`, `tagHandle`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.
1022
1022
 
1023
1023
  **Variables**:
1024
1024
  - `$first`: `Int` *(default: `20`)*
1025
1025
  - `$after`: `String`
1026
- - `$categorySlug`: `String`
1027
- - `$tagSlug`: `String`
1026
+ - `$categoryHandle`: `String`
1027
+ - `$tagHandle`: `String`
1028
1028
  - `$featured`: `Boolean`
1029
1029
  - `$sortKey`: `BlogPostSortKey` *(default: `PUBLISHED_AT`)*
1030
1030
  - `$reverse`: `Boolean` *(default: `false`)*
@@ -1033,12 +1033,12 @@ query WishlistById($id: ID!) {
1033
1033
 
1034
1034
  **GraphQL**:
1035
1035
  ```graphql
1036
- query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlug: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
1036
+ query BlogPosts($first: Int = 20, $after: String, $categoryHandle: String, $tagHandle: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
1037
1037
  blogPosts(
1038
1038
  first: $first
1039
1039
  after: $after
1040
- categorySlug: $categorySlug
1041
- tagSlug: $tagSlug
1040
+ categoryHandle: $categoryHandle
1041
+ tagHandle: $tagHandle
1042
1042
  featured: $featured
1043
1043
  sortKey: $sortKey
1044
1044
  reverse: $reverse
@@ -1061,18 +1061,18 @@ query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlu
1061
1061
 
1062
1062
  **Section**: Blog
1063
1063
 
1064
- **Description**: Fetches a single blog post by `id` or `slug`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).
1064
+ **Description**: Fetches a single blog post by `id` or `handle`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).
1065
1065
 
1066
1066
  **Variables**:
1067
1067
  - `$id`: `ID`
1068
- - `$slug`: `String`
1068
+ - `$handle`: `String`
1069
1069
 
1070
1070
  **Fragments used**: `BlogPost`
1071
1071
 
1072
1072
  **GraphQL**:
1073
1073
  ```graphql
1074
- query BlogPost($id: ID, $slug: String) {
1075
- blogPost(id: $id, slug: $slug) {
1074
+ query BlogPost($id: ID, $handle: String) {
1075
+ blogPost(id: $id, handle: $handle) {
1076
1076
  ...BlogPost
1077
1077
  }
1078
1078
  }
@@ -1202,7 +1202,7 @@ query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $r
1202
1202
 
1203
1203
  **Section**: Content: Navigation Menus
1204
1204
 
1205
- **Description**: Fetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree. Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, or `PAGE` — switch on the type to render the right link target. Linked resources and URLs are resolved on demand by the field selections in the `Menu` fragment.
1205
+ **Description**: Fetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree (up to 3 levels). Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, `PAGE`, or `BRAND` — switch on the type to render the right link target. Each resource-linked item exposes both a pre-resolved `url` (standard `/categories|/collections|/pages|/products|/brands/<handle>` convention) and a typed `resource` union with the raw handle so storefronts with custom routing can construct their own paths instead. All resource lookups are batched per request — no N+1 even for deep menus.
1206
1206
 
1207
1207
  **Variables**:
1208
1208
  - `$handle`: `String!`
@@ -2590,7 +2590,7 @@ fragment ProductCard on Product {
2590
2590
  vendor
2591
2591
  categories {
2592
2592
  id
2593
- slug
2593
+ handle
2594
2594
  name
2595
2595
  }
2596
2596
  isAvailable
@@ -2723,7 +2723,7 @@ fragment Collection on Collection {
2723
2723
 
2724
2724
  **Section**: Categories
2725
2725
 
2726
- **Description**: Category node in the shop's taxonomy — name, slug, hero image, depth `level`, materialized `path`, product count, sort order. Spread on category cards and breadcrumb segments. Does NOT include parent / children — query those fields separately and let the server batch them.
2726
+ **Description**: Category node in the shop's taxonomy — name, handle, hero image, depth `level`, materialized `path`, product count, sort order. Spread on category cards and breadcrumb segments. Does NOT include parent / children — query those fields separately and let the server batch them.
2727
2727
 
2728
2728
  **Uses fragments**: `ImageCard`
2729
2729
 
@@ -2732,7 +2732,7 @@ fragment Collection on Collection {
2732
2732
  fragment Category on Category {
2733
2733
  id
2734
2734
  name
2735
- slug
2735
+ handle
2736
2736
  description
2737
2737
  image {
2738
2738
  ...ImageCard
@@ -3904,14 +3904,14 @@ fragment PriceRangeFilter on PriceRange {
3904
3904
 
3905
3905
  **Section**: Attribute Filters
3906
3906
 
3907
- **Description**: One category option in the categories filter — id, name, slug, count of products in this category within the current listing context, level + parentId for tree rendering.
3907
+ **Description**: One category option in the categories filter — id, name, handle, count of products in this category within the current listing context, level + parentId for tree rendering.
3908
3908
 
3909
3909
  **GraphQL**:
3910
3910
  ```graphql
3911
3911
  fragment CategoryFilterOption on CategoryFilterOption {
3912
3912
  id
3913
3913
  name
3914
- slug
3914
+ handle
3915
3915
  productCount
3916
3916
  level
3917
3917
  parentId
@@ -4094,7 +4094,7 @@ fragment LoyaltyTransaction on LoyaltyTransaction {
4094
4094
  fragment LoyaltyReward on LoyaltyReward {
4095
4095
  id
4096
4096
  name
4097
- slug
4097
+ handle
4098
4098
  type
4099
4099
  pointsCost
4100
4100
  discountPercent
@@ -4327,14 +4327,14 @@ fragment Wishlist on Wishlist {
4327
4327
 
4328
4328
  **Section**: Blog
4329
4329
 
4330
- **Description**: Blog category — name, slug, description, post count. Spread on category navigation and post category labels.
4330
+ **Description**: Blog category — name, handle, description, post count. Spread on category navigation and post category labels.
4331
4331
 
4332
4332
  **GraphQL**:
4333
4333
  ```graphql
4334
4334
  fragment BlogCategory on BlogCategory {
4335
4335
  id
4336
4336
  name
4337
- slug
4337
+ handle
4338
4338
  description
4339
4339
  postCount
4340
4340
  }
@@ -4344,14 +4344,14 @@ fragment BlogCategory on BlogCategory {
4344
4344
 
4345
4345
  **Section**: Blog
4346
4346
 
4347
- **Description**: Blog tag — name, slug, post count. Spread on tag clouds and post tag labels.
4347
+ **Description**: Blog tag — name, handle, post count. Spread on tag clouds and post tag labels.
4348
4348
 
4349
4349
  **GraphQL**:
4350
4350
  ```graphql
4351
4351
  fragment BlogTag on BlogTag {
4352
4352
  id
4353
4353
  name
4354
- slug
4354
+ handle
4355
4355
  postCount
4356
4356
  }
4357
4357
  ```
@@ -4360,7 +4360,7 @@ fragment BlogTag on BlogTag {
4360
4360
 
4361
4361
  **Section**: Blog
4362
4362
 
4363
- **Description**: Full blog post — title, slug, excerpt, content (with `contentFormat` indicating HTML/Markdown), featured image, author, category, tags, publish date, reading time, view + comment counts, SEO metadata. Spread on the post detail page.
4363
+ **Description**: Full blog post — title, handle, excerpt, content (with `contentFormat` indicating HTML/Markdown), featured image, author, category, tags, publish date, reading time, view + comment counts, SEO metadata. Spread on the post detail page.
4364
4364
 
4365
4365
  **Uses fragments**: `BlogCategory`, `BlogTag`, `ImageCard`, `ImageThumbnail`
4366
4366
 
@@ -4369,7 +4369,7 @@ fragment BlogTag on BlogTag {
4369
4369
  fragment BlogPost on BlogPost {
4370
4370
  id
4371
4371
  title
4372
- slug
4372
+ handle
4373
4373
  excerpt
4374
4374
  content
4375
4375
  contentFormat
@@ -4575,7 +4575,7 @@ fragment VariantStoreAvailability on ProductVariant {
4575
4575
 
4576
4576
  **Section**: Pages
4577
4577
 
4578
- **Description**: CMS page — handle (URL slug), title, body (HTML), excerpt, SEO metadata, publish date. Spread on About / Privacy / Terms / Returns Policy pages.
4578
+ **Description**: CMS page — handle (URL-friendly identifier), title, body (HTML), excerpt, SEO metadata, publish date. Spread on About / Privacy / Terms / Returns Policy pages.
4579
4579
 
4580
4580
  **GraphQL**:
4581
4581
  ```graphql
@@ -4599,7 +4599,7 @@ fragment ShopPage on ShopPage {
4599
4599
 
4600
4600
  **Section**: Navigation Menus
4601
4601
 
4602
- **Description**: One menu item with up to 3 levels of nested children — title, URL, type (`HTTP` / `FRONTPAGE` / `SEARCH` / `CATALOG` / `BLOG` / `PRODUCT` / `COLLECTION` / `CATEGORY` / `PAGE`), `resourceId` for typed items, optional image. Switch on `type` to render the right link target.
4602
+ **Description**: One menu item with up to 3 levels of nested children — title, URL, type (`HTTP` / `FRONTPAGE` / `SEARCH` / `CATALOG` / `BLOG` / `PRODUCT` / `COLLECTION` / `CATEGORY` / `PAGE` / `BRAND`), `resourceId` for typed items, optional image, and a typed `resource` union (Category / Collection / ShopPage / Product / Brand) carrying the linked resource's handle. Two ways to render the link target: (1) use the pre-resolved `url` if your storefront follows the standard `/categories|/collections|/pages|/products|/brands/<handle>` route convention; (2) read `resource.__typename` + the per-type `handle` and build your own paths if your storefront uses different routing. Switch on `type` to decide which static (FRONTPAGE/SEARCH/CATALOG/BLOG) or dynamic target to render.
4603
4603
 
4604
4604
  **Uses fragments**: `Image`
4605
4605
 
@@ -4611,6 +4611,35 @@ fragment MenuItem on MenuItem {
4611
4611
  url
4612
4612
  type
4613
4613
  resourceId
4614
+ resource {
4615
+ __typename
4616
+ ... on Category {
4617
+ id
4618
+ handle
4619
+ name
4620
+ }
4621
+ ... on Collection {
4622
+ id
4623
+ handle
4624
+ title
4625
+ }
4626
+ ... on ShopPage {
4627
+ id
4628
+ handle
4629
+ title
4630
+ }
4631
+ ... on Product {
4632
+ id
4633
+ handle
4634
+ title
4635
+ }
4636
+ ... on Brand {
4637
+ id
4638
+ handle
4639
+ name
4640
+ logo
4641
+ }
4642
+ }
4614
4643
  image {
4615
4644
  ...Image
4616
4645
  }
@@ -4620,12 +4649,70 @@ fragment MenuItem on MenuItem {
4620
4649
  url
4621
4650
  type
4622
4651
  resourceId
4652
+ resource {
4653
+ __typename
4654
+ ... on Category {
4655
+ id
4656
+ handle
4657
+ name
4658
+ }
4659
+ ... on Collection {
4660
+ id
4661
+ handle
4662
+ title
4663
+ }
4664
+ ... on ShopPage {
4665
+ id
4666
+ handle
4667
+ title
4668
+ }
4669
+ ... on Product {
4670
+ id
4671
+ handle
4672
+ title
4673
+ }
4674
+ ... on Brand {
4675
+ id
4676
+ handle
4677
+ name
4678
+ logo
4679
+ }
4680
+ }
4623
4681
  items {
4624
4682
  id
4625
4683
  title
4626
4684
  url
4627
4685
  type
4628
4686
  resourceId
4687
+ resource {
4688
+ __typename
4689
+ ... on Category {
4690
+ id
4691
+ handle
4692
+ name
4693
+ }
4694
+ ... on Collection {
4695
+ id
4696
+ handle
4697
+ title
4698
+ }
4699
+ ... on ShopPage {
4700
+ id
4701
+ handle
4702
+ title
4703
+ }
4704
+ ... on Product {
4705
+ id
4706
+ handle
4707
+ title
4708
+ }
4709
+ ... on Brand {
4710
+ id
4711
+ handle
4712
+ name
4713
+ logo
4714
+ }
4715
+ }
4629
4716
  }
4630
4717
  }
4631
4718
  }
@@ -4723,7 +4810,7 @@ fragment ProductAttributeOption on ProductAttributeOption {
4723
4810
  fragment ProductAttributeDefinition on ProductAttributeDefinition {
4724
4811
  id
4725
4812
  name
4726
- slug
4813
+ handle
4727
4814
  description
4728
4815
  type
4729
4816
  fillingMode
package/operations.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "schemaVersion": "13.1.0",
2
+ "schemaVersion": "14.0.0",
3
3
  "queries": [
4
4
  {
5
5
  "name": "Shop",
@@ -16,7 +16,7 @@
16
16
  "name": "Product",
17
17
  "kind": "query",
18
18
  "section": "Products",
19
- "description": "Fetches a single product by `id` or `handle` (URL slug). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).",
19
+ "description": "Fetches a single product by `id` or `handle` (URL-friendly identifier). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).",
20
20
  "variables": [
21
21
  {
22
22
  "name": "id",
@@ -236,7 +236,7 @@
236
236
  "name": "Category",
237
237
  "kind": "query",
238
238
  "section": "Categories",
239
- "description": "Fetches a single category by `id` or `slug` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.",
239
+ "description": "Fetches a single category by `id` or `handle` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.",
240
240
  "variables": [
241
241
  {
242
242
  "name": "id",
@@ -244,7 +244,7 @@
244
244
  "defaultValue": null
245
245
  },
246
246
  {
247
- "name": "slug",
247
+ "name": "handle",
248
248
  "type": "String",
249
249
  "defaultValue": null
250
250
  }
@@ -252,7 +252,7 @@
252
252
  "fragmentRefs": [
253
253
  "Category"
254
254
  ],
255
- "body": "query Category($id: ID, $slug: String) {\n category(id: $id, slug: $slug) {\n ...Category\n parent {\n ...Category\n }\n children {\n ...Category\n }\n }\n}"
255
+ "body": "query Category($id: ID, $handle: String) {\n category(id: $id, handle: $handle) {\n ...Category\n parent {\n ...Category\n }\n children {\n ...Category\n }\n }\n}"
256
256
  },
257
257
  {
258
258
  "name": "Categories",
@@ -758,7 +758,7 @@
758
758
  "name": "BlogPosts",
759
759
  "kind": "query",
760
760
  "section": "Blog",
761
- "description": "Paginated list of published blog posts. Filter by `categorySlug`, `tagSlug`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.",
761
+ "description": "Paginated list of published blog posts. Filter by `categoryHandle`, `tagHandle`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.",
762
762
  "variables": [
763
763
  {
764
764
  "name": "first",
@@ -771,12 +771,12 @@
771
771
  "defaultValue": null
772
772
  },
773
773
  {
774
- "name": "categorySlug",
774
+ "name": "categoryHandle",
775
775
  "type": "String",
776
776
  "defaultValue": null
777
777
  },
778
778
  {
779
- "name": "tagSlug",
779
+ "name": "tagHandle",
780
780
  "type": "String",
781
781
  "defaultValue": null
782
782
  },
@@ -800,13 +800,13 @@
800
800
  "BlogPost",
801
801
  "PageInfo"
802
802
  ],
803
- "body": "query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlug: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {\n blogPosts(\n first: $first\n after: $after\n categorySlug: $categorySlug\n tagSlug: $tagSlug\n featured: $featured\n sortKey: $sortKey\n reverse: $reverse\n ) {\n edges {\n node {\n ...BlogPost\n }\n cursor\n }\n pageInfo {\n ...PageInfo\n }\n totalCount\n }\n}"
803
+ "body": "query BlogPosts($first: Int = 20, $after: String, $categoryHandle: String, $tagHandle: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {\n blogPosts(\n first: $first\n after: $after\n categoryHandle: $categoryHandle\n tagHandle: $tagHandle\n featured: $featured\n sortKey: $sortKey\n reverse: $reverse\n ) {\n edges {\n node {\n ...BlogPost\n }\n cursor\n }\n pageInfo {\n ...PageInfo\n }\n totalCount\n }\n}"
804
804
  },
805
805
  {
806
806
  "name": "BlogPost",
807
807
  "kind": "query",
808
808
  "section": "Blog",
809
- "description": "Fetches a single blog post by `id` or `slug`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).",
809
+ "description": "Fetches a single blog post by `id` or `handle`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).",
810
810
  "variables": [
811
811
  {
812
812
  "name": "id",
@@ -814,7 +814,7 @@
814
814
  "defaultValue": null
815
815
  },
816
816
  {
817
- "name": "slug",
817
+ "name": "handle",
818
818
  "type": "String",
819
819
  "defaultValue": null
820
820
  }
@@ -822,7 +822,7 @@
822
822
  "fragmentRefs": [
823
823
  "BlogPost"
824
824
  ],
825
- "body": "query BlogPost($id: ID, $slug: String) {\n blogPost(id: $id, slug: $slug) {\n ...BlogPost\n }\n}"
825
+ "body": "query BlogPost($id: ID, $handle: String) {\n blogPost(id: $id, handle: $handle) {\n ...BlogPost\n }\n}"
826
826
  },
827
827
  {
828
828
  "name": "BlogCategories",
@@ -937,7 +937,7 @@
937
937
  "name": "Menu",
938
938
  "kind": "query",
939
939
  "section": "Content: Navigation Menus",
940
- "description": "Fetches a navigation menu by `handle` (e.g. `\"main-menu\"`, `\"footer\"`, `\"mobile\"`). Returns the nested item tree. Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, or `PAGE` — switch on the type to render the right link target. Linked resources and URLs are resolved on demand by the field selections in the `Menu` fragment.",
940
+ "description": "Fetches a navigation menu by `handle` (e.g. `\"main-menu\"`, `\"footer\"`, `\"mobile\"`). Returns the nested item tree (up to 3 levels). Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, `PAGE`, or `BRAND` — switch on the type to render the right link target. Each resource-linked item exposes both a pre-resolved `url` (standard `/categories|/collections|/pages|/products|/brands/<handle>` convention) and a typed `resource` union with the raw handle so storefronts with custom routing can construct their own paths instead. All resource lookups are batched per request — no N+1 even for deep menus.",
941
941
  "variables": [
942
942
  {
943
943
  "name": "handle",
@@ -1944,7 +1944,7 @@
1944
1944
  "ImageCard",
1945
1945
  "Money"
1946
1946
  ],
1947
- "body": "fragment ProductCard on Product {\n id\n handle\n title\n vendor\n categories {\n id\n slug\n name\n }\n isAvailable\n averageRating\n reviewCount\n tags\n featuredImage {\n ...ImageCard\n }\n priceRange {\n minVariantPrice {\n ...Money\n }\n maxVariantPrice {\n ...Money\n }\n }\n compareAtPriceRange {\n minVariantPrice {\n ...Money\n }\n maxVariantPrice {\n ...Money\n }\n }\n}",
1947
+ "body": "fragment ProductCard on Product {\n id\n handle\n title\n vendor\n categories {\n id\n handle\n name\n }\n isAvailable\n averageRating\n reviewCount\n tags\n featuredImage {\n ...ImageCard\n }\n priceRange {\n minVariantPrice {\n ...Money\n }\n maxVariantPrice {\n ...Money\n }\n }\n compareAtPriceRange {\n minVariantPrice {\n ...Money\n }\n maxVariantPrice {\n ...Money\n }\n }\n}",
1948
1948
  "onType": "Product"
1949
1949
  },
1950
1950
  {
@@ -1990,12 +1990,12 @@
1990
1990
  "name": "Category",
1991
1991
  "kind": "fragment",
1992
1992
  "section": "Categories",
1993
- "description": "Category node in the shop's taxonomy — name, slug, hero image, depth `level`, materialized `path`, product count, sort order. Spread on category cards and breadcrumb segments. Does NOT include parent / children — query those fields separately and let the server batch them.",
1993
+ "description": "Category node in the shop's taxonomy — name, handle, hero image, depth `level`, materialized `path`, product count, sort order. Spread on category cards and breadcrumb segments. Does NOT include parent / children — query those fields separately and let the server batch them.",
1994
1994
  "variables": [],
1995
1995
  "fragmentRefs": [
1996
1996
  "ImageCard"
1997
1997
  ],
1998
- "body": "fragment Category on Category {\n id\n name\n slug\n description\n image {\n ...ImageCard\n }\n level\n path\n productCount\n sortOrder\n}",
1998
+ "body": "fragment Category on Category {\n id\n name\n handle\n description\n image {\n ...ImageCard\n }\n level\n path\n productCount\n sortOrder\n}",
1999
1999
  "onType": "Category"
2000
2000
  },
2001
2001
  {
@@ -2571,10 +2571,10 @@
2571
2571
  "name": "CategoryFilterOption",
2572
2572
  "kind": "fragment",
2573
2573
  "section": "Attribute Filters",
2574
- "description": "One category option in the categories filter — id, name, slug, count of products in this category within the current listing context, level + parentId for tree rendering.",
2574
+ "description": "One category option in the categories filter — id, name, handle, count of products in this category within the current listing context, level + parentId for tree rendering.",
2575
2575
  "variables": [],
2576
2576
  "fragmentRefs": [],
2577
- "body": "fragment CategoryFilterOption on CategoryFilterOption {\n id\n name\n slug\n productCount\n level\n parentId\n}",
2577
+ "body": "fragment CategoryFilterOption on CategoryFilterOption {\n id\n name\n handle\n productCount\n level\n parentId\n}",
2578
2578
  "onType": "CategoryFilterOption"
2579
2579
  },
2580
2580
  {
@@ -2672,7 +2672,7 @@
2672
2672
  "LoyaltyTier",
2673
2673
  "Money"
2674
2674
  ],
2675
- "body": "fragment LoyaltyReward on LoyaltyReward {\n id\n name\n slug\n type\n pointsCost\n discountPercent\n discountAmount {\n ...Money\n }\n description\n image {\n ...ImageCard\n }\n isAvailable\n tierRequired {\n ...LoyaltyTier\n }\n redemptionsRemaining\n}",
2675
+ "body": "fragment LoyaltyReward on LoyaltyReward {\n id\n name\n handle\n type\n pointsCost\n discountPercent\n discountAmount {\n ...Money\n }\n description\n image {\n ...ImageCard\n }\n isAvailable\n tierRequired {\n ...LoyaltyTier\n }\n redemptionsRemaining\n}",
2676
2676
  "onType": "LoyaltyReward"
2677
2677
  },
2678
2678
  {
@@ -2790,27 +2790,27 @@
2790
2790
  "name": "BlogCategory",
2791
2791
  "kind": "fragment",
2792
2792
  "section": "Blog",
2793
- "description": "Blog category — name, slug, description, post count. Spread on category navigation and post category labels.",
2793
+ "description": "Blog category — name, handle, description, post count. Spread on category navigation and post category labels.",
2794
2794
  "variables": [],
2795
2795
  "fragmentRefs": [],
2796
- "body": "fragment BlogCategory on BlogCategory {\n id\n name\n slug\n description\n postCount\n}",
2796
+ "body": "fragment BlogCategory on BlogCategory {\n id\n name\n handle\n description\n postCount\n}",
2797
2797
  "onType": "BlogCategory"
2798
2798
  },
2799
2799
  {
2800
2800
  "name": "BlogTag",
2801
2801
  "kind": "fragment",
2802
2802
  "section": "Blog",
2803
- "description": "Blog tag — name, slug, post count. Spread on tag clouds and post tag labels.",
2803
+ "description": "Blog tag — name, handle, post count. Spread on tag clouds and post tag labels.",
2804
2804
  "variables": [],
2805
2805
  "fragmentRefs": [],
2806
- "body": "fragment BlogTag on BlogTag {\n id\n name\n slug\n postCount\n}",
2806
+ "body": "fragment BlogTag on BlogTag {\n id\n name\n handle\n postCount\n}",
2807
2807
  "onType": "BlogTag"
2808
2808
  },
2809
2809
  {
2810
2810
  "name": "BlogPost",
2811
2811
  "kind": "fragment",
2812
2812
  "section": "Blog",
2813
- "description": "Full blog post — title, slug, excerpt, content (with `contentFormat` indicating HTML/Markdown), featured image, author, category, tags, publish date, reading time, view + comment counts, SEO metadata. Spread on the post detail page.",
2813
+ "description": "Full blog post — title, handle, excerpt, content (with `contentFormat` indicating HTML/Markdown), featured image, author, category, tags, publish date, reading time, view + comment counts, SEO metadata. Spread on the post detail page.",
2814
2814
  "variables": [],
2815
2815
  "fragmentRefs": [
2816
2816
  "BlogCategory",
@@ -2818,7 +2818,7 @@
2818
2818
  "ImageCard",
2819
2819
  "ImageThumbnail"
2820
2820
  ],
2821
- "body": "fragment BlogPost on BlogPost {\n id\n title\n slug\n excerpt\n content\n contentFormat\n featuredImage {\n ...ImageCard\n }\n author {\n id\n name\n bio\n avatar {\n ...ImageThumbnail\n }\n }\n category {\n ...BlogCategory\n }\n tags {\n ...BlogTag\n }\n publishedAt\n readingTimeMinutes\n viewCount\n commentCount\n allowComments\n isFeatured\n status\n seo {\n title\n description\n }\n createdAt\n updatedAt\n}",
2821
+ "body": "fragment BlogPost on BlogPost {\n id\n title\n handle\n excerpt\n content\n contentFormat\n featuredImage {\n ...ImageCard\n }\n author {\n id\n name\n bio\n avatar {\n ...ImageThumbnail\n }\n }\n category {\n ...BlogCategory\n }\n tags {\n ...BlogTag\n }\n publishedAt\n readingTimeMinutes\n viewCount\n commentCount\n allowComments\n isFeatured\n status\n seo {\n title\n description\n }\n createdAt\n updatedAt\n}",
2822
2822
  "onType": "BlogPost"
2823
2823
  },
2824
2824
  {
@@ -2907,7 +2907,7 @@
2907
2907
  "name": "ShopPage",
2908
2908
  "kind": "fragment",
2909
2909
  "section": "Pages",
2910
- "description": "CMS page — handle (URL slug), title, body (HTML), excerpt, SEO metadata, publish date. Spread on About / Privacy / Terms / Returns Policy pages.",
2910
+ "description": "CMS page — handle (URL-friendly identifier), title, body (HTML), excerpt, SEO metadata, publish date. Spread on About / Privacy / Terms / Returns Policy pages.",
2911
2911
  "variables": [],
2912
2912
  "fragmentRefs": [],
2913
2913
  "body": "fragment ShopPage on ShopPage {\n id\n handle\n title\n body\n excerpt\n seo {\n title\n description\n }\n publishedAt\n createdAt\n updatedAt\n}",
@@ -2917,12 +2917,12 @@
2917
2917
  "name": "MenuItem",
2918
2918
  "kind": "fragment",
2919
2919
  "section": "Navigation Menus",
2920
- "description": "One menu item with up to 3 levels of nested children — title, URL, type (`HTTP` / `FRONTPAGE` / `SEARCH` / `CATALOG` / `BLOG` / `PRODUCT` / `COLLECTION` / `CATEGORY` / `PAGE`), `resourceId` for typed items, optional image. Switch on `type` to render the right link target.",
2920
+ "description": "One menu item with up to 3 levels of nested children — title, URL, type (`HTTP` / `FRONTPAGE` / `SEARCH` / `CATALOG` / `BLOG` / `PRODUCT` / `COLLECTION` / `CATEGORY` / `PAGE` / `BRAND`), `resourceId` for typed items, optional image, and a typed `resource` union (Category / Collection / ShopPage / Product / Brand) carrying the linked resource's handle. Two ways to render the link target: (1) use the pre-resolved `url` if your storefront follows the standard `/categories|/collections|/pages|/products|/brands/<handle>` route convention; (2) read `resource.__typename` + the per-type `handle` and build your own paths if your storefront uses different routing. Switch on `type` to decide which static (FRONTPAGE/SEARCH/CATALOG/BLOG) or dynamic target to render.",
2921
2921
  "variables": [],
2922
2922
  "fragmentRefs": [
2923
2923
  "Image"
2924
2924
  ],
2925
- "body": "fragment MenuItem on MenuItem {\n id\n title\n url\n type\n resourceId\n image {\n ...Image\n }\n items {\n id\n title\n url\n type\n resourceId\n items {\n id\n title\n url\n type\n resourceId\n }\n }\n}",
2925
+ "body": "fragment MenuItem on MenuItem {\n id\n title\n url\n type\n resourceId\n resource {\n __typename\n ... on Category {\n id\n handle\n name\n }\n ... on Collection {\n id\n handle\n title\n }\n ... on ShopPage {\n id\n handle\n title\n }\n ... on Product {\n id\n handle\n title\n }\n ... on Brand {\n id\n handle\n name\n logo\n }\n }\n image {\n ...Image\n }\n items {\n id\n title\n url\n type\n resourceId\n resource {\n __typename\n ... on Category {\n id\n handle\n name\n }\n ... on Collection {\n id\n handle\n title\n }\n ... on ShopPage {\n id\n handle\n title\n }\n ... on Product {\n id\n handle\n title\n }\n ... on Brand {\n id\n handle\n name\n logo\n }\n }\n items {\n id\n title\n url\n type\n resourceId\n resource {\n __typename\n ... on Category {\n id\n handle\n name\n }\n ... on Collection {\n id\n handle\n title\n }\n ... on ShopPage {\n id\n handle\n title\n }\n ... on Product {\n id\n handle\n title\n }\n ... on Brand {\n id\n handle\n name\n logo\n }\n }\n }\n }\n}",
2926
2926
  "onType": "MenuItem"
2927
2927
  },
2928
2928
  {
@@ -2978,7 +2978,7 @@
2978
2978
  "fragmentRefs": [
2979
2979
  "ProductAttributeOption"
2980
2980
  ],
2981
- "body": "fragment ProductAttributeDefinition on ProductAttributeDefinition {\n id\n name\n slug\n description\n type\n fillingMode\n billingMode\n taxClassId\n scopeProductId\n isRequired\n isVisible\n displayOrder\n minValue\n maxValue\n options {\n ...ProductAttributeOption\n }\n}",
2981
+ "body": "fragment ProductAttributeDefinition on ProductAttributeDefinition {\n id\n name\n handle\n description\n type\n fillingMode\n billingMode\n taxClassId\n scopeProductId\n isRequired\n isVisible\n displayOrder\n minValue\n maxValue\n options {\n ...ProductAttributeOption\n }\n}",
2982
2982
  "onType": "ProductAttributeDefinition"
2983
2983
  }
2984
2984
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doswiftly/storefront-operations",
3
- "version": "13.1.0",
3
+ "version": "14.0.0",
4
4
  "description": "GraphQL operations for DoSwiftly Storefront - SSOT from backend",
5
5
  "homepage": "https://doswiftly.pl",
6
6
  "publishConfig": {
package/queries.graphql CHANGED
@@ -18,7 +18,7 @@ query Shop {
18
18
  # Products
19
19
  # ============================================
20
20
 
21
- # Fetches a single product by `id` or `handle` (URL slug). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).
21
+ # Fetches a single product by `id` or `handle` (URL-friendly identifier). Pass either — whichever is provided wins; if both are missing, returns null. Returns null if the product is not storefront-accessible (must be `ACTIVE` status with `PUBLIC` or `BUNDLE_ONLY` visibility).
22
22
  query Product($id: ID, $handle: String) {
23
23
  product(id: $id, handle: $handle) {
24
24
  ...ProductFull
@@ -139,9 +139,9 @@ query Collections($first: Int = 20, $after: String, $query: String, $sortKey: Co
139
139
  # Categories
140
140
  # ============================================
141
141
 
142
- # Fetches a single category by `id` or `slug` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.
143
- query Category($id: ID, $slug: String) {
144
- category(id: $id, slug: $slug) {
142
+ # Fetches a single category by `id` or `handle` with its parent and immediate children. Use for breadcrumbs and sub-navigation. Nested queries on `parent` / `children` are batched server-side — safe to use in lists without N+1 concerns.
143
+ query Category($id: ID, $handle: String) {
144
+ category(id: $id, handle: $handle) {
145
145
  ...Category
146
146
  parent {
147
147
  ...Category
@@ -539,9 +539,9 @@ query WishlistById($id: ID!) {
539
539
  # Blog
540
540
  # ============================================
541
541
 
542
- # Paginated list of published blog posts. Filter by `categorySlug`, `tagSlug`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.
543
- query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlug: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
544
- blogPosts(first: $first, after: $after, categorySlug: $categorySlug, tagSlug: $tagSlug, featured: $featured, sortKey: $sortKey, reverse: $reverse) {
542
+ # Paginated list of published blog posts. Filter by `categoryHandle`, `tagHandle`, or `featured` (boolean flag, not enum). Sort: `PUBLISHED_AT` (default), `TITLE`, `VIEW_COUNT`, or `CREATED_AT`. Public; no auth required.
543
+ query BlogPosts($first: Int = 20, $after: String, $categoryHandle: String, $tagHandle: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
544
+ blogPosts(first: $first, after: $after, categoryHandle: $categoryHandle, tagHandle: $tagHandle, featured: $featured, sortKey: $sortKey, reverse: $reverse) {
545
545
  edges {
546
546
  node {
547
547
  ...BlogPost
@@ -555,9 +555,9 @@ query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlu
555
555
  }
556
556
  }
557
557
 
558
- # Fetches a single blog post by `id` or `slug`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).
559
- query BlogPost($id: ID, $slug: String) {
560
- blogPost(id: $id, slug: $slug) {
558
+ # Fetches a single blog post by `id` or `handle`. Visibility-gated: returns null if the post is not yet `PUBLISHED` or if its publish date is in the future (scheduled posts stay hidden until their publish time). Side effect: fetching a post increments its `view_count` asynchronously (does not block the response).
559
+ query BlogPost($id: ID, $handle: String) {
560
+ blogPost(id: $id, handle: $handle) {
561
561
  ...BlogPost
562
562
  }
563
563
  }
@@ -618,7 +618,7 @@ query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $r
618
618
  # Content: Navigation Menus
619
619
  # ============================================
620
620
 
621
- # Fetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree. Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, or `PAGE` — switch on the type to render the right link target. Linked resources and URLs are resolved on demand by the field selections in the `Menu` fragment.
621
+ # Fetches a navigation menu by `handle` (e.g. `"main-menu"`, `"footer"`, `"mobile"`). Returns the nested item tree (up to 3 levels). Each item is typed as one of: `HTTP`, `FRONTPAGE`, `SEARCH`, `CATALOG`, `BLOG`, `PRODUCT`, `COLLECTION`, `CATEGORY`, `PAGE`, or `BRAND` — switch on the type to render the right link target. Each resource-linked item exposes both a pre-resolved `url` (standard `/categories|/collections|/pages|/products|/brands/<handle>` convention) and a typed `resource` union with the raw handle so storefronts with custom routing can construct their own paths instead. All resource lookups are batched per request — no N+1 even for deep menus.
622
622
  query Menu($handle: String!) {
623
623
  menu(handle: $handle) {
624
624
  ...Menu