@shopify/hydrogen 2026.10.0-preview.3 → 2026.10.0-preview.4
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 +2 -2
- package/dist/cli/index.mjs +131 -29
- package/dist/client/client.mjs +2 -2
- package/dist/client/errors.d.mts +19 -19
- package/dist/client/errors.mjs +19 -16
- package/dist/client/errors.mjs.map +1 -1
- package/dist/client/types.d.mts +91 -10
- package/dist/core/analytics/cart-tracker.d.mts +14 -0
- package/dist/core/analytics/cart-tracker.mjs +15 -1
- package/dist/core/analytics/cart-tracker.mjs.map +1 -1
- package/dist/core/analytics/custom-consent.mjs +12 -0
- package/dist/core/analytics/custom-consent.mjs.map +1 -0
- package/dist/core/analytics/events.d.mts +7 -0
- package/dist/core/analytics/events.mjs +7 -0
- package/dist/core/analytics/events.mjs.map +1 -1
- package/dist/core/analytics/index.d.mts +1 -1
- package/dist/core/analytics/types.d.mts +152 -16
- package/dist/core/cart/actions.d.mts +47 -3
- package/dist/core/cart/actions.mjs +27 -0
- package/dist/core/cart/actions.mjs.map +1 -1
- package/dist/core/cart/attach-quantity-input.d.mts +26 -0
- package/dist/core/cart/attach-quantity-input.mjs +26 -0
- package/dist/core/cart/attach-quantity-input.mjs.map +1 -1
- package/dist/core/cart/cart.d.mts +106 -6
- package/dist/core/cart/cart.mjs +41 -0
- package/dist/core/cart/cart.mjs.map +1 -1
- package/dist/core/cart/cookie.d.mts +15 -0
- package/dist/core/cart/cookie.mjs +15 -0
- package/dist/core/cart/cookie.mjs.map +1 -1
- package/dist/core/cart/form.d.mts +61 -0
- package/dist/core/cart/form.mjs +18 -0
- package/dist/core/cart/form.mjs.map +1 -1
- package/dist/core/cart/get-cart.d.mts +43 -2
- package/dist/core/cart/get-cart.mjs +33 -0
- package/dist/core/cart/get-cart.mjs.map +1 -1
- package/dist/core/cart/index.d.mts +1 -1
- package/dist/core/cart/quantity.d.mts +17 -0
- package/dist/core/cart/quantity.mjs +17 -0
- package/dist/core/cart/quantity.mjs.map +1 -1
- package/dist/core/cart/queries.d.mts +402 -369
- package/dist/core/cart/queries.mjs +2 -1
- package/dist/core/cart/queries.mjs.map +1 -1
- package/dist/core/cart/server-handlers.d.mts +69 -0
- package/dist/core/cart/server-handlers.mjs +2 -10
- package/dist/core/cart/server-handlers.mjs.map +1 -1
- package/dist/core/cart/state.d.mts +133 -0
- package/dist/core/cart/state.mjs +8 -0
- package/dist/core/cart/state.mjs.map +1 -1
- package/dist/core/collection/collection.d.mts +18 -2
- package/dist/core/collection/collection.mjs +11 -0
- package/dist/core/collection/collection.mjs.map +1 -1
- package/dist/core/collection/index.d.mts +1 -1
- package/dist/core/collection/reconciler.d.mts +13 -4
- package/dist/core/collection/reconciler.mjs.map +1 -1
- package/dist/core/collection/state.d.mts +7 -2
- package/dist/core/collection/state.mjs.map +1 -1
- package/dist/core/collection/url.d.mts +3 -0
- package/dist/core/collection/url.mjs.map +1 -1
- package/dist/core/constants.d.mts +1 -1
- package/dist/core/constants.mjs +2 -2
- package/dist/core/constants.mjs.map +1 -1
- package/dist/core/headers.mjs +2 -2
- package/dist/core/headers.mjs.map +1 -1
- package/dist/core/index.d.mts +5 -5
- package/dist/core/logging/logging.mjs.map +1 -1
- package/dist/core/money/format.mjs +6 -3
- package/dist/core/money/format.mjs.map +1 -1
- package/dist/core/observable.mjs +0 -3
- package/dist/core/observable.mjs.map +1 -1
- package/dist/core/predictive-search/form.d.mts +1 -0
- package/dist/core/predictive-search/form.mjs +1 -0
- package/dist/core/predictive-search/form.mjs.map +1 -1
- package/dist/core/predictive-search/index.d.mts +1 -1
- package/dist/core/predictive-search/queries.d.mts +40 -4
- package/dist/core/predictive-search/queries.mjs +7 -1
- package/dist/core/predictive-search/queries.mjs.map +1 -1
- package/dist/core/predictive-search/search.d.mts +43 -10
- package/dist/core/predictive-search/search.mjs +34 -0
- package/dist/core/predictive-search/search.mjs.map +1 -1
- package/dist/core/predictive-search/server-handlers.d.mts +31 -5
- package/dist/core/predictive-search/server-handlers.mjs +5 -3
- package/dist/core/predictive-search/server-handlers.mjs.map +1 -1
- package/dist/core/predictive-search/store.d.mts +3 -1
- package/dist/core/predictive-search/store.mjs.map +1 -1
- package/dist/core/predictive-search/url.d.mts +50 -8
- package/dist/core/predictive-search/url.mjs +9 -0
- package/dist/core/predictive-search/url.mjs.map +1 -1
- package/dist/core/product/options.d.mts +2 -2
- package/dist/core/product/options.mjs +2 -2
- package/dist/core/product/options.mjs.map +1 -1
- package/dist/core/product/product-form.d.mts +33 -1
- package/dist/core/product/product-form.mjs +30 -0
- package/dist/core/product/product-form.mjs.map +1 -1
- package/dist/core/product/state.d.mts +41 -0
- package/dist/core/product/url.d.mts +6 -0
- package/dist/core/product/url.mjs.map +1 -1
- package/dist/core/request-context.d.mts +2 -5
- package/dist/core/request-context.mjs +13 -39
- package/dist/core/request-context.mjs.map +1 -1
- package/dist/core/request-routing/handle-shopify-routes.mjs +2 -1
- package/dist/core/request-routing/handle-shopify-routes.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/ajax-api.mjs +1 -1
- package/dist/core/request-routing/interceptors/api-proxy.mjs +1 -1
- package/dist/core/request-routing/interceptors/checkout.mjs +19 -6
- package/dist/core/request-routing/interceptors/checkout.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
- package/dist/core/request-routing/interceptors/proxy.mjs +20 -5
- package/dist/core/request-routing/interceptors/proxy.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
- package/dist/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
- package/dist/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
- package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
- package/dist/core/request-routing/interceptors/well-known.mjs +1 -1
- package/dist/core/shopify-scripts/analytics.mjs +2 -2
- package/dist/core/shopify-scripts/analytics.mjs.map +1 -1
- package/dist/core/shopify-scripts/constants.mjs +1 -1
- package/dist/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/core/shopify-scripts/global.mjs +5 -1
- package/dist/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/core/shopify-scripts/initialize.d.mts +1 -0
- package/dist/core/shopify-scripts/initialize.mjs +10 -3
- package/dist/core/shopify-scripts/initialize.mjs.map +1 -1
- package/dist/core/shopify-scripts/types.d.mts +1 -0
- package/dist/core/url.mjs +20 -2
- package/dist/core/url.mjs.map +1 -1
- package/dist/customer-account/client.d.mts +128 -4
- package/dist/customer-account/client.mjs +27 -1
- package/dist/customer-account/client.mjs.map +1 -1
- package/dist/customer-account/errors.d.mts +46 -0
- package/dist/customer-account/errors.mjs +46 -0
- package/dist/customer-account/errors.mjs.map +1 -1
- package/dist/customer-account/graphql.d.mts +68 -0
- package/dist/customer-account/graphql.mjs +47 -0
- package/dist/customer-account/graphql.mjs.map +1 -1
- package/dist/customer-account/session.d.mts +114 -23
- package/dist/customer-account/session.mjs +27 -12
- package/dist/customer-account/session.mjs.map +1 -1
- package/dist/customer-account/type-resolver.d.mts +23 -0
- package/dist/customer-account-api-types.d.ts +570 -374
- package/dist/customer-account.schema.json +2981 -1527
- package/dist/development/client/client.mjs +2 -2
- package/dist/development/client/errors.d.mts +19 -19
- package/dist/development/client/errors.mjs +20 -20
- package/dist/development/client/errors.mjs.map +1 -1
- package/dist/development/client/types.d.mts +91 -10
- package/dist/development/core/analytics/cart-tracker.d.mts +14 -0
- package/dist/development/core/analytics/cart-tracker.mjs +15 -1
- package/dist/development/core/analytics/cart-tracker.mjs.map +1 -1
- package/dist/development/core/analytics/custom-consent.mjs +12 -0
- package/dist/development/core/analytics/custom-consent.mjs.map +1 -0
- package/dist/development/core/analytics/events.d.mts +7 -0
- package/dist/development/core/analytics/events.mjs +7 -0
- package/dist/development/core/analytics/events.mjs.map +1 -1
- package/dist/development/core/analytics/index.d.mts +1 -1
- package/dist/development/core/analytics/types.d.mts +152 -16
- package/dist/development/core/cart/actions.d.mts +47 -3
- package/dist/development/core/cart/actions.mjs +27 -0
- package/dist/development/core/cart/actions.mjs.map +1 -1
- package/dist/development/core/cart/attach-quantity-input.d.mts +26 -0
- package/dist/development/core/cart/attach-quantity-input.mjs +26 -0
- package/dist/development/core/cart/attach-quantity-input.mjs.map +1 -1
- package/dist/development/core/cart/cart.d.mts +106 -6
- package/dist/development/core/cart/cart.mjs +41 -0
- package/dist/development/core/cart/cart.mjs.map +1 -1
- package/dist/development/core/cart/cookie.d.mts +15 -0
- package/dist/development/core/cart/cookie.mjs +15 -0
- package/dist/development/core/cart/cookie.mjs.map +1 -1
- package/dist/development/core/cart/form.d.mts +61 -0
- package/dist/development/core/cart/form.mjs +18 -0
- package/dist/development/core/cart/form.mjs.map +1 -1
- package/dist/development/core/cart/get-cart.d.mts +43 -2
- package/dist/development/core/cart/get-cart.mjs +33 -0
- package/dist/development/core/cart/get-cart.mjs.map +1 -1
- package/dist/development/core/cart/index.d.mts +1 -1
- package/dist/development/core/cart/quantity.d.mts +17 -0
- package/dist/development/core/cart/quantity.mjs +17 -0
- package/dist/development/core/cart/quantity.mjs.map +1 -1
- package/dist/development/core/cart/queries.d.mts +402 -369
- package/dist/development/core/cart/queries.mjs +2 -1
- package/dist/development/core/cart/queries.mjs.map +1 -1
- package/dist/development/core/cart/server-handlers.d.mts +69 -0
- package/dist/development/core/cart/server-handlers.mjs +2 -10
- package/dist/development/core/cart/server-handlers.mjs.map +1 -1
- package/dist/development/core/cart/state.d.mts +133 -0
- package/dist/development/core/cart/state.mjs +8 -0
- package/dist/development/core/cart/state.mjs.map +1 -1
- package/dist/development/core/collection/collection.d.mts +18 -2
- package/dist/development/core/collection/collection.mjs +11 -0
- package/dist/development/core/collection/collection.mjs.map +1 -1
- package/dist/development/core/collection/index.d.mts +1 -1
- package/dist/development/core/collection/reconciler.d.mts +13 -4
- package/dist/development/core/collection/reconciler.mjs.map +1 -1
- package/dist/development/core/collection/state.d.mts +7 -2
- package/dist/development/core/collection/state.mjs.map +1 -1
- package/dist/development/core/collection/url.d.mts +3 -0
- package/dist/development/core/collection/url.mjs.map +1 -1
- package/dist/development/core/constants.mjs +1 -1
- package/dist/development/core/constants.mjs.map +1 -1
- package/dist/development/core/development.d.mts +5 -5
- package/dist/development/core/headers.mjs +2 -2
- package/dist/development/core/headers.mjs.map +1 -1
- package/dist/development/core/index.d.mts +4 -4
- package/dist/development/core/logging/logging.mjs.map +1 -1
- package/dist/development/core/money/format.mjs +6 -3
- package/dist/development/core/money/format.mjs.map +1 -1
- package/dist/development/core/observable.mjs +0 -3
- package/dist/development/core/observable.mjs.map +1 -1
- package/dist/development/core/predictive-search/form.d.mts +1 -0
- package/dist/development/core/predictive-search/form.mjs +1 -0
- package/dist/development/core/predictive-search/form.mjs.map +1 -1
- package/dist/development/core/predictive-search/index.d.mts +1 -1
- package/dist/development/core/predictive-search/queries.d.mts +40 -4
- package/dist/development/core/predictive-search/queries.mjs +7 -1
- package/dist/development/core/predictive-search/queries.mjs.map +1 -1
- package/dist/development/core/predictive-search/search.d.mts +43 -10
- package/dist/development/core/predictive-search/search.mjs +34 -0
- package/dist/development/core/predictive-search/search.mjs.map +1 -1
- package/dist/development/core/predictive-search/server-handlers.d.mts +31 -5
- package/dist/development/core/predictive-search/server-handlers.mjs +5 -3
- package/dist/development/core/predictive-search/server-handlers.mjs.map +1 -1
- package/dist/development/core/predictive-search/store.d.mts +3 -1
- package/dist/development/core/predictive-search/store.mjs.map +1 -1
- package/dist/development/core/predictive-search/url.d.mts +50 -8
- package/dist/development/core/predictive-search/url.mjs +9 -0
- package/dist/development/core/predictive-search/url.mjs.map +1 -1
- package/dist/development/core/product/options.d.mts +2 -2
- package/dist/development/core/product/options.mjs +2 -2
- package/dist/development/core/product/options.mjs.map +1 -1
- package/dist/development/core/product/product-form.d.mts +33 -1
- package/dist/development/core/product/product-form.mjs +30 -0
- package/dist/development/core/product/product-form.mjs.map +1 -1
- package/dist/development/core/product/state.d.mts +41 -0
- package/dist/development/core/product/url.d.mts +6 -0
- package/dist/development/core/product/url.mjs.map +1 -1
- package/dist/development/core/request-context.d.mts +2 -5
- package/dist/development/core/request-context.mjs +13 -39
- package/dist/development/core/request-context.mjs.map +1 -1
- package/dist/development/core/request-routing/handle-shopify-routes.mjs +2 -1
- package/dist/development/core/request-routing/handle-shopify-routes.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/ajax-api.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/api-proxy.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/checkout.mjs +19 -6
- package/dist/development/core/request-routing/interceptors/checkout.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/mcp-proxy.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/proxy.mjs +20 -5
- package/dist/development/core/request-routing/interceptors/proxy.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs +5 -11
- package/dist/development/core/request-routing/interceptors/query-param-redirect.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs +19 -1
- package/dist/development/core/request-routing/interceptors/sfapi-proxy.mjs.map +1 -1
- package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs +1 -1
- package/dist/development/core/request-routing/interceptors/well-known.mjs +1 -1
- package/dist/development/core/shopify-scripts/analytics.mjs +2 -2
- package/dist/development/core/shopify-scripts/analytics.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/constants.mjs +1 -1
- package/dist/development/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/global.mjs +5 -1
- package/dist/development/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/initialize.d.mts +1 -0
- package/dist/development/core/shopify-scripts/initialize.mjs +10 -3
- package/dist/development/core/shopify-scripts/initialize.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/types.d.mts +1 -0
- package/dist/development/core/url.mjs +20 -2
- package/dist/development/core/url.mjs.map +1 -1
- package/dist/development/customer-account/session.d.mts +69 -13
- package/dist/development/customer-account/session.mjs +4 -0
- package/dist/development/customer-account/session.mjs.map +1 -1
- package/dist/development/globals.d.mts +2 -4
- package/dist/development/graphql/generated/graphql-env.d.mts +459 -16
- package/dist/development/graphql/generated/storefront-api-types.d.mts +1 -1
- package/dist/development/graphql/graphql.d.mts +33 -0
- package/dist/development/graphql/graphql.mjs +30 -0
- package/dist/development/graphql/graphql.mjs.map +1 -1
- package/dist/development/graphql/type-resolver.d.mts +14 -0
- package/dist/development/react/cart.d.mts +85 -14
- package/dist/development/react/cart.mjs +123 -3
- package/dist/development/react/cart.mjs.map +1 -1
- package/dist/development/react/collection.d.mts +2 -4
- package/dist/development/react/collection.mjs.map +1 -1
- package/dist/development/react/index.d.mts +7 -5
- package/dist/development/react/index.mjs +2 -2
- package/dist/development/react/predictive-search.d.mts +68 -7
- package/dist/development/react/predictive-search.mjs +54 -12
- package/dist/development/react/predictive-search.mjs.map +1 -1
- package/dist/development/react/product.d.mts +1 -0
- package/dist/development/react/product.mjs +5 -2
- package/dist/development/react/product.mjs.map +1 -1
- package/dist/development/react/shopify-scripts.mjs +1 -0
- package/dist/development/react/shopify-scripts.mjs.map +1 -1
- package/dist/development/vue/cart.d.mts +85 -6
- package/dist/development/vue/cart.mjs +95 -0
- package/dist/development/vue/cart.mjs.map +1 -1
- package/dist/development/vue/collection.d.mts +83 -5
- package/dist/development/vue/collection.mjs +52 -0
- package/dist/development/vue/collection.mjs.map +1 -1
- package/dist/development/vue/index.d.mts +6 -4
- package/dist/development/vue/predictive-search.d.mts +53 -6
- package/dist/development/vue/predictive-search.mjs +33 -0
- package/dist/development/vue/predictive-search.mjs.map +1 -1
- package/dist/development/vue/product.d.mts +6 -2
- package/dist/development/vue/product.mjs.map +1 -1
- package/dist/development/vue/shopify-scripts.d.mts +21 -3
- package/dist/development/vue/shopify-scripts.mjs +1 -0
- package/dist/development/vue/shopify-scripts.mjs.map +1 -1
- package/dist/globals.d.mts +2 -4
- package/dist/graphql/generated/customer-account-graphql-env.d.mts +1717 -1090
- package/dist/graphql/generated/graphql-env.d.mts +459 -16
- package/dist/graphql/generated/storefront-api-types.d.mts +1 -1
- package/dist/graphql/graphql.d.mts +33 -0
- package/dist/graphql/graphql.mjs +30 -0
- package/dist/graphql/graphql.mjs.map +1 -1
- package/dist/graphql/type-resolver.d.mts +14 -0
- package/dist/react/cart.d.mts +85 -14
- package/dist/react/cart.mjs +123 -3
- package/dist/react/cart.mjs.map +1 -1
- package/dist/react/collection.d.mts +2 -4
- package/dist/react/collection.mjs.map +1 -1
- package/dist/react/index.d.mts +7 -5
- package/dist/react/index.mjs +2 -2
- package/dist/react/predictive-search.d.mts +68 -7
- package/dist/react/predictive-search.mjs +54 -12
- package/dist/react/predictive-search.mjs.map +1 -1
- package/dist/react/product.d.mts +1 -0
- package/dist/react/product.mjs +5 -2
- package/dist/react/product.mjs.map +1 -1
- package/dist/react/shopify-scripts.mjs +1 -0
- package/dist/react/shopify-scripts.mjs.map +1 -1
- package/dist/storefront-api-types.d.ts +165 -20
- package/dist/storefront.schema.json +782 -57
- package/dist/vite/customer-account.mjs +191 -0
- package/dist/vite/customer-account.mjs.map +1 -0
- package/dist/vite/local-https.mjs +13 -29
- package/dist/vite/local-https.mjs.map +1 -1
- package/dist/vite/mkcert.mjs +1 -1
- package/dist/vue/cart.d.mts +85 -6
- package/dist/vue/cart.mjs +95 -0
- package/dist/vue/cart.mjs.map +1 -1
- package/dist/vue/collection.d.mts +83 -5
- package/dist/vue/collection.mjs +52 -0
- package/dist/vue/collection.mjs.map +1 -1
- package/dist/vue/index.d.mts +6 -4
- package/dist/vue/predictive-search.d.mts +53 -6
- package/dist/vue/predictive-search.mjs +33 -0
- package/dist/vue/predictive-search.mjs.map +1 -1
- package/dist/vue/product.d.mts +6 -2
- package/dist/vue/product.mjs.map +1 -1
- package/dist/vue/shopify-scripts.d.mts +21 -3
- package/dist/vue/shopify-scripts.mjs +1 -0
- package/dist/vue/shopify-scripts.mjs.map +1 -1
- package/package.json +5 -2
- package/skills/hydrogen-analytics/SKILL.md +6 -5
- package/skills/hydrogen-analytics/references/custom-consent.md +52 -0
- package/skills/hydrogen-analytics/references/react.md +1 -1
- package/skills/hydrogen-customer-account/SKILL.md +3 -3
- package/skills/hydrogen-local-https/SKILL.md +22 -7
- package/skills/hydrogen-request-handlers/SKILL.md +5 -5
- package/skills/hydrogen-request-handlers/references/nuxt.md +0 -6
- package/skills/hydrogen-setup/references/analytics.md +24 -23
- package/skills/hydrogen-setup/steps/1-inspect-app.md +1 -1
- package/skills/hydrogen-setup/steps/2-scaffold.md +1 -1
- package/skills/hydrogen-smoke-test/SKILL.md +2 -2
- package/skills/hydrogen-storefront-client/SKILL.md +0 -2
- package/ts-plugin/package.json +5 -0
- package/dist/core/shopify-scripts/deprecated-cookies.mjs +0 -98
- package/dist/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
- package/dist/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/tracking-values.mjs +0 -65
- package/dist/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
- package/dist/core/shopify-scripts/utils/uuid.mjs +0 -17
- package/dist/core/shopify-scripts/utils/uuid.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +0 -98
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs +0 -43
- package/dist/development/core/shopify-scripts/utils/cookie-domain.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs +0 -65
- package/dist/development/core/shopify-scripts/utils/tracking-values.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/utils/uuid.mjs +0 -17
- package/dist/development/core/shopify-scripts/utils/uuid.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -100,13 +100,13 @@ const isLoggedIn = await customerSession.isLoggedIn(
|
|
|
100
100
|
);
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
Customer Account OAuth methods require a public HTTPS origin. The writable session manager should expose the request origin; explicit `origin` options are only needed as overrides. For local development, use a tunnel or trusted local HTTPS through `localHttps` from `@shopify/hydrogen/vite`, and
|
|
103
|
+
Customer Account OAuth methods require a public HTTPS origin. The writable session manager should expose the request origin; explicit `origin` options are only needed as overrides. For local development, use a tunnel or trusted local HTTPS through `localHttps` from `@shopify/hydrogen/vite`, which provisions certificates and uses Shopify CLI to push Customer Account URLs outside CI. Pass the framework's canonical request URL rather than an untrusted forwarded host.
|
|
104
104
|
|
|
105
105
|
Pass `customerSession` to `createCartServerHandlers({customerSession})` to associate newly created carts with the current customer when the session has a usable access token or successfully refreshed access token, and mark checkout URLs in authenticated cart GET responses with `logged_in=true`.
|
|
106
106
|
|
|
107
107
|
Use `createCustomerAccountServerHandlers({customerSession})` with `handleShopifyRoutes` to install the default `GET /account/login`, `GET /account/authorize`, `GET /account/refresh`, and `POST /account/logout` handlers. Pass those cart server handlers as `cartServerHandlers` to also keep the browser cart's buyer identity in step with the customer session: authorization and refresh attach the customer to the cart, a definitive refresh rejection and logout detach it. Sync is best-effort — a failed cart mutation never blocks the route's redirect; a failed detach during logout or definitive refresh rejection expires the cart cookie instead. `cartServerHandlers` requires the `customerSession` returned by `createCustomerSession` shared by both handler groups. Pass the same request-scoped `requestContext` and `sessionManager` into `handleShopifyRoutes` once alongside the `storefrontClient`. Session managers can be read-only for `isLoggedIn()` / `getAccessToken()` and writable for cart POST handlers configured with `customerSession`, `getOrRefreshAccessToken()`, `prepareLoginUrl()`, `handleOAuthCallback()`, `logout()`, and registered account handlers. `isLoggedIn()` is a read-only UI/session-presence check: it returns true for a usable access token or a refresh token that can attempt to restore one later. `getAccessToken()` still returns only a currently usable access token and never refreshes.
|
|
108
108
|
|
|
109
|
-
The login handler respects a
|
|
109
|
+
The login handler respects a `return_to` search parameter when it is a same-origin path or URL, such as `/account/orders`, and otherwise redirects back to `defaultPostLoginRedirectPathname` (default `/`). The logout handler redirects through Shopify using `postLogoutRedirectUri` (default `/`) when an ID token is present; otherwise, it redirects directly to `postLogoutRedirectUri`. Apps can still implement their own framework routes when they need custom behavior.
|
|
110
110
|
|
|
111
111
|
When a writable method can update cookie-backed session state, commit once while finalizing the response and append headers from `await sessionManager.commit?.()` there. After committing session headers, call `requestContext.applyResponseHeaders(response.headers)`. Customer Account session reads and GraphQL calls mark the request context private so the finalizer can prevent public/CDN caching of personalized responses.
|
|
112
112
|
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
6
|
-
import { homedir } from "node:os";
|
|
7
|
-
import { dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
|
|
6
|
+
import { homedir, tmpdir } from "node:os";
|
|
7
|
+
import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
|
|
8
8
|
import { createInterface } from "node:readline/promises";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -444,6 +444,24 @@ function isObjectRecord(value) {
|
|
|
444
444
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
+
//#endregion
|
|
448
|
+
//#region src/cli/terminal.ts
|
|
449
|
+
function canPromptInTerminal(env = process.env) {
|
|
450
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY) && !env.CI;
|
|
451
|
+
}
|
|
452
|
+
async function confirmInTerminal(question) {
|
|
453
|
+
const readline = createInterface({
|
|
454
|
+
input: process.stdin,
|
|
455
|
+
output: process.stdout
|
|
456
|
+
});
|
|
457
|
+
try {
|
|
458
|
+
const answer = (await readline.question(`${question} [Y/n] `)).trim().toLowerCase();
|
|
459
|
+
return answer === "" || answer === "y" || answer === "yes";
|
|
460
|
+
} finally {
|
|
461
|
+
readline.close();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
447
465
|
//#endregion
|
|
448
466
|
//#region src/cli/skills.ts
|
|
449
467
|
const PACKAGE_NAME$1 = "@shopify/hydrogen";
|
|
@@ -681,21 +699,6 @@ async function planOrphans(plans, version, confirm) {
|
|
|
681
699
|
});
|
|
682
700
|
}
|
|
683
701
|
}
|
|
684
|
-
function canPromptInTerminal() {
|
|
685
|
-
return Boolean(process.stdin.isTTY && process.stdout.isTTY) && !process.env.CI;
|
|
686
|
-
}
|
|
687
|
-
async function confirmInTerminal(question) {
|
|
688
|
-
const readline = createInterface({
|
|
689
|
-
input: process.stdin,
|
|
690
|
-
output: process.stdout
|
|
691
|
-
});
|
|
692
|
-
try {
|
|
693
|
-
const answer = (await readline.question(`${question} [Y/n] `)).trim().toLowerCase();
|
|
694
|
-
return answer === "" || answer === "y" || answer === "yes";
|
|
695
|
-
} finally {
|
|
696
|
-
readline.close();
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
702
|
/** Never removes user edits without an answer, so no TTY means keep. */
|
|
700
703
|
function confirmByDefault(question) {
|
|
701
704
|
return canPromptInTerminal() ? confirmInTerminal(question) : Promise.resolve(false);
|
|
@@ -931,13 +934,14 @@ function parsePackageManager(value) {
|
|
|
931
934
|
if (value.startsWith(`${packageManager}/`)) return packageManager;
|
|
932
935
|
}
|
|
933
936
|
}
|
|
937
|
+
function detectPackageManagerFromEnv(env) {
|
|
938
|
+
return parsePackageManager(env.npm_config_user_agent);
|
|
939
|
+
}
|
|
934
940
|
function detectPackageManager(appRoot, packageJson, env) {
|
|
935
941
|
const packageJsonManager = parsePackageManager(packageJson.packageManager);
|
|
936
942
|
if (packageJsonManager) return packageJsonManager;
|
|
937
943
|
for (const [packageManager, lockfile] of PACKAGE_MANAGER_LOCKFILES) if (existsSync(join(appRoot, lockfile))) return packageManager;
|
|
938
|
-
|
|
939
|
-
if (userAgentManager) return userAgentManager;
|
|
940
|
-
throw new Error("Could not detect a package manager. Add a packageManager field or a lockfile before running setup.");
|
|
944
|
+
return detectPackageManagerFromEnv(env) ?? "npm";
|
|
941
945
|
}
|
|
942
946
|
function hasHydrogenDependency(packageJson) {
|
|
943
947
|
return Boolean(packageJson.dependencies?.[PACKAGE_NAME] ?? packageJson.devDependencies?.[PACKAGE_NAME]);
|
|
@@ -961,17 +965,115 @@ function spawnRunCommand(command, args, options) {
|
|
|
961
965
|
});
|
|
962
966
|
});
|
|
963
967
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
968
|
+
const TEMPLATE_TARBALL_URL = "https://codeload.github.com/Shopify/hydrogen/tar.gz/dist-preview";
|
|
969
|
+
const TEMPLATE_TARBALL_PREFIX = "hydrogen-dist-preview/templates/react-router/";
|
|
970
|
+
const TEMPLATE_TARBALL_STRIP_COMPONENTS = TEMPLATE_TARBALL_PREFIX.split("/").filter(Boolean).length;
|
|
971
|
+
async function promptSetupChoice(log) {
|
|
972
|
+
log("\nNo project found in this directory.\n");
|
|
973
|
+
log(" 1) Create a new Hydrogen storefront (React Router)");
|
|
974
|
+
log(" 2) Just install Hydrogen skills\n");
|
|
975
|
+
const readline = createInterface({
|
|
976
|
+
input: process.stdin,
|
|
977
|
+
output: process.stdout
|
|
978
|
+
});
|
|
979
|
+
try {
|
|
980
|
+
while (true) {
|
|
981
|
+
const answer = (await readline.question("Your choice [1] ")).trim();
|
|
982
|
+
if (answer === "" || answer === "1") return "scaffold";
|
|
983
|
+
if (answer === "2") return "skills";
|
|
984
|
+
log("Please enter \"1\" or \"2\".");
|
|
985
|
+
}
|
|
986
|
+
} finally {
|
|
987
|
+
readline.close();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function hasPackageJson(appRoot) {
|
|
991
|
+
return existsSync(join(appRoot, PACKAGE_JSON_FILE_NAME));
|
|
992
|
+
}
|
|
993
|
+
async function downloadAndExtractTemplate(appRoot, runCommand) {
|
|
994
|
+
const response = await fetch(TEMPLATE_TARBALL_URL, { signal: AbortSignal.timeout(3e4) });
|
|
995
|
+
if (!response.ok) throw new Error(`Failed to download template (${response.status}). Check your internet connection.`);
|
|
996
|
+
const tempDir = mkdtempSync(join(tmpdir(), "hydrogen-template-"));
|
|
997
|
+
const tempFile = "template.tar.gz";
|
|
998
|
+
try {
|
|
999
|
+
writeFileSync(join(tempDir, tempFile), Buffer.from(await response.arrayBuffer()));
|
|
1000
|
+
await runCommand("tar", [
|
|
1001
|
+
"xzf",
|
|
1002
|
+
tempFile,
|
|
1003
|
+
`--strip-components=${TEMPLATE_TARBALL_STRIP_COMPONENTS}`,
|
|
1004
|
+
"-C",
|
|
1005
|
+
appRoot,
|
|
1006
|
+
TEMPLATE_TARBALL_PREFIX
|
|
1007
|
+
], { cwd: tempDir });
|
|
1008
|
+
} finally {
|
|
1009
|
+
rmSync(tempDir, {
|
|
1010
|
+
recursive: true,
|
|
1011
|
+
force: true
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
function updateScaffoldedPackageJson(appRoot) {
|
|
1016
|
+
const packageJsonPath = join(appRoot, PACKAGE_JSON_FILE_NAME);
|
|
1017
|
+
const raw = readFileSync(packageJsonPath, "utf8");
|
|
1018
|
+
const parsed = JSON.parse(raw);
|
|
1019
|
+
if (!isObjectRecord(parsed)) return;
|
|
1020
|
+
parsed.name = basename(appRoot);
|
|
1021
|
+
delete parsed.private;
|
|
1022
|
+
delete parsed.packageManager;
|
|
1023
|
+
writeFileSync(packageJsonPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
1024
|
+
}
|
|
1025
|
+
async function scaffoldTemplate(appRoot, env, runCommand, log) {
|
|
1026
|
+
log("Downloading Hydrogen template...");
|
|
1027
|
+
await downloadAndExtractTemplate(appRoot, runCommand);
|
|
1028
|
+
updateScaffoldedPackageJson(appRoot);
|
|
1029
|
+
const packageManager = detectPackageManagerFromEnv(env) ?? "npm";
|
|
1030
|
+
log(`Installing dependencies with ${packageManager}...`);
|
|
1031
|
+
try {
|
|
1032
|
+
await runCommand(packageManager, ["install"], { cwd: appRoot });
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
throw new Error(`Template was created but dependency install failed. Run \`${packageManager} install\` or re-run \`npx @shopify/hydrogen setup\` in ${appRoot} to finish.`, { cause: error });
|
|
1035
|
+
}
|
|
1036
|
+
return packageManager;
|
|
1037
|
+
}
|
|
1038
|
+
async function ensureHydrogenInstalled(appRoot, env, runCommand, log) {
|
|
969
1039
|
const packageJson = readPackageJson(appRoot);
|
|
970
|
-
if (
|
|
1040
|
+
if (hasHydrogenDependency(packageJson) && getInstalledPackageRoot(appRoot)) return;
|
|
1041
|
+
if (hasHydrogenDependency(packageJson)) {
|
|
971
1042
|
const packageManager = detectPackageManager(appRoot, packageJson, env);
|
|
972
|
-
log(
|
|
973
|
-
await
|
|
1043
|
+
log(`${PACKAGE_NAME} is declared but not installed. Running ${packageManager} install...`);
|
|
1044
|
+
await runCommand(packageManager, ["install"], { cwd: appRoot });
|
|
1045
|
+
return;
|
|
974
1046
|
}
|
|
1047
|
+
const packageManager = detectPackageManager(appRoot, packageJson, env);
|
|
1048
|
+
log(`Installing ${PACKAGE_NAME} with ${packageManager}...`);
|
|
1049
|
+
await installHydrogen(appRoot, packageManager, runCommand);
|
|
1050
|
+
}
|
|
1051
|
+
function resolveSetupOptions(options) {
|
|
1052
|
+
const env = options.env ?? process.env;
|
|
1053
|
+
return {
|
|
1054
|
+
appRoot: options.cwd ?? process.cwd(),
|
|
1055
|
+
env,
|
|
1056
|
+
runCommand: options.runCommand ?? spawnRunCommand,
|
|
1057
|
+
log: options.log ?? console.log,
|
|
1058
|
+
prompt: options.prompt ?? (canPromptInTerminal(env) ? promptSetupChoice : void 0)
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
const IGNORED_DIRECTORY_ENTRIES = new Set([".git", ".DS_Store"]);
|
|
1062
|
+
function isEmptyDirectory(dir) {
|
|
1063
|
+
return readdirSync(dir).every((entry) => IGNORED_DIRECTORY_ENTRIES.has(entry));
|
|
1064
|
+
}
|
|
1065
|
+
async function setupHydrogen(options = {}) {
|
|
1066
|
+
const { appRoot, env, runCommand, log, prompt } = resolveSetupOptions(options);
|
|
1067
|
+
if (hasPackageJson(appRoot)) await ensureHydrogenInstalled(appRoot, env, runCommand, log);
|
|
1068
|
+
else if (isEmptyDirectory(appRoot)) {
|
|
1069
|
+
let choice;
|
|
1070
|
+
if (prompt) choice = await prompt(log);
|
|
1071
|
+
else {
|
|
1072
|
+
log("No package.json found and no terminal to prompt; installing skills only.");
|
|
1073
|
+
choice = "skills";
|
|
1074
|
+
}
|
|
1075
|
+
if (choice === "scaffold") log(`\nHydrogen storefront created. Run \`${await scaffoldTemplate(appRoot, env, runCommand, log)} run dev\` to start (uses mock.shop by default).\n`);
|
|
1076
|
+
} else throw new Error("No package.json found. Run this command from your project root.");
|
|
975
1077
|
await syncSkills({
|
|
976
1078
|
force: options.force,
|
|
977
1079
|
cwd: appRoot,
|
package/dist/client/client.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { normalizeStoreDomain } from "../core/url.mjs";
|
|
1
2
|
import { getHydrogenCacheStatus } from "../core/cache/cache-status.mjs";
|
|
2
3
|
import { createFetchWithCache } from "../core/cache/fetch-with-cache.mjs";
|
|
3
4
|
import { DEFAULT_TIMEOUT_IN_MS, STOREFRONT_API_VERSION } from "../core/constants.mjs";
|
|
4
5
|
import { HYDROGEN_VERSION_HEADER, REQUEST_GROUP_ID_HEADER, SDK_VARIANT_HEADER, SDK_VARIANT_SOURCE_HEADER, SDK_VERSION_HEADER, SHOPIFY_STOREFRONT_S_HEADER, SHOPIFY_STOREFRONT_Y_HEADER, SHOPIFY_UNIQUE_TOKEN_HEADER, SHOPIFY_VISIT_TOKEN_HEADER, STOREFRONT_ACCESS_TOKEN_HEADER, STOREFRONT_BUYER_IP_HEADER, STOREFRONT_ID_HEADER, STOREFRONT_PRIVATE_TOKEN_HEADER } from "../core/headers.mjs";
|
|
5
|
-
import { normalizeStoreDomain } from "../core/url.mjs";
|
|
6
6
|
import { StorefrontApiError, StorefrontTimeoutError } from "./errors.mjs";
|
|
7
7
|
|
|
8
8
|
//#region src/client/client.ts
|
|
@@ -42,7 +42,7 @@ function createStorefrontClient(args) {
|
|
|
42
42
|
const { config, requestContext, type: clientType } = args;
|
|
43
43
|
if (!config.storeDomain) throw new Error("storeDomain is required and must be non-empty");
|
|
44
44
|
const storeUrl = normalizeStoreDomain(config.storeDomain);
|
|
45
|
-
const apiUrl = `${storeUrl}/api/${config.apiVersion ?? "2026-
|
|
45
|
+
const apiUrl = `${storeUrl}/api/${config.apiVersion ?? "2026-10"}/graphql.json`;
|
|
46
46
|
const originFetch = config.fetch ?? globalThis.fetch;
|
|
47
47
|
if (typeof originFetch !== "function") throw new Error("No fetch function available. Pass a fetch option or ensure globalThis.fetch exists.");
|
|
48
48
|
const resolvedFetch = config.cache ? createFetchWithCache({
|
package/dist/client/errors.d.mts
CHANGED
|
@@ -5,41 +5,41 @@ interface StorefrontApiErrorOptions {
|
|
|
5
5
|
cause?: unknown;
|
|
6
6
|
queryText?: string;
|
|
7
7
|
variables?: Record<string, unknown>;
|
|
8
|
-
locations?: ReadonlyArray<{
|
|
9
|
-
line: number;
|
|
10
|
-
column: number;
|
|
11
|
-
}>;
|
|
12
|
-
path?: ReadonlyArray<string | number>;
|
|
13
|
-
extensions?: Record<string, unknown>;
|
|
14
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Thrown when a Storefront API request fails — HTTP error, network failure,
|
|
11
|
+
* or an unparseable or unexpected response body.
|
|
12
|
+
*
|
|
13
|
+
* In development, `queryText` and `variables` are attached when available.
|
|
14
|
+
* GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.
|
|
15
|
+
*/
|
|
15
16
|
declare class StorefrontApiError extends Error {
|
|
17
|
+
/** Shopify `x-request-id` header, when available. Useful for support requests. */
|
|
16
18
|
readonly requestId?: string;
|
|
19
|
+
/** HTTP response status code, when the request reached the server. */
|
|
17
20
|
readonly status?: number;
|
|
21
|
+
/** The GraphQL query text. Only populated in development builds. */
|
|
18
22
|
readonly queryText?: string;
|
|
23
|
+
/** The variables sent with the request. Only populated in development builds. */
|
|
19
24
|
readonly variables?: Record<string, unknown>;
|
|
20
|
-
readonly locations?: ReadonlyArray<{
|
|
21
|
-
line: number;
|
|
22
|
-
column: number;
|
|
23
|
-
}>;
|
|
24
|
-
readonly path?: ReadonlyArray<string | number>;
|
|
25
|
-
readonly extensions?: Record<string, unknown>;
|
|
26
25
|
constructor(message: string, options?: StorefrontApiErrorOptions);
|
|
27
26
|
get [Symbol.toStringTag](): string;
|
|
28
|
-
|
|
27
|
+
/** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */
|
|
29
28
|
toJSON(): {
|
|
30
29
|
name: string;
|
|
31
30
|
message: string;
|
|
32
31
|
requestId?: string;
|
|
33
32
|
status?: number;
|
|
34
|
-
locations?: ReadonlyArray<{
|
|
35
|
-
line: number;
|
|
36
|
-
column: number;
|
|
37
|
-
}>;
|
|
38
|
-
path?: ReadonlyArray<string | number>;
|
|
39
|
-
extensions?: Record<string, unknown>;
|
|
40
33
|
};
|
|
41
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.
|
|
37
|
+
*
|
|
38
|
+
* Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.
|
|
39
|
+
* Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.
|
|
40
|
+
*/
|
|
42
41
|
declare class StorefrontTimeoutError extends StorefrontApiError {
|
|
42
|
+
/** The timeout threshold that was exceeded, in milliseconds. */
|
|
43
43
|
readonly timeoutInMs: number;
|
|
44
44
|
constructor(timeoutInMs: number, options?: Omit<StorefrontApiErrorOptions, "cause">);
|
|
45
45
|
}
|
package/dist/client/errors.mjs
CHANGED
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
//#region src/client/errors.ts
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a Storefront API request fails — HTTP error, network failure,
|
|
4
|
+
* or an unparseable or unexpected response body.
|
|
5
|
+
*
|
|
6
|
+
* In development, `queryText` and `variables` are attached when available.
|
|
7
|
+
* GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.
|
|
8
|
+
*/
|
|
2
9
|
var StorefrontApiError = class extends Error {
|
|
10
|
+
/** Shopify `x-request-id` header, when available. Useful for support requests. */
|
|
3
11
|
requestId;
|
|
12
|
+
/** HTTP response status code, when the request reached the server. */
|
|
4
13
|
status;
|
|
14
|
+
/** The GraphQL query text. Only populated in development builds. */
|
|
5
15
|
queryText;
|
|
16
|
+
/** The variables sent with the request. Only populated in development builds. */
|
|
6
17
|
variables;
|
|
7
|
-
locations;
|
|
8
|
-
path;
|
|
9
|
-
extensions;
|
|
10
18
|
constructor(message, options) {
|
|
11
19
|
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
12
20
|
this.name = "StorefrontApiError";
|
|
13
21
|
this.requestId = options?.requestId;
|
|
14
22
|
this.status = options?.status;
|
|
15
|
-
this.locations = options?.locations;
|
|
16
|
-
this.path = options?.path;
|
|
17
|
-
this.extensions = options?.extensions;
|
|
18
23
|
}
|
|
19
24
|
get [Symbol.toStringTag]() {
|
|
20
25
|
return this.name;
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
let result = `${this.name}: ${this.message}`;
|
|
24
|
-
if (this.path) try {
|
|
25
|
-
result += ` | path: ${JSON.stringify(this.path)}`;
|
|
26
|
-
} catch {}
|
|
27
|
-
if (this.extensions) try {
|
|
28
|
-
result += ` | extensions: ${JSON.stringify(this.extensions)}`;
|
|
29
|
-
} catch {}
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
27
|
+
/** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */
|
|
32
28
|
toJSON() {
|
|
33
29
|
return {
|
|
34
30
|
name: this.name,
|
|
@@ -38,7 +34,14 @@ var StorefrontApiError = class extends Error {
|
|
|
38
34
|
};
|
|
39
35
|
}
|
|
40
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.
|
|
39
|
+
*
|
|
40
|
+
* Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.
|
|
41
|
+
* Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.
|
|
42
|
+
*/
|
|
41
43
|
var StorefrontTimeoutError = class extends StorefrontApiError {
|
|
44
|
+
/** The timeout threshold that was exceeded, in milliseconds. */
|
|
42
45
|
timeoutInMs;
|
|
43
46
|
constructor(timeoutInMs, options) {
|
|
44
47
|
super(`Storefront API request timed out after ${timeoutInMs}ms`, options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.mjs","names":[],"sources":["../../src/client/errors.ts"],"sourcesContent":["interface StorefrontApiErrorOptions {\n requestId?: string;\n status?: number;\n cause?: unknown;\n queryText?: string;\n variables?: Record<string, unknown>;\n
|
|
1
|
+
{"version":3,"file":"errors.mjs","names":[],"sources":["../../src/client/errors.ts"],"sourcesContent":["interface StorefrontApiErrorOptions {\n requestId?: string;\n status?: number;\n cause?: unknown;\n queryText?: string;\n variables?: Record<string, unknown>;\n}\n\n/**\n * Thrown when a Storefront API request fails — HTTP error, network failure,\n * or an unparseable or unexpected response body.\n *\n * In development, `queryText` and `variables` are attached when available.\n * GraphQL errors (including `THROTTLED`) are not thrown; read them from `result.errors`.\n */\nexport class StorefrontApiError extends Error {\n /** Shopify `x-request-id` header, when available. Useful for support requests. */\n readonly requestId?: string;\n /** HTTP response status code, when the request reached the server. */\n readonly status?: number;\n /** The GraphQL query text. Only populated in development builds. */\n readonly queryText?: string;\n /** The variables sent with the request. Only populated in development builds. */\n readonly variables?: Record<string, unknown>;\n\n constructor(message: string, options?: StorefrontApiErrorOptions) {\n super(message, options?.cause ? { cause: options.cause } : undefined);\n this.name = \"StorefrontApiError\";\n this.requestId = options?.requestId;\n this.status = options?.status;\n\n if (__DEV__) {\n this.queryText = options?.queryText;\n this.variables = options?.variables;\n }\n }\n\n get [Symbol.toStringTag]() {\n return this.name;\n }\n\n /** Serializes the error. `queryText`, `variables`, `cause`, and `stack` are always omitted. */\n toJSON(): { name: string; message: string; requestId?: string; status?: number } {\n return {\n name: this.name,\n message: this.message,\n ...(this.requestId != null && { requestId: this.requestId }),\n ...(this.status != null && { status: this.status }),\n };\n }\n}\n\n/**\n * Thrown when a Storefront API request exceeds the configured `defaultTimeoutInMs`.\n *\n * Subclass of {@link StorefrontApiError}, so catching `StorefrontApiError` also handles timeouts.\n * Aborts from the request context or a per-call `signal` are rethrown as-is, not wrapped.\n */\nexport class StorefrontTimeoutError extends StorefrontApiError {\n /** The timeout threshold that was exceeded, in milliseconds. */\n readonly timeoutInMs: number;\n\n constructor(timeoutInMs: number, options?: Omit<StorefrontApiErrorOptions, \"cause\">) {\n super(`Storefront API request timed out after ${timeoutInMs}ms`, options);\n this.name = \"StorefrontTimeoutError\";\n this.timeoutInMs = timeoutInMs;\n }\n}\n"],"mappings":";;;;;;;;AAeA,IAAa,qBAAb,cAAwC,MAAM;;CAE5C,AAAS;;CAET,AAAS;;CAET,AAAS;;CAET,AAAS;CAET,YAAY,SAAiB,SAAqC;AAChE,QAAM,SAAS,SAAS,QAAQ,EAAE,OAAO,QAAQ,OAAO,GAAG,OAAU;AACrE,OAAK,OAAO;AACZ,OAAK,YAAY,SAAS;AAC1B,OAAK,SAAS,SAAS;;CAQzB,KAAK,OAAO,eAAe;AACzB,SAAO,KAAK;;;CAId,SAAiF;AAC/E,SAAO;GACL,MAAM,KAAK;GACX,SAAS,KAAK;GACd,GAAI,KAAK,aAAa,QAAQ,EAAE,WAAW,KAAK,WAAW;GAC3D,GAAI,KAAK,UAAU,QAAQ,EAAE,QAAQ,KAAK,QAAQ;GACnD;;;;;;;;;AAUL,IAAa,yBAAb,cAA4C,mBAAmB;;CAE7D,AAAS;CAET,YAAY,aAAqB,SAAoD;AACnF,QAAM,0CAA0C,YAAY,KAAK,QAAQ;AACzE,OAAK,OAAO;AACZ,OAAK,cAAc"}
|
package/dist/client/types.d.mts
CHANGED
|
@@ -15,17 +15,27 @@ type ResultOfDoc<Doc> = Doc extends StorefrontQueryString<infer Result, infer _V
|
|
|
15
15
|
type VariablesOfDoc<Doc> = Doc extends StorefrontQueryString<infer _Result, infer Variables, string> ? Variables : Doc extends TadaDocumentNode<any, any> ? VariablesOf<Doc> : never;
|
|
16
16
|
type StorefrontApiResultOf<Doc extends DocLike> = ResultOf<Doc>;
|
|
17
17
|
type StorefrontApiVariablesOf<Doc extends DocLike> = VariablesOf<Doc>;
|
|
18
|
+
/**
|
|
19
|
+
* Minimal shape matching the GraphQL spec's error format, defined locally to
|
|
20
|
+
* avoid a runtime dependency on the `graphql` package.
|
|
21
|
+
*
|
|
22
|
+
* Present on the `errors` arm of {@link StorefrontGraphqlResult}.
|
|
23
|
+
*/
|
|
18
24
|
interface GraphQLFormattedError {
|
|
25
|
+
/** Human-readable error description. */
|
|
19
26
|
readonly message: string;
|
|
27
|
+
/** Source locations in the query where the error originated. */
|
|
20
28
|
readonly locations?: ReadonlyArray<{
|
|
21
29
|
line: number;
|
|
22
30
|
column: number;
|
|
23
31
|
}>;
|
|
32
|
+
/** Response path to the field that triggered the error. */
|
|
24
33
|
readonly path?: ReadonlyArray<string | number>;
|
|
34
|
+
/** Vendor extensions (e.g. Shopify error codes). */
|
|
25
35
|
readonly extensions?: Record<string, unknown>;
|
|
26
36
|
}
|
|
27
37
|
type CommonOptions = {
|
|
28
|
-
storeDomain: string;
|
|
38
|
+
/** Shopify store domain — e.g. `"my-store.myshopify.com"`. Normalized internally. */storeDomain: string;
|
|
29
39
|
/**
|
|
30
40
|
* Identifies the Hydrogen storefront making Storefront API requests so Shopify can attribute
|
|
31
41
|
* cart analytics to the correct storefront.
|
|
@@ -38,9 +48,9 @@ type CommonOptions = {
|
|
|
38
48
|
* `apiVersion` so version routing stays explicit. Hydrogen's bundled gql.tada schema still
|
|
39
49
|
* controls type inference, so queries against fields outside that schema need their own typing.
|
|
40
50
|
*/
|
|
41
|
-
apiVersion?: string;
|
|
42
|
-
defaultTimeoutInMs?: number;
|
|
43
|
-
cache?: CacheInstance;
|
|
51
|
+
apiVersion?: string; /** Per-request timeout in milliseconds. `0` disables the timeout. Defaults to 30,000 ms. */
|
|
52
|
+
defaultTimeoutInMs?: number; /** Shared cache instance that enables per-query caching via the `cache` option on `graphql()`. */
|
|
53
|
+
cache?: CacheInstance; /** Worker-style `waitUntil` to extend the request lifetime for background cache writes. */
|
|
44
54
|
waitUntil?: WaitUntil;
|
|
45
55
|
};
|
|
46
56
|
type AnyFetch = typeof globalThis.fetch | ((...args: never[]) => Promise<Response>);
|
|
@@ -53,7 +63,9 @@ type AnyFetch = typeof globalThis.fetch | ((...args: never[]) => Promise<Respons
|
|
|
53
63
|
* product tags, metaobjects, metafields, menus, and customers.
|
|
54
64
|
*/
|
|
55
65
|
interface PublicClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
|
|
66
|
+
/** Custom fetch implementation. Falls back to `globalThis.fetch`. */
|
|
56
67
|
fetch?: Fetch;
|
|
68
|
+
/** Public Storefront Access Token. Omit for tokenless access (limited fields). */
|
|
57
69
|
publicStorefrontToken?: string | undefined;
|
|
58
70
|
}
|
|
59
71
|
/**
|
|
@@ -67,7 +79,9 @@ interface PublicClientOptions<Fetch extends AnyFetch | undefined = typeof global
|
|
|
67
79
|
* product tags, metaobjects, metafields, menus, and customers.
|
|
68
80
|
*/
|
|
69
81
|
interface PrivateClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
|
|
82
|
+
/** Custom fetch implementation. Falls back to `globalThis.fetch`. */
|
|
70
83
|
fetch?: Fetch;
|
|
84
|
+
/** Private Storefront Access Token. Must never be exposed to browsers. */
|
|
71
85
|
privateStorefrontToken: string;
|
|
72
86
|
}
|
|
73
87
|
/**
|
|
@@ -78,10 +92,20 @@ interface PrivateClientOptions<Fetch extends AnyFetch | undefined = typeof globa
|
|
|
78
92
|
* shopper identity is available.
|
|
79
93
|
*/
|
|
80
94
|
interface PrivateNoBuyerContextClientOptions<Fetch extends AnyFetch | undefined = typeof globalThis.fetch> extends CommonOptions {
|
|
95
|
+
/** Custom fetch implementation. Falls back to `globalThis.fetch`. */
|
|
81
96
|
fetch?: Fetch;
|
|
97
|
+
/** Private Storefront Access Token. Must never be exposed to browsers. */
|
|
82
98
|
privateStorefrontToken: string;
|
|
83
99
|
}
|
|
100
|
+
/** Union of all config shapes passed as the `config` field of {@link CreateStorefrontClientArgs}. */
|
|
84
101
|
type StorefrontClientOptions = PublicClientOptions | PrivateClientOptions | PrivateNoBuyerContextClientOptions;
|
|
102
|
+
/**
|
|
103
|
+
* Discriminated union accepted by `createStorefrontClient`.
|
|
104
|
+
*
|
|
105
|
+
* Discriminated on `type`: `"public"` requires a public (or no) token,
|
|
106
|
+
* `"private"` requires a private token plus a request context with `buyerIp`,
|
|
107
|
+
* and `"private_no_buyer_context"` requires a private token; `buyerIp` is not forwarded.
|
|
108
|
+
*/
|
|
85
109
|
type CreateStorefrontClientArgs<RequestContext extends ShopifyRequestContext = ShopifyRequestContext, Type extends ClientType = ClientType, CacheConfig extends CacheInstance | undefined = CacheInstance | undefined> = {
|
|
86
110
|
type: "public" & Type;
|
|
87
111
|
requestContext: RequestContext;
|
|
@@ -104,15 +128,38 @@ type CreateStorefrontClientArgs<RequestContext extends ShopifyRequestContext = S
|
|
|
104
128
|
type AutoAddedVariableNames = "country" | "language";
|
|
105
129
|
type UserVariables<Doc> = Omit<VariablesOfDoc<Doc>, AutoAddedVariableNames>;
|
|
106
130
|
type HasNoRequiredKeys<T> = Record<string, never> extends T ? true : false;
|
|
131
|
+
/** Per-call options common to every `storefront.graphql()` invocation. */
|
|
107
132
|
type StorefrontGraphqlOptions = {
|
|
108
|
-
signal?: AbortSignal;
|
|
133
|
+
/** Abort signal forwarded to the underlying fetch. Combined with the request-context signal via `AbortSignal.any`. */signal?: AbortSignal;
|
|
109
134
|
};
|
|
110
135
|
type MergedOptions<Doc extends DocLike, Extra extends Record<string, unknown>> = Extra & StorefrontGraphqlOptions & (HasNoRequiredKeys<UserVariables<Doc>> extends true ? {
|
|
111
136
|
variables?: UserVariables<Doc>;
|
|
112
137
|
} : {
|
|
113
138
|
variables: UserVariables<Doc>;
|
|
114
139
|
});
|
|
140
|
+
/**
|
|
141
|
+
* Rest-parameter tuple for `storefront.graphql()`.
|
|
142
|
+
*
|
|
143
|
+
* Resolves to `[options]` (required) when the document declares required
|
|
144
|
+
* variables, or `[options?]` (optional) when all variables are optional or
|
|
145
|
+
* auto-injected (e.g. `$country`, `$language`).
|
|
146
|
+
*/
|
|
115
147
|
type GqlRestParam<Doc extends DocLike, Extra extends Record<string, unknown> = {}> = HasNoRequiredKeys<MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>> extends true ? [options?: MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>] : [options: MergedOptions<Doc, GraphqlExtraOptionsForDoc<Doc, Extra>>];
|
|
148
|
+
/**
|
|
149
|
+
* Discriminated union returned by `storefront.graphql()`.
|
|
150
|
+
*
|
|
151
|
+
* Discriminated on `errors`:
|
|
152
|
+
*
|
|
153
|
+
* - **No `errors`** — `data` is non-null and fully typed by the document.
|
|
154
|
+
* - **`errors` present** — `data` may be `null` (request-level error, or a non-null
|
|
155
|
+
* field error that propagated to the root) or
|
|
156
|
+
* partial (field-level error absorbed by a nullable ancestor). Always
|
|
157
|
+
* inspect `errors` first.
|
|
158
|
+
*
|
|
159
|
+
* `Partial` is deliberately not used: a non-null `data` never has absent
|
|
160
|
+
* top-level keys — failures surface as `null` values already covered by the
|
|
161
|
+
* schema types.
|
|
162
|
+
*/
|
|
116
163
|
type StorefrontGraphqlResult<Doc extends DocLike> = {
|
|
117
164
|
data: ResultOfDoc<Doc>;
|
|
118
165
|
errors?: undefined;
|
|
@@ -122,24 +169,58 @@ type StorefrontGraphqlResult<Doc extends DocLike> = {
|
|
|
122
169
|
errors: GraphQLFormattedError[];
|
|
123
170
|
headers: Headers;
|
|
124
171
|
};
|
|
172
|
+
/** Base callable signature of `StorefrontClient.graphql` without per-client extra options. Accepts a `gql()` document or a plain string. */
|
|
125
173
|
type StorefrontGraphql = <const Doc extends DocLike | string>(doc: Doc, ...options: GqlRestParam<ResolveDoc<Doc>>) => Promise<StorefrontGraphqlResult<ResolveDoc<Doc>>>;
|
|
126
174
|
type ClientType = /** Public access token or tokenless access. Best for: browser requests. */"public" /** Private token with trusted buyer context. Best for: SSR. */ | "private" /** Private token without buyer context. Best for: background jobs, webhooks. */ | "private_no_buyer_context";
|
|
175
|
+
/**
|
|
176
|
+
* A type-safe Storefront API client returned by `createStorefrontClient`.
|
|
177
|
+
*
|
|
178
|
+
* Call `client.graphql(doc, options?)` to execute a query or mutation against
|
|
179
|
+
* the Storefront API. The result is typed by the document you pass in.
|
|
180
|
+
*/
|
|
127
181
|
type StorefrontClient<Extra extends Record<string, unknown> = {}, Type extends ClientType = ClientType, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = {
|
|
128
|
-
type: Type;
|
|
182
|
+
/** Which client variant was created (`"public"`, `"private"`, or `"private_no_buyer_context"`). */type: Type; /** Resolved i18n config (country + language) used for automatic variable injection. */
|
|
129
183
|
i18n: RequestContext["i18n"];
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
184
|
+
/**
|
|
185
|
+
* Execute a Storefront API GraphQL operation.
|
|
186
|
+
*
|
|
187
|
+
* Accepts a `gql()` document or a plain query string. Variables
|
|
188
|
+
* declared as `$country` / `$language` are auto-injected from the client's
|
|
189
|
+
* i18n config.
|
|
190
|
+
*/
|
|
191
|
+
graphql: <const Doc extends DocLike | string>(doc: Doc, ...options: GqlRestParam<ResolveDoc<Doc>, Extra>) => Promise<StorefrontGraphqlResult<ResolveDoc<Doc>>>; /** Full Storefront API GraphQL endpoint URL. */
|
|
192
|
+
apiUrl: string; /** Normalized store URL (e.g. `"https://my-store.myshopify.com"`). */
|
|
193
|
+
storeUrl: string; /** Storefront identifier for cart analytics attribution, when provided. */
|
|
194
|
+
storefrontId?: string; /** The request context used for request-scoped headers, abort signals, and i18n. */
|
|
134
195
|
requestContext: RequestContext;
|
|
135
196
|
};
|
|
197
|
+
/** A {@link StorefrontClient} narrowed to `type: "public"`. */
|
|
136
198
|
type PublicStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = StorefrontClient<Extra, "public", RequestContext>;
|
|
199
|
+
/** A {@link StorefrontClient} narrowed to `type: "private"`. Requires a request context with `buyerIp`. */
|
|
137
200
|
type PrivateStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContextWithBuyerIp = ShopifyRequestContextWithBuyerIp> = StorefrontClient<Extra, "private", RequestContext>;
|
|
201
|
+
/** Convenience alias: a private client whose request context is always the concrete `ShopifyRequestContextWithBuyerIp`. */
|
|
138
202
|
type RequestScopedPrivateStorefrontClient<Extra extends Record<string, unknown> = {}> = PrivateStorefrontClient<Extra, ShopifyRequestContextWithBuyerIp>;
|
|
203
|
+
/** A {@link StorefrontClient} narrowed to `type: "private_no_buyer_context"`. Best for background jobs and webhooks. */
|
|
139
204
|
type PrivateNoBuyerContextStorefrontClient<Extra extends Record<string, unknown> = {}, RequestContext extends ShopifyRequestContext = ShopifyRequestContext> = StorefrontClient<Extra, "private_no_buyer_context", RequestContext>;
|
|
205
|
+
/**
|
|
206
|
+
* Namespace for extracting result and variable types from Storefront API documents.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* import { gql, type StorefrontApi } from "@shopify/hydrogen";
|
|
211
|
+
*
|
|
212
|
+
* const PRODUCT_QUERY = gql(`query Product($handle: String!) { product(handle: $handle) { title } }`);
|
|
213
|
+
*
|
|
214
|
+
* type Product = StorefrontApi.ResultOf<typeof PRODUCT_QUERY>;
|
|
215
|
+
* type Vars = StorefrontApi.VariablesOf<typeof PRODUCT_QUERY>;
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
140
218
|
declare namespace StorefrontApi {
|
|
219
|
+
/** Extracts the typed result shape from a Storefront API document. */
|
|
141
220
|
type ResultOf<Doc extends DocLike> = StorefrontApiResultOf<Doc>;
|
|
221
|
+
/** Extracts the typed variables shape from a Storefront API document. */
|
|
142
222
|
type VariablesOf<Doc extends DocLike> = StorefrontApiVariablesOf<Doc>;
|
|
223
|
+
/** A typed Storefront API document — a `gql()` document or a `TadaDocumentNode`. */
|
|
143
224
|
type DocumentNode = DocLike;
|
|
144
225
|
}
|
|
145
226
|
//#endregion
|
|
@@ -2,6 +2,20 @@ import { CartStore } from "../cart/cart.mjs";
|
|
|
2
2
|
|
|
3
3
|
//#region src/core/analytics/cart-tracker.d.ts
|
|
4
4
|
type CartAnalyticsStore = Pick<CartStore, "getState" | "subscribe">;
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to a cart store and publishes analytics events when the cart changes.
|
|
7
|
+
*
|
|
8
|
+
* Emits `cart_updated` whenever a settled cart's `updatedAt` changes, plus
|
|
9
|
+
* `product_added_to_cart` / `product_removed_from_cart` for each line that was
|
|
10
|
+
* added, removed, or changed quantity. Deduplicates on `updatedAt` with an
|
|
11
|
+
* in-memory cursor (within this subscription) and `localStorage` (across full
|
|
12
|
+
* page loads and tabs). A store filled from your own cart query must select
|
|
13
|
+
* `updatedAt`, or deduplication can't work.
|
|
14
|
+
*
|
|
15
|
+
* @throws {Error} If `window.Shopify.analytics` is not set (including on the server).
|
|
16
|
+
* Render `ShopifyScripts` (or the `getShopifyScriptTags()` output) first.
|
|
17
|
+
* @returns An unsubscribe function that stops tracking.
|
|
18
|
+
*/
|
|
5
19
|
declare function trackCartAnalytics(store: CartAnalyticsStore): () => void;
|
|
6
20
|
//#endregion
|
|
7
21
|
export { trackCartAnalytics };
|
|
@@ -2,6 +2,20 @@ import { AnalyticsEvent } from "./events.mjs";
|
|
|
2
2
|
import { flattenConnection } from "./utils/flatten-connection.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/core/analytics/cart-tracker.ts
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to a cart store and publishes analytics events when the cart changes.
|
|
7
|
+
*
|
|
8
|
+
* Emits `cart_updated` whenever a settled cart's `updatedAt` changes, plus
|
|
9
|
+
* `product_added_to_cart` / `product_removed_from_cart` for each line that was
|
|
10
|
+
* added, removed, or changed quantity. Deduplicates on `updatedAt` with an
|
|
11
|
+
* in-memory cursor (within this subscription) and `localStorage` (across full
|
|
12
|
+
* page loads and tabs). A store filled from your own cart query must select
|
|
13
|
+
* `updatedAt`, or deduplication can't work.
|
|
14
|
+
*
|
|
15
|
+
* @throws {Error} If `window.Shopify.analytics` is not set (including on the server).
|
|
16
|
+
* Render `ShopifyScripts` (or the `getShopifyScriptTags()` output) first.
|
|
17
|
+
* @returns An unsubscribe function that stops tracking.
|
|
18
|
+
*/
|
|
5
19
|
function trackCartAnalytics(store) {
|
|
6
20
|
const analytics = getGlobalAnalytics();
|
|
7
21
|
const state = {
|
|
@@ -120,7 +134,7 @@ function hasPendingCartWork({ pending, revalidating }) {
|
|
|
120
134
|
return revalidating === true || hasPendingCost || pending.note || pending.attributes;
|
|
121
135
|
}
|
|
122
136
|
function getCartUpdatedAt(cart) {
|
|
123
|
-
return
|
|
137
|
+
return cart.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
124
138
|
}
|
|
125
139
|
function syncShopifyCurrency(cart) {
|
|
126
140
|
if (typeof window === "undefined") return;
|