@salesforce/commerce-sdk-react 3.2.0-preview.3 → 3.2.0-preview.4
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 +13 -9
- package/README.md +13 -62
- package/auth/index.d.ts +57 -8
- package/auth/index.js +249 -36
- 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/hooks/useAuthHelper.d.ts +8 -0
- package/hooks/useAuthHelper.js +8 -0
- package/hooks/useAuthorizationHeader.js +1 -1
- package/hooks/useCustomerType.d.ts +1 -0
- package/hooks/useCustomerType.js +9 -1
- package/hooks/useDNT.d.ts +15 -5
- package/hooks/useDNT.js +24 -9
- package/hooks/useMutation.js +1 -1
- package/hooks/useQuery.js +1 -1
- package/hooks/useTrustedAgent.js +2 -2
- package/package.json +7 -7
- package/provider.d.ts +1 -0
- package/provider.js +4 -1
- package/utils.d.ts +25 -0
- package/utils.js +33 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
##
|
|
2
|
-
## v3.
|
|
3
|
-
## v3.
|
|
4
|
-
## v3.
|
|
5
|
-
## v3.
|
|
6
|
-
##
|
|
7
|
-
## v3.
|
|
8
|
-
## v3.
|
|
1
|
+
## v3.2.0-preview.4 (Feb 14, 2025)
|
|
2
|
+
## v3.2.0-preview.3 (Feb 13, 2025)
|
|
3
|
+
## v3.2.0-preview.2 (Feb 13, 2025)
|
|
4
|
+
## v3.9.0-preview.3 (Feb 13, 2025)
|
|
5
|
+
## v3.2.0-preview.2 (Feb 13, 2025)
|
|
6
|
+
## v3.2.0-preview.1 (Feb 13, 2025)
|
|
7
|
+
## v3.9.0-preview.2 (Feb 13, 2025)
|
|
8
|
+
## v3.2.0-preview.1 (Feb 12, 2025)
|
|
9
|
+
## v3.2.0-preview.0 (Feb 03, 2025)
|
|
9
10
|
## v3.2.0-dev (Oct 29, 2024)
|
|
10
11
|
- Allow cookies for ShopperLogin API [#2190](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2190
|
|
11
12
|
- Fix refresh token TTL warning from firing when override is not provided [#2114](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2114)
|
|
12
|
-
|
|
13
|
+
- Readme updates for private clients [#2212](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2212)
|
|
13
14
|
- Update CacheUpdateMatrix for mergeBasket mutation [#2138](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2092)
|
|
14
15
|
- Clear auth state if session has been invalidated by a password change [#2092](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2092)
|
|
16
|
+
- DNT interface improvement [#2203](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2203)
|
|
17
|
+
- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
|
|
18
|
+
- Add `authorizeIDP`, `loginIDPUser`, `authorizePasswordless`, `getPasswordLessAccessToken`, `getPasswordResetToken`, and `resetPassword` wrapper functions to support Social Login, Passwordless Login, and Password Reset [#2079] (https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2079)
|
|
15
19
|
|
|
16
20
|
## v3.1.0 (Oct 28, 2024)
|
|
17
21
|
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ In practice, we recommend:
|
|
|
43
43
|
npm install @salesforce/commerce-sdk-react @tanstack/react-query
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
## ⚡️ Quickstart (PWA Kit
|
|
46
|
+
## ⚡️ Quickstart (PWA Kit v3.0+)
|
|
47
47
|
|
|
48
48
|
To integrate this library with your PWA Kit application you can use the `CommerceApiProvider` directly assuming that you use the `withReactQuery` higher order component to wrap your `AppConfig` component. Below is a snippet of how this is accomplished.
|
|
49
49
|
|
|
@@ -54,6 +54,10 @@ import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
|
|
|
54
54
|
import {withReactQuery} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query'
|
|
55
55
|
|
|
56
56
|
const AppConfig = ({children}) => {
|
|
57
|
+
const headers = {
|
|
58
|
+
'correlation-id': correlationId
|
|
59
|
+
}
|
|
60
|
+
|
|
57
61
|
return (
|
|
58
62
|
<CommerceApiProvider
|
|
59
63
|
clientId="12345678-1234-1234-1234-123412341234"
|
|
@@ -64,6 +68,11 @@ const AppConfig = ({children}) => {
|
|
|
64
68
|
shortCode="12345678"
|
|
65
69
|
locale="en-US"
|
|
66
70
|
currency="USD"
|
|
71
|
+
headers={headers}
|
|
72
|
+
// Uncomment 'enablePWAKitPrivateClient' to use SLAS private client login flows.
|
|
73
|
+
// Make sure to also enable useSLASPrivateClient in ssr.js when enabling this setting.
|
|
74
|
+
// enablePWAKitPrivateClient={true}
|
|
75
|
+
logger={createLogger({packageName: 'commerce-sdk-react'})}
|
|
67
76
|
>
|
|
68
77
|
{children}
|
|
69
78
|
</CommerceApiProvider>
|
|
@@ -125,68 +134,10 @@ export default App
|
|
|
125
134
|
|
|
126
135
|
_💡 This section assumes you have read and completed the [Authorization for Shopper APIs](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.html) guide._
|
|
127
136
|
|
|
128
|
-
To help reduce boilerplate code for managing shopper authentication, by default, this library automatically initializes shopper session and manages the tokens for developers.
|
|
129
|
-
|
|
130
|
-
Commerce-react-sdk supports both public and private flow of the [Authorization for Shopper APIs](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.html) guide._
|
|
131
|
-
You can choose to use either public or private slas to login. By default, public flow is enabled.
|
|
132
|
-
|
|
133
|
-
#### How private SLAS works
|
|
134
|
-
This section assumes you read and understand how [private SLAS](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-private-client.html) flow works
|
|
135
|
-
|
|
136
|
-
To enable private slas flow, you need to pass your secret into the CommercerProvider via clientSecret prop.
|
|
137
|
-
**Note** You should only use private slas if you know you can secure your secret since commercer-sdk-react runs isomorphically.
|
|
138
|
-
|
|
139
|
-
```js
|
|
140
|
-
// app/components/_app-config/index.jsx
|
|
141
|
-
|
|
142
|
-
import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
|
|
143
|
-
import {withReactQuery} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query'
|
|
144
|
-
|
|
145
|
-
const AppConfig = ({children}) => {
|
|
146
|
-
return (
|
|
147
|
-
<CommerceApiProvider
|
|
148
|
-
clientId="12345678-1234-1234-1234-123412341234"
|
|
149
|
-
organizationId="f_ecom_aaaa_001"
|
|
150
|
-
proxy="localhost:3000/mobify/proxy/api"
|
|
151
|
-
redirectURI="localhost:3000/callback"
|
|
152
|
-
siteId="RefArch"
|
|
153
|
-
shortCode="12345678"
|
|
154
|
-
locale="en-US"
|
|
155
|
-
currency="USD"
|
|
156
|
-
clientSecret="<your-slas-private-secret>"
|
|
157
|
-
>
|
|
158
|
-
{children}
|
|
159
|
-
</CommerceApiProvider>
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
#### Disable slas private warnings
|
|
164
|
-
By default, a warning as below will be displayed on client side to remind developers to always keep their secret safe and secured.
|
|
165
|
-
```js
|
|
166
|
-
'You are potentially exposing SLAS secret on browser. Make sure to keep it safe and secure!'
|
|
167
|
-
```
|
|
168
|
-
You can disable this warning by using CommerceProvider prop `silenceWarnings`
|
|
137
|
+
To help reduce boilerplate code for managing shopper authentication, by default, this library automatically initializes shopper session and manages the tokens for developers. Commerce-sdk-react supports both the [SLAS Public Client login flow](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-public-client.html) and [SLAS Private Client login flow](https://developer.salesforce.com/docs/commerce/commerce-api/guide/slas-private-client.html). Authorization using a private client is supported in PWA Kit 3.5 and later, and is the recommended authorization workflow.
|
|
169
138
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
<CommerceApiProvider
|
|
174
|
-
clientId="12345678-1234-1234-1234-123412341234"
|
|
175
|
-
organizationId="f_ecom_aaaa_001"
|
|
176
|
-
proxy="localhost:3000/mobify/proxy/api"
|
|
177
|
-
redirectURI="localhost:3000/callback"
|
|
178
|
-
siteId="RefArch"
|
|
179
|
-
shortCode="12345678"
|
|
180
|
-
locale="en-US"
|
|
181
|
-
currency="USD"
|
|
182
|
-
clientSecret="<your-slas-private-secret>"
|
|
183
|
-
silenceWarnings={true}
|
|
184
|
-
>
|
|
185
|
-
{children}
|
|
186
|
-
</CommerceApiProvider>
|
|
187
|
-
)
|
|
188
|
-
}
|
|
189
|
-
```
|
|
139
|
+
#### Using a private SLAS client
|
|
140
|
+
To enable a private client, see [Use a SLAS Private Client](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/use-a-slas-private-client.html).
|
|
190
141
|
|
|
191
142
|
### Shopper Session Initialization
|
|
192
143
|
|
package/auth/index.d.ts
CHANGED
|
@@ -15,9 +15,15 @@ interface AuthConfig extends ApiClientConfigParams {
|
|
|
15
15
|
silenceWarnings?: boolean;
|
|
16
16
|
logger: Logger;
|
|
17
17
|
defaultDnt?: boolean;
|
|
18
|
+
passwordlessLoginCallbackURI?: string;
|
|
18
19
|
refreshTokenRegisteredCookieTTL?: number;
|
|
19
20
|
refreshTokenGuestCookieTTL?: number;
|
|
20
21
|
}
|
|
22
|
+
type AuthorizeIDPParams = Parameters<Helpers['authorizeIDP']>[1];
|
|
23
|
+
type LoginIDPUserParams = Parameters<Helpers['loginIDPUser']>[2];
|
|
24
|
+
type AuthorizePasswordlessParams = Parameters<Helpers['authorizePasswordless']>[2];
|
|
25
|
+
type LoginPasswordlessParams = Parameters<Helpers['getPasswordLessAccessToken']>[2];
|
|
26
|
+
type LoginRegisteredUserB2CCredentials = Parameters<Helpers['loginRegisteredUserB2C']>[1];
|
|
21
27
|
/**
|
|
22
28
|
* The extended field is not from api response, we manually store the auth type,
|
|
23
29
|
* so we don't need to make another API call when we already have the data.
|
|
@@ -29,7 +35,10 @@ export type AuthData = Prettify<RemoveStringIndex<TokenResponse> & {
|
|
|
29
35
|
idp_access_token: string;
|
|
30
36
|
}>;
|
|
31
37
|
/** A shopper could be guest or registered, so we store the refresh tokens individually. */
|
|
32
|
-
type AuthDataKeys = Exclude<keyof AuthData, 'refresh_token'> | 'refresh_token_guest' | 'refresh_token_registered' | 'access_token_sfra' | typeof DNT_COOKIE_NAME | typeof DWSID_COOKIE_NAME;
|
|
38
|
+
type AuthDataKeys = Exclude<keyof AuthData, 'refresh_token'> | 'refresh_token_guest' | 'refresh_token_registered' | 'access_token_sfra' | typeof DNT_COOKIE_NAME | typeof DWSID_COOKIE_NAME | 'code_verifier' | 'uido';
|
|
39
|
+
type DntOptions = {
|
|
40
|
+
includeDefaults: boolean;
|
|
41
|
+
};
|
|
33
42
|
export declare const DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL: number;
|
|
34
43
|
export declare const DEFAULT_SLAS_REFRESH_TOKEN_GUEST_TTL: number;
|
|
35
44
|
/**
|
|
@@ -51,6 +60,8 @@ declare class Auth {
|
|
|
51
60
|
private silenceWarnings;
|
|
52
61
|
private logger;
|
|
53
62
|
private defaultDnt;
|
|
63
|
+
private isPrivate;
|
|
64
|
+
private passwordlessLoginCallbackURI;
|
|
54
65
|
private refreshTokenRegisteredCookieTTL;
|
|
55
66
|
private refreshTokenGuestCookieTTL;
|
|
56
67
|
private refreshTrustedAgentHandler;
|
|
@@ -58,7 +69,20 @@ declare class Auth {
|
|
|
58
69
|
get(name: AuthDataKeys): string;
|
|
59
70
|
private set;
|
|
60
71
|
private delete;
|
|
61
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Return the value of the DNT cookie or undefined if it is not set.
|
|
74
|
+
* The DNT cookie being undefined means that there is a necessity to
|
|
75
|
+
* get the user's input for consent tracking, but not that there is no
|
|
76
|
+
* DNT value to apply to analytics layers. DNT value will default to
|
|
77
|
+
* a certain value and this is reflected by effectiveDnt.
|
|
78
|
+
*
|
|
79
|
+
* If the cookie value is invalid, then it will be deleted in this function.
|
|
80
|
+
*
|
|
81
|
+
* If includeDefaults is true, then even if the cookie is not defined,
|
|
82
|
+
* defaultDnt will be returned, if it exists. If defaultDnt is not defined, then
|
|
83
|
+
* the SDK Default will return (false)
|
|
84
|
+
*/
|
|
85
|
+
getDnt(options?: DntOptions): boolean | undefined;
|
|
62
86
|
setDnt(preference: boolean | null): Promise<void>;
|
|
63
87
|
private clearStorage;
|
|
64
88
|
/**
|
|
@@ -69,11 +93,6 @@ declare class Auth {
|
|
|
69
93
|
* Used to validate JWT token expiration.
|
|
70
94
|
*/
|
|
71
95
|
private isTokenExpired;
|
|
72
|
-
/**
|
|
73
|
-
* Gets the Do-Not-Track (DNT) preference from the `dw_dnt` cookie.
|
|
74
|
-
* 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.
|
|
75
|
-
*/
|
|
76
|
-
private getDntPreference;
|
|
77
96
|
/**
|
|
78
97
|
* Returns the SLAS access token or an empty string if the access token
|
|
79
98
|
* is not found in local store or if SFRA wants PWA to trigger refresh token login.
|
|
@@ -224,6 +243,7 @@ declare class Auth {
|
|
|
224
243
|
fax?: string | undefined;
|
|
225
244
|
firstName?: string | undefined;
|
|
226
245
|
gender?: number | undefined;
|
|
246
|
+
hashedLogin?: string | undefined;
|
|
227
247
|
jobTitle?: string | undefined;
|
|
228
248
|
lastLoginTime?: any;
|
|
229
249
|
lastModified?: any;
|
|
@@ -283,7 +303,7 @@ declare class Auth {
|
|
|
283
303
|
* A wrapper method for commerce-sdk-isomorphic helper: loginRegisteredUserB2C.
|
|
284
304
|
*
|
|
285
305
|
*/
|
|
286
|
-
loginRegisteredUserB2C(credentials:
|
|
306
|
+
loginRegisteredUserB2C(credentials: LoginRegisteredUserB2CCredentials): Promise<helpers.TokenResponse>;
|
|
287
307
|
/**
|
|
288
308
|
* Trusted agent authorization
|
|
289
309
|
*
|
|
@@ -343,6 +363,34 @@ declare class Auth {
|
|
|
343
363
|
currentPassword: string;
|
|
344
364
|
shouldReloginCurrentSession?: boolean;
|
|
345
365
|
}): Promise<void>;
|
|
366
|
+
/**
|
|
367
|
+
* A wrapper method for commerce-sdk-isomorphic helper: authorizeIDP.
|
|
368
|
+
*
|
|
369
|
+
*/
|
|
370
|
+
authorizeIDP(parameters: AuthorizeIDPParams): Promise<void>;
|
|
371
|
+
/**
|
|
372
|
+
* A wrapper method for commerce-sdk-isomorphic helper: loginIDPUser.
|
|
373
|
+
*
|
|
374
|
+
*/
|
|
375
|
+
loginIDPUser(parameters: LoginIDPUserParams): Promise<helpers.TokenResponse>;
|
|
376
|
+
/**
|
|
377
|
+
* A wrapper method for commerce-sdk-isomorphic helper: authorizePasswordless.
|
|
378
|
+
*/
|
|
379
|
+
authorizePasswordless(parameters: AuthorizePasswordlessParams): Promise<Response>;
|
|
380
|
+
/**
|
|
381
|
+
* A wrapper method for commerce-sdk-isomorphic helper: getPasswordLessAccessToken.
|
|
382
|
+
*/
|
|
383
|
+
getPasswordLessAccessToken(parameters: LoginPasswordlessParams): Promise<helpers.TokenResponse>;
|
|
384
|
+
/**
|
|
385
|
+
* A wrapper method for the SLAS endpoint: getPasswordResetToken.
|
|
386
|
+
*
|
|
387
|
+
*/
|
|
388
|
+
getPasswordResetToken(parameters: ShopperLoginTypes.PasswordActionRequest): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* A wrapper method for the SLAS endpoint: resetPassword.
|
|
391
|
+
*
|
|
392
|
+
*/
|
|
393
|
+
resetPassword(parameters: ShopperLoginTypes.PasswordActionVerifyRequest): Promise<void>;
|
|
346
394
|
/**
|
|
347
395
|
* Decode SLAS JWT and extract information such as customer id, usid, etc.
|
|
348
396
|
*
|
|
@@ -355,6 +403,7 @@ declare class Auth {
|
|
|
355
403
|
loginId: string;
|
|
356
404
|
isAgent: boolean;
|
|
357
405
|
agentId: string | null;
|
|
406
|
+
uido: string;
|
|
358
407
|
};
|
|
359
408
|
}
|
|
360
409
|
export default Auth;
|
package/auth/index.js
CHANGED
|
@@ -115,6 +115,14 @@ const DATA_MAP = {
|
|
|
115
115
|
dwsid: {
|
|
116
116
|
storageType: 'cookie',
|
|
117
117
|
key: _constant.DWSID_COOKIE_NAME
|
|
118
|
+
},
|
|
119
|
+
code_verifier: {
|
|
120
|
+
storageType: 'local',
|
|
121
|
+
key: 'code_verifier'
|
|
122
|
+
},
|
|
123
|
+
uido: {
|
|
124
|
+
storageType: 'local',
|
|
125
|
+
key: 'uido'
|
|
118
126
|
}
|
|
119
127
|
};
|
|
120
128
|
const DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL = exports.DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL = 90 * 24 * 60 * 60;
|
|
@@ -205,6 +213,9 @@ class Auth {
|
|
|
205
213
|
// PWA users should not need to touch this.
|
|
206
214
|
config.clientSecret || '';
|
|
207
215
|
this.silenceWarnings = config.silenceWarnings || false;
|
|
216
|
+
this.isPrivate = !!this.clientSecret;
|
|
217
|
+
const passwordlessLoginCallbackURI = config.passwordlessLoginCallbackURI;
|
|
218
|
+
this.passwordlessLoginCallbackURI = passwordlessLoginCallbackURI ? (0, _utils.isAbsoluteUrl)(passwordlessLoginCallbackURI) ? passwordlessLoginCallbackURI : `${baseUrl}${passwordlessLoginCallbackURI}` : '';
|
|
208
219
|
}
|
|
209
220
|
get(name) {
|
|
210
221
|
const {
|
|
@@ -232,9 +243,22 @@ class Auth {
|
|
|
232
243
|
const storage = this.stores[storageType];
|
|
233
244
|
storage.delete(key);
|
|
234
245
|
}
|
|
235
|
-
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Return the value of the DNT cookie or undefined if it is not set.
|
|
249
|
+
* The DNT cookie being undefined means that there is a necessity to
|
|
250
|
+
* get the user's input for consent tracking, but not that there is no
|
|
251
|
+
* DNT value to apply to analytics layers. DNT value will default to
|
|
252
|
+
* a certain value and this is reflected by effectiveDnt.
|
|
253
|
+
*
|
|
254
|
+
* If the cookie value is invalid, then it will be deleted in this function.
|
|
255
|
+
*
|
|
256
|
+
* If includeDefaults is true, then even if the cookie is not defined,
|
|
257
|
+
* defaultDnt will be returned, if it exists. If defaultDnt is not defined, then
|
|
258
|
+
* the SDK Default will return (false)
|
|
259
|
+
*/
|
|
260
|
+
getDnt(options) {
|
|
236
261
|
const dntCookieVal = this.get(_constant.DNT_COOKIE_NAME);
|
|
237
|
-
// Only '1' or '0' are valid, and invalid values, lack of cookie, or value conflict with token must be an undefined DNT
|
|
238
262
|
let dntCookieStatus = undefined;
|
|
239
263
|
const accessToken = this.getAccessToken();
|
|
240
264
|
let isInSync = true;
|
|
@@ -249,6 +273,19 @@ class Auth {
|
|
|
249
273
|
} else {
|
|
250
274
|
dntCookieStatus = Boolean(Number(dntCookieVal));
|
|
251
275
|
}
|
|
276
|
+
if (options !== null && options !== void 0 && options.includeDefaults) {
|
|
277
|
+
const defaultDnt = this.defaultDnt;
|
|
278
|
+
let effectiveDnt;
|
|
279
|
+
const dntCookie = dntCookieVal === '1' ? true : dntCookieVal === '0' ? false : undefined;
|
|
280
|
+
if (dntCookie !== undefined) {
|
|
281
|
+
effectiveDnt = dntCookie;
|
|
282
|
+
} else {
|
|
283
|
+
// If the cookie is not set, read the defaultDnt preference.
|
|
284
|
+
// If defaultDnt doesn't exist, default to false, following SLAS default for dnt
|
|
285
|
+
effectiveDnt = defaultDnt !== undefined ? defaultDnt : false;
|
|
286
|
+
}
|
|
287
|
+
return effectiveDnt;
|
|
288
|
+
}
|
|
252
289
|
return dntCookieStatus;
|
|
253
290
|
}
|
|
254
291
|
setDnt(preference) {
|
|
@@ -328,21 +365,6 @@ class Auth {
|
|
|
328
365
|
return validTimeSeconds <= tokenAgeSeconds;
|
|
329
366
|
}
|
|
330
367
|
|
|
331
|
-
/**
|
|
332
|
-
* Gets the Do-Not-Track (DNT) preference from the `dw_dnt` cookie.
|
|
333
|
-
* 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.
|
|
334
|
-
*/
|
|
335
|
-
getDntPreference(dw_dnt, defaultDnt) {
|
|
336
|
-
let dntPref;
|
|
337
|
-
// Read `dw_dnt` cookie
|
|
338
|
-
const dntCookie = dw_dnt === '1' ? true : dw_dnt === '0' ? false : undefined;
|
|
339
|
-
dntPref = dntCookie;
|
|
340
|
-
|
|
341
|
-
// If the cookie is not set, read the default DNT preference.
|
|
342
|
-
if (dntCookie === undefined) dntPref = defaultDnt !== undefined ? defaultDnt : undefined;
|
|
343
|
-
return dntPref;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
368
|
/**
|
|
347
369
|
* Returns the SLAS access token or an empty string if the access token
|
|
348
370
|
* is not found in local store or if SFRA wants PWA to trigger refresh token login.
|
|
@@ -474,6 +496,12 @@ class Auth {
|
|
|
474
496
|
const responseValue = res.refresh_token_expires_in;
|
|
475
497
|
const defaultValue = isGuest ? DEFAULT_SLAS_REFRESH_TOKEN_GUEST_TTL : DEFAULT_SLAS_REFRESH_TOKEN_REGISTERED_TTL;
|
|
476
498
|
const refreshTokenTTLValue = this.getRefreshTokenCookieTTLValue(overrideValue, responseValue, defaultValue);
|
|
499
|
+
if (res.access_token) {
|
|
500
|
+
const {
|
|
501
|
+
uido
|
|
502
|
+
} = this.parseSlasJWT(res.access_token);
|
|
503
|
+
this.set('uido', uido);
|
|
504
|
+
}
|
|
477
505
|
const expiresDate = this.convertSecondsToDate(refreshTokenTTLValue);
|
|
478
506
|
this.set('refresh_token_expires_in', refreshTokenTTLValue.toString());
|
|
479
507
|
this.set(refreshTokenKey, res.refresh_token, {
|
|
@@ -483,17 +511,18 @@ class Auth {
|
|
|
483
511
|
refreshAccessToken() {
|
|
484
512
|
var _this2 = this;
|
|
485
513
|
return _asyncToGenerator(function* () {
|
|
486
|
-
const dntPref = _this2.
|
|
514
|
+
const dntPref = _this2.getDnt({
|
|
515
|
+
includeDefaults: true
|
|
516
|
+
});
|
|
487
517
|
const refreshTokenRegistered = _this2.get('refresh_token_registered');
|
|
488
518
|
const refreshTokenGuest = _this2.get('refresh_token_guest');
|
|
489
519
|
const refreshToken = refreshTokenRegistered || refreshTokenGuest;
|
|
490
520
|
if (refreshToken) {
|
|
491
521
|
try {
|
|
492
|
-
return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client,
|
|
493
|
-
refreshToken
|
|
494
|
-
}, dntPref !== undefined && {
|
|
522
|
+
return yield _this2.queueRequest(() => _commerceSdkIsomorphic.helpers.refreshAccessToken(_this2.client, {
|
|
523
|
+
refreshToken,
|
|
495
524
|
dnt: dntPref
|
|
496
|
-
}
|
|
525
|
+
}, {
|
|
497
526
|
clientSecret: _this2.clientSecret
|
|
498
527
|
}), !!refreshTokenGuest);
|
|
499
528
|
} catch (error) {
|
|
@@ -553,7 +582,7 @@ class Auth {
|
|
|
553
582
|
var _this3 = this;
|
|
554
583
|
return _asyncToGenerator(function* () {
|
|
555
584
|
const queue = _this3.pendingToken ?? Promise.resolve();
|
|
556
|
-
_this3.pendingToken = queue.then(/*#__PURE__*/_asyncToGenerator(function* () {
|
|
585
|
+
_this3.pendingToken = queue.then( /*#__PURE__*/_asyncToGenerator(function* () {
|
|
557
586
|
const token = yield fn();
|
|
558
587
|
_this3.handleTokenResponse(token, isGuest);
|
|
559
588
|
// Q: Why don't we just return token? Why re-construct the same object again?
|
|
@@ -670,20 +699,21 @@ class Auth {
|
|
|
670
699
|
_this6.logWarning(_constant.SLAS_SECRET_WARNING_MSG);
|
|
671
700
|
}
|
|
672
701
|
const usid = _this6.get('usid');
|
|
673
|
-
const dntPref = _this6.
|
|
702
|
+
const dntPref = _this6.getDnt({
|
|
703
|
+
includeDefaults: true
|
|
704
|
+
});
|
|
674
705
|
const isGuest = true;
|
|
675
|
-
const guestPrivateArgs = [_this6.client, _objectSpread(
|
|
706
|
+
const guestPrivateArgs = [_this6.client, _objectSpread({
|
|
676
707
|
dnt: dntPref
|
|
677
|
-
}
|
|
708
|
+
}, usid && {
|
|
678
709
|
usid
|
|
679
710
|
}), {
|
|
680
711
|
clientSecret: _this6.clientSecret
|
|
681
712
|
}];
|
|
682
|
-
const guestPublicArgs = [_this6.client, _objectSpread(
|
|
683
|
-
redirectURI: _this6.redirectURI
|
|
684
|
-
}, dntPref !== undefined && {
|
|
713
|
+
const guestPublicArgs = [_this6.client, _objectSpread({
|
|
714
|
+
redirectURI: _this6.redirectURI,
|
|
685
715
|
dnt: dntPref
|
|
686
|
-
}
|
|
716
|
+
}, usid && {
|
|
687
717
|
usid
|
|
688
718
|
})];
|
|
689
719
|
const callback = _this6.clientSecret ? () => _commerceSdkIsomorphic.helpers.loginGuestUserPrivate(...guestPrivateArgs) : () => _commerceSdkIsomorphic.helpers.loginGuestUser(...guestPublicArgs);
|
|
@@ -748,15 +778,16 @@ class Auth {
|
|
|
748
778
|
}
|
|
749
779
|
const redirectURI = _this8.redirectURI;
|
|
750
780
|
const usid = _this8.get('usid');
|
|
751
|
-
const dntPref = _this8.
|
|
781
|
+
const dntPref = _this8.getDnt({
|
|
782
|
+
includeDefaults: true
|
|
783
|
+
});
|
|
752
784
|
const isGuest = false;
|
|
753
785
|
const token = yield _commerceSdkIsomorphic.helpers.loginRegisteredUserB2C(_this8.client, _objectSpread(_objectSpread({}, credentials), {}, {
|
|
754
786
|
clientSecret: _this8.clientSecret
|
|
755
|
-
}), _objectSpread(
|
|
756
|
-
redirectURI
|
|
757
|
-
}, dntPref !== undefined && {
|
|
787
|
+
}), _objectSpread({
|
|
788
|
+
redirectURI,
|
|
758
789
|
dnt: dntPref
|
|
759
|
-
}
|
|
790
|
+
}, usid && {
|
|
760
791
|
usid
|
|
761
792
|
}));
|
|
762
793
|
_this8.handleTokenResponse(token, isGuest);
|
|
@@ -916,6 +947,186 @@ class Auth {
|
|
|
916
947
|
})();
|
|
917
948
|
}
|
|
918
949
|
|
|
950
|
+
/**
|
|
951
|
+
* A wrapper method for commerce-sdk-isomorphic helper: authorizeIDP.
|
|
952
|
+
*
|
|
953
|
+
*/
|
|
954
|
+
authorizeIDP(parameters) {
|
|
955
|
+
var _this14 = this;
|
|
956
|
+
return _asyncToGenerator(function* () {
|
|
957
|
+
const redirectURI = parameters.redirectURI || _this14.redirectURI;
|
|
958
|
+
const usid = _this14.get('usid');
|
|
959
|
+
const {
|
|
960
|
+
url,
|
|
961
|
+
codeVerifier
|
|
962
|
+
} = yield _commerceSdkIsomorphic.helpers.authorizeIDP(_this14.client, _objectSpread({
|
|
963
|
+
redirectURI,
|
|
964
|
+
hint: parameters.hint
|
|
965
|
+
}, usid && {
|
|
966
|
+
usid
|
|
967
|
+
}), _this14.isPrivate);
|
|
968
|
+
if ((0, _utils.onClient)()) {
|
|
969
|
+
window.location.assign(url);
|
|
970
|
+
} else {
|
|
971
|
+
console.warn('Something went wrong, this client side method is invoked on the server.');
|
|
972
|
+
}
|
|
973
|
+
_this14.set('code_verifier', codeVerifier);
|
|
974
|
+
})();
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* A wrapper method for commerce-sdk-isomorphic helper: loginIDPUser.
|
|
979
|
+
*
|
|
980
|
+
*/
|
|
981
|
+
loginIDPUser(parameters) {
|
|
982
|
+
var _this15 = this;
|
|
983
|
+
return _asyncToGenerator(function* () {
|
|
984
|
+
const codeVerifier = _this15.get('code_verifier');
|
|
985
|
+
const code = parameters.code;
|
|
986
|
+
const usid = parameters.usid || _this15.get('usid');
|
|
987
|
+
const redirectURI = parameters.redirectURI || _this15.redirectURI;
|
|
988
|
+
const dntPref = _this15.getDnt({
|
|
989
|
+
includeDefaults: true
|
|
990
|
+
});
|
|
991
|
+
const token = yield _commerceSdkIsomorphic.helpers.loginIDPUser(_this15.client, {
|
|
992
|
+
codeVerifier,
|
|
993
|
+
clientSecret: _this15.clientSecret
|
|
994
|
+
}, _objectSpread({
|
|
995
|
+
redirectURI,
|
|
996
|
+
code,
|
|
997
|
+
dnt: dntPref
|
|
998
|
+
}, usid && {
|
|
999
|
+
usid
|
|
1000
|
+
}));
|
|
1001
|
+
const isGuest = false;
|
|
1002
|
+
_this15.handleTokenResponse(token, isGuest);
|
|
1003
|
+
// Delete the code verifier once the user has logged in
|
|
1004
|
+
_this15.delete('code_verifier');
|
|
1005
|
+
if ((0, _utils.onClient)()) {
|
|
1006
|
+
void _this15.clearECOMSession();
|
|
1007
|
+
}
|
|
1008
|
+
return token;
|
|
1009
|
+
})();
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* A wrapper method for commerce-sdk-isomorphic helper: authorizePasswordless.
|
|
1014
|
+
*/
|
|
1015
|
+
authorizePasswordless(parameters) {
|
|
1016
|
+
var _this16 = this;
|
|
1017
|
+
return _asyncToGenerator(function* () {
|
|
1018
|
+
const userid = parameters.userid;
|
|
1019
|
+
const callbackURI = parameters.callbackURI || _this16.passwordlessLoginCallbackURI;
|
|
1020
|
+
const usid = _this16.get('usid');
|
|
1021
|
+
const mode = callbackURI ? 'callback' : 'sms';
|
|
1022
|
+
const res = yield _commerceSdkIsomorphic.helpers.authorizePasswordless(_this16.client, {
|
|
1023
|
+
clientSecret: _this16.clientSecret
|
|
1024
|
+
}, _objectSpread(_objectSpread(_objectSpread({}, callbackURI && {
|
|
1025
|
+
callbackURI: callbackURI
|
|
1026
|
+
}), usid && {
|
|
1027
|
+
usid
|
|
1028
|
+
}), {}, {
|
|
1029
|
+
userid,
|
|
1030
|
+
mode
|
|
1031
|
+
}));
|
|
1032
|
+
if (res && res.status !== 200) {
|
|
1033
|
+
const errorData = yield res.json();
|
|
1034
|
+
throw new Error(`${res.status} ${String(errorData.message)}`);
|
|
1035
|
+
}
|
|
1036
|
+
return res;
|
|
1037
|
+
})();
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
/**
|
|
1041
|
+
* A wrapper method for commerce-sdk-isomorphic helper: getPasswordLessAccessToken.
|
|
1042
|
+
*/
|
|
1043
|
+
getPasswordLessAccessToken(parameters) {
|
|
1044
|
+
var _this17 = this;
|
|
1045
|
+
return _asyncToGenerator(function* () {
|
|
1046
|
+
const pwdlessLoginToken = parameters.pwdlessLoginToken;
|
|
1047
|
+
const dntPref = _this17.getDnt({
|
|
1048
|
+
includeDefaults: true
|
|
1049
|
+
});
|
|
1050
|
+
const token = yield _commerceSdkIsomorphic.helpers.getPasswordLessAccessToken(_this17.client, {
|
|
1051
|
+
clientSecret: _this17.clientSecret
|
|
1052
|
+
}, {
|
|
1053
|
+
pwdlessLoginToken,
|
|
1054
|
+
dnt: dntPref !== undefined ? String(dntPref) : undefined
|
|
1055
|
+
});
|
|
1056
|
+
const isGuest = false;
|
|
1057
|
+
_this17.handleTokenResponse(token, isGuest);
|
|
1058
|
+
if ((0, _utils.onClient)()) {
|
|
1059
|
+
void _this17.clearECOMSession();
|
|
1060
|
+
}
|
|
1061
|
+
return token;
|
|
1062
|
+
})();
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* A wrapper method for the SLAS endpoint: getPasswordResetToken.
|
|
1067
|
+
*
|
|
1068
|
+
*/
|
|
1069
|
+
getPasswordResetToken(parameters) {
|
|
1070
|
+
var _this18 = this;
|
|
1071
|
+
return _asyncToGenerator(function* () {
|
|
1072
|
+
const slasClient = _this18.client;
|
|
1073
|
+
const callbackURI = parameters.callback_uri;
|
|
1074
|
+
const options = {
|
|
1075
|
+
headers: {
|
|
1076
|
+
Authorization: ''
|
|
1077
|
+
},
|
|
1078
|
+
body: {
|
|
1079
|
+
user_id: parameters.user_id,
|
|
1080
|
+
mode: 'callback',
|
|
1081
|
+
channel_id: slasClient.clientConfig.parameters.siteId,
|
|
1082
|
+
client_id: slasClient.clientConfig.parameters.clientId,
|
|
1083
|
+
callback_uri: callbackURI,
|
|
1084
|
+
hint: 'cross_device'
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
// Only set authorization header if using private client
|
|
1089
|
+
if (_this18.clientSecret) {
|
|
1090
|
+
options.headers.Authorization = `Basic ${(0, _utils.stringToBase64)(`${slasClient.clientConfig.parameters.clientId}:${_this18.clientSecret}`)}`;
|
|
1091
|
+
}
|
|
1092
|
+
const res = yield slasClient.getPasswordResetToken(options);
|
|
1093
|
+
return res;
|
|
1094
|
+
})();
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* A wrapper method for the SLAS endpoint: resetPassword.
|
|
1099
|
+
*
|
|
1100
|
+
*/
|
|
1101
|
+
resetPassword(parameters) {
|
|
1102
|
+
var _this19 = this;
|
|
1103
|
+
return _asyncToGenerator(function* () {
|
|
1104
|
+
const slasClient = _this19.client;
|
|
1105
|
+
const options = {
|
|
1106
|
+
headers: {
|
|
1107
|
+
Authorization: ''
|
|
1108
|
+
},
|
|
1109
|
+
body: {
|
|
1110
|
+
pwd_action_token: parameters.pwd_action_token,
|
|
1111
|
+
channel_id: slasClient.clientConfig.parameters.siteId,
|
|
1112
|
+
client_id: slasClient.clientConfig.parameters.clientId,
|
|
1113
|
+
new_password: parameters.new_password,
|
|
1114
|
+
user_id: parameters.user_id
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// Only set authorization header if using private client
|
|
1119
|
+
if (_this19.clientSecret) {
|
|
1120
|
+
options.headers.Authorization = `Basic ${(0, _utils.stringToBase64)(`${slasClient.clientConfig.parameters.clientId}:${_this19.clientSecret}`)}`;
|
|
1121
|
+
}
|
|
1122
|
+
// TODO: no code verifier needed with the fix blair has made, delete this when the fix has been merged to production
|
|
1123
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1124
|
+
// @ts-ignore
|
|
1125
|
+
const res = yield _this19.client.resetPassword(options);
|
|
1126
|
+
return res;
|
|
1127
|
+
})();
|
|
1128
|
+
}
|
|
1129
|
+
|
|
919
1130
|
/**
|
|
920
1131
|
* Decode SLAS JWT and extract information such as customer id, usid, etc.
|
|
921
1132
|
*
|
|
@@ -935,6 +1146,7 @@ class Auth {
|
|
|
935
1146
|
// ISB format
|
|
936
1147
|
// 'uido:ecom::upn:Guest||xxxEmailxxx::uidn:FirstName LastName::gcid:xxxGuestCustomerIdxxx::rcid:xxxRegisteredCustomerIdxxx::chid:xxxSiteIdxxx',
|
|
937
1148
|
const isbParts = isb.split('::');
|
|
1149
|
+
const uido = isbParts[0].split('uido:')[1];
|
|
938
1150
|
const isGuest = isbParts[1] === 'upn:Guest';
|
|
939
1151
|
const customerId = isGuest ? isbParts[3].replace('gcid:', '') : isbParts[4].replace('rcid:', '');
|
|
940
1152
|
const loginId = isGuest ? 'guest' : isbParts[1].replace('upn:', '');
|
|
@@ -951,7 +1163,8 @@ class Auth {
|
|
|
951
1163
|
dnt,
|
|
952
1164
|
loginId,
|
|
953
1165
|
isAgent,
|
|
954
|
-
agentId
|
|
1166
|
+
agentId,
|
|
1167
|
+
uido
|
|
955
1168
|
};
|
|
956
1169
|
}
|
|
957
1170
|
}
|
|
@@ -15,8 +15,8 @@ const _excluded = ["data"];
|
|
|
15
15
|
*/
|
|
16
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
18
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
19
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
18
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
19
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
|
|
20
20
|
const ComponentNotFound = ({
|
|
21
21
|
typeId
|
|
22
22
|
}) => /*#__PURE__*/_react.default.createElement("div", null, `Component type '${typeId}' not found!`);
|
|
@@ -22,8 +22,8 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
22
22
|
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
23
23
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
24
24
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
25
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
26
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
25
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
26
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
|
|
27
27
|
// This context will hold the component map as well as any other future context.
|
|
28
28
|
const PageContext = exports.PageContext = /*#__PURE__*/_react.default.createContext(undefined);
|
|
29
29
|
|
|
@@ -17,8 +17,8 @@ const _excluded = ["region", "className"];
|
|
|
17
17
|
*/
|
|
18
18
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
19
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
20
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
21
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
20
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], t.indexOf(o) >= 0 || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
21
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
|
|
22
22
|
/**
|
|
23
23
|
* This PropType represents a `region` object from the ShopperExperience API.
|
|
24
24
|
*/
|
package/hooks/useAuthHelper.d.ts
CHANGED
|
@@ -6,10 +6,16 @@ import Auth from '../auth';
|
|
|
6
6
|
* @enum
|
|
7
7
|
*/
|
|
8
8
|
export declare const AuthHelpers: {
|
|
9
|
+
readonly AuthorizePasswordless: "authorizePasswordless";
|
|
10
|
+
readonly LoginPasswordlessUser: "getPasswordLessAccessToken";
|
|
11
|
+
readonly AuthorizeIDP: "authorizeIDP";
|
|
12
|
+
readonly GetPasswordResetToken: "getPasswordResetToken";
|
|
13
|
+
readonly LoginIDPUser: "loginIDPUser";
|
|
9
14
|
readonly LoginGuestUser: "loginGuestUser";
|
|
10
15
|
readonly LoginRegisteredUserB2C: "loginRegisteredUserB2C";
|
|
11
16
|
readonly Logout: "logout";
|
|
12
17
|
readonly Register: "register";
|
|
18
|
+
readonly ResetPassword: "resetPassword";
|
|
13
19
|
readonly UpdateCustomerPassword: "updateCustomerPassword";
|
|
14
20
|
};
|
|
15
21
|
/**
|
|
@@ -25,6 +31,8 @@ export type AuthHelper = (typeof AuthHelpers)[keyof typeof AuthHelpers];
|
|
|
25
31
|
* For more, see https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic/#public-client-shopper-login-helpers
|
|
26
32
|
*
|
|
27
33
|
* Avaliable helpers:
|
|
34
|
+
* - authorizeIDP
|
|
35
|
+
* - loginIDPUser
|
|
28
36
|
* - loginRegisteredUserB2C
|
|
29
37
|
* - loginGuestUser
|
|
30
38
|
* - logout
|
package/hooks/useAuthHelper.js
CHANGED
|
@@ -22,10 +22,16 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
22
22
|
* @enum
|
|
23
23
|
*/
|
|
24
24
|
const AuthHelpers = exports.AuthHelpers = {
|
|
25
|
+
AuthorizePasswordless: 'authorizePasswordless',
|
|
26
|
+
LoginPasswordlessUser: 'getPasswordLessAccessToken',
|
|
27
|
+
AuthorizeIDP: 'authorizeIDP',
|
|
28
|
+
GetPasswordResetToken: 'getPasswordResetToken',
|
|
29
|
+
LoginIDPUser: 'loginIDPUser',
|
|
25
30
|
LoginGuestUser: 'loginGuestUser',
|
|
26
31
|
LoginRegisteredUserB2C: 'loginRegisteredUserB2C',
|
|
27
32
|
Logout: 'logout',
|
|
28
33
|
Register: 'register',
|
|
34
|
+
ResetPassword: 'resetPassword',
|
|
29
35
|
UpdateCustomerPassword: 'updateCustomerPassword'
|
|
30
36
|
};
|
|
31
37
|
/**
|
|
@@ -47,6 +53,8 @@ const noop = () => ({});
|
|
|
47
53
|
* For more, see https://github.com/SalesforceCommerceCloud/commerce-sdk-isomorphic/#public-client-shopper-login-helpers
|
|
48
54
|
*
|
|
49
55
|
* Avaliable helpers:
|
|
56
|
+
* - authorizeIDP
|
|
57
|
+
* - loginIDPUser
|
|
50
58
|
* - loginRegisteredUserB2C
|
|
51
59
|
* - loginGuestUser
|
|
52
60
|
* - logout
|
|
@@ -42,7 +42,7 @@ const useAuthorizationHeader = method => {
|
|
|
42
42
|
headers: _objectSpread({
|
|
43
43
|
Authorization: `Bearer ${access_token}`
|
|
44
44
|
}, options.headers)
|
|
45
|
-
})).catch(/*#__PURE__*/function () {
|
|
45
|
+
})).catch( /*#__PURE__*/function () {
|
|
46
46
|
var _ref2 = _asyncToGenerator(function* (error) {
|
|
47
47
|
const {
|
|
48
48
|
access_token
|
package/hooks/useCustomerType.js
CHANGED
|
@@ -44,10 +44,18 @@ const useCustomerType = () => {
|
|
|
44
44
|
if (customerType !== null && customerType !== 'guest' && customerType !== 'registered') {
|
|
45
45
|
customerType = null;
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
// The `uido` is a value within the `isb` claim of the SLAS access token that denotes the IDP origin of the user
|
|
49
|
+
// If `uido` is not equal to `slas` or `ecom`, the user is considered an external user
|
|
50
|
+
const uido = onClient ?
|
|
51
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
52
|
+
(0, _useLocalStorage.default)(`uido_${config.siteId}`) : auth.get('uido');
|
|
53
|
+
const isExternal = customerType === 'registered' && uido !== 'slas' && uido !== 'ecom';
|
|
47
54
|
return {
|
|
48
55
|
customerType,
|
|
49
56
|
isGuest,
|
|
50
|
-
isRegistered
|
|
57
|
+
isRegistered,
|
|
58
|
+
isExternal
|
|
51
59
|
};
|
|
52
60
|
};
|
|
53
61
|
var _default = exports.default = useCustomerType;
|
package/hooks/useDNT.d.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
interface useDntReturn {
|
|
2
|
+
selectedDnt: boolean | undefined;
|
|
2
3
|
dntStatus: boolean | undefined;
|
|
4
|
+
effectiveDnt: boolean | undefined;
|
|
3
5
|
updateDNT: (preference: boolean | null) => Promise<void>;
|
|
6
|
+
updateDnt: (preference: boolean | null) => Promise<void>;
|
|
4
7
|
}
|
|
5
8
|
/**
|
|
6
|
-
* Hook that returns
|
|
7
|
-
* dntStatus - a boolean indicating the current DNT preference
|
|
8
|
-
* updateDNT - a function that takes a DNT preference and creates the dw_dnt
|
|
9
|
-
* cookie and reauthroizes with SLAS
|
|
10
|
-
*
|
|
11
9
|
* @group Helpers
|
|
12
10
|
* @category DNT
|
|
13
11
|
*
|
|
12
|
+
* @returns {Object} - The returned object containing DNT states and function to update preference
|
|
13
|
+
* @property {boolean} selectedDnt - DNT user preference. Used to determine
|
|
14
|
+
* if the consent tracking form should be rendered
|
|
15
|
+
* @property {boolean} effectiveDnt - effective DNT value to apply to
|
|
16
|
+
* analytics layers. Takes defaultDnt into account when selectedDnt is undefined.
|
|
17
|
+
* If defaultDnt is undefined as well, then SDK default is used.
|
|
18
|
+
* @property {function} updateDnt - takes a DNT choice and creates the dw_dnt
|
|
19
|
+
* cookie and reauthorizes with SLAS
|
|
20
|
+
* @property {function} updateDNT - @deprecated Deprecated since version 3.1.0. Use updateDnt instead.
|
|
21
|
+
* @property {boolean} dntStatus - @deprecated Deprecated since version 3.1.0. Use selectedDnt instead.
|
|
22
|
+
*
|
|
23
|
+
*
|
|
14
24
|
*/
|
|
15
25
|
declare const useDNT: () => useDntReturn;
|
|
16
26
|
export default useDNT;
|
package/hooks/useDNT.js
CHANGED
|
@@ -14,29 +14,44 @@ function _asyncToGenerator(n) { return function () { var t = this, e = arguments
|
|
|
14
14
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
15
15
|
*/
|
|
16
16
|
/**
|
|
17
|
-
* Hook that returns
|
|
18
|
-
* dntStatus - a boolean indicating the current DNT preference
|
|
19
|
-
* updateDNT - a function that takes a DNT preference and creates the dw_dnt
|
|
20
|
-
* cookie and reauthroizes with SLAS
|
|
21
|
-
*
|
|
22
17
|
* @group Helpers
|
|
23
18
|
* @category DNT
|
|
24
19
|
*
|
|
20
|
+
* @returns {Object} - The returned object containing DNT states and function to update preference
|
|
21
|
+
* @property {boolean} selectedDnt - DNT user preference. Used to determine
|
|
22
|
+
* if the consent tracking form should be rendered
|
|
23
|
+
* @property {boolean} effectiveDnt - effective DNT value to apply to
|
|
24
|
+
* analytics layers. Takes defaultDnt into account when selectedDnt is undefined.
|
|
25
|
+
* If defaultDnt is undefined as well, then SDK default is used.
|
|
26
|
+
* @property {function} updateDnt - takes a DNT choice and creates the dw_dnt
|
|
27
|
+
* cookie and reauthorizes with SLAS
|
|
28
|
+
* @property {function} updateDNT - @deprecated Deprecated since version 3.1.0. Use updateDnt instead.
|
|
29
|
+
* @property {boolean} dntStatus - @deprecated Deprecated since version 3.1.0. Use selectedDnt instead.
|
|
30
|
+
*
|
|
31
|
+
*
|
|
25
32
|
*/
|
|
26
33
|
const useDNT = () => {
|
|
27
34
|
const auth = (0, _useAuthContext.default)();
|
|
28
|
-
const
|
|
29
|
-
const
|
|
35
|
+
const selectedDnt = auth.getDnt();
|
|
36
|
+
const effectiveDnt = auth.getDnt({
|
|
37
|
+
includeDefaults: true
|
|
38
|
+
});
|
|
39
|
+
const updateDnt = /*#__PURE__*/function () {
|
|
30
40
|
var _ref = _asyncToGenerator(function* (preference) {
|
|
31
41
|
yield auth.setDnt(preference);
|
|
32
42
|
});
|
|
33
|
-
return function
|
|
43
|
+
return function updateDnt(_x) {
|
|
34
44
|
return _ref.apply(this, arguments);
|
|
35
45
|
};
|
|
36
46
|
}();
|
|
47
|
+
const updateDNT = updateDnt;
|
|
48
|
+
const dntStatus = selectedDnt;
|
|
37
49
|
return {
|
|
50
|
+
selectedDnt,
|
|
51
|
+
effectiveDnt,
|
|
38
52
|
dntStatus,
|
|
39
|
-
updateDNT
|
|
53
|
+
updateDNT,
|
|
54
|
+
updateDnt
|
|
40
55
|
};
|
|
41
56
|
};
|
|
42
57
|
var _default = exports.default = useDNT;
|
package/hooks/useMutation.js
CHANGED
|
@@ -61,7 +61,7 @@ const useCustomMutation = (apiOptions, mutationOptions) => {
|
|
|
61
61
|
const {
|
|
62
62
|
access_token
|
|
63
63
|
} = yield auth.ready();
|
|
64
|
-
return yield _commerceSdkIsomorphic.helpers.callCustomEndpoint((0, _helpers.generateCustomEndpointOptions)(apiOptions, globalConfig, access_token, args)).catch(/*#__PURE__*/function () {
|
|
64
|
+
return yield _commerceSdkIsomorphic.helpers.callCustomEndpoint((0, _helpers.generateCustomEndpointOptions)(apiOptions, globalConfig, access_token, args)).catch( /*#__PURE__*/function () {
|
|
65
65
|
var _ref2 = _asyncToGenerator(function* (error) {
|
|
66
66
|
const {
|
|
67
67
|
access_token
|
package/hooks/useQuery.js
CHANGED
|
@@ -86,7 +86,7 @@ const useCustomQuery = (apiOptions, queryOptions) => {
|
|
|
86
86
|
access_token
|
|
87
87
|
} = yield auth.ready();
|
|
88
88
|
const customEndpointOptions = (0, _helpers.generateCustomEndpointOptions)(options, config, access_token);
|
|
89
|
-
return yield _commerceSdkIsomorphic.helpers.callCustomEndpoint(customEndpointOptions).catch(/*#__PURE__*/function () {
|
|
89
|
+
return yield _commerceSdkIsomorphic.helpers.callCustomEndpoint(customEndpointOptions).catch( /*#__PURE__*/function () {
|
|
90
90
|
var _ref3 = _asyncToGenerator(function* (error) {
|
|
91
91
|
const {
|
|
92
92
|
access_token
|
package/hooks/useTrustedAgent.js
CHANGED
|
@@ -127,7 +127,7 @@ const useTrustedAgent = () => {
|
|
|
127
127
|
const authorizeTrustedAgent = (0, _reactQuery.useMutation)(auth.authorizeTrustedAgent.bind(auth));
|
|
128
128
|
const loginTrustedAgent = (0, _reactQuery.useMutation)(auth.loginTrustedAgent.bind(auth));
|
|
129
129
|
const logoutTrustedAgent = (0, _reactQuery.useMutation)(auth.logout.bind(auth));
|
|
130
|
-
const login = (0, _react.useCallback)(/*#__PURE__*/function () {
|
|
130
|
+
const login = (0, _react.useCallback)( /*#__PURE__*/function () {
|
|
131
131
|
var _ref2 = _asyncToGenerator(function* (loginId, usid, refresh = false) {
|
|
132
132
|
if (!(0, _utils.onClient)()) {
|
|
133
133
|
throw new Error('Something went wrong, this client side method is invoked on the server.');
|
|
@@ -154,7 +154,7 @@ const useTrustedAgent = () => {
|
|
|
154
154
|
return _ref2.apply(this, arguments);
|
|
155
155
|
};
|
|
156
156
|
}(), [auth]);
|
|
157
|
-
const logout = (0, _react.useCallback)(/*#__PURE__*/_asyncToGenerator(function* () {
|
|
157
|
+
const logout = (0, _react.useCallback)( /*#__PURE__*/_asyncToGenerator(function* () {
|
|
158
158
|
return yield logoutTrustedAgent.mutateAsync();
|
|
159
159
|
}), [auth]);
|
|
160
160
|
(0, _react.useEffect)(() => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/commerce-sdk-react",
|
|
3
|
-
"version": "3.2.0-preview.
|
|
3
|
+
"version": "3.2.0-preview.4",
|
|
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.
|
|
43
|
+
"commerce-sdk-isomorphic": "^3.2.0",
|
|
44
44
|
"js-cookie": "^3.0.1",
|
|
45
45
|
"jwt-decode": "^4.0.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@salesforce/pwa-kit-dev": "
|
|
48
|
+
"@salesforce/pwa-kit-dev": "3.9.0-preview.4",
|
|
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": "
|
|
63
|
+
"internal-lib-build": "3.9.0-preview.4",
|
|
64
64
|
"jsonwebtoken": "^9.0.0",
|
|
65
65
|
"nock": "^13.3.0",
|
|
66
66
|
"nodemon": "^2.0.22",
|
|
@@ -84,11 +84,11 @@
|
|
|
84
84
|
"react-router-dom": "^5.3.4"
|
|
85
85
|
},
|
|
86
86
|
"engines": {
|
|
87
|
-
"node": "^16.11.0 || ^18.0.0 || ^20.0.0",
|
|
88
|
-
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
87
|
+
"node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
|
|
88
|
+
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
|
|
89
89
|
},
|
|
90
90
|
"publishConfig": {
|
|
91
91
|
"directory": "dist"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "1f16c75dcb6939a4edc76bb477888239fa76357b"
|
|
94
94
|
}
|
package/provider.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface CommerceApiProviderProps extends ApiClientConfigParams {
|
|
|
17
17
|
silenceWarnings?: boolean;
|
|
18
18
|
logger?: Logger;
|
|
19
19
|
defaultDnt?: boolean;
|
|
20
|
+
passwordlessLoginCallbackURI?: string;
|
|
20
21
|
refreshTokenRegisteredCookieTTL?: number;
|
|
21
22
|
refreshTokenGuestCookieTTL?: number;
|
|
22
23
|
}
|
package/provider.js
CHANGED
|
@@ -97,6 +97,7 @@ const CommerceApiProvider = props => {
|
|
|
97
97
|
silenceWarnings,
|
|
98
98
|
logger,
|
|
99
99
|
defaultDnt,
|
|
100
|
+
passwordlessLoginCallbackURI,
|
|
100
101
|
refreshTokenRegisteredCookieTTL,
|
|
101
102
|
refreshTokenGuestCookieTTL
|
|
102
103
|
} = props;
|
|
@@ -118,10 +119,11 @@ const CommerceApiProvider = props => {
|
|
|
118
119
|
silenceWarnings,
|
|
119
120
|
logger: configLogger,
|
|
120
121
|
defaultDnt,
|
|
122
|
+
passwordlessLoginCallbackURI,
|
|
121
123
|
refreshTokenRegisteredCookieTTL,
|
|
122
124
|
refreshTokenGuestCookieTTL
|
|
123
125
|
});
|
|
124
|
-
}, [clientId, organizationId, shortCode, siteId, proxy, redirectURI, fetchOptions, fetchedToken, enablePWAKitPrivateClient, clientSecret, silenceWarnings, configLogger, refreshTokenRegisteredCookieTTL, refreshTokenGuestCookieTTL]);
|
|
126
|
+
}, [clientId, organizationId, shortCode, siteId, proxy, redirectURI, fetchOptions, fetchedToken, enablePWAKitPrivateClient, clientSecret, silenceWarnings, configLogger, defaultDnt, passwordlessLoginCallbackURI, refreshTokenRegisteredCookieTTL, refreshTokenGuestCookieTTL]);
|
|
125
127
|
const dwsid = auth.get(_constant.DWSID_COOKIE_NAME);
|
|
126
128
|
const serverAffinityHeader = {};
|
|
127
129
|
if (dwsid) {
|
|
@@ -179,6 +181,7 @@ const CommerceApiProvider = props => {
|
|
|
179
181
|
silenceWarnings,
|
|
180
182
|
logger: configLogger,
|
|
181
183
|
defaultDnt,
|
|
184
|
+
passwordlessLoginCallbackURI,
|
|
182
185
|
refreshTokenRegisteredCookieTTL,
|
|
183
186
|
refreshTokenGuestCookieTTL
|
|
184
187
|
}
|
package/utils.d.ts
CHANGED
|
@@ -33,4 +33,29 @@ export declare const getDefaultCookieAttributes: () => CookieAttributes;
|
|
|
33
33
|
export declare function detectLocalStorageAvailable(): boolean;
|
|
34
34
|
/** Determines whether cookies are available by trying to set a test value. */
|
|
35
35
|
export declare function detectCookiesAvailable(options?: CookieAttributes): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Determines whether the given URL string is a valid absolute URL.
|
|
38
|
+
*
|
|
39
|
+
* Valid absolute URLs:
|
|
40
|
+
* - https://example.com
|
|
41
|
+
* - http://example.com
|
|
42
|
+
*
|
|
43
|
+
* Invalid or relative URLs:
|
|
44
|
+
* - http://example
|
|
45
|
+
* - example.com
|
|
46
|
+
* - /relative/path
|
|
47
|
+
*
|
|
48
|
+
* @param {string} url - The URL string to be checked.
|
|
49
|
+
* @returns {boolean} - Returns true if the given string is a valid absolute URL, false otherwise.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isAbsoluteUrl(url: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Provides a platform-specific method for Base64 encoding.
|
|
54
|
+
*
|
|
55
|
+
* - In a browser environment (where `window` and `document` are defined),
|
|
56
|
+
* the native `btoa` function is used.
|
|
57
|
+
* - In a non-browser environment (like Node.js), a fallback is provided
|
|
58
|
+
* that uses `Buffer` to perform the Base64 encoding.
|
|
59
|
+
*/
|
|
60
|
+
export declare const stringToBase64: typeof btoa;
|
|
36
61
|
//# sourceMappingURL=utils.d.ts.map
|
package/utils.js
CHANGED
|
@@ -7,7 +7,9 @@ exports.DEVELOPMENT_ORIGIN = void 0;
|
|
|
7
7
|
exports.detectCookiesAvailable = detectCookiesAvailable;
|
|
8
8
|
exports.detectInIframe = void 0;
|
|
9
9
|
exports.detectLocalStorageAvailable = detectLocalStorageAvailable;
|
|
10
|
-
exports.
|
|
10
|
+
exports.getParentOrigin = exports.getDefaultCookieAttributes = exports.getCookieSameSiteAttribute = void 0;
|
|
11
|
+
exports.isAbsoluteUrl = isAbsoluteUrl;
|
|
12
|
+
exports.stringToBase64 = exports.onClient = exports.isOriginTrusted = void 0;
|
|
11
13
|
var _jsCookie = _interopRequireDefault(require("js-cookie"));
|
|
12
14
|
var _constant = require("./constant");
|
|
13
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -123,4 +125,33 @@ function detectCookiesAvailable(options) {
|
|
|
123
125
|
} catch {
|
|
124
126
|
return false;
|
|
125
127
|
}
|
|
126
|
-
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Determines whether the given URL string is a valid absolute URL.
|
|
132
|
+
*
|
|
133
|
+
* Valid absolute URLs:
|
|
134
|
+
* - https://example.com
|
|
135
|
+
* - http://example.com
|
|
136
|
+
*
|
|
137
|
+
* Invalid or relative URLs:
|
|
138
|
+
* - http://example
|
|
139
|
+
* - example.com
|
|
140
|
+
* - /relative/path
|
|
141
|
+
*
|
|
142
|
+
* @param {string} url - The URL string to be checked.
|
|
143
|
+
* @returns {boolean} - Returns true if the given string is a valid absolute URL, false otherwise.
|
|
144
|
+
*/
|
|
145
|
+
function isAbsoluteUrl(url) {
|
|
146
|
+
return /^(https?:\/\/)/i.test(url);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Provides a platform-specific method for Base64 encoding.
|
|
151
|
+
*
|
|
152
|
+
* - In a browser environment (where `window` and `document` are defined),
|
|
153
|
+
* the native `btoa` function is used.
|
|
154
|
+
* - In a non-browser environment (like Node.js), a fallback is provided
|
|
155
|
+
* that uses `Buffer` to perform the Base64 encoding.
|
|
156
|
+
*/
|
|
157
|
+
const stringToBase64 = exports.stringToBase64 = typeof window === 'object' && typeof window.document === 'object' ? btoa : unencoded => Buffer.from(unencoded).toString('base64');
|