@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,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hydrogen-collection-browser
|
|
3
|
+
description: >
|
|
4
|
+
Guide for building collection and search browsing UI with @shopify/hydrogen.
|
|
5
|
+
Use when creating, modifying, or reviewing collection routes, search results,
|
|
6
|
+
product grids, filters, sort controls, active filter chips, or URL-synced
|
|
7
|
+
browse state in storefront frameworks.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Collection And Search Browsing
|
|
11
|
+
|
|
12
|
+
Hydrogen's collection primitive manages browse intent: filters, sort, URL params, and loading status. It does not own product data. The framework loader/server component owns Storefront API queries and passes products plus available filters into UI.
|
|
13
|
+
|
|
14
|
+
Use this skill for:
|
|
15
|
+
|
|
16
|
+
- `/collections`, `/collections/:handle`, and `/search` routes.
|
|
17
|
+
- Product grid filtering and sorting.
|
|
18
|
+
- Active filter chips and clear links.
|
|
19
|
+
- No-JS GET form fallbacks for filters and sort.
|
|
20
|
+
- Search-result pages that reuse collection browse state.
|
|
21
|
+
|
|
22
|
+
## Framework References
|
|
23
|
+
|
|
24
|
+
Before building UI, check whether this skill has a reference file for the app's framework in `references/`. If one exists, read it and use that framework binding or route pattern first.
|
|
25
|
+
|
|
26
|
+
If there is no matching reference, use `createCollectionStore` plus the `parseCollectionParams`/`serializeCollectionParams`/`getFilterRemovalUrl`/`isFilterInputActive` helpers from `@shopify/hydrogen` directly, and apply the UI and search rules below with the framework's own form, route, and reactivity primitives.
|
|
27
|
+
|
|
28
|
+
## Data Contract
|
|
29
|
+
|
|
30
|
+
Server data should include:
|
|
31
|
+
|
|
32
|
+
- Collection/search identity: collection `handle`, or `search:${term}` for search pages.
|
|
33
|
+
- `dataSearch`: the exact search string used for the server query.
|
|
34
|
+
- `products`: Storefront API product nodes shaped for the product card.
|
|
35
|
+
- `availableFilters`: normalized filter metadata from `products.filters` or `search.productFilters`.
|
|
36
|
+
- Optional `totalCount` and `pageInfo` for search or pagination UI.
|
|
37
|
+
|
|
38
|
+
Use `parseCollectionParams(searchParams)` before Storefront API queries. Pass parsed `filters`, `sortKey`, and `reverse` into `collection.products(...)` or `search(...)`.
|
|
39
|
+
|
|
40
|
+
## UI Rules
|
|
41
|
+
|
|
42
|
+
- Use the framework binding when a matching reference exists. Otherwise, use the core store directly. Do not hand-roll browse state with component state.
|
|
43
|
+
- The browse form must carry both `method="get"` **and** an explicit `action` (the collection/search route URL, e.g. `action="/collections/shoes"` or the search route) so filters and sort degrade to a real GET submit without JavaScript. `formProps()` only wires the submit handler — it does not set `method` or `action` — so render both literally; the helper cannot infer the route.
|
|
44
|
+
- Choose controls at the filter-group level: `PRICE_RANGE` renders min/max number inputs; `LIST` and `BOOLEAN` render value checkboxes. A price value serializes to two params, so never use the number of serialized entries to decide whether to render the group. Use the fixed `filter.v.price.gte` and `filter.v.price.lte` names for range inputs; continue deriving checkbox names and values from `value.input`.
|
|
45
|
+
- Use `formProps()` on the browse form: spread it, then add the literal `method="get"` and `action`. Submit checkboxes and `<select>` controls on change. Submit price inputs on blur only when the value changed, and let Enter blur the input. Never submit on every keystroke.
|
|
46
|
+
- Render a `noscript` submit button for filter sidebars that auto-submit when hydrated.
|
|
47
|
+
- Render "load more" / pagination as a GET link (the framework's link component) carrying the next-page cursor (e.g. `?after=<endCursor>`), so it works without JavaScript. Hydration may upgrade it to append-in-place; the bare link must still load the next page server-side (it replaces the page rather than appending when JS is off).
|
|
48
|
+
- Clear both `before` and `after` whenever filters or sorting change so the new browse state starts from its first page.
|
|
49
|
+
- Show stale products with a pending visual state while `state.status === "loading"`; do not replace the grid with a skeleton.
|
|
50
|
+
- Serialize active filter chips from `serializeCollectionParams(state)` and remove filters with `getFilterRemovalUrl(...)`.
|
|
51
|
+
- Use `isFilterInputActive(state.filters, value.input)` to mark checked filter inputs.
|
|
52
|
+
- Treat each Storefront API `FilterValue.input` JSON string as the authoritative filter identity. To render one checkbox, parse that JSON into a `ProductFilter`, wrap it as `{ filters: [filter], sortKey: undefined, reverse: false }`, and pass it to `serializeCollectionParams(...)` for the field name/value. Do not derive filter shapes or param names from filter IDs, labels, or types.
|
|
53
|
+
- Build sort option values with `getSortByValue(...)`; it emits the Liquid-compatible `sort_by` strings that `parseCollectionParams()` understands.
|
|
54
|
+
- Treat availability and other single-choice filters as mutually exclusive when the Storefront filter input serializes to the same param name.
|
|
55
|
+
|
|
56
|
+
## Search Rules
|
|
57
|
+
|
|
58
|
+
- Keep the search term in `q`.
|
|
59
|
+
- Use a collection handle like `search:${term}` so a new term rebuilds the browse store and does not carry old filters.
|
|
60
|
+
- Keep `q` as a hidden input inside the filter/sort form.
|
|
61
|
+
- Map unsupported search sorts back to `RELEVANCE`; only `PRICE` uses `reverse`.
|
|
62
|
+
- Empty search terms should return an empty product list and no filters rather than querying Storefront API.
|
|
63
|
+
- The search input is uncontrolled (`defaultValue={term}`) so the no-JS GET submit works; add `key={term}` so navigation (e.g. "Clear search" → `/search`) resets it. Safe because `term` changes only on submit/navigation, not while typing — do **not** put `key={term}` on a controlled input that updates the term per keystroke (focus loss).
|
|
64
|
+
|
|
65
|
+
## Anti-Patterns
|
|
66
|
+
|
|
67
|
+
- Do not use router query objects when filter param names contain dots, unless the framework preserves dotted keys literally.
|
|
68
|
+
- Do not compute filter URLs manually when Hydrogen helpers can serialize/remove filters.
|
|
69
|
+
- Do not write a custom mapping table from `ProductFilter` shapes to URL params. `serializeCollectionParams(...)` already maps supported shapes such as `available`, `productType`, `productVendor`, `tag`, `variantOption`, product metafields, variant metafields, and price into Liquid-compatible params.
|
|
70
|
+
- Do not synthesize Storefront API `ProductFilter` objects from display metadata. `value.input` already contains the supported filter shape.
|
|
71
|
+
- Do not store products in the collection store; products come from the framework data response.
|
|
72
|
+
- Do not clear non-filter params such as `q`, campaign params, or variant params unless the route explicitly owns them.
|
|
73
|
+
|
|
74
|
+
## Verify
|
|
75
|
+
|
|
76
|
+
- Filtering and sorting update the URL without scroll reset when hydrated.
|
|
77
|
+
- Checkbox filters and `PRICE_RANGE` min/max controls both render, apply, and persist after reloading the URL.
|
|
78
|
+
- Reloading the filtered URL server-renders the same filtered state.
|
|
79
|
+
- With JavaScript disabled, checking filters and submitting the form loads the filtered URL.
|
|
80
|
+
- With JavaScript disabled, the load-more / pagination link loads the next page server-side.
|
|
81
|
+
- Active filter chips remove only one filter and preserve unrelated params.
|
|
82
|
+
- Search filters preserve `q`.
|
|
83
|
+
- Back/forward navigation settles loading state.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Next.js App Router
|
|
2
|
+
|
|
3
|
+
Use a client component for browse controls. Server pages fetch products and filters, then pass the snapshot into the client browser component.
|
|
4
|
+
|
|
5
|
+
## Server Page
|
|
6
|
+
|
|
7
|
+
In `app/collections/[handle]/page.tsx`:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
export default async function CollectionPage({
|
|
11
|
+
params,
|
|
12
|
+
searchParams,
|
|
13
|
+
}: {
|
|
14
|
+
params: Promise<{ handle: string }>;
|
|
15
|
+
searchParams: Promise<Record<string, string | string[] | undefined>>;
|
|
16
|
+
}) {
|
|
17
|
+
const { handle } = await params;
|
|
18
|
+
const urlSearch = toURLSearchParams(await searchParams);
|
|
19
|
+
const storefront = await getStorefrontClient();
|
|
20
|
+
const result = await queryCollection({ storefrontClient: storefront, handle, searchParams: urlSearch });
|
|
21
|
+
if (!result) notFound();
|
|
22
|
+
|
|
23
|
+
return <CollectionBrowser mode="collection" {...result} dataSearch={urlSearch.toString()} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function toURLSearchParams(input: Record<string, string | string[] | undefined>) {
|
|
27
|
+
const params = new URLSearchParams();
|
|
28
|
+
for (const [key, value] of Object.entries(input)) {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
for (const item of value) params.append(key, item);
|
|
31
|
+
} else if (value != null) {
|
|
32
|
+
params.set(key, value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return params;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The page may be dynamic when it reads request-scoped Storefront client data or search params.
|
|
40
|
+
|
|
41
|
+
## Client Browser
|
|
42
|
+
|
|
43
|
+
In a `"use client"` component:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { CollectionProvider, useCollection, useCollectionForm } from "@shopify/hydrogen/react";
|
|
47
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
48
|
+
|
|
49
|
+
export function CollectionBrowser(props: Props) {
|
|
50
|
+
const router = useRouter();
|
|
51
|
+
const pathname = usePathname();
|
|
52
|
+
const searchParams = useSearchParams();
|
|
53
|
+
const urlSearch = searchParams.toString();
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<CollectionProvider
|
|
57
|
+
// dataSearch is the server-committed search string for the loaded products.
|
|
58
|
+
// urlSearch is the live browser URL and can be ahead during transitions.
|
|
59
|
+
data={{ handle: props.handle, dataSearch: props.dataSearch }}
|
|
60
|
+
urlSearch={urlSearch}
|
|
61
|
+
onChange={(search) => {
|
|
62
|
+
const href = `${pathname}${search}`;
|
|
63
|
+
if (urlSearch) router.replace(href, { scroll: false });
|
|
64
|
+
else router.push(href, { scroll: false });
|
|
65
|
+
router.refresh();
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<BrowserContent {...props} />
|
|
69
|
+
</CollectionProvider>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`router.refresh()` is important when the client URL changes before the React Server Component payload catches up. Under Partial Prerendering, a `<Link>` to a changed `searchParams` (active-filter chips, clear-all, load-more) can leave the server data stale — if it does, add `onClick={() => router.refresh()}` to those links (the `<Link>` stays the no-JS baseline).
|
|
75
|
+
|
|
76
|
+
Build the actual `BrowserContent` controls from the React reference patterns, including its filter-group dispatch: `PRICE_RANGE` uses min/max inputs, while `LIST` and `BOOLEAN` use checkboxes. Checkbox names/values come from parsing `FilterValue.input` and passing that exact parsed filter through `serializeCollectionParams(...)`. Uncontrolled checkbox reset keys belong on the filter subtree keyed by serialized **filter state** (`serializeCollectionParams({filters: state.filters, sortKey: undefined, reverse: false}).toString()`), not the live URL — the URL clears before the `CollectionProvider` reconciler settles `state.filters`, so a URL-keyed remount bakes in stale `defaultChecked`.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
function filterValueInputParamEntries(input: string): Array<{ name: string; value: string }> {
|
|
80
|
+
let filter: ProductFilter;
|
|
81
|
+
try {
|
|
82
|
+
filter = JSON.parse(input) as ProductFilter;
|
|
83
|
+
} catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return Array.from(
|
|
88
|
+
serializeCollectionParams({ filters: [filter], sortKey: undefined, reverse: false }),
|
|
89
|
+
([name, value]) => ({ name, value }),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This helper is only an adapter from Storefront API `FilterValue.input` to Hydrogen's serializer. Do not replace it with an app-owned filter mapping table.
|
|
95
|
+
|
|
96
|
+
## Search Pages
|
|
97
|
+
|
|
98
|
+
Use the same component with a discriminated `mode`:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
const handle = props.mode === "collection" ? props.handle : `search:${props.term}`;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
For search forms:
|
|
105
|
+
|
|
106
|
+
- Render a separate search form with `name="q"`.
|
|
107
|
+
- Inside the filter/sort form, include `<input type="hidden" name="q" value={term} />`.
|
|
108
|
+
- Use `SEARCH_SORT_OPTIONS` with `RELEVANCE` and `PRICE`; do not offer collection-only sorts.
|
|
109
|
+
|
|
110
|
+
## Links And Clear URLs
|
|
111
|
+
|
|
112
|
+
Use `next/link` for clear links and active filter chips. If a removal URL is `"?"`, link to the base pathname. For search pages, preserve `q` when removing filters.
|
|
113
|
+
|
|
114
|
+
## Gotchas
|
|
115
|
+
|
|
116
|
+
- Components that call `useSearchParams()` must be client components.
|
|
117
|
+
- Do not build browse links through Next route objects if filter param names contain dots. Use the serialized search string from Hydrogen.
|
|
118
|
+
- If a page mixes static data and request-scoped private clients, mark the route dynamic deliberately rather than accidentally calling `headers()` deep inside a helper.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Nuxt
|
|
2
|
+
|
|
3
|
+
Use the Vue binding from `@shopify/hydrogen/vue`. In Nuxt, route query objects can treat dotted keys as nested data, so use Hydrogen's serialized search string for navigation.
|
|
4
|
+
|
|
5
|
+
## Local Re-Export
|
|
6
|
+
|
|
7
|
+
Create a small storefront module:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// storefront/collection.ts
|
|
11
|
+
export {
|
|
12
|
+
CollectionProvider,
|
|
13
|
+
useCollection,
|
|
14
|
+
useCollectionActions,
|
|
15
|
+
useCollectionForm,
|
|
16
|
+
} from "@shopify/hydrogen/vue";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Page Data
|
|
20
|
+
|
|
21
|
+
Use `useAsyncData` or route-level server data to query the Storefront API with `parseCollectionParams(new URLSearchParams(search))`. Return:
|
|
22
|
+
|
|
23
|
+
- `handle`
|
|
24
|
+
- `dataSearch`
|
|
25
|
+
- `products`
|
|
26
|
+
- `availableFilters`
|
|
27
|
+
- For search, `term` and `totalCount`
|
|
28
|
+
|
|
29
|
+
Keep a way to refresh data after hydrated navigation, usually the `refresh` function returned by `useAsyncData`.
|
|
30
|
+
|
|
31
|
+
## Provider Wrapper
|
|
32
|
+
|
|
33
|
+
Nuxt can lag for one tick after `navigateTo`, so pin the target URL search while navigation and refresh are in flight:
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
import { normalizeCollectionSearch } from "@shopify/hydrogen";
|
|
38
|
+
import { CollectionProvider } from "~/storefront/collection";
|
|
39
|
+
|
|
40
|
+
const route = useRoute();
|
|
41
|
+
const urlSearchOverride = ref<string | null>(null);
|
|
42
|
+
const urlSearch = computed(() => urlSearchOverride.value ?? collectionRouteSearch(route));
|
|
43
|
+
const collectionData = computed(() => ({
|
|
44
|
+
handle: props.handle,
|
|
45
|
+
dataSearch: props.dataSearch,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
async function handleChange(search: string) {
|
|
49
|
+
const normalizedSearch = normalizeCollectionSearch(search);
|
|
50
|
+
props.setQueryWatchSuppressed(true);
|
|
51
|
+
urlSearchOverride.value = normalizedSearch;
|
|
52
|
+
try {
|
|
53
|
+
await navigateTo(`${route.path}${search}`, { replace: urlSearch.value.length > 0 });
|
|
54
|
+
await props.refreshCollection(search);
|
|
55
|
+
} finally {
|
|
56
|
+
urlSearchOverride.value = null;
|
|
57
|
+
props.setQueryWatchSuppressed(false);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<CollectionProvider :data="collectionData" :url-search="urlSearch" @change="handleChange">
|
|
64
|
+
<CollectionBrowserContent />
|
|
65
|
+
</CollectionProvider>
|
|
66
|
+
</template>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`collectionRouteSearch(route)` should return the current URL search string with literal dotted keys. Do not rely on `route.query` for filter serialization.
|
|
70
|
+
|
|
71
|
+
## Browse Content
|
|
72
|
+
|
|
73
|
+
In the content component:
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<script setup lang="ts">
|
|
77
|
+
import {
|
|
78
|
+
getFilterRemovalUrl,
|
|
79
|
+
getSortByValue,
|
|
80
|
+
isFilterInputActive,
|
|
81
|
+
serializeCollectionParams,
|
|
82
|
+
} from "@shopify/hydrogen";
|
|
83
|
+
import { useCollection, useCollectionForm } from "~/storefront/collection";
|
|
84
|
+
|
|
85
|
+
const state = useCollection();
|
|
86
|
+
const { formProps } = useCollectionForm();
|
|
87
|
+
const fProps = formProps();
|
|
88
|
+
const isLoading = computed(() => state.value.status === "loading");
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<template>
|
|
92
|
+
<form v-bind="fProps" method="get" :action="collectionPath">
|
|
93
|
+
<!-- filters, sort, product grid -->
|
|
94
|
+
</form>
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Apply form helper props with `v-bind`. Branch on `filter.type`: render min/max number inputs for `PRICE_RANGE`, and value checkboxes for `LIST` and `BOOLEAN`. Submit price inputs on blur only when the value changed; let Enter blur the input.
|
|
99
|
+
|
|
100
|
+
## Search Pages
|
|
101
|
+
|
|
102
|
+
Use `handle = computed(() => \`search:${term.value}\`)` for provider data. Include a hidden `q` input inside the filter/sort form. When the term changes, suppress stale query watchers while refreshing data.
|
|
103
|
+
|
|
104
|
+
## Gotchas
|
|
105
|
+
|
|
106
|
+
- Browser-side Storefront API refetches should use the same-origin SFAPI proxy, not the remote store domain. Use the `hydrogen-storefront-client` skill for the same-origin SFAPI proxy setup.
|
|
107
|
+
- Preserve unrelated query params when removing filters.
|
|
108
|
+
- If loading never settles, verify `dataSearch` and `urlSearch` normalize to the same string.
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# React And React Router
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Loader
|
|
6
|
+
- Provider
|
|
7
|
+
- Browse Form
|
|
8
|
+
- Filters
|
|
9
|
+
- Search Pages
|
|
10
|
+
|
|
11
|
+
Use the React binding:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import {
|
|
15
|
+
getFilterRemovalUrl,
|
|
16
|
+
getSortByValue,
|
|
17
|
+
isFilterInputActive,
|
|
18
|
+
parseCollectionParams,
|
|
19
|
+
serializeCollectionParams,
|
|
20
|
+
type AvailableFilter,
|
|
21
|
+
type CollectionState,
|
|
22
|
+
type ProductFilter,
|
|
23
|
+
} from "@shopify/hydrogen";
|
|
24
|
+
import { CollectionProvider, useCollection, useCollectionForm } from "@shopify/hydrogen/react";
|
|
25
|
+
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use `getSortByValue(...)` for option values so the `sort_by` query param round-trips through `parseCollectionParams()`:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const COLLECTION_SORT_OPTIONS = [
|
|
32
|
+
{ label: "Featured", value: getSortByValue("COLLECTION_DEFAULT", false) },
|
|
33
|
+
{ label: "Best selling", value: getSortByValue("BEST_SELLING", false) },
|
|
34
|
+
{ label: "Alphabetically, A-Z", value: getSortByValue("TITLE", false) },
|
|
35
|
+
{ label: "Alphabetically, Z-A", value: getSortByValue("TITLE", true) },
|
|
36
|
+
{ label: "Price, low to high", value: getSortByValue("PRICE", false) },
|
|
37
|
+
{ label: "Price, high to low", value: getSortByValue("PRICE", true) },
|
|
38
|
+
{ label: "Date, old to new", value: getSortByValue("CREATED", false) },
|
|
39
|
+
{ label: "Date, new to old", value: getSortByValue("CREATED", true) },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const SEARCH_SORT_OPTIONS = [
|
|
43
|
+
{ label: "Relevance", value: getSortByValue("RELEVANCE", false) },
|
|
44
|
+
{ label: "Price, low to high", value: getSortByValue("PRICE", false) },
|
|
45
|
+
{ label: "Price, high to low", value: getSortByValue("PRICE", true) },
|
|
46
|
+
];
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Loader
|
|
50
|
+
|
|
51
|
+
In a route loader, parse the current URL and query the Storefront API with the parsed browse state:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
export async function loader({ context, params, request }: Route.LoaderArgs) {
|
|
55
|
+
const storefrontClient = context.get(storefrontClientContext);
|
|
56
|
+
const url = new URL(request.url);
|
|
57
|
+
const browse = parseCollectionParams(url.searchParams);
|
|
58
|
+
|
|
59
|
+
const { data } = await storefrontClient.graphql(COLLECTION_QUERY, {
|
|
60
|
+
variables: {
|
|
61
|
+
handle: params.handle,
|
|
62
|
+
first: 24,
|
|
63
|
+
filters:
|
|
64
|
+
browse.filters.length > 0 ? (browse.filters as StorefrontApiProductFilter[]) : undefined,
|
|
65
|
+
sortKey: browse.sortKey,
|
|
66
|
+
reverse: browse.reverse || undefined,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (!data?.collection) throw new Response("Collection not found", { status: 404 });
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
collection: data.collection,
|
|
74
|
+
products: data.collection.products.nodes,
|
|
75
|
+
availableFilters: data.collection.products.filters,
|
|
76
|
+
dataSearch: url.searchParams.toString(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Keep `dataSearch` exactly aligned with the query used for the server data.
|
|
82
|
+
|
|
83
|
+
## Provider
|
|
84
|
+
|
|
85
|
+
Wrap the browse UI in `CollectionProvider` and let it own filter/sort intent:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
export default function CollectionRoute({ loaderData }: Route.ComponentProps) {
|
|
89
|
+
const navigate = useNavigate();
|
|
90
|
+
const [searchParams] = useSearchParams();
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<CollectionProvider
|
|
94
|
+
data={{ handle: loaderData.collection.handle, dataSearch: loaderData.dataSearch }}
|
|
95
|
+
urlSearch={searchParams.toString()}
|
|
96
|
+
onChange={(search) =>
|
|
97
|
+
navigate(
|
|
98
|
+
{ search },
|
|
99
|
+
{
|
|
100
|
+
replace: searchParams.size > 0,
|
|
101
|
+
preventScrollReset: true,
|
|
102
|
+
},
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
>
|
|
106
|
+
<CollectionPage {...loaderData} />
|
|
107
|
+
</CollectionProvider>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Browse Form
|
|
113
|
+
|
|
114
|
+
Inside the browse UI:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
function CollectionPage({ availableFilters, products }: Props) {
|
|
118
|
+
const state = useCollection();
|
|
119
|
+
const { formProps } = useCollectionForm();
|
|
120
|
+
const isLoading = state.status === "loading";
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<form {...formProps()} method="get" action={collectionPath} className="browse">
|
|
124
|
+
<FilterSidebar
|
|
125
|
+
availableFilters={availableFilters}
|
|
126
|
+
activeFilters={state.filters}
|
|
127
|
+
disabled={isLoading}
|
|
128
|
+
/>
|
|
129
|
+
<select name="sort_by" defaultValue={currentSortValue(state)} onChange={requestFormSubmit}>
|
|
130
|
+
{COLLECTION_SORT_OPTIONS.map((option) => (
|
|
131
|
+
<option key={option.label} value={option.value}>
|
|
132
|
+
{option.label}
|
|
133
|
+
</option>
|
|
134
|
+
))}
|
|
135
|
+
</select>
|
|
136
|
+
<ProductGrid products={products} pending={isLoading} />
|
|
137
|
+
</form>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function requestFormSubmit(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) {
|
|
142
|
+
event.currentTarget.form?.requestSubmit();
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Pass `method="get"` and an explicit `action={collectionPath}` (the current `/collections/:handle` or `/search` route URL) literally — `formProps()` only wires the submit handler (see the SKILL.md UI rule).
|
|
147
|
+
|
|
148
|
+
Use uncontrolled form controls. When a route needs to remount them after external navigation, put `key={serializeCollectionParams({ filters: state.filters, sortKey: undefined, reverse: false }).toString()}` on the filter subtree (for search, include the term in the key) — keyed by serialized **filter state**, not the live URL. The URL clears before the `CollectionProvider` reconciler settles `state.filters`, so a URL-keyed remount bakes in stale defaults. This resets checkbox and price-input DOM state without coupling active filter chips to the form remount.
|
|
149
|
+
|
|
150
|
+
## Filters
|
|
151
|
+
|
|
152
|
+
Choose the control at the filter-group level. `PRICE_RANGE` uses min/max number inputs; `LIST` and `BOOLEAN` use checkboxes. Do not use the number of serialized entries to choose the control—a price value serializes to both `gte` and `lte`.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
function FilterGroup({
|
|
156
|
+
activeFilters,
|
|
157
|
+
filter,
|
|
158
|
+
}: {
|
|
159
|
+
activeFilters: ProductFilter[];
|
|
160
|
+
filter: AvailableFilter;
|
|
161
|
+
}) {
|
|
162
|
+
if (filter.type === "PRICE_RANGE") {
|
|
163
|
+
return <PriceRangeInput activeFilters={activeFilters} />;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return filter.values.map((value) => (
|
|
167
|
+
<CheckboxFilterValue
|
|
168
|
+
key={value.id}
|
|
169
|
+
activeFilters={activeFilters}
|
|
170
|
+
filter={filter}
|
|
171
|
+
value={value}
|
|
172
|
+
/>
|
|
173
|
+
));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function PriceRangeInput({ activeFilters }: { activeFilters: ProductFilter[] }) {
|
|
177
|
+
const price = activeFilters.find((filter) => filter.price)?.price;
|
|
178
|
+
return (
|
|
179
|
+
<>
|
|
180
|
+
<PriceInput name="filter.v.price.gte" defaultValue={price?.min} label="Minimum price" />
|
|
181
|
+
<PriceInput name="filter.v.price.lte" defaultValue={price?.max} label="Maximum price" />
|
|
182
|
+
</>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function PriceInput({ name, defaultValue, label }: { name: string; defaultValue?: number; label: string }) {
|
|
187
|
+
const initialValue = defaultValue == null ? "" : String(defaultValue);
|
|
188
|
+
return (
|
|
189
|
+
<input
|
|
190
|
+
type="number"
|
|
191
|
+
name={name}
|
|
192
|
+
defaultValue={defaultValue}
|
|
193
|
+
aria-label={label}
|
|
194
|
+
min="0"
|
|
195
|
+
step="any"
|
|
196
|
+
onBlur={(event) => {
|
|
197
|
+
if (event.currentTarget.value !== initialValue) {
|
|
198
|
+
event.currentTarget.form?.requestSubmit();
|
|
199
|
+
}
|
|
200
|
+
}}
|
|
201
|
+
onKeyDown={(event) => {
|
|
202
|
+
if (event.key === "Enter") {
|
|
203
|
+
event.preventDefault();
|
|
204
|
+
event.currentTarget.blur();
|
|
205
|
+
}
|
|
206
|
+
}}
|
|
207
|
+
/>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function filterValueInputParamEntries(input: string): Array<{ name: string; value: string }> {
|
|
212
|
+
let filter: ProductFilter;
|
|
213
|
+
try {
|
|
214
|
+
filter = JSON.parse(input) as ProductFilter;
|
|
215
|
+
} catch {
|
|
216
|
+
return [];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return Array.from(
|
|
220
|
+
serializeCollectionParams({ filters: [filter], sortKey: undefined, reverse: false }),
|
|
221
|
+
([name, value]) => ({ name, value }),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function CheckboxFilterValue({
|
|
226
|
+
activeFilters,
|
|
227
|
+
filter,
|
|
228
|
+
value,
|
|
229
|
+
}: {
|
|
230
|
+
activeFilters: ProductFilter[];
|
|
231
|
+
filter: AvailableFilter;
|
|
232
|
+
value: AvailableFilter["values"][number];
|
|
233
|
+
}) {
|
|
234
|
+
const entries = filterValueInputParamEntries(value.input);
|
|
235
|
+
if (entries.length !== 1) return null;
|
|
236
|
+
|
|
237
|
+
const [{ name, value: paramValue }] = entries;
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<input
|
|
241
|
+
type="checkbox"
|
|
242
|
+
name={name}
|
|
243
|
+
value={paramValue}
|
|
244
|
+
defaultChecked={isFilterInputActive(activeFilters, value.input)}
|
|
245
|
+
onChange={(event) => {
|
|
246
|
+
if (isMutuallyExclusive(filter) && event.currentTarget.checked) {
|
|
247
|
+
uncheckSiblings(event.currentTarget);
|
|
248
|
+
}
|
|
249
|
+
requestFormSubmit(event);
|
|
250
|
+
}}
|
|
251
|
+
/>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Use `filter.type` only to choose the control shape. For checkbox values, keep `filterValueInputParamEntries` as thin app glue: `JSON.parse(value.input)` plus `serializeCollectionParams(...)`. Do not derive checkbox params from IDs, labels, or filter types.
|
|
257
|
+
|
|
258
|
+
For active chips, use parsed active `ProductFilter` values from collection state:
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
function ActiveFilterChip({ collectionPath, filter, state }: Props) {
|
|
262
|
+
const currentParams = serializeCollectionParams(state);
|
|
263
|
+
const removal = getFilterRemovalUrl(currentParams, filter);
|
|
264
|
+
const href = removal === "?" ? collectionPath : `${collectionPath}${removal}`;
|
|
265
|
+
|
|
266
|
+
return (
|
|
267
|
+
<a href={href}>
|
|
268
|
+
{describeFilter(filter)}
|
|
269
|
+
</a>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
When passing `browse.filters` into a `gql()` query variable typed from Storefront API introspection, match the app's established pattern. The Hydrogen examples cast the parsed filters to the generated Storefront API `ProductFilter` type at the query variable boundary:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
|
278
|
+
|
|
279
|
+
variables: {
|
|
280
|
+
filters:
|
|
281
|
+
browse.filters.length > 0 ? (browse.filters as StorefrontApiProductFilter[]) : undefined,
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Keep this as a generated-type cast scoped to the query variable boundary.
|
|
286
|
+
|
|
287
|
+
## Search Pages
|
|
288
|
+
|
|
289
|
+
Use the same binding with a synthetic handle:
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
<CollectionProvider
|
|
293
|
+
data={{ handle: `search:${term}`, dataSearch }}
|
|
294
|
+
urlSearch={searchParams.toString()}
|
|
295
|
+
onChange={(search) => navigate({ search }, { replace: searchParams.size > 0 })}
|
|
296
|
+
>
|
|
297
|
+
<input type="hidden" name="q" value={term} />
|
|
298
|
+
</CollectionProvider>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
When the search term changes, include it in the browse form `key` so old unchecked/checked inputs do not carry over.
|