@doswiftly/storefront-operations 6.1.0 → 7.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 +183 -0
- package/CHANGELOG.md +230 -0
- package/README.md +673 -134
- package/fragments.graphql +137 -53
- package/llms-full.txt +4994 -0
- package/mutations.graphql +47 -3
- package/operations.json +3149 -0
- package/package.json +9 -2
- package/queries.graphql +55 -16
- package/schema.graphql +194 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doswiftly/storefront-operations",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "GraphQL operations for DoSwiftly Storefront - SSOT from backend",
|
|
5
5
|
"homepage": "https://doswiftly.pl",
|
|
6
6
|
"publishConfig": {
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"./fragments.graphql": "./fragments.graphql",
|
|
15
15
|
"./*.graphql": "./*.graphql"
|
|
16
16
|
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"graphql": "^16.13.2"
|
|
19
|
+
},
|
|
17
20
|
"keywords": [
|
|
18
21
|
"graphql",
|
|
19
22
|
"operations",
|
|
@@ -28,11 +31,15 @@
|
|
|
28
31
|
"queries.graphql",
|
|
29
32
|
"mutations.graphql",
|
|
30
33
|
"fragments.graphql",
|
|
34
|
+
"operations.json",
|
|
31
35
|
"README.md",
|
|
36
|
+
"AGENTS.md",
|
|
37
|
+
"llms-full.txt",
|
|
32
38
|
"CHANGELOG.md"
|
|
33
39
|
],
|
|
34
40
|
"scripts": {
|
|
35
41
|
"sync": "node scripts/sync-operations.js",
|
|
36
|
-
"build": "npm run sync"
|
|
42
|
+
"build": "npm run sync",
|
|
43
|
+
"test": "node --test scripts/__tests__/*.test.js"
|
|
37
44
|
}
|
|
38
45
|
}
|
package/queries.graphql
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
# Shop
|
|
8
8
|
# ============================================
|
|
9
9
|
|
|
10
|
+
# Returns shop configuration: name, base + supported currencies, supported locales, branding (logo, colors, fonts, social links), contact info, active payment methods, brand metadata, money format template, and the list of countries the shop ships to. Public; no auth required. Call once per session and cache — almost everything else is contextualized by the shop returned here.
|
|
10
11
|
query Shop {
|
|
11
12
|
shop {
|
|
12
13
|
...Shop
|
|
@@ -17,16 +18,14 @@ query Shop {
|
|
|
17
18
|
# Products
|
|
18
19
|
# ============================================
|
|
19
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).
|
|
20
22
|
query Product($id: ID, $handle: String) {
|
|
21
23
|
product(id: $id, handle: $handle) {
|
|
22
24
|
...ProductFull
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
#
|
|
27
|
-
# Returns product details + union of set/scoped AttributeDefinitions filtered by CUSTOMER fillingMode.
|
|
28
|
-
# Showcase: hurtowniakopiarek.pl Konica Bizhub C258 — 4 customer text fields (from shared set)
|
|
29
|
-
# + Finiszer/Podstawa/Podajnik ADF (per-product scoped z linkedVariantId).
|
|
28
|
+
# Fetches a product together with its filtered attribute definitions, optimized for the configurator UI (e.g. customer-facing text fields, finishing options, scoped variants). `fillingMode: "CUSTOMER"` returns only customer-facing attributes; pass `"BOTH"` to also include attributes shared with the merchant admin. Single round-trip — saves a separate `attributes` query.
|
|
30
29
|
query ProductConfigurator($handle: String!, $fillingMode: String = "CUSTOMER") {
|
|
31
30
|
product(handle: $handle) {
|
|
32
31
|
...ProductFull
|
|
@@ -36,6 +35,7 @@ query ProductConfigurator($handle: String!, $fillingMode: String = "CUSTOMER") {
|
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
# Paginated product list (Relay Connection, default page size 20, max 100). The `query` argument supports a structured search syntax — `tag:summer`, `vendor:foo`, `product_type:shirts`, `variants.price:>10`, plus `AND`/`OR`/`NOT` — falling back to free-text title/content search. The `filters[]` array uses multi-filter logic: same field name appears multiple times → OR; different fields → AND. Sort: `RELEVANCE`, `TITLE`, `PRICE`, `NEWEST`, `OLDEST`, `BEST_SELLING`. The response includes a `filters` block for faceted navigation (counts per filterable attribute value).
|
|
39
39
|
query Products(
|
|
40
40
|
$first: Int = 20
|
|
41
41
|
$after: String
|
|
@@ -61,6 +61,7 @@ query Products(
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
# Full-text product search — `$query` is required. Functionally equivalent to `Products` with `$query` set, minus the `sortKey` argument (search defaults to relevance ranking). Use for the search results page; combine with `filters[]` for guided refinement.
|
|
64
65
|
query ProductSearch($query: String!, $first: Int = 20, $after: String, $filters: [ProductFilter!]) {
|
|
65
66
|
products(query: $query, first: $first, after: $after, filters: $filters) {
|
|
66
67
|
edges {
|
|
@@ -79,6 +80,7 @@ query ProductSearch($query: String!, $first: Int = 20, $after: String, $filters:
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
# Type-ahead suggestions for the storefront search input. Returns up to `$limit` matching products (hard cap 50) plus up to 5 styled query suggestions with `<mark>` tags around matched spans. Polish-language aware (handles morphology in suggestions). Run on each keystroke (debounce 200-300ms). The `$query` is capped at 100 characters server-side.
|
|
82
84
|
query PredictiveSearch($query: String!, $limit: Int = 10) {
|
|
83
85
|
predictiveSearch(query: $query, limit: $limit) {
|
|
84
86
|
products {
|
|
@@ -95,6 +97,7 @@ query PredictiveSearch($query: String!, $limit: Int = 10) {
|
|
|
95
97
|
# Collections
|
|
96
98
|
# ============================================
|
|
97
99
|
|
|
100
|
+
# Fetches a single collection by `id` or `handle`, with paginated products. Collections come in two types: **MANUAL** (curated — products explicitly added by the merchant) and **AUTO** (rule-based — products matched dynamically). Both surfaces use the same field selection.
|
|
98
101
|
query Collection($id: ID, $handle: String, $productsFirst: Int = 20, $productsAfter: String, $productsFilters: [ProductFilter!]) {
|
|
99
102
|
collection(id: $id, handle: $handle) {
|
|
100
103
|
...Collection
|
|
@@ -116,6 +119,7 @@ query Collection($id: ID, $handle: String, $productsFirst: Int = 20, $productsAf
|
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
# Paginated list of all active collections (default 20, max 100). Sort by `TITLE` or `UPDATED_AT` via `sortKey`. Note: the `query` argument is reserved for future text filtering — it is currently accepted but ignored.
|
|
119
123
|
query Collections($first: Int = 20, $after: String, $query: String, $sortKey: CollectionSortKeys = TITLE, $reverse: Boolean = false) {
|
|
120
124
|
collections(first: $first, after: $after, query: $query, sortKey: $sortKey, reverse: $reverse) {
|
|
121
125
|
edges {
|
|
@@ -135,6 +139,7 @@ query Collections($first: Int = 20, $after: String, $query: String, $sortKey: Co
|
|
|
135
139
|
# Categories
|
|
136
140
|
# ============================================
|
|
137
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.
|
|
138
143
|
query Category($id: ID, $slug: String) {
|
|
139
144
|
category(id: $id, slug: $slug) {
|
|
140
145
|
...Category
|
|
@@ -147,6 +152,7 @@ query Category($id: ID, $slug: String) {
|
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
154
|
|
|
155
|
+
# Returns active categories for the shop. Each category exposes its `parent` and `children` — build the tree client-side by walking those fields (server batches the lookups, no N+1). The hierarchy is not depth-capped server-side. Use for nav mega-menus and category pages.
|
|
150
156
|
query Categories {
|
|
151
157
|
categories {
|
|
152
158
|
roots {
|
|
@@ -166,6 +172,7 @@ query Categories {
|
|
|
166
172
|
# Cart
|
|
167
173
|
# ============================================
|
|
168
174
|
|
|
175
|
+
# Fetches a cart by `id` (the value persisted by the SDK in the `cart-id` cookie). The cart query is public — no auth needed to read it — but once a customer logs in and gets associated with the cart, mutations enforce ownership. Returns line items (paginated up to 100), totals, applied discount codes, gift cards, buyer identity, note, attributes, and warnings. Refetch after every cart mutation.
|
|
169
176
|
query Cart($id: ID!) {
|
|
170
177
|
cart(id: $id) {
|
|
171
178
|
...Cart
|
|
@@ -176,6 +183,7 @@ query Cart($id: ID!) {
|
|
|
176
183
|
# Customer (requires auth)
|
|
177
184
|
# ============================================
|
|
178
185
|
|
|
186
|
+
# Full customer profile — basic info plus the first 10 addresses and first 10 orders. Heaviest customer query; for narrow use cases prefer `CustomerProfile` (no orders / addresses) or `CustomerOrder` (single order). Returns null if unauthenticated.
|
|
179
187
|
query Customer {
|
|
180
188
|
customer {
|
|
181
189
|
...Customer
|
|
@@ -209,15 +217,14 @@ query Customer {
|
|
|
209
217
|
}
|
|
210
218
|
}
|
|
211
219
|
|
|
212
|
-
# Lightweight customer profile
|
|
213
|
-
# Use for settings/profile pages that only need basic customer info.
|
|
220
|
+
# Lightweight customer profile (no orders, no addresses list). Use for settings / profile pages that only need basic customer info — much cheaper than `Customer`. Returns null if unauthenticated.
|
|
214
221
|
query CustomerProfile {
|
|
215
222
|
customer {
|
|
216
223
|
...Customer
|
|
217
224
|
}
|
|
218
225
|
}
|
|
219
226
|
|
|
220
|
-
# Single order
|
|
227
|
+
# Single order by `orderId`. Returns only orders that belong to the authenticated customer (cross-customer access returns null, not an error). Much cheaper than fetching the full `Customer` payload to access one order. Use on the order detail page.
|
|
221
228
|
query CustomerOrder($orderId: ID!) {
|
|
222
229
|
customerOrder(orderId: $orderId) {
|
|
223
230
|
...Order
|
|
@@ -228,6 +235,7 @@ query CustomerOrder($orderId: ID!) {
|
|
|
228
235
|
# Checkout
|
|
229
236
|
# ============================================
|
|
230
237
|
|
|
238
|
+
# Fetches a checkout session by `id`. **Important**: `checkoutId` and `cartId` are 1:1 — there is no separate "checkout" record, the response is built dynamically from the cart. Returns line items, addresses, selected shipping rate, available shipping rates + payment methods, applied discount/gift cards (gift card codes are masked for security), and totals (`cost`, `tax`, `paymentDue`). Public read; ownership enforced on mutations. Refetch after every checkout mutation.
|
|
231
239
|
query Checkout($id: ID!) {
|
|
232
240
|
checkout(id: $id) {
|
|
233
241
|
...Checkout
|
|
@@ -235,9 +243,10 @@ query Checkout($id: ID!) {
|
|
|
235
243
|
}
|
|
236
244
|
|
|
237
245
|
# ============================================
|
|
238
|
-
# Payment Methods
|
|
246
|
+
# Payment Methods
|
|
239
247
|
# ============================================
|
|
240
248
|
|
|
249
|
+
# Returns the active payment methods for the shop, sorted by the merchant-configured display position. Shop-level — does NOT vary by cart amount or currency. Each method exposes `type` (`CARD`, `BANK_TRANSFER`, `BLIK`, `PAYPAL`, `APPLE_PAY`, `GOOGLE_PAY`, `CASH_ON_DELIVERY`, `OTHER`), provider, icon, description, and supported currencies. Use to render the payment step of checkout.
|
|
241
250
|
query AvailablePaymentMethods {
|
|
242
251
|
availablePaymentMethods {
|
|
243
252
|
...AvailablePaymentMethods
|
|
@@ -245,9 +254,10 @@ query AvailablePaymentMethods {
|
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
# ============================================
|
|
248
|
-
# Shipments
|
|
257
|
+
# Shipments / Tracking
|
|
249
258
|
# ============================================
|
|
250
259
|
|
|
260
|
+
# Fetches a shipment by `id` with status, tracking events, recipient address, and shipped/delivered timestamps. **Auth required** — customer access token plus ownership of the parent order. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch to prevent enumeration), `FETCH_FAILED`.
|
|
251
261
|
query Shipment($id: ID!) {
|
|
252
262
|
shipment(id: $id) {
|
|
253
263
|
shipment {
|
|
@@ -259,6 +269,7 @@ query Shipment($id: ID!) {
|
|
|
259
269
|
}
|
|
260
270
|
}
|
|
261
271
|
|
|
272
|
+
# **Public** shipment lookup by carrier tracking number — no auth required. Designed for "Track my order" landing pages reachable without login. Returns the basic shipment fragment including recipient address. Wrapped response: `{ shipment, userErrors[] }`. Error codes: `INVALID_INPUT`, `NOT_FOUND`, `FETCH_FAILED`.
|
|
262
273
|
query ShipmentByTrackingNumber($trackingNumber: String!) {
|
|
263
274
|
shipmentByTrackingNumber(trackingNumber: $trackingNumber) {
|
|
264
275
|
shipment {
|
|
@@ -271,9 +282,10 @@ query ShipmentByTrackingNumber($trackingNumber: String!) {
|
|
|
271
282
|
}
|
|
272
283
|
|
|
273
284
|
# ============================================
|
|
274
|
-
# Returns
|
|
285
|
+
# Returns / RMA
|
|
275
286
|
# ============================================
|
|
276
287
|
|
|
288
|
+
# Fetches a single return (RMA) by `id` with line items, refund/compensation info, and history. **Auth required** — customer access token plus ownership of the return. Wrapped response: `{ return, userErrors[] }`. Error codes: `INVALID_TOKEN`, `NOT_FOUND` (also returned on ownership mismatch), `FETCH_FAILED`.
|
|
277
289
|
query Return($id: ID!) {
|
|
278
290
|
return(id: $id) {
|
|
279
291
|
return {
|
|
@@ -285,6 +297,7 @@ query Return($id: ID!) {
|
|
|
285
297
|
}
|
|
286
298
|
}
|
|
287
299
|
|
|
300
|
+
# Lists returns for a given order (paginated, default page size 20, cursor-based). **Auth required** — customer access token plus ownership of the order; the connection is empty (no explicit error) on auth failure. Use on the order detail page to show return history.
|
|
288
301
|
query ReturnsByOrder($orderId: ID!) {
|
|
289
302
|
returnsByOrder(orderId: $orderId) {
|
|
290
303
|
edges {
|
|
@@ -300,6 +313,7 @@ query ReturnsByOrder($orderId: ID!) {
|
|
|
300
313
|
}
|
|
301
314
|
}
|
|
302
315
|
|
|
316
|
+
# Returns the standard list of return reasons used by the RMA flow: `DEFECTIVE`, `NOT_AS_DESCRIBED`, `WRONG_ITEM`, `CHANGED_MIND`, `BETTER_PRICE`, `DAMAGED_SHIPPING`, `OTHER`. The list is fixed across all shops — not per-shop configurable. Public; no auth required.
|
|
303
317
|
query ReturnReasons {
|
|
304
318
|
returnReasons {
|
|
305
319
|
...ReturnReasonOption
|
|
@@ -307,15 +321,17 @@ query ReturnReasons {
|
|
|
307
321
|
}
|
|
308
322
|
|
|
309
323
|
# ============================================
|
|
310
|
-
# Gift Cards
|
|
324
|
+
# Gift Cards
|
|
311
325
|
# ============================================
|
|
312
326
|
|
|
327
|
+
# Public gift-card lookup by `code`. Returns balance, currency, expiry, and `maskedCode` (first 4 + last 4 chars only — the full code never leaks back). Returns null if the code is unknown (rather than an explicit error, to limit enumeration). **Rate-limited**: 10 requests per 60 seconds per IP.
|
|
313
328
|
query GiftCard($code: String!) {
|
|
314
329
|
giftCard(code: $code) {
|
|
315
330
|
...GiftCard
|
|
316
331
|
}
|
|
317
332
|
}
|
|
318
333
|
|
|
334
|
+
# Validates whether a gift card is usable (and optionally for a given `$amount`). Checks status (`DISABLED`, `USED`, `EXPIRED`), expiry date, and — when `$amount` is provided — sufficient balance. Returns `{ validation: { isValid, availableBalance, error: { code, message } }, userErrors[] }`. Validation error codes: `NOT_FOUND`, `DISABLED`, `ALREADY_USED`, `EXPIRED`, `INSUFFICIENT_BALANCE`. **Rate-limited**: 10 / 60s.
|
|
319
335
|
query GiftCardValidate($code: String!, $amount: Float) {
|
|
320
336
|
giftCardValidate(code: $code, amount: $amount) {
|
|
321
337
|
validation {
|
|
@@ -328,9 +344,10 @@ query GiftCardValidate($code: String!, $amount: Float) {
|
|
|
328
344
|
}
|
|
329
345
|
|
|
330
346
|
# ============================================
|
|
331
|
-
# Shipping Methods
|
|
347
|
+
# Shipping Methods
|
|
332
348
|
# ============================================
|
|
333
349
|
|
|
350
|
+
# Returns shipping methods for a given destination address and cart shape (subtotal, total weight, currency). The query computes everything from the inputs alone — no existing cart is required, so it can be used for "shipping cost preview" UIs before the customer adds anything to a cart. Each method includes price, free-shipping progress (`{ qualifies, currentAmount, threshold, remaining, progressPercent }`), estimated delivery, and carrier metadata. Sorted by the merchant's `sortOrder`, then by price.
|
|
334
351
|
query AvailableShippingMethods($address: ShippingAddressInput!, $cart: CartShippingInput) {
|
|
335
352
|
availableShippingMethods(address: $address, cart: $cart) {
|
|
336
353
|
methods {
|
|
@@ -346,9 +363,10 @@ query AvailableShippingMethods($address: ShippingAddressInput!, $cart: CartShipp
|
|
|
346
363
|
}
|
|
347
364
|
|
|
348
365
|
# ============================================
|
|
349
|
-
# Attribute Filters
|
|
366
|
+
# Attribute Filters
|
|
350
367
|
# ============================================
|
|
351
368
|
|
|
369
|
+
# Returns the dynamic facet filters available for a listing context — pass `collectionId`, `categoryId`, or `searchQuery`. For each visible & filterable attribute, returns either discrete value counts (for `SELECT` / `CHECKBOX` types) or numeric range bounds (for `SLIDER` types). Plus `priceRange`, per-category counts, `activeCount` (length of `currentFilters` input), and `matchCount` (total products in the context). Use to render filter sidebars on listing/search pages.
|
|
352
370
|
query AvailableFilters($input: AvailableFiltersInput) {
|
|
353
371
|
availableFilters(input: $input) {
|
|
354
372
|
...AvailableFilters
|
|
@@ -356,27 +374,31 @@ query AvailableFilters($input: AvailableFiltersInput) {
|
|
|
356
374
|
}
|
|
357
375
|
|
|
358
376
|
# ============================================
|
|
359
|
-
# Loyalty Program
|
|
377
|
+
# Loyalty Program
|
|
360
378
|
# ============================================
|
|
361
379
|
|
|
380
|
+
# Returns the logged-in customer's loyalty membership: points (current, pending, redeemed, expired, expiring), current tier, tier progress, annual spend, last activity. Returns null if the customer is not enrolled — there is **no auto-enrollment** here (enrollment happens via signup or a first qualifying order). Auth required.
|
|
362
381
|
query LoyaltyMember {
|
|
363
382
|
loyaltyMember {
|
|
364
383
|
...LoyaltyMember
|
|
365
384
|
}
|
|
366
385
|
}
|
|
367
386
|
|
|
387
|
+
# Lists the loyalty tiers configured for the shop (`BRONZE`, `SILVER`, `GOLD`, `PLATINUM`, `DIAMOND` etc.) with their `minPoints`, `minAnnualSpend`, `pointsMultiplier`, and custom benefits. Sorted by `minPoints` ASC. Public; no auth required.
|
|
368
388
|
query LoyaltyTiers {
|
|
369
389
|
loyaltyTiers {
|
|
370
390
|
...LoyaltyTier
|
|
371
391
|
}
|
|
372
392
|
}
|
|
373
393
|
|
|
394
|
+
# Lists rewards customers can redeem (free shipping, percent off, free product, gift card). Filtered to **active** rewards only (`is_active = true` AND inside their `starts_at`/`ends_at` window). Public; no auth required.
|
|
374
395
|
query LoyaltyRewards {
|
|
375
396
|
loyaltyRewards {
|
|
376
397
|
...LoyaltyReward
|
|
377
398
|
}
|
|
378
399
|
}
|
|
379
400
|
|
|
401
|
+
# Paginated history of loyalty point transactions for the logged-in customer (default 20). Transaction `type` enum: `EARN_PURCHASE`, `EARN_SIGNUP`, `EARN_REFERRAL`, `EARN_REVIEW`, `EARN_BIRTHDAY`, `EARN_BONUS`, `REDEEM`, `EXPIRE`, `ADJUST`, `REFUND_REVERSAL`. Auth required — empty connection if unauthenticated.
|
|
380
402
|
query LoyaltyTransactions($first: Int = 20, $after: String) {
|
|
381
403
|
loyaltyTransactions(first: $first, after: $after) {
|
|
382
404
|
edges {
|
|
@@ -392,18 +414,21 @@ query LoyaltyTransactions($first: Int = 20, $after: String) {
|
|
|
392
414
|
}
|
|
393
415
|
}
|
|
394
416
|
|
|
417
|
+
# Returns the loyalty program configuration: `isEnabled`, `pointsName` (e.g. "stars"), `pointsPerCurrency`, `pointsExpiryMonths`, available earn actions, referral settings. Use this at app boot to decide whether to render any loyalty UI at all. Public; no auth required.
|
|
395
418
|
query LoyaltySettings {
|
|
396
419
|
loyaltySettings {
|
|
397
420
|
...LoyaltySettings
|
|
398
421
|
}
|
|
399
422
|
}
|
|
400
423
|
|
|
424
|
+
# Estimates how many loyalty points the customer would earn for an order of `$orderTotal` (in major currency units). When the customer is authenticated, the result accounts for their current tier's points multiplier. Use on cart/checkout to show "Earn X points with this order".
|
|
401
425
|
query EstimatePoints($orderTotal: Float!) {
|
|
402
426
|
estimatePoints(orderTotal: $orderTotal) {
|
|
403
427
|
...PointsEstimate
|
|
404
428
|
}
|
|
405
429
|
}
|
|
406
430
|
|
|
431
|
+
# Returns the customer's referral statistics: `referralCode`, `shareUrl`, `totalReferred`, `completedReferrals`, `pendingReferrals`, `totalPointsEarned`. Auth required. Returns null if unauthenticated or if the referral program is disabled for the shop.
|
|
407
432
|
query ReferralStats {
|
|
408
433
|
referralStats {
|
|
409
434
|
...ReferralStats
|
|
@@ -414,6 +439,7 @@ query ReferralStats {
|
|
|
414
439
|
# Reviews
|
|
415
440
|
# ============================================
|
|
416
441
|
|
|
442
|
+
# Paginated list of customer reviews for a product, **filtered to APPROVED reviews only** (PENDING / REJECTED reviews are not exposed to the storefront). Sort by `CREATED_AT` (default), helpfulness, or rating. Public; no auth required.
|
|
417
443
|
query ProductReviews($productId: ID!, $first: Int = 10, $after: String, $sortKey: ReviewSortKey = CREATED_AT, $reverse: Boolean = true) {
|
|
418
444
|
productReviews(productId: $productId, first: $first, after: $after, sortKey: $sortKey, reverse: $reverse) {
|
|
419
445
|
edges {
|
|
@@ -429,6 +455,7 @@ query ProductReviews($productId: ID!, $first: Int = 10, $after: String, $sortKey
|
|
|
429
455
|
}
|
|
430
456
|
}
|
|
431
457
|
|
|
458
|
+
# Aggregate review statistics for a product: average rating, total count, distribution per star (1-5). Computed from APPROVED reviews only. Use for product card review summaries. Public; no auth required.
|
|
432
459
|
query ReviewStats($productId: ID!) {
|
|
433
460
|
reviewStats(productId: $productId) {
|
|
434
461
|
...ReviewStats
|
|
@@ -439,6 +466,7 @@ query ReviewStats($productId: ID!) {
|
|
|
439
466
|
# Wishlists
|
|
440
467
|
# ============================================
|
|
441
468
|
|
|
469
|
+
# Paginated list of the logged-in customer's wishlists (default 20). Auth required — empty connection if unauthenticated. Customers typically have a small set (<10).
|
|
442
470
|
query Wishlists($first: Int = 20, $after: String) {
|
|
443
471
|
wishlists(first: $first, after: $after) {
|
|
444
472
|
edges {
|
|
@@ -460,6 +488,7 @@ query Wishlists($first: Int = 20, $after: String) {
|
|
|
460
488
|
}
|
|
461
489
|
}
|
|
462
490
|
|
|
491
|
+
# Fetches a single wishlist by `id`. Private wishlists are visible only to the owner; public wishlists are visible to anyone. Note: this query supports lookup by `id` only — there is currently no way to fetch a wishlist by its share token.
|
|
463
492
|
query WishlistById($id: ID!) {
|
|
464
493
|
wishlist(id: $id) {
|
|
465
494
|
...Wishlist
|
|
@@ -470,6 +499,7 @@ query WishlistById($id: ID!) {
|
|
|
470
499
|
# Blog
|
|
471
500
|
# ============================================
|
|
472
501
|
|
|
502
|
+
# 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.
|
|
473
503
|
query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlug: String, $featured: Boolean, $sortKey: BlogPostSortKey = PUBLISHED_AT, $reverse: Boolean = false) {
|
|
474
504
|
blogPosts(first: $first, after: $after, categorySlug: $categorySlug, tagSlug: $tagSlug, featured: $featured, sortKey: $sortKey, reverse: $reverse) {
|
|
475
505
|
edges {
|
|
@@ -485,18 +515,21 @@ query BlogPosts($first: Int = 20, $after: String, $categorySlug: String, $tagSlu
|
|
|
485
515
|
}
|
|
486
516
|
}
|
|
487
517
|
|
|
518
|
+
# 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).
|
|
488
519
|
query BlogPost($id: ID, $slug: String) {
|
|
489
520
|
blogPost(id: $id, slug: $slug) {
|
|
490
521
|
...BlogPost
|
|
491
522
|
}
|
|
492
523
|
}
|
|
493
524
|
|
|
525
|
+
# Lists all blog categories with per-category `postCount` and SEO metadata. Use to render category navigation on blog pages. Public; no auth required.
|
|
494
526
|
query BlogCategories {
|
|
495
527
|
blogCategories {
|
|
496
528
|
...BlogCategory
|
|
497
529
|
}
|
|
498
530
|
}
|
|
499
531
|
|
|
532
|
+
# Lists blog tags with usage counts (`postCount` per tag). Use to render a tag cloud. Public; no auth required.
|
|
500
533
|
query BlogTags {
|
|
501
534
|
blogTags {
|
|
502
535
|
...BlogTag
|
|
@@ -507,6 +540,7 @@ query BlogTags {
|
|
|
507
540
|
# Recommendations
|
|
508
541
|
# ============================================
|
|
509
542
|
|
|
543
|
+
# Returns up to `$limit` recommended products related to `$productId`. Default `$intent: SIMILAR` — products sharing categories or tags. Use on PDP "You may also like" sections. Public; no auth required.
|
|
510
544
|
query ProductRecommendations($productId: ID!, $limit: Int = 8, $intent: RecommendationIntent = SIMILAR) {
|
|
511
545
|
productRecommendations(productId: $productId, limit: $limit, intent: $intent) {
|
|
512
546
|
...ProductCard
|
|
@@ -517,12 +551,14 @@ query ProductRecommendations($productId: ID!, $limit: Int = 8, $intent: Recommen
|
|
|
517
551
|
# Content: Pages
|
|
518
552
|
# ============================================
|
|
519
553
|
|
|
554
|
+
# Fetches a single CMS page (About, Privacy, Returns Policy, Terms, etc.) by `handle` or `id`. Visibility-gated: returns null if the page is hidden or if its publish date is in the future. Public; no auth required.
|
|
520
555
|
query Page($handle: String, $id: ID) {
|
|
521
556
|
page(handle: $handle, id: $id) {
|
|
522
557
|
...ShopPage
|
|
523
558
|
}
|
|
524
559
|
}
|
|
525
560
|
|
|
561
|
+
# Paginated list of visible, already-published CMS pages. Use for sitemap, footer link list, or page directory. The `query` argument supports text search over the page title/handle. Public; no auth required.
|
|
526
562
|
query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $reverse: Boolean = false, $query: String) {
|
|
527
563
|
pages(first: $first, after: $after, sortKey: $sortKey, reverse: $reverse, query: $query) {
|
|
528
564
|
edges {
|
|
@@ -542,6 +578,7 @@ query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $r
|
|
|
542
578
|
# Content: Navigation Menus
|
|
543
579
|
# ============================================
|
|
544
580
|
|
|
581
|
+
# 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.
|
|
545
582
|
query Menu($handle: String!) {
|
|
546
583
|
menu(handle: $handle) {
|
|
547
584
|
...Menu
|
|
@@ -552,6 +589,7 @@ query Menu($handle: String!) {
|
|
|
552
589
|
# Content: URL Redirects
|
|
553
590
|
# ============================================
|
|
554
591
|
|
|
592
|
+
# Returns the shop's URL redirects (legacy `path` → new `target` mappings). Use server-side at the edge or in SSR to issue 301 redirects for migrated routes (preserves SEO equity). Default page size 250 — most shops fit in a single page.
|
|
555
593
|
query UrlRedirects($first: Int = 250, $after: String) {
|
|
556
594
|
urlRedirects(first: $first, after: $after) {
|
|
557
595
|
nodes {
|
|
@@ -566,9 +604,8 @@ query UrlRedirects($first: Int = 250, $after: String) {
|
|
|
566
604
|
# ============================================
|
|
567
605
|
# Store Availability: per-location stock (BOPIS / multi-location)
|
|
568
606
|
# ============================================
|
|
569
|
-
# Field returns null for single-location shops (storefront can skip the store picker).
|
|
570
|
-
# `near`, `locationType`, and `@inContext(preferredLocationId)` shape the ordering.
|
|
571
607
|
|
|
608
|
+
# Fetches a product (by `handle` or `id`) along with per-variant availability across the merchant's physical locations — for the BOPIS / multi-location flow. The `storeAvailability` connection lives on each `ProductVariant`; its arguments (`first`, `after`, `near`, `locationType`) are set inside the `VariantStoreAvailability` fragment. The connection returns null for single-location shops (in which case the storefront can skip the store picker entirely). `availableStock` is null for anonymous users and an integer for authenticated customers. Apply `@inContext(preferredLocationId: ...)` on the operation to pin the customer's preferred location to the top of the result.
|
|
572
609
|
query ProductStoreAvailability($handle: String, $id: ID) {
|
|
573
610
|
product(handle: $handle, id: $id) {
|
|
574
611
|
id
|
|
@@ -584,6 +621,7 @@ query ProductStoreAvailability($handle: String, $id: ID) {
|
|
|
584
621
|
# Locations (store picker UI)
|
|
585
622
|
# ============================================
|
|
586
623
|
|
|
624
|
+
# Paginated list of active store locations (default 20, max 100). Filters: `near` (`{ latitude, longitude }`) for proximity search — sorts ascending by distance; `hasPickupEnabled` for pickup-only filtering; `locationType` (`RETAIL`, `WAREHOUSE`, `PICKUP_POINT`). When `near` is omitted, results are sorted by the merchant's `priority`, then name. Use for the BOPIS store picker UI. Public; no auth required.
|
|
587
625
|
query Locations(
|
|
588
626
|
$first: Int = 20
|
|
589
627
|
$after: String
|
|
@@ -611,6 +649,7 @@ query Locations(
|
|
|
611
649
|
}
|
|
612
650
|
}
|
|
613
651
|
|
|
652
|
+
# Fetches a single store location by `id` — full address, coordinates, business hours, pickup config (lead time, hours, timezone), and services. Returns null if the location is not found, not active, or owned by another shop. Use on the location detail page. Public; no auth required.
|
|
614
653
|
query Location($id: ID!) {
|
|
615
654
|
location(id: $id) {
|
|
616
655
|
...Location
|