@sixtyninecommerce/client 0.30.0 → 0.32.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.
Files changed (361) hide show
  1. package/README.md +574 -14
  2. package/dist/admin/http.d.ts.map +1 -1
  3. package/dist/admin/http.js.map +1 -1
  4. package/dist/admin/types.d.ts.map +1 -1
  5. package/dist/build-client.d.ts +9 -0
  6. package/dist/build-client.d.ts.map +1 -0
  7. package/dist/build-client.js +58 -0
  8. package/dist/build-client.js.map +1 -0
  9. package/dist/cache-tags.d.ts +35 -1
  10. package/dist/cache-tags.d.ts.map +1 -1
  11. package/dist/cache-tags.js +39 -1
  12. package/dist/cache-tags.js.map +1 -1
  13. package/dist/client.d.ts +25 -0
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +9 -62
  16. package/dist/client.js.map +1 -1
  17. package/dist/commerce/age-verification.d.ts +7 -4
  18. package/dist/commerce/age-verification.d.ts.map +1 -1
  19. package/dist/commerce/age-verification.js +6 -4
  20. package/dist/commerce/age-verification.js.map +1 -1
  21. package/dist/commerce/arguments.d.ts +13 -0
  22. package/dist/commerce/arguments.d.ts.map +1 -0
  23. package/dist/commerce/arguments.js +19 -0
  24. package/dist/commerce/arguments.js.map +1 -0
  25. package/dist/commerce/branding.d.ts.map +1 -1
  26. package/dist/commerce/branding.js.map +1 -1
  27. package/dist/commerce/capabilities.d.ts +40 -0
  28. package/dist/commerce/capabilities.d.ts.map +1 -0
  29. package/dist/commerce/capabilities.js +41 -0
  30. package/dist/commerce/capabilities.js.map +1 -0
  31. package/dist/commerce/cart.d.ts +9 -12
  32. package/dist/commerce/cart.d.ts.map +1 -1
  33. package/dist/commerce/cart.js +6 -1
  34. package/dist/commerce/cart.js.map +1 -1
  35. package/dist/commerce/checkout.d.ts +95 -15
  36. package/dist/commerce/checkout.d.ts.map +1 -1
  37. package/dist/commerce/checkout.js +230 -10
  38. package/dist/commerce/checkout.js.map +1 -1
  39. package/dist/commerce/customer.d.ts +83 -38
  40. package/dist/commerce/customer.d.ts.map +1 -1
  41. package/dist/commerce/customer.js +149 -10
  42. package/dist/commerce/customer.js.map +1 -1
  43. package/dist/commerce/favorites.d.ts +2 -5
  44. package/dist/commerce/favorites.d.ts.map +1 -1
  45. package/dist/commerce/favorites.js.map +1 -1
  46. package/dist/commerce/index.d.ts +194 -133
  47. package/dist/commerce/index.d.ts.map +1 -1
  48. package/dist/commerce/index.js +15 -0
  49. package/dist/commerce/index.js.map +1 -1
  50. package/dist/commerce/order-states.d.ts +18 -0
  51. package/dist/commerce/order-states.d.ts.map +1 -0
  52. package/dist/commerce/order-states.js +30 -0
  53. package/dist/commerce/order-states.js.map +1 -0
  54. package/dist/commerce/parcel-pricing.d.ts +48 -0
  55. package/dist/commerce/parcel-pricing.d.ts.map +1 -0
  56. package/dist/commerce/parcel-pricing.js +39 -0
  57. package/dist/commerce/parcel-pricing.js.map +1 -0
  58. package/dist/commerce/parked-orders.d.ts +22 -0
  59. package/dist/commerce/parked-orders.d.ts.map +1 -0
  60. package/dist/commerce/parked-orders.js +47 -0
  61. package/dist/commerce/parked-orders.js.map +1 -0
  62. package/dist/commerce/payments.d.ts +12 -5
  63. package/dist/commerce/payments.d.ts.map +1 -1
  64. package/dist/commerce/payments.js +10 -1
  65. package/dist/commerce/payments.js.map +1 -1
  66. package/dist/commerce/placement-error.d.ts +17 -0
  67. package/dist/commerce/placement-error.d.ts.map +1 -1
  68. package/dist/commerce/placement-error.js.map +1 -1
  69. package/dist/commerce/products.d.ts +92 -38
  70. package/dist/commerce/products.d.ts.map +1 -1
  71. package/dist/commerce/products.js +157 -123
  72. package/dist/commerce/products.js.map +1 -1
  73. package/dist/commerce/queries.d.ts +216 -49
  74. package/dist/commerce/queries.d.ts.map +1 -1
  75. package/dist/commerce/queries.js +1347 -743
  76. package/dist/commerce/queries.js.map +1 -1
  77. package/dist/commerce/quotes.d.ts +5 -4
  78. package/dist/commerce/quotes.d.ts.map +1 -1
  79. package/dist/commerce/quotes.js +1 -36
  80. package/dist/commerce/quotes.js.map +1 -1
  81. package/dist/commerce/receipt-claim.d.ts +35 -0
  82. package/dist/commerce/receipt-claim.d.ts.map +1 -0
  83. package/dist/commerce/receipt-claim.js +66 -0
  84. package/dist/commerce/receipt-claim.js.map +1 -0
  85. package/dist/commerce/recommendations.d.ts +3 -3
  86. package/dist/commerce/recommendations.d.ts.map +1 -1
  87. package/dist/commerce/recommendations.js +3 -1
  88. package/dist/commerce/recommendations.js.map +1 -1
  89. package/dist/commerce/returns.d.ts +7 -6
  90. package/dist/commerce/returns.d.ts.map +1 -1
  91. package/dist/commerce/returns.js +24 -3
  92. package/dist/commerce/returns.js.map +1 -1
  93. package/dist/commerce/reviews.d.ts +24 -15
  94. package/dist/commerce/reviews.d.ts.map +1 -1
  95. package/dist/commerce/reviews.js +67 -50
  96. package/dist/commerce/reviews.js.map +1 -1
  97. package/dist/commerce/saved-lists.d.ts +15 -15
  98. package/dist/commerce/saved-lists.d.ts.map +1 -1
  99. package/dist/commerce/saved-lists.js +67 -56
  100. package/dist/commerce/saved-lists.js.map +1 -1
  101. package/dist/commerce/search.d.ts +3 -2
  102. package/dist/commerce/search.d.ts.map +1 -1
  103. package/dist/commerce/search.js +2 -2
  104. package/dist/commerce/search.js.map +1 -1
  105. package/dist/commerce/shipping.d.ts +11 -4
  106. package/dist/commerce/shipping.d.ts.map +1 -1
  107. package/dist/commerce/shipping.js +17 -2
  108. package/dist/commerce/shipping.js.map +1 -1
  109. package/dist/commerce/stock-notifications.d.ts +2 -0
  110. package/dist/commerce/stock-notifications.d.ts.map +1 -1
  111. package/dist/commerce/stock-notifications.js +2 -2
  112. package/dist/commerce/stock-notifications.js.map +1 -1
  113. package/dist/commerce/store-pickup.d.ts +37 -0
  114. package/dist/commerce/store-pickup.d.ts.map +1 -0
  115. package/dist/commerce/store-pickup.js +66 -0
  116. package/dist/commerce/store-pickup.js.map +1 -0
  117. package/dist/commerce/subscriptions.d.ts +35 -37
  118. package/dist/commerce/subscriptions.d.ts.map +1 -1
  119. package/dist/commerce/subscriptions.js +159 -120
  120. package/dist/commerce/subscriptions.js.map +1 -1
  121. package/dist/commerce/vat-validation.d.ts +6 -3
  122. package/dist/commerce/vat-validation.d.ts.map +1 -1
  123. package/dist/commerce/vat-validation.js +24 -19
  124. package/dist/commerce/vat-validation.js.map +1 -1
  125. package/dist/constants.d.ts.map +1 -1
  126. package/dist/constants.js.map +1 -1
  127. package/dist/content/assets.d.ts +5 -4
  128. package/dist/content/assets.d.ts.map +1 -1
  129. package/dist/content/assets.js.map +1 -1
  130. package/dist/content/collection-pages.d.ts +3 -2
  131. package/dist/content/collection-pages.d.ts.map +1 -1
  132. package/dist/content/collection-pages.js.map +1 -1
  133. package/dist/content/collections.d.ts +5 -4
  134. package/dist/content/collections.d.ts.map +1 -1
  135. package/dist/content/collections.js.map +1 -1
  136. package/dist/content/filtered-products.d.ts.map +1 -1
  137. package/dist/content/filtered-products.js.map +1 -1
  138. package/dist/content/form-field-types.d.ts +3 -3
  139. package/dist/content/form-field-types.d.ts.map +1 -1
  140. package/dist/content/form-field-types.js.map +1 -1
  141. package/dist/content/forms.d.ts +4 -3
  142. package/dist/content/forms.d.ts.map +1 -1
  143. package/dist/content/forms.js +3 -0
  144. package/dist/content/forms.js.map +1 -1
  145. package/dist/content/index.d.ts +18 -17
  146. package/dist/content/index.d.ts.map +1 -1
  147. package/dist/content/items.d.ts +5 -4
  148. package/dist/content/items.d.ts.map +1 -1
  149. package/dist/content/items.js +2 -0
  150. package/dist/content/items.js.map +1 -1
  151. package/dist/content/menus.d.ts +3 -2
  152. package/dist/content/menus.d.ts.map +1 -1
  153. package/dist/content/menus.js +7 -1
  154. package/dist/content/menus.js.map +1 -1
  155. package/dist/content/resolve.d.ts +3 -2
  156. package/dist/content/resolve.d.ts.map +1 -1
  157. package/dist/content/resolve.js +1 -1
  158. package/dist/content/resolve.js.map +1 -1
  159. package/dist/content/sitemap.d.ts +3 -2
  160. package/dist/content/sitemap.d.ts.map +1 -1
  161. package/dist/content/sitemap.js.map +1 -1
  162. package/dist/content/strings.d.ts +16 -2
  163. package/dist/content/strings.d.ts.map +1 -1
  164. package/dist/content/strings.js +32 -4
  165. package/dist/content/strings.js.map +1 -1
  166. package/dist/core/context.d.ts +127 -1
  167. package/dist/core/context.d.ts.map +1 -1
  168. package/dist/core/context.js +436 -45
  169. package/dist/core/context.js.map +1 -1
  170. package/dist/core/currency.d.ts +14 -0
  171. package/dist/core/currency.d.ts.map +1 -0
  172. package/dist/core/currency.js +52 -0
  173. package/dist/core/currency.js.map +1 -0
  174. package/dist/core/deprecation.d.ts +23 -0
  175. package/dist/core/deprecation.d.ts.map +1 -0
  176. package/dist/core/deprecation.js +81 -0
  177. package/dist/core/deprecation.js.map +1 -0
  178. package/dist/core/http.d.ts +15 -1
  179. package/dist/core/http.d.ts.map +1 -1
  180. package/dist/core/http.js +55 -3
  181. package/dist/core/http.js.map +1 -1
  182. package/dist/core/public-artifact.d.ts +72 -0
  183. package/dist/core/public-artifact.d.ts.map +1 -0
  184. package/dist/core/public-artifact.js +122 -0
  185. package/dist/core/public-artifact.js.map +1 -0
  186. package/dist/core/unknown-field-rejection.d.ts +18 -0
  187. package/dist/core/unknown-field-rejection.d.ts.map +1 -0
  188. package/dist/core/unknown-field-rejection.js +37 -0
  189. package/dist/core/unknown-field-rejection.js.map +1 -0
  190. package/dist/credit/credit-status.d.ts +2 -0
  191. package/dist/credit/credit-status.d.ts.map +1 -1
  192. package/dist/credit/credit-status.js +71 -19
  193. package/dist/credit/credit-status.js.map +1 -1
  194. package/dist/credit/index.d.ts +1 -1
  195. package/dist/credit/payment-terms.d.ts +3 -3
  196. package/dist/credit/payment-terms.d.ts.map +1 -1
  197. package/dist/credit/payment-terms.js +28 -24
  198. package/dist/credit/payment-terms.js.map +1 -1
  199. package/dist/currency/exchange.d.ts +7 -7
  200. package/dist/currency/exchange.d.ts.map +1 -1
  201. package/dist/currency/exchange.js +5 -1
  202. package/dist/currency/exchange.js.map +1 -1
  203. package/dist/errors.d.ts +17 -0
  204. package/dist/errors.d.ts.map +1 -1
  205. package/dist/errors.js +13 -0
  206. package/dist/errors.js.map +1 -1
  207. package/dist/events/index.d.ts +20 -7
  208. package/dist/events/index.d.ts.map +1 -1
  209. package/dist/events/index.js +17 -5
  210. package/dist/events/index.js.map +1 -1
  211. package/dist/events/payloads.d.ts +7 -4
  212. package/dist/events/payloads.d.ts.map +1 -1
  213. package/dist/events/payloads.js +6 -3
  214. package/dist/events/payloads.js.map +1 -1
  215. package/dist/feeds/index.d.ts +5 -0
  216. package/dist/feeds/index.d.ts.map +1 -0
  217. package/dist/feeds/index.js +12 -0
  218. package/dist/feeds/index.js.map +1 -0
  219. package/dist/feeds/types.d.ts +18 -0
  220. package/dist/feeds/types.d.ts.map +1 -0
  221. package/dist/feeds/types.js +8 -0
  222. package/dist/feeds/types.js.map +1 -0
  223. package/dist/generated/cms.d.ts +2136 -0
  224. package/dist/generated/cms.d.ts.map +1 -0
  225. package/dist/generated/cms.js +4 -0
  226. package/dist/generated/cms.js.map +1 -0
  227. package/dist/generated/plugins.d.ts +550 -0
  228. package/dist/generated/plugins.d.ts.map +1 -0
  229. package/dist/generated/plugins.js +4 -0
  230. package/dist/generated/plugins.js.map +1 -0
  231. package/dist/generated/shop.d.ts +5663 -0
  232. package/dist/generated/shop.d.ts.map +1 -0
  233. package/dist/generated/shop.js +5 -0
  234. package/dist/generated/shop.js.map +1 -0
  235. package/dist/graphql-document.d.ts +29 -0
  236. package/dist/graphql-document.d.ts.map +1 -0
  237. package/dist/graphql-document.js +21 -0
  238. package/dist/graphql-document.js.map +1 -0
  239. package/dist/index.d.ts +10 -4
  240. package/dist/index.d.ts.map +1 -1
  241. package/dist/index.js +5 -2
  242. package/dist/index.js.map +1 -1
  243. package/dist/media/urls.d.ts.map +1 -1
  244. package/dist/media/urls.js +12 -1
  245. package/dist/media/urls.js.map +1 -1
  246. package/dist/media/video.d.ts.map +1 -1
  247. package/dist/media/video.js.map +1 -1
  248. package/dist/multi-store.d.ts +200 -0
  249. package/dist/multi-store.d.ts.map +1 -0
  250. package/dist/multi-store.js +558 -0
  251. package/dist/multi-store.js.map +1 -0
  252. package/dist/navigation/routes.d.ts +4 -3
  253. package/dist/navigation/routes.d.ts.map +1 -1
  254. package/dist/navigation/routes.js.map +1 -1
  255. package/dist/next/artifact-handler.d.ts +21 -13
  256. package/dist/next/artifact-handler.d.ts.map +1 -1
  257. package/dist/next/artifact-handler.js +28 -66
  258. package/dist/next/artifact-handler.js.map +1 -1
  259. package/dist/next/event-revalidate-handler.d.ts +26 -6
  260. package/dist/next/event-revalidate-handler.d.ts.map +1 -1
  261. package/dist/next/event-revalidate-handler.js +126 -19
  262. package/dist/next/event-revalidate-handler.js.map +1 -1
  263. package/dist/next/feed-handler.d.ts +50 -0
  264. package/dist/next/feed-handler.d.ts.map +1 -0
  265. package/dist/next/feed-handler.js +61 -0
  266. package/dist/next/feed-handler.js.map +1 -0
  267. package/dist/next/index.d.ts +3 -1
  268. package/dist/next/index.d.ts.map +1 -1
  269. package/dist/next/index.js +1 -0
  270. package/dist/next/index.js.map +1 -1
  271. package/dist/next/metadata.d.ts.map +1 -1
  272. package/dist/next/metadata.js.map +1 -1
  273. package/dist/next/redirect-middleware.d.ts +5 -31
  274. package/dist/next/redirect-middleware.d.ts.map +1 -1
  275. package/dist/next/redirect-middleware.js +4 -46
  276. package/dist/next/redirect-middleware.js.map +1 -1
  277. package/dist/next/revalidate-handler.d.ts.map +1 -1
  278. package/dist/next/revalidate-handler.js.map +1 -1
  279. package/dist/pricing/index.d.ts.map +1 -1
  280. package/dist/pricing/index.js.map +1 -1
  281. package/dist/pricing/tax-display.js +1 -1
  282. package/dist/pricing/tax-display.js.map +1 -1
  283. package/dist/pricing/tiers.d.ts +3 -2
  284. package/dist/pricing/tiers.d.ts.map +1 -1
  285. package/dist/pricing/tiers.js.map +1 -1
  286. package/dist/pricing/validation.d.ts +88 -12
  287. package/dist/pricing/validation.d.ts.map +1 -1
  288. package/dist/pricing/validation.js +93 -12
  289. package/dist/pricing/validation.js.map +1 -1
  290. package/dist/redirects/index.d.ts.map +1 -1
  291. package/dist/redirects/index.js +2 -1
  292. package/dist/redirects/index.js.map +1 -1
  293. package/dist/redirects/store.d.ts.map +1 -1
  294. package/dist/redirects/store.js +6 -2
  295. package/dist/redirects/store.js.map +1 -1
  296. package/dist/redirects/types.d.ts +5 -2
  297. package/dist/redirects/types.d.ts.map +1 -1
  298. package/dist/revalidation/event-plan.d.ts +55 -4
  299. package/dist/revalidation/event-plan.d.ts.map +1 -1
  300. package/dist/revalidation/event-plan.js +115 -8
  301. package/dist/revalidation/event-plan.js.map +1 -1
  302. package/dist/revalidation/event-verify.d.ts +8 -37
  303. package/dist/revalidation/event-verify.d.ts.map +1 -1
  304. package/dist/revalidation/event-verify.js +7 -97
  305. package/dist/revalidation/event-verify.js.map +1 -1
  306. package/dist/revalidation/types.d.ts.map +1 -1
  307. package/dist/revalidation/url-context.d.ts +17 -0
  308. package/dist/revalidation/url-context.d.ts.map +1 -1
  309. package/dist/revalidation/url-context.js +35 -2
  310. package/dist/revalidation/url-context.js.map +1 -1
  311. package/dist/seo/ai.d.ts.map +1 -1
  312. package/dist/seo/ai.js.map +1 -1
  313. package/dist/seo/artifacts.d.ts +86 -4
  314. package/dist/seo/artifacts.d.ts.map +1 -1
  315. package/dist/seo/artifacts.js +115 -16
  316. package/dist/seo/artifacts.js.map +1 -1
  317. package/dist/seo/availability.d.ts +2 -2
  318. package/dist/seo/availability.d.ts.map +1 -1
  319. package/dist/seo/availability.js.map +1 -1
  320. package/dist/seo/index.d.ts +2 -0
  321. package/dist/seo/index.d.ts.map +1 -1
  322. package/dist/seo/index.js +3 -1
  323. package/dist/seo/index.js.map +1 -1
  324. package/dist/seo/json-ld.d.ts.map +1 -1
  325. package/dist/seo/json-ld.js.map +1 -1
  326. package/dist/seo/meta-tags.d.ts.map +1 -1
  327. package/dist/seo/meta-tags.js.map +1 -1
  328. package/dist/seo/metadata-parser.d.ts.map +1 -1
  329. package/dist/seo/metadata-parser.js.map +1 -1
  330. package/dist/seo/metadata-types.d.ts.map +1 -1
  331. package/dist/seo/robots.d.ts.map +1 -1
  332. package/dist/seo/robots.js.map +1 -1
  333. package/dist/seo/types.d.ts +9 -2
  334. package/dist/seo/types.d.ts.map +1 -1
  335. package/dist/seo/url-builder.d.ts +5 -3
  336. package/dist/seo/url-builder.d.ts.map +1 -1
  337. package/dist/seo/url-builder.js +3 -1
  338. package/dist/seo/url-builder.js.map +1 -1
  339. package/dist/types.d.ts +1381 -2537
  340. package/dist/types.d.ts.map +1 -1
  341. package/dist/web/artifact-responder.d.ts +69 -0
  342. package/dist/web/artifact-responder.d.ts.map +1 -0
  343. package/dist/web/artifact-responder.js +90 -0
  344. package/dist/web/artifact-responder.js.map +1 -0
  345. package/dist/web/feed-responder.d.ts +72 -0
  346. package/dist/web/feed-responder.d.ts.map +1 -0
  347. package/dist/web/feed-responder.js +81 -0
  348. package/dist/web/feed-responder.js.map +1 -0
  349. package/dist/web/index.d.ts +23 -0
  350. package/dist/web/index.d.ts.map +1 -0
  351. package/dist/web/index.js +19 -0
  352. package/dist/web/index.js.map +1 -0
  353. package/dist/web/redirect-middleware.d.ts +76 -0
  354. package/dist/web/redirect-middleware.d.ts.map +1 -0
  355. package/dist/web/redirect-middleware.js +94 -0
  356. package/dist/web/redirect-middleware.js.map +1 -0
  357. package/dist/web/respond.d.ts +20 -0
  358. package/dist/web/respond.d.ts.map +1 -0
  359. package/dist/web/respond.js +52 -0
  360. package/dist/web/respond.js.map +1 -0
  361. package/package.json +18 -2
@@ -1,12 +1,54 @@
1
- // --- Product Queries ---
1
+ import { fragment, withFragments } from '../graphql-document.js';
2
+ // Every document and fragment below is tagged `/* GraphQL */` and read by
3
+ // codegen (codegen.ts), which ERASES `${…}` interpolations: a selection shared
4
+ // between documents is a named `fragment`, composed with `withFragments`.
5
+ // Regenerate `src/generated/shop.ts` after any edit: `pnpm codegen`.
6
+ // --- Catalog fragments ---
7
+ /** The merchant publication state — the same three fields wherever it is read. */
8
+ export const PRODUCT_AVAILABILITY_FRAGMENT = fragment(/* GraphQL */ `
9
+ fragment ProductAvailability on ProductAvailability {
10
+ state availableFrom orderable
11
+ }
12
+ `);
13
+ export const PRICE_TIER_FRAGMENT = fragment(/* GraphQL */ `
14
+ fragment PriceTier on PriceTier {
15
+ minQuantity price priceWithTax discountLabel
16
+ }
17
+ `);
18
+ export const VARIANT_LOCATION_AVAILABILITY_FRAGMENT = fragment(/* GraphQL */ `
19
+ fragment VariantLocationAvailability on VariantLocationAvailability {
20
+ locationId locationName inStock
21
+ }
22
+ `);
23
+ export const FACET_VALUE_FRAGMENT = fragment(/* GraphQL */ `
24
+ fragment FacetValue on FacetValue {
25
+ id name code facet { id name code }
26
+ }
27
+ `);
28
+ /**
29
+ * A product's collections, as canonical/hreflang resolution reads them.
30
+ *
31
+ * The parent's `slug` is load-bearing: a top-level collection is parented to
32
+ * the `__root_collection__` SENTINEL (Vendure resolves `parent` to null only
33
+ * when the real parent is PRIVATE), so the slug is what tells "root" from
34
+ * "nested" — see `isUserFacingRoot`.
35
+ */
36
+ export const COLLECTION_REF_FRAGMENT = fragment(/* GraphQL */ `
37
+ fragment CollectionRef on Collection {
38
+ id name slug position
39
+ parent { id slug }
40
+ translations { languageCode name slug }
41
+ customFields { isRoutable isCanonical }
42
+ }
43
+ `);
2
44
  /**
3
- * Fragment for `Product.metadata` (vendure-plugin-product-metadata). The
4
- * server already picks the active-language translation and composes
5
- * `metaRobots` + `resolvedBotDirectives` — the SDK only needs to validate +
6
- * type-narrow the JSON-scalar fields at the boundary.
45
+ * `Product.metadata` (vendure-plugin-product-metadata). The server already
46
+ * picks the active-language translation and composes `metaRobots` +
47
+ * `resolvedBotDirectives` — the SDK only validates and type-narrows the
48
+ * JSON-scalar fields at the boundary (`parseProductMetadata`).
7
49
  */
8
- const PRODUCT_METADATA_FRAGMENT = `
9
- metadata {
50
+ export const PRODUCT_METADATA_FRAGMENT = fragment(/* GraphQL */ `
51
+ fragment ProductMetadata on ProductMetadataShop {
10
52
  seoTitle seoDescription canonicalUrl
11
53
  socialTitle socialDescription socialImageAlt socialOgType
12
54
  socialImage {
@@ -31,73 +73,41 @@ const PRODUCT_METADATA_FRAGMENT = `
31
73
  metaRobots resolvedBotDirectives
32
74
  includeReviewsInJsonld
33
75
  }
34
- `;
35
- export const GET_PRODUCT = `
36
- query GetProduct($slug: String!) {
37
- product(slug: $slug) {
38
- id name slug description
39
- availability { state availableFrom orderable }
76
+ `);
77
+ /** A variant as the product DETAIL read returns it. */
78
+ export const PRODUCT_VARIANT_FRAGMENT = fragment(
79
+ /* GraphQL */ `
80
+ fragment ProductVariant on ProductVariant {
81
+ id name sku
82
+ price priceWithTax currencyCode stockLevel
83
+ stockOnHand stockAllocated saleable
84
+ incomingStock projectedSaleable nextExpectedArrival
85
+ backorderAllowance
86
+ availability { ...ProductAvailability }
87
+ forSaleInCurrency
88
+ priceListName retailPrice retailPriceWithTax taxRateApplied { value }
89
+ priceTiers { ...PriceTier }
90
+ availabilityByLocation { ...VariantLocationAvailability }
91
+ options { id code name group { id name code } }
92
+ customFields { minOrderQuantity salesUnit position }
40
93
  featuredAsset {
41
94
  source name width height
42
95
  customFields { altText }
43
- presets {
44
- xxs { url webpUrl } xs { url webpUrl }
45
- s { url webpUrl } m { url webpUrl }
46
- l { url webpUrl } xl { url webpUrl }
47
- }
96
+ presets { xs { url webpUrl } m { url webpUrl } }
48
97
  }
49
98
  assets {
50
99
  source name width height
51
100
  customFields { altText }
52
- presets {
53
- xs { url webpUrl } m { url webpUrl }
54
- l { url webpUrl } xl { url webpUrl }
55
- }
101
+ presets { m { url webpUrl } l { url webpUrl } }
56
102
  }
57
- variants {
58
- id name sku
59
- price priceWithTax currencyCode stockLevel
60
- stockOnHand stockAllocated saleable
61
- incomingStock projectedSaleable nextExpectedArrival
62
- backorderAllowance
63
- availability { state availableFrom orderable }
64
- priceListName retailPrice retailPriceWithTax taxRateApplied { value }
65
- priceTiers { minQuantity price priceWithTax discountLabel }
66
- availabilityByLocation { locationId locationName inStock }
67
- options { id code name group { id name code } }
68
- customFields { minOrderQuantity salesUnit position }
69
- featuredAsset {
70
- source name width height
71
- customFields { altText }
72
- presets { xs { url webpUrl } m { url webpUrl } }
73
- }
74
- assets {
75
- source name width height
76
- customFields { altText }
77
- presets { m { url webpUrl } l { url webpUrl } }
78
- }
79
- }
80
- optionGroups { id name code options { id name code } }
81
- facetValues { id name code facet { id name code } }
82
- translations { languageCode name slug description }
83
- collections {
84
- id name slug position
85
- parent { id slug }
86
- translations { languageCode name slug }
87
- customFields { isRoutable isCanonical }
88
- }
89
- documents {
90
- id position title description fileUrl fileMimeType fileSize fileName requiresAuth
91
- }
92
- ${PRODUCT_METADATA_FRAGMENT}
93
103
  }
94
- }
95
- `;
96
- export const GET_PRODUCT_BY_ID = `
97
- query GetProductById($id: ID!) {
98
- product(id: $id) {
104
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, VARIANT_LOCATION_AVAILABILITY_FRAGMENT);
105
+ /** The product DETAIL read (`getProduct`, `getProductById`). */
106
+ export const PRODUCT_FRAGMENT = fragment(
107
+ /* GraphQL */ `
108
+ fragment Product on Product {
99
109
  id name slug description
100
- availability { state availableFrom orderable }
110
+ availability { ...ProductAvailability }
101
111
  featuredAsset {
102
112
  source name width height
103
113
  customFields { altText }
@@ -115,80 +125,45 @@ export const GET_PRODUCT_BY_ID = `
115
125
  l { url webpUrl } xl { url webpUrl }
116
126
  }
117
127
  }
128
+ variants { ...ProductVariant }
129
+ optionGroups { id name code options { id name code } }
130
+ facetValues { ...FacetValue }
131
+ translations { languageCode name slug description }
132
+ collections { ...CollectionRef }
133
+ documents {
134
+ id position title description fileUrl fileMimeType fileSize fileName requiresAuth
135
+ }
136
+ metadata { ...ProductMetadata }
137
+ }
138
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRODUCT_VARIANT_FRAGMENT, FACET_VALUE_FRAGMENT, COLLECTION_REF_FRAGMENT, PRODUCT_METADATA_FRAGMENT);
139
+ /** A row of the full product LIST (`getProducts`, the default `detail`). */
140
+ export const PRODUCT_SUMMARY_FRAGMENT = fragment(
141
+ /* GraphQL */ `
142
+ fragment ProductSummary on Product {
143
+ id name slug description enabled
144
+ featuredAsset {
145
+ source name width height
146
+ customFields { altText }
147
+ presets { xs { url webpUrl } m { url webpUrl } l { url webpUrl } }
148
+ }
118
149
  variants {
119
150
  id name sku
120
151
  price priceWithTax currencyCode stockLevel
121
- stockOnHand stockAllocated saleable
122
- incomingStock projectedSaleable nextExpectedArrival
123
- backorderAllowance
124
- availability { state availableFrom orderable }
152
+ stockOnHand stockAllocated saleable
153
+ incomingStock projectedSaleable nextExpectedArrival
154
+ backorderAllowance
155
+ availability { ...ProductAvailability }
156
+ forSaleInCurrency
125
157
  priceListName retailPrice retailPriceWithTax taxRateApplied { value }
126
- priceTiers { minQuantity price priceWithTax discountLabel }
127
- availabilityByLocation { locationId locationName inStock }
128
- options { id code name group { id name code } }
158
+ priceTiers { ...PriceTier }
159
+ availabilityByLocation { ...VariantLocationAvailability }
129
160
  customFields { minOrderQuantity salesUnit position }
130
- featuredAsset {
131
- source name width height
132
- customFields { altText }
133
- presets { xs { url webpUrl } m { url webpUrl } }
134
- }
135
- assets {
136
- source name width height
137
- customFields { altText }
138
- presets { m { url webpUrl } l { url webpUrl } }
139
- }
140
161
  }
141
- optionGroups { id name code options { id name code } }
142
- facetValues { id name code facet { id name code } }
162
+ facetValues { ...FacetValue }
143
163
  translations { languageCode name slug description }
144
- collections {
145
- id name slug position
146
- parent { id slug }
147
- translations { languageCode name slug }
148
- customFields { isRoutable isCanonical }
149
- }
150
- documents {
151
- id position title description fileUrl fileMimeType fileSize fileName requiresAuth
152
- }
153
- ${PRODUCT_METADATA_FRAGMENT}
164
+ collections { ...CollectionRef }
154
165
  }
155
- }
156
- `;
157
- export const LIST_PRODUCTS = `
158
- query ListProducts($options: ProductListOptions) {
159
- products(options: $options) {
160
- items {
161
- id name slug description enabled
162
- featuredAsset {
163
- source name width height
164
- customFields { altText }
165
- presets { xs { url webpUrl } m { url webpUrl } l { url webpUrl } }
166
- }
167
- variants {
168
- id name sku
169
- price priceWithTax currencyCode stockLevel
170
- stockOnHand stockAllocated saleable
171
- incomingStock projectedSaleable nextExpectedArrival
172
- backorderAllowance
173
- availability { state availableFrom orderable }
174
- priceListName retailPrice retailPriceWithTax taxRateApplied { value }
175
- priceTiers { minQuantity price priceWithTax discountLabel }
176
- availabilityByLocation { locationId locationName inStock }
177
- customFields { minOrderQuantity salesUnit position }
178
- }
179
- facetValues { id name code facet { id name code } }
180
- translations { languageCode name slug description }
181
- collections {
182
- id name slug position
183
- parent { id slug }
184
- translations { languageCode name slug }
185
- customFields { isRoutable isCanonical }
186
- }
187
- }
188
- totalItems
189
- }
190
- }
191
- `;
166
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, VARIANT_LOCATION_AVAILABILITY_FRAGMENT, FACET_VALUE_FRAGMENT, COLLECTION_REF_FRAGMENT);
192
167
  /**
193
168
  * The card selection: what a product GRID tile renders, and nothing else.
194
169
  *
@@ -229,9 +204,15 @@ export const LIST_PRODUCTS = `
229
204
  * `customFields.isCanonical` + `parent.slug` + `position`, and its localized
230
205
  * slug from the translations. A card row still satisfies `ProductForSeo`
231
206
  * structurally, so omitting these does not fail to compile — it silently
232
- * hands every product the FLAT path. Note these cost bytes, not queries:
233
- * Vendure resolves `Product.collections` in one query per product whichever
234
- * subfields are asked for.
207
+ * hands every product the FLAT path. Cost: a constant number of queries per
208
+ * page, not per row. The platform batches `Product.collections` for every
209
+ * product of the page into ONE statement and `parent` for every listed
210
+ * collection into one more (`services/vendure/src/collection-batching`),
211
+ * and `translations` / `customFields` come back in those same rows. Core
212
+ * Vendure alone ran one query per product plus one per listed collection
213
+ * — measured 419 statements for an 80-product page, 2 with the batching.
214
+ * Not batched: `featuredAsset`, `children`, `breadcrumbs` or
215
+ * `productVariants` under `collections` still cost a query per collection.
235
216
  * - `priceTiers` — the SDK's own `getPriceDisplay()` reads
236
217
  * `variant.priceTiers?.length ? … : null`, so an ABSENT ladder is
237
218
  * indistinguishable from "this variant has no tiers": a tile would quietly
@@ -245,74 +226,64 @@ export const LIST_PRODUCTS = `
245
226
  * Reached with `getProducts(..., { detail: 'card' })`. The default stays
246
227
  * `LIST_PRODUCTS`, so no existing caller changes behaviour.
247
228
  */
248
- export const LIST_PRODUCT_CARDS = `
249
- query ListProductCards($options: ProductListOptions) {
250
- products(options: $options) {
251
- items {
252
- id name slug enabled
253
- featuredAsset {
254
- source name width height
255
- customFields { altText }
256
- presets { xs { url webpUrl } m { url webpUrl } l { url webpUrl } }
257
- }
258
- variants {
259
- id name sku
260
- price priceWithTax currencyCode stockLevel saleable backorderAllowance
261
- availability { state availableFrom orderable }
262
- priceListName retailPrice retailPriceWithTax taxRateApplied { value }
263
- priceTiers { minQuantity price priceWithTax discountLabel }
264
- customFields { minOrderQuantity salesUnit position }
265
- }
266
- facetValues { id name code facet { id name code } }
267
- translations { languageCode name slug }
268
- collections {
269
- id name slug position
270
- parent { id slug }
271
- translations { languageCode name slug }
272
- customFields { isRoutable isCanonical }
273
- }
229
+ export const PRODUCT_CARD_FRAGMENT = fragment(
230
+ /* GraphQL */ `
231
+ fragment ProductCard on Product {
232
+ id name slug enabled
233
+ featuredAsset {
234
+ source name width height
235
+ customFields { altText }
236
+ presets { xs { url webpUrl } m { url webpUrl } l { url webpUrl } }
274
237
  }
275
- totalItems
276
- }
277
- }
278
- `;
279
- export const LIST_FACETS = `
280
- query ListFacets {
281
- facets {
282
- items {
283
- id name code
284
- values { id name code }
238
+ variants {
239
+ id name sku
240
+ price priceWithTax currencyCode stockLevel saleable backorderAllowance
241
+ availability { ...ProductAvailability }
242
+ forSaleInCurrency
243
+ priceListName retailPrice retailPriceWithTax taxRateApplied { value }
244
+ priceTiers { ...PriceTier }
245
+ customFields { minOrderQuantity salesUnit position }
285
246
  }
286
- totalItems
287
- }
288
- }
289
- `;
290
- // --- Collection Queries ---
291
- export const LIST_COLLECTIONS = `
292
- query ListCollections($options: CollectionListOptions) {
293
- collections(options: $options) {
294
- items {
295
- id name slug description
296
- breadcrumbs { id name slug }
297
- featuredAsset {
298
- source width height
299
- presets { xs { url webpUrl } m { url webpUrl } }
300
- }
301
- parent { id name slug }
302
- children { id name slug }
247
+ facetValues { ...FacetValue }
248
+ translations { languageCode name slug }
249
+ collections { ...CollectionRef }
250
+ }
251
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, FACET_VALUE_FRAGMENT, COLLECTION_REF_FRAGMENT);
252
+ export const FACET_FRAGMENT = fragment(/* GraphQL */ `
253
+ fragment Facet on Facet {
254
+ id name code
255
+ values { id name code }
256
+ }
257
+ `);
258
+ export const BREADCRUMB_FRAGMENT = fragment(/* GraphQL */ `
259
+ fragment Breadcrumb on CollectionBreadcrumb {
260
+ id name slug
261
+ }
262
+ `);
263
+ /** A row of the collection LIST (`getCollections`). */
264
+ export const COLLECTION_FRAGMENT = fragment(
265
+ /* GraphQL */ `
266
+ fragment Collection on Collection {
267
+ id name slug description
268
+ breadcrumbs { ...Breadcrumb }
269
+ featuredAsset {
270
+ source width height
271
+ presets { xs { url webpUrl } m { url webpUrl } }
303
272
  }
304
- totalItems
273
+ parent { id name slug }
274
+ children { id name slug }
305
275
  }
306
- }
307
- `;
308
- /** The collection-detail selection, shared by the slug and the id lookup. */
309
- const COLLECTION_DETAIL_FIELDS = `
276
+ `, BREADCRUMB_FRAGMENT);
277
+ /** The collection DETAIL read, shared by the slug and the id lookup. */
278
+ export const COLLECTION_DETAIL_FRAGMENT = fragment(
279
+ /* GraphQL */ `
280
+ fragment CollectionDetail on Collection {
310
281
  id name slug description position
311
282
  featuredAsset {
312
283
  source width height
313
284
  presets { l { url webpUrl } xl { url webpUrl } }
314
285
  }
315
- breadcrumbs { id name slug }
286
+ breadcrumbs { ...Breadcrumb }
316
287
  parent { id }
317
288
  children { id name slug }
318
289
  customFields {
@@ -349,146 +320,324 @@ const COLLECTION_DETAIL_FIELDS = `
349
320
  stockOnHand stockAllocated saleable
350
321
  incomingStock projectedSaleable nextExpectedArrival
351
322
  backorderAllowance
352
- availability { state availableFrom orderable }
323
+ availability { ...ProductAvailability }
324
+ forSaleInCurrency
353
325
  priceListName retailPrice retailPriceWithTax taxRateApplied { value }
354
- priceTiers { minQuantity price priceWithTax discountLabel }
355
- availabilityByLocation { locationId locationName inStock }
326
+ priceTiers { ...PriceTier }
327
+ availabilityByLocation { ...VariantLocationAvailability }
356
328
  customFields { minOrderQuantity salesUnit position }
357
329
  }
358
330
  totalItems
359
331
  }
360
- `;
361
- export const GET_COLLECTION = `
362
- query GetCollection($slug: String!) {
363
- collection(slug: $slug) {${COLLECTION_DETAIL_FIELDS} }
364
- }
365
- `;
366
- export const GET_COLLECTION_BY_ID = `
367
- query GetCollectionById($id: ID!) {
368
- collection(id: $id) {${COLLECTION_DETAIL_FIELDS} }
369
- }
370
- `;
371
- // --- Search Query ---
372
- export const SEARCH_PRODUCTS = `
373
- query SearchProducts($input: SearchInput!) {
374
- search(input: $input) {
375
- items {
376
- productId productVariantId productName slug description
377
- price { ... on SinglePrice { value } ... on PriceRange { min max } }
378
- priceWithTax { ... on SinglePrice { value } ... on PriceRange { min max } }
379
- currencyCode
380
- productAsset { preview focalPoint { x y } }
381
- collectionIds
382
- inStock
383
- availability { state availableFrom orderable }
384
- }
332
+ }
333
+ `, BREADCRUMB_FRAGMENT, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, VARIANT_LOCATION_AVAILABILITY_FRAGMENT);
334
+ /**
335
+ * One search hit. `productVariantId` is the orderable id (never pass
336
+ * `productId` to `addToCart`); `availability` is null for a document indexed
337
+ * before the attribute existed, until the channel is fully reindexed.
338
+ */
339
+ export const SEARCH_RESULT_ITEM_FRAGMENT = fragment(
340
+ /* GraphQL */ `
341
+ fragment SearchResultItem on SearchResult {
342
+ productId productVariantId productName slug description
343
+ price { ... on SinglePrice { value } ... on PriceRange { min max } }
344
+ priceWithTax { ... on SinglePrice { value } ... on PriceRange { min max } }
345
+ currencyCode
346
+ productAsset { preview focalPoint { x y } }
347
+ collectionIds
348
+ inStock
349
+ availability { ...ProductAvailability }
350
+ forSaleInCurrency
351
+ }
352
+ `, PRODUCT_AVAILABILITY_FRAGMENT);
353
+ export const SEARCH_RESULT_FRAGMENT = fragment(
354
+ /* GraphQL */ `
355
+ fragment SearchResult on SearchResponse {
356
+ items { ...SearchResultItem }
385
357
  totalItems
386
- facetValues { facetValue { id name code facet { id name code } } count }
358
+ facetValues { facetValue { ...FacetValue } count }
387
359
  }
360
+ `, SEARCH_RESULT_ITEM_FRAGMENT, FACET_VALUE_FRAGMENT);
361
+ // --- Product Queries ---
362
+ export const GET_PRODUCT = withFragments(
363
+ /* GraphQL */ `
364
+ query GetProduct($slug: String!) {
365
+ product(slug: $slug) { ...Product }
366
+ }
367
+ `, PRODUCT_FRAGMENT);
368
+ export const GET_PRODUCT_BY_ID = withFragments(
369
+ /* GraphQL */ `
370
+ query GetProductById($id: ID!) {
371
+ product(id: $id) { ...Product }
372
+ }
373
+ `, PRODUCT_FRAGMENT);
374
+ /**
375
+ * A storefront-visible metafield as it arrives ON an entity: the
376
+ * `storefront: read` values an app or the store published (headless spec
377
+ * §8.13). `value` is whatever the definition's type describes.
378
+ */
379
+ export const METAFIELD_FRAGMENT = fragment(/* GraphQL */ `
380
+ fragment Metafield on Metafield {
381
+ namespace key value
388
382
  }
389
- `;
383
+ `);
384
+ /**
385
+ * OPT-IN product reads, chosen by `getProduct(slug, { metafields })` and
386
+ * `getProductById(id, { metafields })`: the default `Product` selection plus
387
+ * the product's own metafields and every variant's, `$namespace` narrowing
388
+ * both to one app (`null` is every namespace).
389
+ *
390
+ * Separate documents, never a `metafields` selection in `PRODUCT_FRAGMENT`
391
+ * (the rule `ORDER_FULFILLMENT_PARCELS_FRAGMENT` follows): `Product.metafields`
392
+ * is an additive Shop API field, and an engine without it fails the WHOLE
393
+ * document at validation. Selected by default, an SDK upgraded ahead of the
394
+ * engine deploy would 400 every product page; selected here, only a caller
395
+ * that asked for metafields needs the newer engine. GraphQL merges this
396
+ * `variants` selection with the fragment's, so each variant still comes back
397
+ * whole.
398
+ *
399
+ * The server reads every product's (and every variant's) metafields of the
400
+ * request in one statement per owner type, so the variant selection costs one
401
+ * read, not one per variant.
402
+ */
403
+ export const GET_PRODUCT_WITH_METAFIELDS = withFragments(
404
+ /* GraphQL */ `
405
+ query GetProductWithMetafields($slug: String!, $namespace: String) {
406
+ product(slug: $slug) {
407
+ ...Product
408
+ metafields(namespace: $namespace) { ...Metafield }
409
+ variants { id metafields(namespace: $namespace) { ...Metafield } }
410
+ }
411
+ }
412
+ `, PRODUCT_FRAGMENT, METAFIELD_FRAGMENT);
413
+ /** {@link GET_PRODUCT_WITH_METAFIELDS} by id. */
414
+ export const GET_PRODUCT_BY_ID_WITH_METAFIELDS = withFragments(
415
+ /* GraphQL */ `
416
+ query GetProductByIdWithMetafields($id: ID!, $namespace: String) {
417
+ product(id: $id) {
418
+ ...Product
419
+ metafields(namespace: $namespace) { ...Metafield }
420
+ variants { id metafields(namespace: $namespace) { ...Metafield } }
421
+ }
422
+ }
423
+ `, PRODUCT_FRAGMENT, METAFIELD_FRAGMENT);
424
+ export const LIST_PRODUCTS = withFragments(
425
+ /* GraphQL */ `
426
+ query ListProducts($options: ProductListOptions) {
427
+ products(options: $options) {
428
+ items { ...ProductSummary }
429
+ totalItems
430
+ }
431
+ }
432
+ `, PRODUCT_SUMMARY_FRAGMENT);
433
+ export const LIST_PRODUCT_CARDS = withFragments(
434
+ /* GraphQL */ `
435
+ query ListProductCards($options: ProductListOptions) {
436
+ products(options: $options) {
437
+ items { ...ProductCard }
438
+ totalItems
439
+ }
440
+ }
441
+ `, PRODUCT_CARD_FRAGMENT);
442
+ export const LIST_FACETS = withFragments(
443
+ /* GraphQL */ `
444
+ query ListFacets {
445
+ facets {
446
+ items { ...Facet }
447
+ totalItems
448
+ }
449
+ }
450
+ `, FACET_FRAGMENT);
451
+ // --- Collection Queries ---
452
+ export const LIST_COLLECTIONS = withFragments(
453
+ /* GraphQL */ `
454
+ query ListCollections($options: CollectionListOptions) {
455
+ collections(options: $options) {
456
+ items { ...Collection }
457
+ totalItems
458
+ }
459
+ }
460
+ `, COLLECTION_FRAGMENT);
461
+ export const GET_COLLECTION = withFragments(
462
+ /* GraphQL */ `
463
+ query GetCollection($slug: String!) {
464
+ collection(slug: $slug) { ...CollectionDetail }
465
+ }
466
+ `, COLLECTION_DETAIL_FRAGMENT);
467
+ export const GET_COLLECTION_BY_ID = withFragments(
468
+ /* GraphQL */ `
469
+ query GetCollectionById($id: ID!) {
470
+ collection(id: $id) { ...CollectionDetail }
471
+ }
472
+ `, COLLECTION_DETAIL_FRAGMENT);
473
+ /**
474
+ * OPT-IN collection reads with the collection's own metafields, chosen by
475
+ * `getCollection(slug, { metafields })` and `getCollectionById(id, {
476
+ * metafields })`. Separate documents for the reason
477
+ * {@link GET_PRODUCT_WITH_METAFIELDS} gives.
478
+ */
479
+ export const GET_COLLECTION_WITH_METAFIELDS = withFragments(
480
+ /* GraphQL */ `
481
+ query GetCollectionWithMetafields($slug: String!, $namespace: String) {
482
+ collection(slug: $slug) {
483
+ ...CollectionDetail
484
+ metafields(namespace: $namespace) { ...Metafield }
485
+ }
486
+ }
487
+ `, COLLECTION_DETAIL_FRAGMENT, METAFIELD_FRAGMENT);
488
+ /** {@link GET_COLLECTION_WITH_METAFIELDS} by id. */
489
+ export const GET_COLLECTION_BY_ID_WITH_METAFIELDS = withFragments(
490
+ /* GraphQL */ `
491
+ query GetCollectionByIdWithMetafields($id: ID!, $namespace: String) {
492
+ collection(id: $id) {
493
+ ...CollectionDetail
494
+ metafields(namespace: $namespace) { ...Metafield }
495
+ }
496
+ }
497
+ `, COLLECTION_DETAIL_FRAGMENT, METAFIELD_FRAGMENT);
498
+ // --- Search Query ---
499
+ export const SEARCH_PRODUCTS = withFragments(
500
+ /* GraphQL */ `
501
+ query SearchProducts($input: SearchInput!) {
502
+ search(input: $input) { ...SearchResult }
503
+ }
504
+ `, SEARCH_RESULT_FRAGMENT);
390
505
  // --- Cart Mutations ---
391
506
  // Shared selection set for full Order objects. Used by ACTIVE_ORDER, ADD_TO_CART,
392
507
  // ADJUST_ORDER_LINE, REMOVE_ORDER_LINE, APPLY_COUPON, REMOVE_COUPON, ORDER_BY_CODE.
393
508
  // Keep in one place so adding fields (e.g. discounts) lands everywhere consistently.
394
- const ORDER_FIELDS = `
395
- id code state active
396
- createdAt orderPlacedAt
397
- totalQuantity
398
- subTotal subTotalWithTax
399
- shipping shippingWithTax
400
- total totalWithTax
401
- currencyCode
402
- lines {
403
- id quantity
404
- unitPrice unitPriceWithTax taxRate
405
- linePrice linePriceWithTax
406
- discountedLinePrice discountedLinePriceWithTax
509
+ const ORDER_FRAGMENT = fragment(/* GraphQL */ `
510
+ fragment Order on Order {
511
+ id code state active
512
+ createdAt orderPlacedAt
513
+ totalQuantity
514
+ subTotal subTotalWithTax
515
+ shipping shippingWithTax
516
+ total totalWithTax
517
+ currencyCode
518
+ lines {
519
+ id quantity
520
+ unitPrice unitPriceWithTax taxRate
521
+ linePrice linePriceWithTax
522
+ discountedLinePrice discountedLinePriceWithTax
523
+ discounts { adjustmentSource type description amount amountWithTax }
524
+ productVariant {
525
+ id name sku saleable
526
+ product { id name slug }
527
+ options { id name group { name } }
528
+ }
529
+ featuredAsset { source presets { xs { url webpUrl } } }
530
+ }
407
531
  discounts { adjustmentSource type description amount amountWithTax }
408
- productVariant {
409
- id name sku saleable
410
- product { id name slug }
411
- options { id name group { name } }
412
- }
413
- featuredAsset { source presets { xs { url webpUrl } } }
414
- }
415
- discounts { adjustmentSource type description amount amountWithTax }
416
- taxSummary { description taxRate taxBase taxTotal }
417
- promotions { id name couponCode description }
418
- shippingLines { shippingMethod { id name code } priceWithTax }
419
- payments { id method amount state transactionId }
420
- shippingAddress { fullName company streetLine1 streetLine2 city province postalCode countryCode phoneNumber }
421
- billingAddress { fullName company streetLine1 streetLine2 city province postalCode countryCode phoneNumber }
422
- customer { id firstName lastName emailAddress }
423
- couponCodes
424
- `;
532
+ taxSummary { description taxRate taxBase taxTotal }
533
+ promotions { id name couponCode description conditions { code } }
534
+ shippingLines { shippingMethod { id name code } priceWithTax }
535
+ payments { id method amount state transactionId }
536
+ shippingAddress { fullName company streetLine1 streetLine2 city province postalCode countryCode phoneNumber }
537
+ billingAddress { fullName company streetLine1 streetLine2 city province postalCode countryCode phoneNumber }
538
+ customer { id firstName lastName emailAddress }
539
+ couponCodes
540
+ }
541
+ `);
425
542
  /**
426
- * Fulfillment/tracking selection for placed orders. Kept out of ORDER_FIELDS
543
+ * Fulfillment/tracking selection for placed orders. Kept out of ORDER_FRAGMENT
427
544
  * so cart mutations don't pay for it — active carts have no fulfillments.
428
545
  * `trackingCode` feeds `trackShipment(barcode, postalCode)`.
429
546
  *
430
547
  * `externalShipments` is the carrier-agnostic list pushed by an external
431
548
  * fulfilment system, and is the right thing to render for tracking: one
432
549
  * fulfilment can cover SEVERAL parcels, which a single `trackingCode` cannot
433
- * express. Render `reference` as a link when `isLink` is true and as a text block
434
- * otherwise — a pallet carrier's reference or ex-works pickup instructions are
435
- * prose, not URLs. The flag is derived server-side so the storefront never has
436
- * to guess.
550
+ * express — though `fulfillments[].trackingCodes` does for a carrier we book
551
+ * ourselves (see {@link ORDER_FULFILLMENT_PARCELS_FRAGMENT}). Render
552
+ * `reference` as a link when `isLink` is true and as a text block otherwise — a
553
+ * pallet carrier's reference or ex-works pickup instructions are prose, not
554
+ * URLs. The flag is derived server-side so the storefront never has to guess.
437
555
  */
438
- const ORDER_FULFILLMENTS_FRAGMENT = `
439
- fulfillments {
440
- id state method trackingCode createdAt updatedAt
441
- lines { orderLineId quantity }
556
+ const ORDER_FULFILLMENTS_FRAGMENT = fragment(/* GraphQL */ `
557
+ fragment OrderFulfillments on Order {
558
+ fulfillments {
559
+ id state method trackingCode createdAt updatedAt
560
+ lines { orderLineId quantity }
561
+ }
562
+ externalShipments {
563
+ carrier reference isLink shippedAt deliveryNumber
564
+ }
442
565
  }
443
- externalShipments {
444
- carrier reference isLink shippedAt deliveryNumber
566
+ `);
567
+ /**
568
+ * OPTIONAL per-parcel barcodes, selected by the two PLACED-order reads
569
+ * (`ORDER_BY_CODE`, `GET_CUSTOMER_ORDERS`) and nowhere else — the same rule
570
+ * `lines { backorderedQuantity }` and `customFields { paymentIntent }` follow.
571
+ *
572
+ * `Fulfillment.trackingCodes` is an additive Shop API field that only an engine
573
+ * shipping the MyParcel plugin's multi-parcel release answers. In the shared
574
+ * `ORDER_FULFILLMENTS_FRAGMENT` it also reached `ORDER_SUMMARY_FRAGMENT` and so
575
+ * `GET_CURRENT_CUSTOMER` — the customer-session read every page makes. An SDK
576
+ * upgrade ahead of the engine deploy would then 400 the whole document at
577
+ * GraphQL validation and log every customer out of their account area, for a
578
+ * field that only enriches a tracking list. GraphQL merges this `fulfillments`
579
+ * selection with the fragment's, so the fulfillment still comes back whole.
580
+ *
581
+ * Needs the engine release named in this package's changeset; against an older
582
+ * one these two reads fail validation while the rest of the SDK keeps working.
583
+ */
584
+ const ORDER_FULFILLMENT_PARCELS_FRAGMENT = fragment(/* GraphQL */ `
585
+ fragment OrderFulfillmentParcels on Order {
586
+ fulfillments { id trackingCodes }
445
587
  }
446
- `;
588
+ `);
447
589
  /** Immutable payment condition captured when a placed order was accepted. */
448
- const ORDER_PAYMENT_TERMS_FRAGMENT = `
449
- paymentTerms {
450
- source managedExternally status
451
- conditionCode conditionDescription summary classification
452
- paymentDays paymentEndOfMonths paymentMethod percentage
453
- discountPaymentDays discountPercentage paymentDiscountType
454
- stale syncedAt error
455
- resolvedAt remoteConditionCode remoteConfirmedAt remoteMismatch
456
- }
457
- `;
590
+ const ORDER_PAYMENT_TERMS_FRAGMENT = fragment(/* GraphQL */ `
591
+ fragment OrderPaymentTerms on Order {
592
+ paymentTerms {
593
+ source managedExternally status
594
+ conditionCode conditionDescription summary classification
595
+ paymentDays paymentEndOfMonths paymentMethod percentage
596
+ discountPaymentDays discountPercentage paymentDiscountType
597
+ stale syncedAt error
598
+ resolvedAt remoteConditionCode remoteConfirmedAt remoteMismatch
599
+ }
600
+ }
601
+ `);
458
602
  /** Immutable delivery terms captured when a placed order was accepted. */
459
- const ORDER_DELIVERY_TERMS_FRAGMENT = `
460
- deliveryTerms {
461
- source managedExternally status shippingMethodStatus policyStatus summary selectionSource
462
- selectedShippingMethodId selectedShippingMethodCode selectedShippingMethodName
463
- platformShippingMethodCode platformShippingMethodName platformShippingMethodDescription
464
- platformShippingPrice platformShippingPriceWithTax
465
- preferredShippingMethodId
466
- incotermStatus incotermCode incotermVersion incotermAddress incotermDescription
467
- shippingLeadDays deliveryAdvice stale syncedAt warning resolvedAt
468
- remoteShippingMethodCode remoteShippingMethodName
469
- remoteIncotermCode remoteIncotermVersion remoteIncotermAddress remoteDeliveryDate
470
- remoteConfirmedAt remoteMismatch
603
+ const ORDER_DELIVERY_TERMS_FRAGMENT = fragment(/* GraphQL */ `
604
+ fragment OrderDeliveryTerms on Order {
605
+ deliveryTerms {
606
+ source managedExternally status shippingMethodStatus policyStatus summary selectionSource
607
+ selectedShippingMethodId selectedShippingMethodCode selectedShippingMethodName
608
+ platformShippingMethodCode platformShippingMethodName platformShippingMethodDescription
609
+ platformShippingPrice platformShippingPriceWithTax
610
+ preferredShippingMethodId
611
+ incotermStatus incotermCode incotermVersion incotermAddress incotermDescription
612
+ shippingLeadDays deliveryAdvice stale syncedAt warning resolvedAt
613
+ remoteShippingMethodCode remoteShippingMethodName
614
+ remoteIncotermCode remoteIncotermVersion remoteIncotermAddress remoteDeliveryDate
615
+ remoteConfirmedAt remoteMismatch
616
+ }
471
617
  }
472
- `;
618
+ `);
473
619
  /**
474
620
  * Order-history list-item selection (customer order history). Enriched beyond a
475
621
  * bare line count so a storefront can render thumbnails + per-line totals
476
622
  * without a follow-up fetch. Shared by GET_CURRENT_CUSTOMER and
477
623
  * GET_CUSTOMER_ORDERS — both map to OrderSummary.
478
624
  */
479
- const ORDER_SUMMARY_FIELDS = `
480
- id code state total totalWithTax currencyCode createdAt
481
- lines {
482
- id quantity linePriceWithTax
483
- productVariant {
484
- id name sku
485
- product { slug featuredAsset { preview presets { xs { webpUrl } } } }
625
+ const ORDER_SUMMARY_FRAGMENT = fragment(
626
+ /* GraphQL */ `
627
+ fragment OrderSummary on Order {
628
+ id code state total totalWithTax currencyCode createdAt
629
+ lines {
630
+ id quantity linePriceWithTax
631
+ productVariant {
632
+ id name sku
633
+ product { slug featuredAsset { preview presets { xs { webpUrl } } } }
634
+ }
635
+ }
636
+ ...OrderFulfillments
637
+ ...OrderPaymentTerms
638
+ ...OrderDeliveryTerms
486
639
  }
487
- }
488
- ${ORDER_FULFILLMENTS_FRAGMENT}
489
- ${ORDER_PAYMENT_TERMS_FRAGMENT}
490
- ${ORDER_DELIVERY_TERMS_FRAGMENT}
491
- `;
640
+ `, ORDER_FULFILLMENTS_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT);
492
641
  /**
493
642
  * The structured half of a placement rejection, selected wherever the Shop API
494
643
  * can answer one.
@@ -499,28 +648,30 @@ const ORDER_SUMMARY_FIELDS = `
499
648
  * are populated per code and null otherwise, so selecting all of them costs
500
649
  * one flat response object and saves a second round of documents per feature.
501
650
  */
502
- const PLACEMENT_FIELDS = `
503
- code
504
- customerMessage
505
- linesTruncated
506
- requiredAmount
507
- currencyCode
508
- amountBasis
509
- requiredQuantity
510
- priceListName
511
- salesUnit
512
- minimumAge
513
- lines {
514
- orderLineId
515
- productVariantId
516
- sku
517
- productName
518
- productVariantName
519
- quantityRequested
520
- quantityAvailable
521
- }
522
- details { field code message }
523
- `;
651
+ const PLACEMENT_REJECTION_FRAGMENT = fragment(/* GraphQL */ `
652
+ fragment PlacementRejection on PlacementRejection {
653
+ code
654
+ customerMessage
655
+ linesTruncated
656
+ requiredAmount
657
+ currencyCode
658
+ amountBasis
659
+ requiredQuantity
660
+ priceListName
661
+ salesUnit
662
+ minimumAge
663
+ lines {
664
+ orderLineId
665
+ productVariantId
666
+ sku
667
+ productName
668
+ productVariantName
669
+ quantityRequested
670
+ quantityAvailable
671
+ }
672
+ details { field code message }
673
+ }
674
+ `);
524
675
  /**
525
676
  * WHICH line an `InsufficientStockError` is about.
526
677
  *
@@ -530,124 +681,157 @@ const PLACEMENT_FIELDS = `
530
681
  * — an error raised outside the overridden cart mutations answers null to all
531
682
  * of them. `inputIndex` is only ever non-null inside `addItemsToOrder`.
532
683
  */
533
- const INSUFFICIENT_STOCK_FIELDS = `
534
- errorCode message quantityAvailable
535
- productVariantId orderLineId sku productName productVariantName
536
- quantityRequested inputIndex
537
- `;
538
- export const ACTIVE_ORDER = `
539
- query ActiveOrder {
540
- activeOrder { ${ORDER_FIELDS} }
541
- }
542
- `;
543
- export const ADD_TO_CART = `
544
- mutation AddToCart($variantId: ID!, $quantity: Int!) {
545
- addItemToOrder(productVariantId: $variantId, quantity: $quantity) {
546
- ... on Order { ${ORDER_FIELDS} }
547
- ... on OrderModificationError { errorCode message }
548
- ... on OrderLimitError { errorCode message maxItems }
549
- ... on NegativeQuantityError { errorCode message }
550
- ... on InsufficientStockError { ${INSUFFICIENT_STOCK_FIELDS} order { id } }
684
+ const INSUFFICIENT_STOCK_ERROR_FRAGMENT = fragment(/* GraphQL */ `
685
+ fragment InsufficientStockError on InsufficientStockError {
686
+ errorCode message quantityAvailable
687
+ productVariantId orderLineId sku productName productVariantName
688
+ quantityRequested inputIndex
689
+ }
690
+ `);
691
+ export const ACTIVE_ORDER = withFragments(
692
+ /* GraphQL */ `
693
+ query ActiveOrder {
694
+ activeOrder { ...Order }
695
+ }
696
+ `, ORDER_FRAGMENT);
697
+ export const ADD_TO_CART = withFragments(
698
+ /* GraphQL */ `
699
+ mutation AddToCart($variantId: ID!, $quantity: Int!) {
700
+ addItemToOrder(productVariantId: $variantId, quantity: $quantity) {
701
+ ... on Order { ...Order }
702
+ ... on OrderModificationError { errorCode message }
703
+ ... on OrderLimitError { errorCode message maxItems }
704
+ ... on NegativeQuantityError { errorCode message }
705
+ ... on InsufficientStockError { ...InsufficientStockError order { id } }
706
+ }
551
707
  }
552
- }
553
- `;
554
- export const ADJUST_ORDER_LINE = `
555
- mutation AdjustOrderLine($lineId: ID!, $quantity: Int!) {
556
- adjustOrderLine(orderLineId: $lineId, quantity: $quantity) {
557
- ... on Order { ${ORDER_FIELDS} }
558
- ... on OrderModificationError { errorCode message }
559
- ... on OrderLimitError { errorCode message maxItems }
560
- ... on NegativeQuantityError { errorCode message }
561
- ... on InsufficientStockError { ${INSUFFICIENT_STOCK_FIELDS} }
708
+ `, ORDER_FRAGMENT, INSUFFICIENT_STOCK_ERROR_FRAGMENT);
709
+ export const ADJUST_ORDER_LINE = withFragments(
710
+ /* GraphQL */ `
711
+ mutation AdjustOrderLine($lineId: ID!, $quantity: Int!) {
712
+ adjustOrderLine(orderLineId: $lineId, quantity: $quantity) {
713
+ ... on Order { ...Order }
714
+ ... on OrderModificationError { errorCode message }
715
+ ... on OrderLimitError { errorCode message maxItems }
716
+ ... on NegativeQuantityError { errorCode message }
717
+ ... on InsufficientStockError { ...InsufficientStockError }
718
+ }
562
719
  }
563
- }
564
- `;
565
- export const REMOVE_ORDER_LINE = `
566
- mutation RemoveOrderLine($lineId: ID!) {
567
- removeOrderLine(orderLineId: $lineId) {
568
- ... on Order { ${ORDER_FIELDS} }
569
- ... on OrderModificationError { errorCode message }
720
+ `, ORDER_FRAGMENT, INSUFFICIENT_STOCK_ERROR_FRAGMENT);
721
+ export const REMOVE_ORDER_LINE = withFragments(
722
+ /* GraphQL */ `
723
+ mutation RemoveOrderLine($lineId: ID!) {
724
+ removeOrderLine(orderLineId: $lineId) {
725
+ ... on Order { ...Order }
726
+ ... on OrderModificationError { errorCode message }
727
+ }
570
728
  }
571
- }
572
- `;
573
- export const APPLY_COUPON = `
574
- mutation ApplyCoupon($code: String!) {
575
- applyCouponCode(couponCode: $code) {
576
- ... on Order { ${ORDER_FIELDS} }
577
- ... on CouponCodeExpiredError { errorCode message couponCode }
578
- ... on CouponCodeInvalidError { errorCode message couponCode }
579
- ... on CouponCodeLimitError { errorCode message couponCode limit }
729
+ `, ORDER_FRAGMENT);
730
+ export const APPLY_COUPON = withFragments(
731
+ /* GraphQL */ `
732
+ mutation ApplyCoupon($code: String!) {
733
+ applyCouponCode(couponCode: $code) {
734
+ ... on Order { ...Order }
735
+ ... on CouponCodeExpiredError { errorCode message couponCode }
736
+ ... on CouponCodeInvalidError { errorCode message couponCode }
737
+ ... on CouponCodeLimitError { errorCode message couponCode limit }
738
+ }
580
739
  }
581
- }
582
- `;
583
- export const REMOVE_COUPON = `
584
- mutation RemoveCoupon($code: String!) {
585
- removeCouponCode(couponCode: $code) { ${ORDER_FIELDS} }
586
- }
587
- `;
588
- export const REMOVE_ALL_ORDER_LINES = `
589
- mutation RemoveAllOrderLines {
590
- removeAllOrderLines {
591
- ... on Order { ${ORDER_FIELDS} }
592
- ... on OrderModificationError { errorCode message }
740
+ `, ORDER_FRAGMENT);
741
+ export const REMOVE_COUPON = withFragments(
742
+ /* GraphQL */ `
743
+ mutation RemoveCoupon($code: String!) {
744
+ removeCouponCode(couponCode: $code) { ...Order }
745
+ }
746
+ `, ORDER_FRAGMENT);
747
+ export const REMOVE_ALL_ORDER_LINES = withFragments(
748
+ /* GraphQL */ `
749
+ mutation RemoveAllOrderLines {
750
+ removeAllOrderLines {
751
+ ... on Order { ...Order }
752
+ ... on OrderModificationError { errorCode message }
753
+ }
593
754
  }
594
- }
595
- `;
755
+ `, ORDER_FRAGMENT);
596
756
  /**
597
757
  * Bulk add (favourite-box bundles). `addItemsToOrder` returns
598
758
  * UpdateMultipleOrderItemsResult: a single resulting Order plus a per-input
599
759
  * `errorResults` list — partial success is possible, so surface both.
600
760
  */
601
- export const ADD_ITEMS_TO_CART = `
602
- mutation AddItemsToCart($inputs: [AddItemInput!]!) {
603
- addItemsToOrder(inputs: $inputs) {
604
- order { ${ORDER_FIELDS} }
605
- errorResults {
606
- ... on OrderModificationError { errorCode message }
607
- ... on OrderLimitError { errorCode message maxItems }
608
- ... on NegativeQuantityError { errorCode message }
609
- ... on InsufficientStockError { ${INSUFFICIENT_STOCK_FIELDS} }
610
- ... on OrderInterceptorError { errorCode message interceptorError }
761
+ export const ADD_ITEMS_TO_CART = withFragments(
762
+ /* GraphQL */ `
763
+ mutation AddItemsToCart($inputs: [AddItemInput!]!) {
764
+ addItemsToOrder(inputs: $inputs) {
765
+ order { ...Order }
766
+ errorResults {
767
+ ... on OrderModificationError { errorCode message }
768
+ ... on OrderLimitError { errorCode message maxItems }
769
+ ... on NegativeQuantityError { errorCode message }
770
+ ... on InsufficientStockError { ...InsufficientStockError }
771
+ ... on OrderInterceptorError { errorCode message interceptorError }
772
+ }
611
773
  }
612
774
  }
613
- }
614
- `;
775
+ `, ORDER_FRAGMENT, INSUFFICIENT_STOCK_ERROR_FRAGMENT);
615
776
  // --- Checkout Mutations ---
616
- export const SET_CUSTOMER = `
617
- mutation SetCustomer($input: CreateCustomerInput!) {
618
- setCustomerForOrder(input: $input) {
619
- ... on Order { ${ORDER_FIELDS} }
620
- ... on AlreadyLoggedInError { errorCode message }
621
- ... on EmailAddressConflictError { errorCode message }
622
- ... on GuestCheckoutError { errorCode message }
623
- ... on NoActiveOrderError { errorCode message }
777
+ export const SET_CUSTOMER = withFragments(
778
+ /* GraphQL */ `
779
+ mutation SetCustomer($input: CreateCustomerInput!) {
780
+ setCustomerForOrder(input: $input) {
781
+ ... on Order { ...Order }
782
+ ... on AlreadyLoggedInError { errorCode message }
783
+ ... on EmailAddressConflictError { errorCode message }
784
+ ... on GuestCheckoutError { errorCode message }
785
+ ... on NoActiveOrderError { errorCode message }
786
+ }
624
787
  }
625
- }
626
- `;
627
- export const SET_SHIPPING_ADDRESS = `
628
- mutation SetShippingAddress($input: CreateAddressInput!) {
629
- setOrderShippingAddress(input: $input) {
630
- ... on Order { ${ORDER_FIELDS} }
631
- ... on NoActiveOrderError { errorCode message }
788
+ `, ORDER_FRAGMENT);
789
+ export const SET_SHIPPING_ADDRESS = withFragments(
790
+ /* GraphQL */ `
791
+ mutation SetShippingAddress($input: CreateAddressInput!) {
792
+ setOrderShippingAddress(input: $input) {
793
+ ... on Order { ...Order }
794
+ ... on NoActiveOrderError { errorCode message }
795
+ }
632
796
  }
633
- }
634
- `;
635
- export const SET_BILLING_ADDRESS = `
636
- mutation SetBillingAddress($input: CreateAddressInput!) {
637
- setOrderBillingAddress(input: $input) {
638
- ... on Order { ${ORDER_FIELDS} }
639
- ... on NoActiveOrderError { errorCode message }
797
+ `, ORDER_FRAGMENT);
798
+ export const SET_BILLING_ADDRESS = withFragments(
799
+ /* GraphQL */ `
800
+ mutation SetBillingAddress($input: CreateAddressInput!) {
801
+ setOrderBillingAddress(input: $input) {
802
+ ... on Order { ...Order }
803
+ ... on NoActiveOrderError { errorCode message }
804
+ }
640
805
  }
641
- }
642
- `;
643
- export const ELIGIBLE_SHIPPING_METHODS = `
806
+ `, ORDER_FRAGMENT);
807
+ export const ELIGIBLE_SHIPPING_METHODS = /* GraphQL */ `
644
808
  query ShippingMethods {
645
809
  eligibleShippingMethods {
646
810
  id name description price priceWithTax metadata isPreferred isDeliveryTermsEligible
647
811
  }
648
812
  }
649
813
  `;
650
- export const MY_DELIVERY_TERMS = `
814
+ /** Every platform method and every app rate the active order can ship with (`shipping.rates`). */
815
+ export const ELIGIBLE_SHIPPING_RATES = /* GraphQL */ `
816
+ query ShippingRates {
817
+ eligibleShippingRates {
818
+ shippingMethodId code rateCode name description price priceWithTax source appSlug selected
819
+ isPreferred isDeliveryTermsEligible
820
+ }
821
+ }
822
+ `;
823
+ export const SET_SHIPPING_RATE = withFragments(
824
+ /* GraphQL */ `
825
+ mutation SetShippingRate($shippingMethodId: ID!, $rateCode: String) {
826
+ setOrderShippingRate(shippingMethodId: $shippingMethodId, rateCode: $rateCode) {
827
+ ... on Order { ...Order }
828
+ ... on OrderModificationError { errorCode message }
829
+ ... on IneligibleShippingMethodError { errorCode message }
830
+ ... on NoActiveOrderError { errorCode message }
831
+ }
832
+ }
833
+ `, ORDER_FRAGMENT);
834
+ export const MY_DELIVERY_TERMS = /* GraphQL */ `
651
835
  query MyDeliveryTerms {
652
836
  myDeliveryTerms {
653
837
  customerId source managedExternally status shippingMethodStatus policyStatus summary
@@ -659,44 +843,204 @@ export const MY_DELIVERY_TERMS = `
659
843
  }
660
844
  }
661
845
  `;
662
- export const SET_SHIPPING_METHOD = `
663
- mutation SetShippingMethod($ids: [ID!]!) {
664
- selectOrderDeliveryMethod(shippingMethodIds: $ids) {
665
- ... on Order { ${ORDER_FIELDS} }
666
- ... on OrderModificationError { errorCode message }
667
- ... on IneligibleShippingMethodError { errorCode message }
668
- ... on NoActiveOrderError { errorCode message }
846
+ export const SET_SHIPPING_METHOD = withFragments(
847
+ /* GraphQL */ `
848
+ mutation SetShippingMethod($ids: [ID!]!) {
849
+ selectOrderDeliveryMethod(shippingMethodIds: $ids) {
850
+ ... on Order { ...Order }
851
+ ... on OrderModificationError { errorCode message }
852
+ ... on IneligibleShippingMethodError { errorCode message }
853
+ ... on NoActiveOrderError { errorCode message }
854
+ }
669
855
  }
670
- }
671
- `;
672
- export const APPLY_PREFERRED_SHIPPING_METHOD = `
673
- mutation ApplyPreferredShippingMethod {
674
- applyPreferredDeliveryMethod {
675
- ... on Order { ${ORDER_FIELDS} }
676
- ... on OrderModificationError { errorCode message }
677
- ... on IneligibleShippingMethodError { errorCode message }
678
- ... on NoActiveOrderError { errorCode message }
856
+ `, ORDER_FRAGMENT);
857
+ export const APPLY_PREFERRED_SHIPPING_METHOD = withFragments(
858
+ /* GraphQL */ `
859
+ mutation ApplyPreferredShippingMethod {
860
+ applyPreferredDeliveryMethod {
861
+ ... on Order { ...Order }
862
+ ... on OrderModificationError { errorCode message }
863
+ ... on IneligibleShippingMethodError { errorCode message }
864
+ ... on NoActiveOrderError { errorCode message }
865
+ }
866
+ }
867
+ `, ORDER_FRAGMENT);
868
+ /**
869
+ * Store pickup (C1/33): the store's shops that offer pickup, each with `available` for the active
870
+ * order (a boolean, never a quantity). Its own document, never in ORDER_FRAGMENT: an engine before
871
+ * store pickup refuses only this read.
872
+ */
873
+ export const STORE_PICKUP_LOCATIONS = fragment(/* GraphQL */ `
874
+ fragment StorePickupLocation on StorePickupLocation {
875
+ id name phone openingHours instructions available
876
+ address { streetLine1 streetLine2 city province postalCode countryCode }
877
+ }
878
+ `);
879
+ export const STORE_PICKUP_LOCATIONS_QUERY = withFragments(
880
+ /* GraphQL */ `
881
+ query StorePickupLocations {
882
+ storePickupLocations { ...StorePickupLocation }
883
+ }
884
+ `, STORE_PICKUP_LOCATIONS);
885
+ /** Name the shop the active order is collected at (null clears); sets the shipping address. */
886
+ export const SET_ACTIVE_ORDER_STORE_PICKUP_LOCATION = withFragments(
887
+ /* GraphQL */ `
888
+ mutation SetActiveOrderStorePickupLocation($stockLocationId: ID) {
889
+ setActiveOrderStorePickupLocation(stockLocationId: $stockLocationId) { ...Order }
890
+ }
891
+ `, ORDER_FRAGMENT);
892
+ /** The active order's store pickup: the chosen shop, then the pickup's state once placed. */
893
+ export const ACTIVE_ORDER_STORE_PICKUP = withFragments(
894
+ /* GraphQL */ `
895
+ query ActiveOrderStorePickup {
896
+ activeOrder {
897
+ id
898
+ storePickup {
899
+ status readyAt holdUntil collectedAt
900
+ location { ...StorePickupLocation }
901
+ }
902
+ }
679
903
  }
904
+ `, STORE_PICKUP_LOCATIONS);
905
+ /** The active order's eligible methods with their codes: how `chooseStorePickup` finds its method. */
906
+ export const ELIGIBLE_SHIPPING_METHOD_CODES = /* GraphQL */ `
907
+ query EligibleShippingMethodCodes {
908
+ eligibleShippingMethods { id code }
680
909
  }
681
910
  `;
682
- export const ELIGIBLE_PAYMENT_METHODS = `
911
+ export const ELIGIBLE_PAYMENT_METHODS = /* GraphQL */ `
683
912
  query PaymentMethods {
684
913
  eligiblePaymentMethods {
685
914
  id name code description isEligible eligibilityMessage
686
915
  }
687
916
  }
688
917
  `;
689
- export const TRANSITION_TO_ARRANGING_PAYMENT = `
690
- mutation TransitionToArrangingPayment {
691
- transitionOrderToState(state: "ArrangingPayment") {
692
- ... on Order { ${ORDER_FIELDS} }
693
- ... on OrderStateTransitionError {
694
- errorCode message transitionError
695
- placement { ${PLACEMENT_FIELDS} }
918
+ export const TRANSITION_TO_ARRANGING_PAYMENT = withFragments(
919
+ /* GraphQL */ `
920
+ mutation TransitionToArrangingPayment {
921
+ transitionOrderToState(state: "ArrangingPayment") {
922
+ ... on Order { ...Order }
923
+ ... on OrderStateTransitionError {
924
+ errorCode message transitionError
925
+ placement { ...PlacementRejection }
926
+ }
696
927
  }
697
928
  }
929
+ `, ORDER_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
930
+ /**
931
+ * `TRANSITION_TO_ARRANGING_PAYMENT` with the target state as a variable. The
932
+ * engine's order process and its placement guards decide which targets a
933
+ * shopper may reach; the document only carries the request.
934
+ */
935
+ export const TRANSITION_ORDER = withFragments(
936
+ /* GraphQL */ `
937
+ mutation TransitionOrder($state: String!) {
938
+ transitionOrderToState(state: $state) {
939
+ ... on Order { ...Order }
940
+ ... on OrderStateTransitionError {
941
+ errorCode message transitionError
942
+ placement { ...PlacementRejection }
943
+ }
944
+ }
945
+ }
946
+ `, ORDER_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
947
+ export const NEXT_ORDER_STATES = /* GraphQL */ `
948
+ query NextOrderStates {
949
+ nextOrderStates
698
950
  }
699
951
  `;
952
+ /**
953
+ * Every payment method enabled on the channel, whatever the active order.
954
+ * `customFields` is NOT selected: it is a raw JSON passthrough of the entity's
955
+ * custom fields, which are all private on this platform.
956
+ */
957
+ const PUBLIC_PAYMENT_METHOD_FRAGMENT = fragment(/* GraphQL */ `
958
+ fragment PublicPaymentMethod on PublicPaymentMethod {
959
+ id code name description
960
+ }
961
+ `);
962
+ export const ACTIVE_PAYMENT_METHODS = withFragments(
963
+ /* GraphQL */ `
964
+ query ActivePaymentMethods {
965
+ activePaymentMethods { ...PublicPaymentMethod }
966
+ }
967
+ `, PUBLIC_PAYMENT_METHOD_FRAGMENT);
968
+ const PUBLIC_SHIPPING_METHOD_FRAGMENT = fragment(/* GraphQL */ `
969
+ fragment PublicShippingMethod on PublicShippingMethod {
970
+ id code name description
971
+ }
972
+ `);
973
+ /** Every shipping method offered on the channel's storefront, whatever the active order. */
974
+ export const ACTIVE_SHIPPING_METHODS = withFragments(
975
+ /* GraphQL */ `
976
+ query ActiveShippingMethods {
977
+ activeShippingMethods { ...PublicShippingMethod }
978
+ }
979
+ `, PUBLIC_SHIPPING_METHOD_FRAGMENT);
980
+ /**
981
+ * The order custom fields the Shop API lets a shopper write — exactly the
982
+ * members of `UpdateOrderCustomFieldsInput` (public, not read-only) — selected
983
+ * back on `setOrderCustomFields` so the caller sees what the engine stored.
984
+ *
985
+ * Selected on that ONE document: the shared `ORDER_FRAGMENT` stays free of
986
+ * custom fields, so an engine that predates one of these fields fails only the
987
+ * call that writes them, never every cart read.
988
+ */
989
+ const ORDER_WRITABLE_CUSTOM_FIELDS_FRAGMENT = fragment(/* GraphQL */ `
990
+ fragment OrderWritableCustomFields on OrderCustomFields {
991
+ isGift giftNote hidePricesOnPackingSlip
992
+ poNumber requestedDeliveryDate orderNotes
993
+ snTid snUtmSource snUtmMedium snUtmCampaign snFlowId snEnrollmentId snStepId
994
+ }
995
+ `);
996
+ export const SET_ORDER_CUSTOM_FIELDS = withFragments(
997
+ /* GraphQL */ `
998
+ mutation SetOrderCustomFields($input: UpdateOrderInput!) {
999
+ setOrderCustomFields(input: $input) {
1000
+ ... on Order {
1001
+ ...Order
1002
+ customFields { ...OrderWritableCustomFields }
1003
+ }
1004
+ ... on NoActiveOrderError { errorCode message }
1005
+ }
1006
+ }
1007
+ `, ORDER_FRAGMENT, ORDER_WRITABLE_CUSTOM_FIELDS_FRAGMENT);
1008
+ export const UNSET_SHIPPING_ADDRESS = withFragments(
1009
+ /* GraphQL */ `
1010
+ mutation UnsetShippingAddress {
1011
+ unsetOrderShippingAddress {
1012
+ ... on Order { ...Order }
1013
+ ... on NoActiveOrderError { errorCode message }
1014
+ }
1015
+ }
1016
+ `, ORDER_FRAGMENT);
1017
+ export const UNSET_BILLING_ADDRESS = withFragments(
1018
+ /* GraphQL */ `
1019
+ mutation UnsetBillingAddress {
1020
+ unsetOrderBillingAddress {
1021
+ ... on Order { ...Order }
1022
+ ... on NoActiveOrderError { errorCode message }
1023
+ }
1024
+ }
1025
+ `, ORDER_FRAGMENT);
1026
+ /**
1027
+ * `setCurrencyCodeForOrder` answers `UpdateOrderItemsResult`, so every member of
1028
+ * that union is selected: an unselected member comes back as `{}`, which
1029
+ * carries no `errorCode` and would read as success.
1030
+ */
1031
+ export const SET_ORDER_CURRENCY = withFragments(
1032
+ /* GraphQL */ `
1033
+ mutation SetOrderCurrency($currencyCode: CurrencyCode!) {
1034
+ setCurrencyCodeForOrder(currencyCode: $currencyCode) {
1035
+ ... on Order { ...Order }
1036
+ ... on OrderModificationError { errorCode message }
1037
+ ... on OrderLimitError { errorCode message maxItems }
1038
+ ... on NegativeQuantityError { errorCode message }
1039
+ ... on InsufficientStockError { ...InsufficientStockError }
1040
+ ... on OrderInterceptorError { errorCode message interceptorError }
1041
+ }
1042
+ }
1043
+ `, ORDER_FRAGMENT, INSUFFICIENT_STOCK_ERROR_FRAGMENT);
700
1044
  /**
701
1045
  * Record how the buyer intends to pay AND re-price the order in one round trip.
702
1046
  *
@@ -708,85 +1052,91 @@ export const TRANSITION_TO_ARRANGING_PAYMENT = `
708
1052
  * the pay-now discount.
709
1053
  *
710
1054
  * `customFields { paymentIntent }` is selected HERE and nowhere else, and that
711
- * is deliberate. Putting it in the shared `ORDER_FIELDS` would make every order
1055
+ * is deliberate. Putting it in the shared `ORDER_FRAGMENT` would make every order
712
1056
  * query and cart mutation in this client fail GraphQL validation against an
713
1057
  * engine that predates the field — one missing feature would take the whole cart
714
1058
  * down. Confined to this document, only the call that needs the field is
715
1059
  * coupled to an engine that has it.
716
1060
  */
717
- export const SET_PAYMENT_INTENT = `
718
- mutation SetOrderPaymentIntent($intent: OrderPaymentIntent!) {
719
- setOrderPaymentIntent(intent: $intent) {
720
- ... on Order {
721
- ${ORDER_FIELDS}
722
- customFields { paymentIntent }
1061
+ export const SET_PAYMENT_INTENT = withFragments(
1062
+ /* GraphQL */ `
1063
+ mutation SetOrderPaymentIntent($intent: OrderPaymentIntent!) {
1064
+ setOrderPaymentIntent(intent: $intent) {
1065
+ ... on Order {
1066
+ ...Order
1067
+ customFields { paymentIntent }
1068
+ }
1069
+ ... on NoActiveOrderError { errorCode message }
723
1070
  }
724
- ... on NoActiveOrderError { errorCode message }
725
1071
  }
726
- }
727
- `;
728
- export const ADD_PAYMENT = `
729
- mutation AddPayment($input: PaymentInput!) {
730
- addPaymentToOrder(input: $input) {
731
- ... on Order {
732
- ${ORDER_FIELDS}
733
- ${ORDER_PAYMENT_TERMS_FRAGMENT}
734
- ${ORDER_DELIVERY_TERMS_FRAGMENT}
735
- }
736
- ... on OrderPaymentStateError { errorCode message }
737
- ... on IneligiblePaymentMethodError { errorCode message }
738
- ... on PaymentFailedError {
739
- errorCode message paymentErrorMessage
740
- placement { ${PLACEMENT_FIELDS} }
741
- }
742
- ... on PaymentDeclinedError {
743
- errorCode message paymentErrorMessage
744
- placement { ${PLACEMENT_FIELDS} }
745
- }
746
- ... on OrderStateTransitionError {
747
- errorCode message transitionError
748
- placement { ${PLACEMENT_FIELDS} }
1072
+ `, ORDER_FRAGMENT);
1073
+ export const ADD_PAYMENT = withFragments(
1074
+ /* GraphQL */ `
1075
+ mutation AddPayment($input: PaymentInput!) {
1076
+ addPaymentToOrder(input: $input) {
1077
+ ... on Order {
1078
+ ...Order
1079
+ ...OrderPaymentTerms
1080
+ ...OrderDeliveryTerms
1081
+ }
1082
+ ... on OrderPaymentStateError { errorCode message }
1083
+ ... on IneligiblePaymentMethodError { errorCode message }
1084
+ ... on PaymentFailedError {
1085
+ errorCode message paymentErrorMessage
1086
+ placement { ...PlacementRejection }
1087
+ }
1088
+ ... on PaymentDeclinedError {
1089
+ errorCode message paymentErrorMessage
1090
+ placement { ...PlacementRejection }
1091
+ }
1092
+ ... on OrderStateTransitionError {
1093
+ errorCode message transitionError
1094
+ placement { ...PlacementRejection }
1095
+ }
1096
+ ... on NoActiveOrderError { errorCode message }
749
1097
  }
750
- ... on NoActiveOrderError { errorCode message }
751
1098
  }
752
- }
753
- `;
1099
+ `, ORDER_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
754
1100
  // --- Carrier-agnostic pickup locations (vendure-plugin-myparcel Phase 6) ---
755
- const PICKUP_LOCATION_FIELDS = `
756
- provider
757
- carrier
758
- locationCode
759
- name
760
- address {
761
- streetLine1
762
- number
763
- postalCode
764
- city
765
- countryCode
766
- region
767
- }
768
- openingHours {
769
- weekday
770
- open
771
- close
772
- }
773
- details
774
- `;
775
- export const PICKUP_LOCATIONS = `
776
- query PickupLocations($input: PickupLocationSearchInput!) {
777
- pickupLocations(input: $input) {
778
- ${PICKUP_LOCATION_FIELDS}
1101
+ const PICKUP_LOCATION_FRAGMENT = fragment(/* GraphQL */ `
1102
+ fragment PickupLocation on PickupLocation {
1103
+ provider
1104
+ carrier
1105
+ locationCode
1106
+ name
1107
+ address {
1108
+ streetLine1
1109
+ number
1110
+ postalCode
1111
+ city
1112
+ countryCode
1113
+ region
1114
+ }
1115
+ openingHours {
1116
+ weekday
1117
+ open
1118
+ close
1119
+ }
1120
+ details
1121
+ }
1122
+ `);
1123
+ export const PICKUP_LOCATIONS = withFragments(
1124
+ /* GraphQL */ `
1125
+ query PickupLocations($input: PickupLocationSearchInput!) {
1126
+ pickupLocations(input: $input) {
1127
+ ...PickupLocation
1128
+ }
779
1129
  }
780
- }
781
- `;
782
- export const ACTIVE_ORDER_PICKUP_LOCATION = `
783
- query ActiveOrderPickupLocation {
784
- activeOrderPickupLocation {
785
- ${PICKUP_LOCATION_FIELDS}
1130
+ `, PICKUP_LOCATION_FRAGMENT);
1131
+ export const ACTIVE_ORDER_PICKUP_LOCATION = withFragments(
1132
+ /* GraphQL */ `
1133
+ query ActiveOrderPickupLocation {
1134
+ activeOrderPickupLocation {
1135
+ ...PickupLocation
1136
+ }
786
1137
  }
787
- }
788
- `;
789
- export const SET_ACTIVE_ORDER_PICKUP_LOCATION = `
1138
+ `, PICKUP_LOCATION_FRAGMENT);
1139
+ export const SET_ACTIVE_ORDER_PICKUP_LOCATION = /* GraphQL */ `
790
1140
  mutation SetActiveOrderPickupLocation($location: StoredPickupLocationInput!) {
791
1141
  setActiveOrderPickupLocation(location: $location) {
792
1142
  __typename
@@ -801,13 +1151,13 @@ export const SET_ACTIVE_ORDER_PICKUP_LOCATION = `
801
1151
  }
802
1152
  `;
803
1153
  // --- Stripe (@vendure-community/stripe-plugin) ---
804
- export const CREATE_STRIPE_PAYMENT_INTENT = `
1154
+ export const CREATE_STRIPE_PAYMENT_INTENT = /* GraphQL */ `
805
1155
  mutation CreateStripePaymentIntent {
806
1156
  createStripePaymentIntent
807
1157
  }
808
1158
  `;
809
1159
  // --- Mollie (@vendure-community/mollie-plugin) ---
810
- export const MOLLIE_PAYMENT_METHODS = `
1160
+ export const MOLLIE_PAYMENT_METHODS = /* GraphQL */ `
811
1161
  query MolliePaymentMethods($input: MolliePaymentMethodsInput!) {
812
1162
  molliePaymentMethods(input: $input) {
813
1163
  id
@@ -820,7 +1170,7 @@ export const MOLLIE_PAYMENT_METHODS = `
820
1170
  }
821
1171
  }
822
1172
  `;
823
- export const ORDERED_MOLLIE_PAYMENT_METHODS = `
1173
+ export const ORDERED_MOLLIE_PAYMENT_METHODS = /* GraphQL */ `
824
1174
  query OrderedMolliePaymentMethods($paymentMethodCode: String!) {
825
1175
  orderedMolliePaymentMethods(paymentMethodCode: $paymentMethodCode) {
826
1176
  id
@@ -831,7 +1181,7 @@ export const ORDERED_MOLLIE_PAYMENT_METHODS = `
831
1181
  }
832
1182
  }
833
1183
  `;
834
- export const CREATE_MOLLIE_PAYMENT_INTENT = `
1184
+ export const CREATE_MOLLIE_PAYMENT_INTENT = /* GraphQL */ `
835
1185
  mutation CreateMolliePaymentIntent($input: MolliePaymentIntentInput!) {
836
1186
  createMolliePaymentIntent(input: $input) {
837
1187
  ... on MolliePaymentIntent { url }
@@ -839,7 +1189,7 @@ export const CREATE_MOLLIE_PAYMENT_INTENT = `
839
1189
  }
840
1190
  }
841
1191
  `;
842
- export const SYNC_MOLLIE_PAYMENT_STATUS = `
1192
+ export const SYNC_MOLLIE_PAYMENT_STATUS = /* GraphQL */ `
843
1193
  mutation SyncMolliePaymentStatus($orderCode: String!) {
844
1194
  syncMolliePaymentStatus(orderCode: $orderCode) {
845
1195
  id
@@ -848,8 +1198,101 @@ export const SYNC_MOLLIE_PAYMENT_STATUS = `
848
1198
  }
849
1199
  }
850
1200
  `;
1201
+ // --- Parked (held) orders ---
1202
+ /**
1203
+ * The money on a held order, as the storefront sees it: what it bills, what is
1204
+ * covered, what is left, and the currency all three are in. Narrower than the
1205
+ * merchant's own view of the same order — settled-vs-authorized and per-payment
1206
+ * refunds are bookkeeping a shopper is not shown.
1207
+ */
1208
+ const PARKED_ORDER_FRAGMENT = fragment(/* GraphQL */ `
1209
+ fragment ParkedOrder on ParkedOrder {
1210
+ id
1211
+ code
1212
+ state
1213
+ position { total covered outstanding currencyCode }
1214
+ reason
1215
+ }
1216
+ `);
1217
+ export const PARKED_ORDERS_QUERY = withFragments(
1218
+ /* GraphQL */ `
1219
+ query ParkedOrders {
1220
+ parkedOrders {
1221
+ ...ParkedOrder
1222
+ }
1223
+ }
1224
+ `, PARKED_ORDER_FRAGMENT);
1225
+ export const PAY_PARKED_ORDER_MUTATION = /* GraphQL */ `
1226
+ mutation PayParkedOrder(
1227
+ $orderCode: String!
1228
+ $input: PayParkedOrderInput!
1229
+ $idempotencyKey: String
1230
+ ) {
1231
+ payParkedOrder(orderCode: $orderCode, input: $input, idempotencyKey: $idempotencyKey) {
1232
+ order { id code state }
1233
+ payment { id state amount method metadata }
1234
+ position { total covered outstanding currencyCode }
1235
+ settled
1236
+ }
1237
+ }
1238
+ `;
1239
+ export const CREATE_PARKED_ORDER_PAYMENT_INTENT_MUTATION = /* GraphQL */ `
1240
+ mutation CreateParkedOrderPaymentIntent(
1241
+ $orderCode: String!
1242
+ $input: ParkedOrderPaymentIntentInput!
1243
+ $idempotencyKey: String
1244
+ ) {
1245
+ createParkedOrderPaymentIntent(
1246
+ orderCode: $orderCode
1247
+ input: $input
1248
+ idempotencyKey: $idempotencyKey
1249
+ ) {
1250
+ provider
1251
+ url
1252
+ clientSecret
1253
+ amount
1254
+ currencyCode
1255
+ }
1256
+ }
1257
+ `;
1258
+ /**
1259
+ * A deposit paid in checkout, which parks the active order (W8-13).
1260
+ *
1261
+ * `order` selects exactly what `ADD_PAYMENT` selects for its `Order` member, so
1262
+ * `addPayment(input, { amount })` — which routes here — resolves to the same
1263
+ * type whether it paid in full or paid a deposit. No `idempotencyKey` argument:
1264
+ * like `addPaymentToOrder`, this mutation is keyed by the `Idempotency-Key`
1265
+ * header (the W8-12 contract), unlike the parked-order calls above.
1266
+ */
1267
+ export const PAY_DEPOSIT_MUTATION = withFragments(
1268
+ /* GraphQL */ `
1269
+ mutation PayDeposit($input: PayDepositInput!) {
1270
+ payDeposit(input: $input) {
1271
+ order {
1272
+ ...Order
1273
+ ...OrderPaymentTerms
1274
+ ...OrderDeliveryTerms
1275
+ }
1276
+ payment { id state amount method metadata }
1277
+ position { total covered outstanding currencyCode }
1278
+ settled
1279
+ }
1280
+ }
1281
+ `, ORDER_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT);
1282
+ /** A card (Mollie) deposit in checkout; keyed by the header, as `PAY_DEPOSIT_MUTATION`. */
1283
+ export const CREATE_DEPOSIT_PAYMENT_INTENT_MUTATION = /* GraphQL */ `
1284
+ mutation CreateDepositPaymentIntent($input: DepositPaymentIntentInput!) {
1285
+ createDepositPaymentIntent(input: $input) {
1286
+ provider
1287
+ url
1288
+ clientSecret
1289
+ amount
1290
+ currencyCode
1291
+ }
1292
+ }
1293
+ `;
851
1294
  // --- Customer Queries/Mutations ---
852
- export const LOGIN = `
1295
+ export const LOGIN = /* GraphQL */ `
853
1296
  mutation Login($email: String!, $password: String!) {
854
1297
  login(username: $email, password: $password) {
855
1298
  ... on CurrentUser { id identifier }
@@ -859,7 +1302,29 @@ export const LOGIN = `
859
1302
  }
860
1303
  }
861
1304
  `;
862
- export const REGISTER = `
1305
+ const CURRENT_USER_FRAGMENT = fragment(/* GraphQL */ `
1306
+ fragment CurrentUser on CurrentUser {
1307
+ id identifier
1308
+ }
1309
+ `);
1310
+ /**
1311
+ * Sign in through a named authentication strategy (`native` is the only one the
1312
+ * engine registers today). Every `AuthenticationResult` member is selected, and
1313
+ * `authenticationError` with it: the engine's native strategy reports an
1314
+ * imported account with no password (`PASSWORD_RESET_REQUIRED`) or an
1315
+ * unverified one (`ACCOUNT_NOT_VERIFIED`) there, not as an error type.
1316
+ */
1317
+ export const AUTHENTICATE = withFragments(
1318
+ /* GraphQL */ `
1319
+ mutation Authenticate($input: AuthenticationInput!, $rememberMe: Boolean) {
1320
+ authenticate(input: $input, rememberMe: $rememberMe) {
1321
+ ... on CurrentUser { ...CurrentUser }
1322
+ ... on InvalidCredentialsError { errorCode message authenticationError }
1323
+ ... on NotVerifiedError { errorCode message }
1324
+ }
1325
+ }
1326
+ `, CURRENT_USER_FRAGMENT);
1327
+ export const REGISTER = /* GraphQL */ `
863
1328
  mutation Register($input: RegisterCustomerInput!) {
864
1329
  registerCustomerAccount(input: $input) {
865
1330
  ... on Success { success }
@@ -869,58 +1334,62 @@ export const REGISTER = `
869
1334
  }
870
1335
  }
871
1336
  `;
872
- export const GET_CURRENT_CUSTOMER = `
873
- query Me {
874
- activeCustomer {
875
- id firstName lastName emailAddress phoneNumber
876
- groups { id name }
877
- isB2B
878
- addresses {
879
- id fullName streetLine1 streetLine2 city province postalCode
880
- country { code name }
881
- defaultShippingAddress defaultBillingAddress
882
- }
883
- orders(options: { take: 10, sort: { createdAt: DESC } }) {
884
- items {
885
- ${ORDER_SUMMARY_FIELDS}
1337
+ export const GET_CURRENT_CUSTOMER = withFragments(
1338
+ /* GraphQL */ `
1339
+ query Me {
1340
+ activeCustomer {
1341
+ id firstName lastName emailAddress phoneNumber
1342
+ groups { id name }
1343
+ isB2B
1344
+ hasPassword
1345
+ addresses {
1346
+ id fullName streetLine1 streetLine2 city province postalCode
1347
+ country { code name }
1348
+ defaultShippingAddress defaultBillingAddress
1349
+ }
1350
+ orders(options: { take: 10, sort: { createdAt: DESC } }) {
1351
+ items {
1352
+ ...OrderSummary
1353
+ }
1354
+ totalItems
886
1355
  }
887
- totalItems
888
1356
  }
889
1357
  }
890
- }
891
- `;
892
- export const ACTIVE_CUSTOMER_PRICE_LISTS = `
1358
+ `, ORDER_SUMMARY_FRAGMENT);
1359
+ export const ACTIVE_CUSTOMER_PRICE_LISTS = /* GraphQL */ `
893
1360
  query ActiveCustomerPriceLists {
894
1361
  activeCustomerPriceLists { id name isContract }
895
1362
  }
896
1363
  `;
897
- export const GET_CUSTOMER_ORDERS = `
898
- query CustomerOrders($options: OrderListOptions) {
899
- activeCustomer {
900
- orders(options: $options) {
901
- items {
902
- ${ORDER_SUMMARY_FIELDS}
903
- lines { id backorderedQuantity }
1364
+ export const GET_CUSTOMER_ORDERS = withFragments(
1365
+ /* GraphQL */ `
1366
+ query CustomerOrders($options: OrderListOptions) {
1367
+ activeCustomer {
1368
+ orders(options: $options) {
1369
+ items {
1370
+ ...OrderSummary
1371
+ lines { id backorderedQuantity }
1372
+ ...OrderFulfillmentParcels
1373
+ }
1374
+ totalItems
904
1375
  }
905
- totalItems
906
1376
  }
907
1377
  }
908
- }
909
- `;
910
- export const LOGOUT = `
1378
+ `, ORDER_FULFILLMENT_PARCELS_FRAGMENT, ORDER_SUMMARY_FRAGMENT);
1379
+ export const LOGOUT = /* GraphQL */ `
911
1380
  mutation Logout {
912
1381
  logout { success }
913
1382
  }
914
1383
  `;
915
1384
  // --- Customer Account Management ---
916
- export const UPDATE_CUSTOMER = `
1385
+ export const UPDATE_CUSTOMER = /* GraphQL */ `
917
1386
  mutation UpdateCustomer($input: UpdateCustomerInput!) {
918
1387
  updateCustomer(input: $input) {
919
1388
  id firstName lastName emailAddress phoneNumber
920
1389
  }
921
1390
  }
922
1391
  `;
923
- export const UPDATE_PASSWORD = `
1392
+ export const UPDATE_PASSWORD = /* GraphQL */ `
924
1393
  mutation UpdatePassword($currentPassword: String!, $newPassword: String!) {
925
1394
  updateCustomerPassword(currentPassword: $currentPassword, newPassword: $newPassword) {
926
1395
  ... on Success { success }
@@ -930,7 +1399,24 @@ export const UPDATE_PASSWORD = `
930
1399
  }
931
1400
  }
932
1401
  `;
933
- export const REQUEST_PASSWORD_RESET = `
1402
+ /**
1403
+ * The signed-in customer's FIRST password, for an account that signed in by
1404
+ * email link or code and has none (`updatePassword` needs the current one).
1405
+ * Every member is selected: an unselected error member arrives as `{}` and the
1406
+ * wrapper would read a refused password as set.
1407
+ */
1408
+ export const SET_CUSTOMER_PASSWORD = /* GraphQL */ `
1409
+ mutation SetCustomerPassword($newPassword: String!) {
1410
+ setCustomerPassword(newPassword: $newPassword) {
1411
+ ... on Success { success }
1412
+ ... on PasswordValidationError { errorCode message validationErrorMessage }
1413
+ ... on PasswordAlreadySetError { errorCode message }
1414
+ ... on NativeAuthStrategyError { errorCode message }
1415
+ ... on SetPasswordRequiresEmailSignInError { errorCode message }
1416
+ }
1417
+ }
1418
+ `;
1419
+ export const REQUEST_PASSWORD_RESET = /* GraphQL */ `
934
1420
  mutation RequestPasswordReset($emailAddress: String!) {
935
1421
  requestPasswordReset(emailAddress: $emailAddress) {
936
1422
  ... on Success { success }
@@ -938,7 +1424,7 @@ export const REQUEST_PASSWORD_RESET = `
938
1424
  }
939
1425
  }
940
1426
  `;
941
- export const RESET_PASSWORD = `
1427
+ export const RESET_PASSWORD = /* GraphQL */ `
942
1428
  mutation ResetPassword($token: String!, $password: String!) {
943
1429
  resetPassword(token: $token, password: $password) {
944
1430
  ... on CurrentUser { id identifier }
@@ -950,15 +1436,18 @@ export const RESET_PASSWORD = `
950
1436
  }
951
1437
  }
952
1438
  `;
953
- export const REQUEST_MAGIC_LINK = `
954
- mutation RequestMagicLink($emailAddress: String!) {
955
- requestMagicLink(emailAddress: $emailAddress) {
1439
+ // `MagicLinkRateLimitedError` must stay selected: an unselected union member
1440
+ // comes back as `{}`, which carries no `errorCode` and reads as success.
1441
+ export const REQUEST_MAGIC_LINK = /* GraphQL */ `
1442
+ mutation RequestMagicLink($emailAddress: String!, $portal: MagicLinkPortal) {
1443
+ requestMagicLink(emailAddress: $emailAddress, portal: $portal) {
956
1444
  ... on Success { success }
957
1445
  ... on NativeAuthStrategyError { errorCode message }
1446
+ ... on MagicLinkRateLimitedError { errorCode message retryAfterSeconds }
958
1447
  }
959
1448
  }
960
1449
  `;
961
- export const LOGIN_WITH_MAGIC_LINK = `
1450
+ export const LOGIN_WITH_MAGIC_LINK = /* GraphQL */ `
962
1451
  mutation LoginWithMagicLink($token: String!) {
963
1452
  loginWithMagicLink(token: $token) {
964
1453
  ... on CurrentUser { id identifier }
@@ -970,7 +1459,7 @@ export const LOGIN_WITH_MAGIC_LINK = `
970
1459
  }
971
1460
  }
972
1461
  `;
973
- export const LOGIN_WITH_MAGIC_CODE = `
1462
+ export const LOGIN_WITH_MAGIC_CODE = /* GraphQL */ `
974
1463
  mutation LoginWithMagicCode($emailAddress: String!, $code: String!) {
975
1464
  loginWithMagicCode(emailAddress: $emailAddress, code: $code) {
976
1465
  ... on CurrentUser { id identifier }
@@ -982,7 +1471,7 @@ export const LOGIN_WITH_MAGIC_CODE = `
982
1471
  }
983
1472
  }
984
1473
  `;
985
- export const REQUEST_EMAIL_UPDATE = `
1474
+ export const REQUEST_EMAIL_UPDATE = /* GraphQL */ `
986
1475
  mutation RequestEmailUpdate($password: String!, $newEmailAddress: String!) {
987
1476
  requestUpdateCustomerEmailAddress(password: $password, newEmailAddress: $newEmailAddress) {
988
1477
  ... on Success { success }
@@ -994,7 +1483,7 @@ export const REQUEST_EMAIL_UPDATE = `
994
1483
  }
995
1484
  }
996
1485
  `;
997
- export const UPDATE_EMAIL = `
1486
+ export const UPDATE_EMAIL = /* GraphQL */ `
998
1487
  mutation UpdateEmail($token: String!) {
999
1488
  updateCustomerEmailAddress(token: $token) {
1000
1489
  ... on Success { success }
@@ -1004,7 +1493,7 @@ export const UPDATE_EMAIL = `
1004
1493
  }
1005
1494
  }
1006
1495
  `;
1007
- export const VERIFY_ACCOUNT = `
1496
+ export const VERIFY_ACCOUNT = /* GraphQL */ `
1008
1497
  mutation VerifyAccount($token: String!, $password: String) {
1009
1498
  verifyCustomerAccount(token: $token, password: $password) {
1010
1499
  ... on CurrentUser { id identifier }
@@ -1017,7 +1506,7 @@ export const VERIFY_ACCOUNT = `
1017
1506
  }
1018
1507
  }
1019
1508
  `;
1020
- export const REFRESH_VERIFICATION = `
1509
+ export const REFRESH_VERIFICATION = /* GraphQL */ `
1021
1510
  mutation RefreshVerification($emailAddress: String!) {
1022
1511
  refreshCustomerVerification(emailAddress: $emailAddress) {
1023
1512
  ... on Success { success }
@@ -1026,7 +1515,7 @@ export const REFRESH_VERIFICATION = `
1026
1515
  }
1027
1516
  `;
1028
1517
  // --- Address Management ---
1029
- export const CREATE_ADDRESS = `
1518
+ export const CREATE_ADDRESS = /* GraphQL */ `
1030
1519
  mutation CreateAddress($input: CreateAddressInput!) {
1031
1520
  createCustomerAddress(input: $input) {
1032
1521
  id fullName streetLine1 streetLine2 city province postalCode
@@ -1035,7 +1524,7 @@ export const CREATE_ADDRESS = `
1035
1524
  }
1036
1525
  }
1037
1526
  `;
1038
- export const UPDATE_ADDRESS = `
1527
+ export const UPDATE_ADDRESS = /* GraphQL */ `
1039
1528
  mutation UpdateAddress($input: UpdateAddressInput!) {
1040
1529
  updateCustomerAddress(input: $input) {
1041
1530
  id fullName streetLine1 streetLine2 city province postalCode
@@ -1044,7 +1533,7 @@ export const UPDATE_ADDRESS = `
1044
1533
  }
1045
1534
  }
1046
1535
  `;
1047
- export const DELETE_ADDRESS = `
1536
+ export const DELETE_ADDRESS = /* GraphQL */ `
1048
1537
  mutation DeleteAddress($id: ID!) {
1049
1538
  deleteCustomerAddress(id: $id) {
1050
1539
  success
@@ -1052,7 +1541,7 @@ export const DELETE_ADDRESS = `
1052
1541
  }
1053
1542
  `;
1054
1543
  // --- Utility Queries ---
1055
- export const AVAILABLE_COUNTRIES = `
1544
+ export const AVAILABLE_COUNTRIES = /* GraphQL */ `
1056
1545
  query AvailableCountries {
1057
1546
  availableCountries {
1058
1547
  id code name
@@ -1062,30 +1551,38 @@ export const AVAILABLE_COUNTRIES = `
1062
1551
  /**
1063
1552
  * `lines { backorderedQuantity }` is selected HERE and on `GET_CUSTOMER_ORDERS`,
1064
1553
  * and nowhere else — the same rule `customFields { paymentIntent }` follows
1065
- * below. In the shared `ORDER_FIELDS` fragment it would make every cart read
1554
+ * below. In the shared `ORDER_FRAGMENT` fragment it would make every cart read
1066
1555
  * and mutation fail validation against an engine that predates the backorders
1067
1556
  * plugin, taking the whole cart down for a field a cart line never carries a
1068
1557
  * value for (the stamp is written at placement). GraphQL merges this `lines`
1069
1558
  * selection with the fragment's, so the line still comes back whole.
1559
+ *
1560
+ * `customFields { chargedParcelCount }` follows the same rule: frozen when the
1561
+ * order leaves the cart, so it belongs to this placed-order read alone. It
1562
+ * does make this document need an engine with the extra-parcel charge: a
1563
+ * client release carrying it publishes after that engine is deployed.
1070
1564
  */
1071
- export const ORDER_BY_CODE = `
1072
- query OrderByCode($code: String!) {
1073
- orderByCode(code: $code) {
1074
- ${ORDER_FIELDS}
1075
- lines { id backorderedQuantity }
1076
- ${ORDER_FULFILLMENTS_FRAGMENT}
1077
- ${ORDER_PAYMENT_TERMS_FRAGMENT}
1078
- ${ORDER_DELIVERY_TERMS_FRAGMENT}
1565
+ export const ORDER_BY_CODE = withFragments(
1566
+ /* GraphQL */ `
1567
+ query OrderByCode($code: String!) {
1568
+ orderByCode(code: $code) {
1569
+ ...Order
1570
+ lines { id backorderedQuantity }
1571
+ customFields { chargedParcelCount }
1572
+ ...OrderFulfillments
1573
+ ...OrderFulfillmentParcels
1574
+ ...OrderPaymentTerms
1575
+ ...OrderDeliveryTerms
1576
+ }
1079
1577
  }
1080
- }
1081
- `;
1578
+ `, ORDER_FRAGMENT, ORDER_FULFILLMENTS_FRAGMENT, ORDER_FULFILLMENT_PARCELS_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT);
1082
1579
  // --- Favorites ---
1083
- export const FAVORITE_VARIANT_IDS = `
1580
+ export const FAVORITE_VARIANT_IDS = /* GraphQL */ `
1084
1581
  query FavoriteVariantIds {
1085
1582
  favoriteProductVariantIds
1086
1583
  }
1087
1584
  `;
1088
- export const MY_FAVORITES = `
1585
+ export const MY_FAVORITES = /* GraphQL */ `
1089
1586
  query MyFavorites($options: FavoriteListOptions) {
1090
1587
  myFavorites(options: $options) {
1091
1588
  items {
@@ -1118,12 +1615,12 @@ export const MY_FAVORITES = `
1118
1615
  }
1119
1616
  }
1120
1617
  `;
1121
- export const TOGGLE_FAVORITE = `
1618
+ export const TOGGLE_FAVORITE = /* GraphQL */ `
1122
1619
  mutation ToggleFavorite($productVariantId: ID!) {
1123
1620
  toggleFavorite(productVariantId: $productVariantId)
1124
1621
  }
1125
1622
  `;
1126
- export const REMOVE_FAVORITE = `
1623
+ export const REMOVE_FAVORITE = /* GraphQL */ `
1127
1624
  mutation RemoveFavorite($productVariantId: ID!) {
1128
1625
  removeFavorite(productVariantId: $productVariantId)
1129
1626
  }
@@ -1135,8 +1632,8 @@ export const REMOVE_FAVORITE = `
1135
1632
  * in types.ts and the `public: true` Channel customFields configured on
1136
1633
  * the Vendure side.
1137
1634
  */
1138
- const CHANNEL_CUSTOM_FIELDS_FRAGMENT = `
1139
- customFields {
1635
+ const CHANNEL_CUSTOM_FIELDS_FRAGMENT = fragment(/* GraphQL */ `
1636
+ fragment ChannelCustomFields on ChannelCustomFields {
1140
1637
  businessName businessDescription
1141
1638
  logoAssetId darkLogoAssetId coverAssetId faviconAssetId
1142
1639
  websiteUrl primaryColor
@@ -1152,57 +1649,68 @@ const CHANNEL_CUSTOM_FIELDS_FRAGMENT = `
1152
1649
  returnsEnabled returnWindowDays
1153
1650
  taxDisplayDefault taxDisplayB2b taxExclusiveCountries
1154
1651
  }
1155
- `;
1156
- export const GET_ACTIVE_CHANNEL = `
1157
- query ActiveChannel {
1158
- activeChannel {
1159
- id code
1160
- defaultLanguageCode
1161
- availableLanguageCodes
1162
- defaultCurrencyCode
1163
- availableCurrencyCodes
1164
- ${CHANNEL_CUSTOM_FIELDS_FRAGMENT}
1652
+ `);
1653
+ export const GET_ACTIVE_CHANNEL = withFragments(
1654
+ /* GraphQL */ `
1655
+ query ActiveChannel {
1656
+ activeChannel {
1657
+ id code
1658
+ defaultLanguageCode
1659
+ availableLanguageCodes
1660
+ defaultCurrencyCode
1661
+ availableCurrencyCodes
1662
+ customFields { ...ChannelCustomFields }
1663
+ }
1165
1664
  }
1166
- }
1167
- `;
1665
+ `, CHANNEL_CUSTOM_FIELDS_FRAGMENT);
1168
1666
  // --- Product Properties ---
1169
- export const PROPERTY_GROUPS = `
1170
- query PropertyGroups {
1171
- productPropertyGroups {
1667
+ /** Every property group, with each property's full config (`getPropertyGroups`). */
1668
+ export const PROPERTY_GROUP_FRAGMENT = fragment(/* GraphQL */ `
1669
+ fragment PropertyGroup on PropertyGroup {
1670
+ id position
1671
+ translations { id languageCode name }
1672
+ properties {
1673
+ id slug fieldType isFilterable isRequired position
1674
+ config { options { value label } min max maxLength allowedCollectionIds filterableFieldSlugs }
1675
+ facetId
1676
+ fieldFacets { fieldSlug fieldType facetId }
1677
+ translations { id languageCode name helpText }
1678
+ }
1679
+ }
1680
+ `);
1681
+ /** One product's values per group (`getProductProperties`); the group config is narrower. */
1682
+ export const PRODUCT_PROPERTY_GROUP_VALUES_FRAGMENT = fragment(/* GraphQL */ `
1683
+ fragment ProductPropertyGroupValues on ProductPropertyGroupValues {
1684
+ group {
1172
1685
  id position
1173
1686
  translations { id languageCode name }
1174
1687
  properties {
1175
1688
  id slug fieldType isFilterable isRequired position
1176
- config { options { value label } min max maxLength allowedCollectionIds filterableFieldSlugs }
1689
+ config { options { value label } min max maxLength }
1177
1690
  facetId
1178
1691
  fieldFacets { fieldSlug fieldType facetId }
1179
1692
  translations { id languageCode name helpText }
1180
1693
  }
1181
1694
  }
1695
+ values { id propertyId languageCode value }
1182
1696
  }
1183
- `;
1184
- export const PRODUCT_PROPERTIES = `
1185
- query ProductProperties($productId: ID!) {
1186
- productPropertyValues(productId: $productId) {
1187
- group {
1188
- id position
1189
- translations { id languageCode name }
1190
- properties {
1191
- id slug fieldType isFilterable isRequired position
1192
- config { options { value label } min max maxLength }
1193
- facetId
1194
- fieldFacets { fieldSlug fieldType facetId }
1195
- translations { id languageCode name helpText }
1196
- }
1197
- }
1198
- values { id propertyId languageCode value }
1697
+ `);
1698
+ export const PROPERTY_GROUPS = withFragments(
1699
+ /* GraphQL */ `
1700
+ query PropertyGroups {
1701
+ productPropertyGroups { ...PropertyGroup }
1199
1702
  }
1200
- }
1201
- `;
1703
+ `, PROPERTY_GROUP_FRAGMENT);
1704
+ export const PRODUCT_PROPERTIES = withFragments(
1705
+ /* GraphQL */ `
1706
+ query ProductProperties($productId: ID!) {
1707
+ productPropertyValues(productId: $productId) { ...ProductPropertyGroupValues }
1708
+ }
1709
+ `, PRODUCT_PROPERTY_GROUP_VALUES_FRAGMENT);
1202
1710
  // --- Product Recommendations ---
1203
- export const GET_PRODUCT_RECOMMENDATIONS = `
1204
- query ProductRecommendations($productId: ID!, $groupSlug: String) {
1205
- productRecommendations(productId: $productId, groupSlug: $groupSlug) {
1711
+ export const RECOMMENDED_PRODUCT_GROUP_FRAGMENT = fragment(
1712
+ /* GraphQL */ `
1713
+ fragment RecommendedProductGroup on RecommendedProducts {
1206
1714
  groupName
1207
1715
  groupSlug
1208
1716
  products {
@@ -1218,18 +1726,26 @@ export const GET_PRODUCT_RECOMMENDATIONS = `
1218
1726
  stockOnHand stockAllocated saleable
1219
1727
  incomingStock projectedSaleable nextExpectedArrival
1220
1728
  backorderAllowance
1221
- availability { state availableFrom orderable }
1729
+ availability { ...ProductAvailability }
1730
+ forSaleInCurrency
1222
1731
  priceListName retailPrice retailPriceWithTax taxRateApplied { value }
1223
- priceTiers { minQuantity price priceWithTax discountLabel }
1224
- availabilityByLocation { locationId locationName inStock }
1732
+ priceTiers { ...PriceTier }
1733
+ availabilityByLocation { ...VariantLocationAvailability }
1225
1734
  customFields { minOrderQuantity salesUnit position }
1226
1735
  }
1227
1736
  }
1228
1737
  }
1229
- }
1230
- `;
1738
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, VARIANT_LOCATION_AVAILABILITY_FRAGMENT);
1739
+ export const GET_PRODUCT_RECOMMENDATIONS = withFragments(
1740
+ /* GraphQL */ `
1741
+ query ProductRecommendations($productId: ID!, $groupSlug: String) {
1742
+ productRecommendations(productId: $productId, groupSlug: $groupSlug) {
1743
+ ...RecommendedProductGroup
1744
+ }
1745
+ }
1746
+ `, RECOMMENDED_PRODUCT_GROUP_FRAGMENT);
1231
1747
  // --- Exchange Rates ---
1232
- export const GET_EXCHANGE_RATES = `
1748
+ export const GET_EXCHANGE_RATES = /* GraphQL */ `
1233
1749
  query ExchangeRates {
1234
1750
  exchangeRates {
1235
1751
  baseCurrency targetCurrency rate inverseRate rateDate
@@ -1237,38 +1753,43 @@ export const GET_EXCHANGE_RATES = `
1237
1753
  }
1238
1754
  `;
1239
1755
  // Shared selection for the exchange-rates plugin's ConvertedAmount type.
1240
- const CONVERTED_AMOUNT_FIELDS = `
1241
- originalAmount originalCurrency convertedAmount targetCurrency rate rateDate
1242
- `;
1243
- export const CONVERT_CURRENCY = `
1244
- query ConvertCurrency($amount: String!, $from: String!, $to: String!) {
1245
- convertCurrency(amount: $amount, fromCurrency: $from, toCurrency: $to) {
1246
- ${CONVERTED_AMOUNT_FIELDS}
1756
+ const CONVERTED_AMOUNT_FRAGMENT = fragment(/* GraphQL */ `
1757
+ fragment ConvertedAmount on ConvertedAmount {
1758
+ originalAmount originalCurrency convertedAmount targetCurrency rate rateDate
1759
+ }
1760
+ `);
1761
+ export const CONVERT_CURRENCY = withFragments(
1762
+ /* GraphQL */ `
1763
+ query ConvertCurrency($amount: String!, $from: String!, $to: String!) {
1764
+ convertCurrency(amount: $amount, fromCurrency: $from, toCurrency: $to) {
1765
+ ...ConvertedAmount
1766
+ }
1247
1767
  }
1248
- }
1249
- `;
1250
- export const GET_EXCHANGE_RATE = `
1768
+ `, CONVERTED_AMOUNT_FRAGMENT);
1769
+ export const GET_EXCHANGE_RATE = /* GraphQL */ `
1251
1770
  query ExchangeRate($targetCurrency: String!) {
1252
1771
  exchangeRate(targetCurrency: $targetCurrency) {
1253
1772
  baseCurrency targetCurrency rate inverseRate rateDate
1254
1773
  }
1255
1774
  }
1256
1775
  `;
1257
- export const CONVERT_FROM_BASE = `
1258
- query ConvertFromBase($amount: String!, $targetCurrency: String!) {
1259
- convertFromBase(amount: $amount, targetCurrency: $targetCurrency) {
1260
- ${CONVERTED_AMOUNT_FIELDS}
1776
+ export const CONVERT_FROM_BASE = withFragments(
1777
+ /* GraphQL */ `
1778
+ query ConvertFromBase($amount: String!, $targetCurrency: String!) {
1779
+ convertFromBase(amount: $amount, targetCurrency: $targetCurrency) {
1780
+ ...ConvertedAmount
1781
+ }
1261
1782
  }
1262
- }
1263
- `;
1264
- export const CONVERT_TO_BASE = `
1265
- query ConvertToBase($amount: String!, $sourceCurrency: String!) {
1266
- convertToBase(amount: $amount, sourceCurrency: $sourceCurrency) {
1267
- ${CONVERTED_AMOUNT_FIELDS}
1783
+ `, CONVERTED_AMOUNT_FRAGMENT);
1784
+ export const CONVERT_TO_BASE = withFragments(
1785
+ /* GraphQL */ `
1786
+ query ConvertToBase($amount: String!, $sourceCurrency: String!) {
1787
+ convertToBase(amount: $amount, sourceCurrency: $sourceCurrency) {
1788
+ ...ConvertedAmount
1789
+ }
1268
1790
  }
1269
- }
1270
- `;
1271
- export const CONVERT_TO_MULTIPLE = `
1791
+ `, CONVERTED_AMOUNT_FRAGMENT);
1792
+ export const CONVERT_TO_MULTIPLE = /* GraphQL */ `
1272
1793
  query ConvertToMultiple($amount: String!, $from: String!, $to: [String!]!) {
1273
1794
  convertToMultiple(amount: $amount, fromCurrency: $from, toCurrencies: $to) {
1274
1795
  currency amount rate
@@ -1277,69 +1798,106 @@ export const CONVERT_TO_MULTIPLE = `
1277
1798
  `;
1278
1799
  // --- B2B Quotes ---
1279
1800
  /**
1280
- * Per-line tax + product identity. These fields reach the Shop API with the
1801
+ * Per-line tax + product identity (`productName sku taxRate unitPriceWithTax
1802
+ * lineTotal lineTotalWithTax`). These fields reach the Shop API with the
1281
1803
  * `vendure-plugin-quotes` release that introduced them, and the SDK can be
1282
1804
  * upgraded before a tenant's Vendure is: an older server rejects the WHOLE
1283
1805
  * document at validation ("Cannot query field ..."), taking the quote page
1284
1806
  * down rather than dropping a column. So every quote document has a legacy
1285
- * twin without them, and `createQuotesMethods` retries with it once — see
1286
- * the fallback there. Keep the twins identical apart from this line.
1807
+ * twin spreading `QuoteLegacy` instead, and `createQuotesMethods` retries with
1808
+ * it once — see the fallback there. Keep the two fragments identical apart
1809
+ * from that line, and each legacy document identical to its twin apart from
1810
+ * the fragment it spreads and its `Legacy` operation name.
1287
1811
  */
1288
- const QUOTE_LINE_TAX_FIELDS = 'productName sku taxRate unitPriceWithTax lineTotal lineTotalWithTax';
1289
- const quoteFields = (lineTaxFields) => `
1290
- id code channelId customerId currencyCode status
1291
- expiresAt salesRepUserId customerNotes convertedOrderId
1292
- createdAt updatedAt
1293
- lines {
1294
- id productVariantId quantity unitPrice discountType discountValue discountLabel position
1295
- ${lineTaxFields}
1812
+ const QUOTE_FRAGMENT = fragment(/* GraphQL */ `
1813
+ fragment Quote on Quote {
1814
+ id code channelId customerId currencyCode status
1815
+ expiresAt salesRepUserId customerNotes convertedOrderId
1296
1816
  createdAt updatedAt
1297
- }
1298
- `;
1299
- const QUOTE_FIELDS = quoteFields(QUOTE_LINE_TAX_FIELDS);
1300
- const QUOTE_FIELDS_LEGACY = quoteFields('');
1301
- const myQuotesDocument = (fields) => `
1302
- query MyQuotes($options: QuoteListOptions) {
1303
- myQuotes(options: $options) {
1304
- items { ${fields} }
1305
- totalItems
1817
+ lines {
1818
+ id productVariantId quantity unitPrice discountType discountValue discountLabel position
1819
+ productName sku taxRate unitPriceWithTax lineTotal lineTotalWithTax
1820
+ createdAt updatedAt
1306
1821
  }
1307
1822
  }
1308
- `;
1309
- const myQuoteDocument = (fields) => `
1310
- query MyQuote($id: ID!) {
1311
- myQuote(id: $id) { ${fields} }
1312
- }
1313
- `;
1314
- const createQuoteRequestDocument = (fields) => `
1315
- mutation CreateQuoteRequest($input: CreateQuoteRequestInput!) {
1316
- createQuoteRequest(input: $input) { ${fields} }
1317
- }
1318
- `;
1319
- const cancelMyQuoteDocument = (fields) => `
1320
- mutation CancelMyQuote($id: ID!, $reason: String) {
1321
- cancelMyQuote(id: $id, reason: $reason) { ${fields} }
1322
- }
1323
- `;
1324
- export const MY_QUOTES = myQuotesDocument(QUOTE_FIELDS);
1325
- export const MY_QUOTES_LEGACY = myQuotesDocument(QUOTE_FIELDS_LEGACY);
1326
- export const MY_QUOTE = myQuoteDocument(QUOTE_FIELDS);
1327
- export const MY_QUOTE_LEGACY = myQuoteDocument(QUOTE_FIELDS_LEGACY);
1328
- export const CREATE_QUOTE_REQUEST = createQuoteRequestDocument(QUOTE_FIELDS);
1329
- export const CREATE_QUOTE_REQUEST_LEGACY = createQuoteRequestDocument(QUOTE_FIELDS_LEGACY);
1330
- export const ACCEPT_QUOTE = `
1331
- mutation AcceptQuote($id: ID!) {
1332
- acceptQuote(id: $id) { ${ORDER_FIELDS} }
1823
+ `);
1824
+ const QUOTE_LEGACY_FRAGMENT = fragment(/* GraphQL */ `
1825
+ fragment QuoteLegacy on Quote {
1826
+ id code channelId customerId currencyCode status
1827
+ expiresAt salesRepUserId customerNotes convertedOrderId
1828
+ createdAt updatedAt
1829
+ lines {
1830
+ id productVariantId quantity unitPrice discountType discountValue discountLabel position
1831
+ createdAt updatedAt
1832
+ }
1333
1833
  }
1334
- `;
1335
- export const CANCEL_MY_QUOTE = cancelMyQuoteDocument(QUOTE_FIELDS);
1336
- export const CANCEL_MY_QUOTE_LEGACY = cancelMyQuoteDocument(QUOTE_FIELDS_LEGACY);
1834
+ `);
1835
+ export const MY_QUOTES = withFragments(
1836
+ /* GraphQL */ `
1837
+ query MyQuotes($options: QuoteListOptions) {
1838
+ myQuotes(options: $options) {
1839
+ items { ...Quote }
1840
+ totalItems
1841
+ }
1842
+ }
1843
+ `, QUOTE_FRAGMENT);
1844
+ export const MY_QUOTES_LEGACY = withFragments(
1845
+ /* GraphQL */ `
1846
+ query MyQuotesLegacy($options: QuoteListOptions) {
1847
+ myQuotes(options: $options) {
1848
+ items { ...QuoteLegacy }
1849
+ totalItems
1850
+ }
1851
+ }
1852
+ `, QUOTE_LEGACY_FRAGMENT);
1853
+ export const MY_QUOTE = withFragments(
1854
+ /* GraphQL */ `
1855
+ query MyQuote($id: ID!) {
1856
+ myQuote(id: $id) { ...Quote }
1857
+ }
1858
+ `, QUOTE_FRAGMENT);
1859
+ export const MY_QUOTE_LEGACY = withFragments(
1860
+ /* GraphQL */ `
1861
+ query MyQuoteLegacy($id: ID!) {
1862
+ myQuote(id: $id) { ...QuoteLegacy }
1863
+ }
1864
+ `, QUOTE_LEGACY_FRAGMENT);
1865
+ export const CREATE_QUOTE_REQUEST = withFragments(
1866
+ /* GraphQL */ `
1867
+ mutation CreateQuoteRequest($input: CreateQuoteRequestInput!) {
1868
+ createQuoteRequest(input: $input) { ...Quote }
1869
+ }
1870
+ `, QUOTE_FRAGMENT);
1871
+ export const CREATE_QUOTE_REQUEST_LEGACY = withFragments(
1872
+ /* GraphQL */ `
1873
+ mutation CreateQuoteRequestLegacy($input: CreateQuoteRequestInput!) {
1874
+ createQuoteRequest(input: $input) { ...QuoteLegacy }
1875
+ }
1876
+ `, QUOTE_LEGACY_FRAGMENT);
1877
+ export const ACCEPT_QUOTE = withFragments(
1878
+ /* GraphQL */ `
1879
+ mutation AcceptQuote($id: ID!) {
1880
+ acceptQuote(id: $id) { ...Order }
1881
+ }
1882
+ `, ORDER_FRAGMENT);
1883
+ export const CANCEL_MY_QUOTE = withFragments(
1884
+ /* GraphQL */ `
1885
+ mutation CancelMyQuote($id: ID!, $reason: String) {
1886
+ cancelMyQuote(id: $id, reason: $reason) { ...Quote }
1887
+ }
1888
+ `, QUOTE_FRAGMENT);
1889
+ export const CANCEL_MY_QUOTE_LEGACY = withFragments(
1890
+ /* GraphQL */ `
1891
+ mutation CancelMyQuoteLegacy($id: ID!, $reason: String) {
1892
+ cancelMyQuote(id: $id, reason: $reason) { ...QuoteLegacy }
1893
+ }
1894
+ `, QUOTE_LEGACY_FRAGMENT);
1337
1895
  /**
1338
1896
  * Single-roundtrip branding query. activeChannel + fontResources (with
1339
1897
  * resolved file Assets) + brandingAssets for the channel-level logo, favicon,
1340
1898
  * and cover IDs already on ctx.channel.customFields.
1341
1899
  */
1342
- export const GET_BRANDING = `
1900
+ export const GET_BRANDING = /* GraphQL */ `
1343
1901
  query GetBranding($ids: [ID!]!) {
1344
1902
  activeChannel {
1345
1903
  id
@@ -1369,7 +1927,7 @@ export const GET_BRANDING = `
1369
1927
  }
1370
1928
  `;
1371
1929
  // --- Order constraints (inline order-constraints plugin) ---
1372
- export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = `
1930
+ export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = /* GraphQL */ `
1373
1931
  query ActiveChannelOrderConstraints {
1374
1932
  activeChannelOrderConstraints {
1375
1933
  minOrderAmountGross
@@ -1382,77 +1940,123 @@ export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = `
1382
1940
  }
1383
1941
  `;
1384
1942
  // --- Customer invoices (vendure-plugin-order-documents shop surface) ---
1385
- export const MY_ORDER_INVOICES = `
1943
+ export const MY_ORDER_INVOICES = /* GraphQL */ `
1386
1944
  query MyOrderInvoices($orderCode: String!) {
1387
1945
  myOrderInvoices(orderCode: $orderCode) {
1388
1946
  id invoiceNumber invoicedOn totalWithTax currencyCode languageCode createdAt
1389
1947
  }
1390
1948
  }
1391
1949
  `;
1392
- export const MY_INVOICE_PDF = `
1950
+ export const MY_INVOICE_PDF = /* GraphQL */ `
1393
1951
  query MyInvoicePdf($invoiceId: ID!) {
1394
1952
  myInvoicePdf(invoiceId: $invoiceId) {
1395
1953
  base64 filename invoiceNumber
1396
1954
  }
1397
1955
  }
1398
1956
  `;
1399
- // --- Order returns (vendure-plugin-returns shop surface) ---
1400
- /**
1401
- * Shared selection set for customer-facing OrderReturn objects. The Shop API
1402
- * never exposes the admin-only fields (`adminNote`, `history`) — do not add
1403
- * them here. Money values are Int minor units.
1404
- */
1405
- const RETURN_FIELDS = `
1406
- id code state
1407
- orderId orderCode currencyCode
1408
- preferredSettlementMethod settlementMethod
1409
- shippingRefundAmount settledAmount
1410
- customerNote requestedAt resolvedAt createdAt
1411
- lines {
1412
- id orderLineId
1413
- productVariantId productVariantName productVariantSku
1414
- requestedQty approvedQty receivedQty restockQty writeOffQty
1415
- reasonCode reasonNote
1416
- unitPriceWithTax unitPriceWithTaxUnrounded refundAmount
1957
+ export const CREATE_INVOICE_DOWNLOAD_URL = /* GraphQL */ `
1958
+ mutation CreateInvoiceDownloadUrl($invoiceId: ID!) {
1959
+ createInvoiceDownloadUrl(invoiceId: $invoiceId) {
1960
+ url expiresAt filename invoiceNumber
1961
+ }
1417
1962
  }
1418
1963
  `;
1419
- export const MY_RETURNS = `
1420
- query MyReturns($take: Int, $skip: Int) {
1421
- myReturns(options: { take: $take, skip: $skip }) {
1422
- items { ${RETURN_FIELDS} }
1423
- totalItems
1964
+ // --- Customer credit notes (vendure-plugin-order-documents shop surface) ---
1965
+ export const MY_ORDER_CREDIT_NOTES = /* GraphQL */ `
1966
+ query MyOrderCreditNotes($orderCode: String!) {
1967
+ myOrderCreditNotes(orderCode: $orderCode) {
1968
+ id creditNoteNumber issuedOn totalWithTax currencyCode kind reason invoiceNumber createdAt
1424
1969
  }
1425
1970
  }
1426
1971
  `;
1427
- export const MY_RETURN = `
1428
- query MyReturn($id: ID!) {
1429
- myReturn(id: $id) { ${RETURN_FIELDS} }
1972
+ export const CREATE_CREDIT_NOTE_DOWNLOAD_URL = /* GraphQL */ `
1973
+ mutation CreateCreditNoteDownloadUrl($creditNoteId: ID!) {
1974
+ createCreditNoteDownloadUrl(creditNoteId: $creditNoteId) {
1975
+ url expiresAt filename creditNoteNumber
1976
+ }
1430
1977
  }
1431
1978
  `;
1432
- export const REQUEST_RETURN = `
1433
- mutation RequestReturn(
1434
- $orderId: ID!
1435
- $lines: [ReturnRequestLineInput!]!
1436
- $customerNote: String
1437
- $preferredSettlementMethod: OrderReturnSettlementMethod
1438
- ) {
1439
- requestReturn(
1440
- input: {
1441
- orderId: $orderId
1442
- lines: $lines
1443
- customerNote: $customerNote
1444
- preferredSettlementMethod: $preferredSettlementMethod
1979
+ // --- Order returns (vendure-plugin-returns shop surface) ---
1980
+ /**
1981
+ * Shared selection set for customer-facing OrderReturn objects. The Shop API
1982
+ * never exposes the admin-only fields (`adminNote`, `history`) — do not add
1983
+ * them here. Money values are Int minor units.
1984
+ */
1985
+ const CUSTOMER_RETURN_FRAGMENT = fragment(/* GraphQL */ `
1986
+ fragment CustomerReturn on OrderReturn {
1987
+ id code state
1988
+ orderId orderCode currencyCode
1989
+ preferredSettlementMethod settlementMethod
1990
+ shippingRefundAmount settledAmount
1991
+ customerNote requestedAt resolvedAt createdAt
1992
+ lines {
1993
+ id orderLineId
1994
+ productVariantId productVariantName productVariantSku
1995
+ requestedQty approvedQty receivedQty restockQty writeOffQty
1996
+ reasonCode reasonNote
1997
+ unitPriceWithTax unitPriceWithTaxUnrounded refundAmount
1998
+ }
1999
+ }
2000
+ `);
2001
+ export const MY_RETURNS = withFragments(
2002
+ /* GraphQL */ `
2003
+ query MyReturns($take: Int, $skip: Int) {
2004
+ myReturns(options: { take: $take, skip: $skip }) {
2005
+ items { ...CustomerReturn }
2006
+ totalItems
1445
2007
  }
1446
- ) { ${RETURN_FIELDS} }
1447
- }
1448
- `;
1449
- export const CANCEL_MY_RETURN = `
1450
- mutation CancelMyReturn($id: ID!) {
1451
- cancelMyReturn(id: $id) { ${RETURN_FIELDS} }
2008
+ }
2009
+ `, CUSTOMER_RETURN_FRAGMENT);
2010
+ export const MY_RETURN = withFragments(
2011
+ /* GraphQL */ `
2012
+ query MyReturn($id: ID!) {
2013
+ myReturn(id: $id) { ...CustomerReturn }
2014
+ }
2015
+ `, CUSTOMER_RETURN_FRAGMENT);
2016
+ export const REQUEST_RETURN = withFragments(
2017
+ /* GraphQL */ `
2018
+ mutation RequestReturn(
2019
+ $orderId: ID!
2020
+ $lines: [ReturnRequestLineInput!]!
2021
+ $customerNote: String
2022
+ $preferredSettlementMethod: OrderReturnSettlementMethod
2023
+ ) {
2024
+ requestReturn(
2025
+ input: {
2026
+ orderId: $orderId
2027
+ lines: $lines
2028
+ customerNote: $customerNote
2029
+ preferredSettlementMethod: $preferredSettlementMethod
2030
+ }
2031
+ ) { ...CustomerReturn }
2032
+ }
2033
+ `, CUSTOMER_RETURN_FRAGMENT);
2034
+ export const CANCEL_MY_RETURN = withFragments(
2035
+ /* GraphQL */ `
2036
+ mutation CancelMyReturn($id: ID!) {
2037
+ cancelMyReturn(id: $id) { ...CustomerReturn }
2038
+ }
2039
+ `, CUSTOMER_RETURN_FRAGMENT);
2040
+ export const RETURNABLE_LINES_FOR_ORDER = /* GraphQL */ `
2041
+ query ReturnableLinesForOrder($orderId: ID!) {
2042
+ returnableLinesForOrder(orderId: $orderId) {
2043
+ orderId eligible reason returnWindowEndsAt
2044
+ lines {
2045
+ orderLineId
2046
+ productVariantId productVariantName productVariantSku
2047
+ fulfilledQty returnableQty unitPriceWithTax unitPriceWithTaxUnrounded
2048
+ creditedQty
2049
+ correctionCredits { orderLineId creditNoteId creditNoteNumber ledger quantity amount }
2050
+ }
2051
+ }
1452
2052
  }
1453
2053
  `;
1454
- export const RETURNABLE_LINES_FOR_ORDER = `
1455
- query ReturnableLinesForOrder($orderId: ID!) {
2054
+ /**
2055
+ * The same read for an engine released before 2026-10-09, which has no `creditedQty` or
2056
+ * `correctionCredits`: GraphQL refuses a whole document over one unknown field.
2057
+ */
2058
+ export const RETURNABLE_LINES_FOR_ORDER_LEGACY = /* GraphQL */ `
2059
+ query ReturnableLinesForOrderLegacy($orderId: ID!) {
1456
2060
  returnableLinesForOrder(orderId: $orderId) {
1457
2061
  orderId eligible reason returnWindowEndsAt
1458
2062
  lines {