@shopify/hydrogen 2023.7.13 → 2023.10.1
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 +639 -165
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +639 -166
- package/dist/development/index.js.map +1 -1
- package/dist/production/index.cjs +169 -130
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.d.cts +63 -26
- package/dist/production/index.d.ts +63 -26
- package/dist/production/index.js +130 -92
- package/dist/production/index.js.map +1 -1
- package/dist/storefront-api-types.d.ts +1046 -979
- package/dist/storefront.schema.json +1 -1
- package/package.json +6 -5
|
@@ -15,13 +15,9 @@ function hashKey(queryKey) {
|
|
|
15
15
|
for (const key of rawKeys) {
|
|
16
16
|
if (key != null) {
|
|
17
17
|
if (typeof key === "object") {
|
|
18
|
-
|
|
19
|
-
hash += key.body;
|
|
20
|
-
} else {
|
|
21
|
-
hash += JSON.stringify(key);
|
|
22
|
-
}
|
|
18
|
+
hash += JSON.stringify(key);
|
|
23
19
|
} else {
|
|
24
|
-
hash += key;
|
|
20
|
+
hash += key.toString();
|
|
25
21
|
}
|
|
26
22
|
}
|
|
27
23
|
}
|
|
@@ -81,6 +77,16 @@ function CacheLong(overrideOptions) {
|
|
|
81
77
|
...overrideOptions
|
|
82
78
|
};
|
|
83
79
|
}
|
|
80
|
+
function CacheDefault(overrideOptions) {
|
|
81
|
+
guardExpirableModeType(overrideOptions);
|
|
82
|
+
return {
|
|
83
|
+
mode: PUBLIC,
|
|
84
|
+
maxAge: 1,
|
|
85
|
+
staleWhileRevalidate: 86399,
|
|
86
|
+
// 1 second less than 24 hours
|
|
87
|
+
...overrideOptions
|
|
88
|
+
};
|
|
89
|
+
}
|
|
84
90
|
function CacheCustom(overrideOptions) {
|
|
85
91
|
return overrideOptions;
|
|
86
92
|
}
|
|
@@ -102,7 +108,7 @@ function getCacheControlSetting(userCacheOptions, options) {
|
|
|
102
108
|
...options
|
|
103
109
|
};
|
|
104
110
|
} else {
|
|
105
|
-
return userCacheOptions ||
|
|
111
|
+
return userCacheOptions || CacheDefault();
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
function generateDefaultCacheControlHeader(userCacheOptions) {
|
|
@@ -173,7 +179,7 @@ function getKeyUrl(key) {
|
|
|
173
179
|
return `https://shopify.dev/?${key}`;
|
|
174
180
|
}
|
|
175
181
|
function getCacheOption(userCacheOptions) {
|
|
176
|
-
return userCacheOptions ||
|
|
182
|
+
return userCacheOptions || CacheDefault();
|
|
177
183
|
}
|
|
178
184
|
async function getItemFromCache(cache, key) {
|
|
179
185
|
if (!cache)
|
|
@@ -357,26 +363,63 @@ var warnOnce = (string) => {
|
|
|
357
363
|
};
|
|
358
364
|
|
|
359
365
|
// src/version.ts
|
|
360
|
-
var LIB_VERSION = "2023.
|
|
366
|
+
var LIB_VERSION = "2023.10.1";
|
|
367
|
+
|
|
368
|
+
// src/utils/graphql.ts
|
|
369
|
+
function minifyQuery(string) {
|
|
370
|
+
return string.replace(/\s*#.*$/gm, "").replace(/\s+/gm, " ").trim();
|
|
371
|
+
}
|
|
372
|
+
var IS_QUERY_RE = /(^|}\s)query[\s({]/im;
|
|
373
|
+
var IS_MUTATION_RE = /(^|}\s)mutation[\s({]/im;
|
|
374
|
+
function assertQuery(query, callerName) {
|
|
375
|
+
if (!IS_QUERY_RE.test(query)) {
|
|
376
|
+
throw new Error(`[h2:error:${callerName}] Can only execute queries`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function assertMutation(query, callerName) {
|
|
380
|
+
if (!IS_MUTATION_RE.test(query)) {
|
|
381
|
+
throw new Error(`[h2:error:${callerName}] Can only execute mutations`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function throwGraphQLError({
|
|
385
|
+
response,
|
|
386
|
+
errors,
|
|
387
|
+
type,
|
|
388
|
+
query,
|
|
389
|
+
queryVariables,
|
|
390
|
+
ErrorConstructor = Error,
|
|
391
|
+
client = "storefront"
|
|
392
|
+
}) {
|
|
393
|
+
const requestId = response.headers.get("x-request-id");
|
|
394
|
+
const errorMessage = (typeof errors === "string" ? errors : errors?.map?.((error) => error.message).join("\n")) || `API response error: ${response.status}`;
|
|
395
|
+
throw new ErrorConstructor(
|
|
396
|
+
`[h2:error:${client}.${type}] ` + errorMessage + (requestId ? ` - Request ID: ${requestId}` : ""),
|
|
397
|
+
{
|
|
398
|
+
cause: JSON.stringify({
|
|
399
|
+
errors,
|
|
400
|
+
requestId,
|
|
401
|
+
...{
|
|
402
|
+
graphql: {
|
|
403
|
+
query,
|
|
404
|
+
variables: JSON.stringify(queryVariables)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
}
|
|
361
411
|
|
|
362
412
|
// src/storefront.ts
|
|
363
413
|
var StorefrontApiError = class extends Error {
|
|
364
414
|
};
|
|
365
415
|
var isStorefrontApiError = (error) => error instanceof StorefrontApiError;
|
|
366
|
-
var isQueryRE = /(^|}\s)query[\s({]/im;
|
|
367
|
-
var isMutationRE = /(^|}\s)mutation[\s({]/im;
|
|
368
|
-
function minifyQuery(string) {
|
|
369
|
-
return string.replace(/\s*#.*$/gm, "").replace(/\s+/gm, " ").trim();
|
|
370
|
-
}
|
|
371
416
|
var defaultI18n = { language: "EN", country: "US" };
|
|
372
417
|
function createStorefrontClient(options) {
|
|
373
418
|
const {
|
|
374
419
|
storefrontHeaders,
|
|
375
420
|
cache,
|
|
376
421
|
waitUntil,
|
|
377
|
-
buyerIp,
|
|
378
422
|
i18n,
|
|
379
|
-
requestGroupId,
|
|
380
423
|
storefrontId,
|
|
381
424
|
...clientOptions
|
|
382
425
|
} = options;
|
|
@@ -395,9 +438,9 @@ function createStorefrontClient(options) {
|
|
|
395
438
|
const getHeaders = clientOptions.privateStorefrontToken ? getPrivateTokenHeaders : getPublicTokenHeaders;
|
|
396
439
|
const defaultHeaders = getHeaders({
|
|
397
440
|
contentType: "json",
|
|
398
|
-
buyerIp: storefrontHeaders?.buyerIp ||
|
|
441
|
+
buyerIp: storefrontHeaders?.buyerIp || ""
|
|
399
442
|
});
|
|
400
|
-
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId ||
|
|
443
|
+
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId || generateUUID();
|
|
401
444
|
if (storefrontId)
|
|
402
445
|
defaultHeaders[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
|
|
403
446
|
defaultHeaders["user-agent"] = `Hydrogen ${LIB_VERSION}`;
|
|
@@ -408,11 +451,14 @@ function createStorefrontClient(options) {
|
|
|
408
451
|
if (cookies[SHOPIFY_S])
|
|
409
452
|
defaultHeaders[SHOPIFY_STOREFRONT_S_HEADER] = cookies[SHOPIFY_S];
|
|
410
453
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
454
|
+
const cacheKeyHeader = JSON.stringify({
|
|
455
|
+
"content-type": defaultHeaders["content-type"],
|
|
456
|
+
"user-agent": defaultHeaders["user-agent"],
|
|
457
|
+
[SDK_VARIANT_HEADER]: defaultHeaders[SDK_VARIANT_HEADER],
|
|
458
|
+
[SDK_VARIANT_SOURCE_HEADER]: defaultHeaders[SDK_VARIANT_SOURCE_HEADER],
|
|
459
|
+
[SDK_VERSION_HEADER]: defaultHeaders[SDK_VERSION_HEADER],
|
|
460
|
+
[STOREFRONT_ACCESS_TOKEN_HEADER]: defaultHeaders[STOREFRONT_ACCESS_TOKEN_HEADER]
|
|
461
|
+
});
|
|
416
462
|
async function fetchStorefrontApi({
|
|
417
463
|
query,
|
|
418
464
|
mutation,
|
|
@@ -441,22 +487,13 @@ function createStorefrontClient(options) {
|
|
|
441
487
|
};
|
|
442
488
|
const cacheKey = [
|
|
443
489
|
url,
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
"content-type": defaultHeaders["content-type"],
|
|
448
|
-
"user-agent": defaultHeaders["user-agent"],
|
|
449
|
-
[SDK_VARIANT_HEADER]: defaultHeaders[SDK_VARIANT_HEADER],
|
|
450
|
-
[SDK_VARIANT_SOURCE_HEADER]: defaultHeaders[SDK_VARIANT_SOURCE_HEADER],
|
|
451
|
-
[SDK_VERSION_HEADER]: defaultHeaders[SDK_VERSION_HEADER],
|
|
452
|
-
[STOREFRONT_ACCESS_TOKEN_HEADER]: defaultHeaders[STOREFRONT_ACCESS_TOKEN_HEADER]
|
|
453
|
-
},
|
|
454
|
-
body: requestInit.body
|
|
455
|
-
}
|
|
490
|
+
requestInit.method,
|
|
491
|
+
cacheKeyHeader,
|
|
492
|
+
requestInit.body
|
|
456
493
|
];
|
|
457
494
|
const [body, response] = await fetchWithServerCache(url, requestInit, {
|
|
458
495
|
cacheInstance: mutation ? void 0 : cache,
|
|
459
|
-
cache: cacheOptions ||
|
|
496
|
+
cache: cacheOptions || CacheDefault(),
|
|
460
497
|
cacheKey,
|
|
461
498
|
shouldCacheResponse: checkGraphQLErrors,
|
|
462
499
|
waitUntil,
|
|
@@ -480,11 +517,11 @@ function createStorefrontClient(options) {
|
|
|
480
517
|
} catch (_e) {
|
|
481
518
|
errors2 = [{ message: body }];
|
|
482
519
|
}
|
|
483
|
-
|
|
520
|
+
throwGraphQLError({ ...errorOptions, errors: errors2 });
|
|
484
521
|
}
|
|
485
522
|
const { data, errors } = body;
|
|
486
523
|
if (errors?.length) {
|
|
487
|
-
|
|
524
|
+
throwGraphQLError({
|
|
488
525
|
...errorOptions,
|
|
489
526
|
errors,
|
|
490
527
|
ErrorConstructor: StorefrontApiError
|
|
@@ -510,11 +547,7 @@ function createStorefrontClient(options) {
|
|
|
510
547
|
*/
|
|
511
548
|
query: (query, payload) => {
|
|
512
549
|
query = minifyQuery(query);
|
|
513
|
-
|
|
514
|
-
throw new Error(
|
|
515
|
-
"[h2:error:storefront.query] Cannot execute mutations"
|
|
516
|
-
);
|
|
517
|
-
}
|
|
550
|
+
assertQuery(query, "storefront.query");
|
|
518
551
|
const result = fetchStorefrontApi({
|
|
519
552
|
...payload,
|
|
520
553
|
query
|
|
@@ -538,11 +571,7 @@ function createStorefrontClient(options) {
|
|
|
538
571
|
*/
|
|
539
572
|
mutate: (mutation, payload) => {
|
|
540
573
|
mutation = minifyQuery(mutation);
|
|
541
|
-
|
|
542
|
-
throw new Error(
|
|
543
|
-
"[h2:error:storefront.mutate] Cannot execute queries"
|
|
544
|
-
);
|
|
545
|
-
}
|
|
574
|
+
assertMutation(mutation, "storefront.mutate");
|
|
546
575
|
const result = fetchStorefrontApi({
|
|
547
576
|
...payload,
|
|
548
577
|
mutation
|
|
@@ -585,32 +614,6 @@ function createStorefrontClient(options) {
|
|
|
585
614
|
}
|
|
586
615
|
};
|
|
587
616
|
}
|
|
588
|
-
function throwError({
|
|
589
|
-
response,
|
|
590
|
-
errors,
|
|
591
|
-
type,
|
|
592
|
-
query,
|
|
593
|
-
queryVariables,
|
|
594
|
-
ErrorConstructor = Error
|
|
595
|
-
}) {
|
|
596
|
-
const requestId = response.headers.get("x-request-id");
|
|
597
|
-
const errorMessage = (typeof errors === "string" ? errors : errors?.map?.((error) => error.message).join("\n")) || `API response error: ${response.status}`;
|
|
598
|
-
throw new ErrorConstructor(
|
|
599
|
-
`[h2:error:storefront.${type}] ` + errorMessage + (requestId ? ` - Request ID: ${requestId}` : ""),
|
|
600
|
-
{
|
|
601
|
-
cause: JSON.stringify({
|
|
602
|
-
errors,
|
|
603
|
-
requestId,
|
|
604
|
-
...{
|
|
605
|
-
graphql: {
|
|
606
|
-
query,
|
|
607
|
-
variables: JSON.stringify(queryVariables)
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
})
|
|
611
|
-
}
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
617
|
|
|
615
618
|
// src/utils/request.ts
|
|
616
619
|
function getHeader(request, key) {
|
|
@@ -790,76 +793,115 @@ var graphiqlLoader = async function graphiqlLoader2({
|
|
|
790
793
|
const url = storefront.getApiUrl();
|
|
791
794
|
const accessToken = storefront.getPublicTokenHeaders()["X-Shopify-Storefront-Access-Token"];
|
|
792
795
|
const favicon = `https://avatars.githubusercontent.com/u/12972006?s=48&v=4`;
|
|
796
|
+
const html = String.raw;
|
|
793
797
|
return new Response(
|
|
794
|
-
`
|
|
795
|
-
<!DOCTYPE html>
|
|
796
|
-
<html lang="en">
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
798
|
+
html`
|
|
799
|
+
<!DOCTYPE html>
|
|
800
|
+
<html lang="en">
|
|
801
|
+
<head>
|
|
802
|
+
<title>GraphiQL</title>
|
|
803
|
+
<link rel="icon" type="image/x-icon" href="${favicon}" />
|
|
804
|
+
<style>
|
|
805
|
+
body {
|
|
806
|
+
height: 100%;
|
|
807
|
+
margin: 0;
|
|
808
|
+
width: 100%;
|
|
809
|
+
overflow: hidden;
|
|
810
|
+
background-color: hsl(219, 29%, 18%);
|
|
811
|
+
}
|
|
807
812
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
</style>
|
|
813
|
+
#graphiql {
|
|
814
|
+
height: 100vh;
|
|
815
|
+
}
|
|
812
816
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
></script>
|
|
821
|
-
<link rel="stylesheet" href="https://unpkg.com/graphiql@3/graphiql.min.css" />
|
|
822
|
-
</head>
|
|
817
|
+
#graphiql > .placeholder {
|
|
818
|
+
color: slategray;
|
|
819
|
+
width: fit-content;
|
|
820
|
+
margin: 40px auto;
|
|
821
|
+
font-family: Arial;
|
|
822
|
+
}
|
|
823
|
+
</style>
|
|
823
824
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
825
|
+
<script
|
|
826
|
+
crossorigin
|
|
827
|
+
src="https://unpkg.com/react@18/umd/react.development.js"
|
|
828
|
+
></script>
|
|
829
|
+
<script
|
|
830
|
+
crossorigin
|
|
831
|
+
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
|
|
832
|
+
></script>
|
|
833
|
+
<link
|
|
834
|
+
rel="stylesheet"
|
|
835
|
+
href="https://unpkg.com/graphiql@3/graphiql.min.css"
|
|
836
|
+
/>
|
|
837
|
+
<link
|
|
838
|
+
rel="stylesheet"
|
|
839
|
+
href="https://unpkg.com/@graphiql/plugin-explorer/dist/style.css"
|
|
840
|
+
/>
|
|
841
|
+
</head>
|
|
832
842
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if (query) query = GraphiQL.GraphQL.print(GraphiQL.GraphQL.parse(query));
|
|
838
|
-
}
|
|
843
|
+
<body>
|
|
844
|
+
<div id="graphiql">
|
|
845
|
+
<div class="placeholder">Loading GraphiQL...</div>
|
|
846
|
+
</div>
|
|
839
847
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
848
|
+
<script
|
|
849
|
+
src="https://unpkg.com/graphiql@3/graphiql.min.js"
|
|
850
|
+
type="application/javascript"
|
|
851
|
+
crossorigin="anonymous"
|
|
852
|
+
></script>
|
|
853
|
+
<script
|
|
854
|
+
src="https://unpkg.com/@graphiql/plugin-explorer/dist/index.umd.js"
|
|
855
|
+
type="application/javascript"
|
|
856
|
+
crossorigin="anonymous"
|
|
857
|
+
></script>
|
|
846
858
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
859
|
+
<script>
|
|
860
|
+
const windowUrl = new URL(document.URL);
|
|
861
|
+
|
|
862
|
+
let query = '{ shop { name } }';
|
|
863
|
+
if (windowUrl.searchParams.has('query')) {
|
|
864
|
+
query = decodeURIComponent(
|
|
865
|
+
windowUrl.searchParams.get('query') ?? query,
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// Prettify query
|
|
870
|
+
query = GraphiQL.GraphQL.print(GraphiQL.GraphQL.parse(query));
|
|
871
|
+
|
|
872
|
+
let variables;
|
|
873
|
+
if (windowUrl.searchParams.has('variables')) {
|
|
874
|
+
variables = decodeURIComponent(
|
|
875
|
+
windowUrl.searchParams.get('variables') ?? '',
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// Prettify variables
|
|
880
|
+
if (variables) {
|
|
881
|
+
variables = JSON.stringify(JSON.parse(variables), null, 2);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const root = ReactDOM.createRoot(
|
|
885
|
+
document.getElementById('graphiql'),
|
|
886
|
+
);
|
|
887
|
+
root.render(
|
|
888
|
+
React.createElement(GraphiQL, {
|
|
889
|
+
fetcher: GraphiQL.createFetcher({
|
|
890
|
+
url: '${url}',
|
|
891
|
+
headers: {
|
|
892
|
+
'X-Shopify-Storefront-Access-Token': '${accessToken}',
|
|
893
|
+
},
|
|
894
|
+
}),
|
|
895
|
+
defaultEditorToolsVisibility: true,
|
|
896
|
+
query,
|
|
897
|
+
variables,
|
|
898
|
+
plugins: [GraphiQLPluginExplorer.explorerPlugin()],
|
|
899
|
+
}),
|
|
900
|
+
);
|
|
901
|
+
</script>
|
|
902
|
+
</body>
|
|
903
|
+
</html>
|
|
904
|
+
`,
|
|
863
905
|
{ status: 200, headers: { "content-type": "text/html" } }
|
|
864
906
|
);
|
|
865
907
|
};
|
|
@@ -965,14 +1007,15 @@ function generateSeoTags(seoInput) {
|
|
|
965
1007
|
if (!content) {
|
|
966
1008
|
break;
|
|
967
1009
|
}
|
|
1010
|
+
const urlWithoutParams = content.split("?")[0];
|
|
968
1011
|
tagResults.push(
|
|
969
1012
|
generateTag("link", {
|
|
970
1013
|
rel: "canonical",
|
|
971
|
-
href:
|
|
1014
|
+
href: urlWithoutParams
|
|
972
1015
|
}),
|
|
973
1016
|
generateTag("meta", {
|
|
974
1017
|
property: "og:url",
|
|
975
|
-
content
|
|
1018
|
+
content: urlWithoutParams
|
|
976
1019
|
})
|
|
977
1020
|
);
|
|
978
1021
|
break;
|
|
@@ -1203,7 +1246,7 @@ function Seo({ debug }) {
|
|
|
1203
1246
|
return [];
|
|
1204
1247
|
}
|
|
1205
1248
|
if (handleSeo) {
|
|
1206
|
-
return recursivelyInvokeOrReturn(
|
|
1249
|
+
return recursivelyInvokeOrReturn(handleSeo, routeData);
|
|
1207
1250
|
} else {
|
|
1208
1251
|
return [loaderSeo];
|
|
1209
1252
|
}
|
|
@@ -1469,6 +1512,456 @@ function getPaginationVariables(request, options = { pageBy: 20 }) {
|
|
|
1469
1512
|
const variables = isPrevious ? prevPage : nextPage;
|
|
1470
1513
|
return variables;
|
|
1471
1514
|
}
|
|
1515
|
+
|
|
1516
|
+
// src/customer/BadRequest.ts
|
|
1517
|
+
var BadRequest = class extends Response {
|
|
1518
|
+
constructor(message, helpMessage) {
|
|
1519
|
+
if (helpMessage && true) {
|
|
1520
|
+
console.error("Customer Account API Error: " + helpMessage);
|
|
1521
|
+
}
|
|
1522
|
+
super(`Bad request: ${message}`, { status: 400 });
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1526
|
+
// src/customer/auth.helpers.ts
|
|
1527
|
+
var USER_AGENT = `Shopify Hydrogen ${LIB_VERSION}`;
|
|
1528
|
+
var CUSTOMER_API_CLIENT_ID = "30243aa5-17c1-465a-8493-944bcc4e88aa";
|
|
1529
|
+
function redirect2(path, options = {}) {
|
|
1530
|
+
const headers = options.headers ? new Headers(options.headers) : new Headers({});
|
|
1531
|
+
headers.set("location", path);
|
|
1532
|
+
return new Response(null, { status: options.status || 302, headers });
|
|
1533
|
+
}
|
|
1534
|
+
async function refreshToken({
|
|
1535
|
+
session,
|
|
1536
|
+
customerAccountId,
|
|
1537
|
+
customerAccountUrl,
|
|
1538
|
+
origin
|
|
1539
|
+
}) {
|
|
1540
|
+
const newBody = new URLSearchParams();
|
|
1541
|
+
const refreshToken2 = session.get("refresh_token");
|
|
1542
|
+
if (!refreshToken2)
|
|
1543
|
+
throw new BadRequest(
|
|
1544
|
+
"Unauthorized",
|
|
1545
|
+
"No refresh_token in the session. Make sure your session is configured correctly and passed to `createCustomerClient`."
|
|
1546
|
+
);
|
|
1547
|
+
newBody.append("grant_type", "refresh_token");
|
|
1548
|
+
newBody.append("refresh_token", refreshToken2);
|
|
1549
|
+
newBody.append("client_id", customerAccountId);
|
|
1550
|
+
const headers = {
|
|
1551
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1552
|
+
"User-Agent": USER_AGENT,
|
|
1553
|
+
Origin: origin
|
|
1554
|
+
};
|
|
1555
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
1556
|
+
method: "POST",
|
|
1557
|
+
headers,
|
|
1558
|
+
body: newBody
|
|
1559
|
+
});
|
|
1560
|
+
if (!response.ok) {
|
|
1561
|
+
const text = await response.text();
|
|
1562
|
+
throw new Response(text, {
|
|
1563
|
+
status: response.status,
|
|
1564
|
+
headers: {
|
|
1565
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1566
|
+
}
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
const { access_token, expires_in, id_token, refresh_token } = await response.json();
|
|
1570
|
+
session.set("customer_authorization_code_token", access_token);
|
|
1571
|
+
session.set(
|
|
1572
|
+
"expires_at",
|
|
1573
|
+
new Date((/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3).getTime() + ""
|
|
1574
|
+
);
|
|
1575
|
+
session.set("id_token", id_token);
|
|
1576
|
+
session.set("refresh_token", refresh_token);
|
|
1577
|
+
const customerAccessToken = await exchangeAccessToken(
|
|
1578
|
+
session,
|
|
1579
|
+
customerAccountId,
|
|
1580
|
+
customerAccountUrl,
|
|
1581
|
+
origin
|
|
1582
|
+
);
|
|
1583
|
+
session.set("customer_access_token", customerAccessToken);
|
|
1584
|
+
}
|
|
1585
|
+
function clearSession(session) {
|
|
1586
|
+
session.unset("code-verifier");
|
|
1587
|
+
session.unset("customer_authorization_code_token");
|
|
1588
|
+
session.unset("expires_at");
|
|
1589
|
+
session.unset("id_token");
|
|
1590
|
+
session.unset("refresh_token");
|
|
1591
|
+
session.unset("customer_access_token");
|
|
1592
|
+
session.unset("state");
|
|
1593
|
+
session.unset("nonce");
|
|
1594
|
+
}
|
|
1595
|
+
async function checkExpires({
|
|
1596
|
+
locks,
|
|
1597
|
+
expiresAt,
|
|
1598
|
+
session,
|
|
1599
|
+
customerAccountId,
|
|
1600
|
+
customerAccountUrl,
|
|
1601
|
+
origin
|
|
1602
|
+
}) {
|
|
1603
|
+
if (parseInt(expiresAt, 10) - 1e3 < (/* @__PURE__ */ new Date()).getTime()) {
|
|
1604
|
+
try {
|
|
1605
|
+
if (!locks.refresh)
|
|
1606
|
+
locks.refresh = refreshToken({
|
|
1607
|
+
session,
|
|
1608
|
+
customerAccountId,
|
|
1609
|
+
customerAccountUrl,
|
|
1610
|
+
origin
|
|
1611
|
+
});
|
|
1612
|
+
await locks.refresh;
|
|
1613
|
+
delete locks.refresh;
|
|
1614
|
+
} catch (error) {
|
|
1615
|
+
clearSession(session);
|
|
1616
|
+
if (error && error.status !== 401) {
|
|
1617
|
+
throw error;
|
|
1618
|
+
} else {
|
|
1619
|
+
throw new BadRequest(
|
|
1620
|
+
"Unauthorized",
|
|
1621
|
+
"Login before querying the Customer Account API."
|
|
1622
|
+
);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
async function generateCodeVerifier() {
|
|
1628
|
+
const rando = generateRandomCode();
|
|
1629
|
+
return base64UrlEncode(rando);
|
|
1630
|
+
}
|
|
1631
|
+
async function generateCodeChallenge(codeVerifier) {
|
|
1632
|
+
const digestOp = await crypto.subtle.digest(
|
|
1633
|
+
{ name: "SHA-256" },
|
|
1634
|
+
new TextEncoder().encode(codeVerifier)
|
|
1635
|
+
);
|
|
1636
|
+
const hash = convertBufferToString(digestOp);
|
|
1637
|
+
return base64UrlEncode(hash);
|
|
1638
|
+
}
|
|
1639
|
+
function generateRandomCode() {
|
|
1640
|
+
const array = new Uint8Array(32);
|
|
1641
|
+
crypto.getRandomValues(array);
|
|
1642
|
+
return String.fromCharCode.apply(null, Array.from(array));
|
|
1643
|
+
}
|
|
1644
|
+
function base64UrlEncode(str) {
|
|
1645
|
+
const base64 = btoa(str);
|
|
1646
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1647
|
+
}
|
|
1648
|
+
function convertBufferToString(hash) {
|
|
1649
|
+
const uintArray = new Uint8Array(hash);
|
|
1650
|
+
const numberArray = Array.from(uintArray);
|
|
1651
|
+
return String.fromCharCode(...numberArray);
|
|
1652
|
+
}
|
|
1653
|
+
async function generateState() {
|
|
1654
|
+
const timestamp = Date.now().toString();
|
|
1655
|
+
const randomString = Math.random().toString(36).substring(2);
|
|
1656
|
+
return timestamp + randomString;
|
|
1657
|
+
}
|
|
1658
|
+
async function exchangeAccessToken(session, customerAccountId, customerAccountUrl, origin) {
|
|
1659
|
+
const clientId = customerAccountId;
|
|
1660
|
+
const accessToken = session.get("customer_authorization_code_token");
|
|
1661
|
+
if (!accessToken)
|
|
1662
|
+
throw new BadRequest(
|
|
1663
|
+
"Unauthorized",
|
|
1664
|
+
"No access token found in the session. Make sure your session is configured correctly and passed to `createCustomerClient`."
|
|
1665
|
+
);
|
|
1666
|
+
const body = new URLSearchParams();
|
|
1667
|
+
body.append("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange");
|
|
1668
|
+
body.append("client_id", clientId);
|
|
1669
|
+
body.append("audience", CUSTOMER_API_CLIENT_ID);
|
|
1670
|
+
body.append("subject_token", accessToken);
|
|
1671
|
+
body.append(
|
|
1672
|
+
"subject_token_type",
|
|
1673
|
+
"urn:ietf:params:oauth:token-type:access_token"
|
|
1674
|
+
);
|
|
1675
|
+
body.append("scopes", "https://api.customers.com/auth/customer.graphql");
|
|
1676
|
+
const headers = {
|
|
1677
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1678
|
+
"User-Agent": USER_AGENT,
|
|
1679
|
+
Origin: origin
|
|
1680
|
+
};
|
|
1681
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
1682
|
+
method: "POST",
|
|
1683
|
+
headers,
|
|
1684
|
+
body
|
|
1685
|
+
});
|
|
1686
|
+
const data = await response.json();
|
|
1687
|
+
if (data.error) {
|
|
1688
|
+
throw new BadRequest(data.error_description);
|
|
1689
|
+
}
|
|
1690
|
+
return data.access_token;
|
|
1691
|
+
}
|
|
1692
|
+
function getNonce(token) {
|
|
1693
|
+
return decodeJwt(token).payload.nonce;
|
|
1694
|
+
}
|
|
1695
|
+
function decodeJwt(token) {
|
|
1696
|
+
const [header, payload, signature] = token.split(".");
|
|
1697
|
+
const decodedHeader = JSON.parse(atob(header));
|
|
1698
|
+
const decodedPayload = JSON.parse(atob(payload));
|
|
1699
|
+
return {
|
|
1700
|
+
header: decodedHeader,
|
|
1701
|
+
payload: decodedPayload,
|
|
1702
|
+
signature
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// src/csp/nonce.ts
|
|
1707
|
+
function generateNonce() {
|
|
1708
|
+
return toHexString(randomUint8Array());
|
|
1709
|
+
}
|
|
1710
|
+
function randomUint8Array() {
|
|
1711
|
+
try {
|
|
1712
|
+
return crypto.getRandomValues(new Uint8Array(16));
|
|
1713
|
+
} catch (e) {
|
|
1714
|
+
return new Uint8Array(16).map(() => Math.random() * 255 | 0);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
function toHexString(byteArray) {
|
|
1718
|
+
return Array.from(byteArray, function(byte) {
|
|
1719
|
+
return ("0" + (byte & 255).toString(16)).slice(-2);
|
|
1720
|
+
}).join("");
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// src/customer/customer.ts
|
|
1724
|
+
function createCustomerClient({
|
|
1725
|
+
session,
|
|
1726
|
+
customerAccountId,
|
|
1727
|
+
customerAccountUrl,
|
|
1728
|
+
customerApiVersion = "2023-10",
|
|
1729
|
+
request,
|
|
1730
|
+
waitUntil
|
|
1731
|
+
}) {
|
|
1732
|
+
if (!request?.url) {
|
|
1733
|
+
throw new Error(
|
|
1734
|
+
"[h2:error:createCustomerClient] The request object does not contain a URL."
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
const url = new URL(request.url);
|
|
1738
|
+
const origin = url.protocol === "http:" ? url.origin.replace("http", "https") : url.origin;
|
|
1739
|
+
const locks = {};
|
|
1740
|
+
const logSubRequestEvent = (query, startTime) => {
|
|
1741
|
+
globalThis.__H2O_LOG_EVENT?.({
|
|
1742
|
+
eventType: "subrequest",
|
|
1743
|
+
url: `https://shopify.dev/?${hashKey([
|
|
1744
|
+
`Customer Account `,
|
|
1745
|
+
/((query|mutation) [^\s\(]+)/g.exec(query)?.[0] || query.substring(0, 10)
|
|
1746
|
+
])}`,
|
|
1747
|
+
startTime,
|
|
1748
|
+
waitUntil,
|
|
1749
|
+
...getDebugHeaders(request)
|
|
1750
|
+
});
|
|
1751
|
+
} ;
|
|
1752
|
+
async function fetchCustomerAPI({
|
|
1753
|
+
query,
|
|
1754
|
+
type,
|
|
1755
|
+
variables = {}
|
|
1756
|
+
}) {
|
|
1757
|
+
const accessToken = session.get("customer_access_token");
|
|
1758
|
+
const expiresAt = session.get("expires_at");
|
|
1759
|
+
if (!accessToken || !expiresAt)
|
|
1760
|
+
throw new BadRequest(
|
|
1761
|
+
"Unauthorized",
|
|
1762
|
+
"Login before querying the Customer Account API."
|
|
1763
|
+
);
|
|
1764
|
+
await checkExpires({
|
|
1765
|
+
locks,
|
|
1766
|
+
expiresAt,
|
|
1767
|
+
session,
|
|
1768
|
+
customerAccountId,
|
|
1769
|
+
customerAccountUrl,
|
|
1770
|
+
origin
|
|
1771
|
+
});
|
|
1772
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
1773
|
+
const response = await fetch(
|
|
1774
|
+
`${customerAccountUrl}/account/customer/api/${customerApiVersion}/graphql`,
|
|
1775
|
+
{
|
|
1776
|
+
method: "POST",
|
|
1777
|
+
headers: {
|
|
1778
|
+
"Content-Type": "application/json",
|
|
1779
|
+
"User-Agent": USER_AGENT,
|
|
1780
|
+
Origin: origin,
|
|
1781
|
+
Authorization: accessToken
|
|
1782
|
+
},
|
|
1783
|
+
body: JSON.stringify({
|
|
1784
|
+
operationName: "SomeQuery",
|
|
1785
|
+
query,
|
|
1786
|
+
variables
|
|
1787
|
+
})
|
|
1788
|
+
}
|
|
1789
|
+
);
|
|
1790
|
+
logSubRequestEvent?.(query, startTime);
|
|
1791
|
+
const body = await response.text();
|
|
1792
|
+
const errorOptions = {
|
|
1793
|
+
response,
|
|
1794
|
+
type,
|
|
1795
|
+
query,
|
|
1796
|
+
queryVariables: variables,
|
|
1797
|
+
errors: void 0,
|
|
1798
|
+
client: "customer"
|
|
1799
|
+
};
|
|
1800
|
+
if (!response.ok) {
|
|
1801
|
+
let errors;
|
|
1802
|
+
try {
|
|
1803
|
+
errors = parseJSON(body);
|
|
1804
|
+
} catch (_e) {
|
|
1805
|
+
errors = [{ message: body }];
|
|
1806
|
+
}
|
|
1807
|
+
throwGraphQLError({ ...errorOptions, errors });
|
|
1808
|
+
}
|
|
1809
|
+
try {
|
|
1810
|
+
return parseJSON(body).data;
|
|
1811
|
+
} catch (e) {
|
|
1812
|
+
throwGraphQLError({ ...errorOptions, errors: [{ message: body }] });
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
login: async () => {
|
|
1817
|
+
const loginUrl = new URL(customerAccountUrl + "/auth/oauth/authorize");
|
|
1818
|
+
const state = await generateState();
|
|
1819
|
+
const nonce = await generateNonce();
|
|
1820
|
+
loginUrl.searchParams.set("client_id", customerAccountId);
|
|
1821
|
+
loginUrl.searchParams.set("scope", "openid email");
|
|
1822
|
+
loginUrl.searchParams.append("response_type", "code");
|
|
1823
|
+
loginUrl.searchParams.append("redirect_uri", origin + "/authorize");
|
|
1824
|
+
loginUrl.searchParams.set(
|
|
1825
|
+
"scope",
|
|
1826
|
+
"openid email https://api.customers.com/auth/customer.graphql"
|
|
1827
|
+
);
|
|
1828
|
+
loginUrl.searchParams.append("state", state);
|
|
1829
|
+
loginUrl.searchParams.append("nonce", nonce);
|
|
1830
|
+
const verifier = await generateCodeVerifier();
|
|
1831
|
+
const challenge = await generateCodeChallenge(verifier);
|
|
1832
|
+
session.set("code-verifier", verifier);
|
|
1833
|
+
session.set("state", state);
|
|
1834
|
+
session.set("nonce", nonce);
|
|
1835
|
+
loginUrl.searchParams.append("code_challenge", challenge);
|
|
1836
|
+
loginUrl.searchParams.append("code_challenge_method", "S256");
|
|
1837
|
+
return redirect2(loginUrl.toString(), {
|
|
1838
|
+
headers: {
|
|
1839
|
+
"Set-Cookie": await session.commit()
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
},
|
|
1843
|
+
logout: async () => {
|
|
1844
|
+
const idToken = session.get("id_token");
|
|
1845
|
+
clearSession(session);
|
|
1846
|
+
return redirect2(
|
|
1847
|
+
`${customerAccountUrl}/auth/logout?id_token_hint=${idToken}`,
|
|
1848
|
+
{
|
|
1849
|
+
status: 302,
|
|
1850
|
+
headers: {
|
|
1851
|
+
"Set-Cookie": await session.commit()
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
);
|
|
1855
|
+
},
|
|
1856
|
+
isLoggedIn: async () => {
|
|
1857
|
+
const expiresAt = session.get("expires_at");
|
|
1858
|
+
if (!session.get("customer_access_token") || !expiresAt)
|
|
1859
|
+
return false;
|
|
1860
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
1861
|
+
try {
|
|
1862
|
+
await checkExpires({
|
|
1863
|
+
locks,
|
|
1864
|
+
expiresAt,
|
|
1865
|
+
session,
|
|
1866
|
+
customerAccountId,
|
|
1867
|
+
customerAccountUrl,
|
|
1868
|
+
origin
|
|
1869
|
+
});
|
|
1870
|
+
logSubRequestEvent?.(" check expires", startTime);
|
|
1871
|
+
} catch {
|
|
1872
|
+
return false;
|
|
1873
|
+
}
|
|
1874
|
+
return true;
|
|
1875
|
+
},
|
|
1876
|
+
mutate(mutation, options) {
|
|
1877
|
+
mutation = minifyQuery(mutation);
|
|
1878
|
+
assertMutation(mutation, "customer.mutate");
|
|
1879
|
+
return fetchCustomerAPI({ query: mutation, type: "mutation", ...options });
|
|
1880
|
+
},
|
|
1881
|
+
query(query, options) {
|
|
1882
|
+
query = minifyQuery(query);
|
|
1883
|
+
assertQuery(query, "customer.query");
|
|
1884
|
+
return fetchCustomerAPI({ query, type: "query", ...options });
|
|
1885
|
+
},
|
|
1886
|
+
authorize: async (redirectPath = "/") => {
|
|
1887
|
+
const code = url.searchParams.get("code");
|
|
1888
|
+
const state = url.searchParams.get("state");
|
|
1889
|
+
if (!code || !state) {
|
|
1890
|
+
clearSession(session);
|
|
1891
|
+
throw new BadRequest(
|
|
1892
|
+
"Unauthorized",
|
|
1893
|
+
"No code or state parameter found in the redirect URL."
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
if (session.get("state") !== state) {
|
|
1897
|
+
clearSession(session);
|
|
1898
|
+
throw new BadRequest(
|
|
1899
|
+
"Unauthorized",
|
|
1900
|
+
"The session state does not match the state parameter. Make sure that the session is configured correctly and passed to `createCustomerClient`."
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1903
|
+
const clientId = customerAccountId;
|
|
1904
|
+
const body = new URLSearchParams();
|
|
1905
|
+
body.append("grant_type", "authorization_code");
|
|
1906
|
+
body.append("client_id", clientId);
|
|
1907
|
+
body.append("redirect_uri", origin + "/authorize");
|
|
1908
|
+
body.append("code", code);
|
|
1909
|
+
const codeVerifier = session.get("code-verifier");
|
|
1910
|
+
if (!codeVerifier)
|
|
1911
|
+
throw new BadRequest(
|
|
1912
|
+
"Unauthorized",
|
|
1913
|
+
"No code verifier found in the session. Make sure that the session is configured correctly and passed to `createCustomerClient`."
|
|
1914
|
+
);
|
|
1915
|
+
body.append("code_verifier", codeVerifier);
|
|
1916
|
+
const headers = {
|
|
1917
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1918
|
+
"User-Agent": USER_AGENT,
|
|
1919
|
+
Origin: origin
|
|
1920
|
+
};
|
|
1921
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
1922
|
+
method: "POST",
|
|
1923
|
+
headers,
|
|
1924
|
+
body
|
|
1925
|
+
});
|
|
1926
|
+
if (!response.ok) {
|
|
1927
|
+
throw new Response(await response.text(), {
|
|
1928
|
+
status: response.status,
|
|
1929
|
+
headers: {
|
|
1930
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1931
|
+
}
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
const { access_token, expires_in, id_token, refresh_token } = await response.json();
|
|
1935
|
+
const sessionNonce = session.get("nonce");
|
|
1936
|
+
const responseNonce = await getNonce(id_token);
|
|
1937
|
+
if (sessionNonce !== responseNonce) {
|
|
1938
|
+
throw new BadRequest(
|
|
1939
|
+
"Unauthorized",
|
|
1940
|
+
`Returned nonce does not match: ${sessionNonce} !== ${responseNonce}`
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
session.set("customer_authorization_code_token", access_token);
|
|
1944
|
+
session.set(
|
|
1945
|
+
"expires_at",
|
|
1946
|
+
new Date((/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3).getTime() + ""
|
|
1947
|
+
);
|
|
1948
|
+
session.set("id_token", id_token);
|
|
1949
|
+
session.set("refresh_token", refresh_token);
|
|
1950
|
+
const customerAccessToken = await exchangeAccessToken(
|
|
1951
|
+
session,
|
|
1952
|
+
customerAccountId,
|
|
1953
|
+
customerAccountUrl,
|
|
1954
|
+
origin
|
|
1955
|
+
);
|
|
1956
|
+
session.set("customer_access_token", customerAccessToken);
|
|
1957
|
+
return redirect2(redirectPath, {
|
|
1958
|
+
headers: {
|
|
1959
|
+
"Set-Cookie": await session.commit()
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1472
1965
|
var INPUT_NAME = "cartFormInput";
|
|
1473
1966
|
function CartForm({
|
|
1474
1967
|
children,
|
|
@@ -2162,10 +2655,10 @@ function createCartHandler(options) {
|
|
|
2162
2655
|
},
|
|
2163
2656
|
deleteMetafield: cartMetafieldDeleteDefault(mutateOptions)
|
|
2164
2657
|
};
|
|
2165
|
-
if ("
|
|
2658
|
+
if ("customMethods" in options) {
|
|
2166
2659
|
return {
|
|
2167
2660
|
...methods,
|
|
2168
|
-
...options.
|
|
2661
|
+
...options.customMethods ?? {}
|
|
2169
2662
|
};
|
|
2170
2663
|
} else {
|
|
2171
2664
|
return methods;
|
|
@@ -2262,25 +2755,6 @@ function useVariantPath(handle, productPath) {
|
|
|
2262
2755
|
};
|
|
2263
2756
|
}, [pathname, search, handle, productPath]);
|
|
2264
2757
|
}
|
|
2265
|
-
|
|
2266
|
-
// src/csp/nonce.ts
|
|
2267
|
-
function generateNonce() {
|
|
2268
|
-
return toHexString(randomUint8Array());
|
|
2269
|
-
}
|
|
2270
|
-
function randomUint8Array() {
|
|
2271
|
-
try {
|
|
2272
|
-
return crypto.getRandomValues(new Uint8Array(16));
|
|
2273
|
-
} catch (e) {
|
|
2274
|
-
return new Uint8Array(16).map(() => Math.random() * 255 | 0);
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
function toHexString(byteArray) {
|
|
2278
|
-
return Array.from(byteArray, function(byte) {
|
|
2279
|
-
return ("0" + (byte & 255).toString(16)).slice(-2);
|
|
2280
|
-
}).join("");
|
|
2281
|
-
}
|
|
2282
|
-
|
|
2283
|
-
// src/csp/csp.ts
|
|
2284
2758
|
var NonceContext = createContext(void 0);
|
|
2285
2759
|
var NonceProvider = NonceContext.Provider;
|
|
2286
2760
|
var useNonce = () => useContext(NonceContext);
|
|
@@ -2333,9 +2807,8 @@ var Script = forwardRef(
|
|
|
2333
2807
|
function useOptimisticData(identifier) {
|
|
2334
2808
|
const fetchers = useFetchers();
|
|
2335
2809
|
const data = {};
|
|
2336
|
-
for (const
|
|
2337
|
-
|
|
2338
|
-
if (formData && formData.get("optimistic-identifier") === identifier) {
|
|
2810
|
+
for (const { formData } of fetchers) {
|
|
2811
|
+
if (formData?.get("optimistic-identifier") === identifier) {
|
|
2339
2812
|
try {
|
|
2340
2813
|
if (formData.has("optimistic-data")) {
|
|
2341
2814
|
const dataInForm = JSON.parse(
|
|
@@ -2372,8 +2845,8 @@ function OptimisticInput({ id, data }) {
|
|
|
2372
2845
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartNoteUpdate
|
|
2373
2846
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartSelectedDeliveryOptionsUpdate
|
|
2374
2847
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartMetafieldsSet
|
|
2375
|
-
//! @see https://shopify.dev/docs/api/storefront/2023-
|
|
2848
|
+
//! @see https://shopify.dev/docs/api/storefront/2023-10/mutations/cartMetafieldDelete
|
|
2376
2849
|
|
|
2377
|
-
export { CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, OptimisticInput, Pagination, Script, Seo, StorefrontApiError, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, createCartHandler, createContentSecurityPolicy, createStorefrontClient, createWithCache, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, graphiqlLoader, isStorefrontApiError, storefrontRedirect, useNonce, useOptimisticData };
|
|
2850
|
+
export { CacheCustom, CacheLong, CacheNone, CacheShort, CartForm, InMemoryCache, OptimisticInput, Pagination, Script, Seo, StorefrontApiError, VariantSelector, cartAttributesUpdateDefault, cartBuyerIdentityUpdateDefault, cartCreateDefault, cartDiscountCodesUpdateDefault, cartGetDefault, cartGetIdDefault, cartLinesAddDefault, cartLinesRemoveDefault, cartLinesUpdateDefault, cartMetafieldDeleteDefault, cartMetafieldsSetDefault, cartNoteUpdateDefault, cartSelectedDeliveryOptionsUpdateDefault, cartSetIdDefault, createCartHandler, createContentSecurityPolicy, createCustomerClient as createCustomerClient__unstable, createStorefrontClient, createWithCache, generateCacheControlHeader, getPaginationVariables, getSelectedProductOptions, graphiqlLoader, isStorefrontApiError, storefrontRedirect, useNonce, useOptimisticData };
|
|
2378
2851
|
//# sourceMappingURL=out.js.map
|
|
2379
2852
|
//# sourceMappingURL=index.js.map
|