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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/index.mjs +131 -29
  3. package/dist/client/client.mjs +2 -2
  4. package/dist/client/errors.d.mts +19 -19
  5. package/dist/client/errors.mjs +19 -16
  6. package/dist/client/errors.mjs.map +1 -1
  7. package/dist/client/types.d.mts +91 -10
  8. package/dist/core/analytics/cart-tracker.d.mts +14 -0
  9. package/dist/core/analytics/cart-tracker.mjs +15 -1
  10. package/dist/core/analytics/cart-tracker.mjs.map +1 -1
  11. package/dist/core/analytics/custom-consent.mjs +12 -0
  12. package/dist/core/analytics/custom-consent.mjs.map +1 -0
  13. package/dist/core/analytics/events.d.mts +7 -0
  14. package/dist/core/analytics/events.mjs +7 -0
  15. package/dist/core/analytics/events.mjs.map +1 -1
  16. package/dist/core/analytics/index.d.mts +1 -1
  17. package/dist/core/analytics/types.d.mts +152 -16
  18. package/dist/core/cart/actions.d.mts +47 -3
  19. package/dist/core/cart/actions.mjs +27 -0
  20. package/dist/core/cart/actions.mjs.map +1 -1
  21. package/dist/core/cart/attach-quantity-input.d.mts +26 -0
  22. package/dist/core/cart/attach-quantity-input.mjs +26 -0
  23. package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
  24. package/dist/core/cart/cart.d.mts +106 -6
  25. package/dist/core/cart/cart.mjs +41 -0
  26. package/dist/core/cart/cart.mjs.map +1 -1
  27. package/dist/core/cart/cookie.d.mts +15 -0
  28. package/dist/core/cart/cookie.mjs +15 -0
  29. package/dist/core/cart/cookie.mjs.map +1 -1
  30. package/dist/core/cart/form.d.mts +61 -0
  31. package/dist/core/cart/form.mjs +18 -0
  32. package/dist/core/cart/form.mjs.map +1 -1
  33. package/dist/core/cart/get-cart.d.mts +43 -2
  34. package/dist/core/cart/get-cart.mjs +33 -0
  35. package/dist/core/cart/get-cart.mjs.map +1 -1
  36. package/dist/core/cart/index.d.mts +1 -1
  37. package/dist/core/cart/quantity.d.mts +17 -0
  38. package/dist/core/cart/quantity.mjs +17 -0
  39. package/dist/core/cart/quantity.mjs.map +1 -1
  40. package/dist/core/cart/queries.d.mts +402 -369
  41. package/dist/core/cart/queries.mjs +2 -1
  42. package/dist/core/cart/queries.mjs.map +1 -1
  43. package/dist/core/cart/server-handlers.d.mts +69 -0
  44. package/dist/core/cart/server-handlers.mjs +2 -10
  45. package/dist/core/cart/server-handlers.mjs.map +1 -1
  46. package/dist/core/cart/state.d.mts +133 -0
  47. package/dist/core/cart/state.mjs +8 -0
  48. package/dist/core/cart/state.mjs.map +1 -1
  49. package/dist/core/collection/collection.d.mts +18 -2
  50. package/dist/core/collection/collection.mjs +11 -0
  51. package/dist/core/collection/collection.mjs.map +1 -1
  52. package/dist/core/collection/index.d.mts +1 -1
  53. package/dist/core/collection/reconciler.d.mts +13 -4
  54. package/dist/core/collection/reconciler.mjs.map +1 -1
  55. package/dist/core/collection/state.d.mts +7 -2
  56. package/dist/core/collection/state.mjs.map +1 -1
  57. package/dist/core/collection/url.d.mts +3 -0
  58. package/dist/core/collection/url.mjs.map +1 -1
  59. package/dist/core/constants.d.mts +1 -1
  60. package/dist/core/constants.mjs +2 -2
  61. package/dist/core/constants.mjs.map +1 -1
  62. package/dist/core/headers.mjs +2 -2
  63. package/dist/core/headers.mjs.map +1 -1
  64. package/dist/core/index.d.mts +5 -5
  65. package/dist/core/logging/logging.mjs.map +1 -1
  66. package/dist/core/money/format.mjs +6 -3
  67. package/dist/core/money/format.mjs.map +1 -1
  68. package/dist/core/observable.mjs +0 -3
  69. package/dist/core/observable.mjs.map +1 -1
  70. package/dist/core/predictive-search/form.d.mts +1 -0
  71. package/dist/core/predictive-search/form.mjs +1 -0
  72. package/dist/core/predictive-search/form.mjs.map +1 -1
  73. package/dist/core/predictive-search/index.d.mts +1 -1
  74. package/dist/core/predictive-search/queries.d.mts +40 -4
  75. package/dist/core/predictive-search/queries.mjs +7 -1
  76. package/dist/core/predictive-search/queries.mjs.map +1 -1
  77. package/dist/core/predictive-search/search.d.mts +43 -10
  78. package/dist/core/predictive-search/search.mjs +34 -0
  79. package/dist/core/predictive-search/search.mjs.map +1 -1
  80. package/dist/core/predictive-search/server-handlers.d.mts +31 -5
  81. package/dist/core/predictive-search/server-handlers.mjs +5 -3
  82. package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
  83. package/dist/core/predictive-search/store.d.mts +3 -1
  84. package/dist/core/predictive-search/store.mjs.map +1 -1
  85. package/dist/core/predictive-search/url.d.mts +50 -8
  86. package/dist/core/predictive-search/url.mjs +9 -0
  87. package/dist/core/predictive-search/url.mjs.map +1 -1
  88. package/dist/core/product/options.d.mts +2 -2
  89. package/dist/core/product/options.mjs +2 -2
  90. package/dist/core/product/options.mjs.map +1 -1
  91. package/dist/core/product/product-form.d.mts +33 -1
  92. package/dist/core/product/product-form.mjs +30 -0
  93. package/dist/core/product/product-form.mjs.map +1 -1
  94. package/dist/core/product/state.d.mts +41 -0
  95. package/dist/core/product/url.d.mts +6 -0
  96. package/dist/core/product/url.mjs.map +1 -1
  97. package/dist/core/request-context.d.mts +2 -5
  98. package/dist/core/request-context.mjs +13 -39
  99. package/dist/core/request-context.mjs.map +1 -1
  100. package/dist/core/request-routing/handle-shopify-routes.mjs +2 -1
  101. package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  102. package/dist/core/request-routing/interceptors/ajax-api.mjs +1 -1
  103. package/dist/core/request-routing/interceptors/api-proxy.mjs +1 -1
  104. package/dist/core/request-routing/interceptors/checkout.mjs +19 -6
  105. package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -1
  106. package/dist/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
  107. package/dist/core/request-routing/interceptors/proxy.mjs +20 -5
  108. package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
  109. package/dist/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
  110. package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
  111. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
  112. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
  113. package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
  114. package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
  115. package/dist/core/shopify-scripts/analytics.mjs +2 -2
  116. package/dist/core/shopify-scripts/analytics.mjs.map +1 -1
  117. package/dist/core/shopify-scripts/constants.mjs +1 -1
  118. package/dist/core/shopify-scripts/constants.mjs.map +1 -1
  119. package/dist/core/shopify-scripts/global.mjs +5 -1
  120. package/dist/core/shopify-scripts/global.mjs.map +1 -1
  121. package/dist/core/shopify-scripts/initialize.d.mts +1 -0
  122. package/dist/core/shopify-scripts/initialize.mjs +10 -3
  123. package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
  124. package/dist/core/shopify-scripts/types.d.mts +1 -0
  125. package/dist/core/url.mjs +20 -2
  126. package/dist/core/url.mjs.map +1 -1
  127. package/dist/customer-account/client.d.mts +128 -4
  128. package/dist/customer-account/client.mjs +27 -1
  129. package/dist/customer-account/client.mjs.map +1 -1
  130. package/dist/customer-account/errors.d.mts +46 -0
  131. package/dist/customer-account/errors.mjs +46 -0
  132. package/dist/customer-account/errors.mjs.map +1 -1
  133. package/dist/customer-account/graphql.d.mts +68 -0
  134. package/dist/customer-account/graphql.mjs +47 -0
  135. package/dist/customer-account/graphql.mjs.map +1 -1
  136. package/dist/customer-account/session.d.mts +114 -23
  137. package/dist/customer-account/session.mjs +27 -12
  138. package/dist/customer-account/session.mjs.map +1 -1
  139. package/dist/customer-account/type-resolver.d.mts +23 -0
  140. package/dist/customer-account-api-types.d.ts +570 -374
  141. package/dist/customer-account.schema.json +2981 -1527
  142. package/dist/development/client/client.mjs +2 -2
  143. package/dist/development/client/errors.d.mts +19 -19
  144. package/dist/development/client/errors.mjs +20 -20
  145. package/dist/development/client/errors.mjs.map +1 -1
  146. package/dist/development/client/types.d.mts +91 -10
  147. package/dist/development/core/analytics/cart-tracker.d.mts +14 -0
  148. package/dist/development/core/analytics/cart-tracker.mjs +15 -1
  149. package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
  150. package/dist/development/core/analytics/custom-consent.mjs +12 -0
  151. package/dist/development/core/analytics/custom-consent.mjs.map +1 -0
  152. package/dist/development/core/analytics/events.d.mts +7 -0
  153. package/dist/development/core/analytics/events.mjs +7 -0
  154. package/dist/development/core/analytics/events.mjs.map +1 -1
  155. package/dist/development/core/analytics/index.d.mts +1 -1
  156. package/dist/development/core/analytics/types.d.mts +152 -16
  157. package/dist/development/core/cart/actions.d.mts +47 -3
  158. package/dist/development/core/cart/actions.mjs +27 -0
  159. package/dist/development/core/cart/actions.mjs.map +1 -1
  160. package/dist/development/core/cart/attach-quantity-input.d.mts +26 -0
  161. package/dist/development/core/cart/attach-quantity-input.mjs +26 -0
  162. package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
  163. package/dist/development/core/cart/cart.d.mts +106 -6
  164. package/dist/development/core/cart/cart.mjs +41 -0
  165. package/dist/development/core/cart/cart.mjs.map +1 -1
  166. package/dist/development/core/cart/cookie.d.mts +15 -0
  167. package/dist/development/core/cart/cookie.mjs +15 -0
  168. package/dist/development/core/cart/cookie.mjs.map +1 -1
  169. package/dist/development/core/cart/form.d.mts +61 -0
  170. package/dist/development/core/cart/form.mjs +18 -0
  171. package/dist/development/core/cart/form.mjs.map +1 -1
  172. package/dist/development/core/cart/get-cart.d.mts +43 -2
  173. package/dist/development/core/cart/get-cart.mjs +33 -0
  174. package/dist/development/core/cart/get-cart.mjs.map +1 -1
  175. package/dist/development/core/cart/index.d.mts +1 -1
  176. package/dist/development/core/cart/quantity.d.mts +17 -0
  177. package/dist/development/core/cart/quantity.mjs +17 -0
  178. package/dist/development/core/cart/quantity.mjs.map +1 -1
  179. package/dist/development/core/cart/queries.d.mts +402 -369
  180. package/dist/development/core/cart/queries.mjs +2 -1
  181. package/dist/development/core/cart/queries.mjs.map +1 -1
  182. package/dist/development/core/cart/server-handlers.d.mts +69 -0
  183. package/dist/development/core/cart/server-handlers.mjs +2 -10
  184. package/dist/development/core/cart/server-handlers.mjs.map +1 -1
  185. package/dist/development/core/cart/state.d.mts +133 -0
  186. package/dist/development/core/cart/state.mjs +8 -0
  187. package/dist/development/core/cart/state.mjs.map +1 -1
  188. package/dist/development/core/collection/collection.d.mts +18 -2
  189. package/dist/development/core/collection/collection.mjs +11 -0
  190. package/dist/development/core/collection/collection.mjs.map +1 -1
  191. package/dist/development/core/collection/index.d.mts +1 -1
  192. package/dist/development/core/collection/reconciler.d.mts +13 -4
  193. package/dist/development/core/collection/reconciler.mjs.map +1 -1
  194. package/dist/development/core/collection/state.d.mts +7 -2
  195. package/dist/development/core/collection/state.mjs.map +1 -1
  196. package/dist/development/core/collection/url.d.mts +3 -0
  197. package/dist/development/core/collection/url.mjs.map +1 -1
  198. package/dist/development/core/constants.mjs +1 -1
  199. package/dist/development/core/constants.mjs.map +1 -1
  200. package/dist/development/core/development.d.mts +5 -5
  201. package/dist/development/core/headers.mjs +2 -2
  202. package/dist/development/core/headers.mjs.map +1 -1
  203. package/dist/development/core/index.d.mts +4 -4
  204. package/dist/development/core/logging/logging.mjs.map +1 -1
  205. package/dist/development/core/money/format.mjs +6 -3
  206. package/dist/development/core/money/format.mjs.map +1 -1
  207. package/dist/development/core/observable.mjs +0 -3
  208. package/dist/development/core/observable.mjs.map +1 -1
  209. package/dist/development/core/predictive-search/form.d.mts +1 -0
  210. package/dist/development/core/predictive-search/form.mjs +1 -0
  211. package/dist/development/core/predictive-search/form.mjs.map +1 -1
  212. package/dist/development/core/predictive-search/index.d.mts +1 -1
  213. package/dist/development/core/predictive-search/queries.d.mts +40 -4
  214. package/dist/development/core/predictive-search/queries.mjs +7 -1
  215. package/dist/development/core/predictive-search/queries.mjs.map +1 -1
  216. package/dist/development/core/predictive-search/search.d.mts +43 -10
  217. package/dist/development/core/predictive-search/search.mjs +34 -0
  218. package/dist/development/core/predictive-search/search.mjs.map +1 -1
  219. package/dist/development/core/predictive-search/server-handlers.d.mts +31 -5
  220. package/dist/development/core/predictive-search/server-handlers.mjs +5 -3
  221. package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
  222. package/dist/development/core/predictive-search/store.d.mts +3 -1
  223. package/dist/development/core/predictive-search/store.mjs.map +1 -1
  224. package/dist/development/core/predictive-search/url.d.mts +50 -8
  225. package/dist/development/core/predictive-search/url.mjs +9 -0
  226. package/dist/development/core/predictive-search/url.mjs.map +1 -1
  227. package/dist/development/core/product/options.d.mts +2 -2
  228. package/dist/development/core/product/options.mjs +2 -2
  229. package/dist/development/core/product/options.mjs.map +1 -1
  230. package/dist/development/core/product/product-form.d.mts +33 -1
  231. package/dist/development/core/product/product-form.mjs +30 -0
  232. package/dist/development/core/product/product-form.mjs.map +1 -1
  233. package/dist/development/core/product/state.d.mts +41 -0
  234. package/dist/development/core/product/url.d.mts +6 -0
  235. package/dist/development/core/product/url.mjs.map +1 -1
  236. package/dist/development/core/request-context.d.mts +2 -5
  237. package/dist/development/core/request-context.mjs +13 -39
  238. package/dist/development/core/request-context.mjs.map +1 -1
  239. package/dist/development/core/request-routing/handle-shopify-routes.mjs +2 -1
  240. package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  241. package/dist/development/core/request-routing/interceptors/ajax-api.mjs +1 -1
  242. package/dist/development/core/request-routing/interceptors/api-proxy.mjs +1 -1
  243. package/dist/development/core/request-routing/interceptors/checkout.mjs +19 -6
  244. package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -1
  245. package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
  246. package/dist/development/core/request-routing/interceptors/proxy.mjs +20 -5
  247. package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
  248. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
  249. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
  250. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
  251. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
  252. package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
  253. package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
  254. package/dist/development/core/shopify-scripts/analytics.mjs +2 -2
  255. package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -1
  256. package/dist/development/core/shopify-scripts/constants.mjs +1 -1
  257. package/dist/development/core/shopify-scripts/constants.mjs.map +1 -1
  258. package/dist/development/core/shopify-scripts/global.mjs +5 -1
  259. package/dist/development/core/shopify-scripts/global.mjs.map +1 -1
  260. package/dist/development/core/shopify-scripts/initialize.d.mts +1 -0
  261. package/dist/development/core/shopify-scripts/initialize.mjs +10 -3
  262. package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
  263. package/dist/development/core/shopify-scripts/types.d.mts +1 -0
  264. package/dist/development/core/url.mjs +20 -2
  265. package/dist/development/core/url.mjs.map +1 -1
  266. package/dist/development/customer-account/session.d.mts +69 -13
  267. package/dist/development/customer-account/session.mjs +4 -0
  268. package/dist/development/customer-account/session.mjs.map +1 -1
  269. package/dist/development/globals.d.mts +2 -4
  270. package/dist/development/graphql/generated/graphql-env.d.mts +459 -16
  271. package/dist/development/graphql/generated/storefront-api-types.d.mts +1 -1
  272. package/dist/development/graphql/graphql.d.mts +33 -0
  273. package/dist/development/graphql/graphql.mjs +30 -0
  274. package/dist/development/graphql/graphql.mjs.map +1 -1
  275. package/dist/development/graphql/type-resolver.d.mts +14 -0
  276. package/dist/development/react/cart.d.mts +85 -14
  277. package/dist/development/react/cart.mjs +123 -3
  278. package/dist/development/react/cart.mjs.map +1 -1
  279. package/dist/development/react/collection.d.mts +2 -4
  280. package/dist/development/react/collection.mjs.map +1 -1
  281. package/dist/development/react/index.d.mts +7 -5
  282. package/dist/development/react/index.mjs +2 -2
  283. package/dist/development/react/predictive-search.d.mts +68 -7
  284. package/dist/development/react/predictive-search.mjs +54 -12
  285. package/dist/development/react/predictive-search.mjs.map +1 -1
  286. package/dist/development/react/product.d.mts +1 -0
  287. package/dist/development/react/product.mjs +5 -2
  288. package/dist/development/react/product.mjs.map +1 -1
  289. package/dist/development/react/shopify-scripts.mjs +1 -0
  290. package/dist/development/react/shopify-scripts.mjs.map +1 -1
  291. package/dist/development/vue/cart.d.mts +85 -6
  292. package/dist/development/vue/cart.mjs +95 -0
  293. package/dist/development/vue/cart.mjs.map +1 -1
  294. package/dist/development/vue/collection.d.mts +83 -5
  295. package/dist/development/vue/collection.mjs +52 -0
  296. package/dist/development/vue/collection.mjs.map +1 -1
  297. package/dist/development/vue/index.d.mts +6 -4
  298. package/dist/development/vue/predictive-search.d.mts +53 -6
  299. package/dist/development/vue/predictive-search.mjs +33 -0
  300. package/dist/development/vue/predictive-search.mjs.map +1 -1
  301. package/dist/development/vue/product.d.mts +6 -2
  302. package/dist/development/vue/product.mjs.map +1 -1
  303. package/dist/development/vue/shopify-scripts.d.mts +21 -3
  304. package/dist/development/vue/shopify-scripts.mjs +1 -0
  305. package/dist/development/vue/shopify-scripts.mjs.map +1 -1
  306. package/dist/globals.d.mts +2 -4
  307. package/dist/graphql/generated/customer-account-graphql-env.d.mts +1717 -1090
  308. package/dist/graphql/generated/graphql-env.d.mts +459 -16
  309. package/dist/graphql/generated/storefront-api-types.d.mts +1 -1
  310. package/dist/graphql/graphql.d.mts +33 -0
  311. package/dist/graphql/graphql.mjs +30 -0
  312. package/dist/graphql/graphql.mjs.map +1 -1
  313. package/dist/graphql/type-resolver.d.mts +14 -0
  314. package/dist/react/cart.d.mts +85 -14
  315. package/dist/react/cart.mjs +123 -3
  316. package/dist/react/cart.mjs.map +1 -1
  317. package/dist/react/collection.d.mts +2 -4
  318. package/dist/react/collection.mjs.map +1 -1
  319. package/dist/react/index.d.mts +7 -5
  320. package/dist/react/index.mjs +2 -2
  321. package/dist/react/predictive-search.d.mts +68 -7
  322. package/dist/react/predictive-search.mjs +54 -12
  323. package/dist/react/predictive-search.mjs.map +1 -1
  324. package/dist/react/product.d.mts +1 -0
  325. package/dist/react/product.mjs +5 -2
  326. package/dist/react/product.mjs.map +1 -1
  327. package/dist/react/shopify-scripts.mjs +1 -0
  328. package/dist/react/shopify-scripts.mjs.map +1 -1
  329. package/dist/storefront-api-types.d.ts +165 -20
  330. package/dist/storefront.schema.json +782 -57
  331. package/dist/vite/customer-account.mjs +191 -0
  332. package/dist/vite/customer-account.mjs.map +1 -0
  333. package/dist/vite/local-https.mjs +13 -29
  334. package/dist/vite/local-https.mjs.map +1 -1
  335. package/dist/vite/mkcert.mjs +1 -1
  336. package/dist/vue/cart.d.mts +85 -6
  337. package/dist/vue/cart.mjs +95 -0
  338. package/dist/vue/cart.mjs.map +1 -1
  339. package/dist/vue/collection.d.mts +83 -5
  340. package/dist/vue/collection.mjs +52 -0
  341. package/dist/vue/collection.mjs.map +1 -1
  342. package/dist/vue/index.d.mts +6 -4
  343. package/dist/vue/predictive-search.d.mts +53 -6
  344. package/dist/vue/predictive-search.mjs +33 -0
  345. package/dist/vue/predictive-search.mjs.map +1 -1
  346. package/dist/vue/product.d.mts +6 -2
  347. package/dist/vue/product.mjs.map +1 -1
  348. package/dist/vue/shopify-scripts.d.mts +21 -3
  349. package/dist/vue/shopify-scripts.mjs +1 -0
  350. package/dist/vue/shopify-scripts.mjs.map +1 -1
  351. package/package.json +5 -2
  352. package/skills/hydrogen-analytics/SKILL.md +6 -5
  353. package/skills/hydrogen-analytics/references/custom-consent.md +52 -0
  354. package/skills/hydrogen-analytics/references/react.md +1 -1
  355. package/skills/hydrogen-customer-account/SKILL.md +3 -3
  356. package/skills/hydrogen-local-https/SKILL.md +22 -7
  357. package/skills/hydrogen-request-handlers/SKILL.md +5 -5
  358. package/skills/hydrogen-request-handlers/references/nuxt.md +0 -6
  359. package/skills/hydrogen-setup/references/analytics.md +24 -23
  360. package/skills/hydrogen-setup/steps/1-inspect-app.md +1 -1
  361. package/skills/hydrogen-setup/steps/2-scaffold.md +1 -1
  362. package/skills/hydrogen-smoke-test/SKILL.md +2 -2
  363. package/skills/hydrogen-storefront-client/SKILL.md +0 -2
  364. package/ts-plugin/package.json +5 -0
  365. package/dist/core/shopify-scripts/deprecated-cookies.mjs +0 -98
  366. package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
  367. package/dist/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
  368. package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
  369. package/dist/core/shopify-scripts/utils/tracking-values.mjs +0 -65
  370. package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
  371. package/dist/core/shopify-scripts/utils/uuid.mjs +0 -17
  372. package/dist/core/shopify-scripts/utils/uuid.mjs.map +0 -1
  373. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +0 -98
  374. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
  375. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
  376. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
  377. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +0 -65
  378. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
  379. package/dist/development/core/shopify-scripts/utils/uuid.mjs +0 -17
  380. package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +0 -1
package/README.md CHANGED
@@ -100,13 +100,13 @@ const isLoggedIn = await customerSession.isLoggedIn(
100
100
  );
101
101
  ```
102
102
 
103
- Customer Account OAuth methods require a public HTTPS origin. The writable session manager should expose the request origin; explicit `origin` options are only needed as overrides. For local development, use a tunnel or trusted local HTTPS through `localHttps` from `@shopify/hydrogen/vite`, and pass the framework's canonical request URL rather than an untrusted forwarded host.
103
+ Customer Account OAuth methods require a public HTTPS origin. The writable session manager should expose the request origin; explicit `origin` options are only needed as overrides. For local development, use a tunnel or trusted local HTTPS through `localHttps` from `@shopify/hydrogen/vite`, which provisions certificates and uses Shopify CLI to push Customer Account URLs outside CI. Pass the framework's canonical request URL rather than an untrusted forwarded host.
104
104
 
105
105
  Pass `customerSession` to `createCartServerHandlers({customerSession})` to associate newly created carts with the current customer when the session has a usable access token or successfully refreshed access token, and mark checkout URLs in authenticated cart GET responses with `logged_in=true`.
106
106
 
107
107
  Use `createCustomerAccountServerHandlers({customerSession})` with `handleShopifyRoutes` to install the default `GET /account/login`, `GET /account/authorize`, `GET /account/refresh`, and `POST /account/logout` handlers. Pass those cart server handlers as `cartServerHandlers` to also keep the browser cart's buyer identity in step with the customer session: authorization and refresh attach the customer to the cart, a definitive refresh rejection and logout detach it. Sync is best-effort — a failed cart mutation never blocks the route's redirect; a failed detach during logout or definitive refresh rejection expires the cart cookie instead. `cartServerHandlers` requires the `customerSession` returned by `createCustomerSession` shared by both handler groups. Pass the same request-scoped `requestContext` and `sessionManager` into `handleShopifyRoutes` once alongside the `storefrontClient`. Session managers can be read-only for `isLoggedIn()` / `getAccessToken()` and writable for cart POST handlers configured with `customerSession`, `getOrRefreshAccessToken()`, `prepareLoginUrl()`, `handleOAuthCallback()`, `logout()`, and registered account handlers. `isLoggedIn()` is a read-only UI/session-presence check: it returns true for a usable access token or a refresh token that can attempt to restore one later. `getAccessToken()` still returns only a currently usable access token and never refreshes.
108
108
 
109
- The login handler respects a sanitized `return_to` search parameter and otherwise redirects back to `defaultPostLoginRedirectPathname` (default `/`). The logout handler redirects through Shopify using `postLogoutRedirectUri` (default `/`) when an ID token is present; otherwise, it redirects directly to `postLogoutRedirectUri`. Apps can still implement their own framework routes when they need custom behavior.
109
+ The login handler respects a `return_to` search parameter when it is a same-origin path or URL, such as `/account/orders`, and otherwise redirects back to `defaultPostLoginRedirectPathname` (default `/`). The logout handler redirects through Shopify using `postLogoutRedirectUri` (default `/`) when an ID token is present; otherwise, it redirects directly to `postLogoutRedirectUri`. Apps can still implement their own framework routes when they need custom behavior.
110
110
 
111
111
  When a writable method can update cookie-backed session state, commit once while finalizing the response and append headers from `await sessionManager.commit?.()` there. After committing session headers, call `requestContext.applyResponseHeaders(response.headers)`. Customer Account session reads and GraphQL calls mark the request context private so the finalizer can prevent public/CDN caching of personalized responses.
112
112
 
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
6
- import { homedir } from "node:os";
7
- import { dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
6
+ import { homedir, tmpdir } from "node:os";
7
+ import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
8
8
  import { createInterface } from "node:readline/promises";
9
9
  import { spawn } from "node:child_process";
10
10
  import { createHash, randomUUID } from "node:crypto";
@@ -444,6 +444,24 @@ function isObjectRecord(value) {
444
444
  return typeof value === "object" && value !== null && !Array.isArray(value);
445
445
  }
446
446
 
447
+ //#endregion
448
+ //#region src/cli/terminal.ts
449
+ function canPromptInTerminal(env = process.env) {
450
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY) && !env.CI;
451
+ }
452
+ async function confirmInTerminal(question) {
453
+ const readline = createInterface({
454
+ input: process.stdin,
455
+ output: process.stdout
456
+ });
457
+ try {
458
+ const answer = (await readline.question(`${question} [Y/n] `)).trim().toLowerCase();
459
+ return answer === "" || answer === "y" || answer === "yes";
460
+ } finally {
461
+ readline.close();
462
+ }
463
+ }
464
+
447
465
  //#endregion
448
466
  //#region src/cli/skills.ts
449
467
  const PACKAGE_NAME$1 = "@shopify/hydrogen";
@@ -681,21 +699,6 @@ async function planOrphans(plans, version, confirm) {
681
699
  });
682
700
  }
683
701
  }
684
- function canPromptInTerminal() {
685
- return Boolean(process.stdin.isTTY && process.stdout.isTTY) && !process.env.CI;
686
- }
687
- async function confirmInTerminal(question) {
688
- const readline = createInterface({
689
- input: process.stdin,
690
- output: process.stdout
691
- });
692
- try {
693
- const answer = (await readline.question(`${question} [Y/n] `)).trim().toLowerCase();
694
- return answer === "" || answer === "y" || answer === "yes";
695
- } finally {
696
- readline.close();
697
- }
698
- }
699
702
  /** Never removes user edits without an answer, so no TTY means keep. */
700
703
  function confirmByDefault(question) {
701
704
  return canPromptInTerminal() ? confirmInTerminal(question) : Promise.resolve(false);
@@ -931,13 +934,14 @@ function parsePackageManager(value) {
931
934
  if (value.startsWith(`${packageManager}/`)) return packageManager;
932
935
  }
933
936
  }
937
+ function detectPackageManagerFromEnv(env) {
938
+ return parsePackageManager(env.npm_config_user_agent);
939
+ }
934
940
  function detectPackageManager(appRoot, packageJson, env) {
935
941
  const packageJsonManager = parsePackageManager(packageJson.packageManager);
936
942
  if (packageJsonManager) return packageJsonManager;
937
943
  for (const [packageManager, lockfile] of PACKAGE_MANAGER_LOCKFILES) if (existsSync(join(appRoot, lockfile))) return packageManager;
938
- const userAgentManager = parsePackageManager(env.npm_config_user_agent);
939
- if (userAgentManager) return userAgentManager;
940
- throw new Error("Could not detect a package manager. Add a packageManager field or a lockfile before running setup.");
944
+ return detectPackageManagerFromEnv(env) ?? "npm";
941
945
  }
942
946
  function hasHydrogenDependency(packageJson) {
943
947
  return Boolean(packageJson.dependencies?.[PACKAGE_NAME] ?? packageJson.devDependencies?.[PACKAGE_NAME]);
@@ -961,17 +965,115 @@ function spawnRunCommand(command, args, options) {
961
965
  });
962
966
  });
963
967
  }
964
- async function setupHydrogen(options = {}) {
965
- const appRoot = options.cwd ?? process.cwd();
966
- const env = options.env ?? process.env;
967
- const runCommand = options.runCommand ?? spawnRunCommand;
968
- const log = options.log ?? console.log;
968
+ const TEMPLATE_TARBALL_URL = "https://codeload.github.com/Shopify/hydrogen/tar.gz/dist-preview";
969
+ const TEMPLATE_TARBALL_PREFIX = "hydrogen-dist-preview/templates/react-router/";
970
+ const TEMPLATE_TARBALL_STRIP_COMPONENTS = TEMPLATE_TARBALL_PREFIX.split("/").filter(Boolean).length;
971
+ async function promptSetupChoice(log) {
972
+ log("\nNo project found in this directory.\n");
973
+ log(" 1) Create a new Hydrogen storefront (React Router)");
974
+ log(" 2) Just install Hydrogen skills\n");
975
+ const readline = createInterface({
976
+ input: process.stdin,
977
+ output: process.stdout
978
+ });
979
+ try {
980
+ while (true) {
981
+ const answer = (await readline.question("Your choice [1] ")).trim();
982
+ if (answer === "" || answer === "1") return "scaffold";
983
+ if (answer === "2") return "skills";
984
+ log("Please enter \"1\" or \"2\".");
985
+ }
986
+ } finally {
987
+ readline.close();
988
+ }
989
+ }
990
+ function hasPackageJson(appRoot) {
991
+ return existsSync(join(appRoot, PACKAGE_JSON_FILE_NAME));
992
+ }
993
+ async function downloadAndExtractTemplate(appRoot, runCommand) {
994
+ const response = await fetch(TEMPLATE_TARBALL_URL, { signal: AbortSignal.timeout(3e4) });
995
+ if (!response.ok) throw new Error(`Failed to download template (${response.status}). Check your internet connection.`);
996
+ const tempDir = mkdtempSync(join(tmpdir(), "hydrogen-template-"));
997
+ const tempFile = "template.tar.gz";
998
+ try {
999
+ writeFileSync(join(tempDir, tempFile), Buffer.from(await response.arrayBuffer()));
1000
+ await runCommand("tar", [
1001
+ "xzf",
1002
+ tempFile,
1003
+ `--strip-components=${TEMPLATE_TARBALL_STRIP_COMPONENTS}`,
1004
+ "-C",
1005
+ appRoot,
1006
+ TEMPLATE_TARBALL_PREFIX
1007
+ ], { cwd: tempDir });
1008
+ } finally {
1009
+ rmSync(tempDir, {
1010
+ recursive: true,
1011
+ force: true
1012
+ });
1013
+ }
1014
+ }
1015
+ function updateScaffoldedPackageJson(appRoot) {
1016
+ const packageJsonPath = join(appRoot, PACKAGE_JSON_FILE_NAME);
1017
+ const raw = readFileSync(packageJsonPath, "utf8");
1018
+ const parsed = JSON.parse(raw);
1019
+ if (!isObjectRecord(parsed)) return;
1020
+ parsed.name = basename(appRoot);
1021
+ delete parsed.private;
1022
+ delete parsed.packageManager;
1023
+ writeFileSync(packageJsonPath, JSON.stringify(parsed, null, 2) + "\n");
1024
+ }
1025
+ async function scaffoldTemplate(appRoot, env, runCommand, log) {
1026
+ log("Downloading Hydrogen template...");
1027
+ await downloadAndExtractTemplate(appRoot, runCommand);
1028
+ updateScaffoldedPackageJson(appRoot);
1029
+ const packageManager = detectPackageManagerFromEnv(env) ?? "npm";
1030
+ log(`Installing dependencies with ${packageManager}...`);
1031
+ try {
1032
+ await runCommand(packageManager, ["install"], { cwd: appRoot });
1033
+ } catch (error) {
1034
+ throw new Error(`Template was created but dependency install failed. Run \`${packageManager} install\` or re-run \`npx @shopify/hydrogen setup\` in ${appRoot} to finish.`, { cause: error });
1035
+ }
1036
+ return packageManager;
1037
+ }
1038
+ async function ensureHydrogenInstalled(appRoot, env, runCommand, log) {
969
1039
  const packageJson = readPackageJson(appRoot);
970
- if (!hasHydrogenDependency(packageJson)) {
1040
+ if (hasHydrogenDependency(packageJson) && getInstalledPackageRoot(appRoot)) return;
1041
+ if (hasHydrogenDependency(packageJson)) {
971
1042
  const packageManager = detectPackageManager(appRoot, packageJson, env);
972
- log(`Installing ${PACKAGE_NAME} with ${packageManager}...`);
973
- await installHydrogen(appRoot, packageManager, runCommand);
1043
+ log(`${PACKAGE_NAME} is declared but not installed. Running ${packageManager} install...`);
1044
+ await runCommand(packageManager, ["install"], { cwd: appRoot });
1045
+ return;
974
1046
  }
1047
+ const packageManager = detectPackageManager(appRoot, packageJson, env);
1048
+ log(`Installing ${PACKAGE_NAME} with ${packageManager}...`);
1049
+ await installHydrogen(appRoot, packageManager, runCommand);
1050
+ }
1051
+ function resolveSetupOptions(options) {
1052
+ const env = options.env ?? process.env;
1053
+ return {
1054
+ appRoot: options.cwd ?? process.cwd(),
1055
+ env,
1056
+ runCommand: options.runCommand ?? spawnRunCommand,
1057
+ log: options.log ?? console.log,
1058
+ prompt: options.prompt ?? (canPromptInTerminal(env) ? promptSetupChoice : void 0)
1059
+ };
1060
+ }
1061
+ const IGNORED_DIRECTORY_ENTRIES = new Set([".git", ".DS_Store"]);
1062
+ function isEmptyDirectory(dir) {
1063
+ return readdirSync(dir).every((entry) => IGNORED_DIRECTORY_ENTRIES.has(entry));
1064
+ }
1065
+ async function setupHydrogen(options = {}) {
1066
+ const { appRoot, env, runCommand, log, prompt } = resolveSetupOptions(options);
1067
+ if (hasPackageJson(appRoot)) await ensureHydrogenInstalled(appRoot, env, runCommand, log);
1068
+ else if (isEmptyDirectory(appRoot)) {
1069
+ let choice;
1070
+ if (prompt) choice = await prompt(log);
1071
+ else {
1072
+ log("No package.json found and no terminal to prompt; installing skills only.");
1073
+ choice = "skills";
1074
+ }
1075
+ if (choice === "scaffold") log(`\nHydrogen storefront created. Run \`${await scaffoldTemplate(appRoot, env, runCommand, log)} run dev\` to start (uses mock.shop by default).\n`);
1076
+ } else throw new Error("No package.json found. Run this command from your project root.");
975
1077
  await syncSkills({
976
1078
  force: options.force,
977
1079
  cwd: appRoot,
@@ -1,8 +1,8 @@
1
+ import { normalizeStoreDomain } from "../core/url.mjs";
1
2
  import { getHydrogenCacheStatus } from "../core/cache/cache-status.mjs";
2
3
  import { createFetchWithCache } from "../core/cache/fetch-with-cache.mjs";
3
4
  import { DEFAULT_TIMEOUT_IN_MS, STOREFRONT_API_VERSION } from "../core/constants.mjs";
4
5
  import { HYDROGEN_VERSION_HEADER, REQUEST_GROUP_ID_HEADER, SDK_VARIANT_HEADER, SDK_VARIANT_SOURCE_HEADER, SDK_VERSION_HEADER, SHOPIFY_STOREFRONT_S_HEADER, SHOPIFY_STOREFRONT_Y_HEADER, SHOPIFY_UNIQUE_TOKEN_HEADER, SHOPIFY_VISIT_TOKEN_HEADER, STOREFRONT_ACCESS_TOKEN_HEADER, STOREFRONT_BUYER_IP_HEADER, STOREFRONT_ID_HEADER, STOREFRONT_PRIVATE_TOKEN_HEADER } from "../core/headers.mjs";
5
- import { normalizeStoreDomain } from "../core/url.mjs";
6
6
  import { StorefrontApiError, StorefrontTimeoutError } from "./errors.mjs";
7
7
 
8
8
  //#region src/client/client.ts
@@ -42,7 +42,7 @@ function createStorefrontClient(args) {
42
42
  const { config, requestContext, type: clientType } = args;
43
43
  if (!config.storeDomain) throw new Error("storeDomain is required and must be non-empty");
44
44
  const storeUrl = normalizeStoreDomain(config.storeDomain);
45
- const apiUrl = `${storeUrl}/api/${config.apiVersion ?? "2026-04"}/graphql.json`;
45
+ const apiUrl = `${storeUrl}/api/${config.apiVersion ?? "2026-10"}/graphql.json`;
46
46
  const originFetch = config.fetch ?? globalThis.fetch;
47
47
  if (typeof originFetch !== "function") throw new Error("No fetch function available. Pass a fetch option or ensure globalThis.fetch exists.");
48
48
  const resolvedFetch = config.cache ? createFetchWithCache({
@@ -5,41 +5,41 @@ interface StorefrontApiErrorOptions {
5
5
  cause?: unknown;
6
6
  queryText?: string;
7
7
  variables?: Record<string, unknown>;
8
- locations?: ReadonlyArray<{
9
- line: number;
10
- column: number;
11
- }>;
12
- path?: ReadonlyArray<string | number>;
13
- extensions?: Record<string, unknown>;
14
8
  }
9
+ /**
10
+ * Thrown when a Storefront API request fails — HTTP error, network failure,
11
+ * or an unparseable or unexpected response body.
12
+ *
13
+ * In development, `queryText` and `variables` are attached when available.
14
+ * GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.
15
+ */
15
16
  declare class StorefrontApiError extends Error {
17
+ /** Shopify `x-request-id` header, when available. Useful for support requests. */
16
18
  readonly requestId?: string;
19
+ /** HTTP response status code, when the request reached the server. */
17
20
  readonly status?: number;
21
+ /** The GraphQL query text. Only populated in development builds. */
18
22
  readonly queryText?: string;
23
+ /** The variables sent with the request. Only populated in development builds. */
19
24
  readonly variables?: Record<string, unknown>;
20
- readonly locations?: ReadonlyArray<{
21
- line: number;
22
- column: number;
23
- }>;
24
- readonly path?: ReadonlyArray<string | number>;
25
- readonly extensions?: Record<string, unknown>;
26
25
  constructor(message: string, options?: StorefrontApiErrorOptions);
27
26
  get [Symbol.toStringTag](): string;
28
- toString(): string;
27
+ /** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */
29
28
  toJSON(): {
30
29
  name: string;
31
30
  message: string;
32
31
  requestId?: string;
33
32
  status?: number;
34
- locations?: ReadonlyArray<{
35
- line: number;
36
- column: number;
37
- }>;
38
- path?: ReadonlyArray<string | number>;
39
- extensions?: Record<string, unknown>;
40
33
  };
41
34
  }
35
+ /**
36
+ * Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.
37
+ *
38
+ * Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.
39
+ * Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.
40
+ */
42
41
  declare class StorefrontTimeoutError extends StorefrontApiError {
42
+ /** The timeout threshold that was exceeded, in milliseconds. */
43
43
  readonly timeoutInMs: number;
44
44
  constructor(timeoutInMs: number, options?: Omit<StorefrontApiErrorOptions, "cause">);
45
45
  }
@@ -1,34 +1,30 @@
1
1
  //#region src/client/errors.ts
2
+ /**
3
+ * Thrown when a Storefront API request fails — HTTP error, network failure,
4
+ * or an unparseable or unexpected response body.
5
+ *
6
+ * In development, `queryText` and `variables` are attached when available.
7
+ * GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.
8
+ */
2
9
  var StorefrontApiError = class extends Error {
10
+ /** Shopify `x-request-id` header, when available. Useful for support requests. */
3
11
  requestId;
12
+ /** HTTP response status code, when the request reached the server. */
4
13
  status;
14
+ /** The GraphQL query text. Only populated in development builds. */
5
15
  queryText;
16
+ /** The variables sent with the request. Only populated in development builds. */
6
17
  variables;
7
- locations;
8
- path;
9
- extensions;
10
18
  constructor(message, options) {
11
19
  super(message, options?.cause ? { cause: options.cause } : void 0);
12
20
  this.name = "StorefrontApiError";
13
21
  this.requestId = options?.requestId;
14
22
  this.status = options?.status;
15
- this.locations = options?.locations;
16
- this.path = options?.path;
17
- this.extensions = options?.extensions;
18
23
  }
19
24
  get [Symbol.toStringTag]() {
20
25
  return this.name;
21
26
  }
22
- toString() {
23
- let result = `${this.name}: ${this.message}`;
24
- if (this.path) try {
25
- result += ` | path: ${JSON.stringify(this.path)}`;
26
- } catch {}
27
- if (this.extensions) try {
28
- result += ` | extensions: ${JSON.stringify(this.extensions)}`;
29
- } catch {}
30
- return result;
31
- }
27
+ /** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */
32
28
  toJSON() {
33
29
  return {
34
30
  name: this.name,
@@ -38,7 +34,14 @@ var StorefrontApiError = class extends Error {
38
34
  };
39
35
  }
40
36
  };
37
+ /**
38
+ * Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.
39
+ *
40
+ * Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.
41
+ * Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.
42
+ */
41
43
  var StorefrontTimeoutError = class extends StorefrontApiError {
44
+ /** The timeout threshold that was exceeded, in milliseconds. */
42
45
  timeoutInMs;
43
46
  constructor(timeoutInMs, options) {
44
47
  super(`Storefront API request timed out after ${timeoutInMs}ms`, options);
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../../src/client/errors.ts"],"sourcesContent":["interface StorefrontApiErrorOptions {\n requestId?: string;\n status?: number;\n cause?: unknown;\n queryText?: string;\n variables?: Record<string, unknown>;\n locations?: ReadonlyArray<{ line: number; column: number }>;\n path?: ReadonlyArray<string | number>;\n extensions?: Record<string, unknown>;\n}\n\nexport class StorefrontApiError extends Error {\n readonly requestId?: string;\n readonly status?: number;\n readonly queryText?: string;\n readonly variables?: Record<string, unknown>;\n readonly locations?: ReadonlyArray<{ line: number; column: number }>;\n readonly path?: ReadonlyArray<string | number>;\n readonly extensions?: Record<string, unknown>;\n\n constructor(message: string, options?: StorefrontApiErrorOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = \"StorefrontApiError\";\n this.requestId = options?.requestId;\n this.status = options?.status;\n this.locations = options?.locations;\n this.path = options?.path;\n this.extensions = options?.extensions;\n\n if (__DEV__) {\n this.queryText = options?.queryText;\n this.variables = options?.variables;\n }\n }\n\n get [Symbol.toStringTag]() {\n return this.name;\n }\n\n override toString(): string {\n let result = `${this.name}: ${this.message}`;\n if (this.path) {\n try {\n result += ` | path: ${JSON.stringify(this.path)}`;\n } catch {}\n }\n if (this.extensions) {\n try {\n result += ` | extensions: ${JSON.stringify(this.extensions)}`;\n } catch {}\n }\n return result;\n }\n\n toJSON(): {\n name: string;\n message: string;\n requestId?: string;\n status?: number;\n locations?: ReadonlyArray<{ line: number; column: number }>;\n path?: ReadonlyArray<string | number>;\n extensions?: Record<string, unknown>;\n } {\n return {\n name: this.name,\n message: this.message,\n ...(this.requestId != null && { requestId: this.requestId }),\n ...(this.status != null && { status: this.status }),\n ...(__DEV__ && this.locations && { locations: this.locations }),\n ...(__DEV__ && this.path && { path: this.path }),\n ...(__DEV__ && this.extensions && { extensions: this.extensions }),\n };\n }\n}\n\nexport class StorefrontTimeoutError extends StorefrontApiError {\n readonly timeoutInMs: number;\n\n constructor(timeoutInMs: number, options?: Omit<StorefrontApiErrorOptions, \"cause\">) {\n super(`Storefront API request timed out after ${timeoutInMs}ms`, options);\n this.name = \"StorefrontTimeoutError\";\n this.timeoutInMs = timeoutInMs;\n }\n}\n"],"mappings":";AAWA,IAAa,qBAAb,cAAwC,MAAM;CAC5C,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,SAAiB,SAAqC;AAChE,QAAM,SAAS,SAAS,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,OAAU;AACrE,OAAK,OAAO;AACZ,OAAK,YAAY,SAAS;AAC1B,OAAK,SAAS,SAAS;AACvB,OAAK,YAAY,SAAS;AAC1B,OAAK,OAAO,SAAS;AACrB,OAAK,aAAa,SAAS;;CAQ7B,KAAK,OAAO,eAAe;AACzB,SAAO,KAAK;;CAGd,AAAS,WAAmB;EAC1B,IAAI,SAAS,GAAG,KAAK,KAAK,IAAI,KAAK;AACnC,MAAI,KAAK,KACP,KAAI;AACF,aAAU,YAAY,KAAK,UAAU,KAAK,KAAK;UACzC;AAEV,MAAI,KAAK,WACP,KAAI;AACF,aAAU,kBAAkB,KAAK,UAAU,KAAK,WAAW;UACrD;AAEV,SAAO;;CAGT,SAQE;AACA,SAAO;GACL,MAAM,KAAK;GACX,SAAS,KAAK;GACd,GAAI,KAAK,aAAa,QAAQ,EAAE,WAAW,KAAK,WAAW;GAC3D,GAAI,KAAK,UAAU,QAAQ,EAAE,QAAQ,KAAK,QAAQ;GAInD;;;AAIL,IAAa,yBAAb,cAA4C,mBAAmB;CAC7D,AAAS;CAET,YAAY,aAAqB,SAAoD;AACnF,QAAM,0CAA0C,YAAY,KAAK,QAAQ;AACzE,OAAK,OAAO;AACZ,OAAK,cAAc"}
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../../src/client/errors.ts"],"sourcesContent":["interface StorefrontApiErrorOptions {\n requestId?: string;\n status?: number;\n cause?: unknown;\n queryText?: string;\n variables?: Record<string, unknown>;\n}\n\n/**\n * Thrown when a Storefront API request fails — HTTP error, network failure,\n * or an unparseable or unexpected response body.\n *\n * In development, `queryText` and `variables` are attached when available.\n * GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.\n */\nexport class StorefrontApiError extends Error {\n /** Shopify `x-request-id` header, when available. Useful for support requests. */\n readonly requestId?: string;\n /** HTTP response status code, when the request reached the server. */\n readonly status?: number;\n /** The GraphQL query text. Only populated in development builds. */\n readonly queryText?: string;\n /** The variables sent with the request. Only populated in development builds. */\n readonly variables?: Record<string, unknown>;\n\n constructor(message: string, options?: StorefrontApiErrorOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = \"StorefrontApiError\";\n this.requestId = options?.requestId;\n this.status = options?.status;\n\n if (__DEV__) {\n this.queryText = options?.queryText;\n this.variables = options?.variables;\n }\n }\n\n get [Symbol.toStringTag]() {\n return this.name;\n }\n\n /** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */\n toJSON(): { name: string; message: string; requestId?: string; status?: number } {\n return {\n name: this.name,\n message: this.message,\n ...(this.requestId != null && { requestId: this.requestId }),\n ...(this.status != null && { status: this.status }),\n };\n }\n}\n\n/**\n * Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.\n *\n * Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.\n * Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.\n */\nexport class StorefrontTimeoutError extends StorefrontApiError {\n /** The timeout threshold that was exceeded, in milliseconds. */\n readonly timeoutInMs: number;\n\n constructor(timeoutInMs: number, options?: Omit<StorefrontApiErrorOptions, \"cause\">) {\n super(`Storefront API request timed out after ${timeoutInMs}ms`, options);\n this.name = \"StorefrontTimeoutError\";\n this.timeoutInMs = timeoutInMs;\n }\n}\n"],"mappings":";;;;;;;;AAeA,IAAa,qBAAb,cAAwC,MAAM;;CAE5C,AAAS;;CAET,AAAS;;CAET,AAAS;;CAET,AAAS;CAET,YAAY,SAAiB,SAAqC;AAChE,QAAM,SAAS,SAAS,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,OAAU;AACrE,OAAK,OAAO;AACZ,OAAK,YAAY,SAAS;AAC1B,OAAK,SAAS,SAAS;;CAQzB,KAAK,OAAO,eAAe;AACzB,SAAO,KAAK;;;CAId,SAAiF;AAC/E,SAAO;GACL,MAAM,KAAK;GACX,SAAS,KAAK;GACd,GAAI,KAAK,aAAa,QAAQ,EAAE,WAAW,KAAK,WAAW;GAC3D,GAAI,KAAK,UAAU,QAAQ,EAAE,QAAQ,KAAK,QAAQ;GACnD;;;;;;;;;AAUL,IAAa,yBAAb,cAA4C,mBAAmB;;CAE7D,AAAS;CAET,YAAY,aAAqB,SAAoD;AACnF,QAAM,0CAA0C,YAAY,KAAK,QAAQ;AACzE,OAAK,OAAO;AACZ,OAAK,cAAc"}
@@ -15,17 +15,27 @@ type ResultOfDoc<Doc> = Doc extends StorefrontQueryString<infer Result, infer _V
15
15
  type VariablesOfDoc<Doc> = Doc extends StorefrontQueryString<infer _Result, infer Variables, string> ? Variables : Doc extends TadaDocumentNode<any, any> ? VariablesOf<Doc> : never;
16
16
  type StorefrontApiResultOf<Doc extends DocLike> = ResultOf<Doc>;
17
17
  type StorefrontApiVariablesOf<Doc extends DocLike> = VariablesOf<Doc>;
18
+ /**
19
+ * Minimal shape matching the GraphQL spec's error format, defined locally to
20
+ * avoid a runtime dependency on the `graphql` package.
21
+ *
22
+ * Present on the `errors` arm of {@link StorefrontGraphqlResult}.
23
+ */
18
24
  interface GraphQLFormattedError {
25
+ /** Human-readable error description. */
19
26
  readonly message: string;
27
+ /** Source locations in the query where the error originated. */
20
28
  readonly locations?: ReadonlyArray<{
21
29
  line: number;
22
30
  column: number;
23
31
  }>;
32
+ /** Response path to the field that triggered the error. */
24
33
  readonly path?: ReadonlyArray<string | number>;
34
+ /** Vendor extensions (e.g. Shopify error codes). */
25
35
  readonly extensions?: Record<string, unknown>;
26
36
  }
27
37
  type CommonOptions = {
28
- storeDomain: string;
38
+ /** Shopify store domain — e.g. `"my-store.myshopify.com"`. Normalized internally. */storeDomain: string;
29
39
  /**
30
40
  * Identifies the Hydrogen storefront making Storefront API requests so Shopify can attribute
31
41
  * cart analytics to the correct storefront.
@@ -38,9 +48,9 @@ type CommonOptions = {
38
48
  * `apiVersion` so version routing stays explicit. Hydrogen's bundled gql.tada schema still
39
49
  * controls type inference, so queries against fields outside that schema need their own typing.
40
50
  */
41
- apiVersion?: string;
42
- defaultTimeoutInMs?: number;
43
- cache?: CacheInstance;
51
+ apiVersion?: string; /** Per-request timeout in milliseconds. `0` disables the timeout. Defaults to 30,000 ms. */
52
+ defaultTimeoutInMs?: number; /** Shared cache instance that enables per-query caching via the `cache` option on `graphql()`. */
53
+ cache?: CacheInstance; /** Worker-style `waitUntil` to extend the request lifetime for background cache writes. */
44
54
  waitUntil?: WaitUntil;
45
55
  };
46
56
  type AnyFetch = typeof globalThis.fetch | ((...args: never[]) => Promise<Response>);
@@ -53,7 +63,9 @@ type AnyFetch = typeof globalThis.fetch | ((...args: never[]) => Promise<Respons
53
63
  * product tags, metaobjects, metafields, menus, and customers.
54
64
  */
55
65
  interface PublicClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
66
+ /** Custom fetch implementation. Falls back to `globalThis.fetch`. */
56
67
  fetch?: Fetch;
68
+ /** Public Storefront Access Token. Omit for tokenless access (limited fields). */
57
69
  publicStorefrontToken?: string | undefined;
58
70
  }
59
71
  /**
@@ -67,7 +79,9 @@ interface PublicClientOptions<Fetch extends AnyFetch | undefined = typeof global
67
79
  * product tags, metaobjects, metafields, menus, and customers.
68
80
  */
69
81
  interface PrivateClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
82
+ /** Custom fetch implementation. Falls back to `globalThis.fetch`. */
70
83
  fetch?: Fetch;
84
+ /** Private Storefront Access Token. Must never be exposed to browsers. */
71
85
  privateStorefrontToken: string;
72
86
  }
73
87
  /**
@@ -78,10 +92,20 @@ interface PrivateClientOptions<Fetch extends AnyFetch | undefined = typeof globa
78
92
  * shopper identity is available.
79
93
  */
80
94
  interface PrivateNoBuyerContextClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
95
+ /** Custom fetch implementation. Falls back to `globalThis.fetch`. */
81
96
  fetch?: Fetch;
97
+ /** Private Storefront Access Token. Must never be exposed to browsers. */
82
98
  privateStorefrontToken: string;
83
99
  }
100
+ /** Union of all config shapes passed as the `config` field of {@link CreateStorefrontClientArgs}. */
84
101
  type StorefrontClientOptions = PublicClientOptions | PrivateClientOptions | PrivateNoBuyerContextClientOptions;
102
+ /**
103
+ * Discriminated union accepted by `createStorefrontClient`.
104
+ *
105
+ * Discriminated on `type`: `"public"` requires a public (or no) token,
106
+ * `"private"` requires a private token plus a request context with `buyerIp`,
107
+ * and `"private_no_buyer_context"` requires a private token; `buyerIp` is not forwarded.
108
+ */
85
109
  type CreateStorefrontClientArgs<RequestContext extends ShopifyRequestContext = ShopifyRequestContext, Type extends ClientType = ClientType, CacheConfig extends CacheInstance | undefined = CacheInstance | undefined> = {
86
110
  type: "public" & Type;
87
111
  requestContext: RequestContext;
@@ -104,15 +128,38 @@ type CreateStorefrontClientArgs<RequestContext extends ShopifyRequestContext = S
104
128
  type AutoAddedVariableNames = "country" | "language";
105
129
  type UserVariables<Doc> = Omit<VariablesOfDoc<Doc>, AutoAddedVariableNames>;
106
130
  type HasNoRequiredKeys<T> = Record<string, never> extends T ? true : false;
131
+ /** Per-call options common to every `storefront.graphql()` invocation. */
107
132
  type StorefrontGraphqlOptions = {
108
- signal?: AbortSignal;
133
+ /** Abort signal forwarded to the underlying fetch. Combined with the request-context signal via `AbortSignal.any`. */signal?: AbortSignal;
109
134
  };
110
135
  type MergedOptions<Doc extends DocLike, Extra extends Record<string, unknown>> = Extra & StorefrontGraphqlOptions & (HasNoRequiredKeys<UserVariables<Doc>> extends true ? {
111
136
  variables?: UserVariables<Doc>;
112
137
  } : {
113
138
  variables: UserVariables<Doc>;
114
139
  });
140
+ /**
141
+ * Rest-parameter tuple for `storefront.graphql()`.
142
+ *
143
+ * Resolves to `[options]` (required) when the document declares required
144
+ * variables, or `[options?]` (optional) when all variables are optional or
145
+ * auto-injected (e.g. `$country`, `$language`).
146
+ */
115
147
  type GqlRestParam<Doc extends DocLike, Extra extends Record<string, unknown> = {}> = HasNoRequiredKeys<MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>> extends true ? [options?: MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>] : [options: MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>];
148
+ /**
149
+ * Discriminated union returned by `storefront.graphql()`.
150
+ *
151
+ * Discriminated on `errors`:
152
+ *
153
+ * - **No `errors`** — `data` is non-null and fully typed by the document.
154
+ * - **`errors` present** — `data` may be `null` (request-level error, or a non-null
155
+ * field error that propagated to the root) or
156
+ * partial (field-level error absorbed by a nullable ancestor). Always
157
+ * inspect `errors` first.
158
+ *
159
+ * `Partial` is deliberately not used: a non-null `data` never has absent
160
+ * top-level keys — failures surface as `null` values already covered by the
161
+ * schema types.
162
+ */
116
163
  type StorefrontGraphqlResult<Doc extends DocLike> = {
117
164
  data: ResultOfDoc<Doc>;
118
165
  errors?: undefined;
@@ -122,24 +169,58 @@ type StorefrontGraphqlResult<Doc extends DocLike> = {
122
169
  errors: GraphQLFormattedError[];
123
170
  headers: Headers;
124
171
  };
172
+ /** Base callable signature of `StorefrontClient.graphql` without per-client extra options. Accepts a `gql()` document or a plain string. */
125
173
  type StorefrontGraphql = <const Doc extends DocLike | string>(doc: Doc, ...options: GqlRestParam<ResolveDoc<Doc>>) => Promise<StorefrontGraphqlResult<ResolveDoc<Doc>>>;
126
174
  type ClientType = /** Public access token or tokenless access. Best for: browser requests. */"public" /** Private token with trusted buyer context. Best for: SSR. */ | "private" /** Private token without buyer context. Best for: background jobs, webhooks. */ | "private_no_buyer_context";
175
+ /**
176
+ * A type-safe Storefront API client returned by `createStorefrontClient`.
177
+ *
178
+ * Call `client.graphql(doc, options?)` to execute a query or mutation against
179
+ * the Storefront API. The result is typed by the document you pass in.
180
+ */
127
181
  type StorefrontClient<Extra extends Record<string, unknown> = {}, Type extends ClientType = ClientType, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = {
128
- type: Type;
182
+ /** Which client variant was created (`"public"`, `"private"`, or `"private_no_buyer_context"`). */type: Type; /** Resolved i18n config (country + language) used for automatic variable injection. */
129
183
  i18n: RequestContext["i18n"];
130
- graphql: <const Doc extends DocLike | string>(doc: Doc, ...options: GqlRestParam<ResolveDoc<Doc>, Extra>) => Promise<StorefrontGraphqlResult<ResolveDoc<Doc>>>;
131
- apiUrl: string;
132
- storeUrl: string;
133
- storefrontId?: string;
184
+ /**
185
+ * Execute a Storefront API GraphQL operation.
186
+ *
187
+ * Accepts a `gql()` document or a plain query string. Variables
188
+ * declared as `$country` / `$language` are auto-injected from the client's
189
+ * i18n config.
190
+ */
191
+ graphql: <const Doc extends DocLike | string>(doc: Doc, ...options: GqlRestParam<ResolveDoc<Doc>, Extra>) => Promise<StorefrontGraphqlResult<ResolveDoc<Doc>>>; /** Full Storefront API GraphQL endpoint URL. */
192
+ apiUrl: string; /** Normalized store URL (e.g. `"https://my-store.myshopify.com"`). */
193
+ storeUrl: string; /** Storefront identifier for cart analytics attribution, when provided. */
194
+ storefrontId?: string; /** The request context used for request-scoped headers, abort signals, and i18n. */
134
195
  requestContext: RequestContext;
135
196
  };
197
+ /** A {@link StorefrontClient} narrowed to `type: "public"`. */
136
198
  type PublicStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = StorefrontClient<Extra, "public", RequestContext>;
199
+ /** A {@link StorefrontClient} narrowed to `type: "private"`. Requires a request context with `buyerIp`. */
137
200
  type PrivateStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContextWithBuyerIp = ShopifyRequestContextWithBuyerIp> = StorefrontClient<Extra, "private", RequestContext>;
201
+ /** Convenience alias: a private client whose request context is always the concrete `ShopifyRequestContextWithBuyerIp`. */
138
202
  type RequestScopedPrivateStorefrontClient<Extra extends Record<string, unknown> = {}> = PrivateStorefrontClient<Extra, ShopifyRequestContextWithBuyerIp>;
203
+ /** A {@link StorefrontClient} narrowed to `type: "private_no_buyer_context"`. Best for background jobs and webhooks. */
139
204
  type PrivateNoBuyerContextStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = StorefrontClient<Extra, "private_no_buyer_context", RequestContext>;
205
+ /**
206
+ * Namespace for extracting result and variable types from Storefront API documents.
207
+ *
208
+ * @example
209
+ * ```ts
210
+ * import { gql, type StorefrontApi } from "@shopify/hydrogen";
211
+ *
212
+ * const PRODUCT_QUERY = gql(`query Product($handle: String!) { product(handle: $handle) { title } }`);
213
+ *
214
+ * type Product = StorefrontApi.ResultOf<typeof PRODUCT_QUERY>;
215
+ * type Vars = StorefrontApi.VariablesOf<typeof PRODUCT_QUERY>;
216
+ * ```
217
+ */
140
218
  declare namespace StorefrontApi {
219
+ /** Extracts the typed result shape from a Storefront API document. */
141
220
  type ResultOf<Doc extends DocLike> = StorefrontApiResultOf<Doc>;
221
+ /** Extracts the typed variables shape from a Storefront API document. */
142
222
  type VariablesOf<Doc extends DocLike> = StorefrontApiVariablesOf<Doc>;
223
+ /** A typed Storefront API document — a `gql()` document or a `TadaDocumentNode`. */
143
224
  type DocumentNode = DocLike;
144
225
  }
145
226
  //#endregion
@@ -2,6 +2,20 @@ import { CartStore } from "../cart/cart.mjs";
2
2
 
3
3
  //#region src/core/analytics/cart-tracker.d.ts
4
4
  type CartAnalyticsStore = Pick<CartStore, "getState" | "subscribe">;
5
+ /**
6
+ * Subscribes to a cart store and publishes analytics events when the cart changes.
7
+ *
8
+ * Emits `cart_updated` whenever a settled cart's `updatedAt` changes, plus
9
+ * `product_added_to_cart` / `product_removed_from_cart` for each line that was
10
+ * added, removed, or changed quantity. Deduplicates on `updatedAt` with an
11
+ * in-memory cursor (within this subscription) and `localStorage` (across full
12
+ * page loads and tabs). A store filled from your own cart query must select
13
+ * `updatedAt`, or deduplication can't work.
14
+ *
15
+ * @throws {Error} If `window.Shopify.analytics` is not set (including on the server).
16
+ * Render `ShopifyScripts` (or the `getShopifyScriptTags()` output) first.
17
+ * @returns An unsubscribe function that stops tracking.
18
+ */
5
19
  declare function trackCartAnalytics(store: CartAnalyticsStore): () => void;
6
20
  //#endregion
7
21
  export { trackCartAnalytics };
@@ -2,6 +2,20 @@ import { AnalyticsEvent } from "./events.mjs";
2
2
  import { flattenConnection } from "./utils/flatten-connection.mjs";
3
3
 
4
4
  //#region src/core/analytics/cart-tracker.ts
5
+ /**
6
+ * Subscribes to a cart store and publishes analytics events when the cart changes.
7
+ *
8
+ * Emits `cart_updated` whenever a settled cart's `updatedAt` changes, plus
9
+ * `product_added_to_cart` / `product_removed_from_cart` for each line that was
10
+ * added, removed, or changed quantity. Deduplicates on `updatedAt` with an
11
+ * in-memory cursor (within this subscription) and `localStorage` (across full
12
+ * page loads and tabs). A store filled from your own cart query must select
13
+ * `updatedAt`, or deduplication can't work.
14
+ *
15
+ * @throws {Error} If `window.Shopify.analytics` is not set (including on the server).
16
+ * Render `ShopifyScripts` (or the `getShopifyScriptTags()` output) first.
17
+ * @returns An unsubscribe function that stops tracking.
18
+ */
5
19
  function trackCartAnalytics(store) {
6
20
  const analytics = getGlobalAnalytics();
7
21
  const state = {
@@ -120,7 +134,7 @@ function hasPendingCartWork({ pending, revalidating }) {
120
134
  return revalidating === true || hasPendingCost || pending.note || pending.attributes;
121
135
  }
122
136
  function getCartUpdatedAt(cart) {
123
- return typeof cart.updatedAt === "string" ? cart.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
137
+ return cart.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
124
138
  }
125
139
  function syncShopifyCurrency(cart) {
126
140
  if (typeof window === "undefined") return;