@salesforce/commerce-sdk-react 3.1.0 → 3.1.1-preview.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/CHANGELOG.md +52 -77
- package/README.md +1 -129
- package/auth/index.d.ts +14 -120
- package/auth/index.js +106 -422
- package/auth/storage/cookie.js +3 -4
- package/components/ShopperExperience/Component/index.js +2 -2
- package/components/ShopperExperience/Page/index.js +2 -2
- package/components/ShopperExperience/Region/index.js +2 -2
- package/constant.d.ts +0 -15
- package/constant.js +2 -20
- package/hooks/ShopperLogin/cache.js +0 -2
- package/hooks/ShopperLogin/mutation.d.ts +0 -10
- package/hooks/ShopperLogin/mutation.js +0 -10
- package/hooks/index.d.ts +0 -2
- package/hooks/index.js +0 -16
- package/hooks/useMutation.d.ts +1 -11
- package/hooks/useMutation.js +29 -37
- package/package.json +5 -5
- package/provider.d.ts +1 -3
- package/provider.js +21 -33
- package/hooks/useDNT.d.ts +0 -17
- package/hooks/useDNT.js +0 -42
- package/hooks/useTrustedAgent.d.ts +0 -24
- package/hooks/useTrustedAgent.js +0 -185
package/auth/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default =
|
|
6
|
+
exports.default = void 0;
|
|
7
7
|
var _commerceSdkIsomorphic = require("commerce-sdk-isomorphic");
|
|
8
8
|
var _jwtDecode = require("jwt-decode");
|
|
9
9
|
var _storage = require("./storage");
|
|
@@ -107,18 +107,8 @@ const DATA_MAP = {
|
|
|
107
107
|
access_token_sfra: {
|
|
108
108
|
storageType: 'cookie',
|
|
109
109
|
key: 'cc-at'
|
|
110
|
-
},
|
|
111
|
-
[_constant.DNT_COOKIE_NAME]: {
|
|
112
|
-
storageType: 'cookie',
|
|
113
|
-
key: _constant.DNT_COOKIE_NAME
|
|
114
|
-
},
|
|
115
|
-
dwsid: {
|
|
116
|
-
storageType: 'cookie',
|
|
117
|
-
key: _constant.DWSID_COOKIE_NAME
|
|
118
110
|
}
|
|
119
111
|
};
|
|
120
|
-
const DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL = exports.DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL = 90 * 24 * 60 * 60;
|
|
121
|
-
const DEFAULT_SLAS_REFRESH_TOKEN_GUEST_TTL = exports.DEFAULT_SLAS_REFRESH_TOKEN_GUEST_TTL = 30 * 24 * 60 * 60;
|
|
122
112
|
|
|
123
113
|
/**
|
|
124
114
|
* This class is used to handle shopper authentication.
|
|
@@ -167,10 +157,8 @@ class Auth {
|
|
|
167
157
|
};
|
|
168
158
|
this.redirectURI = config.redirectURI;
|
|
169
159
|
this.fetchedToken = config.fetchedToken || '';
|
|
160
|
+
this.OCAPISessionsURL = config.OCAPISessionsURL || '';
|
|
170
161
|
this.logger = config.logger;
|
|
171
|
-
this.defaultDnt = config.defaultDnt;
|
|
172
|
-
this.refreshTokenRegisteredCookieTTL = config.refreshTokenRegisteredCookieTTL;
|
|
173
|
-
this.refreshTokenGuestCookieTTL = config.refreshTokenGuestCookieTTL;
|
|
174
162
|
|
|
175
163
|
/*
|
|
176
164
|
* There are 2 ways to enable SLAS private client mode.
|
|
@@ -219,65 +207,6 @@ class Auth {
|
|
|
219
207
|
storage.set(key, value, options);
|
|
220
208
|
(_DATA_MAP$name$callba = (_DATA_MAP$name = DATA_MAP[name]).callback) === null || _DATA_MAP$name$callba === void 0 ? void 0 : _DATA_MAP$name$callba.call(_DATA_MAP$name, storage);
|
|
221
209
|
}
|
|
222
|
-
delete(name) {
|
|
223
|
-
const {
|
|
224
|
-
key,
|
|
225
|
-
storageType
|
|
226
|
-
} = DATA_MAP[name];
|
|
227
|
-
const storage = this.stores[storageType];
|
|
228
|
-
storage.delete(key);
|
|
229
|
-
}
|
|
230
|
-
getDnt() {
|
|
231
|
-
const dntCookieVal = this.get(_constant.DNT_COOKIE_NAME);
|
|
232
|
-
// Only '1' or '0' are valid, and invalid values, lack of cookie, or value conflict with token must be an undefined DNT
|
|
233
|
-
let dntCookieStatus = undefined;
|
|
234
|
-
const accessToken = this.getAccessToken();
|
|
235
|
-
let isInSync = true;
|
|
236
|
-
if (accessToken) {
|
|
237
|
-
const {
|
|
238
|
-
dnt
|
|
239
|
-
} = this.parseSlasJWT(accessToken);
|
|
240
|
-
isInSync = dnt === dntCookieVal;
|
|
241
|
-
}
|
|
242
|
-
if (dntCookieVal !== '1' && dntCookieVal !== '0' || !isInSync) {
|
|
243
|
-
this.delete(_constant.DNT_COOKIE_NAME);
|
|
244
|
-
} else {
|
|
245
|
-
dntCookieStatus = Boolean(Number(dntCookieVal));
|
|
246
|
-
}
|
|
247
|
-
return dntCookieStatus;
|
|
248
|
-
}
|
|
249
|
-
setDnt(preference) {
|
|
250
|
-
var _this = this;
|
|
251
|
-
return _asyncToGenerator(function* () {
|
|
252
|
-
let dntCookieVal = String(Number(preference));
|
|
253
|
-
// Use defaultDNT if defined. If not, use SLAS default DNT
|
|
254
|
-
if (preference === null) {
|
|
255
|
-
dntCookieVal = _this.defaultDnt ? String(Number(_this.defaultDnt)) : '0';
|
|
256
|
-
}
|
|
257
|
-
// Set the cookie once to include dnt in the access token and then again to set the expiry time
|
|
258
|
-
_this.set(_constant.DNT_COOKIE_NAME, dntCookieVal, _objectSpread(_objectSpread({}, (0, _utils.getDefaultCookieAttributes)()), {}, {
|
|
259
|
-
secure: true
|
|
260
|
-
}));
|
|
261
|
-
const accessToken = _this.getAccessToken();
|
|
262
|
-
if (accessToken !== '') {
|
|
263
|
-
const {
|
|
264
|
-
dnt
|
|
265
|
-
} = _this.parseSlasJWT(accessToken);
|
|
266
|
-
if (dnt !== dntCookieVal) {
|
|
267
|
-
yield _this.refreshAccessToken();
|
|
268
|
-
}
|
|
269
|
-
} else {
|
|
270
|
-
yield _this.refreshAccessToken();
|
|
271
|
-
}
|
|
272
|
-
if (preference !== null) {
|
|
273
|
-
const SECONDS_IN_DAY = 86400;
|
|
274
|
-
_this.set(_constant.DNT_COOKIE_NAME, dntCookieVal, _objectSpread(_objectSpread({}, (0, _utils.getDefaultCookieAttributes)()), {}, {
|
|
275
|
-
secure: true,
|
|
276
|
-
expires: Number(_this.get('refresh_token_expires_in')) / SECONDS_IN_DAY
|
|
277
|
-
}));
|
|
278
|
-
}
|
|
279
|
-
})();
|
|
280
|
-
}
|
|
281
210
|
clearStorage() {
|
|
282
211
|
// Type assertion because Object.keys is silly and limited :(
|
|
283
212
|
const keys = Object.keys(DATA_MAP);
|
|
@@ -323,21 +252,6 @@ class Auth {
|
|
|
323
252
|
return validTimeSeconds <= tokenAgeSeconds;
|
|
324
253
|
}
|
|
325
254
|
|
|
326
|
-
/**
|
|
327
|
-
* Gets the Do-Not-Track (DNT) preference from the `dw_dnt` cookie.
|
|
328
|
-
* If user has set their DNT preference, read the cookie, if not, use the default DNT pref. If the default DNT pref has not been set, default to false.
|
|
329
|
-
*/
|
|
330
|
-
getDntPreference(dw_dnt, defaultDnt) {
|
|
331
|
-
let dntPref;
|
|
332
|
-
// Read `dw_dnt` cookie
|
|
333
|
-
const dntCookie = dw_dnt === '1' ? true : dw_dnt === '0' ? false : undefined;
|
|
334
|
-
dntPref = dntCookie;
|
|
335
|
-
|
|
336
|
-
// If the cookie is not set, read the default DNT preference.
|
|
337
|
-
if (dntCookie === undefined) dntPref = defaultDnt !== undefined ? defaultDnt : undefined;
|
|
338
|
-
return dntPref;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
255
|
/**
|
|
342
256
|
* Returns the SLAS access token or an empty string if the access token
|
|
343
257
|
* is not found in local store or if SFRA wants PWA to trigger refresh token login.
|
|
@@ -382,17 +296,6 @@ class Auth {
|
|
|
382
296
|
}
|
|
383
297
|
return accessToken;
|
|
384
298
|
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* For Hybrid storefronts ONLY!!!
|
|
388
|
-
* This method clears out SLAS access token generated in Plugin SLAS and passed in via "cc-at" cookie.
|
|
389
|
-
*
|
|
390
|
-
* In a hybrid setup, whenever any SLAS flow executes in Plugin SLAS and an access token is generated,
|
|
391
|
-
* the access token is sent over to PWA Kit using cc-at cookie.
|
|
392
|
-
*
|
|
393
|
-
* PWA Kit will check to see if cc-at cookie exists, if it does, the access token value in localStorage is updated
|
|
394
|
-
* with value from the cc-at cookie and is then used for all SCAPI requests made from PWA Kit. The cc-at cookie is then cleared.
|
|
395
|
-
*/
|
|
396
299
|
clearSFRAAuthToken() {
|
|
397
300
|
const {
|
|
398
301
|
key,
|
|
@@ -403,52 +306,7 @@ class Auth {
|
|
|
403
306
|
}
|
|
404
307
|
|
|
405
308
|
/**
|
|
406
|
-
*
|
|
407
|
-
* This method clears the dwsid cookie from the browser.
|
|
408
|
-
* In a hybrid setup, dwsid points to an ECOM session and is passed between PWA Kit and SFRA/SG sites via "dwsid" cookie.
|
|
409
|
-
*
|
|
410
|
-
* Whenever a registered shopper logs in on PWA Kit, we must clear the dwsid cookie if one exists. When shopper navigates
|
|
411
|
-
* to SFRA as a logged-in shopper, ECOM notices a missing DWSID, generates a new DWSID and triggers the onSession hook which uses
|
|
412
|
-
* registered shopper refresh-token and restores session and basket on SFRA.
|
|
413
|
-
*/
|
|
414
|
-
clearECOMSession() {
|
|
415
|
-
const {
|
|
416
|
-
key,
|
|
417
|
-
storageType
|
|
418
|
-
} = DATA_MAP[_constant.DWSID_COOKIE_NAME];
|
|
419
|
-
const store = this.stores[storageType];
|
|
420
|
-
store.delete(key);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Converts a duration in seconds to a Date object.
|
|
425
|
-
* This function takes a number representing seconds and returns a Date object
|
|
426
|
-
* for the current time plus the given duration.
|
|
427
|
-
*
|
|
428
|
-
* @param {number} seconds - The number of seconds to add to the current time.
|
|
429
|
-
* @returns {Date} A Date object for the expiration time.
|
|
430
|
-
*/
|
|
431
|
-
convertSecondsToDate(seconds) {
|
|
432
|
-
if (typeof seconds !== 'number') {
|
|
433
|
-
throw new Error('The refresh_token_expires_in seconds parameter must be a number.');
|
|
434
|
-
}
|
|
435
|
-
return new Date(Date.now() + seconds * 1000);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Retrieves our refresh token cookie ttl value
|
|
440
|
-
*/
|
|
441
|
-
getRefreshTokenCookieTTLValue(overrideValue, responseValue, defaultValue) {
|
|
442
|
-
let value = overrideValue;
|
|
443
|
-
if (typeof value !== 'number' || value <= 0 || value > defaultValue) {
|
|
444
|
-
this.logWarning(_constant.SLAS_REFRESH_TOKEN_COOKIE_TTL_OVERRIDE_MSG);
|
|
445
|
-
value = responseValue || defaultValue;
|
|
446
|
-
}
|
|
447
|
-
return value;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/**
|
|
451
|
-
* This method stores the TokenResponse object retrieved from SLAS, and
|
|
309
|
+
* This method stores the TokenResponse object retrived from SLAS, and
|
|
452
310
|
* store the data in storage.
|
|
453
311
|
*/
|
|
454
312
|
handleTokenResponse(res, isGuest) {
|
|
@@ -462,77 +320,10 @@ class Auth {
|
|
|
462
320
|
this.set('usid', res.usid);
|
|
463
321
|
this.set('customer_type', isGuest ? 'guest' : 'registered');
|
|
464
322
|
const refreshTokenKey = isGuest ? 'refresh_token_guest' : 'refresh_token_registered';
|
|
465
|
-
const overrideValue = isGuest ? this.refreshTokenGuestCookieTTL : this.refreshTokenRegisteredCookieTTL;
|
|
466
|
-
const responseValue = res.refresh_token_expires_in;
|
|
467
|
-
const defaultValue = isGuest ? DEFAULT_SLAS_REFRESH_TOKEN_GUEST_TTL : DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL;
|
|
468
|
-
const refreshTokenTTLValue = this.getRefreshTokenCookieTTLValue(overrideValue, responseValue, defaultValue);
|
|
469
|
-
const expiresDate = this.convertSecondsToDate(refreshTokenTTLValue);
|
|
470
|
-
this.set('refresh_token_expires_in', refreshTokenTTLValue.toString());
|
|
471
323
|
this.set(refreshTokenKey, res.refresh_token, {
|
|
472
|
-
expires:
|
|
324
|
+
expires: res.refresh_token_expires_in
|
|
473
325
|
});
|
|
474
326
|
}
|
|
475
|
-
refreshAccessToken() {
|
|
476
|
-
var _this2 = this;
|
|
477
|
-
return _asyncToGenerator(function* () {
|
|
478
|
-
const dntPref = _this2.getDntPreference(_this2.get(_constant.DNT_COOKIE_NAME), _this2.defaultDnt);
|
|
479
|
-
const refreshTokenRegistered = _this2.get('refresh_token_registered');
|
|
480
|
-
const refreshTokenGuest = _this2.get('refresh_token_guest');
|
|
481
|
-
const refreshToken = refreshTokenRegistered || refreshTokenGuest;
|
|
482
|
-
if (refreshToken) {
|
|
483
|
-
try {
|
|
484
|
-
return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, _objectSpread({
|
|
485
|
-
refreshToken
|
|
486
|
-
}, dntPref !== undefined && {
|
|
487
|
-
dnt: dntPref
|
|
488
|
-
}), {
|
|
489
|
-
clientSecret: _this2.clientSecret
|
|
490
|
-
}), !!refreshTokenGuest);
|
|
491
|
-
} catch (error) {
|
|
492
|
-
// If the refresh token is invalid, we need to re-login the user
|
|
493
|
-
if (error instanceof Error && 'response' in error) {
|
|
494
|
-
// commerce-sdk-isomorphic throws a `ResponseError`, but doesn't export the class.
|
|
495
|
-
// We can't use `instanceof`, so instead we just check for the `response` property
|
|
496
|
-
// and assume it is a fetch Response.
|
|
497
|
-
const json = yield error['response'].json();
|
|
498
|
-
if (json.message === 'invalid refresh_token') {
|
|
499
|
-
// clean up storage and restart the login flow
|
|
500
|
-
_this2.clearStorage();
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// refresh flow for TAOB
|
|
507
|
-
const accessToken = _this2.getAccessToken();
|
|
508
|
-
if (accessToken && _this2.isTokenExpired(accessToken)) {
|
|
509
|
-
try {
|
|
510
|
-
const {
|
|
511
|
-
isGuest,
|
|
512
|
-
usid,
|
|
513
|
-
loginId,
|
|
514
|
-
isAgent
|
|
515
|
-
} = _this2.parseSlasJWT(accessToken);
|
|
516
|
-
if (isAgent) {
|
|
517
|
-
return yield _this2.queueRequest(() => _this2.refreshTrustedAgent(loginId, usid), isGuest);
|
|
518
|
-
}
|
|
519
|
-
} catch (e) {
|
|
520
|
-
/* catch invalid jwt */
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// if a TAOB left a usid and it tries to
|
|
525
|
-
// use it, we will be stuck in a fail loop
|
|
526
|
-
let token;
|
|
527
|
-
try {
|
|
528
|
-
token = yield _this2.loginGuestUser();
|
|
529
|
-
} catch (e) {
|
|
530
|
-
_this2.clearStorage();
|
|
531
|
-
token = yield _this2.loginGuestUser();
|
|
532
|
-
}
|
|
533
|
-
return token;
|
|
534
|
-
})();
|
|
535
|
-
}
|
|
536
327
|
|
|
537
328
|
/**
|
|
538
329
|
* This method queues the requests and handles the SLAS token response.
|
|
@@ -542,20 +333,23 @@ class Auth {
|
|
|
542
333
|
* @Internal
|
|
543
334
|
*/
|
|
544
335
|
queueRequest(fn, isGuest) {
|
|
545
|
-
var
|
|
336
|
+
var _this = this;
|
|
546
337
|
return _asyncToGenerator(function* () {
|
|
547
|
-
const queue =
|
|
548
|
-
|
|
338
|
+
const queue = _this.pendingToken ?? Promise.resolve();
|
|
339
|
+
_this.pendingToken = queue.then(/*#__PURE__*/_asyncToGenerator(function* () {
|
|
549
340
|
const token = yield fn();
|
|
550
|
-
|
|
341
|
+
_this.handleTokenResponse(token, isGuest);
|
|
342
|
+
if ((0, _utils.onClient)() && _this.OCAPISessionsURL) {
|
|
343
|
+
void _this.createOCAPISession();
|
|
344
|
+
}
|
|
551
345
|
// Q: Why don't we just return token? Why re-construct the same object again?
|
|
552
346
|
// A: because a user could open multiple tabs and the data in memory could be out-dated
|
|
553
347
|
// We must always grab the data from the storage (cookie/localstorage) directly
|
|
554
|
-
return
|
|
348
|
+
return _this.data;
|
|
555
349
|
})).finally(() => {
|
|
556
|
-
|
|
350
|
+
_this.pendingToken = undefined;
|
|
557
351
|
});
|
|
558
|
-
return yield
|
|
352
|
+
return yield _this.pendingToken;
|
|
559
353
|
})();
|
|
560
354
|
}
|
|
561
355
|
logWarning = msg => {
|
|
@@ -564,42 +358,6 @@ class Auth {
|
|
|
564
358
|
}
|
|
565
359
|
};
|
|
566
360
|
|
|
567
|
-
/**
|
|
568
|
-
* This method extracts the status and message from a ResponseError that is returned
|
|
569
|
-
* by commerce-sdk-isomorphic.
|
|
570
|
-
*
|
|
571
|
-
* commerce-sdk-isomorphic throws a `ResponseError`, but doesn't export the class.
|
|
572
|
-
* We can't use `instanceof`, so instead we just check for the `response` property
|
|
573
|
-
* and assume it is a `ResponseError` if a response is present
|
|
574
|
-
*
|
|
575
|
-
* Once commerce-sdk-isomorphic exports `ResponseError` we can revisit if this method is
|
|
576
|
-
* still required.
|
|
577
|
-
*
|
|
578
|
-
* @returns {status_code, responseMessage} contained within the ResponseError
|
|
579
|
-
* @throws error if the error is not a ResponseError
|
|
580
|
-
* @Internal
|
|
581
|
-
*/
|
|
582
|
-
extractResponseError = (() => function () {
|
|
583
|
-
var _ref2 = _asyncToGenerator(function* (error) {
|
|
584
|
-
// the regular error.message will return only the generic status code message
|
|
585
|
-
// ie. 'Bad Request' for 400. We need to drill specifically into the ResponseError
|
|
586
|
-
// to get a more descriptive error message from SLAS
|
|
587
|
-
if ('response' in error) {
|
|
588
|
-
const json = yield error['response'].json();
|
|
589
|
-
const status_code = json.status_code;
|
|
590
|
-
const responseMessage = json.message;
|
|
591
|
-
return {
|
|
592
|
-
status_code,
|
|
593
|
-
responseMessage
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
throw error;
|
|
597
|
-
});
|
|
598
|
-
return function (_x) {
|
|
599
|
-
return _ref2.apply(this, arguments);
|
|
600
|
-
};
|
|
601
|
-
}())();
|
|
602
|
-
|
|
603
361
|
/**
|
|
604
362
|
* The ready function returns a promise that resolves with valid ShopperLogin
|
|
605
363
|
* token response.
|
|
@@ -609,32 +367,55 @@ class Auth {
|
|
|
609
367
|
* The flow:
|
|
610
368
|
* 1. If we have valid access token - use it
|
|
611
369
|
* 2. If we have valid refresh token - refresh token flow
|
|
612
|
-
* 3.
|
|
613
|
-
* 4. PKCE flow
|
|
370
|
+
* 3. PKCE flow
|
|
614
371
|
*/
|
|
615
372
|
ready() {
|
|
616
|
-
var
|
|
373
|
+
var _this2 = this;
|
|
617
374
|
return _asyncToGenerator(function* () {
|
|
618
|
-
if (
|
|
375
|
+
if (_this2.fetchedToken && _this2.fetchedToken !== '') {
|
|
619
376
|
const {
|
|
620
377
|
isGuest,
|
|
621
378
|
customerId,
|
|
622
379
|
usid
|
|
623
|
-
} =
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
return
|
|
380
|
+
} = _this2.parseSlasJWT(_this2.fetchedToken);
|
|
381
|
+
_this2.set('access_token', _this2.fetchedToken);
|
|
382
|
+
_this2.set('customer_id', customerId);
|
|
383
|
+
_this2.set('usid', usid);
|
|
384
|
+
_this2.set('customer_type', isGuest ? 'guest' : 'registered');
|
|
385
|
+
return _this2.data;
|
|
629
386
|
}
|
|
630
|
-
if (
|
|
631
|
-
return yield
|
|
387
|
+
if (_this2.pendingToken) {
|
|
388
|
+
return yield _this2.pendingToken;
|
|
632
389
|
}
|
|
633
|
-
const accessToken =
|
|
634
|
-
if (accessToken && !
|
|
635
|
-
return
|
|
390
|
+
const accessToken = _this2.getAccessToken();
|
|
391
|
+
if (accessToken && !_this2.isTokenExpired(accessToken)) {
|
|
392
|
+
return _this2.data;
|
|
636
393
|
}
|
|
637
|
-
|
|
394
|
+
const refreshTokenRegistered = _this2.get('refresh_token_registered');
|
|
395
|
+
const refreshTokenGuest = _this2.get('refresh_token_guest');
|
|
396
|
+
const refreshToken = refreshTokenRegistered || refreshTokenGuest;
|
|
397
|
+
if (refreshToken) {
|
|
398
|
+
try {
|
|
399
|
+
return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, {
|
|
400
|
+
refreshToken
|
|
401
|
+
}, {
|
|
402
|
+
clientSecret: _this2.clientSecret
|
|
403
|
+
}), !!refreshTokenGuest);
|
|
404
|
+
} catch (error) {
|
|
405
|
+
// If the refresh token is invalid, we need to re-login the user
|
|
406
|
+
if (error instanceof Error && 'response' in error) {
|
|
407
|
+
// commerce-sdk-isomorphic throws a `ResponseError`, but doesn't export the class.
|
|
408
|
+
// We can't use `instanceof`, so instead we just check for the `response` property
|
|
409
|
+
// and assume it is a fetch Response.
|
|
410
|
+
const json = yield error['response'].json();
|
|
411
|
+
if (json.message === 'invalid refresh_token') {
|
|
412
|
+
// clean up storage and restart the login flow
|
|
413
|
+
_this2.clearStorage();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return _this2.loginGuestUser();
|
|
638
419
|
})();
|
|
639
420
|
}
|
|
640
421
|
|
|
@@ -644,9 +425,9 @@ class Auth {
|
|
|
644
425
|
* @returns Wrapped function
|
|
645
426
|
*/
|
|
646
427
|
whenReady(fn) {
|
|
647
|
-
var
|
|
428
|
+
var _this3 = this;
|
|
648
429
|
return /*#__PURE__*/_asyncToGenerator(function* (...args) {
|
|
649
|
-
yield
|
|
430
|
+
yield _this3.ready();
|
|
650
431
|
return yield fn(...args);
|
|
651
432
|
});
|
|
652
433
|
}
|
|
@@ -656,41 +437,25 @@ class Auth {
|
|
|
656
437
|
*
|
|
657
438
|
*/
|
|
658
439
|
loginGuestUser() {
|
|
659
|
-
var
|
|
440
|
+
var _this4 = this;
|
|
660
441
|
return _asyncToGenerator(function* () {
|
|
661
|
-
if (
|
|
662
|
-
|
|
442
|
+
if (_this4.clientSecret && (0, _utils.onClient)() && _this4.clientSecret !== _constant.SLAS_SECRET_PLACEHOLDER) {
|
|
443
|
+
_this4.logWarning(_constant.SLAS_SECRET_WARNING_MSG);
|
|
663
444
|
}
|
|
664
|
-
const usid =
|
|
665
|
-
const dntPref = _this6.getDntPreference(_this6.get(_constant.DNT_COOKIE_NAME), _this6.defaultDnt);
|
|
445
|
+
const usid = _this4.get('usid');
|
|
666
446
|
const isGuest = true;
|
|
667
|
-
const guestPrivateArgs = [
|
|
668
|
-
dnt: dntPref
|
|
669
|
-
}), usid && {
|
|
447
|
+
const guestPrivateArgs = [_this4.client, _objectSpread({}, usid && {
|
|
670
448
|
usid
|
|
671
449
|
}), {
|
|
672
|
-
clientSecret:
|
|
450
|
+
clientSecret: _this4.clientSecret
|
|
673
451
|
}];
|
|
674
|
-
const guestPublicArgs = [
|
|
675
|
-
redirectURI:
|
|
676
|
-
},
|
|
677
|
-
dnt: dntPref
|
|
678
|
-
}), usid && {
|
|
452
|
+
const guestPublicArgs = [_this4.client, _objectSpread({
|
|
453
|
+
redirectURI: _this4.redirectURI
|
|
454
|
+
}, usid && {
|
|
679
455
|
usid
|
|
680
456
|
})];
|
|
681
|
-
const callback =
|
|
682
|
-
|
|
683
|
-
return yield _this6.queueRequest(callback, isGuest);
|
|
684
|
-
} catch (error) {
|
|
685
|
-
// We catch the error here to do logging but we still need to
|
|
686
|
-
// throw an error to stop the login flow from continuing.
|
|
687
|
-
const {
|
|
688
|
-
status_code,
|
|
689
|
-
responseMessage
|
|
690
|
-
} = yield _this6.extractResponseError(error);
|
|
691
|
-
_this6.logger.error(`${status_code} ${responseMessage}`);
|
|
692
|
-
throw new Error(`New guest user could not be logged in. ${status_code} ${responseMessage}`);
|
|
693
|
-
}
|
|
457
|
+
const callback = _this4.clientSecret ? () => _commerceSdkIsomorphic.helpers.loginGuestUserPrivate(...guestPrivateArgs) : () => _commerceSdkIsomorphic.helpers.loginGuestUser(...guestPublicArgs);
|
|
458
|
+
return yield _this4.queueRequest(callback, isGuest);
|
|
694
459
|
})();
|
|
695
460
|
}
|
|
696
461
|
|
|
@@ -699,7 +464,7 @@ class Auth {
|
|
|
699
464
|
*
|
|
700
465
|
*/
|
|
701
466
|
register(body) {
|
|
702
|
-
var
|
|
467
|
+
var _this5 = this;
|
|
703
468
|
return _asyncToGenerator(function* () {
|
|
704
469
|
const {
|
|
705
470
|
customer: {
|
|
@@ -714,13 +479,13 @@ class Auth {
|
|
|
714
479
|
if (!login) {
|
|
715
480
|
throw new Error('Customer registration is missing login field.');
|
|
716
481
|
}
|
|
717
|
-
const res = yield
|
|
482
|
+
const res = yield _this5.shopperCustomersClient.registerCustomer({
|
|
718
483
|
headers: {
|
|
719
|
-
authorization: `Bearer ${
|
|
484
|
+
authorization: `Bearer ${_this5.get('access_token')}`
|
|
720
485
|
},
|
|
721
486
|
body
|
|
722
487
|
});
|
|
723
|
-
yield
|
|
488
|
+
yield _this5.loginRegisteredUserB2C({
|
|
724
489
|
username: login,
|
|
725
490
|
password
|
|
726
491
|
});
|
|
@@ -733,135 +498,64 @@ class Auth {
|
|
|
733
498
|
*
|
|
734
499
|
*/
|
|
735
500
|
loginRegisteredUserB2C(credentials) {
|
|
736
|
-
var
|
|
501
|
+
var _this6 = this;
|
|
737
502
|
return _asyncToGenerator(function* () {
|
|
738
|
-
if (
|
|
739
|
-
|
|
503
|
+
if (_this6.clientSecret && (0, _utils.onClient)() && _this6.clientSecret !== _constant.SLAS_SECRET_PLACEHOLDER) {
|
|
504
|
+
_this6.logWarning(_constant.SLAS_SECRET_WARNING_MSG);
|
|
740
505
|
}
|
|
741
|
-
const redirectURI =
|
|
742
|
-
const usid =
|
|
743
|
-
const dntPref = _this8.getDntPreference(_this8.get(_constant.DNT_COOKIE_NAME), _this8.defaultDnt);
|
|
506
|
+
const redirectURI = _this6.redirectURI;
|
|
507
|
+
const usid = _this6.get('usid');
|
|
744
508
|
const isGuest = false;
|
|
745
|
-
const token = yield _commerceSdkIsomorphic.helpers.loginRegisteredUserB2C(
|
|
746
|
-
clientSecret:
|
|
747
|
-
}), _objectSpread(
|
|
509
|
+
const token = yield _commerceSdkIsomorphic.helpers.loginRegisteredUserB2C(_this6.client, _objectSpread(_objectSpread({}, credentials), {}, {
|
|
510
|
+
clientSecret: _this6.clientSecret
|
|
511
|
+
}), _objectSpread({
|
|
748
512
|
redirectURI
|
|
749
|
-
},
|
|
750
|
-
dnt: dntPref
|
|
751
|
-
}), usid && {
|
|
513
|
+
}, usid && {
|
|
752
514
|
usid
|
|
753
515
|
}));
|
|
754
|
-
|
|
755
|
-
if ((0, _utils.onClient)()) {
|
|
756
|
-
void
|
|
516
|
+
_this6.handleTokenResponse(token, isGuest);
|
|
517
|
+
if ((0, _utils.onClient)() && _this6.OCAPISessionsURL) {
|
|
518
|
+
void _this6.createOCAPISession();
|
|
757
519
|
}
|
|
758
520
|
return token;
|
|
759
521
|
})();
|
|
760
522
|
}
|
|
761
523
|
|
|
762
524
|
/**
|
|
763
|
-
*
|
|
525
|
+
* A wrapper method for commerce-sdk-isomorphic helper: logout.
|
|
764
526
|
*
|
|
765
|
-
* @warning This method is not supported on the server, it is a client-only method.
|
|
766
527
|
*/
|
|
767
|
-
|
|
768
|
-
var
|
|
528
|
+
logout() {
|
|
529
|
+
var _this7 = this;
|
|
769
530
|
return _asyncToGenerator(function* () {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const isGuest = loginId === 'guest';
|
|
778
|
-
const idpOrigin = isGuest ? 'slas' : 'ecom';
|
|
779
|
-
const url = `${slasClient.clientConfig.proxy || ''}/shopper/auth/v1/organizations/${organizationId}/oauth2/trusted-agent/authorize?${[...[`client_id=${clientId}`, `channel_id=${siteId}`, `login_id=${loginId}`, `redirect_uri=${_this9.redirectURI}`, `idp_origin=${idpOrigin}`, `response_type=code`], ...(!_this9.clientSecret ? [`code_challenge=${codeChallenge}`] : [])].join('&')}`;
|
|
780
|
-
return {
|
|
781
|
-
url,
|
|
782
|
-
codeVerifier
|
|
783
|
-
};
|
|
531
|
+
// Not awaiting on purpose because there isn't much we can do if this fails.
|
|
532
|
+
void _commerceSdkIsomorphic.helpers.logout(_this7.client, {
|
|
533
|
+
accessToken: _this7.get('access_token'),
|
|
534
|
+
refreshToken: _this7.get('refresh_token_registered')
|
|
535
|
+
});
|
|
536
|
+
_this7.clearStorage();
|
|
537
|
+
return yield _this7.loginGuestUser();
|
|
784
538
|
})();
|
|
785
539
|
}
|
|
786
540
|
|
|
787
541
|
/**
|
|
788
|
-
*
|
|
542
|
+
* Make a post request to the OCAPI /session endpoint to bridge the session.
|
|
789
543
|
*
|
|
790
|
-
*
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
var _this10 = this;
|
|
794
|
-
return _asyncToGenerator(function* () {
|
|
795
|
-
const slasClient = _this10.client;
|
|
796
|
-
const loginId = credentials.loginId || 'guest';
|
|
797
|
-
const isGuest = loginId === 'guest';
|
|
798
|
-
const idpOrigin = isGuest ? 'slas' : 'ecom';
|
|
799
|
-
const optionsToken = {
|
|
800
|
-
headers: {
|
|
801
|
-
Authorization: `Bearer ${credentials.code}`
|
|
802
|
-
},
|
|
803
|
-
body: _objectSpread(_objectSpread(_objectSpread({
|
|
804
|
-
channel_id: slasClient.clientConfig.parameters.siteId,
|
|
805
|
-
grant_type: 'client_credentials',
|
|
806
|
-
redirect_uri: _this10.redirectURI,
|
|
807
|
-
login_id: loginId,
|
|
808
|
-
idp_origin: idpOrigin,
|
|
809
|
-
dnt: 'true'
|
|
810
|
-
}, !_this10.clientSecret && {
|
|
811
|
-
client_id: slasClient.clientConfig.parameters.clientId,
|
|
812
|
-
code_verifier: credentials.codeVerifier
|
|
813
|
-
}), credentials.state && {
|
|
814
|
-
state: credentials.state
|
|
815
|
-
}), credentials.usid && {
|
|
816
|
-
usid: credentials.usid
|
|
817
|
-
})
|
|
818
|
-
};
|
|
819
|
-
|
|
820
|
-
// using slas private client
|
|
821
|
-
if (credentials.clientSecret) {
|
|
822
|
-
optionsToken.headers._sfdc_client_auth = `Basic ${_commerceSdkIsomorphic.helpers.stringToBase64(`${slasClient.clientConfig.parameters.clientId}:${credentials.clientSecret}`)}`;
|
|
823
|
-
}
|
|
824
|
-
const token = yield slasClient.getTrustedAgentAccessToken(optionsToken);
|
|
825
|
-
_this10.handleTokenResponse(token, isGuest);
|
|
826
|
-
return token;
|
|
827
|
-
})();
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* Trusted agent refresh handler
|
|
544
|
+
* The HTTP response contains a set-cookie header which sets the dwsid session cookie.
|
|
545
|
+
* This cookie is used on SFRA, and it allows shoppers to navigate between SFRA and
|
|
546
|
+
* this PWA site seamlessly; this is often used to enable hybrid deployment.
|
|
831
547
|
*
|
|
832
|
-
*
|
|
833
|
-
*/
|
|
834
|
-
registerTrustedAgentRefreshHandler(refreshTrustedAgentHandler) {
|
|
835
|
-
this.refreshTrustedAgentHandler = refreshTrustedAgentHandler;
|
|
836
|
-
}
|
|
837
|
-
refreshTrustedAgent(loginId, usid) {
|
|
838
|
-
var _this11 = this;
|
|
839
|
-
return _asyncToGenerator(function* () {
|
|
840
|
-
if (_this11.refreshTrustedAgentHandler) {
|
|
841
|
-
return yield _this11.refreshTrustedAgentHandler(loginId, usid, true);
|
|
842
|
-
}
|
|
843
|
-
_this11.clearStorage();
|
|
844
|
-
return yield _this11.loginGuestUser();
|
|
845
|
-
})();
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
* A wrapper method for commerce-sdk-isomorphic helper: logout.
|
|
548
|
+
* (Note: this method is client side only, b/c MRT doesn't support set-cookie header right now)
|
|
850
549
|
*
|
|
550
|
+
* @returns {Promise}
|
|
851
551
|
*/
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
void _commerceSdkIsomorphic.helpers.logout(_this12.client, {
|
|
858
|
-
accessToken: _this12.get('access_token'),
|
|
859
|
-
refreshToken: _this12.get('refresh_token_registered')
|
|
860
|
-
});
|
|
552
|
+
createOCAPISession() {
|
|
553
|
+
return fetch(this.OCAPISessionsURL, {
|
|
554
|
+
method: 'POST',
|
|
555
|
+
headers: {
|
|
556
|
+
Authorization: 'Bearer ' + this.get('access_token')
|
|
861
557
|
}
|
|
862
|
-
|
|
863
|
-
return yield _this12.loginGuestUser();
|
|
864
|
-
})();
|
|
558
|
+
});
|
|
865
559
|
}
|
|
866
560
|
|
|
867
561
|
/**
|
|
@@ -869,12 +563,10 @@ class Auth {
|
|
|
869
563
|
*
|
|
870
564
|
*/
|
|
871
565
|
parseSlasJWT(jwt) {
|
|
872
|
-
var _isbParts, _isbParts2;
|
|
873
566
|
const payload = (0, _jwtDecode.jwtDecode)(jwt);
|
|
874
567
|
const {
|
|
875
568
|
sub,
|
|
876
|
-
isb
|
|
877
|
-
dnt
|
|
569
|
+
isb
|
|
878
570
|
} = payload;
|
|
879
571
|
if (!sub || !isb) {
|
|
880
572
|
throw new Error('Unable to parse access token payload: missing sub and isb.');
|
|
@@ -885,21 +577,13 @@ class Auth {
|
|
|
885
577
|
const isbParts = isb.split('::');
|
|
886
578
|
const isGuest = isbParts[1] === 'upn:Guest';
|
|
887
579
|
const customerId = isGuest ? isbParts[3].replace('gcid:', '') : isbParts[4].replace('rcid:', '');
|
|
888
|
-
const loginId = isGuest ? 'guest' : isbParts[1].replace('upn:', '');
|
|
889
|
-
const isAgent = !!(isbParts !== null && isbParts !== void 0 && (_isbParts = isbParts[isGuest ? 5 : 6]) !== null && _isbParts !== void 0 && _isbParts.startsWith('agent:'));
|
|
890
|
-
const agentId = isAgent ? isbParts === null || isbParts === void 0 ? void 0 : (_isbParts2 = isbParts[isGuest ? 5 : 6]) === null || _isbParts2 === void 0 ? void 0 : _isbParts2.replace('agent:', '') : null;
|
|
891
|
-
|
|
892
580
|
// SUB format
|
|
893
581
|
// cc-slas::zzrf_001::scid:c9c45bfd-0ed3-4aa2-xxxx-40f88962b836::usid:b4865233-de92-4039-xxxx-aa2dfc8c1ea5
|
|
894
582
|
const usid = sub.split('::')[3].replace('usid:', '');
|
|
895
583
|
return {
|
|
896
584
|
isGuest,
|
|
897
585
|
customerId,
|
|
898
|
-
usid
|
|
899
|
-
dnt,
|
|
900
|
-
loginId,
|
|
901
|
-
isAgent,
|
|
902
|
-
agentId
|
|
586
|
+
usid
|
|
903
587
|
};
|
|
904
588
|
}
|
|
905
589
|
}
|