|
17 | 17 |
|
18 | 18 | import { FirebaseError, querystring } from '@firebase/util';
|
19 | 19 |
|
20 |
| -import { |
21 |
| - AUTH_ERROR_FACTORY, |
22 |
| - AuthErrorCode, |
23 |
| - NamedErrorParams |
24 |
| -} from '../core/errors'; |
| 20 | +import { AUTH_ERROR_FACTORY, AuthErrorCode, NamedErrorParams } from '../core/errors'; |
25 | 21 | import { fail } from '../core/util/assert';
|
26 | 22 | import { Delay } from '../core/util/delay';
|
27 | 23 | import { _emulatorUrl } from '../core/util/emulator';
|
@@ -120,11 +116,16 @@ export async function _performFetchWithErrorHandling<V>(
|
120 | 116 | (auth as Auth)._canInitEmulator = false;
|
121 | 117 | const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap };
|
122 | 118 | try {
|
| 119 | + const networkTimeout = new NetworkTimeout<Response>(auth.name); |
123 | 120 | const response: Response = await Promise.race<Promise<Response>>([
|
124 | 121 | fetchFn(),
|
125 |
| - makeNetworkTimeout(auth.name) |
| 122 | + networkTimeout.promise |
126 | 123 | ]);
|
127 | 124 |
|
| 125 | + // If we've reached this point, the fetch succeeded and the networkTimeout |
| 126 | + // didn't throw; clear the network timeout delay so that Node won't hang |
| 127 | + networkTimeout.clearNetworkTimeout(); |
| 128 | + |
128 | 129 | const json = await response.json();
|
129 | 130 | if ('needConfirmation' in json) {
|
130 | 131 | throw makeTaggedError(auth, AuthErrorCode.NEED_CONFIRMATION, json);
|
@@ -201,16 +202,26 @@ export function _getFinalTarget(
|
201 | 202 | return _emulatorUrl(auth.config, base);
|
202 | 203 | }
|
203 | 204 |
|
204 |
| -function makeNetworkTimeout<T>(appName: string): Promise<T> { |
205 |
| - return new Promise((_, reject) => |
206 |
| - setTimeout(() => { |
| 205 | +class NetworkTimeout<T> { |
| 206 | + // Node timers and browser timers are fundamentally incompatible, but we |
| 207 | + // don't care about the value here |
| 208 | + // eslint-disable-next-line @typescript-eslint/no-explicit-any |
| 209 | + private timer: any|null = null; |
| 210 | + readonly promise = new Promise<T>((_, reject) => { |
| 211 | + this.timer = setTimeout(() => { |
207 | 212 | return reject(
|
208 | 213 | AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, {
|
209 |
| - appName |
| 214 | + appName: this.appName |
210 | 215 | })
|
211 | 216 | );
|
212 |
| - }, DEFAULT_API_TIMEOUT_MS.get()) |
213 |
| - ); |
| 217 | + }, DEFAULT_API_TIMEOUT_MS.get()); |
| 218 | + }); |
| 219 | + |
| 220 | + clearNetworkTimeout():void { |
| 221 | + clearTimeout(this.timer); |
| 222 | + } |
| 223 | + |
| 224 | + constructor(private readonly appName: string) {} |
214 | 225 | }
|
215 | 226 |
|
216 | 227 | interface PotentialResponse extends IdTokenResponse {
|
|
0 commit comments