Skip to content

Commit 47b0913

Browse files
authored
Support restart of FirestoreClient (#8430)
* Support restart of FirestoreClient * Fix errors * Pretty * Fix * lint * pretty * fix * undo not required changes * Only appy required test changes * Apply suggestions from Andy * Fixes from PR review
1 parent 2561b63 commit 47b0913

13 files changed

+274
-202
lines changed

.changeset/small-geckos-mix.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/firestore': patch
3+
---
4+
5+
Refactor Firestore client instantiation. This prepares for future features that require client to restart.

packages/firestore/src/api/cache_config.ts

+45-38
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import {
2020
LruGcMemoryOfflineComponentProvider,
2121
MemoryOfflineComponentProvider,
2222
MultiTabOfflineComponentProvider,
23-
OfflineComponentProvider,
23+
OfflineComponentProviderFactory,
24+
OnlineComponentProviderFactory,
2425
OnlineComponentProvider
2526
} from '../core/component_provider';
2627

@@ -38,31 +39,31 @@ export type MemoryLocalCache = {
3839
/**
3940
* @internal
4041
*/
41-
_onlineComponentProvider: OnlineComponentProvider;
42+
_onlineComponentProvider: OnlineComponentProviderFactory;
4243
/**
4344
* @internal
4445
*/
45-
_offlineComponentProvider: MemoryOfflineComponentProvider;
46+
_offlineComponentProvider: OfflineComponentProviderFactory;
4647
};
4748

4849
class MemoryLocalCacheImpl implements MemoryLocalCache {
4950
kind: 'memory' = 'memory';
5051
/**
5152
* @internal
5253
*/
53-
_onlineComponentProvider: OnlineComponentProvider;
54+
_onlineComponentProvider: OnlineComponentProviderFactory;
5455
/**
5556
* @internal
5657
*/
57-
_offlineComponentProvider: MemoryOfflineComponentProvider;
58+
_offlineComponentProvider: OfflineComponentProviderFactory;
5859

5960
constructor(settings?: MemoryCacheSettings) {
60-
this._onlineComponentProvider = new OnlineComponentProvider();
61+
this._onlineComponentProvider = OnlineComponentProvider.provider;
6162
if (settings?.garbageCollector) {
6263
this._offlineComponentProvider =
6364
settings.garbageCollector._offlineComponentProvider;
6465
} else {
65-
this._offlineComponentProvider = new MemoryOfflineComponentProvider();
66+
this._offlineComponentProvider = MemoryOfflineComponentProvider.provider;
6667
}
6768
}
6869

@@ -83,23 +84,23 @@ export type PersistentLocalCache = {
8384
/**
8485
* @internal
8586
*/
86-
_onlineComponentProvider: OnlineComponentProvider;
87+
_onlineComponentProvider: OnlineComponentProviderFactory;
8788
/**
8889
* @internal
8990
*/
90-
_offlineComponentProvider: OfflineComponentProvider;
91+
_offlineComponentProvider: OfflineComponentProviderFactory;
9192
};
9293

9394
class PersistentLocalCacheImpl implements PersistentLocalCache {
9495
kind: 'persistent' = 'persistent';
9596
/**
9697
* @internal
9798
*/
98-
_onlineComponentProvider: OnlineComponentProvider;
99+
_onlineComponentProvider: OnlineComponentProviderFactory;
99100
/**
100101
* @internal
101102
*/
102-
_offlineComponentProvider: OfflineComponentProvider;
103+
_offlineComponentProvider: OfflineComponentProviderFactory;
103104

104105
constructor(settings: PersistentCacheSettings | undefined) {
105106
let tabManager: PersistentTabManager;
@@ -147,7 +148,7 @@ export type MemoryEagerGarbageCollector = {
147148
/**
148149
* @internal
149150
*/
150-
_offlineComponentProvider: MemoryOfflineComponentProvider;
151+
_offlineComponentProvider: OfflineComponentProviderFactory;
151152
};
152153

153154
/**
@@ -167,18 +168,18 @@ export type MemoryLruGarbageCollector = {
167168
/**
168169
* @internal
169170
*/
170-
_offlineComponentProvider: MemoryOfflineComponentProvider;
171+
_offlineComponentProvider: OfflineComponentProviderFactory;
171172
};
172173

173174
class MemoryEagerGarbageCollectorImpl implements MemoryEagerGarbageCollector {
174175
kind: 'memoryEager' = 'memoryEager';
175176
/**
176177
* @internal
177178
*/
178-
_offlineComponentProvider: MemoryOfflineComponentProvider;
179+
_offlineComponentProvider: OfflineComponentProviderFactory;
179180

180181
constructor() {
181-
this._offlineComponentProvider = new MemoryOfflineComponentProvider();
182+
this._offlineComponentProvider = MemoryOfflineComponentProvider.provider;
182183
}
183184

184185
toJSON(): {} {
@@ -191,12 +192,12 @@ class MemoryLruGarbageCollectorImpl implements MemoryLruGarbageCollector {
191192
/**
192193
* @internal
193194
*/
194-
_offlineComponentProvider: MemoryOfflineComponentProvider;
195+
_offlineComponentProvider: OfflineComponentProviderFactory;
195196

196197
constructor(cacheSize?: number) {
197-
this._offlineComponentProvider = new LruGcMemoryOfflineComponentProvider(
198-
cacheSize
199-
);
198+
this._offlineComponentProvider = {
199+
build: () => new LruGcMemoryOfflineComponentProvider(cacheSize)
200+
};
200201
}
201202

202203
toJSON(): {} {
@@ -297,11 +298,11 @@ export type PersistentSingleTabManager = {
297298
/**
298299
* @internal
299300
*/
300-
_onlineComponentProvider?: OnlineComponentProvider;
301+
_onlineComponentProvider?: OnlineComponentProviderFactory;
301302
/**
302303
* @internal
303304
*/
304-
_offlineComponentProvider?: OfflineComponentProvider;
305+
_offlineComponentProvider?: OfflineComponentProviderFactory;
305306
};
306307

307308
class SingleTabManagerImpl implements PersistentSingleTabManager {
@@ -310,11 +311,11 @@ class SingleTabManagerImpl implements PersistentSingleTabManager {
310311
/**
311312
* @internal
312313
*/
313-
_onlineComponentProvider?: OnlineComponentProvider;
314+
_onlineComponentProvider?: OnlineComponentProviderFactory;
314315
/**
315316
* @internal
316317
*/
317-
_offlineComponentProvider?: OfflineComponentProvider;
318+
_offlineComponentProvider?: OfflineComponentProviderFactory;
318319

319320
constructor(private forceOwnership?: boolean) {}
320321

@@ -328,12 +329,15 @@ class SingleTabManagerImpl implements PersistentSingleTabManager {
328329
_initialize(
329330
settings: Omit<PersistentCacheSettings, 'tabManager'> | undefined
330331
): void {
331-
this._onlineComponentProvider = new OnlineComponentProvider();
332-
this._offlineComponentProvider = new IndexedDbOfflineComponentProvider(
333-
this._onlineComponentProvider,
334-
settings?.cacheSizeBytes,
335-
this.forceOwnership
336-
);
332+
this._onlineComponentProvider = OnlineComponentProvider.provider;
333+
this._offlineComponentProvider = {
334+
build: (onlineComponents: OnlineComponentProvider) =>
335+
new IndexedDbOfflineComponentProvider(
336+
onlineComponents,
337+
settings?.cacheSizeBytes,
338+
this.forceOwnership
339+
)
340+
};
337341
}
338342
}
339343

@@ -350,12 +354,12 @@ export type PersistentMultipleTabManager = {
350354
/**
351355
* @internal
352356
*/
353-
_onlineComponentProvider?: OnlineComponentProvider;
357+
_onlineComponentProvider?: OnlineComponentProviderFactory;
354358
/**
355359
* @internal
356360
*/
357361

358-
_offlineComponentProvider?: OfflineComponentProvider;
362+
_offlineComponentProvider?: OfflineComponentProviderFactory;
359363
};
360364

361365
class MultiTabManagerImpl implements PersistentMultipleTabManager {
@@ -364,11 +368,11 @@ class MultiTabManagerImpl implements PersistentMultipleTabManager {
364368
/**
365369
* @internal
366370
*/
367-
_onlineComponentProvider?: OnlineComponentProvider;
371+
_onlineComponentProvider?: OnlineComponentProviderFactory;
368372
/**
369373
* @internal
370374
*/
371-
_offlineComponentProvider?: OfflineComponentProvider;
375+
_offlineComponentProvider?: OfflineComponentProviderFactory;
372376

373377
toJSON(): {} {
374378
return { kind: this.kind };
@@ -380,11 +384,14 @@ class MultiTabManagerImpl implements PersistentMultipleTabManager {
380384
_initialize(
381385
settings: Omit<PersistentCacheSettings, 'tabManager'> | undefined
382386
): void {
383-
this._onlineComponentProvider = new OnlineComponentProvider();
384-
this._offlineComponentProvider = new MultiTabOfflineComponentProvider(
385-
this._onlineComponentProvider,
386-
settings?.cacheSizeBytes
387-
);
387+
this._onlineComponentProvider = OnlineComponentProvider.provider;
388+
this._offlineComponentProvider = {
389+
build: (onlineComponents: OnlineComponentProvider) =>
390+
new MultiTabOfflineComponentProvider(
391+
onlineComponents,
392+
settings?.cacheSizeBytes
393+
)
394+
};
388395
}
389396
}
390397

packages/firestore/src/api/credentials.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export class FirebaseAuthCredentialsProvider
235235
* The auth token listener registered with FirebaseApp, retained here so we
236236
* can unregister it.
237237
*/
238-
private tokenListener!: () => void;
238+
private tokenListener: (() => void) | undefined;
239239

240240
/** Tracks the current User. */
241241
private currentUser: User = User.UNAUTHENTICATED;
@@ -256,6 +256,10 @@ export class FirebaseAuthCredentialsProvider
256256
asyncQueue: AsyncQueue,
257257
changeListener: CredentialChangeListener<User>
258258
): void {
259+
hardAssert(
260+
this.tokenListener === undefined,
261+
'Token listener already added'
262+
);
259263
let lastTokenId = this.tokenCounter;
260264

261265
// A change listener that prevents double-firing for the same token change.
@@ -293,8 +297,10 @@ export class FirebaseAuthCredentialsProvider
293297
const registerAuth = (auth: FirebaseAuthInternal): void => {
294298
logDebug('FirebaseAuthCredentialsProvider', 'Auth detected');
295299
this.auth = auth;
296-
this.auth.addAuthTokenListener(this.tokenListener);
297-
awaitNextToken();
300+
if (this.tokenListener) {
301+
this.auth.addAuthTokenListener(this.tokenListener);
302+
awaitNextToken();
303+
}
298304
};
299305

300306
this.authProvider.onInit(auth => registerAuth(auth));
@@ -365,9 +371,10 @@ export class FirebaseAuthCredentialsProvider
365371
}
366372

367373
shutdown(): void {
368-
if (this.auth) {
369-
this.auth.removeAuthTokenListener(this.tokenListener!);
374+
if (this.auth && this.tokenListener) {
375+
this.auth.removeAuthTokenListener(this.tokenListener);
370376
}
377+
this.tokenListener = undefined;
371378
}
372379

373380
// Auth.getUid() can return null even with a user logged in. It is because
@@ -484,7 +491,7 @@ export class FirebaseAppCheckTokenProvider
484491
* The AppCheck token listener registered with FirebaseApp, retained here so
485492
* we can unregister it.
486493
*/
487-
private tokenListener!: AppCheckTokenListener;
494+
private tokenListener: AppCheckTokenListener | undefined;
488495
private forceRefresh = false;
489496
private appCheck: FirebaseAppCheckInternal | null = null;
490497
private latestAppCheckToken: string | null = null;
@@ -497,6 +504,11 @@ export class FirebaseAppCheckTokenProvider
497504
asyncQueue: AsyncQueue,
498505
changeListener: CredentialChangeListener<string>
499506
): void {
507+
hardAssert(
508+
this.tokenListener === undefined,
509+
'Token listener already added'
510+
);
511+
500512
const onTokenChanged: (
501513
tokenResult: AppCheckTokenResult
502514
) => Promise<void> = tokenResult => {
@@ -524,7 +536,9 @@ export class FirebaseAppCheckTokenProvider
524536
const registerAppCheck = (appCheck: FirebaseAppCheckInternal): void => {
525537
logDebug('FirebaseAppCheckTokenProvider', 'AppCheck detected');
526538
this.appCheck = appCheck;
527-
this.appCheck.addTokenListener(this.tokenListener);
539+
if (this.tokenListener) {
540+
this.appCheck.addTokenListener(this.tokenListener);
541+
}
528542
};
529543

530544
this.appCheckProvider.onInit(appCheck => registerAppCheck(appCheck));
@@ -579,9 +593,10 @@ export class FirebaseAppCheckTokenProvider
579593
}
580594

581595
shutdown(): void {
582-
if (this.appCheck) {
583-
this.appCheck.removeTokenListener(this.tokenListener!);
596+
if (this.appCheck && this.tokenListener) {
597+
this.appCheck.removeTokenListener(this.tokenListener);
584598
}
599+
this.tokenListener = undefined;
585600
}
586601
}
587602

0 commit comments

Comments
 (0)