@shopify/hydrogen-react 2025.1.3 → 2025.1.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.
Files changed (101) hide show
  1. package/dist/browser-dev/ShopifyProvider.mjs +18 -1
  2. package/dist/browser-dev/ShopifyProvider.mjs.map +1 -1
  3. package/dist/browser-dev/analytics.mjs +4 -5
  4. package/dist/browser-dev/analytics.mjs.map +1 -1
  5. package/dist/browser-dev/cart-hooks.mjs +25 -7
  6. package/dist/browser-dev/cart-hooks.mjs.map +1 -1
  7. package/dist/browser-dev/cookies-utils.mjs +4 -4
  8. package/dist/browser-dev/cookies-utils.mjs.map +1 -1
  9. package/dist/browser-dev/index.mjs +4 -0
  10. package/dist/browser-dev/index.mjs.map +1 -1
  11. package/dist/browser-dev/packages/hydrogen-react/package.json.mjs +1 -1
  12. package/dist/browser-dev/tracking-utils.mjs +88 -0
  13. package/dist/browser-dev/tracking-utils.mjs.map +1 -0
  14. package/dist/browser-dev/useShopifyCookies.mjs +96 -9
  15. package/dist/browser-dev/useShopifyCookies.mjs.map +1 -1
  16. package/dist/browser-prod/ShopifyProvider.mjs +18 -1
  17. package/dist/browser-prod/ShopifyProvider.mjs.map +1 -1
  18. package/dist/browser-prod/analytics.mjs +4 -5
  19. package/dist/browser-prod/analytics.mjs.map +1 -1
  20. package/dist/browser-prod/cart-hooks.mjs +25 -7
  21. package/dist/browser-prod/cart-hooks.mjs.map +1 -1
  22. package/dist/browser-prod/cookies-utils.mjs +4 -4
  23. package/dist/browser-prod/cookies-utils.mjs.map +1 -1
  24. package/dist/browser-prod/index.mjs +4 -0
  25. package/dist/browser-prod/index.mjs.map +1 -1
  26. package/dist/browser-prod/packages/hydrogen-react/package.json.mjs +1 -1
  27. package/dist/browser-prod/tracking-utils.mjs +88 -0
  28. package/dist/browser-prod/tracking-utils.mjs.map +1 -0
  29. package/dist/browser-prod/useShopifyCookies.mjs +96 -9
  30. package/dist/browser-prod/useShopifyCookies.mjs.map +1 -1
  31. package/dist/node-dev/ShopifyProvider.js +18 -1
  32. package/dist/node-dev/ShopifyProvider.js.map +1 -1
  33. package/dist/node-dev/ShopifyProvider.mjs +18 -1
  34. package/dist/node-dev/ShopifyProvider.mjs.map +1 -1
  35. package/dist/node-dev/analytics.js +4 -5
  36. package/dist/node-dev/analytics.js.map +1 -1
  37. package/dist/node-dev/analytics.mjs +4 -5
  38. package/dist/node-dev/analytics.mjs.map +1 -1
  39. package/dist/node-dev/cart-hooks.js +24 -6
  40. package/dist/node-dev/cart-hooks.js.map +1 -1
  41. package/dist/node-dev/cart-hooks.mjs +25 -7
  42. package/dist/node-dev/cart-hooks.mjs.map +1 -1
  43. package/dist/node-dev/cookies-utils.js +4 -4
  44. package/dist/node-dev/cookies-utils.js.map +1 -1
  45. package/dist/node-dev/cookies-utils.mjs +4 -4
  46. package/dist/node-dev/cookies-utils.mjs.map +1 -1
  47. package/dist/node-dev/index.js +4 -0
  48. package/dist/node-dev/index.js.map +1 -1
  49. package/dist/node-dev/index.mjs +4 -0
  50. package/dist/node-dev/index.mjs.map +1 -1
  51. package/dist/node-dev/packages/hydrogen-react/package.json.js +1 -1
  52. package/dist/node-dev/packages/hydrogen-react/package.json.mjs +1 -1
  53. package/dist/node-dev/tracking-utils.js +88 -0
  54. package/dist/node-dev/tracking-utils.js.map +1 -0
  55. package/dist/node-dev/tracking-utils.mjs +88 -0
  56. package/dist/node-dev/tracking-utils.mjs.map +1 -0
  57. package/dist/node-dev/useShopifyCookies.js +94 -7
  58. package/dist/node-dev/useShopifyCookies.js.map +1 -1
  59. package/dist/node-dev/useShopifyCookies.mjs +96 -9
  60. package/dist/node-dev/useShopifyCookies.mjs.map +1 -1
  61. package/dist/node-prod/ShopifyProvider.js +18 -1
  62. package/dist/node-prod/ShopifyProvider.js.map +1 -1
  63. package/dist/node-prod/ShopifyProvider.mjs +18 -1
  64. package/dist/node-prod/ShopifyProvider.mjs.map +1 -1
  65. package/dist/node-prod/analytics.js +4 -5
  66. package/dist/node-prod/analytics.js.map +1 -1
  67. package/dist/node-prod/analytics.mjs +4 -5
  68. package/dist/node-prod/analytics.mjs.map +1 -1
  69. package/dist/node-prod/cart-hooks.js +24 -6
  70. package/dist/node-prod/cart-hooks.js.map +1 -1
  71. package/dist/node-prod/cart-hooks.mjs +25 -7
  72. package/dist/node-prod/cart-hooks.mjs.map +1 -1
  73. package/dist/node-prod/cookies-utils.js +4 -4
  74. package/dist/node-prod/cookies-utils.js.map +1 -1
  75. package/dist/node-prod/cookies-utils.mjs +4 -4
  76. package/dist/node-prod/cookies-utils.mjs.map +1 -1
  77. package/dist/node-prod/index.js +4 -0
  78. package/dist/node-prod/index.js.map +1 -1
  79. package/dist/node-prod/index.mjs +4 -0
  80. package/dist/node-prod/index.mjs.map +1 -1
  81. package/dist/node-prod/packages/hydrogen-react/package.json.js +1 -1
  82. package/dist/node-prod/packages/hydrogen-react/package.json.mjs +1 -1
  83. package/dist/node-prod/tracking-utils.js +88 -0
  84. package/dist/node-prod/tracking-utils.js.map +1 -0
  85. package/dist/node-prod/tracking-utils.mjs +88 -0
  86. package/dist/node-prod/tracking-utils.mjs.map +1 -0
  87. package/dist/node-prod/useShopifyCookies.js +94 -7
  88. package/dist/node-prod/useShopifyCookies.js.map +1 -1
  89. package/dist/node-prod/useShopifyCookies.mjs +96 -9
  90. package/dist/node-prod/useShopifyCookies.mjs.map +1 -1
  91. package/dist/types/ShopifyProvider.d.ts +5 -0
  92. package/dist/types/cookies-utils.d.ts +4 -0
  93. package/dist/types/index.d.cts +1 -0
  94. package/dist/types/index.d.ts +1 -0
  95. package/dist/types/tracking-utils.d.ts +22 -0
  96. package/dist/types/useShopifyCookies.d.ts +28 -2
  97. package/dist/umd/hydrogen-react.dev.js +271 -89
  98. package/dist/umd/hydrogen-react.dev.js.map +1 -1
  99. package/dist/umd/hydrogen-react.prod.js +18 -18
  100. package/dist/umd/hydrogen-react.prod.js.map +1 -1
  101. package/package.json +2 -2
@@ -69,7 +69,7 @@
69
69
  return t2 === n2;
70
70
  };
71
71
  }
72
- function u$1(t2) {
72
+ function u(t2) {
73
73
  return "string" == typeof t2 ? { type: t2 } : t2;
74
74
  }
75
75
  function c(t2, n2) {
@@ -93,7 +93,7 @@
93
93
  var s2 = t(f(r(n2.states[n2.initial].entry).map(function(t2) {
94
94
  return o(t2, i2.actions);
95
95
  }), n2.context, e), 2), l2 = s2[0], v2 = s2[1], y = { config: n2, _options: i2, initialState: { value: n2.initial, actions: l2, context: v2, matches: a(n2.initial) }, transition: function(e2, i3) {
96
- var s3, l3, v3 = "string" == typeof e2 ? { value: e2, context: n2.context } : e2, p = v3.value, g2 = v3.context, d = u$1(i3), x = n2.states[p];
96
+ var s3, l3, v3 = "string" == typeof e2 ? { value: e2, context: n2.context } : e2, p = v3.value, g = v3.context, d = u(i3), x = n2.states[p];
97
97
  if (x.on) {
98
98
  var m = r(x.on[d.type]);
99
99
  try {
@@ -106,16 +106,16 @@
106
106
  throw new TypeError(n3 ? "Object is not iterable." : "Symbol.iterator is not defined.");
107
107
  }(m), b = h.next(); !b.done; b = h.next()) {
108
108
  var S = b.value;
109
- if (void 0 === S) return c(p, g2);
109
+ if (void 0 === S) return c(p, g);
110
110
  var w = "string" == typeof S ? { target: S } : S, j = w.target, E = w.actions, R = void 0 === E ? [] : E, N = w.cond, O = void 0 === N ? function() {
111
111
  return true;
112
112
  } : N, _ = void 0 === j, k = null != j ? j : p, T = n2.states[k];
113
- if (O(g2, d)) {
113
+ if (O(g, d)) {
114
114
  var q = t(f((_ ? r(R) : [].concat(x.exit, R, T.entry).filter(function(t2) {
115
115
  return t2;
116
116
  })).map(function(t2) {
117
117
  return o(t2, y._options.actions);
118
- }), g2, d), 3), z = q[0], A = q[1], B = q[2], C = null != j ? j : p;
118
+ }), g, d), 3), z = q[0], A = q[1], B = q[2], C = null != j ? j : p;
119
119
  return { value: C, context: A, actions: z, changed: j !== p || z.length > 0 || B, matches: a(C) };
120
120
  }
121
121
  }
@@ -129,7 +129,7 @@
129
129
  }
130
130
  }
131
131
  }
132
- return c(p, g2);
132
+ return c(p, g);
133
133
  } };
134
134
  return y;
135
135
  }
@@ -141,7 +141,7 @@
141
141
  };
142
142
  function v(t2) {
143
143
  var r2 = t2.initialState, i2 = n.NotStarted, o2 = /* @__PURE__ */ new Set(), c2 = { _machine: t2, send: function(e2) {
144
- i2 === n.Running && (r2 = t2.transition(r2, e2), l$1(r2, u$1(e2)), o2.forEach(function(t3) {
144
+ i2 === n.Running && (r2 = t2.transition(r2, e2), l$1(r2, u(e2)), o2.forEach(function(t3) {
145
145
  return t3(r2);
146
146
  }));
147
147
  }, subscribe: function(t3) {
@@ -929,6 +929,21 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
929
929
  const ShopifyContext = React$1.createContext(
930
930
  defaultShopifyContext
931
931
  );
932
+ function isSfapiProxyEnabled() {
933
+ var _a, _b, _c;
934
+ if (typeof window === "undefined") return false;
935
+ try {
936
+ const navigationEntry = (_b = (_a = window.performance) == null ? void 0 : _a.getEntriesByType) == null ? void 0 : _b.call(
937
+ _a,
938
+ "navigation"
939
+ )[0];
940
+ return !!((_c = navigationEntry == null ? void 0 : navigationEntry.serverTiming) == null ? void 0 : _c.some(
941
+ (entry) => entry.name === "_sfapi_proxy"
942
+ ));
943
+ } catch (e2) {
944
+ return false;
945
+ }
946
+ }
932
947
  function ShopifyProvider({
933
948
  children,
934
949
  ...shopifyConfig
@@ -944,12 +959,14 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
944
959
  );
945
960
  }
946
961
  const finalConfig = React$1.useMemo(() => {
962
+ const sameDomainForStorefrontApi = shopifyConfig.sameDomainForStorefrontApi ?? isSfapiProxyEnabled();
947
963
  function getShopifyDomain(overrideProps) {
948
964
  const domain = (overrideProps == null ? void 0 : overrideProps.storeDomain) ?? shopifyConfig.storeDomain;
949
965
  return domain.includes("://") ? domain : `https://${domain}`;
950
966
  }
951
967
  return {
952
968
  ...shopifyConfig,
969
+ sameDomainForStorefrontApi,
953
970
  getPublicTokenHeaders(overrideProps) {
954
971
  return getPublicTokenHeadersRaw(
955
972
  overrideProps.contentType,
@@ -959,7 +976,7 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
959
976
  },
960
977
  getShopifyDomain,
961
978
  getStorefrontApiUrl(overrideProps) {
962
- const finalDomainUrl = getShopifyDomain({
979
+ const finalDomainUrl = sameDomainForStorefrontApi && typeof window !== "undefined" ? window.location.origin : getShopifyDomain({
963
980
  storeDomain: (overrideProps == null ? void 0 : overrideProps.storeDomain) ?? shopifyConfig.storeDomain
964
981
  });
965
982
  return `${finalDomainUrl}${finalDomainUrl.endsWith("/") ? "" : "/"}api/${(overrideProps == null ? void 0 : overrideProps.storefrontApiVersion) ?? shopifyConfig.storefrontApiVersion}/graphql.json`;
@@ -981,77 +998,94 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
981
998
  const SHOPIFY_STOREFRONT_S_HEADER = "Shopify-Storefront-S";
982
999
  const SHOPIFY_Y = "_shopify_y";
983
1000
  const SHOPIFY_S = "_shopify_s";
984
- var g = /* @__PURE__ */ new Set([
985
- "domain",
986
- "path",
987
- "max-age",
988
- "expires",
989
- "samesite",
990
- "secure",
991
- "httponly"
992
- ]);
993
- function u(a2) {
994
- let r2 = {}, e2, t2, n2 = 0, m = a2.split(/;\s*/g), s2, i2;
995
- for (; n2 < m.length; n2++)
996
- if (t2 = m[n2], e2 = t2.indexOf("="), ~e2) {
997
- if (s2 = t2.substring(0, e2++).trim(), i2 = t2.substring(e2).trim(), i2[0] === '"' && (i2 = i2.substring(1, i2.length - 1)), ~i2.indexOf("%"))
998
- try {
999
- i2 = decodeURIComponent(i2);
1000
- } catch (f2) {
1001
+ const SHOPIFY_VISIT_TOKEN_HEADER = "X-Shopify-VisitToken";
1002
+ const SHOPIFY_UNIQUE_TOKEN_HEADER = "X-Shopify-UniqueToken";
1003
+ const cachedTrackingValues = { current: null };
1004
+ function getTrackingValues(cookieString) {
1005
+ var _a, _b, _c;
1006
+ let trackingValues;
1007
+ if (typeof window !== "undefined" && typeof window.performance !== "undefined") {
1008
+ try {
1009
+ const resourceRE = /^https?:\/\/([^/]+)(\/api\/(?:unstable|2\d{3}-\d{2})\/graphql\.json(?=$|\?))?/;
1010
+ const entries = performance.getEntriesByType(
1011
+ "resource"
1012
+ );
1013
+ let matchedValues;
1014
+ for (let i2 = entries.length - 1; i2 >= 0; i2--) {
1015
+ const entry = entries[i2];
1016
+ if (entry.initiatorType !== "fetch") continue;
1017
+ const currentHost = window.location.host;
1018
+ const match = entry.name.match(resourceRE);
1019
+ if (!match) continue;
1020
+ const [, matchedHost, sfapiPath] = match;
1021
+ const isMatch = (
1022
+ // Same origin (exact host match)
1023
+ matchedHost === currentHost || // Subdomain with SFAPI path
1024
+ sfapiPath && (matchedHost == null ? void 0 : matchedHost.endsWith(`.${currentHost}`))
1025
+ );
1026
+ if (isMatch) {
1027
+ const values = extractFromPerformanceEntry(entry);
1028
+ if (values) {
1029
+ matchedValues = values;
1030
+ break;
1031
+ }
1001
1032
  }
1002
- g.has(t2 = s2.toLowerCase()) ? t2 === "expires" ? r2.expires = new Date(i2) : t2 === "max-age" ? r2.maxage = +i2 : r2[t2] = i2 : r2[s2] = i2;
1003
- } else
1004
- (s2 = t2.trim().toLowerCase()) && (s2 === "httponly" || s2 === "secure") && (r2[s2] = true);
1005
- return r2;
1006
- }
1007
- function l(a2, r2, e2 = {}) {
1008
- let t2 = a2 + "=" + encodeURIComponent(r2);
1009
- return e2.expires && (t2 += "; Expires=" + new Date(e2.expires).toUTCString()), e2.maxage != null && e2.maxage >= 0 && (t2 += "; Max-Age=" + (e2.maxage | 0)), e2.domain && (t2 += "; Domain=" + e2.domain), e2.path && (t2 += "; Path=" + e2.path), e2.samesite && (t2 += "; SameSite=" + e2.samesite), (e2.secure || e2.samesite === "None") && (t2 += "; Secure"), e2.httponly && (t2 += "; HttpOnly"), t2;
1010
- }
1011
- const tokenHash = "xxxx-4xxx-xxxx-xxxxxxxxxxxx";
1012
- function buildUUID() {
1013
- let hash = "";
1014
- try {
1015
- const crypto = window.crypto;
1016
- const randomValuesArray = new Uint16Array(31);
1017
- crypto.getRandomValues(randomValuesArray);
1018
- let i2 = 0;
1019
- hash = tokenHash.replace(/[x]/g, (c2) => {
1020
- const r2 = randomValuesArray[i2] % 16;
1021
- const v2 = c2 === "x" ? r2 : r2 & 3 | 8;
1022
- i2++;
1023
- return v2.toString(16);
1024
- }).toUpperCase();
1025
- } catch (err) {
1026
- hash = tokenHash.replace(/[x]/g, (c2) => {
1027
- const r2 = Math.random() * 16 | 0;
1028
- const v2 = c2 === "x" ? r2 : r2 & 3 | 8;
1029
- return v2.toString(16);
1030
- }).toUpperCase();
1033
+ }
1034
+ if (matchedValues) {
1035
+ trackingValues = matchedValues;
1036
+ }
1037
+ if (trackingValues) {
1038
+ cachedTrackingValues.current = trackingValues;
1039
+ } else if (cachedTrackingValues.current) {
1040
+ trackingValues = cachedTrackingValues.current;
1041
+ }
1042
+ if (!trackingValues) {
1043
+ const navigationEntries = performance.getEntriesByType(
1044
+ "navigation"
1045
+ )[0];
1046
+ trackingValues = extractFromPerformanceEntry(navigationEntries, false);
1047
+ }
1048
+ } catch {
1049
+ }
1031
1050
  }
1032
- return `${hexTime()}-${hash}`;
1033
- }
1034
- function hexTime() {
1035
- let dateNumber = 0;
1036
- let perfNumber = 0;
1037
- dateNumber = (/* @__PURE__ */ new Date()).getTime() >>> 0;
1038
- try {
1039
- perfNumber = performance.now() >>> 0;
1040
- } catch (err) {
1041
- perfNumber = 0;
1051
+ if (!trackingValues) {
1052
+ const cookie = typeof cookieString === "string" ? cookieString : typeof document !== "undefined" ? document.cookie : "";
1053
+ trackingValues = {
1054
+ uniqueToken: ((_a = cookie.match(/\b_shopify_y=([^;]+)/)) == null ? void 0 : _a[1]) || "",
1055
+ visitToken: ((_b = cookie.match(/\b_shopify_s=([^;]+)/)) == null ? void 0 : _b[1]) || "",
1056
+ consent: ((_c = cookie.match(/\b_tracking_consent=([^;]+)/)) == null ? void 0 : _c[1]) || ""
1057
+ };
1042
1058
  }
1043
- const output = Math.abs(dateNumber + perfNumber).toString(16).toLowerCase();
1044
- return output.padStart(8, "0");
1045
- }
1046
- function getShopifyCookies(cookies) {
1047
- const cookieData = u(cookies);
1048
- return {
1049
- [SHOPIFY_Y]: cookieData[SHOPIFY_Y] || "",
1050
- [SHOPIFY_S]: cookieData[SHOPIFY_S] || ""
1051
- };
1059
+ return trackingValues;
1060
+ }
1061
+ function extractFromPerformanceEntry(entry, isConsentRequired = true) {
1062
+ let uniqueToken = "";
1063
+ let visitToken = "";
1064
+ let consent = "";
1065
+ const serverTiming = entry.serverTiming;
1066
+ if (serverTiming && serverTiming.length >= 3) {
1067
+ for (let i2 = serverTiming.length - 1; i2 >= 0; i2--) {
1068
+ const { name, description } = serverTiming[i2];
1069
+ if (!name || !description) continue;
1070
+ if (name === "_y") {
1071
+ uniqueToken = description;
1072
+ } else if (name === "_s") {
1073
+ visitToken = description;
1074
+ } else if (name === "_cmp") {
1075
+ consent = description;
1076
+ }
1077
+ if (uniqueToken && visitToken && consent) break;
1078
+ }
1079
+ }
1080
+ return uniqueToken && visitToken && (isConsentRequired ? consent : true) ? { uniqueToken, visitToken, consent } : void 0;
1052
1081
  }
1053
1082
  function useCartFetch() {
1054
- const { storefrontId, getPublicTokenHeaders, getStorefrontApiUrl } = useShop();
1083
+ const {
1084
+ storefrontId,
1085
+ getPublicTokenHeaders,
1086
+ getStorefrontApiUrl,
1087
+ sameDomainForStorefrontApi
1088
+ } = useShop();
1055
1089
  return React$1.useCallback(
1056
1090
  ({
1057
1091
  query,
@@ -1061,9 +1095,17 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
1061
1095
  if (storefrontId) {
1062
1096
  headers[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
1063
1097
  }
1064
- const cookieData = getShopifyCookies(document.cookie);
1065
- headers[SHOPIFY_STOREFRONT_Y_HEADER] = cookieData[SHOPIFY_Y];
1066
- headers[SHOPIFY_STOREFRONT_S_HEADER] = cookieData[SHOPIFY_S];
1098
+ if (!sameDomainForStorefrontApi) {
1099
+ const { uniqueToken, visitToken } = getTrackingValues();
1100
+ if (uniqueToken) {
1101
+ headers[SHOPIFY_STOREFRONT_Y_HEADER] = uniqueToken;
1102
+ headers[SHOPIFY_UNIQUE_TOKEN_HEADER] = uniqueToken;
1103
+ }
1104
+ if (visitToken) {
1105
+ headers[SHOPIFY_STOREFRONT_S_HEADER] = visitToken;
1106
+ headers[SHOPIFY_VISIT_TOKEN_HEADER] = visitToken;
1107
+ }
1108
+ }
1067
1109
  return fetch(getStorefrontApiUrl(), {
1068
1110
  method: "POST",
1069
1111
  headers,
@@ -1081,7 +1123,12 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
1081
1123
  };
1082
1124
  });
1083
1125
  },
1084
- [getPublicTokenHeaders, storefrontId, getStorefrontApiUrl]
1126
+ [
1127
+ getPublicTokenHeaders,
1128
+ storefrontId,
1129
+ getStorefrontApiUrl,
1130
+ sameDomainForStorefrontApi
1131
+ ]
1085
1132
  );
1086
1133
  }
1087
1134
  function useCartActions({
@@ -2358,6 +2405,48 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
2358
2405
  }
2359
2406
  return false;
2360
2407
  }
2408
+ const tokenHash = "xxxx-4xxx-xxxx-xxxxxxxxxxxx";
2409
+ function buildUUID() {
2410
+ let hash = "";
2411
+ try {
2412
+ const crypto = window.crypto;
2413
+ const randomValuesArray = new Uint16Array(31);
2414
+ crypto.getRandomValues(randomValuesArray);
2415
+ let i2 = 0;
2416
+ hash = tokenHash.replace(/[x]/g, (c2) => {
2417
+ const r2 = randomValuesArray[i2] % 16;
2418
+ const v2 = c2 === "x" ? r2 : r2 & 3 | 8;
2419
+ i2++;
2420
+ return v2.toString(16);
2421
+ }).toUpperCase();
2422
+ } catch (err) {
2423
+ hash = tokenHash.replace(/[x]/g, (c2) => {
2424
+ const r2 = Math.random() * 16 | 0;
2425
+ const v2 = c2 === "x" ? r2 : r2 & 3 | 8;
2426
+ return v2.toString(16);
2427
+ }).toUpperCase();
2428
+ }
2429
+ return `${hexTime()}-${hash}`;
2430
+ }
2431
+ function hexTime() {
2432
+ let dateNumber = 0;
2433
+ let perfNumber = 0;
2434
+ dateNumber = (/* @__PURE__ */ new Date()).getTime() >>> 0;
2435
+ try {
2436
+ perfNumber = performance.now() >>> 0;
2437
+ } catch (err) {
2438
+ perfNumber = 0;
2439
+ }
2440
+ const output = Math.abs(dateNumber + perfNumber).toString(16).toLowerCase();
2441
+ return output.padStart(8, "0");
2442
+ }
2443
+ function getShopifyCookies(cookies) {
2444
+ const trackingValues = getTrackingValues(cookies);
2445
+ return {
2446
+ [SHOPIFY_Y]: trackingValues.uniqueToken,
2447
+ [SHOPIFY_S]: trackingValues.visitToken
2448
+ };
2449
+ }
2361
2450
  const SCHEMA_ID$1 = "trekkie_storefront_page_view/1.4";
2362
2451
  const OXYGEN_DOMAIN = "myshopify.dev";
2363
2452
  function pageView$1(payload) {
@@ -2409,7 +2498,7 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
2409
2498
  }
2410
2499
  return false;
2411
2500
  }
2412
- const version = "2025.1.3";
2501
+ const version = "2025.1.4";
2413
2502
  const SCHEMA_ID = "custom_storefront_customer_tracking/1.2";
2414
2503
  const PAGE_RENDERED_EVENT_NAME = "page_rendered";
2415
2504
  const COLLECTION_PAGE_RENDERED_EVENT_NAME = "collection_page_rendered";
@@ -2727,10 +2816,10 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
2727
2816
  };
2728
2817
  }
2729
2818
  const [navigationType, navigationApi] = getNavigationType();
2730
- const cookies = getShopifyCookies(document.cookie);
2819
+ const trackingValues = getTrackingValues();
2731
2820
  return {
2732
- uniqueToken: cookies[SHOPIFY_Y],
2733
- visitToken: cookies[SHOPIFY_S],
2821
+ uniqueToken: trackingValues.uniqueToken,
2822
+ visitToken: trackingValues.visitToken,
2734
2823
  url: location.href,
2735
2824
  path: location.pathname,
2736
2825
  search: location.search,
@@ -4557,17 +4646,29 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4557
4646
  }, [JSON.stringify(selectedOptions)]);
4558
4647
  return null;
4559
4648
  }
4649
+ function l(a2, r2, e2 = {}) {
4650
+ let t2 = a2 + "=" + encodeURIComponent(r2);
4651
+ return e2.expires && (t2 += "; Expires=" + new Date(e2.expires).toUTCString()), e2.maxage != null && e2.maxage >= 0 && (t2 += "; Max-Age=" + (e2.maxage | 0)), e2.domain && (t2 += "; Domain=" + e2.domain), e2.path && (t2 += "; Path=" + e2.path), e2.samesite && (t2 += "; SameSite=" + e2.samesite), (e2.secure || e2.samesite === "None") && (t2 += "; Secure"), e2.httponly && (t2 += "; HttpOnly"), t2;
4652
+ }
4560
4653
  const longTermLength = 60 * 60 * 24 * 360 * 1;
4561
4654
  const shortTermLength = 60 * 30;
4562
4655
  function useShopifyCookies(options) {
4563
4656
  const {
4564
- hasUserConsent = false,
4657
+ hasUserConsent,
4565
4658
  domain = "",
4566
- checkoutDomain = ""
4659
+ checkoutDomain = "",
4660
+ storefrontAccessToken,
4661
+ fetchTrackingValues,
4662
+ ignoreDeprecatedCookies = false
4567
4663
  } = options || {};
4664
+ const coreCookiesReady = useCoreShopifyCookies({
4665
+ storefrontAccessToken,
4666
+ fetchTrackingValues,
4667
+ checkoutDomain
4668
+ });
4568
4669
  React$1.useEffect(() => {
4569
- const cookies = getShopifyCookies(document.cookie);
4570
- let currentDomain = domain || window.document.location.host;
4670
+ if (ignoreDeprecatedCookies || !coreCookiesReady) return;
4671
+ let currentDomain = domain || window.location.host;
4571
4672
  if (checkoutDomain) {
4572
4673
  const checkoutDomainParts = checkoutDomain.split(".").reverse();
4573
4674
  const currentDomainParts = currentDomain.split(".").reverse();
@@ -4582,15 +4683,19 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4582
4683
  if (/^localhost/.test(currentDomain)) currentDomain = "";
4583
4684
  const domainWithLeadingDot = currentDomain ? /^\./.test(currentDomain) ? currentDomain : `.${currentDomain}` : "";
4584
4685
  if (hasUserConsent) {
4686
+ const trackingValues = getTrackingValues();
4687
+ if ((trackingValues.uniqueToken || trackingValues.visitToken || "").startsWith("00000000-")) {
4688
+ return;
4689
+ }
4585
4690
  setCookie(
4586
4691
  SHOPIFY_Y,
4587
- cookies[SHOPIFY_Y] || buildUUID(),
4692
+ trackingValues.uniqueToken || buildUUID(),
4588
4693
  longTermLength,
4589
4694
  domainWithLeadingDot
4590
4695
  );
4591
4696
  setCookie(
4592
4697
  SHOPIFY_S,
4593
- cookies[SHOPIFY_S] || buildUUID(),
4698
+ trackingValues.visitToken || buildUUID(),
4594
4699
  shortTermLength,
4595
4700
  domainWithLeadingDot
4596
4701
  );
@@ -4598,7 +4703,14 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4598
4703
  setCookie(SHOPIFY_Y, "", 0, domainWithLeadingDot);
4599
4704
  setCookie(SHOPIFY_S, "", 0, domainWithLeadingDot);
4600
4705
  }
4601
- }, [options, hasUserConsent, domain, checkoutDomain]);
4706
+ }, [
4707
+ coreCookiesReady,
4708
+ hasUserConsent,
4709
+ domain,
4710
+ checkoutDomain,
4711
+ ignoreDeprecatedCookies
4712
+ ]);
4713
+ return coreCookiesReady;
4602
4714
  }
4603
4715
  function setCookie(name, value, maxage, domain) {
4604
4716
  document.cookie = l(name, value, {
@@ -4608,6 +4720,73 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4608
4720
  path: "/"
4609
4721
  });
4610
4722
  }
4723
+ async function fetchTrackingValuesFromBrowser(storefrontAccessToken, storefrontApiDomain = "") {
4724
+ const { uniqueToken, visitToken } = getTrackingValues();
4725
+ const response = await fetch(
4726
+ // TODO: update this endpoint when it becomes stable
4727
+ `${storefrontApiDomain.replace(/\/+$/, "")}/api/unstable/graphql.json`,
4728
+ {
4729
+ method: "POST",
4730
+ headers: {
4731
+ "Content-Type": "application/json",
4732
+ ...storefrontAccessToken && {
4733
+ "X-Shopify-Storefront-Access-Token": storefrontAccessToken
4734
+ },
4735
+ ...visitToken || uniqueToken ? {
4736
+ [SHOPIFY_VISIT_TOKEN_HEADER]: visitToken,
4737
+ [SHOPIFY_UNIQUE_TOKEN_HEADER]: uniqueToken
4738
+ } : void 0
4739
+ },
4740
+ body: JSON.stringify({
4741
+ query: (
4742
+ // This query ensures we get _cmp (consent) server-timing header, which is not available in other queries.
4743
+ // This value can be passed later to consent-tracking-api and privacy-banner scripts to avoid extra requests.
4744
+ "query ensureCookies { consentManagement { cookies(visitorConsent:{}) { cookieDomain } } }"
4745
+ )
4746
+ })
4747
+ }
4748
+ );
4749
+ if (!response.ok) {
4750
+ throw new Error(
4751
+ `Failed to fetch consent from browser: ${response.status} ${response.statusText}`
4752
+ );
4753
+ }
4754
+ await response.json();
4755
+ getTrackingValues();
4756
+ }
4757
+ function useCoreShopifyCookies({
4758
+ checkoutDomain,
4759
+ storefrontAccessToken,
4760
+ fetchTrackingValues = false
4761
+ }) {
4762
+ const [cookiesReady, setCookiesReady] = React$1.useState(!fetchTrackingValues);
4763
+ const hasFetchedTrackingValues = React$1.useRef(false);
4764
+ React$1.useEffect(() => {
4765
+ if (!fetchTrackingValues) {
4766
+ setCookiesReady(true);
4767
+ return;
4768
+ }
4769
+ if (hasFetchedTrackingValues.current) return;
4770
+ hasFetchedTrackingValues.current = true;
4771
+ fetchTrackingValuesFromBrowser(storefrontAccessToken).catch(
4772
+ (error) => checkoutDomain ? (
4773
+ // Retry with checkout domain if available to at least
4774
+ // get the server-timing values for tracking.
4775
+ fetchTrackingValuesFromBrowser(
4776
+ storefrontAccessToken,
4777
+ checkoutDomain
4778
+ )
4779
+ ) : Promise.reject(error)
4780
+ ).catch((error) => {
4781
+ console.warn(
4782
+ "[h2:warn:useShopifyCookies] Failed to fetch tracking values from browser: " + (error instanceof Error ? error.message : String(error))
4783
+ );
4784
+ }).finally(() => {
4785
+ setCookiesReady(true);
4786
+ });
4787
+ }, [checkoutDomain, fetchTrackingValues, storefrontAccessToken]);
4788
+ return cookiesReady;
4789
+ }
4611
4790
  exports2.AddToCartButton = AddToCartButton;
4612
4791
  exports2.AnalyticsEventName = AnalyticsEventName;
4613
4792
  exports2.AnalyticsPageType = AnalyticsPageType;
@@ -4631,6 +4810,8 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4631
4810
  exports2.SHOPIFY_STOREFRONT_ID_HEADER = SHOPIFY_STOREFRONT_ID_HEADER;
4632
4811
  exports2.SHOPIFY_STOREFRONT_S_HEADER = SHOPIFY_STOREFRONT_S_HEADER;
4633
4812
  exports2.SHOPIFY_STOREFRONT_Y_HEADER = SHOPIFY_STOREFRONT_Y_HEADER;
4813
+ exports2.SHOPIFY_UNIQUE_TOKEN_HEADER = SHOPIFY_UNIQUE_TOKEN_HEADER;
4814
+ exports2.SHOPIFY_VISIT_TOKEN_HEADER = SHOPIFY_VISIT_TOKEN_HEADER;
4634
4815
  exports2.SHOPIFY_Y = SHOPIFY_Y;
4635
4816
  exports2.ShopPayButton = ShopPayButton;
4636
4817
  exports2.ShopifyProvider = ShopifyProvider;
@@ -4644,6 +4825,7 @@ Refer to the authentication https://shopify.dev/api/storefront#authentication do
4644
4825
  exports2.getClientBrowserParameters = getClientBrowserParameters;
4645
4826
  exports2.getProductOptions = getProductOptions;
4646
4827
  exports2.getShopifyCookies = getShopifyCookies;
4828
+ exports2.getTrackingValues = getTrackingValues;
4647
4829
  exports2.isOptionValueCombinationInEncodedVariant = isOptionValueCombinationInEncodedVariant;
4648
4830
  exports2.mapSelectedProductOptionToObject = mapSelectedProductOptionToObject;
4649
4831
  exports2.parseGid = parseGid;