@firebase/firestore
Version:
The Cloud Firestore component of the Firebase JS SDK.
1,346 lines (1,296 loc) • 1.14 MB
JavaScript
import { _isFirebaseServerApp as ee, getApp as te, _getProvider, _removeServiceInstance as ne } from "@firebase/app";
import { FirebaseError as re, base64 as ie, DecodeBase64StringError as se, isCloudWorkstation as _e, getGlobal as oe, isIndexedDBAvailable as ae, getUA as ue, pingServer as ce, deepEqual as le, createMockUserToken as Ee, getModularInstance as he, isSafariOrWebkit as Te, isSafari as Pe, getDefaultEmulatorHostnameAndPort as Re } from "@firebase/util";
import { Integer as Ie, Md5 as Ae } from "@firebase/webchannel-wrapper/bloom-blob";
import { Logger as Ve, LogLevel as de } from "@firebase/logger";
import { getStatEventTarget as fe, Event as me, XhrIo as pe, EventType as ge, ErrorCode as ye, WebChannel as we, createWebChannelTransport as be, Stat as ve } from "@firebase/webchannel-wrapper/webchannel-blob";
import { RE2JS as Se } from "re2js";
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** The semver (www.semver.org) version of the SDK. */
let De = "12.17.0";
function __PRIVATE_setSDKVersion(e) {
De = e;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** Formats an object as a JSON string, suitable for logging. */
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const xe = new Ve("@firebase/firestore");
// Helper methods are needed because variables can't be exported as read/write
function __PRIVATE_getLogLevel() {
return xe.logLevel;
}
/**
* Sets the verbosity of Cloud Firestore logs (debug, error, or silent).
*
* @param logLevel - The verbosity you set for activity and error logging. Can
* be any of the following values:
*
* <ul>
* <li>`debug` for the most verbose logging level, primarily for
* debugging.</li>
* <li>`error` to log errors only.</li>
* <li><code>`silent` to turn off logging.</li>
* </ul>
*/ function setLogLevel(e) {
xe.setLogLevel(e);
}
function __PRIVATE_logDebug(e, ...t) {
if (xe.logLevel <= de.DEBUG) {
const n = t.map(__PRIVATE_argToString);
xe.debug(`Firestore (${De}): ${e}`, ...n);
}
}
function __PRIVATE_logError(e, ...t) {
if (xe.logLevel <= de.ERROR) {
const n = t.map(__PRIVATE_argToString);
xe.error(`Firestore (${De}): ${e}`, ...n);
}
}
/**
* @internal
*/ function __PRIVATE_logWarn(e, ...t) {
if (xe.logLevel <= de.WARN) {
const n = t.map(__PRIVATE_argToString);
xe.warn(`Firestore (${De}): ${e}`, ...n);
}
}
/**
* Converts an additional log parameter to a string representation.
*/ function __PRIVATE_argToString(e) {
if ("string" == typeof e) return e;
try {
return function __PRIVATE_formatJSON(e) {
return JSON.stringify(e);
}(e);
} catch (t) {
// Converting to JSON failed, just log the object directly
return e;
}
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ function l(e, t, n) {
let r = "Unexpected state";
"string" == typeof t ? r = t : n = t, __PRIVATE__fail(e, r, n);
}
function __PRIVATE__fail(e, t, n) {
// Log the failure in addition to throw an exception, just in case the
// exception is swallowed.
let r = `FIRESTORE (${De}) INTERNAL ASSERTION FAILED: ${t} (ID: ${e.toString(16)})`;
if (void 0 !== n) try {
r += " CONTEXT: " + JSON.stringify(n);
} catch (e) {
r += " CONTEXT: " + n;
}
// NOTE: We don't use FirestoreError here because these are internal failures
// that cannot be handled by the user. (Also it would create a circular
// dependency between the error and assert modules which doesn't work.)
throw __PRIVATE_logError(r), new Error(r);
}
function __PRIVATE_hardAssert(e, t, n, r) {
let i = "Unexpected state";
"string" == typeof n ? i = n : r = n, e || __PRIVATE__fail(t, i, r);
}
/**
* Fails if the given assertion condition is false, throwing an Error with the
* given message if it did.
*
* The code of callsites invoking this function are stripped out in production
* builds. Any side-effects of code within the debugAssert() invocation will not
* happen in this case.
*
* @internal
*/ function __PRIVATE_debugAssert(e, t) {
e || l(57014, t);
}
/**
* Casts `obj` to `T`. In non-production builds, verifies that `obj` is an
* instance of `T` before casting.
*/ function __PRIVATE_debugCast(e,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
t) {
return e;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Generates `nBytes` of random bytes.
*
* If `nBytes < 0` , an error will be thrown.
*/ function __PRIVATE_randomBytes(e) {
// Polyfills for IE and WebWorker by using `self` and `msCrypto` when `crypto` is not available.
const t =
// eslint-disable-next-line @typescript-eslint/no-explicit-any
"undefined" != typeof self && (self.crypto || self.msCrypto), n = new Uint8Array(e);
if (t && "function" == typeof t.getRandomValues) t.getRandomValues(n); else
// Falls back to Math.random
for (let t = 0; t < e; t++) n[t] = Math.floor(256 * Math.random());
return n;
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A utility class for generating unique alphanumeric IDs of a specified length.
*
* @internal
* Exported internally for testing purposes.
*/ class __PRIVATE_AutoId {
static newId() {
// Alphanumeric characters
const e = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", t = 62 * Math.floor(256 / 62);
// The largest byte value that is a multiple of `char.length`.
let n = "";
for (;n.length < 20; ) {
const r = __PRIVATE_randomBytes(40);
for (let i = 0; i < r.length; ++i)
// Only accept values that are [0, maxMultiple), this ensures they can
// be evenly mapped to indices of `chars` via a modulo operation.
n.length < 20 && r[i] < t && (n += e.charAt(r[i] % 62));
}
return n;
}
}
function __PRIVATE_primitiveComparator(e, t) {
return e < t ? -1 : e > t ? 1 : 0;
}
/** Compare strings in UTF-8 encoded byte order */ function __PRIVATE_compareUtf8Strings(e, t) {
// Find the first differing character (a.k.a. "UTF-16 code unit") in the two strings and,
// if found, use that character to determine the relative ordering of the two strings as a
// whole. Comparing UTF-16 strings in UTF-8 byte order can be done simply and efficiently by
// comparing the UTF-16 code units (chars). This serendipitously works because of the way UTF-8
// and UTF-16 happen to represent Unicode code points.
// After finding the first pair of differing characters, there are two cases:
// Case 1: Both characters are non-surrogates (code points less than or equal to 0xFFFF) or
// both are surrogates from a surrogate pair (that collectively represent code points greater
// than 0xFFFF). In this case their numeric order as UTF-16 code units is the same as the
// lexicographical order of their corresponding UTF-8 byte sequences. A direct comparison is
// sufficient.
// Case 2: One character is a surrogate and the other is not. In this case the surrogate-
// containing string is always ordered after the non-surrogate. This is because surrogates are
// used to represent code points greater than 0xFFFF which have 4-byte UTF-8 representations
// and are lexicographically greater than the 1, 2, or 3-byte representations of code points
// less than or equal to 0xFFFF.
// An example of why Case 2 is required is comparing the following two Unicode code points:
// |-----------------------|------------|---------------------|-----------------|
// | Name | Code Point | UTF-8 Encoding | UTF-16 Encoding |
// |-----------------------|------------|---------------------|-----------------|
// | Replacement Character | U+FFFD | 0xEF 0xBF 0xBD | 0xFFFD |
// | Grinning Face | U+1F600 | 0xF0 0x9F 0x98 0x80 | 0xD83D 0xDE00 |
// |-----------------------|------------|---------------------|-----------------|
// A lexicographical comparison of the UTF-8 encodings of these code points would order
// "Replacement Character" _before_ "Grinning Face" because 0xEF is less than 0xF0. However, a
// direct comparison of the UTF-16 code units, as would be done in case 1, would erroneously
// produce the _opposite_ ordering, because 0xFFFD is _greater than_ 0xD83D. As it turns out,
// this relative ordering holds for all comparisons of UTF-16 code points requiring a surrogate
// pair with those that do not.
const n = Math.min(e.length, t.length);
for (let r = 0; r < n; r++) {
const n = e.charAt(r), i = t.charAt(r);
if (n !== i) return __PRIVATE_isSurrogate(n) === __PRIVATE_isSurrogate(i) ? __PRIVATE_primitiveComparator(n, i) : __PRIVATE_isSurrogate(n) ? 1 : -1;
}
// Use the lengths of the strings to determine the overall comparison result since either the
// strings were equal or one is a prefix of the other.
return __PRIVATE_primitiveComparator(e.length, t.length);
}
const Ce = 55296, Fe = 57343;
function __PRIVATE_isSurrogate(e) {
const t = e.charCodeAt(0);
return t >= Ce && t <= Fe;
}
/** Helper to compare arrays using isEqual(). */ function __PRIVATE_arrayEquals(e, t, n) {
return e.length === t.length && e.every(((e, r) => n(e, t[r])));
}
/**
* Verifies equality for an optional value.
*/ function na(e, t, n) {
return void 0 === e && void 0 === t || void 0 !== e && void 0 !== t && n(e, t);
}
/**
* Returns the immediate lexicographically-following string. This is useful to
* construct an inclusive range for indexeddb iterators.
*/ function __PRIVATE_immediateSuccessor(e) {
// Return the input string, with an additional NUL byte appended.
return e + "\0";
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// An immutable sorted map implementation, based on a Left-leaning Red-Black
// tree.
class SortedMap {
constructor(e, t) {
this.comparator = e, this.root = t || LLRBNode.EMPTY;
}
// Returns a copy of the map, with the specified key/value added or replaced.
insert(e, t) {
return new SortedMap(this.comparator, this.root.insert(e, t, this.comparator).copy(null, null, LLRBNode.BLACK, null, null));
}
// Returns a copy of the map, with the specified key removed.
remove(e) {
return new SortedMap(this.comparator, this.root.remove(e, this.comparator).copy(null, null, LLRBNode.BLACK, null, null));
}
// Returns the value of the node with the given key, or null.
get(e) {
let t = this.root;
for (;!t.isEmpty(); ) {
const n = this.comparator(e, t.key);
if (0 === n) return t.value;
n < 0 ? t = t.left : n > 0 && (t = t.right);
}
return null;
}
// Returns the index of the element in this sorted map, or -1 if it doesn't
// exist.
indexOf(e) {
// Number of nodes that were pruned when descending right
let t = 0, n = this.root;
for (;!n.isEmpty(); ) {
const r = this.comparator(e, n.key);
if (0 === r) return t + n.left.size;
r < 0 ? n = n.left : (
// Count all nodes left of the node plus the node itself
t += n.left.size + 1, n = n.right);
}
// Node not found
return -1;
}
isEmpty() {
return this.root.isEmpty();
}
// Returns the total number of nodes in the map.
get size() {
return this.root.size;
}
// Returns the minimum key in the map.
minKey() {
return this.root.minKey();
}
// Returns the maximum key in the map.
maxKey() {
return this.root.maxKey();
}
// Traverses the map in key order and calls the specified action function
// for each key/value pair. If action returns true, traversal is aborted.
// Returns the first truthy value returned by action, or the last falsey
// value returned by action.
inorderTraversal(e) {
return this.root.inorderTraversal(e);
}
forEach(e) {
this.inorderTraversal(((t, n) => (e(t, n), !1)));
}
toString() {
const e = [];
return this.inorderTraversal(((t, n) => (e.push(`${t}:${n}`), !1))), `{${e.join(", ")}}`;
}
// Traverses the map in reverse key order and calls the specified action
// function for each key/value pair. If action returns true, traversal is
// aborted.
// Returns the first truthy value returned by action, or the last falsey
// value returned by action.
reverseTraversal(e) {
return this.root.reverseTraversal(e);
}
// Returns an iterator over the SortedMap.
getIterator() {
return new SortedMapIterator(this.root, null, this.comparator, !1);
}
getIteratorFrom(e) {
return new SortedMapIterator(this.root, e, this.comparator, !1);
}
getReverseIterator() {
return new SortedMapIterator(this.root, null, this.comparator, !0);
}
getReverseIteratorFrom(e) {
return new SortedMapIterator(this.root, e, this.comparator, !0);
}
}
// end SortedMap
// An iterator over an LLRBNode.
class SortedMapIterator {
constructor(e, t, n, r) {
this.isReverse = r, this.nodeStack = [];
let i = 1;
for (;!e.isEmpty(); ) if (i = t ? n(e.key, t) : 1,
// flip the comparison if we're going in reverse
t && r && (i *= -1), i < 0)
// This node is less than our start key. ignore it
e = this.isReverse ? e.left : e.right; else {
if (0 === i) {
// This node is exactly equal to our start key. Push it on the stack,
// but stop iterating;
this.nodeStack.push(e);
break;
}
// This node is greater than our start key, add it to the stack and move
// to the next one
this.nodeStack.push(e), e = this.isReverse ? e.right : e.left;
}
}
getNext() {
let e = this.nodeStack.pop();
const t = {
key: e.key,
value: e.value
};
if (this.isReverse) for (e = e.left; !e.isEmpty(); ) this.nodeStack.push(e), e = e.right; else for (e = e.right; !e.isEmpty(); ) this.nodeStack.push(e),
e = e.left;
return t;
}
hasNext() {
return this.nodeStack.length > 0;
}
peek() {
if (0 === this.nodeStack.length) return null;
const e = this.nodeStack[this.nodeStack.length - 1];
return {
key: e.key,
value: e.value
};
}
}
// end SortedMapIterator
// Represents a node in a Left-leaning Red-Black tree.
class LLRBNode {
constructor(e, t, n, r, i) {
this.key = e, this.value = t, this.color = null != n ? n : LLRBNode.RED, this.left = null != r ? r : LLRBNode.EMPTY,
this.right = null != i ? i : LLRBNode.EMPTY, this.size = this.left.size + 1 + this.right.size;
}
// Returns a copy of the current node, optionally replacing pieces of it.
copy(e, t, n, r, i) {
return new LLRBNode(null != e ? e : this.key, null != t ? t : this.value, null != n ? n : this.color, null != r ? r : this.left, null != i ? i : this.right);
}
isEmpty() {
return !1;
}
// Traverses the tree in key order and calls the specified action function
// for each node. If action returns true, traversal is aborted.
// Returns the first truthy value returned by action, or the last falsey
// value returned by action.
inorderTraversal(e) {
return this.left.inorderTraversal(e) || e(this.key, this.value) || this.right.inorderTraversal(e);
}
// Traverses the tree in reverse key order and calls the specified action
// function for each node. If action returns true, traversal is aborted.
// Returns the first truthy value returned by action, or the last falsey
// value returned by action.
reverseTraversal(e) {
return this.right.reverseTraversal(e) || e(this.key, this.value) || this.left.reverseTraversal(e);
}
// Returns the minimum node in the tree.
min() {
return this.left.isEmpty() ? this : this.left.min();
}
// Returns the maximum key in the tree.
minKey() {
return this.min().key;
}
// Returns the maximum key in the tree.
maxKey() {
return this.right.isEmpty() ? this.key : this.right.maxKey();
}
// Returns new tree, with the key/value added.
insert(e, t, n) {
let r = this;
const i = n(e, r.key);
return r = i < 0 ? r.copy(null, null, null, r.left.insert(e, t, n), null) : 0 === i ? r.copy(null, t, null, null, null) : r.copy(null, null, null, null, r.right.insert(e, t, n)),
r.fixUp();
}
removeMin() {
if (this.left.isEmpty()) return LLRBNode.EMPTY;
let e = this;
return e.left.isRed() || e.left.left.isRed() || (e = e.moveRedLeft()), e = e.copy(null, null, null, e.left.removeMin(), null),
e.fixUp();
}
// Returns new tree, with the specified item removed.
remove(e, t) {
let n, r = this;
if (t(e, r.key) < 0) r.left.isEmpty() || r.left.isRed() || r.left.left.isRed() || (r = r.moveRedLeft()),
r = r.copy(null, null, null, r.left.remove(e, t), null); else {
if (r.left.isRed() && (r = r.rotateRight()), r.right.isEmpty() || r.right.isRed() || r.right.left.isRed() || (r = r.moveRedRight()),
0 === t(e, r.key)) {
if (r.right.isEmpty()) return LLRBNode.EMPTY;
n = r.right.min(), r = r.copy(n.key, n.value, null, null, r.right.removeMin());
}
r = r.copy(null, null, null, null, r.right.remove(e, t));
}
return r.fixUp();
}
isRed() {
return this.color;
}
// Returns new tree after performing any needed rotations.
fixUp() {
let e = this;
return e.right.isRed() && !e.left.isRed() && (e = e.rotateLeft()), e.left.isRed() && e.left.left.isRed() && (e = e.rotateRight()),
e.left.isRed() && e.right.isRed() && (e = e.colorFlip()), e;
}
moveRedLeft() {
let e = this.colorFlip();
return e.right.left.isRed() && (e = e.copy(null, null, null, null, e.right.rotateRight()),
e = e.rotateLeft(), e = e.colorFlip()), e;
}
moveRedRight() {
let e = this.colorFlip();
return e.left.left.isRed() && (e = e.rotateRight(), e = e.colorFlip()), e;
}
rotateLeft() {
const e = this.copy(null, null, LLRBNode.RED, null, this.right.left);
return this.right.copy(null, null, this.color, e, null);
}
rotateRight() {
const e = this.copy(null, null, LLRBNode.RED, this.left.right, null);
return this.left.copy(null, null, this.color, null, e);
}
colorFlip() {
const e = this.left.copy(null, null, !this.left.color, null, null), t = this.right.copy(null, null, !this.right.color, null, null);
return this.copy(null, null, !this.color, e, t);
}
// For testing.
checkMaxDepth() {
const e = this.check();
return Math.pow(2, e) <= this.size + 1;
}
// In a balanced RB tree, the black-depth (number of black nodes) from root to
// leaves is equal on both sides. This function verifies that or asserts.
check() {
if (this.isRed() && this.left.isRed()) throw l(43730, {
key: this.key,
value: this.value
});
if (this.right.isRed()) throw l(14113, {
key: this.key,
value: this.value
});
const e = this.left.check();
if (e !== this.right.check()) throw l(27949);
return e + (this.isRed() ? 0 : 1);
}
}
// end LLRBNode
// Empty node is shared between all LLRB trees.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LLRBNode.EMPTY = null, LLRBNode.RED = !0, LLRBNode.BLACK = !1;
// end LLRBEmptyNode
LLRBNode.EMPTY = new
// Represents an empty node (a leaf node in the Red-Black Tree).
class LLRBEmptyNode {
constructor() {
this.size = 0;
}
get key() {
throw l(57766);
}
get value() {
throw l(16141);
}
get color() {
throw l(16727);
}
get left() {
throw l(29726);
}
get right() {
throw l(36894);
}
// Returns a copy of the current node.
copy(e, t, n, r, i) {
return this;
}
// Returns a copy of the tree, with the specified key/value added.
insert(e, t, n) {
return new LLRBNode(e, t);
}
// Returns a copy of the tree, with the specified key removed.
remove(e, t) {
return this;
}
isEmpty() {
return !0;
}
inorderTraversal(e) {
return !1;
}
reverseTraversal(e) {
return !1;
}
minKey() {
return null;
}
maxKey() {
return null;
}
isRed() {
return !1;
}
// For testing.
checkMaxDepth() {
return !0;
}
check() {
return 0;
}
};
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* SortedSet is an immutable (copy-on-write) collection that holds elements
* in order specified by the provided comparator.
*
* NOTE: if provided comparator returns 0 for two elements, we consider them to
* be equal!
*/
class SortedSet {
constructor(e) {
this.comparator = e, this.data = new SortedMap(this.comparator);
}
has(e) {
return null !== this.data.get(e);
}
first() {
return this.data.minKey();
}
last() {
return this.data.maxKey();
}
get size() {
return this.data.size;
}
indexOf(e) {
return this.data.indexOf(e);
}
/** Iterates elements in order defined by "comparator" */ forEach(e) {
this.data.inorderTraversal(((t, n) => (e(t), !1)));
}
/** Iterates over `elem`s such that: range[0] <= elem < range[1]. */ forEachInRange(e, t) {
const n = this.data.getIteratorFrom(e[0]);
for (;n.hasNext(); ) {
const r = n.getNext();
if (this.comparator(r.key, e[1]) >= 0) return;
t(r.key);
}
}
/**
* Iterates over `elem`s such that: start <= elem until false is returned.
*/ forEachWhile(e, t) {
let n;
for (n = void 0 !== t ? this.data.getIteratorFrom(t) : this.data.getIterator(); n.hasNext(); ) {
if (!e(n.getNext().key)) return;
}
}
/** Finds the least element greater than or equal to `elem`. */ firstAfterOrEqual(e) {
const t = this.data.getIteratorFrom(e);
return t.hasNext() ? t.getNext().key : null;
}
getIterator() {
return new SortedSetIterator(this.data.getIterator());
}
getIteratorFrom(e) {
return new SortedSetIterator(this.data.getIteratorFrom(e));
}
/** Inserts or updates an element */ add(e) {
return this.copy(this.data.remove(e).insert(e, !0));
}
/** Deletes an element */ delete(e) {
return this.has(e) ? this.copy(this.data.remove(e)) : this;
}
isEmpty() {
return this.data.isEmpty();
}
unionWith(e) {
let t = this;
// Make sure `result` always refers to the larger one of the two sets.
return t.size < e.size && (t = e, e = this), e.forEach((e => {
t = t.add(e);
})), t;
}
isEqual(e) {
if (!(e instanceof SortedSet)) return !1;
if (this.size !== e.size) return !1;
const t = this.data.getIterator(), n = e.data.getIterator();
for (;t.hasNext(); ) {
const e = t.getNext().key, r = n.getNext().key;
if (0 !== this.comparator(e, r)) return !1;
}
return !0;
}
toArray() {
const e = [];
return this.forEach((t => {
e.push(t);
})), e;
}
toString() {
const e = [];
return this.forEach((t => e.push(t))), "SortedSet(" + e.toString() + ")";
}
copy(e) {
const t = new SortedSet(this.comparator);
return t.data = e, t;
}
}
class SortedSetIterator {
constructor(e) {
this.iter = e;
}
getNext() {
return this.iter.getNext().key;
}
hasNext() {
return this.iter.hasNext();
}
}
/**
* Compares two sorted sets for equality using their natural ordering. The
* method computes the intersection and invokes `onAdd` for every element that
* is in `after` but not `before`. `onRemove` is invoked for every element in
* `before` but missing from `after`.
*
* The method creates a copy of both `before` and `after` and runs in O(n log
* n), where n is the size of the two lists.
*
* @param before - The elements that exist in the original set.
* @param after - The elements to diff against the original set.
* @param comparator - The comparator for the elements in before and after.
* @param onAdd - A function to invoke for every element that is part of `
* after` but not `before`.
* @param onRemove - A function to invoke for every element that is part of
* `before` but not `after`.
*/
/**
* Returns the next element from the iterator or `undefined` if none available.
*/
function __PRIVATE_advanceIterator(e) {
return e.hasNext() ? e.getNext() : void 0;
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ const aa = {
// Causes are copied from:
// https://github.com/grpc/grpc/blob/bceec94ea4fc5f0085d81235d8e1c06798dc341a/include/grpc%2B%2B/impl/codegen/status_code_enum.h
/** Not an error; returned on success. */
OK: "ok",
/** The operation was cancelled (typically by the caller). */
CANCELLED: "cancelled",
/** Unknown error or an error from a different error domain. */
UNKNOWN: "unknown",
/**
* Client specified an invalid argument. Note that this differs from
* FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
* problematic regardless of the state of the system (e.g., a malformed file
* name).
*/
INVALID_ARGUMENT: "invalid-argument",
/**
* Deadline expired before operation could complete. For operations that
* change the state of the system, this error may be returned even if the
* operation has completed successfully. For example, a successful response
* from a server could have been delayed long enough for the deadline to
* expire.
*/
DEADLINE_EXCEEDED: "deadline-exceeded",
/** Some requested entity (e.g., file or directory) was not found. */
NOT_FOUND: "not-found",
/**
* Some entity that we attempted to create (e.g., file or directory) already
* exists.
*/
ALREADY_EXISTS: "already-exists",
/**
* The caller does not have permission to execute the specified operation.
* PERMISSION_DENIED must not be used for rejections caused by exhausting
* some resource (use RESOURCE_EXHAUSTED instead for those errors).
* PERMISSION_DENIED must not be used if the caller cannot be identified
* (use UNAUTHENTICATED instead for those errors).
*/
PERMISSION_DENIED: "permission-denied",
/**
* The request does not have valid authentication credentials for the
* operation.
*/
UNAUTHENTICATED: "unauthenticated",
/**
* Some resource has been exhausted, perhaps a per-user quota, or perhaps the
* entire file system is out of space.
*/
RESOURCE_EXHAUSTED: "resource-exhausted",
/**
* Operation was rejected because the system is not in a state required for
* the operation's execution. For example, directory to be deleted may be
* non-empty, an rmdir operation is applied to a non-directory, etc.
*
* A litmus test that may help a service implementor in deciding
* between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
* (a) Use UNAVAILABLE if the client can retry just the failing call.
* (b) Use ABORTED if the client should retry at a higher-level
* (e.g., restarting a read-modify-write sequence).
* (c) Use FAILED_PRECONDITION if the client should not retry until
* the system state has been explicitly fixed. E.g., if an "rmdir"
* fails because the directory is non-empty, FAILED_PRECONDITION
* should be returned since the client should not retry unless
* they have first fixed up the directory by deleting files from it.
* (d) Use FAILED_PRECONDITION if the client performs conditional
* REST Get/Update/Delete on a resource and the resource on the
* server does not match the condition. E.g., conflicting
* read-modify-write on the same resource.
*/
FAILED_PRECONDITION: "failed-precondition",
/**
* The operation was aborted, typically due to a concurrency issue like
* sequencer check failures, transaction aborts, etc.
*
* See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
* and UNAVAILABLE.
*/
ABORTED: "aborted",
/**
* Operation was attempted past the valid range. E.g., seeking or reading
* past end of file.
*
* Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
* if the system state changes. For example, a 32-bit file system will
* generate INVALID_ARGUMENT if asked to read at an offset that is not in the
* range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
* an offset past the current file size.
*
* There is a fair bit of overlap between FAILED_PRECONDITION and
* OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
* when it applies so that callers who are iterating through a space can
* easily look for an OUT_OF_RANGE error to detect when they are done.
*/
OUT_OF_RANGE: "out-of-range",
/** Operation is not implemented or not supported/enabled in this service. */
UNIMPLEMENTED: "unimplemented",
/**
* Internal errors. Means some invariants expected by underlying System has
* been broken. If you see one of these errors, Something is very broken.
*/
INTERNAL: "internal",
/**
* The service is currently unavailable. This is a most likely a transient
* condition and may be corrected by retrying with a backoff.
*
* See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
* and UNAVAILABLE.
*/
UNAVAILABLE: "unavailable",
/** Unrecoverable data loss or corruption. */
DATA_LOSS: "data-loss"
};
/** An error returned by a Firestore operation. */ class s extends re {
/** @hideconstructor */
constructor(
/**
* The backend error code associated with this error.
*/
e,
/**
* A custom error description.
*/
t) {
super(e, t), this.code = e, this.message = t,
// HACK: We write a toString property directly because Error is not a real
// class and so inheritance does not work correctly. We could alternatively
// do the same "back-door inheritance" trick that FirebaseError does.
this.toString = () => `${this.name}: [code=${this.code}]: ${this.message}`;
}
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ const Oe = "__name__";
/**
* Path represents an ordered sequence of string segments.
*/
class BasePath {
constructor(e, t, n) {
void 0 === t ? t = 0 : t > e.length && l(637, {
offset: t,
range: e.length
}), void 0 === n ? n = e.length - t : n > e.length - t && l(1746, {
length: n,
range: e.length - t
}), this.segments = e, this.offset = t, this.len = n;
}
get length() {
return this.len;
}
isEqual(e) {
return 0 === BasePath.comparator(this, e);
}
child(e) {
const t = this.segments.slice(this.offset, this.limit());
return e instanceof BasePath ? e.forEach((e => {
t.push(e);
})) : t.push(e), this.construct(t);
}
/** The index of one past the last segment of the path. */ limit() {
return this.offset + this.length;
}
popFirst(e) {
return e = void 0 === e ? 1 : e, this.construct(this.segments, this.offset + e, this.length - e);
}
popLast() {
return this.construct(this.segments, this.offset, this.length - 1);
}
firstSegment() {
return this.segments[this.offset];
}
lastSegment() {
return this.get(this.length - 1);
}
get(e) {
return this.segments[this.offset + e];
}
isEmpty() {
return 0 === this.length;
}
isPrefixOf(e) {
if (e.length < this.length) return !1;
for (let t = 0; t < this.length; t++) if (this.get(t) !== e.get(t)) return !1;
return !0;
}
isImmediateParentOf(e) {
if (this.length + 1 !== e.length) return !1;
for (let t = 0; t < this.length; t++) if (this.get(t) !== e.get(t)) return !1;
return !0;
}
forEach(e) {
for (let t = this.offset, n = this.limit(); t < n; t++) e(this.segments[t]);
}
toArray() {
return this.segments.slice(this.offset, this.limit());
}
/**
* Compare 2 paths segment by segment, prioritizing numeric IDs
* (e.g., "__id123__") in numeric ascending order, followed by string
* segments in lexicographical order.
*/ static comparator(e, t) {
const n = Math.min(e.length, t.length);
for (let r = 0; r < n; r++) {
const n = BasePath.compareSegments(e.get(r), t.get(r));
if (0 !== n) return n;
}
return __PRIVATE_primitiveComparator(e.length, t.length);
}
static compareSegments(e, t) {
const n = BasePath.isNumericId(e), r = BasePath.isNumericId(t);
return n && !r ? -1 : !n && r ? 1 : n && r ? BasePath.extractNumericId(e).compare(BasePath.extractNumericId(t)) : __PRIVATE_compareUtf8Strings(e, t);
}
// Checks if a segment is a numeric ID (starts with "__id" and ends with "__").
static isNumericId(e) {
return e.startsWith("__id") && e.endsWith("__");
}
static extractNumericId(e) {
return Ie.fromString(e.substring(4, e.length - 2));
}
}
/**
* A slash-separated path for navigating resources (documents and collections)
* within Firestore.
*
* @internal
*/ class ResourcePath extends BasePath {
construct(e, t, n) {
return new ResourcePath(e, t, n);
}
canonicalString() {
// NOTE: The client is ignorant of any path segments containing escape
// sequences (e.g. __id123__) and just passes them through raw (they exist
// for legacy reasons and should not be used frequently).
return this.toArray().join("/");
}
toString() {
return this.canonicalString();
}
toStringWithLeadingSlash() {
return `/${this.canonicalString()}`;
}
/**
* Returns a string representation of this path
* where each path segment has been encoded with
* `encodeURIComponent`.
*/ toUriEncodedString() {
return this.toArray().map(encodeURIComponent).join("/");
}
/**
* Creates a resource path from the given slash-delimited string. If multiple
* arguments are provided, all components are combined. Leading and trailing
* slashes from all components are ignored.
*/ static fromString(...e) {
// NOTE: The client is ignorant of any path segments containing escape
// sequences (e.g. __id123__) and just passes them through raw (they exist
// for legacy reasons and should not be used frequently).
const t = [];
for (const n of e) {
if (n.indexOf("//") >= 0) throw new s(aa.INVALID_ARGUMENT, `Invalid segment (${n}). Paths must not contain // in them.`);
// Strip leading and trailing slashed.
t.push(...n.split("/").filter((e => e.length > 0)));
}
return new ResourcePath(t);
}
static emptyPath() {
return new ResourcePath([]);
}
}
const Me = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
/**
* A dot-separated path for navigating sub-objects within a document.
* @internal
*/ let Ne = class FieldPath extends BasePath {
construct(e, t, n) {
return new FieldPath(e, t, n);
}
/**
* Returns true if the string could be used as a segment in a field path
* without escaping.
*/ static isValidIdentifier(e) {
return Me.test(e);
}
canonicalString() {
return this.toArray().map((e => (e = e.replace(/\\/g, "\\\\").replace(/`/g, "\\`"),
FieldPath.isValidIdentifier(e) || (e = "`" + e + "`"), e))).join(".");
}
toString() {
return this.canonicalString();
}
/**
* Returns true if this field references the key of a document.
*/ isKeyField() {
return 1 === this.length && this.get(0) === Oe;
}
/**
* The field designating the key of a document.
*/ static keyField() {
return new FieldPath([ Oe ]);
}
/**
* Parses a field string from the given server-formatted string.
*
* - Splitting the empty string is not allowed (for now at least).
* - Empty segments within the string (e.g. if there are two consecutive
* separators) are not allowed.
*
* TODO(b/37244157): we should make this more strict. Right now, it allows
* non-identifier path components, even if they aren't escaped.
*/ static fromServerFormat(e) {
const t = [];
let n = "", r = 0;
const __PRIVATE_addCurrentSegment = () => {
if (0 === n.length) throw new s(aa.INVALID_ARGUMENT, `Invalid field path (${e}). Paths must not be empty, begin with '.', end with '.', or contain '..'`);
t.push(n), n = "";
};
let i = !1;
for (;r < e.length; ) {
const t = e[r];
if ("\\" === t) {
if (r + 1 === e.length) throw new s(aa.INVALID_ARGUMENT, "Path has trailing escape character: " + e);
const t = e[r + 1];
if ("\\" !== t && "." !== t && "`" !== t) throw new s(aa.INVALID_ARGUMENT, "Path has invalid escape sequence: " + e);
n += t, r += 2;
} else "`" === t ? (i = !i, r++) : "." !== t || i ? (n += t, r++) : (__PRIVATE_addCurrentSegment(),
r++);
}
if (__PRIVATE_addCurrentSegment(), i) throw new s(aa.INVALID_ARGUMENT, "Unterminated ` in path: " + e);
return new FieldPath(t);
}
static emptyPath() {
return new FieldPath([]);
}
};
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Provides a set of fields that can be used to partially patch a document.
* FieldMask is used in conjunction with ObjectValue.
* Examples:
* foo - Overwrites foo entirely with the provided value. If foo is not
* present in the companion ObjectValue, the field is deleted.
* foo.bar - Overwrites only the field bar of the object foo.
* If foo is not an object, foo is replaced with an object
* containing foo
*/ class FieldMask {
constructor(e) {
this.fields = e,
// TODO(dimond): validation of FieldMask
// Sort the field mask to support `FieldMask.isEqual()` and assert below.
e.sort(Ne.comparator);
}
static empty() {
return new FieldMask([]);
}
/**
* Returns a new FieldMask object that is the result of adding all the given
* fields paths to this field mask.
*/ unionWith(e) {
let t = new SortedSet(Ne.comparator);
for (const e of this.fields) t = t.add(e);
for (const n of e) t = t.add(n);
return new FieldMask(t.toArray());
}
/**
* Verifies that `fieldPath` is included by at least one field in this field
* mask.
*
* This is an O(n) operation, where `n` is the size of the field mask.
*/ covers(e) {
for (const t of this.fields) if (t.isPrefixOf(e)) return !0;
return !1;
}
isEqual(e) {
return __PRIVATE_arrayEquals(this.fields, e.fields, ((e, t) => e.isEqual(t)));
}
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ function __PRIVATE_objectSize(e) {
let t = 0;
for (const n in e) Object.prototype.hasOwnProperty.call(e, n) && t++;
return t;
}
function forEach(e, t) {
for (const n in e) Object.prototype.hasOwnProperty.call(e, n) && t(n, e[n]);
}
function __PRIVATE_mapToArray(e, t) {
const n = [];
for (const r in e) Object.prototype.hasOwnProperty.call(e, r) && n.push(t(e[r], r, e));
return n;
}
function isEmpty(e) {
for (const t in e) if (Object.prototype.hasOwnProperty.call(e, t)) return !1;
return !0;
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @internal
*/ class DocumentKey {
constructor(e) {
this.path = e;
}
static fromPath(e) {
return new DocumentKey(ResourcePath.fromString(e));
}
static fromName(e) {
return new DocumentKey(ResourcePath.fromString(e).popFirst(5));
}
static empty() {
return new DocumentKey(ResourcePath.emptyPath());
}
get collectionGroup() {
return this.path.popLast().lastSegment();
}
/** Returns true if the document is in the specified collectionId. */ hasCollectionId(e) {
return this.path.length >= 2 && this.path.get(this.path.length - 2) === e;
}
/** Returns the collection group (i.e. the name of the parent collection) for this key. */ getCollectionGroup() {
return this.path.get(this.path.length - 2);
}
/** Returns the fully qualified path to the parent collection. */ getCollectionPath() {
return this.path.popLast();
}
isEqual(e) {
return null !== e && 0 === ResourcePath.comparator(this.path, e.path);
}
toString() {
return this.path.toString();
}
static comparator(e, t) {
return ResourcePath.comparator(e.path, t.path);
}
static isDocumentKey(e) {
return e.length % 2 == 0;
}
/**
* Creates and returns a new document key with the given segments.
*
* @param segments - The segments of the path to the document
* @returns A new instance of DocumentKey
*/ static fromSegments(e) {
return new DocumentKey(new ResourcePath(e.slice()));
}
}
/**
* @license
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use