@salesforce/commerce-sdk-react 1.0.0-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/.eslintrc.js +10 -0
- package/CHANGELOG.md +35 -0
- package/LICENSE +14 -0
- package/README.md +327 -0
- package/auth/index.d.ts +220 -0
- package/auth/index.js +472 -0
- package/auth/storage.d.ts +48 -0
- package/auth/storage.js +122 -0
- package/components/ShopperExperience/Component/index.d.ts +17 -0
- package/components/ShopperExperience/Component/index.js +49 -0
- package/components/ShopperExperience/Page/index.d.ts +28 -0
- package/components/ShopperExperience/Page/index.js +97 -0
- package/components/ShopperExperience/Region/index.d.ts +41 -0
- package/components/ShopperExperience/Region/index.js +64 -0
- package/components/ShopperExperience/index.d.ts +5 -0
- package/components/ShopperExperience/index.js +49 -0
- package/components/ShopperExperience/prop-types.d.ts +39 -0
- package/components/ShopperExperience/prop-types.js +46 -0
- package/components/ShopperExperience/types.d.ts +8 -0
- package/components/ShopperExperience/types.js +5 -0
- package/components/index.d.ts +2 -0
- package/components/index.js +16 -0
- package/hooks/ShopperBaskets/cache.d.ts +5 -0
- package/hooks/ShopperBaskets/cache.js +351 -0
- package/hooks/ShopperBaskets/index.d.ts +3 -0
- package/hooks/ShopperBaskets/index.js +27 -0
- package/hooks/ShopperBaskets/mutation.d.ts +381 -0
- package/hooks/ShopperBaskets/mutation.js +380 -0
- package/hooks/ShopperBaskets/query.d.ts +55 -0
- package/hooks/ShopperBaskets/query.js +215 -0
- package/hooks/ShopperBaskets/queryKeyHelpers.d.ts +72 -0
- package/hooks/ShopperBaskets/queryKeyHelpers.js +49 -0
- package/hooks/ShopperContexts/cache.d.ts +5 -0
- package/hooks/ShopperContexts/cache.js +45 -0
- package/hooks/ShopperContexts/index.d.ts +3 -0
- package/hooks/ShopperContexts/index.js +27 -0
- package/hooks/ShopperContexts/mutation.d.ts +35 -0
- package/hooks/ShopperContexts/mutation.js +68 -0
- package/hooks/ShopperContexts/query.d.ts +15 -0
- package/hooks/ShopperContexts/query.js +59 -0
- package/hooks/ShopperContexts/queryKeyHelpers.d.ts +30 -0
- package/hooks/ShopperContexts/queryKeyHelpers.js +25 -0
- package/hooks/ShopperCustomers/cache.d.ts +5 -0
- package/hooks/ShopperCustomers/cache.js +387 -0
- package/hooks/ShopperCustomers/index.d.ts +3 -0
- package/hooks/ShopperCustomers/index.js +27 -0
- package/hooks/ShopperCustomers/mutation.d.ts +163 -0
- package/hooks/ShopperCustomers/mutation.js +203 -0
- package/hooks/ShopperCustomers/query.d.ts +115 -0
- package/hooks/ShopperCustomers/query.js +489 -0
- package/hooks/ShopperCustomers/queryKeyHelpers.d.ts +142 -0
- package/hooks/ShopperCustomers/queryKeyHelpers.js +91 -0
- package/hooks/ShopperExperience/index.d.ts +2 -0
- package/hooks/ShopperExperience/index.js +16 -0
- package/hooks/ShopperExperience/query.d.ts +31 -0
- package/hooks/ShopperExperience/query.js +104 -0
- package/hooks/ShopperExperience/queryKeyHelpers.d.ts +38 -0
- package/hooks/ShopperExperience/queryKeyHelpers.js +31 -0
- package/hooks/ShopperGiftCertificates/index.d.ts +2 -0
- package/hooks/ShopperGiftCertificates/index.js +16 -0
- package/hooks/ShopperGiftCertificates/query.d.ts +15 -0
- package/hooks/ShopperGiftCertificates/query.js +70 -0
- package/hooks/ShopperGiftCertificates/queryKeyHelpers.d.ts +29 -0
- package/hooks/ShopperGiftCertificates/queryKeyHelpers.js +25 -0
- package/hooks/ShopperLogin/cache.d.ts +3 -0
- package/hooks/ShopperLogin/cache.js +33 -0
- package/hooks/ShopperLogin/index.d.ts +3 -0
- package/hooks/ShopperLogin/index.js +27 -0
- package/hooks/ShopperLogin/mutation.d.ts +119 -0
- package/hooks/ShopperLogin/mutation.js +138 -0
- package/hooks/ShopperLogin/query.d.ts +45 -0
- package/hooks/ShopperLogin/query.js +176 -0
- package/hooks/ShopperLogin/queryKeyHelpers.d.ts +53 -0
- package/hooks/ShopperLogin/queryKeyHelpers.js +43 -0
- package/hooks/ShopperOrders/cache.d.ts +5 -0
- package/hooks/ShopperOrders/cache.js +54 -0
- package/hooks/ShopperOrders/index.d.ts +3 -0
- package/hooks/ShopperOrders/index.js +27 -0
- package/hooks/ShopperOrders/mutation.d.ts +54 -0
- package/hooks/ShopperOrders/mutation.js +83 -0
- package/hooks/ShopperOrders/query.d.ts +37 -0
- package/hooks/ShopperOrders/query.js +139 -0
- package/hooks/ShopperOrders/queryKeyHelpers.d.ts +50 -0
- package/hooks/ShopperOrders/queryKeyHelpers.js +37 -0
- package/hooks/ShopperProducts/index.d.ts +2 -0
- package/hooks/ShopperProducts/index.js +16 -0
- package/hooks/ShopperProducts/query.d.ts +47 -0
- package/hooks/ShopperProducts/query.js +178 -0
- package/hooks/ShopperProducts/queryKeyHelpers.d.ts +55 -0
- package/hooks/ShopperProducts/queryKeyHelpers.js +43 -0
- package/hooks/ShopperPromotions/index.d.ts +2 -0
- package/hooks/ShopperPromotions/index.js +16 -0
- package/hooks/ShopperPromotions/query.d.ts +29 -0
- package/hooks/ShopperPromotions/query.js +102 -0
- package/hooks/ShopperPromotions/queryKeyHelpers.d.ts +38 -0
- package/hooks/ShopperPromotions/queryKeyHelpers.js +31 -0
- package/hooks/ShopperSearch/index.d.ts +2 -0
- package/hooks/ShopperSearch/index.js +16 -0
- package/hooks/ShopperSearch/query.d.ts +26 -0
- package/hooks/ShopperSearch/query.js +99 -0
- package/hooks/ShopperSearch/queryKeyHelpers.d.ts +37 -0
- package/hooks/ShopperSearch/queryKeyHelpers.js +31 -0
- package/hooks/index.d.ts +18 -0
- package/hooks/index.js +188 -0
- package/hooks/types.d.ts +128 -0
- package/hooks/types.js +5 -0
- package/hooks/useAccessToken.d.ts +11 -0
- package/hooks/useAccessToken.js +43 -0
- package/hooks/useAuthContext.d.ts +9 -0
- package/hooks/useAuthContext.js +30 -0
- package/hooks/useAuthHelper.d.ts +23 -0
- package/hooks/useAuthHelper.js +66 -0
- package/hooks/useAuthorizationHeader.d.ts +9 -0
- package/hooks/useAuthorizationHeader.js +45 -0
- package/hooks/useCommerceApi.d.ts +9 -0
- package/hooks/useCommerceApi.js +26 -0
- package/hooks/useConfig.d.ts +7 -0
- package/hooks/useConfig.js +24 -0
- package/hooks/useCustomerId.d.ts +7 -0
- package/hooks/useCustomerId.js +38 -0
- package/hooks/useCustomerType.d.ts +21 -0
- package/hooks/useCustomerType.js +43 -0
- package/hooks/useEncUserId.d.ts +9 -0
- package/hooks/useEncUserId.js +36 -0
- package/hooks/useLocalStorage.d.ts +8 -0
- package/hooks/useLocalStorage.js +40 -0
- package/hooks/useMutation.d.ts +12 -0
- package/hooks/useMutation.js +38 -0
- package/hooks/useQuery.d.ts +15 -0
- package/hooks/useQuery.js +57 -0
- package/hooks/useUsid.d.ts +7 -0
- package/hooks/useUsid.js +34 -0
- package/hooks/utils.d.ts +32 -0
- package/hooks/utils.js +125 -0
- package/index.d.ts +5 -0
- package/index.js +40 -0
- package/package.json +88 -0
- package/provider.d.ts +36 -0
- package/provider.js +124 -0
- package/scripts/build-and-release-docs.js +48 -0
- package/scripts/version.js +22 -0
- package/utils.d.ts +5 -0
- package/utils.js +18 -0
package/auth/index.js
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _commerceSdkIsomorphic = require("commerce-sdk-isomorphic");
|
|
8
|
+
var _jwtDecode = _interopRequireDefault(require("jwt-decode"));
|
|
9
|
+
var _storage = require("./storage");
|
|
10
|
+
var _utils = require("../utils");
|
|
11
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
13
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
14
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
15
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
16
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
17
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
18
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } /*
|
|
19
|
+
* Copyright (c) 2023, Salesforce, Inc.
|
|
20
|
+
* All rights reserved.
|
|
21
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
22
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* The extended field is not from api response, we manually store the auth type,
|
|
26
|
+
* so we don't need to make another API call when we already have the data.
|
|
27
|
+
* Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
|
|
28
|
+
* and it's not easy to grab this info in user land, so we add it into the Auth object, and expose it via a hook
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** A shopper could be guest or registered, so we store the refresh tokens individually. */
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A map of the data that this auth module stores. This maps the name of the property to
|
|
35
|
+
* the storage type and the key when stored in that storage. You can also pass in a "callback"
|
|
36
|
+
* function to do extra operation after a property is set.
|
|
37
|
+
*/
|
|
38
|
+
const DATA_MAP = {
|
|
39
|
+
access_token: {
|
|
40
|
+
storageType: 'local',
|
|
41
|
+
key: 'access_token'
|
|
42
|
+
},
|
|
43
|
+
customer_id: {
|
|
44
|
+
storageType: 'local',
|
|
45
|
+
key: 'customer_id'
|
|
46
|
+
},
|
|
47
|
+
usid: {
|
|
48
|
+
storageType: 'cookie',
|
|
49
|
+
key: 'usid'
|
|
50
|
+
},
|
|
51
|
+
enc_user_id: {
|
|
52
|
+
storageType: 'local',
|
|
53
|
+
key: 'enc_user_id'
|
|
54
|
+
},
|
|
55
|
+
expires_in: {
|
|
56
|
+
storageType: 'local',
|
|
57
|
+
key: 'expires_in'
|
|
58
|
+
},
|
|
59
|
+
id_token: {
|
|
60
|
+
storageType: 'local',
|
|
61
|
+
key: 'id_token'
|
|
62
|
+
},
|
|
63
|
+
idp_access_token: {
|
|
64
|
+
storageType: 'local',
|
|
65
|
+
key: 'idp_access_token'
|
|
66
|
+
},
|
|
67
|
+
token_type: {
|
|
68
|
+
storageType: 'local',
|
|
69
|
+
key: 'token_type'
|
|
70
|
+
},
|
|
71
|
+
refresh_token_guest: {
|
|
72
|
+
storageType: 'cookie',
|
|
73
|
+
key: 'cc-nx-g',
|
|
74
|
+
callback: store => {
|
|
75
|
+
store.delete('cc-nx');
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
refresh_token_registered: {
|
|
79
|
+
storageType: 'cookie',
|
|
80
|
+
key: 'cc-nx',
|
|
81
|
+
callback: store => {
|
|
82
|
+
store.delete('cc-nx-g');
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
customer_type: {
|
|
86
|
+
storageType: 'local',
|
|
87
|
+
key: 'customer_type'
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* This class is used to handle shopper authentication.
|
|
93
|
+
* It is responsible for initializing shopper session, manage access
|
|
94
|
+
* and refresh tokens on server/browser environments. As well as providing
|
|
95
|
+
* a mechanism to queue network calls before having a valid access token.
|
|
96
|
+
*
|
|
97
|
+
* @Internal
|
|
98
|
+
*/
|
|
99
|
+
class Auth {
|
|
100
|
+
REFRESH_TOKEN_EXPIRATION_DAYS = 90;
|
|
101
|
+
constructor(config) {
|
|
102
|
+
this.client = new _commerceSdkIsomorphic.ShopperLogin({
|
|
103
|
+
proxy: config.proxy,
|
|
104
|
+
parameters: {
|
|
105
|
+
clientId: config.clientId,
|
|
106
|
+
organizationId: config.organizationId,
|
|
107
|
+
shortCode: config.shortCode,
|
|
108
|
+
siteId: config.siteId
|
|
109
|
+
},
|
|
110
|
+
throwOnBadResponse: true,
|
|
111
|
+
fetchOptions: config.fetchOptions
|
|
112
|
+
});
|
|
113
|
+
this.shopperCustomersClient = new _commerceSdkIsomorphic.ShopperCustomers({
|
|
114
|
+
proxy: config.proxy,
|
|
115
|
+
parameters: {
|
|
116
|
+
clientId: config.clientId,
|
|
117
|
+
organizationId: config.organizationId,
|
|
118
|
+
shortCode: config.shortCode,
|
|
119
|
+
siteId: config.siteId
|
|
120
|
+
},
|
|
121
|
+
throwOnBadResponse: true,
|
|
122
|
+
fetchOptions: config.fetchOptions
|
|
123
|
+
});
|
|
124
|
+
const storageOptions = {
|
|
125
|
+
keySuffix: config.siteId
|
|
126
|
+
};
|
|
127
|
+
const serverStorageOptions = {
|
|
128
|
+
keySuffix: config.siteId,
|
|
129
|
+
sharedContext: true // This allows use to reused guest authentication tokens accross lambda runs.
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.stores = (0, _utils.onClient)() ? {
|
|
133
|
+
cookie: new _storage.CookieStorage(storageOptions),
|
|
134
|
+
local: new _storage.LocalStorage(storageOptions),
|
|
135
|
+
memory: new _storage.MemoryStorage(storageOptions)
|
|
136
|
+
} : {
|
|
137
|
+
// Always use MemoryStorage on the server.
|
|
138
|
+
cookie: new _storage.MemoryStorage(serverStorageOptions),
|
|
139
|
+
local: new _storage.MemoryStorage(serverStorageOptions),
|
|
140
|
+
memory: new _storage.MemoryStorage(serverStorageOptions)
|
|
141
|
+
};
|
|
142
|
+
this.redirectURI = config.redirectURI;
|
|
143
|
+
this.fetchedToken = config.fetchedToken || '';
|
|
144
|
+
this.OCAPISessionsURL = config.OCAPISessionsURL || '';
|
|
145
|
+
}
|
|
146
|
+
get(name) {
|
|
147
|
+
const {
|
|
148
|
+
key,
|
|
149
|
+
storageType
|
|
150
|
+
} = DATA_MAP[name];
|
|
151
|
+
const storage = this.stores[storageType];
|
|
152
|
+
return storage.get(key);
|
|
153
|
+
}
|
|
154
|
+
set(name, value, options) {
|
|
155
|
+
var _DATA_MAP$name$callba, _DATA_MAP$name;
|
|
156
|
+
const {
|
|
157
|
+
key,
|
|
158
|
+
storageType
|
|
159
|
+
} = DATA_MAP[name];
|
|
160
|
+
const storage = this.stores[storageType];
|
|
161
|
+
storage.set(key, value, options);
|
|
162
|
+
(_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);
|
|
163
|
+
}
|
|
164
|
+
clearStorage() {
|
|
165
|
+
// Type assertion because Object.keys is silly and limited :(
|
|
166
|
+
const keys = Object.keys(DATA_MAP);
|
|
167
|
+
keys.forEach(keyName => {
|
|
168
|
+
const {
|
|
169
|
+
key,
|
|
170
|
+
storageType
|
|
171
|
+
} = DATA_MAP[keyName];
|
|
172
|
+
const store = this.stores[storageType];
|
|
173
|
+
store.delete(key);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Every method in this class that returns a `TokenResponse` constructs it via this getter.
|
|
179
|
+
*/
|
|
180
|
+
get data() {
|
|
181
|
+
return {
|
|
182
|
+
access_token: this.get('access_token'),
|
|
183
|
+
customer_id: this.get('customer_id'),
|
|
184
|
+
enc_user_id: this.get('enc_user_id'),
|
|
185
|
+
expires_in: parseInt(this.get('expires_in')),
|
|
186
|
+
id_token: this.get('id_token'),
|
|
187
|
+
idp_access_token: this.get('idp_access_token'),
|
|
188
|
+
refresh_token: this.get('refresh_token_registered') || this.get('refresh_token_guest'),
|
|
189
|
+
token_type: this.get('token_type'),
|
|
190
|
+
usid: this.get('usid'),
|
|
191
|
+
customer_type: this.get('customer_type')
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Used to validate JWT token expiration.
|
|
197
|
+
*/
|
|
198
|
+
isTokenExpired(token) {
|
|
199
|
+
const {
|
|
200
|
+
exp,
|
|
201
|
+
iat
|
|
202
|
+
} = (0, _jwtDecode.default)(token.replace('Bearer ', ''));
|
|
203
|
+
const validTimeSeconds = exp - iat - 60;
|
|
204
|
+
const tokenAgeSeconds = Date.now() / 1000 - iat;
|
|
205
|
+
return validTimeSeconds <= tokenAgeSeconds;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* This method stores the TokenResponse object retrived from SLAS, and
|
|
210
|
+
* store the data in storage.
|
|
211
|
+
*/
|
|
212
|
+
handleTokenResponse(res, isGuest) {
|
|
213
|
+
this.set('access_token', res.access_token);
|
|
214
|
+
this.set('customer_id', res.customer_id);
|
|
215
|
+
this.set('enc_user_id', res.enc_user_id);
|
|
216
|
+
this.set('expires_in', `${res.expires_in}`);
|
|
217
|
+
this.set('id_token', res.id_token);
|
|
218
|
+
this.set('idp_access_token', res.idp_access_token);
|
|
219
|
+
this.set('token_type', res.token_type);
|
|
220
|
+
this.set('usid', res.usid);
|
|
221
|
+
this.set('customer_type', isGuest ? 'guest' : 'registered');
|
|
222
|
+
const refreshTokenKey = isGuest ? 'refresh_token_guest' : 'refresh_token_registered';
|
|
223
|
+
this.set(refreshTokenKey, res.refresh_token, {
|
|
224
|
+
expires: this.REFRESH_TOKEN_EXPIRATION_DAYS
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* This method queues the requests and handles the SLAS token response.
|
|
230
|
+
*
|
|
231
|
+
* It returns the queue.
|
|
232
|
+
*
|
|
233
|
+
* @Internal
|
|
234
|
+
*/
|
|
235
|
+
queueRequest(fn, isGuest) {
|
|
236
|
+
var _this = this;
|
|
237
|
+
return _asyncToGenerator(function* () {
|
|
238
|
+
const queue = _this.pendingToken ?? Promise.resolve();
|
|
239
|
+
_this.pendingToken = queue.then( /*#__PURE__*/_asyncToGenerator(function* () {
|
|
240
|
+
const token = yield fn();
|
|
241
|
+
_this.handleTokenResponse(token, isGuest);
|
|
242
|
+
if ((0, _utils.onClient)() && _this.OCAPISessionsURL) {
|
|
243
|
+
void _this.createOCAPISession();
|
|
244
|
+
}
|
|
245
|
+
// Q: Why don't we just return token? Why re-construct the same object again?
|
|
246
|
+
// A: because a user could open multiple tabs and the data in memory could be out-dated
|
|
247
|
+
// We must always grab the data from the storage (cookie/localstorage) directly
|
|
248
|
+
return _this.data;
|
|
249
|
+
})).finally(() => {
|
|
250
|
+
_this.pendingToken = undefined;
|
|
251
|
+
});
|
|
252
|
+
return _this.pendingToken;
|
|
253
|
+
})();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* The ready function returns a promise that resolves with valid ShopperLogin
|
|
258
|
+
* token response.
|
|
259
|
+
*
|
|
260
|
+
* When this method is called for the very first time, it initializes the session
|
|
261
|
+
* by following the public client auth flow to get access token for the user.
|
|
262
|
+
* The flow:
|
|
263
|
+
* 1. If we have valid access token - use it
|
|
264
|
+
* 2. If we have valid refresh token - refresh token flow
|
|
265
|
+
* 3. PKCE flow
|
|
266
|
+
*/
|
|
267
|
+
ready() {
|
|
268
|
+
var _this2 = this;
|
|
269
|
+
return _asyncToGenerator(function* () {
|
|
270
|
+
if (_this2.fetchedToken && _this2.fetchedToken !== '') {
|
|
271
|
+
const {
|
|
272
|
+
isGuest,
|
|
273
|
+
customerId,
|
|
274
|
+
usid
|
|
275
|
+
} = _this2.parseSlasJWT(_this2.fetchedToken);
|
|
276
|
+
_this2.set('access_token', _this2.fetchedToken);
|
|
277
|
+
_this2.set('customer_id', customerId);
|
|
278
|
+
_this2.set('usid', usid);
|
|
279
|
+
_this2.set('customer_type', isGuest ? 'guest' : 'registered');
|
|
280
|
+
return _this2.data;
|
|
281
|
+
}
|
|
282
|
+
if (_this2.pendingToken) {
|
|
283
|
+
return _this2.pendingToken;
|
|
284
|
+
}
|
|
285
|
+
const accessToken = _this2.get('access_token');
|
|
286
|
+
if (accessToken && !_this2.isTokenExpired(accessToken)) {
|
|
287
|
+
return _this2.data;
|
|
288
|
+
}
|
|
289
|
+
const refreshTokenRegistered = _this2.get('refresh_token_registered');
|
|
290
|
+
const refreshTokenGuest = _this2.get('refresh_token_guest');
|
|
291
|
+
const refreshToken = refreshTokenRegistered || refreshTokenGuest;
|
|
292
|
+
if (refreshToken) {
|
|
293
|
+
try {
|
|
294
|
+
return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, {
|
|
295
|
+
refreshToken
|
|
296
|
+
}), !!refreshTokenGuest);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
// If the refresh token is invalid, we need to re-login the user
|
|
299
|
+
if (error instanceof Error && 'response' in error) {
|
|
300
|
+
// commerce-sdk-isomorphic throws a `ResponseError`, but doesn't export the class.
|
|
301
|
+
// We can't use `instanceof`, so instead we just check for the `response` property
|
|
302
|
+
// and assume it is a fetch Response.
|
|
303
|
+
const json = yield error['response'].json();
|
|
304
|
+
if (json.message === 'invalid refresh_token') {
|
|
305
|
+
// clean up storage and restart the login flow
|
|
306
|
+
_this2.clearStorage();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.loginGuestUser(_this2.client, {
|
|
312
|
+
redirectURI: _this2.redirectURI
|
|
313
|
+
}), true);
|
|
314
|
+
})();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Creates a function that only executes after a session is initialized.
|
|
319
|
+
* @param fn Function that needs to wait until the session is initialized.
|
|
320
|
+
* @returns Wrapped function
|
|
321
|
+
*/
|
|
322
|
+
whenReady(fn) {
|
|
323
|
+
var _this3 = this;
|
|
324
|
+
return /*#__PURE__*/_asyncToGenerator(function* (...args) {
|
|
325
|
+
yield _this3.ready();
|
|
326
|
+
return yield fn(...args);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* A wrapper method for commerce-sdk-isomorphic helper: loginGuestUser.
|
|
332
|
+
*
|
|
333
|
+
*/
|
|
334
|
+
loginGuestUser() {
|
|
335
|
+
var _this4 = this;
|
|
336
|
+
return _asyncToGenerator(function* () {
|
|
337
|
+
const redirectURI = _this4.redirectURI;
|
|
338
|
+
const usid = _this4.get('usid');
|
|
339
|
+
const isGuest = true;
|
|
340
|
+
return _this4.queueRequest(() => _commerceSdkIsomorphic.helpers.loginGuestUser(_this4.client, _objectSpread({
|
|
341
|
+
redirectURI
|
|
342
|
+
}, usid && {
|
|
343
|
+
usid
|
|
344
|
+
})), isGuest);
|
|
345
|
+
})();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* This is a wrapper method for ShopperCustomer API registerCustomer endpoint.
|
|
350
|
+
*
|
|
351
|
+
*/
|
|
352
|
+
register(body) {
|
|
353
|
+
var _this5 = this;
|
|
354
|
+
return _asyncToGenerator(function* () {
|
|
355
|
+
const {
|
|
356
|
+
customer: {
|
|
357
|
+
email
|
|
358
|
+
},
|
|
359
|
+
password
|
|
360
|
+
} = body;
|
|
361
|
+
|
|
362
|
+
// email is optional field from isomorphic library
|
|
363
|
+
// type CustomerRegistration
|
|
364
|
+
// here we had to guard it to avoid ts error
|
|
365
|
+
if (!email) {
|
|
366
|
+
throw new Error('Customer registration is missing email address.');
|
|
367
|
+
}
|
|
368
|
+
const res = yield _this5.shopperCustomersClient.registerCustomer({
|
|
369
|
+
headers: {
|
|
370
|
+
authorization: `Bearer ${_this5.get('access_token')}`
|
|
371
|
+
},
|
|
372
|
+
body
|
|
373
|
+
});
|
|
374
|
+
yield _this5.loginRegisteredUserB2C({
|
|
375
|
+
username: email,
|
|
376
|
+
password
|
|
377
|
+
});
|
|
378
|
+
return res;
|
|
379
|
+
})();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* A wrapper method for commerce-sdk-isomorphic helper: loginRegisteredUserB2C.
|
|
384
|
+
*
|
|
385
|
+
*/
|
|
386
|
+
loginRegisteredUserB2C(credentials) {
|
|
387
|
+
var _this6 = this;
|
|
388
|
+
return _asyncToGenerator(function* () {
|
|
389
|
+
const redirectURI = _this6.redirectURI;
|
|
390
|
+
const usid = _this6.get('usid');
|
|
391
|
+
const isGuest = false;
|
|
392
|
+
const token = yield _commerceSdkIsomorphic.helpers.loginRegisteredUserB2C(_this6.client, credentials, _objectSpread({
|
|
393
|
+
redirectURI
|
|
394
|
+
}, usid && {
|
|
395
|
+
usid
|
|
396
|
+
}));
|
|
397
|
+
_this6.handleTokenResponse(token, isGuest);
|
|
398
|
+
if ((0, _utils.onClient)() && _this6.OCAPISessionsURL) {
|
|
399
|
+
void _this6.createOCAPISession();
|
|
400
|
+
}
|
|
401
|
+
return token;
|
|
402
|
+
})();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* A wrapper method for commerce-sdk-isomorphic helper: logout.
|
|
407
|
+
*
|
|
408
|
+
*/
|
|
409
|
+
logout() {
|
|
410
|
+
var _this7 = this;
|
|
411
|
+
return _asyncToGenerator(function* () {
|
|
412
|
+
// Not awaiting on purpose because there isn't much we can do if this fails.
|
|
413
|
+
void _commerceSdkIsomorphic.helpers.logout(_this7.client, {
|
|
414
|
+
accessToken: _this7.get('access_token'),
|
|
415
|
+
refreshToken: _this7.get('refresh_token_registered')
|
|
416
|
+
});
|
|
417
|
+
_this7.clearStorage();
|
|
418
|
+
return _this7.loginGuestUser();
|
|
419
|
+
})();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Make a post request to the OCAPI /session endpoint to bridge the session.
|
|
424
|
+
*
|
|
425
|
+
* The HTTP response contains a set-cookie header which sets the dwsid session cookie.
|
|
426
|
+
* This cookie is used on SFRA, and it allows shoppers to navigate between SFRA and
|
|
427
|
+
* this PWA site seamlessly; this is often used to enable hybrid deployment.
|
|
428
|
+
*
|
|
429
|
+
* (Note: this method is client side only, b/c MRT doesn't support set-cookie header right now)
|
|
430
|
+
*
|
|
431
|
+
* @returns {Promise}
|
|
432
|
+
*/
|
|
433
|
+
createOCAPISession() {
|
|
434
|
+
return fetch(this.OCAPISessionsURL, {
|
|
435
|
+
method: 'POST',
|
|
436
|
+
headers: {
|
|
437
|
+
Authorization: 'Bearer ' + this.get('access_token')
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Decode SLAS JWT and extract information such as customer id, usid, etc.
|
|
444
|
+
*
|
|
445
|
+
*/
|
|
446
|
+
parseSlasJWT(jwt) {
|
|
447
|
+
const payload = (0, _jwtDecode.default)(jwt);
|
|
448
|
+
const {
|
|
449
|
+
sub,
|
|
450
|
+
isb
|
|
451
|
+
} = payload;
|
|
452
|
+
if (!sub || !isb) {
|
|
453
|
+
throw new Error('Unable to parse access token payload: missing sub and isb.');
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ISB format
|
|
457
|
+
// 'uido:ecom::upn:Guest||xxxEmailxxx::uidn:FirstName LastName::gcid:xxxGuestCustomerIdxxx::rcid:xxxRegisteredCustomerIdxxx::chid:xxxSiteIdxxx',
|
|
458
|
+
const isbParts = isb.split('::');
|
|
459
|
+
const isGuest = isbParts[1] === 'upn:Guest';
|
|
460
|
+
const customerId = isGuest ? isbParts[3].replace('gcid:', '') : isbParts[4].replace('rcid:', '');
|
|
461
|
+
// SUB format
|
|
462
|
+
// cc-slas::zzrf_001::scid:c9c45bfd-0ed3-4aa2-xxxx-40f88962b836::usid:b4865233-de92-4039-xxxx-aa2dfc8c1ea5
|
|
463
|
+
const usid = sub.split('::')[3].replace('usid:', '');
|
|
464
|
+
return {
|
|
465
|
+
isGuest,
|
|
466
|
+
customerId,
|
|
467
|
+
usid
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
var _default = Auth;
|
|
472
|
+
exports.default = _default;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import Cookies from 'js-cookie';
|
|
2
|
+
export declare type StorageType = 'cookie' | 'local' | 'memory';
|
|
3
|
+
export interface BaseStorageOptions {
|
|
4
|
+
keySuffix?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface MemoryStorageOptions extends BaseStorageOptions {
|
|
7
|
+
sharedContext?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare abstract class BaseStorage {
|
|
10
|
+
protected options: BaseStorageOptions;
|
|
11
|
+
constructor(options?: BaseStorageOptions);
|
|
12
|
+
protected getSuffixedKey(key: string): string;
|
|
13
|
+
abstract set(key: string, value: string, options?: unknown): void;
|
|
14
|
+
abstract get(key: string): string;
|
|
15
|
+
abstract delete(key: string): void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A normalized implementation for Cookie store. It implements the BaseStorage interface
|
|
19
|
+
* which allows developers to easily switch between Cookie, LocalStorage, Memory store
|
|
20
|
+
* or a customized storage. This class is mainly used for commerce-sdk-react library
|
|
21
|
+
* to store authentication tokens.
|
|
22
|
+
*/
|
|
23
|
+
export declare class CookieStorage extends BaseStorage {
|
|
24
|
+
constructor(options?: BaseStorageOptions);
|
|
25
|
+
set(key: string, value: string, options?: Cookies.CookieAttributes): void;
|
|
26
|
+
get(key: string): string;
|
|
27
|
+
delete(key: string): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A normalized implementation for LocalStorage. It implements the BaseStorage interface
|
|
31
|
+
* which allows developers to easily switch between Cookie, LocalStorage, Memory store
|
|
32
|
+
* or a customized storage. This class is mainly used for commerce-sdk-react library
|
|
33
|
+
* to store authentication tokens.
|
|
34
|
+
*/
|
|
35
|
+
export declare class LocalStorage extends BaseStorage {
|
|
36
|
+
constructor(options?: BaseStorageOptions);
|
|
37
|
+
set(key: string, value: string): void;
|
|
38
|
+
get(key: string): string;
|
|
39
|
+
delete(key: string): void;
|
|
40
|
+
}
|
|
41
|
+
export declare class MemoryStorage extends BaseStorage {
|
|
42
|
+
private map;
|
|
43
|
+
constructor(options?: MemoryStorageOptions);
|
|
44
|
+
set(key: string, value: string): void;
|
|
45
|
+
get(key: string): string;
|
|
46
|
+
delete(key: string): void;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=storage.d.ts.map
|
package/auth/storage.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MemoryStorage = exports.LocalStorage = exports.CookieStorage = exports.BaseStorage = void 0;
|
|
7
|
+
var _jsCookie = _interopRequireDefault(require("js-cookie"));
|
|
8
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
10
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
11
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
12
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
13
|
+
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } /*
|
|
14
|
+
* Copyright (c) 2022, Salesforce, Inc.
|
|
15
|
+
* All rights reserved.
|
|
16
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
17
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
18
|
+
*/
|
|
19
|
+
class BaseStorage {
|
|
20
|
+
options = {};
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = {
|
|
23
|
+
keySuffix: (options === null || options === void 0 ? void 0 : options.keySuffix) ?? ''
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
getSuffixedKey(key) {
|
|
27
|
+
return this.options.keySuffix ? `${key}_${this.options.keySuffix}` : key;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A normalized implementation for Cookie store. It implements the BaseStorage interface
|
|
33
|
+
* which allows developers to easily switch between Cookie, LocalStorage, Memory store
|
|
34
|
+
* or a customized storage. This class is mainly used for commerce-sdk-react library
|
|
35
|
+
* to store authentication tokens.
|
|
36
|
+
*/
|
|
37
|
+
exports.BaseStorage = BaseStorage;
|
|
38
|
+
class CookieStorage extends BaseStorage {
|
|
39
|
+
constructor(options) {
|
|
40
|
+
super(options);
|
|
41
|
+
if (typeof document === 'undefined') {
|
|
42
|
+
throw new Error('CookieStorage is not avaliable on the current environment.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
set(key, value, options) {
|
|
46
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
47
|
+
_jsCookie.default.set(suffixedKey, value, _objectSpread(_objectSpread({}, options), {}, {
|
|
48
|
+
secure: true
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
get(key) {
|
|
52
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
53
|
+
return _jsCookie.default.get(suffixedKey) || '';
|
|
54
|
+
}
|
|
55
|
+
delete(key) {
|
|
56
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
57
|
+
_jsCookie.default.remove(suffixedKey);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A normalized implementation for LocalStorage. It implements the BaseStorage interface
|
|
63
|
+
* which allows developers to easily switch between Cookie, LocalStorage, Memory store
|
|
64
|
+
* or a customized storage. This class is mainly used for commerce-sdk-react library
|
|
65
|
+
* to store authentication tokens.
|
|
66
|
+
*/
|
|
67
|
+
exports.CookieStorage = CookieStorage;
|
|
68
|
+
class LocalStorage extends BaseStorage {
|
|
69
|
+
constructor(options) {
|
|
70
|
+
super(options);
|
|
71
|
+
if (typeof window === 'undefined') {
|
|
72
|
+
throw new Error('LocalStorage is not avaliable on the current environment.');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
set(key, value) {
|
|
76
|
+
const oldValue = this.get(key);
|
|
77
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
78
|
+
window.localStorage.setItem(suffixedKey, value);
|
|
79
|
+
const event = new StorageEvent('storage', {
|
|
80
|
+
key: suffixedKey,
|
|
81
|
+
oldValue: oldValue,
|
|
82
|
+
newValue: value
|
|
83
|
+
});
|
|
84
|
+
window.dispatchEvent(event);
|
|
85
|
+
}
|
|
86
|
+
get(key) {
|
|
87
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
88
|
+
return window.localStorage.getItem(suffixedKey) || '';
|
|
89
|
+
}
|
|
90
|
+
delete(key) {
|
|
91
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
92
|
+
const oldValue = this.get(suffixedKey);
|
|
93
|
+
window.localStorage.removeItem(suffixedKey);
|
|
94
|
+
const event = new StorageEvent('storage', {
|
|
95
|
+
key: suffixedKey,
|
|
96
|
+
oldValue: oldValue,
|
|
97
|
+
newValue: null
|
|
98
|
+
});
|
|
99
|
+
window.dispatchEvent(event);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.LocalStorage = LocalStorage;
|
|
103
|
+
const globalMap = new Map();
|
|
104
|
+
class MemoryStorage extends BaseStorage {
|
|
105
|
+
constructor(options) {
|
|
106
|
+
super(options);
|
|
107
|
+
this.map = options !== null && options !== void 0 && options.sharedContext ? globalMap : new Map();
|
|
108
|
+
}
|
|
109
|
+
set(key, value) {
|
|
110
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
111
|
+
this.map.set(suffixedKey, value);
|
|
112
|
+
}
|
|
113
|
+
get(key) {
|
|
114
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
115
|
+
return this.map.get(suffixedKey) || '';
|
|
116
|
+
}
|
|
117
|
+
delete(key) {
|
|
118
|
+
const suffixedKey = this.getSuffixedKey(key);
|
|
119
|
+
this.map.delete(suffixedKey);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
exports.MemoryStorage = MemoryStorage;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Component as ComponentType } from '../types';
|
|
2
|
+
declare type ComponentProps = {
|
|
3
|
+
component: ComponentType;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* This component will render a page designer page given its serialized data object.
|
|
7
|
+
*
|
|
8
|
+
* @param {PageProps} props
|
|
9
|
+
* @param {Component} props.component - The page designer component data representation.
|
|
10
|
+
* @returns {React.ReactElement} - Experience component.
|
|
11
|
+
*/
|
|
12
|
+
export declare const Component: {
|
|
13
|
+
({ component }: ComponentProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
displayName: string;
|
|
15
|
+
};
|
|
16
|
+
export default Component;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|