@shopify/hydrogen 2025.7.0 → 2025.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/dev/{get-virtual-routes-KWSSQH4L.js → get-virtual-routes-ZEUPNZWL.js} +0 -36
  2. package/dist/dev/hydrogen-routes.js +1 -1
  3. package/dist/development/{get-virtual-routes-6PVSMJPH.js → get-virtual-routes-XE7G57DS.js} +3 -36
  4. package/dist/development/get-virtual-routes-XE7G57DS.js.map +1 -0
  5. package/dist/development/index.cjs +406 -124
  6. package/dist/development/index.cjs.map +1 -1
  7. package/dist/development/index.js +395 -81
  8. package/dist/development/index.js.map +1 -1
  9. package/dist/development/react-router-preset.d.ts +5 -5
  10. package/dist/development/react-router-preset.js +4 -4
  11. package/dist/development/react-router-preset.js.map +1 -1
  12. package/dist/oxygen/index.d.ts +120 -3
  13. package/dist/oxygen/index.js +111 -5
  14. package/dist/production/get-virtual-routes-MYYLGSAS.js +3 -0
  15. package/dist/production/get-virtual-routes-MYYLGSAS.js.map +1 -0
  16. package/dist/production/index.cjs +76 -76
  17. package/dist/production/index.cjs.map +1 -1
  18. package/dist/production/index.d.cts +76 -15
  19. package/dist/production/index.d.ts +76 -15
  20. package/dist/production/index.js +76 -76
  21. package/dist/production/index.js.map +1 -1
  22. package/dist/production/react-router-preset.d.ts +5 -5
  23. package/dist/production/react-router-preset.js +2 -2
  24. package/dist/vite/get-virtual-routes.d.ts +1 -17
  25. package/dist/vite/get-virtual-routes.js +0 -36
  26. package/package.json +6 -6
  27. package/dist/development/get-virtual-routes-6PVSMJPH.js.map +0 -1
  28. package/dist/oxygen/chunk-RVXKHOUX.js +0 -39
  29. package/dist/oxygen/chunk-T4YWBSCF.js +0 -14
  30. package/dist/oxygen/createRequestHandler.d.ts +0 -10
  31. package/dist/oxygen/createRequestHandler.js +0 -6
  32. package/dist/oxygen/getStorefrontHeaders-BqPh5S1b.d.ts +0 -69
  33. package/dist/oxygen/getStorefrontHeaders.d.ts +0 -1
  34. package/dist/oxygen/getStorefrontHeaders.js +0 -6
  35. package/dist/production/get-virtual-routes-JVKSNI4M.js +0 -3
  36. package/dist/production/get-virtual-routes-JVKSNI4M.js.map +0 -1
@@ -1,12 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var url = require('url');
4
- var path = require('path');
5
- var promises = require('fs/promises');
6
3
  var react = require('react');
7
4
  var reactRouter = require('react-router');
8
5
  var jsxRuntime = require('react/jsx-runtime');
9
6
  var hydrogenReact = require('@shopify/hydrogen-react');
7
+ var loadScript = require('@shopify/hydrogen-react/load-script');
10
8
  var graphqlClient = require('@shopify/graphql-client');
11
9
  var cookie = require('worktop/cookie');
12
10
  var cspBuilder = require('content-security-policy-builder');
@@ -14,7 +12,6 @@ var cspBuilder = require('content-security-policy-builder');
14
12
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
15
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
14
 
17
- var path__default = /*#__PURE__*/_interopDefault(path);
18
15
  var cspBuilder__default = /*#__PURE__*/_interopDefault(cspBuilder);
19
16
 
20
17
  var __defProp = Object.defineProperty;
@@ -30,13 +27,9 @@ var __export = (target, all) => {
30
27
  // src/vite/get-virtual-routes.ts
31
28
  var get_virtual_routes_exports = {};
32
29
  __export(get_virtual_routes_exports, {
33
- VIRTUAL_ROOT: () => VIRTUAL_ROOT,
34
- VIRTUAL_ROOT_ORIG: () => VIRTUAL_ROOT_ORIG,
35
30
  VIRTUAL_ROUTES_DIR: () => VIRTUAL_ROUTES_DIR,
36
- VIRTUAL_ROUTES_DIR_ORIG: () => VIRTUAL_ROUTES_DIR_ORIG,
37
31
  VIRTUAL_ROUTES_DIR_PARTS: () => VIRTUAL_ROUTES_DIR_PARTS,
38
32
  VIRTUAL_ROUTES_ROUTES_DIR_PARTS: () => VIRTUAL_ROUTES_ROUTES_DIR_PARTS,
39
- getVirtualRoutes: () => getVirtualRoutes,
40
33
  getVirtualRoutesV3: () => getVirtualRoutesV3
41
34
  });
42
35
  function getVirtualRoutesPath(pathParts, forFile) {
@@ -94,33 +87,7 @@ async function getVirtualRoutesV3() {
94
87
  }
95
88
  };
96
89
  }
97
- async function getVirtualRoutes() {
98
- const distPath = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
99
- const virtualRoutesPath = path__default.default.join(distPath, VIRTUAL_ROUTES_DIR_ORIG);
100
- const routes = await promises.readdir(virtualRoutesPath, { recursive: true }).then(
101
- (files) => files.map((relativeFilePath) => {
102
- const absoluteFilePath = path__default.default.join(virtualRoutesPath, relativeFilePath);
103
- const id = relativeFilePath.replace(/\.[jt]sx?$/, "").replaceAll("\\", "/");
104
- const isIndex = /(^|\/)index$/.test(id);
105
- const routePath = id.replace(/(^|\/)index$/, "");
106
- return {
107
- id: `${VIRTUAL_ROUTES_DIR_ORIG}/${id}`,
108
- path: routePath,
109
- file: absoluteFilePath,
110
- index: isIndex
111
- };
112
- })
113
- );
114
- return {
115
- routes,
116
- root: {
117
- id: VIRTUAL_ROOT_ORIG,
118
- path: "",
119
- file: path__default.default.join(distPath, VIRTUAL_ROOT_ORIG + ".jsx")
120
- }
121
- };
122
- }
123
- var VIRTUAL_ROUTES_DIR, VIRTUAL_ROUTES_ROUTES_DIR_PARTS, VIRTUAL_ROUTES_DIR_PARTS, VIRTUAL_ROOT, VIRTUAL_ROUTES_DIR_ORIG, VIRTUAL_ROOT_ORIG;
90
+ var VIRTUAL_ROUTES_DIR, VIRTUAL_ROUTES_ROUTES_DIR_PARTS, VIRTUAL_ROUTES_DIR_PARTS;
124
91
  var init_get_virtual_routes = __esm({
125
92
  "src/vite/get-virtual-routes.ts"() {
126
93
  VIRTUAL_ROUTES_DIR = "vite/virtual-routes/routes";
@@ -130,9 +97,6 @@ var init_get_virtual_routes = __esm({
130
97
  "routes"
131
98
  ];
132
99
  VIRTUAL_ROUTES_DIR_PARTS = ["vite", "virtual-routes"];
133
- VIRTUAL_ROOT = "vite/virtual-routes/virtual-root";
134
- VIRTUAL_ROUTES_DIR_ORIG = "virtual-routes/routes";
135
- VIRTUAL_ROOT_ORIG = "virtual-routes/virtual-root-with-layout";
136
100
  }
137
101
  });
138
102
 
@@ -281,7 +245,62 @@ var AnalyticsEvent = {
281
245
  // Custom
282
246
  CUSTOM_EVENT: `custom_`
283
247
  };
284
- var CONSENT_API = "https://cdn.shopify.com/shopifycloud/consent-tracking-api/v0.1/consent-tracking-api.js";
248
+
249
+ // src/constants.ts
250
+ var STOREFRONT_REQUEST_GROUP_ID_HEADER = "Custom-Storefront-Request-Group-ID";
251
+ var STOREFRONT_ACCESS_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
252
+ var SDK_VARIANT_HEADER = "X-SDK-Variant";
253
+ var SDK_VARIANT_SOURCE_HEADER = "X-SDK-Variant-Source";
254
+ var SDK_VERSION_HEADER = "X-SDK-Version";
255
+ var SHOPIFY_CLIENT_IP_HEADER = "X-Shopify-Client-IP";
256
+ var SHOPIFY_CLIENT_IP_SIG_HEADER = "X-Shopify-Client-IP-Sig";
257
+ var HYDROGEN_SFAPI_PROXY_KEY = "_sfapi_proxy";
258
+ var HYDROGEN_SERVER_TRACKING_KEY = "_server_tracking";
259
+
260
+ // src/utils/server-timing.ts
261
+ function buildServerTimingHeader(values) {
262
+ return Object.entries(values).map(([key, value]) => value ? `${key};desc=${value}` : void 0).filter(Boolean).join(", ");
263
+ }
264
+ function appendServerTimingHeader(response, values) {
265
+ const header = typeof values === "string" ? values : buildServerTimingHeader(values);
266
+ if (header) {
267
+ response.headers.append("Server-Timing", header);
268
+ }
269
+ }
270
+ var trackedTimings = ["_y", "_s", "_cmp"];
271
+ function extractServerTimingHeader(serverTimingHeader) {
272
+ const values = {};
273
+ if (!serverTimingHeader) return values;
274
+ const re = new RegExp(
275
+ `\\b(${trackedTimings.join("|")});desc="?([^",]+)"?`,
276
+ "g"
277
+ );
278
+ let match;
279
+ while ((match = re.exec(serverTimingHeader)) !== null) {
280
+ values[match[1]] = match[2];
281
+ }
282
+ return values;
283
+ }
284
+ function hasServerTimingInNavigationEntry(key) {
285
+ if (typeof window === "undefined") return false;
286
+ try {
287
+ const navigationEntry = window.performance.getEntriesByType(
288
+ "navigation"
289
+ )[0];
290
+ return !!navigationEntry?.serverTiming?.some((entry) => entry.name === key);
291
+ } catch (e) {
292
+ return false;
293
+ }
294
+ }
295
+ function isSfapiProxyEnabled() {
296
+ return hasServerTimingInNavigationEntry(HYDROGEN_SFAPI_PROXY_KEY);
297
+ }
298
+ function hasServerReturnedTrackingValues() {
299
+ return hasServerTimingInNavigationEntry(HYDROGEN_SERVER_TRACKING_KEY);
300
+ }
301
+
302
+ // src/customer-privacy/ShopifyCustomerPrivacy.tsx
303
+ var CONSENT_API = "https://cdn.shopify.com/shopifycloud/consent-tracking-api/v0.2/consent-tracking-api.js";
285
304
  var CONSENT_API_WITH_BANNER = "https://cdn.shopify.com/shopifycloud/privacy-banner/storefront-banner.js";
286
305
  function logMissingConfig(fieldName) {
287
306
  console.error(
@@ -293,19 +312,34 @@ function useCustomerPrivacy(props) {
293
312
  withPrivacyBanner = false,
294
313
  onVisitorConsentCollected,
295
314
  onReady,
296
- ...consentConfig
315
+ checkoutDomain,
316
+ storefrontAccessToken,
317
+ country,
318
+ locale,
319
+ sameDomainForStorefrontApi
297
320
  } = props;
298
- hydrogenReact.useLoadScript(withPrivacyBanner ? CONSENT_API_WITH_BANNER : CONSENT_API, {
321
+ const hasSfapiProxy = react.useMemo(
322
+ () => sameDomainForStorefrontApi ?? isSfapiProxyEnabled(),
323
+ [sameDomainForStorefrontApi]
324
+ );
325
+ const fetchTrackingValuesFromBrowser = react.useMemo(
326
+ () => hasSfapiProxy && !hasServerReturnedTrackingValues(),
327
+ [hasSfapiProxy]
328
+ );
329
+ const cookiesReady = hydrogenReact.useShopifyCookies({
330
+ fetchTrackingValues: fetchTrackingValuesFromBrowser,
331
+ storefrontAccessToken,
332
+ ignoreDeprecatedCookies: true
333
+ });
334
+ const initialTrackingValues = react.useMemo(hydrogenReact.getTrackingValues, [cookiesReady]);
335
+ const { revalidate } = reactRouter.useRevalidator();
336
+ loadScript.useLoadScript(withPrivacyBanner ? CONSENT_API_WITH_BANNER : CONSENT_API, {
299
337
  attributes: {
300
338
  id: "customer-privacy-api"
301
339
  }
302
340
  });
303
- const { observing, setLoaded } = useApisLoaded({
304
- withPrivacyBanner,
305
- onLoaded: onReady
306
- });
341
+ const { observing, setLoaded, apisLoaded } = useApisLoaded({ withPrivacyBanner });
307
342
  const config = react.useMemo(() => {
308
- const { checkoutDomain, storefrontAccessToken } = consentConfig;
309
343
  if (!checkoutDomain) logMissingConfig("checkoutDomain");
310
344
  if (!storefrontAccessToken) logMissingConfig("storefrontAccessToken");
311
345
  if (storefrontAccessToken.startsWith("shpat_") || storefrontAccessToken.length !== 32) {
@@ -313,18 +347,54 @@ function useCustomerPrivacy(props) {
313
347
  `[h2:error:useCustomerPrivacy] It looks like you passed a private access token, make sure to use the public token`
314
348
  );
315
349
  }
350
+ const commonAncestorDomain = parseStoreDomain(checkoutDomain);
351
+ const sfapiDomain = (
352
+ // Check if standard route proxy is enabled in Hydrogen server
353
+ // to use it instead of doing a cross-origin request to checkout.
354
+ hasSfapiProxy && typeof window !== "undefined" ? window.location.host : checkoutDomain
355
+ );
316
356
  const config2 = {
317
- checkoutRootDomain: checkoutDomain,
357
+ // This domain is used to send requests to SFAPI for setting and getting consent.
358
+ checkoutRootDomain: sfapiDomain,
359
+ // Prefix with a dot to ensure this domain is different from checkoutRootDomain.
360
+ // This will ensure old cookies are set for a cross-subdomain checkout setup
361
+ // so that we keep backward compatibility until new cookies are rolled out.
362
+ // Once consent-tracking-api is updated to not rely on cookies anymore, we can remove this.
363
+ storefrontRootDomain: commonAncestorDomain ? "." + commonAncestorDomain : void 0,
318
364
  storefrontAccessToken,
319
- storefrontRootDomain: parseStoreDomain(checkoutDomain),
320
- country: consentConfig.country,
321
- locale: consentConfig.locale
365
+ country,
366
+ locale
322
367
  };
323
368
  return config2;
324
- }, [consentConfig, parseStoreDomain, logMissingConfig]);
369
+ }, [
370
+ logMissingConfig,
371
+ checkoutDomain,
372
+ storefrontAccessToken,
373
+ country,
374
+ locale
375
+ ]);
325
376
  react.useEffect(() => {
326
377
  const consentCollectedHandler = (event) => {
378
+ const latestTrackingValues = hydrogenReact.getTrackingValues();
379
+ if (initialTrackingValues.visitToken !== latestTrackingValues.visitToken || initialTrackingValues.uniqueToken !== latestTrackingValues.uniqueToken) {
380
+ revalidate().catch(() => {
381
+ console.warn(
382
+ "[h2:warn:useCustomerPrivacy] Revalidation failed after consent change."
383
+ );
384
+ });
385
+ }
327
386
  if (onVisitorConsentCollected) {
387
+ const customerPrivacy = getCustomerPrivacy();
388
+ if (customerPrivacy?.shouldShowBanner()) {
389
+ const consentValues = customerPrivacy.currentVisitorConsent();
390
+ if (consentValues) {
391
+ const NO_VALUE = "";
392
+ const noInteraction = consentValues.marketing === NO_VALUE && consentValues.analytics === NO_VALUE && consentValues.preferences === NO_VALUE;
393
+ if (noInteraction) {
394
+ return;
395
+ }
396
+ }
397
+ }
328
398
  onVisitorConsentCollected(event.detail);
329
399
  }
330
400
  };
@@ -350,14 +420,11 @@ function useCustomerPrivacy(props) {
350
420
  },
351
421
  set(value) {
352
422
  if (typeof value === "object" && value !== null && "showPreferences" in value && "loadBanner" in value) {
353
- const privacyBanner = value;
354
- privacyBanner.loadBanner(config);
355
423
  customPrivacyBanner = overridePrivacyBannerMethods({
356
- privacyBanner,
424
+ privacyBanner: value,
357
425
  config
358
426
  });
359
427
  setLoaded.privacyBanner();
360
- emitCustomerPrivacyApiLoaded();
361
428
  }
362
429
  }
363
430
  };
@@ -391,6 +458,8 @@ function useCustomerPrivacy(props) {
391
458
  const customerPrivacy = value2;
392
459
  customCustomerPrivacy = {
393
460
  ...customerPrivacy,
461
+ // Note: this method is not used by the privacy-banner,
462
+ // it bundles its own setTrackingConsent.
394
463
  setTrackingConsent: overrideCustomerPrivacySetTrackingConsent(
395
464
  { customerPrivacy, config }
396
465
  )
@@ -400,7 +469,6 @@ function useCustomerPrivacy(props) {
400
469
  customerPrivacy: customCustomerPrivacy
401
470
  };
402
471
  setLoaded.customerPrivacy();
403
- emitCustomerPrivacyApiLoaded();
404
472
  }
405
473
  }
406
474
  });
@@ -412,6 +480,24 @@ function useCustomerPrivacy(props) {
412
480
  overrideCustomerPrivacySetTrackingConsent,
413
481
  setLoaded.customerPrivacy
414
482
  ]);
483
+ react.useEffect(() => {
484
+ if (!apisLoaded || !cookiesReady) return;
485
+ const customerPrivacy = getCustomerPrivacy();
486
+ if (customerPrivacy && !customerPrivacy.cachedConsent) {
487
+ const trackingValues = hydrogenReact.getTrackingValues();
488
+ if (trackingValues.consent) {
489
+ customerPrivacy.cachedConsent = trackingValues.consent;
490
+ }
491
+ }
492
+ if (withPrivacyBanner) {
493
+ const privacyBanner = getPrivacyBanner();
494
+ if (privacyBanner) {
495
+ privacyBanner.loadBanner(config);
496
+ }
497
+ }
498
+ emitCustomerPrivacyApiLoaded();
499
+ onReady?.();
500
+ }, [apisLoaded, cookiesReady]);
415
501
  const result = {
416
502
  customerPrivacy: getCustomerPrivacy()
417
503
  };
@@ -427,15 +513,12 @@ function emitCustomerPrivacyApiLoaded() {
427
513
  const event = new CustomEvent("shopifyCustomerPrivacyApiLoaded");
428
514
  document.dispatchEvent(event);
429
515
  }
430
- function useApisLoaded({
431
- withPrivacyBanner,
432
- onLoaded
433
- }) {
516
+ function useApisLoaded({ withPrivacyBanner }) {
434
517
  const observing = react.useRef({ customerPrivacy: false, privacyBanner: false });
435
- const [apisLoaded, setApisLoaded] = react.useState(
518
+ const [apisLoadedArray, setApisLoaded] = react.useState(
436
519
  withPrivacyBanner ? [false, false] : [false]
437
520
  );
438
- const loaded = apisLoaded.every(Boolean);
521
+ const apisLoaded = apisLoadedArray.every(Boolean);
439
522
  const setLoaded = {
440
523
  customerPrivacy: () => {
441
524
  if (withPrivacyBanner) {
@@ -451,16 +534,11 @@ function useApisLoaded({
451
534
  setApisLoaded((prev) => [prev[0], true]);
452
535
  }
453
536
  };
454
- react.useEffect(() => {
455
- if (loaded && onLoaded) {
456
- onLoaded();
457
- }
458
- }, [loaded, onLoaded]);
459
- return { observing, setLoaded };
537
+ return { observing, setLoaded, apisLoaded };
460
538
  }
461
539
  function parseStoreDomain(checkoutDomain) {
462
540
  if (typeof window === "undefined") return;
463
- const host = window.document.location.host;
541
+ const host = window.location.host;
464
542
  const checkoutDomainParts = checkoutDomain.split(".").reverse();
465
543
  const currentDomainParts = host.split(".").reverse();
466
544
  const sameDomainParts = [];
@@ -469,7 +547,7 @@ function parseStoreDomain(checkoutDomain) {
469
547
  sameDomainParts.push(part);
470
548
  }
471
549
  });
472
- return sameDomainParts.reverse().join(".");
550
+ return sameDomainParts.reverse().join(".") || void 0;
473
551
  }
474
552
  function overrideCustomerPrivacySetTrackingConsent({
475
553
  customerPrivacy,
@@ -527,7 +605,7 @@ function getPrivacyBanner() {
527
605
  }
528
606
 
529
607
  // package.json
530
- var version = "2025.7.0";
608
+ var version = "2025.7.2";
531
609
 
532
610
  // src/analytics-manager/ShopifyAnalytics.tsx
533
611
  function getCustomerPrivacyRequired() {
@@ -547,6 +625,7 @@ function ShopifyAnalytics({
547
625
  const { subscribe: subscribe2, register: register2, canTrack } = useAnalytics();
548
626
  const [shopifyReady, setShopifyReady] = react.useState(false);
549
627
  const [privacyReady, setPrivacyReady] = react.useState(false);
628
+ const [collectedConsent, setCollectedConsent] = react.useState("");
550
629
  const init = react.useRef(false);
551
630
  const { checkoutDomain, storefrontAccessToken, language } = consent;
552
631
  const { ready: shopifyAnalyticsReady } = register2("Internal_Shopify_Analytics");
@@ -555,14 +634,31 @@ function ShopifyAnalytics({
555
634
  locale: language,
556
635
  checkoutDomain: !checkoutDomain ? "mock.shop" : checkoutDomain,
557
636
  storefrontAccessToken: !storefrontAccessToken ? "abcdefghijklmnopqrstuvwxyz123456" : storefrontAccessToken,
558
- onVisitorConsentCollected: () => setPrivacyReady(true),
559
- onReady: () => setPrivacyReady(true)
637
+ // If we use privacy banner, we should wait until consent is collected.
638
+ // Otherwise, we can consider privacy ready immediately:
639
+ onReady: () => !consent.withPrivacyBanner && setPrivacyReady(true),
640
+ onVisitorConsentCollected: (consent2) => {
641
+ try {
642
+ setCollectedConsent(JSON.stringify(consent2));
643
+ } catch (e) {
644
+ }
645
+ setPrivacyReady(true);
646
+ }
560
647
  });
648
+ const hasUserConsent = react.useMemo(
649
+ // must be initialized with true to avoid removing cookies too early
650
+ () => privacyReady ? canTrack() : true,
651
+ // Make this value depend on collectedConsent to re-run `canTrack()` when consent changes
652
+ [privacyReady, canTrack, collectedConsent]
653
+ );
561
654
  hydrogenReact.useShopifyCookies({
562
- hasUserConsent: privacyReady ? canTrack() : true,
563
- // must be initialized with true
655
+ hasUserConsent,
564
656
  domain,
565
- checkoutDomain
657
+ checkoutDomain,
658
+ // Already done inside useCustomerPrivacy
659
+ fetchTrackingValues: false,
660
+ // Avoid creating local cookies too early
661
+ ignoreDeprecatedCookies: !privacyReady
566
662
  });
567
663
  react.useEffect(() => {
568
664
  if (init.current) return;
@@ -612,11 +708,11 @@ function prepareBasePageViewPayload(payload) {
612
708
  ...payload.shop,
613
709
  hasUserConsent,
614
710
  ...hydrogenReact.getClientBrowserParameters(),
615
- ccpaEnforced: !customerPrivacy.saleOfDataAllowed(),
616
- gdprEnforced: !(customerPrivacy.marketingAllowed() && customerPrivacy.analyticsProcessingAllowed()),
617
711
  analyticsAllowed: customerPrivacy.analyticsProcessingAllowed(),
618
712
  marketingAllowed: customerPrivacy.marketingAllowed(),
619
- saleOfDataAllowed: customerPrivacy.saleOfDataAllowed()
713
+ saleOfDataAllowed: customerPrivacy.saleOfDataAllowed(),
714
+ ccpaEnforced: !customerPrivacy.saleOfDataAllowed(),
715
+ gdprEnforced: !(customerPrivacy.marketingAllowed() && customerPrivacy.analyticsProcessingAllowed())
620
716
  };
621
717
  return eventPayload;
622
718
  }
@@ -1049,11 +1145,11 @@ function AnalyticsProvider({
1049
1145
  shop: shopProp = null,
1050
1146
  cookieDomain
1051
1147
  }) {
1052
- const listenerSet = react.useRef(false);
1053
1148
  const { shop } = useShopAnalytics(shopProp);
1054
1149
  const [analyticsLoaded, setAnalyticsLoaded] = react.useState(
1055
1150
  customCanTrack ? true : false
1056
1151
  );
1152
+ const [consentCollected, setConsentCollected] = react.useState(false);
1057
1153
  const [carts, setCarts] = react.useState({ cart: null, prevCart: null });
1058
1154
  const [canTrack, setCanTrack] = react.useState(
1059
1155
  customCanTrack ? () => customCanTrack : () => shopifyCanTrack
@@ -1121,21 +1217,21 @@ function AnalyticsProvider({
1121
1217
  children,
1122
1218
  !!shop && /* @__PURE__ */ jsxRuntime.jsx(AnalyticsPageView, {}),
1123
1219
  !!shop && !!currentCart && /* @__PURE__ */ jsxRuntime.jsx(CartAnalytics, { cart: currentCart, setCarts }),
1124
- !!shop && consent.checkoutDomain && /* @__PURE__ */ jsxRuntime.jsx(
1220
+ !!shop && /* @__PURE__ */ jsxRuntime.jsx(
1125
1221
  ShopifyAnalytics,
1126
1222
  {
1127
1223
  consent,
1128
1224
  onReady: () => {
1129
- listenerSet.current = true;
1130
1225
  setAnalyticsLoaded(true);
1131
1226
  setCanTrack(
1132
1227
  customCanTrack ? () => customCanTrack : () => shopifyCanTrack
1133
1228
  );
1229
+ setConsentCollected(true);
1134
1230
  },
1135
1231
  domain: cookieDomain
1136
1232
  }
1137
1233
  ),
1138
- !!shop && /* @__PURE__ */ jsxRuntime.jsx(PerfKit, { shop })
1234
+ !!shop && consentCollected && /* @__PURE__ */ jsxRuntime.jsx(PerfKit, { shop })
1139
1235
  ] });
1140
1236
  }
1141
1237
  function useAnalytics() {
@@ -1214,6 +1310,31 @@ function getDebugHeaders(request) {
1214
1310
  purpose: request ? getHeader(request, "purpose") : void 0
1215
1311
  };
1216
1312
  }
1313
+ function getStorefrontHeaders(request) {
1314
+ return {
1315
+ requestGroupId: getHeader(request, "request-id"),
1316
+ buyerIp: getHeader(request, "oxygen-buyer-ip"),
1317
+ buyerIpSig: getHeader(request, SHOPIFY_CLIENT_IP_SIG_HEADER),
1318
+ cookie: getHeader(request, "cookie"),
1319
+ // sec-purpose is added by browsers automatically when using link/prefetch or Speculation Rules
1320
+ purpose: getHeader(request, "sec-purpose") || getHeader(request, "purpose")
1321
+ };
1322
+ }
1323
+ var SFAPI_RE = /^\/api\/(unstable|2\d{3}-\d{2})\/graphql\.json$/;
1324
+ var getSafePathname = (url) => {
1325
+ try {
1326
+ return new URL(url, "http://e.c").pathname;
1327
+ } catch {
1328
+ return "/";
1329
+ }
1330
+ };
1331
+ function extractHeaders(extract, keys) {
1332
+ return keys.reduce((acc, key) => {
1333
+ const forwardedValue = extract(key);
1334
+ if (forwardedValue) acc.push([key, forwardedValue]);
1335
+ return acc;
1336
+ }, []);
1337
+ }
1217
1338
 
1218
1339
  // src/utils/callsites.ts
1219
1340
  function withSyncStack(promise, options = {}) {
@@ -1581,13 +1702,16 @@ async function runWithCache(cacheKey, actionFn, {
1581
1702
  }
1582
1703
  return result;
1583
1704
  }
1705
+ var excludedHeaders = ["set-cookie", "server-timing"];
1584
1706
  function toSerializableResponse(body, response) {
1585
1707
  return [
1586
1708
  body,
1587
1709
  {
1588
1710
  status: response.status,
1589
1711
  statusText: response.statusText,
1590
- headers: Array.from(response.headers.entries())
1712
+ headers: [...response.headers].filter(
1713
+ ([key]) => !excludedHeaders.includes(key.toLowerCase())
1714
+ )
1591
1715
  }
1592
1716
  ];
1593
1717
  }
@@ -1601,7 +1725,8 @@ async function fetchWithServerCache(url, requestInit, {
1601
1725
  shouldCacheResponse,
1602
1726
  waitUntil,
1603
1727
  debugInfo,
1604
- streamConfig
1728
+ streamConfig,
1729
+ onRawHeaders
1605
1730
  }) {
1606
1731
  if (!cacheOptions && (!requestInit.method || requestInit.method === "GET")) {
1607
1732
  cacheOptions = CacheShort();
@@ -1615,6 +1740,7 @@ async function fetchWithServerCache(url, requestInit, {
1615
1740
  url,
1616
1741
  customFetchApi: async (url2, options) => {
1617
1742
  rawResponse = await fetch(url2, options);
1743
+ onRawHeaders?.(rawResponse.headers);
1618
1744
  return rawResponse;
1619
1745
  },
1620
1746
  headers: requestInit.headers
@@ -1638,6 +1764,7 @@ async function fetchWithServerCache(url, requestInit, {
1638
1764
  );
1639
1765
  }
1640
1766
  const response = await fetch(url, requestInit);
1767
+ onRawHeaders?.(response.headers);
1641
1768
  if (!response.ok) {
1642
1769
  return response;
1643
1770
  }
@@ -1861,13 +1988,6 @@ var cartSetIdDefault = (cookieOptions) => {
1861
1988
  };
1862
1989
  };
1863
1990
 
1864
- // src/constants.ts
1865
- var STOREFRONT_REQUEST_GROUP_ID_HEADER = "Custom-Storefront-Request-Group-ID";
1866
- var STOREFRONT_ACCESS_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
1867
- var SDK_VARIANT_HEADER = "X-SDK-Variant";
1868
- var SDK_VARIANT_SOURCE_HEADER = "X-SDK-Variant-Source";
1869
- var SDK_VERSION_HEADER = "X-SDK-Version";
1870
-
1871
1991
  // src/utils/uuid.ts
1872
1992
  function generateUUID() {
1873
1993
  if (typeof crypto !== "undefined" && !!crypto.randomUUID) {
@@ -1878,7 +1998,7 @@ function generateUUID() {
1878
1998
  }
1879
1999
 
1880
2000
  // src/version.ts
1881
- var LIB_VERSION = "2025.7.0";
2001
+ var LIB_VERSION = "2025.7.2";
1882
2002
 
1883
2003
  // src/utils/graphql.ts
1884
2004
  function minifyQuery(string) {
@@ -2042,16 +2162,34 @@ function createStorefrontClient(options) {
2042
2162
  contentType: "json",
2043
2163
  buyerIp: storefrontHeaders?.buyerIp || ""
2044
2164
  });
2165
+ if (storefrontHeaders?.buyerIp) {
2166
+ defaultHeaders[SHOPIFY_CLIENT_IP_HEADER] = storefrontHeaders.buyerIp;
2167
+ }
2168
+ if (storefrontHeaders?.buyerIpSig) {
2169
+ defaultHeaders[SHOPIFY_CLIENT_IP_SIG_HEADER] = storefrontHeaders.buyerIpSig;
2170
+ }
2045
2171
  defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId || generateUUID();
2046
2172
  if (storefrontId) defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
2047
2173
  defaultHeaders["user-agent"] = `Hydrogen ${LIB_VERSION}`;
2048
- if (storefrontHeaders && storefrontHeaders.cookie) {
2049
- const cookies = hydrogenReact.getShopifyCookies(storefrontHeaders.cookie ?? "");
2050
- if (cookies[hydrogenReact.SHOPIFY_Y])
2051
- defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_Y_HEADER] = cookies[hydrogenReact.SHOPIFY_Y];
2052
- if (cookies[hydrogenReact.SHOPIFY_S])
2053
- defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_S_HEADER] = cookies[hydrogenReact.SHOPIFY_S];
2054
- }
2174
+ const requestCookie = storefrontHeaders?.cookie ?? "";
2175
+ if (requestCookie) defaultHeaders["cookie"] = requestCookie;
2176
+ let uniqueToken;
2177
+ let visitToken;
2178
+ if (!/\b_shopify_(analytics|marketing)=/.test(requestCookie)) {
2179
+ const legacyUniqueToken = requestCookie.match(/\b_shopify_y=([^;]+)/)?.[1];
2180
+ const legacyVisitToken = requestCookie.match(/\b_shopify_s=([^;]+)/)?.[1];
2181
+ if (legacyUniqueToken) {
2182
+ defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_Y_HEADER] = legacyUniqueToken;
2183
+ }
2184
+ if (legacyVisitToken) {
2185
+ defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_S_HEADER] = legacyVisitToken;
2186
+ }
2187
+ uniqueToken = legacyUniqueToken ?? generateUUID();
2188
+ visitToken = legacyVisitToken ?? generateUUID();
2189
+ defaultHeaders[hydrogenReact.SHOPIFY_UNIQUE_TOKEN_HEADER] = uniqueToken;
2190
+ defaultHeaders[hydrogenReact.SHOPIFY_VISIT_TOKEN_HEADER] = visitToken;
2191
+ }
2192
+ let collectedSubrequestHeaders;
2055
2193
  const cacheKeyHeader = JSON.stringify({
2056
2194
  "content-type": defaultHeaders["content-type"],
2057
2195
  "user-agent": defaultHeaders["user-agent"],
@@ -2118,7 +2256,13 @@ function createStorefrontClient(options) {
2118
2256
  graphql: graphqlData,
2119
2257
  purpose: storefrontHeaders?.purpose
2120
2258
  },
2121
- streamConfig
2259
+ streamConfig,
2260
+ onRawHeaders: (headers2) => {
2261
+ collectedSubrequestHeaders ??= {
2262
+ setCookie: headers2.getSetCookie(),
2263
+ serverTiming: headers2.get("server-timing") ?? ""
2264
+ };
2265
+ }
2122
2266
  });
2123
2267
  const errorOptions = {
2124
2268
  url,
@@ -2217,9 +2361,90 @@ function createStorefrontClient(options) {
2217
2361
  generateCacheControlHeader,
2218
2362
  getPublicTokenHeaders,
2219
2363
  getPrivateTokenHeaders,
2364
+ getHeaders: () => ({ ...defaultHeaders }),
2220
2365
  getShopifyDomain,
2221
2366
  getApiUrl: getStorefrontApiUrl,
2222
- i18n: i18n ?? defaultI18n
2367
+ i18n: i18n ?? defaultI18n,
2368
+ /**
2369
+ * Checks if the request is targeting the Storefront API endpoint.
2370
+ */
2371
+ isStorefrontApiUrl(request) {
2372
+ return SFAPI_RE.test(getSafePathname(request.url ?? ""));
2373
+ },
2374
+ /**
2375
+ * Forwards the request to the Storefront API.
2376
+ */
2377
+ async forward(request, options2) {
2378
+ const forwardedHeaders = new Headers([
2379
+ // Forward only a selected set of headers to the Storefront API
2380
+ // to avoid getting 403 errors due to unexpected headers.
2381
+ ...extractHeaders(
2382
+ (key) => request.headers.get(key),
2383
+ [
2384
+ "accept",
2385
+ "accept-encoding",
2386
+ "accept-language",
2387
+ // Access-Control headers are used for CORS preflight requests.
2388
+ "access-control-request-headers",
2389
+ "access-control-request-method",
2390
+ "content-type",
2391
+ "content-length",
2392
+ "cookie",
2393
+ "origin",
2394
+ "referer",
2395
+ "user-agent",
2396
+ STOREFRONT_ACCESS_TOKEN_HEADER,
2397
+ hydrogenReact.SHOPIFY_UNIQUE_TOKEN_HEADER,
2398
+ hydrogenReact.SHOPIFY_VISIT_TOKEN_HEADER
2399
+ ]
2400
+ ),
2401
+ // Add some headers to help with geolocalization and debugging
2402
+ ...extractHeaders(
2403
+ (key) => defaultHeaders[key],
2404
+ [
2405
+ SHOPIFY_CLIENT_IP_HEADER,
2406
+ SHOPIFY_CLIENT_IP_SIG_HEADER,
2407
+ hydrogenReact.SHOPIFY_STOREFRONT_ID_HEADER,
2408
+ STOREFRONT_REQUEST_GROUP_ID_HEADER
2409
+ ]
2410
+ )
2411
+ ]);
2412
+ if (storefrontHeaders?.buyerIp) {
2413
+ forwardedHeaders.set("x-forwarded-for", storefrontHeaders.buyerIp);
2414
+ }
2415
+ const storefrontApiVersion = options2?.storefrontApiVersion ?? getSafePathname(request.url).match(SFAPI_RE)?.[1];
2416
+ const sfapiResponse = await fetch(
2417
+ getStorefrontApiUrl({ storefrontApiVersion }),
2418
+ {
2419
+ method: request.method,
2420
+ body: request.body,
2421
+ headers: forwardedHeaders
2422
+ }
2423
+ );
2424
+ return new Response(sfapiResponse.body, sfapiResponse);
2425
+ },
2426
+ setCollectedSubrequestHeaders: (response) => {
2427
+ if (collectedSubrequestHeaders) {
2428
+ for (const value of collectedSubrequestHeaders.setCookie) {
2429
+ response.headers.append("Set-Cookie", value);
2430
+ }
2431
+ }
2432
+ const serverTiming = extractServerTimingHeader(
2433
+ collectedSubrequestHeaders?.serverTiming
2434
+ );
2435
+ const isDocumentResponse = response.headers.get("content-type")?.startsWith("text/html");
2436
+ const fallbackValues = isDocumentResponse ? { _y: uniqueToken, _s: visitToken } : void 0;
2437
+ appendServerTimingHeader(response, {
2438
+ ...fallbackValues,
2439
+ ...serverTiming
2440
+ });
2441
+ if (isDocumentResponse && collectedSubrequestHeaders && // _shopify_essential cookie is always set, but we need more than that
2442
+ collectedSubrequestHeaders.setCookie.length > 1 && serverTiming?._y && serverTiming?._s && serverTiming?._cmp) {
2443
+ appendServerTimingHeader(response, {
2444
+ [HYDROGEN_SERVER_TRACKING_KEY]: "1"
2445
+ });
2446
+ }
2447
+ }
2223
2448
  }
2224
2449
  };
2225
2450
  }
@@ -3305,9 +3530,9 @@ var logSubRequestEvent = ({
3305
3530
  }
3306
3531
  });
3307
3532
  } ;
3308
- function redirect(path2, options = {}) {
3533
+ function redirect(path, options = {}) {
3309
3534
  const headers = options.headers ? new Headers(options.headers) : new Headers({});
3310
- headers.set("location", path2);
3535
+ headers.set("location", path);
3311
3536
  return new Response(null, { status: options.status || 302, headers });
3312
3537
  }
3313
3538
  async function refreshToken({
@@ -3815,6 +4040,12 @@ function createCustomerAccountClient({
3815
4040
  if (options?.countryCode) {
3816
4041
  loginUrl.searchParams.append("region_country", options.countryCode);
3817
4042
  }
4043
+ if (options?.acrValues) {
4044
+ loginUrl.searchParams.append("acr_values", options.acrValues);
4045
+ }
4046
+ if (options?.loginHint) {
4047
+ loginUrl.searchParams.append("login_hint", options.loginHint);
4048
+ }
3818
4049
  const verifier = generateCodeVerifier();
3819
4050
  const challenge = await generateCodeChallenge(verifier);
3820
4051
  session.set(CUSTOMER_ACCOUNT_SESSION_KEY, {
@@ -4145,12 +4376,58 @@ function createHydrogenContext(options, additionalContext) {
4145
4376
  });
4146
4377
  return hybridProvider;
4147
4378
  }
4148
- function getStorefrontHeaders(request) {
4149
- return {
4150
- requestGroupId: getHeader(request, "request-id"),
4151
- buyerIp: getHeader(request, "oxygen-buyer-ip"),
4152
- cookie: getHeader(request, "cookie"),
4153
- purpose: getHeader(request, "purpose")
4379
+ function createRequestHandler({
4380
+ build,
4381
+ mode,
4382
+ poweredByHeader = true,
4383
+ getLoadContext,
4384
+ collectTrackingInformation = true,
4385
+ proxyStandardRoutes = true
4386
+ }) {
4387
+ const handleRequest = reactRouter.createRequestHandler(build, mode);
4388
+ const appendPoweredByHeader = poweredByHeader ? (response) => response.headers.append("powered-by", "Shopify, Hydrogen") : void 0;
4389
+ return async (request) => {
4390
+ const method = request.method;
4391
+ if ((method === "GET" || method === "HEAD") && request.body) {
4392
+ return new Response(`${method} requests cannot have a body`, {
4393
+ status: 400
4394
+ });
4395
+ }
4396
+ const url = new URL(request.url);
4397
+ if (url.pathname.includes("//")) {
4398
+ return new Response(null, {
4399
+ status: 301,
4400
+ headers: {
4401
+ location: url.pathname.replace(/\/+/g, "/")
4402
+ }
4403
+ });
4404
+ }
4405
+ const context = await getLoadContext?.(request);
4406
+ const storefront = context?.storefront || context?.get?.(storefrontContext);
4407
+ if (proxyStandardRoutes) {
4408
+ if (!storefront) {
4409
+ warnOnce(
4410
+ "[h2:createRequestHandler] Storefront instance is required to proxy standard routes."
4411
+ );
4412
+ }
4413
+ if (storefront?.isStorefrontApiUrl(request)) {
4414
+ const response2 = await storefront.forward(request);
4415
+ appendPoweredByHeader?.(response2);
4416
+ return response2;
4417
+ }
4418
+ }
4419
+ const response = await handleRequest(request, context);
4420
+ if (storefront && proxyStandardRoutes) {
4421
+ if (collectTrackingInformation) {
4422
+ storefront.setCollectedSubrequestHeaders(response);
4423
+ }
4424
+ const fetchDest = request.headers.get("sec-fetch-dest");
4425
+ if (fetchDest && fetchDest === "document" || request.headers.get("accept")?.includes("text/html")) {
4426
+ appendServerTimingHeader(response, { [HYDROGEN_SFAPI_PROXY_KEY]: "1" });
4427
+ }
4428
+ }
4429
+ appendPoweredByHeader?.(response);
4430
+ return response;
4154
4431
  };
4155
4432
  }
4156
4433
  var NonceContext = react.createContext(void 0);
@@ -4279,12 +4556,12 @@ function LazyScript({
4279
4556
  async function hydrogenRoutes(currentRoutes) {
4280
4557
  const { getVirtualRoutesV3: getVirtualRoutesV32 } = await Promise.resolve().then(() => (init_get_virtual_routes(), get_virtual_routes_exports));
4281
4558
  const { layout, routes: virtualRoutes } = await getVirtualRoutesV32();
4282
- const childVirtualRoutes = virtualRoutes.map(({ path: path2, file, index, id }) => {
4559
+ const childVirtualRoutes = virtualRoutes.map(({ path, file, index, id }) => {
4283
4560
  return {
4284
4561
  file,
4285
4562
  id,
4286
4563
  index,
4287
- path: path2
4564
+ path
4288
4565
  };
4289
4566
  });
4290
4567
  const virtualLayout = {
@@ -4645,7 +4922,7 @@ function VariantSelector({
4645
4922
  }
4646
4923
  }
4647
4924
  const variants = _variants instanceof Array ? _variants : hydrogenReact.flattenConnection(_variants);
4648
- const { searchParams, path: path2, alreadyOnProductPage } = useVariantPath(
4925
+ const { searchParams, path, alreadyOnProductPage } = useVariantPath(
4649
4926
  handle,
4650
4927
  productPath,
4651
4928
  waitForNavigation
@@ -4701,7 +4978,7 @@ function VariantSelector({
4701
4978
  value: value.name,
4702
4979
  optionValue: value,
4703
4980
  isAvailable: variant ? variant.availableForSale : true,
4704
- to: path2 + searchString,
4981
+ to: path + searchString,
4705
4982
  search: searchString,
4706
4983
  isActive: calculatedActiveValue,
4707
4984
  variant
@@ -4735,7 +5012,7 @@ function useVariantPath(handle, productPath, waitForNavigation) {
4735
5012
  const match = /(\/[a-zA-Z]{2}-[a-zA-Z]{2}\/)/g.exec(pathname);
4736
5013
  const isLocalePathname = match && match.length > 0;
4737
5014
  productPath = productPath.startsWith("/") ? productPath.substring(1) : productPath;
4738
- const path2 = isLocalePathname ? `${match[0]}${productPath}/${handle}` : `/${productPath}/${handle}`;
5015
+ const path = isLocalePathname ? `${match[0]}${productPath}/${handle}` : `/${productPath}/${handle}`;
4739
5016
  const searchParams = new URLSearchParams(
4740
5017
  // Remix doesn't update the location until pending loaders complete.
4741
5018
  // By default we use the destination search params to make selecting a variant
@@ -4748,8 +5025,8 @@ function useVariantPath(handle, productPath, waitForNavigation) {
4748
5025
  // If the current pathname matches the product page, we need to make sure
4749
5026
  // that we append to the current search params. Otherwise all the search
4750
5027
  // params can be generated new.
4751
- alreadyOnProductPage: path2 === pathname,
4752
- path: path2
5028
+ alreadyOnProductPage: path === pathname,
5029
+ path
4753
5030
  };
4754
5031
  }, [pathname, search, waitForNavigation, handle, productPath, navigation]);
4755
5032
  }
@@ -4764,10 +5041,10 @@ function hydrogenPreset() {
4764
5041
  ssr: true,
4765
5042
  future: {
4766
5043
  v8_middleware: true,
5044
+ v8_splitRouteModules: true,
5045
+ v8_viteEnvironmentApi: false,
4767
5046
  unstable_optimizeDeps: true,
4768
- unstable_splitRouteModules: true,
4769
- unstable_subResourceIntegrity: false,
4770
- unstable_viteEnvironmentApi: false
5047
+ unstable_subResourceIntegrity: false
4771
5048
  }
4772
5049
  }),
4773
5050
  reactRouterConfigResolved: ({ reactRouterConfig }) => {
@@ -4783,7 +5060,7 @@ function hydrogenPreset() {
4783
5060
  }
4784
5061
  if (reactRouterConfig.serverBundles) {
4785
5062
  throw new Error(
4786
- "[Hydrogen Preset] serverBundles is not supported in Hydrogen 2025.7.0.\nReason: React Router plugin manifest incompatibility with Hydrogen CLI.\nAlternative: Route-level code splitting via unstable_splitRouteModules is enabled."
5063
+ "[Hydrogen Preset] serverBundles is not supported in Hydrogen 2025.7.0.\nReason: React Router plugin manifest incompatibility with Hydrogen CLI.\nAlternative: Route-level code splitting via v8_splitRouteModules is enabled."
4787
5064
  );
4788
5065
  }
4789
5066
  if (reactRouterConfig.buildEnd) {
@@ -5298,10 +5575,10 @@ var schema = {
5298
5575
  if (typeof value !== "string") {
5299
5576
  throw new Error(ERROR_PREFIX.concat("`title` should be a string"));
5300
5577
  }
5301
- if (typeof value === "string" && value.length > 120) {
5578
+ if (typeof value === "string" && value.length > 70) {
5302
5579
  throw new Error(
5303
5580
  ERROR_PREFIX.concat(
5304
- "`title` should not be longer than 120 characters"
5581
+ "`title` should not be longer than 70 characters"
5305
5582
  )
5306
5583
  );
5307
5584
  }
@@ -5318,7 +5595,7 @@ var schema = {
5318
5595
  if (typeof value === "string" && value.length > 155) {
5319
5596
  throw new Error(
5320
5597
  ERROR_PREFIX.concat(
5321
- "`description` should not be longer than 155 characters"
5598
+ "`description` should not be longer than 160 characters"
5322
5599
  )
5323
5600
  );
5324
5601
  }
@@ -6262,6 +6539,10 @@ Object.defineProperty(exports, "getShopifyCookies", {
6262
6539
  enumerable: true,
6263
6540
  get: function () { return hydrogenReact.getShopifyCookies; }
6264
6541
  });
6542
+ Object.defineProperty(exports, "getTrackingValues", {
6543
+ enumerable: true,
6544
+ get: function () { return hydrogenReact.getTrackingValues; }
6545
+ });
6265
6546
  Object.defineProperty(exports, "isOptionValueCombinationInEncodedVariant", {
6266
6547
  enumerable: true,
6267
6548
  get: function () { return hydrogenReact.isOptionValueCombinationInEncodedVariant; }
@@ -6339,6 +6620,7 @@ exports.createCartHandler = createCartHandler;
6339
6620
  exports.createContentSecurityPolicy = createContentSecurityPolicy;
6340
6621
  exports.createCustomerAccountClient = createCustomerAccountClient;
6341
6622
  exports.createHydrogenContext = createHydrogenContext;
6623
+ exports.createRequestHandler = createRequestHandler;
6342
6624
  exports.createStorefrontClient = createStorefrontClient;
6343
6625
  exports.createWithCache = createWithCache;
6344
6626
  exports.formatAPIResult = formatAPIResult;