@doswiftly/storefront-operations 4.4.0 → 5.4.1
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 +93 -0
- package/fragments.graphql +260 -18
- package/mutations.graphql +15 -0
- package/package.json +9 -8
- package/queries.graphql +117 -5
- package/schema.graphql +736 -29
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 5.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7846bdb: Fix `doswiftly dev` port pre-flight on Windows (and any host where another
|
|
8
|
+
process binds the port on IPv6 `::` only): the probe now checks IPv4 and
|
|
9
|
+
IPv6 in parallel and requires BOTH free before marking a port as available.
|
|
10
|
+
Previously an IPv6-only conflict (common on Windows, where Next.js binds
|
|
11
|
+
`::` by default) slipped past the IPv4-only probe — the banner advertised
|
|
12
|
+
`http://localhost:3000` and the framework immediately crashed with
|
|
13
|
+
`EADDRINUSE :::3000`. With this fix `doswiftly dev` falls back to the next
|
|
14
|
+
free port (3001, 3002, …) as documented.
|
|
15
|
+
|
|
16
|
+
Also ship `CHANGELOG.md` inside the npm tarball. Previous releases packed
|
|
17
|
+
only `dist`/`bin`/`templates` (and `schema.graphql`/operations for
|
|
18
|
+
`storefront-operations`, `dist` for `storefront-sdk`), so consumers who
|
|
19
|
+
`npm install @doswiftly/cli` got a version number with no user-visible
|
|
20
|
+
release notes.
|
|
21
|
+
|
|
22
|
+
## 5.4.0
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- 770fcd3: Added `Product.purchasable: Boolean!` to the storefront schema. The field mirrors `visibility === 'PUBLIC'` server-side and lets templates hide the "Add to cart" / "Buy now" path for component products that are only reachable through a parent product's configurator.
|
|
27
|
+
|
|
28
|
+
Templates can render a non-purchasable banner on the PDP instead of exposing a purchase action that the server will reject. Requesting the field is additive — operations that omit it keep working.
|
|
29
|
+
|
|
30
|
+
All notable changes to @doswiftly/storefront-operations will be documented in this file.
|
|
31
|
+
|
|
32
|
+
## [5.0.0] - 2026-04-12
|
|
33
|
+
|
|
34
|
+
### Breaking
|
|
35
|
+
|
|
36
|
+
- Removed `type InventoryLevel`, `fragment InventoryLevel`, `fragment VariantInventoryLevels`, and `query ProductInventory`.
|
|
37
|
+
- Removed `ProductVariant.inventoryLevels(locationType)` field — replaced by `ProductVariant.storeAvailability`.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Shopify-parity `StoreAvailability` surface on `ProductVariant`:
|
|
42
|
+
- `type StoreAvailability { available, quantityAvailable (token-gated), pickUpTime, location }`
|
|
43
|
+
- `type Location`, `LocationAddress`, `BusinessHours`, `BusinessHoursWindow` — full pickup-aware payload.
|
|
44
|
+
- `type StoreAvailabilityConnection` + `StoreAvailabilityEdge` — cursor-paginated, supports `near`, `locationType`, `@inContext(preferredLocationId)`.
|
|
45
|
+
- Root-level queries: `locations(first, after, near, hasPickupEnabled, locationType)` and `location(id)`.
|
|
46
|
+
- `directive @inContext(preferredLocationId: ID) on QUERY | MUTATION | SUBSCRIPTION` — Shopify operation directive for contextual hints (country / language / buyer to follow).
|
|
47
|
+
- Fragments: `StoreAvailability`, `StoreAvailabilityConnection`, `Location`, `LocationAddress`, `BusinessHours`, `BusinessHoursWindow`, `VariantStoreAvailability`.
|
|
48
|
+
- Queries: `ProductStoreAvailability`, `Locations`, `Location`.
|
|
49
|
+
|
|
50
|
+
### Migration
|
|
51
|
+
|
|
52
|
+
Replace:
|
|
53
|
+
|
|
54
|
+
```graphql
|
|
55
|
+
query ProductInventory($handle: String) {
|
|
56
|
+
product(handle: $handle) {
|
|
57
|
+
variants {
|
|
58
|
+
...VariantInventoryLevels
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
with:
|
|
65
|
+
|
|
66
|
+
```graphql
|
|
67
|
+
query ProductStoreAvailability($handle: String) {
|
|
68
|
+
product(handle: $handle) {
|
|
69
|
+
variants {
|
|
70
|
+
...VariantStoreAvailability
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`quantityAvailable` is now token-gated (null for anonymous, Int when `x-customer-access-token` is sent) — matches Shopify Storefront API.
|
|
77
|
+
|
|
78
|
+
## [1.0.0] - 2025-12-09
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- Initial release of @doswiftly/storefront-operations package
|
|
83
|
+
- GraphQL operations synced from backend SSOT
|
|
84
|
+
- Queries: Shop, Product, Products, ProductSearch, Collection, Collections, Category, Categories, Cart, Customer
|
|
85
|
+
- Mutations: Cart operations, Customer auth, Profile management, Address management, Password recovery
|
|
86
|
+
- Fragments: All reusable fragments for products, collections, cart, customer, etc.
|
|
87
|
+
- Sync script to copy operations from backend
|
|
88
|
+
- Package exports for .graphql files
|
|
89
|
+
- README with usage instructions
|
|
90
|
+
|
|
91
|
+
### Purpose
|
|
92
|
+
|
|
93
|
+
Enable direct GraphQL codegen approach for Next.js storefronts while maintaining Single Source of Truth from backend.
|
package/fragments.graphql
CHANGED
|
@@ -20,6 +20,7 @@ fragment UserError on UserError {
|
|
|
20
20
|
field
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
# Base Image — no transform (for logos, favicons, branding assets that are already small)
|
|
23
24
|
fragment Image on Image {
|
|
24
25
|
id
|
|
25
26
|
url
|
|
@@ -28,6 +29,37 @@ fragment Image on Image {
|
|
|
28
29
|
height
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
# Thumbnail — cart items, variant swatches, author avatars (rendered at ~96px, 300px covers 3x DPI)
|
|
33
|
+
# No preferredContentType — imgproxy auto-negotiates AVIF/WEBP from Accept header
|
|
34
|
+
fragment ImageThumbnail on Image {
|
|
35
|
+
id
|
|
36
|
+
url(transform: { maxWidth: 300 })
|
|
37
|
+
altText
|
|
38
|
+
width
|
|
39
|
+
height
|
|
40
|
+
thumbhash
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Card — product cards, collection/category cards, blog posts (rendered at ~400px, 800px covers 2x DPI)
|
|
44
|
+
fragment ImageCard on Image {
|
|
45
|
+
id
|
|
46
|
+
url(transform: { maxWidth: 800 })
|
|
47
|
+
altText
|
|
48
|
+
width
|
|
49
|
+
height
|
|
50
|
+
thumbhash
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Full — product detail gallery, hero images (rendered at ~800px, 1600px covers 2x DPI)
|
|
54
|
+
fragment ImageFull on Image {
|
|
55
|
+
id
|
|
56
|
+
url(transform: { maxWidth: 1600 })
|
|
57
|
+
altText
|
|
58
|
+
width
|
|
59
|
+
height
|
|
60
|
+
thumbhash
|
|
61
|
+
}
|
|
62
|
+
|
|
31
63
|
# Simple money (for originalPrice fields and non-converted prices)
|
|
32
64
|
fragment Money on Money {
|
|
33
65
|
amount
|
|
@@ -79,7 +111,7 @@ fragment ProductVariant on ProductVariant {
|
|
|
79
111
|
available
|
|
80
112
|
quantityAvailable
|
|
81
113
|
image {
|
|
82
|
-
...
|
|
114
|
+
...ImageThumbnail
|
|
83
115
|
}
|
|
84
116
|
selectedOptions {
|
|
85
117
|
...SelectedOption
|
|
@@ -102,7 +134,7 @@ fragment ProductCard on Product {
|
|
|
102
134
|
reviewCount
|
|
103
135
|
tags
|
|
104
136
|
featuredImage {
|
|
105
|
-
...
|
|
137
|
+
...ImageCard
|
|
106
138
|
}
|
|
107
139
|
priceRange {
|
|
108
140
|
minVariantPrice {
|
|
@@ -146,6 +178,9 @@ fragment ProductBase on Product {
|
|
|
146
178
|
totalInventory
|
|
147
179
|
type
|
|
148
180
|
collectRecipientInfo
|
|
181
|
+
# Faza 1.5 (Decision D-A v3 + D-B)
|
|
182
|
+
visibility
|
|
183
|
+
attributeSetId
|
|
149
184
|
createdAt
|
|
150
185
|
updatedAt
|
|
151
186
|
}
|
|
@@ -153,7 +188,7 @@ fragment ProductBase on Product {
|
|
|
153
188
|
fragment ProductFull on Product {
|
|
154
189
|
...ProductBase
|
|
155
190
|
images(first: 20) {
|
|
156
|
-
...
|
|
191
|
+
...ImageFull
|
|
157
192
|
}
|
|
158
193
|
variants(first: 100) {
|
|
159
194
|
...ProductVariant
|
|
@@ -175,7 +210,7 @@ fragment Collection on Collection {
|
|
|
175
210
|
description
|
|
176
211
|
descriptionHtml
|
|
177
212
|
image {
|
|
178
|
-
...
|
|
213
|
+
...ImageCard
|
|
179
214
|
}
|
|
180
215
|
seo {
|
|
181
216
|
title
|
|
@@ -195,7 +230,7 @@ fragment Category on Category {
|
|
|
195
230
|
slug
|
|
196
231
|
description
|
|
197
232
|
image {
|
|
198
|
-
...
|
|
233
|
+
...ImageCard
|
|
199
234
|
}
|
|
200
235
|
level
|
|
201
236
|
path
|
|
@@ -311,6 +346,24 @@ fragment CartLineCost on CartLineCost {
|
|
|
311
346
|
}
|
|
312
347
|
}
|
|
313
348
|
|
|
349
|
+
# Typed customer-filled attribute snapshot (Faza 1 R5 + Decision D-A v3 + D-I).
|
|
350
|
+
# Distinct from CartLine.attributes (Shopify raw KV line item properties).
|
|
351
|
+
fragment AttributeSelection on AttributeSelection {
|
|
352
|
+
attributeDefinitionId
|
|
353
|
+
attributeName
|
|
354
|
+
type
|
|
355
|
+
fillingMode
|
|
356
|
+
billingMode
|
|
357
|
+
optionId
|
|
358
|
+
optionLabel
|
|
359
|
+
optionIds
|
|
360
|
+
textValue
|
|
361
|
+
surchargeAmount
|
|
362
|
+
surchargeType
|
|
363
|
+
taxClassId
|
|
364
|
+
linkedVariantId
|
|
365
|
+
}
|
|
366
|
+
|
|
314
367
|
fragment CartLine on CartLine {
|
|
315
368
|
id
|
|
316
369
|
quantity
|
|
@@ -324,6 +377,9 @@ fragment CartLine on CartLine {
|
|
|
324
377
|
key
|
|
325
378
|
value
|
|
326
379
|
}
|
|
380
|
+
attributeSelections {
|
|
381
|
+
...AttributeSelection
|
|
382
|
+
}
|
|
327
383
|
productId
|
|
328
384
|
productTitle
|
|
329
385
|
productHandle
|
|
@@ -587,7 +643,7 @@ fragment CheckoutLineItem on CheckoutLineItem {
|
|
|
587
643
|
productId
|
|
588
644
|
sku
|
|
589
645
|
image {
|
|
590
|
-
...
|
|
646
|
+
...ImageThumbnail
|
|
591
647
|
}
|
|
592
648
|
}
|
|
593
649
|
|
|
@@ -1092,7 +1148,7 @@ fragment LoyaltyReward on LoyaltyReward {
|
|
|
1092
1148
|
}
|
|
1093
1149
|
description
|
|
1094
1150
|
image {
|
|
1095
|
-
...
|
|
1151
|
+
...ImageCard
|
|
1096
1152
|
}
|
|
1097
1153
|
available
|
|
1098
1154
|
tierRequired {
|
|
@@ -1242,14 +1298,14 @@ fragment BlogPost on BlogPost {
|
|
|
1242
1298
|
content
|
|
1243
1299
|
contentType
|
|
1244
1300
|
featuredImage {
|
|
1245
|
-
...
|
|
1301
|
+
...ImageCard
|
|
1246
1302
|
}
|
|
1247
1303
|
author {
|
|
1248
1304
|
id
|
|
1249
1305
|
name
|
|
1250
1306
|
bio
|
|
1251
1307
|
avatar {
|
|
1252
|
-
...
|
|
1308
|
+
...ImageThumbnail
|
|
1253
1309
|
}
|
|
1254
1310
|
}
|
|
1255
1311
|
category {
|
|
@@ -1306,24 +1362,210 @@ fragment CartRecommendation on CartRecommendations {
|
|
|
1306
1362
|
}
|
|
1307
1363
|
|
|
1308
1364
|
# ============================================
|
|
1309
|
-
#
|
|
1365
|
+
# Store Availability Fragments (Shopify parity — BOPIS / multi-location)
|
|
1310
1366
|
# ============================================
|
|
1367
|
+
# Field access:
|
|
1368
|
+
# - `available: Boolean!` — always public.
|
|
1369
|
+
# - `pickUpTime: String` — public, localized merchant-configured string.
|
|
1370
|
+
# - `quantityAvailable: Int` — TOKEN-GATED (null for anonymous, Int for authenticated).
|
|
1371
|
+
# - `location: Location!` — public, includes coords + businessHours when configured.
|
|
1372
|
+
|
|
1373
|
+
fragment LocationAddress on LocationAddress {
|
|
1374
|
+
address1
|
|
1375
|
+
address2
|
|
1376
|
+
city
|
|
1377
|
+
country
|
|
1378
|
+
countryCode
|
|
1379
|
+
province
|
|
1380
|
+
provinceCode
|
|
1381
|
+
zip
|
|
1382
|
+
phone
|
|
1383
|
+
latitude
|
|
1384
|
+
longitude
|
|
1385
|
+
formatted
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
fragment BusinessHoursWindow on BusinessHoursWindow {
|
|
1389
|
+
openHour
|
|
1390
|
+
closeHour
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
fragment BusinessHours on BusinessHours {
|
|
1394
|
+
monday { ...BusinessHoursWindow }
|
|
1395
|
+
tuesday { ...BusinessHoursWindow }
|
|
1396
|
+
wednesday { ...BusinessHoursWindow }
|
|
1397
|
+
thursday { ...BusinessHoursWindow }
|
|
1398
|
+
friday { ...BusinessHoursWindow }
|
|
1399
|
+
saturday { ...BusinessHoursWindow }
|
|
1400
|
+
sunday { ...BusinessHoursWindow }
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
fragment Location on Location {
|
|
1404
|
+
id
|
|
1405
|
+
name
|
|
1406
|
+
type
|
|
1407
|
+
pickupEnabled
|
|
1408
|
+
timezone
|
|
1409
|
+
pickupInstructions
|
|
1410
|
+
address {
|
|
1411
|
+
...LocationAddress
|
|
1412
|
+
}
|
|
1413
|
+
businessHours {
|
|
1414
|
+
...BusinessHours
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1311
1417
|
|
|
1312
|
-
fragment
|
|
1313
|
-
locationId
|
|
1314
|
-
locationName
|
|
1315
|
-
locationType
|
|
1418
|
+
fragment StoreAvailability on StoreAvailability {
|
|
1316
1419
|
available
|
|
1317
|
-
|
|
1420
|
+
quantityAvailable
|
|
1421
|
+
pickUpTime
|
|
1422
|
+
location {
|
|
1423
|
+
...Location
|
|
1424
|
+
}
|
|
1318
1425
|
}
|
|
1319
1426
|
|
|
1320
|
-
fragment
|
|
1427
|
+
fragment StoreAvailabilityConnection on StoreAvailabilityConnection {
|
|
1428
|
+
totalCount
|
|
1429
|
+
pageInfo {
|
|
1430
|
+
...PageInfo
|
|
1431
|
+
}
|
|
1432
|
+
edges {
|
|
1433
|
+
cursor
|
|
1434
|
+
node {
|
|
1435
|
+
...StoreAvailability
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
fragment VariantStoreAvailability on ProductVariant {
|
|
1321
1441
|
id
|
|
1322
1442
|
title
|
|
1323
1443
|
sku
|
|
1324
1444
|
available
|
|
1325
1445
|
quantityAvailable
|
|
1326
|
-
|
|
1327
|
-
...
|
|
1446
|
+
storeAvailability(first: 10) {
|
|
1447
|
+
...StoreAvailabilityConnection
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
# ============================================
|
|
1452
|
+
# Content: Pages
|
|
1453
|
+
# ============================================
|
|
1454
|
+
|
|
1455
|
+
fragment ShopPage on ShopPage {
|
|
1456
|
+
id
|
|
1457
|
+
handle
|
|
1458
|
+
title
|
|
1459
|
+
body
|
|
1460
|
+
bodySummary
|
|
1461
|
+
seo {
|
|
1462
|
+
title
|
|
1463
|
+
description
|
|
1464
|
+
}
|
|
1465
|
+
publishedAt
|
|
1466
|
+
createdAt
|
|
1467
|
+
updatedAt
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
# ============================================
|
|
1471
|
+
# Content: Navigation Menus
|
|
1472
|
+
# ============================================
|
|
1473
|
+
|
|
1474
|
+
fragment MenuItem on MenuItem {
|
|
1475
|
+
id
|
|
1476
|
+
title
|
|
1477
|
+
url
|
|
1478
|
+
type
|
|
1479
|
+
resourceId
|
|
1480
|
+
image {
|
|
1481
|
+
...Image
|
|
1482
|
+
}
|
|
1483
|
+
items {
|
|
1484
|
+
id
|
|
1485
|
+
title
|
|
1486
|
+
url
|
|
1487
|
+
type
|
|
1488
|
+
resourceId
|
|
1489
|
+
items {
|
|
1490
|
+
id
|
|
1491
|
+
title
|
|
1492
|
+
url
|
|
1493
|
+
type
|
|
1494
|
+
resourceId
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
fragment Menu on Menu {
|
|
1500
|
+
id
|
|
1501
|
+
handle
|
|
1502
|
+
title
|
|
1503
|
+
itemsCount
|
|
1504
|
+
items {
|
|
1505
|
+
...MenuItem
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
# ============================================
|
|
1510
|
+
# Content: URL Redirects
|
|
1511
|
+
# ============================================
|
|
1512
|
+
|
|
1513
|
+
fragment UrlRedirect on UrlRedirect {
|
|
1514
|
+
path
|
|
1515
|
+
target
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
# ============================================
|
|
1519
|
+
# Unified Product Configurator (Faza 1 + Faza 1.5 — Decision D-A v3 + D-I)
|
|
1520
|
+
# ============================================
|
|
1521
|
+
# Hybrid Magento binding:
|
|
1522
|
+
# - Product.attributes returns UNION of set definitions (via Product.attributeSetId)
|
|
1523
|
+
# and per-product scoped definitions (AttributeDefinition.scopeProductId = product.id)
|
|
1524
|
+
# - CUSTOMER fillingMode → rendered in storefront configurator UX
|
|
1525
|
+
# - MERCHANT fillingMode → product metadata (filtering, display)
|
|
1526
|
+
# - BOTH fillingMode → admin default + customer override in cart
|
|
1527
|
+
|
|
1528
|
+
fragment LinkedVariantSummary on LinkedVariantSummary {
|
|
1529
|
+
id
|
|
1530
|
+
productId
|
|
1531
|
+
title
|
|
1532
|
+
sku
|
|
1533
|
+
quantityAvailable
|
|
1534
|
+
isAvailable
|
|
1535
|
+
trackQuantity
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
fragment ProductAttributeOption on ProductAttributeOption {
|
|
1539
|
+
id
|
|
1540
|
+
value
|
|
1541
|
+
label
|
|
1542
|
+
sortOrder
|
|
1543
|
+
colorHex
|
|
1544
|
+
surchargeAmount
|
|
1545
|
+
surchargeType
|
|
1546
|
+
isDefault
|
|
1547
|
+
linkedVariantId
|
|
1548
|
+
linkedVariant {
|
|
1549
|
+
...LinkedVariantSummary
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
fragment ProductAttributeDefinition on ProductAttributeDefinition {
|
|
1554
|
+
id
|
|
1555
|
+
name
|
|
1556
|
+
slug
|
|
1557
|
+
description
|
|
1558
|
+
type
|
|
1559
|
+
fillingMode
|
|
1560
|
+
billingMode
|
|
1561
|
+
taxClassId
|
|
1562
|
+
scopeProductId
|
|
1563
|
+
isRequired
|
|
1564
|
+
isVisible
|
|
1565
|
+
displayOrder
|
|
1566
|
+
minValue
|
|
1567
|
+
maxValue
|
|
1568
|
+
options {
|
|
1569
|
+
...ProductAttributeOption
|
|
1328
1570
|
}
|
|
1329
1571
|
}
|
package/mutations.graphql
CHANGED
|
@@ -497,3 +497,18 @@ mutation WishlistDelete($wishlistId: ID!) {
|
|
|
497
497
|
userErrors
|
|
498
498
|
}
|
|
499
499
|
}
|
|
500
|
+
|
|
501
|
+
# ============================================
|
|
502
|
+
# Cart Attributes
|
|
503
|
+
# ============================================
|
|
504
|
+
|
|
505
|
+
mutation CartAttributesUpdate($cartId: ID!, $attributes: [CartAttributeInput!]!) {
|
|
506
|
+
cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {
|
|
507
|
+
cart {
|
|
508
|
+
...Cart
|
|
509
|
+
}
|
|
510
|
+
userErrors {
|
|
511
|
+
...UserError
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doswiftly/storefront-operations",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.4.1",
|
|
4
4
|
"description": "GraphQL operations for DoSwiftly Storefront - SSOT from backend",
|
|
5
5
|
"homepage": "https://doswiftly.pl",
|
|
6
6
|
"publishConfig": {
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"./fragments.graphql": "./fragments.graphql",
|
|
15
15
|
"./*.graphql": "./*.graphql"
|
|
16
16
|
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"sync": "node scripts/sync-operations.js",
|
|
19
|
-
"build": "npm run sync"
|
|
20
|
-
},
|
|
21
17
|
"keywords": [
|
|
22
18
|
"graphql",
|
|
23
19
|
"operations",
|
|
@@ -32,6 +28,11 @@
|
|
|
32
28
|
"queries.graphql",
|
|
33
29
|
"mutations.graphql",
|
|
34
30
|
"fragments.graphql",
|
|
35
|
-
"README.md"
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
"README.md",
|
|
32
|
+
"CHANGELOG.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"sync": "node scripts/sync-operations.js",
|
|
36
|
+
"build": "npm run sync"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/queries.graphql
CHANGED
|
@@ -23,6 +23,19 @@ query Product($id: ID, $handle: String) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
# Single-query configurator fetch (Faza 1 + Faza 1.5 — Decision D-A v3).
|
|
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).
|
|
30
|
+
query ProductConfigurator($handle: String!, $fillingMode: String = "CUSTOMER") {
|
|
31
|
+
product(handle: $handle) {
|
|
32
|
+
...ProductFull
|
|
33
|
+
attributes(filter: { fillingMode: $fillingMode }) {
|
|
34
|
+
...ProductAttributeDefinition
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
query Products(
|
|
27
40
|
$first: Int = 20
|
|
28
41
|
$after: String
|
|
@@ -460,7 +473,7 @@ query ProductRecommendations($productId: ID!, $limit: Int = 8, $intent: Recommen
|
|
|
460
473
|
query SimilarProducts($productId: String!, $first: Int = 6) {
|
|
461
474
|
similarProducts(productId: $productId, first: $first) {
|
|
462
475
|
items {
|
|
463
|
-
...
|
|
476
|
+
...ProductRecommendation
|
|
464
477
|
}
|
|
465
478
|
totalCount
|
|
466
479
|
}
|
|
@@ -468,11 +481,110 @@ query SimilarProducts($productId: String!, $first: Int = 6) {
|
|
|
468
481
|
|
|
469
482
|
query CartRecommendations($cartId: String!, $first: Int = 4) {
|
|
470
483
|
cartRecommendations(cartId: $cartId, first: $first) {
|
|
471
|
-
|
|
472
|
-
|
|
484
|
+
...CartRecommendation
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
# ============================================
|
|
489
|
+
# Content: Pages
|
|
490
|
+
# ============================================
|
|
491
|
+
|
|
492
|
+
query Page($handle: String, $id: ID) {
|
|
493
|
+
page(handle: $handle, id: $id) {
|
|
494
|
+
...ShopPage
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
query Pages($first: Int = 20, $after: String, $sortKey: PageSortKeys = TITLE, $reverse: Boolean = false, $query: String) {
|
|
499
|
+
pages(first: $first, after: $after, sortKey: $sortKey, reverse: $reverse, query: $query) {
|
|
500
|
+
edges {
|
|
501
|
+
node {
|
|
502
|
+
...ShopPage
|
|
503
|
+
}
|
|
504
|
+
cursor
|
|
473
505
|
}
|
|
474
|
-
|
|
475
|
-
...
|
|
506
|
+
pageInfo {
|
|
507
|
+
...PageInfo
|
|
476
508
|
}
|
|
509
|
+
totalCount
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
# ============================================
|
|
514
|
+
# Content: Navigation Menus
|
|
515
|
+
# ============================================
|
|
516
|
+
|
|
517
|
+
query Menu($handle: String!) {
|
|
518
|
+
menu(handle: $handle) {
|
|
519
|
+
...Menu
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
# ============================================
|
|
524
|
+
# Content: URL Redirects
|
|
525
|
+
# ============================================
|
|
526
|
+
|
|
527
|
+
query UrlRedirects($first: Int = 250, $after: String) {
|
|
528
|
+
urlRedirects(first: $first, after: $after) {
|
|
529
|
+
nodes {
|
|
530
|
+
...UrlRedirect
|
|
531
|
+
}
|
|
532
|
+
pageInfo {
|
|
533
|
+
...PageInfo
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
# ============================================
|
|
539
|
+
# Store Availability: per-location stock (Shopify parity — BOPIS / multi-location)
|
|
540
|
+
# ============================================
|
|
541
|
+
# Field returns null for single-location shops (storefront can skip the store picker).
|
|
542
|
+
# `near`, `locationType`, and `@inContext(preferredLocationId)` shape the ordering.
|
|
543
|
+
|
|
544
|
+
query ProductStoreAvailability($handle: String, $id: ID) {
|
|
545
|
+
product(handle: $handle, id: $id) {
|
|
546
|
+
id
|
|
547
|
+
handle
|
|
548
|
+
title
|
|
549
|
+
variants {
|
|
550
|
+
...VariantStoreAvailability
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
# ============================================
|
|
556
|
+
# Locations (store picker UI, Shopify parity)
|
|
557
|
+
# ============================================
|
|
558
|
+
|
|
559
|
+
query Locations(
|
|
560
|
+
$first: Int = 20
|
|
561
|
+
$after: String
|
|
562
|
+
$near: GeoCoordinateInput
|
|
563
|
+
$hasPickupEnabled: Boolean
|
|
564
|
+
$locationType: LocationType
|
|
565
|
+
) {
|
|
566
|
+
locations(
|
|
567
|
+
first: $first
|
|
568
|
+
after: $after
|
|
569
|
+
near: $near
|
|
570
|
+
hasPickupEnabled: $hasPickupEnabled
|
|
571
|
+
locationType: $locationType
|
|
572
|
+
) {
|
|
573
|
+
totalCount
|
|
574
|
+
pageInfo {
|
|
575
|
+
...PageInfo
|
|
576
|
+
}
|
|
577
|
+
edges {
|
|
578
|
+
cursor
|
|
579
|
+
node {
|
|
580
|
+
...Location
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
query Location($id: ID!) {
|
|
587
|
+
location(id: $id) {
|
|
588
|
+
...Location
|
|
477
589
|
}
|
|
478
590
|
}
|