1
1
/*
2
- * Copyright (c) 2022 , Salesforce, Inc.
2
+ * Copyright (c) 2023 , Salesforce, Inc.
3
3
* All rights reserved.
4
4
* SPDX-License-Identifier: BSD-3-Clause
5
5
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
@@ -12,11 +12,12 @@ import {
12
12
ShopperCustomersTypes
13
13
} from 'commerce-sdk-isomorphic'
14
14
import jwtDecode from 'jwt-decode'
15
- import { ApiClientConfigParams , Argument } from '../hooks/types'
15
+ import { ApiClientConfigParams , Prettify , RemoveStringIndex } from '../hooks/types'
16
16
import { BaseStorage , LocalStorage , CookieStorage , MemoryStorage , StorageType } from './storage'
17
17
import { CustomerType } from '../hooks/useCustomerType'
18
18
import { onClient } from '../utils'
19
19
20
+ type TokenResponse = ShopperLoginTypes . TokenResponse
20
21
type Helpers = typeof helpers
21
22
interface AuthConfig extends ApiClientConfigParams {
22
23
redirectURI : string
@@ -30,24 +31,25 @@ interface JWTHeaders {
30
31
iat : number
31
32
}
32
33
33
- // this type is slightly different from ShopperLoginTypes.TokenResponse, reasons:
34
- // 1. TokenResponse is too generic (with & {[key:string]: any}), we need a more
35
- // restrictive type to make sure type safe
36
- // 2. The refresh tokens are stored separately for guest and registered user. Instead
37
- // of refresh_token, we have refresh_token_guest and refresh_token_registered
34
+ /**
35
+ * The extended field is not from api response, we manually store the auth type,
36
+ * so we don't need to make another API call when we already have the data.
37
+ * Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
38
+ * 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
39
+ */
40
+ export type AuthData = Prettify <
41
+ RemoveStringIndex < TokenResponse > & {
42
+ customer_type : CustomerType
43
+ idp_access_token : string
44
+ }
45
+ >
46
+
47
+ /** A shopper could be guest or registered, so we store the refresh tokens individually. */
38
48
type AuthDataKeys =
39
- | 'access_token'
40
- | 'customer_id'
41
- | 'enc_user_id'
42
- | 'expires_in'
43
- | 'id_token'
44
- | 'idp_access_token'
49
+ | Exclude < keyof AuthData , 'refresh_token' >
45
50
| 'refresh_token_guest'
46
51
| 'refresh_token_registered'
47
- | 'token_type'
48
- | 'usid'
49
- | 'site_id'
50
- | 'customer_type'
52
+
51
53
type AuthDataMap = Record <
52
54
AuthDataKeys ,
53
55
{
@@ -57,16 +59,6 @@ type AuthDataMap = Record<
57
59
}
58
60
>
59
61
60
- /**
61
- * The extended field is not from api response, we manually store the auth type,
62
- * so we don't need to make another API call when we already have the data.
63
- * Plus, the getCustomer endpoint only works for registered user, it returns a 404 for a guest user,
64
- * 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
65
- */
66
- type AuthData = ShopperLoginTypes . TokenResponse & {
67
- customer_type : CustomerType
68
- }
69
-
70
62
/**
71
63
* A map of the data that this auth module stores. This maps the name of the property to
72
64
* the storage type and the key when stored in that storage. You can also pass in a "callback"
@@ -119,10 +111,6 @@ const DATA_MAP: AuthDataMap = {
119
111
store . delete ( 'cc-nx-g' )
120
112
}
121
113
} ,
122
- site_id : {
123
- storageType : 'cookie' ,
124
- key : 'cc-site-id'
125
- } ,
126
114
customer_type : {
127
115
storageType : 'local' ,
128
116
key : 'customer_type'
@@ -141,7 +129,7 @@ class Auth {
141
129
private client : ShopperLogin < ApiClientConfigParams >
142
130
private shopperCustomersClient : ShopperCustomers < ApiClientConfigParams >
143
131
private redirectURI : string
144
- private pendingToken : Promise < ShopperLoginTypes . TokenResponse > | undefined
132
+ private pendingToken : Promise < TokenResponse > | undefined
145
133
private REFRESH_TOKEN_EXPIRATION_DAYS = 90
146
134
private stores : Record < StorageType , BaseStorage >
147
135
private fetchedToken : string
@@ -208,9 +196,10 @@ class Auth {
208
196
}
209
197
210
198
private clearStorage ( ) {
211
- Object . keys ( DATA_MAP ) . forEach ( ( keyName ) => {
212
- type Key = keyof AuthDataMap
213
- const { key, storageType} = DATA_MAP [ keyName as Key ]
199
+ // Type assertion because Object.keys is silly and limited :(
200
+ const keys = Object . keys ( DATA_MAP ) as AuthDataKeys [ ]
201
+ keys . forEach ( ( keyName ) => {
202
+ const { key, storageType} = DATA_MAP [ keyName ]
214
203
const store = this . stores [ storageType ]
215
204
store . delete ( key )
216
205
} )
@@ -248,7 +237,7 @@ class Auth {
248
237
* This method stores the TokenResponse object retrived from SLAS, and
249
238
* store the data in storage.
250
239
*/
251
- private handleTokenResponse ( res : ShopperLoginTypes . TokenResponse , isGuest : boolean ) {
240
+ private handleTokenResponse ( res : TokenResponse , isGuest : boolean ) {
252
241
this . set ( 'access_token' , res . access_token )
253
242
this . set ( 'customer_id' , res . customer_id )
254
243
this . set ( 'enc_user_id' , res . enc_user_id )
@@ -272,7 +261,7 @@ class Auth {
272
261
*
273
262
* @Internal
274
263
*/
275
- async queueRequest ( fn : ( ) => Promise < ShopperLoginTypes . TokenResponse > , isGuest : boolean ) {
264
+ async queueRequest ( fn : ( ) => Promise < TokenResponse > , isGuest : boolean ) {
276
265
const queue = this . pendingToken ?? Promise . resolve ( )
277
266
this . pendingToken = queue . then ( async ( ) => {
278
267
const token = await fn ( )
@@ -331,6 +320,20 @@ class Auth {
331
320
)
332
321
}
333
322
323
+ /**
324
+ * Creates a function that only executes after a session is initialized.
325
+ * @param fn Function that needs to wait until the session is initialized.
326
+ * @returns Wrapped function
327
+ */
328
+ whenReady < Args extends unknown [ ] , Data > (
329
+ fn : ( ...args : Args ) => Promise < Data >
330
+ ) : ( ...args : Args ) => Promise < Data > {
331
+ return async ( ...args ) => {
332
+ await this . ready ( )
333
+ return await fn ( ...args )
334
+ }
335
+ }
336
+
334
337
/**
335
338
* A wrapper method for commerce-sdk-isomorphic helper: loginGuestUser.
336
339
*
0 commit comments