@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,224 @@
|
|
|
1
|
+
import { createObservable } from "../observable.mjs";
|
|
2
|
+
import { PREDICTIVE_SEARCH_API_PATH } from "./constants.mjs";
|
|
3
|
+
import { getEmptyPredictiveSearchResult } from "./search.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/core/predictive-search/store.ts
|
|
6
|
+
/** Default delay before predictive search sends a request after a term changes. */
|
|
7
|
+
const DEFAULT_PREDICTIVE_SEARCH_DEBOUNCE_IN_MS = 150;
|
|
8
|
+
/** Default minimum trimmed term length required before predictive search sends a request. */
|
|
9
|
+
const DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH = 1;
|
|
10
|
+
function createPredictiveSearchStore(options = {}) {
|
|
11
|
+
const resolvedFetch = options.fetch ?? resolveGlobalFetch();
|
|
12
|
+
if (typeof resolvedFetch !== "function") throw new Error("No fetch function available. Pass a fetch option or ensure globalThis.fetch exists.");
|
|
13
|
+
const context = {
|
|
14
|
+
observable: createObservable(createInitialState()),
|
|
15
|
+
predictiveSearchEndpoint: options.predictiveSearchEndpoint ?? "/api/predictive-search",
|
|
16
|
+
debounceInMs: sanitizeDebounceInMs(options.debounceInMs),
|
|
17
|
+
minTermLength: sanitizeMinTermLength(options.minTermLength),
|
|
18
|
+
fetch: resolvedFetch,
|
|
19
|
+
searchOptions: {
|
|
20
|
+
limit: options.limit,
|
|
21
|
+
limitScope: options.limitScope,
|
|
22
|
+
types: options.types,
|
|
23
|
+
searchableFields: options.searchableFields,
|
|
24
|
+
unavailableProducts: options.unavailableProducts
|
|
25
|
+
},
|
|
26
|
+
abortController: null,
|
|
27
|
+
debounceTimer: null,
|
|
28
|
+
requestId: 0,
|
|
29
|
+
pendingResolve: null,
|
|
30
|
+
destroyed: false
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
connect: () => connect(context),
|
|
34
|
+
getState: () => context.observable.state,
|
|
35
|
+
subscribe: (listener) => context.observable.subscribe(listener),
|
|
36
|
+
search: (term) => search(context, term),
|
|
37
|
+
clear: () => clear(context),
|
|
38
|
+
destroy: () => destroy(context)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function connect(context) {
|
|
42
|
+
context.destroyed = false;
|
|
43
|
+
}
|
|
44
|
+
function resolveGlobalFetch() {
|
|
45
|
+
if (typeof globalThis.fetch !== "function") return void 0;
|
|
46
|
+
return globalThis.fetch.bind(globalThis);
|
|
47
|
+
}
|
|
48
|
+
function sanitizeDebounceInMs(debounceInMs) {
|
|
49
|
+
if (typeof debounceInMs !== "number") return 150;
|
|
50
|
+
if (!Number.isFinite(debounceInMs)) return 150;
|
|
51
|
+
if (debounceInMs < 0) return 150;
|
|
52
|
+
return Math.trunc(debounceInMs);
|
|
53
|
+
}
|
|
54
|
+
function sanitizeMinTermLength(minTermLength) {
|
|
55
|
+
if (typeof minTermLength !== "number") return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;
|
|
56
|
+
if (!Number.isFinite(minTermLength)) return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;
|
|
57
|
+
if (minTermLength < 0) return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;
|
|
58
|
+
return Math.trunc(minTermLength);
|
|
59
|
+
}
|
|
60
|
+
function createInitialState() {
|
|
61
|
+
return {
|
|
62
|
+
term: "",
|
|
63
|
+
status: "idle",
|
|
64
|
+
result: getEmptyPredictiveSearchResult(""),
|
|
65
|
+
error: null
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function search(context, term) {
|
|
69
|
+
resolvePending(context);
|
|
70
|
+
cancelScheduledWork(context);
|
|
71
|
+
if (context.destroyed) return Promise.resolve();
|
|
72
|
+
const trimmedTerm = term.trim();
|
|
73
|
+
if (trimmedTerm.length < context.minTermLength) {
|
|
74
|
+
resetState(context, trimmedTerm);
|
|
75
|
+
return Promise.resolve();
|
|
76
|
+
}
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
context.pendingResolve = resolve;
|
|
79
|
+
context.requestId += 1;
|
|
80
|
+
context.observable.setState({
|
|
81
|
+
...context.observable.state,
|
|
82
|
+
term: trimmedTerm,
|
|
83
|
+
status: "loading",
|
|
84
|
+
error: null
|
|
85
|
+
});
|
|
86
|
+
scheduleSearch(context, trimmedTerm, context.requestId);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function clear(context) {
|
|
90
|
+
context.requestId += 1;
|
|
91
|
+
resolvePending(context);
|
|
92
|
+
cancelScheduledWork(context);
|
|
93
|
+
resetState(context, "");
|
|
94
|
+
}
|
|
95
|
+
function destroy(context) {
|
|
96
|
+
context.destroyed = true;
|
|
97
|
+
context.requestId += 1;
|
|
98
|
+
resolvePending(context);
|
|
99
|
+
cancelScheduledWork(context);
|
|
100
|
+
}
|
|
101
|
+
function scheduleSearch(context, term, requestId) {
|
|
102
|
+
if (context.debounceInMs === 0) {
|
|
103
|
+
executeSearch(context, term, requestId);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
context.debounceTimer = setTimeout(() => {
|
|
107
|
+
context.debounceTimer = null;
|
|
108
|
+
executeSearch(context, term, requestId);
|
|
109
|
+
}, context.debounceInMs);
|
|
110
|
+
}
|
|
111
|
+
async function executeSearch(context, term, requestId) {
|
|
112
|
+
const abortController = new AbortController();
|
|
113
|
+
context.abortController = abortController;
|
|
114
|
+
try {
|
|
115
|
+
settleSuccess(context, requestId, await readResponse(await context.fetch(buildRequestUrl(context, term), { signal: abortController.signal })));
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (isAbortError(error)) return;
|
|
118
|
+
settleError(context, requestId, getErrorMessage(error));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function readResponse(response) {
|
|
122
|
+
const body = await readJson(response);
|
|
123
|
+
if (response.ok) return body;
|
|
124
|
+
throw new Error(getResponseErrorMessage(body, response));
|
|
125
|
+
}
|
|
126
|
+
async function readJson(response) {
|
|
127
|
+
try {
|
|
128
|
+
return await response.json();
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function settleSuccess(context, requestId, result) {
|
|
134
|
+
if (!isActiveRequest(context, requestId)) return;
|
|
135
|
+
context.observable.setState({
|
|
136
|
+
term: result.term,
|
|
137
|
+
status: "success",
|
|
138
|
+
result,
|
|
139
|
+
error: null
|
|
140
|
+
});
|
|
141
|
+
finishActiveRequest(context);
|
|
142
|
+
}
|
|
143
|
+
function settleError(context, requestId, message) {
|
|
144
|
+
if (!isActiveRequest(context, requestId)) return;
|
|
145
|
+
context.observable.setState({
|
|
146
|
+
...context.observable.state,
|
|
147
|
+
status: "error",
|
|
148
|
+
error: message
|
|
149
|
+
});
|
|
150
|
+
finishActiveRequest(context);
|
|
151
|
+
}
|
|
152
|
+
function finishActiveRequest(context) {
|
|
153
|
+
context.abortController = null;
|
|
154
|
+
resolvePending(context);
|
|
155
|
+
}
|
|
156
|
+
function resetState(context, term) {
|
|
157
|
+
context.observable.setState({
|
|
158
|
+
term,
|
|
159
|
+
status: "idle",
|
|
160
|
+
result: getEmptyPredictiveSearchResult(term),
|
|
161
|
+
error: null
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function cancelScheduledWork(context) {
|
|
165
|
+
clearDebounceTimer(context);
|
|
166
|
+
abortRequest(context);
|
|
167
|
+
}
|
|
168
|
+
function clearDebounceTimer(context) {
|
|
169
|
+
if (context.debounceTimer === null) return;
|
|
170
|
+
clearTimeout(context.debounceTimer);
|
|
171
|
+
context.debounceTimer = null;
|
|
172
|
+
}
|
|
173
|
+
function abortRequest(context) {
|
|
174
|
+
context.abortController?.abort();
|
|
175
|
+
context.abortController = null;
|
|
176
|
+
}
|
|
177
|
+
function resolvePending(context) {
|
|
178
|
+
context.pendingResolve?.();
|
|
179
|
+
context.pendingResolve = null;
|
|
180
|
+
}
|
|
181
|
+
function isActiveRequest(context, requestId) {
|
|
182
|
+
return !context.destroyed && context.requestId === requestId;
|
|
183
|
+
}
|
|
184
|
+
function buildRequestUrl(context, term) {
|
|
185
|
+
const url = new URL(context.predictiveSearchEndpoint, "https://hydrogen.local");
|
|
186
|
+
url.searchParams.set("q", term);
|
|
187
|
+
appendSearchOptions(url.searchParams, context.searchOptions);
|
|
188
|
+
if (URL.canParse(context.predictiveSearchEndpoint)) return url.href;
|
|
189
|
+
return `${url.pathname}${url.search}`;
|
|
190
|
+
}
|
|
191
|
+
function appendSearchOptions(searchParams, options) {
|
|
192
|
+
setOptionalParam(searchParams, "limit", options.limit);
|
|
193
|
+
setOptionalParam(searchParams, "limitScope", options.limitScope);
|
|
194
|
+
setOptionalParam(searchParams, "types", options.types?.join(","));
|
|
195
|
+
setOptionalParam(searchParams, "searchableFields", options.searchableFields?.join(","));
|
|
196
|
+
setOptionalParam(searchParams, "unavailableProducts", options.unavailableProducts);
|
|
197
|
+
}
|
|
198
|
+
function setOptionalParam(searchParams, name, value) {
|
|
199
|
+
if (value === void 0) return;
|
|
200
|
+
searchParams.set(name, String(value));
|
|
201
|
+
}
|
|
202
|
+
function getResponseErrorMessage(body, response) {
|
|
203
|
+
const message = getNestedErrorMessage(body);
|
|
204
|
+
if (message) return message;
|
|
205
|
+
return `Predictive search request failed with status ${response.status}`;
|
|
206
|
+
}
|
|
207
|
+
function getNestedErrorMessage(body) {
|
|
208
|
+
if (!body || typeof body !== "object") return null;
|
|
209
|
+
if (!("error" in body)) return null;
|
|
210
|
+
const error = body.error;
|
|
211
|
+
if (!error || typeof error !== "object") return null;
|
|
212
|
+
if (!("message" in error)) return null;
|
|
213
|
+
return typeof error.message === "string" ? error.message : null;
|
|
214
|
+
}
|
|
215
|
+
function getErrorMessage(error) {
|
|
216
|
+
return error instanceof Error ? error.message : "Predictive search request failed";
|
|
217
|
+
}
|
|
218
|
+
function isAbortError(error) {
|
|
219
|
+
return error instanceof DOMException && error.name === "AbortError";
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
//#endregion
|
|
223
|
+
export { createPredictiveSearchStore };
|
|
224
|
+
//# sourceMappingURL=store.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.mjs","names":[],"sources":["../../../../src/core/predictive-search/store.ts"],"sourcesContent":["import type {\n PredictiveSearchLimitScope,\n PredictiveSearchType,\n SearchUnavailableProductsType,\n SearchableField,\n} from \"../../graphql/generated/storefront-api-types\";\nimport { createObservable } from \"../observable\";\nimport { PREDICTIVE_SEARCH_API_PATH, PREDICTIVE_SEARCH_QUERY_PARAM } from \"./constants\";\nimport { getEmptyPredictiveSearchResult, type PredictiveSearchData } from \"./search\";\n\n/** Default delay before predictive search sends a request after a term changes. */\nexport const DEFAULT_PREDICTIVE_SEARCH_DEBOUNCE_IN_MS = 150;\n\n/** Default minimum trimmed term length required before predictive search sends a request. */\nconst DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH = 1;\n\n/** Lifecycle state for the predictive search client store. */\nexport type PredictiveSearchStatus = \"idle\" | \"loading\" | \"success\" | \"error\";\n\n/** Current predictive search snapshot exposed to UI bindings. */\nexport type PredictiveSearchState<TData extends PredictiveSearchData = PredictiveSearchData> = {\n /** Latest trimmed search term known to the store. */\n term: string;\n /** Request lifecycle state for the current term. */\n status: PredictiveSearchStatus;\n /** Predictive search data for the current term, or an empty result while idle. */\n result: TData;\n /** Error message for the latest failed request, or null when there is no active error. */\n error: string | null;\n};\n\n/** Options for creating a framework-neutral predictive search client store. */\nexport type CreatePredictiveSearchStoreOptions = {\n /**\n * Same-origin JSON endpoint used for browser predictive-search requests.\n *\n * The endpoint must return JSON matching the data payload from\n * `await predictiveSearchHandlers.get(...)`.\n */\n predictiveSearchEndpoint?: string;\n /** Delay before sending a request after the term changes. */\n debounceInMs?: number;\n /** Minimum trimmed term length required before searching. */\n minTermLength?: number;\n /** Fetch implementation, injectable for tests and non-browser runtimes. */\n fetch?: typeof globalThis.fetch;\n /** Maximum result count requested from the Storefront API. */\n limit?: number;\n /** Whether `limit` applies to each result type or all result types combined. */\n limitScope?: PredictiveSearchLimitScope;\n /** Storefront API result types to include in predictive search. */\n types?: PredictiveSearchType[];\n /** Storefront API fields to search. */\n searchableFields?: SearchableField[];\n /** Storefront API unavailable-product behavior. */\n unavailableProducts?: SearchUnavailableProductsType;\n};\n\n/** Framework-neutral predictive search store used by UI bindings. */\nexport type PredictiveSearchStore<TData extends PredictiveSearchData = PredictiveSearchData> = {\n /** Reactivates store updates after destroy(). */\n connect(): void;\n /** Returns the current predictive search state snapshot. */\n getState(): PredictiveSearchState<TData>;\n /** Subscribes to state changes and returns an unsubscribe callback. */\n subscribe(listener: (state: PredictiveSearchState<TData>) => void): () => void;\n /** Searches for a term using the configured debounce and request lifecycle. */\n search(term: string): Promise<void>;\n /** Cancels pending work and resets the store to an empty state. */\n clear(): void;\n /** Cancels pending work and pauses store updates until reconnect. */\n destroy(): void;\n};\n\ntype PredictiveSearchStoreContext<TData extends PredictiveSearchData> = {\n observable: ReturnType<typeof createObservable<PredictiveSearchState<TData>>>;\n // API route used to fetch predictive search results.\n predictiveSearchEndpoint: string;\n // Delay before firing a search request after the term changes.\n debounceInMs: number;\n // Minimum term length required before searching.\n minTermLength: number;\n // Fetch implementation, injectable for tests and non-browser runtimes.\n fetch: typeof globalThis.fetch;\n // Storefront API search options forwarded to the server handler.\n searchOptions: StoreSearchOptions;\n abortController: AbortController | null;\n // Active debounce timer waiting to start the next search.\n debounceTimer: ReturnType<typeof setTimeout> | null;\n // Monotonic counter used to ignore responses from older requests.\n requestId: number;\n // Resolver for the current debounced search promise.\n pendingResolve: (() => void) | null;\n // Prevents future work after the store has been torn down.\n destroyed: boolean;\n};\n\ntype StoreSearchOptions = Pick<\n CreatePredictiveSearchStoreOptions,\n \"limit\" | \"limitScope\" | \"types\" | \"searchableFields\" | \"unavailableProducts\"\n>;\n\nexport function createPredictiveSearchStore<\n TData extends PredictiveSearchData = PredictiveSearchData,\n>(options: CreatePredictiveSearchStoreOptions = {}): PredictiveSearchStore<TData> {\n // Prefer an injected fetch for tests and non-browser runtimes, then fall back to the ambient runtime fetch.\n const resolvedFetch = options.fetch ?? resolveGlobalFetch();\n if (typeof resolvedFetch !== \"function\") {\n throw new Error(\n \"No fetch function available. Pass a fetch option or ensure globalThis.fetch exists.\",\n );\n }\n\n const context: PredictiveSearchStoreContext<TData> = {\n observable: createObservable(createInitialState<TData>()),\n predictiveSearchEndpoint: options.predictiveSearchEndpoint ?? PREDICTIVE_SEARCH_API_PATH,\n debounceInMs: sanitizeDebounceInMs(options.debounceInMs),\n minTermLength: sanitizeMinTermLength(options.minTermLength),\n fetch: resolvedFetch,\n searchOptions: {\n limit: options.limit,\n limitScope: options.limitScope,\n types: options.types,\n searchableFields: options.searchableFields,\n unavailableProducts: options.unavailableProducts,\n },\n abortController: null,\n debounceTimer: null,\n requestId: 0,\n pendingResolve: null,\n destroyed: false,\n };\n\n return {\n connect: () => connect(context),\n getState: () => context.observable.state,\n subscribe: (listener) => context.observable.subscribe(listener),\n search: (term) => search(context, term),\n clear: () => clear(context),\n destroy: () => destroy(context),\n };\n}\n\nfunction connect<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.destroyed = false;\n}\n\nfunction resolveGlobalFetch(): typeof globalThis.fetch | undefined {\n if (typeof globalThis.fetch !== \"function\") return undefined;\n return globalThis.fetch.bind(globalThis);\n}\n\nfunction sanitizeDebounceInMs(debounceInMs: number | undefined): number {\n if (typeof debounceInMs !== \"number\") return DEFAULT_PREDICTIVE_SEARCH_DEBOUNCE_IN_MS;\n if (!Number.isFinite(debounceInMs)) return DEFAULT_PREDICTIVE_SEARCH_DEBOUNCE_IN_MS;\n if (debounceInMs < 0) return DEFAULT_PREDICTIVE_SEARCH_DEBOUNCE_IN_MS;\n return Math.trunc(debounceInMs);\n}\n\nfunction sanitizeMinTermLength(minTermLength: number | undefined): number {\n if (typeof minTermLength !== \"number\") return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;\n if (!Number.isFinite(minTermLength)) return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;\n if (minTermLength < 0) return DEFAULT_PREDICTIVE_SEARCH_MIN_TERM_LENGTH;\n return Math.trunc(minTermLength);\n}\n\nfunction createInitialState<TData extends PredictiveSearchData>(): PredictiveSearchState<TData> {\n return {\n term: \"\",\n status: \"idle\",\n result: getEmptyPredictiveSearchResult(\"\") as TData,\n error: null,\n };\n}\n\nfunction search<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n term: string,\n): Promise<void> {\n resolvePending(context);\n cancelScheduledWork(context);\n\n if (context.destroyed) return Promise.resolve();\n\n const trimmedTerm = term.trim();\n if (trimmedTerm.length < context.minTermLength) {\n resetState(context, trimmedTerm);\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n context.pendingResolve = resolve;\n context.requestId += 1;\n context.observable.setState({\n ...context.observable.state,\n term: trimmedTerm,\n status: \"loading\",\n error: null,\n });\n scheduleSearch(context, trimmedTerm, context.requestId);\n });\n}\n\nfunction clear<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.requestId += 1;\n resolvePending(context);\n cancelScheduledWork(context);\n resetState(context, \"\");\n}\n\nfunction destroy<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.destroyed = true;\n context.requestId += 1;\n resolvePending(context);\n cancelScheduledWork(context);\n}\n\nfunction scheduleSearch<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n term: string,\n requestId: number,\n): void {\n if (context.debounceInMs === 0) {\n void executeSearch(context, term, requestId);\n return;\n }\n\n context.debounceTimer = setTimeout(() => {\n context.debounceTimer = null;\n void executeSearch(context, term, requestId);\n }, context.debounceInMs);\n}\n\nasync function executeSearch<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n term: string,\n requestId: number,\n): Promise<void> {\n const abortController = new AbortController();\n context.abortController = abortController;\n\n try {\n const response = await context.fetch(buildRequestUrl(context, term), {\n signal: abortController.signal,\n });\n const result = await readResponse<TData>(response);\n settleSuccess(context, requestId, result);\n } catch (error) {\n if (isAbortError(error)) return;\n settleError(context, requestId, getErrorMessage(error));\n }\n}\n\nasync function readResponse<TData extends PredictiveSearchData>(\n response: Response,\n): Promise<TData> {\n const body = await readJson(response);\n if (response.ok) return body as TData;\n throw new Error(getResponseErrorMessage(body, response));\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\nfunction settleSuccess<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n requestId: number,\n result: TData,\n): void {\n if (!isActiveRequest(context, requestId)) return;\n context.observable.setState({\n term: result.term,\n status: \"success\",\n result,\n error: null,\n });\n finishActiveRequest(context);\n}\n\nfunction settleError<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n requestId: number,\n message: string,\n): void {\n if (!isActiveRequest(context, requestId)) return;\n context.observable.setState({\n ...context.observable.state,\n status: \"error\",\n error: message,\n });\n finishActiveRequest(context);\n}\n\nfunction finishActiveRequest<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.abortController = null;\n resolvePending(context);\n}\n\nfunction resetState<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n term: string,\n): void {\n context.observable.setState({\n term,\n status: \"idle\",\n result: getEmptyPredictiveSearchResult(term) as TData,\n error: null,\n });\n}\n\nfunction cancelScheduledWork<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n clearDebounceTimer(context);\n abortRequest(context);\n}\n\nfunction clearDebounceTimer<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n if (context.debounceTimer === null) return;\n clearTimeout(context.debounceTimer);\n context.debounceTimer = null;\n}\n\nfunction abortRequest<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.abortController?.abort();\n context.abortController = null;\n}\n\nfunction resolvePending<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n): void {\n context.pendingResolve?.();\n context.pendingResolve = null;\n}\n\nfunction isActiveRequest<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n requestId: number,\n): boolean {\n return !context.destroyed && context.requestId === requestId;\n}\n\nfunction buildRequestUrl<TData extends PredictiveSearchData>(\n context: PredictiveSearchStoreContext<TData>,\n term: string,\n): string {\n const url = new URL(context.predictiveSearchEndpoint, \"https://hydrogen.local\");\n url.searchParams.set(PREDICTIVE_SEARCH_QUERY_PARAM, term);\n appendSearchOptions(url.searchParams, context.searchOptions);\n if (URL.canParse(context.predictiveSearchEndpoint)) return url.href;\n return `${url.pathname}${url.search}`;\n}\n\nfunction appendSearchOptions(searchParams: URLSearchParams, options: StoreSearchOptions): void {\n setOptionalParam(searchParams, \"limit\", options.limit);\n setOptionalParam(searchParams, \"limitScope\", options.limitScope);\n setOptionalParam(searchParams, \"types\", options.types?.join(\",\"));\n setOptionalParam(searchParams, \"searchableFields\", options.searchableFields?.join(\",\"));\n setOptionalParam(searchParams, \"unavailableProducts\", options.unavailableProducts);\n}\n\nfunction setOptionalParam(\n searchParams: URLSearchParams,\n name: string,\n value: number | string | undefined,\n): void {\n if (value === undefined) return;\n searchParams.set(name, String(value));\n}\n\nfunction getResponseErrorMessage(body: unknown, response: Response): string {\n const message = getNestedErrorMessage(body);\n if (message) return message;\n return `Predictive search request failed with status ${response.status}`;\n}\n\nfunction getNestedErrorMessage(body: unknown): string | null {\n if (!body || typeof body !== \"object\") return null;\n if (!(\"error\" in body)) return null;\n\n const error = body.error;\n if (!error || typeof error !== \"object\") return null;\n if (!(\"message\" in error)) return null;\n\n return typeof error.message === \"string\" ? error.message : null;\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : \"Predictive search request failed\";\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof DOMException && error.name === \"AbortError\";\n}\n"],"mappings":";;;;;;AAWA,MAAa,2CAA2C;;AAGxD,MAAM,4CAA4C;AAwFlD,SAAgB,4BAEd,UAA8C,EAAE,EAAgC;CAEhF,MAAM,gBAAgB,QAAQ,SAAS,oBAAoB;AAC3D,KAAI,OAAO,kBAAkB,WAC3B,OAAM,IAAI,MACR,sFACD;CAGH,MAAM,UAA+C;EACnD,YAAY,iBAAiB,oBAA2B,CAAC;EACzD,0BAA0B,QAAQ;EAClC,cAAc,qBAAqB,QAAQ,aAAa;EACxD,eAAe,sBAAsB,QAAQ,cAAc;EAC3D,OAAO;EACP,eAAe;GACb,OAAO,QAAQ;GACf,YAAY,QAAQ;GACpB,OAAO,QAAQ;GACf,kBAAkB,QAAQ;GAC1B,qBAAqB,QAAQ;GAC9B;EACD,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,gBAAgB;EAChB,WAAW;EACZ;AAED,QAAO;EACL,eAAe,QAAQ,QAAQ;EAC/B,gBAAgB,QAAQ,WAAW;EACnC,YAAY,aAAa,QAAQ,WAAW,UAAU,SAAS;EAC/D,SAAS,SAAS,OAAO,SAAS,KAAK;EACvC,aAAa,MAAM,QAAQ;EAC3B,eAAe,QAAQ,QAAQ;EAChC;;AAGH,SAAS,QACP,SACM;AACN,SAAQ,YAAY;;AAGtB,SAAS,qBAA0D;AACjE,KAAI,OAAO,WAAW,UAAU,WAAY,QAAO;AACnD,QAAO,WAAW,MAAM,KAAK,WAAW;;AAG1C,SAAS,qBAAqB,cAA0C;AACtE,KAAI,OAAO,iBAAiB,SAAU;AACtC,KAAI,CAAC,OAAO,SAAS,aAAa,CAAE;AACpC,KAAI,eAAe,EAAG;AACtB,QAAO,KAAK,MAAM,aAAa;;AAGjC,SAAS,sBAAsB,eAA2C;AACxE,KAAI,OAAO,kBAAkB,SAAU,QAAO;AAC9C,KAAI,CAAC,OAAO,SAAS,cAAc,CAAE,QAAO;AAC5C,KAAI,gBAAgB,EAAG,QAAO;AAC9B,QAAO,KAAK,MAAM,cAAc;;AAGlC,SAAS,qBAAuF;AAC9F,QAAO;EACL,MAAM;EACN,QAAQ;EACR,QAAQ,+BAA+B,GAAG;EAC1C,OAAO;EACR;;AAGH,SAAS,OACP,SACA,MACe;AACf,gBAAe,QAAQ;AACvB,qBAAoB,QAAQ;AAE5B,KAAI,QAAQ,UAAW,QAAO,QAAQ,SAAS;CAE/C,MAAM,cAAc,KAAK,MAAM;AAC/B,KAAI,YAAY,SAAS,QAAQ,eAAe;AAC9C,aAAW,SAAS,YAAY;AAChC,SAAO,QAAQ,SAAS;;AAG1B,QAAO,IAAI,SAAS,YAAY;AAC9B,UAAQ,iBAAiB;AACzB,UAAQ,aAAa;AACrB,UAAQ,WAAW,SAAS;GAC1B,GAAG,QAAQ,WAAW;GACtB,MAAM;GACN,QAAQ;GACR,OAAO;GACR,CAAC;AACF,iBAAe,SAAS,aAAa,QAAQ,UAAU;GACvD;;AAGJ,SAAS,MACP,SACM;AACN,SAAQ,aAAa;AACrB,gBAAe,QAAQ;AACvB,qBAAoB,QAAQ;AAC5B,YAAW,SAAS,GAAG;;AAGzB,SAAS,QACP,SACM;AACN,SAAQ,YAAY;AACpB,SAAQ,aAAa;AACrB,gBAAe,QAAQ;AACvB,qBAAoB,QAAQ;;AAG9B,SAAS,eACP,SACA,MACA,WACM;AACN,KAAI,QAAQ,iBAAiB,GAAG;AAC9B,EAAK,cAAc,SAAS,MAAM,UAAU;AAC5C;;AAGF,SAAQ,gBAAgB,iBAAiB;AACvC,UAAQ,gBAAgB;AACxB,EAAK,cAAc,SAAS,MAAM,UAAU;IAC3C,QAAQ,aAAa;;AAG1B,eAAe,cACb,SACA,MACA,WACe;CACf,MAAM,kBAAkB,IAAI,iBAAiB;AAC7C,SAAQ,kBAAkB;AAE1B,KAAI;AAKF,gBAAc,SAAS,WAAW,MADb,aAAoB,MAHlB,QAAQ,MAAM,gBAAgB,SAAS,KAAK,EAAE,EACnE,QAAQ,gBAAgB,QACzB,CAAC,CACgD,CACT;UAClC,OAAO;AACd,MAAI,aAAa,MAAM,CAAE;AACzB,cAAY,SAAS,WAAW,gBAAgB,MAAM,CAAC;;;AAI3D,eAAe,aACb,UACgB;CAChB,MAAM,OAAO,MAAM,SAAS,SAAS;AACrC,KAAI,SAAS,GAAI,QAAO;AACxB,OAAM,IAAI,MAAM,wBAAwB,MAAM,SAAS,CAAC;;AAG1D,eAAe,SAAS,UAAsC;AAC5D,KAAI;AACF,SAAO,MAAM,SAAS,MAAM;SACtB;AACN,SAAO;;;AAIX,SAAS,cACP,SACA,WACA,QACM;AACN,KAAI,CAAC,gBAAgB,SAAS,UAAU,CAAE;AAC1C,SAAQ,WAAW,SAAS;EAC1B,MAAM,OAAO;EACb,QAAQ;EACR;EACA,OAAO;EACR,CAAC;AACF,qBAAoB,QAAQ;;AAG9B,SAAS,YACP,SACA,WACA,SACM;AACN,KAAI,CAAC,gBAAgB,SAAS,UAAU,CAAE;AAC1C,SAAQ,WAAW,SAAS;EAC1B,GAAG,QAAQ,WAAW;EACtB,QAAQ;EACR,OAAO;EACR,CAAC;AACF,qBAAoB,QAAQ;;AAG9B,SAAS,oBACP,SACM;AACN,SAAQ,kBAAkB;AAC1B,gBAAe,QAAQ;;AAGzB,SAAS,WACP,SACA,MACM;AACN,SAAQ,WAAW,SAAS;EAC1B;EACA,QAAQ;EACR,QAAQ,+BAA+B,KAAK;EAC5C,OAAO;EACR,CAAC;;AAGJ,SAAS,oBACP,SACM;AACN,oBAAmB,QAAQ;AAC3B,cAAa,QAAQ;;AAGvB,SAAS,mBACP,SACM;AACN,KAAI,QAAQ,kBAAkB,KAAM;AACpC,cAAa,QAAQ,cAAc;AACnC,SAAQ,gBAAgB;;AAG1B,SAAS,aACP,SACM;AACN,SAAQ,iBAAiB,OAAO;AAChC,SAAQ,kBAAkB;;AAG5B,SAAS,eACP,SACM;AACN,SAAQ,kBAAkB;AAC1B,SAAQ,iBAAiB;;AAG3B,SAAS,gBACP,SACA,WACS;AACT,QAAO,CAAC,QAAQ,aAAa,QAAQ,cAAc;;AAGrD,SAAS,gBACP,SACA,MACQ;CACR,MAAM,MAAM,IAAI,IAAI,QAAQ,0BAA0B,yBAAyB;AAC/E,KAAI,aAAa,SAAmC,KAAK;AACzD,qBAAoB,IAAI,cAAc,QAAQ,cAAc;AAC5D,KAAI,IAAI,SAAS,QAAQ,yBAAyB,CAAE,QAAO,IAAI;AAC/D,QAAO,GAAG,IAAI,WAAW,IAAI;;AAG/B,SAAS,oBAAoB,cAA+B,SAAmC;AAC7F,kBAAiB,cAAc,SAAS,QAAQ,MAAM;AACtD,kBAAiB,cAAc,cAAc,QAAQ,WAAW;AAChE,kBAAiB,cAAc,SAAS,QAAQ,OAAO,KAAK,IAAI,CAAC;AACjE,kBAAiB,cAAc,oBAAoB,QAAQ,kBAAkB,KAAK,IAAI,CAAC;AACvF,kBAAiB,cAAc,uBAAuB,QAAQ,oBAAoB;;AAGpF,SAAS,iBACP,cACA,MACA,OACM;AACN,KAAI,UAAU,OAAW;AACzB,cAAa,IAAI,MAAM,OAAO,MAAM,CAAC;;AAGvC,SAAS,wBAAwB,MAAe,UAA4B;CAC1E,MAAM,UAAU,sBAAsB,KAAK;AAC3C,KAAI,QAAS,QAAO;AACpB,QAAO,gDAAgD,SAAS;;AAGlE,SAAS,sBAAsB,MAA8B;AAC3D,KAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,KAAI,EAAE,WAAW,MAAO,QAAO;CAE/B,MAAM,QAAQ,KAAK;AACnB,KAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,KAAI,EAAE,aAAa,OAAQ,QAAO;AAElC,QAAO,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;;AAG7D,SAAS,gBAAgB,OAAwB;AAC/C,QAAO,iBAAiB,QAAQ,MAAM,UAAU;;AAGlD,SAAS,aAAa,OAAyB;AAC7C,QAAO,iBAAiB,gBAAgB,MAAM,SAAS"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ShopifyRouteTemplates } from "../standard-routes/types.mjs";
|
|
2
|
+
import { PredictiveSearchData } from "./search.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/core/predictive-search/url.d.ts
|
|
5
|
+
type PredictiveSearchItems = PredictiveSearchData["items"];
|
|
6
|
+
type PredictiveSearchProductItem = PredictiveSearchItems["products"][number];
|
|
7
|
+
type PredictiveSearchCollectionItem = PredictiveSearchItems["collections"][number];
|
|
8
|
+
type PredictiveSearchPageItem = PredictiveSearchItems["pages"][number];
|
|
9
|
+
type PredictiveSearchArticleItem = PredictiveSearchItems["articles"][number];
|
|
10
|
+
type PredictiveSearchQueryItem = PredictiveSearchItems["queries"][number];
|
|
11
|
+
type PredictiveSearchResourceItem = PredictiveSearchProductItem | PredictiveSearchCollectionItem | PredictiveSearchPageItem | PredictiveSearchArticleItem;
|
|
12
|
+
type PredictiveSearchItem = PredictiveSearchResourceItem | PredictiveSearchQueryItem;
|
|
13
|
+
type PredictiveSearchItemUrlOptions = {
|
|
14
|
+
pathPrefix?: string;
|
|
15
|
+
routes: ShopifyRouteTemplates;
|
|
16
|
+
term: string;
|
|
17
|
+
};
|
|
18
|
+
type PredictiveSearchQueryItemUrlOptions = {
|
|
19
|
+
pathPrefix?: string;
|
|
20
|
+
routes?: ShopifyRouteTemplates;
|
|
21
|
+
searchPath?: string;
|
|
22
|
+
};
|
|
23
|
+
type SearchResultUrlOptions = {
|
|
24
|
+
baseUrl: string;
|
|
25
|
+
term: string;
|
|
26
|
+
trackingParameters?: string | null;
|
|
27
|
+
params?: Record<string, string>;
|
|
28
|
+
searchParamName?: string;
|
|
29
|
+
};
|
|
30
|
+
declare function getPredictiveSearchItemUrl(item: PredictiveSearchQueryItem, options?: PredictiveSearchQueryItemUrlOptions): string;
|
|
31
|
+
declare function getPredictiveSearchItemUrl(item: PredictiveSearchResourceItem, options: PredictiveSearchItemUrlOptions): string;
|
|
32
|
+
declare function getSearchResultUrl({
|
|
33
|
+
baseUrl,
|
|
34
|
+
term,
|
|
35
|
+
trackingParameters,
|
|
36
|
+
params,
|
|
37
|
+
searchParamName
|
|
38
|
+
}: SearchResultUrlOptions): string;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { PredictiveSearchArticleItem, PredictiveSearchCollectionItem, PredictiveSearchItem, PredictiveSearchItemUrlOptions, PredictiveSearchPageItem, PredictiveSearchProductItem, PredictiveSearchQueryItem, PredictiveSearchQueryItemUrlOptions, PredictiveSearchResourceItem, getPredictiveSearchItemUrl, getSearchResultUrl };
|
|
41
|
+
//# sourceMappingURL=url.d.mts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getStandardRoute } from "../standard-routes/build.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/predictive-search/url.ts
|
|
4
|
+
const RELATIVE_URL_BASE = "https://hydrogen.local";
|
|
5
|
+
function getPredictiveSearchItemUrl(item, options) {
|
|
6
|
+
return getSearchResultUrl({
|
|
7
|
+
baseUrl: getPredictiveSearchItemBaseUrl(item, options),
|
|
8
|
+
term: getPredictiveSearchItemSearchTerm(item, options),
|
|
9
|
+
trackingParameters: item.trackingParameters
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function getSearchResultUrl({ baseUrl, term, trackingParameters, params, searchParamName = "q" }) {
|
|
13
|
+
const url = new URL(baseUrl, RELATIVE_URL_BASE);
|
|
14
|
+
for (const [name, value] of Object.entries(params ?? {})) url.searchParams.set(name, value);
|
|
15
|
+
url.searchParams.set(searchParamName, term);
|
|
16
|
+
appendTrackingParameters(url.searchParams, trackingParameters);
|
|
17
|
+
if (isAbsoluteUrl(baseUrl)) return url.href;
|
|
18
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
19
|
+
}
|
|
20
|
+
function getPredictiveSearchItemBaseUrl(item, options) {
|
|
21
|
+
if (item.__typename === "SearchQuerySuggestion") return getQueryBaseUrl(options);
|
|
22
|
+
const { pathPrefix, routes } = requirePredictiveSearchItemUrlOptions(options);
|
|
23
|
+
return getResourceBaseUrl(item, routes, pathPrefix);
|
|
24
|
+
}
|
|
25
|
+
function getQueryBaseUrl(options) {
|
|
26
|
+
if (options && "searchPath" in options && options.searchPath) return options.searchPath;
|
|
27
|
+
return getStandardRoute(options?.routes ?? {}, "search", {}, { pathPrefix: options?.pathPrefix });
|
|
28
|
+
}
|
|
29
|
+
function getResourceBaseUrl(item, routes, pathPrefix) {
|
|
30
|
+
switch (item.__typename) {
|
|
31
|
+
case "Product": return getProductBaseUrl(item, routes, pathPrefix);
|
|
32
|
+
case "Collection": return getCollectionBaseUrl(item, routes, pathPrefix);
|
|
33
|
+
case "Page": return getPageBaseUrl(item, routes, pathPrefix);
|
|
34
|
+
case "Article": return getArticleBaseUrl(item, routes, pathPrefix);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function getProductBaseUrl(product, routes, pathPrefix) {
|
|
38
|
+
return getStandardRoute(routes, "product", { productHandle: product.handle }, { pathPrefix });
|
|
39
|
+
}
|
|
40
|
+
function getCollectionBaseUrl(collection, routes, pathPrefix) {
|
|
41
|
+
return getStandardRoute(routes, "collection", { collectionHandle: collection.handle }, { pathPrefix });
|
|
42
|
+
}
|
|
43
|
+
function getPageBaseUrl(page, routes, pathPrefix) {
|
|
44
|
+
return getStandardRoute(routes, "page", { pageHandle: page.handle }, { pathPrefix });
|
|
45
|
+
}
|
|
46
|
+
function getArticleBaseUrl(article, routes, pathPrefix) {
|
|
47
|
+
return getStandardRoute(routes, "article", {
|
|
48
|
+
articleHandle: article.handle,
|
|
49
|
+
blogHandle: article.blog.handle
|
|
50
|
+
}, { pathPrefix });
|
|
51
|
+
}
|
|
52
|
+
function getPredictiveSearchItemSearchTerm(item, options) {
|
|
53
|
+
if (item.__typename === "SearchQuerySuggestion") return item.text;
|
|
54
|
+
return requirePredictiveSearchItemUrlOptions(options).term;
|
|
55
|
+
}
|
|
56
|
+
function requirePredictiveSearchItemUrlOptions(options) {
|
|
57
|
+
if (options && "term" in options && "routes" in options) return options;
|
|
58
|
+
throw new Error("Predictive search resource URLs require route templates and the typed search term.");
|
|
59
|
+
}
|
|
60
|
+
function appendTrackingParameters(params, trackingParameters) {
|
|
61
|
+
if (!trackingParameters) return;
|
|
62
|
+
const tracking = new URLSearchParams(trackingParameters);
|
|
63
|
+
for (const [name, value] of tracking) params.append(name, value);
|
|
64
|
+
}
|
|
65
|
+
function isAbsoluteUrl(url) {
|
|
66
|
+
return URL.canParse(url);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { getPredictiveSearchItemUrl, getSearchResultUrl };
|
|
71
|
+
//# sourceMappingURL=url.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url.mjs","names":[],"sources":["../../../../src/core/predictive-search/url.ts"],"sourcesContent":["import { getStandardRoute, type ShopifyRouteTemplates } from \"../standard-routes/index\";\nimport type { PredictiveSearchData } from \"./search\";\n\nconst RELATIVE_URL_BASE = \"https://hydrogen.local\";\n\ntype PredictiveSearchItems = PredictiveSearchData[\"items\"];\n\nexport type PredictiveSearchProductItem = PredictiveSearchItems[\"products\"][number];\nexport type PredictiveSearchCollectionItem = PredictiveSearchItems[\"collections\"][number];\nexport type PredictiveSearchPageItem = PredictiveSearchItems[\"pages\"][number];\nexport type PredictiveSearchArticleItem = PredictiveSearchItems[\"articles\"][number];\nexport type PredictiveSearchQueryItem = PredictiveSearchItems[\"queries\"][number];\n\nexport type PredictiveSearchResourceItem =\n | PredictiveSearchProductItem\n | PredictiveSearchCollectionItem\n | PredictiveSearchPageItem\n | PredictiveSearchArticleItem;\n\nexport type PredictiveSearchItem = PredictiveSearchResourceItem | PredictiveSearchQueryItem;\n\nexport type PredictiveSearchItemUrlOptions = {\n pathPrefix?: string;\n routes: ShopifyRouteTemplates;\n term: string;\n};\n\nexport type PredictiveSearchQueryItemUrlOptions = {\n pathPrefix?: string;\n routes?: ShopifyRouteTemplates;\n searchPath?: string;\n};\n\ntype AnyPredictiveSearchItemUrlOptions =\n | PredictiveSearchItemUrlOptions\n | PredictiveSearchQueryItemUrlOptions;\n\ntype SearchResultUrlOptions = {\n baseUrl: string;\n term: string;\n trackingParameters?: string | null;\n params?: Record<string, string>;\n searchParamName?: string;\n};\n\nexport function getPredictiveSearchItemUrl(\n item: PredictiveSearchQueryItem,\n options?: PredictiveSearchQueryItemUrlOptions,\n): string;\nexport function getPredictiveSearchItemUrl(\n item: PredictiveSearchResourceItem,\n options: PredictiveSearchItemUrlOptions,\n): string;\nexport function getPredictiveSearchItemUrl(\n item: PredictiveSearchItem,\n options?: AnyPredictiveSearchItemUrlOptions,\n): string {\n return getSearchResultUrl({\n baseUrl: getPredictiveSearchItemBaseUrl(item, options),\n term: getPredictiveSearchItemSearchTerm(item, options),\n trackingParameters: item.trackingParameters,\n });\n}\n\nexport function getSearchResultUrl({\n baseUrl,\n term,\n trackingParameters,\n params,\n searchParamName = \"q\",\n}: SearchResultUrlOptions): string {\n const url = new URL(baseUrl, RELATIVE_URL_BASE);\n\n for (const [name, value] of Object.entries(params ?? {})) {\n url.searchParams.set(name, value);\n }\n\n url.searchParams.set(searchParamName, term);\n appendTrackingParameters(url.searchParams, trackingParameters);\n\n if (isAbsoluteUrl(baseUrl)) return url.href;\n return `${url.pathname}${url.search}${url.hash}`;\n}\n\nfunction getPredictiveSearchItemBaseUrl(\n item: PredictiveSearchItem,\n options: AnyPredictiveSearchItemUrlOptions | undefined,\n): string {\n if (item.__typename === \"SearchQuerySuggestion\") return getQueryBaseUrl(options);\n\n const { pathPrefix, routes } = requirePredictiveSearchItemUrlOptions(options);\n return getResourceBaseUrl(item, routes, pathPrefix);\n}\n\nfunction getQueryBaseUrl(options: AnyPredictiveSearchItemUrlOptions | undefined): string {\n if (options && \"searchPath\" in options && options.searchPath) return options.searchPath;\n\n return getStandardRoute(\n options?.routes ?? {},\n \"search\",\n {},\n {\n pathPrefix: options?.pathPrefix,\n },\n );\n}\n\nfunction getResourceBaseUrl(\n item: PredictiveSearchResourceItem,\n routes: ShopifyRouteTemplates,\n pathPrefix: string | undefined,\n): string {\n switch (item.__typename) {\n case \"Product\":\n return getProductBaseUrl(item, routes, pathPrefix);\n case \"Collection\":\n return getCollectionBaseUrl(item, routes, pathPrefix);\n case \"Page\":\n return getPageBaseUrl(item, routes, pathPrefix);\n case \"Article\":\n return getArticleBaseUrl(item, routes, pathPrefix);\n }\n}\n\nfunction getProductBaseUrl(\n product: PredictiveSearchProductItem,\n routes: ShopifyRouteTemplates,\n pathPrefix: string | undefined,\n): string {\n return getStandardRoute(routes, \"product\", { productHandle: product.handle }, { pathPrefix });\n}\n\nfunction getCollectionBaseUrl(\n collection: PredictiveSearchCollectionItem,\n routes: ShopifyRouteTemplates,\n pathPrefix: string | undefined,\n): string {\n return getStandardRoute(\n routes,\n \"collection\",\n { collectionHandle: collection.handle },\n { pathPrefix },\n );\n}\n\nfunction getPageBaseUrl(\n page: PredictiveSearchPageItem,\n routes: ShopifyRouteTemplates,\n pathPrefix: string | undefined,\n): string {\n return getStandardRoute(routes, \"page\", { pageHandle: page.handle }, { pathPrefix });\n}\n\nfunction getArticleBaseUrl(\n article: PredictiveSearchArticleItem,\n routes: ShopifyRouteTemplates,\n pathPrefix: string | undefined,\n): string {\n return getStandardRoute(\n routes,\n \"article\",\n { articleHandle: article.handle, blogHandle: article.blog.handle },\n { pathPrefix },\n );\n}\n\nfunction getPredictiveSearchItemSearchTerm(\n item: PredictiveSearchItem,\n options: AnyPredictiveSearchItemUrlOptions | undefined,\n): string {\n if (item.__typename === \"SearchQuerySuggestion\") return item.text;\n return requirePredictiveSearchItemUrlOptions(options).term;\n}\n\nfunction requirePredictiveSearchItemUrlOptions(\n options: AnyPredictiveSearchItemUrlOptions | undefined,\n): PredictiveSearchItemUrlOptions {\n if (options && \"term\" in options && \"routes\" in options) return options;\n\n throw new Error(\n \"Predictive search resource URLs require route templates and the typed search term.\",\n );\n}\n\nfunction appendTrackingParameters(params: URLSearchParams, trackingParameters?: string | null) {\n if (!trackingParameters) return;\n\n const tracking = new URLSearchParams(trackingParameters);\n for (const [name, value] of tracking) {\n params.append(name, value);\n }\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n return URL.canParse(url);\n}\n"],"mappings":";;;AAGA,MAAM,oBAAoB;AAkD1B,SAAgB,2BACd,MACA,SACQ;AACR,QAAO,mBAAmB;EACxB,SAAS,+BAA+B,MAAM,QAAQ;EACtD,MAAM,kCAAkC,MAAM,QAAQ;EACtD,oBAAoB,KAAK;EAC1B,CAAC;;AAGJ,SAAgB,mBAAmB,EACjC,SACA,MACA,oBACA,QACA,kBAAkB,OACe;CACjC,MAAM,MAAM,IAAI,IAAI,SAAS,kBAAkB;AAE/C,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,UAAU,EAAE,CAAC,CACtD,KAAI,aAAa,IAAI,MAAM,MAAM;AAGnC,KAAI,aAAa,IAAI,iBAAiB,KAAK;AAC3C,0BAAyB,IAAI,cAAc,mBAAmB;AAE9D,KAAI,cAAc,QAAQ,CAAE,QAAO,IAAI;AACvC,QAAO,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI;;AAG5C,SAAS,+BACP,MACA,SACQ;AACR,KAAI,KAAK,eAAe,wBAAyB,QAAO,gBAAgB,QAAQ;CAEhF,MAAM,EAAE,YAAY,WAAW,sCAAsC,QAAQ;AAC7E,QAAO,mBAAmB,MAAM,QAAQ,WAAW;;AAGrD,SAAS,gBAAgB,SAAgE;AACvF,KAAI,WAAW,gBAAgB,WAAW,QAAQ,WAAY,QAAO,QAAQ;AAE7E,QAAO,iBACL,SAAS,UAAU,EAAE,EACrB,UACA,EAAE,EACF,EACE,YAAY,SAAS,YACtB,CACF;;AAGH,SAAS,mBACP,MACA,QACA,YACQ;AACR,SAAQ,KAAK,YAAb;EACE,KAAK,UACH,QAAO,kBAAkB,MAAM,QAAQ,WAAW;EACpD,KAAK,aACH,QAAO,qBAAqB,MAAM,QAAQ,WAAW;EACvD,KAAK,OACH,QAAO,eAAe,MAAM,QAAQ,WAAW;EACjD,KAAK,UACH,QAAO,kBAAkB,MAAM,QAAQ,WAAW;;;AAIxD,SAAS,kBACP,SACA,QACA,YACQ;AACR,QAAO,iBAAiB,QAAQ,WAAW,EAAE,eAAe,QAAQ,QAAQ,EAAE,EAAE,YAAY,CAAC;;AAG/F,SAAS,qBACP,YACA,QACA,YACQ;AACR,QAAO,iBACL,QACA,cACA,EAAE,kBAAkB,WAAW,QAAQ,EACvC,EAAE,YAAY,CACf;;AAGH,SAAS,eACP,MACA,QACA,YACQ;AACR,QAAO,iBAAiB,QAAQ,QAAQ,EAAE,YAAY,KAAK,QAAQ,EAAE,EAAE,YAAY,CAAC;;AAGtF,SAAS,kBACP,SACA,QACA,YACQ;AACR,QAAO,iBACL,QACA,WACA;EAAE,eAAe,QAAQ;EAAQ,YAAY,QAAQ,KAAK;EAAQ,EAClE,EAAE,YAAY,CACf;;AAGH,SAAS,kCACP,MACA,SACQ;AACR,KAAI,KAAK,eAAe,wBAAyB,QAAO,KAAK;AAC7D,QAAO,sCAAsC,QAAQ,CAAC;;AAGxD,SAAS,sCACP,SACgC;AAChC,KAAI,WAAW,UAAU,WAAW,YAAY,QAAS,QAAO;AAEhE,OAAM,IAAI,MACR,qFACD;;AAGH,SAAS,yBAAyB,QAAyB,oBAAoC;AAC7F,KAAI,CAAC,mBAAoB;CAEzB,MAAM,WAAW,IAAI,gBAAgB,mBAAmB;AACxD,MAAK,MAAM,CAAC,MAAM,UAAU,SAC1B,QAAO,OAAO,MAAM,MAAM;;AAI9B,SAAS,cAAc,KAAsB;AAC3C,QAAO,IAAI,SAAS,IAAI"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { getStandardRoute } from "../standard-routes/build.mjs";
|
|
2
|
+
import { matchStandardRouteUrl } from "../standard-routes/match.mjs";
|
|
3
|
+
import { getLogger } from "../logging/logging.mjs";
|
|
4
|
+
import { gql } from "../../graphql/graphql.mjs";
|
|
5
|
+
import { Cache } from "../cache/strategies.mjs";
|
|
6
|
+
import { StorefrontApiError } from "../../client/errors.mjs";
|
|
7
|
+
import { withStorefrontClientCache } from "../../client/client.mjs";
|
|
8
|
+
import { VARIANT_SEARCH_PARAM, buildProductSelectionSearchParams, parseVariantSearchParam } from "./url.mjs";
|
|
9
|
+
|
|
10
|
+
//#region src/core/product/accept-variant-id.ts
|
|
11
|
+
const log = getLogger("product");
|
|
12
|
+
const HTTP_FOUND_STATUS = 302;
|
|
13
|
+
const VARIANT_SELECTED_OPTIONS_QUERY = gql(`query VariantSelectedOptions($id:ID!$country:CountryCode$language:LanguageCode)@inContext(country:$country language:$language){node(id:$id){...on ProductVariant{selectedOptions{name value}product{handle}}}}`);
|
|
14
|
+
/**
|
|
15
|
+
* Accepts Liquid-style `?variant=<numeric id>` links on product pages by redirecting them
|
|
16
|
+
* to the canonical option-params URL, e.g. `/products/snowboard?variant=123` →
|
|
17
|
+
* `302 /products/snowboard?Color=Red&Size=M`.
|
|
18
|
+
*
|
|
19
|
+
* `handleShopifyRoutes` runs this before app routing. It claims only GET/HEAD requests
|
|
20
|
+
* whose URL matches a product route template and carries a numeric `variant` param;
|
|
21
|
+
* everything else falls through to the framework. When both `variant` and option params
|
|
22
|
+
* are present, the variant wins and the option params are replaced.
|
|
23
|
+
* Unknown/deleted variant ids redirect to the same URL with the `variant` param stripped,
|
|
24
|
+
* preserving any remaining params for the product loader. Params unrelated to the
|
|
25
|
+
* selection (`?ref=campaign`) are preserved. On cross-product (combined listing) redirects,
|
|
26
|
+
* params matching the *source* product's option names are not stripped — the handler only
|
|
27
|
+
* knows the target variant's options; loaders filtering with `allowedOptionNames` ignore
|
|
28
|
+
* the leftovers.
|
|
29
|
+
*
|
|
30
|
+
* Configure the app's URL shape once with `handleShopifyRoutes({ routeTemplates })`.
|
|
31
|
+
*/
|
|
32
|
+
const handleProductVariantId = (url, { request, requestContext, storefrontClient, routeTemplates = {} }) => {
|
|
33
|
+
if (request.method !== "GET" && request.method !== "HEAD") return null;
|
|
34
|
+
const variantId = parseVariantSearchParam(url.searchParams.get(VARIANT_SEARCH_PARAM));
|
|
35
|
+
if (!variantId) return null;
|
|
36
|
+
const pathPrefix = requestContext.i18n.pathPrefix;
|
|
37
|
+
const match = matchStandardRouteUrl({
|
|
38
|
+
routeTemplates,
|
|
39
|
+
pathPrefix,
|
|
40
|
+
url: url.href
|
|
41
|
+
});
|
|
42
|
+
if (match?.pageTemplateName !== "product") return null;
|
|
43
|
+
return resolveVariantRedirect({
|
|
44
|
+
pathPrefix,
|
|
45
|
+
requestedHandle: match.params.productHandle,
|
|
46
|
+
routeTemplates,
|
|
47
|
+
storefrontClient,
|
|
48
|
+
url,
|
|
49
|
+
variantId
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
async function resolveVariantRedirect({ pathPrefix, requestedHandle, routeTemplates, storefrontClient, url, variantId }) {
|
|
53
|
+
const variant = await queryVariantSelectedOptions(storefrontClient, variantId);
|
|
54
|
+
const searchParams = buildProductSelectionSearchParams({
|
|
55
|
+
selectedOptions: variant?.selectedOptions ?? [],
|
|
56
|
+
optionNames: [],
|
|
57
|
+
base: url.searchParams
|
|
58
|
+
});
|
|
59
|
+
const pathname = variant && !isSameHandle(variant.product.handle, requestedHandle) ? getStandardRoute(routeTemplates, "product", { productHandle: variant.product.handle }, { pathPrefix }) : url.pathname;
|
|
60
|
+
const search = searchParams.toString();
|
|
61
|
+
const location = search ? `${pathname}?${search}` : pathname;
|
|
62
|
+
return new Response(null, {
|
|
63
|
+
status: HTTP_FOUND_STATUS,
|
|
64
|
+
headers: { location: new URL(location, url.origin).toString() }
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async function queryVariantSelectedOptions(storefrontClient, variantId) {
|
|
68
|
+
try {
|
|
69
|
+
const result = await storefrontClient.graphql(VARIANT_SELECTED_OPTIONS_QUERY, withStorefrontClientCache(storefrontClient, { variables: { id: variantId } }, Cache.long(), hasResolvedVariant));
|
|
70
|
+
if (result.errors) {
|
|
71
|
+
log.error("variant id redirect lookup failed", {
|
|
72
|
+
errors: result.errors,
|
|
73
|
+
variantId
|
|
74
|
+
});
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const node = result.data?.node;
|
|
78
|
+
if (node && "selectedOptions" in node) return node;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (!(error instanceof StorefrontApiError)) throw error;
|
|
81
|
+
log.error("variant id redirect lookup failed", {
|
|
82
|
+
error,
|
|
83
|
+
variantId
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
function hasResolvedVariant(body) {
|
|
89
|
+
if (!("data" in body) || typeof body.data !== "object" || body.data == null) return false;
|
|
90
|
+
return "node" in body.data && body.data.node != null;
|
|
91
|
+
}
|
|
92
|
+
function isSameHandle(variantProductHandle, requestedHandle) {
|
|
93
|
+
return requestedHandle !== void 0 ? variantProductHandle.toLowerCase() === requestedHandle.toLowerCase() : true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { handleProductVariantId };
|
|
98
|
+
//# sourceMappingURL=accept-variant-id.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accept-variant-id.mjs","names":[],"sources":["../../../../src/core/product/accept-variant-id.ts"],"sourcesContent":["import type { StorefrontClient } from \"../../client\";\nimport { withStorefrontClientCache } from \"../../client/client\";\nimport { StorefrontApiError } from \"../../client/errors\";\nimport { gql } from \"../../graphql\";\nimport { Cache } from \"../cache\";\nimport { getLogger } from \"../logging\";\nimport type { HydrogenRouteInterceptor } from \"../request-routing/route-types\";\nimport { getStandardRoute } from \"../standard-routes/build\";\nimport { matchStandardRouteUrl } from \"../standard-routes/match\";\nimport type { ShopifyRouteTemplates } from \"../standard-routes/types\";\nimport {\n buildProductSelectionSearchParams,\n parseVariantSearchParam,\n VARIANT_SEARCH_PARAM,\n} from \"./url\";\n\nconst log = getLogger(\"product\");\n\nconst HTTP_FOUND_STATUS = 302;\n\nconst VARIANT_SELECTED_OPTIONS_QUERY = gql(`\n query VariantSelectedOptions($id: ID!, $country: CountryCode, $language: LanguageCode)\n @inContext(country: $country, language: $language) {\n node(id: $id) {\n ... on ProductVariant {\n selectedOptions {\n name\n value\n }\n product {\n handle\n }\n }\n }\n }\n`);\n\ntype SelectedOptionsVariant = {\n selectedOptions: { name: string; value: string }[];\n product: { handle: string };\n};\n\n/**\n * Accepts Liquid-style `?variant=<numeric id>` links on product pages by redirecting them\n * to the canonical option-params URL, e.g. `/products/snowboard?variant=123` →\n * `302 /products/snowboard?Color=Red&Size=M`.\n *\n * `handleShopifyRoutes` runs this before app routing. It claims only GET/HEAD requests\n * whose URL matches a product route template and carries a numeric `variant` param;\n * everything else falls through to the framework. When both `variant` and option params\n * are present, the variant wins and the option params are replaced.\n * Unknown/deleted variant ids redirect to the same URL with the `variant` param stripped,\n * preserving any remaining params for the product loader. Params unrelated to the\n * selection (`?ref=campaign`) are preserved. On cross-product (combined listing) redirects,\n * params matching the *source* product's option names are not stripped — the handler only\n * knows the target variant's options; loaders filtering with `allowedOptionNames` ignore\n * the leftovers.\n *\n * Configure the app's URL shape once with `handleShopifyRoutes({ routeTemplates })`.\n */\nexport const handleProductVariantId: HydrogenRouteInterceptor = (\n url,\n { request, requestContext, storefrontClient, routeTemplates = {} },\n) => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") return null;\n\n const variantId = parseVariantSearchParam(url.searchParams.get(VARIANT_SEARCH_PARAM));\n if (!variantId) return null;\n\n const pathPrefix = requestContext.i18n.pathPrefix;\n const match = matchStandardRouteUrl({ routeTemplates, pathPrefix, url: url.href });\n if (match?.pageTemplateName !== \"product\") return null;\n\n return resolveVariantRedirect({\n pathPrefix,\n requestedHandle: match.params.productHandle,\n routeTemplates,\n storefrontClient,\n url,\n variantId,\n });\n};\n\nasync function resolveVariantRedirect({\n pathPrefix,\n requestedHandle,\n routeTemplates,\n storefrontClient,\n url,\n variantId,\n}: {\n pathPrefix: string | undefined;\n requestedHandle: string | undefined;\n routeTemplates: ShopifyRouteTemplates;\n storefrontClient: StorefrontClient;\n url: URL;\n variantId: string;\n}): Promise<Response> {\n const variant = await queryVariantSelectedOptions(storefrontClient, variantId);\n\n const searchParams = buildProductSelectionSearchParams({\n selectedOptions: variant?.selectedOptions ?? [],\n optionNames: [],\n base: url.searchParams,\n });\n\n const pathname =\n variant && !isSameHandle(variant.product.handle, requestedHandle)\n ? getStandardRoute(\n routeTemplates,\n \"product\",\n { productHandle: variant.product.handle },\n { pathPrefix },\n )\n : url.pathname;\n\n const search = searchParams.toString();\n const location = search ? `${pathname}?${search}` : pathname;\n return new Response(null, {\n status: HTTP_FOUND_STATUS,\n headers: { location: new URL(location, url.origin).toString() },\n });\n}\n\nasync function queryVariantSelectedOptions(\n storefrontClient: StorefrontClient,\n variantId: string,\n): Promise<SelectedOptionsVariant | null> {\n try {\n const result = await storefrontClient.graphql(\n VARIANT_SELECTED_OPTIONS_QUERY,\n withStorefrontClientCache(\n storefrontClient,\n { variables: { id: variantId } },\n Cache.long(),\n hasResolvedVariant,\n ),\n );\n\n if (result.errors) {\n log.error(\"variant id redirect lookup failed\", { errors: result.errors, variantId });\n return null;\n }\n\n const node = result.data?.node;\n if (node && \"selectedOptions\" in node) return node;\n } catch (error) {\n if (!(error instanceof StorefrontApiError)) throw error;\n\n // Losing the requested selection beats failing the page: strip the param and render\n // the default variant instead of surfacing a 5xx for a lookup the buyer cannot retry.\n log.error(\"variant id redirect lookup failed\", { error, variantId });\n }\n\n return null;\n}\n\nfunction hasResolvedVariant(body: object): boolean {\n if (!(\"data\" in body) || typeof body.data !== \"object\" || body.data == null) return false;\n return \"node\" in body.data && body.data.node != null;\n}\n\nfunction isSameHandle(variantProductHandle: string, requestedHandle: string | undefined): boolean {\n return requestedHandle !== undefined\n ? variantProductHandle.toLowerCase() === requestedHandle.toLowerCase()\n : true;\n}\n"],"mappings":";;;;;;;;;;AAgBA,MAAA,MAAA,UAAA,UAAA;AAEA,MAAA,oBAAA;AAEA,MAAA,iCAAA,IAAA,iNAeA;;;;;;;;;;;;;;;;;;;AAyBA,MAAA,0BACA,KACA,EAAA,SAAA,gBAAA,kBAAA,iBAAA,EAAA,OACA;AACA,KAAA,QAAA,WAAA,SAAA,QAAA,WAAA,OAAA,QAAA;CAEA,MAAA,YAAA,wBAAA,IAAA,aAAA,IAAA,qBAAA,CAAA;AACA,KAAA,CAAA,UAAA,QAAA;CAEA,MAAA,aAAA,eAAA,KAAA;CACA,MAAA,QAAA,sBAAA;EAAA;EAAA;EAAA,KAAA,IAAA;EAAA,CAAA;AACA,KAAA,OAAA,qBAAA,UAAA,QAAA;AAEA,QAAA,uBAAA;EACA;EACA,iBAAA,MAAA,OAAA;EACA;EACA;EACA;EACA;EACA,CAAA;;AAGA,eAAA,uBAAA,EACA,YACA,iBACA,gBACA,kBACA,KACA,aAQA;CACA,MAAA,UAAA,MAAA,4BAAA,kBAAA,UAAA;CAEA,MAAA,eAAA,kCAAA;EACA,iBAAA,SAAA,mBAAA,EAAA;EACA,aAAA,EAAA;EACA,MAAA,IAAA;EACA,CAAA;CAEA,MAAA,WACA,WAAA,CAAA,aAAA,QAAA,QAAA,QAAA,gBAAA,GACA,iBACA,gBACA,WACA,EAAA,eAAA,QAAA,QAAA,QAAA,EACA,EAAA,YAAA,CACA,GACA,IAAA;CAEA,MAAA,SAAA,aAAA,UAAA;CACA,MAAA,WAAA,SAAA,GAAA,SAAA,GAAA,WAAA;AACA,QAAA,IAAA,SAAA,MAAA;EACA,QAAA;EACA,SAAA,EAAA,UAAA,IAAA,IAAA,UAAA,IAAA,OAAA,CAAA,UAAA,EAAA;EACA,CAAA;;AAGA,eAAA,4BACA,kBACA,WACA;AACA,KAAA;EACA,MAAA,SAAA,MAAA,iBAAA,QACA,gCACA,0BACA,kBACA,EAAA,WAAA,EAAA,IAAA,WAAA,EAAA,EACA,MAAA,MAAA,EACA,mBACA,CACA;AAEA,MAAA,OAAA,QAAA;AACA,OAAA,MAAA,qCAAA;IAAA,QAAA,OAAA;IAAA;IAAA,CAAA;AACA,UAAA;;EAGA,MAAA,OAAA,OAAA,MAAA;AACA,MAAA,QAAA,qBAAA,KAAA,QAAA;UACA,OAAA;AACA,MAAA,EAAA,iBAAA,oBAAA,OAAA;AAIA,MAAA,MAAA,qCAAA;GAAA;GAAA;GAAA,CAAA;;AAGA,QAAA;;AAGA,SAAA,mBAAA,MAAA;AACA,KAAA,EAAA,UAAA,SAAA,OAAA,KAAA,SAAA,YAAA,KAAA,QAAA,KAAA,QAAA;AACA,QAAA,UAAA,KAAA,QAAA,KAAA,KAAA,QAAA;;AAGA,SAAA,aAAA,sBAAA,iBAAA;AACA,QAAA,oBAAA,SACA,qBAAA,aAAA,KAAA,gBAAA,aAAA,GACA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ProductVariantInput } from "./state.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/product/form.d.ts
|
|
4
|
+
/** Props returned by {@link ProductFormRegister} for the `merchandiseId` input. */
|
|
5
|
+
interface ProductMerchandiseIdProps {
|
|
6
|
+
name: "merchandiseId";
|
|
7
|
+
/** The currently selected variant ID, or an empty string when no variant is resolved. */
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
/** Props returned by {@link ProductFormRegister} for a quantity input. */
|
|
11
|
+
interface ProductQuantityProps {
|
|
12
|
+
name: "quantity";
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
/** Props returned by {@link ProductFormRegister} for an uncontrolled quantity input. */
|
|
16
|
+
interface ProductQuantityDefaultProps {
|
|
17
|
+
name: "quantity";
|
|
18
|
+
defaultValue: string;
|
|
19
|
+
}
|
|
20
|
+
/** Props returned by {@link ProductFormRegister} for a variant option value control. */
|
|
21
|
+
interface ProductOptionValueProps {
|
|
22
|
+
name: string;
|
|
23
|
+
value: string;
|
|
24
|
+
onChange: () => void;
|
|
25
|
+
onClick: () => void;
|
|
26
|
+
}
|
|
27
|
+
/** Props returned by {@link ProductFormRegister} for the add-to-cart submit button. */
|
|
28
|
+
interface ProductAddToCartProps {
|
|
29
|
+
name: "add-to-cart";
|
|
30
|
+
type: "submit";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Register function returned by `useProductForm`.
|
|
34
|
+
*
|
|
35
|
+
* Product forms only register product-relevant fields:
|
|
36
|
+
* `merchandiseId`, `quantity`, `optionValue`, and `addToCart`.
|
|
37
|
+
*
|
|
38
|
+
* Option values return form identity and activation handlers. UI props such as
|
|
39
|
+
* `type`, `checked`, `disabled`, and `aria-pressed` belong to the caller — use
|
|
40
|
+
* the state available on `options` (e.g. `value.selected`, `value.available`).
|
|
41
|
+
*/
|
|
42
|
+
type ProductFormRegister = {
|
|
43
|
+
(field: "merchandiseId", opts: {}): ProductMerchandiseIdProps;
|
|
44
|
+
(field: "quantity", opts: {
|
|
45
|
+
value: number;
|
|
46
|
+
}): ProductQuantityProps;
|
|
47
|
+
(field: "quantity", opts: {
|
|
48
|
+
defaultValue: number;
|
|
49
|
+
}): ProductQuantityDefaultProps;
|
|
50
|
+
(field: "optionValue", opts: {
|
|
51
|
+
optionName: string;
|
|
52
|
+
value: string;
|
|
53
|
+
}): ProductOptionValueProps;
|
|
54
|
+
(field: "addToCart", opts: {}): ProductAddToCartProps;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Creates a {@link ProductFormRegister} function bound to the current variant
|
|
58
|
+
* state and `selectOption` dispatcher.
|
|
59
|
+
*/
|
|
60
|
+
declare function createProductFormRegister(selectedVariant: ProductVariantInput | null, selectOption: (name: string, value: string) => void): ProductFormRegister;
|
|
61
|
+
//#endregion
|
|
62
|
+
export { ProductAddToCartProps, ProductFormRegister, ProductMerchandiseIdProps, ProductOptionValueProps, ProductQuantityDefaultProps, ProductQuantityProps, createProductFormRegister };
|
|
63
|
+
//# sourceMappingURL=form.d.mts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/core/product/form.ts
|
|
2
|
+
/**
|
|
3
|
+
* Creates a {@link ProductFormRegister} function bound to the current variant
|
|
4
|
+
* state and `selectOption` dispatcher.
|
|
5
|
+
*/
|
|
6
|
+
function createProductFormRegister(selectedVariant, selectOption) {
|
|
7
|
+
return ((field, opts) => {
|
|
8
|
+
if (field === "merchandiseId") return {
|
|
9
|
+
name: "merchandiseId",
|
|
10
|
+
value: selectedVariant?.id ?? ""
|
|
11
|
+
};
|
|
12
|
+
if (field === "quantity") {
|
|
13
|
+
if (typeof opts?.defaultValue === "number") return {
|
|
14
|
+
name: "quantity",
|
|
15
|
+
defaultValue: String(opts.defaultValue)
|
|
16
|
+
};
|
|
17
|
+
const value = typeof opts?.value === "number" ? opts.value : 1;
|
|
18
|
+
return {
|
|
19
|
+
name: "quantity",
|
|
20
|
+
value: String(value)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (field === "optionValue") {
|
|
24
|
+
const optionName = String(opts?.optionName ?? "");
|
|
25
|
+
const value = String(opts?.value ?? "");
|
|
26
|
+
const handleSelect = () => selectOption(optionName, value);
|
|
27
|
+
return {
|
|
28
|
+
name: optionName,
|
|
29
|
+
value,
|
|
30
|
+
onChange: handleSelect,
|
|
31
|
+
onClick: handleSelect
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (field === "addToCart") return {
|
|
35
|
+
name: "add-to-cart",
|
|
36
|
+
type: "submit"
|
|
37
|
+
};
|
|
38
|
+
throw new Error(`Unknown product form field: "${field}".`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createProductFormRegister };
|
|
44
|
+
//# sourceMappingURL=form.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.mjs","names":[],"sources":["../../../../src/core/product/form.ts"],"sourcesContent":["import type { ProductVariantInput } from \"./state\";\n\n/** Props returned by {@link ProductFormRegister} for the `merchandiseId` input. */\nexport interface ProductMerchandiseIdProps {\n name: \"merchandiseId\";\n /** The currently selected variant ID, or an empty string when no variant is resolved. */\n value: string;\n}\n\n/** Props returned by {@link ProductFormRegister} for a quantity input. */\nexport interface ProductQuantityProps {\n name: \"quantity\";\n value: string;\n}\n\n/** Props returned by {@link ProductFormRegister} for an uncontrolled quantity input. */\nexport interface ProductQuantityDefaultProps {\n name: \"quantity\";\n defaultValue: string;\n}\n\n/** Props returned by {@link ProductFormRegister} for a variant option value control. */\nexport interface ProductOptionValueProps {\n name: string;\n value: string;\n onChange: () => void;\n onClick: () => void;\n}\n\n/** Props returned by {@link ProductFormRegister} for the add-to-cart submit button. */\nexport interface ProductAddToCartProps {\n name: \"add-to-cart\";\n type: \"submit\";\n}\n\n/**\n * Register function returned by `useProductForm`.\n *\n * Product forms only register product-relevant fields:\n * `merchandiseId`, `quantity`, `optionValue`, and `addToCart`.\n *\n * Option values return form identity and activation handlers. UI props such as\n * `type`, `checked`, `disabled`, and `aria-pressed` belong to the caller — use\n * the state available on `options` (e.g. `value.selected`, `value.available`).\n */\nexport type ProductFormRegister = {\n (field: \"merchandiseId\", opts: {}): ProductMerchandiseIdProps;\n (field: \"quantity\", opts: { value: number }): ProductQuantityProps;\n (field: \"quantity\", opts: { defaultValue: number }): ProductQuantityDefaultProps;\n (field: \"optionValue\", opts: { optionName: string; value: string }): ProductOptionValueProps;\n (field: \"addToCart\", opts: {}): ProductAddToCartProps;\n};\n\n/**\n * Creates a {@link ProductFormRegister} function bound to the current variant\n * state and `selectOption` dispatcher.\n */\nexport function createProductFormRegister(\n selectedVariant: ProductVariantInput | null,\n selectOption: (name: string, value: string) => void,\n): ProductFormRegister {\n return ((field: string, opts?: Record<string, unknown>) => {\n if (field === \"merchandiseId\") {\n return { name: \"merchandiseId\", value: selectedVariant?.id ?? \"\" };\n }\n\n if (field === \"quantity\") {\n if (typeof opts?.defaultValue === \"number\") {\n return { name: \"quantity\" as const, defaultValue: String(opts.defaultValue) };\n }\n const value = typeof opts?.value === \"number\" ? opts.value : 1;\n return { name: \"quantity\" as const, value: String(value) };\n }\n\n if (field === \"optionValue\") {\n const optionName = String(opts?.optionName ?? \"\");\n const value = String(opts?.value ?? \"\");\n const handleSelect = () => selectOption(optionName, value);\n return { name: optionName, value, onChange: handleSelect, onClick: handleSelect };\n }\n\n if (field === \"addToCart\") {\n return { name: \"add-to-cart\", type: \"submit\" } satisfies ProductAddToCartProps;\n }\n\n throw new Error(`Unknown product form field: \"${field}\".`);\n }) as ProductFormRegister;\n}\n"],"mappings":";;;;;AAyDA,SAAgB,0BACd,iBACA,cACqB;AACrB,UAAS,OAAe,SAAmC;AACzD,MAAI,UAAU,gBACZ,QAAO;GAAE,MAAM;GAAiB,OAAO,iBAAiB,MAAM;GAAI;AAGpE,MAAI,UAAU,YAAY;AACxB,OAAI,OAAO,MAAM,iBAAiB,SAChC,QAAO;IAAE,MAAM;IAAqB,cAAc,OAAO,KAAK,aAAa;IAAE;GAE/E,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,KAAK,QAAQ;AAC7D,UAAO;IAAE,MAAM;IAAqB,OAAO,OAAO,MAAM;IAAE;;AAG5D,MAAI,UAAU,eAAe;GAC3B,MAAM,aAAa,OAAO,MAAM,cAAc,GAAG;GACjD,MAAM,QAAQ,OAAO,MAAM,SAAS,GAAG;GACvC,MAAM,qBAAqB,aAAa,YAAY,MAAM;AAC1D,UAAO;IAAE,MAAM;IAAY;IAAO,UAAU;IAAc,SAAS;IAAc;;AAGnF,MAAI,UAAU,YACZ,QAAO;GAAE,MAAM;GAAe,MAAM;GAAU;AAGhD,QAAM,IAAI,MAAM,gCAAgC,MAAM,IAAI"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ProductInput, ProductOptionInput, ProductOptionValueInput, ProductVariantFrom, ProductVariantInput, SelectedOption, VariantOptionState, VariantOptionValueState } from "./state.mjs";
|
|
2
|
+
import { CreateProductFormStoreOptions, ProductFormErrors, ProductFormOptions, ProductFormStore, ProductFormStoreState, ValidProductSelectionResult, VariantSelectionResult, canAddToCart, createProductFormStore, findCartLineByMerchandiseId, getSelectedVariant } from "./product-form.mjs";
|
|
3
|
+
import { getSelectedProductOptions } from "./options.mjs";
|
|
4
|
+
import { ProductSelectionLinkStyle, buildProductSelectionSearchParams } from "./url.mjs";
|
|
5
|
+
import { ProductAddToCartProps, ProductFormRegister, ProductMerchandiseIdProps, ProductOptionValueProps, ProductQuantityDefaultProps, ProductQuantityProps, createProductFormRegister } from "./form.mjs";
|