0x1998 - MANAGER
Düzenlenen Dosya: index.rn.esm.js.map
{"version":3,"file":"index.rn.esm.js","sources":["../../src/util/promise.ts","../../src/core/aggregate.ts","../../src/remote/backoff.ts","../../src/lite-api/aggregate_types.ts","../../src/lite-api/aggregate.ts","../../src/lite-api/write_batch.ts","../../src/core/transaction.ts","../../src/core/transaction_options.ts","../../src/core/transaction_runner.ts","../../src/platform/browser/dom.ts","../../src/util/async_queue.ts","../../src/util/async_queue_impl.ts","../../src/local/simple_db.ts","../../src/lite-api/transaction.ts","../../lite/register.ts","../../lite/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport interface Resolver<R> {\n (value: R | Promise<R>): void;\n}\n\nexport interface Rejecter {\n (reason?: Error): void;\n}\n\nexport class Deferred<R = void> {\n promise: Promise<R>;\n // Assigned synchronously in constructor by Promise constructor callback.\n resolve!: Resolver<R>;\n reject!: Rejecter;\n\n constructor() {\n this.promise = new Promise((resolve: Resolver<R>, reject: Rejecter) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n\n/**\n * Takes an array of values and a function from a value to a Promise. The function is run on each\n * value sequentially, waiting for the previous promise to resolve before starting the next one.\n * The returned promise resolves once the function has been run on all values.\n */\nexport function sequence<T>(\n values: T[],\n fn: (value: T) => Promise<void>\n): Promise<void> {\n let p = Promise.resolve();\n for (const value of values) {\n p = p.then(() => fn(value));\n }\n return p;\n}\n","/**\n * @license\n * Copyright 2023 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FieldPath } from '../model/path';\n\n/**\n * Union type representing the aggregate type to be performed.\n */\nexport type AggregateType = 'count' | 'avg' | 'sum';\n\n/**\n * Represents an Aggregate to be performed over a query result set.\n */\nexport interface Aggregate {\n readonly fieldPath?: FieldPath;\n readonly alias: string;\n readonly aggregateType: AggregateType;\n}\n\n/**\n * Concrete implementation of the Aggregate type.\n */\nexport class AggregateImpl implements Aggregate {\n constructor(\n readonly alias: string,\n readonly aggregateType: AggregateType,\n readonly fieldPath?: FieldPath\n ) {}\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AsyncQueue, DelayedOperation, TimerId } from '../util/async_queue';\nimport { logDebug } from '../util/log';\n\nconst LOG_TAG = 'ExponentialBackoff';\n\n/**\n * Initial backoff time in milliseconds after an error.\n * Set to 1s according to https://cloud.google.com/apis/design/errors.\n */\nconst DEFAULT_BACKOFF_INITIAL_DELAY_MS = 1000;\n\nconst DEFAULT_BACKOFF_FACTOR = 1.5;\n\n/** Maximum backoff time in milliseconds */\nconst DEFAULT_BACKOFF_MAX_DELAY_MS = 60 * 1000;\n\n/**\n * A helper for running delayed tasks following an exponential backoff curve\n * between attempts.\n *\n * Each delay is made up of a \"base\" delay which follows the exponential\n * backoff curve, and a +/- 50% \"jitter\" that is calculated and added to the\n * base delay. This prevents clients from accidentally synchronizing their\n * delays causing spikes of load to the backend.\n */\nexport class ExponentialBackoff {\n private currentBaseMs: number = 0;\n private timerPromise: DelayedOperation<void> | null = null;\n /** The last backoff attempt, as epoch milliseconds. */\n private lastAttemptTime = Date.now();\n\n constructor(\n /**\n * The AsyncQueue to run backoff operations on.\n */\n private readonly queue: AsyncQueue,\n /**\n * The ID to use when scheduling backoff operations on the AsyncQueue.\n */\n private readonly timerId: TimerId,\n /**\n * The initial delay (used as the base delay on the first retry attempt).\n * Note that jitter will still be applied, so the actual delay could be as\n * little as 0.5*initialDelayMs.\n */\n private readonly initialDelayMs: number = DEFAULT_BACKOFF_INITIAL_DELAY_MS,\n /**\n * The multiplier to use to determine the extended base delay after each\n * attempt.\n */\n private readonly backoffFactor: number = DEFAULT_BACKOFF_FACTOR,\n /**\n * The maximum base delay after which no further backoff is performed.\n * Note that jitter will still be applied, so the actual delay could be as\n * much as 1.5*maxDelayMs.\n */\n private readonly maxDelayMs: number = DEFAULT_BACKOFF_MAX_DELAY_MS\n ) {\n this.reset();\n }\n\n /**\n * Resets the backoff delay.\n *\n * The very next backoffAndWait() will have no delay. If it is called again\n * (i.e. due to an error), initialDelayMs (plus jitter) will be used, and\n * subsequent ones will increase according to the backoffFactor.\n */\n reset(): void {\n this.currentBaseMs = 0;\n }\n\n /**\n * Resets the backoff delay to the maximum delay (e.g. for use after a\n * RESOURCE_EXHAUSTED error).\n */\n resetToMax(): void {\n this.currentBaseMs = this.maxDelayMs;\n }\n\n /**\n * Returns a promise that resolves after currentDelayMs, and increases the\n * delay for any subsequent attempts. If there was a pending backoff operation\n * already, it will be canceled.\n */\n backoffAndRun(op: () => Promise<void>): void {\n // Cancel any pending backoff operation.\n this.cancel();\n\n // First schedule using the current base (which may be 0 and should be\n // honored as such).\n const desiredDelayWithJitterMs = Math.floor(\n this.currentBaseMs + this.jitterDelayMs()\n );\n\n // Guard against lastAttemptTime being in the future due to a clock change.\n const delaySoFarMs = Math.max(0, Date.now() - this.lastAttemptTime);\n\n // Guard against the backoff delay already being past.\n const remainingDelayMs = Math.max(\n 0,\n desiredDelayWithJitterMs - delaySoFarMs\n );\n\n if (remainingDelayMs > 0) {\n logDebug(\n LOG_TAG,\n `Backing off for ${remainingDelayMs} ms ` +\n `(base delay: ${this.currentBaseMs} ms, ` +\n `delay with jitter: ${desiredDelayWithJitterMs} ms, ` +\n `last attempt: ${delaySoFarMs} ms ago)`\n );\n }\n\n this.timerPromise = this.queue.enqueueAfterDelay(\n this.timerId,\n remainingDelayMs,\n () => {\n this.lastAttemptTime = Date.now();\n return op();\n }\n );\n\n // Apply backoff factor to determine next delay and ensure it is within\n // bounds.\n this.currentBaseMs *= this.backoffFactor;\n if (this.currentBaseMs < this.initialDelayMs) {\n this.currentBaseMs = this.initialDelayMs;\n }\n if (this.currentBaseMs > this.maxDelayMs) {\n this.currentBaseMs = this.maxDelayMs;\n }\n }\n\n skipBackoff(): void {\n if (this.timerPromise !== null) {\n this.timerPromise.skipDelay();\n this.timerPromise = null;\n }\n }\n\n cancel(): void {\n if (this.timerPromise !== null) {\n this.timerPromise.cancel();\n this.timerPromise = null;\n }\n }\n\n /** Returns a random value in the range [-currentBaseMs/2, currentBaseMs/2] */\n private jitterDelayMs(): number {\n return (Math.random() - 0.5) * this.currentBaseMs;\n }\n}\n","/**\n * @license\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { AggregateType } from '../core/aggregate';\nimport { ObjectValue } from '../model/object_value';\nimport { FieldPath as InternalFieldPath } from '../model/path';\nimport {\n ApiClientObjectMap,\n firestoreV1ApiClientInterfaces,\n Value\n} from '../protos/firestore_proto_api';\n\nimport { average, count, sum } from './aggregate';\nimport { DocumentData, Query } from './reference';\nimport { AbstractUserDataWriter } from './user_data_writer';\n\nexport { AggregateType };\n\n/**\n * Represents an aggregation that can be performed by Firestore.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport class AggregateField<T> {\n /** A type string to uniquely identify instances of this class. */\n readonly type = 'AggregateField';\n\n /** Indicates the aggregation operation of this AggregateField. */\n readonly aggregateType: AggregateType;\n\n /**\n * Create a new AggregateField<T>\n * @param aggregateType - Specifies the type of aggregation operation to perform.\n * @param _internalFieldPath - Optionally specifies the field that is aggregated.\n * @internal\n */\n constructor(\n aggregateType: AggregateType = 'count',\n readonly _internalFieldPath?: InternalFieldPath\n ) {\n this.aggregateType = aggregateType;\n }\n}\n\n/**\n * The union of all `AggregateField` types that are supported by Firestore.\n */\nexport type AggregateFieldType =\n | ReturnType<typeof sum>\n | ReturnType<typeof average>\n | ReturnType<typeof count>;\n\n/**\n * Specifies a set of aggregations and their aliases.\n */\nexport interface AggregateSpec {\n [field: string]: AggregateFieldType;\n}\n\n/**\n * A type whose keys are taken from an `AggregateSpec`, and whose values are the\n * result of the aggregation performed by the corresponding `AggregateField`\n * from the input `AggregateSpec`.\n */\nexport type AggregateSpecData<T extends AggregateSpec> = {\n [P in keyof T]: T[P] extends AggregateField<infer U> ? U : never;\n};\n\n/**\n * The results of executing an aggregation query.\n */\nexport class AggregateQuerySnapshot<\n AggregateSpecType extends AggregateSpec,\n AppModelType = DocumentData,\n DbModelType extends DocumentData = DocumentData\n> {\n /** A type string to uniquely identify instances of this class. */\n readonly type = 'AggregateQuerySnapshot';\n\n /**\n * The underlying query over which the aggregations recorded in this\n * `AggregateQuerySnapshot` were performed.\n */\n readonly query: Query<AppModelType, DbModelType>;\n\n /** @hideconstructor */\n constructor(\n query: Query<AppModelType, DbModelType>,\n private readonly _userDataWriter: AbstractUserDataWriter,\n private readonly _data: ApiClientObjectMap<Value>\n ) {\n this.query = query;\n }\n\n /**\n * Returns the results of the aggregations performed over the underlying\n * query.\n *\n * The keys of the returned object will be the same as those of the\n * `AggregateSpec` object specified to the aggregation method, and the values\n * will be the corresponding aggregation result.\n *\n * @returns The results of the aggregations performed over the underlying\n * query.\n */\n data(): AggregateSpecData<AggregateSpecType> {\n return this._userDataWriter.convertObjectMap(\n this._data\n ) as AggregateSpecData<AggregateSpecType>;\n }\n\n /**\n * @internal\n * @private\n *\n * Retrieves all fields in the snapshot as a proto value.\n *\n * @returns An `Object` containing all fields in the snapshot.\n */\n _fieldsProto(): { [key: string]: firestoreV1ApiClientInterfaces.Value } {\n // Wrap data in an ObjectValue to clone it.\n const dataClone = new ObjectValue({\n mapValue: { fields: this._data }\n }).clone();\n\n // Return the cloned value to prevent manipulation of the Snapshot's data\n return dataClone.value.mapValue.fields!;\n }\n}\n","/**\n * @license\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { deepEqual } from '@firebase/util';\n\nimport { AggregateImpl } from '../core/aggregate';\nimport { ApiClientObjectMap, Value } from '../protos/firestore_proto_api';\nimport { invokeRunAggregationQueryRpc } from '../remote/datastore';\nimport { cast } from '../util/input_validation';\nimport { mapToArray } from '../util/obj';\n\nimport {\n AggregateField,\n AggregateQuerySnapshot,\n AggregateSpec\n} from './aggregate_types';\nimport { getDatastore } from './components';\nimport { Firestore } from './database';\nimport { FieldPath } from './field_path';\nimport { DocumentData, Query, queryEqual } from './reference';\nimport { LiteUserDataWriter } from './reference_impl';\nimport { fieldPathFromArgument } from './user_data_reader';\n\n/**\n * Calculates the number of documents in the result set of the given query\n * without actually downloading the documents.\n *\n * Using this function to count the documents is efficient because only the\n * final count, not the documents' data, is downloaded. This function can\n * count the documents in cases where the result set is prohibitively large to\n * download entirely (thousands of documents).\n *\n * @param query - The query whose result set size is calculated.\n * @returns A Promise that will be resolved with the count; the count can be\n * retrieved from `snapshot.data().count`, where `snapshot` is the\n * `AggregateQuerySnapshot` to which the returned Promise resolves.\n */\nexport function getCount<AppModelType, DbModelType extends DocumentData>(\n query: Query<AppModelType, DbModelType>\n): Promise<\n AggregateQuerySnapshot<\n { count: AggregateField<number> },\n AppModelType,\n DbModelType\n >\n> {\n const countQuerySpec: { count: AggregateField<number> } = {\n count: count()\n };\n\n return getAggregate(query, countQuerySpec);\n}\n\n/**\n * Calculates the specified aggregations over the documents in the result\n * set of the given query without actually downloading the documents.\n *\n * Using this function to perform aggregations is efficient because only the\n * final aggregation values, not the documents' data, are downloaded. This\n * function can perform aggregations of the documents in cases where the result\n * set is prohibitively large to download entirely (thousands of documents).\n *\n * @param query - The query whose result set is aggregated over.\n * @param aggregateSpec - An `AggregateSpec` object that specifies the aggregates\n * to perform over the result set. The AggregateSpec specifies aliases for each\n * aggregate, which can be used to retrieve the aggregate result.\n * @example\n * ```typescript\n * const aggregateSnapshot = await getAggregate(query, {\n * countOfDocs: count(),\n * totalHours: sum('hours'),\n * averageScore: average('score')\n * });\n *\n * const countOfDocs: number = aggregateSnapshot.data().countOfDocs;\n * const totalHours: number = aggregateSnapshot.data().totalHours;\n * const averageScore: number | null = aggregateSnapshot.data().averageScore;\n * ```\n */\nexport function getAggregate<\n AggregateSpecType extends AggregateSpec,\n AppModelType,\n DbModelType extends DocumentData\n>(\n query: Query<AppModelType, DbModelType>,\n aggregateSpec: AggregateSpecType\n): Promise<\n AggregateQuerySnapshot<AggregateSpecType, AppModelType, DbModelType>\n> {\n const firestore = cast(query.firestore, Firestore);\n const datastore = getDatastore(firestore);\n\n const internalAggregates = mapToArray(aggregateSpec, (aggregate, alias) => {\n return new AggregateImpl(\n alias,\n aggregate.aggregateType,\n aggregate._internalFieldPath\n );\n });\n\n // Run the aggregation and convert the results\n return invokeRunAggregationQueryRpc(\n datastore,\n query._query,\n internalAggregates\n ).then(aggregateResult =>\n convertToAggregateQuerySnapshot(firestore, query, aggregateResult)\n );\n}\n\nfunction convertToAggregateQuerySnapshot<\n AggregateSpecType extends AggregateSpec,\n AppModelType,\n DbModelType extends DocumentData\n>(\n firestore: Firestore,\n query: Query<AppModelType, DbModelType>,\n aggregateResult: ApiClientObjectMap<Value>\n): AggregateQuerySnapshot<AggregateSpecType, AppModelType, DbModelType> {\n const userDataWriter = new LiteUserDataWriter(firestore);\n const querySnapshot = new AggregateQuerySnapshot<\n AggregateSpecType,\n AppModelType,\n DbModelType\n >(query, userDataWriter, aggregateResult);\n return querySnapshot;\n}\n\n/**\n * Create an AggregateField object that can be used to compute the sum of\n * a specified field over a range of documents in the result set of a query.\n * @param field - Specifies the field to sum across the result set.\n */\nexport function sum(field: string | FieldPath): AggregateField<number> {\n return new AggregateField('sum', fieldPathFromArgument('sum', field));\n}\n\n/**\n * Create an AggregateField object that can be used to compute the average of\n * a specified field over a range of documents in the result set of a query.\n * @param field - Specifies the field to average across the result set.\n */\nexport function average(\n field: string | FieldPath\n): AggregateField<number | null> {\n return new AggregateField('avg', fieldPathFromArgument('average', field));\n}\n\n/**\n * Create an AggregateField object that can be used to compute the count of\n * documents in the result set of a query.\n */\nexport function count(): AggregateField<number> {\n return new AggregateField('count');\n}\n\n/**\n * Compares two 'AggregateField` instances for equality.\n *\n * @param left - Compare this AggregateField to the `right`.\n * @param right - Compare this AggregateField to the `left`.\n */\nexport function aggregateFieldEqual(\n left: AggregateField<unknown>,\n right: AggregateField<unknown>\n): boolean {\n return (\n left instanceof AggregateField &&\n right instanceof AggregateField &&\n left.aggregateType === right.aggregateType &&\n left._internalFieldPath?.canonicalString() ===\n right._internalFieldPath?.canonicalString()\n );\n}\n\n/**\n * Compares two `AggregateQuerySnapshot` instances for equality.\n *\n * Two `AggregateQuerySnapshot` instances are considered \"equal\" if they have\n * underlying queries that compare equal, and the same data.\n *\n * @param left - The first `AggregateQuerySnapshot` to compare.\n * @param right - The second `AggregateQuerySnapshot` to compare.\n *\n * @returns `true` if the objects are \"equal\", as defined above, or `false`\n * otherwise.\n */\nexport function aggregateQuerySnapshotEqual<\n AggregateSpecType extends AggregateSpec,\n AppModelType,\n DbModelType extends DocumentData\n>(\n left: AggregateQuerySnapshot<AggregateSpecType, AppModelType, DbModelType>,\n right: AggregateQuerySnapshot<AggregateSpecType, AppModelType, DbModelType>\n): boolean {\n return (\n queryEqual(left.query, right.query) && deepEqual(left.data(), right.data())\n );\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Compat, getModularInstance } from '@firebase/util';\n\nimport { DeleteMutation, Mutation, Precondition } from '../model/mutation';\nimport { invokeCommitRpc } from '../remote/datastore';\nimport { Code, FirestoreError } from '../util/error';\nimport { cast } from '../util/input_validation';\n\nimport { getDatastore } from './components';\nimport { Firestore } from './database';\nimport { FieldPath } from './field_path';\nimport {\n DocumentData,\n DocumentReference,\n PartialWithFieldValue,\n SetOptions,\n UpdateData,\n WithFieldValue\n} from './reference';\nimport { applyFirestoreDataConverter } from './reference_impl';\nimport {\n newUserDataReader,\n parseSetData,\n parseUpdateData,\n parseUpdateVarargs,\n UserDataReader\n} from './user_data_reader';\n\n/**\n * A write batch, used to perform multiple writes as a single atomic unit.\n *\n * A `WriteBatch` object can be acquired by calling {@link writeBatch}. It\n * provides methods for adding writes to the write batch. None of the writes\n * will be committed (or visible locally) until {@link WriteBatch.commit} is\n * called.\n */\nexport class WriteBatch {\n // This is the lite version of the WriteBatch API used in the legacy SDK. The\n // class is a close copy but takes different input types.\n\n private readonly _dataReader: UserDataReader;\n private _mutations = [] as Mutation[];\n private _committed = false;\n\n /** @hideconstructor */\n constructor(\n private readonly _firestore: Firestore,\n private readonly _commitHandler: (m: Mutation[]) => Promise<void>\n ) {\n this._dataReader = newUserDataReader(_firestore);\n }\n\n /**\n * Writes to the document referred to by the provided {@link\n * DocumentReference}. If the document does not exist yet, it will be created.\n *\n * @param documentRef - A reference to the document to be set.\n * @param data - An object of the fields and values for the document.\n * @returns This `WriteBatch` instance. Used for chaining method calls.\n */\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: WithFieldValue<AppModelType>\n ): WriteBatch;\n /**\n * Writes to the document referred to by the provided {@link\n * DocumentReference}. If the document does not exist yet, it will be created.\n * If you provide `merge` or `mergeFields`, the provided data can be merged\n * into an existing document.\n *\n * @param documentRef - A reference to the document to be set.\n * @param data - An object of the fields and values for the document.\n * @param options - An object to configure the set behavior.\n * @throws Error - If the provided input is not a valid Firestore document.\n * @returns This `WriteBatch` instance. Used for chaining method calls.\n */\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: PartialWithFieldValue<AppModelType>,\n options: SetOptions\n ): WriteBatch;\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: WithFieldValue<AppModelType> | PartialWithFieldValue<AppModelType>,\n options?: SetOptions\n ): WriteBatch {\n this._verifyNotCommitted();\n const ref = validateReference(documentRef, this._firestore);\n\n const convertedValue = applyFirestoreDataConverter(\n ref.converter,\n data,\n options\n );\n const parsed = parseSetData(\n this._dataReader,\n 'WriteBatch.set',\n ref._key,\n convertedValue,\n ref.converter !== null,\n options\n );\n this._mutations.push(parsed.toMutation(ref._key, Precondition.none()));\n return this;\n }\n\n /**\n * Updates fields in the document referred to by the provided {@link\n * DocumentReference}. The update will fail if applied to a document that does\n * not exist.\n *\n * @param documentRef - A reference to the document to be updated.\n * @param data - An object containing the fields and values with which to\n * update the document. Fields can contain dots to reference nested fields\n * within the document.\n * @throws Error - If the provided input is not valid Firestore data.\n * @returns This `WriteBatch` instance. Used for chaining method calls.\n */\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: UpdateData<DbModelType>\n ): WriteBatch;\n /**\n * Updates fields in the document referred to by this {@link\n * DocumentReference}. The update will fail if applied to a document that does\n * not exist.\n *\n * Nested fields can be update by providing dot-separated field path strings\n * or by providing `FieldPath` objects.\n *\n * @param documentRef - A reference to the document to be updated.\n * @param field - The first field to update.\n * @param value - The first value.\n * @param moreFieldsAndValues - Additional key value pairs.\n * @throws Error - If the provided input is not valid Firestore data.\n * @returns This `WriteBatch` instance. Used for chaining method calls.\n */\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n field: string | FieldPath,\n value: unknown,\n ...moreFieldsAndValues: unknown[]\n ): WriteBatch;\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n fieldOrUpdateData: string | FieldPath | UpdateData<DbModelType>,\n value?: unknown,\n ...moreFieldsAndValues: unknown[]\n ): WriteBatch {\n this._verifyNotCommitted();\n const ref = validateReference(documentRef, this._firestore);\n\n // For Compat types, we have to \"extract\" the underlying types before\n // performing validation.\n fieldOrUpdateData = getModularInstance(fieldOrUpdateData);\n\n let parsed;\n if (\n typeof fieldOrUpdateData === 'string' ||\n fieldOrUpdateData instanceof FieldPath\n ) {\n parsed = parseUpdateVarargs(\n this._dataReader,\n 'WriteBatch.update',\n ref._key,\n fieldOrUpdateData,\n value,\n moreFieldsAndValues\n );\n } else {\n parsed = parseUpdateData(\n this._dataReader,\n 'WriteBatch.update',\n ref._key,\n fieldOrUpdateData\n );\n }\n\n this._mutations.push(\n parsed.toMutation(ref._key, Precondition.exists(true))\n );\n return this;\n }\n\n /**\n * Deletes the document referred to by the provided {@link DocumentReference}.\n *\n * @param documentRef - A reference to the document to be deleted.\n * @returns This `WriteBatch` instance. Used for chaining method calls.\n */\n delete<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>\n ): WriteBatch {\n this._verifyNotCommitted();\n const ref = validateReference(documentRef, this._firestore);\n this._mutations = this._mutations.concat(\n new DeleteMutation(ref._key, Precondition.none())\n );\n return this;\n }\n\n /**\n * Commits all of the writes in this write batch as a single atomic unit.\n *\n * The result of these writes will only be reflected in document reads that\n * occur after the returned promise resolves. If the client is offline, the\n * write fails. If you would like to see local modifications or buffer writes\n * until the client is online, use the full Firestore SDK.\n *\n * @returns A `Promise` resolved once all of the writes in the batch have been\n * successfully written to the backend as an atomic unit (note that it won't\n * resolve while you're offline).\n */\n commit(): Promise<void> {\n this._verifyNotCommitted();\n this._committed = true;\n if (this._mutations.length > 0) {\n return this._commitHandler(this._mutations);\n }\n\n return Promise.resolve();\n }\n\n private _verifyNotCommitted(): void {\n if (this._committed) {\n throw new FirestoreError(\n Code.FAILED_PRECONDITION,\n 'A write batch can no longer be used after commit() ' +\n 'has been called.'\n );\n }\n }\n}\n\nexport function validateReference<\n AppModelType,\n DbModelType extends DocumentData\n>(\n documentRef:\n | DocumentReference<AppModelType, DbModelType>\n | Compat<DocumentReference<AppModelType, DbModelType>>,\n firestore: Firestore\n): DocumentReference<AppModelType, DbModelType> {\n documentRef = getModularInstance(documentRef);\n\n if (documentRef.firestore !== firestore) {\n throw new FirestoreError(\n Code.INVALID_ARGUMENT,\n 'Provided document reference is from a different Firestore instance.'\n );\n } else {\n return documentRef as DocumentReference<AppModelType, DbModelType>;\n }\n}\n\n/**\n * Creates a write batch, used for performing multiple writes as a single\n * atomic operation. The maximum number of writes allowed in a single WriteBatch\n * is 500.\n *\n * The result of these writes will only be reflected in document reads that\n * occur after the returned promise resolves. If the client is offline, the\n * write fails. If you would like to see local modifications or buffer writes\n * until the client is online, use the full Firestore SDK.\n *\n * @returns A `WriteBatch` that can be used to atomically execute multiple\n * writes.\n */\nexport function writeBatch(firestore: Firestore): WriteBatch {\n firestore = cast(firestore, Firestore);\n const datastore = getDatastore(firestore);\n return new WriteBatch(firestore, writes =>\n invokeCommitRpc(datastore, writes)\n );\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ParsedSetData, ParsedUpdateData } from '../lite-api/user_data_reader';\nimport { Document } from '../model/document';\nimport { DocumentKey } from '../model/document_key';\nimport {\n DeleteMutation,\n Mutation,\n Precondition,\n VerifyMutation\n} from '../model/mutation';\nimport {\n Datastore,\n invokeBatchGetDocumentsRpc,\n invokeCommitRpc\n} from '../remote/datastore';\nimport { fail, debugAssert } from '../util/assert';\nimport { Code, FirestoreError } from '../util/error';\n\nimport { SnapshotVersion } from './snapshot_version';\n\n/**\n * Internal transaction object responsible for accumulating the mutations to\n * perform and the base versions for any documents read.\n */\nexport class Transaction {\n // The version of each document that was read during this transaction.\n private readVersions = new Map</* path */ string, SnapshotVersion>();\n private mutations: Mutation[] = [];\n private committed = false;\n\n /**\n * A deferred usage error that occurred previously in this transaction that\n * will cause the transaction to fail once it actually commits.\n */\n private lastTransactionError: FirestoreError | null = null;\n\n /**\n * Set of documents that have been written in the transaction.\n *\n * When there's more than one write to the same key in a transaction, any\n * writes after the first are handled differently.\n */\n private writtenDocs: Set</* path= */ string> = new Set();\n\n constructor(private datastore: Datastore) {}\n\n async lookup(keys: DocumentKey[]): Promise<Document[]> {\n this.ensureCommitNotCalled();\n\n if (this.mutations.length > 0) {\n this.lastTransactionError = new FirestoreError(\n Code.INVALID_ARGUMENT,\n 'Firestore transactions require all reads to be executed before all writes.'\n );\n throw this.lastTransactionError;\n }\n const docs = await invokeBatchGetDocumentsRpc(this.datastore, keys);\n docs.forEach(doc => this.recordVersion(doc));\n return docs;\n }\n\n set(key: DocumentKey, data: ParsedSetData): void {\n this.write(data.toMutation(key, this.precondition(key)));\n this.writtenDocs.add(key.toString());\n }\n\n update(key: DocumentKey, data: ParsedUpdateData): void {\n try {\n this.write(data.toMutation(key, this.preconditionForUpdate(key)));\n } catch (e) {\n this.lastTransactionError = e as FirestoreError | null;\n }\n this.writtenDocs.add(key.toString());\n }\n\n delete(key: DocumentKey): void {\n this.write(new DeleteMutation(key, this.precondition(key)));\n this.writtenDocs.add(key.toString());\n }\n\n async commit(): Promise<void> {\n this.ensureCommitNotCalled();\n\n if (this.lastTransactionError) {\n throw this.lastTransactionError;\n }\n const unwritten = this.readVersions;\n // For each mutation, note that the doc was written.\n this.mutations.forEach(mutation => {\n unwritten.delete(mutation.key.toString());\n });\n // For each document that was read but not written to, we want to perform\n // a `verify` operation.\n unwritten.forEach((_, path) => {\n const key = DocumentKey.fromPath(path);\n this.mutations.push(new VerifyMutation(key, this.precondition(key)));\n });\n await invokeCommitRpc(this.datastore, this.mutations);\n this.committed = true;\n }\n\n private recordVersion(doc: Document): void {\n let docVersion: SnapshotVersion;\n\n if (doc.isFoundDocument()) {\n docVersion = doc.version;\n } else if (doc.isNoDocument()) {\n // Represent a deleted doc using SnapshotVersion.min().\n docVersion = SnapshotVersion.min();\n } else {\n throw fail(0xc542, 'Document in a transaction was a ', {\n documentName: doc.constructor.name\n });\n }\n\n const existingVersion = this.readVersions.get(doc.key.toString());\n if (existingVersion) {\n if (!docVersion.isEqual(existingVersion)) {\n // This transaction will fail no matter what.\n throw new FirestoreError(\n Code.ABORTED,\n 'Document version changed between two reads.'\n );\n }\n } else {\n this.readVersions.set(doc.key.toString(), docVersion);\n }\n }\n\n /**\n * Returns the version of this document when it was read in this transaction,\n * as a precondition, or no precondition if it was not read.\n */\n private precondition(key: DocumentKey): Precondition {\n const version = this.readVersions.get(key.toString());\n if (!this.writtenDocs.has(key.toString()) && version) {\n if (version.isEqual(SnapshotVersion.min())) {\n return Precondition.exists(false);\n } else {\n return Precondition.updateTime(version);\n }\n } else {\n return Precondition.none();\n }\n }\n\n /**\n * Returns the precondition for a document if the operation is an update.\n */\n private preconditionForUpdate(key: DocumentKey): Precondition {\n const version = this.readVersions.get(key.toString());\n // The first time a document is written, we want to take into account the\n // read time and existence\n if (!this.writtenDocs.has(key.toString()) && version) {\n if (version.isEqual(SnapshotVersion.min())) {\n // The document doesn't exist, so fail the transaction.\n\n // This has to be validated locally because you can't send a\n // precondition that a document does not exist without changing the\n // semantics of the backend write to be an insert. This is the reverse\n // of what we want, since we want to assert that the document doesn't\n // exist but then send the update and have it fail. Since we can't\n // express that to the backend, we have to validate locally.\n\n // Note: this can change once we can send separate verify writes in the\n // transaction.\n throw new FirestoreError(\n Code.INVALID_ARGUMENT,\n \"Can't update a document that doesn't exist.\"\n );\n }\n // Document exists, base precondition on document update time.\n return Precondition.updateTime(version);\n } else {\n // Document was not read, so we just use the preconditions for a blind\n // update.\n return Precondition.exists(true);\n }\n }\n\n private write(mutation: Mutation): void {\n this.ensureCommitNotCalled();\n this.mutations.push(mutation);\n }\n\n private ensureCommitNotCalled(): void {\n debugAssert(\n !this.committed,\n 'A transaction object cannot be used after its update callback has been invoked.'\n );\n }\n}\n","/**\n * @license\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Code, FirestoreError } from '../util/error';\n\nexport const DEFAULT_TRANSACTION_OPTIONS: TransactionOptions = {\n maxAttempts: 5\n};\n\n/**\n * Options to customize transaction behavior.\n */\nexport declare interface TransactionOptions {\n /** Maximum number of attempts to commit, after which transaction fails. Default is 5. */\n readonly maxAttempts: number;\n}\n\nexport function validateTransactionOptions(options: TransactionOptions): void {\n if (options.maxAttempts < 1) {\n throw new FirestoreError(\n Code.INVALID_ARGUMENT,\n 'Max attempts must be at least 1'\n );\n }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ExponentialBackoff } from '../remote/backoff';\nimport { Datastore } from '../remote/datastore';\nimport { isPermanentError } from '../remote/rpc_error';\nimport { AsyncQueue, TimerId } from '../util/async_queue';\nimport { FirestoreError } from '../util/error';\nimport { Deferred } from '../util/promise';\nimport { isNullOrUndefined } from '../util/types';\n\nimport { Transaction } from './transaction';\nimport { TransactionOptions } from './transaction_options';\n\n/**\n * TransactionRunner encapsulates the logic needed to run and retry transactions\n * with backoff.\n */\nexport class TransactionRunner<T> {\n private attemptsRemaining: number;\n private backoff: ExponentialBackoff;\n\n constructor(\n private readonly asyncQueue: AsyncQueue,\n private readonly datastore: Datastore,\n private readonly options: TransactionOptions,\n private readonly updateFunction: (transaction: Transaction) => Promise<T>,\n private readonly deferred: Deferred<T>\n ) {\n this.attemptsRemaining = options.maxAttempts;\n this.backoff = new ExponentialBackoff(\n this.asyncQueue,\n TimerId.TransactionRetry\n );\n }\n\n /** Runs the transaction and sets the result on deferred. */\n run(): void {\n this.attemptsRemaining -= 1;\n this.runWithBackOff();\n }\n\n private runWithBackOff(): void {\n this.backoff.backoffAndRun(async () => {\n const transaction = new Transaction(this.datastore);\n const userPromise = this.tryRunUpdateFunction(transaction);\n if (userPromise) {\n userPromise\n .then(result => {\n this.asyncQueue.enqueueAndForget(() => {\n return transaction\n .commit()\n .then(() => {\n this.deferred.resolve(result);\n })\n .catch(commitError => {\n this.handleTransactionError(commitError);\n });\n });\n })\n .catch(userPromiseError => {\n this.handleTransactionError(userPromiseError);\n });\n }\n });\n }\n\n private tryRunUpdateFunction(transaction: Transaction): Promise<T> | null {\n try {\n const userPromise = this.updateFunction(transaction);\n if (\n isNullOrUndefined(userPromise) ||\n !userPromise.catch ||\n !userPromise.then\n ) {\n this.deferred.reject(\n Error('Transaction callback must return a Promise')\n );\n return null;\n }\n return userPromise;\n } catch (error) {\n // Do not retry errors thrown by user provided updateFunction.\n this.deferred.reject(error as Error);\n return null;\n }\n }\n\n private handleTransactionError(error: Error): void {\n if (this.attemptsRemaining > 0 && this.isRetryableTransactionError(error)) {\n this.attemptsRemaining -= 1;\n this.asyncQueue.enqueueAndForget(() => {\n this.runWithBackOff();\n return Promise.resolve();\n });\n } else {\n this.deferred.reject(error);\n }\n }\n\n private isRetryableTransactionError(error: Error | undefined): boolean {\n if (error?.name === 'FirebaseError') {\n // In transactions, the backend will fail outdated reads with FAILED_PRECONDITION and\n // non-matching document versions with ABORTED. These errors should be retried.\n const code = (error as FirestoreError).code;\n return (\n code === 'aborted' ||\n code === 'failed-precondition' ||\n code === 'already-exists' ||\n !isPermanentError(code)\n );\n }\n return false;\n }\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** The Platform's 'window' implementation or null if not available. */\nexport function getWindow(): Window | null {\n // `window` is not always available, e.g. in ReactNative and WebWorkers.\n // eslint-disable-next-line no-restricted-globals\n return typeof window !== 'undefined' ? window : null;\n}\n\n/** The Platform's 'document' implementation or null if not available. */\nexport function getDocument(): Document | null {\n // `document` is not always available, e.g. in ReactNative and WebWorkers.\n // eslint-disable-next-line no-restricted-globals\n return typeof document !== 'undefined' ? document : null;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isIndexedDbTransactionError } from '../local/simple_db';\n\nimport { Code, FirestoreError } from './error';\nimport { logError } from './log';\nimport { Deferred } from './promise';\n\nconst LOG_TAG = 'AsyncQueue';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype TimerHandle = any;\n\n/**\n * Wellknown \"timer\" IDs used when scheduling delayed operations on the\n * AsyncQueue. These IDs can then be used from tests to check for the presence\n * of operations or to run them early.\n *\n * The string values are used when encoding these timer IDs in JSON spec tests.\n */\nexport const enum TimerId {\n /** All can be used with runDelayedOperationsEarly() to run all timers. */\n All = 'all',\n\n /**\n * The following 5 timers are used in persistent_stream.ts for the listen and\n * write streams. The \"Idle\" timer is used to close the stream due to\n * inactivity. The \"ConnectionBackoff\" timer is used to restart a stream once\n * the appropriate backoff delay has elapsed. The health check is used to mark\n * a stream healthy if it has not received an error during its initial setup.\n */\n ListenStreamIdle = 'listen_stream_idle',\n ListenStreamConnectionBackoff = 'listen_stream_connection_backoff',\n WriteStreamIdle = 'write_stream_idle',\n WriteStreamConnectionBackoff = 'write_stream_connection_backoff',\n HealthCheckTimeout = 'health_check_timeout',\n\n /**\n * A timer used in online_state_tracker.ts to transition from\n * OnlineState.Unknown to Offline after a set timeout, rather than waiting\n * indefinitely for success or failure.\n */\n OnlineStateTimeout = 'online_state_timeout',\n\n /**\n * A timer used to update the client metadata in IndexedDb, which is used\n * to determine the primary leaseholder.\n */\n ClientMetadataRefresh = 'client_metadata_refresh',\n\n /** A timer used to periodically attempt LRU Garbage collection */\n LruGarbageCollection = 'lru_garbage_collection',\n\n /**\n * A timer used to retry transactions. Since there can be multiple concurrent\n * transactions, multiple of these may be in the queue at a given time.\n */\n TransactionRetry = 'transaction_retry',\n\n /**\n * A timer used to retry operations scheduled via retryable AsyncQueue\n * operations.\n */\n AsyncQueueRetry = 'async_queue_retry',\n\n /**\n * A timer used to periodically attempt index backfill.\n */\n IndexBackfill = 'index_backfill'\n}\n\n/**\n * Represents an operation scheduled to be run in the future on an AsyncQueue.\n *\n * It is created via DelayedOperation.createAndSchedule().\n *\n * Supports cancellation (via cancel()) and early execution (via skipDelay()).\n *\n * Note: We implement `PromiseLike` instead of `Promise`, as the `Promise` type\n * in newer versions of TypeScript defines `finally`, which is not available in\n * IE.\n */\nexport class DelayedOperation<T extends unknown> implements PromiseLike<T> {\n // handle for use with clearTimeout(), or null if the operation has been\n // executed or canceled already.\n private timerHandle: TimerHandle | null;\n\n private readonly deferred = new Deferred<T>();\n\n private constructor(\n private readonly asyncQueue: AsyncQueue,\n readonly timerId: TimerId,\n readonly targetTimeMs: number,\n private readonly op: () => Promise<T>,\n private readonly removalCallback: (op: DelayedOperation<T>) => void\n ) {\n // It's normal for the deferred promise to be canceled (due to cancellation)\n // and so we attach a dummy catch callback to avoid\n // 'UnhandledPromiseRejectionWarning' log spam.\n this.deferred.promise.catch(err => {});\n }\n\n get promise(): Promise<T> {\n return this.deferred.promise;\n }\n\n /**\n * Creates and returns a DelayedOperation that has been scheduled to be\n * executed on the provided asyncQueue after the provided delayMs.\n *\n * @param asyncQueue - The queue to schedule the operation on.\n * @param id - A Timer ID identifying the type of operation this is.\n * @param delayMs - The delay (ms) before the operation should be scheduled.\n * @param op - The operation to run.\n * @param removalCallback - A callback to be called synchronously once the\n * operation is executed or canceled, notifying the AsyncQueue to remove it\n * from its delayedOperations list.\n * PORTING NOTE: This exists to prevent making removeDelayedOperation() and\n * the DelayedOperation class public.\n */\n static createAndSchedule<R extends unknown>(\n asyncQueue: AsyncQueue,\n timerId: TimerId,\n delayMs: number,\n op: () => Promise<R>,\n removalCallback: (op: DelayedOperation<R>) => void\n ): DelayedOperation<R> {\n const targetTime = Date.now() + delayMs;\n const delayedOp = new DelayedOperation(\n asyncQueue,\n timerId,\n targetTime,\n op,\n removalCallback\n );\n delayedOp.start(delayMs);\n return delayedOp;\n }\n\n /**\n * Starts the timer. This is called immediately after construction by\n * createAndSchedule().\n */\n private start(delayMs: number): void {\n this.timerHandle = setTimeout(() => this.handleDelayElapsed(), delayMs);\n }\n\n /**\n * Queues the operation to run immediately (if it hasn't already been run or\n * canceled).\n */\n skipDelay(): void {\n return this.handleDelayElapsed();\n }\n\n /**\n * Cancels the operation if it hasn't already been executed or canceled. The\n * promise will be rejected.\n *\n * As long as the operation has not yet been run, calling cancel() provides a\n * guarantee that the operation will not be run.\n */\n cancel(reason?: string): void {\n if (this.timerHandle !== null) {\n this.clearTimeout();\n this.deferred.reject(\n new FirestoreError(\n Code.CANCELLED,\n 'Operation cancelled' + (reason ? ': ' + reason : '')\n )\n );\n }\n }\n\n then = this.deferred.promise.then.bind(this.deferred.promise);\n\n private handleDelayElapsed(): void {\n this.asyncQueue.enqueueAndForget(() => {\n if (this.timerHandle !== null) {\n this.clearTimeout();\n return this.op().then(result => {\n return this.deferred.resolve(result);\n });\n } else {\n return Promise.resolve();\n }\n });\n }\n\n private clearTimeout(): void {\n if (this.timerHandle !== null) {\n this.removalCallback(this);\n clearTimeout(this.timerHandle);\n this.timerHandle = null;\n }\n }\n}\n\nexport interface AsyncQueue {\n // Is this AsyncQueue being shut down? If true, this instance will not enqueue\n // any new operations, Promises from enqueue requests will not resolve.\n readonly isShuttingDown: boolean;\n\n /**\n * Adds a new operation to the queue without waiting for it to complete (i.e.\n * we ignore the Promise result).\n */\n enqueueAndForget<T extends unknown>(op: () => Promise<T>): void;\n\n /**\n * Regardless if the queue has initialized shutdown, adds a new operation to the\n * queue without waiting for it to complete (i.e. we ignore the Promise result).\n */\n enqueueAndForgetEvenWhileRestricted<T extends unknown>(\n op: () => Promise<T>\n ): void;\n\n /**\n * Initialize the shutdown of this queue. Once this method is called, the\n * only possible way to request running an operation is through\n * `enqueueEvenWhileRestricted()`.\n *\n * @param purgeExistingTasks - Whether already enqueued tasked should be\n * rejected (unless enqueued with `enqueueEvenWhileRestricted()`). Defaults\n * to false.\n */\n enterRestrictedMode(purgeExistingTasks?: boolean): void;\n\n /**\n * Adds a new operation to the queue. Returns a promise that will be resolved\n * when the promise returned by the new operation is (with its value).\n */\n enqueue<T extends unknown>(op: () => Promise<T>): Promise<T>;\n\n /**\n * Enqueue a retryable operation.\n *\n * A retryable operation is rescheduled with backoff if it fails with a\n * IndexedDbTransactionError (the error type used by SimpleDb). All\n * retryable operations are executed in order and only run if all prior\n * operations were retried successfully.\n */\n enqueueRetryable(op: () => Promise<void>): void;\n\n /**\n * Schedules an operation to be queued on the AsyncQueue once the specified\n * `delayMs` has elapsed. The returned DelayedOperation can be used to cancel\n * or fast-forward the operation prior to its running.\n */\n enqueueAfterDelay<T extends unknown>(\n timerId: TimerId,\n delayMs: number,\n op: () => Promise<T>\n ): DelayedOperation<T>;\n\n /**\n * Verifies there's an operation currently in-progress on the AsyncQueue.\n * Unfortunately we can't verify that the running code is in the promise chain\n * of that operation, so this isn't a foolproof check, but it should be enough\n * to catch some bugs.\n */\n verifyOperationInProgress(): void;\n}\n\n/**\n * Returns a FirestoreError that can be surfaced to the user if the provided\n * error is an IndexedDbTransactionError. Re-throws the error otherwise.\n */\nexport function wrapInUserErrorIfRecoverable(\n e: Error,\n msg: string\n): FirestoreError {\n logError(LOG_TAG, `${msg}: ${e}`);\n if (isIndexedDbTransactionError(e)) {\n return new FirestoreError(Code.UNAVAILABLE, `${msg}: ${e}`);\n } else {\n throw e;\n }\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { isIndexedDbTransactionError } from '../local/simple_db';\nimport { getDocument } from '../platform/dom';\nimport { ExponentialBackoff } from '../remote/backoff';\n\nimport { debugAssert, fail } from './assert';\nimport { AsyncQueue, DelayedOperation, TimerId } from './async_queue';\nimport { FirestoreError } from './error';\nimport { logDebug, logError } from './log';\nimport { Deferred } from './promise';\n\nconst LOG_TAG = 'AsyncQueue';\n\nexport class AsyncQueueImpl implements AsyncQueue {\n // The last promise in the queue.\n private tail: Promise<unknown>;\n\n // A list of retryable operations. Retryable operations are run in order and\n // retried with backoff.\n private retryableOps: Array<() => Promise<void>> = [];\n\n // Is this AsyncQueue being shut down? Once it is set to true, it will not\n // be changed again.\n private _isShuttingDown: boolean = false;\n\n // Operations scheduled to be queued in the future. Operations are\n // automatically removed after they are run or canceled.\n private delayedOperations: Array<DelayedOperation<unknown>> = [];\n\n // visible for testing\n failure: FirestoreError | null = null;\n\n // Flag set while there's an outstanding AsyncQueue operation, used for\n // assertion sanity-checks.\n private operationInProgress = false;\n\n // Enabled during shutdown on Safari to prevent future access to IndexedDB.\n private skipNonRestrictedTasks = false;\n\n // List of TimerIds to fast-forward delays for.\n private timerIdsToSkip: TimerId[] = [];\n\n // Backoff timer used to schedule retries for retryable operations\n private backoff = new ExponentialBackoff(this, TimerId.AsyncQueueRetry);\n\n // Visibility handler that triggers an immediate retry of all retryable\n // operations. Meant to speed up recovery when we regain file system access\n // after page comes into foreground.\n private visibilityHandler: () => void = () => {\n const document = getDocument();\n if (document) {\n logDebug(\n LOG_TAG,\n 'Visibility state changed to ' + document.visibilityState\n );\n }\n this.backoff.skipBackoff();\n };\n\n constructor(tail: Promise<unknown> = Promise.resolve()) {\n this.tail = tail;\n const document = getDocument();\n if (document && typeof document.addEventListener === 'function') {\n document.addEventListener('visibilitychange', this.visibilityHandler);\n }\n }\n\n get isShuttingDown(): boolean {\n return this._isShuttingDown;\n }\n\n /**\n * Adds a new operation to the queue without waiting for it to complete (i.e.\n * we ignore the Promise result).\n */\n enqueueAndForget<T extends unknown>(op: () => Promise<T>): void {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.enqueue(op);\n }\n\n enqueueAndForgetEvenWhileRestricted<T extends unknown>(\n op: () => Promise<T>\n ): void {\n this.verifyNotFailed();\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.enqueueInternal(op);\n }\n\n enterRestrictedMode(purgeExistingTasks?: boolean): void {\n if (!this._isShuttingDown) {\n this._isShuttingDown = true;\n this.skipNonRestrictedTasks = purgeExistingTasks || false;\n const document = getDocument();\n if (document && typeof document.removeEventListener === 'function') {\n document.removeEventListener(\n 'visibilitychange',\n this.visibilityHandler\n );\n }\n }\n }\n\n enqueue<T extends unknown>(op: () => Promise<T>): Promise<T> {\n this.verifyNotFailed();\n if (this._isShuttingDown) {\n // Return a Promise which never resolves.\n return new Promise<T>(() => {});\n }\n\n // Create a deferred Promise that we can return to the callee. This\n // allows us to return a \"hanging Promise\" only to the callee and still\n // advance the queue even when the operation is not run.\n const task = new Deferred<T>();\n return this.enqueueInternal<unknown>(() => {\n if (this._isShuttingDown && this.skipNonRestrictedTasks) {\n // We do not resolve 'task'\n return Promise.resolve();\n }\n\n op().then(task.resolve, task.reject);\n return task.promise;\n }).then(() => task.promise);\n }\n\n enqueueRetryable(op: () => Promise<void>): void {\n this.enqueueAndForget(() => {\n this.retryableOps.push(op);\n return this.retryNextOp();\n });\n }\n\n /**\n * Runs the next operation from the retryable queue. If the operation fails,\n * reschedules with backoff.\n */\n private async retryNextOp(): Promise<void> {\n if (this.retryableOps.length === 0) {\n return;\n }\n\n try {\n await this.retryableOps[0]();\n this.retryableOps.shift();\n this.backoff.reset();\n } catch (e) {\n if (isIndexedDbTransactionError(e as Error)) {\n logDebug(LOG_TAG, 'Operation failed with retryable error: ' + e);\n } else {\n throw e; // Failure will be handled by AsyncQueue\n }\n }\n\n if (this.retryableOps.length > 0) {\n // If there are additional operations, we re-schedule `retryNextOp()`.\n // This is necessary to run retryable operations that failed during\n // their initial attempt since we don't know whether they are already\n // enqueued. If, for example, `op1`, `op2`, `op3` are enqueued and `op1`\n // needs to be re-run, we will run `op1`, `op1`, `op2` using the\n // already enqueued calls to `retryNextOp()`. `op3()` will then run in the\n // call scheduled here.\n // Since `backoffAndRun()` cancels an existing backoff and schedules a\n // new backoff on every call, there is only ever a single additional\n // operation in the queue.\n this.backoff.backoffAndRun(() => this.retryNextOp());\n }\n }\n\n private enqueueInternal<T extends unknown>(op: () => Promise<T>): Promise<T> {\n const newTail = this.tail.then(() => {\n this.operationInProgress = true;\n return op()\n .catch((error: FirestoreError) => {\n this.failure = error;\n this.operationInProgress = false;\n const message = getMessageOrStack(error);\n logError('INTERNAL UNHANDLED ERROR: ', message);\n\n // Re-throw the error so that this.tail becomes a rejected Promise and\n // all further attempts to chain (via .then) will just short-circuit\n // and return the rejected Promise.\n throw error;\n })\n .then(result => {\n this.operationInProgress = false;\n return result;\n });\n });\n this.tail = newTail;\n return newTail;\n }\n\n enqueueAfterDelay<T extends unknown>(\n timerId: TimerId,\n delayMs: number,\n op: () => Promise<T>\n ): DelayedOperation<T> {\n this.verifyNotFailed();\n\n debugAssert(\n delayMs >= 0,\n `Attempted to schedule an operation with a negative delay of ${delayMs}`\n );\n\n // Fast-forward delays for timerIds that have been overridden.\n if (this.timerIdsToSkip.indexOf(timerId) > -1) {\n delayMs = 0;\n }\n\n const delayedOp = DelayedOperation.createAndSchedule<T>(\n this,\n timerId,\n delayMs,\n op,\n removedOp =>\n this.removeDelayedOperation(removedOp as DelayedOperation<unknown>)\n );\n this.delayedOperations.push(delayedOp as DelayedOperation<unknown>);\n return delayedOp;\n }\n\n private verifyNotFailed(): void {\n if (this.failure) {\n fail(0xb815, 'AsyncQueue is already failed', {\n messageOrStack: getMessageOrStack(this.failure)\n });\n }\n }\n\n verifyOperationInProgress(): void {\n debugAssert(\n this.operationInProgress,\n 'verifyOpInProgress() called when no op in progress on this queue.'\n );\n }\n\n /**\n * Waits until all currently queued tasks are finished executing. Delayed\n * operations are not run.\n */\n async drain(): Promise<void> {\n // Operations in the queue prior to draining may have enqueued additional\n // operations. Keep draining the queue until the tail is no longer advanced,\n // which indicates that no more new operations were enqueued and that all\n // operations were executed.\n let currentTail: Promise<unknown>;\n do {\n currentTail = this.tail;\n await currentTail;\n } while (currentTail !== this.tail);\n }\n\n /**\n * For Tests: Determine if a delayed operation with a particular TimerId\n * exists.\n */\n containsDelayedOperation(timerId: TimerId): boolean {\n for (const op of this.delayedOperations) {\n if (op.timerId === timerId) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * For Tests: Runs some or all delayed operations early.\n *\n * @param lastTimerId - Delayed operations up to and including this TimerId\n * will be drained. Pass TimerId.All to run all delayed operations.\n * @returns a Promise that resolves once all operations have been run.\n */\n runAllDelayedOperationsUntil(lastTimerId: TimerId): Promise<void> {\n // Note that draining may generate more delayed ops, so we do that first.\n return this.drain().then(() => {\n // Run ops in the same order they'd run if they ran naturally.\n /* eslint-disable-next-line @typescript-eslint/no-floating-promises */\n this.delayedOperations.sort((a, b) => a.targetTimeMs - b.targetTimeMs);\n\n for (const op of this.delayedOperations) {\n op.skipDelay();\n if (lastTimerId !== TimerId.All && op.timerId === lastTimerId) {\n break;\n }\n }\n\n return this.drain();\n });\n }\n\n /**\n * For Tests: Skip all subsequent delays for a timer id.\n */\n skipDelaysForTimerId(timerId: TimerId): void {\n this.timerIdsToSkip.push(timerId);\n }\n\n /** Called once a DelayedOperation is run or canceled. */\n private removeDelayedOperation(op: DelayedOperation<unknown>): void {\n // NOTE: indexOf / slice are O(n), but delayedOperations is expected to be small.\n const index = this.delayedOperations.indexOf(op);\n debugAssert(index >= 0, 'Delayed operation not found.');\n /* eslint-disable-next-line @typescript-eslint/no-floating-promises */\n this.delayedOperations.splice(index, 1);\n }\n}\n\nexport function newAsyncQueue(): AsyncQueue {\n return new AsyncQueueImpl();\n}\n\n/**\n * Chrome includes Error.message in Error.stack. Other browsers do not.\n * This returns expected output of message + stack when available.\n * @param error - Error or FirestoreError\n */\nfunction getMessageOrStack(error: Error): string {\n let message = error.message || '';\n if (error.stack) {\n if (error.stack.includes(error.message)) {\n message = error.stack;\n } else {\n message = error.message + '\\n' + error.stack;\n }\n }\n return message;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getGlobal, getUA, isIndexedDBAvailable } from '@firebase/util';\n\nimport { debugAssert } from '../util/assert';\nimport { Code, FirestoreError } from '../util/error';\nimport { logDebug, logError } from '../util/log';\nimport { Deferred } from '../util/promise';\n\nimport { PersistencePromise } from './persistence_promise';\n\n// References to `indexedDB` are guarded by SimpleDb.isAvailable() and getGlobal()\n/* eslint-disable no-restricted-globals */\n\nconst LOG_TAG = 'SimpleDb';\n\n/**\n * The maximum number of retry attempts for an IndexedDb transaction that fails\n * with a DOMException.\n */\nconst TRANSACTION_RETRY_COUNT = 3;\n\n// The different modes supported by `SimpleDb.runTransaction()`\ntype SimpleDbTransactionMode = 'readonly' | 'readwrite';\n\nexport interface SimpleDbSchemaConverter {\n createOrUpgrade(\n db: IDBDatabase,\n txn: IDBTransaction,\n fromVersion: number,\n toVersion: number\n ): PersistencePromise<void>;\n}\n\n/**\n * Wraps an IDBTransaction and exposes a store() method to get a handle to a\n * specific object store.\n */\nexport class SimpleDbTransaction {\n private aborted = false;\n\n /**\n * A `Promise` that resolves with the result of the IndexedDb transaction.\n */\n private readonly completionDeferred = new Deferred<void>();\n\n static open(\n db: IDBDatabase,\n action: string,\n mode: IDBTransactionMode,\n objectStoreNames: string[]\n ): SimpleDbTransaction {\n try {\n return new SimpleDbTransaction(\n action,\n db.transaction(objectStoreNames, mode)\n );\n } catch (e) {\n throw new IndexedDbTransactionError(action, e as Error);\n }\n }\n\n constructor(\n private readonly action: string,\n private readonly transaction: IDBTransaction\n ) {\n this.transaction.oncomplete = () => {\n this.completionDeferred.resolve();\n };\n this.transaction.onabort = () => {\n if (transaction.error) {\n this.completionDeferred.reject(\n new IndexedDbTransactionError(action, transaction.error)\n );\n } else {\n this.completionDeferred.resolve();\n }\n };\n this.transaction.onerror = (event: Event) => {\n const error = checkForAndReportiOSError(\n (event.target as IDBRequest).error!\n );\n this.completionDeferred.reject(\n new IndexedDbTransactionError(action, error)\n );\n };\n }\n\n get completionPromise(): Promise<void> {\n return this.completionDeferred.promise;\n }\n\n abort(error?: Error): void {\n if (error) {\n this.completionDeferred.reject(error);\n }\n\n if (!this.aborted) {\n logDebug(\n LOG_TAG,\n 'Aborting transaction:',\n error ? error.message : 'Client-initiated abort'\n );\n this.aborted = true;\n this.transaction.abort();\n }\n }\n\n maybeCommit(): void {\n // If the browser supports V3 IndexedDB, we invoke commit() explicitly to\n // speed up index DB processing if the event loop remains blocks.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const maybeV3IndexedDb = this.transaction as any;\n if (!this.aborted && typeof maybeV3IndexedDb.commit === 'function') {\n maybeV3IndexedDb.commit();\n }\n }\n\n /**\n * Returns a SimpleDbStore<KeyType, ValueType> for the specified store. All\n * operations performed on the SimpleDbStore happen within the context of this\n * transaction and it cannot be used anymore once the transaction is\n * completed.\n *\n * Note that we can't actually enforce that the KeyType and ValueType are\n * correct, but they allow type safety through the rest of the consuming code.\n */\n store<KeyType extends IDBValidKey, ValueType extends unknown>(\n storeName: string\n ): SimpleDbStore<KeyType, ValueType> {\n const store = this.transaction.objectStore(storeName);\n debugAssert(!!store, 'Object store not part of transaction: ' + storeName);\n return new SimpleDbStore<KeyType, ValueType>(store);\n }\n}\n\n/**\n * Provides a wrapper around IndexedDb with a simplified interface that uses\n * Promise-like return values to chain operations. Real promises cannot be used\n * since .then() continuations are executed asynchronously (e.g. via\n * .setImmediate), which would cause IndexedDB to end the transaction.\n * See PersistencePromise for more details.\n */\nexport class SimpleDb {\n private db?: IDBDatabase;\n private lastClosedDbVersion: number | null = null;\n private versionchangelistener?: (event: IDBVersionChangeEvent) => void;\n\n /** Deletes the specified database. */\n static delete(name: string): Promise<void> {\n logDebug(LOG_TAG, 'Removing database:', name);\n const globals = getGlobal();\n return wrapRequest<void>(\n globals.indexedDB.deleteDatabase(name)\n ).toPromise();\n }\n\n /** Returns true if IndexedDB is available in the current environment. */\n static isAvailable(): boolean {\n if (!isIndexedDBAvailable()) {\n return false;\n }\n\n if (SimpleDb.isMockPersistence()) {\n return true;\n }\n\n // We extensively use indexed array values and compound keys,\n // which IE and Edge do not support. However, they still have indexedDB\n // defined on the window, so we need to check for them here and make sure\n // to return that persistence is not enabled for those browsers.\n // For tracking support of this feature, see here:\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/status/indexeddbarraysandmultientrysupport/\n\n // Check the UA string to find out the browser.\n const ua = getUA();\n\n // IE 10\n // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';\n\n // IE 11\n // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';\n\n // Edge\n // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML,\n // like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';\n\n // iOS Safari: Disable for users running iOS version < 10.\n const iOSVersion = SimpleDb.getIOSVersion(ua);\n const isUnsupportedIOS = 0 < iOSVersion && iOSVersion < 10;\n\n // Android browser: Disable for users running version < 4.5.\n const androidVersion = getAndroidVersion(ua);\n const isUnsupportedAndroid = 0 < androidVersion && androidVersion < 4.5;\n\n if (\n ua.indexOf('MSIE ') > 0 ||\n ua.indexOf('Trident/') > 0 ||\n ua.indexOf('Edge/') > 0 ||\n isUnsupportedIOS ||\n isUnsupportedAndroid\n ) {\n return false;\n } else {\n return true;\n }\n }\n\n /**\n * Returns true if the backing IndexedDB store is the Node IndexedDBShim\n * (see https://github.com/axemclion/IndexedDBShim).\n */\n static isMockPersistence(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.env?.USE_MOCK_PERSISTENCE === 'YES'\n );\n }\n\n /** Helper to get a typed SimpleDbStore from a transaction. */\n static getStore<KeyType extends IDBValidKey, ValueType extends unknown>(\n txn: SimpleDbTransaction,\n store: string\n ): SimpleDbStore<KeyType, ValueType> {\n return txn.store<KeyType, ValueType>(store);\n }\n\n // visible for testing\n /** Parse User Agent to determine iOS version. Returns -1 if not found. */\n static getIOSVersion(ua: string): number {\n const iOSVersionRegex = ua.match(/i(?:phone|pad|pod) os ([\\d_]+)/i);\n const version = iOSVersionRegex\n ? iOSVersionRegex[1].split('_').slice(0, 2).join('.')\n : '-1';\n return Number(version);\n }\n\n /*\n * Creates a new SimpleDb wrapper for IndexedDb database `name`.\n *\n * Note that `version` must not be a downgrade. IndexedDB does not support\n * downgrading the schema version. We currently do not support any way to do\n * versioning outside of IndexedDB's versioning mechanism, as only\n * version-upgrade transactions are allowed to do things like create\n * objectstores.\n */\n constructor(\n private readonly name: string,\n private readonly version: number,\n private readonly schemaConverter: SimpleDbSchemaConverter\n ) {\n debugAssert(\n SimpleDb.isAvailable(),\n 'IndexedDB not supported in current environment.'\n );\n\n const iOSVersion = SimpleDb.getIOSVersion(getUA());\n // NOTE: According to https://bugs.webkit.org/show_bug.cgi?id=197050, the\n // bug we're checking for should exist in iOS >= 12.2 and < 13, but for\n // whatever reason it's much harder to hit after 12.2 so we only proactively\n // log on 12.2.\n if (iOSVersion === 12.2) {\n logError(\n 'Firestore persistence suffers from a bug in iOS 12.2 ' +\n 'Safari that may cause your app to stop working. See ' +\n 'https://stackoverflow.com/q/56496296/110915 for details ' +\n 'and a potential workaround.'\n );\n }\n }\n\n /**\n * Opens the specified database, creating or upgrading it if necessary.\n */\n async ensureDb(action: string): Promise<IDBDatabase> {\n if (!this.db) {\n logDebug(LOG_TAG, 'Opening database:', this.name);\n this.db = await new Promise<IDBDatabase>((resolve, reject) => {\n // TODO(mikelehen): Investigate browser compatibility.\n // https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB\n // suggests IE9 and older WebKit browsers handle upgrade\n // differently. They expect setVersion, as described here:\n // https://developer.mozilla.org/en-US/docs/Web/API/IDBVersionChangeRequest/setVersion\n const request = indexedDB.open(this.name, this.version);\n\n request.onsuccess = (event: Event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n resolve(db);\n };\n\n request.onblocked = () => {\n reject(\n new IndexedDbTransactionError(\n action,\n 'Cannot upgrade IndexedDB schema while another tab is open. ' +\n 'Close all tabs that access Firestore and reload this page to proceed.'\n )\n );\n };\n\n request.onerror = (event: Event) => {\n const error: DOMException = (event.target as IDBOpenDBRequest).error!;\n if (error.name === 'VersionError') {\n reject(\n new FirestoreError(\n Code.FAILED_PRECONDITION,\n 'A newer version of the Firestore SDK was previously used and so the persisted ' +\n 'data is not compatible with the version of the SDK you are now using. The SDK ' +\n 'will operate with persistence disabled. If you need persistence, please ' +\n 're-upgrade to a newer version of the SDK or else clear the persisted IndexedDB ' +\n 'data for your app to start fresh.'\n )\n );\n } else if (error.name === 'InvalidStateError') {\n reject(\n new FirestoreError(\n Code.FAILED_PRECONDITION,\n 'Unable to open an IndexedDB connection. This could be due to running in a ' +\n 'private browsing session on a browser whose private browsing sessions do not ' +\n 'support IndexedDB: ' +\n error\n )\n );\n } else {\n reject(new IndexedDbTransactionError(action, error));\n }\n };\n\n request.onupgradeneeded = (event: IDBVersionChangeEvent) => {\n logDebug(\n LOG_TAG,\n 'Database \"' + this.name + '\" requires upgrade from version:',\n event.oldVersion\n );\n const db = (event.target as IDBOpenDBRequest).result;\n this.schemaConverter\n .createOrUpgrade(\n db,\n request.transaction!,\n event.oldVersion,\n this.version\n )\n .next(() => {\n logDebug(\n LOG_TAG,\n 'Database upgrade to version ' + this.version + ' complete'\n );\n });\n };\n });\n }\n\n if (this.versionchangelistener) {\n this.db.onversionchange = event => this.versionchangelistener!(event);\n }\n\n return this.db;\n }\n\n setVersionChangeListener(\n versionChangeListener: (event: IDBVersionChangeEvent) => void\n ): void {\n this.versionchangelistener = versionChangeListener;\n if (this.db) {\n this.db.onversionchange = (event: IDBVersionChangeEvent) => {\n return versionChangeListener(event);\n };\n }\n }\n\n async runTransaction<T>(\n action: string,\n mode: SimpleDbTransactionMode,\n objectStores: string[],\n transactionFn: (transaction: SimpleDbTransaction) => PersistencePromise<T>\n ): Promise<T> {\n const readonly = mode === 'readonly';\n let attemptNumber = 0;\n\n while (true) {\n ++attemptNumber;\n\n try {\n this.db = await this.ensureDb(action);\n\n const transaction = SimpleDbTransaction.open(\n this.db,\n action,\n readonly ? 'readonly' : 'readwrite',\n objectStores\n );\n const transactionFnResult = transactionFn(transaction)\n .next(result => {\n transaction.maybeCommit();\n return result;\n })\n .catch(error => {\n // Abort the transaction if there was an error.\n transaction.abort(error);\n // We cannot actually recover, and calling `abort()` will cause the transaction's\n // completion promise to be rejected. This in turn means that we won't use\n // `transactionFnResult` below. We return a rejection here so that we don't add the\n // possibility of returning `void` to the type of `transactionFnResult`.\n return PersistencePromise.reject<T>(error);\n })\n .toPromise();\n\n // As noted above, errors are propagated by aborting the transaction. So\n // we swallow any error here to avoid the browser logging it as unhandled.\n transactionFnResult.catch(() => {});\n\n // Wait for the transaction to complete (i.e. IndexedDb's onsuccess event to\n // fire), but still return the original transactionFnResult back to the\n // caller.\n await transaction.completionPromise;\n return transactionFnResult;\n } catch (e) {\n const error = e as Error;\n // TODO(schmidt-sebastian): We could probably be smarter about this and\n // not retry exceptions that are likely unrecoverable (such as quota\n // exceeded errors).\n\n // Note: We cannot use an instanceof check for FirestoreException, since the\n // exception is wrapped in a generic error by our async/await handling.\n const retryable =\n error.name !== 'FirebaseError' &&\n attemptNumber < TRANSACTION_RETRY_COUNT;\n logDebug(\n LOG_TAG,\n 'Transaction failed with error:',\n error.message,\n 'Retrying:',\n retryable\n );\n\n this.close();\n\n if (!retryable) {\n return Promise.reject(error);\n }\n }\n }\n }\n\n close(): void {\n if (this.db) {\n this.db.close();\n }\n this.db = undefined;\n }\n}\n\n/** Parse User Agent to determine Android version. Returns -1 if not found. */\nexport function getAndroidVersion(ua: string): number {\n const androidVersionRegex = ua.match(/Android ([\\d.]+)/i);\n const version = androidVersionRegex\n ? androidVersionRegex[1].split('.').slice(0, 2).join('.')\n : '-1';\n return Number(version);\n}\n\n/**\n * A controller for iterating over a key range or index. It allows an iterate\n * callback to delete the currently-referenced object, or jump to a new key\n * within the key range or index.\n */\nexport class IterationController {\n private shouldStop = false;\n private nextKey: IDBValidKey | null = null;\n\n constructor(private dbCursor: IDBCursorWithValue) {}\n\n get isDone(): boolean {\n return this.shouldStop;\n }\n\n get skipToKey(): IDBValidKey | null {\n return this.nextKey;\n }\n\n set cursor(value: IDBCursorWithValue) {\n this.dbCursor = value;\n }\n\n /**\n * This function can be called to stop iteration at any point.\n */\n done(): void {\n this.shouldStop = true;\n }\n\n /**\n * This function can be called to skip to that next key, which could be\n * an index or a primary key.\n */\n skip(key: IDBValidKey): void {\n this.nextKey = key;\n }\n\n /**\n * Delete the current cursor value from the object store.\n *\n * NOTE: You CANNOT do this with a keysOnly query.\n */\n delete(): PersistencePromise<void> {\n return wrapRequest<void>(this.dbCursor.delete());\n }\n}\n\n/**\n * Callback used with iterate() method.\n */\nexport type IterateCallback<KeyType, ValueType> = (\n key: KeyType,\n value: ValueType,\n control: IterationController\n) => void | PersistencePromise<void>;\n\n/** Options available to the iterate() method. */\nexport interface IterateOptions {\n /** Index to iterate over (else primary keys will be iterated) */\n index?: string;\n\n /** IndexedDB Range to iterate over (else entire store will be iterated) */\n range?: IDBKeyRange;\n\n /** If true, values aren't read while iterating. */\n keysOnly?: boolean;\n\n /** If true, iterate over the store in reverse. */\n reverse?: boolean;\n}\n\n/** An error that wraps exceptions that thrown during IndexedDB execution. */\nexport class IndexedDbTransactionError extends FirestoreError {\n name = 'IndexedDbTransactionError';\n\n constructor(actionName: string, cause: Error | string) {\n super(\n Code.UNAVAILABLE,\n `IndexedDB transaction '${actionName}' failed: ${cause}`\n );\n }\n}\n\n/** Verifies whether `e` is an IndexedDbTransactionError. */\nexport function isIndexedDbTransactionError(e: Error): boolean {\n // Use name equality, as instanceof checks on errors don't work with errors\n // that wrap other errors.\n return e.name === 'IndexedDbTransactionError';\n}\n\n/**\n * A wrapper around an IDBObjectStore providing an API that:\n *\n * 1) Has generic KeyType / ValueType parameters to provide strongly-typed\n * methods for acting against the object store.\n * 2) Deals with IndexedDB's onsuccess / onerror event callbacks, making every\n * method return a PersistencePromise instead.\n * 3) Provides a higher-level API to avoid needing to do excessive wrapping of\n * intermediate IndexedDB types (IDBCursorWithValue, etc.)\n */\nexport class SimpleDbStore<\n KeyType extends IDBValidKey,\n ValueType extends unknown\n> {\n constructor(private store: IDBObjectStore) {}\n\n /**\n * Writes a value into the Object Store.\n *\n * @param key - Optional explicit key to use when writing the object, else the\n * key will be auto-assigned (e.g. via the defined keyPath for the store).\n * @param value - The object to write.\n */\n put(value: ValueType): PersistencePromise<void>;\n put(key: KeyType, value: ValueType): PersistencePromise<void>;\n put(\n keyOrValue: KeyType | ValueType,\n value?: ValueType\n ): PersistencePromise<void> {\n let request;\n if (value !== undefined) {\n logDebug(LOG_TAG, 'PUT', this.store.name, keyOrValue, value);\n request = this.store.put(value, keyOrValue as KeyType);\n } else {\n logDebug(LOG_TAG, 'PUT', this.store.name, '<auto-key>', keyOrValue);\n request = this.store.put(keyOrValue as ValueType);\n }\n return wrapRequest<void>(request);\n }\n\n /**\n * Adds a new value into an Object Store and returns the new key. Similar to\n * IndexedDb's `add()`, this method will fail on primary key collisions.\n *\n * @param value - The object to write.\n * @returns The key of the value to add.\n */\n add(value: ValueType): PersistencePromise<KeyType> {\n logDebug(LOG_TAG, 'ADD', this.store.name, value, value);\n const request = this.store.add(value as ValueType);\n return wrapRequest<KeyType>(request);\n }\n\n /**\n * Gets the object with the specified key from the specified store, or null\n * if no object exists with the specified key.\n *\n * @key The key of the object to get.\n * @returns The object with the specified key or null if no object exists.\n */\n get(key: KeyType): PersistencePromise<ValueType | null> {\n const request = this.store.get(key);\n // We're doing an unsafe cast to ValueType.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return wrapRequest<any>(request).next(result => {\n // Normalize nonexistence to null.\n if (result === undefined) {\n result = null;\n }\n logDebug(LOG_TAG, 'GET', this.store.name, key, result);\n return result;\n });\n }\n\n delete(key: KeyType | IDBKeyRange): PersistencePromise<void> {\n logDebug(LOG_TAG, 'DELETE', this.store.name, key);\n const request = this.store.delete(key);\n return wrapRequest<void>(request);\n }\n\n /**\n * If we ever need more of the count variants, we can add overloads. For now,\n * all we need is to count everything in a store.\n *\n * Returns the number of rows in the store.\n */\n count(): PersistencePromise<number> {\n logDebug(LOG_TAG, 'COUNT', this.store.name);\n const request = this.store.count();\n return wrapRequest<number>(request);\n }\n\n /** Loads all elements from the object store. */\n loadAll(): PersistencePromise<ValueType[]>;\n /** Loads all elements for the index range from the object store. */\n loadAll(range: IDBKeyRange): PersistencePromise<ValueType[]>;\n /** Loads all elements ordered by the given index. */\n loadAll(index: string): PersistencePromise<ValueType[]>;\n /**\n * Loads all elements from the object store that fall into the provided in the\n * index range for the given index.\n */\n loadAll(index: string, range: IDBKeyRange): PersistencePromise<ValueType[]>;\n loadAll(\n indexOrRange?: string | IDBKeyRange,\n range?: IDBKeyRange\n ): PersistencePromise<ValueType[]> {\n const iterateOptions = this.options(indexOrRange, range);\n // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly\n // 20% faster.\n const store = iterateOptions.index\n ? this.store.index(iterateOptions.index)\n : this.store;\n if (typeof store.getAll === 'function') {\n const request = store.getAll(iterateOptions.range);\n return new PersistencePromise((resolve, reject) => {\n request.onerror = (event: Event) => {\n reject((event.target as IDBRequest).error!);\n };\n request.onsuccess = (event: Event) => {\n resolve((event.target as IDBRequest).result);\n };\n });\n } else {\n const cursor = this.cursor(iterateOptions);\n const results: ValueType[] = [];\n return this.iterateCursor(cursor, (key, value) => {\n results.push(value);\n }).next(() => {\n return results;\n });\n }\n }\n\n /**\n * Loads the first `count` elements from the provided index range. Loads all\n * elements if no limit is provided.\n */\n loadFirst(\n range: IDBKeyRange,\n count: number | null\n ): PersistencePromise<ValueType[]> {\n const request = this.store.getAll(\n range,\n count === null ? undefined : count\n );\n return new PersistencePromise((resolve, reject) => {\n request.onerror = (event: Event) => {\n reject((event.target as IDBRequest).error!);\n };\n request.onsuccess = (event: Event) => {\n resolve((event.target as IDBRequest).result);\n };\n });\n }\n\n deleteAll(): PersistencePromise<void>;\n deleteAll(range: IDBKeyRange): PersistencePromise<void>;\n deleteAll(index: string, range: IDBKeyRange): PersistencePromise<void>;\n deleteAll(\n indexOrRange?: string | IDBKeyRange,\n range?: IDBKeyRange\n ): PersistencePromise<void> {\n logDebug(LOG_TAG, 'DELETE ALL', this.store.name);\n const options = this.options(indexOrRange, range);\n options.keysOnly = false;\n const cursor = this.cursor(options);\n return this.iterateCursor(cursor, (key, value, control) => {\n // NOTE: Calling delete() on a cursor is documented as more efficient than\n // calling delete() on an object store with a single key\n // (https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore/delete),\n // however, this requires us *not* to use a keysOnly cursor\n // (https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor/delete). We\n // may want to compare the performance of each method.\n return control.delete();\n });\n }\n\n /**\n * Iterates over keys and values in an object store.\n *\n * @param options - Options specifying how to iterate the objects in the\n * store.\n * @param callback - will be called for each iterated object. Iteration can be\n * canceled at any point by calling the doneFn passed to the callback.\n * The callback can return a PersistencePromise if it performs async\n * operations but note that iteration will continue without waiting for them\n * to complete.\n * @returns A PersistencePromise that resolves once all PersistencePromises\n * returned by callbacks resolve.\n */\n iterate(\n callback: IterateCallback<KeyType, ValueType>\n ): PersistencePromise<void>;\n iterate(\n options: IterateOptions,\n callback: IterateCallback<KeyType, ValueType>\n ): PersistencePromise<void>;\n iterate(\n optionsOrCallback: IterateOptions | IterateCallback<KeyType, ValueType>,\n callback?: IterateCallback<KeyType, ValueType>\n ): PersistencePromise<void> {\n let options;\n if (!callback) {\n options = {};\n callback = optionsOrCallback as IterateCallback<KeyType, ValueType>;\n } else {\n options = optionsOrCallback as IterateOptions;\n }\n const cursor = this.cursor(options);\n return this.iterateCursor(cursor, callback);\n }\n\n /**\n * Iterates over a store, but waits for the given callback to complete for\n * each entry before iterating the next entry. This allows the callback to do\n * asynchronous work to determine if this iteration should continue.\n *\n * The provided callback should return `true` to continue iteration, and\n * `false` otherwise.\n */\n iterateSerial(\n callback: (k: KeyType, v: ValueType) => PersistencePromise<boolean>\n ): PersistencePromise<void> {\n const cursorRequest = this.cursor({});\n return new PersistencePromise((resolve, reject) => {\n cursorRequest.onerror = (event: Event) => {\n const error = checkForAndReportiOSError(\n (event.target as IDBRequest).error!\n );\n reject(error);\n };\n cursorRequest.onsuccess = (event: Event) => {\n const cursor: IDBCursorWithValue = (event.target as IDBRequest).result;\n if (!cursor) {\n resolve();\n return;\n }\n\n callback(cursor.primaryKey as KeyType, cursor.value).next(\n shouldContinue => {\n if (shouldContinue) {\n cursor.continue();\n } else {\n resolve();\n }\n }\n );\n };\n });\n }\n\n private iterateCursor(\n cursorRequest: IDBRequest,\n fn: IterateCallback<KeyType, ValueType>\n ): PersistencePromise<void> {\n const results: Array<PersistencePromise<void>> = [];\n return new PersistencePromise((resolve, reject) => {\n cursorRequest.onerror = (event: Event) => {\n reject((event.target as IDBRequest).error!);\n };\n cursorRequest.onsuccess = (event: Event) => {\n const cursor: IDBCursorWithValue = (event.target as IDBRequest).result;\n if (!cursor) {\n resolve();\n return;\n }\n const controller = new IterationController(cursor);\n const userResult = fn(\n cursor.primaryKey as KeyType,\n cursor.value,\n controller\n );\n if (userResult instanceof PersistencePromise) {\n const userPromise: PersistencePromise<void> = userResult.catch(\n err => {\n controller.done();\n return PersistencePromise.reject(err);\n }\n );\n results.push(userPromise);\n }\n if (controller.isDone) {\n resolve();\n } else if (controller.skipToKey === null) {\n cursor.continue();\n } else {\n cursor.continue(controller.skipToKey);\n }\n };\n }).next(() => PersistencePromise.waitFor(results));\n }\n\n private options(\n indexOrRange?: string | IDBKeyRange,\n range?: IDBKeyRange\n ): IterateOptions {\n let indexName: string | undefined = undefined;\n if (indexOrRange !== undefined) {\n if (typeof indexOrRange === 'string') {\n indexName = indexOrRange;\n } else {\n debugAssert(\n range === undefined,\n '3rd argument must not be defined if 2nd is a range.'\n );\n range = indexOrRange;\n }\n }\n return { index: indexName, range };\n }\n\n private cursor(options: IterateOptions): IDBRequest {\n let direction: IDBCursorDirection = 'next';\n if (options.reverse) {\n direction = 'prev';\n }\n if (options.index) {\n const index = this.store.index(options.index);\n if (options.keysOnly) {\n return index.openKeyCursor(options.range, direction);\n } else {\n return index.openCursor(options.range, direction);\n }\n } else {\n return this.store.openCursor(options.range, direction);\n }\n }\n}\n\n/**\n * Wraps an IDBRequest in a PersistencePromise, using the onsuccess / onerror\n * handlers to resolve / reject the PersistencePromise as appropriate.\n */\nfunction wrapRequest<R>(request: IDBRequest): PersistencePromise<R> {\n return new PersistencePromise<R>((resolve, reject) => {\n request.onsuccess = (event: Event) => {\n const result = (event.target as IDBRequest).result;\n resolve(result);\n };\n\n request.onerror = (event: Event) => {\n const error = checkForAndReportiOSError(\n (event.target as IDBRequest).error!\n );\n reject(error);\n };\n });\n}\n\n// Guard so we only report the error once.\nlet reportedIOSError = false;\nfunction checkForAndReportiOSError(error: DOMException): Error {\n const iOSVersion = SimpleDb.getIOSVersion(getUA());\n if (iOSVersion >= 12.2 && iOSVersion < 13) {\n const IOS_ERROR =\n 'An internal error was encountered in the Indexed Database server';\n if (error.message.indexOf(IOS_ERROR) >= 0) {\n // Wrap error in a more descriptive one.\n const newError = new FirestoreError(\n 'internal',\n `IOS_INDEXEDDB_BUG1: IndexedDb has thrown '${IOS_ERROR}'. This is likely ` +\n `due to an unavoidable bug in iOS. See https://stackoverflow.com/q/56496296/110915 ` +\n `for details and a potential workaround.`\n );\n if (!reportedIOSError) {\n reportedIOSError = true;\n // Throw a global exception outside of this promise chain, for the user to\n // potentially catch.\n setTimeout(() => {\n throw newError;\n }, 0);\n }\n return newError;\n }\n }\n return error;\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getModularInstance } from '@firebase/util';\n\nimport { Transaction as InternalTransaction } from '../core/transaction';\nimport {\n DEFAULT_TRANSACTION_OPTIONS,\n TransactionOptions as TransactionOptionsInternal,\n validateTransactionOptions\n} from '../core/transaction_options';\nimport { TransactionRunner } from '../core/transaction_runner';\nimport { fail } from '../util/assert';\nimport { newAsyncQueue } from '../util/async_queue_impl';\nimport { cast } from '../util/input_validation';\nimport { Deferred } from '../util/promise';\n\nimport { getDatastore } from './components';\nimport { Firestore } from './database';\nimport { FieldPath } from './field_path';\nimport {\n DocumentData,\n DocumentReference,\n PartialWithFieldValue,\n SetOptions,\n UpdateData,\n WithFieldValue\n} from './reference';\nimport {\n applyFirestoreDataConverter,\n LiteUserDataWriter\n} from './reference_impl';\nimport { DocumentSnapshot } from './snapshot';\nimport { TransactionOptions } from './transaction_options';\nimport {\n newUserDataReader,\n parseSetData,\n parseUpdateData,\n parseUpdateVarargs,\n UserDataReader\n} from './user_data_reader';\nimport { validateReference } from './write_batch';\n\n// TODO(mrschmidt) Consider using `BaseTransaction` as the base class in the\n// legacy SDK.\n\n/**\n * A reference to a transaction.\n *\n * The `Transaction` object passed to a transaction's `updateFunction` provides\n * the methods to read and write data within the transaction context. See\n * {@link runTransaction}.\n */\nexport class Transaction {\n // This is the tree-shakeable version of the Transaction class used in the\n // legacy SDK. The class is a close copy but takes different input and output\n // types. The firestore-exp SDK further extends this class to return its API\n // type.\n\n private readonly _dataReader: UserDataReader;\n\n /** @hideconstructor */\n constructor(\n protected readonly _firestore: Firestore,\n private readonly _transaction: InternalTransaction\n ) {\n this._dataReader = newUserDataReader(_firestore);\n }\n\n /**\n * Reads the document referenced by the provided {@link DocumentReference}.\n *\n * @param documentRef - A reference to the document to be read.\n * @returns A `DocumentSnapshot` with the read data.\n */\n get<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>\n ): Promise<DocumentSnapshot<AppModelType, DbModelType>> {\n const ref = validateReference(documentRef, this._firestore);\n const userDataWriter = new LiteUserDataWriter(this._firestore);\n return this._transaction.lookup([ref._key]).then(docs => {\n if (!docs || docs.length !== 1) {\n return fail(0x5de9, 'Mismatch in docs returned from document lookup.');\n }\n const doc = docs[0];\n if (doc.isFoundDocument()) {\n return new DocumentSnapshot<AppModelType, DbModelType>(\n this._firestore,\n userDataWriter,\n doc.key,\n doc,\n ref.converter\n );\n } else if (doc.isNoDocument()) {\n return new DocumentSnapshot<AppModelType, DbModelType>(\n this._firestore,\n userDataWriter,\n ref._key,\n null,\n ref.converter\n );\n } else {\n throw fail(\n 0x4801,\n 'BatchGetDocumentsRequest returned unexpected document',\n {\n doc\n }\n );\n }\n });\n }\n\n /**\n * Writes to the document referred to by the provided {@link\n * DocumentReference}. If the document does not exist yet, it will be created.\n *\n * @param documentRef - A reference to the document to be set.\n * @param data - An object of the fields and values for the document.\n * @throws Error - If the provided input is not a valid Firestore document.\n * @returns This `Transaction` instance. Used for chaining method calls.\n */\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: WithFieldValue<AppModelType>\n ): this;\n /**\n * Writes to the document referred to by the provided {@link\n * DocumentReference}. If the document does not exist yet, it will be created.\n * If you provide `merge` or `mergeFields`, the provided data can be merged\n * into an existing document.\n *\n * @param documentRef - A reference to the document to be set.\n * @param data - An object of the fields and values for the document.\n * @param options - An object to configure the set behavior.\n * @throws Error - If the provided input is not a valid Firestore document.\n * @returns This `Transaction` instance. Used for chaining method calls.\n */\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: PartialWithFieldValue<AppModelType>,\n options: SetOptions\n ): this;\n set<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n value: PartialWithFieldValue<AppModelType>,\n options?: SetOptions\n ): this {\n const ref = validateReference(documentRef, this._firestore);\n const convertedValue = applyFirestoreDataConverter(\n ref.converter,\n value,\n options\n );\n const parsed = parseSetData(\n this._dataReader,\n 'Transaction.set',\n ref._key,\n convertedValue,\n ref.converter !== null,\n options\n );\n this._transaction.set(ref._key, parsed);\n return this;\n }\n\n /**\n * Updates fields in the document referred to by the provided {@link\n * DocumentReference}. The update will fail if applied to a document that does\n * not exist.\n *\n * @param documentRef - A reference to the document to be updated.\n * @param data - An object containing the fields and values with which to\n * update the document. Fields can contain dots to reference nested fields\n * within the document.\n * @throws Error - If the provided input is not valid Firestore data.\n * @returns This `Transaction` instance. Used for chaining method calls.\n */\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n data: UpdateData<DbModelType>\n ): this;\n /**\n * Updates fields in the document referred to by the provided {@link\n * DocumentReference}. The update will fail if applied to a document that does\n * not exist.\n *\n * Nested fields can be updated by providing dot-separated field path\n * strings or by providing `FieldPath` objects.\n *\n * @param documentRef - A reference to the document to be updated.\n * @param field - The first field to update.\n * @param value - The first value.\n * @param moreFieldsAndValues - Additional key/value pairs.\n * @throws Error - If the provided input is not valid Firestore data.\n * @returns This `Transaction` instance. Used for chaining method calls.\n */\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n field: string | FieldPath,\n value: unknown,\n ...moreFieldsAndValues: unknown[]\n ): this;\n update<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>,\n fieldOrUpdateData: string | FieldPath | UpdateData<DbModelType>,\n value?: unknown,\n ...moreFieldsAndValues: unknown[]\n ): this {\n const ref = validateReference(documentRef, this._firestore);\n\n // For Compat types, we have to \"extract\" the underlying types before\n // performing validation.\n fieldOrUpdateData = getModularInstance(fieldOrUpdateData);\n\n let parsed;\n if (\n typeof fieldOrUpdateData === 'string' ||\n fieldOrUpdateData instanceof FieldPath\n ) {\n parsed = parseUpdateVarargs(\n this._dataReader,\n 'Transaction.update',\n ref._key,\n fieldOrUpdateData,\n value,\n moreFieldsAndValues\n );\n } else {\n parsed = parseUpdateData(\n this._dataReader,\n 'Transaction.update',\n ref._key,\n fieldOrUpdateData\n );\n }\n\n this._transaction.update(ref._key, parsed);\n return this;\n }\n\n /**\n * Deletes the document referred to by the provided {@link DocumentReference}.\n *\n * @param documentRef - A reference to the document to be deleted.\n * @returns This `Transaction` instance. Used for chaining method calls.\n */\n delete<AppModelType, DbModelType extends DocumentData>(\n documentRef: DocumentReference<AppModelType, DbModelType>\n ): this {\n const ref = validateReference(documentRef, this._firestore);\n this._transaction.delete(ref._key);\n return this;\n }\n}\n\n/**\n * Executes the given `updateFunction` and then attempts to commit the changes\n * applied within the transaction. If any document read within the transaction\n * has changed, Cloud Firestore retries the `updateFunction`. If it fails to\n * commit after 5 attempts, the transaction fails.\n *\n * The maximum number of writes allowed in a single transaction is 500.\n *\n * @param firestore - A reference to the Firestore database to run this\n * transaction against.\n * @param updateFunction - The function to execute within the transaction\n * context.\n * @param options - An options object to configure maximum number of attempts to\n * commit.\n * @returns If the transaction completed successfully or was explicitly aborted\n * (the `updateFunction` returned a failed promise), the promise returned by the\n * `updateFunction `is returned here. Otherwise, if the transaction failed, a\n * rejected promise with the corresponding failure error is returned.\n */\nexport function runTransaction<T>(\n firestore: Firestore,\n updateFunction: (transaction: Transaction) => Promise<T>,\n options?: TransactionOptions\n): Promise<T> {\n firestore = cast(firestore, Firestore);\n const datastore = getDatastore(firestore);\n const optionsWithDefaults: TransactionOptionsInternal = {\n ...DEFAULT_TRANSACTION_OPTIONS,\n ...options\n };\n validateTransactionOptions(optionsWithDefaults);\n const deferred = new Deferred<T>();\n new TransactionRunner<T>(\n newAsyncQueue(),\n datastore,\n optionsWithDefaults,\n internalTransaction =>\n updateFunction(new Transaction(firestore, internalTransaction)),\n deferred\n ).run();\n return deferred.promise;\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n _registerComponent,\n registerVersion,\n SDK_VERSION\n} from '@firebase/app';\nimport { Component, ComponentType } from '@firebase/component';\n\nimport { version } from '../package.json';\nimport {\n LiteAppCheckTokenProvider,\n LiteAuthCredentialsProvider\n} from '../src/api/credentials';\nimport { databaseIdFromApp } from '../src/core/database_info';\nimport { setSDKVersion } from '../src/core/version';\nimport { Firestore } from '../src/lite-api/database';\n\ndeclare module '@firebase/component' {\n interface NameServiceMapping {\n 'firestore/lite': Firestore;\n }\n}\n\nexport function registerFirestore(): void {\n setSDKVersion(`${SDK_VERSION}_lite`);\n _registerComponent(\n new Component(\n 'firestore/lite',\n (container, { instanceIdentifier: databaseId, options: settings }) => {\n const app = container.getProvider('app').getImmediate()!;\n const firestoreInstance = new Firestore(\n new LiteAuthCredentialsProvider(\n container.getProvider('auth-internal')\n ),\n new LiteAppCheckTokenProvider(\n app,\n container.getProvider('app-check-internal')\n ),\n databaseIdFromApp(app, databaseId),\n app\n );\n if (settings) {\n firestoreInstance._setSettings(settings);\n }\n return firestoreInstance;\n },\n 'PUBLIC' as ComponentType.PUBLIC\n ).setMultipleInstances(true)\n );\n // RUNTIME_ENV and BUILD_TARGET are replaced by real values during the compilation\n registerVersion('firestore-lite', version, '__RUNTIME_ENV__');\n registerVersion('firestore-lite', version, '__BUILD_TARGET__');\n}\n","/**\n * Firestore Lite\n *\n * @remarks Firestore Lite is a small online-only SDK that allows read\n * and write access to your Firestore database. All operations connect\n * directly to the backend, and `onSnapshot()` APIs are not supported.\n * @packageDocumentation\n */\n\n/**\n * @license\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { registerFirestore } from './register';\nregisterFirestore();\n\nexport {\n aggregateQuerySnapshotEqual,\n getCount,\n getAggregate,\n count,\n sum,\n average,\n aggregateFieldEqual\n} from '../src/lite-api/aggregate';\n\nexport {\n AggregateField,\n AggregateFieldType,\n AggregateSpec,\n AggregateSpecData,\n AggregateQuerySnapshot,\n AggregateType\n} from '../src/lite-api/aggregate_types';\n\nexport { FirestoreSettings as Settings } from '../src/lite-api/settings';\n\nexport {\n Firestore as Firestore,\n EmulatorMockTokenOptions,\n initializeFirestore,\n getFirestore,\n terminate,\n connectFirestoreEmulator\n} from '../src/lite-api/database';\n\nexport {\n DocumentData,\n UpdateData,\n WithFieldValue,\n PartialWithFieldValue,\n SetOptions,\n DocumentReference,\n Query,\n CollectionReference,\n collection,\n collectionGroup,\n doc,\n refEqual,\n queryEqual\n} from '../src/lite-api/reference';\n\nexport {\n and,\n endAt,\n endBefore,\n startAt,\n startAfter,\n limit,\n limitToLast,\n where,\n or,\n orderBy,\n query,\n QueryConstraint,\n QueryConstraintType,\n QueryCompositeFilterConstraint,\n QueryFilterConstraint,\n QueryFieldFilterConstraint,\n QueryOrderByConstraint,\n QueryLimitConstraint,\n QueryNonFilterConstraint,\n QueryStartAtConstraint,\n QueryEndAtConstraint,\n OrderByDirection,\n WhereFilterOp\n} from '../src/lite-api/query';\n\nexport {\n addDoc,\n deleteDoc,\n updateDoc,\n setDoc,\n getDoc,\n getDocs\n} from '../src/lite-api/reference_impl';\n\nexport {\n Primitive,\n NestedUpdateFields,\n ChildUpdateFields,\n AddPrefixToKeys,\n UnionToIntersection\n} from '../src/lite-api/types';\n\n// TODO(firestorelite): Add tests when Queries are usable\nexport { FieldPath, documentId } from '../src/lite-api/field_path';\n\n// TODO(firestorelite): Add tests when setDoc() is available\nexport { FieldValue } from '../src/lite-api/field_value';\n\nexport {\n increment,\n arrayRemove,\n arrayUnion,\n serverTimestamp,\n deleteField,\n vector\n} from '../src/lite-api/field_value_impl';\n\nexport {\n FirestoreDataConverter,\n DocumentSnapshot,\n QueryDocumentSnapshot,\n QuerySnapshot,\n snapshotEqual\n} from '../src/lite-api/snapshot';\n\nexport { VectorValue } from '../src/lite-api/vector_value';\n\nexport { WriteBatch, writeBatch } from '../src/lite-api/write_batch';\n\nexport { TransactionOptions } from '../src/lite-api/transaction_options';\n\nexport { Transaction, runTransaction } from '../src/lite-api/transaction';\n\nexport { setLogLevel, LogLevelString as LogLevel } from '../src/util/log';\n\nexport { Bytes } from '../src/lite-api/bytes';\n\nexport { GeoPoint } from '../src/lite-api/geo_point';\n\nexport { Timestamp } from '../src/lite-api/timestamp';\n\nexport { FirestoreErrorCode, FirestoreError } from '../src/util/error';\n"],"names":["__PRIVATE_Deferred","constructor","this","promise","Promise","resolve","reject","__PRIVATE_AggregateImpl","alias","aggregateType","fieldPath","__PRIVATE_ExponentialBackoff","__PRIVATE_queue","timerId","__PRIVATE_initialDelayMs","__PRIVATE_backoffFactor","__PRIVATE_maxDelayMs","__PRIVATE_currentBaseMs","__PRIVATE_timerPromise","Date","now","reset","__PRIVATE_resetToMax","__PRIVATE_backoffAndRun","op","cancel","__PRIVATE_desiredDelayWithJitterMs","Math","floor","__PRIVATE_jitterDelayMs","__PRIVATE_delaySoFarMs","max","__PRIVATE_lastAttemptTime","__PRIVATE_remainingDelayMs","__PRIVATE_logDebug","enqueueAfterDelay","__PRIVATE_skipBackoff","skipDelay","random","AggregateField","_internalFieldPath","type","AggregateQuerySnapshot","query","_userDataWriter","_data","data","convertObjectMap","_fieldsProto","ObjectValue","mapValue","fields","clone","value","getCount","getAggregate","count","aggregateSpec","firestore","__PRIVATE_cast","Firestore","datastore","__PRIVATE_getDatastore","__PRIVATE_internalAggregates","__PRIVATE_mapToArray","aggregate","__PRIVATE_invokeRunAggregationQueryRpc","_query","then","__PRIVATE_aggregateResult","__PRIVATE_convertToAggregateQuerySnapshot","userDataWriter","__PRIVATE_LiteUserDataWriter","__PRIVATE_querySnapshot","sum","field","__PRIVATE_fieldPathFromArgument","average","aggregateFieldEqual","left","right","canonicalString","aggregateQuerySnapshotEqual","queryEqual","deepEqual","WriteBatch","_firestore","_commitHandler","_mutations","_committed","_dataReader","__PRIVATE_newUserDataReader","set","documentRef","options","_verifyNotCommitted","ref","__PRIVATE_validateReference","__PRIVATE_convertedValue","__PRIVATE_applyFirestoreDataConverter","converter","__PRIVATE_parsed","__PRIVATE_parseSetData","_key","push","toMutation","Precondition","none","update","__PRIVATE_fieldOrUpdateData","moreFieldsAndValues","getModularInstance","FieldPath","__PRIVATE_parseUpdateVarargs","__PRIVATE_parseUpdateData","exists","concat","__PRIVATE_DeleteMutation","commit","length","FirestoreError","Code","FAILED_PRECONDITION","INVALID_ARGUMENT","writeBatch","writes","__PRIVATE_invokeCommitRpc","Transaction","readVersions","Map","mutations","committed","lastTransactionError","writtenDocs","Set","lookup","keys","ensureCommitNotCalled","docs","__PRIVATE_invokeBatchGetDocumentsRpc","forEach","doc","recordVersion","key","write","precondition","add","toString","preconditionForUpdate","e","__PRIVATE_unwritten","mutation","delete","_","path","DocumentKey","fromPath","__PRIVATE_VerifyMutation","__PRIVATE_docVersion","isFoundDocument","version","isNoDocument","fail","__PRIVATE_documentName","name","SnapshotVersion","min","__PRIVATE_existingVersion","get","isEqual","ABORTED","has","updateTime","__PRIVATE_DEFAULT_TRANSACTION_OPTIONS","maxAttempts","__PRIVATE_TransactionRunner","asyncQueue","updateFunction","deferred","__PRIVATE_attemptsRemaining","__PRIVATE_backoff","__PRIVATE_run","__PRIVATE_runWithBackOff","async","transaction","__PRIVATE_userPromise","__PRIVATE_tryRunUpdateFunction","result","enqueueAndForget","catch","__PRIVATE_commitError","__PRIVATE_handleTransactionError","__PRIVATE_userPromiseError","__PRIVATE_isNullOrUndefined","Error","error","__PRIVATE_isRetryableTransactionError","code","__PRIVATE_isPermanentError","getDocument","document","DelayedOperation","targetTimeMs","removalCallback","bind","err","createAndSchedule","delayMs","__PRIVATE_targetTime","__PRIVATE_delayedOp","start","timerHandle","setTimeout","handleDelayElapsed","reason","clearTimeout","CANCELLED","__PRIVATE_LOG_TAG","__PRIVATE_AsyncQueueImpl","__PRIVATE_tail","__PRIVATE_retryableOps","__PRIVATE__isShuttingDown","__PRIVATE_delayedOperations","__PRIVATE_failure","__PRIVATE_operationInProgress","__PRIVATE_skipNonRestrictedTasks","__PRIVATE_timerIdsToSkip","__PRIVATE_visibilityHandler","visibilityState","addEventListener","isShuttingDown","enqueue","enqueueAndForgetEvenWhileRestricted","__PRIVATE_verifyNotFailed","__PRIVATE_enqueueInternal","enterRestrictedMode","purgeExistingTasks","removeEventListener","task","enqueueRetryable","__PRIVATE_retryNextOp","shift","__PRIVATE_isIndexedDbTransactionError","__PRIVATE_newTail","message","__PRIVATE_getMessageOrStack","__PRIVATE_logError","indexOf","__PRIVATE_removedOp","__PRIVATE_removeDelayedOperation","__PRIVATE_messageOrStack","verifyOperationInProgress","__PRIVATE_drain","__PRIVATE_currentTail","__PRIVATE_containsDelayedOperation","__PRIVATE_runAllDelayedOperationsUntil","__PRIVATE_lastTimerId","sort","a","b","__PRIVATE_skipDelaysForTimerId","index","splice","stack","includes","_transaction","DocumentSnapshot","runTransaction","__PRIVATE_optionsWithDefaults","__PRIVATE_validateTransactionOptions","__PRIVATE_newAsyncQueue","__PRIVATE_internalTransaction","__PRIVATE_registerFirestore","__PRIVATE_setSDKVersion","SDK_VERSION","_registerComponent","Component","container","instanceIdentifier","databaseId","settings","app","getProvider","getImmediate","__PRIVATE_firestoreInstance","__PRIVATE_LiteAuthCredentialsProvider","__PRIVATE_LiteAppCheckTokenProvider","__PRIVATE_databaseIdFromApp","_setSettings","setMultipleInstances","registerVersion"],"mappings":"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"}
geri dön