@shopify/hydrogen 2026.4.5 → 2026.10.0-preview.2

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 (764) hide show
  1. package/README.md +73 -13
  2. package/bin/hydrogen.mjs +7 -0
  3. package/dist/cli/index.mjs +647 -0
  4. package/dist/client/client.d.mts +34 -0
  5. package/dist/client/client.mjs +206 -0
  6. package/dist/client/client.mjs.map +1 -0
  7. package/dist/client/errors.d.mts +48 -0
  8. package/dist/client/errors.mjs +52 -0
  9. package/dist/client/errors.mjs.map +1 -0
  10. package/dist/client/index.d.mts +4 -0
  11. package/dist/client/types.d.mts +147 -0
  12. package/dist/core/analytics/cart-tracker.d.mts +8 -0
  13. package/dist/core/analytics/cart-tracker.mjs +144 -0
  14. package/dist/core/analytics/cart-tracker.mjs.map +1 -0
  15. package/dist/core/analytics/events.d.mts +15 -0
  16. package/dist/core/analytics/events.mjs +15 -0
  17. package/dist/core/analytics/events.mjs.map +1 -0
  18. package/dist/core/analytics/index.d.mts +3 -0
  19. package/dist/core/analytics/types.d.mts +143 -0
  20. package/dist/core/analytics/utils/flatten-connection.d.mts +19 -0
  21. package/dist/core/analytics/utils/flatten-connection.mjs +25 -0
  22. package/dist/core/analytics/utils/flatten-connection.mjs.map +1 -0
  23. package/dist/core/cache/cache-status.mjs +17 -0
  24. package/dist/core/cache/cache-status.mjs.map +1 -0
  25. package/dist/core/cache/fetch-with-cache.d.mts +43 -0
  26. package/dist/core/cache/fetch-with-cache.mjs +188 -0
  27. package/dist/core/cache/fetch-with-cache.mjs.map +1 -0
  28. package/dist/core/cache/key.d.mts +6 -0
  29. package/dist/core/cache/key.mjs +27 -0
  30. package/dist/core/cache/key.mjs.map +1 -0
  31. package/dist/core/cache/run-with-cache.d.mts +36 -0
  32. package/dist/core/cache/run-with-cache.mjs +114 -0
  33. package/dist/core/cache/run-with-cache.mjs.map +1 -0
  34. package/dist/core/cache/store.d.mts +19 -0
  35. package/dist/core/cache/store.mjs +62 -0
  36. package/dist/core/cache/store.mjs.map +1 -0
  37. package/dist/core/cache/strategies.d.mts +39 -0
  38. package/dist/core/cache/strategies.mjs +70 -0
  39. package/dist/core/cache/strategies.mjs.map +1 -0
  40. package/dist/core/cart/actions.d.mts +50 -0
  41. package/dist/core/cart/actions.mjs +240 -0
  42. package/dist/core/cart/actions.mjs.map +1 -0
  43. package/dist/core/cart/attach-quantity-input.d.mts +5 -0
  44. package/dist/core/cart/attach-quantity-input.mjs +17 -0
  45. package/dist/core/cart/attach-quantity-input.mjs.map +1 -0
  46. package/dist/core/cart/buyer-identity-sync.d.mts +23 -0
  47. package/dist/core/cart/buyer-identity-sync.mjs +9 -0
  48. package/dist/core/cart/buyer-identity-sync.mjs.map +1 -0
  49. package/dist/core/cart/cart.d.mts +37 -0
  50. package/dist/core/cart/cart.mjs +1707 -0
  51. package/dist/core/cart/cart.mjs.map +1 -0
  52. package/dist/core/cart/cookie.d.mts +5 -0
  53. package/dist/core/cart/cookie.mjs +28 -0
  54. package/dist/core/cart/cookie.mjs.map +1 -0
  55. package/dist/core/cart/form.d.mts +130 -0
  56. package/dist/core/cart/form.mjs +75 -0
  57. package/dist/core/cart/form.mjs.map +1 -0
  58. package/dist/core/cart/get-cart.d.mts +25 -0
  59. package/dist/core/cart/get-cart.mjs +32 -0
  60. package/dist/core/cart/get-cart.mjs.map +1 -0
  61. package/dist/core/cart/index.d.mts +10 -0
  62. package/dist/core/cart/quantity.d.mts +10 -0
  63. package/dist/core/cart/quantity.mjs +14 -0
  64. package/dist/core/cart/quantity.mjs.map +1 -0
  65. package/dist/core/cart/queries.d.mts +4296 -0
  66. package/dist/core/cart/queries.mjs +70 -0
  67. package/dist/core/cart/queries.mjs.map +1 -0
  68. package/dist/core/cart/server-handlers.d.mts +82 -0
  69. package/dist/core/cart/server-handlers.mjs +322 -0
  70. package/dist/core/cart/server-handlers.mjs.map +1 -0
  71. package/dist/core/cart/state.d.mts +137 -0
  72. package/dist/core/cart/state.mjs +76 -0
  73. package/dist/core/cart/state.mjs.map +1 -0
  74. package/dist/core/cart/sync-quantity-inputs.mjs +16 -0
  75. package/dist/core/cart/sync-quantity-inputs.mjs.map +1 -0
  76. package/dist/core/collection/collection.d.mts +134 -0
  77. package/dist/core/collection/collection.mjs +170 -0
  78. package/dist/core/collection/collection.mjs.map +1 -0
  79. package/dist/core/collection/index.d.mts +6 -0
  80. package/dist/core/collection/reconciler.d.mts +32 -0
  81. package/dist/core/collection/reconciler.mjs +89 -0
  82. package/dist/core/collection/reconciler.mjs.map +1 -0
  83. package/dist/core/collection/state.d.mts +66 -0
  84. package/dist/core/collection/state.mjs +20 -0
  85. package/dist/core/collection/state.mjs.map +1 -0
  86. package/dist/core/collection/url.d.mts +71 -0
  87. package/dist/core/collection/url.mjs +376 -0
  88. package/dist/core/collection/url.mjs.map +1 -0
  89. package/dist/core/constants.d.mts +5 -0
  90. package/dist/core/constants.mjs +8 -0
  91. package/dist/core/constants.mjs.map +1 -0
  92. package/dist/core/headers.mjs +43 -0
  93. package/dist/core/headers.mjs.map +1 -0
  94. package/dist/core/index.d.mts +56 -0
  95. package/dist/core/index.mjs +45 -0
  96. package/dist/core/logging/logging.d.mts +21 -0
  97. package/dist/core/logging/logging.mjs +99 -0
  98. package/dist/core/logging/logging.mjs.map +1 -0
  99. package/dist/core/logging/types.d.mts +40 -0
  100. package/dist/core/logging/types.mjs +18 -0
  101. package/dist/core/logging/types.mjs.map +1 -0
  102. package/dist/core/money/cache.mjs +25 -0
  103. package/dist/core/money/cache.mjs.map +1 -0
  104. package/dist/core/money/format.d.mts +15 -0
  105. package/dist/core/money/format.mjs +243 -0
  106. package/dist/core/money/format.mjs.map +1 -0
  107. package/dist/core/money/types.d.mts +47 -0
  108. package/dist/core/observable.mjs +46 -0
  109. package/dist/core/observable.mjs.map +1 -0
  110. package/dist/core/predictive-search/constants.d.mts +5 -0
  111. package/dist/core/predictive-search/constants.mjs +6 -0
  112. package/dist/core/predictive-search/constants.mjs.map +1 -0
  113. package/dist/core/predictive-search/form.d.mts +31 -0
  114. package/dist/core/predictive-search/form.mjs +31 -0
  115. package/dist/core/predictive-search/form.mjs.map +1 -0
  116. package/dist/core/predictive-search/index.d.mts +6 -0
  117. package/dist/core/predictive-search/queries.d.mts +118 -0
  118. package/dist/core/predictive-search/queries.mjs +81 -0
  119. package/dist/core/predictive-search/queries.mjs.map +1 -0
  120. package/dist/core/predictive-search/search.d.mts +32 -0
  121. package/dist/core/predictive-search/search.mjs +74 -0
  122. package/dist/core/predictive-search/search.mjs.map +1 -0
  123. package/dist/core/predictive-search/server-handlers.d.mts +36 -0
  124. package/dist/core/predictive-search/server-handlers.mjs +113 -0
  125. package/dist/core/predictive-search/server-handlers.mjs.map +1 -0
  126. package/dist/core/predictive-search/store.d.mts +44 -0
  127. package/dist/core/predictive-search/store.mjs +224 -0
  128. package/dist/core/predictive-search/store.mjs.map +1 -0
  129. package/dist/core/predictive-search/url.d.mts +41 -0
  130. package/dist/core/predictive-search/url.mjs +71 -0
  131. package/dist/core/predictive-search/url.mjs.map +1 -0
  132. package/dist/core/product/accept-variant-id.mjs +98 -0
  133. package/dist/core/product/accept-variant-id.mjs.map +1 -0
  134. package/dist/core/product/form.d.mts +63 -0
  135. package/dist/core/product/form.mjs +44 -0
  136. package/dist/core/product/form.mjs.map +1 -0
  137. package/dist/core/product/index.d.mts +5 -0
  138. package/dist/core/product/options.d.mts +43 -0
  139. package/dist/core/product/options.mjs +296 -0
  140. package/dist/core/product/options.mjs.map +1 -0
  141. package/dist/core/product/product-form.d.mts +72 -0
  142. package/dist/core/product/product-form.mjs +158 -0
  143. package/dist/core/product/product-form.mjs.map +1 -0
  144. package/dist/core/product/state.d.mts +68 -0
  145. package/dist/core/product/url.d.mts +47 -0
  146. package/dist/core/product/url.mjs +69 -0
  147. package/dist/core/product/url.mjs.map +1 -0
  148. package/dist/core/request-context.d.mts +75 -0
  149. package/dist/core/request-context.mjs +141 -0
  150. package/dist/core/request-context.mjs.map +1 -0
  151. package/dist/core/request-routing/handle-shopify-redirects.d.mts +17 -0
  152. package/dist/core/request-routing/handle-shopify-redirects.mjs +31 -0
  153. package/dist/core/request-routing/handle-shopify-redirects.mjs.map +1 -0
  154. package/dist/core/request-routing/handle-shopify-routes.d.mts +14 -0
  155. package/dist/core/request-routing/handle-shopify-routes.mjs +42 -0
  156. package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -0
  157. package/dist/core/request-routing/interceptors/admin-redirect.mjs +12 -0
  158. package/dist/core/request-routing/interceptors/admin-redirect.mjs.map +1 -0
  159. package/dist/core/request-routing/interceptors/ajax-api.mjs +16 -0
  160. package/dist/core/request-routing/interceptors/ajax-api.mjs.map +1 -0
  161. package/dist/core/request-routing/interceptors/api-proxy.mjs +20 -0
  162. package/dist/core/request-routing/interceptors/api-proxy.mjs.map +1 -0
  163. package/dist/core/request-routing/interceptors/checkout.mjs +58 -0
  164. package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -0
  165. package/dist/core/request-routing/interceptors/mcp-proxy.mjs +23 -0
  166. package/dist/core/request-routing/interceptors/mcp-proxy.mjs.map +1 -0
  167. package/dist/core/request-routing/interceptors/proxy.mjs +73 -0
  168. package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -0
  169. package/dist/core/request-routing/interceptors/query-param-redirect.mjs +22 -0
  170. package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -0
  171. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +27 -0
  172. package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -0
  173. package/dist/core/request-routing/interceptors/standard-routes.mjs +19 -0
  174. package/dist/core/request-routing/interceptors/standard-routes.mjs.map +1 -0
  175. package/dist/core/request-routing/interceptors/url-redirects.mjs +27 -0
  176. package/dist/core/request-routing/interceptors/url-redirects.mjs.map +1 -0
  177. package/dist/core/request-routing/interceptors/well-known.mjs +22 -0
  178. package/dist/core/request-routing/interceptors/well-known.mjs.map +1 -0
  179. package/dist/core/request-routing/registered-routes.d.mts +7 -0
  180. package/dist/core/request-routing/registered-routes.mjs +72 -0
  181. package/dist/core/request-routing/registered-routes.mjs.map +1 -0
  182. package/dist/core/request-routing/route-types.d.mts +56 -0
  183. package/dist/core/request-routing/safe-apply-response-headers.mjs +16 -0
  184. package/dist/core/request-routing/safe-apply-response-headers.mjs.map +1 -0
  185. package/dist/core/shop-pay/shop-pay.d.mts +102 -0
  186. package/dist/core/shop-pay/shop-pay.mjs +289 -0
  187. package/dist/core/shop-pay/shop-pay.mjs.map +1 -0
  188. package/dist/core/shopify-scripts/analytics.mjs +26 -0
  189. package/dist/core/shopify-scripts/analytics.mjs.map +1 -0
  190. package/dist/core/shopify-scripts/consent.mjs +17 -0
  191. package/dist/core/shopify-scripts/consent.mjs.map +1 -0
  192. package/dist/core/shopify-scripts/constants.mjs +19 -0
  193. package/dist/core/shopify-scripts/constants.mjs.map +1 -0
  194. package/dist/core/shopify-scripts/deprecated-cookies.mjs +97 -0
  195. package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +1 -0
  196. package/dist/core/shopify-scripts/global.d.mts +1 -0
  197. package/dist/core/shopify-scripts/global.mjs +86 -0
  198. package/dist/core/shopify-scripts/global.mjs.map +1 -0
  199. package/dist/core/shopify-scripts/index.d.mts +27 -0
  200. package/dist/core/shopify-scripts/index.mjs +135 -0
  201. package/dist/core/shopify-scripts/index.mjs.map +1 -0
  202. package/dist/core/shopify-scripts/initialize.d.mts +18 -0
  203. package/dist/core/shopify-scripts/initialize.mjs +27 -0
  204. package/dist/core/shopify-scripts/initialize.mjs.map +1 -0
  205. package/dist/core/shopify-scripts/page-view.mjs +49 -0
  206. package/dist/core/shopify-scripts/page-view.mjs.map +1 -0
  207. package/dist/core/shopify-scripts/perfkit.mjs +33 -0
  208. package/dist/core/shopify-scripts/perfkit.mjs.map +1 -0
  209. package/dist/core/shopify-scripts/render.d.mts +1 -0
  210. package/dist/core/shopify-scripts/render.mjs +23 -0
  211. package/dist/core/shopify-scripts/render.mjs.map +1 -0
  212. package/dist/core/shopify-scripts/types.d.mts +76 -0
  213. package/dist/core/shopify-scripts/utils/cookie-domain.mjs +43 -0
  214. package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +1 -0
  215. package/dist/core/shopify-scripts/utils/inline-script.mjs +8 -0
  216. package/dist/core/shopify-scripts/utils/inline-script.mjs.map +1 -0
  217. package/dist/core/shopify-scripts/utils/navigation.mjs +46 -0
  218. package/dist/core/shopify-scripts/utils/navigation.mjs.map +1 -0
  219. package/dist/core/shopify-scripts/utils/tracking-values.mjs +65 -0
  220. package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +1 -0
  221. package/dist/core/shopify-scripts/utils/uuid.mjs +17 -0
  222. package/dist/core/shopify-scripts/utils/uuid.mjs.map +1 -0
  223. package/dist/core/shopify-scripts/webmcp.mjs +22 -0
  224. package/dist/core/shopify-scripts/webmcp.mjs.map +1 -0
  225. package/dist/core/standard-routes/build.d.mts +34 -0
  226. package/dist/core/standard-routes/build.mjs +54 -0
  227. package/dist/core/standard-routes/build.mjs.map +1 -0
  228. package/dist/core/standard-routes/defaults.mjs +31 -0
  229. package/dist/core/standard-routes/defaults.mjs.map +1 -0
  230. package/dist/core/standard-routes/match.mjs +108 -0
  231. package/dist/core/standard-routes/match.mjs.map +1 -0
  232. package/dist/core/standard-routes/path.mjs +58 -0
  233. package/dist/core/standard-routes/path.mjs.map +1 -0
  234. package/dist/core/standard-routes/redirects.mjs +51 -0
  235. package/dist/core/standard-routes/redirects.mjs.map +1 -0
  236. package/dist/core/standard-routes/types.d.mts +95 -0
  237. package/dist/core/url.mjs +42 -0
  238. package/dist/core/url.mjs.map +1 -0
  239. package/dist/core/utils/load-script.mjs +34 -0
  240. package/dist/core/utils/load-script.mjs.map +1 -0
  241. package/dist/core/utils/parse-gid.mjs +33 -0
  242. package/dist/core/utils/parse-gid.mjs.map +1 -0
  243. package/dist/core/utils/record.mjs +8 -0
  244. package/dist/core/utils/record.mjs.map +1 -0
  245. package/dist/customer-account/client.d.mts +50 -0
  246. package/dist/customer-account/client.mjs +239 -0
  247. package/dist/customer-account/client.mjs.map +1 -0
  248. package/dist/customer-account/errors.d.mts +28 -0
  249. package/dist/customer-account/errors.mjs +39 -0
  250. package/dist/customer-account/errors.mjs.map +1 -0
  251. package/dist/customer-account/graphql.d.mts +29 -0
  252. package/dist/customer-account/graphql.mjs +39 -0
  253. package/dist/customer-account/graphql.mjs.map +1 -0
  254. package/dist/customer-account/index.d.mts +7 -0
  255. package/dist/customer-account/index.mjs +7 -0
  256. package/dist/customer-account/session.d.mts +117 -0
  257. package/dist/customer-account/session.mjs +733 -0
  258. package/dist/customer-account/session.mjs.map +1 -0
  259. package/dist/customer-account/type-resolver.d.mts +11 -0
  260. package/dist/customer-account-api-types.d.ts +3269 -3270
  261. package/dist/customer-account.schema.json +50753 -1
  262. package/dist/development/_virtual/_@oxc-project_runtime@0.127.0/helpers/taggedTemplateLiteral.mjs +7 -0
  263. package/dist/development/client/client.d.mts +34 -0
  264. package/dist/development/client/client.mjs +206 -0
  265. package/dist/development/client/client.mjs.map +1 -0
  266. package/dist/development/client/errors.d.mts +48 -0
  267. package/dist/development/client/errors.mjs +57 -0
  268. package/dist/development/client/errors.mjs.map +1 -0
  269. package/dist/development/client/index.d.mts +4 -0
  270. package/dist/development/client/types.d.mts +147 -0
  271. package/dist/development/core/analytics/cart-tracker.d.mts +8 -0
  272. package/dist/development/core/analytics/cart-tracker.mjs +144 -0
  273. package/dist/development/core/analytics/cart-tracker.mjs.map +1 -0
  274. package/dist/development/core/analytics/events.d.mts +15 -0
  275. package/dist/development/core/analytics/events.mjs +15 -0
  276. package/dist/development/core/analytics/events.mjs.map +1 -0
  277. package/dist/development/core/analytics/index.d.mts +3 -0
  278. package/dist/development/core/analytics/types.d.mts +143 -0
  279. package/dist/development/core/analytics/utils/flatten-connection.d.mts +19 -0
  280. package/dist/development/core/analytics/utils/flatten-connection.mjs +25 -0
  281. package/dist/development/core/analytics/utils/flatten-connection.mjs.map +1 -0
  282. package/dist/development/core/cache/cache-status.mjs +17 -0
  283. package/dist/development/core/cache/cache-status.mjs.map +1 -0
  284. package/dist/development/core/cache/fetch-with-cache.d.mts +43 -0
  285. package/dist/development/core/cache/fetch-with-cache.mjs +188 -0
  286. package/dist/development/core/cache/fetch-with-cache.mjs.map +1 -0
  287. package/dist/development/core/cache/key.d.mts +6 -0
  288. package/dist/development/core/cache/key.mjs +27 -0
  289. package/dist/development/core/cache/key.mjs.map +1 -0
  290. package/dist/development/core/cache/run-with-cache.d.mts +36 -0
  291. package/dist/development/core/cache/run-with-cache.mjs +114 -0
  292. package/dist/development/core/cache/run-with-cache.mjs.map +1 -0
  293. package/dist/development/core/cache/store.d.mts +19 -0
  294. package/dist/development/core/cache/store.mjs +62 -0
  295. package/dist/development/core/cache/store.mjs.map +1 -0
  296. package/dist/development/core/cache/strategies.d.mts +39 -0
  297. package/dist/development/core/cache/strategies.mjs +70 -0
  298. package/dist/development/core/cache/strategies.mjs.map +1 -0
  299. package/dist/development/core/cart/actions.d.mts +50 -0
  300. package/dist/development/core/cart/actions.mjs +240 -0
  301. package/dist/development/core/cart/actions.mjs.map +1 -0
  302. package/dist/development/core/cart/attach-quantity-input.d.mts +5 -0
  303. package/dist/development/core/cart/attach-quantity-input.mjs +17 -0
  304. package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -0
  305. package/dist/development/core/cart/buyer-identity-sync.d.mts +19 -0
  306. package/dist/development/core/cart/buyer-identity-sync.mjs +6 -0
  307. package/dist/development/core/cart/buyer-identity-sync.mjs.map +1 -0
  308. package/dist/development/core/cart/cart.d.mts +37 -0
  309. package/dist/development/core/cart/cart.mjs +1707 -0
  310. package/dist/development/core/cart/cart.mjs.map +1 -0
  311. package/dist/development/core/cart/cookie.d.mts +5 -0
  312. package/dist/development/core/cart/cookie.mjs +28 -0
  313. package/dist/development/core/cart/cookie.mjs.map +1 -0
  314. package/dist/development/core/cart/form.d.mts +130 -0
  315. package/dist/development/core/cart/form.mjs +75 -0
  316. package/dist/development/core/cart/form.mjs.map +1 -0
  317. package/dist/development/core/cart/get-cart.d.mts +25 -0
  318. package/dist/development/core/cart/get-cart.mjs +32 -0
  319. package/dist/development/core/cart/get-cart.mjs.map +1 -0
  320. package/dist/development/core/cart/index.d.mts +10 -0
  321. package/dist/development/core/cart/quantity.d.mts +10 -0
  322. package/dist/development/core/cart/quantity.mjs +14 -0
  323. package/dist/development/core/cart/quantity.mjs.map +1 -0
  324. package/dist/development/core/cart/queries.d.mts +4296 -0
  325. package/dist/development/core/cart/queries.mjs +70 -0
  326. package/dist/development/core/cart/queries.mjs.map +1 -0
  327. package/dist/development/core/cart/server-handlers.d.mts +82 -0
  328. package/dist/development/core/cart/server-handlers.mjs +322 -0
  329. package/dist/development/core/cart/server-handlers.mjs.map +1 -0
  330. package/dist/development/core/cart/state.d.mts +137 -0
  331. package/dist/development/core/cart/state.mjs +76 -0
  332. package/dist/development/core/cart/state.mjs.map +1 -0
  333. package/dist/development/core/cart/sync-quantity-inputs.mjs +16 -0
  334. package/dist/development/core/cart/sync-quantity-inputs.mjs.map +1 -0
  335. package/dist/development/core/collection/collection.d.mts +134 -0
  336. package/dist/development/core/collection/collection.mjs +170 -0
  337. package/dist/development/core/collection/collection.mjs.map +1 -0
  338. package/dist/development/core/collection/index.d.mts +6 -0
  339. package/dist/development/core/collection/reconciler.d.mts +32 -0
  340. package/dist/development/core/collection/reconciler.mjs +89 -0
  341. package/dist/development/core/collection/reconciler.mjs.map +1 -0
  342. package/dist/development/core/collection/state.d.mts +66 -0
  343. package/dist/development/core/collection/state.mjs +20 -0
  344. package/dist/development/core/collection/state.mjs.map +1 -0
  345. package/dist/development/core/collection/url.d.mts +71 -0
  346. package/dist/development/core/collection/url.mjs +376 -0
  347. package/dist/development/core/collection/url.mjs.map +1 -0
  348. package/dist/development/core/constants.mjs +7 -0
  349. package/dist/development/core/constants.mjs.map +1 -0
  350. package/dist/development/core/development.d.mts +56 -0
  351. package/dist/development/core/development.mjs +45 -0
  352. package/dist/development/core/headers.mjs +43 -0
  353. package/dist/development/core/headers.mjs.map +1 -0
  354. package/dist/development/core/index.d.mts +54 -0
  355. package/dist/development/core/logging/logging.d.mts +21 -0
  356. package/dist/development/core/logging/logging.mjs +99 -0
  357. package/dist/development/core/logging/logging.mjs.map +1 -0
  358. package/dist/development/core/logging/types.d.mts +40 -0
  359. package/dist/development/core/logging/types.mjs +18 -0
  360. package/dist/development/core/logging/types.mjs.map +1 -0
  361. package/dist/development/core/money/cache.mjs +25 -0
  362. package/dist/development/core/money/cache.mjs.map +1 -0
  363. package/dist/development/core/money/format.d.mts +15 -0
  364. package/dist/development/core/money/format.mjs +243 -0
  365. package/dist/development/core/money/format.mjs.map +1 -0
  366. package/dist/development/core/money/types.d.mts +47 -0
  367. package/dist/development/core/observable.mjs +46 -0
  368. package/dist/development/core/observable.mjs.map +1 -0
  369. package/dist/development/core/predictive-search/constants.d.mts +5 -0
  370. package/dist/development/core/predictive-search/constants.mjs +6 -0
  371. package/dist/development/core/predictive-search/constants.mjs.map +1 -0
  372. package/dist/development/core/predictive-search/form.d.mts +31 -0
  373. package/dist/development/core/predictive-search/form.mjs +31 -0
  374. package/dist/development/core/predictive-search/form.mjs.map +1 -0
  375. package/dist/development/core/predictive-search/index.d.mts +6 -0
  376. package/dist/development/core/predictive-search/queries.d.mts +118 -0
  377. package/dist/development/core/predictive-search/queries.mjs +81 -0
  378. package/dist/development/core/predictive-search/queries.mjs.map +1 -0
  379. package/dist/development/core/predictive-search/search.d.mts +32 -0
  380. package/dist/development/core/predictive-search/search.mjs +74 -0
  381. package/dist/development/core/predictive-search/search.mjs.map +1 -0
  382. package/dist/development/core/predictive-search/server-handlers.d.mts +36 -0
  383. package/dist/development/core/predictive-search/server-handlers.mjs +113 -0
  384. package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -0
  385. package/dist/development/core/predictive-search/store.d.mts +44 -0
  386. package/dist/development/core/predictive-search/store.mjs +224 -0
  387. package/dist/development/core/predictive-search/store.mjs.map +1 -0
  388. package/dist/development/core/predictive-search/url.d.mts +41 -0
  389. package/dist/development/core/predictive-search/url.mjs +71 -0
  390. package/dist/development/core/predictive-search/url.mjs.map +1 -0
  391. package/dist/development/core/product/accept-variant-id.mjs +98 -0
  392. package/dist/development/core/product/accept-variant-id.mjs.map +1 -0
  393. package/dist/development/core/product/form.d.mts +63 -0
  394. package/dist/development/core/product/form.mjs +44 -0
  395. package/dist/development/core/product/form.mjs.map +1 -0
  396. package/dist/development/core/product/index.d.mts +5 -0
  397. package/dist/development/core/product/options.d.mts +43 -0
  398. package/dist/development/core/product/options.mjs +296 -0
  399. package/dist/development/core/product/options.mjs.map +1 -0
  400. package/dist/development/core/product/product-form.d.mts +72 -0
  401. package/dist/development/core/product/product-form.mjs +158 -0
  402. package/dist/development/core/product/product-form.mjs.map +1 -0
  403. package/dist/development/core/product/state.d.mts +68 -0
  404. package/dist/development/core/product/url.d.mts +47 -0
  405. package/dist/development/core/product/url.mjs +69 -0
  406. package/dist/development/core/product/url.mjs.map +1 -0
  407. package/dist/development/core/request-context.d.mts +75 -0
  408. package/dist/development/core/request-context.mjs +141 -0
  409. package/dist/development/core/request-context.mjs.map +1 -0
  410. package/dist/development/core/request-routing/handle-shopify-redirects.d.mts +17 -0
  411. package/dist/development/core/request-routing/handle-shopify-redirects.mjs +31 -0
  412. package/dist/development/core/request-routing/handle-shopify-redirects.mjs.map +1 -0
  413. package/dist/development/core/request-routing/handle-shopify-routes.d.mts +1 -0
  414. package/dist/development/core/request-routing/handle-shopify-routes.development.d.mts +11 -0
  415. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs +16 -0
  416. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs.map +1 -0
  417. package/dist/development/core/request-routing/handle-shopify-routes.mjs +42 -0
  418. package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -0
  419. package/dist/development/core/request-routing/interceptors/admin-redirect.mjs +12 -0
  420. package/dist/development/core/request-routing/interceptors/admin-redirect.mjs.map +1 -0
  421. package/dist/development/core/request-routing/interceptors/ajax-api.mjs +16 -0
  422. package/dist/development/core/request-routing/interceptors/ajax-api.mjs.map +1 -0
  423. package/dist/development/core/request-routing/interceptors/api-proxy.mjs +20 -0
  424. package/dist/development/core/request-routing/interceptors/api-proxy.mjs.map +1 -0
  425. package/dist/development/core/request-routing/interceptors/checkout.mjs +58 -0
  426. package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -0
  427. package/dist/development/core/request-routing/interceptors/graphiql.mjs +46 -0
  428. package/dist/development/core/request-routing/interceptors/graphiql.mjs.map +1 -0
  429. package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +23 -0
  430. package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs.map +1 -0
  431. package/dist/development/core/request-routing/interceptors/proxy.mjs +73 -0
  432. package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -0
  433. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +22 -0
  434. package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -0
  435. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +27 -0
  436. package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -0
  437. package/dist/development/core/request-routing/interceptors/standard-routes.mjs +19 -0
  438. package/dist/development/core/request-routing/interceptors/standard-routes.mjs.map +1 -0
  439. package/dist/development/core/request-routing/interceptors/url-redirects.mjs +27 -0
  440. package/dist/development/core/request-routing/interceptors/url-redirects.mjs.map +1 -0
  441. package/dist/development/core/request-routing/interceptors/well-known.mjs +22 -0
  442. package/dist/development/core/request-routing/interceptors/well-known.mjs.map +1 -0
  443. package/dist/development/core/request-routing/registered-routes.d.mts +7 -0
  444. package/dist/development/core/request-routing/registered-routes.mjs +72 -0
  445. package/dist/development/core/request-routing/registered-routes.mjs.map +1 -0
  446. package/dist/development/core/request-routing/route-types.d.mts +56 -0
  447. package/dist/development/core/request-routing/safe-apply-response-headers.mjs +16 -0
  448. package/dist/development/core/request-routing/safe-apply-response-headers.mjs.map +1 -0
  449. package/dist/development/core/shop-pay/shop-pay.d.mts +102 -0
  450. package/dist/development/core/shop-pay/shop-pay.mjs +289 -0
  451. package/dist/development/core/shop-pay/shop-pay.mjs.map +1 -0
  452. package/dist/development/core/shopify-scripts/analytics.mjs +26 -0
  453. package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -0
  454. package/dist/development/core/shopify-scripts/consent.mjs +17 -0
  455. package/dist/development/core/shopify-scripts/consent.mjs.map +1 -0
  456. package/dist/development/core/shopify-scripts/constants.mjs +19 -0
  457. package/dist/development/core/shopify-scripts/constants.mjs.map +1 -0
  458. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +97 -0
  459. package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +1 -0
  460. package/dist/development/core/shopify-scripts/global.d.mts +1 -0
  461. package/dist/development/core/shopify-scripts/global.mjs +86 -0
  462. package/dist/development/core/shopify-scripts/global.mjs.map +1 -0
  463. package/dist/development/core/shopify-scripts/index.d.mts +27 -0
  464. package/dist/development/core/shopify-scripts/index.mjs +145 -0
  465. package/dist/development/core/shopify-scripts/index.mjs.map +1 -0
  466. package/dist/development/core/shopify-scripts/initialize.d.mts +18 -0
  467. package/dist/development/core/shopify-scripts/initialize.mjs +27 -0
  468. package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -0
  469. package/dist/development/core/shopify-scripts/page-view.mjs +49 -0
  470. package/dist/development/core/shopify-scripts/page-view.mjs.map +1 -0
  471. package/dist/development/core/shopify-scripts/perfkit.mjs +33 -0
  472. package/dist/development/core/shopify-scripts/perfkit.mjs.map +1 -0
  473. package/dist/development/core/shopify-scripts/render.d.mts +1 -0
  474. package/dist/development/core/shopify-scripts/render.mjs +23 -0
  475. package/dist/development/core/shopify-scripts/render.mjs.map +1 -0
  476. package/dist/development/core/shopify-scripts/types.d.mts +76 -0
  477. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +43 -0
  478. package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +1 -0
  479. package/dist/development/core/shopify-scripts/utils/inline-script.mjs +8 -0
  480. package/dist/development/core/shopify-scripts/utils/inline-script.mjs.map +1 -0
  481. package/dist/development/core/shopify-scripts/utils/navigation.mjs +46 -0
  482. package/dist/development/core/shopify-scripts/utils/navigation.mjs.map +1 -0
  483. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +65 -0
  484. package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +1 -0
  485. package/dist/development/core/shopify-scripts/utils/uuid.mjs +17 -0
  486. package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +1 -0
  487. package/dist/development/core/shopify-scripts/webmcp.mjs +22 -0
  488. package/dist/development/core/shopify-scripts/webmcp.mjs.map +1 -0
  489. package/dist/development/core/standard-routes/build.d.mts +34 -0
  490. package/dist/development/core/standard-routes/build.mjs +54 -0
  491. package/dist/development/core/standard-routes/build.mjs.map +1 -0
  492. package/dist/development/core/standard-routes/defaults.mjs +31 -0
  493. package/dist/development/core/standard-routes/defaults.mjs.map +1 -0
  494. package/dist/development/core/standard-routes/match.mjs +108 -0
  495. package/dist/development/core/standard-routes/match.mjs.map +1 -0
  496. package/dist/development/core/standard-routes/path.mjs +58 -0
  497. package/dist/development/core/standard-routes/path.mjs.map +1 -0
  498. package/dist/development/core/standard-routes/redirects.mjs +51 -0
  499. package/dist/development/core/standard-routes/redirects.mjs.map +1 -0
  500. package/dist/development/core/standard-routes/types.d.mts +95 -0
  501. package/dist/development/core/types.d.mts +11 -0
  502. package/dist/development/core/url.mjs +42 -0
  503. package/dist/development/core/url.mjs.map +1 -0
  504. package/dist/development/core/utils/load-script.mjs +34 -0
  505. package/dist/development/core/utils/load-script.mjs.map +1 -0
  506. package/dist/development/core/utils/parse-gid.mjs +33 -0
  507. package/dist/development/core/utils/parse-gid.mjs.map +1 -0
  508. package/dist/development/customer-account/session.d.mts +46 -0
  509. package/dist/development/customer-account/session.mjs +21 -0
  510. package/dist/development/customer-account/session.mjs.map +1 -0
  511. package/dist/development/globals.d.mts +64 -0
  512. package/dist/development/graphql/generated/customer-account-api-types.d.mts +13 -0
  513. package/dist/development/graphql/generated/graphql-env.d.mts +19280 -0
  514. package/dist/development/graphql/generated/storefront-api-types.d.mts +47 -0
  515. package/dist/development/graphql/graphql.d.mts +40 -0
  516. package/dist/development/graphql/graphql.mjs +16 -0
  517. package/dist/development/graphql/graphql.mjs.map +1 -0
  518. package/dist/development/graphql/index.d.mts +2 -0
  519. package/dist/development/graphql/scalars.d.mts +15 -0
  520. package/dist/development/graphql/type-resolver.d.mts +229 -0
  521. package/dist/development/react/cart.d.mts +44 -0
  522. package/dist/development/react/cart.mjs +155 -0
  523. package/dist/development/react/cart.mjs.map +1 -0
  524. package/dist/development/react/collection.d.mts +91 -0
  525. package/dist/development/react/collection.mjs +129 -0
  526. package/dist/development/react/collection.mjs.map +1 -0
  527. package/dist/development/react/index.d.mts +13 -0
  528. package/dist/development/react/index.mjs +10 -0
  529. package/dist/development/react/predictive-search.d.mts +49 -0
  530. package/dist/development/react/predictive-search.mjs +133 -0
  531. package/dist/development/react/predictive-search.mjs.map +1 -0
  532. package/dist/development/react/product.d.mts +72 -0
  533. package/dist/development/react/product.mjs +127 -0
  534. package/dist/development/react/product.mjs.map +1 -0
  535. package/dist/development/react/shop-pay.d.mts +9 -0
  536. package/dist/development/react/shop-pay.mjs +16 -0
  537. package/dist/development/react/shop-pay.mjs.map +1 -0
  538. package/dist/development/react/shopify-scripts.d.mts +20 -0
  539. package/dist/development/react/shopify-scripts.mjs +39 -0
  540. package/dist/development/react/shopify-scripts.mjs.map +1 -0
  541. package/dist/development/vendor/standard-actions.d.mts +134 -0
  542. package/dist/development/vendor/standard-events.d.mts +1107 -0
  543. package/dist/development/vue/cart.d.mts +46 -0
  544. package/dist/development/vue/cart.mjs +122 -0
  545. package/dist/development/vue/cart.mjs.map +1 -0
  546. package/dist/development/vue/collection.d.mts +46 -0
  547. package/dist/development/vue/collection.mjs +108 -0
  548. package/dist/development/vue/collection.mjs.map +1 -0
  549. package/dist/development/vue/index.d.mts +11 -0
  550. package/dist/development/vue/index.mjs +8 -0
  551. package/dist/development/vue/predictive-search.d.mts +124 -0
  552. package/dist/development/vue/predictive-search.mjs +171 -0
  553. package/dist/development/vue/predictive-search.mjs.map +1 -0
  554. package/dist/development/vue/product.d.mts +57 -0
  555. package/dist/development/vue/product.mjs +167 -0
  556. package/dist/development/vue/product.mjs.map +1 -0
  557. package/dist/development/vue/shop-pay.d.mts +25 -0
  558. package/dist/development/vue/shop-pay.mjs +35 -0
  559. package/dist/development/vue/shop-pay.mjs.map +1 -0
  560. package/dist/development/vue/shopify-scripts.d.mts +127 -0
  561. package/dist/development/vue/shopify-scripts.mjs +79 -0
  562. package/dist/development/vue/shopify-scripts.mjs.map +1 -0
  563. package/dist/globals.d.mts +64 -0
  564. package/dist/graphql/generated/customer-account-api-types.d.mts +13 -0
  565. package/dist/graphql/generated/customer-account-graphql-env.d.mts +22170 -0
  566. package/dist/graphql/generated/graphql-env.d.mts +19280 -0
  567. package/dist/graphql/generated/storefront-api-types.d.mts +47 -0
  568. package/dist/graphql/graphql.d.mts +40 -0
  569. package/dist/graphql/graphql.mjs +16 -0
  570. package/dist/graphql/graphql.mjs.map +1 -0
  571. package/dist/graphql/index.d.mts +2 -0
  572. package/dist/graphql/scalars.d.mts +26 -0
  573. package/dist/graphql/type-resolver.d.mts +229 -0
  574. package/dist/react/cart.d.mts +44 -0
  575. package/dist/react/cart.mjs +155 -0
  576. package/dist/react/cart.mjs.map +1 -0
  577. package/dist/react/collection.d.mts +91 -0
  578. package/dist/react/collection.mjs +129 -0
  579. package/dist/react/collection.mjs.map +1 -0
  580. package/dist/react/index.d.mts +13 -0
  581. package/dist/react/index.mjs +10 -0
  582. package/dist/react/predictive-search.d.mts +49 -0
  583. package/dist/react/predictive-search.mjs +133 -0
  584. package/dist/react/predictive-search.mjs.map +1 -0
  585. package/dist/react/product.d.mts +72 -0
  586. package/dist/react/product.mjs +127 -0
  587. package/dist/react/product.mjs.map +1 -0
  588. package/dist/react/shop-pay.d.mts +9 -0
  589. package/dist/react/shop-pay.mjs +16 -0
  590. package/dist/react/shop-pay.mjs.map +1 -0
  591. package/dist/react/shopify-scripts.d.mts +20 -0
  592. package/dist/react/shopify-scripts.mjs +39 -0
  593. package/dist/react/shopify-scripts.mjs.map +1 -0
  594. package/dist/storefront-api-types.d.ts +2351 -2390
  595. package/dist/storefront.schema.json +41534 -1
  596. package/dist/ts-plugin/index.cjs +68 -0
  597. package/dist/ts-plugin/index.cjs.map +1 -0
  598. package/dist/ts-plugin/index.d.cts +4 -0
  599. package/dist/vendor/standard-actions.d.mts +134 -0
  600. package/dist/vendor/standard-events.d.mts +1107 -0
  601. package/dist/vite/certificate-prompt.mjs +24 -0
  602. package/dist/vite/certificate-prompt.mjs.map +1 -0
  603. package/dist/vite/index.d.mts +2 -0
  604. package/dist/vite/index.mjs +3 -0
  605. package/dist/vite/local-https.d.mts +47 -0
  606. package/dist/vite/local-https.mjs +276 -0
  607. package/dist/vite/local-https.mjs.map +1 -0
  608. package/dist/vite/mkcert.mjs +141 -0
  609. package/dist/vite/mkcert.mjs.map +1 -0
  610. package/dist/vue/cart.d.mts +46 -0
  611. package/dist/vue/cart.mjs +122 -0
  612. package/dist/vue/cart.mjs.map +1 -0
  613. package/dist/vue/collection.d.mts +46 -0
  614. package/dist/vue/collection.mjs +108 -0
  615. package/dist/vue/collection.mjs.map +1 -0
  616. package/dist/vue/index.d.mts +11 -0
  617. package/dist/vue/index.mjs +8 -0
  618. package/dist/vue/predictive-search.d.mts +124 -0
  619. package/dist/vue/predictive-search.mjs +171 -0
  620. package/dist/vue/predictive-search.mjs.map +1 -0
  621. package/dist/vue/product.d.mts +57 -0
  622. package/dist/vue/product.mjs +167 -0
  623. package/dist/vue/product.mjs.map +1 -0
  624. package/dist/vue/shop-pay.d.mts +25 -0
  625. package/dist/vue/shop-pay.mjs +35 -0
  626. package/dist/vue/shop-pay.mjs.map +1 -0
  627. package/dist/vue/shopify-scripts.d.mts +127 -0
  628. package/dist/vue/shopify-scripts.mjs +79 -0
  629. package/dist/vue/shopify-scripts.mjs.map +1 -0
  630. package/package.json +116 -86
  631. package/skills/hydrogen-analytics/SKILL.md +80 -0
  632. package/skills/hydrogen-analytics/references/react.md +160 -0
  633. package/skills/hydrogen-analytics/references/vue.md +80 -0
  634. package/skills/hydrogen-cart-drawer/SKILL.md +248 -0
  635. package/skills/hydrogen-cart-drawer/references/accessibility.md +109 -0
  636. package/skills/hydrogen-cart-drawer/references/css.md +67 -0
  637. package/skills/hydrogen-cart-ui/SKILL.md +224 -0
  638. package/skills/hydrogen-cart-ui/references/nextjs.md +89 -0
  639. package/skills/hydrogen-cart-ui/references/react.md +285 -0
  640. package/skills/hydrogen-cart-ui/references/vue.md +228 -0
  641. package/skills/hydrogen-collection-browser/SKILL.md +83 -0
  642. package/skills/hydrogen-collection-browser/references/nextjs.md +118 -0
  643. package/skills/hydrogen-collection-browser/references/nuxt.md +108 -0
  644. package/skills/hydrogen-collection-browser/references/react.md +301 -0
  645. package/skills/hydrogen-customer-account/SKILL.md +107 -0
  646. package/skills/hydrogen-image/SKILL.md +65 -0
  647. package/skills/hydrogen-local-https/SKILL.md +142 -0
  648. package/skills/hydrogen-markets/SKILL.md +221 -0
  649. package/skills/hydrogen-markets/references/nextjs.md +157 -0
  650. package/skills/hydrogen-money/SKILL.md +67 -0
  651. package/skills/hydrogen-oxygen/SKILL.md +245 -0
  652. package/skills/hydrogen-oxygen/references/react-router.md +230 -0
  653. package/skills/hydrogen-predictive-search/SKILL.md +130 -0
  654. package/skills/hydrogen-predictive-search/references/react.md +32 -0
  655. package/skills/hydrogen-predictive-search/references/vue.md +40 -0
  656. package/skills/hydrogen-request-handlers/SKILL.md +107 -0
  657. package/skills/hydrogen-request-handlers/references/frameworks.md +179 -0
  658. package/skills/hydrogen-request-handlers/references/nextjs.md +137 -0
  659. package/skills/hydrogen-request-handlers/references/nuxt.md +215 -0
  660. package/skills/hydrogen-routing/SKILL.md +171 -0
  661. package/skills/hydrogen-setup/SKILL.md +50 -0
  662. package/skills/hydrogen-setup/references/analytics.md +624 -0
  663. package/skills/hydrogen-setup/steps/1-inspect-app.md +62 -0
  664. package/skills/hydrogen-setup/steps/10-analytics.md +10 -0
  665. package/skills/hydrogen-setup/steps/11-verify.md +31 -0
  666. package/skills/hydrogen-setup/steps/2-scaffold.md +86 -0
  667. package/skills/hydrogen-setup/steps/3-build-home-page.md +37 -0
  668. package/skills/hydrogen-setup/steps/4-collection-and-search.md +14 -0
  669. package/skills/hydrogen-setup/steps/5-cart.md +10 -0
  670. package/skills/hydrogen-setup/steps/6-product-detail-page.md +416 -0
  671. package/skills/hydrogen-setup/steps/7-shopify-runtime-scripts.md +69 -0
  672. package/skills/hydrogen-setup/steps/8-cart-drawer-and-navbar.md +35 -0
  673. package/skills/hydrogen-setup/steps/9-account-page.md +54 -0
  674. package/skills/hydrogen-shop-pay/SKILL.md +79 -0
  675. package/skills/hydrogen-shop-pay/references/core.md +66 -0
  676. package/skills/hydrogen-shop-pay/references/react.md +50 -0
  677. package/skills/hydrogen-shop-pay/references/vue.md +39 -0
  678. package/skills/hydrogen-smoke-test/SKILL.md +205 -0
  679. package/skills/hydrogen-storefront-client/SKILL.md +322 -0
  680. package/skills/hydrogen-storefront-client/references/astro.md +125 -0
  681. package/skills/hydrogen-storefront-client/references/caching.md +25 -0
  682. package/skills/hydrogen-storefront-client/references/nextjs.md +121 -0
  683. package/skills/hydrogen-storefront-client/references/nuxt.md +121 -0
  684. package/skills/hydrogen-storefront-client/references/query-validation.md +95 -0
  685. package/skills/hydrogen-storefront-client/references/react-router.md +81 -0
  686. package/skills/hydrogen-storefront-client/references/solidstart.md +131 -0
  687. package/skills/hydrogen-storefront-client/references/sveltekit.md +169 -0
  688. package/skills/hydrogen-variant-form/SKILL.md +267 -0
  689. package/skills/hydrogen-variant-form/references/nextjs.md +207 -0
  690. package/skills/hydrogen-variant-form/references/nuxt.md +95 -0
  691. package/skills/hydrogen-variant-form/references/react.md +71 -0
  692. package/dist/dev/get-virtual-routes-H72465VB.js +0 -74
  693. package/dist/dev/hydrogen-routes.d.ts +0 -5
  694. package/dist/dev/hydrogen-routes.js +0 -25
  695. package/dist/development/get-virtual-routes-ACFZHU42.js +0 -71
  696. package/dist/development/get-virtual-routes-ACFZHU42.js.map +0 -1
  697. package/dist/development/index.cjs +0 -6978
  698. package/dist/development/index.cjs.map +0 -1
  699. package/dist/development/index.js +0 -6631
  700. package/dist/development/index.js.map +0 -1
  701. package/dist/development/log-seo-tags-IG37ONQ2.js +0 -74
  702. package/dist/development/log-seo-tags-IG37ONQ2.js.map +0 -1
  703. package/dist/development/react-router-preset.d.ts +0 -45
  704. package/dist/development/react-router-preset.js +0 -49
  705. package/dist/development/react-router-preset.js.map +0 -1
  706. package/dist/index.cjs +0 -1
  707. package/dist/oxygen/index.d.ts +0 -197
  708. package/dist/oxygen/index.js +0 -107
  709. package/dist/production/get-virtual-routes-ZZEGQQDV.js +0 -3
  710. package/dist/production/get-virtual-routes-ZZEGQQDV.js.map +0 -1
  711. package/dist/production/index.cjs +0 -1019
  712. package/dist/production/index.cjs.map +0 -1
  713. package/dist/production/index.d.cts +0 -3260
  714. package/dist/production/index.d.ts +0 -3260
  715. package/dist/production/index.js +0 -1019
  716. package/dist/production/index.js.map +0 -1
  717. package/dist/production/log-seo-tags-TY72EQWZ.js +0 -2
  718. package/dist/production/log-seo-tags-TY72EQWZ.js.map +0 -1
  719. package/dist/production/react-router-preset.d.ts +0 -45
  720. package/dist/production/react-router-preset.js +0 -11
  721. package/dist/react-router.d.ts +0 -75
  722. package/dist/vite/chunk-4O5OI3OO.js +0 -127
  723. package/dist/vite/chunk-FAQ7TVHC.js +0 -9
  724. package/dist/vite/chunk-QXBQVDMY.js +0 -68
  725. package/dist/vite/compat-date.d.ts +0 -3
  726. package/dist/vite/compat-date.js +0 -6
  727. package/dist/vite/get-virtual-routes.d.ts +0 -21
  728. package/dist/vite/get-virtual-routes.js +0 -74
  729. package/dist/vite/hydrogen-middleware.d.ts +0 -9
  730. package/dist/vite/hydrogen-middleware.js +0 -7
  731. package/dist/vite/plugin.d.ts +0 -22
  732. package/dist/vite/plugin.js +0 -171
  733. package/dist/vite/request-events.d.ts +0 -144
  734. package/dist/vite/request-events.js +0 -10
  735. package/dist/vite/types.d.ts +0 -5
  736. package/dist/vite/types.js +0 -0
  737. package/dist/vite/virtual-routes/assets/debug-network.css +0 -609
  738. package/dist/vite/virtual-routes/assets/favicon-dark.svg +0 -20
  739. package/dist/vite/virtual-routes/assets/favicon.svg +0 -28
  740. package/dist/vite/virtual-routes/assets/inter-variable-font.woff2 +0 -0
  741. package/dist/vite/virtual-routes/assets/jetbrainsmono-variable-font.woff2 +0 -0
  742. package/dist/vite/virtual-routes/assets/styles.css +0 -249
  743. package/dist/vite/virtual-routes/components/FlameChartWrapper.jsx +0 -123
  744. package/dist/vite/virtual-routes/components/HydrogenLogoBaseBW.jsx +0 -32
  745. package/dist/vite/virtual-routes/components/HydrogenLogoBaseColor.jsx +0 -47
  746. package/dist/vite/virtual-routes/components/IconBanner.jsx +0 -292
  747. package/dist/vite/virtual-routes/components/IconClose.jsx +0 -38
  748. package/dist/vite/virtual-routes/components/IconDiscard.jsx +0 -44
  749. package/dist/vite/virtual-routes/components/IconError.jsx +0 -61
  750. package/dist/vite/virtual-routes/components/IconGithub.jsx +0 -23
  751. package/dist/vite/virtual-routes/components/IconTwitter.jsx +0 -21
  752. package/dist/vite/virtual-routes/components/Layout.jsx +0 -7
  753. package/dist/vite/virtual-routes/components/RequestDetails.jsx +0 -171
  754. package/dist/vite/virtual-routes/components/RequestTable.jsx +0 -91
  755. package/dist/vite/virtual-routes/components/RequestWaterfall.jsx +0 -151
  756. package/dist/vite/virtual-routes/layout.jsx +0 -33
  757. package/dist/vite/virtual-routes/lib/useDebugNetworkServer.jsx +0 -178
  758. package/dist/vite/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.jsx +0 -37
  759. package/dist/vite/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.tsx +0 -79
  760. package/dist/vite/virtual-routes/routes/graphiql.jsx +0 -5
  761. package/dist/vite/virtual-routes/routes/index.jsx +0 -265
  762. package/dist/vite/virtual-routes/routes/subrequest-profiler.jsx +0 -243
  763. package/dist/vite/virtual-routes/virtual-root-with-layout.jsx +0 -63
  764. package/dist/vite/virtual-routes/virtual-root.jsx +0 -67
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: hydrogen-cart-drawer
3
+ description: >
4
+ Guide for building an accessible cart drawer using @shopify/hydrogen. Use when
5
+ creating or reviewing a cart drawer, mini cart, or slide-out cart, including
6
+ native dialog element (showModal), closedby light dismiss, body scroll lock, exit
7
+ animations, and wiring window.Shopify.actions.openCart().
8
+ ---
9
+
10
+ # Cart Drawer
11
+
12
+ Build an accessible cart drawer that opens from the edge of the viewport and integrates with Standard Actions so any code can open it via `window.Shopify.actions.openCart()`.
13
+
14
+ ---
15
+
16
+ ## 1. Prerequisites
17
+
18
+ Before building the cart drawer, these must be in place:
19
+
20
+ - **Shopify runtime scripts** — render `ShopifyScripts` once in the root document, or use `getShopifyScriptTags()` / `renderShopifyScriptTags()` from core in framework-agnostic heads plus `initializeShopifyScripts({ routes: routeTemplates })` during browser hydration. Use the local `hydrogen-routing` skill for the required routing options. The drawer uses `window.Shopify.actions.openCart()` from that runtime.
21
+ - **`/cart` route** — the full cart page, used as the fallback route when the drawer is unavailable. For strict no-JS live cart HTML, the cart route must receive resolved cart `initialData`.
22
+
23
+ ---
24
+
25
+ ## 2. Drawer structure
26
+
27
+ The drawer has three layout zones (header / body / footer):
28
+
29
+ 1. **Header** — title, close button, and error banner (if any cart errors exist). Always visible, never scrolls.
30
+ 2. **Body** — line items only. This is the only zone that scrolls when content overflows.
31
+ 3. **Footer** — discount codes, order note and/or cart attribute editors, totals, and checkout button. Always visible (pinned to bottom), never scrolls.
32
+
33
+ **Empty state**: When the cart has no items, the body shows an empty message ("Your cart is empty") and the footer is hidden entirely — no totals, no discounts, no notes, no checkout button.
34
+
35
+ The drawer is a `<dialog>` (or primitive library equivalent) rendered once in the root layout. The storefront must also have a `/cart` route that renders a full cart page — this is the fallback route when the drawer is unavailable. The drawer is the progressively-enhanced experience that layers on top after hydration.
36
+
37
+ The full `/cart` page shares the same content components (line items, discounts, note, attributes, totals, checkout) but uses a page layout instead of the fixed header/body/footer zones.
38
+
39
+ The drawer's line item forms must use the same Hydrogen line-item form contract as the `/cart` page — see `hydrogen-cart-ui` ("Form structure"). The layout may differ by framework and design system; the form contract must not.
40
+
41
+ ---
42
+
43
+ ## 3. Accessibility
44
+
45
+ See `references/accessibility.md` for the full dialog accessibility spec grounded in the WHATWG HTML specification.
46
+
47
+ ### Must implement (not provided by `<dialog>`)
48
+
49
+ At-a-glance index — full treatment lives where each concern is implemented:
50
+
51
+ 1. **Body scroll lock** — pure CSS, no JS class toggling (see §6)
52
+ 2. **Backdrop click dismissal** — native light dismiss via `<dialog closedby="any">` (see §5)
53
+ 3. **Exit animation** — `@starting-style` / discrete transitions (see §6)
54
+
55
+ ### Provided by `<dialog>` + `showModal()`
56
+
57
+ These are free — **do not reimplement them**: focus containment (background `inert`), focus restoration to the trigger on `close()`, Escape dismissal, `::backdrop` overlay, and implicit `aria-modal="true"`. See `references/accessibility.md` for the full table and how each works.
58
+
59
+ ### Required markup
60
+
61
+ ```html
62
+ <dialog aria-labelledby="cart-drawer-title">
63
+ <h2 id="cart-drawer-title">Cart</h2>
64
+ <!-- drawer content -->
65
+ </dialog>
66
+ ```
67
+
68
+ All interactive elements inside the drawer must be `<button>` or `<input>` elements — not `<div>` or `<span>` with click handlers.
69
+
70
+ ---
71
+
72
+ ## 4. Dialog primitive recommendation
73
+
74
+ **Default**: use native `<dialog>` with `showModal()`. It gives you most accessibility behaviors for free and avoids adding a dependency.
75
+
76
+ Use a primitive library only when the app already depends on one for dialog-like UI and wants that library's controlled-state or animation model. The accessibility requirements in `references/accessibility.md` are identical regardless of approach.
77
+
78
+ ---
79
+
80
+ ## 5. Open/close behavior
81
+
82
+ ### Opening the drawer
83
+
84
+ The cart trigger renders in SSR as `<a href="/cart">Cart</a>` so it works before hydration and without JavaScript (the anchor navigates to the full `/cart` page). After hydration, an `onClick` calls `e.preventDefault()` then `openCartDrawer()` (which calls `showModal()`), so the click opens the drawer instead of navigating; no `hasHydrated` swap is needed — the anchor is the no-JS baseline and the `onClick` is the enhancement.
85
+
86
+ Keep the drawer as hydrated progressive enhancement. Do not make the drawer itself the fallback route; the `/cart` page is that full-page fallback.
87
+
88
+ ```tsx
89
+ export const CART_DRAWER_ID = "cart-drawer";
90
+ const STANDARD_ACTIONS_READY_EVENT = "DOMContentLoaded";
91
+
92
+ let openCartActionConfigured = false;
93
+ let openCartActionRetryQueued = false;
94
+
95
+ function getCartDrawer() {
96
+ if (typeof document === "undefined") return null;
97
+
98
+ const drawer = document.getElementById(CART_DRAWER_ID);
99
+ return drawer instanceof HTMLDialogElement ? drawer : null;
100
+ }
101
+
102
+ export function openCartDrawer() {
103
+ const drawer = getCartDrawer();
104
+ if (!drawer || drawer.open) return;
105
+ drawer.showModal();
106
+ }
107
+
108
+ export function closeCartDrawer() {
109
+ getCartDrawer()?.close();
110
+ }
111
+
112
+ function configureOpenCartActionNow() {
113
+ const openCart = typeof window !== "undefined" ? window.Shopify?.actions?.openCart : undefined;
114
+ if (!openCart) return false;
115
+
116
+ openCart.configure({
117
+ handler: async () => openCartDrawer(),
118
+ });
119
+ openCartActionConfigured = true;
120
+ return true;
121
+ }
122
+
123
+ export function configureOpenCartAction() {
124
+ if (typeof document === "undefined" || openCartActionConfigured) return;
125
+ if (configureOpenCartActionNow()) return;
126
+ if (openCartActionRetryQueued || document.readyState !== "loading") return;
127
+
128
+ openCartActionRetryQueued = true;
129
+ document.addEventListener(
130
+ STANDARD_ACTIONS_READY_EVENT,
131
+ () => {
132
+ openCartActionRetryQueued = false;
133
+ configureOpenCartAction();
134
+ },
135
+ { once: true },
136
+ );
137
+ }
138
+
139
+ configureOpenCartAction();
140
+ ```
141
+
142
+ The module-scope `configureOpenCartAction()` call is intentional. It no-ops during SSR, configures immediately when Standard Actions is already available, and retries once on `DOMContentLoaded` when the runtime loads after this module.
143
+
144
+ Render the drawer once in the root layout. Use explicit JavaScript open/close helpers for app-owned controls.
145
+
146
+ ```tsx
147
+ import { CART_DRAWER_ID, closeCartDrawer } from "~/lib/cart-drawer";
148
+
149
+ function CartDrawer() {
150
+ return (
151
+ <dialog id={CART_DRAWER_ID} aria-labelledby="cart-drawer-title" closedby="any">
152
+ <h2 id="cart-drawer-title">Cart</h2>
153
+ <button
154
+ type="button"
155
+ aria-label="Close cart"
156
+ onClick={closeCartDrawer}
157
+ >
158
+ Close
159
+ </button>
160
+ {/* cart content */}
161
+ </dialog>
162
+ );
163
+ }
164
+ ```
165
+
166
+ The drawer opens from three surfaces. The cart trigger is the canonical one; the other two reuse the same helper.
167
+
168
+ **1. The cart trigger.** A `/cart` anchor with an `onClick` that opens the drawer after hydration. It carries the accessibility attributes `aria-controls` and `aria-haspopup="dialog"`:
169
+
170
+ ```tsx
171
+ return (
172
+ <a href="/cart" onClick={(e) => { e.preventDefault(); openCartDrawer(); }} aria-controls={CART_DRAWER_ID} aria-haspopup="dialog">
173
+ Cart
174
+ </a>
175
+ );
176
+ ```
177
+
178
+ **2. `window.Shopify.actions.openCart()`** — the Standard Action for programmatic opening, so external code (Standard Actions tools, agents, third-party components) can open the drawer. Register the same stable DOM helper as the `openCart` handler (see §8 for the handler-permanence caveat).
179
+
180
+ ```js
181
+ window.Shopify.actions.openCart();
182
+ ```
183
+
184
+ **3. From add-to-cart** — when the canonical cart trigger is an anchor, open the drawer immediately with optimistic state so pending cart contents remain inspectable. Opening only after success is compatible with the storefront contract only when the page also provides a visible button that opens the drawer while the mutation is pending.
185
+
186
+ ```tsx
187
+ <form {...formProps({ beforeSubmit: openCartDrawer })}>
188
+ {/* add-to-cart controls */}
189
+ </form>
190
+ ```
191
+
192
+ Validate before calling the drawer helper — for example, call `event.preventDefault()` and return if the quantity is invalid. Do not push this policy into core cart mutations; some storefronts want a toast, a cart page navigation, or no automatic UI change.
193
+
194
+ ### Closing the drawer
195
+
196
+ Native: Escape and the back gesture (fires `cancel` then `close`). App-provided: the explicit close `<button>` in the header (`aria-label="Close cart"`). Backdrop (light dismiss) requires `<dialog closedby="any">`.
197
+
198
+ `closedby="any"` is the least compatible part of this pattern. Browsers without `closedby` support will ignore the attribute, so the drawer will still close from Escape and the explicit close button, but backdrop click will not close it. Do not provide a polyfill for `closedby` unless the app explicitly requires backdrop click support in those browsers.
199
+
200
+ If an app does require that polyfill, use a pointerdown-plus-click guard on the `<dialog>` itself: record whether `pointerdown` started on the dialog backdrop, then close only when the following `click` also targets the dialog. Do not close on a plain `click.self` alone, because a drag that starts inside the drawer and ends on the backdrop can produce an accidental close.
201
+
202
+ ### State management
203
+
204
+ Open/close is DOM state owned by the `<dialog>` element. Prefer `dialog.showModal()` and `dialog.close()` over duplicating open state in framework state unless a primitive library requires controlled state.
205
+
206
+ For custom logic, listen to native dialog events instead of duplicating state. Use `toggle` to react after the drawer opens or closes. Use `beforetoggle` with `event.preventDefault()` when the app needs to intercept opening, run custom work such as an animation, and then call `showModal()` manually later.
207
+
208
+ ---
209
+
210
+ ## 6. CSS and animation
211
+
212
+ See `references/css.md` for the reference drawer shell, entry/exit animation, backdrop, and scroll-lock CSS. In Tailwind apps, keep the dialog shell, `::backdrop`, `@starting-style`, and scroll-lock rules in global CSS or a project `@layer`; use utilities for the drawer's internal content layout.
213
+
214
+ ---
215
+
216
+ ## 7. Verify
217
+
218
+ After building the cart drawer, test:
219
+
220
+ - [ ] Cart trigger is a `/cart` anchor pre-hydration; after hydration its `onClick` opens the drawer via `showModal()`
221
+ - [ ] If a no-JS fallback is required, it navigates to `/cart` without JavaScript
222
+ - [ ] `window.Shopify.actions.openCart()` opens drawer (test from browser console)
223
+ - [ ] Drawer closes via Escape, backdrop click (with `closedby="any"`), and the close button
224
+ - [ ] Focus returns to the cart icon after close
225
+ - [ ] Tab cycles only through elements inside the drawer while open
226
+ - [ ] Screen reader announces "Cart" (or equivalent title) on drawer open
227
+ - [ ] While cart data loads, the title and close button remain available and the loading status is announced
228
+ - [ ] Drawer line item forms use the same `hydrogen-cart-ui` progressive form contract as the `/cart` page
229
+
230
+ ---
231
+
232
+ ## 8. Common gotchas
233
+
234
+ - **`openCart` handler is permanent** — `openCart.configure({ handler })` has no corresponding `unconfigure()`. Once registered, the handler persists for the page lifetime. This is fine when the drawer lives in the root layout. Avoid handlers that close over component refs that can go stale during HMR; prefer a small stable helper that looks up `dialog#cart-drawer` and calls `showModal()`.
235
+
236
+ - **Astro view transitions** — if the drawer is vanilla JS (like the base example), it must be re-initialized after view transition navigations. Listen for `astro:after-swap`.
237
+
238
+ - **Cart selectors must be stable** — don't derive arrays or objects inside a cart selector unless the binding accepts an equality function. Select store references such as `state.errors` or `state.data.lines.nodes` and derive banner messages outside the selector with the framework's memoization primitive.
239
+
240
+ ---
241
+
242
+ ## 9. Anti-patterns
243
+
244
+ - **Drawer as a route instead of overlay** — the drawer is overlay UI in the root layout and must be available on every page; the `/cart` route is the full cart page, not the drawer (see §2).
245
+
246
+ - **`dialog.show()` instead of `showModal()`** — `show()` does not get top-layer rendering, focus containment, `inert` on background, or `::backdrop`. Always use `showModal()`.
247
+
248
+ - **Text-only drawer quantities** — rendering line quantities as text with only plus/minus controls breaks the progressive set-quantity path; use the same editable quantity input contract as the `/cart` page (see `hydrogen-cart-ui`).
@@ -0,0 +1,109 @@
1
+ # Dialog/Drawer Accessibility Requirements
2
+
3
+ Framework-agnostic specification for building an accessible modal drawer. Grounded in the WHATWG HTML specification for the `<dialog>` element and WAI-ARIA Authoring Practices.
4
+
5
+ ## The `<dialog>` element with `showModal()`
6
+
7
+ The native `<dialog>` element with `showModal()` is the recommended foundation. It provides six accessibility behaviors for free, leaving only three concerns for the implementation to handle.
8
+
9
+ ### What `showModal()` provides
10
+
11
+ | Behavior | How it works |
12
+ |----------|-------------|
13
+ | **Top-layer rendering** | The dialog is promoted above all other content, regardless of `z-index` stacking. No z-index wars. |
14
+ | **`::backdrop` pseudo-element** | A full-viewport overlay rendered behind the dialog in the top layer. Styleable with CSS. |
15
+ | **Escape key dismissal** | Pressing Escape fires a `cancel` event (cancelable), then closes the dialog and fires a `close` event. |
16
+ | **Focus containment** | All content outside the dialog becomes `inert` — unreachable by Tab, click, or assistive technology. Tab and Shift+Tab cycle only through focusable elements inside the dialog. |
17
+ | **Focus restoration** | The browser stores the previously-focused element when `showModal()` is called and restores focus to it when the dialog closes via `close()`. Per the WHATWG spec, this is automatic. |
18
+ | **Implicit `aria-modal="true"`** | Screen readers recognize the dialog as modal without an explicit attribute. |
19
+
20
+ ### What must be implemented manually
21
+
22
+ These three behaviors are NOT provided by `<dialog>` and must be handled by the implementation or a primitive library:
23
+
24
+ #### 1. Body scroll lock
25
+
26
+ `showModal()` does not prevent the background from scrolling. Use the CSS `:has()` selector to apply `overflow: hidden` on `<body>` when the dialog is open — no JS class toggling or cleanup needed:
27
+
28
+ ```css
29
+ body:has(dialog#cart-drawer[open]) {
30
+ overflow: hidden;
31
+ }
32
+ ```
33
+
34
+ Watch for the scrollbar-gutter shift: when the scrollbar disappears, body width increases by the scrollbar's width. Primitive libraries typically handle this with `padding-right` compensation or `scrollbar-gutter: stable`.
35
+
36
+ #### 2. Backdrop click dismissal
37
+
38
+ The default `<dialog>` behavior does not close on backdrop click. The standard pattern detects clicks on the dialog element itself (as opposed to its children):
39
+
40
+ ```js
41
+ dialog.addEventListener('click', (event) => {
42
+ if (event.target === dialog) dialog.close();
43
+ });
44
+ ```
45
+
46
+ Click events on child elements bubble to the dialog, but `event.target` remains the child — only direct clicks on the dialog element (i.e., the backdrop area) satisfy the condition.
47
+
48
+ **Preferred:** The `closedby` attribute provides native light dismiss. Setting `closedby="any"` enables both Escape and backdrop click dismissal natively. Browsers that do not support it ignore the attribute; keep an explicit close button as the always-available close mechanism.
49
+
50
+ #### 3. Exit animations
51
+
52
+ The hard problem: `close()` removes the dialog from the top layer immediately, making exit animations impossible with the standard approach.
53
+
54
+ Two strategies:
55
+
56
+ **CSS `@starting-style` + `allow-discrete` (modern browsers)**
57
+ ```css
58
+ dialog[open] {
59
+ transform: translateX(0);
60
+ transition: transform 250ms, overlay 250ms allow-discrete, display 250ms allow-discrete;
61
+ }
62
+ @starting-style {
63
+ dialog[open] { transform: translateX(100%); }
64
+ }
65
+ dialog:not([open]) {
66
+ transform: translateX(100%);
67
+ }
68
+ ```
69
+
70
+ **JavaScript-deferred close (broadest compatibility)**
71
+ Run the exit animation first, then call `dialog.close()` after the animation completes. This requires intercepting the native close flow (cancel the `cancel` event, run the animation, then close programmatically).
72
+
73
+ ## Labeling
74
+
75
+ The drawer must have an accessible name. Use `aria-labelledby` pointing to the visible heading element:
76
+
77
+ ```html
78
+ <dialog aria-labelledby="cart-drawer-title">
79
+ <h2 id="cart-drawer-title">Cart</h2>
80
+ ...
81
+ </dialog>
82
+ ```
83
+
84
+ If additional context is useful for screen readers (e.g., item count), use `aria-describedby` pointing to a summary element.
85
+
86
+ ## Keyboard interaction
87
+
88
+ With `<dialog>` + `showModal()` and semantic HTML, all keyboard interactions are native:
89
+
90
+ | Key | Behavior | Source |
91
+ |-----|----------|--------|
92
+ | Escape | Closes the dialog | Native (`cancel` → `close` events) |
93
+ | Tab | Moves focus to next focusable element inside dialog | Native (background is `inert`) |
94
+ | Shift+Tab | Moves focus to previous focusable element inside dialog | Native |
95
+ | Enter / Space | Activates the focused button or link | Native for `<button>`, `<a>`, `<input>` |
96
+
97
+ No additional keyboard handlers are needed if all interactive elements use semantic HTML (`<button>`, `<a>`, `<input>`). Custom elements that are not natively focusable require `tabindex="0"` and `role` attributes — prefer native elements instead.
98
+
99
+ ## How primitive libraries handle these concerns
100
+
101
+ Primitive libraries (Radix UI, Base UI, Melt UI, Kobalte, Headless UI, etc.) implement the same accessibility contract described above. They abstract the manual work:
102
+
103
+ - **Focus containment**: Some libraries build their own focus trap from `<div>` + portal rather than using `<dialog>`. The result is equivalent — Tab cycles within the dialog, background is inert.
104
+ - **Scroll lock**: Libraries typically add `overflow: hidden` with scrollbar-gutter compensation automatically.
105
+ - **Backdrop click**: Handled via an overlay component with an `onClick` handler, or via the `closedby` attribute where supported.
106
+ - **Exit animations**: Libraries integrate with their framework's animation system (React transition groups, Svelte transitions, CSS animation hooks) to defer unmounting until the animation completes.
107
+ - **Focus restoration**: Most libraries implement their own, even though `<dialog>` handles it natively. This is because some libraries render from `<div>` + portal, not `<dialog>`.
108
+
109
+ The accessibility requirements are identical regardless of whether you use a library or native `<dialog>`. Libraries reduce implementation effort but don't change what must be true for the drawer to be accessible.
@@ -0,0 +1,67 @@
1
+ # Cart Drawer CSS
2
+
3
+ Reference drawer shell, entry/exit animation, backdrop, and scroll-lock CSS for the cart drawer.
4
+
5
+ ```css
6
+ dialog#cart-drawer {
7
+ position: fixed;
8
+ inset-block: 0;
9
+ right: 0;
10
+ left: auto;
11
+ margin: 0;
12
+ width: 100%;
13
+ max-width: 28rem;
14
+ height: 100dvh;
15
+ max-height: none;
16
+ border: 0;
17
+ padding: 0;
18
+ }
19
+ ```
20
+
21
+ **Entry and exit animation**: slide in from the edge and let the dialog remain transitionable while closing.
22
+ ```css
23
+ dialog#cart-drawer {
24
+ transform: translateX(100%);
25
+ transition:
26
+ transform 250ms cubic-bezier(0.22, 1, 0.36, 1),
27
+ overlay 250ms allow-discrete,
28
+ display 250ms allow-discrete;
29
+ }
30
+
31
+ dialog#cart-drawer[open] {
32
+ transform: translateX(0);
33
+ }
34
+
35
+ @starting-style {
36
+ dialog#cart-drawer[open] {
37
+ transform: translateX(100%);
38
+ }
39
+ }
40
+ ```
41
+
42
+ **Backdrop**: fade in.
43
+ ```css
44
+ dialog#cart-drawer::backdrop {
45
+ background: rgb(0 0 0 / 0);
46
+ transition:
47
+ background-color 250ms ease-out,
48
+ overlay 250ms allow-discrete,
49
+ display 250ms allow-discrete;
50
+ }
51
+ dialog#cart-drawer[open]::backdrop {
52
+ background: rgb(0 0 0 / 0.3);
53
+ }
54
+
55
+ @starting-style {
56
+ dialog#cart-drawer[open]::backdrop {
57
+ background: rgb(0 0 0 / 0);
58
+ }
59
+ }
60
+ ```
61
+
62
+ **Scroll lock**:
63
+ ```css
64
+ body:has(dialog#cart-drawer[open]) { overflow: hidden; }
65
+ ```
66
+
67
+ Exact measurements and colors are not prescribed — the above matches the base example for reference. Adapt to the project's design system.
@@ -0,0 +1,224 @@
1
+ ---
2
+ name: hydrogen-cart-ui
3
+ description: >
4
+ Behavioral guide for building cart UI with @shopify/hydrogen: line items,
5
+ quantity and remove controls, optimistic updates, discount, note, and cart
6
+ attribute inputs, and the full-page /cart fallback. Use when writing,
7
+ modifying, or reviewing cart line-item UI, quantity/remove controls, or cart
8
+ mutation forms. Framework agnostic.
9
+ ---
10
+
11
+ # Cart Primitive
12
+
13
+ The cart primitive is a client-side store that syncs with Shopify via Standard Actions events. It provides optimistic updates, scoped error handling, and a form-based mutation API. The store is framework-neutral; framework-specific bindings are thin wrappers over the core store.
14
+
15
+ ## Framework Bindings
16
+
17
+ Before building UI, check whether this skill has a reference file for the app's framework in `references/`. If one exists, read it and use that framework binding first; the reference owns provider setup, state selectors, and form helpers for that runtime.
18
+
19
+ If there is no matching reference, there may be no packaged `@shopify/hydrogen/<framework>` export. Use the framework-neutral `createCartStore` and `createCartFormRegister` from `@shopify/hydrogen` directly, subscribe to store changes with the framework's reactivity primitive, and apply every rule in this skill yourself. Packaged bindings are thin wrappers over these same core APIs — match their behavior, do not invent a new contract.
20
+
21
+ In island-based frameworks, use the binding for the island's UI framework when a matching reference exists; otherwise use the core store directly.
22
+
23
+ ## Route Placement
24
+
25
+ When creating a full cart page, use the app's existing route convention when present; otherwise create `/cart`. This page is separate from Hydrogen's `/api/cart` server handler, which is registered with `createCartServerHandlers()` through `handleShopifyRoutes`.
26
+
27
+ **The `/cart` page must render from the server data path.** It is the fallback route for the cart drawer (reachable as a real `/cart` link in the footer), so its line items and totals must not depend only on an ad hoc client store read. Seed `CartProvider` with `initialData` from the server data path (React Router loader, Next.js server layout/page). When the framework can preserve streamed promises, pass the unresolved cart promise as `initialData` instead of awaiting it; the Next.js reference is the best current non-blocking pattern. If strict no-JS HTML must include the real cart today, pass the resolved handler envelope instead. A `/cart` page whose only data source is a client `useCart` read renders "Your cart is empty" without JS even when the shopper has items. See the framework reference for the exact wiring.
28
+
29
+ **The native no-JS add-to-cart POST must set the cart cookie server-side.** With scripting off, the add-to-cart `<form method="post">` submits natively and the cart server handler must respond with the cart cookie so the next `/cart` request server-renders the seeded cart — not only service the hydrated `fetch`. See the `hydrogen-request-handlers` skill for the endpoint contract.
30
+
31
+ ## How the store works
32
+
33
+ The store holds a `CartState` and notifies subscribers when it changes. `state.readyPromise` is present while an applicable full-cart load is pending and resolves after the resulting state is published. Mutations flow through Shopify Standard Actions — the store listens for `shopify:cart:lines-update`, `shopify:cart:discount-update`, `shopify:cart:note-update`, and `shopify:cart:attributes-update` DOM events. Each event carries a `promise` that resolves with the server response.
34
+
35
+ On mutation:
36
+
37
+ 1. The store applies an **optimistic projection** over its settled state, so the UI-visible state changes immediately.
38
+ 2. The affected entity is added to `pending` — a set of in-flight line IDs or discount codes, or a note/attributes boolean.
39
+ 3. When the promise resolves, the store folds that transaction into settled state and reapplies remaining projections. Overlapping mutations discard ambiguous response snapshots, then coalesce one authoritative cart refresh after the burst settles.
40
+ 4. On failure, the store removes only the failed projection, preserves unrelated work, and clears the matching pending entry.
41
+
42
+ When overlapping mutations make response snapshots ambiguous, the store sets `state.revalidating` to `true`. It starts one authoritative refresh after those mutations settle and clears the flag when the refresh completes or fails. Until then, server-derived values such as costs remain at their last trustworthy value. A refresh failure preserves the locally reconciled cart and appears in `errors.network`.
43
+
44
+ App-owned cart mutations outside Standard Actions do not emit the events the store normally observes. After such a mutation succeeds, call `CartStore.refresh()` directly or use the framework binding's `useCartActions().refresh()`. The refresh waits for active optimistic work, reconciles custom fragment fields from the configured cart endpoint, and loads the cart when none exists yet (e.g. one just created server-side). Do not call it after ordinary Hydrogen cart forms; their Standard Actions events already synchronize the store.
45
+
46
+ The store supersedes keyed mutations for the same line, discount batch, note, or complete attribute list. Relative additions remain independent so every submitted quantity reaches the server; their projections are reconciled together without disabling controls.
47
+
48
+ ## Stable selectors
49
+
50
+ Store selectors should select primitives or stable references from the store. Do not allocate arrays, objects, maps, sets, or derived view models inside a selector unless the framework binding also accepts an equality function.
51
+
52
+ Bad:
53
+
54
+ ```ts
55
+ const selectMessages = (state) => [
56
+ ...state.errors.network.map((error) => error.message),
57
+ ...state.errors.cart.userErrors.map((error) => error.message),
58
+ ];
59
+ ```
60
+
61
+ That selector returns a new array whenever the store notifies subscribers, so bindings that rely on referential equality cannot skip unchanged output. Select stable slices first, then derive:
62
+
63
+ ```ts
64
+ const selectErrors = (state) => state.errors;
65
+ const messages = deriveFromErrors(errors, () => {
66
+ return [
67
+ ...errors.network.map((error) => error.message),
68
+ ...errors.cart.userErrors.map((error) => error.message),
69
+ ];
70
+ });
71
+ ```
72
+
73
+ ## Pending state
74
+
75
+ `state.pending` tracks what is currently in-flight:
76
+
77
+ - `pending.lines` — `Set<string>` of line IDs with mutations in flight.
78
+ - `pending.discountCodes` — `Set<string>` of discount codes being applied or removed.
79
+ - `pending.cost` — `true` when pending line or discount mutations can leave totals stale.
80
+ - `pending.note` — `boolean` indicating whether a note save is in flight.
81
+ - `pending.attributes` — `boolean` indicating whether a complete attribute-list update is in flight.
82
+
83
+ Any value whose entity is in a pending set is **optimistic and unconfirmed**. The UI must treat it differently from confirmed values.
84
+
85
+ `state.revalidating` is `true` while the store refreshes authoritative cart-wide fields after overlapping mutations. Treat totals as unconfirmed and suppress cart analytics while it is true.
86
+
87
+ ## Error state
88
+
89
+ `state.errors` is scoped to the entity that caused the error:
90
+
91
+ - `errors.lines` — `Map<string, CartErrorGroup>` keyed by line ID.
92
+ - `errors.discountCodes` — `Map<string, CartErrorGroup>` keyed by discount code string.
93
+ - `errors.note` — `CartErrorGroup` for note-related errors.
94
+ - `errors.attributes` — `Map<string, CartErrorGroup>` keyed by attribute key.
95
+ - `errors.cart` — `CartErrorGroup` for cart-level errors not attributable to a specific entity.
96
+ - `errors.network` — `CartNetworkEntry[]` for transport failures (timeouts, HTTP errors).
97
+ - `errors.lastUpdatedAt` — timestamp of the most recent error update across any scope. Per-scope timestamps also exist (`linesUpdatedAt`, `discountCodesUpdatedAt`, `attributesUpdatedAt`, etc.).
98
+
99
+ Each `CartErrorGroup` contains `{ userErrors: CartUserError[], warnings: CartWarning[] }`.
100
+
101
+ Errors survive unrelated cart work and clear when a new mutation begins for the same key.
102
+
103
+ ---
104
+
105
+ ## Rules
106
+
107
+ ### Money
108
+
109
+ - **NEVER calculate currency amounts on the client.** Display server-provided amounts (`line.cost.totalAmount`, `state.data.cost.subtotalAmount`, etc.) directly. Client-side arithmetic drifts from the truth when discounts, taxes, duties, or rounding apply. If a value is stale because a mutation is in-flight, show it with pending UI — not a client-computed estimate.
110
+ - **Format with Hydrogen money helpers**, not string concatenation. Use the local `hydrogen-money` skill for an app wrapper around `formatMoney()`. The store provides `amount` (string) and `currencyCode` (string).
111
+
112
+ ### Optimistic interactions
113
+
114
+ - **Keep rapid-action controls interactive during pending state.** Increase, decrease, remove, apply, and remove-discount controls must remain interactive. The store's abort-controller pattern makes concurrent mutations safe — a new click supersedes the in-flight request. A save-style editor, such as a gift-message attribute form, may disable its own submit button while its scoped mutation is pending when duplicate saves provide no value. Disabling for a non-pending reason is also fine — for example, the decrease control may be disabled when the quantity is already `<= 1`.
115
+ - **Inventory-aware set-quantity clamping is opt-in.** The default cart query does not request `ProductVariant.quantityAvailable` because that field requires the `unauthenticated_read_product_inventory` Storefront API scope. If a cart UI needs the entered quantity to clamp to sellable inventory before submission, add `quantityAvailable` to the app's custom cart fragment and enable the Hydrogen channel's product inventory permission (`unauthenticated_read_product_inventory`). Without that field, let Shopify validate inventory and surface the returned line error.
116
+ - **NEVER show a spinner or skeleton where a stale value would do.** The user already sees a quantity and a price. Replacing confirmed-looking content with a loading state is a regression. Show the previous value with a visual indicator that it's unconfirmed.
117
+ - **ALWAYS visually indicate unconfirmed data.** Any value whose entity is in a `pending` set must look visually distinct from confirmed values. Reduced opacity is the reference pattern — the stale text acts as a spatial placeholder (like a skeleton), not as readable content. Rules of contrast can be disregarded because the pending value is a signal, not content the user needs to read.
118
+ - **NEVER block navigation during pending.** Cart mutations are fire-and-forget from the user's perspective. No confirmation dialogs on route change.
119
+
120
+ ### Errors
121
+
122
+ - **ALWAYS display errors closest to the element they describe.** A line item error appears next to that line item. A discount code error appears next to that discount code. Errors should not only live in a distant banner.
123
+ - **Use a banner only for errors that have no inline home.** This includes: network errors, cart-level errors, and orphaned line errors.
124
+ - **Orphaned line errors** — when `errors.lines` contains entries for line IDs not present in `state.data.lines.nodes`, those errors have no inline target. Surface them in the banner. This happens when a line was removed but the server returned errors referencing its ID.
125
+ - **Inline errors must be accessible** — use `role="alert"` and link them to the nearest interactive element via `aria-describedby`. Mark the associated input as `aria-invalid="true"`.
126
+ - **Use `errors.lastUpdatedAt` for dismissal.** Track a local `dismissedAt` timestamp. If `lastUpdatedAt <= dismissedAt`, the banner is hidden. If a new error arrives with a newer timestamp, the banner reappears.
127
+
128
+ ### Note editing
129
+
130
+ - **Maintain a local draft** for the note, synced from the store. When the server responds with an updated note, only overwrite the local draft if `pending.note` is `false`. This prevents the server response from clobbering the user's in-progress typing.
131
+ - **Allow users to click the save button even when the draft matches the stored note** (nothing to save), but prevent any action. This enables progressive enhancement and prevents frustration.
132
+ - **Show a pending indicator** while the note mutation is pending.
133
+
134
+ ### Cart attribute editing
135
+
136
+ - **Treat an attribute update as complete-list replacement.** `attributes-update` sends the full next attribute list; attributes omitted from the submission are removed. When editing one attribute, explicitly include every unrelated existing attribute as a hidden keyed `attributeValue` field. Submit no attribute fields to clear all attributes.
137
+ - **Keep each key attached to its value.** Pass the attribute key to every `register("attributeValue", {key, ...})` call. The generated `attributes.<key>` field name encodes that key, so the server never relies on parallel field positions. Storefront API mutation inputs require string values, so normalize a nullable returned value deliberately (usually to `""`) before resubmitting it.
138
+ - **Use the register contract exactly.** Call `register("attributeValue", {key, ...})` rather than spelling its generated `attributes.<key>` field name by hand. The submit intent is kebab-case (`attributes-update`) because action intents follow the existing `discount-apply`, `discount-remove`, and `note-update` convention.
139
+ - **Maintain a local draft** for an editable attribute when the UI can remain mounted across server responses. Only sync confirmed attribute data into that draft while `pending.attributes` is `false`, so a response does not clobber typing that happened during the request.
140
+ - **Show scoped pending and errors.** Use `pending.attributes` for the save state and display entries from `errors.attributes` next to the editor for the matching key. A save-style submit button may be disabled until the attribute promise settles.
141
+
142
+ ### Form structure
143
+
144
+ - **Each line item is its own form.** This gives each line its own identity input and its own submit buttons. A single form containing multiple lines creates ambiguity about which line an action targets.
145
+ - **Each line item form must preserve the progressive-enhancement shape.** The rendered structure will vary by framework and design system, but every line item quantity form needs the same Hydrogen contract: `register("set")`, `register("lineId", { value: line.id })`, and a real editable quantity input using `register("quantity", { value: line.quantity, interactive: true })`. Increase, decrease, and remove buttons are additional submit controls, not replacements for the set intent or the quantity input.
146
+ - **The `set` control is a hidden submit button, not a hidden input.** `register("set")` already returns `{ type: "submit", hidden: true }`; render it on a `<button>`. Do not swap it for `<input type="hidden">` — that removes the submit button, so pressing Enter in the quantity input no longer submits the set action.
147
+ - **Each discount "remove" button is its own form** — separate from the "apply" form. The apply form needs input validation (empty/duplicate prevention); each remove form is a single action.
148
+ - **Attribute forms submit keyed values.** Render one `register("attributeValue", {key, value})` control for every attribute in the complete next list, then submit with `register("attributes-update")`.
149
+
150
+ ### Loading
151
+
152
+ - **While `loading` is `true`**, show skeleton placeholders — not empty state. The cart hasn't been fetched yet.
153
+ - **When `loading` is `false` and `lines` is empty**, show empty state ("Your cart is empty" or equivalent).
154
+ - **If resolved `initialData` is provided** when creating the store, `loading` starts as `false` and the initial fetch is skipped. `initialData` is the cart handler data envelope (`{cart, errors?}`), not only the cart object. Use resolved data when the response should include full cart HTML. **If promise `initialData` is provided**, `loading` starts as `true`, `state.readyPromise` tracks readiness, and `useSuspenseCart` can suspend cart content while the app shell stays non-blocking. Use promises when the backend can stream them into the HTML response. `{cart: null}` means the server already completed the bootstrap with no usable cart, so the UI should render empty state without a browser retry. `undefined` means no server bootstrap was provided, so the store fetches `/api/cart` after hydration; use this only when a client-side fetch is acceptable, such as an SPA. Cart server handlers log bootstrap errors before returning them, so app loaders should forward handler data instead of logging or throwing those errors again.
155
+
156
+ ---
157
+
158
+ ## User Acceptance Tests
159
+
160
+ ### Line items
161
+
162
+ 1. **Increase quantity** — Click the increase control. The displayed quantity increments immediately. The quantity and totals appear in their pending visual state until the server confirms.
163
+ 2. **Decrease quantity** — Click the decrease control. Same optimistic behavior. At quantity 1, decreasing removes the line.
164
+ 3. **Remove line** — Activate the remove control. The line disappears immediately. Totals update optimistically.
165
+ 4. **Rapid clicks** — Click increase five times quickly. Each click increments the displayed quantity by one. The store aborts intermediate requests. The final server-confirmed state matches the quantity the user sees.
166
+ 5. **Failure rollback** — If the server rejects a line update, the quantity reverts to the last confirmed value. An error message appears inline next to the affected line item.
167
+ 6. **Line-scoped error** — When the server returns a `userError` scoped to a specific line, the message appears adjacent to that line (not only in a banner). The relevant input is marked `aria-invalid`.
168
+ 7. **Progressive quantity set** — The line item form contains a hidden `set` submit control, hidden/read-only `lineId`, and an editable quantity input. Pressing Enter in the quantity input submits a set-quantity action.
169
+ 8. **No-JS line update** — If JavaScript fails or hydration has not run, the line item form can still submit an explicit quantity value to the cart action endpoint.
170
+
171
+ ### Discount codes
172
+
173
+ 9. **Apply discount** — Enter a code and submit. The code appears in the list immediately in its pending visual state. When the server confirms, the pending indicator clears and the "applied" / "not applicable" status updates.
174
+ 10. **Duplicate prevention** — Submitting a code that is already present does nothing.
175
+ 11. **Empty input prevention** — Submitting with a blank input does nothing.
176
+ 12. **Remove discount** — Activate the remove control next to a code. The code disappears optimistically.
177
+ 13. **Discount-scoped error** — If the server returns an error for a specific code, the message appears next to that code in the list.
178
+
179
+ ### Order note
180
+
181
+ 14. **Save note** — Edit the text and submit. A pending indicator appears while the mutation is in-flight.
182
+ 15. **No-op save** — When the draft matches the stored note, clicking on save does nothing (but can still be clicked).
183
+ 16. **Server sync without clobber** — After save completes, the local draft updates to match the server response — but only when `pending.note` is `false`, preserving any typing the user did in the meantime.
184
+
185
+ ### Cart attributes
186
+
187
+ 17. **Save attribute** — Edit an attribute and submit. The optimistic value appears immediately, `pending.attributes` is `true`, and the editor shows a saving state until confirmation.
188
+ 18. **Preserve unrelated attributes** — Saving one attribute includes all unrelated existing key/value pairs; those attributes remain after the server response.
189
+ 19. **Clear attributes** — Submitting an empty attribute list removes every cart attribute.
190
+ 20. **Failure rollback** — If the update fails, the complete attribute list returns to the last confirmed baseline.
191
+ 21. **Attribute-scoped error** — An error for a key appears next to that key's editor and marks its input invalid.
192
+ 22. **No draft clobber** — Typing that occurs while an attribute save is pending is not overwritten by the confirming response.
193
+
194
+ ### Error banner
195
+
196
+ 23. **Network error** — When a mutation fails due to a transport error, a banner appears with the error message and a dismiss control.
197
+ 24. **Cart-level error** — Errors not attributable to a line, code, note, or attribute appear in the banner.
198
+ 25. **Orphaned line error** — If a line no longer exists in `state.data.lines.nodes` but `errors.lines` has an entry for its ID, that error appears in the banner.
199
+ 26. **Dismiss and re-trigger** — Dismissing the banner hides it. A subsequent error (with a newer `lastUpdatedAt`) re-shows it.
200
+
201
+ ### Totals
202
+
203
+ 27. **Pending totals** — While any line or discount mutation is in-flight, subtotal and total appear in their pending visual state. The amounts shown are the last server-confirmed values — never client-computed.
204
+ 28. **Settled totals** — After an ordinary mutation settles, totals display the latest server values. Overlapping mutation bursts retain pending styling and the last trustworthy amounts while one authoritative cart refresh is in flight.
205
+
206
+ ### Loading
207
+
208
+ 29. **Initial load** — Before the cart is fetched, show skeleton placeholders.
209
+ 30. **Empty cart** — After fetch completes with zero lines, show empty state.
210
+
211
+ ### Out-of-band mutations
212
+
213
+ 31. **Refresh custom data** — After an app-owned cart mutation succeeds, request a cart refresh. Every cart consumer receives the updated custom fragment data, `revalidating` represents the refresh, and a refresh failure preserves the confirmed cart while appearing in `errors.network`.
214
+
215
+ ---
216
+
217
+ ## Anti-patterns
218
+
219
+ - **Hand-rolled framework cart state.** If the skill has a matching framework reference, use its provider/hooks/helpers. Otherwise, use the core store directly instead of duplicating cart data in component state or custom reducers.
220
+ - **Client-seeded `/cart` page.** Mounting `CartProvider` with no `initialData` (or reading the cart only through a `"use client"` `useCart` hook) leaves the SSR HTML empty, so the `/cart` page cannot render the server cart. Read the cart in the server data path and pass `initialData`. Use resolved `initialData` when strict no-JS live cart HTML is required; use promise `initialData` when the framework can stream and hydrated cart content is wrapped in Suspense.
221
+ - **Quantity as text only.** Rendering quantity as a `<span>` with only plus/minus buttons breaks the set-quantity path and the no-JS fallback. Use a real input wired with `register("quantity", { value, interactive: true })`.
222
+ - **Plus/minus-only line forms.** Increase/decrease/remove buttons do not replace `register("set")` and the interactive quantity input. Omitting them breaks the form invariant even if hydrated clicks appear to work.
223
+ - **Drawer-specific line form drift.** The cart drawer may have a different layout from the `/cart` page, but its line item forms must keep the same Hydrogen form contract. Prefer sharing line item form components between the page and drawer.
224
+ - **Banner-only errors.** A line-level error displayed far from the line it refers to is effectively invisible. Show inline first; promote to the banner only when there's no inline target.