1+ import isFunction from 'lodash/isFunction' ;
12import {
23 ERROR_INVALID_CONFIG ,
34} from './const' ;
@@ -6,26 +7,70 @@ import TokenExpiredException from './services/TokenExpiredException';
67import RetryCountExceededException from './services/RetryCountExceededException' ;
78import AccessTokenProvider from './AccessTokenProvider' ;
89
10+ /**
11+ * Prepares signed request object which can be used for renewing access token
12+ *
13+ * @callback createAccessTokenRequest
14+ * @param {string } refreshToken Refresh token used to sign the request
15+ * @returns {Request } Signed request object which can be used to get access token
16+ */
17+
18+ /**
19+ * Parses access token from access token response object
20+ *
21+ * @callback parseAccessToken
22+ * @param {Response } response Response object with access token
23+ * @returns {string } Access token parsed from response
24+ */
25+
26+ /**
27+ * Checks whether interceptor will intercept this request or just let it pass through
28+ *
29+ * @callback shouldIntercept
30+ * @param {Request } request Request object
31+ * @returns {bool } A value indicating whether this request should be intercepted
32+ */
33+
34+ /**
35+ * Checks whether provided response invalidates current access token
36+ *
37+ * @callback shouldInvalidateAccessToken
38+ * @param {Response } response Response object
39+ * @returns {bool } A value indicating whether token should be invalidated
40+ */
41+
42+ /**
43+ * Adds authorization for intercepted requests
44+ *
45+ * @callback authorizeRequest
46+ * @param {Request } request Request object being intercepted
47+ * @param {string } accessToken Current access token
48+ * @returns {Request } Authorized request object
49+ */
50+
51+ const getDefaultConfig = ( ) => ( {
52+ fetchRetryCount : 1 ,
53+ createAccessTokenRequest : null ,
54+ shouldIntercept : ( ) => false ,
55+ shouldInvalidateAccessToken : ( ) => false ,
56+ isResponseUnauthorized : http . isResponseUnauthorized ,
57+ parseAccessToken : null ,
58+ authorizeRequest : null ,
59+ onAccessTokenChange : null ,
60+ onResponse : null ,
61+ } ) ;
62+
963/**
1064 * Provides a default implementation for intercepting fetch requests. It will try to resolve
1165 * unauthorized responses by renewing the access token and repeating the initial request.
1266 */
13- export default class FetchInterceptor {
67+ class FetchInterceptor {
1468 constructor ( fetch ) {
1569 // stores reference to vanilla fetch method
1670 this . fetch = fetch ;
71+ this . accessTokenProvider = new AccessTokenProvider ( this . fetch ) ;
1772
18- this . config = {
19- fetchRetryCount : 1 ,
20- createAccessTokenRequest : null ,
21- shouldIntercept : ( ) => true ,
22- shouldInvalidateAccessToken : ( ) => false ,
23- isResponseUnauthorized : http . isResponseUnauthorized ,
24- parseAccessToken : null ,
25- authorizeRequest : null ,
26- onAccessTokenChange : null ,
27- onResponse : null ,
28- } ;
73+ this . config = getDefaultConfig ( ) ;
2974
3075 this . intercept = this . intercept . bind ( this ) ;
3176
@@ -48,37 +93,28 @@ export default class FetchInterceptor {
4893 * Configures fetch interceptor with given config object. All required properties can optionally
4994 * return a promise which will be resolved by fetch interceptor automatically.
5095 *
51- * @param config
52- *
53- * (Required) Prepare fetch request for renewing new access token
54- * createAccessTokenRequest: (refreshToken) => request,
55- *
56- * (Required) Parses access token from access token response
57- * parseAccessToken: (response) => accessToken,
58- *
59- * (Required) Defines whether interceptor will intercept this request or just let it pass through
60- * shouldIntercept: (request) => boolean,
61- *
62- * (Required) Defines whether access token will be invalidated after this response
63- * shouldInvalidateAccessToken: (response) => boolean,
64- *
65- * (Required) Adds authorization for intercepted requests
66- * authorizeRequest: (request, accessToken) => authorizedRequest,
67- *
68- * Checks if response should be considered unauthorized (by default only 401 responses are
69- * considered unauthorized. Override this method if you need to trigger token renewal for
70- * other response statuses.
71- * isResponseUnauthorized: (response) => boolean,
72- *
73- * Number of retries after initial request was unauthorized
74- * fetchRetryCount: 1,
75- *
76- * Event invoked when access token has changed
77- * onAccessTokenChange: null,
78- *
79- * Event invoked when response is resolved
80- * onResponse: null,
81- *
96+ * @param {object } config
97+ * @param {createAccessTokenRequest } config.createAccessTokenRequest
98+ * Prepare fetch request for renewing new access token
99+ * @param {parseAccessToken } config.parseAccessToken
100+ * Parses access token from access token response
101+ * @param {shouldIntercept } config.shouldIntercept
102+ * Defines whether interceptor will intercept this request or just let it pass through
103+ * @param {shouldInvalidateAccessToken } config.shouldInvalidateAccessToken
104+ * Defines whether access token will be invalidated after this response
105+ * @param {authorizeRequest } config.authorizeRequest
106+ * Adds authorization for intercepted requests
107+ * @param {function } [config.isResponseUnauthorized=null]
108+ * Checks if response should be considered unauthorized (by default only 401 responses are
109+ * considered unauthorized. Override this method if you need to trigger token renewal for
110+ * other response statuses.
111+ * @param {number } [config.fetchRetryCount=1]
112+ * Number of retries after initial request was unauthorized
113+ * @param {number } [config.onAccessTokenChange=null]
114+ * Event invoked when access token has changed
115+ * @param {number } [config.onResponse=null]
116+ * Event invoked when response is resolved
117+ * </pre>
82118 */
83119 configure ( config ) {
84120 this . config = { ...this . config , ...config } ;
@@ -87,13 +123,13 @@ export default class FetchInterceptor {
87123 throw new Error ( ERROR_INVALID_CONFIG ) ;
88124 }
89125
90- this . accessTokenProvider = new AccessTokenProvider ( this . fetch , this . config ) ;
126+ this . accessTokenProvider . configure ( this . config ) ;
91127 }
92128
93129 /**
94130 * Authorizes fetch interceptor with given refresh token
95- * @param refreshToken
96- * @param accessToken
131+ * @param { string } refreshToken Refresh token
132+ * @param { string } accessToken Access token
97133 */
98134 authorize ( refreshToken , accessToken ) {
99135 this . accessTokenProvider . authorize ( refreshToken , accessToken ) ;
@@ -114,6 +150,15 @@ export default class FetchInterceptor {
114150 this . accessTokenProvider . clear ( ) ;
115151 }
116152
153+ /**
154+ * Clears current authorization and restores default configuration, e.g. interceptor
155+ * will stop intercepting requests.
156+ */
157+ unload ( ) {
158+ this . clear ( ) ;
159+ this . config = getDefaultConfig ( ) ;
160+ }
161+
117162 /**
118163 * Main intercept method, you should chain this inside wrapped fetch call
119164 * @param args Args initially provided to fetch method
@@ -124,10 +169,11 @@ export default class FetchInterceptor {
124169 }
125170
126171 isConfigValid ( ) {
127- return this . config . shouldIntercept &&
128- this . config . authorizeRequest &&
129- this . config . createAccessTokenRequest &&
130- this . config . parseAccessToken ;
172+ return this . config . shouldIntercept && isFunction ( this . config . shouldIntercept ) &&
173+ this . config . authorizeRequest && isFunction ( this . config . authorizeRequest ) &&
174+ this . config . isResponseUnauthorized && isFunction ( this . config . isResponseUnauthorized ) &&
175+ this . config . createAccessTokenRequest && isFunction ( this . config . createAccessTokenRequest ) &&
176+ this . config . parseAccessToken && isFunction ( this . config . parseAccessToken ) ;
131177 }
132178
133179 resolveIntercept ( resolve , reject , ...args ) {
@@ -357,3 +403,5 @@ export default class FetchInterceptor {
357403 throw new Error ( error ) ;
358404 }
359405}
406+
407+ export default FetchInterceptor ;
0 commit comments