@shopify/hydrogen 2026.10.0-preview.4 → 2026.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/dist/cli/index.mjs +23 -12
  2. package/dist/client/client.d.mts +18 -15
  3. package/dist/client/client.mjs +8 -3
  4. package/dist/client/client.mjs.map +1 -1
  5. package/dist/client/errors.d.mts +35 -13
  6. package/dist/client/errors.mjs +23 -13
  7. package/dist/client/errors.mjs.map +1 -1
  8. package/dist/client/types.d.mts +140 -90
  9. package/dist/core/analytics/cart-tracker.d.mts +19 -10
  10. package/dist/core/analytics/cart-tracker.mjs +18 -10
  11. package/dist/core/analytics/cart-tracker.mjs.map +1 -1
  12. package/dist/core/analytics/events.d.mts +17 -11
  13. package/dist/core/analytics/events.mjs +13 -4
  14. package/dist/core/analytics/events.mjs.map +1 -1
  15. package/dist/core/analytics/types.d.mts +207 -118
  16. package/dist/core/analytics/utils/flatten-connection.d.mts +11 -9
  17. package/dist/core/analytics/utils/flatten-connection.mjs +7 -6
  18. package/dist/core/analytics/utils/flatten-connection.mjs.map +1 -1
  19. package/dist/core/cache/fetch-with-cache.d.mts +24 -4
  20. package/dist/core/cache/fetch-with-cache.mjs +17 -2
  21. package/dist/core/cache/fetch-with-cache.mjs.map +1 -1
  22. package/dist/core/cache/key.d.mts +2 -0
  23. package/dist/core/cache/key.mjs.map +1 -1
  24. package/dist/core/cache/run-with-cache.d.mts +56 -8
  25. package/dist/core/cache/run-with-cache.mjs +17 -6
  26. package/dist/core/cache/run-with-cache.mjs.map +1 -1
  27. package/dist/core/cache/store.d.mts +8 -6
  28. package/dist/core/cache/store.mjs.map +1 -1
  29. package/dist/core/cache/strategies.d.mts +27 -2
  30. package/dist/core/cache/strategies.mjs +6 -0
  31. package/dist/core/cache/strategies.mjs.map +1 -1
  32. package/dist/core/cart/actions.d.mts +37 -30
  33. package/dist/core/cart/actions.mjs +21 -9
  34. package/dist/core/cart/actions.mjs.map +1 -1
  35. package/dist/core/cart/attach-quantity-input.d.mts +8 -7
  36. package/dist/core/cart/attach-quantity-input.mjs +8 -7
  37. package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
  38. package/dist/core/cart/buyer-identity-sync.d.mts +7 -6
  39. package/dist/core/cart/buyer-identity-sync.mjs.map +1 -1
  40. package/dist/core/cart/cart.d.mts +59 -46
  41. package/dist/core/cart/cart.mjs +46 -29
  42. package/dist/core/cart/cart.mjs.map +1 -1
  43. package/dist/core/cart/cookie.d.mts +8 -4
  44. package/dist/core/cart/cookie.mjs +8 -4
  45. package/dist/core/cart/cookie.mjs.map +1 -1
  46. package/dist/core/cart/form.d.mts +34 -20
  47. package/dist/core/cart/form.mjs +6 -4
  48. package/dist/core/cart/form.mjs.map +1 -1
  49. package/dist/core/cart/get-cart.d.mts +27 -15
  50. package/dist/core/cart/get-cart.mjs +13 -8
  51. package/dist/core/cart/get-cart.mjs.map +1 -1
  52. package/dist/core/cart/quantity.d.mts +16 -5
  53. package/dist/core/cart/quantity.mjs +16 -5
  54. package/dist/core/cart/quantity.mjs.map +1 -1
  55. package/dist/core/cart/queries.d.mts +25 -19
  56. package/dist/core/cart/queries.mjs +15 -1
  57. package/dist/core/cart/queries.mjs.map +1 -1
  58. package/dist/core/cart/server-handlers.d.mts +82 -45
  59. package/dist/core/cart/server-handlers.mjs +4 -0
  60. package/dist/core/cart/server-handlers.mjs.map +1 -1
  61. package/dist/core/cart/state.d.mts +110 -64
  62. package/dist/core/cart/state.mjs +24 -6
  63. package/dist/core/cart/state.mjs.map +1 -1
  64. package/dist/core/collection/collection.d.mts +52 -53
  65. package/dist/core/collection/collection.mjs +5 -3
  66. package/dist/core/collection/collection.mjs.map +1 -1
  67. package/dist/core/collection/reconciler.d.mts +23 -16
  68. package/dist/core/collection/reconciler.mjs +8 -4
  69. package/dist/core/collection/reconciler.mjs.map +1 -1
  70. package/dist/core/collection/state.d.mts +31 -26
  71. package/dist/core/collection/state.mjs +4 -3
  72. package/dist/core/collection/state.mjs.map +1 -1
  73. package/dist/core/collection/url.d.mts +70 -29
  74. package/dist/core/collection/url.mjs +63 -25
  75. package/dist/core/collection/url.mjs.map +1 -1
  76. package/dist/core/constants.d.mts +1 -0
  77. package/dist/core/constants.mjs +1 -0
  78. package/dist/core/constants.mjs.map +1 -1
  79. package/dist/core/logging/logging.d.mts +14 -8
  80. package/dist/core/logging/logging.mjs +15 -10
  81. package/dist/core/logging/logging.mjs.map +1 -1
  82. package/dist/core/logging/types.d.mts +28 -11
  83. package/dist/core/logging/types.mjs.map +1 -1
  84. package/dist/core/money/format.d.mts +6 -4
  85. package/dist/core/money/format.mjs +19 -9
  86. package/dist/core/money/format.mjs.map +1 -1
  87. package/dist/core/money/types.d.mts +41 -25
  88. package/dist/core/predictive-search/form.d.mts +37 -7
  89. package/dist/core/predictive-search/form.mjs +21 -3
  90. package/dist/core/predictive-search/form.mjs.map +1 -1
  91. package/dist/core/predictive-search/queries.d.mts +18 -30
  92. package/dist/core/predictive-search/queries.mjs +7 -3
  93. package/dist/core/predictive-search/queries.mjs.map +1 -1
  94. package/dist/core/predictive-search/search.d.mts +25 -27
  95. package/dist/core/predictive-search/search.mjs +20 -19
  96. package/dist/core/predictive-search/search.mjs.map +1 -1
  97. package/dist/core/predictive-search/server-handlers.d.mts +25 -26
  98. package/dist/core/predictive-search/server-handlers.mjs +4 -0
  99. package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
  100. package/dist/core/predictive-search/store.d.mts +65 -24
  101. package/dist/core/predictive-search/store.mjs +12 -1
  102. package/dist/core/predictive-search/store.mjs.map +1 -1
  103. package/dist/core/predictive-search/url.d.mts +36 -37
  104. package/dist/core/predictive-search/url.mjs +14 -6
  105. package/dist/core/predictive-search/url.mjs.map +1 -1
  106. package/dist/core/product/form.d.mts +63 -16
  107. package/dist/core/product/form.mjs +8 -2
  108. package/dist/core/product/form.mjs.map +1 -1
  109. package/dist/core/product/options.d.mts +8 -10
  110. package/dist/core/product/options.mjs +8 -10
  111. package/dist/core/product/options.mjs.map +1 -1
  112. package/dist/core/product/product-form.d.mts +77 -29
  113. package/dist/core/product/product-form.mjs +32 -10
  114. package/dist/core/product/product-form.mjs.map +1 -1
  115. package/dist/core/product/state.d.mts +55 -32
  116. package/dist/core/product/url.d.mts +19 -13
  117. package/dist/core/product/url.mjs +10 -10
  118. package/dist/core/product/url.mjs.map +1 -1
  119. package/dist/core/request-context.d.mts +77 -19
  120. package/dist/core/request-context.mjs +5 -1
  121. package/dist/core/request-context.mjs.map +1 -1
  122. package/dist/core/request-routing/handle-shopify-redirects.d.mts +12 -4
  123. package/dist/core/request-routing/handle-shopify-redirects.mjs +9 -2
  124. package/dist/core/request-routing/handle-shopify-redirects.mjs.map +1 -1
  125. package/dist/core/request-routing/handle-shopify-routes.d.mts +5 -5
  126. package/dist/core/request-routing/handle-shopify-routes.mjs +7 -5
  127. package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  128. package/dist/core/request-routing/interceptors/proxy.mjs +79 -43
  129. package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
  130. package/dist/core/request-routing/interceptors/ucp-profile-proxy.mjs +69 -0
  131. package/dist/core/request-routing/interceptors/ucp-profile-proxy.mjs.map +1 -0
  132. package/dist/core/request-routing/interceptors/url-redirects.mjs +6 -1
  133. package/dist/core/request-routing/interceptors/url-redirects.mjs.map +1 -1
  134. package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
  135. package/dist/core/request-routing/interceptors/well-known.mjs.map +1 -1
  136. package/dist/core/request-routing/registered-routes.d.mts +12 -0
  137. package/dist/core/request-routing/registered-routes.mjs +12 -0
  138. package/dist/core/request-routing/registered-routes.mjs.map +1 -1
  139. package/dist/core/request-routing/route-types.d.mts +43 -18
  140. package/dist/core/shop-pay/shop-pay.d.mts +71 -35
  141. package/dist/core/shop-pay/shop-pay.mjs +36 -10
  142. package/dist/core/shop-pay/shop-pay.mjs.map +1 -1
  143. package/dist/core/shopify-scripts/index.d.mts +15 -5
  144. package/dist/core/shopify-scripts/index.mjs +15 -5
  145. package/dist/core/shopify-scripts/index.mjs.map +1 -1
  146. package/dist/core/shopify-scripts/initialize.d.mts +12 -4
  147. package/dist/core/shopify-scripts/initialize.mjs +12 -4
  148. package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
  149. package/dist/core/shopify-scripts/types.d.mts +58 -25
  150. package/dist/core/standard-routes/build.d.mts +11 -12
  151. package/dist/core/standard-routes/build.mjs +11 -12
  152. package/dist/core/standard-routes/build.mjs.map +1 -1
  153. package/dist/core/standard-routes/types.d.mts +30 -24
  154. package/dist/core/url.mjs +2 -1
  155. package/dist/core/url.mjs.map +1 -1
  156. package/dist/customer-account/client.d.mts +36 -69
  157. package/dist/customer-account/client.mjs +7 -8
  158. package/dist/customer-account/client.mjs.map +1 -1
  159. package/dist/customer-account/errors.d.mts +45 -36
  160. package/dist/customer-account/errors.mjs +21 -36
  161. package/dist/customer-account/errors.mjs.map +1 -1
  162. package/dist/customer-account/graphql.d.mts +11 -23
  163. package/dist/customer-account/graphql.mjs +3 -9
  164. package/dist/customer-account/graphql.mjs.map +1 -1
  165. package/dist/customer-account/session.d.mts +130 -100
  166. package/dist/customer-account/session.mjs +32 -10
  167. package/dist/customer-account/session.mjs.map +1 -1
  168. package/dist/customer-account/type-resolver.d.mts +7 -8
  169. package/dist/development/client/client.d.mts +18 -15
  170. package/dist/development/client/client.mjs +8 -3
  171. package/dist/development/client/client.mjs.map +1 -1
  172. package/dist/development/client/errors.d.mts +35 -13
  173. package/dist/development/client/errors.mjs +23 -13
  174. package/dist/development/client/errors.mjs.map +1 -1
  175. package/dist/development/client/types.d.mts +140 -90
  176. package/dist/development/core/analytics/cart-tracker.d.mts +19 -10
  177. package/dist/development/core/analytics/cart-tracker.mjs +18 -10
  178. package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
  179. package/dist/development/core/analytics/events.d.mts +17 -11
  180. package/dist/development/core/analytics/events.mjs +13 -4
  181. package/dist/development/core/analytics/events.mjs.map +1 -1
  182. package/dist/development/core/analytics/types.d.mts +207 -118
  183. package/dist/development/core/analytics/utils/flatten-connection.d.mts +11 -9
  184. package/dist/development/core/analytics/utils/flatten-connection.mjs +7 -6
  185. package/dist/development/core/analytics/utils/flatten-connection.mjs.map +1 -1
  186. package/dist/development/core/cache/fetch-with-cache.d.mts +24 -4
  187. package/dist/development/core/cache/fetch-with-cache.mjs +17 -2
  188. package/dist/development/core/cache/fetch-with-cache.mjs.map +1 -1
  189. package/dist/development/core/cache/key.d.mts +2 -0
  190. package/dist/development/core/cache/key.mjs.map +1 -1
  191. package/dist/development/core/cache/run-with-cache.d.mts +56 -8
  192. package/dist/development/core/cache/run-with-cache.mjs +17 -6
  193. package/dist/development/core/cache/run-with-cache.mjs.map +1 -1
  194. package/dist/development/core/cache/store.d.mts +8 -6
  195. package/dist/development/core/cache/store.mjs.map +1 -1
  196. package/dist/development/core/cache/strategies.d.mts +27 -2
  197. package/dist/development/core/cache/strategies.mjs +6 -0
  198. package/dist/development/core/cache/strategies.mjs.map +1 -1
  199. package/dist/development/core/cart/actions.d.mts +37 -30
  200. package/dist/development/core/cart/actions.mjs +21 -9
  201. package/dist/development/core/cart/actions.mjs.map +1 -1
  202. package/dist/development/core/cart/attach-quantity-input.d.mts +8 -7
  203. package/dist/development/core/cart/attach-quantity-input.mjs +8 -7
  204. package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
  205. package/dist/development/core/cart/buyer-identity-sync.d.mts +6 -5
  206. package/dist/development/core/cart/buyer-identity-sync.mjs.map +1 -1
  207. package/dist/development/core/cart/cart.d.mts +59 -46
  208. package/dist/development/core/cart/cart.mjs +46 -29
  209. package/dist/development/core/cart/cart.mjs.map +1 -1
  210. package/dist/development/core/cart/cookie.d.mts +8 -4
  211. package/dist/development/core/cart/cookie.mjs +8 -4
  212. package/dist/development/core/cart/cookie.mjs.map +1 -1
  213. package/dist/development/core/cart/form.d.mts +34 -20
  214. package/dist/development/core/cart/form.mjs +6 -4
  215. package/dist/development/core/cart/form.mjs.map +1 -1
  216. package/dist/development/core/cart/get-cart.d.mts +27 -15
  217. package/dist/development/core/cart/get-cart.mjs +13 -8
  218. package/dist/development/core/cart/get-cart.mjs.map +1 -1
  219. package/dist/development/core/cart/quantity.d.mts +16 -5
  220. package/dist/development/core/cart/quantity.mjs +16 -5
  221. package/dist/development/core/cart/quantity.mjs.map +1 -1
  222. package/dist/development/core/cart/queries.d.mts +25 -19
  223. package/dist/development/core/cart/queries.mjs +15 -1
  224. package/dist/development/core/cart/queries.mjs.map +1 -1
  225. package/dist/development/core/cart/server-handlers.d.mts +82 -45
  226. package/dist/development/core/cart/server-handlers.mjs +4 -0
  227. package/dist/development/core/cart/server-handlers.mjs.map +1 -1
  228. package/dist/development/core/cart/state.d.mts +110 -64
  229. package/dist/development/core/cart/state.mjs +24 -6
  230. package/dist/development/core/cart/state.mjs.map +1 -1
  231. package/dist/development/core/collection/collection.d.mts +52 -53
  232. package/dist/development/core/collection/collection.mjs +5 -3
  233. package/dist/development/core/collection/collection.mjs.map +1 -1
  234. package/dist/development/core/collection/reconciler.d.mts +23 -16
  235. package/dist/development/core/collection/reconciler.mjs +8 -4
  236. package/dist/development/core/collection/reconciler.mjs.map +1 -1
  237. package/dist/development/core/collection/state.d.mts +31 -26
  238. package/dist/development/core/collection/state.mjs +4 -3
  239. package/dist/development/core/collection/state.mjs.map +1 -1
  240. package/dist/development/core/collection/url.d.mts +70 -29
  241. package/dist/development/core/collection/url.mjs +63 -25
  242. package/dist/development/core/collection/url.mjs.map +1 -1
  243. package/dist/development/core/constants.mjs.map +1 -1
  244. package/dist/development/core/logging/logging.d.mts +14 -8
  245. package/dist/development/core/logging/logging.mjs +15 -10
  246. package/dist/development/core/logging/logging.mjs.map +1 -1
  247. package/dist/development/core/logging/types.d.mts +28 -11
  248. package/dist/development/core/logging/types.mjs.map +1 -1
  249. package/dist/development/core/money/format.d.mts +6 -4
  250. package/dist/development/core/money/format.mjs +19 -9
  251. package/dist/development/core/money/format.mjs.map +1 -1
  252. package/dist/development/core/money/types.d.mts +41 -25
  253. package/dist/development/core/predictive-search/form.d.mts +37 -7
  254. package/dist/development/core/predictive-search/form.mjs +21 -3
  255. package/dist/development/core/predictive-search/form.mjs.map +1 -1
  256. package/dist/development/core/predictive-search/queries.d.mts +18 -30
  257. package/dist/development/core/predictive-search/queries.mjs +7 -3
  258. package/dist/development/core/predictive-search/queries.mjs.map +1 -1
  259. package/dist/development/core/predictive-search/search.d.mts +25 -27
  260. package/dist/development/core/predictive-search/search.mjs +20 -19
  261. package/dist/development/core/predictive-search/search.mjs.map +1 -1
  262. package/dist/development/core/predictive-search/server-handlers.d.mts +25 -26
  263. package/dist/development/core/predictive-search/server-handlers.mjs +4 -0
  264. package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
  265. package/dist/development/core/predictive-search/store.d.mts +65 -24
  266. package/dist/development/core/predictive-search/store.mjs +12 -1
  267. package/dist/development/core/predictive-search/store.mjs.map +1 -1
  268. package/dist/development/core/predictive-search/url.d.mts +36 -37
  269. package/dist/development/core/predictive-search/url.mjs +14 -6
  270. package/dist/development/core/predictive-search/url.mjs.map +1 -1
  271. package/dist/development/core/product/form.d.mts +63 -16
  272. package/dist/development/core/product/form.mjs +8 -2
  273. package/dist/development/core/product/form.mjs.map +1 -1
  274. package/dist/development/core/product/options.d.mts +8 -10
  275. package/dist/development/core/product/options.mjs +8 -10
  276. package/dist/development/core/product/options.mjs.map +1 -1
  277. package/dist/development/core/product/product-form.d.mts +77 -29
  278. package/dist/development/core/product/product-form.mjs +32 -10
  279. package/dist/development/core/product/product-form.mjs.map +1 -1
  280. package/dist/development/core/product/state.d.mts +55 -32
  281. package/dist/development/core/product/url.d.mts +19 -13
  282. package/dist/development/core/product/url.mjs +10 -10
  283. package/dist/development/core/product/url.mjs.map +1 -1
  284. package/dist/development/core/request-context.d.mts +77 -19
  285. package/dist/development/core/request-context.mjs +5 -1
  286. package/dist/development/core/request-context.mjs.map +1 -1
  287. package/dist/development/core/request-routing/handle-shopify-redirects.d.mts +12 -4
  288. package/dist/development/core/request-routing/handle-shopify-redirects.mjs +9 -2
  289. package/dist/development/core/request-routing/handle-shopify-redirects.mjs.map +1 -1
  290. package/dist/development/core/request-routing/handle-shopify-routes.development.d.mts +9 -1
  291. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs +7 -0
  292. package/dist/development/core/request-routing/handle-shopify-routes.development.mjs.map +1 -1
  293. package/dist/development/core/request-routing/handle-shopify-routes.mjs +7 -5
  294. package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
  295. package/dist/development/core/request-routing/interceptors/proxy.mjs +79 -43
  296. package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
  297. package/dist/development/core/request-routing/interceptors/ucp-profile-proxy.mjs +69 -0
  298. package/dist/development/core/request-routing/interceptors/ucp-profile-proxy.mjs.map +1 -0
  299. package/dist/development/core/request-routing/interceptors/url-redirects.mjs +6 -1
  300. package/dist/development/core/request-routing/interceptors/url-redirects.mjs.map +1 -1
  301. package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
  302. package/dist/development/core/request-routing/interceptors/well-known.mjs.map +1 -1
  303. package/dist/development/core/request-routing/registered-routes.d.mts +12 -0
  304. package/dist/development/core/request-routing/registered-routes.mjs +12 -0
  305. package/dist/development/core/request-routing/registered-routes.mjs.map +1 -1
  306. package/dist/development/core/request-routing/route-types.d.mts +43 -18
  307. package/dist/development/core/shop-pay/shop-pay.d.mts +71 -35
  308. package/dist/development/core/shop-pay/shop-pay.mjs +36 -10
  309. package/dist/development/core/shop-pay/shop-pay.mjs.map +1 -1
  310. package/dist/development/core/shopify-scripts/index.d.mts +15 -5
  311. package/dist/development/core/shopify-scripts/index.mjs +15 -5
  312. package/dist/development/core/shopify-scripts/index.mjs.map +1 -1
  313. package/dist/development/core/shopify-scripts/initialize.d.mts +12 -4
  314. package/dist/development/core/shopify-scripts/initialize.mjs +12 -4
  315. package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
  316. package/dist/development/core/shopify-scripts/types.d.mts +58 -25
  317. package/dist/development/core/standard-routes/build.d.mts +11 -12
  318. package/dist/development/core/standard-routes/build.mjs +11 -12
  319. package/dist/development/core/standard-routes/build.mjs.map +1 -1
  320. package/dist/development/core/standard-routes/types.d.mts +30 -24
  321. package/dist/development/core/url.mjs +2 -1
  322. package/dist/development/core/url.mjs.map +1 -1
  323. package/dist/development/customer-account/session.d.mts +45 -54
  324. package/dist/development/customer-account/session.mjs +20 -4
  325. package/dist/development/customer-account/session.mjs.map +1 -1
  326. package/dist/development/globals.d.mts +20 -11
  327. package/dist/development/graphql/generated/storefront-api-types.d.mts +127 -1
  328. package/dist/development/graphql/graphql.d.mts +17 -16
  329. package/dist/development/graphql/graphql.mjs +7 -8
  330. package/dist/development/graphql/graphql.mjs.map +1 -1
  331. package/dist/development/graphql/type-resolver.d.mts +15 -8
  332. package/dist/development/react/cart.d.mts +78 -32
  333. package/dist/development/react/cart.mjs +56 -29
  334. package/dist/development/react/cart.mjs.map +1 -1
  335. package/dist/development/react/collection.d.mts +40 -22
  336. package/dist/development/react/collection.mjs +27 -7
  337. package/dist/development/react/collection.mjs.map +1 -1
  338. package/dist/development/react/predictive-search.d.mts +65 -50
  339. package/dist/development/react/predictive-search.mjs +23 -21
  340. package/dist/development/react/predictive-search.mjs.map +1 -1
  341. package/dist/development/react/product.d.mts +45 -16
  342. package/dist/development/react/product.mjs +13 -11
  343. package/dist/development/react/product.mjs.map +1 -1
  344. package/dist/development/react/shop-pay.d.mts +15 -0
  345. package/dist/development/react/shop-pay.mjs +9 -0
  346. package/dist/development/react/shop-pay.mjs.map +1 -1
  347. package/dist/development/react/shopify-scripts.d.mts +23 -2
  348. package/dist/development/react/shopify-scripts.mjs +9 -0
  349. package/dist/development/react/shopify-scripts.mjs.map +1 -1
  350. package/dist/development/vue/cart.d.mts +28 -23
  351. package/dist/development/vue/cart.mjs +42 -25
  352. package/dist/development/vue/cart.mjs.map +1 -1
  353. package/dist/development/vue/collection.d.mts +20 -12
  354. package/dist/development/vue/collection.mjs +15 -7
  355. package/dist/development/vue/collection.mjs.map +1 -1
  356. package/dist/development/vue/index.d.mts +2 -2
  357. package/dist/development/vue/index.mjs +2 -2
  358. package/dist/development/vue/predictive-search.d.mts +31 -36
  359. package/dist/development/vue/predictive-search.mjs +16 -22
  360. package/dist/development/vue/predictive-search.mjs.map +1 -1
  361. package/dist/development/vue/product.d.mts +16 -15
  362. package/dist/development/vue/product.mjs +11 -11
  363. package/dist/development/vue/product.mjs.map +1 -1
  364. package/dist/development/vue/shop-pay.d.mts +14 -17
  365. package/dist/development/vue/shop-pay.mjs +8 -0
  366. package/dist/development/vue/shop-pay.mjs.map +1 -1
  367. package/dist/development/vue/shopify-scripts.d.mts +11 -0
  368. package/dist/development/vue/shopify-scripts.mjs +6 -0
  369. package/dist/development/vue/shopify-scripts.mjs.map +1 -1
  370. package/dist/globals.d.mts +20 -11
  371. package/dist/graphql/generated/storefront-api-types.d.mts +127 -1
  372. package/dist/graphql/graphql.d.mts +17 -16
  373. package/dist/graphql/graphql.mjs +7 -8
  374. package/dist/graphql/graphql.mjs.map +1 -1
  375. package/dist/graphql/type-resolver.d.mts +15 -8
  376. package/dist/react/cart.d.mts +78 -32
  377. package/dist/react/cart.mjs +56 -29
  378. package/dist/react/cart.mjs.map +1 -1
  379. package/dist/react/collection.d.mts +40 -22
  380. package/dist/react/collection.mjs +27 -7
  381. package/dist/react/collection.mjs.map +1 -1
  382. package/dist/react/predictive-search.d.mts +65 -50
  383. package/dist/react/predictive-search.mjs +23 -21
  384. package/dist/react/predictive-search.mjs.map +1 -1
  385. package/dist/react/product.d.mts +45 -16
  386. package/dist/react/product.mjs +13 -11
  387. package/dist/react/product.mjs.map +1 -1
  388. package/dist/react/shop-pay.d.mts +15 -0
  389. package/dist/react/shop-pay.mjs +9 -0
  390. package/dist/react/shop-pay.mjs.map +1 -1
  391. package/dist/react/shopify-scripts.d.mts +23 -2
  392. package/dist/react/shopify-scripts.mjs +9 -0
  393. package/dist/react/shopify-scripts.mjs.map +1 -1
  394. package/dist/ts-plugin/index.cjs +6 -0
  395. package/dist/ts-plugin/index.cjs.map +1 -1
  396. package/dist/ts-plugin/index.d.cts +6 -0
  397. package/dist/vite/local-https.d.mts +51 -17
  398. package/dist/vite/local-https.mjs +26 -5
  399. package/dist/vite/local-https.mjs.map +1 -1
  400. package/dist/vue/cart.d.mts +28 -23
  401. package/dist/vue/cart.mjs +42 -25
  402. package/dist/vue/cart.mjs.map +1 -1
  403. package/dist/vue/collection.d.mts +20 -12
  404. package/dist/vue/collection.mjs +15 -7
  405. package/dist/vue/collection.mjs.map +1 -1
  406. package/dist/vue/index.d.mts +2 -2
  407. package/dist/vue/index.mjs +2 -2
  408. package/dist/vue/predictive-search.d.mts +31 -36
  409. package/dist/vue/predictive-search.mjs +16 -22
  410. package/dist/vue/predictive-search.mjs.map +1 -1
  411. package/dist/vue/product.d.mts +16 -15
  412. package/dist/vue/product.mjs +11 -11
  413. package/dist/vue/product.mjs.map +1 -1
  414. package/dist/vue/shop-pay.d.mts +14 -17
  415. package/dist/vue/shop-pay.mjs +8 -0
  416. package/dist/vue/shop-pay.mjs.map +1 -1
  417. package/dist/vue/shopify-scripts.d.mts +11 -0
  418. package/dist/vue/shopify-scripts.mjs +6 -0
  419. package/dist/vue/shopify-scripts.mjs.map +1 -1
  420. package/package.json +3 -1
  421. package/skills/hydrogen-analytics/SKILL.md +1 -1
  422. package/skills/hydrogen-cart-ui/SKILL.md +28 -2
  423. package/skills/hydrogen-collection-browser/SKILL.md +9 -1
  424. package/skills/hydrogen-collection-browser/references/nextjs.md +1 -1
  425. package/skills/hydrogen-collection-browser/references/nuxt.md +1 -1
  426. package/skills/hydrogen-collection-browser/references/react.md +151 -32
  427. package/skills/hydrogen-customer-account/SKILL.md +2 -0
  428. package/skills/hydrogen-request-handlers/SKILL.md +21 -11
  429. package/skills/hydrogen-setup/references/analytics.md +14 -8
  430. package/skills/hydrogen-setup/steps/1-inspect-app.md +2 -2
  431. package/skills/hydrogen-setup/steps/6-product-detail-page.md +21 -11
  432. package/skills/hydrogen-storefront-client/SKILL.md +1 -1
  433. package/skills/hydrogen-storefront-client/references/caching.md +2 -0
  434. package/skills/hydrogen-variant-form/SKILL.md +25 -7
  435. package/skills/hydrogen-variant-form/references/nextjs.md +39 -4
  436. package/skills/hydrogen-variant-form/references/nuxt.md +83 -42
  437. package/skills/hydrogen-variant-form/references/react.md +45 -9
@@ -1 +1 @@
1
- {"version":3,"file":"cart-tracker.mjs","names":[],"sources":["../../../../src/core/analytics/cart-tracker.ts"],"sourcesContent":["import type { CartStore } from \"../cart/cart\";\nimport type { CartData, CartState } from \"../cart/state\";\nimport { AnalyticsEvent } from \"./events\";\nimport type {\n AnalyticsCart,\n AnalyticsCartLine,\n CartUpdatePayload,\n StorefrontAnalytics,\n} from \"./types\";\nimport { flattenConnection } from \"./utils/flatten-connection\";\n\ntype CartTrackerAnalytics = Pick<StorefrontAnalytics, \"publish\" | \"getConfig\">;\ntype CartAnalyticsStore = Pick<CartStore, \"getState\" | \"subscribe\">;\n\ntype CartStorage = {\n updatedAt: string;\n id: string;\n};\n\ntype CartTrackerState = {\n prevCart: AnalyticsCart | null;\n lastEventId: string | null;\n};\n\n/**\n * Subscribes to a cart store and publishes analytics events when the cart changes.\n *\n * Emits `cart_updated` whenever a settled cart's `updatedAt` changes, plus\n * `product_added_to_cart` / `product_removed_from_cart` for each line that was\n * added, removed, or changed quantity. Deduplicates on `updatedAt` with an\n * in-memory cursor (within this subscription) and `localStorage` (across full\n * page loads and tabs). A store filled from your own cart query must select\n * `updatedAt`, or deduplication can't work.\n *\n * @throws {Error} If `window.Shopify.analytics` is not set (including on the server).\n * Render `ShopifyScripts` (or the `getShopifyScriptTags()` output) first.\n * @returns An unsubscribe function that stops tracking.\n */\nexport function trackCartAnalytics(store: CartAnalyticsStore): () => void {\n const analytics = getGlobalAnalytics();\n const state: CartTrackerState = {\n prevCart: toAnalyticsCart(store.getState()),\n lastEventId: null,\n };\n\n if (state.prevCart) syncShopifyCurrency(state.prevCart);\n\n return store.subscribe((cartState) => {\n const cart = toAnalyticsCart(cartState);\n if (!cart) return;\n\n trackCartChange(analytics, state, cart);\n });\n}\n\nfunction trackCartChange(\n analytics: CartTrackerAnalytics,\n state: CartTrackerState,\n cart: AnalyticsCart,\n): void {\n if (!cart || !cart.updatedAt) return;\n\n syncShopifyCurrency(cart);\n\n if (cart.updatedAt === state.prevCart?.updatedAt) return;\n\n let cartLastUpdatedAt: CartStorage | null;\n try {\n cartLastUpdatedAt = JSON.parse(localStorage.getItem(\"cartLastUpdatedAt\") || \"\");\n } catch {\n cartLastUpdatedAt = null;\n }\n\n if (cart.id === cartLastUpdatedAt?.id && cart.updatedAt === cartLastUpdatedAt?.updatedAt) {\n state.prevCart = cart;\n return;\n }\n\n if (cart.updatedAt === state.lastEventId) return;\n state.lastEventId = cart.updatedAt;\n\n const config = analytics.getConfig();\n const payload: CartUpdatePayload = {\n eventTimestamp: Date.now(),\n cart,\n prevCart: state.prevCart,\n shop: config.shop,\n customData: config.customData,\n };\n\n analytics.publish(AnalyticsEvent.CART_UPDATED, payload);\n\n try {\n localStorage.setItem(\n \"cartLastUpdatedAt\",\n JSON.stringify({ id: cart.id, updatedAt: cart.updatedAt }),\n );\n } catch {\n // Safari private browsing or storage quota exceeded; analytics\n // deduplication will rely on in-memory prevCart only for this session.\n }\n\n const previousCartLines = flattenConnection<AnalyticsCartLine>(state.prevCart?.lines);\n const currentCartLines = flattenConnection<AnalyticsCartLine>(cart.lines);\n\n previousCartLines.forEach((prevLine) => {\n const matchedLineId = currentCartLines.filter((line) => prevLine.id === line.id);\n if (matchedLineId.length === 1) {\n const matchedLine = matchedLineId[0];\n if (prevLine.quantity < matchedLine.quantity) {\n analytics.publish(AnalyticsEvent.PRODUCT_ADD_TO_CART, {\n ...payload,\n prevLine,\n currentLine: matchedLine,\n });\n } else if (prevLine.quantity > matchedLine.quantity) {\n analytics.publish(AnalyticsEvent.PRODUCT_REMOVED_FROM_CART, {\n ...payload,\n prevLine,\n currentLine: matchedLine,\n });\n }\n } else {\n analytics.publish(AnalyticsEvent.PRODUCT_REMOVED_FROM_CART, {\n ...payload,\n prevLine,\n });\n }\n });\n\n currentCartLines.forEach((line) => {\n const matchedLineId = previousCartLines.filter((previousLine) => line.id === previousLine.id);\n if (!matchedLineId || matchedLineId.length === 0) {\n analytics.publish(AnalyticsEvent.PRODUCT_ADD_TO_CART, {\n ...payload,\n currentLine: line,\n });\n }\n });\n\n state.prevCart = cart;\n}\n\nfunction getGlobalAnalytics(): CartTrackerAnalytics {\n const analytics = typeof window !== \"undefined\" ? window.Shopify?.analytics : undefined;\n if (!analytics) {\n throw new Error(\n \"Shopify analytics bus is not available. Render ShopifyScripts before calling trackCartAnalytics().\",\n );\n }\n\n return analytics;\n}\n\nfunction toAnalyticsCart(state: CartState): AnalyticsCart | null {\n const cart = state.data;\n if (!cart.id || hasPendingCartWork(state)) return null;\n\n return {\n id: cart.id,\n updatedAt: getCartUpdatedAt(cart),\n cost: cart.cost,\n lines: {\n nodes: cart.lines.nodes.flatMap((line): AnalyticsCartLine[] => {\n const merchandise = line.merchandise;\n if (!merchandise) return [];\n\n const product = merchandise.product;\n const productId = typeof product.id === \"string\" ? product.id : \"\";\n const vendor = typeof product.vendor === \"string\" ? product.vendor : \"\";\n const productType =\n typeof product.productType === \"string\" ? product.productType : undefined;\n\n return [\n {\n id: line.id,\n quantity: line.quantity,\n merchandise: {\n id: merchandise.id,\n title: merchandise.title ?? product.title,\n price: line.cost.amountPerQuantity,\n sku: typeof merchandise.sku === \"string\" ? merchandise.sku : null,\n product: {\n id: productId,\n title: product.title,\n vendor,\n productType,\n handle: product.handle,\n },\n },\n },\n ];\n }),\n },\n };\n}\n\nfunction hasPendingCartWork({ pending, revalidating }: CartState): boolean {\n const hasPendingCost = pending.cost ?? (pending.lines.size > 0 || pending.discountCodes.size > 0);\n return revalidating === true || hasPendingCost || pending.note || pending.attributes;\n}\n\nfunction getCartUpdatedAt(cart: CartData): string {\n return cart.updatedAt ?? new Date().toISOString();\n}\n\nfunction syncShopifyCurrency(cart: AnalyticsCart): void {\n if (typeof window === \"undefined\") return;\n\n const currencyCode = getCartCurrencyCode(cart);\n if (!currencyCode) return;\n\n const normalizedCurrencyCode = currencyCode.toUpperCase();\n const shopifyWindow: { Shopify?: { currency?: { active: string } } } = window;\n const shopify = (shopifyWindow.Shopify ??= {});\n if (shopify.currency?.active === normalizedCurrencyCode) return;\n\n shopify.currency = { active: normalizedCurrencyCode };\n}\n\nfunction getCartCurrencyCode(cart: AnalyticsCart): string | undefined {\n return (\n nonEmptyCurrencyCode(cart.cost?.totalAmount?.currencyCode) ??\n nonEmptyCurrencyCode(cart.cost?.subtotalAmount?.currencyCode) ??\n flattenConnection<AnalyticsCartLine>(cart.lines).find(\n (line) => line.merchandise.price.currencyCode,\n )?.merchandise.price.currencyCode\n );\n}\n\nfunction nonEmptyCurrencyCode(currencyCode: string | undefined): string | undefined {\n return currencyCode || undefined;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cart-tracker.mjs","names":[],"sources":["../../../../src/core/analytics/cart-tracker.ts"],"sourcesContent":["import type { CartStore } from \"../cart/cart\";\nimport type { CartData, CartState } from \"../cart/state\";\nimport { AnalyticsEvent } from \"./events\";\nimport type {\n AnalyticsCart,\n AnalyticsCartLine,\n CartUpdatePayload,\n StorefrontAnalytics,\n} from \"./types\";\nimport { flattenConnection } from \"./utils/flatten-connection\";\n\ntype CartTrackerAnalytics = Pick<StorefrontAnalytics, \"publish\" | \"getConfig\">;\n/** A cart store, or any object with the cart store's `getState()` and `subscribe()` methods. */\ntype CartAnalyticsStore = Pick<CartStore, \"getState\" | \"subscribe\">;\n\ntype CartStorage = {\n updatedAt: string;\n id: string;\n};\n\ntype CartTrackerState = {\n prevCart: AnalyticsCart | null;\n lastEventId: string | null;\n};\n\n/**\n * Publishes cart analytics events when the server confirms a change to the customer's cart. In React, call `useCartAnalytics`.\n *\n * The function publishes `cart_updated` when the cart's update time changes, plus\n * `product_added_to_cart` or `product_removed_from_cart` for each added line, removed\n * line, and quantity change. The function waits until no cart change or reload is in flight.\n * Analytics payloads leave out cart lines without merchandise.\n *\n * The function stores the last published cart update in local storage under `cartLastUpdatedAt`\n * to avoid repeat events across page loads and tabs. A store that you fill from your own cart query\n * must select `updatedAt`. Without the update time, the function publishes on every confirmed cart state.\n * The function also sets `window.Shopify.currency.active` to the cart's currency.\n *\n * The function throws when the Shopify analytics bus isn't available, including during server rendering.\n * Render `ShopifyScripts`, then start tracking in a client-only effect, such as `useEffect` or `onMounted`.\n *\n * @param store The cart store to track.\n * @throws {Error} If `window.Shopify.analytics` isn't set, including on the server.\n * Render Shopify's script tags first.\n * @returns A function that stops tracking.\n * @publicDocs\n */\nexport function trackCartAnalytics(store: CartAnalyticsStore): () => void {\n const analytics = getGlobalAnalytics();\n const state: CartTrackerState = {\n prevCart: toAnalyticsCart(store.getState()),\n lastEventId: null,\n };\n\n if (state.prevCart) syncShopifyCurrency(state.prevCart);\n\n return store.subscribe((cartState) => {\n const cart = toAnalyticsCart(cartState);\n if (!cart) return;\n\n trackCartChange(analytics, state, cart);\n });\n}\n\nfunction trackCartChange(\n analytics: CartTrackerAnalytics,\n state: CartTrackerState,\n cart: AnalyticsCart,\n): void {\n if (!cart || !cart.updatedAt) return;\n\n syncShopifyCurrency(cart);\n\n if (cart.updatedAt === state.prevCart?.updatedAt) return;\n\n let cartLastUpdatedAt: CartStorage | null;\n try {\n cartLastUpdatedAt = JSON.parse(localStorage.getItem(\"cartLastUpdatedAt\") || \"\");\n } catch {\n cartLastUpdatedAt = null;\n }\n\n if (cart.id === cartLastUpdatedAt?.id && cart.updatedAt === cartLastUpdatedAt?.updatedAt) {\n state.prevCart = cart;\n return;\n }\n\n if (cart.updatedAt === state.lastEventId) return;\n state.lastEventId = cart.updatedAt;\n\n const config = analytics.getConfig();\n const payload: CartUpdatePayload = {\n eventTimestamp: Date.now(),\n cart,\n prevCart: state.prevCart,\n shop: config.shop,\n customData: config.customData,\n };\n\n analytics.publish(AnalyticsEvent.CART_UPDATED, payload);\n\n try {\n localStorage.setItem(\n \"cartLastUpdatedAt\",\n JSON.stringify({ id: cart.id, updatedAt: cart.updatedAt }),\n );\n } catch {\n // Safari private browsing or storage quota exceeded; analytics\n // deduplication will rely on in-memory prevCart only for this session.\n }\n\n const previousCartLines = flattenConnection<AnalyticsCartLine>(state.prevCart?.lines);\n const currentCartLines = flattenConnection<AnalyticsCartLine>(cart.lines);\n\n previousCartLines.forEach((prevLine) => {\n const matchedLineId = currentCartLines.filter((line) => prevLine.id === line.id);\n if (matchedLineId.length === 1) {\n const matchedLine = matchedLineId[0];\n if (prevLine.quantity < matchedLine.quantity) {\n analytics.publish(AnalyticsEvent.PRODUCT_ADD_TO_CART, {\n ...payload,\n prevLine,\n currentLine: matchedLine,\n });\n } else if (prevLine.quantity > matchedLine.quantity) {\n analytics.publish(AnalyticsEvent.PRODUCT_REMOVED_FROM_CART, {\n ...payload,\n prevLine,\n currentLine: matchedLine,\n });\n }\n } else {\n analytics.publish(AnalyticsEvent.PRODUCT_REMOVED_FROM_CART, {\n ...payload,\n prevLine,\n });\n }\n });\n\n currentCartLines.forEach((line) => {\n const matchedLineId = previousCartLines.filter((previousLine) => line.id === previousLine.id);\n if (!matchedLineId || matchedLineId.length === 0) {\n analytics.publish(AnalyticsEvent.PRODUCT_ADD_TO_CART, {\n ...payload,\n currentLine: line,\n });\n }\n });\n\n state.prevCart = cart;\n}\n\nfunction getGlobalAnalytics(): CartTrackerAnalytics {\n const analytics = typeof window !== \"undefined\" ? window.Shopify?.analytics : undefined;\n if (!analytics) {\n throw new Error(\n \"Shopify analytics bus is not available. Render ShopifyScripts before calling trackCartAnalytics().\",\n );\n }\n\n return analytics;\n}\n\nfunction toAnalyticsCart(state: CartState): AnalyticsCart | null {\n const cart = state.data;\n if (!cart.id || hasPendingCartWork(state)) return null;\n\n return {\n id: cart.id,\n updatedAt: getCartUpdatedAt(cart),\n cost: cart.cost,\n lines: {\n nodes: cart.lines.nodes.flatMap((line): AnalyticsCartLine[] => {\n const merchandise = line.merchandise;\n if (!merchandise) return [];\n\n const product = merchandise.product;\n const productId = typeof product.id === \"string\" ? product.id : \"\";\n const vendor = typeof product.vendor === \"string\" ? product.vendor : \"\";\n const productType =\n typeof product.productType === \"string\" ? product.productType : undefined;\n\n return [\n {\n id: line.id,\n quantity: line.quantity,\n merchandise: {\n id: merchandise.id,\n title: merchandise.title ?? product.title,\n price: line.cost.amountPerQuantity,\n sku: typeof merchandise.sku === \"string\" ? merchandise.sku : null,\n product: {\n id: productId,\n title: product.title,\n vendor,\n productType,\n handle: product.handle,\n },\n },\n },\n ];\n }),\n },\n };\n}\n\nfunction hasPendingCartWork({ pending, revalidating }: CartState): boolean {\n const hasPendingCost = pending.cost ?? (pending.lines.size > 0 || pending.discountCodes.size > 0);\n return revalidating === true || hasPendingCost || pending.note || pending.attributes;\n}\n\nfunction getCartUpdatedAt(cart: CartData): string {\n return cart.updatedAt ?? new Date().toISOString();\n}\n\nfunction syncShopifyCurrency(cart: AnalyticsCart): void {\n if (typeof window === \"undefined\") return;\n\n const currencyCode = getCartCurrencyCode(cart);\n if (!currencyCode) return;\n\n const normalizedCurrencyCode = currencyCode.toUpperCase();\n const shopifyWindow: { Shopify?: { currency?: { active: string } } } = window;\n const shopify = (shopifyWindow.Shopify ??= {});\n if (shopify.currency?.active === normalizedCurrencyCode) return;\n\n shopify.currency = { active: normalizedCurrencyCode };\n}\n\nfunction getCartCurrencyCode(cart: AnalyticsCart): string | undefined {\n return (\n nonEmptyCurrencyCode(cart.cost?.totalAmount?.currencyCode) ??\n nonEmptyCurrencyCode(cart.cost?.subtotalAmount?.currencyCode) ??\n flattenConnection<AnalyticsCartLine>(cart.lines).find(\n (line) => line.merchandise.price.currencyCode,\n )?.merchandise.price.currencyCode\n );\n}\n\nfunction nonEmptyCurrencyCode(currencyCode: string | undefined): string | undefined {\n return currencyCode || undefined;\n}\n"],"mappings":"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"}
@@ -1,21 +1,27 @@
1
1
  //#region src/core/analytics/events.d.ts
2
2
  /**
3
- * Canonical event names for the Hydrogen analytics bus.
3
+ * The names of the analytics events that Hydrogen supports.
4
4
  *
5
- * Use these as the `event` argument to `publish()` and a destination's `subscribe()`. Raw string
6
- * literals are type-checked and narrow the payload the same way; the constants add
7
- * autocomplete and a single place to rename.
5
+ * Pass a constant as the event name when you publish an event or subscribe a destination.
6
+ * TypeScript narrows the payload to match the event name.
7
+ *
8
+ * @publicDocs
8
9
  */
9
10
  declare const AnalyticsEvent: {
10
- PAGE_VIEWED: "page_viewed";
11
- PRODUCT_VIEWED: "product_viewed";
12
- COLLECTION_VIEWED: "collection_viewed";
13
- CART_VIEWED: "cart_viewed";
14
- SEARCH_VIEWED: "search_viewed";
15
- CART_UPDATED: "cart_updated";
16
- PRODUCT_ADD_TO_CART: "product_added_to_cart";
11
+ /** Publish when a customer views a page. Hydrogen fills in the current URL when the payload has none. */PAGE_VIEWED: "page_viewed"; /** Publish when a customer views a product. The payload lists the viewed products. */
12
+ PRODUCT_VIEWED: "product_viewed"; /** Publish when a customer views a collection. The payload identifies the collection by ID and handle. */
13
+ COLLECTION_VIEWED: "collection_viewed"; /** Publish when a customer views the cart. The payload carries the current cart. */
14
+ CART_VIEWED: "cart_viewed"; /** Publish when a customer views search results. The payload carries the search term. */
15
+ SEARCH_VIEWED: "search_viewed"; /** Cart tracking publishes this event when the cart changes. */
16
+ CART_UPDATED: "cart_updated"; /** Cart tracking publishes this event when the customer adds a line or raises a line's quantity. */
17
+ PRODUCT_ADD_TO_CART: "product_added_to_cart"; /** Cart tracking publishes this event when the customer removes a line or lowers a line's quantity. */
17
18
  PRODUCT_REMOVED_FROM_CART: "product_removed_from_cart";
18
19
  };
20
+ /**
21
+ * The name of a supported analytics event, such as `"page_viewed"`.
22
+ *
23
+ * @publicDocs
24
+ */
19
25
  type AnalyticsEventName = (typeof AnalyticsEvent)[keyof typeof AnalyticsEvent];
20
26
  //#endregion
21
27
  export { AnalyticsEvent, AnalyticsEventName };
@@ -1,19 +1,28 @@
1
1
  //#region src/core/analytics/events.ts
2
2
  /**
3
- * Canonical event names for the Hydrogen analytics bus.
3
+ * The names of the analytics events that Hydrogen supports.
4
4
  *
5
- * Use these as the `event` argument to `publish()` and a destination's `subscribe()`. Raw string
6
- * literals are type-checked and narrow the payload the same way; the constants add
7
- * autocomplete and a single place to rename.
5
+ * Pass a constant as the event name when you publish an event or subscribe a destination.
6
+ * TypeScript narrows the payload to match the event name.
7
+ *
8
+ * @publicDocs
8
9
  */
9
10
  const AnalyticsEvent = {
11
+ /** Publish when a customer views a page. Hydrogen fills in the current URL when the payload has none. */
10
12
  PAGE_VIEWED: "page_viewed",
13
+ /** Publish when a customer views a product. The payload lists the viewed products. */
11
14
  PRODUCT_VIEWED: "product_viewed",
15
+ /** Publish when a customer views a collection. The payload identifies the collection by ID and handle. */
12
16
  COLLECTION_VIEWED: "collection_viewed",
17
+ /** Publish when a customer views the cart. The payload carries the current cart. */
13
18
  CART_VIEWED: "cart_viewed",
19
+ /** Publish when a customer views search results. The payload carries the search term. */
14
20
  SEARCH_VIEWED: "search_viewed",
21
+ /** Cart tracking publishes this event when the cart changes. */
15
22
  CART_UPDATED: "cart_updated",
23
+ /** Cart tracking publishes this event when the customer adds a line or raises a line's quantity. */
16
24
  PRODUCT_ADD_TO_CART: "product_added_to_cart",
25
+ /** Cart tracking publishes this event when the customer removes a line or lowers a line's quantity. */
17
26
  PRODUCT_REMOVED_FROM_CART: "product_removed_from_cart"
18
27
  };
19
28
 
@@ -1 +1 @@
1
- {"version":3,"file":"events.mjs","names":[],"sources":["../../../../src/core/analytics/events.ts"],"sourcesContent":["/**\n * Canonical event names for the Hydrogen analytics bus.\n *\n * Use these as the `event` argument to `publish()` and a destination's `subscribe()`. Raw string\n * literals are type-checked and narrow the payload the same way; the constants add\n * autocomplete and a single place to rename.\n */\nexport const AnalyticsEvent = {\n PAGE_VIEWED: \"page_viewed\" as const,\n PRODUCT_VIEWED: \"product_viewed\" as const,\n COLLECTION_VIEWED: \"collection_viewed\" as const,\n CART_VIEWED: \"cart_viewed\" as const,\n SEARCH_VIEWED: \"search_viewed\" as const,\n\n CART_UPDATED: \"cart_updated\" as const,\n PRODUCT_ADD_TO_CART: \"product_added_to_cart\" as const,\n PRODUCT_REMOVED_FROM_CART: \"product_removed_from_cart\" as const,\n};\n\nexport type AnalyticsEventName = (typeof AnalyticsEvent)[keyof typeof AnalyticsEvent];\n"],"mappings":";;;;;;;;AAOA,MAAa,iBAAiB;CAC5B,aAAa;CACb,gBAAgB;CAChB,mBAAmB;CACnB,aAAa;CACb,eAAe;CAEf,cAAc;CACd,qBAAqB;CACrB,2BAA2B;CAC5B"}
1
+ {"version":3,"file":"events.mjs","names":[],"sources":["../../../../src/core/analytics/events.ts"],"sourcesContent":["/**\n * The names of the analytics events that Hydrogen supports.\n *\n * Pass a constant as the event name when you publish an event or subscribe a destination.\n * TypeScript narrows the payload to match the event name.\n *\n * @publicDocs\n */\nexport const AnalyticsEvent = {\n /** Publish when a customer views a page. Hydrogen fills in the current URL when the payload has none. */\n PAGE_VIEWED: \"page_viewed\" as const,\n /** Publish when a customer views a product. The payload lists the viewed products. */\n PRODUCT_VIEWED: \"product_viewed\" as const,\n /** Publish when a customer views a collection. The payload identifies the collection by ID and handle. */\n COLLECTION_VIEWED: \"collection_viewed\" as const,\n /** Publish when a customer views the cart. The payload carries the current cart. */\n CART_VIEWED: \"cart_viewed\" as const,\n /** Publish when a customer views search results. The payload carries the search term. */\n SEARCH_VIEWED: \"search_viewed\" as const,\n\n /** Cart tracking publishes this event when the cart changes. */\n CART_UPDATED: \"cart_updated\" as const,\n /** Cart tracking publishes this event when the customer adds a line or raises a line's quantity. */\n PRODUCT_ADD_TO_CART: \"product_added_to_cart\" as const,\n /** Cart tracking publishes this event when the customer removes a line or lowers a line's quantity. */\n PRODUCT_REMOVED_FROM_CART: \"product_removed_from_cart\" as const,\n};\n\n/** The analytics event constants, keyed by constant name. */\ntype AnalyticsEventMap = typeof AnalyticsEvent;\n\n/**\n * The names of the analytics events that Hydrogen supports. Pass a value as the event name when you publish an event or subscribe a destination. TypeScript narrows the payload to match the event name.\n *\n * @publicDocs\n */\nexport interface AnalyticsEventForDocs extends AnalyticsEventMap {}\n\n/**\n * The name of a supported analytics event, such as `\"page_viewed\"`.\n *\n * @publicDocs\n */\nexport type AnalyticsEventName = (typeof AnalyticsEvent)[keyof typeof AnalyticsEvent];\n"],"mappings":";;;;;;;;;AAQA,MAAa,iBAAiB;;CAE5B,aAAa;;CAEb,gBAAgB;;CAEhB,mBAAmB;;CAEnB,aAAa;;CAEb,eAAe;;CAGf,cAAc;;CAEd,qBAAqB;;CAErB,2BAA2B;CAC5B"}
@@ -1,54 +1,74 @@
1
+ import { MoneyV2 } from "../../graphql/generated/storefront-api-types.mjs";
1
2
  import { AnalyticsEventName } from "./events.mjs";
2
3
  import { ShopifyScriptsShop } from "../shopify-scripts/types.mjs";
3
4
 
4
5
  //#region src/core/analytics/types.d.ts
6
+ /** The shop ID that every analytics payload carries. */
5
7
  type ShopAnalyticsBase = Pick<ShopifyScriptsShop, "shopId">;
6
- /** Discriminant for the analytics channel a storefront is running under. */
8
+ /** The sales channel that Shopify attributes a storefront's analytics to. */
7
9
  type ShopAnalyticsChannel = "hydrogen" | "headless";
8
10
  /**
9
- * Identifies the shop and channel for every analytics payload.
11
+ * Identifies the shop and sales channel in every analytics payload.
10
12
  *
11
- * The `"hydrogen"` variant carries the Hydrogen sales channel's `storefrontId`;
12
- * the `"headless"` variant omits it, because analytics for the Headless channel
13
- * isn't attributed to a specific storefront.
13
+ * The `hydrogen` channel carries the storefront ID. The `headless` channel
14
+ * omits the storefront ID.
15
+ *
16
+ * @publicDocs
14
17
  */
15
- type ShopAnalytics = (ShopAnalyticsBase & {
16
- /** The storefront is served by the Hydrogen sales channel. */channel: "hydrogen"; /** ID of the Hydrogen storefront that analytics are attributed to. */
18
+ type ShopAnalytics = HydrogenShopAnalytics | HeadlessShopAnalytics;
19
+ /** The shop and storefront for a storefront on the Hydrogen sales channel. */
20
+ interface HydrogenShopAnalytics extends ShopAnalyticsBase {
21
+ /** The Hydrogen sales channel serves the storefront. */
22
+ channel: "hydrogen";
23
+ /** The Hydrogen storefront's ID. */
17
24
  storefrontId: ShopifyScriptsShop["storefrontId"];
18
- }) | (ShopAnalyticsBase & {
19
- /** The storefront uses the generic Headless sales channel. */channel: "headless";
25
+ }
26
+ /** The shop for a storefront on the Headless sales channel. */
27
+ interface HeadlessShopAnalytics extends ShopAnalyticsBase {
28
+ /** The Headless sales channel serves the storefront. */
29
+ channel: "headless";
30
+ /** Leave the storefront ID out. The Headless sales channel has no storefront ID. */
20
31
  storefrontId?: never;
21
- });
32
+ }
33
+ /**
34
+ * The consent choices that a custom consent setup passes to
35
+ * `window.Shopify.customerPrivacy.setTrackingConsent()`.
36
+ *
37
+ * @publicDocs
38
+ */
22
39
  type ConsentPreferences = {
23
- analytics: boolean;
24
- marketing: boolean;
25
- preferences: boolean;
40
+ /** Whether the customer allows analytics tracking. */analytics: boolean; /** Whether the customer allows marketing tracking. */
41
+ marketing: boolean; /** Whether the customer allows the storefront to remember their preferences. */
42
+ preferences: boolean; /** Whether the customer allows the sale or sharing of their data. */
26
43
  sale_of_data: boolean;
27
44
  };
28
45
  /**
29
- * Connects a consent provider once per analytics bus, after Shopify's consent API has loaded.
30
- * Use window.Shopify.customerPrivacy to synchronize consent.
31
- * Resolve only after the provider has a saved choice or the shopper interacts, and that
32
- * consent has been synchronized with Shopify. Hydrogen then checks consent and replays
33
- * allowed events. Rejection keeps delivery blocked. The integration stays active
34
- * across component unmounts.
46
+ * Connects a third-party consent provider to Shopify's Customer Privacy API. Hydrogen calls the
47
+ * function once, after the Customer Privacy API loads. Pass the provider's choice to
48
+ * `window.Shopify.customerPrivacy`, and resolve after Shopify receives the choice. Hydrogen then
49
+ * delivers the events that consent allows. When the promise rejects, Hydrogen logs the error,
50
+ * keeps events blocked, and doesn't call the function again.
51
+ */
52
+ type ConsentSetup =
53
+ /**
54
+ * @returns A promise that resolves after consent syncs with Shopify, or rejects to keep delivery blocked.
35
55
  */
36
- type ConsentSetup = () => Promise<void>;
56
+ () => Promise<void>;
37
57
  /**
38
- * Chooses which Shopify consent script `ShopifyScripts` loads and when the
39
- * analytics bus releases events to destinations.
58
+ * Chooses which Shopify consent script loads and when the analytics bus
59
+ * releases events to destinations.
40
60
  *
41
- * - `"default-banner"` loads Shopify's hosted privacy banner. If the visitor
42
- * must see the banner, destinations wait until they accept or decline;
43
- * otherwise events are released as soon as the consent API loads.
44
- * - `"custom-banner"` loads only the Customer Privacy API and requires a
61
+ * - `default-banner` loads Shopify's hosted privacy banner. When the customer
62
+ * must see the banner, destinations wait until the customer accepts or
63
+ * declines. Otherwise, events release as soon as the consent API loads.
64
+ * - `custom-banner` loads only the Customer Privacy API and requires a
45
65
  * `setup` callback that integrates a third-party consent provider.
46
- * Events release once the `setup` callback resolves.
47
- * - `"no-banner"` (or omitted) loads only the Customer Privacy API and
48
- * releases events once it loads.
66
+ * Events release once the callback resolves.
67
+ * - `no-banner` loads only the Customer Privacy API and releases events
68
+ * once the API loads. Omitting the mode has the same effect.
49
69
  *
50
- * In every mode, destinations only receive events while analytics processing is
51
- * allowed.
70
+ * In every mode, destinations receive events only while the Customer Privacy
71
+ * API allows analytics processing.
52
72
  */
53
73
  type ConsentConfig = {
54
74
  mode?: "no-banner";
@@ -60,28 +80,22 @@ type ConsentConfig = {
60
80
  mode: "custom-banner";
61
81
  setup: ConsentSetup;
62
82
  };
63
- /**
64
- * Lightweight cart line shape for analytics payloads.
65
- *
66
- * Mirrors the Storefront API `CartLine` fields needed for tracking without
67
- * depending on the cart store's `CartData` type, so the analytics bus stays
68
- * framework-agnostic.
69
- */
83
+ /** A cart line in an analytics payload, with the Storefront API fields that cart tracking reads. */
70
84
  type AnalyticsCartLine = {
71
- id: string;
72
- quantity: number;
85
+ /** The cart line ID. */id: string; /** The number of units on the line. */
86
+ quantity: number; /** The variant on the line, with its product. */
73
87
  merchandise: {
74
- id: string;
88
+ /** The variant ID. */id: string;
75
89
  /**
76
- * Variant title (`"Default Title"` for single-variant products).
77
- * `trackCartAnalytics` falls back to the product title only when the cart
78
- * fragment doesn't select it.
90
+ * The variant title, which is `"Default Title"` for single-variant products.
91
+ * Cart tracking uses the product title when the cart fragment doesn't select
92
+ * the variant title.
79
93
  */
80
- title: string; /** Per-unit price (`CartLine.cost.amountPerQuantity`). */
94
+ title: string; /** The price of one unit, from the cart line's cost per quantity. */
81
95
  price: {
82
96
  amount: string;
83
97
  currencyCode?: string;
84
- };
98
+ }; /** The variant's SKU. Cart tracking sets `null` when the variant has no SKU. */
85
99
  sku?: string | null;
86
100
  product: {
87
101
  id: string;
@@ -93,17 +107,16 @@ type AnalyticsCartLine = {
93
107
  };
94
108
  };
95
109
  /**
96
- * Lightweight cart snapshot included in cart analytics payloads.
110
+ * A cart snapshot in cart analytics payloads.
97
111
  *
98
- * Accepts both `nodes` and `edges` connection shapes so the analytics layer
99
- * works regardless of which Storefront API query pattern the storefront uses.
112
+ * @publicDocs
100
113
  */
101
114
  type AnalyticsCart = {
102
- id: string;
115
+ /** The cart ID. */id: string;
103
116
  /**
104
- * `Cart.updatedAt` (ISO 8601), used to deduplicate cart events.
117
+ * The time of the cart's last update, as an ISO 8601 string.
105
118
  */
106
- updatedAt: string;
119
+ updatedAt: string; /** The currency codes of the cart's subtotal and total. */
107
120
  cost?: {
108
121
  subtotalAmount?: {
109
122
  currencyCode?: string;
@@ -111,7 +124,7 @@ type AnalyticsCart = {
111
124
  totalAmount?: {
112
125
  currencyCode?: string;
113
126
  };
114
- }; /** Cart lines in Storefront API connection format. */
127
+ }; /** The cart lines, as a `nodes` list or an `edges` list. Cart tracking fills `nodes`. */
115
128
  lines: {
116
129
  nodes?: AnalyticsCartLine[];
117
130
  edges?: Array<{
@@ -120,75 +133,125 @@ type AnalyticsCart = {
120
133
  };
121
134
  [key: string]: unknown;
122
135
  };
123
- /** Index signature that allows arbitrary extra keys on a payload. */
136
+ /**
137
+ * Extra keys that a payload can carry. Cart tracking adds `eventTimestamp`, the publish time
138
+ * in milliseconds.
139
+ *
140
+ * @publicDocs
141
+ */
124
142
  type OtherData = {
125
143
  [key: string]: unknown;
126
144
  };
145
+ /** The shop and custom data that every analytics event payload carries. */
127
146
  type BasePayload = {
128
- shop?: ShopAnalytics | null;
147
+ /**
148
+ * The shop and sales channel. The bus fills in the configured shop when the payload omits
149
+ * the key, and normalizes the shop ID to a Shop GID.
150
+ */
151
+ shop?: ShopAnalytics | null; /** Custom values for destinations. Cart tracking copies the bus configuration's custom data here. */
129
152
  customData?: Record<string, unknown>;
130
153
  };
154
+ /** The page URL that every view event payload carries. */
131
155
  type UrlPayload = {
132
- url?: string;
156
+ /** The page URL. For view events, the bus fills in the current URL when the payload omits it. */url?: string;
133
157
  };
134
- /** Describes a single product for `product_viewed` payloads. */
158
+ /**
159
+ * A product in a product view payload.
160
+ *
161
+ * @publicDocs
162
+ */
135
163
  type ProductPayload = {
136
- id: string;
137
- title: string; /** Decimal amount string for the selected variant (e.g. `"19.99"`). */
138
- price: string;
139
- vendor: string;
140
- variantId: string;
141
- variantTitle: string;
142
- quantity: number;
143
- sku?: string | null;
164
+ /** The product ID. */id: string; /** The product title. */
165
+ title: string; /** The selected variant's price. */
166
+ price: MoneyV2; /** The product vendor. */
167
+ vendor: string; /** The selected variant's ID. */
168
+ variantId: string; /** The selected variant's title. */
169
+ variantTitle: string; /** The selected quantity. */
170
+ quantity: number; /** The selected variant's SKU, or `null` when the variant has none. */
171
+ sku?: string | null; /** The product type. */
144
172
  productType?: string;
145
173
  };
174
+ /** The products in a `product_viewed` event. */
146
175
  type ProductsPayload = {
147
- products: Array<ProductPayload & OtherData>;
176
+ /** The products that the customer views. */products: Array<ProductPayload & OtherData>;
148
177
  };
178
+ /** The collection in a `collection_viewed` event. */
149
179
  type CollectionPayload = {
150
- collection: {
180
+ /** The ID and handle of the collection that the customer views. */collection: {
151
181
  id: string;
152
182
  handle: string;
153
183
  };
154
184
  };
185
+ /** The search term and results in a `search_viewed` event. */
155
186
  type SearchPayload = {
156
- searchTerm: string;
187
+ /** The customer's search query. */searchTerm: string; /** The search results, in any shape that your destinations read. */
157
188
  searchResults?: unknown;
158
189
  };
190
+ /** The current cart in a cart event. */
159
191
  type CartPayload = {
160
- cart: AnalyticsCart | null;
192
+ /** The current cart. */cart: AnalyticsCart | null;
161
193
  };
162
- type CartChangePayload = CartPayload & {
194
+ /** The current cart and the cart before the change, in a cart update or cart line event. */
195
+ interface CartChangePayload extends CartPayload {
196
+ /** The cart before the change, or `null` when cart tracking has no earlier snapshot. */
163
197
  prevCart: AnalyticsCart | null;
164
- };
198
+ }
199
+ /** The cart line before and after the change, in a `product_added_to_cart` or `product_removed_from_cart` event. */
165
200
  type CartLinePayload = {
166
- prevLine?: AnalyticsCartLine;
201
+ /** The line before the change. */prevLine?: AnalyticsCartLine; /** The line after the change. */
167
202
  currentLine?: AnalyticsCartLine;
168
203
  };
169
- /** Payload for `page_viewed` events. */
204
+ /**
205
+ * The data for a `page_viewed` event. The payload has only the fields that every view event shares.
206
+ *
207
+ * @publicDocs
208
+ */
170
209
  type PageViewPayload = UrlPayload & BasePayload;
171
- /** Payload for `product_viewed` events. */
210
+ /**
211
+ * The data for a `product_viewed` event. The payload lists the products that the customer views.
212
+ *
213
+ * @publicDocs
214
+ */
172
215
  type ProductViewPayload = ProductsPayload & UrlPayload & BasePayload;
173
- /** Payload for `collection_viewed` events. */
216
+ /**
217
+ * The data for a `collection_viewed` event. The payload has the ID and handle of the collection that the customer views.
218
+ *
219
+ * @publicDocs
220
+ */
174
221
  type CollectionViewPayload = CollectionPayload & UrlPayload & BasePayload;
175
- /** Payload for `cart_viewed` events. */
222
+ /**
223
+ * The data for a `cart_viewed` event. The payload has the current cart.
224
+ *
225
+ * @publicDocs
226
+ */
176
227
  type CartViewPayload = CartPayload & UrlPayload & BasePayload;
177
- /** Payload for `search_viewed` events. */
228
+ /**
229
+ * The data for a `search_viewed` event. The payload has the customer's search term and optional search results in any shape that your destinations read.
230
+ *
231
+ * @publicDocs
232
+ */
178
233
  type SearchViewPayload = SearchPayload & UrlPayload & BasePayload;
179
- /** Payload for `cart_updated` events. `prevCart` is `null` when there was no earlier snapshot. */
234
+ /**
235
+ * The data for a `cart_updated` event. Cart tracking sends the current cart, the cart before the change, the shop, the custom data from the bus configuration, and the publish time. The previous cart is `null` when cart tracking has no earlier snapshot.
236
+ *
237
+ * @publicDocs
238
+ */
180
239
  type CartUpdatePayload = CartChangePayload & BasePayload & OtherData;
181
240
  /**
182
- * Payload for `product_added_to_cart` and `product_removed_from_cart` events.
183
- * New lines have only `currentLine`, removed lines have only `prevLine`, and
184
- * quantity changes have both.
241
+ * The data for `product_added_to_cart` and `product_removed_from_cart` events. The payload has the same fields as a cart update, plus the line before and after the change.
242
+ * New lines have only the current line, removed lines have only the previous
243
+ * line, and quantity changes have both.
244
+ *
245
+ * @publicDocs
185
246
  */
186
247
  type CartLineUpdatePayload = CartLinePayload & CartChangePayload & BasePayload & OtherData;
187
248
  /**
188
249
  * Maps each analytics event name to its payload type.
189
250
  *
190
- * TypeScript uses this to infer the correct payload when you call
191
- * `publish()` or a destination's `subscribe()` with a specific event name.
251
+ * TypeScript uses the map to infer the payload when you publish an event or
252
+ * subscribe a destination to a specific event name.
253
+ *
254
+ * @publicDocs
192
255
  */
193
256
  interface AnalyticsEventMap {
194
257
  page_viewed: PageViewPayload;
@@ -200,78 +263,104 @@ interface AnalyticsEventMap {
200
263
  product_added_to_cart: CartLineUpdatePayload;
201
264
  product_removed_from_cart: CartLineUpdatePayload;
202
265
  }
203
- /** Resolves the payload type for a supported analytics event name. */
266
+ /**
267
+ * Resolves the payload type for a supported analytics event name.
268
+ *
269
+ * @publicDocs
270
+ */
204
271
  type PayloadFor<E extends AnalyticsEventName> = AnalyticsEventMap[E];
272
+ /** The payload argument for publishing an event. It's optional when every payload field is optional. */
205
273
  type PublishPayloadArgs<E extends AnalyticsEventName> = {} extends PayloadFor<E> ? [payload?: PayloadFor<E>] : [payload: PayloadFor<E>];
206
274
  /**
207
- * Analytics bus configuration, built by `ShopifyScripts` from its `shop`,
208
- * `consent`, and `analytics` options.
275
+ * The analytics bus configuration. Hydrogen builds it from the shop, consent, and analytics
276
+ * options of the Shopify script tags.
277
+ *
278
+ * @publicDocs
209
279
  */
210
280
  type StorefrontAnalyticsConfig = {
211
- /** Shop identity and channel for analytics payloads. */shop: ShopAnalytics | null; /** Serializable consent settings. The provider setup callback stays in the client bundle. */
281
+ /** The shop and sales channel for analytics payloads. */shop: ShopAnalytics | null; /** The consent mode, without the setup callback. */
212
282
  consent: Pick<ConsentConfig, "mode">;
213
283
  /**
214
- * Extra key-value pairs accessible to destinations via `getConfig().customData`.
215
- * Not added to events you publish.
284
+ * Extra key-value pairs that destinations read from the bus configuration. Cart tracking
285
+ * copies them into cart event payloads. The bus doesn't add them to events that you publish.
216
286
  */
217
287
  customData?: Record<string, unknown>;
218
288
  };
219
289
  /**
220
- * Visitor identifiers from Shopify's Customer Privacy API, used to correlate
221
- * analytics events. See `getTrackingValues` for when they are empty.
290
+ * Visitor identifiers from Shopify's Customer Privacy API. Destinations use them to correlate
291
+ * analytics events. Both identifiers are empty strings when the values are unavailable.
292
+ *
293
+ * @publicDocs
222
294
  */
223
295
  type AnalyticsTrackingValues = {
224
- /** Long-lived browser identifier; persists across visits. */uniqueToken: string; /** Session identifier (30-minute rolling expiry). */
296
+ /** The browser's unique visitor identifier. */uniqueToken: string; /** The session identifier. */
225
297
  visitToken: string;
226
298
  };
227
- /** Context provided to destination callbacks alongside each event payload. */
299
+ /**
300
+ * The context that a destination callback receives with each event payload.
301
+ *
302
+ * @publicDocs
303
+ */
228
304
  type StorefrontAnalyticsDestinationEventContext = {
229
305
  /**
230
- * Reads current tokens from the consent API. Returns empty strings when tokens are
231
- * unavailable or analytics tracking is not currently allowed.
306
+ * Returns the current visitor tokens from the Customer Privacy API. The function checks consent
307
+ * on every call, and returns empty strings when the tokens are unavailable or consent blocks tracking.
232
308
  */
233
309
  getTrackingValues: () => AnalyticsTrackingValues;
234
310
  };
235
- /** Context passed into a destination's `setup()` function. */
311
+ /**
312
+ * The context that a destination's setup function receives.
313
+ *
314
+ * @publicDocs
315
+ */
236
316
  type StorefrontAnalyticsDestinationSetupContext = {
237
- /** Subscribe to an analytics event. Returns an unsubscribe function. */subscribe: <E extends AnalyticsEventName>(event: E, callback: (payload: PayloadFor<E>, context: StorefrontAnalyticsDestinationEventContext) => void) => () => void; /** Returns the current analytics bus configuration. */
317
+ /**
318
+ * Subscribes a callback to an analytics event and returns a function that unsubscribes it.
319
+ * The bus warns and ignores unsupported event names.
320
+ */
321
+ subscribe: <E extends AnalyticsEventName>(event: E, callback: (payload: PayloadFor<E>, context: StorefrontAnalyticsDestinationEventContext) => void) => () => void; /** Returns the current analytics bus configuration. */
238
322
  getConfig: () => StorefrontAnalyticsConfig;
239
323
  };
240
324
  /**
241
- * A consent-gated analytics integration that receives events after consent is granted.
325
+ * An analytics integration that receives events once consent allows tracking.
326
+ *
327
+ * Subscribe to events in the setup function. After consent allows tracking, the destination
328
+ * receives the earlier events from the buffer and then new events. Return a cleanup function
329
+ * from setup to undo side effects when you remove the destination.
242
330
  *
243
- * Destinations subscribe to events during `setup()` and receive live delivery
244
- * plus replayed buffered events once tracking is allowed. Return a cleanup
245
- * function from `setup()` to tear down side effects when the destination is
246
- * removed via the function returned by `addDestination()`. The bus itself lives
247
- * for the page's lifetime.
331
+ * @publicDocs
248
332
  */
249
333
  type StorefrontAnalyticsDestination = {
250
- /** Unique name for this destination — duplicates are rejected with a warning. */name: string;
334
+ /** A unique name. The bus warns and ignores a destination that reuses the name of an active destination. */name: string;
251
335
  /**
252
- * Runs immediately when the destination is added, before consent is known, so
253
- * don't load third-party scripts or set cookies here. Subscribe via the context.
254
- * May be async: buffered events replay after it resolves (once tracking is
255
- * allowed). If it throws or rejects, the destination is removed.
336
+ * Runs as soon as you add the destination, which can happen before the customer consents.
337
+ * Subscribe to events through the context. Don't load third-party scripts or set cookies in
338
+ * setup. The function can be async. The bus replays buffered events after setup resolves and
339
+ * consent allows tracking. When setup throws or rejects, the bus logs the error and removes
340
+ * the destination.
256
341
  */
257
342
  setup: (context: StorefrontAnalyticsDestinationSetupContext) => void | (() => void) | Promise<void | (() => void)>;
258
343
  };
259
344
  /**
260
- * The framework-agnostic analytics event bus that `ShopifyScripts` exposes on
261
- * `window.Shopify.analytics`.
345
+ * The analytics event bus that the Shopify script tags create at `window.Shopify.analytics`.
346
+ *
347
+ * Storefronts publish events such as page views, product views, and cart changes. Tracking
348
+ * integrations register as destinations and receive events once consent allows tracking.
262
349
  *
263
- * Storefronts publish events (page views, product views, cart changes) via
264
- * `publish()`. Consent-gated tracking integrations register through
265
- * `addDestination()` and receive buffered events once consent is granted.
350
+ * @publicDocs
266
351
  */
267
352
  type StorefrontAnalytics = {
268
353
  /**
269
- * Emits an event to destinations while tracking is allowed. Otherwise the
270
- * event goes into a bounded replay buffer. Fills in `shop` and (for view
271
- * events) `url` when omitted.
354
+ * Publishes an event. The bus delivers the event to destinations while consent allows
355
+ * tracking, and records the event in a replay buffer for destinations that you add later.
356
+ * The buffer keeps the latest 500 events. When consent completes without allowing tracking,
357
+ * the bus clears the buffer and stops recording until consent allows tracking.
358
+ *
359
+ * The bus fills in the shop when the payload omits it, and the current URL for view events.
360
+ * The bus warns and drops events with unsupported names.
272
361
  */
273
- publish: <E extends AnalyticsEventName>(event: E, ...payload: PublishPayloadArgs<E>) => void; /** Register a consent-gated destination integration. Returns a removal function. */
274
- addDestination: (destination: StorefrontAnalyticsDestination) => () => void; /** Returns the bus configuration; `shop.shopId` is normalized to a Shop GID. */
362
+ publish: <E extends AnalyticsEventName>(event: E, ...payload: PublishPayloadArgs<E>) => void; /** Adds a destination and returns a function that removes it. Removing a destination runs its cleanup function. */
363
+ addDestination: (destination: StorefrontAnalyticsDestination) => () => void; /** Returns the bus configuration, with the shop ID normalized to a Shop GID. */
275
364
  getConfig: () => StorefrontAnalyticsConfig;
276
365
  };
277
366
  //#endregion