@@ -18,10 +18,12 @@ limitations under the License.
18
18
* This is an internal module. See {@link MatrixHttpApi} for the public class.
19
19
*/
20
20
21
+ import { ErrorResponse as OidcAuthError } from "oidc-client-ts" ;
22
+
21
23
import { checkObjectHasKeys , encodeParams } from "../utils.ts" ;
22
24
import { type TypedEventEmitter } from "../models/typed-event-emitter.ts" ;
23
25
import { Method } from "./method.ts" ;
24
- import { ConnectionError , type MatrixError } from "./errors.ts" ;
26
+ import { ConnectionError , MatrixError , TokenRefreshError } from "./errors.ts" ;
25
27
import {
26
28
HttpApiEvent ,
27
29
type HttpApiEventHandlerMap ,
@@ -43,6 +45,12 @@ export type ResponseType<T, O extends IHttpOpts> = O extends undefined
43
45
? T
44
46
: TypedResponse < T > ;
45
47
48
+ const enum TokenRefreshOutcome {
49
+ Success = "success" ,
50
+ Failure = "failure" ,
51
+ Logout = "logout" ,
52
+ }
53
+
46
54
export class FetchHttpApi < O extends IHttpOpts > {
47
55
private abortController = new AbortController ( ) ;
48
56
@@ -174,29 +182,36 @@ export class FetchHttpApi<O extends IHttpOpts> {
174
182
const response = await this . request < T > ( method , path , queryParams , body , opts ) ;
175
183
return response ;
176
184
} catch ( error ) {
177
- const err = error as MatrixError ;
185
+ if ( ! ( error instanceof MatrixError ) ) {
186
+ throw error ;
187
+ }
178
188
179
- if ( err . errcode === "M_UNKNOWN_TOKEN" && ! opts . doNotAttemptTokenRefresh ) {
189
+ if ( error . errcode === "M_UNKNOWN_TOKEN" && ! opts . doNotAttemptTokenRefresh ) {
180
190
const tokenRefreshPromise = this . tryRefreshToken ( ) ;
181
191
this . tokenRefreshPromise = Promise . allSettled ( [ tokenRefreshPromise ] ) ;
182
- const shouldRetry = await tokenRefreshPromise ;
183
- // if we got a new token retry the request
184
- if ( shouldRetry ) {
192
+ const outcome = await tokenRefreshPromise ;
193
+
194
+ if ( outcome === TokenRefreshOutcome . Success ) {
195
+ // if we got a new token retry the request
185
196
return this . authedRequest ( method , path , queryParams , body , {
186
197
...paramOpts ,
187
198
doNotAttemptTokenRefresh : true ,
188
199
} ) ;
189
200
}
201
+ if ( outcome === TokenRefreshOutcome . Failure ) {
202
+ throw new TokenRefreshError ( error ) ;
203
+ }
204
+ // Fall through to SessionLoggedOut handler below
190
205
}
191
206
192
207
// otherwise continue with error handling
193
- if ( err . errcode == "M_UNKNOWN_TOKEN" && ! opts ?. inhibitLogoutEmit ) {
194
- this . eventEmitter . emit ( HttpApiEvent . SessionLoggedOut , err ) ;
195
- } else if ( err . errcode == "M_CONSENT_NOT_GIVEN" ) {
196
- this . eventEmitter . emit ( HttpApiEvent . NoConsent , err . message , err . data . consent_uri ) ;
208
+ if ( error . errcode == "M_UNKNOWN_TOKEN" && ! opts ?. inhibitLogoutEmit ) {
209
+ this . eventEmitter . emit ( HttpApiEvent . SessionLoggedOut , error ) ;
210
+ } else if ( error . errcode == "M_CONSENT_NOT_GIVEN" ) {
211
+ this . eventEmitter . emit ( HttpApiEvent . NoConsent , error . message , error . data . consent_uri ) ;
197
212
}
198
213
199
- throw err ;
214
+ throw error ;
200
215
}
201
216
}
202
217
@@ -206,20 +221,23 @@ export class FetchHttpApi<O extends IHttpOpts> {
206
221
* @returns Promise that resolves to a boolean - true when token was refreshed successfully
207
222
*/
208
223
@singleAsyncExecution
209
- private async tryRefreshToken ( ) : Promise < boolean > {
224
+ private async tryRefreshToken ( ) : Promise < TokenRefreshOutcome > {
210
225
if ( ! this . opts . refreshToken || ! this . opts . tokenRefreshFunction ) {
211
- return false ;
226
+ return TokenRefreshOutcome . Logout ;
212
227
}
213
228
214
229
try {
215
230
const { accessToken, refreshToken } = await this . opts . tokenRefreshFunction ( this . opts . refreshToken ) ;
216
231
this . opts . accessToken = accessToken ;
217
232
this . opts . refreshToken = refreshToken ;
218
233
// successfully got new tokens
219
- return true ;
234
+ return TokenRefreshOutcome . Success ;
220
235
} catch ( error ) {
221
236
this . opts . logger ?. warn ( "Failed to refresh token" , error ) ;
222
- return false ;
237
+ if ( error instanceof OidcAuthError || error instanceof MatrixError ) {
238
+ return TokenRefreshOutcome . Logout ;
239
+ }
240
+ return TokenRefreshOutcome . Failure ;
223
241
}
224
242
}
225
243
0 commit comments