@shopify/hydrogen 2026.4.6 → 2026.4.8

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.
@@ -490,7 +490,7 @@ function getPrivacyBanner() {
490
490
  }
491
491
 
492
492
  // package.json
493
- var version = "2026.4.6";
493
+ var version = "2026.4.8";
494
494
 
495
495
  // src/analytics-manager/ShopifyAnalytics.tsx
496
496
  function getCustomerPrivacyRequired() {
@@ -992,6 +992,8 @@ function register(key) {
992
992
  }
993
993
  };
994
994
  }
995
+ var noopPublish = () => {
996
+ };
995
997
  function messageOnError(field, envVar) {
996
998
  return `[h2:error:Analytics.Provider] - ${field} is required. Make sure ${envVar} is defined in your environment variables. See https://h2o.fyi/analytics/consent to learn how to setup environment variables in the Shopify admin.`;
997
999
  }
@@ -1006,11 +1008,25 @@ function AnalyticsProvider({
1006
1008
  const { shop } = useShopAnalytics(shopProp);
1007
1009
  const [consentVersion, setConsentVersion] = react.useState(0);
1008
1010
  const [privacyReady, setPrivacyReady] = react.useState(false);
1009
- const [carts, setCarts] = react.useState({ cart: null, prevCart: null });
1011
+ const [carts, setCartsState] = react.useState({ cart: null, prevCart: null });
1012
+ const setCarts = react.useCallback(
1013
+ (update) => react.startTransition(() => setCartsState(update)),
1014
+ []
1015
+ );
1010
1016
  const canTrack = customCanTrack ?? hasAnalyticsConsent;
1017
+ const canTrackRef = react.useRef(canTrack);
1018
+ canTrackRef.current = canTrack;
1019
+ const guardedPublish = react.useCallback(
1020
+ (event, payload) => {
1021
+ if (canTrackRef.current()) publish(event, payload);
1022
+ },
1023
+ []
1024
+ );
1011
1025
  const onConsentChange = react.useCallback(() => {
1012
- setPrivacyReady(true);
1013
- setConsentVersion((version2) => version2 + 1);
1026
+ react.startTransition(() => {
1027
+ setPrivacyReady(true);
1028
+ setConsentVersion((version2) => version2 + 1);
1029
+ });
1014
1030
  }, []);
1015
1031
  if (!!shop) {
1016
1032
  if (/\/68817551382$/.test(shop.shopId)) {
@@ -1048,8 +1064,7 @@ function AnalyticsProvider({
1048
1064
  canTrack,
1049
1065
  ...carts,
1050
1066
  customData,
1051
- publish: canTrack() ? publish : () => {
1052
- },
1067
+ publish: canTrack() ? guardedPublish : noopPublish,
1053
1068
  shop,
1054
1069
  subscribe,
1055
1070
  register,
@@ -1062,7 +1077,7 @@ function AnalyticsProvider({
1062
1077
  carts,
1063
1078
  carts.cart?.updatedAt,
1064
1079
  carts.prevCart,
1065
- publish,
1080
+ guardedPublish,
1066
1081
  subscribe,
1067
1082
  customData,
1068
1083
  shop,
@@ -1091,7 +1106,9 @@ function useAnalytics() {
1091
1106
  function useShopAnalytics(shopProp) {
1092
1107
  const [shop, setShop] = react.useState(null);
1093
1108
  react.useEffect(() => {
1094
- Promise.resolve(shopProp).then(setShop);
1109
+ Promise.resolve(shopProp).then((resolvedShop) => {
1110
+ react.startTransition(() => setShop(resolvedShop));
1111
+ });
1095
1112
  return () => {
1096
1113
  };
1097
1114
  }, [setShop, shopProp]);
@@ -1857,7 +1874,7 @@ function generateUUID() {
1857
1874
  }
1858
1875
 
1859
1876
  // src/version.ts
1860
- var LIB_VERSION = "2026.4.6";
1877
+ var LIB_VERSION = "2026.4.8";
1861
1878
 
1862
1879
  // src/utils/graphql.ts
1863
1880
  function minifyQuery(string) {
@@ -3541,7 +3558,7 @@ function useOptimisticCart(cart) {
3541
3558
  }
3542
3559
 
3543
3560
  // src/changelogHandler.ts
3544
- var DEFAULT_GITHUB_CHANGELOG_URL = "https://raw.githubusercontent.com/Shopify/hydrogen/main/docs/changelog.json";
3561
+ var DEFAULT_GITHUB_CHANGELOG_URL = "https://raw.githubusercontent.com/Shopify/hydrogen/2026-04/docs/changelog.json";
3545
3562
  async function changelogHandler({
3546
3563
  request,
3547
3564
  changelogUrl
@@ -3845,6 +3862,17 @@ function getRedirectUrl(requestUrl) {
3845
3862
  }
3846
3863
  }
3847
3864
  }
3865
+ function getSameOriginPath(target, origin) {
3866
+ if (!target) return void 0;
3867
+ try {
3868
+ const url = target.startsWith("/") ? new URL(target, origin) : new URL(target);
3869
+ if (url.origin !== origin) return void 0;
3870
+ const path = `${url.pathname}${url.search}${url.hash}`;
3871
+ return path.startsWith("//") ? void 0 : path;
3872
+ } catch {
3873
+ return void 0;
3874
+ }
3875
+ }
3848
3876
  function isLocalPath(requestUrl, redirectUrl) {
3849
3877
  try {
3850
3878
  return new URL(requestUrl).origin === new URL(redirectUrl, requestUrl).origin;
@@ -4183,7 +4211,9 @@ function createCustomerAccountClient({
4183
4211
  codeVerifier: verifier,
4184
4212
  state,
4185
4213
  nonce,
4186
- redirectPath: getRedirectUrl(request.url) || getHeader(request, "Referer") || defaultRedirectPath
4214
+ redirectPath: getRedirectUrl(request.url) || // The same HTTPS origin the OAuth `redirect_uri` uses, so an http
4215
+ // `request.url` still matches the https pages customers browse.
4216
+ getSameOriginPath(getHeader(request, "Referer"), httpsOrigin) || defaultRedirectPath
4187
4217
  });
4188
4218
  loginUrl.searchParams.append("code_challenge", challenge);
4189
4219
  loginUrl.searchParams.append("code_challenge_method", "S256");