@shopify/hydrogen 2024.4.0 → 2024.4.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.
@@ -5,10 +5,12 @@ var react = require('react');
5
5
  var react$1 = require('@remix-run/react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var cspBuilder = require('content-security-policy-builder');
8
+ var invariant = require('tiny-invariant');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
12
  var cspBuilder__default = /*#__PURE__*/_interopDefault(cspBuilder);
13
+ var invariant__default = /*#__PURE__*/_interopDefault(invariant);
12
14
 
13
15
  var __defProp = Object.defineProperty;
14
16
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -335,9 +337,10 @@ async function runWithCache(cacheKey, actionFn, {
335
337
  // '__HYDROGEN_CACHE_ID__', // TODO purgeQueryCacheOnBuild
336
338
  ...typeof cacheKey === "string" ? [cacheKey] : cacheKey
337
339
  ]);
338
- let debugData;
340
+ let cachedDebugInfo;
341
+ let userDebugInfo;
339
342
  const addDebugData = (info) => {
340
- debugData = {
343
+ userDebugInfo = {
341
344
  displayName: info.displayName,
342
345
  url: info.response?.url,
343
346
  responseInit: {
@@ -347,26 +350,31 @@ async function runWithCache(cacheKey, actionFn, {
347
350
  }
348
351
  };
349
352
  };
353
+ const mergeDebugInfo = () => ({
354
+ ...cachedDebugInfo,
355
+ ...debugInfo,
356
+ url: userDebugInfo?.url || debugInfo?.url || cachedDebugInfo?.url || getKeyUrl(key),
357
+ displayName: debugInfo?.displayName || userDebugInfo?.displayName || cachedDebugInfo?.displayName
358
+ });
350
359
  const logSubRequestEvent2 = ({
351
360
  result: result2,
352
361
  cacheStatus,
353
362
  overrideStartTime
354
363
  }) => {
355
364
  globalThis.__H2O_LOG_EVENT?.({
365
+ ...mergeDebugInfo(),
356
366
  eventType: "subrequest",
357
367
  startTime: overrideStartTime || startTime,
368
+ endTime: Date.now(),
358
369
  cacheStatus,
359
370
  responsePayload: result2 && result2[0] || result2,
360
- responseInit: result2 && result2[1] || debugData?.responseInit,
371
+ responseInit: result2 && result2[1] || userDebugInfo?.responseInit,
361
372
  cache: {
362
373
  status: cacheStatus,
363
374
  strategy: generateCacheControlHeader(strategy || {}),
364
375
  key
365
376
  },
366
- waitUntil,
367
- ...debugInfo,
368
- url: debugData?.url || debugInfo?.url || getKeyUrl(key),
369
- displayName: debugInfo?.displayName || debugData?.displayName
377
+ waitUntil
370
378
  });
371
379
  } ;
372
380
  if (!cacheInstance || !strategy || strategy.mode === NO_STORE) {
@@ -374,9 +382,19 @@ async function runWithCache(cacheKey, actionFn, {
374
382
  logSubRequestEvent2?.({ result: result2 });
375
383
  return result2;
376
384
  }
385
+ const storeInCache = (value) => setItemInCache(
386
+ cacheInstance,
387
+ key,
388
+ {
389
+ value,
390
+ debugInfo: mergeDebugInfo()
391
+ },
392
+ strategy
393
+ );
377
394
  const cachedItem = await getItemFromCache(cacheInstance, key);
378
- if (cachedItem) {
379
- const [cachedResult, cacheInfo] = cachedItem;
395
+ if (cachedItem && typeof cachedItem[0] !== "string") {
396
+ const [{ value: cachedResult, debugInfo: debugInfo2 }, cacheInfo] = cachedItem;
397
+ cachedDebugInfo = debugInfo2;
380
398
  const cacheStatus = isStale2(key, cacheInfo) ? "STALE" : "HIT";
381
399
  if (!swrLock.has(key) && cacheStatus === "STALE") {
382
400
  swrLock.add(key);
@@ -385,7 +403,7 @@ async function runWithCache(cacheKey, actionFn, {
385
403
  try {
386
404
  const result2 = await actionFn({ addDebugData });
387
405
  if (shouldCacheResult(result2)) {
388
- await setItemInCache(cacheInstance, key, result2, strategy);
406
+ await storeInCache(result2);
389
407
  logSubRequestEvent2?.({
390
408
  result: result2,
391
409
  cacheStatus: "PUT",
@@ -415,16 +433,16 @@ async function runWithCache(cacheKey, actionFn, {
415
433
  cacheStatus: "MISS"
416
434
  });
417
435
  if (shouldCacheResult(result)) {
418
- const setItemInCachePromise = Promise.resolve().then(async () => {
436
+ const cacheStoringPromise = Promise.resolve().then(async () => {
419
437
  const putStartTime = Date.now();
420
- await setItemInCache(cacheInstance, key, result, strategy);
438
+ await storeInCache(result);
421
439
  logSubRequestEvent2?.({
422
440
  result,
423
441
  cacheStatus: "PUT",
424
442
  overrideStartTime: putStartTime
425
443
  });
426
444
  });
427
- waitUntil?.(setItemInCachePromise);
445
+ waitUntil?.(cacheStoringPromise);
428
446
  }
429
447
  return result;
430
448
  }
@@ -466,12 +484,20 @@ async function fetchWithServerCache(url, requestInit, {
466
484
  ).then(fromSerializableResponse);
467
485
  }
468
486
 
487
+ // src/version.ts
488
+ var LIB_VERSION = "2024.4.2";
489
+
469
490
  // src/constants.ts
470
491
  var STOREFRONT_REQUEST_GROUP_ID_HEADER = "Custom-Storefront-Request-Group-ID";
471
492
  var STOREFRONT_ACCESS_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
472
493
  var SDK_VARIANT_HEADER = "X-SDK-Variant";
473
494
  var SDK_VARIANT_SOURCE_HEADER = "X-SDK-Variant-Source";
474
495
  var SDK_VERSION_HEADER = "X-SDK-Version";
496
+ var DEFAULT_CUSTOMER_API_VERSION = "2024-04";
497
+ var USER_AGENT = `Shopify Hydrogen ${LIB_VERSION}`;
498
+ var CUSTOMER_API_CLIENT_ID = "30243aa5-17c1-465a-8493-944bcc4e88aa";
499
+ var CUSTOMER_ACCOUNT_SESSION_KEY = "customerAccount";
500
+ var BUYER_SESSION_KEY = "buyer";
475
501
 
476
502
  // src/utils/uuid.ts
477
503
  function generateUUID() {
@@ -491,9 +517,6 @@ var warnOnce = (string) => {
491
517
  }
492
518
  };
493
519
 
494
- // src/version.ts
495
- var LIB_VERSION = "2024.4.0";
496
-
497
520
  // src/utils/graphql.ts
498
521
  function minifyQuery(string) {
499
522
  return string.replace(/\s*#.*$/gm, "").replace(/\s+/gm, " ").trim();
@@ -766,12 +789,12 @@ function createStorefrontClient(options) {
766
789
  shouldCacheResponse: checkGraphQLErrors,
767
790
  waitUntil,
768
791
  debugInfo: {
769
- url,
770
- graphql: graphqlData,
771
792
  requestId: requestInit.headers[STOREFRONT_REQUEST_GROUP_ID_HEADER],
772
- purpose: storefrontHeaders?.purpose,
793
+ displayName,
794
+ url,
773
795
  stackInfo,
774
- displayName
796
+ graphql: graphqlData,
797
+ purpose: storefrontHeaders?.purpose
775
798
  }
776
799
  });
777
800
  const errorOptions = {
@@ -1802,6 +1825,9 @@ var SeoLogger = react.lazy(() => Promise.resolve().then(() => (init_log_seo_tags
1802
1825
  function Seo({ debug }) {
1803
1826
  const matches = react$1.useMatches();
1804
1827
  const location = react$1.useLocation();
1828
+ console.warn(
1829
+ "[h2:warn:Seo] The `<Seo/>` component is deprecated. Use `getSeoMeta` instead.\nSee: https://shopify.dev/docs/api/hydrogen/2024-01/utilities/getseometa"
1830
+ );
1805
1831
  const seoConfig = react.useMemo(() => {
1806
1832
  return matches.flatMap((match) => {
1807
1833
  const { handle, ...routeMatch } = match;
@@ -2276,12 +2302,6 @@ function getPaginationVariables(request, options = { pageBy: 20 }) {
2276
2302
  return variables;
2277
2303
  }
2278
2304
 
2279
- // src/customer/constants.ts
2280
- var DEFAULT_CUSTOMER_API_VERSION = "2024-04";
2281
- var USER_AGENT = `Shopify Hydrogen ${LIB_VERSION}`;
2282
- var CUSTOMER_API_CLIENT_ID = "30243aa5-17c1-465a-8493-944bcc4e88aa";
2283
- var CUSTOMER_ACCOUNT_SESSION_KEY = "customerAccount";
2284
-
2285
2305
  // src/customer/BadRequest.ts
2286
2306
  var BadRequest = class extends Response {
2287
2307
  constructor(message, helpMessage, headers) {
@@ -2324,7 +2344,8 @@ async function refreshToken({
2324
2344
  customerAccountId,
2325
2345
  customerAccountUrl,
2326
2346
  httpsOrigin,
2327
- debugInfo
2347
+ debugInfo,
2348
+ exchangeForStorefrontCustomerAccessToken
2328
2349
  }) {
2329
2350
  const newBody = new URLSearchParams();
2330
2351
  const customerAccount = session.get(CUSTOMER_ACCOUNT_SESSION_KEY);
@@ -2380,9 +2401,11 @@ async function refreshToken({
2380
2401
  refreshToken: refresh_token,
2381
2402
  idToken: id_token
2382
2403
  });
2404
+ await exchangeForStorefrontCustomerAccessToken();
2383
2405
  }
2384
2406
  function clearSession(session) {
2385
2407
  session.unset(CUSTOMER_ACCOUNT_SESSION_KEY);
2408
+ session.unset(BUYER_SESSION_KEY);
2386
2409
  }
2387
2410
  async function checkExpires({
2388
2411
  locks,
@@ -2391,7 +2414,8 @@ async function checkExpires({
2391
2414
  customerAccountId,
2392
2415
  customerAccountUrl,
2393
2416
  httpsOrigin,
2394
- debugInfo
2417
+ debugInfo,
2418
+ exchangeForStorefrontCustomerAccessToken
2395
2419
  }) {
2396
2420
  if (parseInt(expiresAt, 10) - 1e3 < (/* @__PURE__ */ new Date()).getTime()) {
2397
2421
  try {
@@ -2401,7 +2425,8 @@ async function checkExpires({
2401
2425
  customerAccountId,
2402
2426
  customerAccountUrl,
2403
2427
  httpsOrigin,
2404
- debugInfo
2428
+ debugInfo,
2429
+ exchangeForStorefrontCustomerAccessToken
2405
2430
  });
2406
2431
  await locks.refresh;
2407
2432
  delete locks.refresh;
@@ -2545,7 +2570,8 @@ function createCustomerAccountClient({
2545
2570
  waitUntil,
2546
2571
  authUrl,
2547
2572
  customAuthStatusHandler,
2548
- logErrors = true
2573
+ logErrors = true,
2574
+ unstableB2b = false
2549
2575
  }) {
2550
2576
  if (customerApiVersion !== DEFAULT_CUSTOMER_API_VERSION) {
2551
2577
  console.warn(
@@ -2568,7 +2594,7 @@ function createCustomerAccountClient({
2568
2594
  const customerAccountApiUrl = `${customerAccountUrl}/account/customer/api/${customerApiVersion}/graphql`;
2569
2595
  const locks = {};
2570
2596
  async function fetchCustomerAPI({
2571
- query,
2597
+ query: query2,
2572
2598
  type,
2573
2599
  variables = {}
2574
2600
  }) {
@@ -2586,7 +2612,7 @@ function createCustomerAccountClient({
2586
2612
  Origin: httpsOrigin,
2587
2613
  Authorization: accessToken
2588
2614
  },
2589
- body: JSON.stringify({ query, variables })
2615
+ body: JSON.stringify({ query: query2, variables })
2590
2616
  });
2591
2617
  logSubRequestEvent?.({
2592
2618
  url: customerAccountApiUrl,
@@ -2594,7 +2620,7 @@ function createCustomerAccountClient({
2594
2620
  response,
2595
2621
  waitUntil,
2596
2622
  stackInfo,
2597
- query,
2623
+ query: query2,
2598
2624
  variables,
2599
2625
  ...getDebugHeaders(request)
2600
2626
  });
@@ -2603,7 +2629,7 @@ function createCustomerAccountClient({
2603
2629
  url: customerAccountApiUrl,
2604
2630
  response,
2605
2631
  type,
2606
- query,
2632
+ query: query2,
2607
2633
  queryVariables: variables,
2608
2634
  errors: void 0,
2609
2635
  client: "customer"
@@ -2634,7 +2660,7 @@ function createCustomerAccountClient({
2634
2660
  clientOperation: `customerAccount.${errorOptions.type}`,
2635
2661
  requestId: response.headers.get("x-request-id"),
2636
2662
  queryVariables: variables,
2637
- query
2663
+ query: query2
2638
2664
  })
2639
2665
  );
2640
2666
  return { ...APIresponse, ...errors && { errors: gqlErrors } };
@@ -2663,7 +2689,8 @@ function createCustomerAccountClient({
2663
2689
  waitUntil,
2664
2690
  stackInfo,
2665
2691
  ...getDebugHeaders(request)
2666
- }
2692
+ },
2693
+ exchangeForStorefrontCustomerAccessToken
2667
2694
  });
2668
2695
  } catch {
2669
2696
  return false;
@@ -2680,6 +2707,55 @@ function createCustomerAccountClient({
2680
2707
  if (hasAccessToken)
2681
2708
  return session.get(CUSTOMER_ACCOUNT_SESSION_KEY)?.accessToken;
2682
2709
  }
2710
+ async function mutate(mutation, options) {
2711
+ ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
2712
+ mutation = minifyQuery(mutation);
2713
+ assertMutation(mutation, "customer.mutate");
2714
+ return withSyncStack(
2715
+ fetchCustomerAPI({ query: mutation, type: "mutation", ...options }),
2716
+ { logErrors }
2717
+ );
2718
+ }
2719
+ async function query(query2, options) {
2720
+ ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
2721
+ query2 = minifyQuery(query2);
2722
+ assertQuery(query2, "customer.query");
2723
+ return withSyncStack(fetchCustomerAPI({ query: query2, type: "query", ...options }), {
2724
+ logErrors
2725
+ });
2726
+ }
2727
+ function setBuyer(buyer) {
2728
+ session.set(BUYER_SESSION_KEY, {
2729
+ ...session.get(BUYER_SESSION_KEY),
2730
+ ...buyer
2731
+ });
2732
+ }
2733
+ async function getBuyer() {
2734
+ const hasAccessToken = await isLoggedIn();
2735
+ if (!hasAccessToken) {
2736
+ return;
2737
+ }
2738
+ return session.get(BUYER_SESSION_KEY);
2739
+ }
2740
+ async function exchangeForStorefrontCustomerAccessToken() {
2741
+ if (!unstableB2b) {
2742
+ return;
2743
+ }
2744
+ const STOREFRONT_CUSTOMER_ACCOUNT_TOKEN_CREATE = `#graphql
2745
+ mutation storefrontCustomerAccessTokenCreate {
2746
+ storefrontCustomerAccessTokenCreate {
2747
+ customerAccessToken
2748
+ }
2749
+ }
2750
+ `;
2751
+ const { data } = await mutate(STOREFRONT_CUSTOMER_ACCOUNT_TOKEN_CREATE);
2752
+ const customerAccessToken = data?.storefrontCustomerAccessTokenCreate?.customerAccessToken;
2753
+ if (customerAccessToken) {
2754
+ setBuyer({
2755
+ customerAccessToken
2756
+ });
2757
+ }
2758
+ }
2683
2759
  return {
2684
2760
  login: async (options) => {
2685
2761
  ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
@@ -2747,24 +2823,8 @@ function createCustomerAccountClient({
2747
2823
  handleAuthStatus,
2748
2824
  getAccessToken,
2749
2825
  getApiUrl: () => customerAccountApiUrl,
2750
- mutate(mutation, options) {
2751
- ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
2752
- mutation = minifyQuery(mutation);
2753
- assertMutation(mutation, "customer.mutate");
2754
- return withSyncStack(
2755
- fetchCustomerAPI({ query: mutation, type: "mutation", ...options }),
2756
- { logErrors }
2757
- );
2758
- },
2759
- query(query, options) {
2760
- ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
2761
- query = minifyQuery(query);
2762
- assertQuery(query, "customer.query");
2763
- return withSyncStack(
2764
- fetchCustomerAPI({ query, type: "query", ...options }),
2765
- { logErrors }
2766
- );
2767
- },
2826
+ mutate,
2827
+ query,
2768
2828
  authorize: async () => {
2769
2829
  ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId);
2770
2830
  const code = requestUrl.searchParams.get("code");
@@ -2859,19 +2919,19 @@ function createCustomerAccountClient({
2859
2919
  )?.redirectPath;
2860
2920
  session.set(CUSTOMER_ACCOUNT_SESSION_KEY, {
2861
2921
  accessToken: customerAccessToken,
2862
- expiresAt: new Date(
2863
- (/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3
2864
- ).getTime() + "",
2922
+ expiresAt: new Date((/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3).getTime() + "",
2865
2923
  refreshToken: refresh_token,
2866
- idToken: id_token,
2867
- redirectPath: void 0
2924
+ idToken: id_token
2868
2925
  });
2926
+ await exchangeForStorefrontCustomerAccessToken();
2869
2927
  return redirect(redirectPath || DEFAULT_REDIRECT_PATH, {
2870
2928
  headers: {
2871
2929
  "Set-Cookie": await session.commit()
2872
2930
  }
2873
2931
  });
2874
- }
2932
+ },
2933
+ UNSTABLE_setBuyer: setBuyer,
2934
+ UNSTABLE_getBuyer: getBuyer
2875
2935
  };
2876
2936
  }
2877
2937
  function ifInvalidCredentialThrowError(customerAccountUrl, customerAccountId) {
@@ -2972,10 +3032,18 @@ var MINIMAL_CART_FRAGMENT = `#graphql
2972
3032
  // src/cart/queries/cartCreateDefault.ts
2973
3033
  function cartCreateDefault(options) {
2974
3034
  return async (input, optionalParams) => {
3035
+ const buyer = options.customerAccount ? await options.customerAccount.UNSTABLE_getBuyer() : void 0;
2975
3036
  const { cartId, ...restOfOptionalParams } = optionalParams || {};
3037
+ const { buyerIdentity, ...restOfInput } = input;
2976
3038
  const { cartCreate, errors } = await options.storefront.mutate(CART_CREATE_MUTATION(options.cartFragment), {
2977
3039
  variables: {
2978
- input,
3040
+ input: {
3041
+ ...restOfInput,
3042
+ buyerIdentity: {
3043
+ ...buyer,
3044
+ ...buyerIdentity
3045
+ }
3046
+ },
2979
3047
  ...restOfOptionalParams
2980
3048
  }
2981
3049
  });
@@ -3302,10 +3370,19 @@ var CART_DISCOUNT_CODE_UPDATE_MUTATION = (cartFragment = MINIMAL_CART_FRAGMENT)
3302
3370
  // src/cart/queries/cartBuyerIdentityUpdateDefault.ts
3303
3371
  function cartBuyerIdentityUpdateDefault(options) {
3304
3372
  return async (buyerIdentity, optionalParams) => {
3373
+ if (buyerIdentity.companyLocationId && options.customerAccount) {
3374
+ options.customerAccount.UNSTABLE_setBuyer({
3375
+ companyLocationId: buyerIdentity.companyLocationId
3376
+ });
3377
+ }
3378
+ const buyer = options.customerAccount ? await options.customerAccount.UNSTABLE_getBuyer() : void 0;
3305
3379
  const { cartBuyerIdentityUpdate, errors } = await options.storefront.mutate(CART_BUYER_IDENTITY_UPDATE_MUTATION(options.cartFragment), {
3306
3380
  variables: {
3307
3381
  cartId: options.getCartId(),
3308
- buyerIdentity,
3382
+ buyerIdentity: {
3383
+ ...buyer,
3384
+ ...buyerIdentity
3385
+ },
3309
3386
  ...optionalParams
3310
3387
  }
3311
3388
  });
@@ -3348,7 +3425,7 @@ function cartNoteUpdateDefault(options) {
3348
3425
  var CART_NOTE_UPDATE_MUTATION = (cartFragment = MINIMAL_CART_FRAGMENT) => `#graphql
3349
3426
  mutation cartNoteUpdate(
3350
3427
  $cartId: ID!
3351
- $note: String
3428
+ $note: String!
3352
3429
  $language: LanguageCode
3353
3430
  $country: CountryCode
3354
3431
  ) @inContext(country: $country, language: $language) {
@@ -3573,7 +3650,8 @@ function createCartHandler(options) {
3573
3650
  const mutateOptions = {
3574
3651
  storefront,
3575
3652
  getCartId,
3576
- cartFragment: cartMutateFragment
3653
+ cartFragment: cartMutateFragment,
3654
+ customerAccount
3577
3655
  };
3578
3656
  const _cartCreate = cartCreateDefault(mutateOptions);
3579
3657
  const cartCreate = async function(...args) {
@@ -3800,7 +3878,11 @@ function createCSPHeader(nonce, props) {
3800
3878
  function addCspDirective(currentValue, value) {
3801
3879
  const normalizedValue = typeof value === "string" ? [value] : value;
3802
3880
  const normalizedCurrentValue = Array.isArray(currentValue) ? currentValue : [String(currentValue)];
3803
- const newValue = Array.isArray(normalizedValue) ? [...normalizedCurrentValue, ...normalizedValue] : normalizedValue;
3881
+ const newValue = Array.isArray(normalizedValue) ? (
3882
+ // If the default directive is `none`, don't
3883
+ // merge the override with the default value.
3884
+ normalizedValue.every((a) => a === `'none'`) ? normalizedCurrentValue : [...normalizedCurrentValue, ...normalizedValue]
3885
+ ) : normalizedValue;
3804
3886
  return newValue;
3805
3887
  }
3806
3888
  var Script = react.forwardRef(
@@ -3908,6 +3990,7 @@ function useCustomerPrivacy(props) {
3908
3990
  const {
3909
3991
  withPrivacyBanner = true,
3910
3992
  onVisitorConsentCollected,
3993
+ onReady,
3911
3994
  ...consentConfig
3912
3995
  } = props;
3913
3996
  const loadedEvent = react.useRef(false);
@@ -3964,6 +4047,9 @@ function useCustomerPrivacy(props) {
3964
4047
  );
3965
4048
  };
3966
4049
  }
4050
+ if (onReady && !withPrivacyBanner) {
4051
+ onReady();
4052
+ }
3967
4053
  }, [scriptStatus, withPrivacyBanner, consentConfig]);
3968
4054
  return;
3969
4055
  }
@@ -3984,17 +4070,26 @@ function getCustomerPrivacyRequired() {
3984
4070
  return customerPrivacy;
3985
4071
  }
3986
4072
  function ShopifyAnalytics({
3987
- consent
4073
+ consent,
4074
+ onReady
3988
4075
  }) {
3989
4076
  const { subscribe: subscribe2, register: register2, canTrack } = useAnalytics();
3990
4077
  const { ready: shopifyAnalyticsReady } = register2("Internal_Shopify_Analytics");
3991
4078
  const { ready: customerPrivacyReady } = register2(
3992
4079
  "Internal_Shopify_CustomerPrivacy"
3993
4080
  );
3994
- const { checkoutDomain, storefrontAccessToken } = consent;
3995
- checkoutDomain && storefrontAccessToken && useCustomerPrivacy({
4081
+ const analyticsReady = () => {
4082
+ customerPrivacyReady();
4083
+ onReady();
4084
+ };
4085
+ useCustomerPrivacy({
3996
4086
  ...consent,
3997
- onVisitorConsentCollected: customerPrivacyReady
4087
+ onVisitorConsentCollected: analyticsReady,
4088
+ onReady: () => {
4089
+ if (!consent.withPrivacyBanner) {
4090
+ analyticsReady();
4091
+ }
4092
+ }
3998
4093
  });
3999
4094
  hydrogenReact.useShopifyCookies({ hasUserConsent: canTrack() });
4000
4095
  react.useEffect(() => {
@@ -4014,7 +4109,7 @@ function logMissingConfig2(fieldName) {
4014
4109
  }
4015
4110
  function prepareBasePageViewPayload(payload) {
4016
4111
  const customerPrivacy = getCustomerPrivacyRequired();
4017
- const hasUserConsent = customerPrivacy.userCanBeTracked();
4112
+ const hasUserConsent = customerPrivacy.analyticsProcessingAllowed();
4018
4113
  if (!payload?.shop?.shopId) {
4019
4114
  logMissingConfig2("shopId");
4020
4115
  return;
@@ -4304,8 +4399,10 @@ function CartAnalytics({
4304
4399
  updatedAt: cart.updatedAt
4305
4400
  })
4306
4401
  );
4307
- prevCart?.lines?.nodes?.forEach((prevLine) => {
4308
- const matchedLineId = cart?.lines.nodes.filter(
4402
+ const previousCartLines = prevCart?.lines ? hydrogenReact.flattenConnection(prevCart?.lines) : [];
4403
+ const currentCartLines = cart.lines ? hydrogenReact.flattenConnection(cart.lines) : [];
4404
+ previousCartLines?.forEach((prevLine) => {
4405
+ const matchedLineId = currentCartLines.filter(
4309
4406
  (line) => prevLine.id === line.id
4310
4407
  );
4311
4408
  if (matchedLineId?.length === 1) {
@@ -4330,8 +4427,8 @@ function CartAnalytics({
4330
4427
  });
4331
4428
  }
4332
4429
  });
4333
- cart?.lines?.nodes?.forEach((line) => {
4334
- const matchedLineId = prevCart?.lines.nodes.filter(
4430
+ currentCartLines?.forEach((line) => {
4431
+ const matchedLineId = previousCartLines.filter(
4335
4432
  (previousLine) => line.id === previousLine.id
4336
4433
  );
4337
4434
  if (!matchedLineId || matchedLineId.length === 0) {
@@ -4414,19 +4511,40 @@ function register(key) {
4414
4511
  };
4415
4512
  }
4416
4513
  function shopifyCanTrack() {
4417
- if (typeof window !== "undefined" && typeof window?.Shopify === "object" && typeof window?.Shopify?.customerPrivacy === "object" && typeof window?.Shopify?.customerPrivacy?.userCanBeTracked === "function") {
4418
- return window.Shopify.customerPrivacy.userCanBeTracked();
4514
+ try {
4515
+ return window.Shopify.customerPrivacy.analyticsProcessingAllowed();
4516
+ } catch (e) {
4419
4517
  }
4420
4518
  return false;
4421
4519
  }
4520
+ function messageOnError(field) {
4521
+ return `[h2:error:Analytics.Provider] - ${field} is required`;
4522
+ }
4422
4523
  function AnalyticsProvider({
4423
4524
  canTrack: customCanTrack,
4424
4525
  cart: currentCart,
4425
4526
  children,
4426
4527
  consent,
4427
4528
  customData = {},
4428
- shop: shopProp = null
4529
+ shop: shopProp = null,
4530
+ disableThrowOnError = false
4429
4531
  }) {
4532
+ if (!consent.checkoutDomain) {
4533
+ const errorMsg = messageOnError("consent.checkoutDomain");
4534
+ if (disableThrowOnError) {
4535
+ console.error(errorMsg);
4536
+ } else {
4537
+ invariant__default.default(false, errorMsg);
4538
+ }
4539
+ }
4540
+ if (!consent.storefrontAccessToken) {
4541
+ const errorMsg = messageOnError("consent.storefrontAccessToken");
4542
+ if (disableThrowOnError) {
4543
+ console.error(errorMsg);
4544
+ } else {
4545
+ invariant__default.default(false, errorMsg);
4546
+ }
4547
+ }
4430
4548
  const listenerSet = react.useRef(false);
4431
4549
  const { shop } = useShopAnalytics(shopProp);
4432
4550
  const [consentLoaded, setConsentLoaded] = react.useState(
@@ -4436,17 +4554,6 @@ function AnalyticsProvider({
4436
4554
  const [canTrack, setCanTrack] = react.useState(
4437
4555
  customCanTrack ? () => customCanTrack : () => shopifyCanTrack
4438
4556
  );
4439
- react.useEffect(() => {
4440
- if (customCanTrack)
4441
- return;
4442
- if (listenerSet.current)
4443
- return;
4444
- listenerSet.current = true;
4445
- document.addEventListener("visitorConsentCollected", () => {
4446
- setConsentLoaded(true);
4447
- setCanTrack(() => shopifyCanTrack);
4448
- });
4449
- }, [setConsentLoaded, setCanTrack, customCanTrack]);
4450
4557
  const value = react.useMemo(() => {
4451
4558
  return {
4452
4559
  canTrack,
@@ -4475,9 +4582,19 @@ function AnalyticsProvider({
4475
4582
  ]);
4476
4583
  return /* @__PURE__ */ jsxRuntime.jsxs(AnalyticsContext.Provider, { value, children: [
4477
4584
  children,
4478
- shop && /* @__PURE__ */ jsxRuntime.jsx(AnalyticsPageView, {}),
4479
- shop && currentCart && /* @__PURE__ */ jsxRuntime.jsx(CartAnalytics, { cart: currentCart, setCarts }),
4480
- shop && consent && /* @__PURE__ */ jsxRuntime.jsx(ShopifyAnalytics, { consent })
4585
+ !!shop && /* @__PURE__ */ jsxRuntime.jsx(AnalyticsPageView, {}),
4586
+ !!shop && !!currentCart && /* @__PURE__ */ jsxRuntime.jsx(CartAnalytics, { cart: currentCart, setCarts }),
4587
+ !!shop && /* @__PURE__ */ jsxRuntime.jsx(
4588
+ ShopifyAnalytics,
4589
+ {
4590
+ consent,
4591
+ onReady: () => {
4592
+ listenerSet.current = true;
4593
+ setConsentLoaded(true);
4594
+ setCanTrack(() => shopifyCanTrack);
4595
+ }
4596
+ }
4597
+ )
4481
4598
  ] });
4482
4599
  }
4483
4600
  function useAnalytics() {