@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
@@ -2,11 +2,23 @@ import { ShopifyRoutesOptions, ShopifyScriptTagsOptions } from "../core/shopify-
2
2
  import * as React from "react";
3
3
 
4
4
  //#region src/react/shopify-scripts.d.ts
5
- type ShopifyScriptsProps = ShopifyScriptTagsOptions & {
5
+ /**
6
+ * Props for the `ShopifyScripts` component in React and Vue. The component renders Shopify's script
7
+ * tags and starts the scripts in the browser after hydration. The component starts the scripts
8
+ * once, with the first props. Later prop changes don't restart the scripts.
9
+ *
10
+ * In Next.js App Router, render the component from a client component when you pass a consent `setup` function. Function props can't cross the server-to-client boundary.
11
+ *
12
+ * @publicDocs
13
+ */
14
+ interface ShopifyScriptsProps extends ShopifyScriptTagsOptions {
15
+ /** Navigates after Shopify's scripts resolve a URL to your app's route. Defaults to a full page load. */
6
16
  navigate?: ShopifyRoutesOptions["navigate"];
17
+ /** Your app's custom route templates, which Shopify's scripts use to match storefront URLs. */
7
18
  routes?: ShopifyRoutesOptions["routes"];
19
+ /** Loads Shopify's WebMCP tools when the browser supports WebMCP. Defaults to `true`. */
8
20
  webMcp?: boolean;
9
- };
21
+ }
10
22
  declare module "react" {
11
23
  namespace JSX {
12
24
  interface IntrinsicElements {
@@ -14,6 +26,15 @@ declare module "react" {
14
26
  }
15
27
  }
16
28
  }
29
+ /**
30
+ * Renders Shopify's script tags and starts the scripts in the browser after hydration. The component starts the scripts once, with the first props. Later prop changes don't restart the scripts.
31
+ *
32
+ * `ShopifyScripts` is a client component. In Next.js App Router, render it from a client component when you pass a consent `setup` function. Function props can't cross the server-to-client boundary.
33
+ *
34
+ * @param options - The script tag options, plus the consent, route, and WebMCP settings for starting the scripts.
35
+ * @returns Shopify's link and script tags, with the link tags first.
36
+ * @publicDocs
37
+ */
17
38
  declare function ShopifyScripts(options: ShopifyScriptsProps): React.FunctionComponentElement<React.FragmentProps>;
18
39
  //#endregion
19
40
  export { ShopifyScripts, ShopifyScriptsProps };
@@ -5,6 +5,15 @@ import { getShopifyScriptTags } from "../core/shopify-scripts/index.mjs";
5
5
  import { Fragment, createElement, useEffect } from "react";
6
6
 
7
7
  //#region src/react/shopify-scripts.tsx
8
+ /**
9
+ * Renders Shopify's script tags and starts the scripts in the browser after hydration. The component starts the scripts once, with the first props. Later prop changes don't restart the scripts.
10
+ *
11
+ * `ShopifyScripts` is a client component. In Next.js App Router, render it from a client component when you pass a consent `setup` function. Function props can't cross the server-to-client boundary.
12
+ *
13
+ * @param options - The script tag options, plus the consent, route, and WebMCP settings for starting the scripts.
14
+ * @returns Shopify's link and script tags, with the link tags first.
15
+ * @publicDocs
16
+ */
8
17
  function ShopifyScripts(options) {
9
18
  const { consent, navigate, routes, webMcp = true, ...scriptOptions } = options;
10
19
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"shopify-scripts.mjs","names":[],"sources":["../../src/react/shopify-scripts.tsx"],"sourcesContent":["\"use client\";\n\nimport { createElement, Fragment, useEffect } from \"react\";\nimport type * as React from \"react\";\n\nimport {\n getShopifyScriptTags,\n initializeShopifyScripts,\n type ShopifyRoutesOptions,\n type ShopifyScriptTagsOptions,\n} from \"../core/shopify-scripts\";\n\nexport type ShopifyScriptsProps = ShopifyScriptTagsOptions & {\n navigate?: ShopifyRoutesOptions[\"navigate\"];\n routes?: ShopifyRoutesOptions[\"routes\"];\n webMcp?: boolean;\n};\n\ndeclare module \"react\" {\n namespace JSX {\n interface IntrinsicElements {\n \"shopify-chat\": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;\n }\n }\n}\n\nexport function ShopifyScripts(options: ShopifyScriptsProps) {\n const { consent, navigate, routes, webMcp = true, ...scriptOptions } = options;\n\n useEffect(() => {\n void initializeShopifyScripts({ consent, navigate, routes, webMcp });\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- ShopifyScripts browser startup is initialized once from initial props.\n }, []);\n\n return createElement(\n Fragment,\n null,\n getShopifyScriptTags({ ...scriptOptions, consent }).tags.map(\n ({ tagName, attributes, innerHTML }, index) =>\n createElement(tagName, {\n key: index,\n ...getReactAttributes(attributes),\n ...(innerHTML ? { dangerouslySetInnerHTML: { __html: innerHTML } } : {}),\n }),\n ),\n );\n}\n\nfunction getReactAttributes(attributes: Record<string, string | boolean> = {}) {\n const reactAttributes = Object.fromEntries(\n Object.entries(attributes).map(([name, value]) => [\n name === \"crossorigin\" ? \"crossOrigin\" : name,\n value,\n ]),\n );\n\n if (attributes.nonce !== undefined) {\n // Browsers intentionally hide nonce content attributes from getAttribute(),\n // which can make React report a false hydration mismatch for SSR scripts.\n reactAttributes.suppressHydrationWarning = true;\n }\n\n if (attributes.async === true && typeof attributes.src === \"string\") {\n // React hoists async scripts without handlers, which can let them execute before\n // the inline Shopify bootstrap scripts that configure their globals.\n return { ...reactAttributes, onLoad: disableReactScriptHoisting };\n }\n\n return reactAttributes;\n}\n\nconst disableReactScriptHoisting = () => {};\n"],"mappings":";;;;;;;AA0BA,SAAgB,eAAe,SAA8B;CAC3D,MAAM,EAAE,SAAS,UAAU,QAAQ,SAAS,MAAM,GAAG,kBAAkB;AAEvE,iBAAgB;AACd,EAAK,yBAAyB;GAAE;GAAS;GAAU;GAAQ;GAAQ,CAAC;IAEnE,EAAE,CAAC;AAEN,QAAO,cACL,UACA,MACA,qBAAqB;EAAE,GAAG;EAAe;EAAS,CAAC,CAAC,KAAK,KACtD,EAAE,SAAS,YAAY,aAAa,UACnC,cAAc,SAAS;EACrB,KAAK;EACL,GAAG,mBAAmB,WAAW;EACjC,GAAI,YAAY,EAAE,yBAAyB,EAAE,QAAQ,WAAW,EAAE,GAAG,EAAE;EACxE,CAAC,CACL,CACF;;AAGH,SAAS,mBAAmB,aAA+C,EAAE,EAAE;CAC7E,MAAM,kBAAkB,OAAO,YAC7B,OAAO,QAAQ,WAAW,CAAC,KAAK,CAAC,MAAM,WAAW,CAChD,SAAS,gBAAgB,gBAAgB,MACzC,MACD,CAAC,CACH;AAED,KAAI,WAAW,UAAU,OAGvB,iBAAgB,2BAA2B;AAG7C,KAAI,WAAW,UAAU,QAAQ,OAAO,WAAW,QAAQ,SAGzD,QAAO;EAAE,GAAG;EAAiB,QAAQ;EAA4B;AAGnE,QAAO;;AAGT,MAAM,mCAAmC"}
1
+ {"version":3,"file":"shopify-scripts.mjs","names":[],"sources":["../../src/react/shopify-scripts.tsx"],"sourcesContent":["\"use client\";\n\nimport { createElement, Fragment, useEffect } from \"react\";\nimport type * as React from \"react\";\n\nimport {\n getShopifyScriptTags,\n initializeShopifyScripts,\n type ShopifyRoutesOptions,\n type ShopifyScriptTagsOptions,\n} from \"../core/shopify-scripts\";\n\n/**\n * Props for the `ShopifyScripts` component in React and Vue. The component renders Shopify's script\n * tags and starts the scripts in the browser after hydration. The component starts the scripts\n * once, with the first props. Later prop changes don't restart the scripts.\n *\n * In Next.js App Router, render the component from a client component when you pass a consent `setup` function. Function props can't cross the server-to-client boundary.\n *\n * @publicDocs\n */\nexport interface ShopifyScriptsProps extends ShopifyScriptTagsOptions {\n /** Navigates after Shopify's scripts resolve a URL to your app's route. Defaults to a full page load. */\n navigate?: ShopifyRoutesOptions[\"navigate\"];\n /** Your app's custom route templates, which Shopify's scripts use to match storefront URLs. */\n routes?: ShopifyRoutesOptions[\"routes\"];\n /** Loads Shopify's WebMCP tools when the browser supports WebMCP. Defaults to `true`. */\n webMcp?: boolean;\n}\n\ndeclare module \"react\" {\n namespace JSX {\n interface IntrinsicElements {\n \"shopify-chat\": React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;\n }\n }\n}\n\n/**\n * Renders Shopify's script tags and starts the scripts in the browser after hydration. The component starts the scripts once, with the first props. Later prop changes don't restart the scripts.\n *\n * `ShopifyScripts` is a client component. In Next.js App Router, render it from a client component when you pass a consent `setup` function. Function props can't cross the server-to-client boundary.\n *\n * @param options - The script tag options, plus the consent, route, and WebMCP settings for starting the scripts.\n * @returns Shopify's link and script tags, with the link tags first.\n * @publicDocs\n */\nexport function ShopifyScripts(options: ShopifyScriptsProps) {\n const { consent, navigate, routes, webMcp = true, ...scriptOptions } = options;\n\n useEffect(() => {\n void initializeShopifyScripts({ consent, navigate, routes, webMcp });\n // oxlint-disable-next-line react-hooks/exhaustive-deps -- ShopifyScripts browser startup is initialized once from initial props.\n }, []);\n\n return createElement(\n Fragment,\n null,\n getShopifyScriptTags({ ...scriptOptions, consent }).tags.map(\n ({ tagName, attributes, innerHTML }, index) =>\n createElement(tagName, {\n key: index,\n ...getReactAttributes(attributes),\n ...(innerHTML ? { dangerouslySetInnerHTML: { __html: innerHTML } } : {}),\n }),\n ),\n );\n}\n\nfunction getReactAttributes(attributes: Record<string, string | boolean> = {}) {\n const reactAttributes = Object.fromEntries(\n Object.entries(attributes).map(([name, value]) => [\n name === \"crossorigin\" ? \"crossOrigin\" : name,\n value,\n ]),\n );\n\n if (attributes.nonce !== undefined) {\n // Browsers intentionally hide nonce content attributes from getAttribute(),\n // which can make React report a false hydration mismatch for SSR scripts.\n reactAttributes.suppressHydrationWarning = true;\n }\n\n if (attributes.async === true && typeof attributes.src === \"string\") {\n // React hoists async scripts without handlers, which can let them execute before\n // the inline Shopify bootstrap scripts that configure their globals.\n return { ...reactAttributes, onLoad: disableReactScriptHoisting };\n }\n\n return reactAttributes;\n}\n\nconst disableReactScriptHoisting = () => {};\n"],"mappings":";;;;;;;;;;;;;;;;AA+CA,SAAgB,eAAe,SAA8B;CAC3D,MAAM,EAAE,SAAS,UAAU,QAAQ,SAAS,MAAM,GAAG,kBAAkB;AAEvE,iBAAgB;AACd,EAAK,yBAAyB;GAAE;GAAS;GAAU;GAAQ;GAAQ,CAAC;IAEnE,EAAE,CAAC;AAEN,QAAO,cACL,UACA,MACA,qBAAqB;EAAE,GAAG;EAAe;EAAS,CAAC,CAAC,KAAK,KACtD,EAAE,SAAS,YAAY,aAAa,UACnC,cAAc,SAAS;EACrB,KAAK;EACL,GAAG,mBAAmB,WAAW;EACjC,GAAI,YAAY,EAAE,yBAAyB,EAAE,QAAQ,WAAW,EAAE,GAAG,EAAE;EACxE,CAAC,CACL,CACF;;AAGH,SAAS,mBAAmB,aAA+C,EAAE,EAAE;CAC7E,MAAM,kBAAkB,OAAO,YAC7B,OAAO,QAAQ,WAAW,CAAC,KAAK,CAAC,MAAM,WAAW,CAChD,SAAS,gBAAgB,gBAAgB,MACzC,MACD,CAAC,CACH;AAED,KAAI,WAAW,UAAU,OAGvB,iBAAgB,2BAA2B;AAG7C,KAAI,WAAW,UAAU,QAAQ,OAAO,WAAW,QAAQ,SAGzD,QAAO;EAAE,GAAG;EAAiB,QAAQ;EAA4B;AAGnE,QAAO;;AAGT,MAAM,mCAAmC"}
@@ -53,6 +53,12 @@ function createGraphQLPluginConfig(schemaDirectory) {
53
53
  //#endregion
54
54
  //#region src/ts-plugin/index.ts
55
55
  const SCHEMA_DIRECTORY = (0, node_path.resolve)(__dirname, "..");
56
+ /**
57
+ * TypeScript language service plugin that configures gql.tada with Hydrogen's bundled Storefront and
58
+ * Customer Account API schemas.
59
+ *
60
+ * @publicDocs
61
+ */
56
62
  const init = (modules) => {
57
63
  const plugin = (0, gql_tada_ts_plugin.default)(modules);
58
64
  return { create(info) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/graphql/plugin-config.ts","../../src/ts-plugin/index.ts"],"sourcesContent":["import { join } from \"node:path\";\n\nconst STOREFRONT_SCHEMA_FILE_NAME = \"storefront.schema.json\";\nconst CUSTOMER_ACCOUNT_SCHEMA_FILE_NAME = \"customer-account.schema.json\";\nconst STOREFRONT_OUTPUT_FILE_NAME = \"storefront-graphql-env.d.ts\";\nconst CUSTOMER_ACCOUNT_OUTPUT_FILE_NAME = \"customer-account-graphql-env.d.ts\";\n\nexport function createGraphQLPluginConfig(schemaDirectory: string) {\n return {\n name: \"gql.tada/ts-plugin\",\n schemas: [\n {\n name: \"storefront\",\n schema: join(schemaDirectory, STOREFRONT_SCHEMA_FILE_NAME),\n tadaOutputLocation: STOREFRONT_OUTPUT_FILE_NAME,\n },\n {\n name: \"customer-account\",\n schema: join(schemaDirectory, CUSTOMER_ACCOUNT_SCHEMA_FILE_NAME),\n tadaOutputLocation: CUSTOMER_ACCOUNT_OUTPUT_FILE_NAME,\n },\n ],\n trackFieldUsage: false,\n } as const;\n}\n","import { resolve } from \"node:path\";\n\nimport gqlTadaPlugin from \"gql.tada/ts-plugin\";\nimport type ts from \"typescript/lib/tsserverlibrary\";\n\nimport { createGraphQLPluginConfig } from \"../graphql/plugin-config\";\n\nconst SCHEMA_DIRECTORY = resolve(__dirname, \"..\");\n\nconst init: ts.server.PluginModuleFactory = (modules) => {\n const plugin = gqlTadaPlugin(modules);\n\n return {\n create(info) {\n return plugin.create({\n ...info,\n config: createGraphQLPluginConfig(SCHEMA_DIRECTORY),\n });\n },\n };\n};\n\nexport default init;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,MAAM,8BAA8B;AACpC,MAAM,oCAAoC;AAC1C,MAAM,8BAA8B;AACpC,MAAM,oCAAoC;AAE1C,SAAgB,0BAA0B,iBAAyB;AACjE,QAAO;EACL,MAAM;EACN,SAAS,CACP;GACE,MAAM;GACN,4BAAa,iBAAiB,4BAA4B;GAC1D,oBAAoB;GACrB,EACD;GACE,MAAM;GACN,4BAAa,iBAAiB,kCAAkC;GAChE,oBAAoB;GACrB,CACF;EACD,iBAAiB;EAClB;;;;;AChBH,MAAM,0CAA2B,WAAW,KAAK;AAEjD,MAAM,QAAuC,YAAY;CACvD,MAAM,yCAAuB,QAAQ;AAErC,QAAO,EACL,OAAO,MAAM;AACX,SAAO,OAAO,OAAO;GACnB,GAAG;GACH,QAAQ,0BAA0B,iBAAiB;GACpD,CAAC;IAEL"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../src/graphql/plugin-config.ts","../../src/ts-plugin/index.ts"],"sourcesContent":["import { join } from \"node:path\";\n\nconst STOREFRONT_SCHEMA_FILE_NAME = \"storefront.schema.json\";\nconst CUSTOMER_ACCOUNT_SCHEMA_FILE_NAME = \"customer-account.schema.json\";\nconst STOREFRONT_OUTPUT_FILE_NAME = \"storefront-graphql-env.d.ts\";\nconst CUSTOMER_ACCOUNT_OUTPUT_FILE_NAME = \"customer-account-graphql-env.d.ts\";\n\nexport function createGraphQLPluginConfig(schemaDirectory: string) {\n return {\n name: \"gql.tada/ts-plugin\",\n schemas: [\n {\n name: \"storefront\",\n schema: join(schemaDirectory, STOREFRONT_SCHEMA_FILE_NAME),\n tadaOutputLocation: STOREFRONT_OUTPUT_FILE_NAME,\n },\n {\n name: \"customer-account\",\n schema: join(schemaDirectory, CUSTOMER_ACCOUNT_SCHEMA_FILE_NAME),\n tadaOutputLocation: CUSTOMER_ACCOUNT_OUTPUT_FILE_NAME,\n },\n ],\n trackFieldUsage: false,\n } as const;\n}\n","import { resolve } from \"node:path\";\n\nimport gqlTadaPlugin from \"gql.tada/ts-plugin\";\nimport type ts from \"typescript/lib/tsserverlibrary\";\n\nimport { createGraphQLPluginConfig } from \"../graphql/plugin-config\";\n\nconst SCHEMA_DIRECTORY = resolve(__dirname, \"..\");\n\n/**\n * TypeScript language service plugin that configures gql.tada with Hydrogen's bundled Storefront and\n * Customer Account API schemas.\n *\n * @publicDocs\n */\nconst init: ts.server.PluginModuleFactory = (modules) => {\n const plugin = gqlTadaPlugin(modules);\n\n return {\n create(info) {\n return plugin.create({\n ...info,\n config: createGraphQLPluginConfig(SCHEMA_DIRECTORY),\n });\n },\n };\n};\n\nexport default init;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,MAAM,8BAA8B;AACpC,MAAM,oCAAoC;AAC1C,MAAM,8BAA8B;AACpC,MAAM,oCAAoC;AAE1C,SAAgB,0BAA0B,iBAAyB;AACjE,QAAO;EACL,MAAM;EACN,SAAS,CACP;GACE,MAAM;GACN,4BAAa,iBAAiB,4BAA4B;GAC1D,oBAAoB;GACrB,EACD;GACE,MAAM;GACN,4BAAa,iBAAiB,kCAAkC;GAChE,oBAAoB;GACrB,CACF;EACD,iBAAiB;EAClB;;;;;AChBH,MAAM,0CAA2B,WAAW,KAAK;;;;;;;AAQjD,MAAM,QAAuC,YAAY;CACvD,MAAM,yCAAuB,QAAQ;AAErC,QAAO,EACL,OAAO,MAAM;AACX,SAAO,OAAO,OAAO;GACnB,GAAG;GACH,QAAQ,0BAA0B,iBAAiB;GACpD,CAAC;IAEL"}
@@ -1,4 +1,10 @@
1
1
  import ts = require("typescript/lib/tsserverlibrary");
2
2
 
3
+ /**
4
+ * TypeScript language service plugin that configures gql.tada with Hydrogen's bundled Storefront and
5
+ * Customer Account API schemas.
6
+ *
7
+ * @publicDocs
8
+ */
3
9
  declare const init: ts.server.PluginModuleFactory;
4
10
  export = init;
@@ -1,41 +1,75 @@
1
1
  import { Plugin } from "vite";
2
2
 
3
3
  //#region src/vite/local-https.d.ts
4
+ /**
5
+ * Default host, `local.tryhydrogen.dev`, and port, `5173`, for local HTTPS. Pass the values to frameworks that set their own dev server host and port, such as Astro.
6
+ *
7
+ * @publicDocs
8
+ */
4
9
  declare const LOCAL_HTTPS_DEFAULTS: {
5
10
  readonly host: "local.tryhydrogen.dev";
6
11
  readonly port: 5173;
7
12
  };
8
- /** Options for Hydrogen's local HTTPS Vite plugin. */
13
+ /** Switch, host, port, and certificate files for local HTTPS. */
9
14
  type LocalHttpsOptions = {
10
- /** Enable trusted local HTTPS for the dev server. */enabled: boolean; /** Local hostname registered in Shopify admin. Defaults to `local.tryhydrogen.dev`. */
11
- host?: string; /** Local port registered in Shopify admin. Defaults to `5173`. */
12
- port?: number; /** Certificate file path. Defaults to Hydrogen's mkcert path under `~/.shopify/hydrogen/certs`. */
13
- certPath?: string | URL; /** Private key file path. Defaults to Hydrogen's mkcert path under `~/.shopify/hydrogen/certs`. */
15
+ /** Turns on local HTTPS for the dev server. When `false`, the plugin leaves the Vite config unchanged. */enabled: boolean; /** Hostname for the dev server and the Customer Account API URLs. Defaults to `local.tryhydrogen.dev`. */
16
+ host?: string; /** Port for the dev server. Vite exits when another process uses the port. Defaults to `5173`. */
17
+ port?: number; /** Path to the certificate file. Defaults to `~/.shopify/hydrogen/certs/<host>.pem`. A leading `~/` points to your home directory, and a relative path starts from the current working directory. */
18
+ certPath?: string | URL; /** Path to the private key file. Defaults to `~/.shopify/hydrogen/certs/<host>-key.pem`. Accepts the same path forms as `certPath`. */
14
19
  keyPath?: string | URL;
15
20
  };
16
- type LocalHttpsPlugin = Plugin & {
17
- api: {
18
- /** Returns host, port, and TLS file paths for frameworks that terminate HTTPS outside Vite. */getDevServerConfig(): LocalHttpsDevServerConfig | undefined;
19
- };
20
- };
21
+ /** The local HTTPS Vite plugin, with an API for frameworks that start their own HTTPS server. */
22
+ type LocalHttpsPlugin = Plugin & LocalHttpsPluginExtension;
23
+ /** The API that the local HTTPS Vite plugin adds to the Vite plugin object. */
24
+ interface LocalHttpsPluginExtension {
25
+ /** Methods for frameworks that start their own HTTPS server. */
26
+ api: LocalHttpsPluginApi;
27
+ }
28
+ /** Methods for frameworks that start their own HTTPS server. */
29
+ interface LocalHttpsPluginApi {
30
+ /**
31
+ * Returns the host, port, and certificate paths for frameworks that serve HTTPS outside Vite, such as Nuxt.
32
+ *
33
+ * Returns `undefined` when `enabled` is `false` or a certificate file is missing.
34
+ */
35
+ getDevServerConfig(): LocalHttpsDevServerConfig | undefined;
36
+ }
37
+ /** Host, port, and certificate file paths for serving local HTTPS outside Vite. */
21
38
  type LocalHttpsDevServerConfig = {
22
- host: string;
23
- port: number;
39
+ /** Local hostname that the dev server serves, such as `local.tryhydrogen.dev`. */host: string; /** Port for the dev server. */
40
+ port: number; /** Absolute paths to the certificate file and the private key file. */
24
41
  https: {
25
42
  cert: string;
26
43
  key: string;
27
44
  };
28
45
  };
29
46
  /**
30
- * Configures Vite for trusted local HTTPS on Hydrogen's default development host.
47
+ * Serves your Vite dev server over trusted HTTPS on a fixed host and port, and adds the dev server URLs to your Customer Account API settings.
48
+ * Vite exits when another process uses the port. The dev server speaks HTTP/1.1 only.
49
+ *
50
+ * When `vite dev` starts without certificate files, the plugin asks for permission in the terminal, then creates the files. The plugin skips the prompt without an interactive terminal and in CI. Hydrogen treats any `CI` environment variable value other than an empty string, `false`, or `0` as CI. While certificate files are missing, the plugin prints a warning and leaves HTTPS off.
51
+ *
52
+ * After the dev server starts, the plugin runs Shopify CLI to update your Customer Account API settings with the dev server URLs. The update needs a Shopify CLI that includes `@shopify/cli-hydrogen` 13.0.4 or later. When the project has no linked Hydrogen storefront, Shopify CLI asks you to link one first. When Shopify CLI is missing or outdated, or the update fails, the plugin prints the URLs to enter by hand and the dev server keeps running. In CI, the plugin prints the URLs and skips Shopify CLI.
53
+ *
54
+ * @param options Switch, host, port, and certificate paths for local HTTPS.
55
+ * @returns A Vite plugin. Its `api.getDevServerConfig()` method returns the HTTPS settings for frameworks that serve HTTPS outside Vite.
56
+ * @publicDocs
31
57
  */
32
58
  declare function localHttps(options: LocalHttpsOptions): LocalHttpsPlugin;
59
+ /** Host and certificate paths for provisionLocalHttps. */
33
60
  type ProvisionLocalHttpsOptions = Omit<LocalHttpsOptions, "enabled" | "port">;
34
61
  /**
35
- * Downloads a pinned, checksum-verified mkcert release and generates the
36
- * trusted local certificate files when they do not exist yet. The Vite plugin
37
- * runs this automatically on `vite dev`; call it directly for frameworks that
38
- * read certificate paths before Vite starts or from setup scripts.
62
+ * Creates trusted certificate files for local HTTPS. Call the function from a setup script, or
63
+ * before you start a framework that reads certificate paths when its config loads, such as Nuxt.
64
+ *
65
+ * When both files exist, the function returns their paths and changes nothing. Otherwise, the
66
+ * function downloads a pinned, checksum-verified mkcert release, adds the mkcert certificate
67
+ * authority to your system trust store, and creates the certificate and private key. mkcert can
68
+ * ask for your password.
69
+ *
70
+ * @param options Host and certificate paths. Each option has a Hydrogen default.
71
+ * @returns The host and the absolute paths to the certificate and the private key.
72
+ * @publicDocs
39
73
  */
40
74
  declare function provisionLocalHttps(options?: ProvisionLocalHttpsOptions): Promise<{
41
75
  host: string;
@@ -7,6 +7,11 @@ import { dirname, isAbsolute, join, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
9
  //#region src/vite/local-https.ts
10
+ /**
11
+ * Default host, `local.tryhydrogen.dev`, and port, `5173`, for local HTTPS. Pass the values to frameworks that set their own dev server host and port, such as Astro.
12
+ *
13
+ * @publicDocs
14
+ */
10
15
  const LOCAL_HTTPS_DEFAULTS = {
11
16
  host: "local.tryhydrogen.dev",
12
17
  port: 5173
@@ -25,7 +30,16 @@ const HTTP1_ONLY_RESPONSE_HEADERS = new Set([
25
30
  const emittedMissingCertificateWarnings = /* @__PURE__ */ new Set();
26
31
  const startedCustomerAccountSetups = /* @__PURE__ */ new Set();
27
32
  /**
28
- * Configures Vite for trusted local HTTPS on Hydrogen's default development host.
33
+ * Serves your Vite dev server over trusted HTTPS on a fixed host and port, and adds the dev server URLs to your Customer Account API settings.
34
+ * Vite exits when another process uses the port. The dev server speaks HTTP/1.1 only.
35
+ *
36
+ * When `vite dev` starts without certificate files, the plugin asks for permission in the terminal, then creates the files. The plugin skips the prompt without an interactive terminal and in CI. Hydrogen treats any `CI` environment variable value other than an empty string, `false`, or `0` as CI. While certificate files are missing, the plugin prints a warning and leaves HTTPS off.
37
+ *
38
+ * After the dev server starts, the plugin runs Shopify CLI to update your Customer Account API settings with the dev server URLs. The update needs a Shopify CLI that includes `@shopify/cli-hydrogen` 13.0.4 or later. When the project has no linked Hydrogen storefront, Shopify CLI asks you to link one first. When Shopify CLI is missing or outdated, or the update fails, the plugin prints the URLs to enter by hand and the dev server keeps running. In CI, the plugin prints the URLs and skips Shopify CLI.
39
+ *
40
+ * @param options Switch, host, port, and certificate paths for local HTTPS.
41
+ * @returns A Vite plugin. Its `api.getDevServerConfig()` method returns the HTTPS settings for frameworks that serve HTTPS outside Vite.
42
+ * @publicDocs
29
43
  */
30
44
  function localHttps(options) {
31
45
  const settings = options.enabled ? resolveLocalHttpsSettings(options) : void 0;
@@ -80,10 +94,17 @@ function localHttps(options) {
80
94
  };
81
95
  }
82
96
  /**
83
- * Downloads a pinned, checksum-verified mkcert release and generates the
84
- * trusted local certificate files when they do not exist yet. The Vite plugin
85
- * runs this automatically on `vite dev`; call it directly for frameworks that
86
- * read certificate paths before Vite starts or from setup scripts.
97
+ * Creates trusted certificate files for local HTTPS. Call the function from a setup script, or
98
+ * before you start a framework that reads certificate paths when its config loads, such as Nuxt.
99
+ *
100
+ * When both files exist, the function returns their paths and changes nothing. Otherwise, the
101
+ * function downloads a pinned, checksum-verified mkcert release, adds the mkcert certificate
102
+ * authority to your system trust store, and creates the certificate and private key. mkcert can
103
+ * ask for your password.
104
+ *
105
+ * @param options Host and certificate paths. Each option has a Hydrogen default.
106
+ * @returns The host and the absolute paths to the certificate and the private key.
107
+ * @publicDocs
87
108
  */
88
109
  async function provisionLocalHttps(options = {}) {
89
110
  const settings = resolveLocalHttpsSettings({
@@ -1 +1 @@
1
- {"version":3,"file":"local-https.mjs","names":[],"sources":["../../src/vite/local-https.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport type { OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { ConfigEnv, Plugin, ViteDevServer } from \"vite\";\n\nimport { confirmCertificateInstallation } from \"./certificate-prompt\";\nimport {\n configureCustomerAccountUrls,\n isContinuousIntegration,\n resolveCustomerAccountUrls,\n} from \"./customer-account\";\nimport { provisionCertificates } from \"./mkcert\";\n\nexport const LOCAL_HTTPS_DEFAULTS = {\n host: \"local.tryhydrogen.dev\",\n port: 5_173,\n} as const;\n\nconst HEADER_PAIR_SIZE = 2;\nconst HTTP1_ONLY_RESPONSE_HEADERS = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n]);\nconst emittedMissingCertificateWarnings = new Set<string>();\nconst startedCustomerAccountSetups = new Set<string>();\n\n/** Options for Hydrogen's local HTTPS Vite plugin. */\nexport type LocalHttpsOptions = {\n /** Enable trusted local HTTPS for the dev server. */\n enabled: boolean;\n /** Local hostname registered in Shopify admin. Defaults to `local.tryhydrogen.dev`. */\n host?: string;\n /** Local port registered in Shopify admin. Defaults to `5173`. */\n port?: number;\n /** Certificate file path. Defaults to Hydrogen's mkcert path under `~/.shopify/hydrogen/certs`. */\n certPath?: string | URL;\n /** Private key file path. Defaults to Hydrogen's mkcert path under `~/.shopify/hydrogen/certs`. */\n keyPath?: string | URL;\n};\n\nexport type LocalHttpsPlugin = Plugin & {\n api: {\n /** Returns host, port, and TLS file paths for frameworks that terminate HTTPS outside Vite. */\n getDevServerConfig(): LocalHttpsDevServerConfig | undefined;\n };\n};\n\nexport type LocalHttpsDevServerConfig = {\n host: string;\n port: number;\n https: {\n cert: string;\n key: string;\n };\n};\n\n/**\n * Configures Vite for trusted local HTTPS on Hydrogen's default development host.\n */\nexport function localHttps(options: LocalHttpsOptions): LocalHttpsPlugin {\n const settings = options.enabled ? resolveLocalHttpsSettings(options) : undefined;\n let certificateFiles: LocalHttpsCertificateFiles | undefined;\n\n const getCertificateFiles = () => {\n if (!settings) return;\n\n certificateFiles ??= readCertificateFiles(settings);\n return certificateFiles;\n };\n\n const getDevServerConfig = () => {\n if (!settings || !checkCertificateFiles(settings)) return;\n\n getCertificateFiles();\n\n return {\n host: settings.host,\n port: settings.port,\n https: {\n cert: settings.certPath,\n key: settings.keyPath,\n },\n };\n };\n\n return {\n name: \"hydrogen-local-https\",\n api: { getDevServerConfig },\n async config(_config: unknown, env: ConfigEnv) {\n if (settings && env.command === \"serve\" && !env.isPreview) {\n const certificatesAvailable = await ensureCertificateFiles(settings);\n if (!certificatesAvailable) return;\n } else if (settings && !checkCertificateFiles(settings)) {\n return;\n }\n\n const certificates = getCertificateFiles();\n if (!settings || !certificates) return;\n\n return {\n server: {\n allowedHosts: [settings.host],\n host: settings.host,\n port: settings.port,\n strictPort: true,\n https: {\n // Several framework dev servers fail when Vite negotiates HTTP/2.\n ALPNProtocols: [\"http/1.1\"],\n cert: certificates.cert,\n key: certificates.key,\n },\n hmr: {\n host: settings.host,\n protocol: \"wss\",\n },\n },\n };\n },\n configureServer(server) {\n if (!settings || !checkCertificateFiles(settings)) return;\n\n getCertificateFiles();\n configureLocalHttpsServer(server, settings);\n },\n };\n}\n\nexport type ProvisionLocalHttpsOptions = Omit<LocalHttpsOptions, \"enabled\" | \"port\">;\n\n/**\n * Downloads a pinned, checksum-verified mkcert release and generates the\n * trusted local certificate files when they do not exist yet. The Vite plugin\n * runs this automatically on `vite dev`; call it directly for frameworks that\n * read certificate paths before Vite starts or from setup scripts.\n */\nexport async function provisionLocalHttps(options: ProvisionLocalHttpsOptions = {}) {\n const settings = resolveLocalHttpsSettings({ enabled: true, ...options });\n\n if (!certificateFilesExist(settings)) {\n await provisionCertificates(settings);\n }\n\n return {\n host: settings.host,\n certPath: settings.certPath,\n keyPath: settings.keyPath,\n };\n}\n\ntype LocalHttpsSettings = {\n host: string;\n port: number;\n certPath: string;\n keyPath: string;\n};\n\ntype LocalHttpsCertificateFiles = {\n cert: Buffer;\n key: Buffer;\n};\n\nfunction resolveLocalHttpsSettings(options: LocalHttpsOptions): LocalHttpsSettings {\n const host = options.host ?? LOCAL_HTTPS_DEFAULTS.host;\n const certificateDirectory = join(homedir(), \".shopify\", \"hydrogen\", \"certs\");\n\n return {\n host,\n port: options.port ?? LOCAL_HTTPS_DEFAULTS.port,\n certPath: resolveCertificatePath(options.certPath ?? join(certificateDirectory, `${host}.pem`)),\n keyPath: resolveCertificatePath(\n options.keyPath ?? join(certificateDirectory, `${host}-key.pem`),\n ),\n };\n}\n\nfunction resolveCertificatePath(path: string | URL) {\n if (path instanceof URL) return fileURLToPath(path);\n if (path === \"~\") return homedir();\n if (path.startsWith(\"~/\")) return resolve(homedir(), path.slice(2));\n return isAbsolute(path) ? path : resolve(path);\n}\n\nfunction certificateFilesExist(settings: LocalHttpsSettings) {\n return existsSync(settings.certPath) && existsSync(settings.keyPath);\n}\n\nasync function ensureCertificateFiles(settings: LocalHttpsSettings): Promise<boolean> {\n if (certificateFilesExist(settings)) return true;\n\n // Installing the mkcert certificate authority needs an interactive trust\n // prompt on first run, which hangs or fails on CI runners.\n if (isContinuousIntegration()) {\n return checkCertificateFiles(\n settings,\n \"Automatic certificate provisioning is skipped in CI environments (the CI environment variable is set).\",\n );\n }\n\n if (!(await confirmCertificateInstallation(settings.host))) {\n return checkCertificateFiles(\n settings,\n \"Automatic certificate provisioning requires confirmation in an interactive terminal.\",\n );\n }\n\n try {\n await provisionCertificates(settings);\n return true;\n } catch (error) {\n return checkCertificateFiles(\n settings,\n `Automatic certificate provisioning failed:\\n ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction checkCertificateFiles(settings: LocalHttpsSettings, provisioningNote?: string) {\n const missingPaths = [settings.certPath, settings.keyPath].filter((path) => !existsSync(path));\n if (missingPaths.length === 0) return true;\n\n const warning = formatMissingCertificateWarning(settings, missingPaths, provisioningNote);\n if (!emittedMissingCertificateWarnings.has(warning)) {\n emittedMissingCertificateWarnings.add(warning);\n process.emitWarning(warning, { type: \"HydrogenLocalHttpsWarning\" });\n }\n return false;\n}\n\nfunction formatMissingCertificateWarning(\n { certPath, host, keyPath }: LocalHttpsSettings,\n missingPaths: string[],\n provisioningNote?: string,\n) {\n const certificateDirectories = [...new Set([dirname(certPath), dirname(keyPath)])];\n const provisioningFailure = provisioningNote === undefined ? [] : [\"\", provisioningNote];\n\n return [\n \"Local HTTPS is disabled because certificate files are missing:\",\n ...missingPaths.map((path) => ` ${path}`),\n ...provisioningFailure,\n \"\",\n \"Expected certificate files:\",\n ` Certificate: ${certPath}`,\n ` Private key: ${keyPath}`,\n \"\",\n \"Run the automatic setup:\",\n \" npx hydrogen certs install\",\n \"\",\n \"Or install and configure mkcert, then generate the certificate:\",\n \" macOS: brew install mkcert\",\n \" mkcert -install\",\n ` mkdir -p ${certificateDirectories.map(shellQuote).join(\" \")}`,\n ` mkcert -cert-file ${shellQuote(certPath)} -key-file ${shellQuote(keyPath)} ${shellQuote(host)}`,\n ].join(\"\\n\");\n}\n\nfunction readCertificateFiles(settings: LocalHttpsSettings): LocalHttpsCertificateFiles {\n return {\n cert: readCertificateFile(settings, \"certificate\", settings.certPath),\n key: readCertificateFile(settings, \"private key\", settings.keyPath),\n };\n}\n\nfunction readCertificateFile(settings: LocalHttpsSettings, label: string, path: string) {\n try {\n return readFileSync(path);\n } catch (error) {\n throw new Error(formatCertificateReadError(settings, label, path, error), { cause: error });\n }\n}\n\nfunction formatCertificateReadError(\n { certPath, host, keyPath }: LocalHttpsSettings,\n label: string,\n path: string,\n error: unknown,\n) {\n const certificateDirectories = [...new Set([dirname(certPath), dirname(keyPath)])];\n const reason = error instanceof Error ? error.message : String(error);\n\n return [\n `Local HTTPS requires a readable ${label} file:`,\n ` ${path}`,\n `Reason: ${reason}`,\n \"\",\n \"Expected certificate files:\",\n ` Certificate: ${certPath}`,\n ` Private key: ${keyPath}`,\n \"\",\n \"Install and configure mkcert, then generate the certificate:\",\n \" macOS: brew install mkcert\",\n \" mkcert -install\",\n ` mkdir -p ${certificateDirectories.map(shellQuote).join(\" \")}`,\n ` mkcert -cert-file ${shellQuote(certPath)} -key-file ${shellQuote(keyPath)} ${shellQuote(host)}`,\n ].join(\"\\n\");\n}\n\nfunction shellQuote(value: string) {\n return `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\nfunction configureLocalHttpsServer(server: ViteDevServer, settings: LocalHttpsSettings) {\n // The configured port is only a fallback: frameworks that own the listener\n // (or auto-incremented ports) can bind somewhere else, and the Customer\n // Account URLs registered in admin must match the port actually served.\n const resolveBoundPort = () => {\n const address = server.httpServer?.address();\n return address && typeof address === \"object\" ? address.port : settings.port;\n };\n\n server.middlewares.use((request, response, next) => {\n request.headers[\"x-forwarded-host\"] ??=\n request.headers.host ?? `${settings.host}:${resolveBoundPort()}`;\n request.headers[\"x-forwarded-proto\"] ??= \"https\";\n stripHttp1OnlyResponseHeaders(response);\n next();\n });\n\n const configureCustomerAccounts = () => {\n const port = resolveBoundPort();\n const settingsKey = `${server.config.root}:${settings.host}:${port}`;\n if (startedCustomerAccountSetups.has(settingsKey)) return;\n startedCustomerAccountSetups.add(settingsKey);\n\n void configureCustomerAccountUrls({\n logger: server.config.logger,\n root: server.config.root,\n urls: resolveCustomerAccountUrls(settings.host, port),\n });\n };\n\n if (server.httpServer) {\n server.httpServer.once(\"listening\", configureCustomerAccounts);\n } else {\n configureCustomerAccounts();\n }\n}\n\nfunction stripHttp1OnlyResponseHeaders(response: ServerResponse) {\n const originalWriteHead = response.writeHead.bind(response);\n\n response.writeHead = (\n statusCode: number,\n statusMessageOrHeaders?: string | OutgoingHttpHeaders | OutgoingHttpHeader[],\n headers?: OutgoingHttpHeaders | OutgoingHttpHeader[],\n ) => {\n removeStoredHttp1OnlyHeaders(response);\n\n if (typeof statusMessageOrHeaders === \"string\") {\n return originalWriteHead(\n statusCode,\n statusMessageOrHeaders,\n sanitizeWriteHeadHeaders(headers),\n );\n }\n\n return originalWriteHead(statusCode, sanitizeWriteHeadHeaders(statusMessageOrHeaders));\n };\n}\n\nfunction removeStoredHttp1OnlyHeaders(response: ServerResponse) {\n for (const header of HTTP1_ONLY_RESPONSE_HEADERS) {\n response.removeHeader(header);\n }\n}\n\nfunction sanitizeWriteHeadHeaders(headers: OutgoingHttpHeaders | OutgoingHttpHeader[] | undefined) {\n if (Array.isArray(headers)) return sanitizeHeaderArray(headers);\n if (headers) return sanitizeHeaderObject(headers);\n return headers;\n}\n\nfunction sanitizeHeaderObject(headers: OutgoingHttpHeaders) {\n const sanitizedHeaders: OutgoingHttpHeaders = {};\n\n for (const [name, value] of Object.entries(headers)) {\n if (!isHttp1OnlyHeader(name)) sanitizedHeaders[name] = value;\n }\n\n return sanitizedHeaders;\n}\n\nfunction sanitizeHeaderArray(headers: OutgoingHttpHeader[]) {\n const sanitizedHeaders: OutgoingHttpHeader[] = [];\n\n for (let index = 0; index < headers.length; index += HEADER_PAIR_SIZE) {\n const name = headers[index];\n const value = headers[index + 1];\n if (typeof name === \"string\" && isHttp1OnlyHeader(name)) continue;\n\n sanitizedHeaders.push(name);\n if (value !== undefined) sanitizedHeaders.push(value);\n }\n\n return sanitizedHeaders;\n}\n\nfunction isHttp1OnlyHeader(name: string) {\n return HTTP1_ONLY_RESPONSE_HEADERS.has(name.toLowerCase());\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"local-https.mjs","names":[],"sources":["../../src/vite/local-https.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport type { OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { ConfigEnv, Plugin, ViteDevServer } from \"vite\";\n\nimport { confirmCertificateInstallation } from \"./certificate-prompt\";\nimport {\n configureCustomerAccountUrls,\n isContinuousIntegration,\n resolveCustomerAccountUrls,\n} from \"./customer-account\";\nimport { provisionCertificates } from \"./mkcert\";\n\n/**\n * Default host, `local.tryhydrogen.dev`, and port, `5173`, for local HTTPS. Pass the values to frameworks that set their own dev server host and port, such as Astro.\n *\n * @publicDocs\n */\nexport const LOCAL_HTTPS_DEFAULTS = {\n host: \"local.tryhydrogen.dev\",\n port: 5_173,\n} as const;\n\nconst HEADER_PAIR_SIZE = 2;\nconst HTTP1_ONLY_RESPONSE_HEADERS = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n]);\nconst emittedMissingCertificateWarnings = new Set<string>();\nconst startedCustomerAccountSetups = new Set<string>();\n\n/** Switch, host, port, and certificate files for local HTTPS. */\nexport type LocalHttpsOptions = {\n /** Turns on local HTTPS for the dev server. When `false`, the plugin leaves the Vite config unchanged. */\n enabled: boolean;\n /** Hostname for the dev server and the Customer Account API URLs. Defaults to `local.tryhydrogen.dev`. */\n host?: string;\n /** Port for the dev server. Vite exits when another process uses the port. Defaults to `5173`. */\n port?: number;\n /** Path to the certificate file. Defaults to `~/.shopify/hydrogen/certs/<host>.pem`. A leading `~/` points to your home directory, and a relative path starts from the current working directory. */\n certPath?: string | URL;\n /** Path to the private key file. Defaults to `~/.shopify/hydrogen/certs/<host>-key.pem`. Accepts the same path forms as `certPath`. */\n keyPath?: string | URL;\n};\n\n/** The local HTTPS Vite plugin, with an API for frameworks that start their own HTTPS server. */\nexport type LocalHttpsPlugin = Plugin & LocalHttpsPluginExtension;\n\n/** The API that the local HTTPS Vite plugin adds to the Vite plugin object. */\ninterface LocalHttpsPluginExtension {\n /** Methods for frameworks that start their own HTTPS server. */\n api: LocalHttpsPluginApi;\n}\n\n/** Methods for frameworks that start their own HTTPS server. */\ninterface LocalHttpsPluginApi {\n /**\n * Returns the host, port, and certificate paths for frameworks that serve HTTPS outside Vite, such as Nuxt.\n *\n * Returns `undefined` when `enabled` is `false` or a certificate file is missing.\n */\n getDevServerConfig(): LocalHttpsDevServerConfig | undefined;\n}\n\n/** Host, port, and certificate file paths for serving local HTTPS outside Vite. */\nexport type LocalHttpsDevServerConfig = {\n /** Local hostname that the dev server serves, such as `local.tryhydrogen.dev`. */\n host: string;\n /** Port for the dev server. */\n port: number;\n /** Absolute paths to the certificate file and the private key file. */\n https: {\n cert: string;\n key: string;\n };\n};\n\n/**\n * Serves your Vite dev server over trusted HTTPS on a fixed host and port, and adds the dev server URLs to your Customer Account API settings.\n * Vite exits when another process uses the port. The dev server speaks HTTP/1.1 only.\n *\n * When `vite dev` starts without certificate files, the plugin asks for permission in the terminal, then creates the files. The plugin skips the prompt without an interactive terminal and in CI. Hydrogen treats any `CI` environment variable value other than an empty string, `false`, or `0` as CI. While certificate files are missing, the plugin prints a warning and leaves HTTPS off.\n *\n * After the dev server starts, the plugin runs Shopify CLI to update your Customer Account API settings with the dev server URLs. The update needs a Shopify CLI that includes `@shopify/cli-hydrogen` 13.0.4 or later. When the project has no linked Hydrogen storefront, Shopify CLI asks you to link one first. When Shopify CLI is missing or outdated, or the update fails, the plugin prints the URLs to enter by hand and the dev server keeps running. In CI, the plugin prints the URLs and skips Shopify CLI.\n *\n * @param options Switch, host, port, and certificate paths for local HTTPS.\n * @returns A Vite plugin. Its `api.getDevServerConfig()` method returns the HTTPS settings for frameworks that serve HTTPS outside Vite.\n * @publicDocs\n */\nexport function localHttps(options: LocalHttpsOptions): LocalHttpsPlugin {\n const settings = options.enabled ? resolveLocalHttpsSettings(options) : undefined;\n let certificateFiles: LocalHttpsCertificateFiles | undefined;\n\n const getCertificateFiles = () => {\n if (!settings) return;\n\n certificateFiles ??= readCertificateFiles(settings);\n return certificateFiles;\n };\n\n const getDevServerConfig = () => {\n if (!settings || !checkCertificateFiles(settings)) return;\n\n getCertificateFiles();\n\n return {\n host: settings.host,\n port: settings.port,\n https: {\n cert: settings.certPath,\n key: settings.keyPath,\n },\n };\n };\n\n return {\n name: \"hydrogen-local-https\",\n api: { getDevServerConfig },\n async config(_config: unknown, env: ConfigEnv) {\n if (settings && env.command === \"serve\" && !env.isPreview) {\n const certificatesAvailable = await ensureCertificateFiles(settings);\n if (!certificatesAvailable) return;\n } else if (settings && !checkCertificateFiles(settings)) {\n return;\n }\n\n const certificates = getCertificateFiles();\n if (!settings || !certificates) return;\n\n return {\n server: {\n allowedHosts: [settings.host],\n host: settings.host,\n port: settings.port,\n strictPort: true,\n https: {\n // Several framework dev servers fail when Vite negotiates HTTP/2.\n ALPNProtocols: [\"http/1.1\"],\n cert: certificates.cert,\n key: certificates.key,\n },\n hmr: {\n host: settings.host,\n protocol: \"wss\",\n },\n },\n };\n },\n configureServer(server) {\n if (!settings || !checkCertificateFiles(settings)) return;\n\n getCertificateFiles();\n configureLocalHttpsServer(server, settings);\n },\n };\n}\n\n/** Host and certificate paths for provisionLocalHttps. */\nexport type ProvisionLocalHttpsOptions = Omit<LocalHttpsOptions, \"enabled\" | \"port\">;\n\n/**\n * Creates trusted certificate files for local HTTPS. Call the function from a setup script, or\n * before you start a framework that reads certificate paths when its config loads, such as Nuxt.\n *\n * When both files exist, the function returns their paths and changes nothing. Otherwise, the\n * function downloads a pinned, checksum-verified mkcert release, adds the mkcert certificate\n * authority to your system trust store, and creates the certificate and private key. mkcert can\n * ask for your password.\n *\n * @param options Host and certificate paths. Each option has a Hydrogen default.\n * @returns The host and the absolute paths to the certificate and the private key.\n * @publicDocs\n */\nexport async function provisionLocalHttps(options: ProvisionLocalHttpsOptions = {}) {\n const settings = resolveLocalHttpsSettings({ enabled: true, ...options });\n\n if (!certificateFilesExist(settings)) {\n await provisionCertificates(settings);\n }\n\n return {\n host: settings.host,\n certPath: settings.certPath,\n keyPath: settings.keyPath,\n };\n}\n\ntype LocalHttpsSettings = {\n host: string;\n port: number;\n certPath: string;\n keyPath: string;\n};\n\ntype LocalHttpsCertificateFiles = {\n cert: Buffer;\n key: Buffer;\n};\n\nfunction resolveLocalHttpsSettings(options: LocalHttpsOptions): LocalHttpsSettings {\n const host = options.host ?? LOCAL_HTTPS_DEFAULTS.host;\n const certificateDirectory = join(homedir(), \".shopify\", \"hydrogen\", \"certs\");\n\n return {\n host,\n port: options.port ?? LOCAL_HTTPS_DEFAULTS.port,\n certPath: resolveCertificatePath(options.certPath ?? join(certificateDirectory, `${host}.pem`)),\n keyPath: resolveCertificatePath(\n options.keyPath ?? join(certificateDirectory, `${host}-key.pem`),\n ),\n };\n}\n\nfunction resolveCertificatePath(path: string | URL) {\n if (path instanceof URL) return fileURLToPath(path);\n if (path === \"~\") return homedir();\n if (path.startsWith(\"~/\")) return resolve(homedir(), path.slice(2));\n return isAbsolute(path) ? path : resolve(path);\n}\n\nfunction certificateFilesExist(settings: LocalHttpsSettings) {\n return existsSync(settings.certPath) && existsSync(settings.keyPath);\n}\n\nasync function ensureCertificateFiles(settings: LocalHttpsSettings): Promise<boolean> {\n if (certificateFilesExist(settings)) return true;\n\n // Installing the mkcert certificate authority needs an interactive trust\n // prompt on first run, which hangs or fails on CI runners.\n if (isContinuousIntegration()) {\n return checkCertificateFiles(\n settings,\n \"Automatic certificate provisioning is skipped in CI environments (the CI environment variable is set).\",\n );\n }\n\n if (!(await confirmCertificateInstallation(settings.host))) {\n return checkCertificateFiles(\n settings,\n \"Automatic certificate provisioning requires confirmation in an interactive terminal.\",\n );\n }\n\n try {\n await provisionCertificates(settings);\n return true;\n } catch (error) {\n return checkCertificateFiles(\n settings,\n `Automatic certificate provisioning failed:\\n ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction checkCertificateFiles(settings: LocalHttpsSettings, provisioningNote?: string) {\n const missingPaths = [settings.certPath, settings.keyPath].filter((path) => !existsSync(path));\n if (missingPaths.length === 0) return true;\n\n const warning = formatMissingCertificateWarning(settings, missingPaths, provisioningNote);\n if (!emittedMissingCertificateWarnings.has(warning)) {\n emittedMissingCertificateWarnings.add(warning);\n process.emitWarning(warning, { type: \"HydrogenLocalHttpsWarning\" });\n }\n return false;\n}\n\nfunction formatMissingCertificateWarning(\n { certPath, host, keyPath }: LocalHttpsSettings,\n missingPaths: string[],\n provisioningNote?: string,\n) {\n const certificateDirectories = [...new Set([dirname(certPath), dirname(keyPath)])];\n const provisioningFailure = provisioningNote === undefined ? [] : [\"\", provisioningNote];\n\n return [\n \"Local HTTPS is disabled because certificate files are missing:\",\n ...missingPaths.map((path) => ` ${path}`),\n ...provisioningFailure,\n \"\",\n \"Expected certificate files:\",\n ` Certificate: ${certPath}`,\n ` Private key: ${keyPath}`,\n \"\",\n \"Run the automatic setup:\",\n \" npx hydrogen certs install\",\n \"\",\n \"Or install and configure mkcert, then generate the certificate:\",\n \" macOS: brew install mkcert\",\n \" mkcert -install\",\n ` mkdir -p ${certificateDirectories.map(shellQuote).join(\" \")}`,\n ` mkcert -cert-file ${shellQuote(certPath)} -key-file ${shellQuote(keyPath)} ${shellQuote(host)}`,\n ].join(\"\\n\");\n}\n\nfunction readCertificateFiles(settings: LocalHttpsSettings): LocalHttpsCertificateFiles {\n return {\n cert: readCertificateFile(settings, \"certificate\", settings.certPath),\n key: readCertificateFile(settings, \"private key\", settings.keyPath),\n };\n}\n\nfunction readCertificateFile(settings: LocalHttpsSettings, label: string, path: string) {\n try {\n return readFileSync(path);\n } catch (error) {\n throw new Error(formatCertificateReadError(settings, label, path, error), { cause: error });\n }\n}\n\nfunction formatCertificateReadError(\n { certPath, host, keyPath }: LocalHttpsSettings,\n label: string,\n path: string,\n error: unknown,\n) {\n const certificateDirectories = [...new Set([dirname(certPath), dirname(keyPath)])];\n const reason = error instanceof Error ? error.message : String(error);\n\n return [\n `Local HTTPS requires a readable ${label} file:`,\n ` ${path}`,\n `Reason: ${reason}`,\n \"\",\n \"Expected certificate files:\",\n ` Certificate: ${certPath}`,\n ` Private key: ${keyPath}`,\n \"\",\n \"Install and configure mkcert, then generate the certificate:\",\n \" macOS: brew install mkcert\",\n \" mkcert -install\",\n ` mkdir -p ${certificateDirectories.map(shellQuote).join(\" \")}`,\n ` mkcert -cert-file ${shellQuote(certPath)} -key-file ${shellQuote(keyPath)} ${shellQuote(host)}`,\n ].join(\"\\n\");\n}\n\nfunction shellQuote(value: string) {\n return `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n}\n\nfunction configureLocalHttpsServer(server: ViteDevServer, settings: LocalHttpsSettings) {\n // The configured port is only a fallback: frameworks that own the listener\n // (or auto-incremented ports) can bind somewhere else, and the Customer\n // Account URLs registered in admin must match the port actually served.\n const resolveBoundPort = () => {\n const address = server.httpServer?.address();\n return address && typeof address === \"object\" ? address.port : settings.port;\n };\n\n server.middlewares.use((request, response, next) => {\n request.headers[\"x-forwarded-host\"] ??=\n request.headers.host ?? `${settings.host}:${resolveBoundPort()}`;\n request.headers[\"x-forwarded-proto\"] ??= \"https\";\n stripHttp1OnlyResponseHeaders(response);\n next();\n });\n\n const configureCustomerAccounts = () => {\n const port = resolveBoundPort();\n const settingsKey = `${server.config.root}:${settings.host}:${port}`;\n if (startedCustomerAccountSetups.has(settingsKey)) return;\n startedCustomerAccountSetups.add(settingsKey);\n\n void configureCustomerAccountUrls({\n logger: server.config.logger,\n root: server.config.root,\n urls: resolveCustomerAccountUrls(settings.host, port),\n });\n };\n\n if (server.httpServer) {\n server.httpServer.once(\"listening\", configureCustomerAccounts);\n } else {\n configureCustomerAccounts();\n }\n}\n\nfunction stripHttp1OnlyResponseHeaders(response: ServerResponse) {\n const originalWriteHead = response.writeHead.bind(response);\n\n response.writeHead = (\n statusCode: number,\n statusMessageOrHeaders?: string | OutgoingHttpHeaders | OutgoingHttpHeader[],\n headers?: OutgoingHttpHeaders | OutgoingHttpHeader[],\n ) => {\n removeStoredHttp1OnlyHeaders(response);\n\n if (typeof statusMessageOrHeaders === \"string\") {\n return originalWriteHead(\n statusCode,\n statusMessageOrHeaders,\n sanitizeWriteHeadHeaders(headers),\n );\n }\n\n return originalWriteHead(statusCode, sanitizeWriteHeadHeaders(statusMessageOrHeaders));\n };\n}\n\nfunction removeStoredHttp1OnlyHeaders(response: ServerResponse) {\n for (const header of HTTP1_ONLY_RESPONSE_HEADERS) {\n response.removeHeader(header);\n }\n}\n\nfunction sanitizeWriteHeadHeaders(headers: OutgoingHttpHeaders | OutgoingHttpHeader[] | undefined) {\n if (Array.isArray(headers)) return sanitizeHeaderArray(headers);\n if (headers) return sanitizeHeaderObject(headers);\n return headers;\n}\n\nfunction sanitizeHeaderObject(headers: OutgoingHttpHeaders) {\n const sanitizedHeaders: OutgoingHttpHeaders = {};\n\n for (const [name, value] of Object.entries(headers)) {\n if (!isHttp1OnlyHeader(name)) sanitizedHeaders[name] = value;\n }\n\n return sanitizedHeaders;\n}\n\nfunction sanitizeHeaderArray(headers: OutgoingHttpHeader[]) {\n const sanitizedHeaders: OutgoingHttpHeader[] = [];\n\n for (let index = 0; index < headers.length; index += HEADER_PAIR_SIZE) {\n const name = headers[index];\n const value = headers[index + 1];\n if (typeof name === \"string\" && isHttp1OnlyHeader(name)) continue;\n\n sanitizedHeaders.push(name);\n if (value !== undefined) sanitizedHeaders.push(value);\n }\n\n return sanitizedHeaders;\n}\n\nfunction isHttp1OnlyHeader(name: string) {\n return HTTP1_ONLY_RESPONSE_HEADERS.has(name.toLowerCase());\n}\n"],"mappings":"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"}
@@ -18,18 +18,20 @@ type TypedCartProvider<TData extends CartData> = {
18
18
  };
19
19
  };
20
20
  };
21
+ /** Cart provider and composables whose cart state carries the custom fields from your cart server handlers. */
21
22
  type TypedCartComponents<TData extends CartData> = {
22
- CartProvider: TypedCartProvider<TData>;
23
- useCart: TypedUseCart<TData>;
24
- useOptionalCart: TypedUseOptionalCart<TData>;
25
- useCartActions: typeof useCartActions;
23
+ /** The provider that creates the cart store. The provider connects the store on mount and destroys the store on unmount. */CartProvider: TypedCartProvider<TData>; /** Returns cart state as a read-only shallow ref. The selector is optional. Without a selector, the ref holds the full cart state. */
24
+ useCart: TypedUseCart<TData>; /** Returns the slice of cart state that the selector picks as a read-only shallow ref. Outside the provider, the ref holds `undefined`. */
25
+ useOptionalCart: TypedUseOptionalCart<TData>; /** Returns the `refresh` action. Call `refresh` after a server-side cart mutation that bypasses cart forms. */
26
+ useCartActions: typeof useCartActions; /** Returns form props, a register function, and pending state for cart forms. */
26
27
  useCartForm: typeof useCartForm;
27
28
  };
28
29
  /**
29
- * Returns cart actions for reconciling state after out-of-band mutations.
30
+ * Returns the cart action that syncs the cart after a mutation outside cart forms.
30
31
  *
31
- * Currently exposes {@link CartStore.refresh} — call it after server-side cart
32
- * mutations that bypass the form system.
32
+ * Call `refresh` after a server-side cart mutation that bypasses cart forms, such as a server action that creates the cart.
33
+ *
34
+ * @returns The `refresh` action.
33
35
  *
34
36
  * @example
35
37
  * ```vue
@@ -42,13 +44,13 @@ type TypedCartComponents<TData extends CartData> = {
42
44
  * }
43
45
  * </script>
44
46
  * ```
47
+ * @publicDocs
45
48
  */
46
49
  declare function useCartActions(): CartActions;
47
50
  /**
48
- * Subscribes the {@link CartStore} to the analytics event dispatcher.
51
+ * Publishes cart analytics events when the cart changes.
49
52
  *
50
- * Call once near the root of your app. Starts tracking on mount via `onMounted`
51
- * and cleans up via `onScopeDispose`.
53
+ * Call the composable once near the root of your app. The composable starts tracking on mount and stops when the component's scope ends. The composable throws when you call it outside the cart provider.
52
54
  *
53
55
  * @example
54
56
  * ```vue
@@ -56,19 +58,19 @@ declare function useCartActions(): CartActions;
56
58
  * useCartAnalytics();
57
59
  * </script>
58
60
  * ```
61
+ * @publicDocs
59
62
  */
60
63
  declare function useCartAnalytics(): void;
61
64
  /**
62
- * Returns form props, a field register function, and reactive pending state
63
- * for building cart forms in Vue.
65
+ * Returns form props, a register function, and pending state for cart forms.
66
+ *
67
+ * The form props post to the cart endpoint and send each submission through the cart store. A `beforeSubmit` callback that prevents the event's default skips the cart submission.
64
68
  *
65
- * Unlike the React hook, the Vue variant includes `isPending` — a reactive
66
- * object with `initial` (`ComputedRef<boolean>`) for the initial cart load
67
- * and `lines(lineId?)` for checking per-line or any-line pending state.
69
+ * The pending state holds a computed ref that's `true` during a full cart load, and a function that checks whether one line or any line has a mutation in flight.
68
70
  *
69
- * Note: `interactive: true` returns numeric input attributes but does **not**
70
- * auto-submit on change — that behavior requires `attachQuantityInput`, which
71
- * is only wired by the React adapter.
71
+ * Registering the quantity field with `interactive: true` returns numeric input attributes without auto-submit. Call attachQuantityInput on the input to submit the form when the quantity changes.
72
+ *
73
+ * @returns The form props function, the register function, and the pending state.
72
74
  *
73
75
  * @example
74
76
  * ```vue
@@ -87,6 +89,7 @@ declare function useCartAnalytics(): void;
87
89
  * </form>
88
90
  * </template>
89
91
  * ```
92
+ * @publicDocs
90
93
  */
91
94
  declare function useCartForm(): {
92
95
  formProps: (opts?: {
@@ -100,11 +103,12 @@ declare function useCartForm(): {
100
103
  };
101
104
  };
102
105
  /**
103
- * Factory that returns typed cart components and composables matched to your
104
- * server handler's cart query shape.
106
+ * Returns a cart provider and composables typed to the cart query in your cart server handlers.
107
+ * Pass the type of your cart server handlers as the `THandlers` type argument. Every composable's cart state then includes your custom cart fields.
108
+ *
109
+ * On mount, the provider points cart requests at `/api/cart` and connects the store. Every composable except the optional cart composable throws when you call it outside the provider.
105
110
  *
106
- * The generic `THandlers` parameter is inferred from your `createCartServerHandlers`
107
- * call, so every composable's {@link CartState} carries your custom cart fields.
111
+ * @returns The typed cart provider, the cart state composables, and the cart actions and form composables.
108
112
  *
109
113
  * @example
110
114
  * ```ts
@@ -118,8 +122,9 @@ declare function useCartForm(): {
118
122
  * useCartForm,
119
123
  * } = createCartComponents<typeof cartServerHandlers>();
120
124
  * ```
125
+ * @publicDocs
121
126
  */
122
127
  declare function createCartComponents<THandlers>(): TypedCartComponents<CartDataFromHandlers<THandlers>>;
123
128
  //#endregion
124
- export { createCartComponents, useCartActions, useCartAnalytics };
129
+ export { createCartComponents, useCartAnalytics };
125
130
  //# sourceMappingURL=cart.d.mts.map