@shopify/hydrogen 2023.7.13 → 2023.10.0
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 +636 -163
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +636 -164
- 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
|
@@ -109,13 +109,9 @@ function hashKey(queryKey) {
|
|
|
109
109
|
for (const key of rawKeys) {
|
|
110
110
|
if (key != null) {
|
|
111
111
|
if (typeof key === "object") {
|
|
112
|
-
|
|
113
|
-
hash += key.body;
|
|
114
|
-
} else {
|
|
115
|
-
hash += JSON.stringify(key);
|
|
116
|
-
}
|
|
112
|
+
hash += JSON.stringify(key);
|
|
117
113
|
} else {
|
|
118
|
-
hash += key;
|
|
114
|
+
hash += key.toString();
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
117
|
}
|
|
@@ -175,6 +171,16 @@ function CacheLong(overrideOptions) {
|
|
|
175
171
|
...overrideOptions
|
|
176
172
|
};
|
|
177
173
|
}
|
|
174
|
+
function CacheDefault(overrideOptions) {
|
|
175
|
+
guardExpirableModeType(overrideOptions);
|
|
176
|
+
return {
|
|
177
|
+
mode: PUBLIC,
|
|
178
|
+
maxAge: 1,
|
|
179
|
+
staleWhileRevalidate: 86399,
|
|
180
|
+
// 1 second less than 24 hours
|
|
181
|
+
...overrideOptions
|
|
182
|
+
};
|
|
183
|
+
}
|
|
178
184
|
function CacheCustom(overrideOptions) {
|
|
179
185
|
return overrideOptions;
|
|
180
186
|
}
|
|
@@ -196,7 +202,7 @@ function getCacheControlSetting(userCacheOptions, options) {
|
|
|
196
202
|
...options
|
|
197
203
|
};
|
|
198
204
|
} else {
|
|
199
|
-
return userCacheOptions ||
|
|
205
|
+
return userCacheOptions || CacheDefault();
|
|
200
206
|
}
|
|
201
207
|
}
|
|
202
208
|
function generateDefaultCacheControlHeader(userCacheOptions) {
|
|
@@ -267,7 +273,7 @@ function getKeyUrl(key) {
|
|
|
267
273
|
return `https://shopify.dev/?${key}`;
|
|
268
274
|
}
|
|
269
275
|
function getCacheOption(userCacheOptions) {
|
|
270
|
-
return userCacheOptions ||
|
|
276
|
+
return userCacheOptions || CacheDefault();
|
|
271
277
|
}
|
|
272
278
|
async function getItemFromCache(cache, key) {
|
|
273
279
|
if (!cache)
|
|
@@ -451,26 +457,63 @@ var warnOnce = (string) => {
|
|
|
451
457
|
};
|
|
452
458
|
|
|
453
459
|
// src/version.ts
|
|
454
|
-
var LIB_VERSION = "2023.
|
|
460
|
+
var LIB_VERSION = "2023.10.0";
|
|
461
|
+
|
|
462
|
+
// src/utils/graphql.ts
|
|
463
|
+
function minifyQuery(string) {
|
|
464
|
+
return string.replace(/\s*#.*$/gm, "").replace(/\s+/gm, " ").trim();
|
|
465
|
+
}
|
|
466
|
+
var IS_QUERY_RE = /(^|}\s)query[\s({]/im;
|
|
467
|
+
var IS_MUTATION_RE = /(^|}\s)mutation[\s({]/im;
|
|
468
|
+
function assertQuery(query, callerName) {
|
|
469
|
+
if (!IS_QUERY_RE.test(query)) {
|
|
470
|
+
throw new Error(`[h2:error:${callerName}] Can only execute queries`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
function assertMutation(query, callerName) {
|
|
474
|
+
if (!IS_MUTATION_RE.test(query)) {
|
|
475
|
+
throw new Error(`[h2:error:${callerName}] Can only execute mutations`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function throwGraphQLError({
|
|
479
|
+
response,
|
|
480
|
+
errors,
|
|
481
|
+
type,
|
|
482
|
+
query,
|
|
483
|
+
queryVariables,
|
|
484
|
+
ErrorConstructor = Error,
|
|
485
|
+
client = "storefront"
|
|
486
|
+
}) {
|
|
487
|
+
const requestId = response.headers.get("x-request-id");
|
|
488
|
+
const errorMessage = (typeof errors === "string" ? errors : errors?.map?.((error) => error.message).join("\n")) || `API response error: ${response.status}`;
|
|
489
|
+
throw new ErrorConstructor(
|
|
490
|
+
`[h2:error:${client}.${type}] ` + errorMessage + (requestId ? ` - Request ID: ${requestId}` : ""),
|
|
491
|
+
{
|
|
492
|
+
cause: JSON.stringify({
|
|
493
|
+
errors,
|
|
494
|
+
requestId,
|
|
495
|
+
...{
|
|
496
|
+
graphql: {
|
|
497
|
+
query,
|
|
498
|
+
variables: JSON.stringify(queryVariables)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
})
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
}
|
|
455
505
|
|
|
456
506
|
// src/storefront.ts
|
|
457
507
|
var StorefrontApiError = class extends Error {
|
|
458
508
|
};
|
|
459
509
|
var isStorefrontApiError = (error) => error instanceof StorefrontApiError;
|
|
460
|
-
var isQueryRE = /(^|}\s)query[\s({]/im;
|
|
461
|
-
var isMutationRE = /(^|}\s)mutation[\s({]/im;
|
|
462
|
-
function minifyQuery(string) {
|
|
463
|
-
return string.replace(/\s*#.*$/gm, "").replace(/\s+/gm, " ").trim();
|
|
464
|
-
}
|
|
465
510
|
var defaultI18n = { language: "EN", country: "US" };
|
|
466
511
|
function createStorefrontClient(options) {
|
|
467
512
|
const {
|
|
468
513
|
storefrontHeaders,
|
|
469
514
|
cache,
|
|
470
515
|
waitUntil,
|
|
471
|
-
buyerIp,
|
|
472
516
|
i18n,
|
|
473
|
-
requestGroupId,
|
|
474
517
|
storefrontId,
|
|
475
518
|
...clientOptions
|
|
476
519
|
} = options;
|
|
@@ -489,9 +532,9 @@ function createStorefrontClient(options) {
|
|
|
489
532
|
const getHeaders = clientOptions.privateStorefrontToken ? getPrivateTokenHeaders : getPublicTokenHeaders;
|
|
490
533
|
const defaultHeaders = getHeaders({
|
|
491
534
|
contentType: "json",
|
|
492
|
-
buyerIp: storefrontHeaders?.buyerIp ||
|
|
535
|
+
buyerIp: storefrontHeaders?.buyerIp || ""
|
|
493
536
|
});
|
|
494
|
-
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId ||
|
|
537
|
+
defaultHeaders[STOREFRONT_REQUEST_GROUP_ID_HEADER] = storefrontHeaders?.requestGroupId || generateUUID();
|
|
495
538
|
if (storefrontId)
|
|
496
539
|
defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
|
|
497
540
|
defaultHeaders["user-agent"] = `Hydrogen ${LIB_VERSION}`;
|
|
@@ -502,11 +545,14 @@ function createStorefrontClient(options) {
|
|
|
502
545
|
if (cookies[hydrogenReact.SHOPIFY_S])
|
|
503
546
|
defaultHeaders[hydrogenReact.SHOPIFY_STOREFRONT_S_HEADER] = cookies[hydrogenReact.SHOPIFY_S];
|
|
504
547
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
548
|
+
const cacheKeyHeader = JSON.stringify({
|
|
549
|
+
"content-type": defaultHeaders["content-type"],
|
|
550
|
+
"user-agent": defaultHeaders["user-agent"],
|
|
551
|
+
[SDK_VARIANT_HEADER]: defaultHeaders[SDK_VARIANT_HEADER],
|
|
552
|
+
[SDK_VARIANT_SOURCE_HEADER]: defaultHeaders[SDK_VARIANT_SOURCE_HEADER],
|
|
553
|
+
[SDK_VERSION_HEADER]: defaultHeaders[SDK_VERSION_HEADER],
|
|
554
|
+
[STOREFRONT_ACCESS_TOKEN_HEADER]: defaultHeaders[STOREFRONT_ACCESS_TOKEN_HEADER]
|
|
555
|
+
});
|
|
510
556
|
async function fetchStorefrontApi({
|
|
511
557
|
query,
|
|
512
558
|
mutation,
|
|
@@ -535,22 +581,13 @@ function createStorefrontClient(options) {
|
|
|
535
581
|
};
|
|
536
582
|
const cacheKey = [
|
|
537
583
|
url,
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
"content-type": defaultHeaders["content-type"],
|
|
542
|
-
"user-agent": defaultHeaders["user-agent"],
|
|
543
|
-
[SDK_VARIANT_HEADER]: defaultHeaders[SDK_VARIANT_HEADER],
|
|
544
|
-
[SDK_VARIANT_SOURCE_HEADER]: defaultHeaders[SDK_VARIANT_SOURCE_HEADER],
|
|
545
|
-
[SDK_VERSION_HEADER]: defaultHeaders[SDK_VERSION_HEADER],
|
|
546
|
-
[STOREFRONT_ACCESS_TOKEN_HEADER]: defaultHeaders[STOREFRONT_ACCESS_TOKEN_HEADER]
|
|
547
|
-
},
|
|
548
|
-
body: requestInit.body
|
|
549
|
-
}
|
|
584
|
+
requestInit.method,
|
|
585
|
+
cacheKeyHeader,
|
|
586
|
+
requestInit.body
|
|
550
587
|
];
|
|
551
588
|
const [body, response] = await fetchWithServerCache(url, requestInit, {
|
|
552
589
|
cacheInstance: mutation ? void 0 : cache,
|
|
553
|
-
cache: cacheOptions ||
|
|
590
|
+
cache: cacheOptions || CacheDefault(),
|
|
554
591
|
cacheKey,
|
|
555
592
|
shouldCacheResponse: checkGraphQLErrors,
|
|
556
593
|
waitUntil,
|
|
@@ -574,11 +611,11 @@ function createStorefrontClient(options) {
|
|
|
574
611
|
} catch (_e) {
|
|
575
612
|
errors2 = [{ message: body }];
|
|
576
613
|
}
|
|
577
|
-
|
|
614
|
+
throwGraphQLError({ ...errorOptions, errors: errors2 });
|
|
578
615
|
}
|
|
579
616
|
const { data, errors } = body;
|
|
580
617
|
if (errors?.length) {
|
|
581
|
-
|
|
618
|
+
throwGraphQLError({
|
|
582
619
|
...errorOptions,
|
|
583
620
|
errors,
|
|
584
621
|
ErrorConstructor: StorefrontApiError
|
|
@@ -604,11 +641,7 @@ function createStorefrontClient(options) {
|
|
|
604
641
|
*/
|
|
605
642
|
query: (query, payload) => {
|
|
606
643
|
query = minifyQuery(query);
|
|
607
|
-
|
|
608
|
-
throw new Error(
|
|
609
|
-
"[h2:error:storefront.query] Cannot execute mutations"
|
|
610
|
-
);
|
|
611
|
-
}
|
|
644
|
+
assertQuery(query, "storefront.query");
|
|
612
645
|
const result = fetchStorefrontApi({
|
|
613
646
|
...payload,
|
|
614
647
|
query
|
|
@@ -632,11 +665,7 @@ function createStorefrontClient(options) {
|
|
|
632
665
|
*/
|
|
633
666
|
mutate: (mutation, payload) => {
|
|
634
667
|
mutation = minifyQuery(mutation);
|
|
635
|
-
|
|
636
|
-
throw new Error(
|
|
637
|
-
"[h2:error:storefront.mutate] Cannot execute queries"
|
|
638
|
-
);
|
|
639
|
-
}
|
|
668
|
+
assertMutation(mutation, "storefront.mutate");
|
|
640
669
|
const result = fetchStorefrontApi({
|
|
641
670
|
...payload,
|
|
642
671
|
mutation
|
|
@@ -679,32 +708,6 @@ function createStorefrontClient(options) {
|
|
|
679
708
|
}
|
|
680
709
|
};
|
|
681
710
|
}
|
|
682
|
-
function throwError({
|
|
683
|
-
response,
|
|
684
|
-
errors,
|
|
685
|
-
type,
|
|
686
|
-
query,
|
|
687
|
-
queryVariables,
|
|
688
|
-
ErrorConstructor = Error
|
|
689
|
-
}) {
|
|
690
|
-
const requestId = response.headers.get("x-request-id");
|
|
691
|
-
const errorMessage = (typeof errors === "string" ? errors : errors?.map?.((error) => error.message).join("\n")) || `API response error: ${response.status}`;
|
|
692
|
-
throw new ErrorConstructor(
|
|
693
|
-
`[h2:error:storefront.${type}] ` + errorMessage + (requestId ? ` - Request ID: ${requestId}` : ""),
|
|
694
|
-
{
|
|
695
|
-
cause: JSON.stringify({
|
|
696
|
-
errors,
|
|
697
|
-
requestId,
|
|
698
|
-
...{
|
|
699
|
-
graphql: {
|
|
700
|
-
query,
|
|
701
|
-
variables: JSON.stringify(queryVariables)
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
})
|
|
705
|
-
}
|
|
706
|
-
);
|
|
707
|
-
}
|
|
708
711
|
|
|
709
712
|
// src/utils/request.ts
|
|
710
713
|
function getHeader(request, key) {
|
|
@@ -884,76 +887,115 @@ var graphiqlLoader = async function graphiqlLoader2({
|
|
|
884
887
|
const url = storefront.getApiUrl();
|
|
885
888
|
const accessToken = storefront.getPublicTokenHeaders()["X-Shopify-Storefront-Access-Token"];
|
|
886
889
|
const favicon = `https://avatars.githubusercontent.com/u/12972006?s=48&v=4`;
|
|
890
|
+
const html = String.raw;
|
|
887
891
|
return new Response(
|
|
888
|
-
`
|
|
889
|
-
<!DOCTYPE html>
|
|
890
|
-
<html lang="en">
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
892
|
+
html`
|
|
893
|
+
<!DOCTYPE html>
|
|
894
|
+
<html lang="en">
|
|
895
|
+
<head>
|
|
896
|
+
<title>GraphiQL</title>
|
|
897
|
+
<link rel="icon" type="image/x-icon" href="${favicon}" />
|
|
898
|
+
<style>
|
|
899
|
+
body {
|
|
900
|
+
height: 100%;
|
|
901
|
+
margin: 0;
|
|
902
|
+
width: 100%;
|
|
903
|
+
overflow: hidden;
|
|
904
|
+
background-color: hsl(219, 29%, 18%);
|
|
905
|
+
}
|
|
901
906
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
</style>
|
|
907
|
+
#graphiql {
|
|
908
|
+
height: 100vh;
|
|
909
|
+
}
|
|
906
910
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
></script>
|
|
915
|
-
<link rel="stylesheet" href="https://unpkg.com/graphiql@3/graphiql.min.css" />
|
|
916
|
-
</head>
|
|
911
|
+
#graphiql > .placeholder {
|
|
912
|
+
color: slategray;
|
|
913
|
+
width: fit-content;
|
|
914
|
+
margin: 40px auto;
|
|
915
|
+
font-family: Arial;
|
|
916
|
+
}
|
|
917
|
+
</style>
|
|
917
918
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
919
|
+
<script
|
|
920
|
+
crossorigin
|
|
921
|
+
src="https://unpkg.com/react@18/umd/react.development.js"
|
|
922
|
+
></script>
|
|
923
|
+
<script
|
|
924
|
+
crossorigin
|
|
925
|
+
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
|
|
926
|
+
></script>
|
|
927
|
+
<link
|
|
928
|
+
rel="stylesheet"
|
|
929
|
+
href="https://unpkg.com/graphiql@3/graphiql.min.css"
|
|
930
|
+
/>
|
|
931
|
+
<link
|
|
932
|
+
rel="stylesheet"
|
|
933
|
+
href="https://unpkg.com/@graphiql/plugin-explorer/dist/style.css"
|
|
934
|
+
/>
|
|
935
|
+
</head>
|
|
926
936
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
if (query) query = GraphiQL.GraphQL.print(GraphiQL.GraphQL.parse(query));
|
|
932
|
-
}
|
|
937
|
+
<body>
|
|
938
|
+
<div id="graphiql">
|
|
939
|
+
<div class="placeholder">Loading GraphiQL...</div>
|
|
940
|
+
</div>
|
|
933
941
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
942
|
+
<script
|
|
943
|
+
src="https://unpkg.com/graphiql@3/graphiql.min.js"
|
|
944
|
+
type="application/javascript"
|
|
945
|
+
crossorigin="anonymous"
|
|
946
|
+
></script>
|
|
947
|
+
<script
|
|
948
|
+
src="https://unpkg.com/@graphiql/plugin-explorer/dist/index.umd.js"
|
|
949
|
+
type="application/javascript"
|
|
950
|
+
crossorigin="anonymous"
|
|
951
|
+
></script>
|
|
940
952
|
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
953
|
+
<script>
|
|
954
|
+
const windowUrl = new URL(document.URL);
|
|
955
|
+
|
|
956
|
+
let query = '{ shop { name } }';
|
|
957
|
+
if (windowUrl.searchParams.has('query')) {
|
|
958
|
+
query = decodeURIComponent(
|
|
959
|
+
windowUrl.searchParams.get('query') ?? query,
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Prettify query
|
|
964
|
+
query = GraphiQL.GraphQL.print(GraphiQL.GraphQL.parse(query));
|
|
965
|
+
|
|
966
|
+
let variables;
|
|
967
|
+
if (windowUrl.searchParams.has('variables')) {
|
|
968
|
+
variables = decodeURIComponent(
|
|
969
|
+
windowUrl.searchParams.get('variables') ?? '',
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// Prettify variables
|
|
974
|
+
if (variables) {
|
|
975
|
+
variables = JSON.stringify(JSON.parse(variables), null, 2);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
const root = ReactDOM.createRoot(
|
|
979
|
+
document.getElementById('graphiql'),
|
|
980
|
+
);
|
|
981
|
+
root.render(
|
|
982
|
+
React.createElement(GraphiQL, {
|
|
983
|
+
fetcher: GraphiQL.createFetcher({
|
|
984
|
+
url: '${url}',
|
|
985
|
+
headers: {
|
|
986
|
+
'X-Shopify-Storefront-Access-Token': '${accessToken}',
|
|
987
|
+
},
|
|
988
|
+
}),
|
|
989
|
+
defaultEditorToolsVisibility: true,
|
|
990
|
+
query,
|
|
991
|
+
variables,
|
|
992
|
+
plugins: [GraphiQLPluginExplorer.explorerPlugin()],
|
|
993
|
+
}),
|
|
994
|
+
);
|
|
995
|
+
</script>
|
|
996
|
+
</body>
|
|
997
|
+
</html>
|
|
998
|
+
`,
|
|
957
999
|
{ status: 200, headers: { "content-type": "text/html" } }
|
|
958
1000
|
);
|
|
959
1001
|
};
|
|
@@ -1297,7 +1339,7 @@ function Seo({ debug }) {
|
|
|
1297
1339
|
return [];
|
|
1298
1340
|
}
|
|
1299
1341
|
if (handleSeo) {
|
|
1300
|
-
return recursivelyInvokeOrReturn(
|
|
1342
|
+
return recursivelyInvokeOrReturn(handleSeo, routeData);
|
|
1301
1343
|
} else {
|
|
1302
1344
|
return [loaderSeo];
|
|
1303
1345
|
}
|
|
@@ -1563,6 +1605,456 @@ function getPaginationVariables(request, options = { pageBy: 20 }) {
|
|
|
1563
1605
|
const variables = isPrevious ? prevPage : nextPage;
|
|
1564
1606
|
return variables;
|
|
1565
1607
|
}
|
|
1608
|
+
|
|
1609
|
+
// src/customer/BadRequest.ts
|
|
1610
|
+
var BadRequest = class extends Response {
|
|
1611
|
+
constructor(message, helpMessage) {
|
|
1612
|
+
if (helpMessage && true) {
|
|
1613
|
+
console.error("Customer Account API Error: " + helpMessage);
|
|
1614
|
+
}
|
|
1615
|
+
super(`Bad request: ${message}`, { status: 400 });
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
// src/customer/auth.helpers.ts
|
|
1620
|
+
var USER_AGENT = `Shopify Hydrogen ${LIB_VERSION}`;
|
|
1621
|
+
var CUSTOMER_API_CLIENT_ID = "30243aa5-17c1-465a-8493-944bcc4e88aa";
|
|
1622
|
+
function redirect2(path, options = {}) {
|
|
1623
|
+
const headers = options.headers ? new Headers(options.headers) : new Headers({});
|
|
1624
|
+
headers.set("location", path);
|
|
1625
|
+
return new Response(null, { status: options.status || 302, headers });
|
|
1626
|
+
}
|
|
1627
|
+
async function refreshToken({
|
|
1628
|
+
session,
|
|
1629
|
+
customerAccountId,
|
|
1630
|
+
customerAccountUrl,
|
|
1631
|
+
origin
|
|
1632
|
+
}) {
|
|
1633
|
+
const newBody = new URLSearchParams();
|
|
1634
|
+
const refreshToken2 = session.get("refresh_token");
|
|
1635
|
+
if (!refreshToken2)
|
|
1636
|
+
throw new BadRequest(
|
|
1637
|
+
"Unauthorized",
|
|
1638
|
+
"No refresh_token in the session. Make sure your session is configured correctly and passed to `createCustomerClient`."
|
|
1639
|
+
);
|
|
1640
|
+
newBody.append("grant_type", "refresh_token");
|
|
1641
|
+
newBody.append("refresh_token", refreshToken2);
|
|
1642
|
+
newBody.append("client_id", customerAccountId);
|
|
1643
|
+
const headers = {
|
|
1644
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1645
|
+
"User-Agent": USER_AGENT,
|
|
1646
|
+
Origin: origin
|
|
1647
|
+
};
|
|
1648
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
1649
|
+
method: "POST",
|
|
1650
|
+
headers,
|
|
1651
|
+
body: newBody
|
|
1652
|
+
});
|
|
1653
|
+
if (!response.ok) {
|
|
1654
|
+
const text = await response.text();
|
|
1655
|
+
throw new Response(text, {
|
|
1656
|
+
status: response.status,
|
|
1657
|
+
headers: {
|
|
1658
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
const { access_token, expires_in, id_token, refresh_token } = await response.json();
|
|
1663
|
+
session.set("customer_authorization_code_token", access_token);
|
|
1664
|
+
session.set(
|
|
1665
|
+
"expires_at",
|
|
1666
|
+
new Date((/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3).getTime() + ""
|
|
1667
|
+
);
|
|
1668
|
+
session.set("id_token", id_token);
|
|
1669
|
+
session.set("refresh_token", refresh_token);
|
|
1670
|
+
const customerAccessToken = await exchangeAccessToken(
|
|
1671
|
+
session,
|
|
1672
|
+
customerAccountId,
|
|
1673
|
+
customerAccountUrl,
|
|
1674
|
+
origin
|
|
1675
|
+
);
|
|
1676
|
+
session.set("customer_access_token", customerAccessToken);
|
|
1677
|
+
}
|
|
1678
|
+
function clearSession(session) {
|
|
1679
|
+
session.unset("code-verifier");
|
|
1680
|
+
session.unset("customer_authorization_code_token");
|
|
1681
|
+
session.unset("expires_at");
|
|
1682
|
+
session.unset("id_token");
|
|
1683
|
+
session.unset("refresh_token");
|
|
1684
|
+
session.unset("customer_access_token");
|
|
1685
|
+
session.unset("state");
|
|
1686
|
+
session.unset("nonce");
|
|
1687
|
+
}
|
|
1688
|
+
async function checkExpires({
|
|
1689
|
+
locks,
|
|
1690
|
+
expiresAt,
|
|
1691
|
+
session,
|
|
1692
|
+
customerAccountId,
|
|
1693
|
+
customerAccountUrl,
|
|
1694
|
+
origin
|
|
1695
|
+
}) {
|
|
1696
|
+
if (parseInt(expiresAt, 10) - 1e3 < (/* @__PURE__ */ new Date()).getTime()) {
|
|
1697
|
+
try {
|
|
1698
|
+
if (!locks.refresh)
|
|
1699
|
+
locks.refresh = refreshToken({
|
|
1700
|
+
session,
|
|
1701
|
+
customerAccountId,
|
|
1702
|
+
customerAccountUrl,
|
|
1703
|
+
origin
|
|
1704
|
+
});
|
|
1705
|
+
await locks.refresh;
|
|
1706
|
+
delete locks.refresh;
|
|
1707
|
+
} catch (error) {
|
|
1708
|
+
clearSession(session);
|
|
1709
|
+
if (error && error.status !== 401) {
|
|
1710
|
+
throw error;
|
|
1711
|
+
} else {
|
|
1712
|
+
throw new BadRequest(
|
|
1713
|
+
"Unauthorized",
|
|
1714
|
+
"Login before querying the Customer Account API."
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
async function generateCodeVerifier() {
|
|
1721
|
+
const rando = generateRandomCode();
|
|
1722
|
+
return base64UrlEncode(rando);
|
|
1723
|
+
}
|
|
1724
|
+
async function generateCodeChallenge(codeVerifier) {
|
|
1725
|
+
const digestOp = await crypto.subtle.digest(
|
|
1726
|
+
{ name: "SHA-256" },
|
|
1727
|
+
new TextEncoder().encode(codeVerifier)
|
|
1728
|
+
);
|
|
1729
|
+
const hash = convertBufferToString(digestOp);
|
|
1730
|
+
return base64UrlEncode(hash);
|
|
1731
|
+
}
|
|
1732
|
+
function generateRandomCode() {
|
|
1733
|
+
const array = new Uint8Array(32);
|
|
1734
|
+
crypto.getRandomValues(array);
|
|
1735
|
+
return String.fromCharCode.apply(null, Array.from(array));
|
|
1736
|
+
}
|
|
1737
|
+
function base64UrlEncode(str) {
|
|
1738
|
+
const base64 = btoa(str);
|
|
1739
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1740
|
+
}
|
|
1741
|
+
function convertBufferToString(hash) {
|
|
1742
|
+
const uintArray = new Uint8Array(hash);
|
|
1743
|
+
const numberArray = Array.from(uintArray);
|
|
1744
|
+
return String.fromCharCode(...numberArray);
|
|
1745
|
+
}
|
|
1746
|
+
async function generateState() {
|
|
1747
|
+
const timestamp = Date.now().toString();
|
|
1748
|
+
const randomString = Math.random().toString(36).substring(2);
|
|
1749
|
+
return timestamp + randomString;
|
|
1750
|
+
}
|
|
1751
|
+
async function exchangeAccessToken(session, customerAccountId, customerAccountUrl, origin) {
|
|
1752
|
+
const clientId = customerAccountId;
|
|
1753
|
+
const accessToken = session.get("customer_authorization_code_token");
|
|
1754
|
+
if (!accessToken)
|
|
1755
|
+
throw new BadRequest(
|
|
1756
|
+
"Unauthorized",
|
|
1757
|
+
"No access token found in the session. Make sure your session is configured correctly and passed to `createCustomerClient`."
|
|
1758
|
+
);
|
|
1759
|
+
const body = new URLSearchParams();
|
|
1760
|
+
body.append("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange");
|
|
1761
|
+
body.append("client_id", clientId);
|
|
1762
|
+
body.append("audience", CUSTOMER_API_CLIENT_ID);
|
|
1763
|
+
body.append("subject_token", accessToken);
|
|
1764
|
+
body.append(
|
|
1765
|
+
"subject_token_type",
|
|
1766
|
+
"urn:ietf:params:oauth:token-type:access_token"
|
|
1767
|
+
);
|
|
1768
|
+
body.append("scopes", "https://api.customers.com/auth/customer.graphql");
|
|
1769
|
+
const headers = {
|
|
1770
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
1771
|
+
"User-Agent": USER_AGENT,
|
|
1772
|
+
Origin: origin
|
|
1773
|
+
};
|
|
1774
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
1775
|
+
method: "POST",
|
|
1776
|
+
headers,
|
|
1777
|
+
body
|
|
1778
|
+
});
|
|
1779
|
+
const data = await response.json();
|
|
1780
|
+
if (data.error) {
|
|
1781
|
+
throw new BadRequest(data.error_description);
|
|
1782
|
+
}
|
|
1783
|
+
return data.access_token;
|
|
1784
|
+
}
|
|
1785
|
+
function getNonce(token) {
|
|
1786
|
+
return decodeJwt(token).payload.nonce;
|
|
1787
|
+
}
|
|
1788
|
+
function decodeJwt(token) {
|
|
1789
|
+
const [header, payload, signature] = token.split(".");
|
|
1790
|
+
const decodedHeader = JSON.parse(atob(header));
|
|
1791
|
+
const decodedPayload = JSON.parse(atob(payload));
|
|
1792
|
+
return {
|
|
1793
|
+
header: decodedHeader,
|
|
1794
|
+
payload: decodedPayload,
|
|
1795
|
+
signature
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
// src/csp/nonce.ts
|
|
1800
|
+
function generateNonce() {
|
|
1801
|
+
return toHexString(randomUint8Array());
|
|
1802
|
+
}
|
|
1803
|
+
function randomUint8Array() {
|
|
1804
|
+
try {
|
|
1805
|
+
return crypto.getRandomValues(new Uint8Array(16));
|
|
1806
|
+
} catch (e) {
|
|
1807
|
+
return new Uint8Array(16).map(() => Math.random() * 255 | 0);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
function toHexString(byteArray) {
|
|
1811
|
+
return Array.from(byteArray, function(byte) {
|
|
1812
|
+
return ("0" + (byte & 255).toString(16)).slice(-2);
|
|
1813
|
+
}).join("");
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// src/customer/customer.ts
|
|
1817
|
+
function createCustomerClient({
|
|
1818
|
+
session,
|
|
1819
|
+
customerAccountId,
|
|
1820
|
+
customerAccountUrl,
|
|
1821
|
+
customerApiVersion = "2023-10",
|
|
1822
|
+
request,
|
|
1823
|
+
waitUntil
|
|
1824
|
+
}) {
|
|
1825
|
+
if (!request?.url) {
|
|
1826
|
+
throw new Error(
|
|
1827
|
+
"[h2:error:createCustomerClient] The request object does not contain a URL."
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
const url = new URL(request.url);
|
|
1831
|
+
const origin = url.protocol === "http:" ? url.origin.replace("http", "https") : url.origin;
|
|
1832
|
+
const locks = {};
|
|
1833
|
+
const logSubRequestEvent = (query, startTime) => {
|
|
1834
|
+
globalThis.__H2O_LOG_EVENT?.({
|
|
1835
|
+
eventType: "subrequest",
|
|
1836
|
+
url: `https://shopify.dev/?${hashKey([
|
|
1837
|
+
`Customer Account `,
|
|
1838
|
+
/((query|mutation) [^\s\(]+)/g.exec(query)?.[0] || query.substring(0, 10)
|
|
1839
|
+
])}`,
|
|
1840
|
+
startTime,
|
|
1841
|
+
waitUntil,
|
|
1842
|
+
...getDebugHeaders(request)
|
|
1843
|
+
});
|
|
1844
|
+
} ;
|
|
1845
|
+
async function fetchCustomerAPI({
|
|
1846
|
+
query,
|
|
1847
|
+
type,
|
|
1848
|
+
variables = {}
|
|
1849
|
+
}) {
|
|
1850
|
+
const accessToken = session.get("customer_access_token");
|
|
1851
|
+
const expiresAt = session.get("expires_at");
|
|
1852
|
+
if (!accessToken || !expiresAt)
|
|
1853
|
+
throw new BadRequest(
|
|
1854
|
+
"Unauthorized",
|
|
1855
|
+
"Login before querying the Customer Account API."
|
|
1856
|
+
);
|
|
1857
|
+
await checkExpires({
|
|
1858
|
+
locks,
|
|
1859
|
+
expiresAt,
|
|
1860
|
+
session,
|
|
1861
|
+
customerAccountId,
|
|
1862
|
+
customerAccountUrl,
|
|
1863
|
+
origin
|
|
1864
|
+
});
|
|
1865
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
1866
|
+
const response = await fetch(
|
|
1867
|
+
`${customerAccountUrl}/account/customer/api/${customerApiVersion}/graphql`,
|
|
1868
|
+
{
|
|
1869
|
+
method: "POST",
|
|
1870
|
+
headers: {
|
|
1871
|
+
"Content-Type": "application/json",
|
|
1872
|
+
"User-Agent": USER_AGENT,
|
|
1873
|
+
Origin: origin,
|
|
1874
|
+
Authorization: accessToken
|
|
1875
|
+
},
|
|
1876
|
+
body: JSON.stringify({
|
|
1877
|
+
operationName: "SomeQuery",
|
|
1878
|
+
query,
|
|
1879
|
+
variables
|
|
1880
|
+
})
|
|
1881
|
+
}
|
|
1882
|
+
);
|
|
1883
|
+
logSubRequestEvent?.(query, startTime);
|
|
1884
|
+
const body = await response.text();
|
|
1885
|
+
const errorOptions = {
|
|
1886
|
+
response,
|
|
1887
|
+
type,
|
|
1888
|
+
query,
|
|
1889
|
+
queryVariables: variables,
|
|
1890
|
+
errors: void 0,
|
|
1891
|
+
client: "customer"
|
|
1892
|
+
};
|
|
1893
|
+
if (!response.ok) {
|
|
1894
|
+
let errors;
|
|
1895
|
+
try {
|
|
1896
|
+
errors = parseJSON(body);
|
|
1897
|
+
} catch (_e) {
|
|
1898
|
+
errors = [{ message: body }];
|
|
1899
|
+
}
|
|
1900
|
+
throwGraphQLError({ ...errorOptions, errors });
|
|
1901
|
+
}
|
|
1902
|
+
try {
|
|
1903
|
+
return parseJSON(body).data;
|
|
1904
|
+
} catch (e) {
|
|
1905
|
+
throwGraphQLError({ ...errorOptions, errors: [{ message: body }] });
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
return {
|
|
1909
|
+
login: async () => {
|
|
1910
|
+
const loginUrl = new URL(customerAccountUrl + "/auth/oauth/authorize");
|
|
1911
|
+
const state = await generateState();
|
|
1912
|
+
const nonce = await generateNonce();
|
|
1913
|
+
loginUrl.searchParams.set("client_id", customerAccountId);
|
|
1914
|
+
loginUrl.searchParams.set("scope", "openid email");
|
|
1915
|
+
loginUrl.searchParams.append("response_type", "code");
|
|
1916
|
+
loginUrl.searchParams.append("redirect_uri", origin + "/authorize");
|
|
1917
|
+
loginUrl.searchParams.set(
|
|
1918
|
+
"scope",
|
|
1919
|
+
"openid email https://api.customers.com/auth/customer.graphql"
|
|
1920
|
+
);
|
|
1921
|
+
loginUrl.searchParams.append("state", state);
|
|
1922
|
+
loginUrl.searchParams.append("nonce", nonce);
|
|
1923
|
+
const verifier = await generateCodeVerifier();
|
|
1924
|
+
const challenge = await generateCodeChallenge(verifier);
|
|
1925
|
+
session.set("code-verifier", verifier);
|
|
1926
|
+
session.set("state", state);
|
|
1927
|
+
session.set("nonce", nonce);
|
|
1928
|
+
loginUrl.searchParams.append("code_challenge", challenge);
|
|
1929
|
+
loginUrl.searchParams.append("code_challenge_method", "S256");
|
|
1930
|
+
return redirect2(loginUrl.toString(), {
|
|
1931
|
+
headers: {
|
|
1932
|
+
"Set-Cookie": await session.commit()
|
|
1933
|
+
}
|
|
1934
|
+
});
|
|
1935
|
+
},
|
|
1936
|
+
logout: async () => {
|
|
1937
|
+
const idToken = session.get("id_token");
|
|
1938
|
+
clearSession(session);
|
|
1939
|
+
return redirect2(
|
|
1940
|
+
`${customerAccountUrl}/auth/logout?id_token_hint=${idToken}`,
|
|
1941
|
+
{
|
|
1942
|
+
status: 302,
|
|
1943
|
+
headers: {
|
|
1944
|
+
"Set-Cookie": await session.commit()
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
);
|
|
1948
|
+
},
|
|
1949
|
+
isLoggedIn: async () => {
|
|
1950
|
+
const expiresAt = session.get("expires_at");
|
|
1951
|
+
if (!session.get("customer_access_token") || !expiresAt)
|
|
1952
|
+
return false;
|
|
1953
|
+
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
1954
|
+
try {
|
|
1955
|
+
await checkExpires({
|
|
1956
|
+
locks,
|
|
1957
|
+
expiresAt,
|
|
1958
|
+
session,
|
|
1959
|
+
customerAccountId,
|
|
1960
|
+
customerAccountUrl,
|
|
1961
|
+
origin
|
|
1962
|
+
});
|
|
1963
|
+
logSubRequestEvent?.(" check expires", startTime);
|
|
1964
|
+
} catch {
|
|
1965
|
+
return false;
|
|
1966
|
+
}
|
|
1967
|
+
return true;
|
|
1968
|
+
},
|
|
1969
|
+
mutate(mutation, options) {
|
|
1970
|
+
mutation = minifyQuery(mutation);
|
|
1971
|
+
assertMutation(mutation, "customer.mutate");
|
|
1972
|
+
return fetchCustomerAPI({ query: mutation, type: "mutation", ...options });
|
|
1973
|
+
},
|
|
1974
|
+
query(query, options) {
|
|
1975
|
+
query = minifyQuery(query);
|
|
1976
|
+
assertQuery(query, "customer.query");
|
|
1977
|
+
return fetchCustomerAPI({ query, type: "query", ...options });
|
|
1978
|
+
},
|
|
1979
|
+
authorize: async (redirectPath = "/") => {
|
|
1980
|
+
const code = url.searchParams.get("code");
|
|
1981
|
+
const state = url.searchParams.get("state");
|
|
1982
|
+
if (!code || !state) {
|
|
1983
|
+
clearSession(session);
|
|
1984
|
+
throw new BadRequest(
|
|
1985
|
+
"Unauthorized",
|
|
1986
|
+
"No code or state parameter found in the redirect URL."
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1989
|
+
if (session.get("state") !== state) {
|
|
1990
|
+
clearSession(session);
|
|
1991
|
+
throw new BadRequest(
|
|
1992
|
+
"Unauthorized",
|
|
1993
|
+
"The session state does not match the state parameter. Make sure that the session is configured correctly and passed to `createCustomerClient`."
|
|
1994
|
+
);
|
|
1995
|
+
}
|
|
1996
|
+
const clientId = customerAccountId;
|
|
1997
|
+
const body = new URLSearchParams();
|
|
1998
|
+
body.append("grant_type", "authorization_code");
|
|
1999
|
+
body.append("client_id", clientId);
|
|
2000
|
+
body.append("redirect_uri", origin + "/authorize");
|
|
2001
|
+
body.append("code", code);
|
|
2002
|
+
const codeVerifier = session.get("code-verifier");
|
|
2003
|
+
if (!codeVerifier)
|
|
2004
|
+
throw new BadRequest(
|
|
2005
|
+
"Unauthorized",
|
|
2006
|
+
"No code verifier found in the session. Make sure that the session is configured correctly and passed to `createCustomerClient`."
|
|
2007
|
+
);
|
|
2008
|
+
body.append("code_verifier", codeVerifier);
|
|
2009
|
+
const headers = {
|
|
2010
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
2011
|
+
"User-Agent": USER_AGENT,
|
|
2012
|
+
Origin: origin
|
|
2013
|
+
};
|
|
2014
|
+
const response = await fetch(`${customerAccountUrl}/auth/oauth/token`, {
|
|
2015
|
+
method: "POST",
|
|
2016
|
+
headers,
|
|
2017
|
+
body
|
|
2018
|
+
});
|
|
2019
|
+
if (!response.ok) {
|
|
2020
|
+
throw new Response(await response.text(), {
|
|
2021
|
+
status: response.status,
|
|
2022
|
+
headers: {
|
|
2023
|
+
"Content-Type": "text/html; charset=utf-8"
|
|
2024
|
+
}
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
const { access_token, expires_in, id_token, refresh_token } = await response.json();
|
|
2028
|
+
const sessionNonce = session.get("nonce");
|
|
2029
|
+
const responseNonce = await getNonce(id_token);
|
|
2030
|
+
if (sessionNonce !== responseNonce) {
|
|
2031
|
+
throw new BadRequest(
|
|
2032
|
+
"Unauthorized",
|
|
2033
|
+
`Returned nonce does not match: ${sessionNonce} !== ${responseNonce}`
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
session.set("customer_authorization_code_token", access_token);
|
|
2037
|
+
session.set(
|
|
2038
|
+
"expires_at",
|
|
2039
|
+
new Date((/* @__PURE__ */ new Date()).getTime() + (expires_in - 120) * 1e3).getTime() + ""
|
|
2040
|
+
);
|
|
2041
|
+
session.set("id_token", id_token);
|
|
2042
|
+
session.set("refresh_token", refresh_token);
|
|
2043
|
+
const customerAccessToken = await exchangeAccessToken(
|
|
2044
|
+
session,
|
|
2045
|
+
customerAccountId,
|
|
2046
|
+
customerAccountUrl,
|
|
2047
|
+
origin
|
|
2048
|
+
);
|
|
2049
|
+
session.set("customer_access_token", customerAccessToken);
|
|
2050
|
+
return redirect2(redirectPath, {
|
|
2051
|
+
headers: {
|
|
2052
|
+
"Set-Cookie": await session.commit()
|
|
2053
|
+
}
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
1566
2058
|
var INPUT_NAME = "cartFormInput";
|
|
1567
2059
|
function CartForm({
|
|
1568
2060
|
children,
|
|
@@ -2256,10 +2748,10 @@ function createCartHandler(options) {
|
|
|
2256
2748
|
},
|
|
2257
2749
|
deleteMetafield: cartMetafieldDeleteDefault(mutateOptions)
|
|
2258
2750
|
};
|
|
2259
|
-
if ("
|
|
2751
|
+
if ("customMethods" in options) {
|
|
2260
2752
|
return {
|
|
2261
2753
|
...methods,
|
|
2262
|
-
...options.
|
|
2754
|
+
...options.customMethods ?? {}
|
|
2263
2755
|
};
|
|
2264
2756
|
} else {
|
|
2265
2757
|
return methods;
|
|
@@ -2356,25 +2848,6 @@ function useVariantPath(handle, productPath) {
|
|
|
2356
2848
|
};
|
|
2357
2849
|
}, [pathname, search, handle, productPath]);
|
|
2358
2850
|
}
|
|
2359
|
-
|
|
2360
|
-
// src/csp/nonce.ts
|
|
2361
|
-
function generateNonce() {
|
|
2362
|
-
return toHexString(randomUint8Array());
|
|
2363
|
-
}
|
|
2364
|
-
function randomUint8Array() {
|
|
2365
|
-
try {
|
|
2366
|
-
return crypto.getRandomValues(new Uint8Array(16));
|
|
2367
|
-
} catch (e) {
|
|
2368
|
-
return new Uint8Array(16).map(() => Math.random() * 255 | 0);
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
function toHexString(byteArray) {
|
|
2372
|
-
return Array.from(byteArray, function(byte) {
|
|
2373
|
-
return ("0" + (byte & 255).toString(16)).slice(-2);
|
|
2374
|
-
}).join("");
|
|
2375
|
-
}
|
|
2376
|
-
|
|
2377
|
-
// src/csp/csp.ts
|
|
2378
2851
|
var NonceContext = react.createContext(void 0);
|
|
2379
2852
|
var NonceProvider = NonceContext.Provider;
|
|
2380
2853
|
var useNonce = () => react.useContext(NonceContext);
|
|
@@ -2427,9 +2900,8 @@ var Script = react.forwardRef(
|
|
|
2427
2900
|
function useOptimisticData(identifier) {
|
|
2428
2901
|
const fetchers = react$1.useFetchers();
|
|
2429
2902
|
const data = {};
|
|
2430
|
-
for (const
|
|
2431
|
-
|
|
2432
|
-
if (formData && formData.get("optimistic-identifier") === identifier) {
|
|
2903
|
+
for (const { formData } of fetchers) {
|
|
2904
|
+
if (formData?.get("optimistic-identifier") === identifier) {
|
|
2433
2905
|
try {
|
|
2434
2906
|
if (formData.has("optimistic-data")) {
|
|
2435
2907
|
const dataInForm = JSON.parse(
|
|
@@ -2466,7 +2938,7 @@ function OptimisticInput({ id, data }) {
|
|
|
2466
2938
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartNoteUpdate
|
|
2467
2939
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartSelectedDeliveryOptionsUpdate
|
|
2468
2940
|
//! @see https://shopify.dev/docs/api/storefront/latest/mutations/cartMetafieldsSet
|
|
2469
|
-
//! @see https://shopify.dev/docs/api/storefront/2023-
|
|
2941
|
+
//! @see https://shopify.dev/docs/api/storefront/2023-10/mutations/cartMetafieldDelete
|
|
2470
2942
|
|
|
2471
2943
|
Object.defineProperty(exports, 'AnalyticsEventName', {
|
|
2472
2944
|
enumerable: true,
|
|
@@ -2580,6 +3052,7 @@ exports.cartSelectedDeliveryOptionsUpdateDefault = cartSelectedDeliveryOptionsUp
|
|
|
2580
3052
|
exports.cartSetIdDefault = cartSetIdDefault;
|
|
2581
3053
|
exports.createCartHandler = createCartHandler;
|
|
2582
3054
|
exports.createContentSecurityPolicy = createContentSecurityPolicy;
|
|
3055
|
+
exports.createCustomerClient__unstable = createCustomerClient;
|
|
2583
3056
|
exports.createStorefrontClient = createStorefrontClient;
|
|
2584
3057
|
exports.createWithCache = createWithCache;
|
|
2585
3058
|
exports.generateCacheControlHeader = generateCacheControlHeader;
|