@sixtyninecommerce/client 0.30.0 → 0.31.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 (352) hide show
  1. package/README.md +548 -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 +82 -38
  40. package/dist/commerce/customer.d.ts.map +1 -1
  41. package/dist/commerce/customer.js +146 -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 +189 -133
  47. package/dist/commerce/index.d.ts.map +1 -1
  48. package/dist/commerce/index.js +9 -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 +197 -48
  74. package/dist/commerce/queries.d.ts.map +1 -1
  75. package/dist/commerce/queries.js +1289 -746
  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/recommendations.d.ts +3 -3
  82. package/dist/commerce/recommendations.d.ts.map +1 -1
  83. package/dist/commerce/recommendations.js +3 -1
  84. package/dist/commerce/recommendations.js.map +1 -1
  85. package/dist/commerce/returns.d.ts +7 -6
  86. package/dist/commerce/returns.d.ts.map +1 -1
  87. package/dist/commerce/returns.js.map +1 -1
  88. package/dist/commerce/reviews.d.ts +24 -15
  89. package/dist/commerce/reviews.d.ts.map +1 -1
  90. package/dist/commerce/reviews.js +67 -50
  91. package/dist/commerce/reviews.js.map +1 -1
  92. package/dist/commerce/saved-lists.d.ts +15 -15
  93. package/dist/commerce/saved-lists.d.ts.map +1 -1
  94. package/dist/commerce/saved-lists.js +67 -56
  95. package/dist/commerce/saved-lists.js.map +1 -1
  96. package/dist/commerce/search.d.ts +3 -2
  97. package/dist/commerce/search.d.ts.map +1 -1
  98. package/dist/commerce/search.js +2 -2
  99. package/dist/commerce/search.js.map +1 -1
  100. package/dist/commerce/shipping.d.ts +11 -4
  101. package/dist/commerce/shipping.d.ts.map +1 -1
  102. package/dist/commerce/shipping.js +17 -2
  103. package/dist/commerce/shipping.js.map +1 -1
  104. package/dist/commerce/stock-notifications.d.ts +2 -0
  105. package/dist/commerce/stock-notifications.d.ts.map +1 -1
  106. package/dist/commerce/stock-notifications.js +2 -2
  107. package/dist/commerce/stock-notifications.js.map +1 -1
  108. package/dist/commerce/subscriptions.d.ts +35 -37
  109. package/dist/commerce/subscriptions.d.ts.map +1 -1
  110. package/dist/commerce/subscriptions.js +159 -120
  111. package/dist/commerce/subscriptions.js.map +1 -1
  112. package/dist/commerce/vat-validation.d.ts +6 -3
  113. package/dist/commerce/vat-validation.d.ts.map +1 -1
  114. package/dist/commerce/vat-validation.js +24 -19
  115. package/dist/commerce/vat-validation.js.map +1 -1
  116. package/dist/constants.d.ts.map +1 -1
  117. package/dist/constants.js.map +1 -1
  118. package/dist/content/assets.d.ts +5 -4
  119. package/dist/content/assets.d.ts.map +1 -1
  120. package/dist/content/assets.js.map +1 -1
  121. package/dist/content/collection-pages.d.ts +3 -2
  122. package/dist/content/collection-pages.d.ts.map +1 -1
  123. package/dist/content/collection-pages.js.map +1 -1
  124. package/dist/content/collections.d.ts +5 -4
  125. package/dist/content/collections.d.ts.map +1 -1
  126. package/dist/content/collections.js.map +1 -1
  127. package/dist/content/filtered-products.d.ts.map +1 -1
  128. package/dist/content/filtered-products.js.map +1 -1
  129. package/dist/content/form-field-types.d.ts +3 -3
  130. package/dist/content/form-field-types.d.ts.map +1 -1
  131. package/dist/content/form-field-types.js.map +1 -1
  132. package/dist/content/forms.d.ts +4 -3
  133. package/dist/content/forms.d.ts.map +1 -1
  134. package/dist/content/forms.js +3 -0
  135. package/dist/content/forms.js.map +1 -1
  136. package/dist/content/index.d.ts +18 -17
  137. package/dist/content/index.d.ts.map +1 -1
  138. package/dist/content/items.d.ts +5 -4
  139. package/dist/content/items.d.ts.map +1 -1
  140. package/dist/content/items.js +2 -0
  141. package/dist/content/items.js.map +1 -1
  142. package/dist/content/menus.d.ts +3 -2
  143. package/dist/content/menus.d.ts.map +1 -1
  144. package/dist/content/menus.js +7 -1
  145. package/dist/content/menus.js.map +1 -1
  146. package/dist/content/resolve.d.ts +3 -2
  147. package/dist/content/resolve.d.ts.map +1 -1
  148. package/dist/content/resolve.js +1 -1
  149. package/dist/content/resolve.js.map +1 -1
  150. package/dist/content/sitemap.d.ts +3 -2
  151. package/dist/content/sitemap.d.ts.map +1 -1
  152. package/dist/content/sitemap.js.map +1 -1
  153. package/dist/content/strings.d.ts +16 -2
  154. package/dist/content/strings.d.ts.map +1 -1
  155. package/dist/content/strings.js +32 -4
  156. package/dist/content/strings.js.map +1 -1
  157. package/dist/core/context.d.ts +127 -1
  158. package/dist/core/context.d.ts.map +1 -1
  159. package/dist/core/context.js +436 -45
  160. package/dist/core/context.js.map +1 -1
  161. package/dist/core/currency.d.ts +14 -0
  162. package/dist/core/currency.d.ts.map +1 -0
  163. package/dist/core/currency.js +52 -0
  164. package/dist/core/currency.js.map +1 -0
  165. package/dist/core/deprecation.d.ts +23 -0
  166. package/dist/core/deprecation.d.ts.map +1 -0
  167. package/dist/core/deprecation.js +81 -0
  168. package/dist/core/deprecation.js.map +1 -0
  169. package/dist/core/http.d.ts +15 -1
  170. package/dist/core/http.d.ts.map +1 -1
  171. package/dist/core/http.js +55 -3
  172. package/dist/core/http.js.map +1 -1
  173. package/dist/core/public-artifact.d.ts +72 -0
  174. package/dist/core/public-artifact.d.ts.map +1 -0
  175. package/dist/core/public-artifact.js +122 -0
  176. package/dist/core/public-artifact.js.map +1 -0
  177. package/dist/core/unknown-field-rejection.d.ts +18 -0
  178. package/dist/core/unknown-field-rejection.d.ts.map +1 -0
  179. package/dist/core/unknown-field-rejection.js +37 -0
  180. package/dist/core/unknown-field-rejection.js.map +1 -0
  181. package/dist/credit/credit-status.d.ts +2 -0
  182. package/dist/credit/credit-status.d.ts.map +1 -1
  183. package/dist/credit/credit-status.js +71 -19
  184. package/dist/credit/credit-status.js.map +1 -1
  185. package/dist/credit/index.d.ts +1 -1
  186. package/dist/credit/payment-terms.d.ts +3 -3
  187. package/dist/credit/payment-terms.d.ts.map +1 -1
  188. package/dist/credit/payment-terms.js +28 -24
  189. package/dist/credit/payment-terms.js.map +1 -1
  190. package/dist/currency/exchange.d.ts +7 -7
  191. package/dist/currency/exchange.d.ts.map +1 -1
  192. package/dist/currency/exchange.js +5 -1
  193. package/dist/currency/exchange.js.map +1 -1
  194. package/dist/errors.d.ts +17 -0
  195. package/dist/errors.d.ts.map +1 -1
  196. package/dist/errors.js +13 -0
  197. package/dist/errors.js.map +1 -1
  198. package/dist/events/index.d.ts +20 -7
  199. package/dist/events/index.d.ts.map +1 -1
  200. package/dist/events/index.js +17 -5
  201. package/dist/events/index.js.map +1 -1
  202. package/dist/events/payloads.d.ts +7 -4
  203. package/dist/events/payloads.d.ts.map +1 -1
  204. package/dist/events/payloads.js +6 -3
  205. package/dist/events/payloads.js.map +1 -1
  206. package/dist/feeds/index.d.ts +5 -0
  207. package/dist/feeds/index.d.ts.map +1 -0
  208. package/dist/feeds/index.js +12 -0
  209. package/dist/feeds/index.js.map +1 -0
  210. package/dist/feeds/types.d.ts +18 -0
  211. package/dist/feeds/types.d.ts.map +1 -0
  212. package/dist/feeds/types.js +8 -0
  213. package/dist/feeds/types.js.map +1 -0
  214. package/dist/generated/cms.d.ts +2136 -0
  215. package/dist/generated/cms.d.ts.map +1 -0
  216. package/dist/generated/cms.js +4 -0
  217. package/dist/generated/cms.js.map +1 -0
  218. package/dist/generated/plugins.d.ts +550 -0
  219. package/dist/generated/plugins.d.ts.map +1 -0
  220. package/dist/generated/plugins.js +4 -0
  221. package/dist/generated/plugins.js.map +1 -0
  222. package/dist/generated/shop.d.ts +5539 -0
  223. package/dist/generated/shop.d.ts.map +1 -0
  224. package/dist/generated/shop.js +5 -0
  225. package/dist/generated/shop.js.map +1 -0
  226. package/dist/graphql-document.d.ts +29 -0
  227. package/dist/graphql-document.d.ts.map +1 -0
  228. package/dist/graphql-document.js +21 -0
  229. package/dist/graphql-document.js.map +1 -0
  230. package/dist/index.d.ts +9 -4
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +4 -2
  233. package/dist/index.js.map +1 -1
  234. package/dist/media/urls.d.ts.map +1 -1
  235. package/dist/media/urls.js +12 -1
  236. package/dist/media/urls.js.map +1 -1
  237. package/dist/media/video.d.ts.map +1 -1
  238. package/dist/media/video.js.map +1 -1
  239. package/dist/multi-store.d.ts +200 -0
  240. package/dist/multi-store.d.ts.map +1 -0
  241. package/dist/multi-store.js +558 -0
  242. package/dist/multi-store.js.map +1 -0
  243. package/dist/navigation/routes.d.ts +4 -3
  244. package/dist/navigation/routes.d.ts.map +1 -1
  245. package/dist/navigation/routes.js.map +1 -1
  246. package/dist/next/artifact-handler.d.ts +21 -13
  247. package/dist/next/artifact-handler.d.ts.map +1 -1
  248. package/dist/next/artifact-handler.js +28 -66
  249. package/dist/next/artifact-handler.js.map +1 -1
  250. package/dist/next/event-revalidate-handler.d.ts +26 -6
  251. package/dist/next/event-revalidate-handler.d.ts.map +1 -1
  252. package/dist/next/event-revalidate-handler.js +126 -19
  253. package/dist/next/event-revalidate-handler.js.map +1 -1
  254. package/dist/next/feed-handler.d.ts +50 -0
  255. package/dist/next/feed-handler.d.ts.map +1 -0
  256. package/dist/next/feed-handler.js +61 -0
  257. package/dist/next/feed-handler.js.map +1 -0
  258. package/dist/next/index.d.ts +3 -1
  259. package/dist/next/index.d.ts.map +1 -1
  260. package/dist/next/index.js +1 -0
  261. package/dist/next/index.js.map +1 -1
  262. package/dist/next/metadata.d.ts.map +1 -1
  263. package/dist/next/metadata.js.map +1 -1
  264. package/dist/next/redirect-middleware.d.ts +5 -31
  265. package/dist/next/redirect-middleware.d.ts.map +1 -1
  266. package/dist/next/redirect-middleware.js +4 -46
  267. package/dist/next/redirect-middleware.js.map +1 -1
  268. package/dist/next/revalidate-handler.d.ts.map +1 -1
  269. package/dist/next/revalidate-handler.js.map +1 -1
  270. package/dist/pricing/index.d.ts.map +1 -1
  271. package/dist/pricing/index.js.map +1 -1
  272. package/dist/pricing/tax-display.js +1 -1
  273. package/dist/pricing/tax-display.js.map +1 -1
  274. package/dist/pricing/tiers.d.ts +3 -2
  275. package/dist/pricing/tiers.d.ts.map +1 -1
  276. package/dist/pricing/tiers.js.map +1 -1
  277. package/dist/pricing/validation.d.ts +63 -12
  278. package/dist/pricing/validation.d.ts.map +1 -1
  279. package/dist/pricing/validation.js +60 -12
  280. package/dist/pricing/validation.js.map +1 -1
  281. package/dist/redirects/index.d.ts.map +1 -1
  282. package/dist/redirects/index.js +2 -1
  283. package/dist/redirects/index.js.map +1 -1
  284. package/dist/redirects/store.d.ts.map +1 -1
  285. package/dist/redirects/store.js +6 -2
  286. package/dist/redirects/store.js.map +1 -1
  287. package/dist/redirects/types.d.ts +5 -2
  288. package/dist/redirects/types.d.ts.map +1 -1
  289. package/dist/revalidation/event-plan.d.ts +55 -4
  290. package/dist/revalidation/event-plan.d.ts.map +1 -1
  291. package/dist/revalidation/event-plan.js +115 -8
  292. package/dist/revalidation/event-plan.js.map +1 -1
  293. package/dist/revalidation/event-verify.d.ts +8 -37
  294. package/dist/revalidation/event-verify.d.ts.map +1 -1
  295. package/dist/revalidation/event-verify.js +7 -97
  296. package/dist/revalidation/event-verify.js.map +1 -1
  297. package/dist/revalidation/types.d.ts.map +1 -1
  298. package/dist/revalidation/url-context.d.ts +17 -0
  299. package/dist/revalidation/url-context.d.ts.map +1 -1
  300. package/dist/revalidation/url-context.js +35 -2
  301. package/dist/revalidation/url-context.js.map +1 -1
  302. package/dist/seo/ai.d.ts.map +1 -1
  303. package/dist/seo/ai.js.map +1 -1
  304. package/dist/seo/artifacts.d.ts +86 -4
  305. package/dist/seo/artifacts.d.ts.map +1 -1
  306. package/dist/seo/artifacts.js +115 -16
  307. package/dist/seo/artifacts.js.map +1 -1
  308. package/dist/seo/availability.d.ts +2 -2
  309. package/dist/seo/availability.d.ts.map +1 -1
  310. package/dist/seo/availability.js.map +1 -1
  311. package/dist/seo/index.d.ts +2 -0
  312. package/dist/seo/index.d.ts.map +1 -1
  313. package/dist/seo/index.js +3 -1
  314. package/dist/seo/index.js.map +1 -1
  315. package/dist/seo/json-ld.d.ts.map +1 -1
  316. package/dist/seo/json-ld.js.map +1 -1
  317. package/dist/seo/meta-tags.d.ts.map +1 -1
  318. package/dist/seo/meta-tags.js.map +1 -1
  319. package/dist/seo/metadata-parser.d.ts.map +1 -1
  320. package/dist/seo/metadata-parser.js.map +1 -1
  321. package/dist/seo/metadata-types.d.ts.map +1 -1
  322. package/dist/seo/robots.d.ts.map +1 -1
  323. package/dist/seo/robots.js.map +1 -1
  324. package/dist/seo/types.d.ts +9 -2
  325. package/dist/seo/types.d.ts.map +1 -1
  326. package/dist/seo/url-builder.d.ts +5 -3
  327. package/dist/seo/url-builder.d.ts.map +1 -1
  328. package/dist/seo/url-builder.js +3 -1
  329. package/dist/seo/url-builder.js.map +1 -1
  330. package/dist/types.d.ts +1226 -2522
  331. package/dist/types.d.ts.map +1 -1
  332. package/dist/web/artifact-responder.d.ts +69 -0
  333. package/dist/web/artifact-responder.d.ts.map +1 -0
  334. package/dist/web/artifact-responder.js +90 -0
  335. package/dist/web/artifact-responder.js.map +1 -0
  336. package/dist/web/feed-responder.d.ts +72 -0
  337. package/dist/web/feed-responder.d.ts.map +1 -0
  338. package/dist/web/feed-responder.js +81 -0
  339. package/dist/web/feed-responder.js.map +1 -0
  340. package/dist/web/index.d.ts +23 -0
  341. package/dist/web/index.d.ts.map +1 -0
  342. package/dist/web/index.js +19 -0
  343. package/dist/web/index.js.map +1 -0
  344. package/dist/web/redirect-middleware.d.ts +76 -0
  345. package/dist/web/redirect-middleware.d.ts.map +1 -0
  346. package/dist/web/redirect-middleware.js +94 -0
  347. package/dist/web/redirect-middleware.js.map +1 -0
  348. package/dist/web/respond.d.ts +20 -0
  349. package/dist/web/respond.d.ts.map +1 -0
  350. package/dist/web/respond.js +52 -0
  351. package/dist/web/respond.js.map +1 -0
  352. 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
- }
56
- }
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
101
+ presets { m { url webpUrl } l { url webpUrl } }
91
102
  }
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 }
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,161 @@ 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
+ }
679
866
  }
680
- }
681
- `;
682
- export const ELIGIBLE_PAYMENT_METHODS = `
867
+ `, ORDER_FRAGMENT);
868
+ export const ELIGIBLE_PAYMENT_METHODS = /* GraphQL */ `
683
869
  query PaymentMethods {
684
870
  eligiblePaymentMethods {
685
871
  id name code description isEligible eligibilityMessage
686
872
  }
687
873
  }
688
874
  `;
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} }
875
+ export const TRANSITION_TO_ARRANGING_PAYMENT = withFragments(
876
+ /* GraphQL */ `
877
+ mutation TransitionToArrangingPayment {
878
+ transitionOrderToState(state: "ArrangingPayment") {
879
+ ... on Order { ...Order }
880
+ ... on OrderStateTransitionError {
881
+ errorCode message transitionError
882
+ placement { ...PlacementRejection }
883
+ }
884
+ }
885
+ }
886
+ `, ORDER_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
887
+ /**
888
+ * `TRANSITION_TO_ARRANGING_PAYMENT` with the target state as a variable. The
889
+ * engine's order process and its placement guards decide which targets a
890
+ * shopper may reach; the document only carries the request.
891
+ */
892
+ export const TRANSITION_ORDER = withFragments(
893
+ /* GraphQL */ `
894
+ mutation TransitionOrder($state: String!) {
895
+ transitionOrderToState(state: $state) {
896
+ ... on Order { ...Order }
897
+ ... on OrderStateTransitionError {
898
+ errorCode message transitionError
899
+ placement { ...PlacementRejection }
900
+ }
696
901
  }
697
902
  }
903
+ `, ORDER_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
904
+ export const NEXT_ORDER_STATES = /* GraphQL */ `
905
+ query NextOrderStates {
906
+ nextOrderStates
698
907
  }
699
908
  `;
909
+ /**
910
+ * Every payment method enabled on the channel, whatever the active order.
911
+ * `customFields` is NOT selected: it is a raw JSON passthrough of the entity's
912
+ * custom fields, which are all private on this platform.
913
+ */
914
+ const PUBLIC_PAYMENT_METHOD_FRAGMENT = fragment(/* GraphQL */ `
915
+ fragment PublicPaymentMethod on PublicPaymentMethod {
916
+ id code name description
917
+ }
918
+ `);
919
+ export const ACTIVE_PAYMENT_METHODS = withFragments(
920
+ /* GraphQL */ `
921
+ query ActivePaymentMethods {
922
+ activePaymentMethods { ...PublicPaymentMethod }
923
+ }
924
+ `, PUBLIC_PAYMENT_METHOD_FRAGMENT);
925
+ const PUBLIC_SHIPPING_METHOD_FRAGMENT = fragment(/* GraphQL */ `
926
+ fragment PublicShippingMethod on PublicShippingMethod {
927
+ id code name description
928
+ }
929
+ `);
930
+ /** Every shipping method offered on the channel's storefront, whatever the active order. */
931
+ export const ACTIVE_SHIPPING_METHODS = withFragments(
932
+ /* GraphQL */ `
933
+ query ActiveShippingMethods {
934
+ activeShippingMethods { ...PublicShippingMethod }
935
+ }
936
+ `, PUBLIC_SHIPPING_METHOD_FRAGMENT);
937
+ /**
938
+ * The order custom fields the Shop API lets a shopper write — exactly the
939
+ * members of `UpdateOrderCustomFieldsInput` (public, not read-only) — selected
940
+ * back on `setOrderCustomFields` so the caller sees what the engine stored.
941
+ *
942
+ * Selected on that ONE document: the shared `ORDER_FRAGMENT` stays free of
943
+ * custom fields, so an engine that predates one of these fields fails only the
944
+ * call that writes them, never every cart read.
945
+ */
946
+ const ORDER_WRITABLE_CUSTOM_FIELDS_FRAGMENT = fragment(/* GraphQL */ `
947
+ fragment OrderWritableCustomFields on OrderCustomFields {
948
+ isGift giftNote hidePricesOnPackingSlip
949
+ poNumber requestedDeliveryDate orderNotes
950
+ snTid snUtmSource snUtmMedium snUtmCampaign snFlowId snEnrollmentId snStepId
951
+ }
952
+ `);
953
+ export const SET_ORDER_CUSTOM_FIELDS = withFragments(
954
+ /* GraphQL */ `
955
+ mutation SetOrderCustomFields($input: UpdateOrderInput!) {
956
+ setOrderCustomFields(input: $input) {
957
+ ... on Order {
958
+ ...Order
959
+ customFields { ...OrderWritableCustomFields }
960
+ }
961
+ ... on NoActiveOrderError { errorCode message }
962
+ }
963
+ }
964
+ `, ORDER_FRAGMENT, ORDER_WRITABLE_CUSTOM_FIELDS_FRAGMENT);
965
+ export const UNSET_SHIPPING_ADDRESS = withFragments(
966
+ /* GraphQL */ `
967
+ mutation UnsetShippingAddress {
968
+ unsetOrderShippingAddress {
969
+ ... on Order { ...Order }
970
+ ... on NoActiveOrderError { errorCode message }
971
+ }
972
+ }
973
+ `, ORDER_FRAGMENT);
974
+ export const UNSET_BILLING_ADDRESS = withFragments(
975
+ /* GraphQL */ `
976
+ mutation UnsetBillingAddress {
977
+ unsetOrderBillingAddress {
978
+ ... on Order { ...Order }
979
+ ... on NoActiveOrderError { errorCode message }
980
+ }
981
+ }
982
+ `, ORDER_FRAGMENT);
983
+ /**
984
+ * `setCurrencyCodeForOrder` answers `UpdateOrderItemsResult`, so every member of
985
+ * that union is selected: an unselected member comes back as `{}`, which
986
+ * carries no `errorCode` and would read as success.
987
+ */
988
+ export const SET_ORDER_CURRENCY = withFragments(
989
+ /* GraphQL */ `
990
+ mutation SetOrderCurrency($currencyCode: CurrencyCode!) {
991
+ setCurrencyCodeForOrder(currencyCode: $currencyCode) {
992
+ ... on Order { ...Order }
993
+ ... on OrderModificationError { errorCode message }
994
+ ... on OrderLimitError { errorCode message maxItems }
995
+ ... on NegativeQuantityError { errorCode message }
996
+ ... on InsufficientStockError { ...InsufficientStockError }
997
+ ... on OrderInterceptorError { errorCode message interceptorError }
998
+ }
999
+ }
1000
+ `, ORDER_FRAGMENT, INSUFFICIENT_STOCK_ERROR_FRAGMENT);
700
1001
  /**
701
1002
  * Record how the buyer intends to pay AND re-price the order in one round trip.
702
1003
  *
@@ -708,85 +1009,91 @@ export const TRANSITION_TO_ARRANGING_PAYMENT = `
708
1009
  * the pay-now discount.
709
1010
  *
710
1011
  * `customFields { paymentIntent }` is selected HERE and nowhere else, and that
711
- * is deliberate. Putting it in the shared `ORDER_FIELDS` would make every order
1012
+ * is deliberate. Putting it in the shared `ORDER_FRAGMENT` would make every order
712
1013
  * query and cart mutation in this client fail GraphQL validation against an
713
1014
  * engine that predates the field — one missing feature would take the whole cart
714
1015
  * down. Confined to this document, only the call that needs the field is
715
1016
  * coupled to an engine that has it.
716
1017
  */
717
- export const SET_PAYMENT_INTENT = `
718
- mutation SetOrderPaymentIntent($intent: OrderPaymentIntent!) {
719
- setOrderPaymentIntent(intent: $intent) {
720
- ... on Order {
721
- ${ORDER_FIELDS}
722
- customFields { paymentIntent }
1018
+ export const SET_PAYMENT_INTENT = withFragments(
1019
+ /* GraphQL */ `
1020
+ mutation SetOrderPaymentIntent($intent: OrderPaymentIntent!) {
1021
+ setOrderPaymentIntent(intent: $intent) {
1022
+ ... on Order {
1023
+ ...Order
1024
+ customFields { paymentIntent }
1025
+ }
1026
+ ... on NoActiveOrderError { errorCode message }
723
1027
  }
724
- ... on NoActiveOrderError { errorCode message }
725
1028
  }
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} }
1029
+ `, ORDER_FRAGMENT);
1030
+ export const ADD_PAYMENT = withFragments(
1031
+ /* GraphQL */ `
1032
+ mutation AddPayment($input: PaymentInput!) {
1033
+ addPaymentToOrder(input: $input) {
1034
+ ... on Order {
1035
+ ...Order
1036
+ ...OrderPaymentTerms
1037
+ ...OrderDeliveryTerms
1038
+ }
1039
+ ... on OrderPaymentStateError { errorCode message }
1040
+ ... on IneligiblePaymentMethodError { errorCode message }
1041
+ ... on PaymentFailedError {
1042
+ errorCode message paymentErrorMessage
1043
+ placement { ...PlacementRejection }
1044
+ }
1045
+ ... on PaymentDeclinedError {
1046
+ errorCode message paymentErrorMessage
1047
+ placement { ...PlacementRejection }
1048
+ }
1049
+ ... on OrderStateTransitionError {
1050
+ errorCode message transitionError
1051
+ placement { ...PlacementRejection }
1052
+ }
1053
+ ... on NoActiveOrderError { errorCode message }
749
1054
  }
750
- ... on NoActiveOrderError { errorCode message }
751
1055
  }
752
- }
753
- `;
1056
+ `, ORDER_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT, PLACEMENT_REJECTION_FRAGMENT);
754
1057
  // --- 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}
1058
+ const PICKUP_LOCATION_FRAGMENT = fragment(/* GraphQL */ `
1059
+ fragment PickupLocation on PickupLocation {
1060
+ provider
1061
+ carrier
1062
+ locationCode
1063
+ name
1064
+ address {
1065
+ streetLine1
1066
+ number
1067
+ postalCode
1068
+ city
1069
+ countryCode
1070
+ region
1071
+ }
1072
+ openingHours {
1073
+ weekday
1074
+ open
1075
+ close
1076
+ }
1077
+ details
1078
+ }
1079
+ `);
1080
+ export const PICKUP_LOCATIONS = withFragments(
1081
+ /* GraphQL */ `
1082
+ query PickupLocations($input: PickupLocationSearchInput!) {
1083
+ pickupLocations(input: $input) {
1084
+ ...PickupLocation
1085
+ }
779
1086
  }
780
- }
781
- `;
782
- export const ACTIVE_ORDER_PICKUP_LOCATION = `
783
- query ActiveOrderPickupLocation {
784
- activeOrderPickupLocation {
785
- ${PICKUP_LOCATION_FIELDS}
1087
+ `, PICKUP_LOCATION_FRAGMENT);
1088
+ export const ACTIVE_ORDER_PICKUP_LOCATION = withFragments(
1089
+ /* GraphQL */ `
1090
+ query ActiveOrderPickupLocation {
1091
+ activeOrderPickupLocation {
1092
+ ...PickupLocation
1093
+ }
786
1094
  }
787
- }
788
- `;
789
- export const SET_ACTIVE_ORDER_PICKUP_LOCATION = `
1095
+ `, PICKUP_LOCATION_FRAGMENT);
1096
+ export const SET_ACTIVE_ORDER_PICKUP_LOCATION = /* GraphQL */ `
790
1097
  mutation SetActiveOrderPickupLocation($location: StoredPickupLocationInput!) {
791
1098
  setActiveOrderPickupLocation(location: $location) {
792
1099
  __typename
@@ -801,13 +1108,13 @@ export const SET_ACTIVE_ORDER_PICKUP_LOCATION = `
801
1108
  }
802
1109
  `;
803
1110
  // --- Stripe (@vendure-community/stripe-plugin) ---
804
- export const CREATE_STRIPE_PAYMENT_INTENT = `
1111
+ export const CREATE_STRIPE_PAYMENT_INTENT = /* GraphQL */ `
805
1112
  mutation CreateStripePaymentIntent {
806
1113
  createStripePaymentIntent
807
1114
  }
808
1115
  `;
809
1116
  // --- Mollie (@vendure-community/mollie-plugin) ---
810
- export const MOLLIE_PAYMENT_METHODS = `
1117
+ export const MOLLIE_PAYMENT_METHODS = /* GraphQL */ `
811
1118
  query MolliePaymentMethods($input: MolliePaymentMethodsInput!) {
812
1119
  molliePaymentMethods(input: $input) {
813
1120
  id
@@ -820,7 +1127,7 @@ export const MOLLIE_PAYMENT_METHODS = `
820
1127
  }
821
1128
  }
822
1129
  `;
823
- export const ORDERED_MOLLIE_PAYMENT_METHODS = `
1130
+ export const ORDERED_MOLLIE_PAYMENT_METHODS = /* GraphQL */ `
824
1131
  query OrderedMolliePaymentMethods($paymentMethodCode: String!) {
825
1132
  orderedMolliePaymentMethods(paymentMethodCode: $paymentMethodCode) {
826
1133
  id
@@ -831,7 +1138,7 @@ export const ORDERED_MOLLIE_PAYMENT_METHODS = `
831
1138
  }
832
1139
  }
833
1140
  `;
834
- export const CREATE_MOLLIE_PAYMENT_INTENT = `
1141
+ export const CREATE_MOLLIE_PAYMENT_INTENT = /* GraphQL */ `
835
1142
  mutation CreateMolliePaymentIntent($input: MolliePaymentIntentInput!) {
836
1143
  createMolliePaymentIntent(input: $input) {
837
1144
  ... on MolliePaymentIntent { url }
@@ -839,7 +1146,7 @@ export const CREATE_MOLLIE_PAYMENT_INTENT = `
839
1146
  }
840
1147
  }
841
1148
  `;
842
- export const SYNC_MOLLIE_PAYMENT_STATUS = `
1149
+ export const SYNC_MOLLIE_PAYMENT_STATUS = /* GraphQL */ `
843
1150
  mutation SyncMolliePaymentStatus($orderCode: String!) {
844
1151
  syncMolliePaymentStatus(orderCode: $orderCode) {
845
1152
  id
@@ -848,8 +1155,101 @@ export const SYNC_MOLLIE_PAYMENT_STATUS = `
848
1155
  }
849
1156
  }
850
1157
  `;
1158
+ // --- Parked (held) orders ---
1159
+ /**
1160
+ * The money on a held order, as the storefront sees it: what it bills, what is
1161
+ * covered, what is left, and the currency all three are in. Narrower than the
1162
+ * merchant's own view of the same order — settled-vs-authorized and per-payment
1163
+ * refunds are bookkeeping a shopper is not shown.
1164
+ */
1165
+ const PARKED_ORDER_FRAGMENT = fragment(/* GraphQL */ `
1166
+ fragment ParkedOrder on ParkedOrder {
1167
+ id
1168
+ code
1169
+ state
1170
+ position { total covered outstanding currencyCode }
1171
+ reason
1172
+ }
1173
+ `);
1174
+ export const PARKED_ORDERS_QUERY = withFragments(
1175
+ /* GraphQL */ `
1176
+ query ParkedOrders {
1177
+ parkedOrders {
1178
+ ...ParkedOrder
1179
+ }
1180
+ }
1181
+ `, PARKED_ORDER_FRAGMENT);
1182
+ export const PAY_PARKED_ORDER_MUTATION = /* GraphQL */ `
1183
+ mutation PayParkedOrder(
1184
+ $orderCode: String!
1185
+ $input: PayParkedOrderInput!
1186
+ $idempotencyKey: String
1187
+ ) {
1188
+ payParkedOrder(orderCode: $orderCode, input: $input, idempotencyKey: $idempotencyKey) {
1189
+ order { id code state }
1190
+ payment { id state amount method metadata }
1191
+ position { total covered outstanding currencyCode }
1192
+ settled
1193
+ }
1194
+ }
1195
+ `;
1196
+ export const CREATE_PARKED_ORDER_PAYMENT_INTENT_MUTATION = /* GraphQL */ `
1197
+ mutation CreateParkedOrderPaymentIntent(
1198
+ $orderCode: String!
1199
+ $input: ParkedOrderPaymentIntentInput!
1200
+ $idempotencyKey: String
1201
+ ) {
1202
+ createParkedOrderPaymentIntent(
1203
+ orderCode: $orderCode
1204
+ input: $input
1205
+ idempotencyKey: $idempotencyKey
1206
+ ) {
1207
+ provider
1208
+ url
1209
+ clientSecret
1210
+ amount
1211
+ currencyCode
1212
+ }
1213
+ }
1214
+ `;
1215
+ /**
1216
+ * A deposit paid in checkout, which parks the active order (W8-13).
1217
+ *
1218
+ * `order` selects exactly what `ADD_PAYMENT` selects for its `Order` member, so
1219
+ * `addPayment(input, { amount })` — which routes here — resolves to the same
1220
+ * type whether it paid in full or paid a deposit. No `idempotencyKey` argument:
1221
+ * like `addPaymentToOrder`, this mutation is keyed by the `Idempotency-Key`
1222
+ * header (the W8-12 contract), unlike the parked-order calls above.
1223
+ */
1224
+ export const PAY_DEPOSIT_MUTATION = withFragments(
1225
+ /* GraphQL */ `
1226
+ mutation PayDeposit($input: PayDepositInput!) {
1227
+ payDeposit(input: $input) {
1228
+ order {
1229
+ ...Order
1230
+ ...OrderPaymentTerms
1231
+ ...OrderDeliveryTerms
1232
+ }
1233
+ payment { id state amount method metadata }
1234
+ position { total covered outstanding currencyCode }
1235
+ settled
1236
+ }
1237
+ }
1238
+ `, ORDER_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT);
1239
+ /** A card (Mollie) deposit in checkout; keyed by the header, as `PAY_DEPOSIT_MUTATION`. */
1240
+ export const CREATE_DEPOSIT_PAYMENT_INTENT_MUTATION = /* GraphQL */ `
1241
+ mutation CreateDepositPaymentIntent($input: DepositPaymentIntentInput!) {
1242
+ createDepositPaymentIntent(input: $input) {
1243
+ provider
1244
+ url
1245
+ clientSecret
1246
+ amount
1247
+ currencyCode
1248
+ }
1249
+ }
1250
+ `;
851
1251
  // --- Customer Queries/Mutations ---
852
- export const LOGIN = `
1252
+ export const LOGIN = /* GraphQL */ `
853
1253
  mutation Login($email: String!, $password: String!) {
854
1254
  login(username: $email, password: $password) {
855
1255
  ... on CurrentUser { id identifier }
@@ -859,7 +1259,29 @@ export const LOGIN = `
859
1259
  }
860
1260
  }
861
1261
  `;
862
- export const REGISTER = `
1262
+ const CURRENT_USER_FRAGMENT = fragment(/* GraphQL */ `
1263
+ fragment CurrentUser on CurrentUser {
1264
+ id identifier
1265
+ }
1266
+ `);
1267
+ /**
1268
+ * Sign in through a named authentication strategy (`native` is the only one the
1269
+ * engine registers today). Every `AuthenticationResult` member is selected, and
1270
+ * `authenticationError` with it: the engine's native strategy reports an
1271
+ * imported account with no password (`PASSWORD_RESET_REQUIRED`) or an
1272
+ * unverified one (`ACCOUNT_NOT_VERIFIED`) there, not as an error type.
1273
+ */
1274
+ export const AUTHENTICATE = withFragments(
1275
+ /* GraphQL */ `
1276
+ mutation Authenticate($input: AuthenticationInput!, $rememberMe: Boolean) {
1277
+ authenticate(input: $input, rememberMe: $rememberMe) {
1278
+ ... on CurrentUser { ...CurrentUser }
1279
+ ... on InvalidCredentialsError { errorCode message authenticationError }
1280
+ ... on NotVerifiedError { errorCode message }
1281
+ }
1282
+ }
1283
+ `, CURRENT_USER_FRAGMENT);
1284
+ export const REGISTER = /* GraphQL */ `
863
1285
  mutation Register($input: RegisterCustomerInput!) {
864
1286
  registerCustomerAccount(input: $input) {
865
1287
  ... on Success { success }
@@ -869,58 +1291,62 @@ export const REGISTER = `
869
1291
  }
870
1292
  }
871
1293
  `;
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}
1294
+ export const GET_CURRENT_CUSTOMER = withFragments(
1295
+ /* GraphQL */ `
1296
+ query Me {
1297
+ activeCustomer {
1298
+ id firstName lastName emailAddress phoneNumber
1299
+ groups { id name }
1300
+ isB2B
1301
+ hasPassword
1302
+ addresses {
1303
+ id fullName streetLine1 streetLine2 city province postalCode
1304
+ country { code name }
1305
+ defaultShippingAddress defaultBillingAddress
1306
+ }
1307
+ orders(options: { take: 10, sort: { createdAt: DESC } }) {
1308
+ items {
1309
+ ...OrderSummary
1310
+ }
1311
+ totalItems
886
1312
  }
887
- totalItems
888
1313
  }
889
1314
  }
890
- }
891
- `;
892
- export const ACTIVE_CUSTOMER_PRICE_LISTS = `
1315
+ `, ORDER_SUMMARY_FRAGMENT);
1316
+ export const ACTIVE_CUSTOMER_PRICE_LISTS = /* GraphQL */ `
893
1317
  query ActiveCustomerPriceLists {
894
1318
  activeCustomerPriceLists { id name isContract }
895
1319
  }
896
1320
  `;
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 }
1321
+ export const GET_CUSTOMER_ORDERS = withFragments(
1322
+ /* GraphQL */ `
1323
+ query CustomerOrders($options: OrderListOptions) {
1324
+ activeCustomer {
1325
+ orders(options: $options) {
1326
+ items {
1327
+ ...OrderSummary
1328
+ lines { id backorderedQuantity }
1329
+ ...OrderFulfillmentParcels
1330
+ }
1331
+ totalItems
904
1332
  }
905
- totalItems
906
1333
  }
907
1334
  }
908
- }
909
- `;
910
- export const LOGOUT = `
1335
+ `, ORDER_FULFILLMENT_PARCELS_FRAGMENT, ORDER_SUMMARY_FRAGMENT);
1336
+ export const LOGOUT = /* GraphQL */ `
911
1337
  mutation Logout {
912
1338
  logout { success }
913
1339
  }
914
1340
  `;
915
1341
  // --- Customer Account Management ---
916
- export const UPDATE_CUSTOMER = `
1342
+ export const UPDATE_CUSTOMER = /* GraphQL */ `
917
1343
  mutation UpdateCustomer($input: UpdateCustomerInput!) {
918
1344
  updateCustomer(input: $input) {
919
1345
  id firstName lastName emailAddress phoneNumber
920
1346
  }
921
1347
  }
922
1348
  `;
923
- export const UPDATE_PASSWORD = `
1349
+ export const UPDATE_PASSWORD = /* GraphQL */ `
924
1350
  mutation UpdatePassword($currentPassword: String!, $newPassword: String!) {
925
1351
  updateCustomerPassword(currentPassword: $currentPassword, newPassword: $newPassword) {
926
1352
  ... on Success { success }
@@ -930,7 +1356,24 @@ export const UPDATE_PASSWORD = `
930
1356
  }
931
1357
  }
932
1358
  `;
933
- export const REQUEST_PASSWORD_RESET = `
1359
+ /**
1360
+ * The signed-in customer's FIRST password, for an account that signed in by
1361
+ * email link or code and has none (`updatePassword` needs the current one).
1362
+ * Every member is selected: an unselected error member arrives as `{}` and the
1363
+ * wrapper would read a refused password as set.
1364
+ */
1365
+ export const SET_CUSTOMER_PASSWORD = /* GraphQL */ `
1366
+ mutation SetCustomerPassword($newPassword: String!) {
1367
+ setCustomerPassword(newPassword: $newPassword) {
1368
+ ... on Success { success }
1369
+ ... on PasswordValidationError { errorCode message validationErrorMessage }
1370
+ ... on PasswordAlreadySetError { errorCode message }
1371
+ ... on NativeAuthStrategyError { errorCode message }
1372
+ ... on SetPasswordRequiresEmailSignInError { errorCode message }
1373
+ }
1374
+ }
1375
+ `;
1376
+ export const REQUEST_PASSWORD_RESET = /* GraphQL */ `
934
1377
  mutation RequestPasswordReset($emailAddress: String!) {
935
1378
  requestPasswordReset(emailAddress: $emailAddress) {
936
1379
  ... on Success { success }
@@ -938,7 +1381,7 @@ export const REQUEST_PASSWORD_RESET = `
938
1381
  }
939
1382
  }
940
1383
  `;
941
- export const RESET_PASSWORD = `
1384
+ export const RESET_PASSWORD = /* GraphQL */ `
942
1385
  mutation ResetPassword($token: String!, $password: String!) {
943
1386
  resetPassword(token: $token, password: $password) {
944
1387
  ... on CurrentUser { id identifier }
@@ -950,15 +1393,18 @@ export const RESET_PASSWORD = `
950
1393
  }
951
1394
  }
952
1395
  `;
953
- export const REQUEST_MAGIC_LINK = `
954
- mutation RequestMagicLink($emailAddress: String!) {
955
- requestMagicLink(emailAddress: $emailAddress) {
1396
+ // `MagicLinkRateLimitedError` must stay selected: an unselected union member
1397
+ // comes back as `{}`, which carries no `errorCode` and reads as success.
1398
+ export const REQUEST_MAGIC_LINK = /* GraphQL */ `
1399
+ mutation RequestMagicLink($emailAddress: String!, $portal: MagicLinkPortal) {
1400
+ requestMagicLink(emailAddress: $emailAddress, portal: $portal) {
956
1401
  ... on Success { success }
957
1402
  ... on NativeAuthStrategyError { errorCode message }
1403
+ ... on MagicLinkRateLimitedError { errorCode message retryAfterSeconds }
958
1404
  }
959
1405
  }
960
1406
  `;
961
- export const LOGIN_WITH_MAGIC_LINK = `
1407
+ export const LOGIN_WITH_MAGIC_LINK = /* GraphQL */ `
962
1408
  mutation LoginWithMagicLink($token: String!) {
963
1409
  loginWithMagicLink(token: $token) {
964
1410
  ... on CurrentUser { id identifier }
@@ -970,7 +1416,7 @@ export const LOGIN_WITH_MAGIC_LINK = `
970
1416
  }
971
1417
  }
972
1418
  `;
973
- export const LOGIN_WITH_MAGIC_CODE = `
1419
+ export const LOGIN_WITH_MAGIC_CODE = /* GraphQL */ `
974
1420
  mutation LoginWithMagicCode($emailAddress: String!, $code: String!) {
975
1421
  loginWithMagicCode(emailAddress: $emailAddress, code: $code) {
976
1422
  ... on CurrentUser { id identifier }
@@ -982,7 +1428,7 @@ export const LOGIN_WITH_MAGIC_CODE = `
982
1428
  }
983
1429
  }
984
1430
  `;
985
- export const REQUEST_EMAIL_UPDATE = `
1431
+ export const REQUEST_EMAIL_UPDATE = /* GraphQL */ `
986
1432
  mutation RequestEmailUpdate($password: String!, $newEmailAddress: String!) {
987
1433
  requestUpdateCustomerEmailAddress(password: $password, newEmailAddress: $newEmailAddress) {
988
1434
  ... on Success { success }
@@ -994,7 +1440,7 @@ export const REQUEST_EMAIL_UPDATE = `
994
1440
  }
995
1441
  }
996
1442
  `;
997
- export const UPDATE_EMAIL = `
1443
+ export const UPDATE_EMAIL = /* GraphQL */ `
998
1444
  mutation UpdateEmail($token: String!) {
999
1445
  updateCustomerEmailAddress(token: $token) {
1000
1446
  ... on Success { success }
@@ -1004,7 +1450,7 @@ export const UPDATE_EMAIL = `
1004
1450
  }
1005
1451
  }
1006
1452
  `;
1007
- export const VERIFY_ACCOUNT = `
1453
+ export const VERIFY_ACCOUNT = /* GraphQL */ `
1008
1454
  mutation VerifyAccount($token: String!, $password: String) {
1009
1455
  verifyCustomerAccount(token: $token, password: $password) {
1010
1456
  ... on CurrentUser { id identifier }
@@ -1017,7 +1463,7 @@ export const VERIFY_ACCOUNT = `
1017
1463
  }
1018
1464
  }
1019
1465
  `;
1020
- export const REFRESH_VERIFICATION = `
1466
+ export const REFRESH_VERIFICATION = /* GraphQL */ `
1021
1467
  mutation RefreshVerification($emailAddress: String!) {
1022
1468
  refreshCustomerVerification(emailAddress: $emailAddress) {
1023
1469
  ... on Success { success }
@@ -1026,7 +1472,7 @@ export const REFRESH_VERIFICATION = `
1026
1472
  }
1027
1473
  `;
1028
1474
  // --- Address Management ---
1029
- export const CREATE_ADDRESS = `
1475
+ export const CREATE_ADDRESS = /* GraphQL */ `
1030
1476
  mutation CreateAddress($input: CreateAddressInput!) {
1031
1477
  createCustomerAddress(input: $input) {
1032
1478
  id fullName streetLine1 streetLine2 city province postalCode
@@ -1035,7 +1481,7 @@ export const CREATE_ADDRESS = `
1035
1481
  }
1036
1482
  }
1037
1483
  `;
1038
- export const UPDATE_ADDRESS = `
1484
+ export const UPDATE_ADDRESS = /* GraphQL */ `
1039
1485
  mutation UpdateAddress($input: UpdateAddressInput!) {
1040
1486
  updateCustomerAddress(input: $input) {
1041
1487
  id fullName streetLine1 streetLine2 city province postalCode
@@ -1044,7 +1490,7 @@ export const UPDATE_ADDRESS = `
1044
1490
  }
1045
1491
  }
1046
1492
  `;
1047
- export const DELETE_ADDRESS = `
1493
+ export const DELETE_ADDRESS = /* GraphQL */ `
1048
1494
  mutation DeleteAddress($id: ID!) {
1049
1495
  deleteCustomerAddress(id: $id) {
1050
1496
  success
@@ -1052,7 +1498,7 @@ export const DELETE_ADDRESS = `
1052
1498
  }
1053
1499
  `;
1054
1500
  // --- Utility Queries ---
1055
- export const AVAILABLE_COUNTRIES = `
1501
+ export const AVAILABLE_COUNTRIES = /* GraphQL */ `
1056
1502
  query AvailableCountries {
1057
1503
  availableCountries {
1058
1504
  id code name
@@ -1062,30 +1508,38 @@ export const AVAILABLE_COUNTRIES = `
1062
1508
  /**
1063
1509
  * `lines { backorderedQuantity }` is selected HERE and on `GET_CUSTOMER_ORDERS`,
1064
1510
  * and nowhere else — the same rule `customFields { paymentIntent }` follows
1065
- * below. In the shared `ORDER_FIELDS` fragment it would make every cart read
1511
+ * below. In the shared `ORDER_FRAGMENT` fragment it would make every cart read
1066
1512
  * and mutation fail validation against an engine that predates the backorders
1067
1513
  * plugin, taking the whole cart down for a field a cart line never carries a
1068
1514
  * value for (the stamp is written at placement). GraphQL merges this `lines`
1069
1515
  * selection with the fragment's, so the line still comes back whole.
1516
+ *
1517
+ * `customFields { chargedParcelCount }` follows the same rule: frozen when the
1518
+ * order leaves the cart, so it belongs to this placed-order read alone. It
1519
+ * does make this document need an engine with the extra-parcel charge: a
1520
+ * client release carrying it publishes after that engine is deployed.
1070
1521
  */
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}
1522
+ export const ORDER_BY_CODE = withFragments(
1523
+ /* GraphQL */ `
1524
+ query OrderByCode($code: String!) {
1525
+ orderByCode(code: $code) {
1526
+ ...Order
1527
+ lines { id backorderedQuantity }
1528
+ customFields { chargedParcelCount }
1529
+ ...OrderFulfillments
1530
+ ...OrderFulfillmentParcels
1531
+ ...OrderPaymentTerms
1532
+ ...OrderDeliveryTerms
1533
+ }
1079
1534
  }
1080
- }
1081
- `;
1535
+ `, ORDER_FRAGMENT, ORDER_FULFILLMENTS_FRAGMENT, ORDER_FULFILLMENT_PARCELS_FRAGMENT, ORDER_PAYMENT_TERMS_FRAGMENT, ORDER_DELIVERY_TERMS_FRAGMENT);
1082
1536
  // --- Favorites ---
1083
- export const FAVORITE_VARIANT_IDS = `
1537
+ export const FAVORITE_VARIANT_IDS = /* GraphQL */ `
1084
1538
  query FavoriteVariantIds {
1085
1539
  favoriteProductVariantIds
1086
1540
  }
1087
1541
  `;
1088
- export const MY_FAVORITES = `
1542
+ export const MY_FAVORITES = /* GraphQL */ `
1089
1543
  query MyFavorites($options: FavoriteListOptions) {
1090
1544
  myFavorites(options: $options) {
1091
1545
  items {
@@ -1118,12 +1572,12 @@ export const MY_FAVORITES = `
1118
1572
  }
1119
1573
  }
1120
1574
  `;
1121
- export const TOGGLE_FAVORITE = `
1575
+ export const TOGGLE_FAVORITE = /* GraphQL */ `
1122
1576
  mutation ToggleFavorite($productVariantId: ID!) {
1123
1577
  toggleFavorite(productVariantId: $productVariantId)
1124
1578
  }
1125
1579
  `;
1126
- export const REMOVE_FAVORITE = `
1580
+ export const REMOVE_FAVORITE = /* GraphQL */ `
1127
1581
  mutation RemoveFavorite($productVariantId: ID!) {
1128
1582
  removeFavorite(productVariantId: $productVariantId)
1129
1583
  }
@@ -1135,8 +1589,8 @@ export const REMOVE_FAVORITE = `
1135
1589
  * in types.ts and the `public: true` Channel customFields configured on
1136
1590
  * the Vendure side.
1137
1591
  */
1138
- const CHANNEL_CUSTOM_FIELDS_FRAGMENT = `
1139
- customFields {
1592
+ const CHANNEL_CUSTOM_FIELDS_FRAGMENT = fragment(/* GraphQL */ `
1593
+ fragment ChannelCustomFields on ChannelCustomFields {
1140
1594
  businessName businessDescription
1141
1595
  logoAssetId darkLogoAssetId coverAssetId faviconAssetId
1142
1596
  websiteUrl primaryColor
@@ -1152,57 +1606,68 @@ const CHANNEL_CUSTOM_FIELDS_FRAGMENT = `
1152
1606
  returnsEnabled returnWindowDays
1153
1607
  taxDisplayDefault taxDisplayB2b taxExclusiveCountries
1154
1608
  }
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}
1609
+ `);
1610
+ export const GET_ACTIVE_CHANNEL = withFragments(
1611
+ /* GraphQL */ `
1612
+ query ActiveChannel {
1613
+ activeChannel {
1614
+ id code
1615
+ defaultLanguageCode
1616
+ availableLanguageCodes
1617
+ defaultCurrencyCode
1618
+ availableCurrencyCodes
1619
+ customFields { ...ChannelCustomFields }
1620
+ }
1165
1621
  }
1166
- }
1167
- `;
1622
+ `, CHANNEL_CUSTOM_FIELDS_FRAGMENT);
1168
1623
  // --- Product Properties ---
1169
- export const PROPERTY_GROUPS = `
1170
- query PropertyGroups {
1171
- productPropertyGroups {
1624
+ /** Every property group, with each property's full config (`getPropertyGroups`). */
1625
+ export const PROPERTY_GROUP_FRAGMENT = fragment(/* GraphQL */ `
1626
+ fragment PropertyGroup on PropertyGroup {
1627
+ id position
1628
+ translations { id languageCode name }
1629
+ properties {
1630
+ id slug fieldType isFilterable isRequired position
1631
+ config { options { value label } min max maxLength allowedCollectionIds filterableFieldSlugs }
1632
+ facetId
1633
+ fieldFacets { fieldSlug fieldType facetId }
1634
+ translations { id languageCode name helpText }
1635
+ }
1636
+ }
1637
+ `);
1638
+ /** One product's values per group (`getProductProperties`); the group config is narrower. */
1639
+ export const PRODUCT_PROPERTY_GROUP_VALUES_FRAGMENT = fragment(/* GraphQL */ `
1640
+ fragment ProductPropertyGroupValues on ProductPropertyGroupValues {
1641
+ group {
1172
1642
  id position
1173
1643
  translations { id languageCode name }
1174
1644
  properties {
1175
1645
  id slug fieldType isFilterable isRequired position
1176
- config { options { value label } min max maxLength allowedCollectionIds filterableFieldSlugs }
1646
+ config { options { value label } min max maxLength }
1177
1647
  facetId
1178
1648
  fieldFacets { fieldSlug fieldType facetId }
1179
1649
  translations { id languageCode name helpText }
1180
1650
  }
1181
1651
  }
1652
+ values { id propertyId languageCode value }
1182
1653
  }
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 }
1654
+ `);
1655
+ export const PROPERTY_GROUPS = withFragments(
1656
+ /* GraphQL */ `
1657
+ query PropertyGroups {
1658
+ productPropertyGroups { ...PropertyGroup }
1199
1659
  }
1200
- }
1201
- `;
1660
+ `, PROPERTY_GROUP_FRAGMENT);
1661
+ export const PRODUCT_PROPERTIES = withFragments(
1662
+ /* GraphQL */ `
1663
+ query ProductProperties($productId: ID!) {
1664
+ productPropertyValues(productId: $productId) { ...ProductPropertyGroupValues }
1665
+ }
1666
+ `, PRODUCT_PROPERTY_GROUP_VALUES_FRAGMENT);
1202
1667
  // --- Product Recommendations ---
1203
- export const GET_PRODUCT_RECOMMENDATIONS = `
1204
- query ProductRecommendations($productId: ID!, $groupSlug: String) {
1205
- productRecommendations(productId: $productId, groupSlug: $groupSlug) {
1668
+ export const RECOMMENDED_PRODUCT_GROUP_FRAGMENT = fragment(
1669
+ /* GraphQL */ `
1670
+ fragment RecommendedProductGroup on RecommendedProducts {
1206
1671
  groupName
1207
1672
  groupSlug
1208
1673
  products {
@@ -1218,18 +1683,26 @@ export const GET_PRODUCT_RECOMMENDATIONS = `
1218
1683
  stockOnHand stockAllocated saleable
1219
1684
  incomingStock projectedSaleable nextExpectedArrival
1220
1685
  backorderAllowance
1221
- availability { state availableFrom orderable }
1686
+ availability { ...ProductAvailability }
1687
+ forSaleInCurrency
1222
1688
  priceListName retailPrice retailPriceWithTax taxRateApplied { value }
1223
- priceTiers { minQuantity price priceWithTax discountLabel }
1224
- availabilityByLocation { locationId locationName inStock }
1689
+ priceTiers { ...PriceTier }
1690
+ availabilityByLocation { ...VariantLocationAvailability }
1225
1691
  customFields { minOrderQuantity salesUnit position }
1226
1692
  }
1227
1693
  }
1228
1694
  }
1229
- }
1230
- `;
1695
+ `, PRODUCT_AVAILABILITY_FRAGMENT, PRICE_TIER_FRAGMENT, VARIANT_LOCATION_AVAILABILITY_FRAGMENT);
1696
+ export const GET_PRODUCT_RECOMMENDATIONS = withFragments(
1697
+ /* GraphQL */ `
1698
+ query ProductRecommendations($productId: ID!, $groupSlug: String) {
1699
+ productRecommendations(productId: $productId, groupSlug: $groupSlug) {
1700
+ ...RecommendedProductGroup
1701
+ }
1702
+ }
1703
+ `, RECOMMENDED_PRODUCT_GROUP_FRAGMENT);
1231
1704
  // --- Exchange Rates ---
1232
- export const GET_EXCHANGE_RATES = `
1705
+ export const GET_EXCHANGE_RATES = /* GraphQL */ `
1233
1706
  query ExchangeRates {
1234
1707
  exchangeRates {
1235
1708
  baseCurrency targetCurrency rate inverseRate rateDate
@@ -1237,38 +1710,43 @@ export const GET_EXCHANGE_RATES = `
1237
1710
  }
1238
1711
  `;
1239
1712
  // 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}
1713
+ const CONVERTED_AMOUNT_FRAGMENT = fragment(/* GraphQL */ `
1714
+ fragment ConvertedAmount on ConvertedAmount {
1715
+ originalAmount originalCurrency convertedAmount targetCurrency rate rateDate
1716
+ }
1717
+ `);
1718
+ export const CONVERT_CURRENCY = withFragments(
1719
+ /* GraphQL */ `
1720
+ query ConvertCurrency($amount: String!, $from: String!, $to: String!) {
1721
+ convertCurrency(amount: $amount, fromCurrency: $from, toCurrency: $to) {
1722
+ ...ConvertedAmount
1723
+ }
1247
1724
  }
1248
- }
1249
- `;
1250
- export const GET_EXCHANGE_RATE = `
1725
+ `, CONVERTED_AMOUNT_FRAGMENT);
1726
+ export const GET_EXCHANGE_RATE = /* GraphQL */ `
1251
1727
  query ExchangeRate($targetCurrency: String!) {
1252
1728
  exchangeRate(targetCurrency: $targetCurrency) {
1253
1729
  baseCurrency targetCurrency rate inverseRate rateDate
1254
1730
  }
1255
1731
  }
1256
1732
  `;
1257
- export const CONVERT_FROM_BASE = `
1258
- query ConvertFromBase($amount: String!, $targetCurrency: String!) {
1259
- convertFromBase(amount: $amount, targetCurrency: $targetCurrency) {
1260
- ${CONVERTED_AMOUNT_FIELDS}
1733
+ export const CONVERT_FROM_BASE = withFragments(
1734
+ /* GraphQL */ `
1735
+ query ConvertFromBase($amount: String!, $targetCurrency: String!) {
1736
+ convertFromBase(amount: $amount, targetCurrency: $targetCurrency) {
1737
+ ...ConvertedAmount
1738
+ }
1261
1739
  }
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}
1740
+ `, CONVERTED_AMOUNT_FRAGMENT);
1741
+ export const CONVERT_TO_BASE = withFragments(
1742
+ /* GraphQL */ `
1743
+ query ConvertToBase($amount: String!, $sourceCurrency: String!) {
1744
+ convertToBase(amount: $amount, sourceCurrency: $sourceCurrency) {
1745
+ ...ConvertedAmount
1746
+ }
1268
1747
  }
1269
- }
1270
- `;
1271
- export const CONVERT_TO_MULTIPLE = `
1748
+ `, CONVERTED_AMOUNT_FRAGMENT);
1749
+ export const CONVERT_TO_MULTIPLE = /* GraphQL */ `
1272
1750
  query ConvertToMultiple($amount: String!, $from: String!, $to: [String!]!) {
1273
1751
  convertToMultiple(amount: $amount, fromCurrency: $from, toCurrencies: $to) {
1274
1752
  currency amount rate
@@ -1277,69 +1755,106 @@ export const CONVERT_TO_MULTIPLE = `
1277
1755
  `;
1278
1756
  // --- B2B Quotes ---
1279
1757
  /**
1280
- * Per-line tax + product identity. These fields reach the Shop API with the
1758
+ * Per-line tax + product identity (`productName sku taxRate unitPriceWithTax
1759
+ * lineTotal lineTotalWithTax`). These fields reach the Shop API with the
1281
1760
  * `vendure-plugin-quotes` release that introduced them, and the SDK can be
1282
1761
  * upgraded before a tenant's Vendure is: an older server rejects the WHOLE
1283
1762
  * document at validation ("Cannot query field ..."), taking the quote page
1284
1763
  * 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.
1764
+ * twin spreading `QuoteLegacy` instead, and `createQuotesMethods` retries with
1765
+ * it once — see the fallback there. Keep the two fragments identical apart
1766
+ * from that line, and each legacy document identical to its twin apart from
1767
+ * the fragment it spreads and its `Legacy` operation name.
1287
1768
  */
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}
1769
+ const QUOTE_FRAGMENT = fragment(/* GraphQL */ `
1770
+ fragment Quote on Quote {
1771
+ id code channelId customerId currencyCode status
1772
+ expiresAt salesRepUserId customerNotes convertedOrderId
1296
1773
  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
1774
+ lines {
1775
+ id productVariantId quantity unitPrice discountType discountValue discountLabel position
1776
+ productName sku taxRate unitPriceWithTax lineTotal lineTotalWithTax
1777
+ createdAt updatedAt
1306
1778
  }
1307
1779
  }
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} }
1780
+ `);
1781
+ const QUOTE_LEGACY_FRAGMENT = fragment(/* GraphQL */ `
1782
+ fragment QuoteLegacy on Quote {
1783
+ id code channelId customerId currencyCode status
1784
+ expiresAt salesRepUserId customerNotes convertedOrderId
1785
+ createdAt updatedAt
1786
+ lines {
1787
+ id productVariantId quantity unitPrice discountType discountValue discountLabel position
1788
+ createdAt updatedAt
1789
+ }
1333
1790
  }
1334
- `;
1335
- export const CANCEL_MY_QUOTE = cancelMyQuoteDocument(QUOTE_FIELDS);
1336
- export const CANCEL_MY_QUOTE_LEGACY = cancelMyQuoteDocument(QUOTE_FIELDS_LEGACY);
1791
+ `);
1792
+ export const MY_QUOTES = withFragments(
1793
+ /* GraphQL */ `
1794
+ query MyQuotes($options: QuoteListOptions) {
1795
+ myQuotes(options: $options) {
1796
+ items { ...Quote }
1797
+ totalItems
1798
+ }
1799
+ }
1800
+ `, QUOTE_FRAGMENT);
1801
+ export const MY_QUOTES_LEGACY = withFragments(
1802
+ /* GraphQL */ `
1803
+ query MyQuotesLegacy($options: QuoteListOptions) {
1804
+ myQuotes(options: $options) {
1805
+ items { ...QuoteLegacy }
1806
+ totalItems
1807
+ }
1808
+ }
1809
+ `, QUOTE_LEGACY_FRAGMENT);
1810
+ export const MY_QUOTE = withFragments(
1811
+ /* GraphQL */ `
1812
+ query MyQuote($id: ID!) {
1813
+ myQuote(id: $id) { ...Quote }
1814
+ }
1815
+ `, QUOTE_FRAGMENT);
1816
+ export const MY_QUOTE_LEGACY = withFragments(
1817
+ /* GraphQL */ `
1818
+ query MyQuoteLegacy($id: ID!) {
1819
+ myQuote(id: $id) { ...QuoteLegacy }
1820
+ }
1821
+ `, QUOTE_LEGACY_FRAGMENT);
1822
+ export const CREATE_QUOTE_REQUEST = withFragments(
1823
+ /* GraphQL */ `
1824
+ mutation CreateQuoteRequest($input: CreateQuoteRequestInput!) {
1825
+ createQuoteRequest(input: $input) { ...Quote }
1826
+ }
1827
+ `, QUOTE_FRAGMENT);
1828
+ export const CREATE_QUOTE_REQUEST_LEGACY = withFragments(
1829
+ /* GraphQL */ `
1830
+ mutation CreateQuoteRequestLegacy($input: CreateQuoteRequestInput!) {
1831
+ createQuoteRequest(input: $input) { ...QuoteLegacy }
1832
+ }
1833
+ `, QUOTE_LEGACY_FRAGMENT);
1834
+ export const ACCEPT_QUOTE = withFragments(
1835
+ /* GraphQL */ `
1836
+ mutation AcceptQuote($id: ID!) {
1837
+ acceptQuote(id: $id) { ...Order }
1838
+ }
1839
+ `, ORDER_FRAGMENT);
1840
+ export const CANCEL_MY_QUOTE = withFragments(
1841
+ /* GraphQL */ `
1842
+ mutation CancelMyQuote($id: ID!, $reason: String) {
1843
+ cancelMyQuote(id: $id, reason: $reason) { ...Quote }
1844
+ }
1845
+ `, QUOTE_FRAGMENT);
1846
+ export const CANCEL_MY_QUOTE_LEGACY = withFragments(
1847
+ /* GraphQL */ `
1848
+ mutation CancelMyQuoteLegacy($id: ID!, $reason: String) {
1849
+ cancelMyQuote(id: $id, reason: $reason) { ...QuoteLegacy }
1850
+ }
1851
+ `, QUOTE_LEGACY_FRAGMENT);
1337
1852
  /**
1338
1853
  * Single-roundtrip branding query. activeChannel + fontResources (with
1339
1854
  * resolved file Assets) + brandingAssets for the channel-level logo, favicon,
1340
1855
  * and cover IDs already on ctx.channel.customFields.
1341
1856
  */
1342
- export const GET_BRANDING = `
1857
+ export const GET_BRANDING = /* GraphQL */ `
1343
1858
  query GetBranding($ids: [ID!]!) {
1344
1859
  activeChannel {
1345
1860
  id
@@ -1369,7 +1884,7 @@ export const GET_BRANDING = `
1369
1884
  }
1370
1885
  `;
1371
1886
  // --- Order constraints (inline order-constraints plugin) ---
1372
- export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = `
1887
+ export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = /* GraphQL */ `
1373
1888
  query ActiveChannelOrderConstraints {
1374
1889
  activeChannelOrderConstraints {
1375
1890
  minOrderAmountGross
@@ -1382,76 +1897,104 @@ export const ACTIVE_CHANNEL_ORDER_CONSTRAINTS = `
1382
1897
  }
1383
1898
  `;
1384
1899
  // --- Customer invoices (vendure-plugin-order-documents shop surface) ---
1385
- export const MY_ORDER_INVOICES = `
1900
+ export const MY_ORDER_INVOICES = /* GraphQL */ `
1386
1901
  query MyOrderInvoices($orderCode: String!) {
1387
1902
  myOrderInvoices(orderCode: $orderCode) {
1388
1903
  id invoiceNumber invoicedOn totalWithTax currencyCode languageCode createdAt
1389
1904
  }
1390
1905
  }
1391
1906
  `;
1392
- export const MY_INVOICE_PDF = `
1907
+ export const MY_INVOICE_PDF = /* GraphQL */ `
1393
1908
  query MyInvoicePdf($invoiceId: ID!) {
1394
1909
  myInvoicePdf(invoiceId: $invoiceId) {
1395
1910
  base64 filename invoiceNumber
1396
1911
  }
1397
1912
  }
1398
1913
  `;
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
1914
+ export const CREATE_INVOICE_DOWNLOAD_URL = /* GraphQL */ `
1915
+ mutation CreateInvoiceDownloadUrl($invoiceId: ID!) {
1916
+ createInvoiceDownloadUrl(invoiceId: $invoiceId) {
1917
+ url expiresAt filename invoiceNumber
1918
+ }
1417
1919
  }
1418
1920
  `;
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
1921
+ // --- Customer credit notes (vendure-plugin-order-documents shop surface) ---
1922
+ export const MY_ORDER_CREDIT_NOTES = /* GraphQL */ `
1923
+ query MyOrderCreditNotes($orderCode: String!) {
1924
+ myOrderCreditNotes(orderCode: $orderCode) {
1925
+ id creditNoteNumber issuedOn totalWithTax currencyCode kind reason invoiceNumber createdAt
1424
1926
  }
1425
1927
  }
1426
1928
  `;
1427
- export const MY_RETURN = `
1428
- query MyReturn($id: ID!) {
1429
- myReturn(id: $id) { ${RETURN_FIELDS} }
1929
+ export const CREATE_CREDIT_NOTE_DOWNLOAD_URL = /* GraphQL */ `
1930
+ mutation CreateCreditNoteDownloadUrl($creditNoteId: ID!) {
1931
+ createCreditNoteDownloadUrl(creditNoteId: $creditNoteId) {
1932
+ url expiresAt filename creditNoteNumber
1933
+ }
1430
1934
  }
1431
1935
  `;
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
1936
+ // --- Order returns (vendure-plugin-returns shop surface) ---
1937
+ /**
1938
+ * Shared selection set for customer-facing OrderReturn objects. The Shop API
1939
+ * never exposes the admin-only fields (`adminNote`, `history`) — do not add
1940
+ * them here. Money values are Int minor units.
1941
+ */
1942
+ const CUSTOMER_RETURN_FRAGMENT = fragment(/* GraphQL */ `
1943
+ fragment CustomerReturn on OrderReturn {
1944
+ id code state
1945
+ orderId orderCode currencyCode
1946
+ preferredSettlementMethod settlementMethod
1947
+ shippingRefundAmount settledAmount
1948
+ customerNote requestedAt resolvedAt createdAt
1949
+ lines {
1950
+ id orderLineId
1951
+ productVariantId productVariantName productVariantSku
1952
+ requestedQty approvedQty receivedQty restockQty writeOffQty
1953
+ reasonCode reasonNote
1954
+ unitPriceWithTax unitPriceWithTaxUnrounded refundAmount
1955
+ }
1956
+ }
1957
+ `);
1958
+ export const MY_RETURNS = withFragments(
1959
+ /* GraphQL */ `
1960
+ query MyReturns($take: Int, $skip: Int) {
1961
+ myReturns(options: { take: $take, skip: $skip }) {
1962
+ items { ...CustomerReturn }
1963
+ totalItems
1445
1964
  }
1446
- ) { ${RETURN_FIELDS} }
1447
- }
1448
- `;
1449
- export const CANCEL_MY_RETURN = `
1450
- mutation CancelMyReturn($id: ID!) {
1451
- cancelMyReturn(id: $id) { ${RETURN_FIELDS} }
1452
- }
1453
- `;
1454
- export const RETURNABLE_LINES_FOR_ORDER = `
1965
+ }
1966
+ `, CUSTOMER_RETURN_FRAGMENT);
1967
+ export const MY_RETURN = withFragments(
1968
+ /* GraphQL */ `
1969
+ query MyReturn($id: ID!) {
1970
+ myReturn(id: $id) { ...CustomerReturn }
1971
+ }
1972
+ `, CUSTOMER_RETURN_FRAGMENT);
1973
+ export const REQUEST_RETURN = withFragments(
1974
+ /* GraphQL */ `
1975
+ mutation RequestReturn(
1976
+ $orderId: ID!
1977
+ $lines: [ReturnRequestLineInput!]!
1978
+ $customerNote: String
1979
+ $preferredSettlementMethod: OrderReturnSettlementMethod
1980
+ ) {
1981
+ requestReturn(
1982
+ input: {
1983
+ orderId: $orderId
1984
+ lines: $lines
1985
+ customerNote: $customerNote
1986
+ preferredSettlementMethod: $preferredSettlementMethod
1987
+ }
1988
+ ) { ...CustomerReturn }
1989
+ }
1990
+ `, CUSTOMER_RETURN_FRAGMENT);
1991
+ export const CANCEL_MY_RETURN = withFragments(
1992
+ /* GraphQL */ `
1993
+ mutation CancelMyReturn($id: ID!) {
1994
+ cancelMyReturn(id: $id) { ...CustomerReturn }
1995
+ }
1996
+ `, CUSTOMER_RETURN_FRAGMENT);
1997
+ export const RETURNABLE_LINES_FOR_ORDER = /* GraphQL */ `
1455
1998
  query ReturnableLinesForOrder($orderId: ID!) {
1456
1999
  returnableLinesForOrder(orderId: $orderId) {
1457
2000
  orderId eligible reason returnWindowEndsAt