diff --git a/.changeset/brown-beers-tease.md b/.changeset/brown-beers-tease.md new file mode 100644 index 00000000000..f22213b3489 --- /dev/null +++ b/.changeset/brown-beers-tease.md @@ -0,0 +1,6 @@ +--- +"@firebase/firestore": minor +"firebase": minor +--- + +Introduces a new way to config Firestore SDK Cache. diff --git a/.changeset/chilled-buckets-sneeze.md b/.changeset/chilled-buckets-sneeze.md deleted file mode 100644 index d485e384f70..00000000000 --- a/.changeset/chilled-buckets-sneeze.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@firebase/firestore': patch -'firebase': patch ---- - -Check navigator.userAgent, in addition to navigator.appVersion, when determining whether to work around an IndexedDb bug in Safari. diff --git a/.changeset/fluffy-seas-behave.md b/.changeset/fluffy-seas-behave.md deleted file mode 100644 index 073429be5d8..00000000000 --- a/.changeset/fluffy-seas-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@firebase/auth": patch ---- - -Explicitly set createdAt and lastLoginAt when cloning UserImpl diff --git a/.changeset/friendly-ads-yell.md b/.changeset/friendly-ads-yell.md new file mode 100644 index 00000000000..2da2f6dede1 --- /dev/null +++ b/.changeset/friendly-ads-yell.md @@ -0,0 +1,6 @@ +--- +'@firebase/firestore': patch +'firebase': patch +--- + +Check that DOMException exists before referencing it, to fix react-native, which was broken by https://github.com/firebase/firebase-js-sdk/pull/7019 in v9.17.2. diff --git a/.changeset/blue-eels-warn.md b/.changeset/plenty-radios-look.md similarity index 50% rename from .changeset/blue-eels-warn.md rename to .changeset/plenty-radios-look.md index 1e963c7e68e..f8d34fd34b6 100644 --- a/.changeset/blue-eels-warn.md +++ b/.changeset/plenty-radios-look.md @@ -3,4 +3,4 @@ 'firebase': patch --- -Improved debug logging of networking abstractions +Remove the deprecated gapi.auth from FirstPartyToken. diff --git a/.changeset/sixty-buckets-repeat.md b/.changeset/sixty-buckets-repeat.md new file mode 100644 index 00000000000..40591209839 --- /dev/null +++ b/.changeset/sixty-buckets-repeat.md @@ -0,0 +1,5 @@ +--- +'@firebase/auth': patch +--- + +Modify \_fail to use AuthErrorCode.NETWORK_REQUEST_FAILED diff --git a/.changeset/sweet-rats-compete.md b/.changeset/sweet-rats-compete.md deleted file mode 100644 index 0c10ba8bac5..00000000000 --- a/.changeset/sweet-rats-compete.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@firebase/firestore": minor -'firebase': minor ---- - -OR Query public API diff --git a/.changeset/tasty-cooks-leave.md b/.changeset/tasty-cooks-leave.md new file mode 100644 index 00000000000..69dbdd34e43 --- /dev/null +++ b/.changeset/tasty-cooks-leave.md @@ -0,0 +1,5 @@ +--- +'@firebase/analytics': patch +--- + +Use the Trusted Types API when composing the gtag URL. diff --git a/.github/workflows/update-api-reports.yml b/.github/workflows/update-api-reports.yml index da09152d3c2..f566337600d 100644 --- a/.github/workflows/update-api-reports.yml +++ b/.github/workflows/update-api-reports.yml @@ -27,7 +27,7 @@ jobs: run: yarn build id: update-api-reports - name: Commit & Push changes - uses: EndBug/add-and-commit@v7 + uses: EndBug/add-and-commit@v9 with: add: 'common/api-review/*' message: 'Update API reports' diff --git a/common/api-review/firestore.api.md b/common/api-review/firestore.api.md index 077e0e4426f..905629f870a 100644 --- a/common/api-review/firestore.api.md +++ b/common/api-review/firestore.api.md @@ -163,10 +163,10 @@ export class DocumentSnapshot { export { EmulatorMockTokenOptions } -// @public +// @public @deprecated export function enableIndexedDbPersistence(firestore: Firestore, persistenceSettings?: PersistenceSettings): Promise; -// @public +// @public @deprecated export function enableMultiTabIndexedDbPersistence(firestore: Firestore): Promise; // @public @@ -219,6 +219,9 @@ export class FirestoreError extends FirebaseError { // @public export type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; +// @public +export type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; + // @public export interface FirestoreSettings { cacheSizeBytes?: number; @@ -226,6 +229,7 @@ export interface FirestoreSettings { experimentalForceLongPolling?: boolean; host?: string; ignoreUndefinedProperties?: boolean; + localCache?: FirestoreLocalCache; ssl?: boolean; } @@ -327,6 +331,15 @@ export interface LoadBundleTaskProgress { export { LogLevel } +// @public +export interface MemoryLocalCache { + // (undocumented) + kind: 'memory'; +} + +// @public +export function memoryLocalCache(): MemoryLocalCache; + // @public export function namedQuery(firestore: Firestore, name: string): Promise; @@ -404,6 +417,47 @@ export interface PersistenceSettings { forceOwnership?: boolean; } +// @public +export interface PersistentCacheSettings { + cacheSizeBytes?: number; + tabManager?: PersistentTabManager; +} + +// @public +export interface PersistentLocalCache { + // (undocumented) + kind: 'persistent'; +} + +// @public +export function persistentLocalCache(settings?: PersistentCacheSettings): PersistentLocalCache; + +// @public +export interface PersistentMultipleTabManager { + // (undocumented) + kind: 'PersistentMultipleTab'; +} + +// @public +export function persistentMultipleTabManager(): PersistentMultipleTabManager; + +// @public +export interface PersistentSingleTabManager { + // (undocumented) + kind: 'persistentSingleTab'; +} + +// @public +export function persistentSingleTabManager(settings: PersistentSingleTabManagerSettings | undefined): PersistentSingleTabManager; + +// @public +export interface PersistentSingleTabManagerSettings { + forceOwnership?: boolean; +} + +// @public +export type PersistentTabManager = PersistentSingleTabManager | PersistentMultipleTabManager; + // @public export type Primitive = string | number | boolean | undefined | null; diff --git a/docs-devsite/firestore_.firestoresettings.md b/docs-devsite/firestore_.firestoresettings.md index 96fe454cb77..8e6da365f46 100644 --- a/docs-devsite/firestore_.firestoresettings.md +++ b/docs-devsite/firestore_.firestoresettings.md @@ -22,15 +22,18 @@ export declare interface FirestoreSettings | Property | Type | Description | | --- | --- | --- | -| [cacheSizeBytes](./firestore_.firestoresettings.md#firestoresettingscachesizebytes) | number | An approximate cache size threshold for the on-disk data. If the cache grows beyond this size, Firestore will start removing data that hasn't been recently used. The size is not a guarantee that the cache will stay below that size, only that if the cache exceeds the given size, cleanup will be attempted.The default value is 40 MB. The threshold must be set to at least 1 MB, and can be set to CACHE_SIZE_UNLIMITED to disable garbage collection. | +| [cacheSizeBytes](./firestore_.firestoresettings.md#firestoresettingscachesizebytes) | number | NOTE: This field will be deprecated in a future major release. Use cache field instead to specify cache size, and other cache configurations.An approximate cache size threshold for the on-disk data. If the cache grows beyond this size, Firestore will start removing data that hasn't been recently used. The size is not a guarantee that the cache will stay below that size, only that if the cache exceeds the given size, cleanup will be attempted.The default value is 40 MB. The threshold must be set to at least 1 MB, and can be set to CACHE_SIZE_UNLIMITED to disable garbage collection. | | [experimentalAutoDetectLongPolling](./firestore_.firestoresettings.md#firestoresettingsexperimentalautodetectlongpolling) | boolean | Configures the SDK's underlying transport (WebChannel) to automatically detect if long-polling should be used. This is very similar to experimentalForceLongPolling, but only uses long-polling if required.This setting will likely be enabled by default in future releases and cannot be combined with experimentalForceLongPolling. | | [experimentalForceLongPolling](./firestore_.firestoresettings.md#firestoresettingsexperimentalforcelongpolling) | boolean | Forces the SDK’s underlying network transport (WebChannel) to use long-polling. Each response from the backend will be closed immediately after the backend sends data (by default responses are kept open in case the backend has more data to send). This avoids incompatibility issues with certain proxies, antivirus software, etc. that incorrectly buffer traffic indefinitely. Use of this option will cause some performance degradation though.This setting cannot be used with experimentalAutoDetectLongPolling and may be removed in a future release. If you find yourself using it to work around a specific network reliability issue, please tell us about it in https://github.com/firebase/firebase-js-sdk/issues/1674. | | [host](./firestore_.firestoresettings.md#firestoresettingshost) | string | The hostname to connect to. | | [ignoreUndefinedProperties](./firestore_.firestoresettings.md#firestoresettingsignoreundefinedproperties) | boolean | Whether to skip nested properties that are set to undefined during object serialization. If set to true, these properties are skipped and not written to Firestore. If set to false or omitted, the SDK throws an exception when it encounters properties of type undefined. | +| [localCache](./firestore_.firestoresettings.md#firestoresettingslocalcache) | [FirestoreLocalCache](./firestore_.md#firestorelocalcache) | Specifies the cache used by the SDK. Availabe options are MemoryLocalCache and IndexedDbLocalCache, each with different configuration options.When unspecified, MemoryLocalCache will be used by default.NOTE: setting this field and cacheSizeBytes at the same time will throw exception during SDK initialization. Instead, using the configuration in the FirestoreLocalCache object to specify the cache size. | | [ssl](./firestore_.firestoresettings.md#firestoresettingsssl) | boolean | Whether to use SSL when connecting. | ## FirestoreSettings.cacheSizeBytes +NOTE: This field will be deprecated in a future major release. Use `cache` field instead to specify cache size, and other cache configurations. + An approximate cache size threshold for the on-disk data. If the cache grows beyond this size, Firestore will start removing data that hasn't been recently used. The size is not a guarantee that the cache will stay below that size, only that if the cache exceeds the given size, cleanup will be attempted. The default value is 40 MB. The threshold must be set to at least 1 MB, and can be set to `CACHE_SIZE_UNLIMITED` to disable garbage collection. @@ -85,6 +88,20 @@ Whether to skip nested properties that are set to `undefined` during object seri ignoreUndefinedProperties?: boolean; ``` +## FirestoreSettings.localCache + +Specifies the cache used by the SDK. Availabe options are `MemoryLocalCache` and `IndexedDbLocalCache`, each with different configuration options. + +When unspecified, `MemoryLocalCache` will be used by default. + +NOTE: setting this field and `cacheSizeBytes` at the same time will throw exception during SDK initialization. Instead, using the configuration in the `FirestoreLocalCache` object to specify the cache size. + +Signature: + +```typescript +localCache?: FirestoreLocalCache; +``` + ## FirestoreSettings.ssl Whether to use SSL when connecting. diff --git a/docs-devsite/firestore_.md b/docs-devsite/firestore_.md index 9351f162119..365635c434d 100644 --- a/docs-devsite/firestore_.md +++ b/docs-devsite/firestore_.md @@ -33,7 +33,7 @@ https://github.com/firebase/firebase-js-sdk | [onSnapshotsInSync(firestore, observer)](./firestore_.md#onsnapshotsinsync) | Attaches a listener for a snapshots-in-sync event. The snapshots-in-sync event indicates that all listeners affected by a given change have fired, even if a single server-generated change affects multiple listeners.NOTE: The snapshots-in-sync event only indicates that listeners are in sync with each other, but does not relate to whether those snapshots are in sync with the server. Use SnapshotMetadata in the individual listeners to determine if a snapshot is from the cache or the server. | | [onSnapshotsInSync(firestore, onSync)](./firestore_.md#onsnapshotsinsync) | Attaches a listener for a snapshots-in-sync event. The snapshots-in-sync event indicates that all listeners affected by a given change have fired, even if a single server-generated change affects multiple listeners.NOTE: The snapshots-in-sync event only indicates that listeners are in sync with each other, but does not relate to whether those snapshots are in sync with the server. Use SnapshotMetadata in the individual listeners to determine if a snapshot is from the cache or the server. | | [runTransaction(firestore, updateFunction, options)](./firestore_.md#runtransaction) | Executes the given updateFunction and then attempts to commit the changes applied within the transaction. If any document read within the transaction has changed, Cloud Firestore retries the updateFunction. If it fails to commit after 5 attempts, the transaction fails.The maximum number of writes allowed in a single transaction is 500. | -| [setIndexConfiguration(firestore, configuration)](./firestore_.md#setindexconfiguration) | (BETA) Configures indexing for local query execution. Any previous index configuration is overridden. The Promise resolves once the index configuration has been persisted.The index entries themselves are created asynchronously. You can continue to use queries that require indexing even if the indices are not yet available. Query execution will automatically start using the index once the index entries have been written.Indexes are only supported with IndexedDb persistence. Invoke either enableIndexedDbPersistence() or enableMultiTabIndexedDbPersistence() before setting an index configuration. If IndexedDb is not enabled, any index configuration is ignored. | +| [setIndexConfiguration(firestore, configuration)](./firestore_.md#setindexconfiguration) | (BETA) Configures indexing for local query execution. Any previous index configuration is overridden. The Promise resolves once the index configuration has been persisted.The index entries themselves are created asynchronously. You can continue to use queries that require indexing even if the indices are not yet available. Query execution will automatically start using the index once the index entries have been written.Indexes are only supported with IndexedDb persistence. If IndexedDb is not enabled, any index configuration is ignored. | | [setIndexConfiguration(firestore, json)](./firestore_.md#setindexconfiguration) | (BETA) Configures indexing for local query execution. Any previous index configuration is overridden. The Promise resolves once the index configuration has been persisted.The index entries themselves are created asynchronously. You can continue to use queries that require indexing even if the indices are not yet available. Query execution will automatically start using the index once the index entries have been written.Indexes are only supported with IndexedDb persistence. Invoke either enableIndexedDbPersistence() or enableMultiTabIndexedDbPersistence() before setting an index configuration. If IndexedDb is not enabled, any index configuration is ignored.The method accepts the JSON format exported by the Firebase CLI (firebase firestore:indexes). If the JSON format is invalid, this method throws an error. | | [terminate(firestore)](./firestore_.md#terminate) | Terminates the provided [Firestore](./firestore_.firestore.md#firestore_class) instance.After calling terminate() only the clearIndexedDbPersistence() function may be used. Any other function will throw a FirestoreError.To restart after termination, create a new instance of FirebaseFirestore with [getFirestore()](./firestore_.md#getfirestore).Termination does not cancel any pending writes, and any promises that are awaiting a response from the server will not be resolved. If you have persistence enabled, the next time you start this instance, it will resume sending these writes to the server.Note: Under normal circumstances, calling terminate() is not required. This function is useful only when you want to force this instance to release all of its resources or in combination with clearIndexedDbPersistence() to ensure that all local state is destroyed between test runs. | | [waitForPendingWrites(firestore)](./firestore_.md#waitforpendingwrites) | Waits until all currently pending writes for the active user have been acknowledged by the backend.The returned promise resolves immediately if there are no outstanding writes. Otherwise, the promise waits for all previously issued writes (including those written in a previous app session), but it does not wait for writes that were added after the function is called. If you want to wait for additional writes, call waitForPendingWrites() again.Any outstanding waitForPendingWrites() promises are rejected during user changes. | @@ -42,6 +42,8 @@ https://github.com/firebase/firebase-js-sdk | [deleteField()](./firestore_.md#deletefield) | Returns a sentinel for use with [updateDoc()](./firestore_lite.md#updatedoc) or [setDoc()](./firestore_lite.md#setdoc) with {merge: true} to mark a field for deletion. | | [documentId()](./firestore_.md#documentid) | Returns a special sentinel FieldPath to refer to the ID of a document. It can be used in queries to sort or filter by the document ID. | | [getFirestore()](./firestore_.md#getfirestore) | Returns the existing default [Firestore](./firestore_.firestore.md#firestore_class) instance that is associated with the default [FirebaseApp](./app.firebaseapp.md#firebaseapp_interface). If no instance exists, initializes a new instance with default settings. | +| [memoryLocalCache()](./firestore_.md#memorylocalcache) | Creates an instance of MemoryLocalCache. The instance can be set to FirestoreSettings.cache to tell the SDK which cache layer to use. | +| [persistentMultipleTabManager()](./firestore_.md#persistentmultipletabmanager) | Creates an instance of PersistentMultipleTabManager. | | [serverTimestamp()](./firestore_.md#servertimestamp) | Returns a sentinel used with [setDoc()](./firestore_lite.md#setdoc) or [updateDoc()](./firestore_lite.md#updatedoc) to include a server-generated timestamp in the written data. | | function(elements...) | | [arrayRemove(elements)](./firestore_.md#arrayremove) | Returns a special value that can be used with [setDoc()](./firestore_.md#setdoc) or that tells the server to remove the given elements from any array value that already exists on the server. All instances of each element specified will be removed from the array. If the field being modified is not already an array it will be overwritten with an empty array. | @@ -98,6 +100,9 @@ https://github.com/firebase/firebase-js-sdk | [setDoc(reference, data, options)](./firestore_.md#setdoc) | Writes to the document referred to by the specified DocumentReference. If the document does not yet exist, it will be created. If you provide merge or mergeFields, the provided data can be merged into an existing document. | | [updateDoc(reference, data)](./firestore_.md#updatedoc) | Updates fields in the document referred to by the specified DocumentReference. The update will fail if applied to a document that does not exist. | | [updateDoc(reference, field, value, moreFieldsAndValues)](./firestore_.md#updatedoc) | Updates fields in the document referred to by the specified DocumentReference The update will fail if applied to a document that does not exist.Nested fields can be updated by providing dot-separated field path strings or by providing FieldPath objects. | +| function(settings...) | +| [persistentLocalCache(settings)](./firestore_.md#persistentlocalcache) | Creates an instance of PersistentLocalCache. The instance can be set to FirestoreSettings.cache to tell the SDK which cache layer to use. | +| [persistentSingleTabManager(settings)](./firestore_.md#persistentsingletabmanager) | Creates an instance of PersistentSingleTabManager. | | function(snapshot...) | | [endAt(snapshot)](./firestore_.md#endat) | Creates a [QueryEndAtConstraint](./firestore_.queryendatconstraint.md#queryendatconstraint_class) that modifies the result set to end at the provided document (inclusive). The end position is relative to the order of the query. The document must contain all of the fields provided in the orderBy of the query. | | [endBefore(snapshot)](./firestore_.md#endbefore) | Creates a [QueryEndAtConstraint](./firestore_.queryendatconstraint.md#queryendatconstraint_class) that modifies the result set to end before the provided document (exclusive). The end position is relative to the order of the query. The document must contain all of the fields provided in the orderBy of the query. | @@ -148,7 +153,13 @@ https://github.com/firebase/firebase-js-sdk | [IndexConfiguration](./firestore_.indexconfiguration.md#indexconfiguration_interface) | (BETA) A list of Firestore indexes to speed up local query execution.See [JSON Format](https://firebase.google.com/docs/reference/firestore/indexes/#json_format) for a description of the format of the index definition. | | [IndexField](./firestore_.indexfield.md#indexfield_interface) | (BETA) A single field element in an index configuration. | | [LoadBundleTaskProgress](./firestore_.loadbundletaskprogress.md#loadbundletaskprogress_interface) | Represents a progress update or a final state from loading bundles. | +| [MemoryLocalCache](./firestore_.memorylocalcache.md#memorylocalcache_interface) | Provides an in-memory cache to the SDK. This is the default cache unless explicitly configured otherwise.To use, create an instance using the factory function , then set the instance to FirestoreSettings.cache and call initializeFirestore using the settings object. | | [PersistenceSettings](./firestore_.persistencesettings.md#persistencesettings_interface) | Settings that can be passed to enableIndexedDbPersistence() to configure Firestore persistence. | +| [PersistentCacheSettings](./firestore_.persistentcachesettings.md#persistentcachesettings_interface) | An settings object to configure an PersistentLocalCache instance. | +| [PersistentLocalCache](./firestore_.persistentlocalcache.md#persistentlocalcache_interface) | Provides a persistent cache backed by IndexedDb to the SDK.To use, create an instance using the factory function , then set the instance to FirestoreSettings.cache and call initializeFirestore using the settings object. | +| [PersistentMultipleTabManager](./firestore_.persistentmultipletabmanager.md#persistentmultipletabmanager_interface) | A tab manager supportting multiple tabs. SDK will synchronize queries and mutations done across all tabs using the SDK. | +| [PersistentSingleTabManager](./firestore_.persistentsingletabmanager.md#persistentsingletabmanager_interface) | A tab manager supportting only one tab, no synchronization will be performed across tabs. | +| [PersistentSingleTabManagerSettings](./firestore_.persistentsingletabmanagersettings.md#persistentsingletabmanagersettings_interface) | Type to configure an PersistentSingleTabManager instace. | | [SnapshotListenOptions](./firestore_.snapshotlistenoptions.md#snapshotlistenoptions_interface) | An options object that can be passed to [onSnapshot()](./firestore_.md#onsnapshot) and [QuerySnapshot.docChanges()](./firestore_.querysnapshot.md#querysnapshotdocchanges) to control which types of changes to include in the result set. | | [SnapshotOptions](./firestore_.snapshotoptions.md#snapshotoptions_interface) | Options that configure how data is retrieved from a DocumentSnapshot (for example the desired behavior for server timestamps that have not yet been set to their final value). | | [TransactionOptions](./firestore_.transactionoptions.md#transactionoptions_interface) | Options to customize transaction behavior. | @@ -170,9 +181,11 @@ https://github.com/firebase/firebase-js-sdk | [ChildUpdateFields](./firestore_.md#childupdatefields) | Helper for calculating the nested fields for a given type T1. This is needed to distribute union types such as undefined | {...} (happens for optional props) or {a: A} | {b: B}.In this use case, V is used to distribute the union types of T[K] on Record, since T[K] is evaluated as an expression and not distributed.See https://www.typescriptlang.org/docs/handbook/advanced-types.html\#distributive-conditional-types | | [DocumentChangeType](./firestore_.md#documentchangetype) | The type of a DocumentChange may be 'added', 'removed', or 'modified'. | | [FirestoreErrorCode](./firestore_.md#firestoreerrorcode) | The set of Firestore status codes. The codes are the same at the ones exposed by gRPC here: https://github.com/grpc/grpc/blob/master/doc/statuscodes.mdPossible values: - 'cancelled': The operation was cancelled (typically by the caller). - 'unknown': Unknown error or an error from a different error domain. - 'invalid-argument': Client specified an invalid argument. Note that this differs from 'failed-precondition'. 'invalid-argument' indicates arguments that are problematic regardless of the state of the system (e.g. an invalid field name). - 'deadline-exceeded': Deadline expired before operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire. - 'not-found': Some requested document was not found. - 'already-exists': Some document that we attempted to create already exists. - 'permission-denied': The caller does not have permission to execute the specified operation. - 'resource-exhausted': Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space. - 'failed-precondition': Operation was rejected because the system is not in a state required for the operation's execution. - 'aborted': The operation was aborted, typically due to a concurrency issue like transaction aborts, etc. - 'out-of-range': Operation was attempted past the valid range. - 'unimplemented': Operation is not implemented or not supported/enabled. - 'internal': Internal errors. Means some invariants expected by underlying system has been broken. If you see one of these errors, something is very broken. - 'unavailable': The service is currently unavailable. This is most likely a transient condition and may be corrected by retrying with a backoff. - 'data-loss': Unrecoverable data loss or corruption. - 'unauthenticated': The request does not have valid authentication credentials for the operation. | +| [FirestoreLocalCache](./firestore_.md#firestorelocalcache) | Union type from all supported SDK cache layer. | | [NestedUpdateFields](./firestore_.md#nestedupdatefields) | For each field (e.g. 'bar'), find all nested keys (e.g. {'bar.baz': T1, 'bar.qux': T2}). Intersect them together to make a single map containing all possible keys that are all marked as optional | | [OrderByDirection](./firestore_.md#orderbydirection) | The direction of a [orderBy()](./firestore_.md#orderby) clause is specified as 'desc' or 'asc' (descending or ascending). | | [PartialWithFieldValue](./firestore_.md#partialwithfieldvalue) | Similar to Typescript's Partial<T>, but allows nested fields to be omitted and FieldValues to be passed in as property values. | +| [PersistentTabManager](./firestore_.md#persistenttabmanager) | A union of all avaialbe tab managers. | | [Primitive](./firestore_.md#primitive) | Primitive types. | | [QueryConstraintType](./firestore_.md#queryconstrainttype) | Describes the different query constraints available in this SDK. | | [QueryFilterConstraint](./firestore_.md#queryfilterconstraint) | QueryFilterConstraint is a helper union type that represents [QueryFieldFilterConstraint](./firestore_.queryfieldfilterconstraint.md#queryfieldfilterconstraint_class) and [QueryCompositeFilterConstraint](./firestore_.querycompositefilterconstraint.md#querycompositefilterconstraint_class). | @@ -386,6 +399,11 @@ If the final path has an odd number of segments and does not point to a document ## enableIndexedDbPersistence() +> Warning: This API is now obsolete. +> +> This function will be removed in a future major release. Instead, set `FirestoreSettings.cache` to an instance of `IndexedDbLocalCache` to turn on IndexedDb cache. Calling this function when `FirestoreSettings.cache` is already specified will throw an exception. +> + Attempts to enable persistent storage, if possible. Must be called before any other functions (other than [initializeFirestore()](./firestore_.md#initializefirestore), [getFirestore()](./firestore_.md#getfirestore) or [clearIndexedDbPersistence()](./firestore_.md#clearindexeddbpersistence). @@ -417,6 +435,11 @@ A `Promise` that represents successfully enabling persistent storage. ## enableMultiTabIndexedDbPersistence() +> Warning: This API is now obsolete. +> +> This function will be removed in a future major release. Instead, set `FirestoreSettings.cache` to an instance of `IndexedDbLocalCache` to turn on indexeddb cache. Calling this function when `FirestoreSettings.cache` is already specified will throw an exception. +> + Attempts to enable multi-tab persistent storage, if possible. If enabled across all tabs, all operations share access to local persistence, including shared execution of queries and latency-compensated local document updates across all connected instances. If this fails, `enableMultiTabIndexedDbPersistence()` will reject the promise it returns. Note that even after this failure, the [Firestore](./firestore_.firestore.md#firestore_class) instance will remain usable, however offline persistence will be disabled. @@ -602,7 +625,7 @@ Configures indexing for local query execution. Any previous index configuration The index entries themselves are created asynchronously. You can continue to use queries that require indexing even if the indices are not yet available. Query execution will automatically start using the index once the index entries have been written. -Indexes are only supported with IndexedDb persistence. Invoke either `enableIndexedDbPersistence()` or `enableMultiTabIndexedDbPersistence()` before setting an index configuration. If IndexedDb is not enabled, any index configuration is ignored. +Indexes are only supported with IndexedDb persistence. If IndexedDb is not enabled, any index configuration is ignored. Signature: @@ -784,6 +807,32 @@ export declare function getFirestore(): Firestore; The [Firestore](./firestore_.firestore.md#firestore_class) instance of the provided app. +## memoryLocalCache() + +Creates an instance of `MemoryLocalCache`. The instance can be set to `FirestoreSettings.cache` to tell the SDK which cache layer to use. + +Signature: + +```typescript +export declare function memoryLocalCache(): MemoryLocalCache; +``` +Returns: + +[MemoryLocalCache](./firestore_.memorylocalcache.md#memorylocalcache_interface) + +## persistentMultipleTabManager() + +Creates an instance of `PersistentMultipleTabManager`. + +Signature: + +```typescript +export declare function persistentMultipleTabManager(): PersistentMultipleTabManager; +``` +Returns: + +[PersistentMultipleTabManager](./firestore_.persistentmultipletabmanager.md#persistentmultipletabmanager_interface) + ## serverTimestamp() Returns a sentinel used with [setDoc()](./firestore_lite.md#setdoc) or [updateDoc()](./firestore_lite.md#updatedoc) to include a server-generated timestamp in the written data. @@ -1905,6 +1954,46 @@ Promise<void> A `Promise` resolved once the data has been successfully written to the backend (note that it won't resolve while you're offline). +## persistentLocalCache() + +Creates an instance of `PersistentLocalCache`. The instance can be set to `FirestoreSettings.cache` to tell the SDK which cache layer to use. + +Signature: + +```typescript +export declare function persistentLocalCache(settings?: PersistentCacheSettings): PersistentLocalCache; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| settings | [PersistentCacheSettings](./firestore_.persistentcachesettings.md#persistentcachesettings_interface) | | + +Returns: + +[PersistentLocalCache](./firestore_.persistentlocalcache.md#persistentlocalcache_interface) + +## persistentSingleTabManager() + +Creates an instance of `PersistentSingleTabManager`. + +Signature: + +```typescript +export declare function persistentSingleTabManager(settings: PersistentSingleTabManagerSettings | undefined): PersistentSingleTabManager; +``` + +### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| settings | [PersistentSingleTabManagerSettings](./firestore_.persistentsingletabmanagersettings.md#persistentsingletabmanagersettings_interface) \| undefined | Configures the created tab manager. | + +Returns: + +[PersistentSingleTabManager](./firestore_.persistentsingletabmanager.md#persistentsingletabmanager_interface) + ## endAt() Creates a [QueryEndAtConstraint](./firestore_.queryendatconstraint.md#queryendatconstraint_class) that modifies the result set to end at the provided document (inclusive). The end position is relative to the order of the query. The document must contain all of the fields provided in the orderBy of the query. @@ -2073,6 +2162,16 @@ Possible values: - 'cancelled': The operation was cancelled (typically by the ca export declare type FirestoreErrorCode = 'cancelled' | 'unknown' | 'invalid-argument' | 'deadline-exceeded' | 'not-found' | 'already-exists' | 'permission-denied' | 'resource-exhausted' | 'failed-precondition' | 'aborted' | 'out-of-range' | 'unimplemented' | 'internal' | 'unavailable' | 'data-loss' | 'unauthenticated'; ``` +## FirestoreLocalCache + +Union type from all supported SDK cache layer. + +Signature: + +```typescript +export declare type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; +``` + ## NestedUpdateFields For each field (e.g. 'bar'), find all nested keys (e.g. {'bar.baz': T1, 'bar.qux': T2}). Intersect them together to make a single map containing all possible keys that are all marked as optional @@ -2107,6 +2206,16 @@ export declare type PartialWithFieldValue = Partial | (T extends Primitive } : never); ``` +## PersistentTabManager + +A union of all avaialbe tab managers. + +Signature: + +```typescript +export declare type PersistentTabManager = PersistentSingleTabManager | PersistentMultipleTabManager; +``` + ## Primitive Primitive types. diff --git a/docs-devsite/firestore_.memorylocalcache.md b/docs-devsite/firestore_.memorylocalcache.md new file mode 100644 index 00000000000..92b7d3a2c72 --- /dev/null +++ b/docs-devsite/firestore_.memorylocalcache.md @@ -0,0 +1,35 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# MemoryLocalCache interface +Provides an in-memory cache to the SDK. This is the default cache unless explicitly configured otherwise. + +To use, create an instance using the factory function , then set the instance to `FirestoreSettings.cache` and call `initializeFirestore` using the settings object. + +Signature: + +```typescript +export declare interface MemoryLocalCache +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [kind](./firestore_.memorylocalcache.md#memorylocalcachekind) | 'memory' | | + +## MemoryLocalCache.kind + +Signature: + +```typescript +kind: 'memory'; +``` diff --git a/docs-devsite/firestore_.persistentcachesettings.md b/docs-devsite/firestore_.persistentcachesettings.md new file mode 100644 index 00000000000..dd491918894 --- /dev/null +++ b/docs-devsite/firestore_.persistentcachesettings.md @@ -0,0 +1,48 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# PersistentCacheSettings interface +An settings object to configure an `PersistentLocalCache` instance. + +Signature: + +```typescript +export declare interface PersistentCacheSettings +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [cacheSizeBytes](./firestore_.persistentcachesettings.md#persistentcachesettingscachesizebytes) | number | An approximate cache size threshold for the on-disk data. If the cache grows beyond this size, Firestore will start removing data that hasn't been recently used. The SDK does not guarantee that the cache will stay below that size, only that if the cache exceeds the given size, cleanup will be attempted.The default value is 40 MB. The threshold must be set to at least 1 MB, and can be set to CACHE_SIZE_UNLIMITED to disable garbage collection. | +| [tabManager](./firestore_.persistentcachesettings.md#persistentcachesettingstabmanager) | [PersistentTabManager](./firestore_.md#persistenttabmanager) | Specifies how multiple tabs/windows will be managed by the SDK. | + +## PersistentCacheSettings.cacheSizeBytes + +An approximate cache size threshold for the on-disk data. If the cache grows beyond this size, Firestore will start removing data that hasn't been recently used. The SDK does not guarantee that the cache will stay below that size, only that if the cache exceeds the given size, cleanup will be attempted. + +The default value is 40 MB. The threshold must be set to at least 1 MB, and can be set to `CACHE_SIZE_UNLIMITED` to disable garbage collection. + +Signature: + +```typescript +cacheSizeBytes?: number; +``` + +## PersistentCacheSettings.tabManager + +Specifies how multiple tabs/windows will be managed by the SDK. + +Signature: + +```typescript +tabManager?: PersistentTabManager; +``` diff --git a/docs-devsite/firestore_.persistentlocalcache.md b/docs-devsite/firestore_.persistentlocalcache.md new file mode 100644 index 00000000000..48d876d15bd --- /dev/null +++ b/docs-devsite/firestore_.persistentlocalcache.md @@ -0,0 +1,35 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# PersistentLocalCache interface +Provides a persistent cache backed by IndexedDb to the SDK. + +To use, create an instance using the factory function , then set the instance to `FirestoreSettings.cache` and call `initializeFirestore` using the settings object. + +Signature: + +```typescript +export declare interface PersistentLocalCache +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [kind](./firestore_.persistentlocalcache.md#persistentlocalcachekind) | 'persistent' | | + +## PersistentLocalCache.kind + +Signature: + +```typescript +kind: 'persistent'; +``` diff --git a/docs-devsite/firestore_.persistentmultipletabmanager.md b/docs-devsite/firestore_.persistentmultipletabmanager.md new file mode 100644 index 00000000000..b0c21b378a1 --- /dev/null +++ b/docs-devsite/firestore_.persistentmultipletabmanager.md @@ -0,0 +1,33 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# PersistentMultipleTabManager interface +A tab manager supportting multiple tabs. SDK will synchronize queries and mutations done across all tabs using the SDK. + +Signature: + +```typescript +export declare interface PersistentMultipleTabManager +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [kind](./firestore_.persistentmultipletabmanager.md#persistentmultipletabmanagerkind) | 'PersistentMultipleTab' | | + +## PersistentMultipleTabManager.kind + +Signature: + +```typescript +kind: 'PersistentMultipleTab'; +``` diff --git a/docs-devsite/firestore_.persistentsingletabmanager.md b/docs-devsite/firestore_.persistentsingletabmanager.md new file mode 100644 index 00000000000..ee130b6fc6a --- /dev/null +++ b/docs-devsite/firestore_.persistentsingletabmanager.md @@ -0,0 +1,33 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# PersistentSingleTabManager interface +A tab manager supportting only one tab, no synchronization will be performed across tabs. + +Signature: + +```typescript +export declare interface PersistentSingleTabManager +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [kind](./firestore_.persistentsingletabmanager.md#persistentsingletabmanagerkind) | 'persistentSingleTab' | | + +## PersistentSingleTabManager.kind + +Signature: + +```typescript +kind: 'persistentSingleTab'; +``` diff --git a/docs-devsite/firestore_.persistentsingletabmanagersettings.md b/docs-devsite/firestore_.persistentsingletabmanagersettings.md new file mode 100644 index 00000000000..de5ddc71b5c --- /dev/null +++ b/docs-devsite/firestore_.persistentsingletabmanagersettings.md @@ -0,0 +1,35 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# PersistentSingleTabManagerSettings interface +Type to configure an `PersistentSingleTabManager` instace. + +Signature: + +```typescript +export declare interface PersistentSingleTabManagerSettings +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [forceOwnership](./firestore_.persistentsingletabmanagersettings.md#persistentsingletabmanagersettingsforceownership) | boolean | Whether to force-enable persistent (IndexedDB) cache for the client. This cannot be used with multi-tab synchronization and is primarily intended for use with Web Workers. Setting this to true will enable IndexedDB, but cause other tabs using IndexedDB cache to fail. | + +## PersistentSingleTabManagerSettings.forceOwnership + +Whether to force-enable persistent (IndexedDB) cache for the client. This cannot be used with multi-tab synchronization and is primarily intended for use with Web Workers. Setting this to `true` will enable IndexedDB, but cause other tabs using IndexedDB cache to fail. + +Signature: + +```typescript +forceOwnership?: boolean; +``` diff --git a/e2e/package.json b/e2e/package.json index 5bd0ff6a071..ab708590571 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -35,7 +35,7 @@ "karma-typescript-es6-transform": "5.5.3", "mocha": "9.2.2", "typescript": "4.7.4", - "webpack": "5.75.0", + "webpack": "5.76.0", "webpack-cli": "4.10.0", "webpack-dev-server": "4.11.1" } diff --git a/e2e/yarn.lock b/e2e/yarn.lock index 83cee91277f..92b3439c7fa 100644 --- a/e2e/yarn.lock +++ b/e2e/yarn.lock @@ -1825,394 +1825,384 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d" integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g== -"@firebase/analytics-compat@0.1.13": - version "0.1.13" - resolved "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.1.13.tgz#61e1d6f9e4d033c3ed9943d91530eb3e0f382f92" - integrity sha512-QC1DH/Dwc8fBihn0H+jocBWyE17GF1fOCpCrpAiQ2u16F/NqsVDVG4LjIqdhq963DXaXneNY7oDwa25Up682AA== - dependencies: - "@firebase/analytics" "0.8.0" - "@firebase/analytics-types" "0.7.0" - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" +"@firebase/analytics-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.3.tgz#ed60472dcd2bfa3f2fa7a5478b63bb7aece652ed" + integrity sha512-HmvbB4GMgh8AUlIDIo/OuFENLCGRXxMvtOueK+m8+DcfqBvG+mkii0Mi9ovo0TnMM62cy3oBYG7PHdjIQNLSLA== + dependencies: + "@firebase/analytics" "0.9.3" + "@firebase/analytics-types" "0.8.0" + "@firebase/component" "0.6.3" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/analytics-types@0.7.0": - version "0.7.0" - resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.7.0.tgz#91960e7c87ce8bf18cf8dd9e55ccbf5dc3989b5d" - integrity sha512-DNE2Waiwy5+zZnCfintkDtBfaW6MjIG883474v6Z0K1XZIvl76cLND4iv0YUb48leyF+PJK1KO2XrgHb/KpmhQ== - -"@firebase/analytics@0.8.0": +"@firebase/analytics-types@0.8.0": version "0.8.0" - resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.8.0.tgz#b5d595082f57d33842b1fd9025d88f83065e87fe" - integrity sha512-wkcwainNm8Cu2xkJpDSHfhBSdDJn86Q1TZNmLWc67VrhZUHXIKXxIqb65/tNUVE+I8+sFiDDNwA+9R3MqTQTaA== + resolved "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz#551e744a29adbc07f557306530a2ec86add6d410" + integrity sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw== + +"@firebase/analytics@0.9.3": + version "0.9.3" + resolved "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.9.3.tgz#ae653a6c6bcd667efd1d3cc5207e3e621d737028" + integrity sha512-XdYHBi6RvHYVAHGyLxXX0uRPwZmGeqw1JuWS1rMEeRF/jvbxnrL81kcFAHZVRkEvG9bXAJgL2fX9wmDo3e622w== dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/installations" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/app-check-compat@0.2.12": - version "0.2.12" - resolved "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.2.12.tgz#e30b2395e3d30f8cfcf3554fc87875f82c1aa086" - integrity sha512-GFppNLlUyMN9Iq31ME/+GkjRVKlc+MeanzUKQ9UaR73ZsYH3oX3Ja+xjoYgixaVJDDG+ofBYR7ZXTkkQdSR/pw== - dependencies: - "@firebase/app-check" "0.5.12" - "@firebase/app-check-types" "0.4.0" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" +"@firebase/app-check-compat@0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.3.tgz#a1d594ec722fa81f7e11977b407a187e8afdb19a" + integrity sha512-25AQ4W7WUL8OWas40GsABuNU622Dm1ojbfeZ03uKtLj5Af7FerJ25u7zkgm+11pc6rpr5v8E5oxEG9vmNRndEA== + dependencies: + "@firebase/app-check" "0.6.3" + "@firebase/app-check-types" "0.5.0" + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/app-check-interop-types@0.1.0": - version "0.1.0" - resolved "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.1.0.tgz#83afd9d41f99166c2bdb2d824e5032e9edd8fe53" - integrity sha512-uZfn9s4uuRsaX5Lwx+gFP3B6YsyOKUE+Rqa6z9ojT4VSRAsZFko9FRn6OxQUA1z5t5d08fY4pf+/+Dkd5wbdbA== +"@firebase/app-check-interop-types@0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.2.0.tgz#9106270114ca4e7732457e8319333866a26285d8" + integrity sha512-+3PQIeX6/eiVK+x/yg8r6xTNR97fN7MahFDm+jiQmDjcyvSefoGuTTNQuuMScGyx3vYUBeZn+Cp9kC0yY/9uxQ== -"@firebase/app-check-types@0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.4.0.tgz#7007a9d1d720db20bcf466fe6785c96feaa0a82d" - integrity sha512-SsWafqMABIOu7zLgWbmwvHGOeQQVQlwm42kwwubsmfLmL4Sf5uGpBfDhQ0CAkpi7bkJ/NwNFKafNDL9prRNP0Q== +"@firebase/app-check-types@0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz#1b02826213d7ce6a1cf773c329b46ea1c67064f4" + integrity sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ== -"@firebase/app-check@0.5.12": - version "0.5.12" - resolved "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.5.12.tgz#82f305cc01bfe4d32c35e425941b2eca2ce9f089" - integrity sha512-l+MmvupSGT/F+I5ei7XjhEfpoL4hLVJr0vUwcG5NEf2hAkQnySli9fnbl9fZu1BJaQ2kthrMmtg1gcbcM9BUCQ== +"@firebase/app-check@0.6.3": + version "0.6.3" + resolved "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.6.3.tgz#221060e5e0eac1e20ee724478b61e89ad6e8420a" + integrity sha512-T9f9ceFLs7x4D2T6whu5a6j7B3qPuYHiZHZxW6DkMh/FoMmRA4/q/HVyu01i9+LyJJx2Xdo6eCcj6ofs9YZjqA== dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/app-compat@0.1.31": - version "0.1.31" - resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.1.31.tgz#a52b3cc34d2dd8b790a48eaefbf05ce0f3b20be4" - integrity sha512-oH3F4Pf0/Q0WTyNynMlaoM1qjUTTu7ofDdAWUOgr9BH9gftIClqeCulltXSQH3DO3XUE61pIIpIakAWQ7zzumA== +"@firebase/app-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.3.tgz#a31c823d415c041591ee8c355776cd5bca7ef6e2" + integrity sha512-sX6rD1KFX6K2CuCnQvc9jZLOgAFZ+sv2jKKahIl4SbTM561D682B8n4Jtx/SgDrvcTVTdb05g4NhZOws9hxYxA== dependencies: - "@firebase/app" "0.7.30" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" + "@firebase/app" "0.9.3" + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/app-types@0.7.0": - version "0.7.0" - resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.7.0.tgz#c9e16d1b8bed1a991840b8d2a725fb58d0b5899f" - integrity sha512-6fbHQwDv2jp/v6bXhBw2eSRbNBpxHcd1NBF864UksSMVIqIyri9qpJB1Mn6sGZE+bnDsSQBC5j2TbMxYsJQkQg== +"@firebase/app-types@0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz#35b5c568341e9e263b29b3d2ba0e9cfc9ec7f01e" + integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q== -"@firebase/app@0.7.30": - version "0.7.30" - resolved "https://registry.npmjs.org/@firebase/app/-/app-0.7.30.tgz#20cba8f01540c7dcc072726d4f8ac745837457f4" - integrity sha512-uJRMShpCWCrW6eO+/UuN0ExgztPMpK/w/AUryHJh7Ll4lFkc71pqE9P/XlfE+XXi0zkWoXVgPeLAQDkUJwgmMA== +"@firebase/app@0.9.3": + version "0.9.3" + resolved "https://registry.npmjs.org/@firebase/app/-/app-0.9.3.tgz#6a9c9b2544fa9a50ad8f405355896c54339c228b" + integrity sha512-G79JUceVDaHRZ4WkA11GyVldVXhdyRJRwWVQFFvAAVfQJLvy2TA6lQjeUn28F6FmeUWxDGwPC30bxCRWq7Op8Q== dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" idb "7.0.1" tslib "^2.1.0" -"@firebase/auth-compat@0.2.18": - version "0.2.18" - resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.2.18.tgz#c7bb254fbb23447069f81abb15f96e91de40b285" - integrity sha512-Fw2PJS0G/tGrfyEBcYJQ42sfy5+sANrK5xd7tuzgV7zLFW5rYkHUIZngXjuOBwLOcfO2ixa/FavfeJle3oJ38Q== +"@firebase/auth-compat@0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.3.3.tgz#e52f654e3f14b81cecb2fe252e564778fbba0a47" + integrity sha512-9asUuGtkzUVELH3LYXdiom1nVVV9bqEPqzHohanoofHL/oVTNcHZ4AQ5CXjNATfb6c1WH32U+nEuPiYg26UUIw== dependencies: - "@firebase/auth" "0.20.5" - "@firebase/auth-types" "0.11.0" - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" + "@firebase/auth" "0.21.3" + "@firebase/auth-types" "0.12.0" + "@firebase/component" "0.6.3" + "@firebase/util" "1.9.2" node-fetch "2.6.7" - selenium-webdriver "4.1.2" tslib "^2.1.0" -"@firebase/auth-interop-types@0.1.6": - version "0.1.6" - resolved "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.1.6.tgz#5ce13fc1c527ad36f1bb1322c4492680a6cf4964" - integrity sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g== - -"@firebase/auth-types@0.11.0": - version "0.11.0" - resolved "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.11.0.tgz#b9c73c60ca07945b3bbd7a097633e5f78fa9e886" - integrity sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw== - -"@firebase/auth@0.20.5": - version "0.20.5" - resolved "https://registry.npmjs.org/@firebase/auth/-/auth-0.20.5.tgz#a2e6c6b593d8f9cf8276a7d1f8ab5b055d65cc50" - integrity sha512-SbKj7PCAuL0lXEToUOoprc1im2Lr/bzOePXyPC7WWqVgdVBt0qovbfejlzKYwJLHUAPg9UW1y3XYe3IlbXr77w== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" +"@firebase/auth-interop-types@0.2.1": + version "0.2.1" + resolved "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz#78884f24fa539e34a06c03612c75f222fcc33742" + integrity sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg== + +"@firebase/auth-types@0.12.0": + version "0.12.0" + resolved "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz#f28e1b68ac3b208ad02a15854c585be6da3e8e79" + integrity sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA== + +"@firebase/auth@0.21.3": + version "0.21.3" + resolved "https://registry.npmjs.org/@firebase/auth/-/auth-0.21.3.tgz#277a3bf4b09db1b5dd471970cecd844d1835dcbf" + integrity sha512-HPbcwgArLBVTowFcn4qaQr6LCx7BidI9yrQ5MRbQNv4PsgK/3UGpzCYaNPPbvgr9fe+0jNdJO+uC0+dk4xIzCQ== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" node-fetch "2.6.7" - selenium-webdriver "4.1.2" tslib "^2.1.0" -"@firebase/component@0.5.17": - version "0.5.17" - resolved "https://registry.npmjs.org/@firebase/component/-/component-0.5.17.tgz#89291f378714df05d44430c524708669380d8ea6" - integrity sha512-mTM5CBSIlmI+i76qU4+DhuExnWtzcPS3cVgObA3VAjliPPr3GrUlTaaa8KBGfxsD27juQxMsYA0TvCR5X+GQ3Q== +"@firebase/component@0.6.3": + version "0.6.3" + resolved "https://registry.npmjs.org/@firebase/component/-/component-0.6.3.tgz#2baea3fa37861eef314a612eba194b0ff7c7ac11" + integrity sha512-rnhq5SOsB5nuJphZF50iwqnBiuuyg9kdnlUn1rBrKfu7/cUVJZF5IG1cWrL0rXXyiZW1WBI/J2pmTvVO8dStGQ== dependencies: - "@firebase/util" "1.6.3" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/database-compat@0.2.4": - version "0.2.4" - resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.2.4.tgz#4e72dfa477011f69595fec80a9b688e3ea672d2f" - integrity sha512-VtsGixO5mTjNMJn6PwxAJEAR70fj+3blCXIdQKel3q+eYGZAfdqxox1+tzZDnf9NWBJpaOgAHPk3JVDxEo9NFQ== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/database" "0.13.4" - "@firebase/database-types" "0.9.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" +"@firebase/database-compat@0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.3.tgz#4668e32527f57c1dde6cb03f5fde81eb04503ad4" + integrity sha512-r+L9jTbvsnb7sD+xz6UKU39DgBWqB2pyjzPNdBeriGC9Ssa2MAZe0bIqjCQg51RRXYc/aa/zK1Q2/4uesZeVgQ== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/database" "0.14.3" + "@firebase/database-types" "0.10.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/database-types@0.9.12": - version "0.9.12" - resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.9.12.tgz#517844fc7723494a7bf33c906a9c6b2dc7f3c9bb" - integrity sha512-FP4UYx1/bIOYSbTFmKajKKaEjXZKCQFUNZNIxaiCEZmsXb4vt0PJAmBufJf6LJLsaXNoywkcTyPYwjsotviyxg== +"@firebase/database-types@0.10.3": + version "0.10.3" + resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.3.tgz#f057e150b8c2aff0c623162abef139ff5df9bfd2" + integrity sha512-Hu34CDhHYZsd2eielr0jeaWrTJk8Hz0nd7WsnYDnXtQX4i49ppgPesUzPdXVBdIBLJmT0ZZRvT7qWHknkOT+zg== dependencies: - "@firebase/app-types" "0.7.0" - "@firebase/util" "1.6.3" + "@firebase/app-types" "0.9.0" + "@firebase/util" "1.9.2" -"@firebase/database@0.13.4": - version "0.13.4" - resolved "https://registry.npmjs.org/@firebase/database/-/database-0.13.4.tgz#9b95968932a2c0e16f5dc995370262d366e0a469" - integrity sha512-NW7bOoiaC4sJCj6DY/m9xHoFNa0CK32YPMCh6FiMweLCDQbOZM8Ql/Kn6yyuxCb7K7ypz9eSbRlCWQJsJRQjhg== +"@firebase/database@0.14.3": + version "0.14.3" + resolved "https://registry.npmjs.org/@firebase/database/-/database-0.14.3.tgz#0ddd92e5eeef2dbebefd55ce78b39472a57dd5d3" + integrity sha512-J76W6N7JiVkLaAtPyjaGRkrsIu9pi6iZikuGGtGjqvV19vkn7oiL4Hbo5uTYCMd4waTUWoL9iI08eX184W+5GQ== dependencies: - "@firebase/auth-interop-types" "0.1.6" - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" + "@firebase/auth-interop-types" "0.2.1" + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" faye-websocket "0.11.4" tslib "^2.1.0" -"@firebase/firestore-compat@0.1.23": - version "0.1.23" - resolved "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.1.23.tgz#e941fa10f3eeca615df119470103fb4656842eef" - integrity sha512-QfcuyMAavp//fQnjSfCEpnbWi7spIdKaXys1kOLu7395fLr+U6ykmto1HUMCSz8Yus9cEr/03Ujdi2SUl2GUAA== +"@firebase/firestore-compat@0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.3.tgz#2fedc13e6242aa98a78cfb710242721d9822c1da" + integrity sha512-fMTsSC0s2cF5w2+JoB0dWD/o4kXtLrUCPGnZPuz4S0bqTN2t0vHr3gdAsQLtnadgwB78ACtinYmf4Udwx7TzDg== dependencies: - "@firebase/component" "0.5.17" - "@firebase/firestore" "3.4.14" - "@firebase/firestore-types" "2.5.0" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/firestore" "3.8.3" + "@firebase/firestore-types" "2.5.1" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/firestore-types@2.5.0": - version "2.5.0" - resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.5.0.tgz#16fca40b6980fdb000de86042d7a96635f2bcdd7" - integrity sha512-I6c2m1zUhZ5SH0cWPmINabDyH5w0PPFHk2UHsjBpKdZllzJZ2TwTkXbDtpHUZNmnc/zAa0WNMNMvcvbb/xJLKA== - -"@firebase/firestore@3.4.14": - version "3.4.14" - resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-3.4.14.tgz#864a56e70b3fd8f0274d3497ed67fabf5b38fdb2" - integrity sha512-F4Pqd5OUBtJaAWWC39C0vrMLIdZtx7jsO7sARFHSiOZY/8bikfH9YovIRkpxk7OSs3HT/SgVdK0B1vISGNSnJA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" - "@firebase/webchannel-wrapper" "0.6.2" - "@grpc/grpc-js" "^1.3.2" +"@firebase/firestore-types@2.5.1": + version "2.5.1" + resolved "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-2.5.1.tgz#464b2ee057956599ca34de50eae957c30fdbabb7" + integrity sha512-xG0CA6EMfYo8YeUxC8FeDzf6W3FX1cLlcAGBYV6Cku12sZRI81oWcu61RSKM66K6kUENP+78Qm8mvroBcm1whw== + +"@firebase/firestore@3.8.3": + version "3.8.3" + resolved "https://registry.npmjs.org/@firebase/firestore/-/firestore-3.8.3.tgz#8305113b9535747f982b585b0dd72e85122b5b89" + integrity sha512-4xR3Mqj95bxHg3hZnz0O+LQrHkjq+siT2y+B9da6u68qJ8bzzT42JaFgd1vifhbBpVbBzpFaS2RuCq2E+kGv9g== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" + "@firebase/webchannel-wrapper" "0.9.0" + "@grpc/grpc-js" "~1.7.0" "@grpc/proto-loader" "^0.6.13" node-fetch "2.6.7" tslib "^2.1.0" -"@firebase/functions-compat@0.2.4": - version "0.2.4" - resolved "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.2.4.tgz#afa5d8eefe6d51c7b89e44d9262700b68fbcb73f" - integrity sha512-Crfn6il1yXGuXkjSd8nKrqR4XxPvuP19g64bXpM6Ix67qOkQg676kyOuww0FF17xN0NSXHfG8Pyf+CUrx8wJ5g== +"@firebase/functions-compat@0.3.3": + version "0.3.3" + resolved "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.3.tgz#530c30b4dfea14e71657f780d2c281e16209aed7" + integrity sha512-UIAJ2gzNq0p/61cXqkpi9DnlQt0hdlGqgmL5an7KuJth2Iv5uGpKg/+OapAZxPuiUNZgTEyZDB7kNBHvnxWq5w== dependencies: - "@firebase/component" "0.5.17" - "@firebase/functions" "0.8.4" - "@firebase/functions-types" "0.5.0" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/functions" "0.9.3" + "@firebase/functions-types" "0.6.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/functions-types@0.5.0": - version "0.5.0" - resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.5.0.tgz#b50ba95ccce9e96f7cda453228ffe1684645625b" - integrity sha512-qza0M5EwX+Ocrl1cYI14zoipUX4gI/Shwqv0C1nB864INAD42Dgv4v94BCyxGHBg2kzlWy8PNafdP7zPO8aJQA== - -"@firebase/functions@0.8.4": - version "0.8.4" - resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.8.4.tgz#a9b7a10314f286df1ded87d8546fb8d9107a9c06" - integrity sha512-o1bB0xMyQKe+b246zGnjwHj4R6BH4mU2ZrSaa/3QvTpahUQ3hqYfkZPLOXCU7+vEFxHb3Hd4UUjkFhxoAcPqLA== - dependencies: - "@firebase/app-check-interop-types" "0.1.0" - "@firebase/auth-interop-types" "0.1.6" - "@firebase/component" "0.5.17" - "@firebase/messaging-interop-types" "0.1.0" - "@firebase/util" "1.6.3" +"@firebase/functions-types@0.6.0": + version "0.6.0" + resolved "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz#ccd7000dc6fc668f5acb4e6a6a042a877a555ef2" + integrity sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw== + +"@firebase/functions@0.9.3": + version "0.9.3" + resolved "https://registry.npmjs.org/@firebase/functions/-/functions-0.9.3.tgz#9ef33efcd38b0235e84ae472d9b51597efe3f871" + integrity sha512-tPJgYY2ROQSYuzvgxZRoHeDj+Ic07/bWHwaftgTriawtupmFOkt5iikuhJSJUhaOpFh9TB335OvCXJw1N+BIlQ== + dependencies: + "@firebase/app-check-interop-types" "0.2.0" + "@firebase/auth-interop-types" "0.2.1" + "@firebase/component" "0.6.3" + "@firebase/messaging-interop-types" "0.2.0" + "@firebase/util" "1.9.2" node-fetch "2.6.7" tslib "^2.1.0" -"@firebase/installations-compat@0.1.12": - version "0.1.12" - resolved "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.1.12.tgz#d0394127f71aff596cb8bb607840095d1617246e" - integrity sha512-BIhFpWIn/GkuOa+jnXkp3SDJT2RLYJF6MWpinHIBKFJs7MfrgYZ3zQ1AlhobDEql+bkD1dK4dB5sNcET2T+EyA== +"@firebase/installations-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.3.tgz#42b05f4e5204c354e0fa059378402bd47635e5bf" + integrity sha512-K9rKM/ym06lkpaKz7bMLxzHK/HEk65XfLJBV+dJkIuWeO0EqqC9VFGrpWAo0QmgC4BqbU58T6VBbzoJjb0gaFw== dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/installations-types" "0.4.0" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/installations" "0.6.3" + "@firebase/installations-types" "0.5.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/installations-types@0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.4.0.tgz#256782ff9adfb390ac658c25bc32f89635ddce7c" - integrity sha512-nXxWKQDvBGctuvsizbUEJKfxXU9WAaDhon+j0jpjIfOJkvkj3YHqlLB/HeYjpUn85Pb22BjplpTnDn4Gm9pc3A== +"@firebase/installations-types@0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz#2adad64755cd33648519b573ec7ec30f21fb5354" + integrity sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg== -"@firebase/installations@0.5.12": - version "0.5.12" - resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.5.12.tgz#1d5764aa6f0b73d9d6d1a81a07eab5cd71a5ea27" - integrity sha512-Zq43fCE0PB5tGJ3ojzx5RNQzKdej1188qgAk22rwjuhP7npaG/PlJqDG1/V0ZjTLRePZ1xGrfXSPlA17c/vtNw== +"@firebase/installations@0.6.3": + version "0.6.3" + resolved "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.3.tgz#b833cf12ac63666246a57100dbdd669fb76a23aa" + integrity sha512-20JFWm+tweNoRjRbz8/Y4I7O5pUJGZsFKCkLl1qNxfNYECSfrZUuozIDJDZC/MeVn5+kB9CwjThDlgQEPrfLdg== dependencies: - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/util" "1.9.2" idb "7.0.1" tslib "^2.1.0" -"@firebase/logger@0.3.3": - version "0.3.3" - resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.3.3.tgz#0f724b1e0b166d17ac285aac5c8ec14d136beed4" - integrity sha512-POTJl07jOKTOevLXrTvJD/VZ0M6PnJXflbAh5J9VGkmtXPXNG6MdZ9fmRgqYhXKTaDId6AQenQ262uwgpdtO0Q== +"@firebase/logger@0.4.0": + version "0.4.0" + resolved "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz#15ecc03c452525f9d47318ad9491b81d1810f113" + integrity sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA== dependencies: tslib "^2.1.0" -"@firebase/messaging-compat@0.1.16": - version "0.1.16" - resolved "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.1.16.tgz#4fe4e2c1b496e62f63e815cb242a2ab323cd7899" - integrity sha512-uG7rWcXJzU8vvlEBFpwG1ndw/GURrrmKcwsHopEWbsPGjMRaVWa7XrdKbvIR7IZohqPzcC/V9L8EeqF4Q4lz8w== +"@firebase/messaging-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.3.tgz#2d222e4078643e49a708b61b6d0e51edc2bc73bd" + integrity sha512-MmuuohXV2YRzIoJmDngI5qqO/cF2q7SdAaw7k4r61W3ReJy7x4/rtqrIvwNVhM6X/X8NFGBbsYKsCfRHWjFdkg== dependencies: - "@firebase/component" "0.5.17" - "@firebase/messaging" "0.9.16" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/messaging" "0.12.3" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/messaging-interop-types@0.1.0": - version "0.1.0" - resolved "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.1.0.tgz#bdac02dd31edd5cb9eec37b1db698ea5e2c1a631" - integrity sha512-DbvUl/rXAZpQeKBnwz0NYY5OCqr2nFA0Bj28Fmr3NXGqR4PAkfTOHuQlVtLO1Nudo3q0HxAYLa68ZDAcuv2uKQ== - -"@firebase/messaging@0.9.16": - version "0.9.16" - resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.9.16.tgz#96b57ebbb054e57f78585f85f59d521c5ba5cd85" - integrity sha512-Yl9gGrAvJF6C1gg3+Cr2HxlL6APsDEkrorkFafmSP1l+rg1epZKoOAcKJbSF02Vtb50wfb9FqGGy8tzodgETxg== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/messaging-interop-types" "0.1.0" - "@firebase/util" "1.6.3" +"@firebase/messaging-interop-types@0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz#6056f8904a696bf0f7fdcf5f2ca8f008e8f6b064" + integrity sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ== + +"@firebase/messaging@0.12.3": + version "0.12.3" + resolved "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.3.tgz#3fd521e31deb9b81ec6316062deb1dcc8198d038" + integrity sha512-a3ZKcGDiV2sKmQDB56PpgL1yjFxXCtff2+v1grnAZZ4GnfNQ74t2EHCbmgY7xRX7ThzMqug54oxhuk4ur0MIoA== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/installations" "0.6.3" + "@firebase/messaging-interop-types" "0.2.0" + "@firebase/util" "1.9.2" idb "7.0.1" tslib "^2.1.0" -"@firebase/performance-compat@0.1.12": - version "0.1.12" - resolved "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.1.12.tgz#ac50b0cd29bf7f5e1e33c640dba25e2f8db95f0b" - integrity sha512-IBORzUeGY1MGdZnsix9Mu5z4+C3WHIwalu0usxvygL0EZKHztGG8bppYPGH/b5vvg8QyHs9U+Pn1Ot2jZhffQQ== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/performance" "0.5.12" - "@firebase/performance-types" "0.1.0" - "@firebase/util" "1.6.3" +"@firebase/performance-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.3.tgz#f3939bedc2017a95772fde64a72e97fe4b184268" + integrity sha512-I3rqZsIhauXn4iApfj1ttKQdlti/r8OZBG4YK10vxKSdhAzTIDWDKEsdoCXvvKLwplcMv36sM3WPAPGQLqY5MQ== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/performance" "0.6.3" + "@firebase/performance-types" "0.2.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/performance-types@0.1.0": - version "0.1.0" - resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.1.0.tgz#5e6efa9dc81860aee2cb7121b39ae8fa137e69fc" - integrity sha512-6p1HxrH0mpx+622Ql6fcxFxfkYSBpE3LSuwM7iTtYU2nw91Hj6THC8Bc8z4nboIq7WvgsT/kOTYVVZzCSlXl8w== - -"@firebase/performance@0.5.12": - version "0.5.12" - resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.5.12.tgz#4eae3eb91eeffb29b996e7908172052d4a901856" - integrity sha512-MPVTkOkGrm2SMQgI1FPNBm85y2pPqlPb6VDjIMCWkVpAr6G1IZzUT24yEMySRcIlK/Hh7/Qu1Nu5ASRzRuX6+Q== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" +"@firebase/performance-types@0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz#400685f7a3455970817136d9b48ce07a4b9562ff" + integrity sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA== + +"@firebase/performance@0.6.3": + version "0.6.3" + resolved "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.3.tgz#663c468dc4d62b6e211938377e21a01854803646" + integrity sha512-NQmQN6Ete7i9jz1mzULJZEGvsOmwwdUy6vpqnhUxSFMYPnlBKjX+yypCUUJDDN5zff5+kfwSD1qCyUAaS0xWUA== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/installations" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/polyfill@0.3.36": - version "0.3.36" - resolved "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.36.tgz#c057cce6748170f36966b555749472b25efdb145" - integrity sha512-zMM9oSJgY6cT2jx3Ce9LYqb0eIpDE52meIzd/oe/y70F+v9u1LDqk5kUF5mf16zovGBWMNFmgzlsh6Wj0OsFtg== - dependencies: - core-js "3.6.5" - promise-polyfill "8.1.3" - whatwg-fetch "2.0.4" - -"@firebase/remote-config-compat@0.1.12": - version "0.1.12" - resolved "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.1.12.tgz#7606752d7bfe2701d58568345ca536beda14ee53" - integrity sha512-Yz7Gtb2rLa7ykXZX9DnSTId8CXd++jFFLW3foUImrYwJEtWgLJc7gwkRfd1M73IlKGNuQAY+DpUNF0n1dLbecA== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/logger" "0.3.3" - "@firebase/remote-config" "0.3.11" - "@firebase/remote-config-types" "0.2.0" - "@firebase/util" "1.6.3" +"@firebase/remote-config-compat@0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.3.tgz#b0c0ef9978186bc58b262a39b9a41ec1bf819df3" + integrity sha512-w/ZL03YgYaXq03xIRyJ5oPhXZi6iDsY/v0J9Y7I7SqxCYytEnHVrL9nvBqd9R94y5LRAVNPCLokJeeizaUz4VQ== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/remote-config" "0.4.3" + "@firebase/remote-config-types" "0.3.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/remote-config-types@0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.2.0.tgz#1e2759fc01f20b58c564db42196f075844c3d1fd" - integrity sha512-hqK5sCPeZvcHQ1D6VjJZdW6EexLTXNMJfPdTwbD8NrXUw6UjWC4KWhLK/TSlL0QPsQtcKRkaaoP+9QCgKfMFPw== - -"@firebase/remote-config@0.3.11": - version "0.3.11" - resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.3.11.tgz#93c82b5944a20c027f4ee82c145813ca96b430bb" - integrity sha512-qA84dstrvVpO7rWT/sb2CLv1kjHVmz59SRFPKohJJYFBcPOGK4Pe4FWWhKAE9yg1Gnl0qYAGkahOwNawq3vE0g== - dependencies: - "@firebase/component" "0.5.17" - "@firebase/installations" "0.5.12" - "@firebase/logger" "0.3.3" - "@firebase/util" "1.6.3" +"@firebase/remote-config-types@0.3.0": + version "0.3.0" + resolved "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz#689900dcdb3e5c059e8499b29db393e4e51314b4" + integrity sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA== + +"@firebase/remote-config@0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.3.tgz#85c4934d093a4c7b8a336af70ada83e936347a2b" + integrity sha512-Q6d4jBWZoNt6SYq87bjtDGUHFkKwAmGnNjWyRjl14AZqE1ilgd9NZHmutharlYJ3LvxMsid80HdK5SgGEpIPfg== + dependencies: + "@firebase/component" "0.6.3" + "@firebase/installations" "0.6.3" + "@firebase/logger" "0.4.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/storage-compat@0.1.17": - version "0.1.17" - resolved "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.1.17.tgz#da721071e006d066fb9b1cff69481bd59a02346b" - integrity sha512-nOYmnpI0gwoz5nROseMi9WbmHGf+xumfsOvdPyMZAjy0VqbDnpKIwmTUZQBdR+bLuB5oIkHQsvw9nbb1SH+PzQ== +"@firebase/storage-compat@0.3.1": + version "0.3.1" + resolved "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.1.tgz#b8536c3a435f8ce5eb07796ca10fda16896a9bae" + integrity sha512-6HaTvWsT5Yy3j4UpCZpMcFUYEkJ2XYWukdyTl02u6VjSBRLvkhOXPzEfMvgVWqhnF/rYVfPdjrZ904wk5OxtmQ== dependencies: - "@firebase/component" "0.5.17" - "@firebase/storage" "0.9.9" - "@firebase/storage-types" "0.6.0" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/storage" "0.11.1" + "@firebase/storage-types" "0.8.0" + "@firebase/util" "1.9.2" tslib "^2.1.0" -"@firebase/storage-types@0.6.0": - version "0.6.0" - resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.6.0.tgz#0b1af64a2965af46fca138e5b70700e9b7e6312a" - integrity sha512-1LpWhcCb1ftpkP/akhzjzeFxgVefs6eMD2QeKiJJUGH1qOiows2w5o0sKCUSQrvrRQS1lz3SFGvNR1Ck/gqxeA== +"@firebase/storage-types@0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz#f1e40a5361d59240b6e84fac7fbbbb622bfaf707" + integrity sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg== -"@firebase/storage@0.9.9": - version "0.9.9" - resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.9.9.tgz#3d0080dd130bc3315731483384a7ef7c00f76e22" - integrity sha512-Zch7srLT2SIh9y2nCVv/4Kne0HULn7OPkmreY70BJTUJ+g5WLRjggBq6x9fV5ls9V38iqMWfn4prxzX8yIc08A== +"@firebase/storage@0.11.1": + version "0.11.1" + resolved "https://registry.npmjs.org/@firebase/storage/-/storage-0.11.1.tgz#602ddb7bce77077800a46bcdfa76f36d7a265c51" + integrity sha512-Xv8EG2j52ugF2xayBz26U9J0VBXHXPMVxSN+ph3R3BSoHxvMLaPu+qUYKHavSt+zbcgPH2GyBhrCdJK6SaDFPA== dependencies: - "@firebase/component" "0.5.17" - "@firebase/util" "1.6.3" + "@firebase/component" "0.6.3" + "@firebase/util" "1.9.2" node-fetch "2.6.7" tslib "^2.1.0" -"@firebase/util@1.6.3": - version "1.6.3" - resolved "https://registry.npmjs.org/@firebase/util/-/util-1.6.3.tgz#76128c1b5684c031823e95f6c08a7fb8560655c6" - integrity sha512-FujteO6Zjv6v8A4HS+t7c+PjU0Kaxj+rOnka0BsI/twUaCC9t8EQPmXpWZdk7XfszfahJn2pqsflUWUhtUkRlg== +"@firebase/util@1.9.2": + version "1.9.2" + resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.2.tgz#f5e9e393c5bae3547b9c823ee12076be1e23b1e2" + integrity sha512-9l0uMGPGw3GsoD5khjMmYCCcMq/OR/OOSViiWMN+s2Q0pxM+fYzrii1H+r8qC/uoMjSVXomjLZt0vZIyryCqtQ== dependencies: tslib "^2.1.0" -"@firebase/webchannel-wrapper@0.6.2": - version "0.6.2" - resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.6.2.tgz#6d05fa126104c9907573364dc04147b89b530e15" - integrity sha512-zThUKcqIU6utWzM93uEvhlh8qj8A5LMPFJPvk/ODb+8GSSif19xM2Lw1M2ijyBy8+6skSkQBbavPzOU5Oh/8tQ== +"@firebase/webchannel-wrapper@0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz#9340bce56560a8bdba1d25d6281d4bfc397450dc" + integrity sha512-BpiZLBWdLFw+qFel9p3Zs1jD6QmH7Ii4aTDu6+vx8ShdidChZUXqDhYJly4ZjSgQh54miXbBgBrk0S+jTIh/Qg== -"@grpc/grpc-js@^1.3.2": - version "1.3.5" - resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.5.tgz#0cfecfbfd5b7723064db1b7b7109678fbd6ce424" - integrity sha512-V29L2QNKkLWM3bcJfVFMSo+Z7kkO8A1s7MAfdzBXLYEC1PE5/M0n1iXBDiD5aUtyVLh5GILcbme2bGtIHl0FMQ== +"@grpc/grpc-js@~1.7.0": + version "1.7.3" + resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.7.3.tgz#f2ea79f65e31622d7f86d4b4c9ae38f13ccab99a" + integrity sha512-H9l79u4kJ2PVSxUNA08HMYAnUBLj9v6KjYQ7SQ71hOZcEXhShE/y5iQCesP8+6/Ik/7i2O0a10bPquIcYfufog== dependencies: + "@grpc/proto-loader" "^0.7.0" "@types/node" ">=12.12.47" "@grpc/proto-loader@^0.6.13": @@ -2226,6 +2216,17 @@ protobufjs "^6.11.3" yargs "^16.2.0" +"@grpc/proto-loader@^0.7.0": + version "0.7.5" + resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.5.tgz#ee9e7488fa585dc6b0f7fe88cd39723a3e64c906" + integrity sha512-mfcTuMbFowq1wh/Rn5KQl6qb95M21Prej3bewD9dUQMurYGVckGO/Pbe2Ocwto6sD05b/mxZLspvqwx60xO2Rg== + dependencies: + "@types/long" "^4.0.1" + lodash.camelcase "^4.3.0" + long "^4.0.0" + protobufjs "^7.0.0" + yargs "^16.2.0" + "@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" @@ -3462,11 +3463,6 @@ core-js-compat@^3.25.1: dependencies: browserslist "^4.21.4" -core-js@3.6.5: - version "3.6.5" - resolved "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== - core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -4023,38 +4019,37 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" -firebase@9.9.2: - version "9.9.2" - resolved "https://registry.npmjs.org/firebase/-/firebase-9.9.2.tgz#00cbf5912a27b233875626f5e7346ecc582ddabb" - integrity sha512-zhWUEyBQbwWhLEYhULwZ0A6eRuHP/EP2bpwASpHkI1QQgO1GVqkyCZEpp/feGSDve0COhv9oWC1wOuAzrQrV6g== - dependencies: - "@firebase/analytics" "0.8.0" - "@firebase/analytics-compat" "0.1.13" - "@firebase/app" "0.7.30" - "@firebase/app-check" "0.5.12" - "@firebase/app-check-compat" "0.2.12" - "@firebase/app-compat" "0.1.31" - "@firebase/app-types" "0.7.0" - "@firebase/auth" "0.20.5" - "@firebase/auth-compat" "0.2.18" - "@firebase/database" "0.13.4" - "@firebase/database-compat" "0.2.4" - "@firebase/firestore" "3.4.14" - "@firebase/firestore-compat" "0.1.23" - "@firebase/functions" "0.8.4" - "@firebase/functions-compat" "0.2.4" - "@firebase/installations" "0.5.12" - "@firebase/installations-compat" "0.1.12" - "@firebase/messaging" "0.9.16" - "@firebase/messaging-compat" "0.1.16" - "@firebase/performance" "0.5.12" - "@firebase/performance-compat" "0.1.12" - "@firebase/polyfill" "0.3.36" - "@firebase/remote-config" "0.3.11" - "@firebase/remote-config-compat" "0.1.12" - "@firebase/storage" "0.9.9" - "@firebase/storage-compat" "0.1.17" - "@firebase/util" "1.6.3" +firebase@9.17.1: + version "9.17.1" + resolved "https://registry.npmjs.org/firebase/-/firebase-9.17.1.tgz#91c56fe9d9bf5ed1c405030e4fe8133c6069fd40" + integrity sha512-MSZaTRaaRLgDFLqoEnoPYK8zkLwQNvYeLZ3YSKdcQxG8hDifNO22ywS1cSA1ZCGHlQeOsDtfDwBejKcANf/RQw== + dependencies: + "@firebase/analytics" "0.9.3" + "@firebase/analytics-compat" "0.2.3" + "@firebase/app" "0.9.3" + "@firebase/app-check" "0.6.3" + "@firebase/app-check-compat" "0.3.3" + "@firebase/app-compat" "0.2.3" + "@firebase/app-types" "0.9.0" + "@firebase/auth" "0.21.3" + "@firebase/auth-compat" "0.3.3" + "@firebase/database" "0.14.3" + "@firebase/database-compat" "0.3.3" + "@firebase/firestore" "3.8.3" + "@firebase/firestore-compat" "0.3.3" + "@firebase/functions" "0.9.3" + "@firebase/functions-compat" "0.3.3" + "@firebase/installations" "0.6.3" + "@firebase/installations-compat" "0.2.3" + "@firebase/messaging" "0.12.3" + "@firebase/messaging-compat" "0.2.3" + "@firebase/performance" "0.6.3" + "@firebase/performance-compat" "0.2.3" + "@firebase/remote-config" "0.4.3" + "@firebase/remote-config-compat" "0.2.3" + "@firebase/storage" "0.11.1" + "@firebase/storage-compat" "0.3.1" + "@firebase/util" "1.9.2" flat@^5.0.2: version "5.0.2" @@ -4391,11 +4386,6 @@ ieee754@^1.1.13: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= - import-local@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" @@ -4735,16 +4725,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jszip@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz#839b72812e3f97819cc13ac4134ffced95dd6af9" - integrity sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ== - dependencies: - lie "~3.3.0" - pako "~1.0.2" - readable-stream "~2.3.6" - set-immediate-shim "~1.0.1" - karma-chrome-launcher@3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz#baca9cc071b1562a1db241827257bfe5cab597ea" @@ -4862,13 +4842,6 @@ kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -lie@~3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" - integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== - dependencies: - immediate "~3.0.5" - loader-runner@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" @@ -4952,6 +4925,11 @@ long@^4.0.0: resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +long@^5.0.0: + version "5.2.1" + resolved "https://registry.npmjs.org/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f" + integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== + loupe@^2.3.1: version "2.3.4" resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz#7e0b9bffc76f148f9be769cb1321d3dcf3cb25f3" @@ -5369,7 +5347,7 @@ pad@^3.2.0: dependencies: wcwidth "^1.0.1" -pako@~1.0.2, pako@~1.0.5: +pako@~1.0.5: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== @@ -5468,11 +5446,6 @@ process@^0.11.10: resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -promise-polyfill@8.1.3: - version "8.1.3" - resolved "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116" - integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g== - protobufjs@^6.11.3: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" @@ -5492,6 +5465,24 @@ protobufjs@^6.11.3: "@types/node" ">=13.7.0" long "^4.0.0" +protobufjs@^7.0.0: + version "7.2.2" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.2.tgz#2af401d8c547b9476fb37ffc65782cf302342ca3" + integrity sha512-++PrQIjrom+bFDPpfmqXfAGSQs40116JRrqqyf53dymUMvvb5d/LMRyicRoF1AUKoXVS1/IgJXlEgcpr4gTF3Q== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -5589,7 +5580,7 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -readable-stream@^2.0.1, readable-stream@~2.3.6: +readable-stream@^2.0.1: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -5828,19 +5819,10 @@ select-hose@^2.0.0: resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.1.2.tgz#d463b4335632d2ea41a9e988e435a55dc41f5314" - integrity sha512-e4Ap8vQvhipgBB8Ry9zBiKGkU6kHKyNnWiavGGLKkrdW81Zv7NVMtFOL/j3yX0G8QScM7XIXijKssNd4EUxSOw== - dependencies: - jszip "^3.6.0" - tmp "^0.2.1" - ws ">=7.4.6" - -selfsigned@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56" - integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ== +selfsigned@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" + integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== dependencies: node-forge "^1" @@ -5903,11 +5885,6 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" -set-immediate-shim@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= - setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -6470,10 +6447,10 @@ webpack-dev-middleware@^5.3.1: range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@4.10.0: - version "4.10.0" - resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.10.0.tgz#de270d0009eba050546912be90116e7fd740a9ca" - integrity sha512-7dezwAs+k6yXVFZ+MaL8VnE+APobiO3zvpp3rBHe/HmWQ+avwh0Q3d0xxacOiBybZZ3syTZw9HXzpa3YNbAZDQ== +webpack-dev-server@4.11.1: + version "4.11.1" + resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz#ae07f0d71ca0438cf88446f09029b92ce81380b5" + integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw== dependencies: "@types/bonjour" "^3.5.9" "@types/connect-history-api-fallback" "^1.3.5" @@ -6498,7 +6475,7 @@ webpack-dev-server@4.10.0: p-retry "^4.5.0" rimraf "^3.0.2" schema-utils "^4.0.0" - selfsigned "^2.0.1" + selfsigned "^2.1.1" serve-index "^1.9.1" sockjs "^0.3.24" spdy "^4.0.2" @@ -6518,10 +6495,10 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.75.0: - version "5.75.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152" - integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ== +webpack@5.76.0: + version "5.76.0" + resolved "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz#f9fb9fb8c4a7dbdcd0d56a98e56b8a942ee2692c" + integrity sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -6562,11 +6539,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-fetch@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -6637,11 +6609,6 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@>=7.4.6: - version "7.5.3" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== - ws@^8.4.2: version "8.6.0" resolved "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23" diff --git a/integration/compat-interop/package.json b/integration/compat-interop/package.json index 928d6cfd004..c64c27b5828 100644 --- a/integration/compat-interop/package.json +++ b/integration/compat-interop/package.json @@ -8,12 +8,12 @@ "test:debug": "karma start --browsers Chrome --auto-watch" }, "dependencies": { - "@firebase/app": "0.9.4", - "@firebase/app-compat": "0.2.4", + "@firebase/app": "0.9.5", + "@firebase/app-compat": "0.2.5", "@firebase/analytics": "0.9.4", "@firebase/analytics-compat": "0.2.4", - "@firebase/auth": "0.21.4", - "@firebase/auth-compat": "0.3.4", + "@firebase/auth": "0.21.5", + "@firebase/auth-compat": "0.3.5", "@firebase/functions": "0.9.4", "@firebase/functions-compat": "0.3.4", "@firebase/messaging": "0.12.4", diff --git a/integration/firebase/package.json b/integration/firebase/package.json index 4b1a38417ac..6d626452d21 100644 --- a/integration/firebase/package.json +++ b/integration/firebase/package.json @@ -7,7 +7,7 @@ "test:ci": "node ../../scripts/run_tests_in_ci.js -s test" }, "devDependencies": { - "firebase": "9.17.2", + "firebase": "9.18.0", "@types/chai": "4.3.4", "@types/mocha": "9.1.1", "chai": "4.3.7", diff --git a/integration/firestore/package.json b/integration/firestore/package.json index f81affb9d0e..82822838fe2 100644 --- a/integration/firestore/package.json +++ b/integration/firestore/package.json @@ -15,8 +15,8 @@ "test:memory:debug": "yarn build:memory; karma start --auto-watch --browsers Chrome" }, "dependencies": { - "@firebase/app": "0.9.4", - "@firebase/firestore": "3.8.4" + "@firebase/app": "0.9.5", + "@firebase/firestore": "3.9.0" }, "devDependencies": { "@types/mocha": "9.1.1", diff --git a/integration/messaging/package.json b/integration/messaging/package.json index 426cae8f075..cbf8cd3c7c3 100644 --- a/integration/messaging/package.json +++ b/integration/messaging/package.json @@ -9,7 +9,7 @@ "test:manual": "mocha --exit" }, "devDependencies": { - "firebase": "9.17.2", + "firebase": "9.18.0", "chai": "4.3.7", "chromedriver": "98.0.1", "express": "4.18.2", diff --git a/package.json b/package.json index 4ab7309f129..f2968c9d201 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "@types/sinon-chai": "3.2.9", "@types/tmp": "0.2.3", "@types/yargs": "17.0.22", + "@types/trusted-types": "2.0.3", "@typescript-eslint/eslint-plugin": "5.43.0", "@typescript-eslint/eslint-plugin-tslint": "5.43.0", "@typescript-eslint/parser": "5.43.0", @@ -140,7 +141,7 @@ "protractor": "5.4.2", "request": "2.88.2", "semver": "7.3.8", - "simple-git": "3.15.1", + "simple-git": "3.16.0", "sinon": "9.2.4", "sinon-chai": "3.7.0", "source-map-loader": "1.1.3", diff --git a/packages/analytics-compat/package.json b/packages/analytics-compat/package.json index a2d917e063f..0a6d79b9554 100644 --- a/packages/analytics-compat/package.json +++ b/packages/analytics-compat/package.json @@ -24,7 +24,7 @@ "@firebase/app-compat": "0.x" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "rollup": "2.79.1", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", diff --git a/packages/analytics/package.json b/packages/analytics/package.json index db9245c8ffb..a454897b01e 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -48,7 +48,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "@rollup/plugin-commonjs": "21.1.0", "@rollup/plugin-json": "4.1.0", diff --git a/packages/analytics/src/errors.ts b/packages/analytics/src/errors.ts index 98293447c65..eacda193573 100644 --- a/packages/analytics/src/errors.ts +++ b/packages/analytics/src/errors.ts @@ -27,7 +27,8 @@ export const enum AnalyticsError { FETCH_THROTTLE = 'fetch-throttle', CONFIG_FETCH_FAILED = 'config-fetch-failed', NO_API_KEY = 'no-api-key', - NO_APP_ID = 'no-app-id' + NO_APP_ID = 'no-app-id', + INVALID_GTAG_RESOURCE = 'invalid-gtag-resource' } const ERRORS: ErrorMap = { @@ -64,7 +65,9 @@ const ERRORS: ErrorMap = { 'contain a valid API key.', [AnalyticsError.NO_APP_ID]: 'The "appId" field is empty in the local Firebase config. Firebase Analytics requires this field to' + - 'contain a valid app ID.' + 'contain a valid app ID.', + [AnalyticsError.INVALID_GTAG_RESOURCE]: + 'Trusted Types detected an invalid gtag resource: {$gtagURL}.' }; interface ErrorParams { @@ -77,6 +80,7 @@ interface ErrorParams { }; [AnalyticsError.INVALID_ANALYTICS_CONTEXT]: { errorInfo: string }; [AnalyticsError.INDEXEDDB_UNAVAILABLE]: { errorInfo: string }; + [AnalyticsError.INVALID_GTAG_RESOURCE]: { gtagURL: string }; } export const ERROR_FACTORY = new ErrorFactory( diff --git a/packages/analytics/src/helpers.test.ts b/packages/analytics/src/helpers.test.ts index 1175ff0f61e..98df87b6c04 100644 --- a/packages/analytics/src/helpers.test.ts +++ b/packages/analytics/src/helpers.test.ts @@ -24,12 +24,16 @@ import { insertScriptTag, wrapOrCreateGtag, findGtagScriptOnPage, - promiseAllSettled + promiseAllSettled, + createGtagTrustedTypesScriptURL, + createTrustedTypesPolicy } from './helpers'; -import { GtagCommand } from './constants'; +import { GtagCommand, GTAG_URL } from './constants'; import { Deferred } from '@firebase/util'; import { ConsentSettings } from './public-types'; import { removeGtagScripts } from '../testing/gtag-script-util'; +import { logger } from './logger'; +import { AnalyticsError, ERROR_FACTORY } from './errors'; const fakeMeasurementId = 'abcd-efgh-ijkl'; const fakeAppId = 'my-test-app-1234'; @@ -46,6 +50,70 @@ const fakeDynamicConfig: DynamicConfig = { }; const fakeDynamicConfigPromises = [Promise.resolve(fakeDynamicConfig)]; +describe('Trusted Types policies and functions', () => { + describe('Trusted types exists', () => { + let ttStub: SinonStub; + + beforeEach(() => { + ttStub = stub( + window.trustedTypes as TrustedTypePolicyFactory, + 'createPolicy' + ).returns({ + createScriptURL: (s: string) => s + } as any); + }); + + afterEach(() => { + removeGtagScripts(); + ttStub.restore(); + }); + + it('Verify trustedTypes is called if the API is available', () => { + const trustedTypesPolicy = createTrustedTypesPolicy( + 'firebase-js-sdk-policy', + { + createScriptURL: createGtagTrustedTypesScriptURL + } + ); + + expect(ttStub).to.be.called; + expect(trustedTypesPolicy).not.to.be.undefined; + }); + + it('createGtagTrustedTypesScriptURL verifies gtag URL base exists when a URL is provided', () => { + expect(createGtagTrustedTypesScriptURL(GTAG_URL)).to.equal(GTAG_URL); + }); + + it('createGtagTrustedTypesScriptURL rejects URLs with non-gtag base', () => { + const NON_GTAG_URL = 'http://iamnotgtag.com'; + const loggerWarnStub = stub(logger, 'warn'); + const errorMessage = ERROR_FACTORY.create( + AnalyticsError.INVALID_GTAG_RESOURCE, + { + gtagURL: NON_GTAG_URL + } + ).message; + + expect(createGtagTrustedTypesScriptURL(NON_GTAG_URL)).to.equal(''); + expect(loggerWarnStub).to.be.calledWith(errorMessage); + }); + }); + + describe('Trusted types does not exist', () => { + it('Verify trustedTypes functions are not called if the API is not available', () => { + delete window.trustedTypes; + const trustedTypesPolicy = createTrustedTypesPolicy( + 'firebase-js-sdk-policy', + { + createScriptURL: createGtagTrustedTypesScriptURL + } + ); + + expect(trustedTypesPolicy).to.be.undefined; + }); + }); +}); + describe('Gtag wrapping functions', () => { afterEach(() => { removeGtagScripts(); diff --git a/packages/analytics/src/helpers.ts b/packages/analytics/src/helpers.ts index 1fb8a38319c..e926c14a725 100644 --- a/packages/analytics/src/helpers.ts +++ b/packages/analytics/src/helpers.ts @@ -24,10 +24,25 @@ import { import { DynamicConfig, DataLayer, Gtag, MinimalDynamicConfig } from './types'; import { GtagCommand, GTAG_URL } from './constants'; import { logger } from './logger'; +import { AnalyticsError, ERROR_FACTORY } from './errors'; // Possible parameter types for gtag 'event' and 'config' commands type GtagConfigOrEventParams = ControlParams & EventParams & CustomParams; +/** + * Verifies and creates a TrustedScriptURL. + */ +export function createGtagTrustedTypesScriptURL(url: string): string { + if (!url.startsWith(GTAG_URL)) { + const err = ERROR_FACTORY.create(AnalyticsError.INVALID_GTAG_RESOURCE, { + gtagURL: url + }); + logger.warn(err.message); + return ''; + } + return url; +} + /** * Makeshift polyfill for Promise.allSettled(). Resolves when all promises * have either resolved or rejected. @@ -40,6 +55,29 @@ export function promiseAllSettled( return Promise.all(promises.map(promise => promise.catch(e => e))); } +/** + * Creates a TrustedTypePolicy object that implements the rules passed as policyOptions. + * + * @param policyName A string containing the name of the policy + * @param policyOptions Object containing implementations of instance methods for TrustedTypesPolicy, see {@link https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypePolicy#instance_methods + * | the TrustedTypePolicy reference documentation}. + */ +export function createTrustedTypesPolicy( + policyName: string, + policyOptions: Partial +): Partial | undefined { + // Create a TrustedTypes policy that we can use for updating src + // properties + let trustedTypesPolicy: Partial | undefined; + if (window.trustedTypes) { + trustedTypesPolicy = window.trustedTypes.createPolicy( + policyName, + policyOptions + ); + } + return trustedTypesPolicy; +} + /** * Inserts gtag script tag into the page to asynchronously download gtag. * @param dataLayerName Name of datalayer (most often the default, "_dataLayer"). @@ -48,10 +86,22 @@ export function insertScriptTag( dataLayerName: string, measurementId: string ): void { + const trustedTypesPolicy = createTrustedTypesPolicy( + 'firebase-js-sdk-policy', + { + createScriptURL: createGtagTrustedTypesScriptURL + } + ); + const script = document.createElement('script'); // We are not providing an analyticsId in the URL because it would trigger a `page_view` // without fid. We will initialize ga-id using gtag (config) command together with fid. - script.src = `${GTAG_URL}?l=${dataLayerName}&id=${measurementId}`; + + const gtagScriptURL = `${GTAG_URL}?l=${dataLayerName}&id=${measurementId}`; + (script.src as string | TrustedScriptURL) = trustedTypesPolicy + ? (trustedTypesPolicy as TrustedTypePolicy)?.createScriptURL(gtagScriptURL) + : gtagScriptURL; + script.async = true; document.head.appendChild(script); } diff --git a/packages/app-check-compat/package.json b/packages/app-check-compat/package.json index fb08cdbbc0e..ab0a4458409 100644 --- a/packages/app-check-compat/package.json +++ b/packages/app-check-compat/package.json @@ -44,7 +44,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "rollup": "2.79.1", "@rollup/plugin-commonjs": "21.1.0", "@rollup/plugin-json": "4.1.0", diff --git a/packages/app-check/package.json b/packages/app-check/package.json index c08557700b6..94c1974990f 100644 --- a/packages/app-check/package.json +++ b/packages/app-check/package.json @@ -45,7 +45,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "@rollup/plugin-commonjs": "21.1.0", "@rollup/plugin-json": "4.1.0", diff --git a/packages/app-compat/CHANGELOG.md b/packages/app-compat/CHANGELOG.md index 3ebb05d3da4..d6c87c586ed 100644 --- a/packages/app-compat/CHANGELOG.md +++ b/packages/app-compat/CHANGELOG.md @@ -1,5 +1,12 @@ # @firebase/app-compat +## 0.2.5 + +### Patch Changes + +- Updated dependencies []: + - @firebase/app@0.9.5 + ## 0.2.4 ### Patch Changes diff --git a/packages/app-compat/package.json b/packages/app-compat/package.json index d46a19a45ce..d8e916a13fb 100644 --- a/packages/app-compat/package.json +++ b/packages/app-compat/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/app-compat", - "version": "0.2.4", + "version": "0.2.5", "description": "The primary entrypoint to the Firebase JS SDK", "author": "Firebase (https://firebase.google.com/)", "main": "dist/index.cjs.js", @@ -40,7 +40,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "@firebase/util": "1.9.3", "@firebase/logger": "0.4.0", "@firebase/component": "0.6.4", diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index fec4909d1a0..93dc61c41fd 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,11 @@ # @firebase/app +## 0.9.5 + +### Patch Changes + +- Update SDK_VERSION. + ## 0.9.4 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index 463aa8bce44..6bea73e091a 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/app", - "version": "0.9.4", + "version": "0.9.5", "description": "The primary entrypoint to the Firebase JS SDK", "author": "Firebase (https://firebase.google.com/)", "main": "dist/index.cjs.js", diff --git a/packages/auth-compat/CHANGELOG.md b/packages/auth-compat/CHANGELOG.md index f389f1a0124..5dc40123e2c 100644 --- a/packages/auth-compat/CHANGELOG.md +++ b/packages/auth-compat/CHANGELOG.md @@ -1,5 +1,12 @@ # @firebase/auth-compat +## 0.3.5 + +### Patch Changes + +- Updated dependencies [[`e0b677e70`](https://github.com/firebase/firebase-js-sdk/commit/e0b677e70ed2fd9e488737c77ebe2fc65d3a0822)]: + - @firebase/auth@0.21.5 + ## 0.3.4 ### Patch Changes diff --git a/packages/auth-compat/package.json b/packages/auth-compat/package.json index 2253abb9007..030bbed1f6b 100644 --- a/packages/auth-compat/package.json +++ b/packages/auth-compat/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/auth-compat", - "version": "0.3.4", + "version": "0.3.5", "description": "FirebaseAuth compatibility package that uses API style compatible with Firebase@8 and prior versions", "author": "Firebase (https://firebase.google.com/)", "main": "dist/index.node.cjs.js", @@ -50,7 +50,7 @@ "@firebase/app-compat": "0.x" }, "dependencies": { - "@firebase/auth": "0.21.4", + "@firebase/auth": "0.21.5", "@firebase/auth-types": "0.12.0", "@firebase/component": "0.6.4", "@firebase/util": "1.9.3", @@ -59,7 +59,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "@rollup/plugin-json": "4.1.0", "rollup": "2.79.1", "rollup-plugin-replace": "2.2.0", diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index f734331449f..027b6bce09c 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,5 +1,11 @@ # @firebase/auth +## 0.21.5 + +### Patch Changes + +- [`e0b677e70`](https://github.com/firebase/firebase-js-sdk/commit/e0b677e70ed2fd9e488737c77ebe2fc65d3a0822) [#7066](https://github.com/firebase/firebase-js-sdk/pull/7066) - Explicitly set createdAt and lastLoginAt when cloning UserImpl + ## 0.21.4 ### Patch Changes diff --git a/packages/auth/package.json b/packages/auth/package.json index 0f5ddf521bf..9eac3e524b4 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/auth", - "version": "0.21.4", + "version": "0.21.5", "description": "The Firebase Authenticaton component of the Firebase JS SDK.", "author": "Firebase (https://firebase.google.com/)", "main": "dist/node/index.js", @@ -118,7 +118,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "@rollup/plugin-json": "4.1.0", "@rollup/plugin-strip": "2.1.0", "chromedriver": "98.0.1", diff --git a/packages/auth/src/api/index.test.ts b/packages/auth/src/api/index.test.ts index 579f6c5e8ad..af3b61610d2 100644 --- a/packages/auth/src/api/index.test.ts +++ b/packages/auth/src/api/index.test.ts @@ -308,26 +308,6 @@ describe('api/_performApiRequest', () => { }); }); - context('with non-Firebase Errors', () => { - afterEach(mockFetch.tearDown); - - it('should handle non-FirebaseErrors', async () => { - mockFetch.setUpWithOverride(() => { - return new Promise((_, reject) => reject(new Error('error'))); - }); - const promise = _performApiRequest( - auth, - HttpMethod.POST, - Endpoint.SIGN_UP, - request - ); - await expect(promise).to.be.rejectedWith( - FirebaseError, - 'auth/internal-error' - ); - }); - }); - context('with network issues', () => { afterEach(mockFetch.tearDown); @@ -365,6 +345,26 @@ describe('api/_performApiRequest', () => { expect(clock.clearTimeout).to.have.been.called; clock.restore(); }); + + it('should handle network failure', async () => { + mockFetch.setUpWithOverride(() => { + return new Promise((_, reject) => + reject(new Error('network error')) + ); + }); + const promise = _performApiRequest( + auth, + HttpMethod.POST, + Endpoint.SIGN_UP, + request + ); + await expect(promise) + .to.be.rejectedWith(FirebaseError, 'auth/network-request-failed') + .eventually.with.nested.property( + 'customData.message', + 'Error: network error' + ); + }); }); context('edgcase error mapping', () => { diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index 0194c43d9a5..6c9d775d243 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -181,7 +181,10 @@ export async function _performFetchWithErrorHandling( if (e instanceof FirebaseError) { throw e; } - _fail(auth, AuthErrorCode.INTERNAL_ERROR, { 'message': String(e) }); + // Changing this to a different error code will log user out when there is a network error + // because we treat any error other than NETWORK_REQUEST_FAILED as token is invalid. + // https://github.com/firebase/firebase-js-sdk/blob/4fbc73610d70be4e0852e7de63a39cb7897e8546/packages/auth/src/core/auth/auth_impl.ts#L309-L316 + _fail(auth, AuthErrorCode.NETWORK_REQUEST_FAILED, { 'message': String(e) }); } } diff --git a/packages/database-compat/package.json b/packages/database-compat/package.json index 1d9ffb23b3c..1b1066618ac 100644 --- a/packages/database-compat/package.json +++ b/packages/database-compat/package.json @@ -58,7 +58,7 @@ "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "typescript": "4.7.4" }, "repository": { diff --git a/packages/database/package.json b/packages/database/package.json index 7b6b7bb4221..1ebd14ea6c5 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -57,7 +57,7 @@ "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "rollup-plugin-typescript2": "0.31.2", "typescript": "4.7.4" diff --git a/packages/firebase/CHANGELOG.md b/packages/firebase/CHANGELOG.md index 5b745562e87..66ff15fac6e 100644 --- a/packages/firebase/CHANGELOG.md +++ b/packages/firebase/CHANGELOG.md @@ -1,5 +1,25 @@ # firebase +## 9.18.0 + +### Minor Changes + +- [`5ba524313`](https://github.com/firebase/firebase-js-sdk/commit/5ba524313bdeddb012c44b1b1161c9229396b195) [#7053](https://github.com/firebase/firebase-js-sdk/pull/7053) - Add support for disjunctions in queries (OR queries). + +### Patch Changes + +- [`e2bf2eca2`](https://github.com/firebase/firebase-js-sdk/commit/e2bf2eca21308670c73d6c642a88c06f0b87d44a) [#7076](https://github.com/firebase/firebase-js-sdk/pull/7076) - Improved debug logging of networking abstractions + +- [`5099f0f60`](https://github.com/firebase/firebase-js-sdk/commit/5099f0f60a5198b48942e8b2a574505432bdc213) [#6899](https://github.com/firebase/firebase-js-sdk/pull/6899) (fixes [#6509](https://github.com/firebase/firebase-js-sdk/issues/6509)) - Check navigator.userAgent, in addition to navigator.appVersion, when determining whether to work around an IndexedDb bug in Safari. + +- Updated dependencies [[`e2bf2eca2`](https://github.com/firebase/firebase-js-sdk/commit/e2bf2eca21308670c73d6c642a88c06f0b87d44a), [`5099f0f60`](https://github.com/firebase/firebase-js-sdk/commit/5099f0f60a5198b48942e8b2a574505432bdc213), [`e0b677e70`](https://github.com/firebase/firebase-js-sdk/commit/e0b677e70ed2fd9e488737c77ebe2fc65d3a0822), [`5ba524313`](https://github.com/firebase/firebase-js-sdk/commit/5ba524313bdeddb012c44b1b1161c9229396b195)]: + - @firebase/firestore@3.9.0 + - @firebase/app@0.9.5 + - @firebase/auth@0.21.5 + - @firebase/firestore-compat@0.3.5 + - @firebase/app-compat@0.2.5 + - @firebase/auth-compat@0.3.5 + ## 9.17.2 ### Patch Changes diff --git a/packages/firebase/compat/rollup.config.js b/packages/firebase/compat/rollup.config.js index e7b05d2e2d8..4b481b93b1f 100644 --- a/packages/firebase/compat/rollup.config.js +++ b/packages/firebase/compat/rollup.config.js @@ -31,7 +31,10 @@ import { emitModulePackageFile } from '../../../scripts/build/rollup_emit_module const external = Object.keys(pkg.dependencies || {}); const uglifyOptions = { - mangle: true, + mangle: { + // Hack for a bug in Closure regarding switch block scope + reserved: ['__PRIVATE_lastReasonableEscapeIndex'] + }, webkit: true // Necessary to avoid https://bugs.webkit.org/show_bug.cgi?id=223533 }; diff --git a/packages/firebase/package.json b/packages/firebase/package.json index 03643b024ff..d5d22508b11 100644 --- a/packages/firebase/package.json +++ b/packages/firebase/package.json @@ -1,6 +1,6 @@ { "name": "firebase", - "version": "9.17.2", + "version": "9.18.0", "description": "Firebase JavaScript library for web and Node.js", "author": "Firebase (https://firebase.google.com/)", "license": "Apache-2.0", @@ -373,15 +373,15 @@ "test:ci": "echo 'No test suite for firebase wrapper'" }, "dependencies": { - "@firebase/app": "0.9.4", - "@firebase/app-compat": "0.2.4", + "@firebase/app": "0.9.5", + "@firebase/app-compat": "0.2.5", "@firebase/app-types": "0.9.0", - "@firebase/auth": "0.21.4", - "@firebase/auth-compat": "0.3.4", + "@firebase/auth": "0.21.5", + "@firebase/auth-compat": "0.3.5", "@firebase/database": "0.14.4", "@firebase/database-compat": "0.3.4", - "@firebase/firestore": "3.8.4", - "@firebase/firestore-compat": "0.3.4", + "@firebase/firestore": "3.9.0", + "@firebase/firestore-compat": "0.3.5", "@firebase/functions": "0.9.4", "@firebase/functions-compat": "0.3.4", "@firebase/installations": "0.6.4", diff --git a/packages/firestore-compat/CHANGELOG.md b/packages/firestore-compat/CHANGELOG.md index f17a107ddc9..2b1f69b230b 100644 --- a/packages/firestore-compat/CHANGELOG.md +++ b/packages/firestore-compat/CHANGELOG.md @@ -1,5 +1,12 @@ # @firebase/firestore-compat +## 0.3.5 + +### Patch Changes + +- Updated dependencies [[`e2bf2eca2`](https://github.com/firebase/firebase-js-sdk/commit/e2bf2eca21308670c73d6c642a88c06f0b87d44a), [`5099f0f60`](https://github.com/firebase/firebase-js-sdk/commit/5099f0f60a5198b48942e8b2a574505432bdc213), [`5ba524313`](https://github.com/firebase/firebase-js-sdk/commit/5ba524313bdeddb012c44b1b1161c9229396b195)]: + - @firebase/firestore@3.9.0 + ## 0.3.4 ### Patch Changes diff --git a/packages/firestore-compat/package.json b/packages/firestore-compat/package.json index 87eccd2eb0a..31a45517c5e 100644 --- a/packages/firestore-compat/package.json +++ b/packages/firestore-compat/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/firestore-compat", - "version": "0.3.4", + "version": "0.3.5", "description": "The Cloud Firestore component of the Firebase JS SDK.", "author": "Firebase (https://firebase.google.com/)", "main": "dist/index.node.cjs.js", @@ -48,13 +48,13 @@ }, "dependencies": { "@firebase/component": "0.6.4", - "@firebase/firestore": "3.8.4", + "@firebase/firestore": "3.9.0", "@firebase/util": "1.9.3", "@firebase/firestore-types": "2.5.1", "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "@types/eslint": "7.29.0", "rollup": "2.79.1", "rollup-plugin-sourcemaps": "0.6.3", diff --git a/packages/firestore/CHANGELOG.md b/packages/firestore/CHANGELOG.md index 787be89b251..5999b6468ee 100644 --- a/packages/firestore/CHANGELOG.md +++ b/packages/firestore/CHANGELOG.md @@ -1,5 +1,17 @@ # @firebase/firestore +## 3.9.0 + +### Minor Changes + +- [`5ba524313`](https://github.com/firebase/firebase-js-sdk/commit/5ba524313bdeddb012c44b1b1161c9229396b195) [#7053](https://github.com/firebase/firebase-js-sdk/pull/7053) - Add support for disjunctions in queries (OR queries). + +### Patch Changes + +- [`e2bf2eca2`](https://github.com/firebase/firebase-js-sdk/commit/e2bf2eca21308670c73d6c642a88c06f0b87d44a) [#7076](https://github.com/firebase/firebase-js-sdk/pull/7076) - Improved debug logging of networking abstractions + +- [`5099f0f60`](https://github.com/firebase/firebase-js-sdk/commit/5099f0f60a5198b48942e8b2a574505432bdc213) [#6899](https://github.com/firebase/firebase-js-sdk/pull/6899) (fixes [#6509](https://github.com/firebase/firebase-js-sdk/issues/6509)) - Check navigator.userAgent, in addition to navigator.appVersion, when determining whether to work around an IndexedDb bug in Safari. + ## 3.8.4 ### Patch Changes diff --git a/packages/firestore/package.json b/packages/firestore/package.json index 7f83d260f40..7603de17d6c 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -1,6 +1,6 @@ { "name": "@firebase/firestore", - "version": "3.8.4", + "version": "3.9.0", "engines": { "node": ">=10.10.0" }, @@ -103,9 +103,9 @@ "@firebase/app": "0.x" }, "devDependencies": { - "@firebase/app": "0.9.4", - "@firebase/app-compat": "0.2.4", - "@firebase/auth": "0.21.4", + "@firebase/app": "0.9.5", + "@firebase/app-compat": "0.2.5", + "@firebase/auth": "0.21.5", "@rollup/plugin-alias": "3.1.9", "@rollup/plugin-json": "4.1.0", "@types/eslint": "7.29.0", diff --git a/packages/firestore/rollup.shared.js b/packages/firestore/rollup.shared.js index 42836f0aa2e..3f37106344c 100644 --- a/packages/firestore/rollup.shared.js +++ b/packages/firestore/rollup.shared.js @@ -150,8 +150,10 @@ const manglePrivatePropertiesOptions = { // This can be removed if the problem in the downstream library is fixed // or if terser's mangler provides an option to avoid mangling everything // that isn't a property. + // `lastReasonableEscapeIndex` was causing problems in a switch statement + // due to a Closure bug. // See issue: https://github.com/firebase/firebase-js-sdk/issues/5384 - reserved: ['_getProvider'], + reserved: ['_getProvider', '__PRIVATE_lastReasonableEscapeIndex'], properties: { regex: /^__PRIVATE_/, // All JS Keywords are reserved. Although this should be taken cared of by diff --git a/packages/firestore/src/api.ts b/packages/firestore/src/api.ts index 93da0b1ee08..807e5dcd647 100644 --- a/packages/firestore/src/api.ts +++ b/packages/firestore/src/api.ts @@ -34,6 +34,21 @@ export { AggregateType } from './lite-api/aggregate_types'; +export { + FirestoreLocalCache, + PersistentLocalCache, + PersistentMultipleTabManager, + persistentLocalCache, + persistentMultipleTabManager, + PersistentCacheSettings, + persistentSingleTabManager, + PersistentSingleTabManager, + PersistentSingleTabManagerSettings, + MemoryLocalCache, + memoryLocalCache, + PersistentTabManager +} from './api/cache_config'; + export { FieldPath, documentId } from './api/field_path'; export { diff --git a/packages/firestore/src/api/cache_config.ts b/packages/firestore/src/api/cache_config.ts new file mode 100644 index 00000000000..a6e05bc6d7f --- /dev/null +++ b/packages/firestore/src/api/cache_config.ts @@ -0,0 +1,302 @@ +/** + * @license + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + IndexedDbOfflineComponentProvider, + MemoryOfflineComponentProvider, + MultiTabOfflineComponentProvider, + OfflineComponentProvider, + OnlineComponentProvider +} from '../core/component_provider'; + +/* eslint @typescript-eslint/consistent-type-definitions: ["error", "type"] */ +/** + * Provides an in-memory cache to the SDK. This is the default cache unless explicitly + * configured otherwise. + * + * To use, create an instance using the factory function {@link memoryLocalCache()}, then + * set the instance to `FirestoreSettings.cache` and call `initializeFirestore` using + * the settings object. + */ +export type MemoryLocalCache = { + kind: 'memory'; + /** + * @internal + */ + _onlineComponentProvider: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider: MemoryOfflineComponentProvider; +}; + +class MemoryLocalCacheImpl implements MemoryLocalCache { + kind: 'memory' = 'memory'; + /** + * @internal + */ + _onlineComponentProvider: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider: MemoryOfflineComponentProvider; + + constructor() { + this._onlineComponentProvider = new OnlineComponentProvider(); + this._offlineComponentProvider = new MemoryOfflineComponentProvider(); + } + + toJSON(): {} { + return { kind: this.kind }; + } +} + +/** + * Provides a persistent cache backed by IndexedDb to the SDK. + * + * To use, create an instance using the factory function {@link persistentLocalCache()}, then + * set the instance to `FirestoreSettings.cache` and call `initializeFirestore` using + * the settings object. + */ +export type PersistentLocalCache = { + kind: 'persistent'; + /** + * @internal + */ + _onlineComponentProvider: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider: OfflineComponentProvider; +}; + +class PersistentLocalCacheImpl implements PersistentLocalCache { + kind: 'persistent' = 'persistent'; + /** + * @internal + */ + _onlineComponentProvider: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider: OfflineComponentProvider; + + constructor(settings: PersistentCacheSettings | undefined) { + let tabManager: PersistentTabManager; + if (settings?.tabManager) { + settings.tabManager._initialize(settings); + tabManager = settings.tabManager; + } else { + tabManager = persistentSingleTabManager(undefined); + tabManager._initialize(settings); + } + this._onlineComponentProvider = tabManager._onlineComponentProvider!; + this._offlineComponentProvider = tabManager._offlineComponentProvider!; + } + + toJSON(): {} { + return { kind: this.kind }; + } +} + +/** + * Union type from all supported SDK cache layer. + */ +export type FirestoreLocalCache = MemoryLocalCache | PersistentLocalCache; + +/** + * Creates an instance of `MemoryLocalCache`. The instance can be set to + * `FirestoreSettings.cache` to tell the SDK which cache layer to use. + */ +export function memoryLocalCache(): MemoryLocalCache { + return new MemoryLocalCacheImpl(); +} + +/** + * An settings object to configure an `PersistentLocalCache` instance. + */ +export type PersistentCacheSettings = { + /** + * An approximate cache size threshold for the on-disk data. If the cache + * grows beyond this size, Firestore will start removing data that hasn't been + * recently used. The SDK does not guarantee that the cache will stay below + * that size, only that if the cache exceeds the given size, cleanup will be + * attempted. + * + * The default value is 40 MB. The threshold must be set to at least 1 MB, and + * can be set to `CACHE_SIZE_UNLIMITED` to disable garbage collection. + */ + cacheSizeBytes?: number; + + /** + * Specifies how multiple tabs/windows will be managed by the SDK. + */ + tabManager?: PersistentTabManager; +}; + +/** + * Creates an instance of `PersistentLocalCache`. The instance can be set to + * `FirestoreSettings.cache` to tell the SDK which cache layer to use. + */ +export function persistentLocalCache( + settings?: PersistentCacheSettings +): PersistentLocalCache { + return new PersistentLocalCacheImpl(settings); +} + +/** + * A tab manager supportting only one tab, no synchronization will be + * performed across tabs. + */ +export type PersistentSingleTabManager = { + kind: 'persistentSingleTab'; + /** + * @internal + */ + _initialize: ( + settings: Omit | undefined + ) => void; + /** + * @internal + */ + _onlineComponentProvider?: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider?: OfflineComponentProvider; +}; + +class SingleTabManagerImpl implements PersistentSingleTabManager { + kind: 'persistentSingleTab' = 'persistentSingleTab'; + + /** + * @internal + */ + _onlineComponentProvider?: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider?: OfflineComponentProvider; + + constructor(private forceOwnership?: boolean) {} + + toJSON(): {} { + return { kind: this.kind }; + } + + /** + * @internal + */ + _initialize( + settings: Omit | undefined + ): void { + this._onlineComponentProvider = new OnlineComponentProvider(); + this._offlineComponentProvider = new IndexedDbOfflineComponentProvider( + this._onlineComponentProvider, + settings?.cacheSizeBytes, + this.forceOwnership + ); + } +} + +/** + * A tab manager supportting multiple tabs. SDK will synchronize queries and + * mutations done across all tabs using the SDK. + */ +export type PersistentMultipleTabManager = { + kind: 'PersistentMultipleTab'; + /** + * @internal + */ + _initialize: (settings: Omit) => void; + /** + * @internal + */ + _onlineComponentProvider?: OnlineComponentProvider; + /** + * @internal + */ + + _offlineComponentProvider?: OfflineComponentProvider; +}; + +class MultiTabManagerImpl implements PersistentMultipleTabManager { + kind: 'PersistentMultipleTab' = 'PersistentMultipleTab'; + + /** + * @internal + */ + _onlineComponentProvider?: OnlineComponentProvider; + /** + * @internal + */ + _offlineComponentProvider?: OfflineComponentProvider; + + toJSON(): {} { + return { kind: this.kind }; + } + + /** + * @internal + */ + _initialize( + settings: Omit | undefined + ): void { + this._onlineComponentProvider = new OnlineComponentProvider(); + this._offlineComponentProvider = new MultiTabOfflineComponentProvider( + this._onlineComponentProvider, + settings?.cacheSizeBytes + ); + } +} + +/** + * A union of all avaialbe tab managers. + */ +export type PersistentTabManager = + | PersistentSingleTabManager + | PersistentMultipleTabManager; + +/** + * Type to configure an `PersistentSingleTabManager` instace. + */ +export type PersistentSingleTabManagerSettings = { + /** + * Whether to force-enable persistent (IndexedDB) cache for the client. This + * cannot be used with multi-tab synchronization and is primarily intended for + * use with Web Workers. Setting this to `true` will enable IndexedDB, but cause + * other tabs using IndexedDB cache to fail. + */ + forceOwnership?: boolean; +}; +/** + * Creates an instance of `PersistentSingleTabManager`. + * + * @param settings Configures the created tab manager. + */ +export function persistentSingleTabManager( + settings: PersistentSingleTabManagerSettings | undefined +): PersistentSingleTabManager { + return new SingleTabManagerImpl(settings?.forceOwnership); +} + +/** + * Creates an instance of `PersistentMultipleTabManager`. + */ +export function persistentMultipleTabManager(): PersistentMultipleTabManager { + return new MultiTabManagerImpl(); +} diff --git a/packages/firestore/src/api/credentials.ts b/packages/firestore/src/api/credentials.ts index 7ee1ca941b1..f8af49696cb 100644 --- a/packages/firestore/src/api/credentials.ts +++ b/packages/firestore/src/api/credentials.ts @@ -41,8 +41,7 @@ export type AuthTokenFactory = () => string; export interface FirstPartyCredentialsSettings { // These are external types. Prevent minification. - ['type']: 'gapi'; - ['client']: unknown; + ['type']: 'firstParty'; ['sessionIndex']: string; ['iamToken']: string | null; ['authTokenFactory']: AuthTokenFactory | null; @@ -379,15 +378,6 @@ export class FirebaseAuthCredentialsProvider } } -// Manual type definition for the subset of Gapi we use. -interface Gapi { - auth: { - getAuthHeaderValueForFirstParty: ( - userIdentifiers: Array<{ [key: string]: string }> - ) => string | null; - }; -} - /* * FirstPartyToken provides a fresh token each time its value * is requested, because if the token is too old, requests will be rejected. @@ -401,28 +391,20 @@ export class FirstPartyToken implements Token { private _headers = new Map(); constructor( - private readonly gapi: Gapi | null, private readonly sessionIndex: string, private readonly iamToken: string | null, private readonly authTokenFactory: AuthTokenFactory | null ) {} - /** Gets an authorization token, using a provided factory function, or falling back to First Party GAPI. */ + /** + * Gets an authorization token, using a provided factory function, or return + * null. + */ private getAuthToken(): string | null { if (this.authTokenFactory) { return this.authTokenFactory(); } else { - // Make sure this really is a Gapi client. - hardAssert( - !!( - typeof this.gapi === 'object' && - this.gapi !== null && - this.gapi['auth'] && - this.gapi['auth']['getAuthHeaderValueForFirstParty'] - ), - 'unexpected gapi interface' - ); - return this.gapi!['auth']['getAuthHeaderValueForFirstParty']([]); + return null; } } @@ -450,7 +432,6 @@ export class FirstPartyAuthCredentialsProvider implements CredentialsProvider { constructor( - private gapi: Gapi | null, private sessionIndex: string, private iamToken: string | null, private authTokenFactory: AuthTokenFactory | null @@ -459,7 +440,6 @@ export class FirstPartyAuthCredentialsProvider getToken(): Promise { return Promise.resolve( new FirstPartyToken( - this.gapi, this.sessionIndex, this.iamToken, this.authTokenFactory @@ -668,12 +648,9 @@ export function makeAuthCredentialsProvider( if (!credentials) { return new EmptyAuthCredentialsProvider(); } - switch (credentials['type']) { - case 'gapi': - const client = credentials['client'] as Gapi; + case 'firstParty': return new FirstPartyAuthCredentialsProvider( - client, credentials['sessionIndex'] || '0', credentials['iamToken'] || null, credentials['authTokenFactory'] || null diff --git a/packages/firestore/src/api/database.ts b/packages/firestore/src/api/database.ts index 29cca7e68ca..93aab4880d9 100644 --- a/packages/firestore/src/api/database.ts +++ b/packages/firestore/src/api/database.ts @@ -32,6 +32,7 @@ import { } from '../core/component_provider'; import { DatabaseId, DEFAULT_DATABASE_NAME } from '../core/database_info'; import { + canFallbackFromIndexedDbError, FirestoreClient, firestoreClientDisableNetwork, firestoreClientEnableNetwork, @@ -75,11 +76,6 @@ declare module '@firebase/component' { } } -/** DOMException error code constants. */ -const DOM_EXCEPTION_INVALID_STATE = 11; -const DOM_EXCEPTION_ABORTED = 20; -const DOM_EXCEPTION_QUOTA_EXCEEDED = 22; - /** * Constant used to indicate the LRU garbage collection should be disabled. * Set this value as the `cacheSizeBytes` on the settings passed to the @@ -171,6 +167,17 @@ export function initializeFirestore( } } + if ( + settings.cacheSizeBytes !== undefined && + settings.localCache !== undefined + ) { + throw new FirestoreError( + Code.INVALID_ARGUMENT, + `cache and cacheSizeBytes cannot be specified at the same time as cacheSizeBytes will` + + `be deprecated. Instead, specify the cache size in the cache object` + ); + } + if ( settings.cacheSizeBytes !== undefined && settings.cacheSizeBytes !== CACHE_SIZE_UNLIMITED && @@ -283,6 +290,16 @@ export function configureFirestore(firestore: Firestore): void { firestore._queue, databaseInfo ); + if ( + settings.cache?._offlineComponentProvider && + settings.cache?._onlineComponentProvider + ) { + firestore._firestoreClient._uninitializedComponentsProvider = { + _offlineKind: settings.cache.kind, + _offline: settings.cache._offlineComponentProvider, + _online: settings.cache._onlineComponentProvider + }; + } } /** @@ -307,6 +324,10 @@ export function configureFirestore(firestore: Firestore): void { * @param persistenceSettings - Optional settings object to configure * persistence. * @returns A `Promise` that represents successfully enabling persistent storage. + * @deprecated This function will be removed in a future major release. Instead, set + * `FirestoreSettings.cache` to an instance of `IndexedDbLocalCache` to + * turn on IndexedDb cache. Calling this function when `FirestoreSettings.cache` + * is already specified will throw an exception. */ export function enableIndexedDbPersistence( firestore: Firestore, @@ -316,6 +337,17 @@ export function enableIndexedDbPersistence( verifyNotInitialized(firestore); const client = ensureFirestoreConfigured(firestore); + if (client._uninitializedComponentsProvider) { + throw new FirestoreError( + Code.FAILED_PRECONDITION, + 'SDK cache is already specified.' + ); + } + + logWarn( + 'enableIndexedDbPersistence() will be deprecated in the future, ' + + 'you can use `FirestoreSettings.cache` instead.' + ); const settings = firestore._freezeSettings(); const onlineComponentProvider = new OnlineComponentProvider(); @@ -352,6 +384,10 @@ export function enableIndexedDbPersistence( * @param firestore - The {@link Firestore} instance to enable persistence for. * @returns A `Promise` that represents successfully enabling persistent * storage. + * @deprecated This function will be removed in a future major release. Instead, set + * `FirestoreSettings.cache` to an instance of `IndexedDbLocalCache` to + * turn on indexeddb cache. Calling this function when `FirestoreSettings.cache` + * is already specified will throw an exception. */ export function enableMultiTabIndexedDbPersistence( firestore: Firestore @@ -360,6 +396,17 @@ export function enableMultiTabIndexedDbPersistence( verifyNotInitialized(firestore); const client = ensureFirestoreConfigured(firestore); + if (client._uninitializedComponentsProvider) { + throw new FirestoreError( + Code.FAILED_PRECONDITION, + 'SDK cache is already specified.' + ); + } + + logWarn( + 'enableMultiTabIndexedDbPersistence() will be deprecated in the future, ' + + 'you can use `FirestoreSettings.cache` instead.' + ); const settings = firestore._freezeSettings(); const onlineComponentProvider = new OnlineComponentProvider(); @@ -398,8 +445,8 @@ function setPersistenceProviders( throw error; } logWarn( - 'Error enabling offline persistence. Falling back to ' + - 'persistence disabled: ' + + 'Error enabling indexeddb cache. Falling back to ' + + 'memory cache: ' + error ); persistenceResult.reject(error); @@ -408,44 +455,6 @@ function setPersistenceProviders( .then(() => persistenceResult.promise); } -/** - * Decides whether the provided error allows us to gracefully disable - * persistence (as opposed to crashing the client). - */ -function canFallbackFromIndexedDbError( - error: FirestoreError | DOMException -): boolean { - if (error.name === 'FirebaseError') { - return ( - error.code === Code.FAILED_PRECONDITION || - error.code === Code.UNIMPLEMENTED - ); - } else if ( - typeof DOMException !== 'undefined' && - error instanceof DOMException - ) { - // There are a few known circumstances where we can open IndexedDb but - // trying to read/write will fail (e.g. quota exceeded). For - // well-understood cases, we attempt to detect these and then gracefully - // fall back to memory persistence. - // NOTE: Rather than continue to add to this list, we could decide to - // always fall back, with the risk that we might accidentally hide errors - // representing actual SDK bugs. - return ( - // When the browser is out of quota we could get either quota exceeded - // or an aborted error depending on whether the error happened during - // schema migration. - error.code === DOM_EXCEPTION_QUOTA_EXCEEDED || - error.code === DOM_EXCEPTION_ABORTED || - // Firefox Private Browsing mode disables IndexedDb and returns - // INVALID_STATE for any usage. - error.code === DOM_EXCEPTION_INVALID_STATE - ); - } - - return true; -} - /** * Clears the persistent storage. This includes pending writes and cached * documents. diff --git a/packages/firestore/src/api/index_configuration.ts b/packages/firestore/src/api/index_configuration.ts index 9ea31a28db1..94754636176 100644 --- a/packages/firestore/src/api/index_configuration.ts +++ b/packages/firestore/src/api/index_configuration.ts @@ -15,9 +15,8 @@ * limitations under the License. */ -import { getLocalStore } from '../core/firestore_client'; +import { firestoreClientSetIndexConfiguration } from '../core/firestore_client'; import { fieldPathFromDotSeparatedString } from '../lite-api/user_data_reader'; -import { localStoreConfigureFieldIndexes } from '../local/local_store_impl'; import { FieldIndex, IndexKind, @@ -97,10 +96,8 @@ export interface IndexConfiguration { * Query execution will automatically start using the index once the index * entries have been written. * - * Indexes are only supported with IndexedDb persistence. Invoke either - * `enableIndexedDbPersistence()` or `enableMultiTabIndexedDbPersistence()` - * before setting an index configuration. If IndexedDb is not enabled, any - * index configuration is ignored. + * Indexes are only supported with IndexedDb persistence. If IndexedDb is not + * enabled, any index configuration is ignored. * * @param firestore - The {@link Firestore} instance to configure indexes for. * @param configuration -The index definition. @@ -151,17 +148,17 @@ export function setIndexConfiguration( ): Promise { firestore = cast(firestore, Firestore); const client = ensureFirestoreConfigured(firestore); - - // PORTING NOTE: We don't return an error if the user has not enabled - // persistence since `enableIndexeddbPersistence()` can fail on the Web. - if (!client.offlineComponents?.indexBackfillerScheduler) { + if ( + !client._uninitializedComponentsProvider || + client._uninitializedComponentsProvider?._offlineKind === 'memory' + ) { + // PORTING NOTE: We don't return an error if the user has not enabled + // persistence since `enableIndexeddbPersistence()` can fail on the Web. logWarn('Cannot enable indexes when persistence is disabled'); return Promise.resolve(); } const parsedIndexes = parseIndexes(jsonOrConfiguration); - return getLocalStore(client).then(localStore => - localStoreConfigureFieldIndexes(localStore, parsedIndexes) - ); + return firestoreClientSetIndexConfiguration(client, parsedIndexes); } export function parseIndexes( diff --git a/packages/firestore/src/api/settings.ts b/packages/firestore/src/api/settings.ts index f6e92854495..0a9dc9d7ebe 100644 --- a/packages/firestore/src/api/settings.ts +++ b/packages/firestore/src/api/settings.ts @@ -17,6 +17,8 @@ import { FirestoreSettings as LiteSettings } from '../lite-api/settings'; +import { FirestoreLocalCache } from './cache_config'; + export { DEFAULT_HOST } from '../lite-api/settings'; /** @@ -39,6 +41,9 @@ export interface PersistenceSettings { */ export interface FirestoreSettings extends LiteSettings { /** + * NOTE: This field will be deprecated in a future major release. Use `cache` field + * instead to specify cache size, and other cache configurations. + * * An approximate cache size threshold for the on-disk data. If the cache * grows beyond this size, Firestore will start removing data that hasn't been * recently used. The size is not a guarantee that the cache will stay below @@ -50,6 +55,18 @@ export interface FirestoreSettings extends LiteSettings { */ cacheSizeBytes?: number; + /** + * Specifies the cache used by the SDK. Availabe options are `MemoryLocalCache` + * and `IndexedDbLocalCache`, each with different configuration options. + * + * When unspecified, `MemoryLocalCache` will be used by default. + * + * NOTE: setting this field and `cacheSizeBytes` at the same time will throw + * exception during SDK initialization. Instead, using the configuration in + * the `FirestoreLocalCache` object to specify the cache size. + */ + localCache?: FirestoreLocalCache; + /** * Forces the SDK’s underlying network transport (WebChannel) to use * long-polling. Each response from the backend will be closed immediately diff --git a/packages/firestore/src/core/firestore_client.ts b/packages/firestore/src/core/firestore_client.ts index ae96b64fa6e..2d69b322db7 100644 --- a/packages/firestore/src/core/firestore_client.ts +++ b/packages/firestore/src/core/firestore_client.ts @@ -25,6 +25,7 @@ import { import { User } from '../auth/user'; import { LocalStore } from '../local/local_store'; import { + localStoreConfigureFieldIndexes, localStoreExecuteQuery, localStoreGetNamedQuery, localStoreHandleUserChange, @@ -33,6 +34,7 @@ import { import { Persistence } from '../local/persistence'; import { Document } from '../model/document'; import { DocumentKey } from '../model/document_key'; +import { FieldIndex } from '../model/field_index'; import { Mutation } from '../model/mutation'; import { ObjectValue } from '../model/object_value'; import { toByteStreamReader } from '../platform/byte_stream_reader'; @@ -53,7 +55,7 @@ import { AsyncQueue, wrapInUserErrorIfRecoverable } from '../util/async_queue'; import { BundleReader } from '../util/bundle_reader'; import { newBundleReader } from '../util/bundle_reader_impl'; import { Code, FirestoreError } from '../util/error'; -import { logDebug } from '../util/log'; +import { logDebug, logWarn } from '../util/log'; import { AutoId } from '../util/misc'; import { Deferred } from '../util/promise'; @@ -94,10 +96,15 @@ import { ViewSnapshot } from './view_snapshot'; const LOG_TAG = 'FirestoreClient'; export const MAX_CONCURRENT_LIMBO_RESOLUTIONS = 100; +/** DOMException error code constants. */ +const DOM_EXCEPTION_INVALID_STATE = 11; +const DOM_EXCEPTION_ABORTED = 20; +const DOM_EXCEPTION_QUOTA_EXCEEDED = 22; + /** - * FirestoreClient is a top-level class that constructs and owns all of the - * pieces of the client SDK architecture. It is responsible for creating the - * async queue that is shared by all of the other components in the system. + * FirestoreClient is a top-level class that constructs and owns all of the // + * pieces of the client SDK architecture. It is responsible for creating the // + * async queue that is shared by all of the other components in the system. // */ export class FirestoreClient { private user = User.UNAUTHENTICATED; @@ -108,9 +115,14 @@ export class FirestoreClient { appCheckToken: string, user: User ) => Promise = () => Promise.resolve(); + _uninitializedComponentsProvider?: { + _offline: OfflineComponentProvider; + _offlineKind: 'memory' | 'persistent'; + _online: OnlineComponentProvider; + }; - offlineComponents?: OfflineComponentProvider; - onlineComponents?: OnlineComponentProvider; + _offlineComponents?: OfflineComponentProvider; + _onlineComponents?: OnlineComponentProvider; constructor( private authCredentials: CredentialsProvider, @@ -160,8 +172,8 @@ export class FirestoreClient { } /** - * Checks that the client has not been terminated. Ensures that other methods on - * this class cannot be called after the client is terminated. + * Checks that the client has not been terminated. Ensures that other methods on // + * this class cannot be called after the client is terminated. // */ verifyNotTerminated(): void { if (this.asyncQueue.isShuttingDown) { @@ -177,11 +189,11 @@ export class FirestoreClient { const deferred = new Deferred(); this.asyncQueue.enqueueAndForgetEvenWhileRestricted(async () => { try { - if (this.onlineComponents) { - await this.onlineComponents.terminate(); + if (this._onlineComponents) { + await this._onlineComponents.terminate(); } - if (this.offlineComponents) { - await this.offlineComponents.terminate(); + if (this._offlineComponents) { + await this._offlineComponents.terminate(); } // The credentials provider must be terminated after shutting down the @@ -229,7 +241,7 @@ export async function setOfflineComponentProvider( client.terminate() ); - client.offlineComponents = offlineComponentProvider; + client._offlineComponents = offlineComponentProvider; } export async function setOnlineComponentProvider( @@ -254,32 +266,102 @@ export async function setOnlineComponentProvider( client.setAppCheckTokenChangeListener((_, user) => remoteStoreHandleCredentialChange(onlineComponentProvider.remoteStore, user) ); - client.onlineComponents = onlineComponentProvider; + client._onlineComponents = onlineComponentProvider; +} + +/** + * Decides whether the provided error allows us to gracefully disable + * persistence (as opposed to crashing the client). + */ +export function canFallbackFromIndexedDbError( + error: FirestoreError | DOMException +): boolean { + if (error.name === 'FirebaseError') { + return ( + error.code === Code.FAILED_PRECONDITION || + error.code === Code.UNIMPLEMENTED + ); + } else if ( + typeof DOMException !== 'undefined' && + error instanceof DOMException + ) { + // There are a few known circumstances where we can open IndexedDb but + // trying to read/write will fail (e.g. quota exceeded). For + // well-understood cases, we attempt to detect these and then gracefully + // fall back to memory persistence. + // NOTE: Rather than continue to add to this list, we could decide to + // always fall back, with the risk that we might accidentally hide errors + // representing actual SDK bugs. + return ( + // When the browser is out of quota we could get either quota exceeded + // or an aborted error depending on whether the error happened during + // schema migration. + error.code === DOM_EXCEPTION_QUOTA_EXCEEDED || + error.code === DOM_EXCEPTION_ABORTED || + // Firefox Private Browsing mode disables IndexedDb and returns + // INVALID_STATE for any usage. + error.code === DOM_EXCEPTION_INVALID_STATE + ); + } + + return true; } async function ensureOfflineComponents( client: FirestoreClient ): Promise { - if (!client.offlineComponents) { - logDebug(LOG_TAG, 'Using default OfflineComponentProvider'); - await setOfflineComponentProvider( - client, - new MemoryOfflineComponentProvider() - ); + if (!client._offlineComponents) { + if (client._uninitializedComponentsProvider) { + logDebug(LOG_TAG, 'Using user provided OfflineComponentProvider'); + try { + await setOfflineComponentProvider( + client, + client._uninitializedComponentsProvider._offline + ); + } catch (e) { + const error = e as FirestoreError | DOMException; + if (!canFallbackFromIndexedDbError(error)) { + throw error; + } + logWarn( + 'Error using user provided cache. Falling back to ' + + 'memory cache: ' + + error + ); + await setOfflineComponentProvider( + client, + new MemoryOfflineComponentProvider() + ); + } + } else { + logDebug(LOG_TAG, 'Using default OfflineComponentProvider'); + await setOfflineComponentProvider( + client, + new MemoryOfflineComponentProvider() + ); + } } - return client.offlineComponents!; + return client._offlineComponents!; } async function ensureOnlineComponents( client: FirestoreClient ): Promise { - if (!client.onlineComponents) { - logDebug(LOG_TAG, 'Using default OnlineComponentProvider'); - await setOnlineComponentProvider(client, new OnlineComponentProvider()); + if (!client._onlineComponents) { + if (client._uninitializedComponentsProvider) { + logDebug(LOG_TAG, 'Using user provided OnlineComponentProvider'); + await setOnlineComponentProvider( + client, + client._uninitializedComponentsProvider._online + ); + } else { + logDebug(LOG_TAG, 'Using default OnlineComponentProvider'); + await setOnlineComponentProvider(client, new OnlineComponentProvider()); + } } - return client.onlineComponents!; + return client._onlineComponents!; } function getPersistence(client: FirestoreClient): Promise { @@ -744,3 +826,15 @@ function createBundleReader( } return newBundleReader(toByteStreamReader(content), serializer); } + +export function firestoreClientSetIndexConfiguration( + client: FirestoreClient, + indexes: FieldIndex[] +): Promise { + return client.asyncQueue.enqueue(async () => { + return localStoreConfigureFieldIndexes( + await getLocalStore(client), + indexes + ); + }); +} diff --git a/packages/firestore/src/lite-api/settings.ts b/packages/firestore/src/lite-api/settings.ts index 3743cc344d0..5f395846720 100644 --- a/packages/firestore/src/lite-api/settings.ts +++ b/packages/firestore/src/lite-api/settings.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { FirestoreLocalCache } from '../api/cache_config'; import { CredentialsSettings } from '../api/credentials'; import { LRU_COLLECTION_DISABLED, @@ -60,6 +61,8 @@ export interface PrivateSettings extends FirestoreSettings { experimentalAutoDetectLongPolling?: boolean; // Used in firestore@exp useFetchStreams?: boolean; + + localCache?: FirestoreLocalCache; } /** @@ -83,6 +86,7 @@ export class FirestoreSettingsImpl { readonly ignoreUndefinedProperties: boolean; readonly useFetchStreams: boolean; + readonly cache?: FirestoreLocalCache; // Can be a google-auth-library or gapi client. // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -105,6 +109,7 @@ export class FirestoreSettingsImpl { this.credentials = settings.credentials; this.ignoreUndefinedProperties = !!settings.ignoreUndefinedProperties; + this.cache = settings.localCache; if (settings.cacheSizeBytes === undefined) { this.cacheSizeBytes = LRU_DEFAULT_CACHE_SIZE_BYTES; diff --git a/packages/firestore/src/local/local_store_impl.ts b/packages/firestore/src/local/local_store_impl.ts index ae1760f5930..447a982e7ea 100644 --- a/packages/firestore/src/local/local_store_impl.ts +++ b/packages/firestore/src/local/local_store_impl.ts @@ -875,6 +875,10 @@ export async function localStoreNotifyLocalViewChanges( ); localStoreImpl.targetDataByTarget = localStoreImpl.targetDataByTarget.insert(targetId, updatedTargetData); + + // TODO(b/272564316): Apply the optimization done on other platforms. + // This is a problem for web because saving the updated targetData from + // non-primary client conflicts with what primary client saved. } } } diff --git a/packages/firestore/src/platform/browser/base64.ts b/packages/firestore/src/platform/browser/base64.ts index 4cbbfe6ced9..26235a36a19 100644 --- a/packages/firestore/src/platform/browser/base64.ts +++ b/packages/firestore/src/platform/browser/base64.ts @@ -22,7 +22,10 @@ export function decodeBase64(encoded: string): string { try { return atob(encoded); } catch (e) { - if (e instanceof DOMException) { + // Check that `DOMException` is defined before using it to avoid + // "ReferenceError: Property 'DOMException' doesn't exist" in react-native. + // (https://github.com/firebase/firebase-js-sdk/issues/7115) + if (typeof DOMException !== 'undefined' && e instanceof DOMException) { throw new Base64DecodeError('Invalid base64 string: ' + e); } else { throw e; diff --git a/packages/firestore/test/integration/api/database.test.ts b/packages/firestore/test/integration/api/database.test.ts index 5f3e2dc6c61..174048020e6 100644 --- a/packages/firestore/test/integration/api/database.test.ts +++ b/packages/firestore/test/integration/api/database.test.ts @@ -1214,6 +1214,7 @@ apiDescribe('Database', (persistence: boolean) => { 'cannot clear persistence if the client has been initialized', async () => { await withTestDoc(persistence, async (docRef, firestore) => { + await setDoc(docRef, {}); const expectedError = 'Persistence can only be cleared before a Firestore instance is ' + 'initialized or after it is terminated.'; diff --git a/packages/firestore/test/integration/api/provider.test.ts b/packages/firestore/test/integration/api/provider.test.ts index ffcd0e7f350..04a148bf987 100644 --- a/packages/firestore/test/integration/api/provider.test.ts +++ b/packages/firestore/test/integration/api/provider.test.ts @@ -25,7 +25,11 @@ import { initializeFirestore, Firestore, terminate, - getDoc + getDoc, + enableIndexedDbPersistence, + setDoc, + memoryLocalCache, + getDocFromCache } from '../util/firebase_export'; import { DEFAULT_SETTINGS } from '../util/settings'; @@ -120,6 +124,37 @@ describe('Firestore Provider', () => { expect(fs1).to.be.equal(fs2); }); + it('can still use enableIndexedDbPersistence()', async () => { + const app = initializeApp( + { apiKey: 'fake-api-key', projectId: 'test-project' }, + 'test-use-enablePersistence' + ); + const db = initializeFirestore(app, DEFAULT_SETTINGS); + // eslint-disable-next-line @typescript-eslint/no-floating-promises + expect(enableIndexedDbPersistence(db)).to.be.rejected; + + // SDK still functions. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + setDoc(doc(db, 'coll/doc'), { field: 'foo' }); + expect((await getDocFromCache(doc(db, 'coll/doc'))).data()).to.deep.equal({ + field: 'foo' + }); + }); + + it('cannot mix enableIndexedDbPersistence() and settings.cache', async () => { + const app = initializeApp( + { apiKey: 'fake-api-key', projectId: 'test-project' }, + 'test-cannot-mix' + ); + const db = initializeFirestore(app, { + ...DEFAULT_SETTINGS, + localCache: memoryLocalCache() + }); + expect(() => enableIndexedDbPersistence(db)).to.throw( + 'SDK cache is already specified.' + ); + }); + it('cannot use once terminated', () => { const app = initializeApp( { apiKey: 'fake-api-key', projectId: 'test-project' }, diff --git a/packages/firestore/test/integration/api/query.test.ts b/packages/firestore/test/integration/api/query.test.ts index bec924e3fb9..cd401b28d68 100644 --- a/packages/firestore/test/integration/api/query.test.ts +++ b/packages/firestore/test/integration/api/query.test.ts @@ -47,6 +47,7 @@ import { Query, query, QuerySnapshot, + runTransaction, setDoc, startAfter, startAt, @@ -2059,6 +2060,62 @@ apiDescribe('Queries', (persistence: boolean) => { }); }); }); + + it('resuming a query should use existence filter to detect deletes', async () => { + // Prepare the names and contents of the 100 documents to create. + const testDocs: { [key: string]: object } = {}; + for (let i = 0; i < 100; i++) { + testDocs['doc' + (1000 + i)] = { key: 42 }; + } + + return withTestCollection(persistence, testDocs, async (coll, db) => { + // Run a query to populate the local cache with the 100 documents and a + // resume token. + const snapshot1 = await getDocs(coll); + expect(snapshot1.size, 'snapshot1.size').to.equal(100); + const createdDocuments = snapshot1.docs.map(snapshot => snapshot.ref); + + // Delete 50 of the 100 documents. Do this in a transaction, rather than + // deleteDoc(), to avoid affecting the local cache. + const deletedDocumentIds = new Set(); + await runTransaction(db, async txn => { + for (let i = 0; i < createdDocuments.length; i += 2) { + const documentToDelete = createdDocuments[i]; + txn.delete(documentToDelete); + deletedDocumentIds.add(documentToDelete.id); + } + }); + + // Wait for 10 seconds, during which Watch will stop tracking the query + // and will send an existence filter rather than "delete" events when the + // query is resumed. + await new Promise(resolve => setTimeout(resolve, 10000)); + + // Resume the query and save the resulting snapshot for verification. + const snapshot2 = await getDocs(coll); + + // Verify that the snapshot from the resumed query contains the expected + // documents; that is, that it contains the 50 documents that were _not_ + // deleted. + // TODO(b/270731363): Remove the "if" condition below once the + // Firestore Emulator is fixed to send an existence filter. At the time of + // writing, the Firestore emulator fails to send an existence filter, + // resulting in the client including the deleted documents in the snapshot + // of the resumed query. + if (!(USE_EMULATOR && snapshot2.size === 100)) { + const actualDocumentIds = snapshot2.docs + .map(documentSnapshot => documentSnapshot.ref.id) + .sort(); + const expectedDocumentIds = createdDocuments + .filter(documentRef => !deletedDocumentIds.has(documentRef.id)) + .map(documentRef => documentRef.id) + .sort(); + expect(actualDocumentIds, 'snapshot2.docs').to.deep.equal( + expectedDocumentIds + ); + } + }); + }).timeout('90s'); }); function verifyDocumentChange( diff --git a/packages/firestore/test/integration/api/validation.test.ts b/packages/firestore/test/integration/api/validation.test.ts index 8ec14d1ae3e..f422eb4ad07 100644 --- a/packages/firestore/test/integration/api/validation.test.ts +++ b/packages/firestore/test/integration/api/validation.test.ts @@ -240,9 +240,7 @@ apiDescribe('Validation:', (persistence: boolean) => { doc(db, 'foo/bar'); } expect(() => enableIndexedDbPersistence(db)).to.throw( - 'Firestore has already been started and persistence can no ' + - 'longer be enabled. You can only enable persistence before ' + - 'calling any other methods on a Firestore object.' + 'SDK cache is already specified.' ); } ); diff --git a/packages/firestore/test/integration/browser/indexeddb.test.ts b/packages/firestore/test/integration/browser/indexeddb.test.ts index a63d5178118..b00fd7fbb83 100644 --- a/packages/firestore/test/integration/browser/indexeddb.test.ts +++ b/packages/firestore/test/integration/browser/indexeddb.test.ts @@ -26,7 +26,7 @@ import { } from '../util/firebase_export'; import { isPersistenceAvailable, withTestDb } from '../util/helpers'; -describe('where persistence is unsupported, enablePersistence', () => { +describe('where indexeddb is not available: ', () => { // Only test on platforms where persistence is *not* available (e.g. Edge, // Node.JS). if (isPersistenceAvailable()) { @@ -61,4 +61,14 @@ describe('where persistence is unsupported, enablePersistence', () => { ); }); }); + + it('fails back to memory cache with initializeFirestore too', () => { + // withTestDb will fail the test if persistence is requested but it fails + // so we'll enable persistence here instead. + return withTestDb(/* persistence= */ true, db => { + // Do the set immediately without waiting on the promise. + const testDoc = doc(collection(db, 'test-collection')); + return setDoc(testDoc, { foo: 'bar' }); + }); + }); }); diff --git a/packages/firestore/test/integration/util/helpers.ts b/packages/firestore/test/integration/util/helpers.ts index 79dbacaafa0..5cd73532d5c 100644 --- a/packages/firestore/test/integration/util/helpers.ts +++ b/packages/firestore/test/integration/util/helpers.ts @@ -23,8 +23,8 @@ import { DocumentReference, Firestore, terminate, + persistentLocalCache, clearIndexedDbPersistence, - enableIndexedDbPersistence, CollectionReference, DocumentData, QuerySnapshot, @@ -32,7 +32,9 @@ import { PrivateSettings, SnapshotListenOptions, newTestFirestore, - newTestApp + newTestApp, + writeBatch, + WriteBatch } from './firebase_export'; import { ALT_PROJECT_ID, @@ -184,10 +186,11 @@ export async function withTestDbsSettings( const dbs: Firestore[] = []; for (let i = 0; i < numDbs; i++) { - const db = newTestFirestore(newTestApp(projectId), settings); + const newSettings = { ...settings }; if (persistence) { - await enableIndexedDbPersistence(db); + newSettings.localCache = persistentLocalCache(); } + const db = newTestFirestore(newTestApp(projectId), newSettings); dbs.push(db); } @@ -218,10 +221,11 @@ export async function withNamedTestDbsOrSkipUnlessUsingEmulator( const app = newTestApp(DEFAULT_PROJECT_ID); const dbs: Firestore[] = []; for (const dbName of dbNames) { - const db = newTestFirestore(app, DEFAULT_SETTINGS, dbName); + const newSettings = { ...DEFAULT_SETTINGS }; if (persistence) { - await enableIndexedDbPersistence(db); + newSettings.localCache = persistentLocalCache(); } + const db = newTestFirestore(app, newSettings, dbName); dbs.push(db); } @@ -315,11 +319,34 @@ export function withTestCollectionSettings( const collectionId = 'test-collection-' + doc(collection(testDb, 'x')).id; const testCollection = collection(testDb, collectionId); const setupCollection = collection(setupDb, collectionId); - const sets: Array> = []; - Object.keys(docs).forEach(key => { - sets.push(setDoc(doc(setupCollection, key), docs[key])); - }); - return Promise.all(sets).then(() => fn(testCollection, testDb)); + + const writeBatchCommits: Array> = []; + let writeBatch_: WriteBatch | null = null; + let writeBatchSize = 0; + + for (const key of Object.keys(docs)) { + if (writeBatch_ === null) { + writeBatch_ = writeBatch(setupDb); + } + + writeBatch_.set(doc(setupCollection, key), docs[key]); + writeBatchSize++; + + // Write batches are capped at 500 writes. Use 400 just to be safe. + if (writeBatchSize === 400) { + writeBatchCommits.push(writeBatch_.commit()); + writeBatch_ = null; + writeBatchSize = 0; + } + } + + if (writeBatch_ !== null) { + writeBatchCommits.push(writeBatch_.commit()); + } + + return Promise.all(writeBatchCommits).then(() => + fn(testCollection, testDb) + ); } ); } diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index f10fa13c1d7..530ca40b5e4 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -15,6 +15,7 @@ * limitations under the License. */ +import { isIndexedDBAvailable } from '@firebase/util'; import { expect } from 'chai'; import { serverTimestamp, Timestamp } from '../../../src'; @@ -188,6 +189,10 @@ class AsyncLocalStoreTester { } describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { + if (!isIndexedDBAvailable()) { + return; + } + let persistence: Persistence; let test: AsyncLocalStoreTester; diff --git a/packages/firestore/test/unit/specs/bundle_spec.test.ts b/packages/firestore/test/unit/specs/bundle_spec.test.ts index 3efa1be4d63..51fb3c3970a 100644 --- a/packages/firestore/test/unit/specs/bundle_spec.test.ts +++ b/packages/firestore/test/unit/specs/bundle_spec.test.ts @@ -85,7 +85,7 @@ function bundleWithDocumentAndQuery( ); } -describeSpec('Bundles:', ['no-ios'], () => { +describeSpec('Bundles:', [], () => { specTest('Newer docs from bundles should overwrite cache', [], () => { const query1 = query('collection'); const docA = doc('collection/a', 1000, { value: 'a' }); diff --git a/packages/functions-compat/package.json b/packages/functions-compat/package.json index c54b1cc46fa..6bac274d7c6 100644 --- a/packages/functions-compat/package.json +++ b/packages/functions-compat/package.json @@ -31,7 +31,7 @@ "@firebase/app-compat": "0.x" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "rollup": "2.79.1", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", diff --git a/packages/functions/package.json b/packages/functions/package.json index 02a40f1df0f..7493b77d3b5 100644 --- a/packages/functions/package.json +++ b/packages/functions/package.json @@ -50,7 +50,7 @@ "@firebase/app": "0.x" }, "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", diff --git a/packages/installations-compat/package.json b/packages/installations-compat/package.json index 7ee2f6cc7bd..774c21d5e8c 100644 --- a/packages/installations-compat/package.json +++ b/packages/installations-compat/package.json @@ -45,7 +45,7 @@ "url": "https://github.com/firebase/firebase-js-sdk/issues" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "rollup": "2.79.1", "@rollup/plugin-commonjs": "21.1.0", "@rollup/plugin-json": "4.1.0", diff --git a/packages/installations/package.json b/packages/installations/package.json index e7c180d2c2b..98b8fced7a5 100644 --- a/packages/installations/package.json +++ b/packages/installations/package.json @@ -50,7 +50,7 @@ "url": "https://github.com/firebase/firebase-js-sdk/issues" }, "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "@rollup/plugin-commonjs": "21.1.0", "@rollup/plugin-json": "4.1.0", diff --git a/packages/messaging-compat/package.json b/packages/messaging-compat/package.json index 509ca1fd0d2..ed4e324d958 100644 --- a/packages/messaging-compat/package.json +++ b/packages/messaging-compat/package.json @@ -45,7 +45,7 @@ "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", + "@firebase/app-compat": "0.2.5", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", "ts-essentials": "9.3.0", diff --git a/packages/messaging/package.json b/packages/messaging/package.json index f552c2d14dd..af77e9f645f 100644 --- a/packages/messaging/package.json +++ b/packages/messaging/package.json @@ -61,7 +61,7 @@ "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "rollup-plugin-typescript2": "0.31.2", "@rollup/plugin-json": "4.1.0", diff --git a/packages/performance-compat/package.json b/packages/performance-compat/package.json index 842ce2de1ed..f5b67f4063a 100644 --- a/packages/performance-compat/package.json +++ b/packages/performance-compat/package.json @@ -52,7 +52,7 @@ "rollup-plugin-replace": "2.2.0", "rollup-plugin-typescript2": "0.31.2", "typescript": "4.7.4", - "@firebase/app-compat": "0.2.4" + "@firebase/app-compat": "0.2.5" }, "repository": { "directory": "packages/performance-compat", diff --git a/packages/performance/package.json b/packages/performance/package.json index 3d7317015ca..d2445641ef6 100644 --- a/packages/performance/package.json +++ b/packages/performance/package.json @@ -47,7 +47,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", diff --git a/packages/remote-config-compat/package.json b/packages/remote-config-compat/package.json index 7838c7aff0b..5d2d91be6e6 100644 --- a/packages/remote-config-compat/package.json +++ b/packages/remote-config-compat/package.json @@ -51,7 +51,7 @@ "rollup-plugin-replace": "2.2.0", "rollup-plugin-typescript2": "0.31.2", "typescript": "4.7.4", - "@firebase/app-compat": "0.2.4" + "@firebase/app-compat": "0.2.5" }, "repository": { "directory": "packages/remote-config-compat", diff --git a/packages/remote-config/package.json b/packages/remote-config/package.json index 960e7b4542d..b5135c502e0 100644 --- a/packages/remote-config/package.json +++ b/packages/remote-config/package.json @@ -49,7 +49,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "rollup-plugin-typescript2": "0.31.2", "typescript": "4.7.4" diff --git a/packages/storage-compat/package.json b/packages/storage-compat/package.json index 9bcb93e84a8..03117fc77bb 100644 --- a/packages/storage-compat/package.json +++ b/packages/storage-compat/package.json @@ -45,8 +45,8 @@ "tslib": "^2.1.0" }, "devDependencies": { - "@firebase/app-compat": "0.2.4", - "@firebase/auth-compat": "0.3.4", + "@firebase/app-compat": "0.2.5", + "@firebase/auth-compat": "0.3.5", "rollup": "2.79.1", "@rollup/plugin-json": "4.1.0", "rollup-plugin-typescript2": "0.31.2", diff --git a/packages/storage/package.json b/packages/storage/package.json index efb3ca2c9d9..23b5421642e 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -55,8 +55,8 @@ "@firebase/app": "0.x" }, "devDependencies": { - "@firebase/app": "0.9.4", - "@firebase/auth": "0.21.4", + "@firebase/app": "0.9.5", + "@firebase/auth": "0.21.5", "rollup": "2.79.1", "@rollup/plugin-alias": "3.1.9", "@rollup/plugin-json": "4.1.0", diff --git a/packages/template/package.json b/packages/template/package.json index 5300fa69fa1..d42012e56bc 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -49,7 +49,7 @@ }, "license": "Apache-2.0", "devDependencies": { - "@firebase/app": "0.9.4", + "@firebase/app": "0.9.5", "rollup": "2.79.1", "rollup-plugin-typescript2": "0.31.2", "typescript": "4.7.4" diff --git a/repo-scripts/size-analysis/package.json b/repo-scripts/size-analysis/package.json index c5b7c9de79e..6985d6644c5 100644 --- a/repo-scripts/size-analysis/package.json +++ b/repo-scripts/size-analysis/package.json @@ -42,7 +42,7 @@ "license": "Apache-2.0", "devDependencies": { "@firebase/logger": "0.4.0", - "@firebase/app": "0.9.4" + "@firebase/app": "0.9.5" }, "repository": { "directory": "repo-scripts/size-analysis", diff --git a/yarn.lock b/yarn.lock index c6f341a4ce7..b55df34dc8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3693,6 +3693,11 @@ resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== +"@types/trusted-types@2.0.3": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" + integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== + "@types/vinyl@^2.0.4": version "2.0.6" resolved "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.6.tgz#b2d134603557a7c3d2b5d3dc23863ea2b5eb29b0" @@ -15618,10 +15623,10 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz#366a4684d175b9cab2081e3681fda3747b6c51d7" integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q== -simple-git@3.15.1: - version "3.15.1" - resolved "https://registry.npmjs.org/simple-git/-/simple-git-3.15.1.tgz#57f595682cb0c2475d5056da078a05c8715a25ef" - integrity sha512-73MVa5984t/JP4JcQt0oZlKGr42ROYWC3BcUZfuHtT3IHKPspIvL0cZBnvPXF7LL3S/qVeVHVdYYmJ3LOTw4Rg== +simple-git@3.16.0: + version "3.16.0" + resolved "https://registry.npmjs.org/simple-git/-/simple-git-3.16.0.tgz#421773e24680f5716999cc4a1d60127b4b6a9dec" + integrity sha512-zuWYsOLEhbJRWVxpjdiXl6eyAyGo/KzVW+KFhhw9MqEEJttcq+32jTWSGyxTdf9e/YCohxRE+9xpWFj9FdiJNw== dependencies: "@kwsites/file-exists" "^1.1.1" "@kwsites/promise-deferred" "^1.1.1"