@shopify/hydrogen 2026.10.0-preview.4 → 2026.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/dist/cli/index.mjs +23 -12
  2. package/dist/client/client.d.mts +18 -15
  3. package/dist/client/client.mjs +8 -3
  4. package/dist/client/client.mjs.map +1 -1
  5. package/dist/client/errors.d.mts +35 -13
  6. package/dist/client/errors.mjs +23 -13
  7. package/dist/client/errors.mjs.map +1 -1
  8. package/dist/client/types.d.mts +140 -90
  9. package/dist/core/analytics/cart-tracker.d.mts +19 -10
  10. package/dist/core/analytics/cart-tracker.mjs +18 -10
  11. package/dist/core/analytics/cart-tracker.mjs.map +1 -1
  12. package/dist/core/analytics/events.d.mts +17 -11
  13. package/dist/core/analytics/events.mjs +13 -4
  14. package/dist/core/analytics/events.mjs.map +1 -1
  15. package/dist/core/analytics/types.d.mts +207 -118
  16. package/dist/core/analytics/utils/flatten-connection.d.mts +11 -9
  17. package/dist/core/analytics/utils/flatten-connection.mjs +7 -6
  18. package/dist/core/analytics/utils/flatten-connection.mjs.map +1 -1
  19. package/dist/core/cache/fetch-with-cache.d.mts +24 -4
  20. package/dist/core/cache/fetch-with-cache.mjs +17 -2
  21. package/dist/core/cache/fetch-with-cache.mjs.map +1 -1
  22. package/dist/core/cache/key.d.mts +2 -0
  23. package/dist/core/cache/key.mjs.map +1 -1
  24. package/dist/core/cache/run-with-cache.d.mts +56 -8
  25. package/dist/core/cache/run-with-cache.mjs +17 -6
  26. package/dist/core/cache/run-with-cache.mjs.map +1 -1
  27. package/dist/core/cache/store.d.mts +8 -6
  28. package/dist/core/cache/store.mjs.map +1 -1
  29. package/dist/core/cache/strategies.d.mts +27 -2
  30. package/dist/core/cache/strategies.mjs +6 -0
  31. package/dist/core/cache/strategies.mjs.map +1 -1
  32. package/dist/core/cart/actions.d.mts +37 -30
  33. package/dist/core/cart/actions.mjs +21 -9
  34. package/dist/core/cart/actions.mjs.map +1 -1
  35. package/dist/core/cart/attach-quantity-input.d.mts +8 -7
  36. package/dist/core/cart/attach-quantity-input.mjs +8 -7
  37. package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
  38. package/dist/core/cart/buyer-identity-sync.d.mts +7 -6
  39. package/dist/core/cart/buyer-identity-sync.mjs.map +1 -1
  40. package/dist/core/cart/cart.d.mts +59 -46
  41. package/dist/core/cart/cart.mjs +46 -29
  42. package/dist/core/cart/cart.mjs.map +1 -1
  43. package/dist/core/cart/cookie.d.mts +8 -4
  44. package/dist/core/cart/cookie.mjs +8 -4
  45. package/dist/core/cart/cookie.mjs.map +1 -1
  46. package/dist/core/cart/form.d.mts +34 -20
  47. package/dist/core/cart/form.mjs +6 -4
  48. package/dist/core/cart/form.mjs.map +1 -1
  49. package/dist/core/cart/get-cart.d.mts +27 -15
  50. package/dist/core/cart/get-cart.mjs +13 -8
  51. package/dist/core/cart/get-cart.mjs.map +1 -1
  52. package/dist/core/cart/quantity.d.mts +16 -5
  53. package/dist/core/cart/quantity.mjs +16 -5
  54. package/dist/core/cart/quantity.mjs.map +1 -1
  55. package/dist/core/cart/queries.d.mts +25 -19
  56. package/dist/core/cart/queries.mjs +15 -1
  57. package/dist/core/cart/queries.mjs.map +1 -1
  58. package/dist/core/cart/server-handlers.d.mts +82 -45
  59. package/dist/core/cart/server-handlers.mjs +4 -0
  60. package/dist/core/cart/server-handlers.mjs.map +1 -1
  61. package/dist/core/cart/state.d.mts +110 -64
  62. package/dist/core/cart/state.mjs +24 -6
  63. package/dist/core/cart/state.mjs.map +1 -1
  64. package/dist/core/collection/collection.d.mts +52 -53
  65. package/dist/core/collection/collection.mjs +5 -3
  66. package/dist/core/collection/collection.mjs.map +1 -1
  67. package/dist/core/collection/reconciler.d.mts +23 -16
  68. package/dist/core/collection/reconciler.mjs +8 -4
  69. package/dist/core/collection/reconciler.mjs.map +1 -1
  70. package/dist/core/collection/state.d.mts +31 -26
  71. package/dist/core/collection/state.mjs +4 -3
  72. package/dist/core/collection/state.mjs.map +1 -1
  73. package/dist/core/collection/url.d.mts +70 -29
  74. package/dist/core/collection/url.mjs +63 -25
  75. package/dist/core/collection/url.mjs.map +1 -1
  76. package/dist/core/constants.d.mts +1 -0
  77. package/dist/core/constants.mjs +1 -0
  78. package/dist/core/constants.mjs.map +1 -1
  79. package/dist/core/logging/logging.d.mts +14 -8
  80. package/dist/core/logging/logging.mjs +15 -10
  81. package/dist/core/logging/logging.mjs.map +1 -1
  82. package/dist/core/logging/types.d.mts +28 -11
  83. package/dist/core/logging/types.mjs.map +1 -1
  84. package/dist/core/money/format.d.mts +6 -4
  85. package/dist/core/money/format.mjs +19 -9
  86. package/dist/core/money/format.mjs.map +1 -1
  87. package/dist/core/money/types.d.mts +41 -25
  88. package/dist/core/predictive-search/form.d.mts +37 -7
  89. package/dist/core/predictive-search/form.mjs +21 -3
  90. package/dist/core/predictive-search/form.mjs.map +1 -1
  91. package/dist/core/predictive-search/queries.d.mts +18 -30
  92. package/dist/core/predictive-search/queries.mjs +7 -3
  93. package/dist/core/predictive-search/queries.mjs.map +1 -1
  94. package/dist/core/predictive-search/search.d.mts +25 -27
  95. package/dist/core/predictive-search/search.mjs +20 -19
  96. package/dist/core/predictive-search/search.mjs.map +1 -1
  97. package/dist/core/predictive-search/server-handlers.d.mts +25 -26
  98. package/dist/core/predictive-search/server-handlers.mjs +4 -0
  99. package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
  100. package/dist/core/predictive-search/store.d.mts +65 -24
  101. package/dist/core/predictive-search/store.mjs +12 -1
  102. package/dist/core/predictive-search/store.mjs.map +1 -1
  103. package/dist/core/predictive-search/url.d.mts +36 -37
  104. package/dist/core/predictive-search/url.mjs +14 -6
  105. package/dist/core/predictive-search/url.mjs.map +1 -1
  106. package/dist/core/product/form.d.mts +63 -16
  107. package/dist/core/product/form.mjs +8 -2
  108. package/dist/core/product/form.mjs.map +1 -1
  109. package/dist/core/product/options.d.mts +8 -10
  110. package/dist/core/product/options.mjs +8 -10
  111. package/dist/core/product/options.mjs.map +1 -1
  112. package/dist/core/product/product-form.d.mts +77 -29
  113. package/dist/core/product/product-form.mjs +32 -10
  114. package/dist/core/product/product-form.mjs.map +1 -1
  115. package/dist/core/product/state.d.mts +55 -32
  116. package/dist/core/product/url.d.mts +19 -13
  117. package/dist/core/product/url.mjs +10 -10
  118. package/dist/core/product/url.mjs.map +1 -1
  119. package/dist/core/request-context.d.mts +77 -19
  120. package/dist/core/request-context.mjs +5 -1
  121. package/dist/core/request-context.mjs.map +1 -1
  122. package/dist/core/request-routing/handle-shopify-redirects.d.mts +12 -4
  123. package/dist/core/request-routing/handle-shopify-redirects.mjs +9 -2
  124. package/dist/core/request-routing/handle-shopify-redirects.mjs.map +1 -1
  125. package/dist/core/request-routing/handle-shopify-routes.d.mts +5 -5
  126. package/dist/core/request-routing/handle-shopify-routes.mjs +7 -5
  127. package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  128. package/dist/core/request-routing/interceptors/proxy.mjs +79 -43
  129. package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
  130. package/dist/core/request-routing/interceptors/ucp-profile-proxy.mjs +69 -0
  131. package/dist/core/request-routing/interceptors/ucp-profile-proxy.mjs.map +1 -0
  132. package/dist/core/request-routing/interceptors/url-redirects.mjs +6 -1
  133. package/dist/core/request-routing/interceptors/url-redirects.mjs.map +1 -1
  134. package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
  135. package/dist/core/request-routing/interceptors/well-known.mjs.map +1 -1
  136. package/dist/core/request-routing/registered-routes.d.mts +12 -0
  137. package/dist/core/request-routing/registered-routes.mjs +12 -0
  138. package/dist/core/request-routing/registered-routes.mjs.map +1 -1
  139. package/dist/core/request-routing/route-types.d.mts +43 -18
  140. package/dist/core/shop-pay/shop-pay.d.mts +71 -35
  141. package/dist/core/shop-pay/shop-pay.mjs +36 -10
  142. package/dist/core/shop-pay/shop-pay.mjs.map +1 -1
  143. package/dist/core/shopify-scripts/index.d.mts +15 -5
  144. package/dist/core/shopify-scripts/index.mjs +15 -5
  145. package/dist/core/shopify-scripts/index.mjs.map +1 -1
  146. package/dist/core/shopify-scripts/initialize.d.mts +12 -4
  147. package/dist/core/shopify-scripts/initialize.mjs +12 -4
  148. package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
  149. package/dist/core/shopify-scripts/types.d.mts +58 -25
  150. package/dist/core/standard-routes/build.d.mts +11 -12
  151. package/dist/core/standard-routes/build.mjs +11 -12
  152. package/dist/core/standard-routes/build.mjs.map +1 -1
  153. package/dist/core/standard-routes/types.d.mts +30 -24
  154. package/dist/core/url.mjs +2 -1
  155. package/dist/core/url.mjs.map +1 -1
  156. package/dist/customer-account/client.d.mts +36 -69
  157. package/dist/customer-account/client.mjs +7 -8
  158. package/dist/customer-account/client.mjs.map +1 -1
  159. package/dist/customer-account/errors.d.mts +45 -36
  160. package/dist/customer-account/errors.mjs +21 -36
  161. package/dist/customer-account/errors.mjs.map +1 -1
  162. package/dist/customer-account/graphql.d.mts +11 -23
  163. package/dist/customer-account/graphql.mjs +3 -9
  164. package/dist/customer-account/graphql.mjs.map +1 -1
  165. package/dist/customer-account/session.d.mts +130 -100
  166. package/dist/customer-account/session.mjs +32 -10
  167. package/dist/customer-account/session.mjs.map +1 -1
  168. package/dist/customer-account/type-resolver.d.mts +7 -8
  169. package/dist/development/client/client.d.mts +18 -15
  170. package/dist/development/client/client.mjs +8 -3
  171. package/dist/development/client/client.mjs.map +1 -1
  172. package/dist/development/client/errors.d.mts +35 -13
  173. package/dist/development/client/errors.mjs +23 -13
  174. package/dist/development/client/errors.mjs.map +1 -1
  175. package/dist/development/client/types.d.mts +140 -90
  176. package/dist/development/core/analytics/cart-tracker.d.mts +19 -10
  177. package/dist/development/core/analytics/cart-tracker.mjs +18 -10
  178. package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
  179. package/dist/development/core/analytics/events.d.mts +17 -11
  180. package/dist/development/core/analytics/events.mjs +13 -4
  181. package/dist/development/core/analytics/events.mjs.map +1 -1
  182. package/dist/development/core/analytics/types.d.mts +207 -118
  183. package/dist/development/core/analytics/utils/flatten-connection.d.mts +11 -9
  184. package/dist/development/core/analytics/utils/flatten-connection.mjs +7 -6
  185. package/dist/development/core/analytics/utils/flatten-connection.mjs.map +1 -1
  186. package/dist/development/core/cache/fetch-with-cache.d.mts +24 -4
  187. package/dist/development/core/cache/fetch-with-cache.mjs +17 -2
  188. package/dist/development/core/cache/fetch-with-cache.mjs.map +1 -1
  189. package/dist/development/core/cache/key.d.mts +2 -0
  190. package/dist/development/core/cache/key.mjs.map +1 -1
  191. package/dist/development/core/cache/run-with-cache.d.mts +56 -8
  192. package/dist/development/core/cache/run-with-cache.mjs +17 -6
  193. package/dist/development/core/cache/run-with-cache.mjs.map +1 -1
  194. package/dist/development/core/cache/store.d.mts +8 -6
  195. package/dist/development/core/cache/store.mjs.map +1 -1
  196. package/dist/development/core/cache/strategies.d.mts +27 -2
  197. package/dist/development/core/cache/strategies.mjs +6 -0
  198. package/dist/development/core/cache/strategies.mjs.map +1 -1
  199. package/dist/development/core/cart/actions.d.mts +37 -30
  200. package/dist/development/core/cart/actions.mjs +21 -9
  201. package/dist/development/core/cart/actions.mjs.map +1 -1
  202. package/dist/development/core/cart/attach-quantity-input.d.mts +8 -7
  203. package/dist/development/core/cart/attach-quantity-input.mjs +8 -7
  204. package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
  205. package/dist/development/core/cart/buyer-identity-sync.d.mts +6 -5
  206. package/dist/development/core/cart/buyer-identity-sync.mjs.map +1 -1
  207. package/dist/development/core/cart/cart.d.mts +59 -46
  208. package/dist/development/core/cart/cart.mjs +46 -29
  209. package/dist/development/core/cart/cart.mjs.map +1 -1
  210. package/dist/development/core/cart/cookie.d.mts +8 -4
  211. package/dist/development/core/cart/cookie.mjs +8 -4
  212. package/dist/development/core/cart/cookie.mjs.map +1 -1
  213. package/dist/development/core/cart/form.d.mts +34 -20
  214. package/dist/development/core/cart/form.mjs +6 -4
  215. package/dist/development/core/cart/form.mjs.map +1 -1
  216. package/dist/development/core/cart/get-cart.d.mts +27 -15
  217. package/dist/development/core/cart/get-cart.mjs +13 -8
  218. package/dist/development/core/cart/get-cart.mjs.map +1 -1
  219. package/dist/development/core/cart/quantity.d.mts +16 -5
  220. package/dist/development/core/cart/quantity.mjs +16 -5
  221. package/dist/development/core/cart/quantity.mjs.map +1 -1
  222. package/dist/development/core/cart/queries.d.mts +25 -19
  223. package/dist/development/core/cart/queries.mjs +15 -1
  224. package/dist/development/core/cart/queries.mjs.map +1 -1
  225. package/dist/development/core/cart/server-handlers.d.mts +82 -45
  226. package/dist/development/core/cart/server-handlers.mjs +4 -0
  227. package/dist/development/core/cart/server-handlers.mjs.map +1 -1
  228. package/dist/development/core/cart/state.d.mts +110 -64
  229. package/dist/development/core/cart/state.mjs +24 -6
  230. package/dist/development/core/cart/state.mjs.map +1 -1
  231. package/dist/development/core/collection/collection.d.mts +52 -53
  232. package/dist/development/core/collection/collection.mjs +5 -3
  233. package/dist/development/core/collection/collection.mjs.map +1 -1
  234. package/dist/development/core/collection/reconciler.d.mts +23 -16
  235. package/dist/development/core/collection/reconciler.mjs +8 -4
  236. package/dist/development/core/collection/reconciler.mjs.map +1 -1
  237. package/dist/development/core/collection/state.d.mts +31 -26
  238. package/dist/development/core/collection/state.mjs +4 -3
  239. package/dist/development/core/collection/state.mjs.map +1 -1
  240. package/dist/development/core/collection/url.d.mts +70 -29
  241. package/dist/development/core/collection/url.mjs +63 -25
  242. package/dist/development/core/collection/url.mjs.map +1 -1
  243. package/dist/development/core/constants.mjs.map +1 -1
  244. package/dist/development/core/logging/logging.d.mts +14 -8
  245. package/dist/development/core/logging/logging.mjs +15 -10
  246. package/dist/development/core/logging/logging.mjs.map +1 -1
  247. package/dist/development/core/logging/types.d.mts +28 -11
  248. package/dist/development/core/logging/types.mjs.map +1 -1
  249. package/dist/development/core/money/format.d.mts +6 -4
  250. package/dist/development/core/money/format.mjs +19 -9
  251. package/dist/development/core/money/format.mjs.map +1 -1
  252. package/dist/development/core/money/types.d.mts +41 -25
  253. package/dist/development/core/predictive-search/form.d.mts +37 -7
  254. package/dist/development/core/predictive-search/form.mjs +21 -3
  255. package/dist/development/core/predictive-search/form.mjs.map +1 -1
  256. package/dist/development/core/predictive-search/queries.d.mts +18 -30
  257. package/dist/development/core/predictive-search/queries.mjs +7 -3
  258. package/dist/development/core/predictive-search/queries.mjs.map +1 -1
  259. package/dist/development/core/predictive-search/search.d.mts +25 -27
  260. package/dist/development/core/predictive-search/search.mjs +20 -19
  261. package/dist/development/core/predictive-search/search.mjs.map +1 -1
  262. package/dist/development/core/predictive-search/server-handlers.d.mts +25 -26
  263. package/dist/development/core/predictive-search/server-handlers.mjs +4 -0
  264. package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
  265. package/dist/development/core/predictive-search/store.d.mts +65 -24
  266. package/dist/development/core/predictive-search/store.mjs +12 -1
  267. package/dist/development/core/predictive-search/store.mjs.map +1 -1
  268. package/dist/development/core/predictive-search/url.d.mts +36 -37
  269. package/dist/development/core/predictive-search/url.mjs +14 -6
  270. package/dist/development/core/predictive-search/url.mjs.map +1 -1
  271. package/dist/development/core/product/form.d.mts +63 -16
  272. package/dist/development/core/product/form.mjs +8 -2
  273. package/dist/development/core/product/form.mjs.map +1 -1
  274. package/dist/development/core/product/options.d.mts +8 -10
  275. package/dist/development/core/product/options.mjs +8 -10
  276. package/dist/development/core/product/options.mjs.map +1 -1
  277. package/dist/development/core/product/product-form.d.mts +77 -29
  278. package/dist/development/core/product/product-form.mjs +32 -10
  279. package/dist/development/core/product/product-form.mjs.map +1 -1
  280. package/dist/development/core/product/state.d.mts +55 -32
  281. package/dist/development/core/product/url.d.mts +19 -13
  282. package/dist/development/core/product/url.mjs +10 -10
  283. package/dist/development/core/product/url.mjs.map +1 -1
  284. package/dist/development/core/request-context.d.mts +77 -19
  285. package/dist/development/core/request-context.mjs +5 -1
  286. package/dist/development/core/request-context.mjs.map +1 -1
  287. package/dist/development/core/request-routing/handle-shopify-redirects.d.mts +12 -4
  288. package/dist/development/core/request-routing/handle-shopify-redirects.mjs +9 -2
  289. package/dist/development/core/request-routing/handle-shopify-redirects.mjs.map +1 -1
  290. package/dist/development/core/request-routing/handle-shopify-routes.development.d.mts +9 -1
  291. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs +7 -0
  292. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs.map +1 -1
  293. package/dist/development/core/request-routing/handle-shopify-routes.mjs +7 -5
  294. package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  295. package/dist/development/core/request-routing/interceptors/proxy.mjs +79 -43
  296. package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
  297. package/dist/development/core/request-routing/interceptors/ucp-profile-proxy.mjs +69 -0
  298. package/dist/development/core/request-routing/interceptors/ucp-profile-proxy.mjs.map +1 -0
  299. package/dist/development/core/request-routing/interceptors/url-redirects.mjs +6 -1
  300. package/dist/development/core/request-routing/interceptors/url-redirects.mjs.map +1 -1
  301. package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
  302. package/dist/development/core/request-routing/interceptors/well-known.mjs.map +1 -1
  303. package/dist/development/core/request-routing/registered-routes.d.mts +12 -0
  304. package/dist/development/core/request-routing/registered-routes.mjs +12 -0
  305. package/dist/development/core/request-routing/registered-routes.mjs.map +1 -1
  306. package/dist/development/core/request-routing/route-types.d.mts +43 -18
  307. package/dist/development/core/shop-pay/shop-pay.d.mts +71 -35
  308. package/dist/development/core/shop-pay/shop-pay.mjs +36 -10
  309. package/dist/development/core/shop-pay/shop-pay.mjs.map +1 -1
  310. package/dist/development/core/shopify-scripts/index.d.mts +15 -5
  311. package/dist/development/core/shopify-scripts/index.mjs +15 -5
  312. package/dist/development/core/shopify-scripts/index.mjs.map +1 -1
  313. package/dist/development/core/shopify-scripts/initialize.d.mts +12 -4
  314. package/dist/development/core/shopify-scripts/initialize.mjs +12 -4
  315. package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
  316. package/dist/development/core/shopify-scripts/types.d.mts +58 -25
  317. package/dist/development/core/standard-routes/build.d.mts +11 -12
  318. package/dist/development/core/standard-routes/build.mjs +11 -12
  319. package/dist/development/core/standard-routes/build.mjs.map +1 -1
  320. package/dist/development/core/standard-routes/types.d.mts +30 -24
  321. package/dist/development/core/url.mjs +2 -1
  322. package/dist/development/core/url.mjs.map +1 -1
  323. package/dist/development/customer-account/session.d.mts +45 -54
  324. package/dist/development/customer-account/session.mjs +20 -4
  325. package/dist/development/customer-account/session.mjs.map +1 -1
  326. package/dist/development/globals.d.mts +20 -11
  327. package/dist/development/graphql/generated/storefront-api-types.d.mts +127 -1
  328. package/dist/development/graphql/graphql.d.mts +17 -16
  329. package/dist/development/graphql/graphql.mjs +7 -8
  330. package/dist/development/graphql/graphql.mjs.map +1 -1
  331. package/dist/development/graphql/type-resolver.d.mts +15 -8
  332. package/dist/development/react/cart.d.mts +78 -32
  333. package/dist/development/react/cart.mjs +56 -29
  334. package/dist/development/react/cart.mjs.map +1 -1
  335. package/dist/development/react/collection.d.mts +40 -22
  336. package/dist/development/react/collection.mjs +27 -7
  337. package/dist/development/react/collection.mjs.map +1 -1
  338. package/dist/development/react/predictive-search.d.mts +65 -50
  339. package/dist/development/react/predictive-search.mjs +23 -21
  340. package/dist/development/react/predictive-search.mjs.map +1 -1
  341. package/dist/development/react/product.d.mts +45 -16
  342. package/dist/development/react/product.mjs +13 -11
  343. package/dist/development/react/product.mjs.map +1 -1
  344. package/dist/development/react/shop-pay.d.mts +15 -0
  345. package/dist/development/react/shop-pay.mjs +9 -0
  346. package/dist/development/react/shop-pay.mjs.map +1 -1
  347. package/dist/development/react/shopify-scripts.d.mts +23 -2
  348. package/dist/development/react/shopify-scripts.mjs +9 -0
  349. package/dist/development/react/shopify-scripts.mjs.map +1 -1
  350. package/dist/development/vue/cart.d.mts +28 -23
  351. package/dist/development/vue/cart.mjs +42 -25
  352. package/dist/development/vue/cart.mjs.map +1 -1
  353. package/dist/development/vue/collection.d.mts +20 -12
  354. package/dist/development/vue/collection.mjs +15 -7
  355. package/dist/development/vue/collection.mjs.map +1 -1
  356. package/dist/development/vue/index.d.mts +2 -2
  357. package/dist/development/vue/index.mjs +2 -2
  358. package/dist/development/vue/predictive-search.d.mts +31 -36
  359. package/dist/development/vue/predictive-search.mjs +16 -22
  360. package/dist/development/vue/predictive-search.mjs.map +1 -1
  361. package/dist/development/vue/product.d.mts +16 -15
  362. package/dist/development/vue/product.mjs +11 -11
  363. package/dist/development/vue/product.mjs.map +1 -1
  364. package/dist/development/vue/shop-pay.d.mts +14 -17
  365. package/dist/development/vue/shop-pay.mjs +8 -0
  366. package/dist/development/vue/shop-pay.mjs.map +1 -1
  367. package/dist/development/vue/shopify-scripts.d.mts +11 -0
  368. package/dist/development/vue/shopify-scripts.mjs +6 -0
  369. package/dist/development/vue/shopify-scripts.mjs.map +1 -1
  370. package/dist/globals.d.mts +20 -11
  371. package/dist/graphql/generated/storefront-api-types.d.mts +127 -1
  372. package/dist/graphql/graphql.d.mts +17 -16
  373. package/dist/graphql/graphql.mjs +7 -8
  374. package/dist/graphql/graphql.mjs.map +1 -1
  375. package/dist/graphql/type-resolver.d.mts +15 -8
  376. package/dist/react/cart.d.mts +78 -32
  377. package/dist/react/cart.mjs +56 -29
  378. package/dist/react/cart.mjs.map +1 -1
  379. package/dist/react/collection.d.mts +40 -22
  380. package/dist/react/collection.mjs +27 -7
  381. package/dist/react/collection.mjs.map +1 -1
  382. package/dist/react/predictive-search.d.mts +65 -50
  383. package/dist/react/predictive-search.mjs +23 -21
  384. package/dist/react/predictive-search.mjs.map +1 -1
  385. package/dist/react/product.d.mts +45 -16
  386. package/dist/react/product.mjs +13 -11
  387. package/dist/react/product.mjs.map +1 -1
  388. package/dist/react/shop-pay.d.mts +15 -0
  389. package/dist/react/shop-pay.mjs +9 -0
  390. package/dist/react/shop-pay.mjs.map +1 -1
  391. package/dist/react/shopify-scripts.d.mts +23 -2
  392. package/dist/react/shopify-scripts.mjs +9 -0
  393. package/dist/react/shopify-scripts.mjs.map +1 -1
  394. package/dist/ts-plugin/index.cjs +6 -0
  395. package/dist/ts-plugin/index.cjs.map +1 -1
  396. package/dist/ts-plugin/index.d.cts +6 -0
  397. package/dist/vite/local-https.d.mts +51 -17
  398. package/dist/vite/local-https.mjs +26 -5
  399. package/dist/vite/local-https.mjs.map +1 -1
  400. package/dist/vue/cart.d.mts +28 -23
  401. package/dist/vue/cart.mjs +42 -25
  402. package/dist/vue/cart.mjs.map +1 -1
  403. package/dist/vue/collection.d.mts +20 -12
  404. package/dist/vue/collection.mjs +15 -7
  405. package/dist/vue/collection.mjs.map +1 -1
  406. package/dist/vue/index.d.mts +2 -2
  407. package/dist/vue/index.mjs +2 -2
  408. package/dist/vue/predictive-search.d.mts +31 -36
  409. package/dist/vue/predictive-search.mjs +16 -22
  410. package/dist/vue/predictive-search.mjs.map +1 -1
  411. package/dist/vue/product.d.mts +16 -15
  412. package/dist/vue/product.mjs +11 -11
  413. package/dist/vue/product.mjs.map +1 -1
  414. package/dist/vue/shop-pay.d.mts +14 -17
  415. package/dist/vue/shop-pay.mjs +8 -0
  416. package/dist/vue/shop-pay.mjs.map +1 -1
  417. package/dist/vue/shopify-scripts.d.mts +11 -0
  418. package/dist/vue/shopify-scripts.mjs +6 -0
  419. package/dist/vue/shopify-scripts.mjs.map +1 -1
  420. package/package.json +3 -1
  421. package/skills/hydrogen-analytics/SKILL.md +1 -1
  422. package/skills/hydrogen-cart-ui/SKILL.md +28 -2
  423. package/skills/hydrogen-collection-browser/SKILL.md +9 -1
  424. package/skills/hydrogen-collection-browser/references/nextjs.md +1 -1
  425. package/skills/hydrogen-collection-browser/references/nuxt.md +1 -1
  426. package/skills/hydrogen-collection-browser/references/react.md +151 -32
  427. package/skills/hydrogen-customer-account/SKILL.md +2 -0
  428. package/skills/hydrogen-request-handlers/SKILL.md +21 -11
  429. package/skills/hydrogen-setup/references/analytics.md +14 -8
  430. package/skills/hydrogen-setup/steps/1-inspect-app.md +2 -2
  431. package/skills/hydrogen-setup/steps/6-product-detail-page.md +21 -11
  432. package/skills/hydrogen-storefront-client/SKILL.md +1 -1
  433. package/skills/hydrogen-storefront-client/references/caching.md +2 -0
  434. package/skills/hydrogen-variant-form/SKILL.md +25 -7
  435. package/skills/hydrogen-variant-form/references/nextjs.md +39 -4
  436. package/skills/hydrogen-variant-form/references/nuxt.md +83 -42
  437. package/skills/hydrogen-variant-form/references/react.md +45 -9
@@ -1,11 +1,14 @@
1
1
  //#region src/core/cart/cookie.d.ts
2
2
  /**
3
- * Serializes a cart GID into a `Set-Cookie` header value.
3
+ * Creates the `Set-Cookie` header value that stores the cart ID in the `cart` cookie.
4
4
  *
5
- * Strips the `gid://shopify/Cart/` prefix before encoding — the cookie stores
6
- * only the opaque suffix to keep the header compact. The cookie is set with
7
- * `Path=/; SameSite=Lax` and a 14-day `Max-Age`.
5
+ * The cookie holds the cart token without the `gid://shopify/Cart/` prefix and expires
6
+ * after 14 days. The cookie sets `Path=/` and `SameSite=Lax`, and leaves out `HttpOnly`
7
+ * and `Secure`. Append the value to the response headers to keep the response's
8
+ * other cookies.
8
9
  *
10
+ * @param cartId The cart GID or cart token to store.
11
+ * @returns The header value that sets the `cart` cookie.
9
12
  * @example
10
13
  * ```ts
11
14
  * const cookie = createCartCookie("gid://shopify/Cart/abc123");
@@ -13,6 +16,7 @@
13
16
  *
14
17
  * headers.append("Set-Cookie", cookie);
15
18
  * ```
19
+ * @publicDocs
16
20
  */
17
21
  declare function createCartCookie(cartId: string): string;
18
22
  //#endregion
@@ -16,12 +16,15 @@ function getCartIdFromCookie(input) {
16
16
  return normalizeCartId(token);
17
17
  }
18
18
  /**
19
- * Serializes a cart GID into a `Set-Cookie` header value.
19
+ * Creates the `Set-Cookie` header value that stores the cart ID in the `cart` cookie.
20
20
  *
21
- * Strips the `gid://shopify/Cart/` prefix before encoding — the cookie stores
22
- * only the opaque suffix to keep the header compact. The cookie is set with
23
- * `Path=/; SameSite=Lax` and a 14-day `Max-Age`.
21
+ * The cookie holds the cart token without the `gid://shopify/Cart/` prefix and expires
22
+ * after 14 days. The cookie sets `Path=/` and `SameSite=Lax`, and leaves out `HttpOnly`
23
+ * and `Secure`. Append the value to the response headers to keep the response's
24
+ * other cookies.
24
25
  *
26
+ * @param cartId The cart GID or cart token to store.
27
+ * @returns The header value that sets the `cart` cookie.
25
28
  * @example
26
29
  * ```ts
27
30
  * const cookie = createCartCookie("gid://shopify/Cart/abc123");
@@ -29,6 +32,7 @@ function getCartIdFromCookie(input) {
29
32
  *
30
33
  * headers.append("Set-Cookie", cookie);
31
34
  * ```
35
+ * @publicDocs
32
36
  */
33
37
  function createCartCookie(cartId) {
34
38
  const token = cartId.startsWith(CART_GID_PREFIX) ? cartId.slice(19) : cartId;
@@ -1 +1 @@
1
- {"version":3,"file":"cookie.mjs","names":[],"sources":["../../../../src/core/cart/cookie.ts"],"sourcesContent":["const COOKIE_NAME = \"cart\";\nconst MAX_AGE_IN_SECONDS = 1209600; // 14 days\nconst CART_GID_PREFIX = \"gid://shopify/Cart/\";\n\ntype CartCookieSource = Request | { cookie?: string };\n\nexport function normalizeCartId(cartId: string | null | undefined): string | null {\n if (!cartId) return null;\n return cartId.startsWith(CART_GID_PREFIX) ? cartId : CART_GID_PREFIX + cartId;\n}\n\nexport function getCartIdFromCookie(input: CartCookieSource): string | null {\n const header = input instanceof Request ? input.headers.get(\"cookie\") : input.cookie;\n if (!header) return null;\n\n const match = header.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]*)`));\n if (!match || !match[1]) return null;\n\n const token = decodeURIComponent(match[1]);\n if (!token) return null;\n\n return normalizeCartId(token);\n}\n\n/**\n * Serializes a cart GID into a `Set-Cookie` header value.\n *\n * Strips the `gid://shopify/Cart/` prefix before encoding — the cookie stores\n * only the opaque suffix to keep the header compact. The cookie is set with\n * `Path=/; SameSite=Lax` and a 14-day `Max-Age`.\n *\n * @example\n * ```ts\n * const cookie = createCartCookie(\"gid://shopify/Cart/abc123\");\n * // \"cart=abc123; Path=/; SameSite=Lax; Max-Age=1209600\"\n *\n * headers.append(\"Set-Cookie\", cookie);\n * ```\n */\nexport function createCartCookie(cartId: string): string {\n const token = cartId.startsWith(CART_GID_PREFIX) ? cartId.slice(CART_GID_PREFIX.length) : cartId;\n const encoded = encodeURIComponent(token);\n return `${COOKIE_NAME}=${encoded}; Path=/; SameSite=Lax; Max-Age=${MAX_AGE_IN_SECONDS}`;\n}\n\nexport function createExpiredCartCookie(): string {\n return `${COOKIE_NAME}=; Path=/; SameSite=Lax; Max-Age=0`;\n}\n"],"mappings":";AAAA,MAAM,cAAc;AACpB,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AAIxB,SAAgB,gBAAgB,QAAkD;AAChF,KAAI,CAAC,OAAQ,QAAO;AACpB,QAAO,OAAO,WAAW,gBAAgB,GAAG,SAAS,kBAAkB;;AAGzE,SAAgB,oBAAoB,OAAwC;CAC1E,MAAM,SAAS,iBAAiB,UAAU,MAAM,QAAQ,IAAI,SAAS,GAAG,MAAM;AAC9E,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,QAAQ,OAAO,MAAM,IAAI,OAAO,cAAc,YAAY,UAAU,CAAC;AAC3E,KAAI,CAAC,SAAS,CAAC,MAAM,GAAI,QAAO;CAEhC,MAAM,QAAQ,mBAAmB,MAAM,GAAG;AAC1C,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,gBAAgB,MAAM;;;;;;;;;;;;;;;;;AAkB/B,SAAgB,iBAAiB,QAAwB;CACvD,MAAM,QAAQ,OAAO,WAAW,gBAAgB,GAAG,OAAO,MAAM,GAAuB,GAAG;AAE1F,QAAO,GAAG,YAAY,GADN,mBAAmB,MACH,CAAC,kCAAkC;;AAGrE,SAAgB,0BAAkC;AAChD,QAAO,GAAG,YAAY"}
1
+ {"version":3,"file":"cookie.mjs","names":[],"sources":["../../../../src/core/cart/cookie.ts"],"sourcesContent":["const COOKIE_NAME = \"cart\";\nconst MAX_AGE_IN_SECONDS = 1209600; // 14 days\nconst CART_GID_PREFIX = \"gid://shopify/Cart/\";\n\ntype CartCookieSource = Request | { cookie?: string };\n\nexport function normalizeCartId(cartId: string | null | undefined): string | null {\n if (!cartId) return null;\n return cartId.startsWith(CART_GID_PREFIX) ? cartId : CART_GID_PREFIX + cartId;\n}\n\nexport function getCartIdFromCookie(input: CartCookieSource): string | null {\n const header = input instanceof Request ? input.headers.get(\"cookie\") : input.cookie;\n if (!header) return null;\n\n const match = header.match(new RegExp(`(?:^|;\\\\s*)${COOKIE_NAME}=([^;]*)`));\n if (!match || !match[1]) return null;\n\n const token = decodeURIComponent(match[1]);\n if (!token) return null;\n\n return normalizeCartId(token);\n}\n\n/**\n * Creates the `Set-Cookie` header value that stores the cart ID in the `cart` cookie.\n *\n * The cookie holds the cart token without the `gid://shopify/Cart/` prefix and expires\n * after 14 days. The cookie sets `Path=/` and `SameSite=Lax`, and leaves out `HttpOnly`\n * and `Secure`. Append the value to the response headers to keep the response's\n * other cookies.\n *\n * @param cartId The cart GID or cart token to store.\n * @returns The header value that sets the `cart` cookie.\n * @example\n * ```ts\n * const cookie = createCartCookie(\"gid://shopify/Cart/abc123\");\n * // \"cart=abc123; Path=/; SameSite=Lax; Max-Age=1209600\"\n *\n * headers.append(\"Set-Cookie\", cookie);\n * ```\n * @publicDocs\n */\nexport function createCartCookie(cartId: string): string {\n const token = cartId.startsWith(CART_GID_PREFIX) ? cartId.slice(CART_GID_PREFIX.length) : cartId;\n const encoded = encodeURIComponent(token);\n return `${COOKIE_NAME}=${encoded}; Path=/; SameSite=Lax; Max-Age=${MAX_AGE_IN_SECONDS}`;\n}\n\nexport function createExpiredCartCookie(): string {\n return `${COOKIE_NAME}=; Path=/; SameSite=Lax; Max-Age=0`;\n}\n"],"mappings":";AAAA,MAAM,cAAc;AACpB,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AAIxB,SAAgB,gBAAgB,QAAkD;AAChF,KAAI,CAAC,OAAQ,QAAO;AACpB,QAAO,OAAO,WAAW,gBAAgB,GAAG,SAAS,kBAAkB;;AAGzE,SAAgB,oBAAoB,OAAwC;CAC1E,MAAM,SAAS,iBAAiB,UAAU,MAAM,QAAQ,IAAI,SAAS,GAAG,MAAM;AAC9E,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,QAAQ,OAAO,MAAM,IAAI,OAAO,cAAc,YAAY,UAAU,CAAC;AAC3E,KAAI,CAAC,SAAS,CAAC,MAAM,GAAI,QAAO;CAEhC,MAAM,QAAQ,mBAAmB,MAAM,GAAG;AAC1C,KAAI,CAAC,MAAO,QAAO;AAEnB,QAAO,gBAAgB,MAAM;;;;;;;;;;;;;;;;;;;;;AAsB/B,SAAgB,iBAAiB,QAAwB;CACvD,MAAM,QAAQ,OAAO,WAAW,gBAAgB,GAAG,OAAO,MAAM,GAAuB,GAAG;AAE1F,QAAO,GAAG,YAAY,GADN,mBAAmB,MACH,CAAC,kCAAkC;;AAGrE,SAAgB,0BAAkC;AAChD,QAAO,GAAG,YAAY"}
@@ -1,43 +1,55 @@
1
1
  //#region src/core/cart/form.d.ts
2
2
  /**
3
- * HTML attributes for a hidden submit button that triggers the `"set"` intent.
3
+ * HTML attributes for the hidden submit button that sets a line to the quantity in the form's quantity input.
4
4
  *
5
- * Used by {@link CartFormRegister} when `register("set")` is called. The button
6
- * must be the first submit button in the form for `attachQuantityInput`
7
- * to auto-submit on quantity changes.
5
+ * `register("set")` returns the attributes. Make the set button the form's first submit button. A quantity input submits on change only when the set button comes first.
6
+ *
7
+ * @publicDocs
8
8
  */
9
9
  interface SetButtonAttributes {
10
+ /** The form field that names the cart change. */
10
11
  name: "intent";
12
+ /** Sets the line to the quantity in the form's quantity input. */
11
13
  value: "set";
14
+ /** Makes the button the one that submits the form when the quantity changes. */
12
15
  type: "submit";
16
+ /** Hides the button from view. */
13
17
  hidden: true;
14
18
  }
15
19
  /**
16
- * HTML attributes for a quantity `<input>` in interactive mode.
20
+ * HTML attributes for a quantity input that submits the form when the customer changes the quantity.
21
+ *
22
+ * `register("quantity", { value, interactive: true })` returns the attributes. The input shows a number keyboard on mobile devices and has no spinner arrows.
17
23
  *
18
- * Returned by `register("quantity", { value, interactive: true })`. Uses
19
- * `type: "text"` with `inputMode: "numeric"` for mobile number keyboards
20
- * without the native spinner arrows.
24
+ * @publicDocs
21
25
  */
22
26
  interface QuantityInputAttributes {
27
+ /** The form field that holds the quantity. */
23
28
  name: "quantity";
29
+ /** The current quantity as a string. */
24
30
  value: string;
31
+ /** Renders a text input, which has no number spinner arrows. */
25
32
  type: "text";
33
+ /** Shows a numeric keyboard on mobile devices. */
26
34
  inputMode: "numeric";
35
+ /** Accepts digits only. */
27
36
  pattern: string;
37
+ /** Turns off browser autocomplete for the input. */
28
38
  autoComplete: "off";
39
+ /** Turns off autocorrect for the input. */
29
40
  autoCorrect: "off";
30
41
  }
31
42
  type AttributeValueName = `attributes.${string}`;
32
43
  /**
33
- * Overloaded function that produces the correct HTML attributes for any cart
34
- * form field or action button.
44
+ * A function that returns the HTML attributes for a cart form field or action button.
35
45
  *
36
- * Call with a **field name** (`"lineId"`, `"quantity"`, `"merchandiseId"`,
37
- * `"discountCode"`, `"note"`, `"attributeValue"`, `"sellingPlanId"`) to get
38
- * input attributes, or with an **action name** (`"add"`, `"increase"`,
39
- * `"decrease"`, `"remove"`, `"set"`, `"discount-apply"`, `"discount-remove"`,
40
- * `"note-update"`, `"attributes-update"`) to get submit button attributes.
46
+ * Pass a field name to get input attributes: `lineId`, `quantity`,
47
+ * `merchandiseId`, `discountCode`, `note`, `attributeValue`, or `sellingPlanId`.
48
+ * Pass an action name to get submit button attributes: `add`,
49
+ * `increase`, `decrease`, `remove`, `set`, `discount-apply`, `discount-remove`,
50
+ * `note-update`, or `attributes-update`.
51
+ *
52
+ * For an attribute value, pass a `key` option. The function names the field `attributes.<key>` and throws a type error when the key is missing or empty. The line ID input is read-only. Add `type="hidden"` to hide the line ID input.
41
53
  *
42
54
  * @example
43
55
  * ```tsx
@@ -56,7 +68,7 @@ type AttributeValueName = `attributes.${string}`;
56
68
  * <button {...register("increase")}>+</button>
57
69
  * ```
58
70
  *
59
- * @throws `TypeError` when called with `"attributeValue"` and no non-empty `key`.
71
+ * @throws A type error when an attribute value has a missing or empty key.
60
72
  */
61
73
  type CartFormRegister = {
62
74
  (field: "lineId", opts: {
@@ -168,11 +180,11 @@ type CartFormRegister = {
168
180
  };
169
181
  };
170
182
  /**
171
- * Creates a {@link CartFormRegister} function for generating cart form field attributes.
183
+ * Creates a register function that returns the HTML attributes for cart form fields and action buttons.
184
+ *
185
+ * Use the function to build cart forms without a framework binding. In React, `useCartForm` returns a register function and form props for you. To submit an interactive quantity input on change, call `attachQuantityInput`.
172
186
  *
173
- * The returned `register` function is stateless — it can be called multiple times
174
- * and shared across components. Framework hooks (`useCartForm`) wrap this with
175
- * additional conveniences like `formProps()` and interactive `ref` wiring.
187
+ * The register function holds no state. Share one register function across components.
176
188
  *
177
189
  * @example
178
190
  * ```ts
@@ -184,6 +196,8 @@ type CartFormRegister = {
184
196
  * const addAttrs = register("add");
185
197
  * // → { name: "intent", value: "add" }
186
198
  * ```
199
+ * @returns A register function for cart form fields and action buttons.
200
+ * @publicDocs
187
201
  */
188
202
  declare function createCartFormRegister(): CartFormRegister;
189
203
  //#endregion
@@ -54,11 +54,11 @@ function createFieldAttributes(name, opts) {
54
54
  return attrs;
55
55
  }
56
56
  /**
57
- * Creates a {@link CartFormRegister} function for generating cart form field attributes.
57
+ * Creates a register function that returns the HTML attributes for cart form fields and action buttons.
58
58
  *
59
- * The returned `register` function is stateless — it can be called multiple times
60
- * and shared across components. Framework hooks (`useCartForm`) wrap this with
61
- * additional conveniences like `formProps()` and interactive `ref` wiring.
59
+ * Use the function to build cart forms without a framework binding. In React, `useCartForm` returns a register function and form props for you. To submit an interactive quantity input on change, call `attachQuantityInput`.
60
+ *
61
+ * The register function holds no state. Share one register function across components.
62
62
  *
63
63
  * @example
64
64
  * ```ts
@@ -70,6 +70,8 @@ function createFieldAttributes(name, opts) {
70
70
  * const addAttrs = register("add");
71
71
  * // → { name: "intent", value: "add" }
72
72
  * ```
73
+ * @returns A register function for cart form fields and action buttons.
74
+ * @publicDocs
73
75
  */
74
76
  function createCartFormRegister() {
75
77
  return ((nameOrAction, opts) => {
@@ -1 +1 @@
1
- {"version":3,"file":"form.mjs","names":[],"sources":["../../../../src/core/cart/form.ts"],"sourcesContent":["/**\n * HTML attributes for a hidden submit button that triggers the `\"set\"` intent.\n *\n * Used by {@link CartFormRegister} when `register(\"set\")` is called. The button\n * must be the first submit button in the form for `attachQuantityInput`\n * to auto-submit on quantity changes.\n */\nexport interface SetButtonAttributes {\n name: \"intent\";\n value: \"set\";\n type: \"submit\";\n hidden: true;\n}\n\n/**\n * HTML attributes for a quantity `<input>` in interactive mode.\n *\n * Returned by `register(\"quantity\", { value, interactive: true })`. Uses\n * `type: \"text\"` with `inputMode: \"numeric\"` for mobile number keyboards\n * without the native spinner arrows.\n */\nexport interface QuantityInputAttributes {\n name: \"quantity\";\n value: string;\n type: \"text\";\n inputMode: \"numeric\";\n pattern: string;\n autoComplete: \"off\";\n autoCorrect: \"off\";\n}\n\ntype AttributeValueName = `attributes.${string}`;\n\n/**\n * Overloaded function that produces the correct HTML attributes for any cart\n * form field or action button.\n *\n * Call with a **field name** (`\"lineId\"`, `\"quantity\"`, `\"merchandiseId\"`,\n * `\"discountCode\"`, `\"note\"`, `\"attributeValue\"`, `\"sellingPlanId\"`) to get\n * input attributes, or with an **action name** (`\"add\"`, `\"increase\"`,\n * `\"decrease\"`, `\"remove\"`, `\"set\"`, `\"discount-apply\"`, `\"discount-remove\"`,\n * `\"note-update\"`, `\"attributes-update\"`) to get submit button attributes.\n *\n * @example\n * ```tsx\n * const register = createCartFormRegister();\n *\n * // Line ID field (register returns readOnly; add type=\"hidden\" to hide it)\n * <input {...register(\"lineId\", { value: line.id })} />\n *\n * // Interactive quantity input (pair with attachQuantityInput to auto-submit on change)\n * <input {...register(\"quantity\", { value: line.quantity, interactive: true })} />\n *\n * // Hidden submit button for the \"set\" intent\n * <button {...register(\"set\")} />\n *\n * // Increase quantity button\n * <button {...register(\"increase\")}>+</button>\n * ```\n *\n * @throws `TypeError` when called with `\"attributeValue\"` and no non-empty `key`.\n */\nexport type CartFormRegister = {\n (field: \"lineId\", opts: { value: string }): { name: \"lineId\"; value: string; readOnly: true };\n (field: \"quantity\", opts: { value: number | string; interactive: true }): QuantityInputAttributes;\n (\n field: \"quantity\",\n opts: { value: number | string; interactive?: false },\n ): { name: \"quantity\"; value: string };\n (field: \"quantity\", opts: { defaultValue: number }): { name: \"quantity\"; defaultValue: string };\n (field: \"discountCode\", opts: { value: string }): { name: \"discountCode\"; value: string };\n (\n field: \"discountCode\",\n opts: { defaultValue: string },\n ): { name: \"discountCode\"; defaultValue: string };\n (field: \"merchandiseId\", opts: { value: string }): { name: \"merchandiseId\"; value: string };\n (field: \"note\", opts: { value: string }): { name: \"note\"; value: string };\n (field: \"note\", opts: { defaultValue: string }): { name: \"note\"; defaultValue: string };\n (\n field: \"attributeValue\",\n opts: { key: string; value: string },\n ): { name: AttributeValueName; value: string };\n (\n field: \"attributeValue\",\n opts: { key: string; defaultValue: string },\n ): { name: AttributeValueName; defaultValue: string };\n (field: \"sellingPlanId\", opts: { value: string }): { name: \"sellingPlanId\"; value: string };\n (action: \"add\"): { name: \"intent\"; value: \"add\" };\n (action: \"increase\"): { name: \"intent\"; value: \"increase\" };\n (action: \"decrease\"): { name: \"intent\"; value: \"decrease\" };\n (action: \"remove\"): { name: \"intent\"; value: \"remove\" };\n (action: \"set\"): SetButtonAttributes;\n (action: \"discount-apply\"): { name: \"intent\"; value: \"discount-apply\" };\n (action: \"discount-remove\"): { name: \"intent\"; value: \"discount-remove\" };\n (action: \"note-update\"): { name: \"intent\"; value: \"note-update\" };\n (action: \"attributes-update\"): { name: \"intent\"; value: \"attributes-update\" };\n};\n\nconst FIELD_REGISTERS = new Set([\n \"lineId\",\n \"quantity\",\n \"discountCode\",\n \"merchandiseId\",\n \"note\",\n \"sellingPlanId\",\n]);\n\nconst ATTRIBUTE_VALUE_NAME_PREFIX = \"attributes.\";\n\ntype RegisterOptions = {\n key?: string;\n value?: string | number;\n defaultValue?: string;\n interactive?: boolean;\n};\n\nexport function getCartAttributeFormEntries(\n formData: FormData,\n): Array<{ key: string; value: FormDataEntryValue }> {\n const attributes: Array<{ key: string; value: FormDataEntryValue }> = [];\n for (const [name, value] of formData.entries()) {\n if (!name.startsWith(ATTRIBUTE_VALUE_NAME_PREFIX)) continue;\n attributes.push({ key: name.slice(ATTRIBUTE_VALUE_NAME_PREFIX.length), value });\n }\n return attributes;\n}\n\nfunction createAttributeValueAttributes(opts?: RegisterOptions) {\n if (!opts?.key) throw new TypeError('Cart attribute values require a non-empty \"key\".');\n const name = `${ATTRIBUTE_VALUE_NAME_PREFIX}${opts.key}` as AttributeValueName;\n if (\"defaultValue\" in opts) {\n return { name, defaultValue: String(opts.defaultValue) };\n }\n return { name, value: String(opts.value ?? \"\") };\n}\n\nfunction createFieldAttributes(name: string, opts?: RegisterOptions) {\n if (opts && \"defaultValue\" in opts) {\n return { name, defaultValue: String(opts.defaultValue) };\n }\n\n const value = String(opts?.value ?? \"\");\n\n if (name === \"quantity\" && opts?.interactive) {\n return {\n name: \"quantity\",\n value,\n type: \"text\",\n inputMode: \"numeric\",\n pattern: \"\\\\d+\",\n autoComplete: \"off\",\n autoCorrect: \"off\",\n } satisfies QuantityInputAttributes;\n }\n\n const attrs: Record<string, string | boolean> = { name, value };\n if (name === \"lineId\") attrs.readOnly = true;\n return attrs;\n}\n\n/**\n * Creates a {@link CartFormRegister} function for generating cart form field attributes.\n *\n * The returned `register` function is stateless — it can be called multiple times\n * and shared across components. Framework hooks (`useCartForm`) wrap this with\n * additional conveniences like `formProps()` and interactive `ref` wiring.\n *\n * @example\n * ```ts\n * const register = createCartFormRegister();\n *\n * const lineIdAttrs = register(\"lineId\", { value: \"gid://shopify/CartLine/123\" });\n * // → { name: \"lineId\", value: \"gid://shopify/CartLine/123\", readOnly: true }\n *\n * const addAttrs = register(\"add\");\n * // → { name: \"intent\", value: \"add\" }\n * ```\n */\nexport function createCartFormRegister(): CartFormRegister {\n return ((nameOrAction: string, opts?: RegisterOptions) => {\n if (nameOrAction === \"attributeValue\") {\n return createAttributeValueAttributes(opts);\n }\n\n if (FIELD_REGISTERS.has(nameOrAction)) {\n return createFieldAttributes(nameOrAction, opts);\n }\n\n if (nameOrAction === \"set\") {\n return {\n name: \"intent\",\n value: \"set\",\n type: \"submit\",\n hidden: true,\n } satisfies SetButtonAttributes;\n }\n\n return { name: \"intent\", value: nameOrAction };\n }) as CartFormRegister;\n}\n"],"mappings":";AAkGA,MAAM,kBAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,8BAA8B;AASpC,SAAgB,4BACd,UACmD;CACnD,MAAM,aAAgE,EAAE;AACxE,MAAK,MAAM,CAAC,MAAM,UAAU,SAAS,SAAS,EAAE;AAC9C,MAAI,CAAC,KAAK,WAAW,4BAA4B,CAAE;AACnD,aAAW,KAAK;GAAE,KAAK,KAAK,MAAM,GAAmC;GAAE;GAAO,CAAC;;AAEjF,QAAO;;AAGT,SAAS,+BAA+B,MAAwB;AAC9D,KAAI,CAAC,MAAM,IAAK,OAAM,IAAI,UAAU,qDAAmD;CACvF,MAAM,OAAO,GAAG,8BAA8B,KAAK;AACnD,KAAI,kBAAkB,KACpB,QAAO;EAAE;EAAM,cAAc,OAAO,KAAK,aAAa;EAAE;AAE1D,QAAO;EAAE;EAAM,OAAO,OAAO,KAAK,SAAS,GAAG;EAAE;;AAGlD,SAAS,sBAAsB,MAAc,MAAwB;AACnE,KAAI,QAAQ,kBAAkB,KAC5B,QAAO;EAAE;EAAM,cAAc,OAAO,KAAK,aAAa;EAAE;CAG1D,MAAM,QAAQ,OAAO,MAAM,SAAS,GAAG;AAEvC,KAAI,SAAS,cAAc,MAAM,YAC/B,QAAO;EACL,MAAM;EACN;EACA,MAAM;EACN,WAAW;EACX,SAAS;EACT,cAAc;EACd,aAAa;EACd;CAGH,MAAM,QAA0C;EAAE;EAAM;EAAO;AAC/D,KAAI,SAAS,SAAU,OAAM,WAAW;AACxC,QAAO;;;;;;;;;;;;;;;;;;;;AAqBT,SAAgB,yBAA2C;AACzD,UAAS,cAAsB,SAA2B;AACxD,MAAI,iBAAiB,iBACnB,QAAO,+BAA+B,KAAK;AAG7C,MAAI,gBAAgB,IAAI,aAAa,CACnC,QAAO,sBAAsB,cAAc,KAAK;AAGlD,MAAI,iBAAiB,MACnB,QAAO;GACL,MAAM;GACN,OAAO;GACP,MAAM;GACN,QAAQ;GACT;AAGH,SAAO;GAAE,MAAM;GAAU,OAAO;GAAc"}
1
+ {"version":3,"file":"form.mjs","names":[],"sources":["../../../../src/core/cart/form.ts"],"sourcesContent":["/**\n * HTML attributes for the hidden submit button that sets a line to the quantity in the form's quantity input.\n *\n * `register(\"set\")` returns the attributes. Make the set button the form's first submit button. A quantity input submits on change only when the set button comes first.\n *\n * @publicDocs\n */\nexport interface SetButtonAttributes {\n /** The form field that names the cart change. */\n name: \"intent\";\n /** Sets the line to the quantity in the form's quantity input. */\n value: \"set\";\n /** Makes the button the one that submits the form when the quantity changes. */\n type: \"submit\";\n /** Hides the button from view. */\n hidden: true;\n}\n\n/**\n * HTML attributes for a quantity input that submits the form when the customer changes the quantity.\n *\n * `register(\"quantity\", { value, interactive: true })` returns the attributes. The input shows a number keyboard on mobile devices and has no spinner arrows.\n *\n * @publicDocs\n */\nexport interface QuantityInputAttributes {\n /** The form field that holds the quantity. */\n name: \"quantity\";\n /** The current quantity as a string. */\n value: string;\n /** Renders a text input, which has no number spinner arrows. */\n type: \"text\";\n /** Shows a numeric keyboard on mobile devices. */\n inputMode: \"numeric\";\n /** Accepts digits only. */\n pattern: string;\n /** Turns off browser autocomplete for the input. */\n autoComplete: \"off\";\n /** Turns off autocorrect for the input. */\n autoCorrect: \"off\";\n}\n\ntype AttributeValueName = `attributes.${string}`;\n\n/**\n * A function that returns the HTML attributes for a cart form field or action button.\n *\n * Pass a field name to get input attributes: `lineId`, `quantity`,\n * `merchandiseId`, `discountCode`, `note`, `attributeValue`, or `sellingPlanId`.\n * Pass an action name to get submit button attributes: `add`,\n * `increase`, `decrease`, `remove`, `set`, `discount-apply`, `discount-remove`,\n * `note-update`, or `attributes-update`.\n *\n * For an attribute value, pass a `key` option. The function names the field `attributes.<key>` and throws a type error when the key is missing or empty. The line ID input is read-only. Add `type=\"hidden\"` to hide the line ID input.\n *\n * @example\n * ```tsx\n * const register = createCartFormRegister();\n *\n * // Line ID field (register returns readOnly; add type=\"hidden\" to hide it)\n * <input {...register(\"lineId\", { value: line.id })} />\n *\n * // Interactive quantity input (pair with attachQuantityInput to auto-submit on change)\n * <input {...register(\"quantity\", { value: line.quantity, interactive: true })} />\n *\n * // Hidden submit button for the \"set\" intent\n * <button {...register(\"set\")} />\n *\n * // Increase quantity button\n * <button {...register(\"increase\")}>+</button>\n * ```\n *\n * @throws A type error when an attribute value has a missing or empty key.\n */\nexport type CartFormRegister = {\n (field: \"lineId\", opts: { value: string }): { name: \"lineId\"; value: string; readOnly: true };\n (field: \"quantity\", opts: { value: number | string; interactive: true }): QuantityInputAttributes;\n (\n field: \"quantity\",\n opts: { value: number | string; interactive?: false },\n ): { name: \"quantity\"; value: string };\n (field: \"quantity\", opts: { defaultValue: number }): { name: \"quantity\"; defaultValue: string };\n (field: \"discountCode\", opts: { value: string }): { name: \"discountCode\"; value: string };\n (\n field: \"discountCode\",\n opts: { defaultValue: string },\n ): { name: \"discountCode\"; defaultValue: string };\n (field: \"merchandiseId\", opts: { value: string }): { name: \"merchandiseId\"; value: string };\n (field: \"note\", opts: { value: string }): { name: \"note\"; value: string };\n (field: \"note\", opts: { defaultValue: string }): { name: \"note\"; defaultValue: string };\n (\n field: \"attributeValue\",\n opts: { key: string; value: string },\n ): { name: AttributeValueName; value: string };\n (\n field: \"attributeValue\",\n opts: { key: string; defaultValue: string },\n ): { name: AttributeValueName; defaultValue: string };\n (field: \"sellingPlanId\", opts: { value: string }): { name: \"sellingPlanId\"; value: string };\n (action: \"add\"): { name: \"intent\"; value: \"add\" };\n (action: \"increase\"): { name: \"intent\"; value: \"increase\" };\n (action: \"decrease\"): { name: \"intent\"; value: \"decrease\" };\n (action: \"remove\"): { name: \"intent\"; value: \"remove\" };\n (action: \"set\"): SetButtonAttributes;\n (action: \"discount-apply\"): { name: \"intent\"; value: \"discount-apply\" };\n (action: \"discount-remove\"): { name: \"intent\"; value: \"discount-remove\" };\n (action: \"note-update\"): { name: \"intent\"; value: \"note-update\" };\n (action: \"attributes-update\"): { name: \"intent\"; value: \"attributes-update\" };\n};\n\nconst FIELD_REGISTERS = new Set([\n \"lineId\",\n \"quantity\",\n \"discountCode\",\n \"merchandiseId\",\n \"note\",\n \"sellingPlanId\",\n]);\n\nconst ATTRIBUTE_VALUE_NAME_PREFIX = \"attributes.\";\n\ntype RegisterOptions = {\n key?: string;\n value?: string | number;\n defaultValue?: string;\n interactive?: boolean;\n};\n\nexport function getCartAttributeFormEntries(\n formData: FormData,\n): Array<{ key: string; value: FormDataEntryValue }> {\n const attributes: Array<{ key: string; value: FormDataEntryValue }> = [];\n for (const [name, value] of formData.entries()) {\n if (!name.startsWith(ATTRIBUTE_VALUE_NAME_PREFIX)) continue;\n attributes.push({ key: name.slice(ATTRIBUTE_VALUE_NAME_PREFIX.length), value });\n }\n return attributes;\n}\n\nfunction createAttributeValueAttributes(opts?: RegisterOptions) {\n if (!opts?.key) throw new TypeError('Cart attribute values require a non-empty \"key\".');\n const name = `${ATTRIBUTE_VALUE_NAME_PREFIX}${opts.key}` as AttributeValueName;\n if (\"defaultValue\" in opts) {\n return { name, defaultValue: String(opts.defaultValue) };\n }\n return { name, value: String(opts.value ?? \"\") };\n}\n\nfunction createFieldAttributes(name: string, opts?: RegisterOptions) {\n if (opts && \"defaultValue\" in opts) {\n return { name, defaultValue: String(opts.defaultValue) };\n }\n\n const value = String(opts?.value ?? \"\");\n\n if (name === \"quantity\" && opts?.interactive) {\n return {\n name: \"quantity\",\n value,\n type: \"text\",\n inputMode: \"numeric\",\n pattern: \"\\\\d+\",\n autoComplete: \"off\",\n autoCorrect: \"off\",\n } satisfies QuantityInputAttributes;\n }\n\n const attrs: Record<string, string | boolean> = { name, value };\n if (name === \"lineId\") attrs.readOnly = true;\n return attrs;\n}\n\n/**\n * Creates a register function that returns the HTML attributes for cart form fields and action buttons.\n *\n * Use the function to build cart forms without a framework binding. In React, `useCartForm` returns a register function and form props for you. To submit an interactive quantity input on change, call `attachQuantityInput`.\n *\n * The register function holds no state. Share one register function across components.\n *\n * @example\n * ```ts\n * const register = createCartFormRegister();\n *\n * const lineIdAttrs = register(\"lineId\", { value: \"gid://shopify/CartLine/123\" });\n * // → { name: \"lineId\", value: \"gid://shopify/CartLine/123\", readOnly: true }\n *\n * const addAttrs = register(\"add\");\n * // → { name: \"intent\", value: \"add\" }\n * ```\n * @returns A register function for cart form fields and action buttons.\n * @publicDocs\n */\nexport function createCartFormRegister(): CartFormRegister {\n return ((nameOrAction: string, opts?: RegisterOptions) => {\n if (nameOrAction === \"attributeValue\") {\n return createAttributeValueAttributes(opts);\n }\n\n if (FIELD_REGISTERS.has(nameOrAction)) {\n return createFieldAttributes(nameOrAction, opts);\n }\n\n if (nameOrAction === \"set\") {\n return {\n name: \"intent\",\n value: \"set\",\n type: \"submit\",\n hidden: true,\n } satisfies SetButtonAttributes;\n }\n\n return { name: \"intent\", value: nameOrAction };\n }) as CartFormRegister;\n}\n"],"mappings":";AA8GA,MAAM,kBAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAM,8BAA8B;AASpC,SAAgB,4BACd,UACmD;CACnD,MAAM,aAAgE,EAAE;AACxE,MAAK,MAAM,CAAC,MAAM,UAAU,SAAS,SAAS,EAAE;AAC9C,MAAI,CAAC,KAAK,WAAW,4BAA4B,CAAE;AACnD,aAAW,KAAK;GAAE,KAAK,KAAK,MAAM,GAAmC;GAAE;GAAO,CAAC;;AAEjF,QAAO;;AAGT,SAAS,+BAA+B,MAAwB;AAC9D,KAAI,CAAC,MAAM,IAAK,OAAM,IAAI,UAAU,qDAAmD;CACvF,MAAM,OAAO,GAAG,8BAA8B,KAAK;AACnD,KAAI,kBAAkB,KACpB,QAAO;EAAE;EAAM,cAAc,OAAO,KAAK,aAAa;EAAE;AAE1D,QAAO;EAAE;EAAM,OAAO,OAAO,KAAK,SAAS,GAAG;EAAE;;AAGlD,SAAS,sBAAsB,MAAc,MAAwB;AACnE,KAAI,QAAQ,kBAAkB,KAC5B,QAAO;EAAE;EAAM,cAAc,OAAO,KAAK,aAAa;EAAE;CAG1D,MAAM,QAAQ,OAAO,MAAM,SAAS,GAAG;AAEvC,KAAI,SAAS,cAAc,MAAM,YAC/B,QAAO;EACL,MAAM;EACN;EACA,MAAM;EACN,WAAW;EACX,SAAS;EACT,cAAc;EACd,aAAa;EACd;CAGH,MAAM,QAA0C;EAAE;EAAM;EAAO;AAC/D,KAAI,SAAS,SAAU,OAAM,WAAW;AACxC,QAAO;;;;;;;;;;;;;;;;;;;;;;AAuBT,SAAgB,yBAA2C;AACzD,UAAS,cAAsB,SAA2B;AACxD,MAAI,iBAAiB,iBACnB,QAAO,+BAA+B,KAAK;AAG7C,MAAI,gBAAgB,IAAI,aAAa,CACnC,QAAO,sBAAsB,cAAc,KAAK;AAGlD,MAAI,iBAAiB,MACnB,QAAO;GACL,MAAM;GACN,OAAO;GACP,MAAM;GACN,QAAQ;GACT;AAGH,SAAO;GAAE,MAAM;GAAU,OAAO;GAAc"}
@@ -5,34 +5,41 @@ import { CartData } from "./state.mjs";
5
5
  import { cartQueries } from "./queries.mjs";
6
6
 
7
7
  //#region src/core/cart/get-cart.d.ts
8
+ /** The cart data type with the fields from your cart query. Your query's field types replace the matching default cart fields. */
8
9
  type MergeCartData<TCart> = Omit<CartData, keyof TCart> & TCart;
9
10
  /**
10
- * Infers the {@link CartData} shape from a custom Storefront API cart query string.
11
+ * Gets the cart data type from a custom Storefront API cart query.
11
12
  *
12
- * When you pass a custom cart query to {@link getCart}, this type extracts the
13
- * `cart` field from the query's result type and merges it with the base
14
- * {@link CartData} interface, so the returned data is fully typed to your query.
13
+ * The type adds the cart fields from your query to the base cart data type.
14
+ *
15
+ * @publicDocs
15
16
  */
16
17
  type CartDataFromQuery<TQuery extends AnyStorefrontQueryString> = TQuery extends StorefrontQueryString<infer Result, infer _Variables, string> ? Result extends {
17
18
  cart?: (infer Cart) | null;
18
19
  } ? MergeCartData<NonNullable<Cart>> : CartData : CartData;
19
- /** Result of a {@link getCart} call — the cart data (or `null`), any errors, and response headers. */
20
+ /**
21
+ * The cart that `getCart` returns, with any GraphQL errors and the Storefront API response headers.
22
+ *
23
+ * @publicDocs
24
+ */
20
25
  type CartResult<TCart extends CartData = CartData> = {
21
- /** The cart, or `null` when no cart exists or the query failed. */cart: TCart | null;
26
+ /** The cart, or `null` when the cart ID is missing, the cart doesn't exist, or the query fails. */cart: TCart | null; /** GraphQL errors from the cart query. */
22
27
  errors?: Array<{
23
28
  message: string;
24
- }>; /** Response headers from the Storefront API (e.g. cache directives). */
29
+ }>; /** The Storefront API response headers, such as cache directives. The headers are empty when `getCart` skips the request. */
25
30
  headers: Headers;
26
31
  };
32
+ /** The Storefront API client that runs the cart query. */
27
33
  type StorefrontCartClient = Pick<StorefrontClient, "graphql">;
34
+ /** A request, or a request context with a `Cookie` header and a URL. */
28
35
  type CartIdSource = Request | Pick<ShopifyRequestContext, "cookie" | "url">;
29
36
  /**
30
- * Extracts the cart GID from a request.
37
+ * Reads the cart ID from a request.
31
38
  *
32
- * Checks the `cartId` search parameter first (for explicit linking), then
33
- * falls back to the `cart` cookie. Returns `null` when neither source
34
- * contains a cart identifier.
39
+ * The function checks the `cartId` search parameter first, then the `cart` cookie. The function returns a search parameter value unchanged and adds the `gid://shopify/Cart/` prefix to a cookie value.
35
40
  *
41
+ * @param input The request or request context that carries the cart ID.
42
+ * @returns The cart ID, or `null` when neither the search parameter nor the cookie has one.
36
43
  * @example
37
44
  * ```ts
38
45
  * // In a framework loader
@@ -41,16 +48,20 @@ type CartIdSource = Request | Pick<ShopifyRequestContext, "cookie" | "url">;
41
48
  * const { cart } = await getCart(cartId, storefront);
42
49
  * }
43
50
  * ```
51
+ * @publicDocs
44
52
  */
45
53
  declare function getCartId(input: CartIdSource): string | null;
46
54
  /**
47
55
  * Fetches a cart by ID from the Storefront API.
48
56
  *
49
- * Accepts an optional custom cart query document — the result type is inferred
50
- * via {@link CartDataFromQuery} so the returned `cart` is fully typed to your
51
- * query's fields. When `cartId` is `null`, returns `{ cart: null }` immediately
52
- * without making a network request.
57
+ * Pass a custom cart query to get a cart with that query's fields. Declare an `$id` variable in the query. The function passes the cart ID as the query's only variable.
58
+ *
59
+ * When the cart ID is `null`, the function returns a `null` cart without a network request. The function throws when the Storefront API request fails.
53
60
  *
61
+ * @param cartId The ID of the cart to fetch, or `null` to skip the request.
62
+ * @param storefront The Storefront API client that runs the cart query.
63
+ * @param cartQuery A cart query document that replaces the default cart query.
64
+ * @returns The cart or `null`, any GraphQL errors, and the Storefront API response headers.
54
65
  * @example
55
66
  * ```ts
56
67
  * const cartId = getCartId(request);
@@ -59,6 +70,7 @@ declare function getCartId(input: CartIdSource): string | null;
59
70
  * // With a custom query
60
71
  * const { cart } = await getCart(cartId, storefront, CUSTOM_CART_QUERY);
61
72
  * ```
73
+ * @publicDocs
62
74
  */
63
75
  declare function getCart<TQuery extends AnyStorefrontQueryString = typeof cartQueries.cart>(cartId: string | null, storefront: StorefrontCartClient, cartQuery?: TQuery): Promise<CartResult<CartDataFromQuery<TQuery>>>;
64
76
  //#endregion
@@ -3,12 +3,12 @@ import { cartQueries } from "./queries.mjs";
3
3
 
4
4
  //#region src/core/cart/get-cart.ts
5
5
  /**
6
- * Extracts the cart GID from a request.
6
+ * Reads the cart ID from a request.
7
7
  *
8
- * Checks the `cartId` search parameter first (for explicit linking), then
9
- * falls back to the `cart` cookie. Returns `null` when neither source
10
- * contains a cart identifier.
8
+ * The function checks the `cartId` search parameter first, then the `cart` cookie. The function returns a search parameter value unchanged and adds the `gid://shopify/Cart/` prefix to a cookie value.
11
9
  *
10
+ * @param input The request or request context that carries the cart ID.
11
+ * @returns The cart ID, or `null` when neither the search parameter nor the cookie has one.
12
12
  * @example
13
13
  * ```ts
14
14
  * // In a framework loader
@@ -17,6 +17,7 @@ import { cartQueries } from "./queries.mjs";
17
17
  * const { cart } = await getCart(cartId, storefront);
18
18
  * }
19
19
  * ```
20
+ * @publicDocs
20
21
  */
21
22
  function getCartId(input) {
22
23
  if (input.url) {
@@ -28,11 +29,14 @@ function getCartId(input) {
28
29
  /**
29
30
  * Fetches a cart by ID from the Storefront API.
30
31
  *
31
- * Accepts an optional custom cart query document — the result type is inferred
32
- * via {@link CartDataFromQuery} so the returned `cart` is fully typed to your
33
- * query's fields. When `cartId` is `null`, returns `{ cart: null }` immediately
34
- * without making a network request.
32
+ * Pass a custom cart query to get a cart with that query's fields. Declare an `$id` variable in the query. The function passes the cart ID as the query's only variable.
35
33
  *
34
+ * When the cart ID is `null`, the function returns a `null` cart without a network request. The function throws when the Storefront API request fails.
35
+ *
36
+ * @param cartId The ID of the cart to fetch, or `null` to skip the request.
37
+ * @param storefront The Storefront API client that runs the cart query.
38
+ * @param cartQuery A cart query document that replaces the default cart query.
39
+ * @returns The cart or `null`, any GraphQL errors, and the Storefront API response headers.
36
40
  * @example
37
41
  * ```ts
38
42
  * const cartId = getCartId(request);
@@ -41,6 +45,7 @@ function getCartId(input) {
41
45
  * // With a custom query
42
46
  * const { cart } = await getCart(cartId, storefront, CUSTOM_CART_QUERY);
43
47
  * ```
48
+ * @publicDocs
44
49
  */
45
50
  async function getCart(cartId, storefront, cartQuery = cartQueries.cart) {
46
51
  if (!cartId) return {
@@ -1 +1 @@
1
- {"version":3,"file":"get-cart.mjs","names":[],"sources":["../../../../src/core/cart/get-cart.ts"],"sourcesContent":["import type { StorefrontClient } from \"../../client\";\nimport type { AnyStorefrontQueryString, StorefrontQueryString } from \"../../graphql\";\nimport type { ShopifyRequestContext } from \"../request-context\";\nimport { getCartIdFromCookie } from \"./cookie\";\nimport { cartQueries } from \"./queries\";\nimport type { CartData } from \"./state\";\n\ntype MergeCartData<TCart> = Omit<CartData, keyof TCart> & TCart;\n\n/**\n * Infers the {@link CartData} shape from a custom Storefront API cart query string.\n *\n * When you pass a custom cart query to {@link getCart}, this type extracts the\n * `cart` field from the query's result type and merges it with the base\n * {@link CartData} interface, so the returned data is fully typed to your query.\n */\nexport type CartDataFromQuery<TQuery extends AnyStorefrontQueryString> =\n TQuery extends StorefrontQueryString<infer Result, infer _Variables, string>\n ? Result extends { cart?: (infer Cart) | null }\n ? MergeCartData<NonNullable<Cart>>\n : CartData\n : CartData;\n\n/** Result of a {@link getCart} call — the cart data (or `null`), any errors, and response headers. */\nexport type CartResult<TCart extends CartData = CartData> = {\n /** The cart, or `null` when no cart exists or the query failed. */\n cart: TCart | null;\n errors?: Array<{ message: string }>;\n /** Response headers from the Storefront API (e.g. cache directives). */\n headers: Headers;\n};\n\ntype CartQueryResult = {\n data: { cart?: unknown } | null;\n errors?: Array<{ message: string }>;\n headers: Headers;\n};\n\ntype StorefrontCartClient = Pick<StorefrontClient, \"graphql\">;\n\ntype CartQueryDocument = AnyStorefrontQueryString;\n\ntype CartQueryGraphql = (\n query: CartQueryDocument,\n options: { variables: { id: string } },\n) => Promise<CartQueryResult>;\n\ntype CartIdSource = Request | Pick<ShopifyRequestContext, \"cookie\" | \"url\">;\n\n/**\n * Extracts the cart GID from a request.\n *\n * Checks the `cartId` search parameter first (for explicit linking), then\n * falls back to the `cart` cookie. Returns `null` when neither source\n * contains a cart identifier.\n *\n * @example\n * ```ts\n * // In a framework loader\n * const cartId = getCartId(request);\n * if (cartId) {\n * const { cart } = await getCart(cartId, storefront);\n * }\n * ```\n */\nexport function getCartId(input: CartIdSource): string | null {\n if (input.url) {\n const parsedUrl = new URL(input.url, \"https://hydrogen.local\");\n const cartId = parsedUrl.searchParams.get(\"cartId\");\n if (cartId) return cartId;\n }\n\n return getCartIdFromCookie(input);\n}\n\n/**\n * Fetches a cart by ID from the Storefront API.\n *\n * Accepts an optional custom cart query document — the result type is inferred\n * via {@link CartDataFromQuery} so the returned `cart` is fully typed to your\n * query's fields. When `cartId` is `null`, returns `{ cart: null }` immediately\n * without making a network request.\n *\n * @example\n * ```ts\n * const cartId = getCartId(request);\n * const { cart, errors, headers } = await getCart(cartId, storefront);\n *\n * // With a custom query\n * const { cart } = await getCart(cartId, storefront, CUSTOM_CART_QUERY);\n * ```\n */\nexport async function getCart<TQuery extends AnyStorefrontQueryString = typeof cartQueries.cart>(\n cartId: string | null,\n storefront: StorefrontCartClient,\n cartQuery: TQuery = cartQueries.cart as TQuery,\n): Promise<CartResult<CartDataFromQuery<TQuery>>> {\n if (!cartId) {\n return {\n cart: null,\n headers: new Headers(),\n };\n }\n\n const queryCart = storefront.graphql as CartQueryGraphql;\n const result = await queryCart(cartQuery, { variables: { id: cartId } });\n\n if (result.errors || !result.data?.cart) {\n return {\n cart: null,\n errors: result.errors,\n headers: result.headers,\n };\n }\n\n return { cart: result.data.cart as CartDataFromQuery<TQuery>, headers: result.headers };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAiEA,SAAgB,UAAU,OAAoC;AAC5D,KAAI,MAAM,KAAK;EAEb,MAAM,SAAS,IADO,IAAI,MAAM,KAAK,yBACb,CAAC,aAAa,IAAI,SAAS;AACnD,MAAI,OAAQ,QAAO;;AAGrB,QAAO,oBAAoB,MAAM;;;;;;;;;;;;;;;;;;;AAoBnC,eAAsB,QACpB,QACA,YACA,YAAoB,YAAY,MACgB;AAChD,KAAI,CAAC,OACH,QAAO;EACL,MAAM;EACN,SAAS,IAAI,SAAS;EACvB;CAGH,MAAM,YAAY,WAAW;CAC7B,MAAM,SAAS,MAAM,UAAU,WAAW,EAAE,WAAW,EAAE,IAAI,QAAQ,EAAE,CAAC;AAExE,KAAI,OAAO,UAAU,CAAC,OAAO,MAAM,KACjC,QAAO;EACL,MAAM;EACN,QAAQ,OAAO;EACf,SAAS,OAAO;EACjB;AAGH,QAAO;EAAE,MAAM,OAAO,KAAK;EAAmC,SAAS,OAAO;EAAS"}
1
+ {"version":3,"file":"get-cart.mjs","names":[],"sources":["../../../../src/core/cart/get-cart.ts"],"sourcesContent":["import type { StorefrontClient } from \"../../client\";\nimport type { AnyStorefrontQueryString, StorefrontQueryString } from \"../../graphql\";\nimport type { ShopifyRequestContext } from \"../request-context\";\nimport { getCartIdFromCookie } from \"./cookie\";\nimport { cartQueries } from \"./queries\";\nimport type { CartData } from \"./state\";\n\n/** The cart data type with the fields from your cart query. Your query's field types replace the matching default cart fields. */\ntype MergeCartData<TCart> = Omit<CartData, keyof TCart> & TCart;\n\n/**\n * Gets the cart data type from a custom Storefront API cart query.\n *\n * The type adds the cart fields from your query to the base cart data type.\n *\n * @publicDocs\n */\nexport type CartDataFromQuery<TQuery extends AnyStorefrontQueryString> =\n TQuery extends StorefrontQueryString<infer Result, infer _Variables, string>\n ? Result extends { cart?: (infer Cart) | null }\n ? MergeCartData<NonNullable<Cart>>\n : CartData\n : CartData;\n\n/**\n * The cart that `getCart` returns, with any GraphQL errors and the Storefront API response headers.\n *\n * @publicDocs\n */\nexport type CartResult<TCart extends CartData = CartData> = {\n /** The cart, or `null` when the cart ID is missing, the cart doesn't exist, or the query fails. */\n cart: TCart | null;\n /** GraphQL errors from the cart query. */\n errors?: Array<{ message: string }>;\n /** The Storefront API response headers, such as cache directives. The headers are empty when `getCart` skips the request. */\n headers: Headers;\n};\n\ntype CartQueryResult = {\n data: { cart?: unknown } | null;\n errors?: Array<{ message: string }>;\n headers: Headers;\n};\n\n/** The Storefront API client that runs the cart query. */\ntype StorefrontCartClient = Pick<StorefrontClient, \"graphql\">;\n\ntype CartQueryDocument = AnyStorefrontQueryString;\n\ntype CartQueryGraphql = (\n query: CartQueryDocument,\n options: { variables: { id: string } },\n) => Promise<CartQueryResult>;\n\n/** A request, or a request context with a `Cookie` header and a URL. */\ntype CartIdSource = Request | Pick<ShopifyRequestContext, \"cookie\" | \"url\">;\n\n/**\n * Reads the cart ID from a request.\n *\n * The function checks the `cartId` search parameter first, then the `cart` cookie. The function returns a search parameter value unchanged and adds the `gid://shopify/Cart/` prefix to a cookie value.\n *\n * @param input The request or request context that carries the cart ID.\n * @returns The cart ID, or `null` when neither the search parameter nor the cookie has one.\n * @example\n * ```ts\n * // In a framework loader\n * const cartId = getCartId(request);\n * if (cartId) {\n * const { cart } = await getCart(cartId, storefront);\n * }\n * ```\n * @publicDocs\n */\nexport function getCartId(input: CartIdSource): string | null {\n if (input.url) {\n const parsedUrl = new URL(input.url, \"https://hydrogen.local\");\n const cartId = parsedUrl.searchParams.get(\"cartId\");\n if (cartId) return cartId;\n }\n\n return getCartIdFromCookie(input);\n}\n\n/**\n * Fetches a cart by ID from the Storefront API.\n *\n * Pass a custom cart query to get a cart with that query's fields. Declare an `$id` variable in the query. The function passes the cart ID as the query's only variable.\n *\n * When the cart ID is `null`, the function returns a `null` cart without a network request. The function throws when the Storefront API request fails.\n *\n * @param cartId The ID of the cart to fetch, or `null` to skip the request.\n * @param storefront The Storefront API client that runs the cart query.\n * @param cartQuery A cart query document that replaces the default cart query.\n * @returns The cart or `null`, any GraphQL errors, and the Storefront API response headers.\n * @example\n * ```ts\n * const cartId = getCartId(request);\n * const { cart, errors, headers } = await getCart(cartId, storefront);\n *\n * // With a custom query\n * const { cart } = await getCart(cartId, storefront, CUSTOM_CART_QUERY);\n * ```\n * @publicDocs\n */\nexport async function getCart<TQuery extends AnyStorefrontQueryString = typeof cartQueries.cart>(\n cartId: string | null,\n storefront: StorefrontCartClient,\n cartQuery: TQuery = cartQueries.cart as TQuery,\n): Promise<CartResult<CartDataFromQuery<TQuery>>> {\n if (!cartId) {\n return {\n cart: null,\n headers: new Headers(),\n };\n }\n\n const queryCart = storefront.graphql as CartQueryGraphql;\n const result = await queryCart(cartQuery, { variables: { id: cartId } });\n\n if (result.errors || !result.data?.cart) {\n return {\n cart: null,\n errors: result.errors,\n headers: result.headers,\n };\n }\n\n return { cart: result.data.cart as CartDataFromQuery<TQuery>, headers: result.headers };\n}\n\n/**\n * Fetches a cart by ID from the Storefront API.\n *\n * Pass a custom cart query to get a cart with that query's fields. Declare an `$id` variable in the query. The function passes the cart ID as the query's only variable.\n *\n * When the cart ID is `null`, the function returns a `null` cart without a network request. The function throws when the Storefront API request fails.\n *\n * @example\n * ```ts\n * const cartId = getCartId(request);\n * const { cart, errors, headers } = await getCart(cartId, storefront);\n *\n * // With a custom query\n * const { cart } = await getCart(cartId, storefront, CUSTOM_CART_QUERY);\n * ```\n * @publicDocs\n */\nexport type GetCartForDocs =\n /**\n * @param cartId - The ID of the cart to fetch, or `null` to skip the request.\n * @param storefront - The Storefront API client that runs the cart query.\n * @param cartQuery - A cart query document that replaces the default cart query.\n * @returns The cart or `null`, any GraphQL errors, and the Storefront API response headers.\n */\n (\n cartId: string | null,\n storefront: StorefrontCartClient,\n cartQuery?: AnyStorefrontQueryString,\n ) => Promise<CartResult<CartData>>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0EA,SAAgB,UAAU,OAAoC;AAC5D,KAAI,MAAM,KAAK;EAEb,MAAM,SAAS,IADO,IAAI,MAAM,KAAK,yBACb,CAAC,aAAa,IAAI,SAAS;AACnD,MAAI,OAAQ,QAAO;;AAGrB,QAAO,oBAAoB,MAAM;;;;;;;;;;;;;;;;;;;;;;;AAwBnC,eAAsB,QACpB,QACA,YACA,YAAoB,YAAY,MACgB;AAChD,KAAI,CAAC,OACH,QAAO;EACL,MAAM;EACN,SAAS,IAAI,SAAS;EACvB;CAGH,MAAM,YAAY,WAAW;CAC7B,MAAM,SAAS,MAAM,UAAU,WAAW,EAAE,WAAW,EAAE,IAAI,QAAQ,EAAE,CAAC;AAExE,KAAI,OAAO,UAAU,CAAC,OAAO,MAAM,KACjC,QAAO;EACL,MAAM;EACN,QAAQ,OAAO;EACf,SAAS,OAAO;EACjB;AAGH,QAAO;EAAE,MAAM,OAAO,KAAK;EAAmC,SAAS,OAAO;EAAS"}
@@ -1,14 +1,24 @@
1
1
  //#region src/core/cart/quantity.d.ts
2
- /** Default lower bound for {@link sanitizeQuantity} when no `min` is given. */
2
+ /**
3
+ * The minimum quantity that sanitizeQuantity uses when you omit `min`.
4
+ *
5
+ * @publicDocs
6
+ */
3
7
  declare const DEFAULT_MINIMUM_QUANTITY = 1;
4
- /** Sentinel upper bound for {@link sanitizeQuantity} meaning "no maximum". */
8
+ /**
9
+ * The maximum quantity that sanitizeQuantity uses when you omit `max`. The value, `Infinity`, sets no upper limit.
10
+ *
11
+ * @publicDocs
12
+ */
5
13
  declare const NO_QUANTITY_LIMIT: number;
6
14
  /**
7
- * Clamps a raw value to a valid integer quantity within `min`/`max` bounds.
15
+ * Turns a raw value, such as text from a quantity input, into a whole-number quantity between a minimum and a maximum.
8
16
  *
9
- * Parses strings, rounds floats, and falls back to `min` for unparseable input.
10
- * Used internally by the cart form system to sanitize user-typed quantities.
17
+ * The function parses strings and rounds decimals. Input that the function can't parse returns the minimum.
11
18
  *
19
+ * @param raw The value to turn into a quantity.
20
+ * @param options The lower and upper bounds. The `min` option defaults to `1`, and `max` defaults to no limit. To stop at available stock, pass the variant's available quantity as `max`.
21
+ * @returns The rounded quantity, between the minimum and the maximum.
12
22
  * @example
13
23
  * ```ts
14
24
  * sanitizeQuantity("3") // → 3
@@ -17,6 +27,7 @@ declare const NO_QUANTITY_LIMIT: number;
17
27
  * sanitizeQuantity(5, { max: 3 }) // → 3
18
28
  * sanitizeQuantity(0, { min: 1 }) // → 1
19
29
  * ```
30
+ * @publicDocs
20
31
  */
21
32
  declare function sanitizeQuantity(raw: unknown, options?: {
22
33
  min?: number;
@@ -1,14 +1,24 @@
1
1
  //#region src/core/cart/quantity.ts
2
- /** Default lower bound for {@link sanitizeQuantity} when no `min` is given. */
2
+ /**
3
+ * The minimum quantity that sanitizeQuantity uses when you omit `min`.
4
+ *
5
+ * @publicDocs
6
+ */
3
7
  const DEFAULT_MINIMUM_QUANTITY = 1;
4
- /** Sentinel upper bound for {@link sanitizeQuantity} meaning "no maximum". */
8
+ /**
9
+ * The maximum quantity that sanitizeQuantity uses when you omit `max`. The value, `Infinity`, sets no upper limit.
10
+ *
11
+ * @publicDocs
12
+ */
5
13
  const NO_QUANTITY_LIMIT = Infinity;
6
14
  /**
7
- * Clamps a raw value to a valid integer quantity within `min`/`max` bounds.
15
+ * Turns a raw value, such as text from a quantity input, into a whole-number quantity between a minimum and a maximum.
8
16
  *
9
- * Parses strings, rounds floats, and falls back to `min` for unparseable input.
10
- * Used internally by the cart form system to sanitize user-typed quantities.
17
+ * The function parses strings and rounds decimals. Input that the function can't parse returns the minimum.
11
18
  *
19
+ * @param raw The value to turn into a quantity.
20
+ * @param options The lower and upper bounds. The `min` option defaults to `1`, and `max` defaults to no limit. To stop at available stock, pass the variant's available quantity as `max`.
21
+ * @returns The rounded quantity, between the minimum and the maximum.
12
22
  * @example
13
23
  * ```ts
14
24
  * sanitizeQuantity("3") // → 3
@@ -17,6 +27,7 @@ const NO_QUANTITY_LIMIT = Infinity;
17
27
  * sanitizeQuantity(5, { max: 3 }) // → 3
18
28
  * sanitizeQuantity(0, { min: 1 }) // → 1
19
29
  * ```
30
+ * @publicDocs
20
31
  */
21
32
  function sanitizeQuantity(raw, options) {
22
33
  const min = options?.min ?? 1;
@@ -1 +1 @@
1
- {"version":3,"file":"quantity.mjs","names":[],"sources":["../../../../src/core/cart/quantity.ts"],"sourcesContent":["/** Default lower bound for {@link sanitizeQuantity} when no `min` is given. */\nexport const DEFAULT_MINIMUM_QUANTITY = 1;\n\n/** Sentinel upper bound for {@link sanitizeQuantity} meaning \"no maximum\". */\nexport const NO_QUANTITY_LIMIT = Infinity;\n\n/**\n * Clamps a raw value to a valid integer quantity within `min`/`max` bounds.\n *\n * Parses strings, rounds floats, and falls back to `min` for unparseable input.\n * Used internally by the cart form system to sanitize user-typed quantities.\n *\n * @example\n * ```ts\n * sanitizeQuantity(\"3\") // → 3\n * sanitizeQuantity(\"2.7\") // → 3\n * sanitizeQuantity(\"abc\") // → 1 (falls back to min)\n * sanitizeQuantity(5, { max: 3 }) // → 3\n * sanitizeQuantity(0, { min: 1 }) // → 1\n * ```\n */\nexport function sanitizeQuantity(raw: unknown, options?: { min?: number; max?: number }): number {\n const min = options?.min ?? DEFAULT_MINIMUM_QUANTITY;\n const max = options?.max ?? NO_QUANTITY_LIMIT;\n\n const parsed = Number(String(raw).trim());\n if (Number.isNaN(parsed)) return min;\n\n const rounded = Math.round(parsed);\n return Math.min(Math.max(rounded, min), max);\n}\n"],"mappings":";;AACA,MAAa,2BAA2B;;AAGxC,MAAa,oBAAoB;;;;;;;;;;;;;;;;AAiBjC,SAAgB,iBAAiB,KAAc,SAAkD;CAC/F,MAAM,MAAM,SAAS;CACrB,MAAM,MAAM,SAAS;CAErB,MAAM,SAAS,OAAO,OAAO,IAAI,CAAC,MAAM,CAAC;AACzC,KAAI,OAAO,MAAM,OAAO,CAAE,QAAO;AAGjC,QAAO,KAAK,IAAI,KAAK,IADL,KAAK,MAAM,OACK,EAAE,IAAI,EAAE,IAAI"}
1
+ {"version":3,"file":"quantity.mjs","names":[],"sources":["../../../../src/core/cart/quantity.ts"],"sourcesContent":["/**\n * The minimum quantity that sanitizeQuantity uses when you omit `min`.\n *\n * @publicDocs\n */\nexport const DEFAULT_MINIMUM_QUANTITY = 1;\n\n/**\n * The maximum quantity that sanitizeQuantity uses when you omit `max`. The value, `Infinity`, sets no upper limit.\n *\n * @publicDocs\n */\nexport const NO_QUANTITY_LIMIT = Infinity;\n\n/**\n * Turns a raw value, such as text from a quantity input, into a whole-number quantity between a minimum and a maximum.\n *\n * The function parses strings and rounds decimals. Input that the function can't parse returns the minimum.\n *\n * @param raw The value to turn into a quantity.\n * @param options The lower and upper bounds. The `min` option defaults to `1`, and `max` defaults to no limit. To stop at available stock, pass the variant's available quantity as `max`.\n * @returns The rounded quantity, between the minimum and the maximum.\n * @example\n * ```ts\n * sanitizeQuantity(\"3\") // → 3\n * sanitizeQuantity(\"2.7\") // → 3\n * sanitizeQuantity(\"abc\") // → 1 (falls back to min)\n * sanitizeQuantity(5, { max: 3 }) // → 3\n * sanitizeQuantity(0, { min: 1 }) // → 1\n * ```\n * @publicDocs\n */\nexport function sanitizeQuantity(raw: unknown, options?: { min?: number; max?: number }): number {\n const min = options?.min ?? DEFAULT_MINIMUM_QUANTITY;\n const max = options?.max ?? NO_QUANTITY_LIMIT;\n\n const parsed = Number(String(raw).trim());\n if (Number.isNaN(parsed)) return min;\n\n const rounded = Math.round(parsed);\n return Math.min(Math.max(rounded, min), max);\n}\n"],"mappings":";;;;;;AAKA,MAAa,2BAA2B;;;;;;AAOxC,MAAa,oBAAoB;;;;;;;;;;;;;;;;;;;AAoBjC,SAAgB,iBAAiB,KAAc,SAAkD;CAC/F,MAAM,MAAM,SAAS;CACrB,MAAM,MAAM,SAAS;CAErB,MAAM,SAAS,OAAO,OAAO,IAAI,CAAC,MAAM,CAAC;AACzC,KAAI,OAAO,MAAM,OAAO,CAAE,QAAO;AAGjC,QAAO,KAAK,IAAI,KAAK,IADL,KAAK,MAAM,OACK,EAAE,IAAI,EAAE,IAAI"}