@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.
- package/README.md +73 -13
- package/bin/hydrogen.mjs +7 -0
- package/dist/cli/index.mjs +647 -0
- package/dist/client/client.d.mts +34 -0
- package/dist/client/client.mjs +206 -0
- package/dist/client/client.mjs.map +1 -0
- package/dist/client/errors.d.mts +48 -0
- package/dist/client/errors.mjs +52 -0
- package/dist/client/errors.mjs.map +1 -0
- package/dist/client/index.d.mts +4 -0
- package/dist/client/types.d.mts +147 -0
- package/dist/core/analytics/cart-tracker.d.mts +8 -0
- package/dist/core/analytics/cart-tracker.mjs +144 -0
- package/dist/core/analytics/cart-tracker.mjs.map +1 -0
- package/dist/core/analytics/events.d.mts +15 -0
- package/dist/core/analytics/events.mjs +15 -0
- package/dist/core/analytics/events.mjs.map +1 -0
- package/dist/core/analytics/index.d.mts +3 -0
- package/dist/core/analytics/types.d.mts +143 -0
- package/dist/core/analytics/utils/flatten-connection.d.mts +19 -0
- package/dist/core/analytics/utils/flatten-connection.mjs +25 -0
- package/dist/core/analytics/utils/flatten-connection.mjs.map +1 -0
- package/dist/core/cache/cache-status.mjs +17 -0
- package/dist/core/cache/cache-status.mjs.map +1 -0
- package/dist/core/cache/fetch-with-cache.d.mts +43 -0
- package/dist/core/cache/fetch-with-cache.mjs +188 -0
- package/dist/core/cache/fetch-with-cache.mjs.map +1 -0
- package/dist/core/cache/key.d.mts +6 -0
- package/dist/core/cache/key.mjs +27 -0
- package/dist/core/cache/key.mjs.map +1 -0
- package/dist/core/cache/run-with-cache.d.mts +36 -0
- package/dist/core/cache/run-with-cache.mjs +114 -0
- package/dist/core/cache/run-with-cache.mjs.map +1 -0
- package/dist/core/cache/store.d.mts +19 -0
- package/dist/core/cache/store.mjs +62 -0
- package/dist/core/cache/store.mjs.map +1 -0
- package/dist/core/cache/strategies.d.mts +39 -0
- package/dist/core/cache/strategies.mjs +70 -0
- package/dist/core/cache/strategies.mjs.map +1 -0
- package/dist/core/cart/actions.d.mts +50 -0
- package/dist/core/cart/actions.mjs +240 -0
- package/dist/core/cart/actions.mjs.map +1 -0
- package/dist/core/cart/attach-quantity-input.d.mts +5 -0
- package/dist/core/cart/attach-quantity-input.mjs +17 -0
- package/dist/core/cart/attach-quantity-input.mjs.map +1 -0
- package/dist/core/cart/buyer-identity-sync.d.mts +23 -0
- package/dist/core/cart/buyer-identity-sync.mjs +9 -0
- package/dist/core/cart/buyer-identity-sync.mjs.map +1 -0
- package/dist/core/cart/cart.d.mts +37 -0
- package/dist/core/cart/cart.mjs +1707 -0
- package/dist/core/cart/cart.mjs.map +1 -0
- package/dist/core/cart/cookie.d.mts +5 -0
- package/dist/core/cart/cookie.mjs +28 -0
- package/dist/core/cart/cookie.mjs.map +1 -0
- package/dist/core/cart/form.d.mts +130 -0
- package/dist/core/cart/form.mjs +75 -0
- package/dist/core/cart/form.mjs.map +1 -0
- package/dist/core/cart/get-cart.d.mts +25 -0
- package/dist/core/cart/get-cart.mjs +32 -0
- package/dist/core/cart/get-cart.mjs.map +1 -0
- package/dist/core/cart/index.d.mts +10 -0
- package/dist/core/cart/quantity.d.mts +10 -0
- package/dist/core/cart/quantity.mjs +14 -0
- package/dist/core/cart/quantity.mjs.map +1 -0
- package/dist/core/cart/queries.d.mts +4296 -0
- package/dist/core/cart/queries.mjs +70 -0
- package/dist/core/cart/queries.mjs.map +1 -0
- package/dist/core/cart/server-handlers.d.mts +82 -0
- package/dist/core/cart/server-handlers.mjs +322 -0
- package/dist/core/cart/server-handlers.mjs.map +1 -0
- package/dist/core/cart/state.d.mts +137 -0
- package/dist/core/cart/state.mjs +76 -0
- package/dist/core/cart/state.mjs.map +1 -0
- package/dist/core/cart/sync-quantity-inputs.mjs +16 -0
- package/dist/core/cart/sync-quantity-inputs.mjs.map +1 -0
- package/dist/core/collection/collection.d.mts +134 -0
- package/dist/core/collection/collection.mjs +170 -0
- package/dist/core/collection/collection.mjs.map +1 -0
- package/dist/core/collection/index.d.mts +6 -0
- package/dist/core/collection/reconciler.d.mts +32 -0
- package/dist/core/collection/reconciler.mjs +89 -0
- package/dist/core/collection/reconciler.mjs.map +1 -0
- package/dist/core/collection/state.d.mts +66 -0
- package/dist/core/collection/state.mjs +20 -0
- package/dist/core/collection/state.mjs.map +1 -0
- package/dist/core/collection/url.d.mts +71 -0
- package/dist/core/collection/url.mjs +376 -0
- package/dist/core/collection/url.mjs.map +1 -0
- package/dist/core/constants.d.mts +5 -0
- package/dist/core/constants.mjs +8 -0
- package/dist/core/constants.mjs.map +1 -0
- package/dist/core/headers.mjs +43 -0
- package/dist/core/headers.mjs.map +1 -0
- package/dist/core/index.d.mts +56 -0
- package/dist/core/index.mjs +45 -0
- package/dist/core/logging/logging.d.mts +21 -0
- package/dist/core/logging/logging.mjs +99 -0
- package/dist/core/logging/logging.mjs.map +1 -0
- package/dist/core/logging/types.d.mts +40 -0
- package/dist/core/logging/types.mjs +18 -0
- package/dist/core/logging/types.mjs.map +1 -0
- package/dist/core/money/cache.mjs +25 -0
- package/dist/core/money/cache.mjs.map +1 -0
- package/dist/core/money/format.d.mts +15 -0
- package/dist/core/money/format.mjs +243 -0
- package/dist/core/money/format.mjs.map +1 -0
- package/dist/core/money/types.d.mts +47 -0
- package/dist/core/observable.mjs +46 -0
- package/dist/core/observable.mjs.map +1 -0
- package/dist/core/predictive-search/constants.d.mts +5 -0
- package/dist/core/predictive-search/constants.mjs +6 -0
- package/dist/core/predictive-search/constants.mjs.map +1 -0
- package/dist/core/predictive-search/form.d.mts +31 -0
- package/dist/core/predictive-search/form.mjs +31 -0
- package/dist/core/predictive-search/form.mjs.map +1 -0
- package/dist/core/predictive-search/index.d.mts +6 -0
- package/dist/core/predictive-search/queries.d.mts +118 -0
- package/dist/core/predictive-search/queries.mjs +81 -0
- package/dist/core/predictive-search/queries.mjs.map +1 -0
- package/dist/core/predictive-search/search.d.mts +32 -0
- package/dist/core/predictive-search/search.mjs +74 -0
- package/dist/core/predictive-search/search.mjs.map +1 -0
- package/dist/core/predictive-search/server-handlers.d.mts +36 -0
- package/dist/core/predictive-search/server-handlers.mjs +113 -0
- package/dist/core/predictive-search/server-handlers.mjs.map +1 -0
- package/dist/core/predictive-search/store.d.mts +44 -0
- package/dist/core/predictive-search/store.mjs +224 -0
- package/dist/core/predictive-search/store.mjs.map +1 -0
- package/dist/core/predictive-search/url.d.mts +41 -0
- package/dist/core/predictive-search/url.mjs +71 -0
- package/dist/core/predictive-search/url.mjs.map +1 -0
- package/dist/core/product/accept-variant-id.mjs +98 -0
- package/dist/core/product/accept-variant-id.mjs.map +1 -0
- package/dist/core/product/form.d.mts +63 -0
- package/dist/core/product/form.mjs +44 -0
- package/dist/core/product/form.mjs.map +1 -0
- package/dist/core/product/index.d.mts +5 -0
- package/dist/core/product/options.d.mts +43 -0
- package/dist/core/product/options.mjs +296 -0
- package/dist/core/product/options.mjs.map +1 -0
- package/dist/core/product/product-form.d.mts +72 -0
- package/dist/core/product/product-form.mjs +158 -0
- package/dist/core/product/product-form.mjs.map +1 -0
- package/dist/core/product/state.d.mts +68 -0
- package/dist/core/product/url.d.mts +47 -0
- package/dist/core/product/url.mjs +69 -0
- package/dist/core/product/url.mjs.map +1 -0
- package/dist/core/request-context.d.mts +75 -0
- package/dist/core/request-context.mjs +141 -0
- package/dist/core/request-context.mjs.map +1 -0
- package/dist/core/request-routing/handle-shopify-redirects.d.mts +17 -0
- package/dist/core/request-routing/handle-shopify-redirects.mjs +31 -0
- package/dist/core/request-routing/handle-shopify-redirects.mjs.map +1 -0
- package/dist/core/request-routing/handle-shopify-routes.d.mts +14 -0
- package/dist/core/request-routing/handle-shopify-routes.mjs +42 -0
- package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/admin-redirect.mjs +12 -0
- package/dist/core/request-routing/interceptors/admin-redirect.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/ajax-api.mjs +16 -0
- package/dist/core/request-routing/interceptors/ajax-api.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/api-proxy.mjs +20 -0
- package/dist/core/request-routing/interceptors/api-proxy.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/checkout.mjs +58 -0
- package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/mcp-proxy.mjs +23 -0
- package/dist/core/request-routing/interceptors/mcp-proxy.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/proxy.mjs +73 -0
- package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs +22 -0
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +27 -0
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/standard-routes.mjs +19 -0
- package/dist/core/request-routing/interceptors/standard-routes.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/url-redirects.mjs +27 -0
- package/dist/core/request-routing/interceptors/url-redirects.mjs.map +1 -0
- package/dist/core/request-routing/interceptors/well-known.mjs +22 -0
- package/dist/core/request-routing/interceptors/well-known.mjs.map +1 -0
- package/dist/core/request-routing/registered-routes.d.mts +7 -0
- package/dist/core/request-routing/registered-routes.mjs +72 -0
- package/dist/core/request-routing/registered-routes.mjs.map +1 -0
- package/dist/core/request-routing/route-types.d.mts +56 -0
- package/dist/core/request-routing/safe-apply-response-headers.mjs +16 -0
- package/dist/core/request-routing/safe-apply-response-headers.mjs.map +1 -0
- package/dist/core/shop-pay/shop-pay.d.mts +102 -0
- package/dist/core/shop-pay/shop-pay.mjs +289 -0
- package/dist/core/shop-pay/shop-pay.mjs.map +1 -0
- package/dist/core/shopify-scripts/analytics.mjs +26 -0
- package/dist/core/shopify-scripts/analytics.mjs.map +1 -0
- package/dist/core/shopify-scripts/consent.mjs +17 -0
- package/dist/core/shopify-scripts/consent.mjs.map +1 -0
- package/dist/core/shopify-scripts/constants.mjs +19 -0
- package/dist/core/shopify-scripts/constants.mjs.map +1 -0
- package/dist/core/shopify-scripts/deprecated-cookies.mjs +97 -0
- package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +1 -0
- package/dist/core/shopify-scripts/global.d.mts +1 -0
- package/dist/core/shopify-scripts/global.mjs +86 -0
- package/dist/core/shopify-scripts/global.mjs.map +1 -0
- package/dist/core/shopify-scripts/index.d.mts +27 -0
- package/dist/core/shopify-scripts/index.mjs +135 -0
- package/dist/core/shopify-scripts/index.mjs.map +1 -0
- package/dist/core/shopify-scripts/initialize.d.mts +18 -0
- package/dist/core/shopify-scripts/initialize.mjs +27 -0
- package/dist/core/shopify-scripts/initialize.mjs.map +1 -0
- package/dist/core/shopify-scripts/page-view.mjs +49 -0
- package/dist/core/shopify-scripts/page-view.mjs.map +1 -0
- package/dist/core/shopify-scripts/perfkit.mjs +33 -0
- package/dist/core/shopify-scripts/perfkit.mjs.map +1 -0
- package/dist/core/shopify-scripts/render.d.mts +1 -0
- package/dist/core/shopify-scripts/render.mjs +23 -0
- package/dist/core/shopify-scripts/render.mjs.map +1 -0
- package/dist/core/shopify-scripts/types.d.mts +76 -0
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs +43 -0
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +1 -0
- package/dist/core/shopify-scripts/utils/inline-script.mjs +8 -0
- package/dist/core/shopify-scripts/utils/inline-script.mjs.map +1 -0
- package/dist/core/shopify-scripts/utils/navigation.mjs +46 -0
- package/dist/core/shopify-scripts/utils/navigation.mjs.map +1 -0
- package/dist/core/shopify-scripts/utils/tracking-values.mjs +65 -0
- package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +1 -0
- package/dist/core/shopify-scripts/utils/uuid.mjs +17 -0
- package/dist/core/shopify-scripts/utils/uuid.mjs.map +1 -0
- package/dist/core/shopify-scripts/webmcp.mjs +22 -0
- package/dist/core/shopify-scripts/webmcp.mjs.map +1 -0
- package/dist/core/standard-routes/build.d.mts +34 -0
- package/dist/core/standard-routes/build.mjs +54 -0
- package/dist/core/standard-routes/build.mjs.map +1 -0
- package/dist/core/standard-routes/defaults.mjs +31 -0
- package/dist/core/standard-routes/defaults.mjs.map +1 -0
- package/dist/core/standard-routes/match.mjs +108 -0
- package/dist/core/standard-routes/match.mjs.map +1 -0
- package/dist/core/standard-routes/path.mjs +58 -0
- package/dist/core/standard-routes/path.mjs.map +1 -0
- package/dist/core/standard-routes/redirects.mjs +51 -0
- package/dist/core/standard-routes/redirects.mjs.map +1 -0
- package/dist/core/standard-routes/types.d.mts +95 -0
- package/dist/core/url.mjs +42 -0
- package/dist/core/url.mjs.map +1 -0
- package/dist/core/utils/load-script.mjs +34 -0
- package/dist/core/utils/load-script.mjs.map +1 -0
- package/dist/core/utils/parse-gid.mjs +33 -0
- package/dist/core/utils/parse-gid.mjs.map +1 -0
- package/dist/core/utils/record.mjs +8 -0
- package/dist/core/utils/record.mjs.map +1 -0
- package/dist/customer-account/client.d.mts +50 -0
- package/dist/customer-account/client.mjs +239 -0
- package/dist/customer-account/client.mjs.map +1 -0
- package/dist/customer-account/errors.d.mts +28 -0
- package/dist/customer-account/errors.mjs +39 -0
- package/dist/customer-account/errors.mjs.map +1 -0
- package/dist/customer-account/graphql.d.mts +29 -0
- package/dist/customer-account/graphql.mjs +39 -0
- package/dist/customer-account/graphql.mjs.map +1 -0
- package/dist/customer-account/index.d.mts +7 -0
- package/dist/customer-account/index.mjs +7 -0
- package/dist/customer-account/session.d.mts +117 -0
- package/dist/customer-account/session.mjs +733 -0
- package/dist/customer-account/session.mjs.map +1 -0
- package/dist/customer-account/type-resolver.d.mts +11 -0
- package/dist/customer-account-api-types.d.ts +3269 -3270
- package/dist/customer-account.schema.json +50753 -1
- package/dist/development/_virtual/_@oxc-project_runtime@0.127.0/helpers/taggedTemplateLiteral.mjs +7 -0
- package/dist/development/client/client.d.mts +34 -0
- package/dist/development/client/client.mjs +206 -0
- package/dist/development/client/client.mjs.map +1 -0
- package/dist/development/client/errors.d.mts +48 -0
- package/dist/development/client/errors.mjs +57 -0
- package/dist/development/client/errors.mjs.map +1 -0
- package/dist/development/client/index.d.mts +4 -0
- package/dist/development/client/types.d.mts +147 -0
- package/dist/development/core/analytics/cart-tracker.d.mts +8 -0
- package/dist/development/core/analytics/cart-tracker.mjs +144 -0
- package/dist/development/core/analytics/cart-tracker.mjs.map +1 -0
- package/dist/development/core/analytics/events.d.mts +15 -0
- package/dist/development/core/analytics/events.mjs +15 -0
- package/dist/development/core/analytics/events.mjs.map +1 -0
- package/dist/development/core/analytics/index.d.mts +3 -0
- package/dist/development/core/analytics/types.d.mts +143 -0
- package/dist/development/core/analytics/utils/flatten-connection.d.mts +19 -0
- package/dist/development/core/analytics/utils/flatten-connection.mjs +25 -0
- package/dist/development/core/analytics/utils/flatten-connection.mjs.map +1 -0
- package/dist/development/core/cache/cache-status.mjs +17 -0
- package/dist/development/core/cache/cache-status.mjs.map +1 -0
- package/dist/development/core/cache/fetch-with-cache.d.mts +43 -0
- package/dist/development/core/cache/fetch-with-cache.mjs +188 -0
- package/dist/development/core/cache/fetch-with-cache.mjs.map +1 -0
- package/dist/development/core/cache/key.d.mts +6 -0
- package/dist/development/core/cache/key.mjs +27 -0
- package/dist/development/core/cache/key.mjs.map +1 -0
- package/dist/development/core/cache/run-with-cache.d.mts +36 -0
- package/dist/development/core/cache/run-with-cache.mjs +114 -0
- package/dist/development/core/cache/run-with-cache.mjs.map +1 -0
- package/dist/development/core/cache/store.d.mts +19 -0
- package/dist/development/core/cache/store.mjs +62 -0
- package/dist/development/core/cache/store.mjs.map +1 -0
- package/dist/development/core/cache/strategies.d.mts +39 -0
- package/dist/development/core/cache/strategies.mjs +70 -0
- package/dist/development/core/cache/strategies.mjs.map +1 -0
- package/dist/development/core/cart/actions.d.mts +50 -0
- package/dist/development/core/cart/actions.mjs +240 -0
- package/dist/development/core/cart/actions.mjs.map +1 -0
- package/dist/development/core/cart/attach-quantity-input.d.mts +5 -0
- package/dist/development/core/cart/attach-quantity-input.mjs +17 -0
- package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -0
- package/dist/development/core/cart/buyer-identity-sync.d.mts +19 -0
- package/dist/development/core/cart/buyer-identity-sync.mjs +6 -0
- package/dist/development/core/cart/buyer-identity-sync.mjs.map +1 -0
- package/dist/development/core/cart/cart.d.mts +37 -0
- package/dist/development/core/cart/cart.mjs +1707 -0
- package/dist/development/core/cart/cart.mjs.map +1 -0
- package/dist/development/core/cart/cookie.d.mts +5 -0
- package/dist/development/core/cart/cookie.mjs +28 -0
- package/dist/development/core/cart/cookie.mjs.map +1 -0
- package/dist/development/core/cart/form.d.mts +130 -0
- package/dist/development/core/cart/form.mjs +75 -0
- package/dist/development/core/cart/form.mjs.map +1 -0
- package/dist/development/core/cart/get-cart.d.mts +25 -0
- package/dist/development/core/cart/get-cart.mjs +32 -0
- package/dist/development/core/cart/get-cart.mjs.map +1 -0
- package/dist/development/core/cart/index.d.mts +10 -0
- package/dist/development/core/cart/quantity.d.mts +10 -0
- package/dist/development/core/cart/quantity.mjs +14 -0
- package/dist/development/core/cart/quantity.mjs.map +1 -0
- package/dist/development/core/cart/queries.d.mts +4296 -0
- package/dist/development/core/cart/queries.mjs +70 -0
- package/dist/development/core/cart/queries.mjs.map +1 -0
- package/dist/development/core/cart/server-handlers.d.mts +82 -0
- package/dist/development/core/cart/server-handlers.mjs +322 -0
- package/dist/development/core/cart/server-handlers.mjs.map +1 -0
- package/dist/development/core/cart/state.d.mts +137 -0
- package/dist/development/core/cart/state.mjs +76 -0
- package/dist/development/core/cart/state.mjs.map +1 -0
- package/dist/development/core/cart/sync-quantity-inputs.mjs +16 -0
- package/dist/development/core/cart/sync-quantity-inputs.mjs.map +1 -0
- package/dist/development/core/collection/collection.d.mts +134 -0
- package/dist/development/core/collection/collection.mjs +170 -0
- package/dist/development/core/collection/collection.mjs.map +1 -0
- package/dist/development/core/collection/index.d.mts +6 -0
- package/dist/development/core/collection/reconciler.d.mts +32 -0
- package/dist/development/core/collection/reconciler.mjs +89 -0
- package/dist/development/core/collection/reconciler.mjs.map +1 -0
- package/dist/development/core/collection/state.d.mts +66 -0
- package/dist/development/core/collection/state.mjs +20 -0
- package/dist/development/core/collection/state.mjs.map +1 -0
- package/dist/development/core/collection/url.d.mts +71 -0
- package/dist/development/core/collection/url.mjs +376 -0
- package/dist/development/core/collection/url.mjs.map +1 -0
- package/dist/development/core/constants.mjs +7 -0
- package/dist/development/core/constants.mjs.map +1 -0
- package/dist/development/core/development.d.mts +56 -0
- package/dist/development/core/development.mjs +45 -0
- package/dist/development/core/headers.mjs +43 -0
- package/dist/development/core/headers.mjs.map +1 -0
- package/dist/development/core/index.d.mts +54 -0
- package/dist/development/core/logging/logging.d.mts +21 -0
- package/dist/development/core/logging/logging.mjs +99 -0
- package/dist/development/core/logging/logging.mjs.map +1 -0
- package/dist/development/core/logging/types.d.mts +40 -0
- package/dist/development/core/logging/types.mjs +18 -0
- package/dist/development/core/logging/types.mjs.map +1 -0
- package/dist/development/core/money/cache.mjs +25 -0
- package/dist/development/core/money/cache.mjs.map +1 -0
- package/dist/development/core/money/format.d.mts +15 -0
- package/dist/development/core/money/format.mjs +243 -0
- package/dist/development/core/money/format.mjs.map +1 -0
- package/dist/development/core/money/types.d.mts +47 -0
- package/dist/development/core/observable.mjs +46 -0
- package/dist/development/core/observable.mjs.map +1 -0
- package/dist/development/core/predictive-search/constants.d.mts +5 -0
- package/dist/development/core/predictive-search/constants.mjs +6 -0
- package/dist/development/core/predictive-search/constants.mjs.map +1 -0
- package/dist/development/core/predictive-search/form.d.mts +31 -0
- package/dist/development/core/predictive-search/form.mjs +31 -0
- package/dist/development/core/predictive-search/form.mjs.map +1 -0
- package/dist/development/core/predictive-search/index.d.mts +6 -0
- package/dist/development/core/predictive-search/queries.d.mts +118 -0
- package/dist/development/core/predictive-search/queries.mjs +81 -0
- package/dist/development/core/predictive-search/queries.mjs.map +1 -0
- package/dist/development/core/predictive-search/search.d.mts +32 -0
- package/dist/development/core/predictive-search/search.mjs +74 -0
- package/dist/development/core/predictive-search/search.mjs.map +1 -0
- package/dist/development/core/predictive-search/server-handlers.d.mts +36 -0
- package/dist/development/core/predictive-search/server-handlers.mjs +113 -0
- package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -0
- package/dist/development/core/predictive-search/store.d.mts +44 -0
- package/dist/development/core/predictive-search/store.mjs +224 -0
- package/dist/development/core/predictive-search/store.mjs.map +1 -0
- package/dist/development/core/predictive-search/url.d.mts +41 -0
- package/dist/development/core/predictive-search/url.mjs +71 -0
- package/dist/development/core/predictive-search/url.mjs.map +1 -0
- package/dist/development/core/product/accept-variant-id.mjs +98 -0
- package/dist/development/core/product/accept-variant-id.mjs.map +1 -0
- package/dist/development/core/product/form.d.mts +63 -0
- package/dist/development/core/product/form.mjs +44 -0
- package/dist/development/core/product/form.mjs.map +1 -0
- package/dist/development/core/product/index.d.mts +5 -0
- package/dist/development/core/product/options.d.mts +43 -0
- package/dist/development/core/product/options.mjs +296 -0
- package/dist/development/core/product/options.mjs.map +1 -0
- package/dist/development/core/product/product-form.d.mts +72 -0
- package/dist/development/core/product/product-form.mjs +158 -0
- package/dist/development/core/product/product-form.mjs.map +1 -0
- package/dist/development/core/product/state.d.mts +68 -0
- package/dist/development/core/product/url.d.mts +47 -0
- package/dist/development/core/product/url.mjs +69 -0
- package/dist/development/core/product/url.mjs.map +1 -0
- package/dist/development/core/request-context.d.mts +75 -0
- package/dist/development/core/request-context.mjs +141 -0
- package/dist/development/core/request-context.mjs.map +1 -0
- package/dist/development/core/request-routing/handle-shopify-redirects.d.mts +17 -0
- package/dist/development/core/request-routing/handle-shopify-redirects.mjs +31 -0
- package/dist/development/core/request-routing/handle-shopify-redirects.mjs.map +1 -0
- package/dist/development/core/request-routing/handle-shopify-routes.d.mts +1 -0
- package/dist/development/core/request-routing/handle-shopify-routes.development.d.mts +11 -0
- package/dist/development/core/request-routing/handle-shopify-routes.development.mjs +16 -0
- package/dist/development/core/request-routing/handle-shopify-routes.development.mjs.map +1 -0
- package/dist/development/core/request-routing/handle-shopify-routes.mjs +42 -0
- package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/admin-redirect.mjs +12 -0
- package/dist/development/core/request-routing/interceptors/admin-redirect.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/ajax-api.mjs +16 -0
- package/dist/development/core/request-routing/interceptors/ajax-api.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/api-proxy.mjs +20 -0
- package/dist/development/core/request-routing/interceptors/api-proxy.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/checkout.mjs +58 -0
- package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/graphiql.mjs +46 -0
- package/dist/development/core/request-routing/interceptors/graphiql.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +23 -0
- package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/proxy.mjs +73 -0
- package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +22 -0
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +27 -0
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/standard-routes.mjs +19 -0
- package/dist/development/core/request-routing/interceptors/standard-routes.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/url-redirects.mjs +27 -0
- package/dist/development/core/request-routing/interceptors/url-redirects.mjs.map +1 -0
- package/dist/development/core/request-routing/interceptors/well-known.mjs +22 -0
- package/dist/development/core/request-routing/interceptors/well-known.mjs.map +1 -0
- package/dist/development/core/request-routing/registered-routes.d.mts +7 -0
- package/dist/development/core/request-routing/registered-routes.mjs +72 -0
- package/dist/development/core/request-routing/registered-routes.mjs.map +1 -0
- package/dist/development/core/request-routing/route-types.d.mts +56 -0
- package/dist/development/core/request-routing/safe-apply-response-headers.mjs +16 -0
- package/dist/development/core/request-routing/safe-apply-response-headers.mjs.map +1 -0
- package/dist/development/core/shop-pay/shop-pay.d.mts +102 -0
- package/dist/development/core/shop-pay/shop-pay.mjs +289 -0
- package/dist/development/core/shop-pay/shop-pay.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/analytics.mjs +26 -0
- package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/consent.mjs +17 -0
- package/dist/development/core/shopify-scripts/consent.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/constants.mjs +19 -0
- package/dist/development/core/shopify-scripts/constants.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +97 -0
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/global.d.mts +1 -0
- package/dist/development/core/shopify-scripts/global.mjs +86 -0
- package/dist/development/core/shopify-scripts/global.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/index.d.mts +27 -0
- package/dist/development/core/shopify-scripts/index.mjs +145 -0
- package/dist/development/core/shopify-scripts/index.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/initialize.d.mts +18 -0
- package/dist/development/core/shopify-scripts/initialize.mjs +27 -0
- package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/page-view.mjs +49 -0
- package/dist/development/core/shopify-scripts/page-view.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/perfkit.mjs +33 -0
- package/dist/development/core/shopify-scripts/perfkit.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/render.d.mts +1 -0
- package/dist/development/core/shopify-scripts/render.mjs +23 -0
- package/dist/development/core/shopify-scripts/render.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/types.d.mts +76 -0
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +43 -0
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/utils/inline-script.mjs +8 -0
- package/dist/development/core/shopify-scripts/utils/inline-script.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/utils/navigation.mjs +46 -0
- package/dist/development/core/shopify-scripts/utils/navigation.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +65 -0
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/utils/uuid.mjs +17 -0
- package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +1 -0
- package/dist/development/core/shopify-scripts/webmcp.mjs +22 -0
- package/dist/development/core/shopify-scripts/webmcp.mjs.map +1 -0
- package/dist/development/core/standard-routes/build.d.mts +34 -0
- package/dist/development/core/standard-routes/build.mjs +54 -0
- package/dist/development/core/standard-routes/build.mjs.map +1 -0
- package/dist/development/core/standard-routes/defaults.mjs +31 -0
- package/dist/development/core/standard-routes/defaults.mjs.map +1 -0
- package/dist/development/core/standard-routes/match.mjs +108 -0
- package/dist/development/core/standard-routes/match.mjs.map +1 -0
- package/dist/development/core/standard-routes/path.mjs +58 -0
- package/dist/development/core/standard-routes/path.mjs.map +1 -0
- package/dist/development/core/standard-routes/redirects.mjs +51 -0
- package/dist/development/core/standard-routes/redirects.mjs.map +1 -0
- package/dist/development/core/standard-routes/types.d.mts +95 -0
- package/dist/development/core/types.d.mts +11 -0
- package/dist/development/core/url.mjs +42 -0
- package/dist/development/core/url.mjs.map +1 -0
- package/dist/development/core/utils/load-script.mjs +34 -0
- package/dist/development/core/utils/load-script.mjs.map +1 -0
- package/dist/development/core/utils/parse-gid.mjs +33 -0
- package/dist/development/core/utils/parse-gid.mjs.map +1 -0
- package/dist/development/customer-account/session.d.mts +46 -0
- package/dist/development/customer-account/session.mjs +21 -0
- package/dist/development/customer-account/session.mjs.map +1 -0
- package/dist/development/globals.d.mts +64 -0
- package/dist/development/graphql/generated/customer-account-api-types.d.mts +13 -0
- package/dist/development/graphql/generated/graphql-env.d.mts +19280 -0
- package/dist/development/graphql/generated/storefront-api-types.d.mts +47 -0
- package/dist/development/graphql/graphql.d.mts +40 -0
- package/dist/development/graphql/graphql.mjs +16 -0
- package/dist/development/graphql/graphql.mjs.map +1 -0
- package/dist/development/graphql/index.d.mts +2 -0
- package/dist/development/graphql/scalars.d.mts +15 -0
- package/dist/development/graphql/type-resolver.d.mts +229 -0
- package/dist/development/react/cart.d.mts +44 -0
- package/dist/development/react/cart.mjs +155 -0
- package/dist/development/react/cart.mjs.map +1 -0
- package/dist/development/react/collection.d.mts +91 -0
- package/dist/development/react/collection.mjs +129 -0
- package/dist/development/react/collection.mjs.map +1 -0
- package/dist/development/react/index.d.mts +13 -0
- package/dist/development/react/index.mjs +10 -0
- package/dist/development/react/predictive-search.d.mts +49 -0
- package/dist/development/react/predictive-search.mjs +133 -0
- package/dist/development/react/predictive-search.mjs.map +1 -0
- package/dist/development/react/product.d.mts +72 -0
- package/dist/development/react/product.mjs +127 -0
- package/dist/development/react/product.mjs.map +1 -0
- package/dist/development/react/shop-pay.d.mts +9 -0
- package/dist/development/react/shop-pay.mjs +16 -0
- package/dist/development/react/shop-pay.mjs.map +1 -0
- package/dist/development/react/shopify-scripts.d.mts +20 -0
- package/dist/development/react/shopify-scripts.mjs +39 -0
- package/dist/development/react/shopify-scripts.mjs.map +1 -0
- package/dist/development/vendor/standard-actions.d.mts +134 -0
- package/dist/development/vendor/standard-events.d.mts +1107 -0
- package/dist/development/vue/cart.d.mts +46 -0
- package/dist/development/vue/cart.mjs +122 -0
- package/dist/development/vue/cart.mjs.map +1 -0
- package/dist/development/vue/collection.d.mts +46 -0
- package/dist/development/vue/collection.mjs +108 -0
- package/dist/development/vue/collection.mjs.map +1 -0
- package/dist/development/vue/index.d.mts +11 -0
- package/dist/development/vue/index.mjs +8 -0
- package/dist/development/vue/predictive-search.d.mts +124 -0
- package/dist/development/vue/predictive-search.mjs +171 -0
- package/dist/development/vue/predictive-search.mjs.map +1 -0
- package/dist/development/vue/product.d.mts +57 -0
- package/dist/development/vue/product.mjs +167 -0
- package/dist/development/vue/product.mjs.map +1 -0
- package/dist/development/vue/shop-pay.d.mts +25 -0
- package/dist/development/vue/shop-pay.mjs +35 -0
- package/dist/development/vue/shop-pay.mjs.map +1 -0
- package/dist/development/vue/shopify-scripts.d.mts +127 -0
- package/dist/development/vue/shopify-scripts.mjs +79 -0
- package/dist/development/vue/shopify-scripts.mjs.map +1 -0
- package/dist/globals.d.mts +64 -0
- package/dist/graphql/generated/customer-account-api-types.d.mts +13 -0
- package/dist/graphql/generated/customer-account-graphql-env.d.mts +22170 -0
- package/dist/graphql/generated/graphql-env.d.mts +19280 -0
- package/dist/graphql/generated/storefront-api-types.d.mts +47 -0
- package/dist/graphql/graphql.d.mts +40 -0
- package/dist/graphql/graphql.mjs +16 -0
- package/dist/graphql/graphql.mjs.map +1 -0
- package/dist/graphql/index.d.mts +2 -0
- package/dist/graphql/scalars.d.mts +26 -0
- package/dist/graphql/type-resolver.d.mts +229 -0
- package/dist/react/cart.d.mts +44 -0
- package/dist/react/cart.mjs +155 -0
- package/dist/react/cart.mjs.map +1 -0
- package/dist/react/collection.d.mts +91 -0
- package/dist/react/collection.mjs +129 -0
- package/dist/react/collection.mjs.map +1 -0
- package/dist/react/index.d.mts +13 -0
- package/dist/react/index.mjs +10 -0
- package/dist/react/predictive-search.d.mts +49 -0
- package/dist/react/predictive-search.mjs +133 -0
- package/dist/react/predictive-search.mjs.map +1 -0
- package/dist/react/product.d.mts +72 -0
- package/dist/react/product.mjs +127 -0
- package/dist/react/product.mjs.map +1 -0
- package/dist/react/shop-pay.d.mts +9 -0
- package/dist/react/shop-pay.mjs +16 -0
- package/dist/react/shop-pay.mjs.map +1 -0
- package/dist/react/shopify-scripts.d.mts +20 -0
- package/dist/react/shopify-scripts.mjs +39 -0
- package/dist/react/shopify-scripts.mjs.map +1 -0
- package/dist/storefront-api-types.d.ts +2351 -2390
- package/dist/storefront.schema.json +41534 -1
- package/dist/ts-plugin/index.cjs +68 -0
- package/dist/ts-plugin/index.cjs.map +1 -0
- package/dist/ts-plugin/index.d.cts +4 -0
- package/dist/vendor/standard-actions.d.mts +134 -0
- package/dist/vendor/standard-events.d.mts +1107 -0
- package/dist/vite/certificate-prompt.mjs +24 -0
- package/dist/vite/certificate-prompt.mjs.map +1 -0
- package/dist/vite/index.d.mts +2 -0
- package/dist/vite/index.mjs +3 -0
- package/dist/vite/local-https.d.mts +47 -0
- package/dist/vite/local-https.mjs +276 -0
- package/dist/vite/local-https.mjs.map +1 -0
- package/dist/vite/mkcert.mjs +141 -0
- package/dist/vite/mkcert.mjs.map +1 -0
- package/dist/vue/cart.d.mts +46 -0
- package/dist/vue/cart.mjs +122 -0
- package/dist/vue/cart.mjs.map +1 -0
- package/dist/vue/collection.d.mts +46 -0
- package/dist/vue/collection.mjs +108 -0
- package/dist/vue/collection.mjs.map +1 -0
- package/dist/vue/index.d.mts +11 -0
- package/dist/vue/index.mjs +8 -0
- package/dist/vue/predictive-search.d.mts +124 -0
- package/dist/vue/predictive-search.mjs +171 -0
- package/dist/vue/predictive-search.mjs.map +1 -0
- package/dist/vue/product.d.mts +57 -0
- package/dist/vue/product.mjs +167 -0
- package/dist/vue/product.mjs.map +1 -0
- package/dist/vue/shop-pay.d.mts +25 -0
- package/dist/vue/shop-pay.mjs +35 -0
- package/dist/vue/shop-pay.mjs.map +1 -0
- package/dist/vue/shopify-scripts.d.mts +127 -0
- package/dist/vue/shopify-scripts.mjs +79 -0
- package/dist/vue/shopify-scripts.mjs.map +1 -0
- package/package.json +116 -86
- package/skills/hydrogen-analytics/SKILL.md +80 -0
- package/skills/hydrogen-analytics/references/react.md +160 -0
- package/skills/hydrogen-analytics/references/vue.md +80 -0
- package/skills/hydrogen-cart-drawer/SKILL.md +248 -0
- package/skills/hydrogen-cart-drawer/references/accessibility.md +109 -0
- package/skills/hydrogen-cart-drawer/references/css.md +67 -0
- package/skills/hydrogen-cart-ui/SKILL.md +224 -0
- package/skills/hydrogen-cart-ui/references/nextjs.md +89 -0
- package/skills/hydrogen-cart-ui/references/react.md +285 -0
- package/skills/hydrogen-cart-ui/references/vue.md +228 -0
- package/skills/hydrogen-collection-browser/SKILL.md +83 -0
- package/skills/hydrogen-collection-browser/references/nextjs.md +118 -0
- package/skills/hydrogen-collection-browser/references/nuxt.md +108 -0
- package/skills/hydrogen-collection-browser/references/react.md +301 -0
- package/skills/hydrogen-customer-account/SKILL.md +107 -0
- package/skills/hydrogen-image/SKILL.md +65 -0
- package/skills/hydrogen-local-https/SKILL.md +142 -0
- package/skills/hydrogen-markets/SKILL.md +221 -0
- package/skills/hydrogen-markets/references/nextjs.md +157 -0
- package/skills/hydrogen-money/SKILL.md +67 -0
- package/skills/hydrogen-oxygen/SKILL.md +245 -0
- package/skills/hydrogen-oxygen/references/react-router.md +230 -0
- package/skills/hydrogen-predictive-search/SKILL.md +130 -0
- package/skills/hydrogen-predictive-search/references/react.md +32 -0
- package/skills/hydrogen-predictive-search/references/vue.md +40 -0
- package/skills/hydrogen-request-handlers/SKILL.md +107 -0
- package/skills/hydrogen-request-handlers/references/frameworks.md +179 -0
- package/skills/hydrogen-request-handlers/references/nextjs.md +137 -0
- package/skills/hydrogen-request-handlers/references/nuxt.md +215 -0
- package/skills/hydrogen-routing/SKILL.md +171 -0
- package/skills/hydrogen-setup/SKILL.md +50 -0
- package/skills/hydrogen-setup/references/analytics.md +624 -0
- package/skills/hydrogen-setup/steps/1-inspect-app.md +62 -0
- package/skills/hydrogen-setup/steps/10-analytics.md +10 -0
- package/skills/hydrogen-setup/steps/11-verify.md +31 -0
- package/skills/hydrogen-setup/steps/2-scaffold.md +86 -0
- package/skills/hydrogen-setup/steps/3-build-home-page.md +37 -0
- package/skills/hydrogen-setup/steps/4-collection-and-search.md +14 -0
- package/skills/hydrogen-setup/steps/5-cart.md +10 -0
- package/skills/hydrogen-setup/steps/6-product-detail-page.md +416 -0
- package/skills/hydrogen-setup/steps/7-shopify-runtime-scripts.md +69 -0
- package/skills/hydrogen-setup/steps/8-cart-drawer-and-navbar.md +35 -0
- package/skills/hydrogen-setup/steps/9-account-page.md +54 -0
- package/skills/hydrogen-shop-pay/SKILL.md +79 -0
- package/skills/hydrogen-shop-pay/references/core.md +66 -0
- package/skills/hydrogen-shop-pay/references/react.md +50 -0
- package/skills/hydrogen-shop-pay/references/vue.md +39 -0
- package/skills/hydrogen-smoke-test/SKILL.md +205 -0
- package/skills/hydrogen-storefront-client/SKILL.md +322 -0
- package/skills/hydrogen-storefront-client/references/astro.md +125 -0
- package/skills/hydrogen-storefront-client/references/caching.md +25 -0
- package/skills/hydrogen-storefront-client/references/nextjs.md +121 -0
- package/skills/hydrogen-storefront-client/references/nuxt.md +121 -0
- package/skills/hydrogen-storefront-client/references/query-validation.md +95 -0
- package/skills/hydrogen-storefront-client/references/react-router.md +81 -0
- package/skills/hydrogen-storefront-client/references/solidstart.md +131 -0
- package/skills/hydrogen-storefront-client/references/sveltekit.md +169 -0
- package/skills/hydrogen-variant-form/SKILL.md +267 -0
- package/skills/hydrogen-variant-form/references/nextjs.md +207 -0
- package/skills/hydrogen-variant-form/references/nuxt.md +95 -0
- package/skills/hydrogen-variant-form/references/react.md +71 -0
- package/dist/dev/get-virtual-routes-H72465VB.js +0 -74
- package/dist/dev/hydrogen-routes.d.ts +0 -5
- package/dist/dev/hydrogen-routes.js +0 -25
- package/dist/development/get-virtual-routes-ACFZHU42.js +0 -71
- package/dist/development/get-virtual-routes-ACFZHU42.js.map +0 -1
- package/dist/development/index.cjs +0 -6978
- package/dist/development/index.cjs.map +0 -1
- package/dist/development/index.js +0 -6631
- package/dist/development/index.js.map +0 -1
- package/dist/development/log-seo-tags-IG37ONQ2.js +0 -74
- package/dist/development/log-seo-tags-IG37ONQ2.js.map +0 -1
- package/dist/development/react-router-preset.d.ts +0 -45
- package/dist/development/react-router-preset.js +0 -49
- package/dist/development/react-router-preset.js.map +0 -1
- package/dist/index.cjs +0 -1
- package/dist/oxygen/index.d.ts +0 -197
- package/dist/oxygen/index.js +0 -107
- package/dist/production/get-virtual-routes-ZZEGQQDV.js +0 -3
- package/dist/production/get-virtual-routes-ZZEGQQDV.js.map +0 -1
- package/dist/production/index.cjs +0 -1019
- package/dist/production/index.cjs.map +0 -1
- package/dist/production/index.d.cts +0 -3260
- package/dist/production/index.d.ts +0 -3260
- package/dist/production/index.js +0 -1019
- package/dist/production/index.js.map +0 -1
- package/dist/production/log-seo-tags-TY72EQWZ.js +0 -2
- package/dist/production/log-seo-tags-TY72EQWZ.js.map +0 -1
- package/dist/production/react-router-preset.d.ts +0 -45
- package/dist/production/react-router-preset.js +0 -11
- package/dist/react-router.d.ts +0 -75
- package/dist/vite/chunk-4O5OI3OO.js +0 -127
- package/dist/vite/chunk-FAQ7TVHC.js +0 -9
- package/dist/vite/chunk-QXBQVDMY.js +0 -68
- package/dist/vite/compat-date.d.ts +0 -3
- package/dist/vite/compat-date.js +0 -6
- package/dist/vite/get-virtual-routes.d.ts +0 -21
- package/dist/vite/get-virtual-routes.js +0 -74
- package/dist/vite/hydrogen-middleware.d.ts +0 -9
- package/dist/vite/hydrogen-middleware.js +0 -7
- package/dist/vite/plugin.d.ts +0 -22
- package/dist/vite/plugin.js +0 -171
- package/dist/vite/request-events.d.ts +0 -144
- package/dist/vite/request-events.js +0 -10
- package/dist/vite/types.d.ts +0 -5
- package/dist/vite/types.js +0 -0
- package/dist/vite/virtual-routes/assets/debug-network.css +0 -609
- package/dist/vite/virtual-routes/assets/favicon-dark.svg +0 -20
- package/dist/vite/virtual-routes/assets/favicon.svg +0 -28
- package/dist/vite/virtual-routes/assets/inter-variable-font.woff2 +0 -0
- package/dist/vite/virtual-routes/assets/jetbrainsmono-variable-font.woff2 +0 -0
- package/dist/vite/virtual-routes/assets/styles.css +0 -249
- package/dist/vite/virtual-routes/components/FlameChartWrapper.jsx +0 -123
- package/dist/vite/virtual-routes/components/HydrogenLogoBaseBW.jsx +0 -32
- package/dist/vite/virtual-routes/components/HydrogenLogoBaseColor.jsx +0 -47
- package/dist/vite/virtual-routes/components/IconBanner.jsx +0 -292
- package/dist/vite/virtual-routes/components/IconClose.jsx +0 -38
- package/dist/vite/virtual-routes/components/IconDiscard.jsx +0 -44
- package/dist/vite/virtual-routes/components/IconError.jsx +0 -61
- package/dist/vite/virtual-routes/components/IconGithub.jsx +0 -23
- package/dist/vite/virtual-routes/components/IconTwitter.jsx +0 -21
- package/dist/vite/virtual-routes/components/Layout.jsx +0 -7
- package/dist/vite/virtual-routes/components/RequestDetails.jsx +0 -171
- package/dist/vite/virtual-routes/components/RequestTable.jsx +0 -91
- package/dist/vite/virtual-routes/components/RequestWaterfall.jsx +0 -151
- package/dist/vite/virtual-routes/layout.jsx +0 -33
- package/dist/vite/virtual-routes/lib/useDebugNetworkServer.jsx +0 -178
- package/dist/vite/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.jsx +0 -37
- package/dist/vite/virtual-routes/routes/[.]well-known.appspecific.com[.]chrome[.]devtools[.]json.tsx +0 -79
- package/dist/vite/virtual-routes/routes/graphiql.jsx +0 -5
- package/dist/vite/virtual-routes/routes/index.jsx +0 -265
- package/dist/vite/virtual-routes/routes/subrequest-profiler.jsx +0 -243
- package/dist/vite/virtual-routes/virtual-root-with-layout.jsx +0 -63
- package/dist/vite/virtual-routes/virtual-root.jsx +0 -67
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
# Analytics
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- What you're installing, and what it does on its own
|
|
6
|
+
- Configuration
|
|
7
|
+
- `shop`
|
|
8
|
+
- `consent`
|
|
9
|
+
- The shared singleton pattern
|
|
10
|
+
- Root configuration examples
|
|
11
|
+
- Per-route view events
|
|
12
|
+
- Framework-specific shapes
|
|
13
|
+
- SvelteKit — single-hook (cleanest case)
|
|
14
|
+
- Next.js App Router — Suspense-wrapped tracker + per-page client trackers
|
|
15
|
+
- Astro — inline `<script>` + hidden-data bridge (MPA pattern)
|
|
16
|
+
- Adapting to a new framework
|
|
17
|
+
- Cart Tracking
|
|
18
|
+
- Wiring third-party destinations
|
|
19
|
+
- Verify
|
|
20
|
+
- Common gotchas
|
|
21
|
+
- Anti-patterns
|
|
22
|
+
|
|
23
|
+
**Prerequisites:**
|
|
24
|
+
|
|
25
|
+
- A storefront built on `@shopify/hydrogen` with the request interceptors already wired (`handleShopifyRoutes` and `handleShopifyRedirects`). The analytics bus depends on the SFAPI proxy so the browser can observe same-origin Storefront API responses for session cookies. Without the proxy, analytics falls back to deprecated JavaScript-visible cookies and should be treated as incomplete. If you have not installed the interceptors yet, install them first with the local `hydrogen-request-handlers` skill.
|
|
26
|
+
- Shopify runtime scripts rendered from the root/document head. Use `ShopifyScripts` from your framework binding if it exports one, or `getShopifyScriptTags()` / `renderShopifyScriptTags()` from core in other framework heads. Pass `{country, language, currency?}` as `i18n`; pass `{shopId: env.SHOP_ID, storefrontId: env.PUBLIC_STOREFRONT_ID ?? "0", myshopifyDomain: env.PUBLIC_STORE_DOMAIN}` as `shop`. Resolve both on the server, declare them as consts annotated with the `ShopifyScriptsShop` / `ShopifyScriptsI18n` types from `@shopify/hydrogen` (so wrong or missing fields fail typecheck where they are built), and serialize them into ShopifyScripts. ShopifyScripts creates `window.Shopify.analytics` by default and exposes the permanent domain as `window.Shopify.shop`. Analytics consent config does not accept `country` or `language`.
|
|
27
|
+
- A client-side lifecycle hook in your framework (route-change effect, navigation event, `<script>` tag, etc.) so view events can fire on the right URL transitions.
|
|
28
|
+
|
|
29
|
+
`ShopifyScripts` creates the zero-dependency analytics bus, sets it on `window.Shopify.analytics`, and owns Shopify consent setup, analytics CDN loading, and deprecated-cookie compatibility. Framework adapters stay thin: they translate framework lifecycle events into bus calls and wire cart delta tracking with `trackCartAnalytics()`.
|
|
30
|
+
|
|
31
|
+
## What you're installing, and what it does on its own
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Your app code
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
window.Shopify.analytics
|
|
38
|
+
│
|
|
39
|
+
├── publish / subscribe / addDestination / destroy (app-facing)
|
|
40
|
+
├── raw live subscribers
|
|
41
|
+
└── consent-gated destinations with replay
|
|
42
|
+
│
|
|
43
|
+
└── Customer Privacy gates destination delivery and replay
|
|
44
|
+
|
|
45
|
+
ShopifyScripts
|
|
46
|
+
│
|
|
47
|
+
├── loads Shopify Customer Privacy script (consent + region gating)
|
|
48
|
+
├── loads Privacy Banner script in default-banner mode
|
|
49
|
+
├── loads Shopify analytics destination by default
|
|
50
|
+
└── writes deprecated _shopify_y / _shopify_s cookies
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The bus is **browser-only effective** and is created by ShopifyScripts in the browser. There is no server-side dispatch.
|
|
54
|
+
|
|
55
|
+
What the bus does for you out of the box:
|
|
56
|
+
|
|
57
|
+
- Sends `page_viewed`, `product_viewed`, `collection_viewed`, `search_viewed`, and `product_added_to_cart` events to Monorail (`https://monorail-edge.shopifysvc.com/unstable/produce_batch`) using the customer-tracking schema.
|
|
58
|
+
- Exposes itself on `window.Shopify.analytics` so Shopify runtime scripts can attach browser-only analytics integrations.
|
|
59
|
+
|
|
60
|
+
What it does **not** do:
|
|
61
|
+
|
|
62
|
+
- Server-side analytics dispatch.
|
|
63
|
+
- Third-party destination integrations (GA4, Meta Pixel, Klaviyo) — wire those with `addDestination()`.
|
|
64
|
+
- Cart event publishing without `trackCartAnalytics()`. App code should not manually publish `cart_updated` etc.
|
|
65
|
+
- DOM event ingestion or Standard Events. Explicit `publish()` is the API.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
type ConsentConfig,
|
|
74
|
+
type ShopifyScriptTagsOptions,
|
|
75
|
+
type ShopifyScriptsShop,
|
|
76
|
+
type ShopifyScriptsI18n,
|
|
77
|
+
} from "@shopify/hydrogen";
|
|
78
|
+
|
|
79
|
+
const shop: ShopifyScriptsShop = {
|
|
80
|
+
shopId: "12345", // numeric Shop ID or Shopify Shop GID
|
|
81
|
+
storefrontId: "0", // your storefront ID, or "0"
|
|
82
|
+
myshopifyDomain: "example.myshopify.com", // permanent MyShopify domain
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const i18n: ShopifyScriptsI18n = {
|
|
86
|
+
country: "US",
|
|
87
|
+
language: "EN", // sent as Monorail content language
|
|
88
|
+
currency: "USD", // optional; sets window.Shopify.currency.active
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const consent: ConsentConfig = {
|
|
92
|
+
mode: "default-banner", // "default-banner" | "custom-banner" | "no-banner"
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const analytics: NonNullable<ShopifyScriptTagsOptions["analytics"]> = {
|
|
96
|
+
customData: { theme: "v2" }, // optional, attached to bus-generated payloads
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`ShopifyScripts` loads Shopify's built-in analytics destination by default. Pass
|
|
101
|
+
`shopifyAnalytics: false` to `getShopifyScriptTags()` / `renderShopifyScriptTags()` if a
|
|
102
|
+
storefront needs to omit that CDN script.
|
|
103
|
+
|
|
104
|
+
### `shop`
|
|
105
|
+
|
|
106
|
+
Required flat shop metadata. `shopId` may be a numeric Shop ID or a Shopify Shop GID (e.g. `gid://shopify/Shop/12345`); it is normalized before the analytics bus receives it.
|
|
107
|
+
|
|
108
|
+
`shopId` and `storefrontId` are different identifiers: `shopId` identifies the shop itself (the same shop as the Customer Account API `SHOP_ID`), while `storefrontId` identifies the specific headless/Hydrogen storefront instance attached to that shop — a shop can have several storefronts, and analytics/PerfKit attribute traffic to this one. Use `"0"` when the app has no provisioned storefront ID.
|
|
109
|
+
|
|
110
|
+
Resolve shop metadata on the server and pass it to ShopifyScripts. Shopify analytics needs the shop ID, PerfKit needs the numeric shop ID plus storefront ID, and storefront components use `myshopifyDomain` through `window.Shopify.shop`.
|
|
111
|
+
|
|
112
|
+
### `i18n`
|
|
113
|
+
|
|
114
|
+
Pass the app's resolved `country` and `language` market values. Optional `currency` sets `window.Shopify.currency.active` for Shopify runtime scripts and Shopify analytics. Shopify analytics reads its content language from `window.Shopify.locale`.
|
|
115
|
+
|
|
116
|
+
### `analytics`
|
|
117
|
+
|
|
118
|
+
The analytics bus is enabled by default. Pass `analytics` only when you need optional bus configuration such as `customData`, which is attached to bus-generated payloads. Shopify analytics reads currency from `window.Shopify.currency.active`, which is seeded by `i18n.currency` and updated from cart currency when available.
|
|
119
|
+
|
|
120
|
+
### `consent`
|
|
121
|
+
|
|
122
|
+
This is where the location/region nuance lives. Shopify's hosted Customer Privacy API decides per-visitor whether tracking requires consent based on the visitor's geography:
|
|
123
|
+
|
|
124
|
+
- **Visitors in jurisdictions with consent requirements** (EU/EEA/UK GDPR, parts of Canada, California CCPA, etc.) — analytics must wait for consent. Use `mode: "default-banner"` for Shopify's hosted privacy banner, or `mode: "custom-banner"` if your app renders its own banner and calls `window.Shopify.customerPrivacy.setTrackingConsent()`.
|
|
125
|
+
- **Visitors in jurisdictions without consent requirements** — the Customer Privacy SDK auto-allows tracking and the banner does not render. The bus dispatches normally.
|
|
126
|
+
|
|
127
|
+
`mode` controls how consent is collected:
|
|
128
|
+
|
|
129
|
+
- `"default-banner"` loads Shopify's hosted privacy banner and waits when the Customer Privacy API says banner interaction is required.
|
|
130
|
+
- `"custom-banner"` loads only the Customer Privacy API and treats the initial consent event as actionable. Your banner must call `setTrackingConsent()` when the shopper accepts or declines.
|
|
131
|
+
- `"no-banner"` loads only the Customer Privacy API and releases analytics after consent setup. Use this only when consent is already allowed or managed outside this storefront.
|
|
132
|
+
|
|
133
|
+
### Consent Gating
|
|
134
|
+
|
|
135
|
+
Default:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
() => window.Shopify?.customerPrivacy?.analyticsProcessingAllowed() ?? false
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This is conservative by design: if the Customer Privacy script is blocked, hasn't loaded, or is unavailable, **destination delivery is blocked**. Raw `subscribe()` listeners still see live events, but analytics destinations do not receive events until `analyticsProcessingAllowed()` returns true.
|
|
142
|
+
|
|
143
|
+
Events published before consent is ready are buffered for destinations and replayed only if analytics consent is granted. Destinations only receive supported event names they subscribe to. If the visitor explicitly denies analytics consent, the replay buffer is cleared.
|
|
144
|
+
|
|
145
|
+
Custom event names such as `custom_*` are temporarily unsupported. Publishing or subscribing to an unsupported event name logs a small warning and the event is ignored.
|
|
146
|
+
|
|
147
|
+
Do not bypass this gate in production. Shipping consent bypasses is a regulatory issue.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## The shared singleton pattern
|
|
152
|
+
|
|
153
|
+
Across all frameworks the right shape is **one bus per page lifetime**, created by ShopifyScripts and read lazily on the client. Resolve `shop` and `i18n` on the server, pass them to ShopifyScripts in the root layout/document head, then let route components publish through the shared global bus. Pass `i18n.currency` when Shopify runtime scripts and Shopify analytics need `window.Shopify.currency.active`. A module-level `getAnalytics()` helper works everywhere — React, Solid, Svelte, vanilla JS — and is what every framework example should use:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// app/lib/analytics.ts (or your framework's idiomatic shared-lib path)
|
|
157
|
+
import {
|
|
158
|
+
AnalyticsEvent,
|
|
159
|
+
type StorefrontAnalytics,
|
|
160
|
+
} from "@shopify/hydrogen";
|
|
161
|
+
|
|
162
|
+
export { AnalyticsEvent };
|
|
163
|
+
|
|
164
|
+
let bus: StorefrontAnalytics | null = null;
|
|
165
|
+
|
|
166
|
+
export function getAnalytics(): StorefrontAnalytics | null {
|
|
167
|
+
if (typeof window === "undefined") return null; // SSR no-op
|
|
168
|
+
if (bus) return bus;
|
|
169
|
+
bus = window.Shopify?.analytics ?? null;
|
|
170
|
+
return bus;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Non-optional constraints:
|
|
175
|
+
|
|
176
|
+
- **No client env reads.** `shopId`, `storefrontId`, `myshopifyDomain`, `country`, `language`, and `currency` are safe to serialize, but they should still be resolved on the server and passed into ShopifyScripts. Do not read `process.env` or `import.meta.env` inside this browser-lazy module.
|
|
177
|
+
- **Root configuration before publishing.** The root route/layout should render ShopifyScripts with `shop` and `i18n` before route components publish analytics events.
|
|
178
|
+
- **Browser-only access.** `typeof window === 'undefined'` guard (or your framework's equivalent — SvelteKit's `$app/environment.browser`, Next.js implicit on `"use client"`) prevents reading the global bus on the server.
|
|
179
|
+
- **One instance per page.** The singleton means every route, every effect, every script tag shares the same bus. Multiple instances on the same page overwrite `window.Shopify.customerPrivacy.config`; the latest initialized config wins. Multi-store on one page is not supported.
|
|
180
|
+
- **Lazy.** Reading the bus happens on first `getAnalytics()` call. ShopifyScripts owns bus construction.
|
|
181
|
+
|
|
182
|
+
App code can add explicit destinations for development logging or third-party integrations, then publish from each route:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
const cleanup = analytics.addDestination({
|
|
186
|
+
name: "example-console-logger",
|
|
187
|
+
setup({ subscribe }) {
|
|
188
|
+
const events = [
|
|
189
|
+
AnalyticsEvent.PAGE_VIEWED,
|
|
190
|
+
AnalyticsEvent.PRODUCT_VIEWED,
|
|
191
|
+
AnalyticsEvent.COLLECTION_VIEWED,
|
|
192
|
+
AnalyticsEvent.CART_VIEWED,
|
|
193
|
+
AnalyticsEvent.SEARCH_VIEWED,
|
|
194
|
+
] as const;
|
|
195
|
+
const unsubscribers = events.map((event) =>
|
|
196
|
+
subscribe(event, (payload) => {
|
|
197
|
+
console.log(`[analytics] ${event}`, payload);
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return () => {
|
|
202
|
+
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Destinations are consent-gated and receive replayed buffered events once tracking is allowed.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Root configuration examples
|
|
213
|
+
|
|
214
|
+
Each framework should derive `shop` and `i18n` on the server and render ShopifyScripts before publishing. The exact env API varies by framework; these examples show the data flow, not a requirement to use these file names.
|
|
215
|
+
|
|
216
|
+
Do not query `localization.language` just to echo the language already passed to `@inContext`. If the app only knows country/language and does not have a market currency code, add `currencyCode` to the app's market config or query `localization { country { currency { isoCode } } }` as a fallback.
|
|
217
|
+
|
|
218
|
+
React root layout:
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
<ShopifyScripts
|
|
222
|
+
shop={{
|
|
223
|
+
shopId: env.SHOP_ID,
|
|
224
|
+
storefrontId: env.PUBLIC_STOREFRONT_ID ?? "0",
|
|
225
|
+
myshopifyDomain: env.PUBLIC_STORE_DOMAIN,
|
|
226
|
+
}}
|
|
227
|
+
i18n={{ country: market.country, language: market.language, currency: market.currencyCode }}
|
|
228
|
+
consent={{ mode: "default-banner" }}
|
|
229
|
+
/>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Core renderer for non-React heads:
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
const shopifyTags = renderShopifyScriptTags({
|
|
236
|
+
shop: {
|
|
237
|
+
shopId: env.SHOP_ID,
|
|
238
|
+
storefrontId: env.PUBLIC_STOREFRONT_ID ?? "0",
|
|
239
|
+
myshopifyDomain: env.PUBLIC_STORE_DOMAIN,
|
|
240
|
+
},
|
|
241
|
+
i18n: { country: market.country, language: market.language, currency: market.currencyCode },
|
|
242
|
+
consent: { mode: "default-banner" },
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Per-page trackers can then call `getAnalytics()` as shown below. They do not need to configure the bus; ShopifyScripts already put it on `window.Shopify.analytics`.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Per-route view events
|
|
251
|
+
|
|
252
|
+
The bus is consent- and consent-region-aware on its own. The framework adapter is responsible for **when** to publish events — namely, on every relevant page transition. View events infer `url` from `window.location.href`, and `shop` defaults from the ShopifyScripts analytics config; pass either field only when a framework needs an explicit override.
|
|
253
|
+
|
|
254
|
+
The generic shape is:
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
On every page transition:
|
|
258
|
+
analytics.publish(AnalyticsEvent.PAGE_VIEWED)
|
|
259
|
+
|
|
260
|
+
On product page mount:
|
|
261
|
+
analytics.publish(AnalyticsEvent.PRODUCT_VIEWED, { products: [...] })
|
|
262
|
+
|
|
263
|
+
On collection page mount:
|
|
264
|
+
analytics.publish(AnalyticsEvent.COLLECTION_VIEWED, { collection })
|
|
265
|
+
|
|
266
|
+
On search results page:
|
|
267
|
+
analytics.publish(AnalyticsEvent.SEARCH_VIEWED, { searchTerm })
|
|
268
|
+
|
|
269
|
+
On cart view (page or drawer):
|
|
270
|
+
analytics.publish(AnalyticsEvent.CART_VIEWED, { cart })
|
|
271
|
+
|
|
272
|
+
Once per cart store lifecycle, in a client-only effect after ShopifyScripts has rendered:
|
|
273
|
+
trackCartAnalytics(cartStore) // subscribes to the store; emits cart_updated / product_added_to_cart / product_removed_from_cart on confirmed changes
|
|
274
|
+
// never at cart-store creation time — that runs during SSR, where the analytics bus does not exist
|
|
275
|
+
// React/Vue bindings: render useCartAnalytics() inside CartProvider instead
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Required product fields for `product_viewed` and `product_added_to_cart` Monorail dispatch: `id`, `title`, `price`, `vendor`, `variantId`, `variantTitle`. `id` must be the Shopify Product GID and `variantId` must be the Shopify ProductVariant GID when one is available; handles are routing/display data, not analytics IDs. Missing fields cause the Shopify analytics subscriber to skip the Monorail event and log a field-specific error — the bus event still fires for your subscribers, only the Monorail leg drops.
|
|
279
|
+
|
|
280
|
+
`CART_VIEWED` requires `{ cart }`. `cart` is `AnalyticsCart | null`; when a compatible cart is available, include `id`, `updatedAt`, and connection-shaped `lines`, otherwise pass `cart: null` rather than a partial object. (`prevCart` belongs to the cart-change events emitted by `trackCartAnalytics`, not to `CART_VIEWED`.)
|
|
281
|
+
|
|
282
|
+
## Framework-specific shapes
|
|
283
|
+
|
|
284
|
+
The patterns below cover the main shapes a framework will land in. They are illustrative — the universal singleton above is the load-bearing piece. For frameworks not listed, see "Adapting to a new framework" below.
|
|
285
|
+
|
|
286
|
+
### SvelteKit — single-hook (cleanest case)
|
|
287
|
+
|
|
288
|
+
SvelteKit's `afterNavigate` hook fires on every client-side navigation. Combined with `$app/environment.browser`, the entire wiring fits in the root layout:
|
|
289
|
+
|
|
290
|
+
```svelte
|
|
291
|
+
<!-- src/routes/+layout.svelte -->
|
|
292
|
+
<script lang="ts">
|
|
293
|
+
import { afterNavigate } from '$app/navigation';
|
|
294
|
+
import { getAnalytics, AnalyticsEvent } from '$lib/analytics';
|
|
295
|
+
|
|
296
|
+
let { children } = $props();
|
|
297
|
+
|
|
298
|
+
afterNavigate(() => {
|
|
299
|
+
const analytics = getAnalytics();
|
|
300
|
+
if (!analytics) return;
|
|
301
|
+
analytics.publish(AnalyticsEvent.PAGE_VIEWED);
|
|
302
|
+
});
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
{@render children()}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Per-page view events go in the route's `$effect`. The route loader must include `product.id` and `selectedOrFirstAvailableVariant { id title sku price { amount currencyCode } }` so analytics publishes Shopify GIDs, not handles. The empty `void handle;` line is intentional — Svelte 5's `$effect` only re-runs when reactive reads happen inside it; reading `data.product.handle` once forces tracking:
|
|
309
|
+
|
|
310
|
+
```svelte
|
|
311
|
+
<!-- src/routes/products/[handle]/+page.svelte -->
|
|
312
|
+
<script lang="ts">
|
|
313
|
+
import { getAnalytics, AnalyticsEvent } from '$lib/analytics';
|
|
314
|
+
let { data } = $props();
|
|
315
|
+
|
|
316
|
+
$effect(() => {
|
|
317
|
+
const handle = data.product.handle;
|
|
318
|
+
const variant = data.product.selectedOrFirstAvailableVariant;
|
|
319
|
+
const analytics = getAnalytics();
|
|
320
|
+
if (!analytics) return;
|
|
321
|
+
analytics.publish(AnalyticsEvent.PRODUCT_VIEWED, {
|
|
322
|
+
products: [{
|
|
323
|
+
id: data.product.id,
|
|
324
|
+
title: data.product.title,
|
|
325
|
+
price: variant?.price.amount ?? data.product.priceRange.minVariantPrice.amount,
|
|
326
|
+
vendor: data.product.vendor,
|
|
327
|
+
variantId: variant?.id ?? data.product.id,
|
|
328
|
+
variantTitle: variant?.title ?? data.product.title,
|
|
329
|
+
quantity: 1,
|
|
330
|
+
sku: variant?.sku,
|
|
331
|
+
}],
|
|
332
|
+
});
|
|
333
|
+
void handle;
|
|
334
|
+
});
|
|
335
|
+
</script>
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Next.js App Router — Suspense-wrapped tracker + per-page client trackers
|
|
339
|
+
|
|
340
|
+
Next App Router pages are async server components. Effects must live in client components. The pattern: one root-level `AnalyticsTracker` for `page_viewed`, plus per-page client trackers for product/collection/search.
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
// app/components/AnalyticsTracker.tsx
|
|
344
|
+
"use client";
|
|
345
|
+
import { useEffect } from "react";
|
|
346
|
+
import { usePathname, useSearchParams } from "next/navigation";
|
|
347
|
+
import { getAnalytics, AnalyticsEvent } from "../lib/analytics";
|
|
348
|
+
|
|
349
|
+
export function AnalyticsTracker() {
|
|
350
|
+
const pathname = usePathname();
|
|
351
|
+
const searchParams = useSearchParams();
|
|
352
|
+
const key = `${pathname}?${searchParams?.toString() ?? ""}`;
|
|
353
|
+
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
const bus = getAnalytics();
|
|
356
|
+
if (!bus) return;
|
|
357
|
+
bus.publish(AnalyticsEvent.PAGE_VIEWED);
|
|
358
|
+
}, [key]);
|
|
359
|
+
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Wrap the tracker in `<Suspense>` in the root layout. `useSearchParams()` opts the client tree out of static rendering; the Suspense boundary keeps that opt-out scoped to the tracker, not the whole layout:
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
// app/layout.tsx
|
|
368
|
+
import { Suspense } from "react";
|
|
369
|
+
import { AnalyticsTracker } from "./components/AnalyticsTracker";
|
|
370
|
+
|
|
371
|
+
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
372
|
+
return (
|
|
373
|
+
<html lang="en">
|
|
374
|
+
<body>
|
|
375
|
+
<Suspense fallback={null}>
|
|
376
|
+
<AnalyticsTracker />
|
|
377
|
+
</Suspense>
|
|
378
|
+
{children}
|
|
379
|
+
</body>
|
|
380
|
+
</html>
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Per-page trackers are thin client components that take server-resolved data and publish on mount:
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
// app/components/ProductViewedTracker.tsx
|
|
389
|
+
"use client";
|
|
390
|
+
import { useEffect } from "react";
|
|
391
|
+
import { getAnalytics, AnalyticsEvent } from "../lib/analytics";
|
|
392
|
+
|
|
393
|
+
type Props = {
|
|
394
|
+
product: {
|
|
395
|
+
id: string;
|
|
396
|
+
handle: string;
|
|
397
|
+
title: string;
|
|
398
|
+
vendor: string;
|
|
399
|
+
selectedOrFirstAvailableVariant: {
|
|
400
|
+
id: string;
|
|
401
|
+
title: string;
|
|
402
|
+
price: { amount: string };
|
|
403
|
+
sku?: string | null;
|
|
404
|
+
} | null;
|
|
405
|
+
priceRange: { minVariantPrice: { amount: string } };
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export function ProductViewedTracker({ product }: Props) {
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
const bus = getAnalytics();
|
|
412
|
+
if (!bus) return;
|
|
413
|
+
bus.publish(AnalyticsEvent.PRODUCT_VIEWED, {
|
|
414
|
+
products: [{
|
|
415
|
+
id: product.id,
|
|
416
|
+
title: product.title,
|
|
417
|
+
price:
|
|
418
|
+
product.selectedOrFirstAvailableVariant?.price.amount ??
|
|
419
|
+
product.priceRange.minVariantPrice.amount,
|
|
420
|
+
vendor: product.vendor,
|
|
421
|
+
variantId: product.selectedOrFirstAvailableVariant?.id ?? product.id,
|
|
422
|
+
variantTitle:
|
|
423
|
+
product.selectedOrFirstAvailableVariant?.title ?? product.title,
|
|
424
|
+
quantity: 1,
|
|
425
|
+
sku: product.selectedOrFirstAvailableVariant?.sku,
|
|
426
|
+
}],
|
|
427
|
+
});
|
|
428
|
+
}, [product.handle]);
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Render it from the (server) page component:
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
// app/products/[handle]/page.tsx
|
|
437
|
+
export default async function ProductPage({ params }: { params: Promise<{ handle: string }> }) {
|
|
438
|
+
const { handle } = await params;
|
|
439
|
+
const product = await fetchProduct(handle);
|
|
440
|
+
return (
|
|
441
|
+
<main>
|
|
442
|
+
<ProductViewedTracker product={product} />
|
|
443
|
+
{/* …rest of UI… */}
|
|
444
|
+
</main>
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Astro — inline `<script>` + hidden-data bridge (MPA pattern)
|
|
450
|
+
|
|
451
|
+
Astro is MPA-by-default. Each navigation is a full page load, so there is no client-side route-change hook to wire to. Page-view tracking goes in an inline `<script>` in the root layout:
|
|
452
|
+
|
|
453
|
+
```astro
|
|
454
|
+
---
|
|
455
|
+
// src/layouts/BaseLayout.astro
|
|
456
|
+
const { title } = Astro.props;
|
|
457
|
+
---
|
|
458
|
+
<html lang="en">
|
|
459
|
+
<head><title>{title}</title></head>
|
|
460
|
+
<body>
|
|
461
|
+
<slot />
|
|
462
|
+
<script>
|
|
463
|
+
import { getAnalytics, AnalyticsEvent } from "../lib/analytics";
|
|
464
|
+
const analytics = getAnalytics();
|
|
465
|
+
if (analytics) analytics.publish(AnalyticsEvent.PAGE_VIEWED);
|
|
466
|
+
</script>
|
|
467
|
+
</body>
|
|
468
|
+
</html>
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Astro `<script>` tags are processed and hoisted at build time — they cannot reference component-scoped variables directly. To bridge SSR data into the client script, render hidden DOM with `data-*` attributes and read them from the script:
|
|
472
|
+
|
|
473
|
+
```astro
|
|
474
|
+
---
|
|
475
|
+
// src/pages/products/[handle].astro
|
|
476
|
+
const product = await fetchProduct(Astro.params.handle);
|
|
477
|
+
---
|
|
478
|
+
<BaseLayout title={`${product.title} — Mock.shop`}>
|
|
479
|
+
<main>{/* …product UI… */}</main>
|
|
480
|
+
|
|
481
|
+
<div
|
|
482
|
+
id="product-analytics"
|
|
483
|
+
data-id={product.id}
|
|
484
|
+
data-title={product.title}
|
|
485
|
+
data-vendor={product.vendor}
|
|
486
|
+
data-price={product.selectedOrFirstAvailableVariant?.price.amount ?? product.priceRange.minVariantPrice.amount}
|
|
487
|
+
data-variant-id={product.selectedOrFirstAvailableVariant?.id ?? product.id}
|
|
488
|
+
data-variant-title={product.selectedOrFirstAvailableVariant?.title ?? product.title}
|
|
489
|
+
data-sku={product.selectedOrFirstAvailableVariant?.sku ?? ""}
|
|
490
|
+
hidden
|
|
491
|
+
></div>
|
|
492
|
+
|
|
493
|
+
<script>
|
|
494
|
+
import { getAnalytics, AnalyticsEvent } from "../../lib/analytics";
|
|
495
|
+
const el = document.getElementById("product-analytics");
|
|
496
|
+
const analytics = getAnalytics();
|
|
497
|
+
if (el && analytics) {
|
|
498
|
+
analytics.publish(AnalyticsEvent.PRODUCT_VIEWED, {
|
|
499
|
+
products: [{
|
|
500
|
+
id: el.dataset.id ?? "",
|
|
501
|
+
title: el.dataset.title ?? "",
|
|
502
|
+
price: el.dataset.price ?? "",
|
|
503
|
+
vendor: el.dataset.vendor ?? "",
|
|
504
|
+
variantId: el.dataset.variantId ?? el.dataset.id ?? "",
|
|
505
|
+
variantTitle: el.dataset.variantTitle ?? el.dataset.title ?? "",
|
|
506
|
+
quantity: 1,
|
|
507
|
+
sku: el.dataset.sku || undefined,
|
|
508
|
+
}],
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
</script>
|
|
512
|
+
</BaseLayout>
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
If you adopt Astro's View Transitions, swap the inline page-view script for a listener on the `astro:after-swap` event instead — the inline form only fires on full page loads.
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Adapting to a new framework
|
|
520
|
+
|
|
521
|
+
Three questions, in order, decide where things go:
|
|
522
|
+
|
|
523
|
+
1. **Is there a route-change hook on the client?** (SvelteKit `afterNavigate`, Solid `useLocation` reactive read, React Router `useLocation`, etc.) That is where `page_viewed` goes. If the framework is MPA-only and has no SPA navigation, fall back to a script in the root document layout — the page-view fires on every full load.
|
|
524
|
+
|
|
525
|
+
2. **Where does per-page server-resolved data become available on the client?** That is where each view event (`product_viewed`, `collection_viewed`, etc.) goes. In React, that is a `useEffect` keyed on the resolved data. In Solid, a `createEffect` reading the async value. In Svelte 5, an `$effect`. In Astro, an inline script that reads from a data-attribute bridge.
|
|
526
|
+
|
|
527
|
+
3. **Where does the client first have the cart store?** That is where you call `trackCartAnalytics(cartStore)` once — in a client-only effect after ShopifyScripts has rendered, never at cart-store creation time (that runs during SSR, where the analytics bus does not exist yet). The tracker subscribes to the store itself, so every confirmed cart change from any source (initial fetch, mutation result, SPA navigation re-fetch, optimistic update settled) is tracked without further app code. Keep the cleanup returned by the tracker when your framework has teardown hooks. See Cart Tracking below.
|
|
528
|
+
|
|
529
|
+
The singleton + lazy-init pattern from the previous section is universal. Every framework converges on the same shape: one shared analytics module, getter that no-ops on the server, and adapters that translate framework lifecycle into `publish()` / `trackCartAnalytics()` calls.
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Cart Tracking
|
|
534
|
+
|
|
535
|
+
Cart events do not come from `publish()` — they come from a cart tracker subscribed to the cart store:
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
const stopTracking = trackCartAnalytics(cartStore);
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Pass the cart store created by Hydrogen (`createCartStore`, or the store provided by the React/Vue `CartProvider` — the React and Vue bindings export a `useCartAnalytics()` hook/composable that does this for the provider's store). The tracker subscribes to the store itself, stores tracker state internally per analytics bus, skips pending/revalidating/note updates, and returns an unsubscribe function. It throws if `window.Shopify.analytics` is unavailable — render ShopifyScripts first — and runs change detection:
|
|
542
|
+
|
|
543
|
+
- Compares the new cart's `updatedAt` against the previous in-memory cart, against `localStorage.cartLastUpdatedAt`, and against the last emitted event ID.
|
|
544
|
+
- Diffs lines: removed lines emit `product_removed_from_cart`, new lines or quantity increases emit `product_added_to_cart`, quantity decreases emit `product_removed_from_cart`.
|
|
545
|
+
- Emits `cart_updated` first, then any line-level events.
|
|
546
|
+
|
|
547
|
+
The cart payload type is intentionally lightweight (no Hydrogen cart-type dependency):
|
|
548
|
+
|
|
549
|
+
```ts
|
|
550
|
+
type AnalyticsCart = {
|
|
551
|
+
id: string;
|
|
552
|
+
updatedAt: string; // required by AnalyticsCart for stable dedupe
|
|
553
|
+
lines: { nodes?: AnalyticsCartLine[]; edges?: { node: AnalyticsCartLine }[] };
|
|
554
|
+
[key: string]: unknown;
|
|
555
|
+
};
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Manually published `AnalyticsCart` payloads (like `CART_VIEWED`) accept both `lines.nodes` and `lines.edges` (GraphQL connection) shapes at the type level; the bus forwards them unchanged, so subscribers that read lines should flatten them with the exported `flattenConnection()` helper. The cart store consumed by `trackCartAnalytics` is different: it reads `cart.lines.nodes` directly, so the app's cart query must select `lines.nodes`. The tracker falls back to the current time internally if store data is missing `updatedAt`, but include `updatedAt` in the cart query for stable dedupe.
|
|
559
|
+
|
|
560
|
+
Application code should not manually publish `cart_updated`, `product_added_to_cart`, or `product_removed_from_cart`. Always go through `trackCartAnalytics`.
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Wiring third-party destinations
|
|
565
|
+
|
|
566
|
+
The bus is the right integration point for GA4, Meta Pixel, Klaviyo, etc. Register third-party analytics with `addDestination()`. The bus gates destination callbacks with Shopify Customer Privacy and replays buffered events after analytics consent is granted:
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
const analytics = getAnalytics();
|
|
570
|
+
analytics?.addDestination({
|
|
571
|
+
name: "ga4",
|
|
572
|
+
setup({ subscribe }) {
|
|
573
|
+
subscribe(AnalyticsEvent.PAGE_VIEWED, (payload) => {
|
|
574
|
+
if (!payload.url) return;
|
|
575
|
+
window.gtag?.("event", "page_view", { page_location: payload.url });
|
|
576
|
+
});
|
|
577
|
+
},
|
|
578
|
+
});
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
Consent gating happens at the bus level before destination callbacks see the payload. Raw `analytics.subscribe()` is live-only and consent-agnostic; use `addDestination()` for logging or analytics destinations that should respect consent and replay.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Verify
|
|
586
|
+
|
|
587
|
+
After wiring, smoke-test each event in the browser dev tools:
|
|
588
|
+
|
|
589
|
+
1. **Destination log fires** — open the page with the dev console open. You should see `[analytics] page_viewed` (or whichever events you logged) after consent allows tracking. If nothing logs, either `getAnalytics()` is no-op'ing on the server, the bus is unavailable, or `analyticsProcessingAllowed()` is false.
|
|
590
|
+
2. **Monorail request fires** — Network tab, filter for `monorail-edge.shopifysvc.com`. A `produce_batch` POST should land within ~1s of consent being granted (or immediately if the visitor is in a no-consent-required region). If it never fires, either consent has not been granted, the schemas are missing required fields (check console for warnings about missing `id`/`title`/`vendor`/etc.), or `hasUserConsent` is false on the payload.
|
|
591
|
+
3. **Per-route navigation fires page_viewed** — click around. Each navigation should produce a fresh `page_viewed` event. If only the initial page load fires, the route-change hook is wired wrong (e.g. effect dependency missing in React, reactive read missing in Solid).
|
|
592
|
+
4. **Cart events fire** — add an item to the cart. You should see `cart_updated` followed by `product_added_to_cart`. If you see `cart_updated` repeating with the same payload, the dedupe key (`updatedAt`) is stale — confirm your cart query selects `updatedAt`.
|
|
593
|
+
5. **Privacy banner renders for EU/UK visitors** — if `mode: "default-banner"`, simulate a GDPR-protected region with browser dev-tools location override or VPN. The banner should render. If it does not, check that `cdn.shopify.com` is not blocked by your CSP.
|
|
594
|
+
|
|
595
|
+
For production, re-verify against the production bundle. Several gotchas only appear once the SSR/CSR boundary stabilizes.
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Common gotchas
|
|
600
|
+
|
|
601
|
+
- **Replay is destination-only.** Raw `analytics.subscribe()` listeners only receive live events. `analytics.addDestination()` callbacks receive consent-gated live events plus buffered replay after analytics consent is granted. If the visitor explicitly denies analytics consent, the buffer is cleared and those pre-denial events are never replayed.
|
|
602
|
+
- **The singleton must be lazy.** Reading the global bus at module top-level can run on the server during SSR and crash on `window` access. Always wrap in a `typeof window === 'undefined'` guard.
|
|
603
|
+
- **Use the right shop shape for each API.** `ShopifyScripts` accepts a numeric Shop ID or Shopify Shop GID plus `storefrontId` and the permanent `myshopifyDomain`; the analytics bus normalizes `shop.shopId` to a Shopify Shop GID before dispatch, while the bootstrap exposes the domain as `window.Shopify.shop`.
|
|
604
|
+
- **Customer Privacy script blocked by CSP.** If your CSP does not allow `cdn.shopify.com`, the consent script never loads, `analyticsProcessingAllowed()` stays `false`, and destination events never deliver. Check Network tab for blocked requests; add `cdn.shopify.com` to `script-src`.
|
|
605
|
+
- **`mode: "no-banner"` is wrong for any storefront with EU/UK/CA visitors unless consent is handled elsewhere.** Without a hosted or custom banner, those visitors have no UI to grant consent — destination events never deliver. Default to `mode: "default-banner"` unless you have a custom consent UI that calls `setTrackingConsent()`.
|
|
606
|
+
- **Multiple bus instances on the same page conflict.** `window.Shopify.customerPrivacy.config` is global; the latest initialized config wins. Multi-store-per-page is not supported. Use one bus per active storefront shell.
|
|
607
|
+
- **Astro inline scripts cannot reference component scope.** Astro hoists `<script>` tags at build time. Bridge SSR data through hidden DOM (`data-*` attributes) and read it from the script. Trying to interpolate `{product.id}` directly into a script body silently fails — the script ships as a static string.
|
|
608
|
+
- **Astro page-view fires only on full loads.** Astro is MPA-by-default. If you adopt View Transitions, listen for `astro:after-swap` instead of relying on the inline-script-runs-on-load behavior — otherwise SPA-nav transitions skip `page_viewed`.
|
|
609
|
+
- **Required product fields silently drop the Monorail leg.** Missing `id`/`title`/`vendor`/`variantId`/`variantTitle`/`price` causes the Shopify analytics subscriber to skip Monorail dispatch and log a field-specific error. The bus event still fires for your subscribers — the loss is only in Shopify analytics. Watch the console.
|
|
610
|
+
- **`updatedAt` missing from cart query weakens dedupe.** The cart tracker prefers cart `updatedAt`, but falls back to the current time when it is absent. Include `updatedAt` in cart queries for stable dedupe across navigations and reloads.
|
|
611
|
+
- **`destroy()` is not called by any of the framework adapter sketches.** During HMR or React Strict Mode double-mount, this means duplicate event subscribers and possibly duplicate Monorail events in dev. For production this is rarely visible (one bus per page lifetime). If duplicate dev events bother you, wire `analytics.destroy()` into your framework's teardown (React effect cleanup, Svelte `onDestroy`, Solid `onCleanup`, or equivalent).
|
|
612
|
+
- **Lighthouse skip is silent.** Monorail dispatch is skipped for Chrome Lighthouse user-agents. If your synthetic monitoring runs Lighthouse, you will see no Monorail requests in those runs — this is intentional.
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## Anti-patterns
|
|
617
|
+
|
|
618
|
+
- **Don't construct the bus on the server.** SSR has no `window`, no consent SDK, and no useful behavior. Constructing on the server initializes browser internals against undefined globals and crashes — or worse, no-ops silently and ships analytics-free.
|
|
619
|
+
- **Don't manually publish `cart_updated` / `product_added_to_cart` / `product_removed_from_cart`.** These events come from `trackCartAnalytics(cartStore)`'s diff. Manual publishing bypasses the dedupe and produces duplicate or contradictory cart history.
|
|
620
|
+
- **Don't reimplement consent.** Shopify's Customer Privacy SDK already implements region-aware gating. Trying to replace that logic almost always introduces regulatory exposure.
|
|
621
|
+
- **Don't reimplement Monorail dispatch.** If you need a third-party destination, register it with `addDestination()` and forward from there — do not parallel-publish to Monorail yourself.
|
|
622
|
+
- **Don't put per-route view events in a global subscriber.** A single subscriber that watches `page_viewed` and synthesizes `product_viewed` from URL parsing is brittle and loses payload context. Publish each view event from the route that has the data.
|
|
623
|
+
- **Don't construct multiple buses for "different consent contexts" on the same page.** Customer Privacy config is global; the latest initialized config takes effect. If you need conditional behavior, branch inside subscribers, not at construction.
|
|
624
|
+
- **Don't skip the request-handler prerequisite.** Without the SFAPI proxy, modern same-origin Shopify cookies cannot be set. Analytics may appear to work via deprecated JS-visible cookies, but session continuity into checkout breaks. Treat analytics as incomplete until the proxy is live in production.
|