@shopify/hydrogen 2026.4.3 → 2026.4.5
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 +46 -16
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +46 -16
- package/dist/development/index.js.map +1 -1
- package/dist/production/index.cjs +46 -46
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.js +46 -46
- package/dist/production/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -437,7 +437,7 @@ function getPrivacyBanner() {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
// package.json
|
|
440
|
-
var version = "2026.4.
|
|
440
|
+
var version = "2026.4.5";
|
|
441
441
|
|
|
442
442
|
// src/analytics-manager/ShopifyAnalytics.tsx
|
|
443
443
|
function getCustomerPrivacyRequired() {
|
|
@@ -846,7 +846,7 @@ function PerfKit({ shop }) {
|
|
|
846
846
|
"data-storefront-id": shop.hydrogenSubchannelId,
|
|
847
847
|
"data-monorail-region": "global",
|
|
848
848
|
"data-spa-mode": "true",
|
|
849
|
-
"data-resource-timing-sampling-rate": "
|
|
849
|
+
"data-resource-timing-sampling-rate": "10"
|
|
850
850
|
}
|
|
851
851
|
});
|
|
852
852
|
useEffect(() => {
|
|
@@ -1833,7 +1833,7 @@ function generateUUID() {
|
|
|
1833
1833
|
}
|
|
1834
1834
|
|
|
1835
1835
|
// src/version.ts
|
|
1836
|
-
var LIB_VERSION = "2026.4.
|
|
1836
|
+
var LIB_VERSION = "2026.4.5";
|
|
1837
1837
|
|
|
1838
1838
|
// src/utils/graphql.ts
|
|
1839
1839
|
function minifyQuery(string) {
|
|
@@ -3604,11 +3604,13 @@ async function refreshToken({
|
|
|
3604
3604
|
const customerAccount = session.get(CUSTOMER_ACCOUNT_SESSION_KEY);
|
|
3605
3605
|
const refreshToken2 = customerAccount?.refreshToken;
|
|
3606
3606
|
const idToken = customerAccount?.idToken;
|
|
3607
|
-
if (!refreshToken2)
|
|
3607
|
+
if (!refreshToken2) {
|
|
3608
|
+
clearSession(session);
|
|
3608
3609
|
throw new BadRequest(
|
|
3609
3610
|
"Unauthorized",
|
|
3610
3611
|
"No refreshToken found in the session. Make sure your session is configured correctly and passed to `createCustomerAccountClient`."
|
|
3611
3612
|
);
|
|
3613
|
+
}
|
|
3612
3614
|
newBody.append("grant_type", "refresh_token");
|
|
3613
3615
|
newBody.append("refresh_token", refreshToken2);
|
|
3614
3616
|
newBody.append("client_id", customerAccountId);
|
|
@@ -3633,6 +3635,9 @@ async function refreshToken({
|
|
|
3633
3635
|
});
|
|
3634
3636
|
if (!response.ok) {
|
|
3635
3637
|
const text = await response.text();
|
|
3638
|
+
if (getOAuthError(text) === "invalid_grant") {
|
|
3639
|
+
clearSession(session);
|
|
3640
|
+
}
|
|
3636
3641
|
throw new Response(text, {
|
|
3637
3642
|
status: response.status,
|
|
3638
3643
|
headers: {
|
|
@@ -3643,9 +3648,13 @@ async function refreshToken({
|
|
|
3643
3648
|
const {
|
|
3644
3649
|
access_token,
|
|
3645
3650
|
expires_in,
|
|
3646
|
-
refresh_token
|
|
3651
|
+
refresh_token,
|
|
3652
|
+
error
|
|
3647
3653
|
} = await response.json();
|
|
3648
3654
|
if (!access_token || access_token.length === 0) {
|
|
3655
|
+
if (error === "invalid_grant") {
|
|
3656
|
+
clearSession(session);
|
|
3657
|
+
}
|
|
3649
3658
|
throw new BadRequest("Unauthorized", "Invalid access token received.");
|
|
3650
3659
|
}
|
|
3651
3660
|
session.set(CUSTOMER_ACCOUNT_SESSION_KEY, {
|
|
@@ -3682,7 +3691,6 @@ async function checkExpires({
|
|
|
3682
3691
|
await locks.refresh;
|
|
3683
3692
|
delete locks.refresh;
|
|
3684
3693
|
} catch (error) {
|
|
3685
|
-
clearSession(session);
|
|
3686
3694
|
if (error && error.status !== 401) {
|
|
3687
3695
|
throw error;
|
|
3688
3696
|
} else {
|
|
@@ -3694,6 +3702,14 @@ async function checkExpires({
|
|
|
3694
3702
|
}
|
|
3695
3703
|
}
|
|
3696
3704
|
}
|
|
3705
|
+
function getOAuthError(body) {
|
|
3706
|
+
try {
|
|
3707
|
+
const data = JSON.parse(body);
|
|
3708
|
+
return typeof data?.error === "string" ? data.error : void 0;
|
|
3709
|
+
} catch {
|
|
3710
|
+
return void 0;
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3697
3713
|
function generateCodeVerifier() {
|
|
3698
3714
|
const rando = generateRandomCode();
|
|
3699
3715
|
return base64UrlEncode(rando);
|
|
@@ -3721,9 +3737,7 @@ function convertBufferToString(hash) {
|
|
|
3721
3737
|
return String.fromCharCode(...numberArray);
|
|
3722
3738
|
}
|
|
3723
3739
|
function generateState() {
|
|
3724
|
-
|
|
3725
|
-
const randomString = Math.random().toString(36).substring(2);
|
|
3726
|
-
return timestamp + randomString;
|
|
3740
|
+
return base64UrlEncode(generateRandomCode());
|
|
3727
3741
|
}
|
|
3728
3742
|
async function exchangeAccessToken(authAccessToken, customerAccountId, customerAccountTokenExchangeUrl, httpsOrigin, debugInfo) {
|
|
3729
3743
|
const clientId = customerAccountId;
|
|
@@ -3877,6 +3891,8 @@ function createCustomerAccountHelper(customerApiVersion, shopId) {
|
|
|
3877
3891
|
|
|
3878
3892
|
// src/customer/customer.ts
|
|
3879
3893
|
var HYDROGEN_TUNNEL_DOMAIN_SUFFIX = ".tryhydrogen.dev";
|
|
3894
|
+
var OAUTH_RECOVERY_PARAM = "oauth_recovery";
|
|
3895
|
+
var OAUTH_RECOVERY_STATE_PREFIX = "oauth-recovery.";
|
|
3880
3896
|
function checkTunnelDomain(hostname, useCustomAuthDomain, redirectUri) {
|
|
3881
3897
|
if (hostname.endsWith(HYDROGEN_TUNNEL_DOMAIN_SUFFIX)) return;
|
|
3882
3898
|
if (useCustomAuthDomain) {
|
|
@@ -4108,7 +4124,8 @@ function createCustomerAccountClient({
|
|
|
4108
4124
|
ensureTunnel(requestUrl.hostname);
|
|
4109
4125
|
ifInvalidCredentialThrowError();
|
|
4110
4126
|
const loginUrl = new URL(getCustomerAccountUrl("AUTH" /* AUTH */));
|
|
4111
|
-
const
|
|
4127
|
+
const isOAuthRecovery = requestUrl.searchParams.get(OAUTH_RECOVERY_PARAM) === "true";
|
|
4128
|
+
const state = `${isOAuthRecovery ? OAUTH_RECOVERY_STATE_PREFIX : ""}${generateState()}`;
|
|
4112
4129
|
const nonce = generateNonce();
|
|
4113
4130
|
loginUrl.searchParams.set("client_id", customerAccountId);
|
|
4114
4131
|
loginUrl.searchParams.set("scope", "openid email");
|
|
@@ -4197,17 +4214,30 @@ function createCustomerAccountClient({
|
|
|
4197
4214
|
const code = requestUrl.searchParams.get("code");
|
|
4198
4215
|
const state = requestUrl.searchParams.get("state");
|
|
4199
4216
|
if (!code || !state) {
|
|
4200
|
-
clearSession(session);
|
|
4201
4217
|
throw new BadRequest(
|
|
4202
4218
|
"Unauthorized",
|
|
4203
4219
|
"No code or state parameter found in the redirect URL."
|
|
4204
4220
|
);
|
|
4205
4221
|
}
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4222
|
+
const customerAccountSession = session.get(CUSTOMER_ACCOUNT_SESSION_KEY);
|
|
4223
|
+
if (customerAccountSession?.state !== state) {
|
|
4224
|
+
if (state.startsWith(OAUTH_RECOVERY_STATE_PREFIX)) {
|
|
4225
|
+
throw new BadRequest(
|
|
4226
|
+
"Unable to complete sign in. Please try again.",
|
|
4227
|
+
"The session state does not match the state parameter. Make sure that the session is configured correctly and passed to `createCustomerAccountClient`."
|
|
4228
|
+
);
|
|
4229
|
+
}
|
|
4230
|
+
warnOnce(
|
|
4231
|
+
"[h2:warn:customerAccount] OAuth callback state mismatch. Restarting customer login once."
|
|
4232
|
+
);
|
|
4233
|
+
const recoveryLoginUrl = new URL(loginPath, request.url);
|
|
4234
|
+
recoveryLoginUrl.searchParams.set(
|
|
4235
|
+
"return_to",
|
|
4236
|
+
customerAccountSession?.redirectPath ?? defaultRedirectPath
|
|
4237
|
+
);
|
|
4238
|
+
recoveryLoginUrl.searchParams.set(OAUTH_RECOVERY_PARAM, "true");
|
|
4239
|
+
return redirect(
|
|
4240
|
+
`${recoveryLoginUrl.pathname}${recoveryLoginUrl.search}`
|
|
4211
4241
|
);
|
|
4212
4242
|
}
|
|
4213
4243
|
const clientId = customerAccountId;
|