@shopify/hydrogen 2026.10.0-preview.2 → 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 +34 -3
- package/dist/cli/index.mjs +578 -85
- 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 +29 -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 +57 -6
- 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/form.d.mts +21 -2
- package/dist/core/product/form.mjs +13 -0
- package/dist/core/product/form.mjs.map +1 -1
- package/dist/core/product/index.d.mts +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 +8 -5
- package/dist/core/request-context.mjs +17 -39
- package/dist/core/request-context.mjs.map +1 -1
- package/dist/core/request-routing/handle-shopify-routes.mjs +4 -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 +22 -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 +36 -10
- 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 +35 -0
- package/dist/core/request-routing/interceptors/ucp-mcp-proxy.mjs.map +1 -0
- 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 +4 -2
- package/dist/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/core/shopify-scripts/global.mjs +9 -4
- package/dist/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/core/shopify-scripts/index.d.mts +1 -0
- package/dist/core/shopify-scripts/index.mjs +14 -12
- package/dist/core/shopify-scripts/index.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 +6 -0
- package/dist/core/url.mjs +21 -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 +29 -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 +57 -6
- 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 +345 -312
- 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 +38 -2
- 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/form.d.mts +21 -2
- package/dist/development/core/product/form.mjs +13 -0
- package/dist/development/core/product/form.mjs.map +1 -1
- package/dist/development/core/product/index.d.mts +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 +8 -5
- package/dist/development/core/request-context.mjs +17 -39
- package/dist/development/core/request-context.mjs.map +1 -1
- package/dist/development/core/request-routing/handle-shopify-routes.mjs +4 -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 +22 -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 +36 -10
- 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 +35 -0
- package/dist/development/core/request-routing/interceptors/ucp-mcp-proxy.mjs.map +1 -0
- 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 +4 -2
- package/dist/development/core/shopify-scripts/constants.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/global.mjs +9 -4
- package/dist/development/core/shopify-scripts/global.mjs.map +1 -1
- package/dist/development/core/shopify-scripts/index.d.mts +1 -0
- package/dist/development/core/shopify-scripts/index.mjs +14 -12
- package/dist/development/core/shopify-scripts/index.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 +6 -0
- package/dist/development/core/url.mjs +21 -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 +6 -5
- 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 +8 -6
- 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 +30 -3
- package/dist/development/vue/shopify-scripts.mjs +6 -0
- package/dist/development/vue/shopify-scripts.mjs.map +1 -1
- package/dist/globals.d.mts +6 -5
- 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 +8 -6
- 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 +31 -4
- package/dist/vue/shopify-scripts.mjs +6 -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-cart-metafields/SKILL.md +133 -0
- package/skills/hydrogen-cart-ui/SKILL.md +2 -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/11-verify.md +1 -0
- package/skills/hydrogen-setup/steps/2-scaffold.md +22 -1
- package/skills/hydrogen-smoke-test/SKILL.md +2 -2
- package/skills/hydrogen-storefront-client/SKILL.md +4 -2
- package/skills/hydrogen-variant-form/SKILL.md +10 -4
- package/ts-plugin/package.json +5 -0
- package/dist/core/shopify-scripts/consent.mjs +0 -17
- package/dist/core/shopify-scripts/consent.mjs.map +0 -1
- package/dist/core/shopify-scripts/deprecated-cookies.mjs +0 -97
- 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/consent.mjs +0 -17
- package/dist/development/core/shopify-scripts/consent.mjs.map +0 -1
- package/dist/development/core/shopify-scripts/deprecated-cookies.mjs +0 -97
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/core/shopify-scripts/index.ts"],"sourcesContent":["import { getShopifyAnalyticsBusScript, getShopifyAnalyticsConfig } from \"./analytics\";\nimport {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/core/shopify-scripts/index.ts"],"sourcesContent":["import { getShopifyAnalyticsBusScript, getShopifyAnalyticsConfig } from \"./analytics\";\nimport {\n SHOPIFY_ACCOUNT_SCRIPT,\n SHOPIFY_CONSENT_API_SCRIPT,\n SHOPIFY_CDN_ORIGIN,\n SHOPIFY_CONSENT_SCRIPT_ID,\n SHOPIFY_PRIVACY_BANNER_SCRIPT,\n SHOPIFY_SHOP_APP_ORIGIN,\n SHOPIFY_INBOX_SCRIPT,\n SHOPIFY_STOREFRONT_ANALYTICS_SCRIPT,\n SHOPIFY_STOREFRONT_STANDARD_ACTIONS_SCRIPT,\n SHOPIFY_STOREFRONT_STANDARD_EVENTS_INSPECTOR_SCRIPT,\n SHOPIFY_STOREFRONT_STANDARD_EVENTS_SCRIPT,\n} from \"./constants\";\nimport { getShopifyGlobalBootstrapScript } from \"./global\";\nimport { getPerfKitScript } from \"./perfkit\";\nimport { renderShopifyScriptTag } from \"./render\";\nimport type {\n ShopifyLinkDescriptor,\n ShopifyScriptDescriptor,\n ShopifyScriptTagDescriptors,\n ShopifyScriptTagsOptions,\n} from \"./types\";\n\nexport {\n CONSENT_TRACKING_API_LOADED_EVENT,\n SHOPIFY_ACCOUNT_SCRIPT,\n SHOPIFY_CDN_ORIGIN,\n SHOPIFY_CONSENT_API_SCRIPT,\n SHOPIFY_PERF_KIT_SCRIPT,\n SHOPIFY_PRIVACY_BANNER_SCRIPT,\n SHOPIFY_SHOP_APP_ORIGIN,\n SHOPIFY_INBOX_SCRIPT,\n SHOPIFY_STOREFRONT_ANALYTICS_SCRIPT,\n SHOPIFY_STOREFRONT_STANDARD_ACTIONS_SCRIPT,\n SHOPIFY_STOREFRONT_STANDARD_EVENTS_SCRIPT,\n SHOPIFY_STOREFRONT_WEBMCP_SCRIPT,\n VISITOR_CONSENT_COLLECTED_EVENT,\n} from \"./constants\";\nexport { getShopifyGlobal, getShopifyGlobalBootstrapScript } from \"./global\";\nexport { initializeShopifyScripts } from \"./initialize\";\nexport { renderShopifyScriptTag } from \"./render\";\nexport type {\n ShopifyScriptsAnalyticsConfig,\n ShopifyRoutesOptions,\n ShopifyScriptTagDescriptor,\n ShopifyScriptTagDescriptors,\n ShopifyScriptTagsOptions,\n ShopifyScriptsOptions,\n ShopifyScriptsI18n,\n ShopifyScriptsShop,\n} from \"./types\";\n\n/**\n * Returns grouped Shopify storefront script/link descriptors for SSR frameworks and bindings.\n *\n * Framework bindings wrap this with `initializeShopifyScripts()` to form their `ShopifyScripts`\n * component. Frameworks without a binding can render these descriptors during SSR and call\n * `initializeShopifyScripts()` during browser hydration.\n */\n// oxlint-disable-next-line complexity -- ordered assembly of optional Shopify script tags; each flag adds one branch and splitting would obscure the required load order\nexport function getShopifyScriptTags({\n account = false,\n analytics,\n consent,\n debug,\n i18n,\n nonce,\n shop,\n shopifyAnalytics = true,\n inbox = false,\n}: ShopifyScriptTagsOptions): ShopifyScriptTagDescriptors {\n const nonceAttributes = nonce !== undefined ? { nonce } : undefined;\n const analyticsConfig = getShopifyAnalyticsConfig({ analytics, consent, shop });\n\n const links: ShopifyLinkDescriptor[] = [\n {\n tagName: \"link\",\n attributes: {\n rel: \"preconnect\",\n href: SHOPIFY_CDN_ORIGIN,\n },\n },\n {\n tagName: \"link\",\n attributes: {\n rel: \"preconnect\",\n href: SHOPIFY_SHOP_APP_ORIGIN,\n },\n },\n {\n tagName: \"link\",\n attributes: {\n rel: \"prefetch\",\n as: \"script\",\n href: SHOPIFY_STOREFRONT_STANDARD_EVENTS_SCRIPT,\n crossorigin: \"anonymous\",\n },\n },\n ];\n const scripts: ShopifyScriptDescriptor[] = [\n {\n tagName: \"script\",\n attributes: { id: \"shopify-global-bootstrap\", ...nonceAttributes },\n innerHTML: getShopifyGlobalBootstrapScript({ i18n, shop }),\n },\n {\n tagName: \"script\",\n attributes: {\n id: \"shopify-standard-actions\",\n type: \"module\",\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src: SHOPIFY_STOREFRONT_STANDARD_ACTIONS_SCRIPT,\n },\n },\n ];\n\n if (__DEV__ && debug?.standardEventsInspector) {\n scripts.push({\n tagName: \"script\",\n attributes: {\n id: \"shopify-standard-events-inspector\",\n defer: true,\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src: SHOPIFY_STOREFRONT_STANDARD_EVENTS_INSPECTOR_SCRIPT,\n },\n });\n }\n\n if (inbox) {\n scripts.push({\n tagName: \"script\",\n attributes: {\n id: \"shopify-inbox\",\n type: \"module\",\n async: true,\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src: SHOPIFY_INBOX_SCRIPT,\n },\n });\n }\n\n if (account) {\n scripts.push({\n tagName: \"script\",\n attributes: {\n id: \"shopify-account\",\n type: \"module\",\n async: true,\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src: SHOPIFY_ACCOUNT_SCRIPT,\n },\n });\n }\n\n // Install readiness listeners before loading the async consent library so a\n // cached script cannot finish initialization before Hydrogen starts listening.\n scripts.push({\n tagName: \"script\",\n attributes: { id: \"shopify-analytics-bus\", ...nonceAttributes },\n innerHTML: getShopifyAnalyticsBusScript(analyticsConfig),\n });\n\n scripts.push({\n tagName: \"script\",\n attributes: {\n id: SHOPIFY_CONSENT_SCRIPT_ID,\n async: true,\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src:\n consent?.mode === \"default-banner\"\n ? SHOPIFY_PRIVACY_BANNER_SCRIPT\n : SHOPIFY_CONSENT_API_SCRIPT,\n },\n });\n\n if (shopifyAnalytics) {\n scripts.push({\n tagName: \"script\",\n attributes: {\n id: \"shopify-storefront-analytics\",\n async: true,\n crossorigin: \"anonymous\",\n ...nonceAttributes,\n src: SHOPIFY_STOREFRONT_ANALYTICS_SCRIPT,\n },\n });\n }\n\n const perfKitScript = getPerfKitScript(shop, nonceAttributes);\n if (perfKitScript) {\n scripts.push(perfKitScript);\n }\n\n return {\n links,\n scripts,\n get tags() {\n return [...links, ...scripts];\n },\n };\n}\n\n/**\n * Renders all Shopify storefront script/link descriptors to HTML strings.\n */\nexport function renderShopifyScriptTags(options: ShopifyScriptTagsOptions): string[] {\n return getShopifyScriptTags(options).tags.map(renderShopifyScriptTag);\n}\n"],"mappings":";;;;;;;;;;;;;;;AA6DA,SAAgB,qBAAqB,EACnC,UAAU,OACV,WACA,SACA,OACA,MACA,OACA,MACA,mBAAmB,MACnB,QAAQ,SACgD;CACxD,MAAM,kBAAkB,UAAU,SAAY,EAAE,OAAO,GAAG;CAC1D,MAAM,kBAAkB,0BAA0B;EAAE;EAAW;EAAS;EAAM,CAAC;CAE/E,MAAM,QAAiC;EACrC;GACE,SAAS;GACT,YAAY;IACV,KAAK;IACL,MAAM;IACP;GACF;EACD;GACE,SAAS;GACT,YAAY;IACV,KAAK;IACL,MAAM;IACP;GACF;EACD;GACE,SAAS;GACT,YAAY;IACV,KAAK;IACL,IAAI;IACJ,MAAM;IACN,aAAa;IACd;GACF;EACF;CACD,MAAM,UAAqC,CACzC;EACE,SAAS;EACT,YAAY;GAAE,IAAI;GAA4B,GAAG;GAAiB;EAClE,WAAW,gCAAgC;GAAE;GAAM;GAAM,CAAC;EAC3D,EACD;EACE,SAAS;EACT,YAAY;GACV,IAAI;GACJ,MAAM;GACN,aAAa;GACb,GAAG;GACH,KAAK;GACN;EACF,CACF;AAeD,KAAI,MACF,SAAQ,KAAK;EACX,SAAS;EACT,YAAY;GACV,IAAI;GACJ,MAAM;GACN,OAAO;GACP,aAAa;GACb,GAAG;GACH,KAAK;GACN;EACF,CAAC;AAGJ,KAAI,QACF,SAAQ,KAAK;EACX,SAAS;EACT,YAAY;GACV,IAAI;GACJ,MAAM;GACN,OAAO;GACP,aAAa;GACb,GAAG;GACH,KAAK;GACN;EACF,CAAC;AAKJ,SAAQ,KAAK;EACX,SAAS;EACT,YAAY;GAAE,IAAI;GAAyB,GAAG;GAAiB;EAC/D,WAAW,6BAA6B,gBAAgB;EACzD,CAAC;AAEF,SAAQ,KAAK;EACX,SAAS;EACT,YAAY;GACV,IAAI;GACJ,OAAO;GACP,aAAa;GACb,GAAG;GACH,KACE,SAAS,SAAS,mBACd,gCACA;GACP;EACF,CAAC;AAEF,KAAI,iBACF,SAAQ,KAAK;EACX,SAAS;EACT,YAAY;GACV,IAAI;GACJ,OAAO;GACP,aAAa;GACb,GAAG;GACH,KAAK;GACN;EACF,CAAC;CAGJ,MAAM,gBAAgB,iBAAiB,MAAM,gBAAgB;AAC7D,KAAI,cACF,SAAQ,KAAK,cAAc;AAG7B,QAAO;EACL;EACA;EACA,IAAI,OAAO;AACT,UAAO,CAAC,GAAG,OAAO,GAAG,QAAQ;;EAEhC;;;;;AAMH,SAAgB,wBAAwB,SAA6C;AACnF,QAAO,qBAAqB,QAAQ,CAAC,KAAK,IAAI,uBAAuB"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { getLogger } from "../logging/logging.mjs";
|
|
1
2
|
import { configureShopifyRouting } from "./global.mjs";
|
|
2
|
-
import {
|
|
3
|
+
import { initializeCustomConsent } from "../analytics/custom-consent.mjs";
|
|
3
4
|
import { initializeShopifyPageViewEvents } from "./page-view.mjs";
|
|
4
5
|
import { loadShopifyWebMcpTools } from "./webmcp.mjs";
|
|
5
6
|
|
|
6
7
|
//#region src/core/shopify-scripts/initialize.ts
|
|
8
|
+
const log = getLogger("consent");
|
|
7
9
|
/**
|
|
8
10
|
* Initializes Shopify browser script behavior for frameworks without a Hydrogen binding.
|
|
9
11
|
*
|
|
@@ -11,13 +13,18 @@ import { loadShopifyWebMcpTools } from "./webmcp.mjs";
|
|
|
11
13
|
* into a `ShopifyScripts` component, while custom integrations can render script tags during SSR
|
|
12
14
|
* and call this helper from their browser lifecycle.
|
|
13
15
|
*/
|
|
14
|
-
function initializeShopifyScripts({ navigate, routes, webMcp = true }) {
|
|
16
|
+
function initializeShopifyScripts({ consent, navigate, routes, webMcp = true }) {
|
|
15
17
|
configureShopifyRouting({
|
|
16
18
|
navigate,
|
|
17
19
|
routes
|
|
18
20
|
});
|
|
19
|
-
initializeDeprecatedCookies();
|
|
20
21
|
initializeShopifyPageViewEvents();
|
|
22
|
+
if (consent?.mode === "custom-banner") if (typeof consent.setup !== "function") log.warn("custom-banner requires a consent.setup callback; analytics delivery remains blocked until setup completes");
|
|
23
|
+
else try {
|
|
24
|
+
initializeCustomConsent(consent.setup);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
log.error("custom consent initialization failed", { error });
|
|
27
|
+
}
|
|
21
28
|
if (!webMcp) return Promise.resolve();
|
|
22
29
|
return loadShopifyWebMcpTools();
|
|
23
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initialize.mjs","names":[],"sources":["../../../src/core/shopify-scripts/initialize.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"initialize.mjs","names":[],"sources":["../../../src/core/shopify-scripts/initialize.ts"],"sourcesContent":["import { initializeCustomConsent } from \"../analytics/custom-consent\";\nimport { getLogger } from \"../logging\";\nimport { configureShopifyRouting } from \"./global\";\nimport { initializeShopifyPageViewEvents } from \"./page-view\";\nimport type { InitializeShopifyScriptsOptions } from \"./types\";\nimport { loadShopifyWebMcpTools } from \"./webmcp\";\n\nconst log = getLogger(\"consent\");\n\n/**\n * Initializes Shopify browser script behavior for frameworks without a Hydrogen binding.\n *\n * This is the browser hydration half of `getShopifyScriptTags()`: framework bindings combine both\n * into a `ShopifyScripts` component, while custom integrations can render script tags during SSR\n * and call this helper from their browser lifecycle.\n */\nexport function initializeShopifyScripts({\n consent,\n navigate,\n routes,\n webMcp = true,\n}: InitializeShopifyScriptsOptions): Promise<boolean | void> {\n configureShopifyRouting({ navigate, routes });\n initializeShopifyPageViewEvents();\n\n if (consent?.mode === \"custom-banner\") {\n if (typeof consent.setup !== \"function\") {\n log.warn(\n \"custom-banner requires a consent.setup callback; analytics delivery remains blocked until setup completes\",\n );\n } else {\n try {\n initializeCustomConsent(consent.setup);\n } catch (error) {\n log.error(\"custom consent initialization failed\", { error });\n }\n }\n }\n\n if (!webMcp) return Promise.resolve();\n\n return loadShopifyWebMcpTools();\n}\n"],"mappings":";;;;;;;AAOA,MAAM,MAAM,UAAU,UAAU;;;;;;;;AAShC,SAAgB,yBAAyB,EACvC,SACA,UACA,QACA,SAAS,QACkD;AAC3D,yBAAwB;EAAE;EAAU;EAAQ,CAAC;AAC7C,kCAAiC;AAEjC,KAAI,SAAS,SAAS,gBACpB,KAAI,OAAO,QAAQ,UAAU,WAC3B,KAAI,KACF,4GACD;KAED,KAAI;AACF,0BAAwB,QAAQ,MAAM;UAC/B,OAAO;AACd,MAAI,MAAM,wCAAwC,EAAE,OAAO,CAAC;;AAKlE,KAAI,CAAC,OAAQ,QAAO,QAAQ,SAAS;AAErC,QAAO,wBAAwB"}
|
|
@@ -52,6 +52,11 @@ type ShopifyScriptsShop = {
|
|
|
52
52
|
myshopifyDomain: string;
|
|
53
53
|
};
|
|
54
54
|
type ShopifyScriptTagsOptions = {
|
|
55
|
+
/**
|
|
56
|
+
* Loads the customer account component. Render `<shopify-account>` where you want the account UI to appear.
|
|
57
|
+
* @see {@link https://shopify.dev/docs/api/storefront-web-components/components/shopify-account | shopify-account}
|
|
58
|
+
*/
|
|
59
|
+
account?: boolean;
|
|
55
60
|
analytics?: ShopifyScriptsAnalyticsConfig;
|
|
56
61
|
consent?: ConsentConfig;
|
|
57
62
|
debug?: {
|
|
@@ -68,6 +73,7 @@ type ShopifyRoutesOptions = {
|
|
|
68
73
|
routes?: ShopifyRouteTemplates;
|
|
69
74
|
};
|
|
70
75
|
type InitializeShopifyScriptsOptions = ShopifyRoutesOptions & {
|
|
76
|
+
/** Pass the same consent configuration used to render the script tags. Setup runs once per bus. */consent?: ConsentConfig;
|
|
71
77
|
webMcp?: boolean;
|
|
72
78
|
};
|
|
73
79
|
type ShopifyScriptsOptions = ShopifyScriptTagsOptions & InitializeShopifyScriptsOptions;
|
package/dist/core/url.mjs
CHANGED
|
@@ -3,8 +3,11 @@ const SFAPI_RE = /^\/api\/(unstable|2\d{3}-\d{2})\/graphql\.json$/;
|
|
|
3
3
|
const SHOPIFY_API_PROXY_PREFIX = "/__shopify";
|
|
4
4
|
const SHOPIFY_API_PROXY_RE = /^\/__shopify(?:\/|$)/;
|
|
5
5
|
const MCP_RE = /^\/api\/mcp$/;
|
|
6
|
+
const UCP_MCP_RE = /^\/api\/ucp\/mcp$/;
|
|
6
7
|
const CHECKOUT_RE = /^\/checkout$/;
|
|
7
8
|
const CART_PERMALINK_RE = /^\/cart\/\d+:\d+(?:,\d+:\d+)*$/;
|
|
9
|
+
const BUY_ITEM_PAIR = String.raw`(?:[A-Za-z0-9._-]+|~[A-Za-z0-9_-]+):[1-9]\d*`;
|
|
10
|
+
const BUY_PERMALINK_RE = new RegExp(`^/buy/${BUY_ITEM_PAIR}(?:,${BUY_ITEM_PAIR})*$`);
|
|
8
11
|
const CUSTOMER_ACCOUNT_PATHS = {
|
|
9
12
|
authorize: "/account/authorize",
|
|
10
13
|
login: "/account/login",
|
|
@@ -19,7 +22,7 @@ const CUSTOMER_ACCOUNT_HANDOFF_PATHS = new Set(Object.values(CUSTOMER_ACCOUNT_PA
|
|
|
19
22
|
* interceptors are intentionally excluded because they are not browser navigation destinations.
|
|
20
23
|
*/
|
|
21
24
|
function isHydrogenServerHandoffPath(pathname) {
|
|
22
|
-
return CHECKOUT_RE.test(pathname) || CART_PERMALINK_RE.test(pathname) || CUSTOMER_ACCOUNT_HANDOFF_PATHS.has(pathname);
|
|
25
|
+
return CHECKOUT_RE.test(pathname) || CART_PERMALINK_RE.test(pathname) || BUY_PERMALINK_RE.test(pathname) || CUSTOMER_ACCOUNT_HANDOFF_PATHS.has(pathname);
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
25
28
|
* Allowlisted `.well-known` resources proxied to the Online Store origin:
|
|
@@ -31,6 +34,22 @@ function isHydrogenServerHandoffPath(pathname) {
|
|
|
31
34
|
*/
|
|
32
35
|
const WELL_KNOWN_RE = /^\/\.well-known\/(?:apple-developer-merchantid-domain-association|shopify\/fec\/produce)$/;
|
|
33
36
|
const AJAX_CART_RE = /^(?:\/[a-z]{2}(?:-[a-z]{2})?)?\/cart(?:\.(?:js|json)|\/(?:add|update|change|clear)(?:\.(?:js|json))?)$/i;
|
|
37
|
+
/**
|
|
38
|
+
* Normalizes `target` to a path on `origin` that is safe to use as a redirect location.
|
|
39
|
+
* Returns `undefined` unless `target` is a path starting with `/` or an absolute URL,
|
|
40
|
+
* stays on `origin`, and its normalized pathname does not start with `//`.
|
|
41
|
+
*/
|
|
42
|
+
function getSameOriginPath(target, origin) {
|
|
43
|
+
if (!target) return void 0;
|
|
44
|
+
try {
|
|
45
|
+
const url = target.startsWith("/") ? new URL(target, origin) : new URL(target);
|
|
46
|
+
if (url.origin !== origin) return void 0;
|
|
47
|
+
const path = `${url.pathname}${url.search}${url.hash}`;
|
|
48
|
+
return path.startsWith("//") ? void 0 : path;
|
|
49
|
+
} catch {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
34
53
|
function normalizeStoreDomain(domain) {
|
|
35
54
|
if (!domain) throw new Error("Storefront `storeDomain` is required.");
|
|
36
55
|
if (domain.startsWith("http://") || domain.startsWith("https://")) return domain.replace(/\/+$/, "");
|
|
@@ -38,5 +57,5 @@ function normalizeStoreDomain(domain) {
|
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
//#endregion
|
|
41
|
-
export { AJAX_CART_RE, CHECKOUT_RE, CUSTOMER_ACCOUNT_PATHS, MCP_RE, SFAPI_RE, SHOPIFY_API_PROXY_PREFIX, SHOPIFY_API_PROXY_RE, WELL_KNOWN_RE, isHydrogenServerHandoffPath, normalizeStoreDomain };
|
|
60
|
+
export { AJAX_CART_RE, BUY_PERMALINK_RE, CHECKOUT_RE, CUSTOMER_ACCOUNT_PATHS, MCP_RE, SFAPI_RE, SHOPIFY_API_PROXY_PREFIX, SHOPIFY_API_PROXY_RE, UCP_MCP_RE, WELL_KNOWN_RE, getSameOriginPath, isHydrogenServerHandoffPath, normalizeStoreDomain };
|
|
42
61
|
//# sourceMappingURL=url.mjs.map
|
package/dist/core/url.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.mjs","names":[],"sources":["../../src/core/url.ts"],"sourcesContent":["export const SFAPI_RE = /^\\/api\\/(unstable|2\\d{3}-\\d{2})\\/graphql\\.json$/;\nexport const SHOPIFY_API_PROXY_PREFIX = \"/__shopify\";\nexport const SHOPIFY_API_PROXY_RE = /^\\/__shopify(?:\\/|$)/;\nexport const MCP_RE = /^\\/api\\/mcp$/;\nexport const CHECKOUT_RE = /^\\/checkout$/;\nexport const CART_PERMALINK_RE = /^\\/cart\\/\\d+:\\d+(?:,\\d+:\\d+)*$/;\nexport const CUSTOMER_ACCOUNT_PATHS = {\n authorize: \"/account/authorize\",\n login: \"/account/login\",\n logout: \"/account/logout\",\n refresh: \"/account/refresh\",\n} as const;\n\nconst CUSTOMER_ACCOUNT_HANDOFF_PATHS: ReadonlySet<string> = new Set(\n Object.values(CUSTOMER_ACCOUNT_PATHS),\n);\n\n/**\n * Returns whether the pathname conventionally represents a Hydrogen document-level server handoff.\n *\n * Keep this aligned with the routes intercepted before framework routing. API and protocol\n * interceptors are intentionally excluded because they are not browser navigation destinations.\n */\nexport function isHydrogenServerHandoffPath(pathname: string): boolean {\n return (\n CHECKOUT_RE.test(pathname) ||\n CART_PERMALINK_RE.test(pathname) ||\n CUSTOMER_ACCOUNT_HANDOFF_PATHS.has(pathname)\n );\n}\n\n/**\n * Allowlisted `.well-known` resources proxied to the Online Store origin:\n * - `apple-developer-merchantid-domain-association` — Apple Pay domain verification.\n * - `shopify/fec/produce` — Frontend Event Collector ingress. On the Online\n * Store the myshopify.com edge forwards this first-party path to the\n * collector; headless storefronts have no such edge, so Hydrogen proxies it\n * to the same origin (used by WebMCP's Event Refinery client).\n */\nexport const WELL_KNOWN_RE =\n /^\\/\\.well-known\\/(?:apple-developer-merchantid-domain-association|shopify\\/fec\\/produce)$/;\nexport const AJAX_CART_RE =\n /^(?:\\/[a-z]{2}(?:-[a-z]{2})?)?\\/cart(?:\\.(?:js|json)|\\/(?:add|update|change|clear)(?:\\.(?:js|json))?)$/i;\n\nexport function normalizeStoreDomain(domain: string): string {\n if (!domain) {\n throw new Error(\"Storefront `storeDomain` is required.\");\n }\n\n if (domain.startsWith(\"http://\") || domain.startsWith(\"https://\")) {\n return domain.replace(/\\/+$/, \"\");\n }\n return `https://${domain}`.replace(/\\/+$/, \"\");\n}\n"],"mappings":";AAAA,MAAa,WAAW;AACxB,MAAa,2BAA2B;AACxC,MAAa,uBAAuB;AACpC,MAAa,SAAS;AACtB,MAAa,cAAc;AAC3B,MAAa,oBAAoB;AACjC,MAAa,yBAAyB;CACpC,WAAW;CACX,OAAO;CACP,QAAQ;CACR,SAAS;CACV;AAED,MAAM,iCAAsD,IAAI,IAC9D,OAAO,OAAO,uBAAuB,CACtC;;;;;;;AAQD,SAAgB,4BAA4B,UAA2B;AACrE,QACE,YAAY,KAAK,SAAS,IAC1B,kBAAkB,KAAK,SAAS,IAChC,+BAA+B,IAAI,SAAS;;;;;;;;;;AAYhD,MAAa,gBACX;AACF,MAAa,eACX;
|
|
1
|
+
{"version":3,"file":"url.mjs","names":[],"sources":["../../src/core/url.ts"],"sourcesContent":["export const SFAPI_RE = /^\\/api\\/(unstable|2\\d{3}-\\d{2})\\/graphql\\.json$/;\nexport const SHOPIFY_API_PROXY_PREFIX = \"/__shopify\";\nexport const SHOPIFY_API_PROXY_RE = /^\\/__shopify(?:\\/|$)/;\nexport const MCP_RE = /^\\/api\\/mcp$/;\nexport const UCP_MCP_RE = /^\\/api\\/ucp\\/mcp$/;\nexport const CHECKOUT_RE = /^\\/checkout$/;\nexport const CART_PERMALINK_RE = /^\\/cart\\/\\d+:\\d+(?:,\\d+:\\d+)*$/;\nconst BUY_ITEM_PAIR = String.raw`(?:[A-Za-z0-9._-]+|~[A-Za-z0-9_-]+):[1-9]\\d*`;\n// Items are required so a storefront's own /buy pages keep routing to the app.\nexport const BUY_PERMALINK_RE = new RegExp(`^/buy/${BUY_ITEM_PAIR}(?:,${BUY_ITEM_PAIR})*$`);\nexport const CUSTOMER_ACCOUNT_PATHS = {\n authorize: \"/account/authorize\",\n login: \"/account/login\",\n logout: \"/account/logout\",\n refresh: \"/account/refresh\",\n} as const;\n\nconst CUSTOMER_ACCOUNT_HANDOFF_PATHS: ReadonlySet<string> = new Set(\n Object.values(CUSTOMER_ACCOUNT_PATHS),\n);\n\n/**\n * Returns whether the pathname conventionally represents a Hydrogen document-level server handoff.\n *\n * Keep this aligned with the routes intercepted before framework routing. API and protocol\n * interceptors are intentionally excluded because they are not browser navigation destinations.\n */\nexport function isHydrogenServerHandoffPath(pathname: string): boolean {\n return (\n CHECKOUT_RE.test(pathname) ||\n CART_PERMALINK_RE.test(pathname) ||\n BUY_PERMALINK_RE.test(pathname) ||\n CUSTOMER_ACCOUNT_HANDOFF_PATHS.has(pathname)\n );\n}\n\n/**\n * Allowlisted `.well-known` resources proxied to the Online Store origin:\n * - `apple-developer-merchantid-domain-association` — Apple Pay domain verification.\n * - `shopify/fec/produce` — Frontend Event Collector ingress. On the Online\n * Store the myshopify.com edge forwards this first-party path to the\n * collector; headless storefronts have no such edge, so Hydrogen proxies it\n * to the same origin (used by WebMCP's Event Refinery client).\n */\nexport const WELL_KNOWN_RE =\n /^\\/\\.well-known\\/(?:apple-developer-merchantid-domain-association|shopify\\/fec\\/produce)$/;\nexport const AJAX_CART_RE =\n /^(?:\\/[a-z]{2}(?:-[a-z]{2})?)?\\/cart(?:\\.(?:js|json)|\\/(?:add|update|change|clear)(?:\\.(?:js|json))?)$/i;\n\n/**\n * Normalizes `target` to a path on `origin` that is safe to use as a redirect location.\n * Returns `undefined` unless `target` is a path starting with `/` or an absolute URL,\n * stays on `origin`, and its normalized pathname does not start with `//`.\n */\nexport function getSameOriginPath(\n target: string | null | undefined,\n origin: string,\n): string | undefined {\n if (!target) return undefined;\n\n try {\n // Parse absolute URLs without a base so scheme-relative forms like `https:evil.example`\n // resolve to their own host, as a browser would, instead of onto `origin`.\n const url = target.startsWith(\"/\") ? new URL(target, origin) : new URL(target);\n if (url.origin !== origin) return undefined;\n const path = `${url.pathname}${url.search}${url.hash}`;\n // The parsed pathname can itself start with `//` (e.g. from `/x/..//evil`),\n // which a redirect would resolve as a protocol-relative URL to another host.\n return path.startsWith(\"//\") ? undefined : path;\n } catch {\n return undefined;\n }\n}\n\nexport function normalizeStoreDomain(domain: string): string {\n if (!domain) {\n throw new Error(\"Storefront `storeDomain` is required.\");\n }\n\n if (domain.startsWith(\"http://\") || domain.startsWith(\"https://\")) {\n return domain.replace(/\\/+$/, \"\");\n }\n return `https://${domain}`.replace(/\\/+$/, \"\");\n}\n"],"mappings":";AAAA,MAAa,WAAW;AACxB,MAAa,2BAA2B;AACxC,MAAa,uBAAuB;AACpC,MAAa,SAAS;AACtB,MAAa,aAAa;AAC1B,MAAa,cAAc;AAC3B,MAAa,oBAAoB;AACjC,MAAM,gBAAgB,OAAO,GAAG;AAEhC,MAAa,mBAAmB,IAAI,OAAO,SAAS,cAAc,MAAM,cAAc,KAAK;AAC3F,MAAa,yBAAyB;CACpC,WAAW;CACX,OAAO;CACP,QAAQ;CACR,SAAS;CACV;AAED,MAAM,iCAAsD,IAAI,IAC9D,OAAO,OAAO,uBAAuB,CACtC;;;;;;;AAQD,SAAgB,4BAA4B,UAA2B;AACrE,QACE,YAAY,KAAK,SAAS,IAC1B,kBAAkB,KAAK,SAAS,IAChC,iBAAiB,KAAK,SAAS,IAC/B,+BAA+B,IAAI,SAAS;;;;;;;;;;AAYhD,MAAa,gBACX;AACF,MAAa,eACX;;;;;;AAOF,SAAgB,kBACd,QACA,QACoB;AACpB,KAAI,CAAC,OAAQ,QAAO;AAEpB,KAAI;EAGF,MAAM,MAAM,OAAO,WAAW,IAAI,GAAG,IAAI,IAAI,QAAQ,OAAO,GAAG,IAAI,IAAI,OAAO;AAC9E,MAAI,IAAI,WAAW,OAAQ,QAAO;EAClC,MAAM,OAAO,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI;AAGhD,SAAO,KAAK,WAAW,KAAK,GAAG,SAAY;SACrC;AACN;;;AAIJ,SAAgB,qBAAqB,QAAwB;AAC3D,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,wCAAwC;AAG1D,KAAI,OAAO,WAAW,UAAU,IAAI,OAAO,WAAW,WAAW,CAC/D,QAAO,OAAO,QAAQ,QAAQ,GAAG;AAEnC,QAAO,WAAW,SAAS,QAAQ,QAAQ,GAAG"}
|
|
@@ -3,16 +3,53 @@ import { GraphQLFormattedError } from "../client/types.mjs";
|
|
|
3
3
|
import { AnyCustomerAccountDocument, CustomerAccountDocument } from "./graphql.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/customer-account/client.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Options for {@link createCustomerAccountClient}.
|
|
8
|
+
*
|
|
9
|
+
* The client validates `shopId`, `customerApiVersion`, and `defaultTimeoutInMs`
|
|
10
|
+
* at construction time and throws synchronously on invalid values.
|
|
11
|
+
*/
|
|
6
12
|
type CreateCustomerAccountClientOptions = {
|
|
7
|
-
shopId: string;
|
|
13
|
+
/** Numeric Shopify shop ID as a string (e.g. `"12345"`). Validated against `/^\d+$/`. */shopId: string;
|
|
14
|
+
/**
|
|
15
|
+
* Customer Account API version in `YYYY-MM` format.
|
|
16
|
+
* Defaults to {@link CUSTOMER_ACCOUNT_API_VERSION}.
|
|
17
|
+
*/
|
|
8
18
|
customerApiVersion?: string;
|
|
9
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Request-scoped context created by `createShopifyRequestContext`. Must
|
|
21
|
+
* have a `url` property (throws at construction when missing or non-HTTPS;
|
|
22
|
+
* `http://localhost`, `127.0.0.1` and `::1` are accepted and sent as
|
|
23
|
+
* HTTPS). Supplies the i18n language for automatic `$language` variable
|
|
24
|
+
* injection, an abort signal that propagates request cancellation, and a
|
|
25
|
+
* personalization marker (sets `private, no-store` and removes CDN cache
|
|
26
|
+
* headers).
|
|
27
|
+
*/
|
|
28
|
+
requestContext: ShopifyRequestContext; /** Custom `fetch` implementation. Falls back to `globalThis.fetch`. */
|
|
10
29
|
fetch?: typeof globalThis.fetch;
|
|
30
|
+
/**
|
|
31
|
+
* Per-request timeout in milliseconds. Must be a positive safe integer no
|
|
32
|
+
* greater than 2,147,483,647. Defaults to 30,000 ms.
|
|
33
|
+
*/
|
|
11
34
|
defaultTimeoutInMs?: number;
|
|
12
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Per-call options passed to {@link CustomerAccountClient.graphql}.
|
|
38
|
+
* See `variables` for automatic `$language` injection.
|
|
39
|
+
*/
|
|
13
40
|
type CustomerAccountGraphqlOptions<Variables = Record<string, unknown>> = {
|
|
14
|
-
accessToken: string;
|
|
41
|
+
/** Customer Account API access token, e.g. from `CustomerSession.getAccessToken()` or `getOrRefreshAccessToken()`. */accessToken: string;
|
|
42
|
+
/**
|
|
43
|
+
* Query variables. When the GraphQL document declares a `$language` variable
|
|
44
|
+
* and you omit it here, the client injects it automatically from
|
|
45
|
+
* `requestContext.i18n.language`.
|
|
46
|
+
*/
|
|
15
47
|
variables?: Variables;
|
|
48
|
+
/**
|
|
49
|
+
* Optional abort signal. Combined with the request context signal and the
|
|
50
|
+
* per-request timeout signal via `AbortSignal.any`, so cancellation from any
|
|
51
|
+
* source stops the request.
|
|
52
|
+
*/
|
|
16
53
|
signal?: AbortSignal;
|
|
17
54
|
};
|
|
18
55
|
type ResultOfDoc<Doc> = Doc extends CustomerAccountDocument<infer Result, never, string> ? Result : never;
|
|
@@ -22,6 +59,18 @@ type OptionalAutoVariables<Variables> = "language" extends keyof Variables ? {
|
|
|
22
59
|
} : {};
|
|
23
60
|
type UserVariables<Doc> = Omit<VariablesOfDoc<Doc>, "language"> & OptionalAutoVariables<VariablesOfDoc<Doc>>;
|
|
24
61
|
type HasNoRequiredKeys<T> = Record<string, never> extends T ? true : false;
|
|
62
|
+
/**
|
|
63
|
+
* Discriminated union returned by {@link CustomerAccountClient.graphql}.
|
|
64
|
+
*
|
|
65
|
+
* Discriminate on the presence of `errors`, not via `Partial`:
|
|
66
|
+
*
|
|
67
|
+
* - **Success:** `data` is always present, `errors` is `undefined`.
|
|
68
|
+
* - **Partial or error:** `errors` is a non-empty array of
|
|
69
|
+
* {@link GraphQLFormattedError}, and `data` may be `null`.
|
|
70
|
+
*
|
|
71
|
+
* Both arms expose the raw response `headers` for inspecting
|
|
72
|
+
* `x-request-id` or rate-limit metadata.
|
|
73
|
+
*/
|
|
25
74
|
type CustomerAccountGraphqlResult<Result = unknown> = {
|
|
26
75
|
data: Result;
|
|
27
76
|
errors?: undefined;
|
|
@@ -31,13 +80,88 @@ type CustomerAccountGraphqlResult<Result = unknown> = {
|
|
|
31
80
|
errors: GraphQLFormattedError[];
|
|
32
81
|
headers: Headers;
|
|
33
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* Conditional rest parameter for {@link CustomerAccountClient.graphql}.
|
|
85
|
+
*
|
|
86
|
+
* When the document has no required user variables (after `language` is
|
|
87
|
+
* excluded from the requirement), `options.variables` is optional. When the
|
|
88
|
+
* document declares required variables, the type forces the caller to supply
|
|
89
|
+
* them, turning a missing-variables bug into a compile error.
|
|
90
|
+
*/
|
|
34
91
|
type CustomerAccountGqlRestParam<Doc extends AnyCustomerAccountDocument> = HasNoRequiredKeys<UserVariables<Doc>> extends true ? [options: CustomerAccountGraphqlOptions<UserVariables<Doc>>] : [options: CustomerAccountGraphqlOptions<UserVariables<Doc>> & {
|
|
35
92
|
variables: UserVariables<Doc>;
|
|
36
93
|
}];
|
|
94
|
+
/**
|
|
95
|
+
* A server-side GraphQL client for the Shopify Customer Account API.
|
|
96
|
+
*
|
|
97
|
+
* Created by {@link createCustomerAccountClient}. Each call to `graphql()`
|
|
98
|
+
* validates that the document was produced by `gql()` (runtime branded with a
|
|
99
|
+
* private Symbol), validates the access token, auto-injects the `language`
|
|
100
|
+
* variable from i18n context when applicable, and marks the response as
|
|
101
|
+
* personalized so the app response is sent with private, no-store cache headers.
|
|
102
|
+
*/
|
|
37
103
|
type CustomerAccountClient = {
|
|
38
|
-
readonly apiUrl: string;
|
|
104
|
+
/** Constructed endpoint: `https://shopify.com/{shopId}/account/customer/api/{version}/graphql`. */readonly apiUrl: string;
|
|
105
|
+
/**
|
|
106
|
+
* Send a GraphQL request to the Customer Account API.
|
|
107
|
+
*
|
|
108
|
+
* The document must be created by `gql()`. At call time the client:
|
|
109
|
+
* 1. Validates the document brand and options object.
|
|
110
|
+
* 2. Marks the response as personalized (sets `private, no-store`).
|
|
111
|
+
* 3. Validates the access token.
|
|
112
|
+
* 4. Throws if a signal is already aborted.
|
|
113
|
+
* 5. Combines the request context signal, the caller's signal, and a timeout
|
|
114
|
+
* signal via `AbortSignal.any`.
|
|
115
|
+
* 6. Auto-injects the `language` variable from `requestContext.i18n.language`
|
|
116
|
+
* when the document declares `$language` and the caller omits it.
|
|
117
|
+
*
|
|
118
|
+
* @throws {TypeError} When the document is not a branded `gql()` result.
|
|
119
|
+
* @throws {CustomerAccountAuthenticationError} When the access token fails pre-flight validation.
|
|
120
|
+
* @throws {CustomerAccountTimeoutError} When the request exceeds `defaultTimeoutInMs`.
|
|
121
|
+
* @throws {CustomerAccountApiError} On non-OK HTTP status, unparseable JSON, or missing `data`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const result = await client.graphql(
|
|
126
|
+
* gql(`query { customer { firstName lastName } }`),
|
|
127
|
+
* { accessToken },
|
|
128
|
+
* );
|
|
129
|
+
*
|
|
130
|
+
* if (result.errors) {
|
|
131
|
+
* console.error(result.errors);
|
|
132
|
+
* } else {
|
|
133
|
+
* console.log(result.data.customer.firstName);
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
39
137
|
graphql: <const Doc extends AnyCustomerAccountDocument>(document: Doc, ...options: CustomerAccountGqlRestParam<Doc>) => Promise<CustomerAccountGraphqlResult<ResultOfDoc<Doc>>>;
|
|
40
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Creates a server-only {@link CustomerAccountClient} for the Shopify Customer
|
|
141
|
+
* Account API.
|
|
142
|
+
*
|
|
143
|
+
* Validates `shopId`, `customerApiVersion`, and `defaultTimeoutInMs` at
|
|
144
|
+
* construction time. The returned client auto-injects the `language` variable
|
|
145
|
+
* from `requestContext.i18n.language` when applicable, composes abort signals,
|
|
146
|
+
* and marks responses as personalized (sets `private, no-store` cache headers).
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* import { createCustomerAccountClient, gql } from "@shopify/hydrogen/customer-account";
|
|
151
|
+
*
|
|
152
|
+
* const customerAccount = createCustomerAccountClient({
|
|
153
|
+
* shopId: "12345",
|
|
154
|
+
* requestContext,
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* const { data } = await customerAccount.graphql(
|
|
158
|
+
* gql(`query { customer { firstName } }`),
|
|
159
|
+
* { accessToken },
|
|
160
|
+
* );
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @throws {Error} When called in a browser context, when `shopId`, `customerApiVersion`, or `defaultTimeoutInMs` is invalid, when no `fetch` is available, or when `requestContext.url` is missing or not HTTPS.
|
|
164
|
+
*/
|
|
41
165
|
declare function createCustomerAccountClient({
|
|
42
166
|
shopId,
|
|
43
167
|
customerApiVersion,
|
|
@@ -15,8 +15,34 @@ const LOCAL_ORIGIN_HOSTS = new Set([
|
|
|
15
15
|
"::1",
|
|
16
16
|
"[::1]"
|
|
17
17
|
]);
|
|
18
|
-
const USER_AGENT = `Hydrogen 2026.10.0-preview.
|
|
18
|
+
const USER_AGENT = `Hydrogen 2026.10.0-preview.4`;
|
|
19
19
|
const CUSTOMER_ACCOUNT_GRAPHQL_PERSONALIZATION_REASON = "customer-account-graphql";
|
|
20
|
+
/**
|
|
21
|
+
* Creates a server-only {@link CustomerAccountClient} for the Shopify Customer
|
|
22
|
+
* Account API.
|
|
23
|
+
*
|
|
24
|
+
* Validates `shopId`, `customerApiVersion`, and `defaultTimeoutInMs` at
|
|
25
|
+
* construction time. The returned client auto-injects the `language` variable
|
|
26
|
+
* from `requestContext.i18n.language` when applicable, composes abort signals,
|
|
27
|
+
* and marks responses as personalized (sets `private, no-store` cache headers).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { createCustomerAccountClient, gql } from "@shopify/hydrogen/customer-account";
|
|
32
|
+
*
|
|
33
|
+
* const customerAccount = createCustomerAccountClient({
|
|
34
|
+
* shopId: "12345",
|
|
35
|
+
* requestContext,
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* const { data } = await customerAccount.graphql(
|
|
39
|
+
* gql(`query { customer { firstName } }`),
|
|
40
|
+
* { accessToken },
|
|
41
|
+
* );
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @throws {Error} When called in a browser context, when `shopId`, `customerApiVersion`, or `defaultTimeoutInMs` is invalid, when no `fetch` is available, or when `requestContext.url` is missing or not HTTPS.
|
|
45
|
+
*/
|
|
20
46
|
function createCustomerAccountClient({ shopId, customerApiVersion = CUSTOMER_ACCOUNT_API_VERSION, requestContext, fetch: customFetch, defaultTimeoutInMs = DEFAULT_TIMEOUT_IN_MS }) {
|
|
21
47
|
if (typeof document !== "undefined") throw new Error("Customer Account API tokens cannot be used in a browser context. Use this client from server or edge routes only.");
|
|
22
48
|
validateShopId(shopId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../../src/customer-account/client.ts"],"sourcesContent":["import type { GraphQLFormattedError } from \"../client/types\";\nimport { CUSTOMER_ACCOUNT_API_VERSION, DEFAULT_TIMEOUT_IN_MS } from \"../core/constants\";\nimport type { ShopifyRequestContext } from \"../core/request-context\";\nimport { isObjectRecord } from \"../core/utils/record\";\nimport {\n CustomerAccountApiError,\n CustomerAccountAuthenticationError,\n CustomerAccountTimeoutError,\n} from \"./errors\";\nimport {\n assertCustomerAccountDocument,\n type AnyCustomerAccountDocument,\n type CustomerAccountDocument,\n} from \"./graphql\";\n\nconst SHOP_ID_RE = /^\\d+$/;\nconst CUSTOMER_API_VERSION_RE = /^\\d{4}-\\d{2}$/;\nconst MAX_ASCII_CONTROL_CODE_POINT = 31;\nconst ASCII_DELETE_CODE_POINT = 127;\nconst MAX_SET_TIMEOUT_IN_MS = 2_147_483_647;\nconst LOCAL_ORIGIN_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\"]);\nconst USER_AGENT = `Hydrogen ${__HYDROGEN_VERSION__}`;\nconst CUSTOMER_ACCOUNT_GRAPHQL_PERSONALIZATION_REASON = \"customer-account-graphql\";\n\ntype AccessToken = string | null | undefined;\ntype FetchCustomerAccountGraphqlParams = {\n fetch: typeof globalThis.fetch;\n apiUrl: string;\n accessToken: string;\n origin: string;\n query: string;\n variables: Record<string, unknown>;\n signal: AbortSignal;\n timeoutSignal: AbortSignal;\n timeoutInMs: number;\n};\n\nexport type CreateCustomerAccountClientOptions = {\n shopId: string;\n customerApiVersion?: string;\n requestContext: ShopifyRequestContext;\n fetch?: typeof globalThis.fetch;\n defaultTimeoutInMs?: number;\n};\n\nexport type CustomerAccountGraphqlOptions<Variables = Record<string, unknown>> = {\n accessToken: string;\n variables?: Variables;\n signal?: AbortSignal;\n};\n\ntype ResultOfDoc<Doc> =\n Doc extends CustomerAccountDocument<infer Result, never, string> ? Result : never;\ntype VariablesOfDoc<Doc> =\n Doc extends CustomerAccountDocument<unknown, infer Variables, string> ? Variables : never;\ntype OptionalAutoVariables<Variables> = \"language\" extends keyof Variables\n ? { language?: Variables[\"language\"] }\n : {};\ntype UserVariables<Doc> = Omit<VariablesOfDoc<Doc>, \"language\"> &\n OptionalAutoVariables<VariablesOfDoc<Doc>>;\ntype HasNoRequiredKeys<T> = Record<string, never> extends T ? true : false;\n\nexport type CustomerAccountGraphqlResult<Result = unknown> =\n | { data: Result; errors?: undefined; headers: Headers }\n | { data: Result | null; errors: GraphQLFormattedError[]; headers: Headers };\n\nexport type CustomerAccountGqlRestParam<Doc extends AnyCustomerAccountDocument> =\n HasNoRequiredKeys<UserVariables<Doc>> extends true\n ? [options: CustomerAccountGraphqlOptions<UserVariables<Doc>>]\n : [\n options: CustomerAccountGraphqlOptions<UserVariables<Doc>> & {\n variables: UserVariables<Doc>;\n },\n ];\n\nexport type CustomerAccountClient = {\n readonly apiUrl: string;\n graphql: <const Doc extends AnyCustomerAccountDocument>(\n document: Doc,\n ...options: CustomerAccountGqlRestParam<Doc>\n ) => Promise<CustomerAccountGraphqlResult<ResultOfDoc<Doc>>>;\n};\n\nexport function createCustomerAccountClient({\n shopId,\n customerApiVersion = CUSTOMER_ACCOUNT_API_VERSION,\n requestContext,\n fetch: customFetch,\n defaultTimeoutInMs = DEFAULT_TIMEOUT_IN_MS,\n}: CreateCustomerAccountClientOptions): CustomerAccountClient {\n if (typeof document !== \"undefined\") {\n throw new Error(\n \"Customer Account API tokens cannot be used in a browser context. Use this client from server or edge routes only.\",\n );\n }\n\n validateShopId(shopId);\n validateCustomerApiVersion(customerApiVersion);\n validateTimeout(defaultTimeoutInMs);\n\n const resolvedFetch = customFetch ?? globalThis.fetch;\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 origin = getOrigin(requestContext.url);\n const apiUrl = `https://shopify.com/${shopId}/account/customer/api/${customerApiVersion}/graphql`;\n\n async function graphql<const Doc extends AnyCustomerAccountDocument>(\n document: Doc,\n ...rest: CustomerAccountGqlRestParam<Doc>\n ): Promise<CustomerAccountGraphqlResult<ResultOfDoc<Doc>>>;\n async function graphql(\n document: AnyCustomerAccountDocument,\n ...rest: [options?: CustomerAccountGraphqlOptions<unknown>]\n ): Promise<CustomerAccountGraphqlResult<unknown>> {\n assertCustomerAccountDocument(document);\n const options = validateGraphqlOptions(rest[0]);\n requestContext.markResponseAsPersonalized(CUSTOMER_ACCOUNT_GRAPHQL_PERSONALIZATION_REASON);\n const accessToken = validateAccessToken(options.accessToken);\n const externalSignals = [requestContext.signal, options.signal].filter(\n (signal): signal is AbortSignal => Boolean(signal),\n );\n throwIfAlreadyAborted(externalSignals);\n\n const { signal: timeoutSignal, cleanup: cleanupTimeout } =\n createCustomerAccountTimeoutSignal(defaultTimeoutInMs);\n externalSignals.push(timeoutSignal);\n const signal = AbortSignal.any(externalSignals);\n\n try {\n const variables = getVariables(\n document,\n getOptionalVariables(options.variables),\n requestContext.i18n.language,\n );\n const response = await fetchCustomerAccountGraphql({\n fetch: resolvedFetch,\n apiUrl,\n accessToken,\n origin,\n query: document.source,\n variables,\n signal,\n timeoutSignal,\n timeoutInMs: defaultTimeoutInMs,\n });\n\n return await readCustomerAccountGraphqlResponse(\n response,\n signal,\n timeoutSignal,\n defaultTimeoutInMs,\n );\n } finally {\n cleanupTimeout();\n }\n }\n\n return { apiUrl, graphql };\n}\n\nasync function fetchCustomerAccountGraphql({\n fetch,\n apiUrl,\n accessToken,\n origin,\n query,\n variables,\n signal,\n timeoutSignal,\n timeoutInMs,\n}: FetchCustomerAccountGraphqlParams): Promise<Response> {\n try {\n return await withAbort(\n fetch(apiUrl, {\n method: \"POST\",\n headers: new Headers({\n Authorization: accessToken,\n \"Content-Type\": \"application/json\",\n Origin: origin,\n \"User-Agent\": USER_AGENT,\n }),\n body: JSON.stringify({ query, variables }),\n cache: \"no-store\",\n redirect: \"manual\",\n signal,\n }),\n signal,\n );\n } catch (cause) {\n throwIfCustomerAccountSignalAborted(signal, timeoutSignal, timeoutInMs);\n if (isAbortError(cause)) throw cause;\n throw new CustomerAccountApiError(\"Customer Account API request failed\", { cause });\n }\n}\n\nasync function readCustomerAccountGraphqlResponse(\n response: Response,\n signal: AbortSignal,\n timeoutSignal: AbortSignal,\n timeoutInMs: number,\n): Promise<CustomerAccountGraphqlResult<unknown>> {\n const requestId = response.headers.get(\"x-request-id\") ?? undefined;\n if (!response.ok) {\n cancelResponseBody(response);\n throw new CustomerAccountApiError(`Customer Account API responded with ${response.status}`, {\n status: response.status,\n requestId,\n retryAfter: response.headers.get(\"retry-after\") ?? undefined,\n });\n }\n\n let body: { data?: unknown; errors?: GraphQLFormattedError[] };\n try {\n body = parseGraphqlResponse(await withAbort(response.json(), signal));\n } catch (cause) {\n cancelResponseBody(response);\n\n throwIfCustomerAccountSignalAborted(signal, timeoutSignal, timeoutInMs);\n if (isAbortError(cause)) throw cause;\n throw new CustomerAccountApiError(\"Failed to parse Customer Account API response as JSON\", {\n status: response.status,\n requestId,\n cause,\n });\n }\n\n if (body.errors) {\n return { data: body.data ?? null, errors: body.errors, headers: response.headers };\n }\n\n if (body.data == null) {\n throw new CustomerAccountApiError(\"Customer Account API response did not include data\", {\n status: response.status,\n requestId,\n });\n }\n\n return { data: body.data, headers: response.headers };\n}\n\nfunction cancelResponseBody(response: Response): void {\n try {\n void response.body?.cancel().catch(() => undefined);\n } catch {}\n}\n\nfunction validateTimeout(timeoutInMs: number): void {\n if (\n !Number.isSafeInteger(timeoutInMs) ||\n timeoutInMs <= 0 ||\n timeoutInMs > MAX_SET_TIMEOUT_IN_MS\n ) {\n throw new Error(\n `defaultTimeoutInMs must be a positive safe integer no greater than ${MAX_SET_TIMEOUT_IN_MS}`,\n );\n }\n}\n\nfunction createCustomerAccountTimeoutSignal(timeoutInMs: number): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort(new CustomerAccountTimeoutError(timeoutInMs));\n }, timeoutInMs);\n\n return { signal: controller.signal, cleanup: () => clearTimeout(timeoutId) };\n}\n\nfunction withAbort<T>(promise: T | Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return Promise.resolve(promise);\n if (signal.aborted) {\n return Promise.reject(\n signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\"),\n );\n }\n\n return new Promise<T>((resolve, reject) => {\n const abort = () => {\n signal.removeEventListener(\"abort\", abort);\n const reason =\n signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n reject(reason);\n };\n signal.addEventListener(\"abort\", abort, { once: true });\n Promise.resolve(promise).then(\n (value) => {\n signal.removeEventListener(\"abort\", abort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", abort);\n reject(error);\n },\n );\n });\n}\n\nfunction getVariables(\n document: { variableNames: ReadonlySet<string> },\n variables: Record<string, unknown>,\n language: ShopifyRequestContext[\"i18n\"][\"language\"],\n): Record<string, unknown> {\n if (!document.variableNames.has(\"language\")) return variables;\n if (\"language\" in variables) return variables;\n return { ...variables, language };\n}\n\nfunction throwIfAlreadyAborted(signals: AbortSignal[]): void {\n const abortedSignal = signals.find((signal) => signal.aborted);\n if (!abortedSignal) return;\n throw abortedSignal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n}\n\nfunction throwIfCustomerAccountSignalAborted(\n signal: AbortSignal,\n timeoutSignal: AbortSignal,\n timeoutInMs: number,\n): void {\n if (!signal.aborted) return;\n if (timeoutSignal.aborted && signal.reason === timeoutSignal.reason) {\n const reason = timeoutSignal.reason;\n throw reason instanceof CustomerAccountTimeoutError\n ? reason\n : new CustomerAccountTimeoutError(timeoutInMs);\n }\n throw signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n}\n\nfunction isAbortError(cause: unknown): cause is DOMException {\n return cause instanceof DOMException && cause.name === \"AbortError\";\n}\n\nfunction parseGraphqlResponse(json: unknown): {\n data?: unknown;\n errors?: GraphQLFormattedError[];\n} {\n if (!isObjectRecord(json)) {\n throw new Error(\"Customer Account API returned unexpected JSON type\");\n }\n\n if (!(\"data\" in json) && !(\"errors\" in json)) {\n throw new Error(\"Customer Account API response must include data or errors\");\n }\n const errors = json.errors;\n if (errors !== undefined && !isGraphqlErrorArray(errors)) {\n throw new Error(\"Customer Account API returned invalid GraphQL errors\");\n }\n return { data: json.data, errors };\n}\n\nfunction isGraphqlErrorArray(value: unknown): value is GraphQLFormattedError[] {\n if (!Array.isArray(value)) return false;\n return value.every((error) => {\n return typeof error === \"object\" && error !== null && typeof error.message === \"string\";\n });\n}\n\nfunction validateShopId(shopId: string): void {\n if (!SHOP_ID_RE.test(shopId)) {\n throw new Error(\"shopId must be a numeric Shopify shop ID string\");\n }\n}\n\nfunction validateCustomerApiVersion(customerApiVersion: string): void {\n if (!CUSTOMER_API_VERSION_RE.test(customerApiVersion)) {\n throw new Error(\"customerApiVersion must use YYYY-MM format\");\n }\n}\n\nfunction validateAccessToken(accessToken: AccessToken): string {\n if (\n typeof accessToken !== \"string\" ||\n accessToken === \"\" ||\n accessToken.trim() !== accessToken ||\n hasAsciiControlCharacter(accessToken)\n ) {\n throw new CustomerAccountAuthenticationError();\n }\n return accessToken;\n}\n\nfunction validateGraphqlOptions(\n options: CustomerAccountGraphqlOptions<unknown> | undefined,\n): CustomerAccountGraphqlOptions<unknown> {\n if (typeof options !== \"object\" || options === null) {\n throw new CustomerAccountAuthenticationError();\n }\n return options;\n}\n\nfunction getOptionalVariables(variables: unknown): Record<string, unknown> {\n if (variables === undefined) return {};\n if (!isObjectRecord(variables)) {\n throw new TypeError(\"Customer Account API variables must be an object\");\n }\n return variables;\n}\n\nfunction hasAsciiControlCharacter(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n const codePoint = value.charCodeAt(index);\n if (codePoint <= MAX_ASCII_CONTROL_CODE_POINT || codePoint === ASCII_DELETE_CODE_POINT) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Customer Account API requires an HTTPS Origin, but local dev frameworks often\n * receive `http://localhost` requests. Keep that local-only exception without\n * weakening origin validation for non-local requests.\n */\nfunction getOrigin(requestUrl: string | undefined): string {\n if (!requestUrl) {\n throw new Error(\"requestContext.url is required for Customer Account API requests\");\n }\n\n const url = new URL(requestUrl);\n if (url.protocol === \"https:\") return url.origin;\n if (url.protocol === \"http:\" && LOCAL_ORIGIN_HOSTS.has(url.hostname)) {\n return `https://${url.host}`;\n }\n throw new Error(`Customer Account API origin must use HTTPS. Received: ${requestUrl}`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../../src/customer-account/client.ts"],"sourcesContent":["import type { GraphQLFormattedError } from \"../client/types\";\nimport { CUSTOMER_ACCOUNT_API_VERSION, DEFAULT_TIMEOUT_IN_MS } from \"../core/constants\";\nimport type { ShopifyRequestContext } from \"../core/request-context\";\nimport { isObjectRecord } from \"../core/utils/record\";\nimport {\n CustomerAccountApiError,\n CustomerAccountAuthenticationError,\n CustomerAccountTimeoutError,\n} from \"./errors\";\nimport {\n assertCustomerAccountDocument,\n type AnyCustomerAccountDocument,\n type CustomerAccountDocument,\n} from \"./graphql\";\n\nconst SHOP_ID_RE = /^\\d+$/;\nconst CUSTOMER_API_VERSION_RE = /^\\d{4}-\\d{2}$/;\nconst MAX_ASCII_CONTROL_CODE_POINT = 31;\nconst ASCII_DELETE_CODE_POINT = 127;\nconst MAX_SET_TIMEOUT_IN_MS = 2_147_483_647;\nconst LOCAL_ORIGIN_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\"]);\nconst USER_AGENT = `Hydrogen ${__HYDROGEN_VERSION__}`;\nconst CUSTOMER_ACCOUNT_GRAPHQL_PERSONALIZATION_REASON = \"customer-account-graphql\";\n\ntype AccessToken = string | null | undefined;\ntype FetchCustomerAccountGraphqlParams = {\n fetch: typeof globalThis.fetch;\n apiUrl: string;\n accessToken: string;\n origin: string;\n query: string;\n variables: Record<string, unknown>;\n signal: AbortSignal;\n timeoutSignal: AbortSignal;\n timeoutInMs: number;\n};\n\n/**\n * Options for {@link createCustomerAccountClient}.\n *\n * The client validates `shopId`, `customerApiVersion`, and `defaultTimeoutInMs`\n * at construction time and throws synchronously on invalid values.\n */\nexport type CreateCustomerAccountClientOptions = {\n /** Numeric Shopify shop ID as a string (e.g. `\"12345\"`). Validated against `/^\\d+$/`. */\n shopId: string;\n /**\n * Customer Account API version in `YYYY-MM` format.\n * Defaults to {@link CUSTOMER_ACCOUNT_API_VERSION}.\n */\n customerApiVersion?: string;\n /**\n * Request-scoped context created by `createShopifyRequestContext`. Must\n * have a `url` property (throws at construction when missing or non-HTTPS;\n * `http://localhost`, `127.0.0.1` and `::1` are accepted and sent as\n * HTTPS). Supplies the i18n language for automatic `$language` variable\n * injection, an abort signal that propagates request cancellation, and a\n * personalization marker (sets `private, no-store` and removes CDN cache\n * headers).\n */\n requestContext: ShopifyRequestContext;\n /** Custom `fetch` implementation. Falls back to `globalThis.fetch`. */\n fetch?: typeof globalThis.fetch;\n /**\n * Per-request timeout in milliseconds. Must be a positive safe integer no\n * greater than 2,147,483,647. Defaults to 30,000 ms.\n */\n defaultTimeoutInMs?: number;\n};\n\n/**\n * Per-call options passed to {@link CustomerAccountClient.graphql}.\n * See `variables` for automatic `$language` injection.\n */\nexport type CustomerAccountGraphqlOptions<Variables = Record<string, unknown>> = {\n /** Customer Account API access token, e.g. from `CustomerSession.getAccessToken()` or `getOrRefreshAccessToken()`. */\n accessToken: string;\n /**\n * Query variables. When the GraphQL document declares a `$language` variable\n * and you omit it here, the client injects it automatically from\n * `requestContext.i18n.language`.\n */\n variables?: Variables;\n /**\n * Optional abort signal. Combined with the request context signal and the\n * per-request timeout signal via `AbortSignal.any`, so cancellation from any\n * source stops the request.\n */\n signal?: AbortSignal;\n};\n\ntype ResultOfDoc<Doc> =\n Doc extends CustomerAccountDocument<infer Result, never, string> ? Result : never;\ntype VariablesOfDoc<Doc> =\n Doc extends CustomerAccountDocument<unknown, infer Variables, string> ? Variables : never;\ntype OptionalAutoVariables<Variables> = \"language\" extends keyof Variables\n ? { language?: Variables[\"language\"] }\n : {};\ntype UserVariables<Doc> = Omit<VariablesOfDoc<Doc>, \"language\"> &\n OptionalAutoVariables<VariablesOfDoc<Doc>>;\ntype HasNoRequiredKeys<T> = Record<string, never> extends T ? true : false;\n\n/**\n * Discriminated union returned by {@link CustomerAccountClient.graphql}.\n *\n * Discriminate on the presence of `errors`, not via `Partial`:\n *\n * - **Success:** `data` is always present, `errors` is `undefined`.\n * - **Partial or error:** `errors` is a non-empty array of\n * {@link GraphQLFormattedError}, and `data` may be `null`.\n *\n * Both arms expose the raw response `headers` for inspecting\n * `x-request-id` or rate-limit metadata.\n */\nexport type CustomerAccountGraphqlResult<Result = unknown> =\n | { data: Result; errors?: undefined; headers: Headers }\n | { data: Result | null; errors: GraphQLFormattedError[]; headers: Headers };\n\n/**\n * Conditional rest parameter for {@link CustomerAccountClient.graphql}.\n *\n * When the document has no required user variables (after `language` is\n * excluded from the requirement), `options.variables` is optional. When the\n * document declares required variables, the type forces the caller to supply\n * them, turning a missing-variables bug into a compile error.\n */\nexport type CustomerAccountGqlRestParam<Doc extends AnyCustomerAccountDocument> =\n HasNoRequiredKeys<UserVariables<Doc>> extends true\n ? [options: CustomerAccountGraphqlOptions<UserVariables<Doc>>]\n : [\n options: CustomerAccountGraphqlOptions<UserVariables<Doc>> & {\n variables: UserVariables<Doc>;\n },\n ];\n\n/**\n * A server-side GraphQL client for the Shopify Customer Account API.\n *\n * Created by {@link createCustomerAccountClient}. Each call to `graphql()`\n * validates that the document was produced by `gql()` (runtime branded with a\n * private Symbol), validates the access token, auto-injects the `language`\n * variable from i18n context when applicable, and marks the response as\n * personalized so the app response is sent with private, no-store cache headers.\n */\nexport type CustomerAccountClient = {\n /** Constructed endpoint: `https://shopify.com/{shopId}/account/customer/api/{version}/graphql`. */\n readonly apiUrl: string;\n /**\n * Send a GraphQL request to the Customer Account API.\n *\n * The document must be created by `gql()`. At call time the client:\n * 1. Validates the document brand and options object.\n * 2. Marks the response as personalized (sets `private, no-store`).\n * 3. Validates the access token.\n * 4. Throws if a signal is already aborted.\n * 5. Combines the request context signal, the caller's signal, and a timeout\n * signal via `AbortSignal.any`.\n * 6. Auto-injects the `language` variable from `requestContext.i18n.language`\n * when the document declares `$language` and the caller omits it.\n *\n * @throws {TypeError} When the document is not a branded `gql()` result.\n * @throws {CustomerAccountAuthenticationError} When the access token fails pre-flight validation.\n * @throws {CustomerAccountTimeoutError} When the request exceeds `defaultTimeoutInMs`.\n * @throws {CustomerAccountApiError} On non-OK HTTP status, unparseable JSON, or missing `data`.\n *\n * @example\n * ```ts\n * const result = await client.graphql(\n * gql(`query { customer { firstName lastName } }`),\n * { accessToken },\n * );\n *\n * if (result.errors) {\n * console.error(result.errors);\n * } else {\n * console.log(result.data.customer.firstName);\n * }\n * ```\n */\n graphql: <const Doc extends AnyCustomerAccountDocument>(\n document: Doc,\n ...options: CustomerAccountGqlRestParam<Doc>\n ) => Promise<CustomerAccountGraphqlResult<ResultOfDoc<Doc>>>;\n};\n\n/**\n * Creates a server-only {@link CustomerAccountClient} for the Shopify Customer\n * Account API.\n *\n * Validates `shopId`, `customerApiVersion`, and `defaultTimeoutInMs` at\n * construction time. The returned client auto-injects the `language` variable\n * from `requestContext.i18n.language` when applicable, composes abort signals,\n * and marks responses as personalized (sets `private, no-store` cache headers).\n *\n * @example\n * ```ts\n * import { createCustomerAccountClient, gql } from \"@shopify/hydrogen/customer-account\";\n *\n * const customerAccount = createCustomerAccountClient({\n * shopId: \"12345\",\n * requestContext,\n * });\n *\n * const { data } = await customerAccount.graphql(\n * gql(`query { customer { firstName } }`),\n * { accessToken },\n * );\n * ```\n *\n * @throws {Error} When called in a browser context, when `shopId`, `customerApiVersion`, or `defaultTimeoutInMs` is invalid, when no `fetch` is available, or when `requestContext.url` is missing or not HTTPS.\n */\nexport function createCustomerAccountClient({\n shopId,\n customerApiVersion = CUSTOMER_ACCOUNT_API_VERSION,\n requestContext,\n fetch: customFetch,\n defaultTimeoutInMs = DEFAULT_TIMEOUT_IN_MS,\n}: CreateCustomerAccountClientOptions): CustomerAccountClient {\n if (typeof document !== \"undefined\") {\n throw new Error(\n \"Customer Account API tokens cannot be used in a browser context. Use this client from server or edge routes only.\",\n );\n }\n\n validateShopId(shopId);\n validateCustomerApiVersion(customerApiVersion);\n validateTimeout(defaultTimeoutInMs);\n\n const resolvedFetch = customFetch ?? globalThis.fetch;\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 origin = getOrigin(requestContext.url);\n const apiUrl = `https://shopify.com/${shopId}/account/customer/api/${customerApiVersion}/graphql`;\n\n async function graphql<const Doc extends AnyCustomerAccountDocument>(\n document: Doc,\n ...rest: CustomerAccountGqlRestParam<Doc>\n ): Promise<CustomerAccountGraphqlResult<ResultOfDoc<Doc>>>;\n async function graphql(\n document: AnyCustomerAccountDocument,\n ...rest: [options?: CustomerAccountGraphqlOptions<unknown>]\n ): Promise<CustomerAccountGraphqlResult<unknown>> {\n assertCustomerAccountDocument(document);\n const options = validateGraphqlOptions(rest[0]);\n requestContext.markResponseAsPersonalized(CUSTOMER_ACCOUNT_GRAPHQL_PERSONALIZATION_REASON);\n const accessToken = validateAccessToken(options.accessToken);\n const externalSignals = [requestContext.signal, options.signal].filter(\n (signal): signal is AbortSignal => Boolean(signal),\n );\n throwIfAlreadyAborted(externalSignals);\n\n const { signal: timeoutSignal, cleanup: cleanupTimeout } =\n createCustomerAccountTimeoutSignal(defaultTimeoutInMs);\n externalSignals.push(timeoutSignal);\n const signal = AbortSignal.any(externalSignals);\n\n try {\n const variables = getVariables(\n document,\n getOptionalVariables(options.variables),\n requestContext.i18n.language,\n );\n const response = await fetchCustomerAccountGraphql({\n fetch: resolvedFetch,\n apiUrl,\n accessToken,\n origin,\n query: document.source,\n variables,\n signal,\n timeoutSignal,\n timeoutInMs: defaultTimeoutInMs,\n });\n\n return await readCustomerAccountGraphqlResponse(\n response,\n signal,\n timeoutSignal,\n defaultTimeoutInMs,\n );\n } finally {\n cleanupTimeout();\n }\n }\n\n return { apiUrl, graphql };\n}\n\nasync function fetchCustomerAccountGraphql({\n fetch,\n apiUrl,\n accessToken,\n origin,\n query,\n variables,\n signal,\n timeoutSignal,\n timeoutInMs,\n}: FetchCustomerAccountGraphqlParams): Promise<Response> {\n try {\n return await withAbort(\n fetch(apiUrl, {\n method: \"POST\",\n headers: new Headers({\n Authorization: accessToken,\n \"Content-Type\": \"application/json\",\n Origin: origin,\n \"User-Agent\": USER_AGENT,\n }),\n body: JSON.stringify({ query, variables }),\n cache: \"no-store\",\n redirect: \"manual\",\n signal,\n }),\n signal,\n );\n } catch (cause) {\n throwIfCustomerAccountSignalAborted(signal, timeoutSignal, timeoutInMs);\n if (isAbortError(cause)) throw cause;\n throw new CustomerAccountApiError(\"Customer Account API request failed\", { cause });\n }\n}\n\nasync function readCustomerAccountGraphqlResponse(\n response: Response,\n signal: AbortSignal,\n timeoutSignal: AbortSignal,\n timeoutInMs: number,\n): Promise<CustomerAccountGraphqlResult<unknown>> {\n const requestId = response.headers.get(\"x-request-id\") ?? undefined;\n if (!response.ok) {\n cancelResponseBody(response);\n throw new CustomerAccountApiError(`Customer Account API responded with ${response.status}`, {\n status: response.status,\n requestId,\n retryAfter: response.headers.get(\"retry-after\") ?? undefined,\n });\n }\n\n let body: { data?: unknown; errors?: GraphQLFormattedError[] };\n try {\n body = parseGraphqlResponse(await withAbort(response.json(), signal));\n } catch (cause) {\n cancelResponseBody(response);\n\n throwIfCustomerAccountSignalAborted(signal, timeoutSignal, timeoutInMs);\n if (isAbortError(cause)) throw cause;\n throw new CustomerAccountApiError(\"Failed to parse Customer Account API response as JSON\", {\n status: response.status,\n requestId,\n cause,\n });\n }\n\n if (body.errors) {\n return { data: body.data ?? null, errors: body.errors, headers: response.headers };\n }\n\n if (body.data == null) {\n throw new CustomerAccountApiError(\"Customer Account API response did not include data\", {\n status: response.status,\n requestId,\n });\n }\n\n return { data: body.data, headers: response.headers };\n}\n\nfunction cancelResponseBody(response: Response): void {\n try {\n void response.body?.cancel().catch(() => undefined);\n } catch {}\n}\n\nfunction validateTimeout(timeoutInMs: number): void {\n if (\n !Number.isSafeInteger(timeoutInMs) ||\n timeoutInMs <= 0 ||\n timeoutInMs > MAX_SET_TIMEOUT_IN_MS\n ) {\n throw new Error(\n `defaultTimeoutInMs must be a positive safe integer no greater than ${MAX_SET_TIMEOUT_IN_MS}`,\n );\n }\n}\n\nfunction createCustomerAccountTimeoutSignal(timeoutInMs: number): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort(new CustomerAccountTimeoutError(timeoutInMs));\n }, timeoutInMs);\n\n return { signal: controller.signal, cleanup: () => clearTimeout(timeoutId) };\n}\n\nfunction withAbort<T>(promise: T | Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return Promise.resolve(promise);\n if (signal.aborted) {\n return Promise.reject(\n signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\"),\n );\n }\n\n return new Promise<T>((resolve, reject) => {\n const abort = () => {\n signal.removeEventListener(\"abort\", abort);\n const reason =\n signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n reject(reason);\n };\n signal.addEventListener(\"abort\", abort, { once: true });\n Promise.resolve(promise).then(\n (value) => {\n signal.removeEventListener(\"abort\", abort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", abort);\n reject(error);\n },\n );\n });\n}\n\nfunction getVariables(\n document: { variableNames: ReadonlySet<string> },\n variables: Record<string, unknown>,\n language: ShopifyRequestContext[\"i18n\"][\"language\"],\n): Record<string, unknown> {\n if (!document.variableNames.has(\"language\")) return variables;\n if (\"language\" in variables) return variables;\n return { ...variables, language };\n}\n\nfunction throwIfAlreadyAborted(signals: AbortSignal[]): void {\n const abortedSignal = signals.find((signal) => signal.aborted);\n if (!abortedSignal) return;\n throw abortedSignal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n}\n\nfunction throwIfCustomerAccountSignalAborted(\n signal: AbortSignal,\n timeoutSignal: AbortSignal,\n timeoutInMs: number,\n): void {\n if (!signal.aborted) return;\n if (timeoutSignal.aborted && signal.reason === timeoutSignal.reason) {\n const reason = timeoutSignal.reason;\n throw reason instanceof CustomerAccountTimeoutError\n ? reason\n : new CustomerAccountTimeoutError(timeoutInMs);\n }\n throw signal.reason ?? new DOMException(\"signal is aborted without reason\", \"AbortError\");\n}\n\nfunction isAbortError(cause: unknown): cause is DOMException {\n return cause instanceof DOMException && cause.name === \"AbortError\";\n}\n\nfunction parseGraphqlResponse(json: unknown): {\n data?: unknown;\n errors?: GraphQLFormattedError[];\n} {\n if (!isObjectRecord(json)) {\n throw new Error(\"Customer Account API returned unexpected JSON type\");\n }\n\n if (!(\"data\" in json) && !(\"errors\" in json)) {\n throw new Error(\"Customer Account API response must include data or errors\");\n }\n const errors = json.errors;\n if (errors !== undefined && !isGraphqlErrorArray(errors)) {\n throw new Error(\"Customer Account API returned invalid GraphQL errors\");\n }\n return { data: json.data, errors };\n}\n\nfunction isGraphqlErrorArray(value: unknown): value is GraphQLFormattedError[] {\n if (!Array.isArray(value)) return false;\n return value.every((error) => {\n return typeof error === \"object\" && error !== null && typeof error.message === \"string\";\n });\n}\n\nfunction validateShopId(shopId: string): void {\n if (!SHOP_ID_RE.test(shopId)) {\n throw new Error(\"shopId must be a numeric Shopify shop ID string\");\n }\n}\n\nfunction validateCustomerApiVersion(customerApiVersion: string): void {\n if (!CUSTOMER_API_VERSION_RE.test(customerApiVersion)) {\n throw new Error(\"customerApiVersion must use YYYY-MM format\");\n }\n}\n\nfunction validateAccessToken(accessToken: AccessToken): string {\n if (\n typeof accessToken !== \"string\" ||\n accessToken === \"\" ||\n accessToken.trim() !== accessToken ||\n hasAsciiControlCharacter(accessToken)\n ) {\n throw new CustomerAccountAuthenticationError();\n }\n return accessToken;\n}\n\nfunction validateGraphqlOptions(\n options: CustomerAccountGraphqlOptions<unknown> | undefined,\n): CustomerAccountGraphqlOptions<unknown> {\n if (typeof options !== \"object\" || options === null) {\n throw new CustomerAccountAuthenticationError();\n }\n return options;\n}\n\nfunction getOptionalVariables(variables: unknown): Record<string, unknown> {\n if (variables === undefined) return {};\n if (!isObjectRecord(variables)) {\n throw new TypeError(\"Customer Account API variables must be an object\");\n }\n return variables;\n}\n\nfunction hasAsciiControlCharacter(value: string): boolean {\n for (let index = 0; index < value.length; index++) {\n const codePoint = value.charCodeAt(index);\n if (codePoint <= MAX_ASCII_CONTROL_CODE_POINT || codePoint === ASCII_DELETE_CODE_POINT) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Customer Account API requires an HTTPS Origin, but local dev frameworks often\n * receive `http://localhost` requests. Keep that local-only exception without\n * weakening origin validation for non-local requests.\n */\nfunction getOrigin(requestUrl: string | undefined): string {\n if (!requestUrl) {\n throw new Error(\"requestContext.url is required for Customer Account API requests\");\n }\n\n const url = new URL(requestUrl);\n if (url.protocol === \"https:\") return url.origin;\n if (url.protocol === \"http:\" && LOCAL_ORIGIN_HOSTS.has(url.hostname)) {\n return `https://${url.host}`;\n }\n throw new Error(`Customer Account API origin must use HTTPS. Received: ${requestUrl}`);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
//#region src/customer-account/errors.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Base error for Customer Account API failures. Thrown by
|
|
4
|
+
* `CustomerAccountClient.graphql()` when the API responds with a non-OK
|
|
5
|
+
* HTTP status, when the response body cannot be parsed as JSON, or when the
|
|
6
|
+
* parsed response is missing `data`. Also thrown (without subclassing) for
|
|
7
|
+
* OAuth token-request timeouts and network failures.
|
|
8
|
+
*
|
|
9
|
+
* Not all fields are populated on every instance. `status` is present
|
|
10
|
+
* whenever an HTTP response was received. `requestId` is set when the
|
|
11
|
+
* `x-request-id` response header exists. Both are absent on network
|
|
12
|
+
* failures where no response arrived. `retryAfter` is populated only on
|
|
13
|
+
* non-OK responses.
|
|
14
|
+
*/
|
|
2
15
|
declare class CustomerAccountApiError extends Error {
|
|
16
|
+
/** HTTP status code from the API response. Present whenever an HTTP response was received (including parse failures), absent on network failures where no response arrived. */
|
|
3
17
|
readonly status?: number;
|
|
18
|
+
/** Value of the `x-request-id` response header, when the API returned one. Useful for Shopify support requests. */
|
|
4
19
|
readonly requestId?: string;
|
|
20
|
+
/** Value of the `retry-after` response header, when present. Indicates when the client should retry a rate-limited request. */
|
|
5
21
|
readonly retryAfter?: string;
|
|
6
22
|
constructor(message: string, options?: {
|
|
7
23
|
status?: number;
|
|
@@ -10,14 +26,44 @@ declare class CustomerAccountApiError extends Error {
|
|
|
10
26
|
cause?: unknown;
|
|
11
27
|
});
|
|
12
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Client-side pre-flight check. Thrown when the access token is missing,
|
|
31
|
+
* empty, has leading or trailing whitespace, or contains ASCII control
|
|
32
|
+
* characters (including DEL). Also thrown when the options object is
|
|
33
|
+
* missing. A token the server rejects (e.g. expired or revoked) produces
|
|
34
|
+
* the base {@link CustomerAccountApiError} with `status: 401` instead.
|
|
35
|
+
*/
|
|
13
36
|
declare class CustomerAccountAuthenticationError extends CustomerAccountApiError {
|
|
14
37
|
constructor(message?: string);
|
|
15
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when a `CustomerAccountClient.graphql()` request exceeds
|
|
41
|
+
* `defaultTimeoutInMs`. (OAuth token-request timeouts throw the base
|
|
42
|
+
* {@link CustomerAccountApiError} instead.) Extends
|
|
43
|
+
* {@link CustomerAccountApiError}.
|
|
44
|
+
*/
|
|
16
45
|
declare class CustomerAccountTimeoutError extends CustomerAccountApiError {
|
|
46
|
+
/** The timeout threshold (in milliseconds) that was exceeded. */
|
|
17
47
|
readonly timeoutInMs: number;
|
|
18
48
|
constructor(timeoutInMs: number);
|
|
19
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Thrown during the Customer Account OAuth authorization code exchange
|
|
52
|
+
* or id_token validation in `handleOAuthCallback`. Refresh failures never
|
|
53
|
+
* surface this error (they are caught internally and returned as
|
|
54
|
+
* `undefined`). Extends `Error` directly, **not**
|
|
55
|
+
* {@link CustomerAccountApiError}. A `catch` block for
|
|
56
|
+
* `CustomerAccountApiError` will not catch this error.
|
|
57
|
+
*
|
|
58
|
+
* Use the `code` field for programmatic handling. Known codes:
|
|
59
|
+
* `"missing_callback_params"`, `"state_mismatch"`,
|
|
60
|
+
* `"token_exchange_rejected"`, `"token_exchange_failed"`,
|
|
61
|
+
* `"invalid_token_response"`, `"nonce_mismatch"`, `"issuer_mismatch"`,
|
|
62
|
+
* `"audience_mismatch"`, `"expired_id_token"`, `"invalid_id_token"`,
|
|
63
|
+
* `"missing_pending_login"`.
|
|
64
|
+
*/
|
|
20
65
|
declare class CustomerAccountOAuthError extends Error {
|
|
66
|
+
/** Machine-readable error identifier for programmatic handling. */
|
|
21
67
|
readonly code: string;
|
|
22
68
|
constructor(code: string, message: string, options?: {
|
|
23
69
|
cause?: unknown;
|