Skip to content

Commit 48d814b

Browse files
Simplify ComponentProviders
1 parent eeb1dfa commit 48d814b

File tree

14 files changed

+290
-353
lines changed

14 files changed

+290
-353
lines changed

packages/firestore/exp/src/api/components.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717

1818
import { FirebaseFirestore } from './database';
19-
import { PersistenceSettings } from '../../../src/core/firestore_client';
2019
import {
2120
MemoryOfflineComponentProvider,
2221
OfflineComponentProvider,
@@ -55,16 +54,13 @@ const onlineComponentProviders = new Map<
5554

5655
export async function setOfflineComponentProvider(
5756
firestore: FirebaseFirestore,
58-
persistenceSettings: PersistenceSettings,
5957
offlineComponentProvider: OfflineComponentProvider
6058
): Promise<void> {
6159
const offlineDeferred = new Deferred<OfflineComponentProvider>();
6260
offlineComponentProviders.set(firestore, offlineDeferred.promise);
6361

64-
const configuration = await firestore._getConfiguration();
65-
configuration.persistenceSettings = persistenceSettings;
66-
6762
logDebug(LOG_TAG, 'Initializing OfflineComponentProvider');
63+
const configuration = await firestore._getConfiguration();
6864
await offlineComponentProvider.initialize(configuration);
6965
firestore._setCredentialChangeListener(user =>
7066
// TODO(firestorexp): This should be a retryable IndexedDB operation
@@ -121,7 +117,6 @@ function getOfflineComponentProvider(
121117
// eslint-disable-next-line @typescript-eslint/no-floating-promises
122118
setOfflineComponentProvider(
123119
firestore,
124-
{ durable: false },
125120
new MemoryOfflineComponentProvider()
126121
);
127122
}

packages/firestore/exp/src/api/database.ts

Lines changed: 94 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
ComponentConfiguration,
3030
IndexedDbOfflineComponentProvider,
3131
MultiTabOfflineComponentProvider,
32+
OfflineComponentProvider,
3233
OnlineComponentProvider
3334
} from '../../../src/core/component_provider';
3435
import {
@@ -66,6 +67,11 @@ import { PersistenceSettings } from '../../../exp-types';
6667

6768
const LOG_TAG = 'Firestore';
6869

70+
/** DOMException error code constants. */
71+
const DOM_EXCEPTION_INVALID_STATE = 11;
72+
const DOM_EXCEPTION_ABORTED = 20;
73+
const DOM_EXCEPTION_QUOTA_EXCEEDED = 22;
74+
6975
export interface Settings extends LiteSettings {
7076
cacheSizeBytes?: number;
7177
}
@@ -130,9 +136,7 @@ export class FirebaseFirestore
130136
clientId: this._clientId,
131137
credentials: this._credentials,
132138
initialUser: this._user,
133-
maxConcurrentLimboResolutions: MAX_CONCURRENT_LIMBO_RESOLUTIONS,
134-
// Note: This will be overwritten if IndexedDB persistence is enabled.
135-
persistenceSettings: { durable: false }
139+
maxConcurrentLimboResolutions: MAX_CONCURRENT_LIMBO_RESOLUTIONS
136140
};
137141
}
138142

@@ -259,23 +263,15 @@ export function enableIndexedDbPersistence(
259263

260264
const onlineComponentProvider = new OnlineComponentProvider();
261265
const offlineComponentProvider = new IndexedDbOfflineComponentProvider(
262-
onlineComponentProvider
266+
onlineComponentProvider,
267+
settings.cacheSizeBytes,
268+
persistenceSettings?.forceOwnership
269+
);
270+
return setPersistenceProviders(
271+
firestore,
272+
onlineComponentProvider,
273+
offlineComponentProvider
263274
);
264-
265-
return firestore._queue.enqueue(async () => {
266-
await setOfflineComponentProvider(
267-
firestore,
268-
{
269-
durable: true,
270-
synchronizeTabs: false,
271-
cacheSizeBytes:
272-
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES,
273-
forceOwningTab: !!persistenceSettings?.forceOwnership
274-
},
275-
offlineComponentProvider
276-
);
277-
await setOnlineComponentProvider(firestore, onlineComponentProvider);
278-
});
279275
}
280276

281277
/**
@@ -313,22 +309,87 @@ export function enableMultiTabIndexedDbPersistence(
313309

314310
const onlineComponentProvider = new OnlineComponentProvider();
315311
const offlineComponentProvider = new MultiTabOfflineComponentProvider(
316-
onlineComponentProvider
312+
onlineComponentProvider,
313+
settings.cacheSizeBytes
317314
);
318-
return firestore._queue.enqueue(async () => {
319-
await setOfflineComponentProvider(
320-
firestore,
321-
{
322-
durable: true,
323-
synchronizeTabs: true,
324-
cacheSizeBytes:
325-
settings.cacheSizeBytes || LruParams.DEFAULT_CACHE_SIZE_BYTES,
326-
forceOwningTab: false
327-
},
328-
offlineComponentProvider
315+
return setPersistenceProviders(
316+
firestore,
317+
onlineComponentProvider,
318+
offlineComponentProvider
319+
);
320+
}
321+
322+
/**
323+
* Registers both the `OfflineComponentProvider` and `OnlineComponentProvider`.
324+
* If the operation fails with a recoverable error (see
325+
* `canRecoverFromIndexedDbError()` below), the returned Promise is rejected
326+
* but the client remains usable.
327+
*/
328+
function setPersistenceProviders(
329+
firestore: FirebaseFirestore,
330+
onlineComponentProvider: OnlineComponentProvider,
331+
offlineComponentProvider: OfflineComponentProvider
332+
): Promise<void> {
333+
const persistenceResult = new Deferred();
334+
return firestore._queue
335+
.enqueue(async () => {
336+
try {
337+
await setOfflineComponentProvider(firestore, offlineComponentProvider);
338+
await setOnlineComponentProvider(firestore, onlineComponentProvider);
339+
persistenceResult.resolve();
340+
} catch (e) {
341+
if (!canFallbackFromIndexedDbError(e)) {
342+
throw e;
343+
}
344+
console.warn(
345+
'Error enabling offline persistence. Falling back to ' +
346+
'persistence disabled: ' +
347+
e
348+
);
349+
persistenceResult.reject(e);
350+
}
351+
})
352+
.then(() => persistenceResult.promise);
353+
}
354+
355+
/**
356+
* Decides whether the provided error allows us to gracefully disable
357+
* persistence (as opposed to crashing the client).
358+
*/
359+
// TODO(schmidt-sebastian): Remove `export` in
360+
// https://github.com/firebase/firebase-js-sdk/pull/3901
361+
export function canFallbackFromIndexedDbError(
362+
error: FirestoreError | DOMException
363+
): boolean {
364+
if (error.name === 'FirebaseError') {
365+
return (
366+
error.code === Code.FAILED_PRECONDITION ||
367+
error.code === Code.UNIMPLEMENTED
329368
);
330-
await setOnlineComponentProvider(firestore, onlineComponentProvider);
331-
});
369+
} else if (
370+
typeof DOMException !== 'undefined' &&
371+
error instanceof DOMException
372+
) {
373+
// There are a few known circumstances where we can open IndexedDb but
374+
// trying to read/write will fail (e.g. quota exceeded). For
375+
// well-understood cases, we attempt to detect these and then gracefully
376+
// fall back to memory persistence.
377+
// NOTE: Rather than continue to add to this list, we could decide to
378+
// always fall back, with the risk that we might accidentally hide errors
379+
// representing actual SDK bugs.
380+
return (
381+
// When the browser is out of quota we could get either quota exceeded
382+
// or an aborted error depending on whether the error happened during
383+
// schema migration.
384+
error.code === DOM_EXCEPTION_QUOTA_EXCEEDED ||
385+
error.code === DOM_EXCEPTION_ABORTED ||
386+
// Firefox Private Browsing mode disables IndexedDb and returns
387+
// INVALID_STATE for any usage.
388+
error.code === DOM_EXCEPTION_INVALID_STATE
389+
);
390+
}
391+
392+
return true;
332393
}
333394

334395
/**

packages/firestore/index.memory.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@
1818
import firebase from '@firebase/app';
1919
import { FirebaseNamespace } from '@firebase/app-types';
2020

21-
import { Firestore } from './src/api/database';
22-
import {
23-
MemoryOfflineComponentProvider,
24-
OnlineComponentProvider
25-
} from './src/core/component_provider';
21+
import { Firestore, MemoryPersistenceProvider } from './src/api/database';
2622
import { configureForFirebase } from './src/config';
2723

2824
import './register-module';
@@ -35,13 +31,7 @@ import { name, version } from './package.json';
3531
export function registerFirestore(instance: FirebaseNamespace): void {
3632
configureForFirebase(
3733
instance,
38-
(app, auth) =>
39-
new Firestore(
40-
app,
41-
auth,
42-
new MemoryOfflineComponentProvider(),
43-
new OnlineComponentProvider()
44-
)
34+
(app, auth) => new Firestore(app, auth, new MemoryPersistenceProvider())
4535
);
4636
instance.registerVersion(name, version);
4737
}

packages/firestore/index.node.memory.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@
1818
import firebase from '@firebase/app';
1919
import { FirebaseNamespace } from '@firebase/app-types';
2020

21-
import { Firestore } from './src/api/database';
22-
import {
23-
MemoryOfflineComponentProvider,
24-
OnlineComponentProvider
25-
} from './src/core/component_provider';
21+
import { Firestore, MemoryPersistenceProvider } from './src/api/database';
2622
import { configureForFirebase } from './src/config';
2723
import './register-module';
2824

@@ -35,13 +31,7 @@ import { name, version } from './package.json';
3531
export function registerFirestore(instance: FirebaseNamespace): void {
3632
configureForFirebase(
3733
instance,
38-
(app, auth) =>
39-
new Firestore(
40-
app,
41-
auth,
42-
new MemoryOfflineComponentProvider(),
43-
new OnlineComponentProvider()
44-
)
34+
(app, auth) => new Firestore(app, auth, new MemoryPersistenceProvider())
4535
);
4636
instance.registerVersion(name, version, 'node');
4737
}

packages/firestore/index.node.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
import firebase from '@firebase/app';
1818
import { FirebaseNamespace } from '@firebase/app-types';
1919

20-
import { Firestore } from './src/api/database';
21-
import {
22-
MultiTabOfflineComponentProvider,
23-
OnlineComponentProvider
24-
} from './src/core/component_provider';
20+
import { Firestore, IndexedDbPersistenceProvider } from './src/api/database';
2521
import { configureForFirebase } from './src/config';
2622

2723
import './register-module';
@@ -34,16 +30,7 @@ import { name, version } from './package.json';
3430
*/
3531
export function registerFirestore(instance: FirebaseNamespace): void {
3632
configureForFirebase(instance, (app, auth) => {
37-
const onlineComponentProvider = new OnlineComponentProvider();
38-
const offlineComponentProvider = new MultiTabOfflineComponentProvider(
39-
onlineComponentProvider
40-
);
41-
return new Firestore(
42-
app,
43-
auth,
44-
offlineComponentProvider,
45-
onlineComponentProvider
46-
);
33+
return new Firestore(app, auth, new IndexedDbPersistenceProvider());
4734
});
4835
instance.registerVersion(name, version, 'node');
4936
}

packages/firestore/index.rn.memory.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@
1818
import firebase from '@firebase/app';
1919
import { FirebaseNamespace } from '@firebase/app-types';
2020

21-
import { Firestore } from './src/api/database';
22-
import {
23-
MemoryOfflineComponentProvider,
24-
OnlineComponentProvider
25-
} from './src/core/component_provider';
21+
import { Firestore, MemoryPersistenceProvider } from './src/api/database';
2622
import { configureForFirebase } from './src/config';
2723

2824
import './register-module';
@@ -36,13 +32,7 @@ import { name, version } from './package.json';
3632
export function registerFirestore(instance: FirebaseNamespace): void {
3733
configureForFirebase(
3834
instance,
39-
(app, auth) =>
40-
new Firestore(
41-
app,
42-
auth,
43-
new MemoryOfflineComponentProvider(),
44-
new OnlineComponentProvider()
45-
)
35+
(app, auth) => new Firestore(app, auth, new MemoryPersistenceProvider())
4636
);
4737
instance.registerVersion(name, version, 'rn');
4838
}

packages/firestore/index.rn.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@
1717
import firebase from '@firebase/app';
1818
import { FirebaseNamespace } from '@firebase/app-types';
1919

20-
import { Firestore } from './src/api/database';
21-
import {
22-
MultiTabOfflineComponentProvider,
23-
OnlineComponentProvider
24-
} from './src/core/component_provider';
20+
import { Firestore, IndexedDbPersistenceProvider } from './src/api/database';
2521
import { configureForFirebase } from './src/config';
2622

2723
import './register-module';
@@ -33,16 +29,7 @@ import { name, version } from './package.json';
3329
*/
3430
export function registerFirestore(instance: FirebaseNamespace): void {
3531
configureForFirebase(instance, (app, auth) => {
36-
const onlineComponentProvider = new OnlineComponentProvider();
37-
const offlineComponentProvider = new MultiTabOfflineComponentProvider(
38-
onlineComponentProvider
39-
);
40-
return new Firestore(
41-
app,
42-
auth,
43-
offlineComponentProvider,
44-
onlineComponentProvider
45-
);
32+
return new Firestore(app, auth, new IndexedDbPersistenceProvider());
4633
});
4734
instance.registerVersion(name, version, 'rn');
4835
}

packages/firestore/index.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@
1818
import firebase from '@firebase/app';
1919
import { FirebaseNamespace } from '@firebase/app-types';
2020

21-
import { Firestore } from './src/api/database';
22-
import {
23-
MultiTabOfflineComponentProvider,
24-
OnlineComponentProvider
25-
} from './src/core/component_provider';
21+
import { Firestore, IndexedDbPersistenceProvider } from './src/api/database';
2622
import { configureForFirebase } from './src/config';
2723
import { name, version } from './package.json';
2824

@@ -34,16 +30,7 @@ import './register-module';
3430
*/
3531
export function registerFirestore(instance: FirebaseNamespace): void {
3632
configureForFirebase(instance, (app, auth) => {
37-
const onlineComponentProvider = new OnlineComponentProvider();
38-
const offlineComponentProvider = new MultiTabOfflineComponentProvider(
39-
onlineComponentProvider
40-
);
41-
return new Firestore(
42-
app,
43-
auth,
44-
offlineComponentProvider,
45-
onlineComponentProvider
46-
);
33+
return new Firestore(app, auth, new IndexedDbPersistenceProvider());
4734
});
4835
instance.registerVersion(name, version);
4936
}

0 commit comments

Comments
 (0)