@shopify/hydrogen 2025.4.0 → 2025.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.
- package/dist/development/index.cjs +383 -68
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +382 -72
- package/dist/development/index.js.map +1 -1
- package/dist/production/index.cjs +71 -71
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.d.cts +71 -10
- package/dist/production/index.d.ts +71 -10
- package/dist/production/index.js +74 -74
- package/dist/production/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createContext, forwardRef, useContext, lazy, useMemo, useEffect, useRef, useState, createElement, Fragment as Fragment$1, Suspense } from 'react';
|
|
2
|
-
import { useFetcher, useFetchers, useNavigation, useLocation, useNavigate, Link, useMatches } from '@remix-run/react';
|
|
2
|
+
import { useRevalidator, useFetcher, useFetchers, useNavigation, useLocation, useNavigate, Link, useMatches } from '@remix-run/react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { useLoadScript, createStorefrontClient as createStorefrontClient$1, SHOPIFY_STOREFRONT_ID_HEADER,
|
|
5
|
-
export { AnalyticsEventName, AnalyticsPageType, ExternalVideo, IMAGE_FRAGMENT, Image, MediaFile, ModelViewer, Money, ShopifySalesChannel, Video, customerAccountApiCustomScalars, decodeEncodedVariant, flattenConnection, getAdjacentAndFirstAvailableVariants, getClientBrowserParameters, getProductOptions, getShopifyCookies, isOptionValueCombinationInEncodedVariant, mapSelectedProductOptionToObject, parseGid, parseMetafield, sendShopifyAnalytics, storefrontApiCustomScalars, useLoadScript, useMoney, useSelectedOptionInUrlParam, useShopifyCookies } from '@shopify/hydrogen-react';
|
|
4
|
+
import { useLoadScript, useShopifyCookies, getTrackingValues, createStorefrontClient as createStorefrontClient$1, SHOPIFY_STOREFRONT_ID_HEADER, SHOPIFY_STOREFRONT_Y_HEADER, SHOPIFY_STOREFRONT_S_HEADER, SHOPIFY_UNIQUE_TOKEN_HEADER, SHOPIFY_VISIT_TOKEN_HEADER, flattenConnection, RichText as RichText$1, ShopPayButton as ShopPayButton$1, parseGid, sendShopifyAnalytics, AnalyticsEventName, AnalyticsPageType, getClientBrowserParameters } from '@shopify/hydrogen-react';
|
|
5
|
+
export { AnalyticsEventName, AnalyticsPageType, ExternalVideo, IMAGE_FRAGMENT, Image, MediaFile, ModelViewer, Money, ShopifySalesChannel, Video, customerAccountApiCustomScalars, decodeEncodedVariant, flattenConnection, getAdjacentAndFirstAvailableVariants, getClientBrowserParameters, getProductOptions, getShopifyCookies, getTrackingValues, isOptionValueCombinationInEncodedVariant, mapSelectedProductOptionToObject, parseGid, parseMetafield, sendShopifyAnalytics, storefrontApiCustomScalars, useLoadScript, useMoney, useSelectedOptionInUrlParam, useShopifyCookies } from '@shopify/hydrogen-react';
|
|
6
6
|
import { parse, stringify } from 'worktop/cookie';
|
|
7
|
+
import { createRequestHandler as createRequestHandler$1 } from '@remix-run/server-runtime';
|
|
7
8
|
import cspBuilder from 'content-security-policy-builder';
|
|
8
9
|
|
|
9
10
|
// src/analytics-manager/AnalyticsProvider.tsx
|
|
@@ -72,7 +73,62 @@ var AnalyticsEvent = {
|
|
|
72
73
|
// Custom
|
|
73
74
|
CUSTOM_EVENT: `custom_`
|
|
74
75
|
};
|
|
75
|
-
|
|
76
|
+
|
|
77
|
+
// src/constants.ts
|
|
78
|
+
var STOREFRONT_REQUEST_GROUP_ID_HEADER = "Custom-Storefront-Request-Group-ID";
|
|
79
|
+
var STOREFRONT_ACCESS_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
|
|
80
|
+
var SDK_VARIANT_HEADER = "X-SDK-Variant";
|
|
81
|
+
var SDK_VARIANT_SOURCE_HEADER = "X-SDK-Variant-Source";
|
|
82
|
+
var SDK_VERSION_HEADER = "X-SDK-Version";
|
|
83
|
+
var SHOPIFY_CLIENT_IP_HEADER = "X-Shopify-Client-IP";
|
|
84
|
+
var SHOPIFY_CLIENT_IP_SIG_HEADER = "X-Shopify-Client-IP-Sig";
|
|
85
|
+
var HYDROGEN_SFAPI_PROXY_KEY = "_sfapi_proxy";
|
|
86
|
+
var HYDROGEN_SERVER_TRACKING_KEY = "_server_tracking";
|
|
87
|
+
|
|
88
|
+
// src/utils/server-timing.ts
|
|
89
|
+
function buildServerTimingHeader(values) {
|
|
90
|
+
return Object.entries(values).map(([key, value]) => value ? `${key};desc=${value}` : void 0).filter(Boolean).join(", ");
|
|
91
|
+
}
|
|
92
|
+
function appendServerTimingHeader(response, values) {
|
|
93
|
+
const header = typeof values === "string" ? values : buildServerTimingHeader(values);
|
|
94
|
+
if (header) {
|
|
95
|
+
response.headers.append("Server-Timing", header);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
var trackedTimings = ["_y", "_s", "_cmp"];
|
|
99
|
+
function extractServerTimingHeader(serverTimingHeader) {
|
|
100
|
+
const values = {};
|
|
101
|
+
if (!serverTimingHeader) return values;
|
|
102
|
+
const re = new RegExp(
|
|
103
|
+
`\\b(${trackedTimings.join("|")});desc="?([^",]+)"?`,
|
|
104
|
+
"g"
|
|
105
|
+
);
|
|
106
|
+
let match;
|
|
107
|
+
while ((match = re.exec(serverTimingHeader)) !== null) {
|
|
108
|
+
values[match[1]] = match[2];
|
|
109
|
+
}
|
|
110
|
+
return values;
|
|
111
|
+
}
|
|
112
|
+
function hasServerTimingInNavigationEntry(key) {
|
|
113
|
+
if (typeof window === "undefined") return false;
|
|
114
|
+
try {
|
|
115
|
+
const navigationEntry = window.performance.getEntriesByType(
|
|
116
|
+
"navigation"
|
|
117
|
+
)[0];
|
|
118
|
+
return !!navigationEntry?.serverTiming?.some((entry) => entry.name === key);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function isSfapiProxyEnabled() {
|
|
124
|
+
return hasServerTimingInNavigationEntry(HYDROGEN_SFAPI_PROXY_KEY);
|
|
125
|
+
}
|
|
126
|
+
function hasServerReturnedTrackingValues() {
|
|
127
|
+
return hasServerTimingInNavigationEntry(HYDROGEN_SERVER_TRACKING_KEY);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/customer-privacy/ShopifyCustomerPrivacy.tsx
|
|
131
|
+
var CONSENT_API = "https://cdn.shopify.com/shopifycloud/consent-tracking-api/v0.2/consent-tracking-api.js";
|
|
76
132
|
var CONSENT_API_WITH_BANNER = "https://cdn.shopify.com/shopifycloud/privacy-banner/storefront-banner.js";
|
|
77
133
|
function logMissingConfig(fieldName) {
|
|
78
134
|
console.error(
|
|
@@ -84,19 +140,34 @@ function useCustomerPrivacy(props) {
|
|
|
84
140
|
withPrivacyBanner = false,
|
|
85
141
|
onVisitorConsentCollected,
|
|
86
142
|
onReady,
|
|
87
|
-
|
|
143
|
+
checkoutDomain,
|
|
144
|
+
storefrontAccessToken,
|
|
145
|
+
country,
|
|
146
|
+
locale,
|
|
147
|
+
sameDomainForStorefrontApi
|
|
88
148
|
} = props;
|
|
149
|
+
const hasSfapiProxy = useMemo(
|
|
150
|
+
() => sameDomainForStorefrontApi ?? isSfapiProxyEnabled(),
|
|
151
|
+
[sameDomainForStorefrontApi]
|
|
152
|
+
);
|
|
153
|
+
const fetchTrackingValuesFromBrowser = useMemo(
|
|
154
|
+
() => hasSfapiProxy && !hasServerReturnedTrackingValues(),
|
|
155
|
+
[hasSfapiProxy]
|
|
156
|
+
);
|
|
157
|
+
const cookiesReady = useShopifyCookies({
|
|
158
|
+
fetchTrackingValues: fetchTrackingValuesFromBrowser,
|
|
159
|
+
storefrontAccessToken,
|
|
160
|
+
ignoreDeprecatedCookies: true
|
|
161
|
+
});
|
|
162
|
+
const initialTrackingValues = useMemo(getTrackingValues, [cookiesReady]);
|
|
163
|
+
const { revalidate } = useRevalidator();
|
|
89
164
|
useLoadScript(withPrivacyBanner ? CONSENT_API_WITH_BANNER : CONSENT_API, {
|
|
90
165
|
attributes: {
|
|
91
166
|
id: "customer-privacy-api"
|
|
92
167
|
}
|
|
93
168
|
});
|
|
94
|
-
const { observing, setLoaded } = useApisLoaded({
|
|
95
|
-
withPrivacyBanner,
|
|
96
|
-
onLoaded: onReady
|
|
97
|
-
});
|
|
169
|
+
const { observing, setLoaded, apisLoaded } = useApisLoaded({ withPrivacyBanner });
|
|
98
170
|
const config = useMemo(() => {
|
|
99
|
-
const { checkoutDomain, storefrontAccessToken } = consentConfig;
|
|
100
171
|
if (!checkoutDomain) logMissingConfig("checkoutDomain");
|
|
101
172
|
if (!storefrontAccessToken) logMissingConfig("storefrontAccessToken");
|
|
102
173
|
if (storefrontAccessToken.startsWith("shpat_") || storefrontAccessToken.length !== 32) {
|
|
@@ -104,18 +175,50 @@ function useCustomerPrivacy(props) {
|
|
|
104
175
|
`[h2:error:useCustomerPrivacy] It looks like you passed a private access token, make sure to use the public token`
|
|
105
176
|
);
|
|
106
177
|
}
|
|
178
|
+
const commonAncestorDomain = parseStoreDomain(checkoutDomain);
|
|
179
|
+
const sfapiDomain = (
|
|
180
|
+
// Check if standard route proxy is enabled in Hydrogen server
|
|
181
|
+
// to use it instead of doing a cross-origin request to checkout.
|
|
182
|
+
hasSfapiProxy && typeof window !== "undefined" ? window.location.host : checkoutDomain
|
|
183
|
+
);
|
|
107
184
|
const config2 = {
|
|
108
|
-
|
|
185
|
+
// This domain is used to send requests to SFAPI for setting and getting consent.
|
|
186
|
+
checkoutRootDomain: sfapiDomain,
|
|
187
|
+
// Prefix with a dot to ensure this domain is different from checkoutRootDomain.
|
|
188
|
+
// This will ensure old cookies are set for a cross-subdomain checkout setup
|
|
189
|
+
// so that we keep backward compatibility until new cookies are rolled out.
|
|
190
|
+
// Once consent-tracking-api is updated to not rely on cookies anymore, we can remove this.
|
|
191
|
+
storefrontRootDomain: commonAncestorDomain ? "." + commonAncestorDomain : void 0,
|
|
109
192
|
storefrontAccessToken,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
locale: consentConfig.locale
|
|
193
|
+
country,
|
|
194
|
+
locale
|
|
113
195
|
};
|
|
114
196
|
return config2;
|
|
115
|
-
}, [
|
|
197
|
+
}, [
|
|
198
|
+
logMissingConfig,
|
|
199
|
+
checkoutDomain,
|
|
200
|
+
storefrontAccessToken,
|
|
201
|
+
country,
|
|
202
|
+
locale
|
|
203
|
+
]);
|
|
116
204
|
useEffect(() => {
|
|
117
205
|
const consentCollectedHandler = (event) => {
|
|
206
|
+
const latestTrackingValues = getTrackingValues();
|
|
207
|
+
if (initialTrackingValues.visitToken !== latestTrackingValues.visitToken || initialTrackingValues.uniqueToken !== latestTrackingValues.uniqueToken) {
|
|
208
|
+
revalidate();
|
|
209
|
+
}
|
|
118
210
|
if (onVisitorConsentCollected) {
|
|
211
|
+
const customerPrivacy = getCustomerPrivacy();
|
|
212
|
+
if (customerPrivacy?.shouldShowBanner()) {
|
|
213
|
+
const consentValues = customerPrivacy.currentVisitorConsent();
|
|
214
|
+
if (consentValues) {
|
|
215
|
+
const NO_VALUE = "";
|
|
216
|
+
const noInteraction = consentValues.marketing === NO_VALUE && consentValues.analytics === NO_VALUE && consentValues.preferences === NO_VALUE;
|
|
217
|
+
if (noInteraction) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
119
222
|
onVisitorConsentCollected(event.detail);
|
|
120
223
|
}
|
|
121
224
|
};
|
|
@@ -141,14 +244,11 @@ function useCustomerPrivacy(props) {
|
|
|
141
244
|
},
|
|
142
245
|
set(value) {
|
|
143
246
|
if (typeof value === "object" && value !== null && "showPreferences" in value && "loadBanner" in value) {
|
|
144
|
-
const privacyBanner = value;
|
|
145
|
-
privacyBanner.loadBanner(config);
|
|
146
247
|
customPrivacyBanner = overridePrivacyBannerMethods({
|
|
147
|
-
privacyBanner,
|
|
248
|
+
privacyBanner: value,
|
|
148
249
|
config
|
|
149
250
|
});
|
|
150
251
|
setLoaded.privacyBanner();
|
|
151
|
-
emitCustomerPrivacyApiLoaded();
|
|
152
252
|
}
|
|
153
253
|
}
|
|
154
254
|
};
|
|
@@ -182,6 +282,8 @@ function useCustomerPrivacy(props) {
|
|
|
182
282
|
const customerPrivacy = value2;
|
|
183
283
|
customCustomerPrivacy = {
|
|
184
284
|
...customerPrivacy,
|
|
285
|
+
// Note: this method is not used by the privacy-banner,
|
|
286
|
+
// it bundles its own setTrackingConsent.
|
|
185
287
|
setTrackingConsent: overrideCustomerPrivacySetTrackingConsent(
|
|
186
288
|
{ customerPrivacy, config }
|
|
187
289
|
)
|
|
@@ -191,7 +293,6 @@ function useCustomerPrivacy(props) {
|
|
|
191
293
|
customerPrivacy: customCustomerPrivacy
|
|
192
294
|
};
|
|
193
295
|
setLoaded.customerPrivacy();
|
|
194
|
-
emitCustomerPrivacyApiLoaded();
|
|
195
296
|
}
|
|
196
297
|
}
|
|
197
298
|
});
|
|
@@ -203,6 +304,24 @@ function useCustomerPrivacy(props) {
|
|
|
203
304
|
overrideCustomerPrivacySetTrackingConsent,
|
|
204
305
|
setLoaded.customerPrivacy
|
|
205
306
|
]);
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (!apisLoaded || !cookiesReady) return;
|
|
309
|
+
const customerPrivacy = getCustomerPrivacy();
|
|
310
|
+
if (customerPrivacy && !customerPrivacy.cachedConsent) {
|
|
311
|
+
const trackingValues = getTrackingValues();
|
|
312
|
+
if (trackingValues.consent) {
|
|
313
|
+
customerPrivacy.cachedConsent = trackingValues.consent;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (withPrivacyBanner) {
|
|
317
|
+
const privacyBanner = getPrivacyBanner();
|
|
318
|
+
if (privacyBanner) {
|
|
319
|
+
privacyBanner.loadBanner(config);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
emitCustomerPrivacyApiLoaded();
|
|
323
|
+
onReady?.();
|
|
324
|
+
}, [apisLoaded, cookiesReady]);
|
|
206
325
|
const result = {
|
|
207
326
|
customerPrivacy: getCustomerPrivacy()
|
|
208
327
|
};
|
|
@@ -218,15 +337,12 @@ function emitCustomerPrivacyApiLoaded() {
|
|
|
218
337
|
const event = new CustomEvent("shopifyCustomerPrivacyApiLoaded");
|
|
219
338
|
document.dispatchEvent(event);
|
|
220
339
|
}
|
|
221
|
-
function useApisLoaded({
|
|
222
|
-
withPrivacyBanner,
|
|
223
|
-
onLoaded
|
|
224
|
-
}) {
|
|
340
|
+
function useApisLoaded({ withPrivacyBanner }) {
|
|
225
341
|
const observing = useRef({ customerPrivacy: false, privacyBanner: false });
|
|
226
|
-
const [
|
|
342
|
+
const [apisLoadedArray, setApisLoaded] = useState(
|
|
227
343
|
withPrivacyBanner ? [false, false] : [false]
|
|
228
344
|
);
|
|
229
|
-
const
|
|
345
|
+
const apisLoaded = apisLoadedArray.every(Boolean);
|
|
230
346
|
const setLoaded = {
|
|
231
347
|
customerPrivacy: () => {
|
|
232
348
|
if (withPrivacyBanner) {
|
|
@@ -242,16 +358,11 @@ function useApisLoaded({
|
|
|
242
358
|
setApisLoaded((prev) => [prev[0], true]);
|
|
243
359
|
}
|
|
244
360
|
};
|
|
245
|
-
|
|
246
|
-
if (loaded && onLoaded) {
|
|
247
|
-
onLoaded();
|
|
248
|
-
}
|
|
249
|
-
}, [loaded, onLoaded]);
|
|
250
|
-
return { observing, setLoaded };
|
|
361
|
+
return { observing, setLoaded, apisLoaded };
|
|
251
362
|
}
|
|
252
363
|
function parseStoreDomain(checkoutDomain) {
|
|
253
364
|
if (typeof window === "undefined") return;
|
|
254
|
-
const host = window.
|
|
365
|
+
const host = window.location.host;
|
|
255
366
|
const checkoutDomainParts = checkoutDomain.split(".").reverse();
|
|
256
367
|
const currentDomainParts = host.split(".").reverse();
|
|
257
368
|
const sameDomainParts = [];
|
|
@@ -260,7 +371,7 @@ function parseStoreDomain(checkoutDomain) {
|
|
|
260
371
|
sameDomainParts.push(part);
|
|
261
372
|
}
|
|
262
373
|
});
|
|
263
|
-
return sameDomainParts.reverse().join(".");
|
|
374
|
+
return sameDomainParts.reverse().join(".") || void 0;
|
|
264
375
|
}
|
|
265
376
|
function overrideCustomerPrivacySetTrackingConsent({
|
|
266
377
|
customerPrivacy,
|
|
@@ -318,7 +429,7 @@ function getPrivacyBanner() {
|
|
|
318
429
|
}
|
|
319
430
|
|
|
320
431
|
// package.json
|
|
321
|
-
var version = "2025.4.
|
|
432
|
+
var version = "2025.4.2";
|
|
322
433
|
|
|
323
434
|
// src/analytics-manager/ShopifyAnalytics.tsx
|
|
324
435
|
function getCustomerPrivacyRequired() {
|
|
@@ -338,6 +449,7 @@ function ShopifyAnalytics({
|
|
|
338
449
|
const { subscribe: subscribe2, register: register2, canTrack } = useAnalytics();
|
|
339
450
|
const [shopifyReady, setShopifyReady] = useState(false);
|
|
340
451
|
const [privacyReady, setPrivacyReady] = useState(false);
|
|
452
|
+
const [collectedConsent, setCollectedConsent] = useState("");
|
|
341
453
|
const init = useRef(false);
|
|
342
454
|
const { checkoutDomain, storefrontAccessToken, language } = consent;
|
|
343
455
|
const { ready: shopifyAnalyticsReady } = register2("Internal_Shopify_Analytics");
|
|
@@ -346,14 +458,31 @@ function ShopifyAnalytics({
|
|
|
346
458
|
locale: language,
|
|
347
459
|
checkoutDomain: !checkoutDomain ? "mock.shop" : checkoutDomain,
|
|
348
460
|
storefrontAccessToken: !storefrontAccessToken ? "abcdefghijklmnopqrstuvwxyz123456" : storefrontAccessToken,
|
|
349
|
-
|
|
350
|
-
|
|
461
|
+
// If we use privacy banner, we should wait until consent is collected.
|
|
462
|
+
// Otherwise, we can consider privacy ready immediately:
|
|
463
|
+
onReady: () => !consent.withPrivacyBanner && setPrivacyReady(true),
|
|
464
|
+
onVisitorConsentCollected: (consent2) => {
|
|
465
|
+
try {
|
|
466
|
+
setCollectedConsent(JSON.stringify(consent2));
|
|
467
|
+
} catch (e) {
|
|
468
|
+
}
|
|
469
|
+
setPrivacyReady(true);
|
|
470
|
+
}
|
|
351
471
|
});
|
|
472
|
+
const hasUserConsent = useMemo(
|
|
473
|
+
// must be initialized with true to avoid removing cookies too early
|
|
474
|
+
() => privacyReady ? canTrack() : true,
|
|
475
|
+
// Make this value depend on collectedConsent to re-run `canTrack()` when consent changes
|
|
476
|
+
[privacyReady, canTrack, collectedConsent]
|
|
477
|
+
);
|
|
352
478
|
useShopifyCookies({
|
|
353
|
-
hasUserConsent
|
|
354
|
-
// must be initialized with true
|
|
479
|
+
hasUserConsent,
|
|
355
480
|
domain,
|
|
356
|
-
checkoutDomain
|
|
481
|
+
checkoutDomain,
|
|
482
|
+
// Already done inside useCustomerPrivacy
|
|
483
|
+
fetchTrackingValues: false,
|
|
484
|
+
// Avoid creating local cookies too early
|
|
485
|
+
ignoreDeprecatedCookies: !privacyReady
|
|
357
486
|
});
|
|
358
487
|
useEffect(() => {
|
|
359
488
|
if (init.current) return;
|
|
@@ -403,11 +532,11 @@ function prepareBasePageViewPayload(payload) {
|
|
|
403
532
|
...payload.shop,
|
|
404
533
|
hasUserConsent,
|
|
405
534
|
...getClientBrowserParameters(),
|
|
406
|
-
ccpaEnforced: !customerPrivacy.saleOfDataAllowed(),
|
|
407
|
-
gdprEnforced: !(customerPrivacy.marketingAllowed() && customerPrivacy.analyticsProcessingAllowed()),
|
|
408
535
|
analyticsAllowed: customerPrivacy.analyticsProcessingAllowed(),
|
|
409
536
|
marketingAllowed: customerPrivacy.marketingAllowed(),
|
|
410
|
-
saleOfDataAllowed: customerPrivacy.saleOfDataAllowed()
|
|
537
|
+
saleOfDataAllowed: customerPrivacy.saleOfDataAllowed(),
|
|
538
|
+
ccpaEnforced: !customerPrivacy.saleOfDataAllowed(),
|
|
539
|
+
gdprEnforced: !(customerPrivacy.marketingAllowed() && customerPrivacy.analyticsProcessingAllowed())
|
|
411
540
|
};
|
|
412
541
|
return eventPayload;
|
|
413
542
|
}
|
|
@@ -840,11 +969,11 @@ function AnalyticsProvider({
|
|
|
840
969
|
shop: shopProp = null,
|
|
841
970
|
cookieDomain
|
|
842
971
|
}) {
|
|
843
|
-
const listenerSet = useRef(false);
|
|
844
972
|
const { shop } = useShopAnalytics(shopProp);
|
|
845
973
|
const [analyticsLoaded, setAnalyticsLoaded] = useState(
|
|
846
974
|
customCanTrack ? true : false
|
|
847
975
|
);
|
|
976
|
+
const [consentCollected, setConsentCollected] = useState(false);
|
|
848
977
|
const [carts, setCarts] = useState({ cart: null, prevCart: null });
|
|
849
978
|
const [canTrack, setCanTrack] = useState(
|
|
850
979
|
customCanTrack ? () => customCanTrack : () => shopifyCanTrack
|
|
@@ -912,21 +1041,21 @@ function AnalyticsProvider({
|
|
|
912
1041
|
children,
|
|
913
1042
|
!!shop && /* @__PURE__ */ jsx(AnalyticsPageView, {}),
|
|
914
1043
|
!!shop && !!currentCart && /* @__PURE__ */ jsx(CartAnalytics, { cart: currentCart, setCarts }),
|
|
915
|
-
!!shop &&
|
|
1044
|
+
!!shop && /* @__PURE__ */ jsx(
|
|
916
1045
|
ShopifyAnalytics,
|
|
917
1046
|
{
|
|
918
1047
|
consent,
|
|
919
1048
|
onReady: () => {
|
|
920
|
-
listenerSet.current = true;
|
|
921
1049
|
setAnalyticsLoaded(true);
|
|
922
1050
|
setCanTrack(
|
|
923
1051
|
customCanTrack ? () => customCanTrack : () => shopifyCanTrack
|
|
924
1052
|
);
|
|
1053
|
+
setConsentCollected(true);
|
|
925
1054
|
},
|
|
926
1055
|
domain: cookieDomain
|
|
927
1056
|
}
|
|
928
1057
|
),
|
|
929
|
-
!!shop && /* @__PURE__ */ jsx(PerfKit, { shop })
|
|
1058
|
+
!!shop && consentCollected && /* @__PURE__ */ jsx(PerfKit, { shop })
|
|
930
1059
|
] });
|
|
931
1060
|
}
|
|
932
1061
|
function useAnalytics() {
|
|
@@ -1005,6 +1134,21 @@ function getDebugHeaders(request) {
|
|
|
1005
1134
|
purpose: request ? getHeader(request, "purpose") : void 0
|
|
1006
1135
|
};
|
|
1007
1136
|
}
|
|
1137
|
+
var SFAPI_RE = /^\/api\/(unstable|2\d{3}-\d{2})\/graphql\.json$/;
|
|
1138
|
+
var getSafePathname = (url) => {
|
|
1139
|
+
try {
|
|
1140
|
+
return new URL(url, "http://e.c").pathname;
|
|
1141
|
+
} catch {
|
|
1142
|
+
return "/";
|
|
1143
|
+
}
|
|
1144
|
+
};
|
|
1145
|
+
function extractHeaders(extract, keys) {
|
|
1146
|
+
return keys.reduce((acc, key) => {
|
|
1147
|
+
const forwardedValue = extract(key);
|
|
1148
|
+
if (forwardedValue) acc.push([key, forwardedValue]);
|
|
1149
|
+
return acc;
|
|
1150
|
+
}, []);
|
|
1151
|
+
}
|
|
1008
1152
|
|
|
1009
1153
|
// src/utils/callsites.ts
|
|
1010
1154
|
function withSyncStack(promise, options = {}) {
|
|
@@ -1374,13 +1518,16 @@ async function runWithCache(cacheKey, actionFn, {
|
|
|
1374
1518
|
}
|
|
1375
1519
|
|
|
1376
1520
|
// src/cache/server-fetch.ts
|
|
1521
|
+
var excludedHeaders = ["set-cookie", "server-timing"];
|
|
1377
1522
|
function toSerializableResponse(body, response) {
|
|
1378
1523
|
return [
|
|
1379
1524
|
body,
|
|
1380
1525
|
{
|
|
1381
1526
|
status: response.status,
|
|
1382
1527
|
statusText: response.statusText,
|
|
1383
|
-
headers:
|
|
1528
|
+
headers: [...response.headers].filter(
|
|
1529
|
+
([key]) => !excludedHeaders.includes(key.toLowerCase())
|
|
1530
|
+
)
|
|
1384
1531
|
}
|
|
1385
1532
|
];
|
|
1386
1533
|
}
|
|
@@ -1393,7 +1540,8 @@ async function fetchWithServerCache(url, requestInit, {
|
|
|
1393
1540
|
cacheKey = [url, requestInit],
|
|
1394
1541
|
shouldCacheResponse,
|
|
1395
1542
|
waitUntil,
|
|
1396
|
-
debugInfo
|
|
1543
|
+
debugInfo,
|
|
1544
|
+
onRawHeaders
|
|
1397
1545
|
}) {
|
|
1398
1546
|
if (!cacheOptions && (!requestInit.method || requestInit.method === "GET")) {
|
|
1399
1547
|
cacheOptions = CacheShort();
|
|
@@ -1402,6 +1550,7 @@ async function fetchWithServerCache(url, requestInit, {
|
|
|
1402
1550
|
cacheKey,
|
|
1403
1551
|
async () => {
|
|
1404
1552
|
const response = await fetch(url, requestInit);
|
|
1553
|
+
onRawHeaders?.(response.headers);
|
|
1405
1554
|
if (!response.ok) {
|
|
1406
1555
|
return response;
|
|
1407
1556
|
}
|
|
@@ -1624,13 +1773,6 @@ var cartSetIdDefault = (cookieOptions) => {
|
|
|
1624
1773
|
};
|
|
1625
1774
|
};
|
|
1626
1775
|
|
|
1627
|
-
// src/constants.ts
|
|
1628
|
-
var STOREFRONT_REQUEST_GROUP_ID_HEADER = "Custom-Storefront-Request-Group-ID";
|
|
1629
|
-
var STOREFRONT_ACCESS_TOKEN_HEADER = "X-Shopify-Storefront-Access-Token";
|
|
1630
|
-
var SDK_VARIANT_HEADER = "X-SDK-Variant";
|
|
1631
|
-
var SDK_VARIANT_SOURCE_HEADER = "X-SDK-Variant-Source";
|
|
1632
|
-
var SDK_VERSION_HEADER = "X-SDK-Version";
|
|
1633
|
-
|
|
1634
1776
|
// src/utils/uuid.ts
|
|
1635
1777
|
function generateUUID() {
|
|
1636
1778
|
if (typeof crypto !== "undefined" && !!crypto.randomUUID) {
|
|
@@ -1641,7 +1783,7 @@ function generateUUID() {
|
|
|
1641
1783
|
}
|
|
1642
1784
|
|
|
1643
1785
|
// src/version.ts
|
|
1644
|
-
var LIB_VERSION = "2025.4.
|
|
1786
|
+
var LIB_VERSION = "2025.4.2";
|
|
1645
1787
|
|
|
1646
1788
|
// src/utils/graphql.ts
|
|
1647
1789
|
function minifyQuery(string) {
|
|
@@ -1802,16 +1944,34 @@ function createStorefrontClient(options) {
|
|
|
1802
1944
|
contentType: "json",
|
|
1803
1945
|
buyerIp: storefrontHeaders?.buyerIp || ""
|
|
1804
1946
|
});
|
|
1947
|
+
if (storefrontHeaders?.buyerIp) {
|
|
1948
|
+
defaultHeaders[SHOPIFY_CLIENT_IP_HEADER] = storefrontHeaders.buyerIp;
|
|
1949
|
+
}
|
|
1950
|
+
if (storefrontHeaders?.buyerIpSig) {
|
|
1951
|
+
defaultHeaders[SHOPIFY_CLIENT_IP_SIG_HEADER] = storefrontHeaders.buyerIpSig;
|
|
1952
|
+
}
|
|
1805
1953
|
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId || generateUUID();
|
|
1806
1954
|
if (storefrontId) defaultHeaders[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
|
|
1807
1955
|
defaultHeaders["user-agent"] = `Hydrogen ${LIB_VERSION}`;
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1956
|
+
const requestCookie = storefrontHeaders?.cookie ?? "";
|
|
1957
|
+
if (requestCookie) defaultHeaders["cookie"] = requestCookie;
|
|
1958
|
+
let uniqueToken;
|
|
1959
|
+
let visitToken;
|
|
1960
|
+
if (!/\b_shopify_(analytics|marketing)=/.test(requestCookie)) {
|
|
1961
|
+
const legacyUniqueToken = requestCookie.match(/\b_shopify_y=([^;]+)/)?.[1];
|
|
1962
|
+
const legacyVisitToken = requestCookie.match(/\b_shopify_s=([^;]+)/)?.[1];
|
|
1963
|
+
if (legacyUniqueToken) {
|
|
1964
|
+
defaultHeaders[SHOPIFY_STOREFRONT_Y_HEADER] = legacyUniqueToken;
|
|
1965
|
+
}
|
|
1966
|
+
if (legacyVisitToken) {
|
|
1967
|
+
defaultHeaders[SHOPIFY_STOREFRONT_S_HEADER] = legacyVisitToken;
|
|
1968
|
+
}
|
|
1969
|
+
uniqueToken = legacyUniqueToken ?? generateUUID();
|
|
1970
|
+
visitToken = legacyVisitToken ?? generateUUID();
|
|
1971
|
+
defaultHeaders[SHOPIFY_UNIQUE_TOKEN_HEADER] = uniqueToken;
|
|
1972
|
+
defaultHeaders[SHOPIFY_VISIT_TOKEN_HEADER] = visitToken;
|
|
1814
1973
|
}
|
|
1974
|
+
let collectedSubrequestHeaders;
|
|
1815
1975
|
const cacheKeyHeader = JSON.stringify({
|
|
1816
1976
|
"content-type": defaultHeaders["content-type"],
|
|
1817
1977
|
"user-agent": defaultHeaders["user-agent"],
|
|
@@ -1873,6 +2033,13 @@ function createStorefrontClient(options) {
|
|
|
1873
2033
|
stackInfo,
|
|
1874
2034
|
graphql: graphqlData,
|
|
1875
2035
|
purpose: storefrontHeaders?.purpose
|
|
2036
|
+
},
|
|
2037
|
+
onRawHeaders: (headers2) => {
|
|
2038
|
+
collectedSubrequestHeaders ??= {
|
|
2039
|
+
// `getSetCookie` may not be available in all environments (e.g., classic Remix compiler)
|
|
2040
|
+
setCookie: typeof headers2.getSetCookie === "function" ? headers2.getSetCookie() : [],
|
|
2041
|
+
serverTiming: headers2.get("server-timing") ?? ""
|
|
2042
|
+
};
|
|
1876
2043
|
}
|
|
1877
2044
|
});
|
|
1878
2045
|
const errorOptions = {
|
|
@@ -1971,9 +2138,90 @@ function createStorefrontClient(options) {
|
|
|
1971
2138
|
generateCacheControlHeader,
|
|
1972
2139
|
getPublicTokenHeaders,
|
|
1973
2140
|
getPrivateTokenHeaders,
|
|
2141
|
+
getHeaders: () => ({ ...defaultHeaders }),
|
|
1974
2142
|
getShopifyDomain,
|
|
1975
2143
|
getApiUrl: getStorefrontApiUrl,
|
|
1976
|
-
i18n: i18n ?? defaultI18n
|
|
2144
|
+
i18n: i18n ?? defaultI18n,
|
|
2145
|
+
/**
|
|
2146
|
+
* Checks if the request is targeting the Storefront API endpoint.
|
|
2147
|
+
*/
|
|
2148
|
+
isStorefrontApiUrl(request) {
|
|
2149
|
+
return SFAPI_RE.test(getSafePathname(request.url ?? ""));
|
|
2150
|
+
},
|
|
2151
|
+
/**
|
|
2152
|
+
* Forwards the request to the Storefront API.
|
|
2153
|
+
*/
|
|
2154
|
+
async forward(request, options2) {
|
|
2155
|
+
const forwardedHeaders = new Headers([
|
|
2156
|
+
// Forward only a selected set of headers to the Storefront API
|
|
2157
|
+
// to avoid getting 403 errors due to unexpected headers.
|
|
2158
|
+
...extractHeaders(
|
|
2159
|
+
(key) => request.headers.get(key),
|
|
2160
|
+
[
|
|
2161
|
+
"accept",
|
|
2162
|
+
"accept-encoding",
|
|
2163
|
+
"accept-language",
|
|
2164
|
+
// Access-Control headers are used for CORS preflight requests.
|
|
2165
|
+
"access-control-request-headers",
|
|
2166
|
+
"access-control-request-method",
|
|
2167
|
+
"content-type",
|
|
2168
|
+
"content-length",
|
|
2169
|
+
"cookie",
|
|
2170
|
+
"origin",
|
|
2171
|
+
"referer",
|
|
2172
|
+
"user-agent",
|
|
2173
|
+
STOREFRONT_ACCESS_TOKEN_HEADER,
|
|
2174
|
+
SHOPIFY_UNIQUE_TOKEN_HEADER,
|
|
2175
|
+
SHOPIFY_VISIT_TOKEN_HEADER
|
|
2176
|
+
]
|
|
2177
|
+
),
|
|
2178
|
+
// Add some headers to help with geolocalization and debugging
|
|
2179
|
+
...extractHeaders(
|
|
2180
|
+
(key) => defaultHeaders[key],
|
|
2181
|
+
[
|
|
2182
|
+
SHOPIFY_CLIENT_IP_HEADER,
|
|
2183
|
+
SHOPIFY_CLIENT_IP_SIG_HEADER,
|
|
2184
|
+
SHOPIFY_STOREFRONT_ID_HEADER,
|
|
2185
|
+
STOREFRONT_REQUEST_GROUP_ID_HEADER
|
|
2186
|
+
]
|
|
2187
|
+
)
|
|
2188
|
+
]);
|
|
2189
|
+
if (storefrontHeaders?.buyerIp) {
|
|
2190
|
+
forwardedHeaders.set("x-forwarded-for", storefrontHeaders.buyerIp);
|
|
2191
|
+
}
|
|
2192
|
+
const storefrontApiVersion = options2?.storefrontApiVersion ?? getSafePathname(request.url).match(SFAPI_RE)?.[1];
|
|
2193
|
+
const sfapiResponse = await fetch(
|
|
2194
|
+
getStorefrontApiUrl({ storefrontApiVersion }),
|
|
2195
|
+
{
|
|
2196
|
+
method: request.method,
|
|
2197
|
+
body: request.body,
|
|
2198
|
+
headers: forwardedHeaders
|
|
2199
|
+
}
|
|
2200
|
+
);
|
|
2201
|
+
return new Response(sfapiResponse.body, sfapiResponse);
|
|
2202
|
+
},
|
|
2203
|
+
setCollectedSubrequestHeaders: (response) => {
|
|
2204
|
+
if (collectedSubrequestHeaders) {
|
|
2205
|
+
for (const value of collectedSubrequestHeaders.setCookie) {
|
|
2206
|
+
response.headers.append("Set-Cookie", value);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
const serverTiming = extractServerTimingHeader(
|
|
2210
|
+
collectedSubrequestHeaders?.serverTiming
|
|
2211
|
+
);
|
|
2212
|
+
const isDocumentResponse = response.headers.get("content-type")?.startsWith("text/html");
|
|
2213
|
+
const fallbackValues = isDocumentResponse ? { _y: uniqueToken, _s: visitToken } : void 0;
|
|
2214
|
+
appendServerTimingHeader(response, {
|
|
2215
|
+
...fallbackValues,
|
|
2216
|
+
...serverTiming
|
|
2217
|
+
});
|
|
2218
|
+
if (isDocumentResponse && collectedSubrequestHeaders && // _shopify_essential cookie is always set, but we need more than that
|
|
2219
|
+
collectedSubrequestHeaders.setCookie.length > 1 && serverTiming?._y && serverTiming?._s && serverTiming?._cmp) {
|
|
2220
|
+
appendServerTimingHeader(response, {
|
|
2221
|
+
[HYDROGEN_SERVER_TRACKING_KEY]: "1"
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
1977
2225
|
}
|
|
1978
2226
|
};
|
|
1979
2227
|
}
|
|
@@ -2770,7 +3018,8 @@ function createCartHandler(options) {
|
|
|
2770
3018
|
storefront,
|
|
2771
3019
|
customerAccount,
|
|
2772
3020
|
cartQueryFragment,
|
|
2773
|
-
cartMutateFragment
|
|
3021
|
+
cartMutateFragment,
|
|
3022
|
+
buyerIdentity
|
|
2774
3023
|
} = options;
|
|
2775
3024
|
let cartId = _getCartId();
|
|
2776
3025
|
const getCartId = () => cartId || _getCartId();
|
|
@@ -2782,6 +3031,10 @@ function createCartHandler(options) {
|
|
|
2782
3031
|
};
|
|
2783
3032
|
const _cartCreate = cartCreateDefault(mutateOptions);
|
|
2784
3033
|
const cartCreate = async function(...args) {
|
|
3034
|
+
args[0].buyerIdentity = {
|
|
3035
|
+
...buyerIdentity,
|
|
3036
|
+
...args[0].buyerIdentity
|
|
3037
|
+
};
|
|
2785
3038
|
const result = await _cartCreate(...args);
|
|
2786
3039
|
cartId = result?.cart?.id;
|
|
2787
3040
|
return result;
|
|
@@ -2805,7 +3058,7 @@ function createCartHandler(options) {
|
|
|
2805
3058
|
sellingPlanId: line.sellingPlanId
|
|
2806
3059
|
};
|
|
2807
3060
|
});
|
|
2808
|
-
return cartId || optionalParams?.cartId ? await cartLinesAddDefault(mutateOptions)(lines, optionalParams) : await cartCreate({ lines }, optionalParams);
|
|
3061
|
+
return cartId || optionalParams?.cartId ? await cartLinesAddDefault(mutateOptions)(lines, optionalParams) : await cartCreate({ lines, buyerIdentity }, optionalParams);
|
|
2809
3062
|
},
|
|
2810
3063
|
updateLines: cartLinesUpdateDefault(mutateOptions),
|
|
2811
3064
|
removeLines: cartLinesRemoveDefault(mutateOptions),
|
|
@@ -2821,11 +3074,11 @@ function createCartHandler(options) {
|
|
|
2821
3074
|
optionalParams
|
|
2822
3075
|
) : await cartCreate({ giftCardCodes }, optionalParams);
|
|
2823
3076
|
},
|
|
2824
|
-
updateBuyerIdentity: async (
|
|
3077
|
+
updateBuyerIdentity: async (buyerIdentity2, optionalParams) => {
|
|
2825
3078
|
return cartId || optionalParams?.cartId ? await cartBuyerIdentityUpdateDefault(mutateOptions)(
|
|
2826
|
-
|
|
3079
|
+
buyerIdentity2,
|
|
2827
3080
|
optionalParams
|
|
2828
|
-
) : await cartCreate({ buyerIdentity }, optionalParams);
|
|
3081
|
+
) : await cartCreate({ buyerIdentity: buyerIdentity2 }, optionalParams);
|
|
2829
3082
|
},
|
|
2830
3083
|
updateNote: async (note, optionalParams) => {
|
|
2831
3084
|
return cartId || optionalParams?.cartId ? await cartNoteUpdateDefault(mutateOptions)(note, optionalParams) : await cartCreate({ note }, optionalParams);
|
|
@@ -3720,7 +3973,8 @@ function createHydrogenContext(options) {
|
|
|
3720
3973
|
logErrors,
|
|
3721
3974
|
storefront: storefrontOptions = {},
|
|
3722
3975
|
customerAccount: customerAccountOptions,
|
|
3723
|
-
cart: cartOptions = {}
|
|
3976
|
+
cart: cartOptions = {},
|
|
3977
|
+
buyerIdentity
|
|
3724
3978
|
} = options;
|
|
3725
3979
|
if (!session) {
|
|
3726
3980
|
console.warn(
|
|
@@ -3770,6 +4024,7 @@ function createHydrogenContext(options) {
|
|
|
3770
4024
|
cartQueryFragment: cartOptions.queryFragment,
|
|
3771
4025
|
cartMutateFragment: cartOptions.mutateFragment,
|
|
3772
4026
|
customMethods: cartOptions.customMethods,
|
|
4027
|
+
buyerIdentity,
|
|
3773
4028
|
// defaults
|
|
3774
4029
|
storefront,
|
|
3775
4030
|
customerAccount
|
|
@@ -3787,8 +4042,63 @@ function getStorefrontHeaders(request) {
|
|
|
3787
4042
|
return {
|
|
3788
4043
|
requestGroupId: getHeader(request, "request-id"),
|
|
3789
4044
|
buyerIp: getHeader(request, "oxygen-buyer-ip"),
|
|
4045
|
+
buyerIpSig: getHeader(request, "X-Shopify-Client-IP-Sig"),
|
|
3790
4046
|
cookie: getHeader(request, "cookie"),
|
|
3791
|
-
purpose: getHeader(request, "purpose")
|
|
4047
|
+
purpose: getHeader(request, "sec-purpose") || getHeader(request, "purpose")
|
|
4048
|
+
};
|
|
4049
|
+
}
|
|
4050
|
+
function createRequestHandler({
|
|
4051
|
+
build,
|
|
4052
|
+
mode,
|
|
4053
|
+
poweredByHeader = true,
|
|
4054
|
+
getLoadContext,
|
|
4055
|
+
collectTrackingInformation = true,
|
|
4056
|
+
proxyStandardRoutes = true
|
|
4057
|
+
}) {
|
|
4058
|
+
const handleRequest = createRequestHandler$1(build, mode);
|
|
4059
|
+
const appendPoweredByHeader = poweredByHeader ? (response) => response.headers.append("powered-by", "Shopify, Hydrogen") : void 0;
|
|
4060
|
+
return async (request) => {
|
|
4061
|
+
const method = request.method;
|
|
4062
|
+
if ((method === "GET" || method === "HEAD") && request.body) {
|
|
4063
|
+
return new Response(`${method} requests cannot have a body`, {
|
|
4064
|
+
status: 400
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
const url = new URL(request.url);
|
|
4068
|
+
if (url.pathname.includes("//")) {
|
|
4069
|
+
return new Response(null, {
|
|
4070
|
+
status: 301,
|
|
4071
|
+
headers: {
|
|
4072
|
+
location: url.pathname.replace(/\/+/g, "/")
|
|
4073
|
+
}
|
|
4074
|
+
});
|
|
4075
|
+
}
|
|
4076
|
+
const context = getLoadContext ? await getLoadContext(request) : void 0;
|
|
4077
|
+
const storefront = context?.storefront;
|
|
4078
|
+
if (proxyStandardRoutes) {
|
|
4079
|
+
if (!storefront) {
|
|
4080
|
+
warnOnce(
|
|
4081
|
+
"[h2:createRequestHandler] Storefront instance is required to proxy standard routes."
|
|
4082
|
+
);
|
|
4083
|
+
}
|
|
4084
|
+
if (storefront?.isStorefrontApiUrl(request)) {
|
|
4085
|
+
const response2 = await storefront.forward(request);
|
|
4086
|
+
appendPoweredByHeader?.(response2);
|
|
4087
|
+
return response2;
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
const response = await handleRequest(request, context);
|
|
4091
|
+
if (storefront && proxyStandardRoutes) {
|
|
4092
|
+
if (collectTrackingInformation) {
|
|
4093
|
+
storefront.setCollectedSubrequestHeaders(response);
|
|
4094
|
+
}
|
|
4095
|
+
const fetchDest = request.headers.get("sec-fetch-dest");
|
|
4096
|
+
if (fetchDest && fetchDest === "document" || request.headers.get("accept")?.includes("text/html")) {
|
|
4097
|
+
appendServerTimingHeader(response, { [HYDROGEN_SFAPI_PROXY_KEY]: "1" });
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
appendPoweredByHeader?.(response);
|
|
4101
|
+
return response;
|
|
3792
4102
|
};
|
|
3793
4103
|
}
|
|
3794
4104
|
var NonceContext = createContext(void 0);
|
|
@@ -5782,6 +6092,6 @@ var QUERIES = {
|
|
|
5782
6092
|
//! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartDeliveryAddressesRemove
|
|
5783
6093
|
//! @see: https://shopify.dev/docs/api/storefront/latest/mutations/cartDeliveryAddressesUpdate
|
|
5784
6094
|
|
|
5785
|
-
export { Analytics, AnalyticsEvent, CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, OptimisticInput, Pagination, RichText, Script, Seo, ShopPayButton, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartGiftCardCodesUpdateDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, changelogHandler, createCartHandler, createContentSecurityPolicy, createCustomerAccountClient, createHydrogenContext, createStorefrontClient, createWithCache, formatAPIResult, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, getSeoMeta, getShopAnalytics, getSitemap, getSitemapIndex, graphiqlLoader, hydrogenRoutes, storefrontRedirect, useAnalytics, useCustomerPrivacy, useNonce, useOptimisticCart, useOptimisticData, useOptimisticVariant };
|
|
6095
|
+
export { Analytics, AnalyticsEvent, CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, OptimisticInput, Pagination, RichText, Script, Seo, ShopPayButton, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartGiftCardCodesUpdateDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, changelogHandler, createCartHandler, createContentSecurityPolicy, createCustomerAccountClient, createHydrogenContext, createRequestHandler, createStorefrontClient, createWithCache, formatAPIResult, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, getSeoMeta, getShopAnalytics, getSitemap, getSitemapIndex, graphiqlLoader, hydrogenRoutes, storefrontRedirect, useAnalytics, useCustomerPrivacy, useNonce, useOptimisticCart, useOptimisticData, useOptimisticVariant };
|
|
5786
6096
|
//# sourceMappingURL=index.js.map
|
|
5787
6097
|
//# sourceMappingURL=index.js.map
|