@shopify/hydrogen 2026.10.0-preview.3 → 2026.10.0-preview.4

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 (380) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/index.mjs +131 -29
  3. package/dist/client/client.mjs +2 -2
  4. package/dist/client/errors.d.mts +19 -19
  5. package/dist/client/errors.mjs +19 -16
  6. package/dist/client/errors.mjs.map +1 -1
  7. package/dist/client/types.d.mts +91 -10
  8. package/dist/core/analytics/cart-tracker.d.mts +14 -0
  9. package/dist/core/analytics/cart-tracker.mjs +15 -1
  10. package/dist/core/analytics/cart-tracker.mjs.map +1 -1
  11. package/dist/core/analytics/custom-consent.mjs +12 -0
  12. package/dist/core/analytics/custom-consent.mjs.map +1 -0
  13. package/dist/core/analytics/events.d.mts +7 -0
  14. package/dist/core/analytics/events.mjs +7 -0
  15. package/dist/core/analytics/events.mjs.map +1 -1
  16. package/dist/core/analytics/index.d.mts +1 -1
  17. package/dist/core/analytics/types.d.mts +152 -16
  18. package/dist/core/cart/actions.d.mts +47 -3
  19. package/dist/core/cart/actions.mjs +27 -0
  20. package/dist/core/cart/actions.mjs.map +1 -1
  21. package/dist/core/cart/attach-quantity-input.d.mts +26 -0
  22. package/dist/core/cart/attach-quantity-input.mjs +26 -0
  23. package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
  24. package/dist/core/cart/cart.d.mts +106 -6
  25. package/dist/core/cart/cart.mjs +41 -0
  26. package/dist/core/cart/cart.mjs.map +1 -1
  27. package/dist/core/cart/cookie.d.mts +15 -0
  28. package/dist/core/cart/cookie.mjs +15 -0
  29. package/dist/core/cart/cookie.mjs.map +1 -1
  30. package/dist/core/cart/form.d.mts +61 -0
  31. package/dist/core/cart/form.mjs +18 -0
  32. package/dist/core/cart/form.mjs.map +1 -1
  33. package/dist/core/cart/get-cart.d.mts +43 -2
  34. package/dist/core/cart/get-cart.mjs +33 -0
  35. package/dist/core/cart/get-cart.mjs.map +1 -1
  36. package/dist/core/cart/index.d.mts +1 -1
  37. package/dist/core/cart/quantity.d.mts +17 -0
  38. package/dist/core/cart/quantity.mjs +17 -0
  39. package/dist/core/cart/quantity.mjs.map +1 -1
  40. package/dist/core/cart/queries.d.mts +402 -369
  41. package/dist/core/cart/queries.mjs +2 -1
  42. package/dist/core/cart/queries.mjs.map +1 -1
  43. package/dist/core/cart/server-handlers.d.mts +69 -0
  44. package/dist/core/cart/server-handlers.mjs +2 -10
  45. package/dist/core/cart/server-handlers.mjs.map +1 -1
  46. package/dist/core/cart/state.d.mts +133 -0
  47. package/dist/core/cart/state.mjs +8 -0
  48. package/dist/core/cart/state.mjs.map +1 -1
  49. package/dist/core/collection/collection.d.mts +18 -2
  50. package/dist/core/collection/collection.mjs +11 -0
  51. package/dist/core/collection/collection.mjs.map +1 -1
  52. package/dist/core/collection/index.d.mts +1 -1
  53. package/dist/core/collection/reconciler.d.mts +13 -4
  54. package/dist/core/collection/reconciler.mjs.map +1 -1
  55. package/dist/core/collection/state.d.mts +7 -2
  56. package/dist/core/collection/state.mjs.map +1 -1
  57. package/dist/core/collection/url.d.mts +3 -0
  58. package/dist/core/collection/url.mjs.map +1 -1
  59. package/dist/core/constants.d.mts +1 -1
  60. package/dist/core/constants.mjs +2 -2
  61. package/dist/core/constants.mjs.map +1 -1
  62. package/dist/core/headers.mjs +2 -2
  63. package/dist/core/headers.mjs.map +1 -1
  64. package/dist/core/index.d.mts +5 -5
  65. package/dist/core/logging/logging.mjs.map +1 -1
  66. package/dist/core/money/format.mjs +6 -3
  67. package/dist/core/money/format.mjs.map +1 -1
  68. package/dist/core/observable.mjs +0 -3
  69. package/dist/core/observable.mjs.map +1 -1
  70. package/dist/core/predictive-search/form.d.mts +1 -0
  71. package/dist/core/predictive-search/form.mjs +1 -0
  72. package/dist/core/predictive-search/form.mjs.map +1 -1
  73. package/dist/core/predictive-search/index.d.mts +1 -1
  74. package/dist/core/predictive-search/queries.d.mts +40 -4
  75. package/dist/core/predictive-search/queries.mjs +7 -1
  76. package/dist/core/predictive-search/queries.mjs.map +1 -1
  77. package/dist/core/predictive-search/search.d.mts +43 -10
  78. package/dist/core/predictive-search/search.mjs +34 -0
  79. package/dist/core/predictive-search/search.mjs.map +1 -1
  80. package/dist/core/predictive-search/server-handlers.d.mts +31 -5
  81. package/dist/core/predictive-search/server-handlers.mjs +5 -3
  82. package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
  83. package/dist/core/predictive-search/store.d.mts +3 -1
  84. package/dist/core/predictive-search/store.mjs.map +1 -1
  85. package/dist/core/predictive-search/url.d.mts +50 -8
  86. package/dist/core/predictive-search/url.mjs +9 -0
  87. package/dist/core/predictive-search/url.mjs.map +1 -1
  88. package/dist/core/product/options.d.mts +2 -2
  89. package/dist/core/product/options.mjs +2 -2
  90. package/dist/core/product/options.mjs.map +1 -1
  91. package/dist/core/product/product-form.d.mts +33 -1
  92. package/dist/core/product/product-form.mjs +30 -0
  93. package/dist/core/product/product-form.mjs.map +1 -1
  94. package/dist/core/product/state.d.mts +41 -0
  95. package/dist/core/product/url.d.mts +6 -0
  96. package/dist/core/product/url.mjs.map +1 -1
  97. package/dist/core/request-context.d.mts +2 -5
  98. package/dist/core/request-context.mjs +13 -39
  99. package/dist/core/request-context.mjs.map +1 -1
  100. package/dist/core/request-routing/handle-shopify-routes.mjs +2 -1
  101. package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  102. package/dist/core/request-routing/interceptors/ajax-api.mjs +1 -1
  103. package/dist/core/request-routing/interceptors/api-proxy.mjs +1 -1
  104. package/dist/core/request-routing/interceptors/checkout.mjs +19 -6
  105. package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -1
  106. package/dist/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
  107. package/dist/core/request-routing/interceptors/proxy.mjs +20 -5
  108. package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
  109. package/dist/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
  110. package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
  111. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
  112. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
  113. package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
  114. package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
  115. package/dist/core/shopify-scripts/analytics.mjs +2 -2
  116. package/dist/core/shopify-scripts/analytics.mjs.map +1 -1
  117. package/dist/core/shopify-scripts/constants.mjs +1 -1
  118. package/dist/core/shopify-scripts/constants.mjs.map +1 -1
  119. package/dist/core/shopify-scripts/global.mjs +5 -1
  120. package/dist/core/shopify-scripts/global.mjs.map +1 -1
  121. package/dist/core/shopify-scripts/initialize.d.mts +1 -0
  122. package/dist/core/shopify-scripts/initialize.mjs +10 -3
  123. package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
  124. package/dist/core/shopify-scripts/types.d.mts +1 -0
  125. package/dist/core/url.mjs +20 -2
  126. package/dist/core/url.mjs.map +1 -1
  127. package/dist/customer-account/client.d.mts +128 -4
  128. package/dist/customer-account/client.mjs +27 -1
  129. package/dist/customer-account/client.mjs.map +1 -1
  130. package/dist/customer-account/errors.d.mts +46 -0
  131. package/dist/customer-account/errors.mjs +46 -0
  132. package/dist/customer-account/errors.mjs.map +1 -1
  133. package/dist/customer-account/graphql.d.mts +68 -0
  134. package/dist/customer-account/graphql.mjs +47 -0
  135. package/dist/customer-account/graphql.mjs.map +1 -1
  136. package/dist/customer-account/session.d.mts +114 -23
  137. package/dist/customer-account/session.mjs +27 -12
  138. package/dist/customer-account/session.mjs.map +1 -1
  139. package/dist/customer-account/type-resolver.d.mts +23 -0
  140. package/dist/customer-account-api-types.d.ts +570 -374
  141. package/dist/customer-account.schema.json +2981 -1527
  142. package/dist/development/client/client.mjs +2 -2
  143. package/dist/development/client/errors.d.mts +19 -19
  144. package/dist/development/client/errors.mjs +20 -20
  145. package/dist/development/client/errors.mjs.map +1 -1
  146. package/dist/development/client/types.d.mts +91 -10
  147. package/dist/development/core/analytics/cart-tracker.d.mts +14 -0
  148. package/dist/development/core/analytics/cart-tracker.mjs +15 -1
  149. package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
  150. package/dist/development/core/analytics/custom-consent.mjs +12 -0
  151. package/dist/development/core/analytics/custom-consent.mjs.map +1 -0
  152. package/dist/development/core/analytics/events.d.mts +7 -0
  153. package/dist/development/core/analytics/events.mjs +7 -0
  154. package/dist/development/core/analytics/events.mjs.map +1 -1
  155. package/dist/development/core/analytics/index.d.mts +1 -1
  156. package/dist/development/core/analytics/types.d.mts +152 -16
  157. package/dist/development/core/cart/actions.d.mts +47 -3
  158. package/dist/development/core/cart/actions.mjs +27 -0
  159. package/dist/development/core/cart/actions.mjs.map +1 -1
  160. package/dist/development/core/cart/attach-quantity-input.d.mts +26 -0
  161. package/dist/development/core/cart/attach-quantity-input.mjs +26 -0
  162. package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
  163. package/dist/development/core/cart/cart.d.mts +106 -6
  164. package/dist/development/core/cart/cart.mjs +41 -0
  165. package/dist/development/core/cart/cart.mjs.map +1 -1
  166. package/dist/development/core/cart/cookie.d.mts +15 -0
  167. package/dist/development/core/cart/cookie.mjs +15 -0
  168. package/dist/development/core/cart/cookie.mjs.map +1 -1
  169. package/dist/development/core/cart/form.d.mts +61 -0
  170. package/dist/development/core/cart/form.mjs +18 -0
  171. package/dist/development/core/cart/form.mjs.map +1 -1
  172. package/dist/development/core/cart/get-cart.d.mts +43 -2
  173. package/dist/development/core/cart/get-cart.mjs +33 -0
  174. package/dist/development/core/cart/get-cart.mjs.map +1 -1
  175. package/dist/development/core/cart/index.d.mts +1 -1
  176. package/dist/development/core/cart/quantity.d.mts +17 -0
  177. package/dist/development/core/cart/quantity.mjs +17 -0
  178. package/dist/development/core/cart/quantity.mjs.map +1 -1
  179. package/dist/development/core/cart/queries.d.mts +402 -369
  180. package/dist/development/core/cart/queries.mjs +2 -1
  181. package/dist/development/core/cart/queries.mjs.map +1 -1
  182. package/dist/development/core/cart/server-handlers.d.mts +69 -0
  183. package/dist/development/core/cart/server-handlers.mjs +2 -10
  184. package/dist/development/core/cart/server-handlers.mjs.map +1 -1
  185. package/dist/development/core/cart/state.d.mts +133 -0
  186. package/dist/development/core/cart/state.mjs +8 -0
  187. package/dist/development/core/cart/state.mjs.map +1 -1
  188. package/dist/development/core/collection/collection.d.mts +18 -2
  189. package/dist/development/core/collection/collection.mjs +11 -0
  190. package/dist/development/core/collection/collection.mjs.map +1 -1
  191. package/dist/development/core/collection/index.d.mts +1 -1
  192. package/dist/development/core/collection/reconciler.d.mts +13 -4
  193. package/dist/development/core/collection/reconciler.mjs.map +1 -1
  194. package/dist/development/core/collection/state.d.mts +7 -2
  195. package/dist/development/core/collection/state.mjs.map +1 -1
  196. package/dist/development/core/collection/url.d.mts +3 -0
  197. package/dist/development/core/collection/url.mjs.map +1 -1
  198. package/dist/development/core/constants.mjs +1 -1
  199. package/dist/development/core/constants.mjs.map +1 -1
  200. package/dist/development/core/development.d.mts +5 -5
  201. package/dist/development/core/headers.mjs +2 -2
  202. package/dist/development/core/headers.mjs.map +1 -1
  203. package/dist/development/core/index.d.mts +4 -4
  204. package/dist/development/core/logging/logging.mjs.map +1 -1
  205. package/dist/development/core/money/format.mjs +6 -3
  206. package/dist/development/core/money/format.mjs.map +1 -1
  207. package/dist/development/core/observable.mjs +0 -3
  208. package/dist/development/core/observable.mjs.map +1 -1
  209. package/dist/development/core/predictive-search/form.d.mts +1 -0
  210. package/dist/development/core/predictive-search/form.mjs +1 -0
  211. package/dist/development/core/predictive-search/form.mjs.map +1 -1
  212. package/dist/development/core/predictive-search/index.d.mts +1 -1
  213. package/dist/development/core/predictive-search/queries.d.mts +40 -4
  214. package/dist/development/core/predictive-search/queries.mjs +7 -1
  215. package/dist/development/core/predictive-search/queries.mjs.map +1 -1
  216. package/dist/development/core/predictive-search/search.d.mts +43 -10
  217. package/dist/development/core/predictive-search/search.mjs +34 -0
  218. package/dist/development/core/predictive-search/search.mjs.map +1 -1
  219. package/dist/development/core/predictive-search/server-handlers.d.mts +31 -5
  220. package/dist/development/core/predictive-search/server-handlers.mjs +5 -3
  221. package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
  222. package/dist/development/core/predictive-search/store.d.mts +3 -1
  223. package/dist/development/core/predictive-search/store.mjs.map +1 -1
  224. package/dist/development/core/predictive-search/url.d.mts +50 -8
  225. package/dist/development/core/predictive-search/url.mjs +9 -0
  226. package/dist/development/core/predictive-search/url.mjs.map +1 -1
  227. package/dist/development/core/product/options.d.mts +2 -2
  228. package/dist/development/core/product/options.mjs +2 -2
  229. package/dist/development/core/product/options.mjs.map +1 -1
  230. package/dist/development/core/product/product-form.d.mts +33 -1
  231. package/dist/development/core/product/product-form.mjs +30 -0
  232. package/dist/development/core/product/product-form.mjs.map +1 -1
  233. package/dist/development/core/product/state.d.mts +41 -0
  234. package/dist/development/core/product/url.d.mts +6 -0
  235. package/dist/development/core/product/url.mjs.map +1 -1
  236. package/dist/development/core/request-context.d.mts +2 -5
  237. package/dist/development/core/request-context.mjs +13 -39
  238. package/dist/development/core/request-context.mjs.map +1 -1
  239. package/dist/development/core/request-routing/handle-shopify-routes.mjs +2 -1
  240. package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  241. package/dist/development/core/request-routing/interceptors/ajax-api.mjs +1 -1
  242. package/dist/development/core/request-routing/interceptors/api-proxy.mjs +1 -1
  243. package/dist/development/core/request-routing/interceptors/checkout.mjs +19 -6
  244. package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -1
  245. package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
  246. package/dist/development/core/request-routing/interceptors/proxy.mjs +20 -5
  247. package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
  248. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
  249. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
  250. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
  251. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
  252. package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
  253. package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
  254. package/dist/development/core/shopify-scripts/analytics.mjs +2 -2
  255. package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -1
  256. package/dist/development/core/shopify-scripts/constants.mjs +1 -1
  257. package/dist/development/core/shopify-scripts/constants.mjs.map +1 -1
  258. package/dist/development/core/shopify-scripts/global.mjs +5 -1
  259. package/dist/development/core/shopify-scripts/global.mjs.map +1 -1
  260. package/dist/development/core/shopify-scripts/initialize.d.mts +1 -0
  261. package/dist/development/core/shopify-scripts/initialize.mjs +10 -3
  262. package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
  263. package/dist/development/core/shopify-scripts/types.d.mts +1 -0
  264. package/dist/development/core/url.mjs +20 -2
  265. package/dist/development/core/url.mjs.map +1 -1
  266. package/dist/development/customer-account/session.d.mts +69 -13
  267. package/dist/development/customer-account/session.mjs +4 -0
  268. package/dist/development/customer-account/session.mjs.map +1 -1
  269. package/dist/development/globals.d.mts +2 -4
  270. package/dist/development/graphql/generated/graphql-env.d.mts +459 -16
  271. package/dist/development/graphql/generated/storefront-api-types.d.mts +1 -1
  272. package/dist/development/graphql/graphql.d.mts +33 -0
  273. package/dist/development/graphql/graphql.mjs +30 -0
  274. package/dist/development/graphql/graphql.mjs.map +1 -1
  275. package/dist/development/graphql/type-resolver.d.mts +14 -0
  276. package/dist/development/react/cart.d.mts +85 -14
  277. package/dist/development/react/cart.mjs +123 -3
  278. package/dist/development/react/cart.mjs.map +1 -1
  279. package/dist/development/react/collection.d.mts +2 -4
  280. package/dist/development/react/collection.mjs.map +1 -1
  281. package/dist/development/react/index.d.mts +7 -5
  282. package/dist/development/react/index.mjs +2 -2
  283. package/dist/development/react/predictive-search.d.mts +68 -7
  284. package/dist/development/react/predictive-search.mjs +54 -12
  285. package/dist/development/react/predictive-search.mjs.map +1 -1
  286. package/dist/development/react/product.d.mts +1 -0
  287. package/dist/development/react/product.mjs +5 -2
  288. package/dist/development/react/product.mjs.map +1 -1
  289. package/dist/development/react/shopify-scripts.mjs +1 -0
  290. package/dist/development/react/shopify-scripts.mjs.map +1 -1
  291. package/dist/development/vue/cart.d.mts +85 -6
  292. package/dist/development/vue/cart.mjs +95 -0
  293. package/dist/development/vue/cart.mjs.map +1 -1
  294. package/dist/development/vue/collection.d.mts +83 -5
  295. package/dist/development/vue/collection.mjs +52 -0
  296. package/dist/development/vue/collection.mjs.map +1 -1
  297. package/dist/development/vue/index.d.mts +6 -4
  298. package/dist/development/vue/predictive-search.d.mts +53 -6
  299. package/dist/development/vue/predictive-search.mjs +33 -0
  300. package/dist/development/vue/predictive-search.mjs.map +1 -1
  301. package/dist/development/vue/product.d.mts +6 -2
  302. package/dist/development/vue/product.mjs.map +1 -1
  303. package/dist/development/vue/shopify-scripts.d.mts +21 -3
  304. package/dist/development/vue/shopify-scripts.mjs +1 -0
  305. package/dist/development/vue/shopify-scripts.mjs.map +1 -1
  306. package/dist/globals.d.mts +2 -4
  307. package/dist/graphql/generated/customer-account-graphql-env.d.mts +1717 -1090
  308. package/dist/graphql/generated/graphql-env.d.mts +459 -16
  309. package/dist/graphql/generated/storefront-api-types.d.mts +1 -1
  310. package/dist/graphql/graphql.d.mts +33 -0
  311. package/dist/graphql/graphql.mjs +30 -0
  312. package/dist/graphql/graphql.mjs.map +1 -1
  313. package/dist/graphql/type-resolver.d.mts +14 -0
  314. package/dist/react/cart.d.mts +85 -14
  315. package/dist/react/cart.mjs +123 -3
  316. package/dist/react/cart.mjs.map +1 -1
  317. package/dist/react/collection.d.mts +2 -4
  318. package/dist/react/collection.mjs.map +1 -1
  319. package/dist/react/index.d.mts +7 -5
  320. package/dist/react/index.mjs +2 -2
  321. package/dist/react/predictive-search.d.mts +68 -7
  322. package/dist/react/predictive-search.mjs +54 -12
  323. package/dist/react/predictive-search.mjs.map +1 -1
  324. package/dist/react/product.d.mts +1 -0
  325. package/dist/react/product.mjs +5 -2
  326. package/dist/react/product.mjs.map +1 -1
  327. package/dist/react/shopify-scripts.mjs +1 -0
  328. package/dist/react/shopify-scripts.mjs.map +1 -1
  329. package/dist/storefront-api-types.d.ts +165 -20
  330. package/dist/storefront.schema.json +782 -57
  331. package/dist/vite/customer-account.mjs +191 -0
  332. package/dist/vite/customer-account.mjs.map +1 -0
  333. package/dist/vite/local-https.mjs +13 -29
  334. package/dist/vite/local-https.mjs.map +1 -1
  335. package/dist/vite/mkcert.mjs +1 -1
  336. package/dist/vue/cart.d.mts +85 -6
  337. package/dist/vue/cart.mjs +95 -0
  338. package/dist/vue/cart.mjs.map +1 -1
  339. package/dist/vue/collection.d.mts +83 -5
  340. package/dist/vue/collection.mjs +52 -0
  341. package/dist/vue/collection.mjs.map +1 -1
  342. package/dist/vue/index.d.mts +6 -4
  343. package/dist/vue/predictive-search.d.mts +53 -6
  344. package/dist/vue/predictive-search.mjs +33 -0
  345. package/dist/vue/predictive-search.mjs.map +1 -1
  346. package/dist/vue/product.d.mts +6 -2
  347. package/dist/vue/product.mjs.map +1 -1
  348. package/dist/vue/shopify-scripts.d.mts +21 -3
  349. package/dist/vue/shopify-scripts.mjs +1 -0
  350. package/dist/vue/shopify-scripts.mjs.map +1 -1
  351. package/package.json +5 -2
  352. package/skills/hydrogen-analytics/SKILL.md +6 -5
  353. package/skills/hydrogen-analytics/references/custom-consent.md +52 -0
  354. package/skills/hydrogen-analytics/references/react.md +1 -1
  355. package/skills/hydrogen-customer-account/SKILL.md +3 -3
  356. package/skills/hydrogen-local-https/SKILL.md +22 -7
  357. package/skills/hydrogen-request-handlers/SKILL.md +5 -5
  358. package/skills/hydrogen-request-handlers/references/nuxt.md +0 -6
  359. package/skills/hydrogen-setup/references/analytics.md +24 -23
  360. package/skills/hydrogen-setup/steps/1-inspect-app.md +1 -1
  361. package/skills/hydrogen-setup/steps/2-scaffold.md +1 -1
  362. package/skills/hydrogen-smoke-test/SKILL.md +2 -2
  363. package/skills/hydrogen-storefront-client/SKILL.md +0 -2
  364. package/ts-plugin/package.json +5 -0
  365. package/dist/core/shopify-scripts/deprecated-cookies.mjs +0 -98
  366. package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
  367. package/dist/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
  368. package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
  369. package/dist/core/shopify-scripts/utils/tracking-values.mjs +0 -65
  370. package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
  371. package/dist/core/shopify-scripts/utils/uuid.mjs +0 -17
  372. package/dist/core/shopify-scripts/utils/uuid.mjs.map +0 -1
  373. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +0 -98
  374. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
  375. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
  376. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
  377. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +0 -65
  378. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
  379. package/dist/development/core/shopify-scripts/utils/uuid.mjs +0 -17
  380. package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +0 -1
@@ -7,7 +7,7 @@ const CART_FRAGMENT_CONTRACT = {
7
7
  typeName: "Cart"
8
8
  };
9
9
  const CART_FRAGMENT_PATTERN = createFragmentPattern(CART_FRAGMENT_CONTRACT);
10
- const HYDROGEN_CART_FRAGMENT = gql(`fragment HydrogenCartFragment on Cart{id checkoutUrl totalQuantity note attributes{key value}cost{subtotalAmount{amount currencyCode}totalAmount{amount currencyCode}checkoutChargeAmount{amount currencyCode}}lines(first:250){nodes{id quantity attributes{key value}cost{totalAmount{amount currencyCode}subtotalAmount{amount currencyCode}amountPerQuantity{amount currencyCode}compareAtAmountPerQuantity{amount currencyCode}}merchandise{...on ProductVariant{id title sku image{id url altText width height}product{id title handle vendor productType}selectedOptions{name value}}}sellingPlanAllocation{sellingPlan{id}}...on CartLine{parentRelationship{parent{id}}}}}discountCodes{applicable code}}`);
10
+ const HYDROGEN_CART_FRAGMENT = gql(`fragment HydrogenCartFragment on Cart{id updatedAt checkoutUrl totalQuantity note attributes{key value}cost{subtotalAmount{amount currencyCode}totalAmount{amount currencyCode}checkoutChargeAmount{amount currencyCode}}lines(first:250){nodes{id quantity attributes{key value}cost{totalAmount{amount currencyCode}subtotalAmount{amount currencyCode}amountPerQuantity{amount currencyCode}compareAtAmountPerQuantity{amount currencyCode}}merchandise{...on ProductVariant{id title sku image{id url altText width height}product{id title handle vendor productType}selectedOptions{name value}}}sellingPlanAllocation{sellingPlan{id}}...on CartLine{parentRelationship{parent{id}}}}}discountCodes{applicable code}}`);
11
11
  const CART_QUERY = gql(`query Cart($id:ID!$country:CountryCode$language:LanguageCode)@inContext(country:$country language:$language){cart(id:$id){...HydrogenCartFragment}}`, [HYDROGEN_CART_FRAGMENT]);
12
12
  const CART_CREATE_MUTATION = gql(`mutation CartCreate($input:CartInput!$country:CountryCode$language:LanguageCode)@inContext(country:$country language:$language){cartCreate(input:$input){cart{...HydrogenCartFragment}userErrors{code field message}warnings{code message target}}}`, [HYDROGEN_CART_FRAGMENT]);
13
13
  const CART_LINES_ADD_MUTATION = gql(`mutation CartLinesAdd($cartId:ID!$lines:[CartLineInput!]!$country:CountryCode$language:LanguageCode)@inContext(country:$country language:$language){cartLinesAdd(cartId:$cartId lines:$lines){cart{...HydrogenCartFragment}userErrors{code field message}warnings{code message target}}}`, [HYDROGEN_CART_FRAGMENT]);
@@ -63,6 +63,7 @@ function makeCartQueries(options) {
63
63
  }
64
64
  return DEFAULT_CART_QUERIES;
65
65
  }
66
+ /** Default cart GraphQL queries and mutations. */
66
67
  const cartQueries = makeCartQueries();
67
68
 
68
69
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"queries.mjs","names":[],"sources":["../../../src/core/cart/queries.ts"],"sourcesContent":["import {\n gql,\n type AnyStorefrontQueryString,\n type ComposedSource,\n type SourceOf,\n type StorefrontQueryString,\n} from \"../../graphql\";\nimport type { InferResult, InferVariables } from \"../../graphql\";\nimport type { CartData, CartLineConnection } from \"./state\";\n\nconst CART_FRAGMENT_NAME = \"CartFragment\";\nconst CART_FRAGMENT_TYPE = \"Cart\";\n\ntype FragmentContract = {\n readonly name: string;\n readonly typeName: string;\n};\n\nconst CART_FRAGMENT_CONTRACT = {\n name: CART_FRAGMENT_NAME,\n typeName: CART_FRAGMENT_TYPE,\n} as const satisfies FragmentContract;\n\nconst CART_FRAGMENT_PATTERN = createFragmentPattern(CART_FRAGMENT_CONTRACT);\n\nconst HYDROGEN_CART_FRAGMENT = gql(`\n fragment HydrogenCartFragment on Cart {\n id\n checkoutUrl\n totalQuantity\n note\n attributes {\n key\n value\n }\n cost {\n subtotalAmount {\n amount\n currencyCode\n }\n totalAmount {\n amount\n currencyCode\n }\n checkoutChargeAmount {\n amount\n currencyCode\n }\n }\n lines(first: 250) {\n nodes {\n id\n quantity\n attributes {\n key\n value\n }\n cost {\n totalAmount {\n amount\n currencyCode\n }\n subtotalAmount {\n amount\n currencyCode\n }\n amountPerQuantity {\n amount\n currencyCode\n }\n compareAtAmountPerQuantity {\n amount\n currencyCode\n }\n }\n merchandise {\n ... on ProductVariant {\n id\n title\n sku\n image {\n id\n url\n altText\n width\n height\n }\n product {\n id\n title\n handle\n vendor\n productType\n }\n selectedOptions {\n name\n value\n }\n }\n }\n sellingPlanAllocation {\n sellingPlan {\n id\n }\n }\n ... on CartLine {\n parentRelationship {\n parent {\n id\n }\n }\n }\n }\n }\n discountCodes {\n applicable\n code\n }\n }\n`);\n\nconst CART_QUERY = gql(\n `query Cart($id: ID!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cart(id: $id) {\n ...HydrogenCartFragment\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_CREATE_MUTATION = gql(\n `mutation CartCreate($input: CartInput!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartCreate(input: $input) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_ADD_MUTATION = gql(\n `mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesAdd(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_UPDATE_MUTATION = gql(\n `mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesUpdate(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_REMOVE_MUTATION = gql(\n `mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_DISCOUNT_CODES_UPDATE_MUTATION = gql(\n `mutation CartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_NOTE_UPDATE_MUTATION = gql(\n `mutation CartNoteUpdate($cartId: ID!, $note: String!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartNoteUpdate(cartId: $cartId, note: $note) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_ATTRIBUTES_UPDATE_MUTATION = gql(\n `mutation CartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\n// The custom variants spread the consumer's `CartFragment`, which only exists\n// at runtime. Its spread is interpolated on purpose: the gql.tada plugin skips\n// documents containing interpolations instead of flagging an unknown fragment,\n// while TypeScript still resolves the full literal source type. The consumer's\n// fragment is composed in at runtime by `createCartQueries`.\nconst CUSTOM_CART_QUERY = gql(\n `query Cart($id: ID!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cart(id: $id) {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_CREATE_MUTATION = gql(\n `mutation CartCreate($input: CartInput!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartCreate(input: $input) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_ADD_MUTATION = gql(\n `mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesAdd(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_UPDATE_MUTATION = gql(\n `mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesUpdate(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_REMOVE_MUTATION = gql(\n `mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION = gql(\n `mutation CartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_NOTE_UPDATE_MUTATION = gql(\n `mutation CartNoteUpdate($cartId: ID!, $note: String!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartNoteUpdate(cartId: $cartId, note: $note) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION = gql(\n `mutation CartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\n// Minimal payload on purpose: buyer identity sync callers only need success or\n// userErrors, never the cart body, so no custom-fragment variant exists.\nconst CART_BUYER_IDENTITY_UPDATE_MUTATION_SOURCE = /* GraphQL */ `\n mutation CartBuyerIdentityUpdate($cartId: ID!, $buyerIdentity: CartBuyerIdentityInput!) {\n cartBuyerIdentityUpdate(cartId: $cartId, buyerIdentity: $buyerIdentity) {\n cart {\n id\n }\n userErrors {\n code\n field\n message\n }\n }\n }\n`;\n\nconst DEFAULT_CART_QUERIES = {\n cart: CART_QUERY,\n cartCreate: CART_CREATE_MUTATION,\n cartLinesAdd: CART_LINES_ADD_MUTATION,\n cartLinesUpdate: CART_LINES_UPDATE_MUTATION,\n cartLinesRemove: CART_LINES_REMOVE_MUTATION,\n cartDiscountCodesUpdate: CART_DISCOUNT_CODES_UPDATE_MUTATION,\n cartNoteUpdate: CART_NOTE_UPDATE_MUTATION,\n cartAttributesUpdate: CART_ATTRIBUTES_UPDATE_MUTATION,\n} as const;\n\ntype DefaultCartQueries = typeof DEFAULT_CART_QUERIES;\n\nexport const cartBuyerIdentityUpdateMutation = gql(CART_BUYER_IDENTITY_UPDATE_MUTATION_SOURCE);\n\ntype QueryFor<\n Source extends string,\n Fragments extends readonly AnyStorefrontQueryString[],\n DocumentSource extends string = ComposedSource<Source, Fragments>,\n> = StorefrontQueryString<\n InferResult<DocumentSource>,\n InferVariables<DocumentSource>,\n DocumentSource\n>;\n\ntype CartFragmentDocument = AnyStorefrontQueryString;\n\ntype CustomQueryFor<\n Document extends AnyStorefrontQueryString,\n TCartFragment extends CartFragmentDocument,\n> = QueryFor<SourceOf<Document>, readonly [TCartFragment]>;\n\ntype CartQueriesForFragment<TCartFragment extends CartFragmentDocument> = {\n readonly cart: CustomQueryFor<typeof CUSTOM_CART_QUERY, TCartFragment>;\n readonly cartCreate: CustomQueryFor<typeof CUSTOM_CART_CREATE_MUTATION, TCartFragment>;\n readonly cartLinesAdd: CustomQueryFor<typeof CUSTOM_CART_LINES_ADD_MUTATION, TCartFragment>;\n readonly cartLinesUpdate: CustomQueryFor<typeof CUSTOM_CART_LINES_UPDATE_MUTATION, TCartFragment>;\n readonly cartLinesRemove: CustomQueryFor<typeof CUSTOM_CART_LINES_REMOVE_MUTATION, TCartFragment>;\n readonly cartDiscountCodesUpdate: CustomQueryFor<\n typeof CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION,\n TCartFragment\n >;\n readonly cartNoteUpdate: CustomQueryFor<typeof CUSTOM_CART_NOTE_UPDATE_MUTATION, TCartFragment>;\n readonly cartAttributesUpdate: CustomQueryFor<\n typeof CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION,\n TCartFragment\n >;\n};\n\ntype CartDataFromCartQuery<TQuery extends AnyStorefrontQueryString> =\n TQuery extends StorefrontQueryString<infer Result, infer _Variables, string>\n ? Result extends { cart?: (infer Cart) | null }\n ? MergeCartData<NormalizeCartData<NonNullable<Cart>>>\n : CartData\n : CartData;\n\ntype MergeCartData<TCart> = Omit<CartData, keyof TCart> & TCart;\n\ntype NormalizeCartData<TCart> = TCart extends { lines: infer TLines }\n ? Omit<TCart, \"lines\"> & { lines: NormalizeCartLines<TLines> }\n : TCart;\n\ntype NormalizeCartLines<TLines> = TLines extends { nodes: infer TNodes }\n ? Omit<TLines, \"nodes\"> & { nodes: Array<CartLineFromNodes<TNodes>> }\n : TLines;\n\ntype CartLineFromNodes<TNodes> = TNodes extends CartLineConnection[\"nodes\"]\n ? TNodes[number]\n : TNodes extends ReadonlyArray<infer TLine>\n ? TLine\n : never;\n\nexport type CartDataForOptions<TOptions> = CartDataFromCartQuery<\n CartQueriesForOptions<TOptions>[\"cart\"]\n>;\n\nexport type CreateCartQueriesOptions<\n TCartFragment extends AnyStorefrontQueryString = AnyStorefrontQueryString,\n> = {\n /**\n * Cart fragment spread into every cart query and mutation response.\n *\n * The fragment must be named `CartFragment` and target `Cart`.\n */\n readonly fragment: TCartFragment;\n};\n\nexport type CartQueriesForOptions<TOptions> = TOptions extends {\n readonly fragment: infer TCartFragment extends AnyStorefrontQueryString;\n}\n ? CartQueriesForFragment<TCartFragment>\n : DefaultCartQueries;\n\nfunction assertCartFragmentName(fragment: string): void {\n if (CART_FRAGMENT_PATTERN.test(fragment)) return;\n\n throw new Error(\n `Cart fragment must be named ${CART_FRAGMENT_NAME} and target ${CART_FRAGMENT_CONTRACT.typeName}`,\n );\n}\n\nfunction createFragmentPattern({ name, typeName }: FragmentContract): RegExp {\n return new RegExp(`fragment\\\\s+${name}\\\\s+on\\\\s+${typeName}`);\n}\n\nfunction createCartQueries<const TCartFragment extends CartFragmentDocument>(\n cartFragment: TCartFragment,\n): CartQueriesForFragment<TCartFragment> {\n const fragments = [cartFragment] as const;\n\n const cart = gql(CUSTOM_CART_QUERY, fragments);\n\n const cartCreate = gql(CUSTOM_CART_CREATE_MUTATION, fragments);\n\n const cartLinesAdd = gql(CUSTOM_CART_LINES_ADD_MUTATION, fragments);\n\n const cartLinesUpdate = gql(CUSTOM_CART_LINES_UPDATE_MUTATION, fragments);\n\n const cartLinesRemove = gql(CUSTOM_CART_LINES_REMOVE_MUTATION, fragments);\n\n const cartDiscountCodesUpdate = gql(CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION, fragments);\n\n const cartNoteUpdate = gql(CUSTOM_CART_NOTE_UPDATE_MUTATION, fragments);\n\n const cartAttributesUpdate = gql(CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION, fragments);\n\n return {\n cart,\n cartCreate,\n cartLinesAdd,\n cartLinesUpdate,\n cartLinesRemove,\n cartDiscountCodesUpdate,\n cartNoteUpdate,\n cartAttributesUpdate,\n } as const;\n}\n\nexport function makeCartQueries<const TOptions extends CreateCartQueriesOptions>(\n options: TOptions,\n): CartQueriesForOptions<TOptions>;\nexport function makeCartQueries(): DefaultCartQueries;\nexport function makeCartQueries(options?: CreateCartQueriesOptions) {\n if (options) {\n assertCartFragmentName(options.fragment);\n return createCartQueries(options.fragment);\n }\n\n return DEFAULT_CART_QUERIES;\n}\n\nexport const cartQueries = makeCartQueries();\n"],"mappings":";;;AAUA,MAAA,qBAAA;AAQA,MAAA,yBAAA;CACA,MAAA;CACA,UAAA;CACA;AAEA,MAAA,wBAAA,sBAAA,uBAAA;AAEA,MAAA,yBAAA,IAAA,qrBA8FA;AAEA,MAAA,aAAA,IACA,uJAMA,CAAA,uBAAA,CACA;AAEA,MAAA,uBAAA,IACA,uPAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,0BAAA,IACA,4RAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,6BAAA,IACA,wSAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,6BAAA,IACA,6RAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,sCAAA,IACA,mUAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,4BAAA,IACA,mRAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,kCAAA,IACA,4TAkBA,CAAA,uBAAA,CACA;AAOA,MAAA,oBAAA,IACA,wJAIS,mBAAqB,KAG9B,CAAA,uBAAA,CACA;AAEA,MAAA,8BAAA,IACA,4LAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,iCAAA,IACA,iOAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,oCAAA,IACA,6OAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,oCAAA,IACA,kOAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,6CAAA,IACA,wQAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,mCAAA,IACA,wNAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,yCAAA,IACA,iQAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAIA,MAAA,6CAAA;AAeA,MAAA,uBAAA;CACA,MAAA;CACA,YAAA;CACA,cAAA;CACA,iBAAA;CACA,iBAAA;CACA,yBAAA;CACA,gBAAA;CACA,sBAAA;CACA;AAIA,MAAA,kCAAA,IAAA,2CAAA;AAgFA,SAAA,uBAAA,UAAA;AACA,KAAA,sBAAA,KAAA,SAAA,CAAA;AAEA,OAAA,IAAA,MACA,+BAAA,mBAAA,cAAA,uBAAA,WACA;;AAGA,SAAA,sBAAA,EAAA,MAAA,YAAA;AACA,QAAA,IAAA,OAAA,eAAA,KAAA,YAAA,WAAA;;AAGA,SAAA,kBACA,cACA;CACA,MAAA,YAAA,CAAA,aAAA;AAkBA,QAAA;EACA,MAjBA,IAAA,mBAAA,UAiBA;EACA,YAhBA,IAAA,6BAAA,UAgBA;EACA,cAfA,IAAA,gCAAA,UAeA;EACA,iBAdA,IAAA,mCAAA,UAcA;EACA,iBAbA,IAAA,mCAAA,UAaA;EACA,yBAZA,IAAA,4CAAA,UAYA;EACA,gBAXA,IAAA,kCAAA,UAWA;EACA,sBAVA,IAAA,wCAAA,UAUA;EACA;;AAOA,SAAA,gBAAA,SAAA;AACA,KAAA,SAAA;AACA,yBAAA,QAAA,SAAA;AACA,SAAA,kBAAA,QAAA,SAAA;;AAGA,QAAA;;AAGA,MAAA,cAAA,iBAAA"}
1
+ {"version":3,"file":"queries.mjs","names":[],"sources":["../../../src/core/cart/queries.ts"],"sourcesContent":["import {\n gql,\n type AnyStorefrontQueryString,\n type ComposedSource,\n type SourceOf,\n type StorefrontQueryString,\n} from \"../../graphql\";\nimport type { InferResult, InferVariables } from \"../../graphql\";\nimport type { CartData, CartLineConnection } from \"./state\";\n\nconst CART_FRAGMENT_NAME = \"CartFragment\";\nconst CART_FRAGMENT_TYPE = \"Cart\";\n\ntype FragmentContract = {\n readonly name: string;\n readonly typeName: string;\n};\n\nconst CART_FRAGMENT_CONTRACT = {\n name: CART_FRAGMENT_NAME,\n typeName: CART_FRAGMENT_TYPE,\n} as const satisfies FragmentContract;\n\nconst CART_FRAGMENT_PATTERN = createFragmentPattern(CART_FRAGMENT_CONTRACT);\n\nconst HYDROGEN_CART_FRAGMENT = gql(`\n fragment HydrogenCartFragment on Cart {\n id\n updatedAt\n checkoutUrl\n totalQuantity\n note\n attributes {\n key\n value\n }\n cost {\n subtotalAmount {\n amount\n currencyCode\n }\n totalAmount {\n amount\n currencyCode\n }\n checkoutChargeAmount {\n amount\n currencyCode\n }\n }\n lines(first: 250) {\n nodes {\n id\n quantity\n attributes {\n key\n value\n }\n cost {\n totalAmount {\n amount\n currencyCode\n }\n subtotalAmount {\n amount\n currencyCode\n }\n amountPerQuantity {\n amount\n currencyCode\n }\n compareAtAmountPerQuantity {\n amount\n currencyCode\n }\n }\n merchandise {\n ... on ProductVariant {\n id\n title\n sku\n image {\n id\n url\n altText\n width\n height\n }\n product {\n id\n title\n handle\n vendor\n productType\n }\n selectedOptions {\n name\n value\n }\n }\n }\n sellingPlanAllocation {\n sellingPlan {\n id\n }\n }\n ... on CartLine {\n parentRelationship {\n parent {\n id\n }\n }\n }\n }\n }\n discountCodes {\n applicable\n code\n }\n }\n`);\n\nconst CART_QUERY = gql(\n `query Cart($id: ID!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cart(id: $id) {\n ...HydrogenCartFragment\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_CREATE_MUTATION = gql(\n `mutation CartCreate($input: CartInput!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartCreate(input: $input) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_ADD_MUTATION = gql(\n `mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesAdd(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_UPDATE_MUTATION = gql(\n `mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesUpdate(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_LINES_REMOVE_MUTATION = gql(\n `mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_DISCOUNT_CODES_UPDATE_MUTATION = gql(\n `mutation CartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_NOTE_UPDATE_MUTATION = gql(\n `mutation CartNoteUpdate($cartId: ID!, $note: String!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartNoteUpdate(cartId: $cartId, note: $note) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CART_ATTRIBUTES_UPDATE_MUTATION = gql(\n `mutation CartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {\n cart {\n ...HydrogenCartFragment\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\n// The custom variants spread the consumer's `CartFragment`, which only exists\n// at runtime. Its spread is interpolated on purpose: the gql.tada plugin skips\n// documents containing interpolations instead of flagging an unknown fragment,\n// while TypeScript still resolves the full literal source type. The consumer's\n// fragment is composed in at runtime by `createCartQueries`.\nconst CUSTOM_CART_QUERY = gql(\n `query Cart($id: ID!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cart(id: $id) {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_CREATE_MUTATION = gql(\n `mutation CartCreate($input: CartInput!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartCreate(input: $input) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_ADD_MUTATION = gql(\n `mutation CartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesAdd(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_UPDATE_MUTATION = gql(\n `mutation CartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesUpdate(cartId: $cartId, lines: $lines) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_LINES_REMOVE_MUTATION = gql(\n `mutation CartLinesRemove($cartId: ID!, $lineIds: [ID!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION = gql(\n `mutation CartDiscountCodesUpdate($cartId: ID!, $discountCodes: [String!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartDiscountCodesUpdate(cartId: $cartId, discountCodes: $discountCodes) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_NOTE_UPDATE_MUTATION = gql(\n `mutation CartNoteUpdate($cartId: ID!, $note: String!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartNoteUpdate(cartId: $cartId, note: $note) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\nconst CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION = gql(\n `mutation CartAttributesUpdate($cartId: ID!, $attributes: [AttributeInput!]!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n cartAttributesUpdate(cartId: $cartId, attributes: $attributes) {\n cart {\n ...HydrogenCartFragment\n ...${CART_FRAGMENT_NAME}\n }\n userErrors {\n code\n field\n message\n }\n warnings {\n code\n message\n target\n }\n }\n }`,\n [HYDROGEN_CART_FRAGMENT],\n);\n\n// Minimal payload on purpose: buyer identity sync callers only need success or\n// userErrors, never the cart body, so no custom-fragment variant exists.\nconst CART_BUYER_IDENTITY_UPDATE_MUTATION_SOURCE = /* GraphQL */ `\n mutation CartBuyerIdentityUpdate($cartId: ID!, $buyerIdentity: CartBuyerIdentityInput!) {\n cartBuyerIdentityUpdate(cartId: $cartId, buyerIdentity: $buyerIdentity) {\n cart {\n id\n }\n userErrors {\n code\n field\n message\n }\n }\n }\n`;\n\nconst DEFAULT_CART_QUERIES = {\n cart: CART_QUERY,\n cartCreate: CART_CREATE_MUTATION,\n cartLinesAdd: CART_LINES_ADD_MUTATION,\n cartLinesUpdate: CART_LINES_UPDATE_MUTATION,\n cartLinesRemove: CART_LINES_REMOVE_MUTATION,\n cartDiscountCodesUpdate: CART_DISCOUNT_CODES_UPDATE_MUTATION,\n cartNoteUpdate: CART_NOTE_UPDATE_MUTATION,\n cartAttributesUpdate: CART_ATTRIBUTES_UPDATE_MUTATION,\n} as const;\n\ntype DefaultCartQueries = typeof DEFAULT_CART_QUERIES;\n\nexport const cartBuyerIdentityUpdateMutation = gql(CART_BUYER_IDENTITY_UPDATE_MUTATION_SOURCE);\n\ntype QueryFor<\n Source extends string,\n Fragments extends readonly AnyStorefrontQueryString[],\n DocumentSource extends string = ComposedSource<Source, Fragments>,\n> = StorefrontQueryString<\n InferResult<DocumentSource>,\n InferVariables<DocumentSource>,\n DocumentSource\n>;\n\ntype CartFragmentDocument = AnyStorefrontQueryString;\n\ntype CustomQueryFor<\n Document extends AnyStorefrontQueryString,\n TCartFragment extends CartFragmentDocument,\n> = QueryFor<SourceOf<Document>, readonly [TCartFragment]>;\n\ntype CartQueriesForFragment<TCartFragment extends CartFragmentDocument> = {\n readonly cart: CustomQueryFor<typeof CUSTOM_CART_QUERY, TCartFragment>;\n readonly cartCreate: CustomQueryFor<typeof CUSTOM_CART_CREATE_MUTATION, TCartFragment>;\n readonly cartLinesAdd: CustomQueryFor<typeof CUSTOM_CART_LINES_ADD_MUTATION, TCartFragment>;\n readonly cartLinesUpdate: CustomQueryFor<typeof CUSTOM_CART_LINES_UPDATE_MUTATION, TCartFragment>;\n readonly cartLinesRemove: CustomQueryFor<typeof CUSTOM_CART_LINES_REMOVE_MUTATION, TCartFragment>;\n readonly cartDiscountCodesUpdate: CustomQueryFor<\n typeof CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION,\n TCartFragment\n >;\n readonly cartNoteUpdate: CustomQueryFor<typeof CUSTOM_CART_NOTE_UPDATE_MUTATION, TCartFragment>;\n readonly cartAttributesUpdate: CustomQueryFor<\n typeof CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION,\n TCartFragment\n >;\n};\n\ntype CartDataFromCartQuery<TQuery extends AnyStorefrontQueryString> =\n TQuery extends StorefrontQueryString<infer Result, infer _Variables, string>\n ? Result extends { cart?: (infer Cart) | null }\n ? MergeCartData<NormalizeCartData<NonNullable<Cart>>>\n : CartData\n : CartData;\n\ntype MergeCartData<TCart> = Omit<CartData, keyof TCart> & TCart;\n\ntype NormalizeCartData<TCart> = TCart extends { lines: infer TLines }\n ? Omit<TCart, \"lines\"> & { lines: NormalizeCartLines<TLines> }\n : TCart;\n\ntype NormalizeCartLines<TLines> = TLines extends { nodes: infer TNodes }\n ? Omit<TLines, \"nodes\"> & { nodes: Array<CartLineFromNodes<TNodes>> }\n : TLines;\n\ntype CartLineFromNodes<TNodes> = TNodes extends CartLineConnection[\"nodes\"]\n ? TNodes[number]\n : TNodes extends ReadonlyArray<infer TLine>\n ? TLine\n : never;\n\n/** Infers the {@link CartData} shape from `CreateCartServerHandlersOptions`. */\nexport type CartDataForOptions<TOptions> = CartDataFromCartQuery<\n CartQueriesForOptions<TOptions>[\"cart\"]\n>;\n\n/**\n * Options for {@link makeCartQueries} when providing a custom cart fragment.\n *\n * The fragment extends the default `HydrogenCartFragment` — your additional\n * fields are merged into every cart query and mutation response.\n */\nexport type CreateCartQueriesOptions<\n TCartFragment extends AnyStorefrontQueryString = AnyStorefrontQueryString,\n> = {\n /**\n * Cart fragment spread into every cart query and mutation response.\n *\n * The fragment must be named `CartFragment` and target `Cart`.\n */\n readonly fragment: TCartFragment;\n};\n\n/** Resolves the cart query set from handler options — custom queries when a fragment is provided, defaults otherwise. */\nexport type CartQueriesForOptions<TOptions> = TOptions extends {\n readonly fragment: infer TCartFragment extends AnyStorefrontQueryString;\n}\n ? CartQueriesForFragment<TCartFragment>\n : DefaultCartQueries;\n\nfunction assertCartFragmentName(fragment: string): void {\n if (CART_FRAGMENT_PATTERN.test(fragment)) return;\n\n throw new Error(\n `Cart fragment must be named ${CART_FRAGMENT_NAME} and target ${CART_FRAGMENT_CONTRACT.typeName}`,\n );\n}\n\nfunction createFragmentPattern({ name, typeName }: FragmentContract): RegExp {\n return new RegExp(`fragment\\\\s+${name}\\\\s+on\\\\s+${typeName}`);\n}\n\nfunction createCartQueries<const TCartFragment extends CartFragmentDocument>(\n cartFragment: TCartFragment,\n): CartQueriesForFragment<TCartFragment> {\n const fragments = [cartFragment] as const;\n\n const cart = gql(CUSTOM_CART_QUERY, fragments);\n\n const cartCreate = gql(CUSTOM_CART_CREATE_MUTATION, fragments);\n\n const cartLinesAdd = gql(CUSTOM_CART_LINES_ADD_MUTATION, fragments);\n\n const cartLinesUpdate = gql(CUSTOM_CART_LINES_UPDATE_MUTATION, fragments);\n\n const cartLinesRemove = gql(CUSTOM_CART_LINES_REMOVE_MUTATION, fragments);\n\n const cartDiscountCodesUpdate = gql(CUSTOM_CART_DISCOUNT_CODES_UPDATE_MUTATION, fragments);\n\n const cartNoteUpdate = gql(CUSTOM_CART_NOTE_UPDATE_MUTATION, fragments);\n\n const cartAttributesUpdate = gql(CUSTOM_CART_ATTRIBUTES_UPDATE_MUTATION, fragments);\n\n return {\n cart,\n cartCreate,\n cartLinesAdd,\n cartLinesUpdate,\n cartLinesRemove,\n cartDiscountCodesUpdate,\n cartNoteUpdate,\n cartAttributesUpdate,\n } as const;\n}\n\n/**\n * Builds a complete set of cart GraphQL query and mutation documents.\n *\n * Without options, returns the default Hydrogen cart queries. With a\n * {@link CreateCartQueriesOptions.fragment | custom fragment}, returns\n * queries that spread both `HydrogenCartFragment` and your fragment into\n * every response, so the result types include your additional fields.\n *\n * @example\n * ```ts\n * // Default queries\n * const queries = makeCartQueries();\n *\n * // With a custom fragment for metafields\n * const queries = makeCartQueries({\n * fragment: CART_FRAGMENT,\n * });\n * ```\n */\nexport function makeCartQueries<const TOptions extends CreateCartQueriesOptions>(\n options: TOptions,\n): CartQueriesForOptions<TOptions>;\nexport function makeCartQueries(): DefaultCartQueries;\nexport function makeCartQueries(options?: CreateCartQueriesOptions) {\n if (options) {\n assertCartFragmentName(options.fragment);\n return createCartQueries(options.fragment);\n }\n\n return DEFAULT_CART_QUERIES;\n}\n\n/** Default cart GraphQL queries and mutations. */\nexport const cartQueries = makeCartQueries();\n"],"mappings":";;;AAUA,MAAA,qBAAA;AAQA,MAAA,yBAAA;CACA,MAAA;CACA,UAAA;CACA;AAEA,MAAA,wBAAA,sBAAA,uBAAA;AAEA,MAAA,yBAAA,IAAA,+rBA+FA;AAEA,MAAA,aAAA,IACA,uJAMA,CAAA,uBAAA,CACA;AAEA,MAAA,uBAAA,IACA,uPAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,0BAAA,IACA,4RAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,6BAAA,IACA,wSAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,6BAAA,IACA,6RAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,sCAAA,IACA,mUAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,4BAAA,IACA,mRAkBA,CAAA,uBAAA,CACA;AAEA,MAAA,kCAAA,IACA,4TAkBA,CAAA,uBAAA,CACA;AAOA,MAAA,oBAAA,IACA,wJAIS,mBAAqB,KAG9B,CAAA,uBAAA,CACA;AAEA,MAAA,8BAAA,IACA,4LAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,iCAAA,IACA,iOAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,oCAAA,IACA,6OAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,oCAAA,IACA,kOAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,6CAAA,IACA,wQAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,mCAAA,IACA,wNAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAEA,MAAA,yCAAA,IACA,iQAKW,mBAAqB,iEAchC,CAAA,uBAAA,CACA;AAIA,MAAA,6CAAA;AAeA,MAAA,uBAAA;CACA,MAAA;CACA,YAAA;CACA,cAAA;CACA,iBAAA;CACA,iBAAA;CACA,yBAAA;CACA,gBAAA;CACA,sBAAA;CACA;AAIA,MAAA,kCAAA,IAAA,2CAAA;AAwFA,SAAA,uBAAA,UAAA;AACA,KAAA,sBAAA,KAAA,SAAA,CAAA;AAEA,OAAA,IAAA,MACA,+BAAA,mBAAA,cAAA,uBAAA,WACA;;AAGA,SAAA,sBAAA,EAAA,MAAA,YAAA;AACA,QAAA,IAAA,OAAA,eAAA,KAAA,YAAA,WAAA;;AAGA,SAAA,kBACA,cACA;CACA,MAAA,YAAA,CAAA,aAAA;AAkBA,QAAA;EACA,MAjBA,IAAA,mBAAA,UAiBA;EACA,YAhBA,IAAA,6BAAA,UAgBA;EACA,cAfA,IAAA,gCAAA,UAeA;EACA,iBAdA,IAAA,mCAAA,UAcA;EACA,iBAbA,IAAA,mCAAA,UAaA;EACA,yBAZA,IAAA,4CAAA,UAYA;EACA,gBAXA,IAAA,kCAAA,UAWA;EACA,sBAVA,IAAA,wCAAA,UAUA;EACA;;AA0BA,SAAA,gBAAA,SAAA;AACA,KAAA,SAAA;AACA,yBAAA,QAAA,SAAA;AACA,SAAA,kBAAA,QAAA,SAAA;;AAGA,QAAA;;;AAIA,MAAA,cAAA,iBAAA"}
@@ -13,17 +13,27 @@ declare const CART_API_PATH: "/api/cart";
13
13
  declare const CART_GET_METHOD: "GET";
14
14
  declare const CART_POST_METHOD: "POST";
15
15
  declare const cartServerHandlersCartQuery: unique symbol;
16
+ /** Response shape from the cart GET handler — the fetched cart plus any GraphQL errors. */
16
17
  type CartGetData<TCart = CartData> = {
17
18
  cart: TCart | null;
18
19
  errors?: Array<{
19
20
  message: string;
20
21
  }>;
21
22
  };
23
+ /** Full route result from the cart GET handler — JSON with {@link CartGetData} payload and response headers. */
22
24
  type CartGetResult<TCart = CartData> = ShopifyRouteJsonResult<CartGetData<TCart>>;
25
+ /** Machine-readable error codes returned by the cart POST handler. */
23
26
  type CartErrorCode = "invalid_cart_request" | "missing_cart" | "cart_mutation_failed";
27
+ /** A cart route error carrying a {@link CartErrorCode} for programmatic handling. */
24
28
  type CartError = ShopifyRouteError & {
25
29
  code: CartErrorCode;
26
30
  };
31
+ /**
32
+ * Result from the cart POST handler — one of:
33
+ * - JSON with the mutation payload (programmatic clients)
34
+ * - 303 redirect back to the referrer (HTML form submissions)
35
+ * - An error with a {@link CartErrorCode}
36
+ */
27
37
  type CartPostResult = ShopifyRouteJsonResult<Record<string, unknown>> | ShopifyRouteRedirectResult | ShopifyRouteErrorResult<CartError>;
28
38
  type CartGetHandlerContext = {
29
39
  storefrontClient: StorefrontClient;
@@ -42,13 +52,29 @@ type CartCustomerSessionWriteContext = {
42
52
  requestContext: ShopifyRequestContext;
43
53
  };
44
54
  type CartCustomerSession = CustomerSession;
55
+ /** GET handler for the `/api/cart` route — fetches the current cart from the Storefront API. */
45
56
  type CartGetHandler<TCart = CartData, TContext extends CartGetHandlerContext = CartGetHandlerContext> = CallableRouteHandler<TContext, CartGetResult<TCart>, typeof CART_API_PATH, typeof CART_GET_METHOD>;
57
+ /** POST handler for the `/api/cart` route — processes cart mutations from JSON or FormData bodies. */
46
58
  type CartPostHandler<TContext extends CartPostHandlerContext = CartPostHandlerContext> = CallableRouteHandler<TContext, CartPostResult, typeof CART_API_PATH, typeof CART_POST_METHOD>;
59
+ /**
60
+ * GET and POST handlers for the `/api/cart` route.
61
+ *
62
+ * Created by {@link createCartServerHandlers}. Register these with your
63
+ * framework's router so the client cart store can communicate with the
64
+ * Storefront API.
65
+ */
47
66
  type CartServerHandlers<TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart, TCart extends CartData = CartDataFromQuery<TCartQuery>> = {
48
67
  readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;
49
68
  get: CartGetHandler<TCart>;
50
69
  post: CartPostHandler;
51
70
  };
71
+ /**
72
+ * {@link CartServerHandlers} variant that additionally syncs the cart's buyer
73
+ * identity with a customer session — the handler contexts require a session
74
+ * manager and request context.
75
+ *
76
+ * Created by passing `customerSession` to {@link createCartServerHandlers}.
77
+ */
52
78
  type CartServerHandlersWithCustomerSession<TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart, TCart extends CartData = CartDataFromQuery<TCartQuery>> = {
53
79
  readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;
54
80
  readonly [cartBuyerIdentitySync]: CartBuyerIdentitySync;
@@ -64,8 +90,24 @@ type CartDataFromHandlerResult<TResult> = [TResult] extends [never] ? never : TR
64
90
  cart: infer TCart;
65
91
  };
66
92
  } ? NonNullable<TCart> extends CartData ? NonNullable<TCart> : CartData : CartData;
93
+ /**
94
+ * Infers the {@link CartData} shape from a {@link CartServerHandlers} instance.
95
+ *
96
+ * Use this to type framework components and hooks so they match the server
97
+ * handler's custom cart query without repeating the generic parameter.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * type MyCartData = CartDataFromHandlers<typeof cartHandlers>;
102
+ * ```
103
+ */
67
104
  type CartDataFromHandlers<THandlers> = CartDataFromHandlerResult<CartGetHandlerResult<THandlers>>;
105
+ /** Options for {@link createCartServerHandlers}. */
68
106
  type CreateCartServerHandlersOptions<TCartFragment extends AnyStorefrontQueryString = AnyStorefrontQueryString> = {
107
+ /**
108
+ * Custom cart GraphQL fragment spread into every query and mutation response.
109
+ * The fragment must be named `CartFragment` and target `Cart`.
110
+ */
69
111
  readonly fragment?: TCartFragment;
70
112
  } & ({
71
113
  readonly customerSession: CartCustomerSession;
@@ -75,6 +117,33 @@ type CreateCartServerHandlersOptions<TCartFragment extends AnyStorefrontQueryStr
75
117
  type CartServerHandlersForOptions<TOptions> = TOptions extends {
76
118
  readonly customerSession: CartCustomerSession;
77
119
  } ? CartServerHandlersWithCustomerSession<CartQueriesForOptions<TOptions>["cart"], CartDataForOptions<TOptions>> : CartServerHandlers<CartQueriesForOptions<TOptions>["cart"], CartDataForOptions<TOptions>>;
120
+ /**
121
+ * Creates GET and POST handlers for the `/api/cart` route.
122
+ *
123
+ * The handlers parse incoming requests (JSON or FormData), resolve the cart
124
+ * identity from a cookie, execute the matching Storefront API mutation, and
125
+ * return either JSON (programmatic clients) or a 303 redirect (form submissions).
126
+ *
127
+ * Pass `customerSession` to additionally sync the cart's buyer identity with
128
+ * the logged-in customer — the returned handlers then require a session manager
129
+ * in their context.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * // Basic setup
134
+ * const cartHandlers = createCartServerHandlers();
135
+ *
136
+ * // With a custom cart fragment
137
+ * const cartHandlers = createCartServerHandlers({
138
+ * fragment: CART_FRAGMENT,
139
+ * });
140
+ *
141
+ * // With customer session for buyer identity sync
142
+ * const cartHandlers = createCartServerHandlers({
143
+ * customerSession,
144
+ * });
145
+ * ```
146
+ */
78
147
  declare function createCartServerHandlers(): CartServerHandlers<typeof cartQueries.cart>;
79
148
  declare function createCartServerHandlers<const TOptions extends CreateCartServerHandlersOptions>(options: TOptions): CartServerHandlersForOptions<TOptions>;
80
149
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import { getLogger } from "../logging/logging.mjs";
2
+ import { getSameOriginPath } from "../url.mjs";
2
3
  import { applyPrivateResponseCacheHeaders } from "../headers.mjs";
3
4
  import { createProxyResponseHeaders } from "../request-routing/interceptors/proxy.mjs";
4
5
  import { createCartCookie, createExpiredCartCookie, getCartIdFromCookie } from "./cookie.mjs";
@@ -136,16 +137,7 @@ function appendHeaders(headers, headersToAppend) {
136
137
  for (const setCookie of headersToAppend.getSetCookie()) headers.append("set-cookie", setCookie);
137
138
  }
138
139
  function safeRedirectTarget(request) {
139
- const referer = request.headers.get("referer");
140
- if (!referer) return "/";
141
- try {
142
- const refererUrl = new URL(referer);
143
- const requestUrl = new URL(request.url);
144
- if (refererUrl.origin !== requestUrl.origin) return "/";
145
- return refererUrl.toString().replace(refererUrl.origin, "");
146
- } catch {
147
- return "/";
148
- }
140
+ return getSameOriginPath(request.headers.get("referer"), new URL(request.url).origin) ?? "/";
149
141
  }
150
142
  function assertGraphQLData(result) {
151
143
  if (result.errors || !result.data) {
@@ -1 +1 @@
1
- {"version":3,"file":"server-handlers.mjs","names":["_exhaustive"],"sources":["../../../src/core/cart/server-handlers.ts"],"sourcesContent":["import type { GraphQLFormattedError, StorefrontClient } from \"../../client\";\nimport type {\n CustomerSession,\n ReadonlyCustomerSessionManager,\n WritableCustomerSessionManager,\n} from \"../../customer-account/session\";\nimport { getCustomerSessionRefreshResult } from \"../../customer-account/session\";\nimport type { AnyStorefrontQueryString } from \"../../graphql\";\nimport { applyPrivateResponseCacheHeaders } from \"../headers\";\nimport { getLogger } from \"../logging\";\nimport type { ShopifyRequestContext } from \"../request-context\";\nimport { createProxyResponseHeaders } from \"../request-routing/interceptors/proxy\";\nimport type {\n CallableRouteHandler,\n ShopifyRouteError,\n ShopifyRouteErrorResult,\n ShopifyRouteJsonResult,\n ShopifyRouteRedirectResult,\n} from \"../request-routing/registered-routes\";\nimport { createCallableRouteHandler } from \"../request-routing/registered-routes\";\nimport { parseCartRequest } from \"./actions\";\nimport type { CartAction, CartLineAddInput } from \"./actions\";\nimport {\n cartBuyerIdentitySync,\n type CartBuyerIdentitySync,\n type CartBuyerIdentitySyncContext,\n} from \"./buyer-identity-sync\";\nimport { getCartIdFromCookie, createCartCookie, createExpiredCartCookie } from \"./cookie\";\nimport { getCart, getCartId, type CartDataFromQuery } from \"./get-cart\";\nimport {\n cartBuyerIdentityUpdateMutation,\n cartQueries,\n makeCartQueries,\n type CartDataForOptions,\n type CartQueriesForOptions,\n type CreateCartQueriesOptions,\n} from \"./queries\";\nimport type { CartData } from \"./state\";\nconst log = getLogger(\"cart-api\");\n\nconst CART_API_PATH = \"/api/cart\" as const;\nconst CART_GET_METHOD = \"GET\" as const;\nconst CART_POST_METHOD = \"POST\" as const;\nconst CART_MUTATION_FAILED_STATUS = 500;\nconst CART_MUTATION_FAILED_MESSAGE = \"Cart mutation failed. Please try again.\";\nconst cartServerHandlersCartQuery: unique symbol = Symbol(\"hydrogen.cartQuery\");\n\nexport type CartGetData<TCart = CartData> = {\n cart: TCart | null;\n errors?: Array<{ message: string }>;\n};\n\nexport type CartGetResult<TCart = CartData> = ShopifyRouteJsonResult<CartGetData<TCart>>;\nexport type CartErrorCode = \"invalid_cart_request\" | \"missing_cart\" | \"cart_mutation_failed\";\nexport type CartError = ShopifyRouteError & {\n code: CartErrorCode;\n};\nexport type CartPostResult =\n | ShopifyRouteJsonResult<Record<string, unknown>>\n | ShopifyRouteRedirectResult\n | ShopifyRouteErrorResult<CartError>;\n\ntype CartCustomerAccessTokenResult = {\n accessToken?: string;\n commitSession: boolean;\n};\n\ntype ParsedCartRequestResult =\n | { type: \"action\"; action: CartAction; bodyCartId: string | null }\n | { type: \"response\"; response: CartPostResult };\n\ntype CartGetHandlerContext = {\n storefrontClient: StorefrontClient;\n request?: Request;\n};\n\ntype CartPostHandlerContext = {\n request: Request;\n storefrontClient: StorefrontClient;\n};\n\ntype CartCustomerSessionReadContext = {\n sessionManager: ReadonlyCustomerSessionManager;\n requestContext: ShopifyRequestContext;\n};\n\ntype CartCustomerSessionWriteContext = {\n sessionManager: WritableCustomerSessionManager;\n requestContext: ShopifyRequestContext;\n};\n\ntype CartCustomerSession = CustomerSession;\n\nexport type CartGetHandler<\n TCart = CartData,\n TContext extends CartGetHandlerContext = CartGetHandlerContext,\n> = CallableRouteHandler<\n TContext,\n CartGetResult<TCart>,\n typeof CART_API_PATH,\n typeof CART_GET_METHOD\n>;\n\nexport type CartPostHandler<TContext extends CartPostHandlerContext = CartPostHandlerContext> =\n CallableRouteHandler<TContext, CartPostResult, typeof CART_API_PATH, typeof CART_POST_METHOD>;\n\nexport type CartServerHandlers<\n TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart,\n TCart extends CartData = CartDataFromQuery<TCartQuery>,\n> = {\n readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;\n get: CartGetHandler<TCart>;\n post: CartPostHandler;\n};\n\nexport type CartServerHandlersWithCustomerSession<\n TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart,\n TCart extends CartData = CartDataFromQuery<TCartQuery>,\n> = {\n readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;\n readonly [cartBuyerIdentitySync]: CartBuyerIdentitySync;\n get: CartGetHandler<TCart, CartGetHandlerContext & CartCustomerSessionReadContext>;\n post: CartPostHandler<CartPostHandlerContext & CartCustomerSessionWriteContext>;\n};\n\ntype AsyncHandlerResult<THandler> = THandler extends (\n ...args: infer _Args\n) => Promise<infer TResult>\n ? TResult\n : never;\n\ntype CartGetHandlerResult<THandlers> = THandlers extends { get: infer THandler }\n ? AsyncHandlerResult<THandler>\n : never;\n\ntype CartDataFromHandlerResult<TResult> = [TResult] extends [never]\n ? never\n : TResult extends { data: { cart: infer TCart } }\n ? NonNullable<TCart> extends CartData\n ? NonNullable<TCart>\n : CartData\n : CartData;\n\nexport type CartDataFromHandlers<THandlers> = CartDataFromHandlerResult<\n CartGetHandlerResult<THandlers>\n>;\n\nexport type CreateCartServerHandlersOptions<\n TCartFragment extends AnyStorefrontQueryString = AnyStorefrontQueryString,\n> = {\n readonly fragment?: TCartFragment;\n} & ({ readonly customerSession: CartCustomerSession } | { readonly customerSession?: undefined });\n\ntype CartServerHandlersForOptions<TOptions> = TOptions extends {\n readonly customerSession: CartCustomerSession;\n}\n ? CartServerHandlersWithCustomerSession<\n CartQueriesForOptions<TOptions>[\"cart\"],\n CartDataForOptions<TOptions>\n >\n : CartServerHandlers<CartQueriesForOptions<TOptions>[\"cart\"], CartDataForOptions<TOptions>>;\n\nexport function createCartServerHandlers(): CartServerHandlers<typeof cartQueries.cart>;\nexport function createCartServerHandlers<const TOptions extends CreateCartServerHandlersOptions>(\n options: TOptions,\n): CartServerHandlersForOptions<TOptions>;\nexport function createCartServerHandlers(\n options?: CreateCartServerHandlersOptions,\n): CartServerHandlers | CartServerHandlersWithCustomerSession {\n const queries = options?.fragment\n ? makeCartQueries({ fragment: options.fragment } as CreateCartQueriesOptions)\n : cartQueries;\n const runtimeQueries = queries as RuntimeCartQueries;\n const customerSession = options?.customerSession;\n\n const handlers = {\n get: createCallableRouteHandler(\n CART_API_PATH,\n CART_GET_METHOD,\n (context: CartGetHandlerContext & Partial<CartCustomerSessionReadContext>) =>\n handleGet(context, runtimeQueries, customerSession),\n ),\n post: createCallableRouteHandler(\n CART_API_PATH,\n CART_POST_METHOD,\n (context: CartPostHandlerContext & Partial<CartCustomerSessionWriteContext>) =>\n handlePost(context, runtimeQueries, customerSession),\n ),\n };\n\n Object.defineProperty(handlers, cartServerHandlersCartQuery, { value: queries.cart });\n if (customerSession) {\n // Symbol-keyed and non-enumerable so the capability never registers as a\n // route in handleShopifyRoutes and stays uncallable outside Hydrogen wiring.\n Object.defineProperty(handlers, cartBuyerIdentitySync, {\n value: createCartBuyerIdentitySync(),\n });\n }\n return handlers as CartServerHandlers | CartServerHandlersWithCustomerSession;\n}\n\nfunction createCartBuyerIdentitySync(): CartBuyerIdentitySync {\n return {\n updateBuyerIdentity: updateCartBuyerIdentity,\n expiredCartCookie: createExpiredCartCookie(),\n };\n}\n\nasync function updateCartBuyerIdentity(\n context: CartBuyerIdentitySyncContext,\n customerAccessToken: string | null,\n): Promise<void> {\n const cartId = getCartIdFromCookie(context.request);\n if (!cartId) return;\n\n const result = await context.storefrontClient.graphql(cartBuyerIdentityUpdateMutation, {\n variables: { cartId, buyerIdentity: { customerAccessToken } },\n });\n const { userErrors } = assertMutationData(result, \"cartBuyerIdentityUpdate\");\n if (userErrors.length > 0) {\n throw new Error(userErrors.map(({ message }) => message).join(\"\\n\"));\n }\n}\n\ntype RuntimeCartQueries = typeof cartQueries;\n\nasync function handleGet(\n context: CartGetHandlerContext & Partial<CartCustomerSessionReadContext>,\n queries: RuntimeCartQueries,\n customerSession?: CartCustomerSession,\n): Promise<CartGetResult> {\n const { request, storefrontClient } = context;\n const cartIdSource = request ?? storefrontClient.requestContext;\n const result = await getCart(getCartId(cartIdSource), storefrontClient, queries.cart);\n logCartErrors(result.errors);\n const cart = await addLoggedInCheckoutParam(result.cart, context, customerSession);\n const data = { cart, ...(result.errors && { errors: result.errors }) };\n const headers = createProxyResponseHeaders(result.headers);\n applyPrivateResponseCacheHeaders(headers);\n\n return {\n type: \"json\",\n data,\n headers,\n };\n}\n\nfunction logCartErrors(errors: CartGetData[\"errors\"]): void {\n if (!errors?.length) return;\n log.error(errors.map(({ message }) => message).join(\"\\n\"));\n}\n\nasync function handlePost(\n context: CartPostHandlerContext & Partial<CartCustomerSessionWriteContext>,\n queries: RuntimeCartQueries,\n customerSession?: CartCustomerSession,\n): Promise<CartPostResult> {\n const { request, storefrontClient } = context;\n const isFormRequest = !request.headers.get(\"content-type\")?.includes(\"application/json\");\n const redirectTarget = safeRedirectTarget(request);\n\n const parsedCartRequest = await parseCartAction(request, isFormRequest, redirectTarget);\n if (parsedCartRequest.type === \"response\") return parsedCartRequest.response;\n\n const cookieCartId = getCartIdFromCookie(request);\n const cartId = parsedCartRequest.bodyCartId ?? cookieCartId;\n const missingCartResponse = getMissingCartResponse(\n parsedCartRequest.action,\n cartId,\n isFormRequest,\n redirectTarget,\n );\n if (missingCartResponse) return missingCartResponse;\n\n const { action } = parsedCartRequest;\n const customerAccess = await getCartCreateCustomerAccess(\n parsedCartRequest.action,\n cartId,\n context,\n customerSession,\n );\n const customerSessionHeaders = customerAccess.commitSession\n ? await getCustomerSessionHeaders(context)\n : undefined;\n const result = await executeCartMutation(\n action,\n cartId,\n storefrontClient,\n queries,\n customerAccess.accessToken,\n customerSessionHeaders,\n );\n if (result.type !== \"mutation\") return result.response;\n\n const headers = createProxyResponseHeaders(result.headers);\n appendHeaders(headers, customerSessionHeaders);\n\n // Only persist carts the browser already owns, including newly-created carts.\n if (cartId === cookieCartId && result.cartId !== null && result.cartId !== cookieCartId) {\n headers.append(\"set-cookie\", createCartCookie(result.cartId));\n }\n\n if (isFormRequest) return redirectResult(redirectTarget, headers);\n return jsonResult(result.data, headers);\n}\n\nasync function parseCartAction(\n request: Request,\n isFormRequest: boolean,\n redirectTarget: string,\n): Promise<ParsedCartRequestResult> {\n try {\n const { action, cartId: bodyCartId } = await parseCartRequest(request);\n return { type: \"action\", action, bodyCartId };\n } catch (error) {\n if (isFormRequest) return { type: \"response\", response: redirectResult(redirectTarget) };\n return {\n type: \"response\",\n response: errorResult(\"invalid_cart_request\", getErrorMessage(error, \"Bad Request\")),\n };\n }\n}\n\nfunction getMissingCartResponse(\n action: CartAction,\n cartId: string | null,\n isFormRequest: boolean,\n redirectTarget: string,\n): CartPostResult | undefined {\n if (action.intent === \"add\" || cartId) return undefined;\n if (isFormRequest) return redirectResult(redirectTarget);\n return errorResult(\"missing_cart\", \"No cart exists. Add an item first.\");\n}\n\nasync function executeCartMutation(\n action: CartAction,\n cartId: string | null,\n storefrontClient: StorefrontClient,\n queries: RuntimeCartQueries,\n customerAccessToken: string | undefined,\n customerSessionHeaders: Headers | undefined,\n): Promise<\n ({ type: \"mutation\" } & MutationResult) | { type: \"response\"; response: CartPostResult }\n> {\n try {\n return {\n type: \"mutation\",\n ...(await executeMutation(action, cartId, storefrontClient, queries, customerAccessToken)),\n };\n } catch (error) {\n if (!customerSessionHeaders) throw error;\n log.error(\"cart mutation failed\", { error });\n return {\n type: \"response\",\n response: errorResult(\n \"cart_mutation_failed\",\n CART_MUTATION_FAILED_MESSAGE,\n customerSessionHeaders,\n CART_MUTATION_FAILED_STATUS,\n ),\n };\n }\n}\n\nasync function getCustomerSessionHeaders(\n context: Partial<CartCustomerSessionWriteContext>,\n): Promise<Headers | undefined> {\n assertCustomerSessionWriteContext(context);\n const sessionHeaders = await context.sessionManager.commit?.();\n if (!sessionHeaders) return undefined;\n return new Headers(sessionHeaders);\n}\n\nfunction appendHeaders(headers: Headers, headersToAppend: Headers | undefined) {\n if (!headersToAppend) return;\n for (const [key, value] of headersToAppend) {\n if (key !== \"set-cookie\") headers.append(key, value);\n }\n for (const setCookie of headersToAppend.getSetCookie()) {\n headers.append(\"set-cookie\", setCookie);\n }\n}\n\nfunction safeRedirectTarget(request: Request): string {\n const referer = request.headers.get(\"referer\");\n if (!referer) return \"/\";\n try {\n const refererUrl = new URL(referer);\n const requestUrl = new URL(request.url);\n if (refererUrl.origin !== requestUrl.origin) return \"/\";\n return refererUrl.toString().replace(refererUrl.origin, \"\");\n } catch {\n return \"/\";\n }\n}\n\ntype MutationResult = {\n data: Record<string, unknown>;\n cartId: string | null;\n headers: Headers;\n};\n\ntype GraphQLResult<D> = {\n data: D | null;\n errors?: GraphQLFormattedError[];\n headers: Headers;\n};\n\nfunction assertGraphQLData<D>(result: GraphQLResult<D>): NonNullable<D> {\n if (result.errors || !result.data) {\n const message = result.errors?.[0]?.message ?? \"GraphQL error\";\n throw new Error(message);\n }\n return result.data as NonNullable<D>;\n}\n\nfunction assertMutationData<D, K extends keyof NonNullable<D>>(\n result: GraphQLResult<D>,\n key: K,\n): NonNullable<NonNullable<D>[K]> {\n const data = assertGraphQLData(result);\n const payload = data[key];\n if (payload == null) {\n throw new Error(`Missing ${String(key)} in mutation response`);\n }\n return payload as NonNullable<NonNullable<D>[K]>;\n}\n\nfunction createMutationResult(\n cart: unknown,\n userErrors: unknown,\n warnings: unknown,\n headers: Headers,\n): MutationResult {\n const storefrontCart = (cart ?? null) as Record<string, unknown> | null;\n\n return {\n data: { cart: storefrontCart, userErrors, warnings },\n cartId: typeof storefrontCart?.id === \"string\" ? storefrontCart.id : null,\n headers,\n };\n}\n\ntype CartMutationClient = Pick<StorefrontClient, \"graphql\">;\n\nasync function executeMutation(\n action: CartAction,\n cartId: string | null,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n customerAccessToken?: string,\n): Promise<MutationResult> {\n if (action.intent === \"add\") {\n return executeAdd(action.lines, cartId, storefront, queries, customerAccessToken);\n }\n\n if (!cartId) {\n throw new Error(\"cartId is required for non-add mutations\");\n }\n\n switch (action.intent) {\n case \"update\": {\n const result = await storefront.graphql(queries.cartLinesUpdate, {\n variables: { cartId, lines: action.lines },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"remove\": {\n const result = await storefront.graphql(queries.cartLinesRemove, {\n variables: { cartId, lineIds: action.lineIds },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesRemove\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"discount-update\": {\n const result = await storefront.graphql(queries.cartDiscountCodesUpdate, {\n variables: { cartId, discountCodes: action.discountCodes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartDiscountCodesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"discount-apply\":\n return executeDiscountModify(cartId, \"apply\", action.code, storefront, queries);\n case \"discount-remove\":\n return executeDiscountModify(cartId, \"remove\", action.code, storefront, queries);\n case \"note-update\": {\n const result = await storefront.graphql(queries.cartNoteUpdate, {\n variables: { cartId, note: action.note },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartNoteUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"attributes-update\": {\n const result = await storefront.graphql(queries.cartAttributesUpdate, {\n variables: { cartId, attributes: action.attributes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartAttributesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n default: {\n const _exhaustive: never = action;\n throw new Error(`Unhandled cart action intent: ${(_exhaustive as CartAction).intent}`);\n }\n }\n}\n\nasync function executeAdd(\n lines: CartLineAddInput[],\n cartId: string | null,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n customerAccessToken?: string,\n): Promise<MutationResult> {\n if (cartId) {\n const result = await storefront.graphql(queries.cartLinesAdd, {\n variables: { cartId, lines },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesAdd\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n\n const result = await storefront.graphql(queries.cartCreate, {\n variables: {\n input: {\n lines,\n ...(customerAccessToken && { buyerIdentity: { customerAccessToken } }),\n },\n },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartCreate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n}\n\nasync function getCartCreateCustomerAccess(\n action: CartAction,\n cartId: string | null,\n context: Partial<CartCustomerSessionWriteContext>,\n customerSession?: CartCustomerSession,\n): Promise<CartCustomerAccessTokenResult> {\n if (action.intent !== \"add\" || cartId || !customerSession) {\n return { commitSession: false };\n }\n\n assertCustomerSessionWriteContext(context);\n const accessToken = await customerSession.getAccessToken(\n context.sessionManager,\n context.requestContext,\n );\n if (accessToken) return { accessToken, commitSession: false };\n\n const isLoggedIn = await customerSession.isLoggedIn(\n context.sessionManager,\n context.requestContext,\n );\n if (!isLoggedIn) return { commitSession: false };\n\n const refreshResult = await getCustomerSessionRefreshResult(\n customerSession,\n context.sessionManager,\n context.requestContext,\n );\n if (refreshResult) {\n return {\n accessToken: refreshResult.accessToken,\n commitSession: refreshResult.status !== \"transient\",\n };\n }\n\n const refreshedAccessToken = await customerSession.getOrRefreshAccessToken(\n context.sessionManager,\n context.requestContext,\n );\n return {\n accessToken: refreshedAccessToken,\n commitSession: true,\n };\n}\n\nasync function addLoggedInCheckoutParam<TCart extends CartData>(\n cart: TCart | null,\n context: Partial<CartCustomerSessionReadContext>,\n customerSession?: CartCustomerSession,\n): Promise<TCart | null> {\n if (!cart || !customerSession) return cart;\n assertCustomerSessionReadContext(context);\n if (!(await customerSession.isLoggedIn(context.sessionManager, context.requestContext)))\n return cart;\n if (!cart.checkoutUrl) return cart;\n\n const checkoutUrl = new URL(cart.checkoutUrl);\n checkoutUrl.searchParams.set(\"logged_in\", \"true\");\n return { ...cart, checkoutUrl: checkoutUrl.toString() };\n}\n\nfunction assertCustomerSessionContext(\n context: Partial<CartCustomerSessionReadContext | CartCustomerSessionWriteContext>,\n): void {\n if (context.sessionManager && context.requestContext) return;\n throw new Error(\n \"Cart handlers configured with customerSession require sessionManager and requestContext.\",\n );\n}\n\nfunction assertCustomerSessionReadContext(\n context: Partial<CartCustomerSessionReadContext>,\n): asserts context is CartCustomerSessionReadContext {\n assertCustomerSessionContext(context);\n}\n\nfunction assertCustomerSessionWriteContext(\n context: Partial<CartCustomerSessionWriteContext>,\n): asserts context is CartCustomerSessionWriteContext {\n assertCustomerSessionContext(context);\n}\n\nasync function executeDiscountModify(\n cartId: string,\n mode: \"apply\" | \"remove\",\n code: string,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n): Promise<MutationResult> {\n // Read-then-write: SFAPI has no atomic discount modify endpoint, so concurrent\n // requests can overwrite each other's discount codes.\n const cartResult = await storefront.graphql(queries.cart, {\n variables: { id: cartId },\n });\n const cartData = assertGraphQLData(cartResult);\n\n const currentCodes: string[] = (cartData.cart?.discountCodes ?? []).map((dc) => dc.code);\n\n const updatedCodes =\n mode === \"apply\" ? [...currentCodes, code] : currentCodes.filter((c) => c !== code);\n\n const result = await storefront.graphql(queries.cartDiscountCodesUpdate, {\n variables: { cartId, discountCodes: updatedCodes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartDiscountCodesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n}\n\nfunction jsonResult<TData>(data: TData, headers: HeadersInit = {}): ShopifyRouteJsonResult<TData> {\n return { type: \"json\", data, headers };\n}\n\nfunction redirectResult(location: string, headers: HeadersInit = {}): ShopifyRouteRedirectResult {\n return { type: \"redirect\", location, headers };\n}\n\nfunction errorResult(\n code: CartErrorCode,\n message: string,\n headers?: HeadersInit,\n status?: number,\n): ShopifyRouteErrorResult<CartError> {\n return {\n type: \"error\",\n error: { code, message },\n ...(headers && { headers }),\n ...(status !== undefined && { status }),\n };\n}\n\nfunction getErrorMessage(error: unknown, fallback: string): string {\n if (error instanceof Error) return error.message;\n return fallback;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server-handlers.mjs","names":["_exhaustive"],"sources":["../../../src/core/cart/server-handlers.ts"],"sourcesContent":["import type { GraphQLFormattedError, StorefrontClient } from \"../../client\";\nimport type {\n CustomerSession,\n ReadonlyCustomerSessionManager,\n WritableCustomerSessionManager,\n} from \"../../customer-account/session\";\nimport { getCustomerSessionRefreshResult } from \"../../customer-account/session\";\nimport type { AnyStorefrontQueryString } from \"../../graphql\";\nimport { applyPrivateResponseCacheHeaders } from \"../headers\";\nimport { getLogger } from \"../logging\";\nimport type { ShopifyRequestContext } from \"../request-context\";\nimport { createProxyResponseHeaders } from \"../request-routing/interceptors/proxy\";\nimport type {\n CallableRouteHandler,\n ShopifyRouteError,\n ShopifyRouteErrorResult,\n ShopifyRouteJsonResult,\n ShopifyRouteRedirectResult,\n} from \"../request-routing/registered-routes\";\nimport { createCallableRouteHandler } from \"../request-routing/registered-routes\";\nimport { getSameOriginPath } from \"../url\";\nimport { parseCartRequest } from \"./actions\";\nimport type { CartAction, CartLineAddInput } from \"./actions\";\nimport {\n cartBuyerIdentitySync,\n type CartBuyerIdentitySync,\n type CartBuyerIdentitySyncContext,\n} from \"./buyer-identity-sync\";\nimport { getCartIdFromCookie, createCartCookie, createExpiredCartCookie } from \"./cookie\";\nimport { getCart, getCartId, type CartDataFromQuery } from \"./get-cart\";\nimport {\n cartBuyerIdentityUpdateMutation,\n cartQueries,\n makeCartQueries,\n type CartDataForOptions,\n type CartQueriesForOptions,\n type CreateCartQueriesOptions,\n} from \"./queries\";\nimport type { CartData } from \"./state\";\nconst log = getLogger(\"cart-api\");\n\nconst CART_API_PATH = \"/api/cart\" as const;\nconst CART_GET_METHOD = \"GET\" as const;\nconst CART_POST_METHOD = \"POST\" as const;\nconst CART_MUTATION_FAILED_STATUS = 500;\nconst CART_MUTATION_FAILED_MESSAGE = \"Cart mutation failed. Please try again.\";\nconst cartServerHandlersCartQuery: unique symbol = Symbol(\"hydrogen.cartQuery\");\n\n/** Response shape from the cart GET handler — the fetched cart plus any GraphQL errors. */\nexport type CartGetData<TCart = CartData> = {\n cart: TCart | null;\n errors?: Array<{ message: string }>;\n};\n\n/** Full route result from the cart GET handler — JSON with {@link CartGetData} payload and response headers. */\nexport type CartGetResult<TCart = CartData> = ShopifyRouteJsonResult<CartGetData<TCart>>;\n\n/** Machine-readable error codes returned by the cart POST handler. */\nexport type CartErrorCode = \"invalid_cart_request\" | \"missing_cart\" | \"cart_mutation_failed\";\n\n/** A cart route error carrying a {@link CartErrorCode} for programmatic handling. */\nexport type CartError = ShopifyRouteError & {\n code: CartErrorCode;\n};\n\n/**\n * Result from the cart POST handler — one of:\n * - JSON with the mutation payload (programmatic clients)\n * - 303 redirect back to the referrer (HTML form submissions)\n * - An error with a {@link CartErrorCode}\n */\nexport type CartPostResult =\n | ShopifyRouteJsonResult<Record<string, unknown>>\n | ShopifyRouteRedirectResult\n | ShopifyRouteErrorResult<CartError>;\n\ntype CartCustomerAccessTokenResult = {\n accessToken?: string;\n commitSession: boolean;\n};\n\ntype ParsedCartRequestResult =\n | { type: \"action\"; action: CartAction; bodyCartId: string | null }\n | { type: \"response\"; response: CartPostResult };\n\ntype CartGetHandlerContext = {\n storefrontClient: StorefrontClient;\n request?: Request;\n};\n\ntype CartPostHandlerContext = {\n request: Request;\n storefrontClient: StorefrontClient;\n};\n\ntype CartCustomerSessionReadContext = {\n sessionManager: ReadonlyCustomerSessionManager;\n requestContext: ShopifyRequestContext;\n};\n\ntype CartCustomerSessionWriteContext = {\n sessionManager: WritableCustomerSessionManager;\n requestContext: ShopifyRequestContext;\n};\n\ntype CartCustomerSession = CustomerSession;\n\n/** GET handler for the `/api/cart` route — fetches the current cart from the Storefront API. */\nexport type CartGetHandler<\n TCart = CartData,\n TContext extends CartGetHandlerContext = CartGetHandlerContext,\n> = CallableRouteHandler<\n TContext,\n CartGetResult<TCart>,\n typeof CART_API_PATH,\n typeof CART_GET_METHOD\n>;\n\n/** POST handler for the `/api/cart` route — processes cart mutations from JSON or FormData bodies. */\nexport type CartPostHandler<TContext extends CartPostHandlerContext = CartPostHandlerContext> =\n CallableRouteHandler<TContext, CartPostResult, typeof CART_API_PATH, typeof CART_POST_METHOD>;\n\n/**\n * GET and POST handlers for the `/api/cart` route.\n *\n * Created by {@link createCartServerHandlers}. Register these with your\n * framework's router so the client cart store can communicate with the\n * Storefront API.\n */\nexport type CartServerHandlers<\n TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart,\n TCart extends CartData = CartDataFromQuery<TCartQuery>,\n> = {\n readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;\n get: CartGetHandler<TCart>;\n post: CartPostHandler;\n};\n\n/**\n * {@link CartServerHandlers} variant that additionally syncs the cart's buyer\n * identity with a customer session — the handler contexts require a session\n * manager and request context.\n *\n * Created by passing `customerSession` to {@link createCartServerHandlers}.\n */\nexport type CartServerHandlersWithCustomerSession<\n TCartQuery extends AnyStorefrontQueryString = typeof cartQueries.cart,\n TCart extends CartData = CartDataFromQuery<TCartQuery>,\n> = {\n readonly [cartServerHandlersCartQuery]: TCartQuery | undefined;\n readonly [cartBuyerIdentitySync]: CartBuyerIdentitySync;\n get: CartGetHandler<TCart, CartGetHandlerContext & CartCustomerSessionReadContext>;\n post: CartPostHandler<CartPostHandlerContext & CartCustomerSessionWriteContext>;\n};\n\ntype AsyncHandlerResult<THandler> = THandler extends (\n ...args: infer _Args\n) => Promise<infer TResult>\n ? TResult\n : never;\n\ntype CartGetHandlerResult<THandlers> = THandlers extends { get: infer THandler }\n ? AsyncHandlerResult<THandler>\n : never;\n\ntype CartDataFromHandlerResult<TResult> = [TResult] extends [never]\n ? never\n : TResult extends { data: { cart: infer TCart } }\n ? NonNullable<TCart> extends CartData\n ? NonNullable<TCart>\n : CartData\n : CartData;\n\n/**\n * Infers the {@link CartData} shape from a {@link CartServerHandlers} instance.\n *\n * Use this to type framework components and hooks so they match the server\n * handler's custom cart query without repeating the generic parameter.\n *\n * @example\n * ```ts\n * type MyCartData = CartDataFromHandlers<typeof cartHandlers>;\n * ```\n */\nexport type CartDataFromHandlers<THandlers> = CartDataFromHandlerResult<\n CartGetHandlerResult<THandlers>\n>;\n\n/** Options for {@link createCartServerHandlers}. */\nexport type CreateCartServerHandlersOptions<\n TCartFragment extends AnyStorefrontQueryString = AnyStorefrontQueryString,\n> = {\n /**\n * Custom cart GraphQL fragment spread into every query and mutation response.\n * The fragment must be named `CartFragment` and target `Cart`.\n */\n readonly fragment?: TCartFragment;\n} & ({ readonly customerSession: CartCustomerSession } | { readonly customerSession?: undefined });\n\ntype CartServerHandlersForOptions<TOptions> = TOptions extends {\n readonly customerSession: CartCustomerSession;\n}\n ? CartServerHandlersWithCustomerSession<\n CartQueriesForOptions<TOptions>[\"cart\"],\n CartDataForOptions<TOptions>\n >\n : CartServerHandlers<CartQueriesForOptions<TOptions>[\"cart\"], CartDataForOptions<TOptions>>;\n\n/**\n * Creates GET and POST handlers for the `/api/cart` route.\n *\n * The handlers parse incoming requests (JSON or FormData), resolve the cart\n * identity from a cookie, execute the matching Storefront API mutation, and\n * return either JSON (programmatic clients) or a 303 redirect (form submissions).\n *\n * Pass `customerSession` to additionally sync the cart's buyer identity with\n * the logged-in customer — the returned handlers then require a session manager\n * in their context.\n *\n * @example\n * ```ts\n * // Basic setup\n * const cartHandlers = createCartServerHandlers();\n *\n * // With a custom cart fragment\n * const cartHandlers = createCartServerHandlers({\n * fragment: CART_FRAGMENT,\n * });\n *\n * // With customer session for buyer identity sync\n * const cartHandlers = createCartServerHandlers({\n * customerSession,\n * });\n * ```\n */\nexport function createCartServerHandlers(): CartServerHandlers<typeof cartQueries.cart>;\nexport function createCartServerHandlers<const TOptions extends CreateCartServerHandlersOptions>(\n options: TOptions,\n): CartServerHandlersForOptions<TOptions>;\nexport function createCartServerHandlers(\n options?: CreateCartServerHandlersOptions,\n): CartServerHandlers | CartServerHandlersWithCustomerSession {\n const queries = options?.fragment\n ? makeCartQueries({ fragment: options.fragment } as CreateCartQueriesOptions)\n : cartQueries;\n const runtimeQueries = queries as RuntimeCartQueries;\n const customerSession = options?.customerSession;\n\n const handlers = {\n get: createCallableRouteHandler(\n CART_API_PATH,\n CART_GET_METHOD,\n (context: CartGetHandlerContext & Partial<CartCustomerSessionReadContext>) =>\n handleGet(context, runtimeQueries, customerSession),\n ),\n post: createCallableRouteHandler(\n CART_API_PATH,\n CART_POST_METHOD,\n (context: CartPostHandlerContext & Partial<CartCustomerSessionWriteContext>) =>\n handlePost(context, runtimeQueries, customerSession),\n ),\n };\n\n Object.defineProperty(handlers, cartServerHandlersCartQuery, { value: queries.cart });\n if (customerSession) {\n // Symbol-keyed and non-enumerable so the capability never registers as a\n // route in handleShopifyRoutes and stays uncallable outside Hydrogen wiring.\n Object.defineProperty(handlers, cartBuyerIdentitySync, {\n value: createCartBuyerIdentitySync(),\n });\n }\n return handlers as CartServerHandlers | CartServerHandlersWithCustomerSession;\n}\n\nfunction createCartBuyerIdentitySync(): CartBuyerIdentitySync {\n return {\n updateBuyerIdentity: updateCartBuyerIdentity,\n expiredCartCookie: createExpiredCartCookie(),\n };\n}\n\nasync function updateCartBuyerIdentity(\n context: CartBuyerIdentitySyncContext,\n customerAccessToken: string | null,\n): Promise<void> {\n const cartId = getCartIdFromCookie(context.request);\n if (!cartId) return;\n\n const result = await context.storefrontClient.graphql(cartBuyerIdentityUpdateMutation, {\n variables: { cartId, buyerIdentity: { customerAccessToken } },\n });\n const { userErrors } = assertMutationData(result, \"cartBuyerIdentityUpdate\");\n if (userErrors.length > 0) {\n throw new Error(userErrors.map(({ message }) => message).join(\"\\n\"));\n }\n}\n\ntype RuntimeCartQueries = typeof cartQueries;\n\nasync function handleGet(\n context: CartGetHandlerContext & Partial<CartCustomerSessionReadContext>,\n queries: RuntimeCartQueries,\n customerSession?: CartCustomerSession,\n): Promise<CartGetResult> {\n const { request, storefrontClient } = context;\n const cartIdSource = request ?? storefrontClient.requestContext;\n const result = await getCart(getCartId(cartIdSource), storefrontClient, queries.cart);\n logCartErrors(result.errors);\n const cart = await addLoggedInCheckoutParam(result.cart, context, customerSession);\n const data = { cart, ...(result.errors && { errors: result.errors }) };\n const headers = createProxyResponseHeaders(result.headers);\n applyPrivateResponseCacheHeaders(headers);\n\n return {\n type: \"json\",\n data,\n headers,\n };\n}\n\nfunction logCartErrors(errors: CartGetData[\"errors\"]): void {\n if (!errors?.length) return;\n log.error(errors.map(({ message }) => message).join(\"\\n\"));\n}\n\nasync function handlePost(\n context: CartPostHandlerContext & Partial<CartCustomerSessionWriteContext>,\n queries: RuntimeCartQueries,\n customerSession?: CartCustomerSession,\n): Promise<CartPostResult> {\n const { request, storefrontClient } = context;\n const isFormRequest = !request.headers.get(\"content-type\")?.includes(\"application/json\");\n const redirectTarget = safeRedirectTarget(request);\n\n const parsedCartRequest = await parseCartAction(request, isFormRequest, redirectTarget);\n if (parsedCartRequest.type === \"response\") return parsedCartRequest.response;\n\n const cookieCartId = getCartIdFromCookie(request);\n const cartId = parsedCartRequest.bodyCartId ?? cookieCartId;\n const missingCartResponse = getMissingCartResponse(\n parsedCartRequest.action,\n cartId,\n isFormRequest,\n redirectTarget,\n );\n if (missingCartResponse) return missingCartResponse;\n\n const { action } = parsedCartRequest;\n const customerAccess = await getCartCreateCustomerAccess(\n parsedCartRequest.action,\n cartId,\n context,\n customerSession,\n );\n const customerSessionHeaders = customerAccess.commitSession\n ? await getCustomerSessionHeaders(context)\n : undefined;\n const result = await executeCartMutation(\n action,\n cartId,\n storefrontClient,\n queries,\n customerAccess.accessToken,\n customerSessionHeaders,\n );\n if (result.type !== \"mutation\") return result.response;\n\n const headers = createProxyResponseHeaders(result.headers);\n appendHeaders(headers, customerSessionHeaders);\n\n // Only persist carts the browser already owns, including newly-created carts.\n if (cartId === cookieCartId && result.cartId !== null && result.cartId !== cookieCartId) {\n headers.append(\"set-cookie\", createCartCookie(result.cartId));\n }\n\n if (isFormRequest) return redirectResult(redirectTarget, headers);\n return jsonResult(result.data, headers);\n}\n\nasync function parseCartAction(\n request: Request,\n isFormRequest: boolean,\n redirectTarget: string,\n): Promise<ParsedCartRequestResult> {\n try {\n const { action, cartId: bodyCartId } = await parseCartRequest(request);\n return { type: \"action\", action, bodyCartId };\n } catch (error) {\n if (isFormRequest) return { type: \"response\", response: redirectResult(redirectTarget) };\n return {\n type: \"response\",\n response: errorResult(\"invalid_cart_request\", getErrorMessage(error, \"Bad Request\")),\n };\n }\n}\n\nfunction getMissingCartResponse(\n action: CartAction,\n cartId: string | null,\n isFormRequest: boolean,\n redirectTarget: string,\n): CartPostResult | undefined {\n if (action.intent === \"add\" || cartId) return undefined;\n if (isFormRequest) return redirectResult(redirectTarget);\n return errorResult(\"missing_cart\", \"No cart exists. Add an item first.\");\n}\n\nasync function executeCartMutation(\n action: CartAction,\n cartId: string | null,\n storefrontClient: StorefrontClient,\n queries: RuntimeCartQueries,\n customerAccessToken: string | undefined,\n customerSessionHeaders: Headers | undefined,\n): Promise<\n ({ type: \"mutation\" } & MutationResult) | { type: \"response\"; response: CartPostResult }\n> {\n try {\n return {\n type: \"mutation\",\n ...(await executeMutation(action, cartId, storefrontClient, queries, customerAccessToken)),\n };\n } catch (error) {\n if (!customerSessionHeaders) throw error;\n log.error(\"cart mutation failed\", { error });\n return {\n type: \"response\",\n response: errorResult(\n \"cart_mutation_failed\",\n CART_MUTATION_FAILED_MESSAGE,\n customerSessionHeaders,\n CART_MUTATION_FAILED_STATUS,\n ),\n };\n }\n}\n\nasync function getCustomerSessionHeaders(\n context: Partial<CartCustomerSessionWriteContext>,\n): Promise<Headers | undefined> {\n assertCustomerSessionWriteContext(context);\n const sessionHeaders = await context.sessionManager.commit?.();\n if (!sessionHeaders) return undefined;\n return new Headers(sessionHeaders);\n}\n\nfunction appendHeaders(headers: Headers, headersToAppend: Headers | undefined) {\n if (!headersToAppend) return;\n for (const [key, value] of headersToAppend) {\n if (key !== \"set-cookie\") headers.append(key, value);\n }\n for (const setCookie of headersToAppend.getSetCookie()) {\n headers.append(\"set-cookie\", setCookie);\n }\n}\n\nfunction safeRedirectTarget(request: Request): string {\n return getSameOriginPath(request.headers.get(\"referer\"), new URL(request.url).origin) ?? \"/\";\n}\n\ntype MutationResult = {\n data: Record<string, unknown>;\n cartId: string | null;\n headers: Headers;\n};\n\ntype GraphQLResult<D> = {\n data: D | null;\n errors?: GraphQLFormattedError[];\n headers: Headers;\n};\n\nfunction assertGraphQLData<D>(result: GraphQLResult<D>): NonNullable<D> {\n if (result.errors || !result.data) {\n const message = result.errors?.[0]?.message ?? \"GraphQL error\";\n throw new Error(message);\n }\n return result.data as NonNullable<D>;\n}\n\nfunction assertMutationData<D, K extends keyof NonNullable<D>>(\n result: GraphQLResult<D>,\n key: K,\n): NonNullable<NonNullable<D>[K]> {\n const data = assertGraphQLData(result);\n const payload = data[key];\n if (payload == null) {\n throw new Error(`Missing ${String(key)} in mutation response`);\n }\n return payload as NonNullable<NonNullable<D>[K]>;\n}\n\nfunction createMutationResult(\n cart: unknown,\n userErrors: unknown,\n warnings: unknown,\n headers: Headers,\n): MutationResult {\n const storefrontCart = (cart ?? null) as Record<string, unknown> | null;\n\n return {\n data: { cart: storefrontCart, userErrors, warnings },\n cartId: typeof storefrontCart?.id === \"string\" ? storefrontCart.id : null,\n headers,\n };\n}\n\ntype CartMutationClient = Pick<StorefrontClient, \"graphql\">;\n\nasync function executeMutation(\n action: CartAction,\n cartId: string | null,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n customerAccessToken?: string,\n): Promise<MutationResult> {\n if (action.intent === \"add\") {\n return executeAdd(action.lines, cartId, storefront, queries, customerAccessToken);\n }\n\n if (!cartId) {\n throw new Error(\"cartId is required for non-add mutations\");\n }\n\n switch (action.intent) {\n case \"update\": {\n const result = await storefront.graphql(queries.cartLinesUpdate, {\n variables: { cartId, lines: action.lines },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"remove\": {\n const result = await storefront.graphql(queries.cartLinesRemove, {\n variables: { cartId, lineIds: action.lineIds },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesRemove\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"discount-update\": {\n const result = await storefront.graphql(queries.cartDiscountCodesUpdate, {\n variables: { cartId, discountCodes: action.discountCodes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartDiscountCodesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"discount-apply\":\n return executeDiscountModify(cartId, \"apply\", action.code, storefront, queries);\n case \"discount-remove\":\n return executeDiscountModify(cartId, \"remove\", action.code, storefront, queries);\n case \"note-update\": {\n const result = await storefront.graphql(queries.cartNoteUpdate, {\n variables: { cartId, note: action.note },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartNoteUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n case \"attributes-update\": {\n const result = await storefront.graphql(queries.cartAttributesUpdate, {\n variables: { cartId, attributes: action.attributes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartAttributesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n default: {\n const _exhaustive: never = action;\n throw new Error(`Unhandled cart action intent: ${(_exhaustive as CartAction).intent}`);\n }\n }\n}\n\nasync function executeAdd(\n lines: CartLineAddInput[],\n cartId: string | null,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n customerAccessToken?: string,\n): Promise<MutationResult> {\n if (cartId) {\n const result = await storefront.graphql(queries.cartLinesAdd, {\n variables: { cartId, lines },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartLinesAdd\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n }\n\n const result = await storefront.graphql(queries.cartCreate, {\n variables: {\n input: {\n lines,\n ...(customerAccessToken && { buyerIdentity: { customerAccessToken } }),\n },\n },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartCreate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n}\n\nasync function getCartCreateCustomerAccess(\n action: CartAction,\n cartId: string | null,\n context: Partial<CartCustomerSessionWriteContext>,\n customerSession?: CartCustomerSession,\n): Promise<CartCustomerAccessTokenResult> {\n if (action.intent !== \"add\" || cartId || !customerSession) {\n return { commitSession: false };\n }\n\n assertCustomerSessionWriteContext(context);\n const accessToken = await customerSession.getAccessToken(\n context.sessionManager,\n context.requestContext,\n );\n if (accessToken) return { accessToken, commitSession: false };\n\n const isLoggedIn = await customerSession.isLoggedIn(\n context.sessionManager,\n context.requestContext,\n );\n if (!isLoggedIn) return { commitSession: false };\n\n const refreshResult = await getCustomerSessionRefreshResult(\n customerSession,\n context.sessionManager,\n context.requestContext,\n );\n if (refreshResult) {\n return {\n accessToken: refreshResult.accessToken,\n commitSession: refreshResult.status !== \"transient\",\n };\n }\n\n const refreshedAccessToken = await customerSession.getOrRefreshAccessToken(\n context.sessionManager,\n context.requestContext,\n );\n return {\n accessToken: refreshedAccessToken,\n commitSession: true,\n };\n}\n\nasync function addLoggedInCheckoutParam<TCart extends CartData>(\n cart: TCart | null,\n context: Partial<CartCustomerSessionReadContext>,\n customerSession?: CartCustomerSession,\n): Promise<TCart | null> {\n if (!cart || !customerSession) return cart;\n assertCustomerSessionReadContext(context);\n if (!(await customerSession.isLoggedIn(context.sessionManager, context.requestContext)))\n return cart;\n if (!cart.checkoutUrl) return cart;\n\n const checkoutUrl = new URL(cart.checkoutUrl);\n checkoutUrl.searchParams.set(\"logged_in\", \"true\");\n return { ...cart, checkoutUrl: checkoutUrl.toString() };\n}\n\nfunction assertCustomerSessionContext(\n context: Partial<CartCustomerSessionReadContext | CartCustomerSessionWriteContext>,\n): void {\n if (context.sessionManager && context.requestContext) return;\n throw new Error(\n \"Cart handlers configured with customerSession require sessionManager and requestContext.\",\n );\n}\n\nfunction assertCustomerSessionReadContext(\n context: Partial<CartCustomerSessionReadContext>,\n): asserts context is CartCustomerSessionReadContext {\n assertCustomerSessionContext(context);\n}\n\nfunction assertCustomerSessionWriteContext(\n context: Partial<CartCustomerSessionWriteContext>,\n): asserts context is CartCustomerSessionWriteContext {\n assertCustomerSessionContext(context);\n}\n\nasync function executeDiscountModify(\n cartId: string,\n mode: \"apply\" | \"remove\",\n code: string,\n storefront: CartMutationClient,\n queries: RuntimeCartQueries,\n): Promise<MutationResult> {\n // Read-then-write: SFAPI has no atomic discount modify endpoint, so concurrent\n // requests can overwrite each other's discount codes.\n const cartResult = await storefront.graphql(queries.cart, {\n variables: { id: cartId },\n });\n const cartData = assertGraphQLData(cartResult);\n\n const currentCodes: string[] = (cartData.cart?.discountCodes ?? []).map((dc) => dc.code);\n\n const updatedCodes =\n mode === \"apply\" ? [...currentCodes, code] : currentCodes.filter((c) => c !== code);\n\n const result = await storefront.graphql(queries.cartDiscountCodesUpdate, {\n variables: { cartId, discountCodes: updatedCodes },\n });\n const { cart, userErrors, warnings } = assertMutationData(result, \"cartDiscountCodesUpdate\");\n return createMutationResult(cart, userErrors, warnings, result.headers);\n}\n\nfunction jsonResult<TData>(data: TData, headers: HeadersInit = {}): ShopifyRouteJsonResult<TData> {\n return { type: \"json\", data, headers };\n}\n\nfunction redirectResult(location: string, headers: HeadersInit = {}): ShopifyRouteRedirectResult {\n return { type: \"redirect\", location, headers };\n}\n\nfunction errorResult(\n code: CartErrorCode,\n message: string,\n headers?: HeadersInit,\n status?: number,\n): ShopifyRouteErrorResult<CartError> {\n return {\n type: \"error\",\n error: { code, message },\n ...(headers && { headers }),\n ...(status !== undefined && { status }),\n };\n}\n\nfunction getErrorMessage(error: unknown, fallback: string): string {\n if (error instanceof Error) return error.message;\n return fallback;\n}\n"],"mappings":"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"}