@salesforce/commerce-sdk-react 3.0.1 → 3.1.0-exp-server-affinity.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
- ## v3.0.1 (Sep 03, 2024)
1
+ ## v3.1.0-exp-server-affinity.1 (Sep 11, 2024)
2
+ ## v3.1.0-dev (Aug 08, 2024)
3
+
4
+ - Add `defaultDnt` to support setting the dnt flag for SLAS. Upgrade `commerce-sdk-isomorphic` to v3.1.1 [#1979](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1979)
5
+ - Update logout helper to work for guest users [#1997](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1997)
6
+
7
+ ## v3.0.1 (Sep 04, 2024)
2
8
  - Fixed an issue where the `expires` attribute in cookies, ensuring it uses seconds instead of days. [#1994](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1994)
3
9
 
4
10
  ## v3.0.0 (Aug 07, 2024)
package/auth/index.d.ts CHANGED
@@ -9,11 +9,11 @@ interface AuthConfig extends ApiClientConfigParams {
9
9
  proxy: string;
10
10
  fetchOptions?: ShopperLoginTypes.FetchOptions;
11
11
  fetchedToken?: string;
12
- OCAPISessionsURL?: string;
13
12
  enablePWAKitPrivateClient?: boolean;
14
13
  clientSecret?: string;
15
14
  silenceWarnings?: boolean;
16
15
  logger: Logger;
16
+ defaultDnt?: boolean;
17
17
  }
18
18
  /**
19
19
  * The extended field is not from api response, we manually store the auth type,
@@ -26,7 +26,7 @@ export type AuthData = Prettify<RemoveStringIndex<TokenResponse> & {
26
26
  idp_access_token: string;
27
27
  }>;
28
28
  /** A shopper could be guest or registered, so we store the refresh tokens individually. */
29
- type AuthDataKeys = Exclude<keyof AuthData, 'refresh_token'> | 'refresh_token_guest' | 'refresh_token_registered' | 'access_token_sfra';
29
+ type AuthDataKeys = Exclude<keyof AuthData, 'refresh_token'> | 'refresh_token_guest' | 'refresh_token_registered' | 'access_token_sfra' | 'dwsid';
30
30
  /**
31
31
  * This class is used to handle shopper authentication.
32
32
  * It is responsible for initializing shopper session, manage access
@@ -42,10 +42,10 @@ declare class Auth {
42
42
  private pendingToken;
43
43
  private stores;
44
44
  private fetchedToken;
45
- private OCAPISessionsURL;
46
45
  private clientSecret;
47
46
  private silenceWarnings;
48
47
  private logger;
48
+ private defaultDnt;
49
49
  constructor(config: AuthConfig);
50
50
  get(name: AuthDataKeys): string;
51
51
  private set;
@@ -74,6 +74,7 @@ declare class Auth {
74
74
  */
75
75
  private getAccessToken;
76
76
  private clearSFRAAuthToken;
77
+ private clearECOMSession;
77
78
  /**
78
79
  * Converts a duration in seconds to a Date object.
79
80
  * This function takes a number representing seconds and returns a Date object
@@ -228,18 +229,6 @@ declare class Auth {
228
229
  *
229
230
  */
230
231
  logout(): Promise<ShopperLoginTypes.TokenResponse>;
231
- /**
232
- * Make a post request to the OCAPI /session endpoint to bridge the session.
233
- *
234
- * The HTTP response contains a set-cookie header which sets the dwsid session cookie.
235
- * This cookie is used on SFRA, and it allows shoppers to navigate between SFRA and
236
- * this PWA site seamlessly; this is often used to enable hybrid deployment.
237
- *
238
- * (Note: this method is client side only, b/c MRT doesn't support set-cookie header right now)
239
- *
240
- * @returns {Promise}
241
- */
242
- createOCAPISession(): Promise<Response>;
243
232
  /**
244
233
  * Decode SLAS JWT and extract information such as customer id, usid, etc.
245
234
  *
package/auth/index.js CHANGED
@@ -107,6 +107,10 @@ const DATA_MAP = {
107
107
  access_token_sfra: {
108
108
  storageType: 'cookie',
109
109
  key: 'cc-at'
110
+ },
111
+ dwsid: {
112
+ storageType: 'cookie',
113
+ key: 'dwsid'
110
114
  }
111
115
  };
112
116
 
@@ -157,8 +161,8 @@ class Auth {
157
161
  };
158
162
  this.redirectURI = config.redirectURI;
159
163
  this.fetchedToken = config.fetchedToken || '';
160
- this.OCAPISessionsURL = config.OCAPISessionsURL || '';
161
164
  this.logger = config.logger;
165
+ this.defaultDnt = config.defaultDnt;
162
166
 
163
167
  /*
164
168
  * There are 2 ways to enable SLAS private client mode.
@@ -304,6 +308,14 @@ class Auth {
304
308
  const store = this.stores[storageType];
305
309
  store.delete(key);
306
310
  }
311
+ clearECOMSession() {
312
+ const {
313
+ key,
314
+ storageType
315
+ } = DATA_MAP['dwsid'];
316
+ const store = this.stores[storageType];
317
+ store.delete(key);
318
+ }
307
319
 
308
320
  /**
309
321
  * Converts a duration in seconds to a Date object.
@@ -355,9 +367,6 @@ class Auth {
355
367
  _this.pendingToken = queue.then( /*#__PURE__*/_asyncToGenerator(function* () {
356
368
  const token = yield fn();
357
369
  _this.handleTokenResponse(token, isGuest);
358
- if ((0, _utils.onClient)() && _this.OCAPISessionsURL) {
359
- void _this.createOCAPISession();
360
- }
361
370
  // Q: Why don't we just return token? Why re-construct the same object again?
362
371
  // A: because a user could open multiple tabs and the data in memory could be out-dated
363
372
  // We must always grab the data from the storage (cookie/localstorage) directly
@@ -412,9 +421,11 @@ class Auth {
412
421
  const refreshToken = refreshTokenRegistered || refreshTokenGuest;
413
422
  if (refreshToken) {
414
423
  try {
415
- return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, {
424
+ return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, _objectSpread({
416
425
  refreshToken
417
- }, {
426
+ }, _this2.defaultDnt !== undefined && {
427
+ dnt: _this2.defaultDnt
428
+ }), {
418
429
  clientSecret: _this2.clientSecret
419
430
  }), !!refreshTokenGuest);
420
431
  } catch (error) {
@@ -460,14 +471,18 @@ class Auth {
460
471
  }
461
472
  const usid = _this4.get('usid');
462
473
  const isGuest = true;
463
- const guestPrivateArgs = [_this4.client, _objectSpread({}, usid && {
474
+ const guestPrivateArgs = [_this4.client, _objectSpread(_objectSpread({}, _this4.defaultDnt !== undefined && {
475
+ dnt: _this4.defaultDnt
476
+ }), usid && {
464
477
  usid
465
478
  }), {
466
479
  clientSecret: _this4.clientSecret
467
480
  }];
468
- const guestPublicArgs = [_this4.client, _objectSpread({
481
+ const guestPublicArgs = [_this4.client, _objectSpread(_objectSpread({
469
482
  redirectURI: _this4.redirectURI
470
- }, usid && {
483
+ }, _this4.defaultDnt !== undefined && {
484
+ dnt: _this4.defaultDnt
485
+ }), usid && {
471
486
  usid
472
487
  })];
473
488
  const callback = _this4.clientSecret ? () => _commerceSdkIsomorphic.helpers.loginGuestUserPrivate(...guestPrivateArgs) : () => _commerceSdkIsomorphic.helpers.loginGuestUser(...guestPublicArgs);
@@ -524,14 +539,16 @@ class Auth {
524
539
  const isGuest = false;
525
540
  const token = yield _commerceSdkIsomorphic.helpers.loginRegisteredUserB2C(_this6.client, _objectSpread(_objectSpread({}, credentials), {}, {
526
541
  clientSecret: _this6.clientSecret
527
- }), _objectSpread({
542
+ }), _objectSpread(_objectSpread({
528
543
  redirectURI
529
- }, usid && {
544
+ }, _this6.defaultDnt !== undefined && {
545
+ dnt: _this6.defaultDnt
546
+ }), usid && {
530
547
  usid
531
548
  }));
532
549
  _this6.handleTokenResponse(token, isGuest);
533
- if ((0, _utils.onClient)() && _this6.OCAPISessionsURL) {
534
- void _this6.createOCAPISession();
550
+ if ((0, _utils.onClient)()) {
551
+ void _this6.clearECOMSession();
535
552
  }
536
553
  return token;
537
554
  })();
@@ -544,36 +561,18 @@ class Auth {
544
561
  logout() {
545
562
  var _this7 = this;
546
563
  return _asyncToGenerator(function* () {
547
- // Not awaiting on purpose because there isn't much we can do if this fails.
548
- void _commerceSdkIsomorphic.helpers.logout(_this7.client, {
549
- accessToken: _this7.get('access_token'),
550
- refreshToken: _this7.get('refresh_token_registered')
551
- });
564
+ if (_this7.get('customer_type') === 'registered') {
565
+ // Not awaiting on purpose because there isn't much we can do if this fails.
566
+ void _commerceSdkIsomorphic.helpers.logout(_this7.client, {
567
+ accessToken: _this7.get('access_token'),
568
+ refreshToken: _this7.get('refresh_token_registered')
569
+ });
570
+ }
552
571
  _this7.clearStorage();
553
572
  return yield _this7.loginGuestUser();
554
573
  })();
555
574
  }
556
575
 
557
- /**
558
- * Make a post request to the OCAPI /session endpoint to bridge the session.
559
- *
560
- * The HTTP response contains a set-cookie header which sets the dwsid session cookie.
561
- * This cookie is used on SFRA, and it allows shoppers to navigate between SFRA and
562
- * this PWA site seamlessly; this is often used to enable hybrid deployment.
563
- *
564
- * (Note: this method is client side only, b/c MRT doesn't support set-cookie header right now)
565
- *
566
- * @returns {Promise}
567
- */
568
- createOCAPISession() {
569
- return fetch(this.OCAPISessionsURL, {
570
- method: 'POST',
571
- headers: {
572
- Authorization: 'Bearer ' + this.get('access_token')
573
- }
574
- });
575
- }
576
-
577
576
  /**
578
577
  * Decode SLAS JWT and extract information such as customer id, usid, etc.
579
578
  *
@@ -7,6 +7,7 @@ exports.CookieStorage = void 0;
7
7
  var _jsCookie = _interopRequireDefault(require("js-cookie"));
8
8
  var _utils = require("../../utils");
9
9
  var _base = require("./base");
10
+ var _constant = require("../../constant");
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
12
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
12
13
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -33,11 +34,11 @@ class CookieStorage extends _base.BaseStorage {
33
34
  super(options);
34
35
  }
35
36
  set(key, value, options) {
36
- const suffixedKey = this.getSuffixedKey(key);
37
+ const suffixedKey = _constant.EXCLUDE_COOKIE_SUFFIX.includes(key) ? key : this.getSuffixedKey(key);
37
38
  _jsCookie.default.set(suffixedKey, value, _objectSpread(_objectSpread({}, (0, _utils.getDefaultCookieAttributes)()), options));
38
39
  }
39
40
  get(key) {
40
- const suffixedKey = this.getSuffixedKey(key);
41
+ const suffixedKey = _constant.EXCLUDE_COOKIE_SUFFIX.includes(key) ? key : this.getSuffixedKey(key);
41
42
  let value = _jsCookie.default.get(suffixedKey) || '';
42
43
  if (value) {
43
44
  // Some values, like the access token, may be split
@@ -54,7 +55,7 @@ class CookieStorage extends _base.BaseStorage {
54
55
  return value;
55
56
  }
56
57
  delete(key, options) {
57
- const suffixedKey = this.getSuffixedKey(key);
58
+ const suffixedKey = _constant.EXCLUDE_COOKIE_SUFFIX.includes(key) ? key : this.getSuffixedKey(key);
58
59
  _jsCookie.default.remove(suffixedKey, _objectSpread(_objectSpread({}, (0, _utils.getDefaultCookieAttributes)()), options));
59
60
 
60
61
  // Some values, like the access token, may be split
package/constant.d.ts CHANGED
@@ -9,4 +9,6 @@ export declare const SLAS_PRIVATE_PROXY_PATH: string;
9
9
  export declare const SLAS_SECRET_WARNING_MSG = "You are potentially exposing SLAS secret on browser. Make sure to keep it safe and secure!";
10
10
  export declare const SLAS_SECRET_PLACEHOLDER = "_PLACEHOLDER_PROXY-PWA_KIT_SLAS_CLIENT_SECRET";
11
11
  export declare const SLAS_SECRET_OVERRIDE_MSG = "You have enabled PWA Kit Private Client mode which gets the SLAS secret from your environment variable. The SLAS secret you have set in the Auth provider will be ignored.";
12
+ export declare const SERVER_AFFINITY_HEADER_KEY = "sfdc_dwsid";
13
+ export declare const EXCLUDE_COOKIE_SUFFIX: string[];
12
14
  //# sourceMappingURL=constant.d.ts.map
package/constant.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SLAS_SECRET_WARNING_MSG = exports.SLAS_SECRET_PLACEHOLDER = exports.SLAS_SECRET_OVERRIDE_MSG = exports.SLAS_PRIVATE_PROXY_PATH = exports.PROXY_PATH = exports.MOBIFY_PATH = exports.LOCAL_BUNDLE_PATH = exports.IFRAME_HOST_ALLOW_LIST = void 0;
6
+ exports.SLAS_SECRET_WARNING_MSG = exports.SLAS_SECRET_PLACEHOLDER = exports.SLAS_SECRET_OVERRIDE_MSG = exports.SLAS_PRIVATE_PROXY_PATH = exports.SERVER_AFFINITY_HEADER_KEY = exports.PROXY_PATH = exports.MOBIFY_PATH = exports.LOCAL_BUNDLE_PATH = exports.IFRAME_HOST_ALLOW_LIST = exports.EXCLUDE_COOKIE_SUFFIX = void 0;
7
7
  /*
8
8
  * Copyright (c) 2023, Salesforce, Inc.
9
9
  * All rights reserved.
@@ -23,4 +23,9 @@ const LOCAL_BUNDLE_PATH = exports.LOCAL_BUNDLE_PATH = `${MOBIFY_PATH}/bundle/dev
23
23
  const SLAS_PRIVATE_PROXY_PATH = exports.SLAS_PRIVATE_PROXY_PATH = `${MOBIFY_PATH}/slas/private`;
24
24
  const SLAS_SECRET_WARNING_MSG = exports.SLAS_SECRET_WARNING_MSG = 'You are potentially exposing SLAS secret on browser. Make sure to keep it safe and secure!';
25
25
  const SLAS_SECRET_PLACEHOLDER = exports.SLAS_SECRET_PLACEHOLDER = '_PLACEHOLDER_PROXY-PWA_KIT_SLAS_CLIENT_SECRET';
26
- const SLAS_SECRET_OVERRIDE_MSG = exports.SLAS_SECRET_OVERRIDE_MSG = 'You have enabled PWA Kit Private Client mode which gets the SLAS secret from your environment variable. The SLAS secret you have set in the Auth provider will be ignored.';
26
+ const SLAS_SECRET_OVERRIDE_MSG = exports.SLAS_SECRET_OVERRIDE_MSG = 'You have enabled PWA Kit Private Client mode which gets the SLAS secret from your environment variable. The SLAS secret you have set in the Auth provider will be ignored.';
27
+ const SERVER_AFFINITY_HEADER_KEY = exports.SERVER_AFFINITY_HEADER_KEY = 'sfdc_dwsid';
28
+
29
+ // commerce-sdk-react namespaces cookies with siteID as suffixes to allow multisite setups.
30
+ // However some cookies are set and used outside of PWA Kit and must not be modified with suffixes.
31
+ const EXCLUDE_COOKIE_SUFFIX = exports.EXCLUDE_COOKIE_SUFFIX = ['dwsid'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/commerce-sdk-react",
3
- "version": "3.0.1",
3
+ "version": "3.1.0-exp-server-affinity.1",
4
4
  "description": "A library that provides react hooks for fetching data from Commerce Cloud",
5
5
  "homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/ecom-react-hooks#readme",
6
6
  "bugs": {
@@ -40,12 +40,12 @@
40
40
  "version": "node ./scripts/version.js"
41
41
  },
42
42
  "dependencies": {
43
- "commerce-sdk-isomorphic": "^3.0.0",
43
+ "commerce-sdk-isomorphic": "^3.1.1",
44
44
  "js-cookie": "^3.0.1",
45
45
  "jwt-decode": "^4.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@salesforce/pwa-kit-dev": "3.7.0",
48
+ "@salesforce/pwa-kit-dev": "3.8.0-dev",
49
49
  "@tanstack/react-query": "^4.28.0",
50
50
  "@testing-library/jest-dom": "^5.16.5",
51
51
  "@testing-library/react": "^14.0.0",
@@ -60,7 +60,7 @@
60
60
  "@types/react-helmet": "~6.1.6",
61
61
  "@types/react-router-dom": "~5.3.3",
62
62
  "cross-env": "^5.2.1",
63
- "internal-lib-build": "3.7.0",
63
+ "internal-lib-build": "3.8.0-dev",
64
64
  "jsonwebtoken": "^9.0.0",
65
65
  "nock": "^13.3.0",
66
66
  "nodemon": "^2.0.22",
@@ -90,5 +90,5 @@
90
90
  "publishConfig": {
91
91
  "directory": "dist"
92
92
  },
93
- "gitHead": "1fef72f07d07392046c245082df8f8c07c14aeb8"
93
+ "gitHead": "5d64e1caeee3e6d075bb574db61de8b48971d2e9"
94
94
  }
package/provider.d.ts CHANGED
@@ -12,11 +12,11 @@ export interface CommerceApiProviderProps extends ApiClientConfigParams {
12
12
  fetchOptions?: ShopperBasketsTypes.FetchOptions;
13
13
  headers?: Record<string, string>;
14
14
  fetchedToken?: string;
15
- OCAPISessionsURL?: string;
16
15
  enablePWAKitPrivateClient?: boolean;
17
16
  clientSecret?: string;
18
17
  silenceWarnings?: boolean;
19
18
  logger?: Logger;
19
+ defaultDnt?: boolean;
20
20
  }
21
21
  /**
22
22
  * @internal
package/provider.js CHANGED
@@ -92,18 +92,40 @@ const CommerceApiProvider = props => {
92
92
  locale,
93
93
  currency,
94
94
  fetchedToken,
95
- OCAPISessionsURL,
96
95
  enablePWAKitPrivateClient,
97
96
  clientSecret,
98
97
  silenceWarnings,
99
- logger
98
+ logger,
99
+ defaultDnt
100
100
  } = props;
101
101
 
102
102
  // Set the logger based on provided configuration, or default to the console object if no logger is provided
103
103
  const configLogger = logger || console;
104
+ const auth = (0, _react.useMemo)(() => {
105
+ return new _auth.default({
106
+ clientId,
107
+ organizationId,
108
+ shortCode,
109
+ siteId,
110
+ proxy,
111
+ redirectURI,
112
+ fetchOptions,
113
+ fetchedToken,
114
+ enablePWAKitPrivateClient,
115
+ clientSecret,
116
+ silenceWarnings,
117
+ logger: configLogger,
118
+ defaultDnt
119
+ });
120
+ }, [clientId, organizationId, shortCode, siteId, proxy, redirectURI, fetchOptions, fetchedToken, enablePWAKitPrivateClient, clientSecret, silenceWarnings, configLogger]);
121
+ const dwsid = auth.get('dwsid');
122
+ const serverAffinityHeader = {};
123
+ if (dwsid) {
124
+ serverAffinityHeader[_constant.SERVER_AFFINITY_HEADER_KEY] = dwsid;
125
+ }
104
126
  const config = {
105
127
  proxy,
106
- headers,
128
+ headers: _objectSpread(_objectSpread({}, headers), serverAffinityHeader),
107
129
  parameters: {
108
130
  clientId,
109
131
  organizationId,
@@ -135,23 +157,6 @@ const CommerceApiProvider = props => {
135
157
  shopperStores: new _commerceSdkIsomorphic.ShopperStores(config)
136
158
  };
137
159
  }, [clientId, organizationId, shortCode, siteId, proxy, fetchOptions, locale, currency, headers === null || headers === void 0 ? void 0 : headers['correlation-id']]);
138
- const auth = (0, _react.useMemo)(() => {
139
- return new _auth.default({
140
- clientId,
141
- organizationId,
142
- shortCode,
143
- siteId,
144
- proxy,
145
- redirectURI,
146
- fetchOptions,
147
- fetchedToken,
148
- OCAPISessionsURL,
149
- enablePWAKitPrivateClient,
150
- clientSecret,
151
- silenceWarnings,
152
- logger: configLogger
153
- });
154
- }, [clientId, organizationId, shortCode, siteId, proxy, redirectURI, fetchOptions, fetchedToken, OCAPISessionsURL, enablePWAKitPrivateClient, clientSecret, silenceWarnings, configLogger]);
155
160
 
156
161
  // Initialize the session
157
162
  (0, _react.useEffect)(() => void auth.ready(), [auth]);
@@ -168,7 +173,8 @@ const CommerceApiProvider = props => {
168
173
  locale,
169
174
  currency,
170
175
  silenceWarnings,
171
- logger: configLogger
176
+ logger: configLogger,
177
+ defaultDnt
172
178
  }
173
179
  }, /*#__PURE__*/_react.default.createElement(CommerceApiContext.Provider, {
174
180
  value: apiClients