@aws-amplify/auth 4.3.19 → 4.3.20-custom-pk.79

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/src/Auth.ts CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  StorageHelper,
42
42
  ICredentials,
43
43
  Parser,
44
- JS,
44
+ browserOrNode,
45
45
  UniversalStorage,
46
46
  urlSafeDecode,
47
47
  } from '@aws-amplify/core';
@@ -80,10 +80,11 @@ const USER_ADMIN_SCOPE = 'aws.cognito.signin.user.admin';
80
80
  // 10 sec, following this guide https://www.nngroup.com/articles/response-times-3-important-limits/
81
81
  const OAUTH_FLOW_MS_TIMEOUT = 10 * 1000;
82
82
 
83
- const AMPLIFY_SYMBOL = (typeof Symbol !== 'undefined' &&
84
- typeof Symbol.for === 'function'
85
- ? Symbol.for('amplify_default')
86
- : '@@amplify_default') as Symbol;
83
+ const AMPLIFY_SYMBOL = (
84
+ typeof Symbol !== 'undefined' && typeof Symbol.for === 'function'
85
+ ? Symbol.for('amplify_default')
86
+ : '@@amplify_default'
87
+ ) as Symbol;
87
88
 
88
89
  const dispatchAuthEvent = (event: string, data: any, message: string) => {
89
90
  Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL);
@@ -699,9 +700,21 @@ export class AuthClass {
699
700
 
700
701
  const bypassCache = params ? params.bypassCache : false;
701
702
  user.getUserData(
702
- (err, data) => {
703
+ async (err, data) => {
703
704
  if (err) {
704
705
  logger.debug('getting preferred mfa failed', err);
706
+ if (this.isSessionInvalid(err)) {
707
+ try {
708
+ await this.cleanUpInvalidSession(user);
709
+ } catch (cleanUpError) {
710
+ rej(
711
+ new Error(
712
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
713
+ )
714
+ );
715
+ return;
716
+ }
717
+ }
705
718
  rej(err);
706
719
  return;
707
720
  }
@@ -752,14 +765,25 @@ export class AuthClass {
752
765
 
753
766
  private _getUserData(user, params) {
754
767
  return new Promise((res, rej) => {
755
- user.getUserData((err, data) => {
768
+ user.getUserData(async (err, data) => {
756
769
  if (err) {
757
770
  logger.debug('getting user data failed', err);
771
+ if (this.isSessionInvalid(err)) {
772
+ try {
773
+ await this.cleanUpInvalidSession(user);
774
+ } catch (cleanUpError) {
775
+ rej(
776
+ new Error(
777
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
778
+ )
779
+ );
780
+ return;
781
+ }
782
+ }
758
783
  rej(err);
759
784
  return;
760
785
  } else {
761
786
  res(data);
762
- return;
763
787
  }
764
788
  }, params);
765
789
  });
@@ -773,7 +797,7 @@ export class AuthClass {
773
797
  */
774
798
  public async setPreferredMFA(
775
799
  user: CognitoUser | any,
776
- mfaMethod: 'TOTP' | 'SMS' | 'NOMFA' | 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA'
800
+ mfaMethod: 'TOTP' | 'SMS' | 'NOMFA' | 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA'
777
801
  ): Promise<string> {
778
802
  const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
779
803
 
@@ -793,7 +817,7 @@ export class AuthClass {
793
817
  };
794
818
  break;
795
819
  case 'SMS':
796
- case 'SMS_MFA':
820
+ case 'SMS_MFA':
797
821
  smsMfaSettings = {
798
822
  PreferredMfa: true,
799
823
  Enabled: true,
@@ -855,9 +879,21 @@ export class AuthClass {
855
879
  logger.debug('Caching the latest user data into local');
856
880
  // cache the latest result into user data
857
881
  user.getUserData(
858
- (err, data) => {
882
+ async (err, data) => {
859
883
  if (err) {
860
884
  logger.debug('getting user data failed', err);
885
+ if (this.isSessionInvalid(err)) {
886
+ try {
887
+ await this.cleanUpInvalidSession(user);
888
+ } catch (cleanUpError) {
889
+ rej(
890
+ new Error(
891
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
892
+ )
893
+ );
894
+ return;
895
+ }
896
+ }
861
897
  return rej(err);
862
898
  } else {
863
899
  return res(result);
@@ -1120,24 +1156,102 @@ export class AuthClass {
1120
1156
  **/
1121
1157
  public deleteUserAttributes(
1122
1158
  user: CognitoUser | any,
1123
- attributeNames: string[],
1159
+ attributeNames: string[]
1124
1160
  ) {
1125
1161
  const that = this;
1126
1162
  return new Promise((resolve, reject) => {
1127
1163
  that.userSession(user).then(session => {
1128
- user.deleteAttributes(
1129
- attributeNames,
1130
- (err, result) => {
1131
- if (err) {
1132
- return reject(err);
1133
- } else {
1134
- return resolve(result);
1135
- }
1164
+ user.deleteAttributes(attributeNames, (err, result) => {
1165
+ if (err) {
1166
+ return reject(err);
1167
+ } else {
1168
+ return resolve(result);
1136
1169
  }
1137
- );
1170
+ });
1138
1171
  });
1139
1172
  });
1173
+ }
1174
+
1175
+ /**
1176
+ * Delete the current authenticated user
1177
+ * @return {Promise}
1178
+ **/
1179
+ // TODO: Check return type void
1180
+ public async deleteUser(): Promise<string | void> {
1181
+ try {
1182
+ await this._storageSync;
1183
+ } catch (e) {
1184
+ logger.debug('Failed to sync cache info into memory', e);
1185
+ throw new Error(e);
1186
+ }
1187
+
1188
+ const isSignedInHostedUI =
1189
+ this._oAuthHandler &&
1190
+ this._storage.getItem('amplify-signin-with-hostedUI') === 'true';
1191
+
1192
+ return new Promise(async (res, rej) => {
1193
+ if (this.userPool) {
1194
+ const user = this.userPool.getCurrentUser();
1140
1195
 
1196
+ if (!user) {
1197
+ logger.debug('Failed to get user from user pool');
1198
+ return rej(new Error('No current user.'));
1199
+ } else {
1200
+ user.getSession(async (err, session) => {
1201
+ if (err) {
1202
+ logger.debug('Failed to get the user session', err);
1203
+ if (this.isSessionInvalid(err)) {
1204
+ try {
1205
+ await this.cleanUpInvalidSession(user);
1206
+ } catch (cleanUpError) {
1207
+ rej(
1208
+ new Error(
1209
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1210
+ )
1211
+ );
1212
+ return;
1213
+ }
1214
+ }
1215
+ return rej(err);
1216
+ } else {
1217
+ user.deleteUser((err, result: string) => {
1218
+ if (err) {
1219
+ rej(err);
1220
+ } else {
1221
+ dispatchAuthEvent(
1222
+ 'userDeleted',
1223
+ result,
1224
+ 'The authenticated user has been deleted.'
1225
+ );
1226
+ user.signOut();
1227
+ this.user = null;
1228
+ try {
1229
+ this.cleanCachedItems(); // clean aws credentials
1230
+ } catch (e) {
1231
+ // TODO: change to rejects in refactor
1232
+ logger.debug('failed to clear cached items');
1233
+ }
1234
+
1235
+ if (isSignedInHostedUI) {
1236
+ this.oAuthSignOutRedirect(res, rej);
1237
+ } else {
1238
+ dispatchAuthEvent(
1239
+ 'signOut',
1240
+ this.user,
1241
+ `A user has been signed out`
1242
+ );
1243
+ res(result);
1244
+ }
1245
+ }
1246
+ });
1247
+ }
1248
+ });
1249
+ }
1250
+ } else {
1251
+ logger.debug('no Congito User pool');
1252
+ rej(new Error('Cognito User pool does not exist'));
1253
+ }
1254
+ });
1141
1255
  }
1142
1256
 
1143
1257
  /**
@@ -1225,6 +1339,89 @@ export class AuthClass {
1225
1339
  });
1226
1340
  }
1227
1341
 
1342
+ private isErrorWithMessage(err: any): err is { message: string } {
1343
+ return (
1344
+ typeof err === 'object' &&
1345
+ Object.prototype.hasOwnProperty.call(err, 'message')
1346
+ );
1347
+ }
1348
+
1349
+ // Session revoked by another app
1350
+ private isTokenRevokedError(
1351
+ err: any
1352
+ ): err is { message: 'Access Token has been revoked' } {
1353
+ return (
1354
+ this.isErrorWithMessage(err) &&
1355
+ err.message === 'Access Token has been revoked'
1356
+ );
1357
+ }
1358
+
1359
+ private isRefreshTokenRevokedError(
1360
+ err: any
1361
+ ): err is { message: 'Refresh Token has been revoked' } {
1362
+ return (
1363
+ this.isErrorWithMessage(err) &&
1364
+ err.message === 'Refresh Token has been revoked'
1365
+ );
1366
+ }
1367
+
1368
+ private isUserDisabledError(
1369
+ err: any
1370
+ ): err is { message: 'User is disabled.' } {
1371
+ return this.isErrorWithMessage(err) && err.message === 'User is disabled.';
1372
+ }
1373
+
1374
+ private isUserDoesNotExistError(
1375
+ err: any
1376
+ ): err is { message: 'User does not exist.' } {
1377
+ return (
1378
+ this.isErrorWithMessage(err) && err.message === 'User does not exist.'
1379
+ );
1380
+ }
1381
+
1382
+ private isRefreshTokenExpiredError(
1383
+ err: any
1384
+ ): err is { message: 'Refresh Token has expired' } {
1385
+ return (
1386
+ this.isErrorWithMessage(err) &&
1387
+ err.message === 'Refresh Token has expired'
1388
+ );
1389
+ }
1390
+
1391
+ private isSignedInHostedUI() {
1392
+ return (
1393
+ this._oAuthHandler &&
1394
+ this._storage.getItem('amplify-signin-with-hostedUI') === 'true'
1395
+ );
1396
+ }
1397
+
1398
+ private isSessionInvalid(err: any) {
1399
+ return (
1400
+ this.isUserDisabledError(err) ||
1401
+ this.isUserDoesNotExistError(err) ||
1402
+ this.isTokenRevokedError(err) ||
1403
+ this.isRefreshTokenRevokedError(err) ||
1404
+ this.isRefreshTokenExpiredError(err)
1405
+ );
1406
+ }
1407
+
1408
+ private async cleanUpInvalidSession(user: CognitoUser) {
1409
+ user.signOut();
1410
+ this.user = null;
1411
+ try {
1412
+ await this.cleanCachedItems(); // clean aws credentials
1413
+ } catch (e) {
1414
+ logger.debug('failed to clear cached items');
1415
+ }
1416
+ if (this.isSignedInHostedUI()) {
1417
+ return new Promise((res, rej) => {
1418
+ this.oAuthSignOutRedirect(res, rej);
1419
+ });
1420
+ } else {
1421
+ dispatchAuthEvent('signOut', this.user, `A user has been signed out`);
1422
+ }
1423
+ }
1424
+
1228
1425
  /**
1229
1426
  * Get current authenticated user
1230
1427
  * @return - A promise resolves to current authenticated CognitoUser if success
@@ -1286,6 +1483,18 @@ export class AuthClass {
1286
1483
  async (err, session) => {
1287
1484
  if (err) {
1288
1485
  logger.debug('Failed to get the user session', err);
1486
+ if (this.isSessionInvalid(err)) {
1487
+ try {
1488
+ await this.cleanUpInvalidSession(user);
1489
+ } catch (cleanUpError) {
1490
+ rej(
1491
+ new Error(
1492
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1493
+ )
1494
+ );
1495
+ return;
1496
+ }
1497
+ }
1289
1498
  rej(err);
1290
1499
  return;
1291
1500
  }
@@ -1303,19 +1512,22 @@ export class AuthClass {
1303
1512
  const { scope = '' } = session.getAccessToken().decodePayload();
1304
1513
  if (scope.split(' ').includes(USER_ADMIN_SCOPE)) {
1305
1514
  user.getUserData(
1306
- (err, data) => {
1515
+ async (err, data) => {
1307
1516
  if (err) {
1308
1517
  logger.debug('getting user data failed', err);
1309
- // Make sure the user is still valid
1310
- if (
1311
- err.message === 'User is disabled.' ||
1312
- err.message === 'User does not exist.' ||
1313
- err.message === 'Access Token has been revoked' // Session revoked by another app
1314
- ) {
1518
+ if (this.isSessionInvalid(err)) {
1519
+ try {
1520
+ await this.cleanUpInvalidSession(user);
1521
+ } catch (cleanUpError) {
1522
+ rej(
1523
+ new Error(
1524
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1525
+ )
1526
+ );
1527
+ return;
1528
+ }
1315
1529
  rej(err);
1316
1530
  } else {
1317
- // the error may also be thrown when lack of permissions to get user info etc
1318
- // in that case we just bypass the error
1319
1531
  res(user);
1320
1532
  }
1321
1533
  return;
@@ -1424,7 +1636,7 @@ export class AuthClass {
1424
1636
  logger.debug('Getting current session');
1425
1637
  // Purposely not calling the reject method here because we don't need a console error
1426
1638
  if (!this.userPool) {
1427
- return Promise.reject();
1639
+ return this.rejectNoUserPool();
1428
1640
  }
1429
1641
 
1430
1642
  return new Promise((res, rej) => {
@@ -1463,17 +1675,29 @@ export class AuthClass {
1463
1675
  }
1464
1676
  const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
1465
1677
 
1466
- return new Promise((resolve, reject) => {
1678
+ return new Promise((res, rej) => {
1467
1679
  logger.debug('Getting the session from this user:', user);
1468
1680
  user.getSession(
1469
- (err, session) => {
1681
+ async (err, session) => {
1470
1682
  if (err) {
1471
1683
  logger.debug('Failed to get the session from user', user);
1472
- reject(err);
1684
+ if (this.isSessionInvalid(err)) {
1685
+ try {
1686
+ await this.cleanUpInvalidSession(user);
1687
+ } catch (cleanUpError) {
1688
+ rej(
1689
+ new Error(
1690
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1691
+ )
1692
+ );
1693
+ return;
1694
+ }
1695
+ }
1696
+ rej(err);
1473
1697
  return;
1474
1698
  } else {
1475
1699
  logger.debug('Succeed to get the user session', session);
1476
- resolve(session);
1700
+ res(session);
1477
1701
  return;
1478
1702
  }
1479
1703
  },
@@ -1515,8 +1739,8 @@ export class AuthClass {
1515
1739
  logger.debug('getting session success', session);
1516
1740
  return this.Credentials.set(session, 'session');
1517
1741
  })
1518
- .catch(error => {
1519
- logger.debug('getting session failed', error);
1742
+ .catch(() => {
1743
+ logger.debug('getting guest credentials');
1520
1744
  return this.Credentials.set(null, 'guest');
1521
1745
  });
1522
1746
  }
@@ -1630,9 +1854,21 @@ export class AuthClass {
1630
1854
  const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
1631
1855
 
1632
1856
  user.getSession(
1633
- (err, result) => {
1857
+ async (err, result) => {
1634
1858
  if (err) {
1635
1859
  logger.debug('failed to get the user session', err);
1860
+ if (this.isSessionInvalid(err)) {
1861
+ try {
1862
+ await this.cleanUpInvalidSession(user);
1863
+ } catch (cleanUpError) {
1864
+ rej(
1865
+ new Error(
1866
+ `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1867
+ )
1868
+ );
1869
+ return;
1870
+ }
1871
+ }
1636
1872
  return rej(err);
1637
1873
  }
1638
1874
  user.globalSignOut({
@@ -1669,7 +1905,7 @@ export class AuthClass {
1669
1905
  resolve: () => void,
1670
1906
  reject: (reason?: any) => void
1671
1907
  ) {
1672
- const { isBrowser } = JS.browserOrNode();
1908
+ const { isBrowser } = browserOrNode();
1673
1909
 
1674
1910
  if (isBrowser) {
1675
1911
  this.oAuthSignOutRedirectOrReject(reject);
@@ -1687,7 +1923,7 @@ export class AuthClass {
1687
1923
  this._oAuthHandler.signOut(); // this method redirects url
1688
1924
 
1689
1925
  // App should be redirected to another url otherwise it will reject
1690
- setTimeout(() => reject('Signout timeout fail'), 3000);
1926
+ setTimeout(() => reject(Error('Signout timeout fail')), 3000);
1691
1927
  }
1692
1928
 
1693
1929
  /**
@@ -1710,7 +1946,7 @@ export class AuthClass {
1710
1946
  logger.debug('no current Cognito user');
1711
1947
  }
1712
1948
  } else {
1713
- logger.debug('no Congito User pool');
1949
+ logger.debug('no Cognito User pool');
1714
1950
  }
1715
1951
 
1716
1952
  /**
@@ -1841,7 +2077,7 @@ export class AuthClass {
1841
2077
  code,
1842
2078
  password,
1843
2079
  {
1844
- onSuccess: (success) => {
2080
+ onSuccess: success => {
1845
2081
  dispatchAuthEvent(
1846
2082
  'forgotPasswordSubmit',
1847
2083
  user,
@@ -2037,7 +2273,7 @@ export class AuthClass {
2037
2273
  );
2038
2274
 
2039
2275
  const currentUrl =
2040
- URL || (JS.browserOrNode().isBrowser ? window.location.href : '');
2276
+ URL || (browserOrNode().isBrowser ? window.location.href : '');
2041
2277
 
2042
2278
  const hasCodeOrError = !!(parse(currentUrl).query || '')
2043
2279
  .split('&')
@@ -2053,12 +2289,8 @@ export class AuthClass {
2053
2289
  if (hasCodeOrError || hasTokenOrError) {
2054
2290
  this._storage.setItem('amplify-redirected-from-hosted-ui', 'true');
2055
2291
  try {
2056
- const {
2057
- accessToken,
2058
- idToken,
2059
- refreshToken,
2060
- state,
2061
- } = await this._oAuthHandler.handleAuthResponse(currentUrl);
2292
+ const { accessToken, idToken, refreshToken, state } =
2293
+ await this._oAuthHandler.handleAuthResponse(currentUrl);
2062
2294
  const session = new CognitoUserSession({
2063
2295
  IdToken: new CognitoIdToken({ IdToken: idToken }),
2064
2296
  RefreshToken: new CognitoRefreshToken({
@@ -2076,7 +2308,7 @@ export class AuthClass {
2076
2308
  logger.debug('AWS credentials', credentials);
2077
2309
  }
2078
2310
 
2079
- /*
2311
+ /*
2080
2312
  Prior to the request we do sign the custom state along with the state we set. This check will verify
2081
2313
  if there is a dash indicated when setting custom state from the request. If a dash is contained
2082
2314
  then there is custom state present on the state string.
@@ -2115,10 +2347,7 @@ export class AuthClass {
2115
2347
  );
2116
2348
 
2117
2349
  if (isCustomStateIncluded) {
2118
- const customState = state
2119
- .split('-')
2120
- .splice(1)
2121
- .join('-');
2350
+ const customState = state.split('-').splice(1).join('-');
2122
2351
 
2123
2352
  dispatchAuthEvent(
2124
2353
  'customOAuthState',
@@ -2352,4 +2581,3 @@ export class AuthClass {
2352
2581
  export const Auth = new AuthClass(null);
2353
2582
 
2354
2583
  Amplify.register(Auth);
2355
-
package/src/index.ts CHANGED
@@ -1,35 +1,40 @@
1
- /*
2
- * Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
5
- * the License. A copy of the License is located at
6
- *
7
- * http://aws.amazon.com/apache2.0/
8
- *
9
- * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10
- * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11
- * and limitations under the License.
12
- */
13
-
14
- import { Auth } from './Auth';
15
- import { CognitoHostedUIIdentityProvider, SignUpParams } from './types/Auth';
16
- import {
17
- CognitoUser,
18
- CookieStorage,
19
- appendToCognitoUserAgent,
20
- } from 'amazon-cognito-identity-js';
21
- import { AuthErrorStrings } from './common/AuthErrorStrings';
22
-
23
- /**
24
- * @deprecated use named import
25
- */
26
- export default Auth;
27
- export {
28
- Auth,
29
- CognitoUser,
30
- CookieStorage,
31
- CognitoHostedUIIdentityProvider,
32
- SignUpParams,
33
- appendToCognitoUserAgent,
34
- AuthErrorStrings,
35
- };
1
+ /*
2
+ * Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
5
+ * the License. A copy of the License is located at
6
+ *
7
+ * http://aws.amazon.com/apache2.0/
8
+ *
9
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11
+ * and limitations under the License.
12
+ */
13
+
14
+ import { Auth } from './Auth';
15
+ import {
16
+ CognitoHostedUIIdentityProvider,
17
+ SignUpParams,
18
+ GRAPHQL_AUTH_MODE,
19
+ } from './types/Auth';
20
+ import {
21
+ CognitoUser,
22
+ CookieStorage,
23
+ appendToCognitoUserAgent,
24
+ } from 'amazon-cognito-identity-js';
25
+ import { AuthErrorStrings } from './common/AuthErrorStrings';
26
+
27
+ /**
28
+ * @deprecated use named import
29
+ */
30
+ export default Auth;
31
+ export {
32
+ Auth,
33
+ CognitoUser,
34
+ CookieStorage,
35
+ CognitoHostedUIIdentityProvider,
36
+ SignUpParams,
37
+ appendToCognitoUserAgent,
38
+ AuthErrorStrings,
39
+ GRAPHQL_AUTH_MODE,
40
+ };
package/src/types/Auth.ts CHANGED
@@ -227,3 +227,11 @@ export interface IAuthDevice {
227
227
  id: string;
228
228
  name: string;
229
229
  }
230
+
231
+ export enum GRAPHQL_AUTH_MODE {
232
+ API_KEY = 'API_KEY',
233
+ AWS_IAM = 'AWS_IAM',
234
+ OPENID_CONNECT = 'OPENID_CONNECT',
235
+ AMAZON_COGNITO_USER_POOLS = 'AMAZON_COGNITO_USER_POOLS',
236
+ AWS_LAMBDA = 'AWS_LAMBDA',
237
+ }
@@ -10,14 +10,14 @@
10
10
  * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11
11
  * and limitations under the License.
12
12
  */
13
- import { JS } from '@aws-amplify/core';
13
+ import { browserOrNode } from '@aws-amplify/core';
14
14
 
15
15
  export default callback => {
16
- if (JS.browserOrNode().isBrowser && window.location) {
16
+ if (browserOrNode().isBrowser && window.location) {
17
17
  const url = window.location.href;
18
18
 
19
19
  callback({ url });
20
- } else if (JS.browserOrNode().isNode) {
20
+ } else if (browserOrNode().isNode) {
21
21
  // continue building on ssr
22
22
  () => {}; // noop
23
23
  } else {