@firebase/firestore
Version:
The Cloud Firestore component of the Firebase JS SDK.
1,303 lines (1,250 loc) • 975 kB
JavaScript
import { _isFirebaseServerApp as e, _getProvider, getApp as t, _removeServiceInstance as n, _registerComponent as r, registerVersion as i, SDK_VERSION as s } from "@firebase/app";
import { Component as o } from "@firebase/component";
import { Logger as _, LogLevel as a } from "@firebase/logger";
import { FirebaseError as u, getGlobal as c, isIndexedDBAvailable as l, getUA as h, base64 as P, DecodeBase64StringError as T, isSafariOrWebkit as I, isSafari as E, isCloudWorkstation as d, pingServer as A, updateEmulatorBanner as R, deepEqual as V, createMockUserToken as m, getModularInstance as f, getDefaultEmulatorHostnameAndPort as g } from "@firebase/util";
import { Integer as p, Md5 as y } from "@firebase/webchannel-wrapper/bloom-blob";
import { XhrIo as w, EventType as S, ErrorCode as b, createWebChannelTransport as D, getStatEventTarget as v, WebChannel as C, Event as F, Stat as M } from "@firebase/webchannel-wrapper/webchannel-blob";
const x = "@firebase/firestore", O = "4.7.16";
/**
* @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.
*/
/**
* Simple wrapper around a nullable UID. Mostly exists to make code more
* readable.
*/
class User {
constructor(e) {
this.uid = e;
}
isAuthenticated() {
return null != this.uid;
}
/**
* Returns a key representing this user, suitable for inclusion in a
* dictionary.
*/ toKey() {
return this.isAuthenticated() ? "uid:" + this.uid : "anonymous-user";
}
isEqual(e) {
return e.uid === this.uid;
}
}
/** A user with a null UID. */ User.UNAUTHENTICATED = new User(null),
// TODO(mikelehen): Look into getting a proper uid-equivalent for
// non-FirebaseAuth providers.
User.GOOGLE_CREDENTIALS = new User("google-credentials-uid"), User.FIRST_PARTY = new User("first-party-uid"),
User.MOCK_USER = new User("mock-user");
/**
* @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.
*/
let N = "11.8.1";
/**
* @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 B = new _("@firebase/firestore");
// Helper methods are needed because variables can't be exported as read/write
function __PRIVATE_getLogLevel() {
return B.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) {
B.setLogLevel(e);
}
function __PRIVATE_logDebug(e, ...t) {
if (B.logLevel <= a.DEBUG) {
const n = t.map(__PRIVATE_argToString);
B.debug(`Firestore (${N}): ${e}`, ...n);
}
}
function __PRIVATE_logError(e, ...t) {
if (B.logLevel <= a.ERROR) {
const n = t.map(__PRIVATE_argToString);
B.error(`Firestore (${N}): ${e}`, ...n);
}
}
/**
* @internal
*/ function __PRIVATE_logWarn(e, ...t) {
if (B.logLevel <= a.WARN) {
const n = t.map(__PRIVATE_argToString);
B.warn(`Firestore (${N}): ${e}`, ...n);
}
}
/**
* Converts an additional log parameter to a string representation.
*/ function __PRIVATE_argToString(e) {
if ("string" == typeof e) return e;
try {
/**
* @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. */
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 fail(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 (${N}) 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 || fail(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 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 L = {
// 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 FirestoreError extends u {
/** @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.
*/ class __PRIVATE_Deferred {
constructor() {
this.promise = new Promise(((e, t) => {
this.resolve = e, this.reject = 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.
*/ class __PRIVATE_OAuthToken {
constructor(e, t) {
this.user = t, this.type = "OAuth", this.headers = new Map, this.headers.set("Authorization", `Bearer ${e}`);
}
}
/**
* A CredentialsProvider that always yields an empty token.
* @internal
*/ class __PRIVATE_EmptyAuthCredentialsProvider {
getToken() {
return Promise.resolve(null);
}
invalidateToken() {}
start(e, t) {
// Fire with initial user.
e.enqueueRetryable((() => t(User.UNAUTHENTICATED)));
}
shutdown() {}
}
/**
* A CredentialsProvider that always returns a constant token. Used for
* emulator token mocking.
*/ class __PRIVATE_EmulatorAuthCredentialsProvider {
constructor(e) {
this.token = e,
/**
* Stores the listener registered with setChangeListener()
* This isn't actually necessary since the UID never changes, but we use this
* to verify the listen contract is adhered to in tests.
*/
this.changeListener = null;
}
getToken() {
return Promise.resolve(this.token);
}
invalidateToken() {}
start(e, t) {
this.changeListener = t,
// Fire with initial user.
e.enqueueRetryable((() => t(this.token.user)));
}
shutdown() {
this.changeListener = null;
}
}
class __PRIVATE_FirebaseAuthCredentialsProvider {
constructor(e) {
this.t = e,
/** Tracks the current User. */
this.currentUser = User.UNAUTHENTICATED,
/**
* Counter used to detect if the token changed while a getToken request was
* outstanding.
*/
this.i = 0, this.forceRefresh = !1, this.auth = null;
}
start(e, t) {
__PRIVATE_hardAssert(void 0 === this.o, 42304);
let n = this.i;
// A change listener that prevents double-firing for the same token change.
const __PRIVATE_guardedChangeListener = e => this.i !== n ? (n = this.i,
t(e)) : Promise.resolve();
// A promise that can be waited on to block on the next token change.
// This promise is re-created after each change.
let r = new __PRIVATE_Deferred;
this.o = () => {
this.i++, this.currentUser = this.u(), r.resolve(), r = new __PRIVATE_Deferred,
e.enqueueRetryable((() => __PRIVATE_guardedChangeListener(this.currentUser)));
};
const __PRIVATE_awaitNextToken = () => {
const t = r;
e.enqueueRetryable((async () => {
await t.promise, await __PRIVATE_guardedChangeListener(this.currentUser);
}));
}, __PRIVATE_registerAuth = e => {
__PRIVATE_logDebug("FirebaseAuthCredentialsProvider", "Auth detected"), this.auth = e,
this.o && (this.auth.addAuthTokenListener(this.o), __PRIVATE_awaitNextToken());
};
this.t.onInit((e => __PRIVATE_registerAuth(e))),
// Our users can initialize Auth right after Firestore, so we give it
// a chance to register itself with the component framework before we
// determine whether to start up in unauthenticated mode.
setTimeout((() => {
if (!this.auth) {
const e = this.t.getImmediate({
optional: !0
});
e ? __PRIVATE_registerAuth(e) : (
// If auth is still not available, proceed with `null` user
__PRIVATE_logDebug("FirebaseAuthCredentialsProvider", "Auth not yet detected"),
r.resolve(), r = new __PRIVATE_Deferred);
}
}), 0), __PRIVATE_awaitNextToken();
}
getToken() {
// Take note of the current value of the tokenCounter so that this method
// can fail (with an ABORTED error) if there is a token change while the
// request is outstanding.
const e = this.i, t = this.forceRefresh;
return this.forceRefresh = !1, this.auth ? this.auth.getToken(t).then((t =>
// Cancel the request since the token changed while the request was
// outstanding so the response is potentially for a previous user (which
// user, we can't be sure).
this.i !== e ? (__PRIVATE_logDebug("FirebaseAuthCredentialsProvider", "getToken aborted due to token change."),
this.getToken()) : t ? (__PRIVATE_hardAssert("string" == typeof t.accessToken, 31837, {
l: t
}), new __PRIVATE_OAuthToken(t.accessToken, this.currentUser)) : null)) : Promise.resolve(null);
}
invalidateToken() {
this.forceRefresh = !0;
}
shutdown() {
this.auth && this.o && this.auth.removeAuthTokenListener(this.o), this.o = void 0;
}
// Auth.getUid() can return null even with a user logged in. It is because
// getUid() is synchronous, but the auth code populating Uid is asynchronous.
// This method should only be called in the AuthTokenListener callback
// to guarantee to get the actual user.
u() {
const e = this.auth && this.auth.getUid();
return __PRIVATE_hardAssert(null === e || "string" == typeof e, 2055, {
h: e
}), new User(e);
}
}
/*
* FirstPartyToken provides a fresh token each time its value
* is requested, because if the token is too old, requests will be rejected.
* Technically this may no longer be necessary since the SDK should gracefully
* recover from unauthenticated errors (see b/33147818 for context), but it's
* safer to keep the implementation as-is.
*/ class __PRIVATE_FirstPartyToken {
constructor(e, t, n) {
this.P = e, this.T = t, this.I = n, this.type = "FirstParty", this.user = User.FIRST_PARTY,
this.A = new Map;
}
/**
* Gets an authorization token, using a provided factory function, or return
* null.
*/ R() {
return this.I ? this.I() : null;
}
get headers() {
this.A.set("X-Goog-AuthUser", this.P);
// Use array notation to prevent minification
const e = this.R();
return e && this.A.set("Authorization", e), this.T && this.A.set("X-Goog-Iam-Authorization-Token", this.T),
this.A;
}
}
/*
* Provides user credentials required for the Firestore JavaScript SDK
* to authenticate the user, using technique that is only available
* to applications hosted by Google.
*/ class __PRIVATE_FirstPartyAuthCredentialsProvider {
constructor(e, t, n) {
this.P = e, this.T = t, this.I = n;
}
getToken() {
return Promise.resolve(new __PRIVATE_FirstPartyToken(this.P, this.T, this.I));
}
start(e, t) {
// Fire with initial uid.
e.enqueueRetryable((() => t(User.FIRST_PARTY)));
}
shutdown() {}
invalidateToken() {}
}
class AppCheckToken {
constructor(e) {
this.value = e, this.type = "AppCheck", this.headers = new Map, e && e.length > 0 && this.headers.set("x-firebase-appcheck", this.value);
}
}
class __PRIVATE_FirebaseAppCheckTokenProvider {
constructor(t, n) {
this.V = n, this.forceRefresh = !1, this.appCheck = null, this.m = null, this.p = null,
e(t) && t.settings.appCheckToken && (this.p = t.settings.appCheckToken);
}
start(e, t) {
__PRIVATE_hardAssert(void 0 === this.o, 3512);
const onTokenChanged = e => {
null != e.error && __PRIVATE_logDebug("FirebaseAppCheckTokenProvider", `Error getting App Check token; using placeholder token instead. Error: ${e.error.message}`);
const n = e.token !== this.m;
return this.m = e.token, __PRIVATE_logDebug("FirebaseAppCheckTokenProvider", `Received ${n ? "new" : "existing"} token.`),
n ? t(e.token) : Promise.resolve();
};
this.o = t => {
e.enqueueRetryable((() => onTokenChanged(t)));
};
const __PRIVATE_registerAppCheck = e => {
__PRIVATE_logDebug("FirebaseAppCheckTokenProvider", "AppCheck detected"), this.appCheck = e,
this.o && this.appCheck.addTokenListener(this.o);
};
this.V.onInit((e => __PRIVATE_registerAppCheck(e))),
// Our users can initialize AppCheck after Firestore, so we give it
// a chance to register itself with the component framework.
setTimeout((() => {
if (!this.appCheck) {
const e = this.V.getImmediate({
optional: !0
});
e ? __PRIVATE_registerAppCheck(e) :
// If AppCheck is still not available, proceed without it.
__PRIVATE_logDebug("FirebaseAppCheckTokenProvider", "AppCheck not yet detected");
}
}), 0);
}
getToken() {
if (this.p) return Promise.resolve(new AppCheckToken(this.p));
const e = this.forceRefresh;
return this.forceRefresh = !1, this.appCheck ? this.appCheck.getToken(e).then((e => e ? (__PRIVATE_hardAssert("string" == typeof e.token, 44558, {
tokenResult: e
}), this.m = e.token, new AppCheckToken(e.token)) : null)) : Promise.resolve(null);
}
invalidateToken() {
this.forceRefresh = !0;
}
shutdown() {
this.appCheck && this.o && this.appCheck.removeTokenListener(this.o), this.o = void 0;
}
}
/**
* An AppCheck token provider that always yields an empty token.
* @internal
*/ class __PRIVATE_EmptyAppCheckTokenProvider {
getToken() {
return Promise.resolve(new AppCheckToken(""));
}
invalidateToken() {}
start(e, t) {}
shutdown() {}
}
/**
* Builds a CredentialsProvider depending on the type of
* the credentials passed in.
*/
/**
* @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 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* An instance of the Platform's 'TextEncoder' implementation.
*/ function __PRIVATE_newTextEncoder() {
return new TextEncoder;
}
/**
* An instance of the Platform's 'TextDecoder' implementation.
*/
/**
* @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) {
let n = 0;
for (;n < e.length && n < t.length; ) {
const r = e.codePointAt(n), i = t.codePointAt(n);
if (r !== i) {
if (r < 128 && i < 128)
// ASCII comparison
return __PRIVATE_primitiveComparator(r, i);
{
// Lazy instantiate TextEncoder
const s = __PRIVATE_newTextEncoder(), o = __PRIVATE_compareByteArrays$1(s.encode(__PRIVATE_getUtf8SafeSubstring(e, n)), s.encode(__PRIVATE_getUtf8SafeSubstring(t, n)));
// UTF-8 encode the character at index i for byte comparison.
return 0 !== o ? o : __PRIVATE_primitiveComparator(r, i);
}
}
// Increment by 2 for surrogate pairs, 1 otherwise
n += r > 65535 ? 2 : 1;
}
// Compare lengths if all characters are equal
return __PRIVATE_primitiveComparator(e.length, t.length);
}
function __PRIVATE_getUtf8SafeSubstring(e, t) {
return e.codePointAt(t) > 65535 ? e.substring(t, t + 2) : e.substring(t, t + 1);
}
function __PRIVATE_compareByteArrays$1(e, t) {
for (let n = 0; n < e.length && n < t.length; ++n) if (e[n] !== t[n]) return __PRIVATE_primitiveComparator(e[n], t[n]);
return __PRIVATE_primitiveComparator(e.length, t.length);
}
/** 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])));
}
/**
* 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.
*/
// The earliest date supported by Firestore timestamps (0001-01-01T00:00:00Z).
const k = -62135596800, q = 1e6;
// Number of nanoseconds in a millisecond.
/**
* A `Timestamp` represents a point in time independent of any time zone or
* calendar, represented as seconds and fractions of seconds at nanosecond
* resolution in UTC Epoch time.
*
* It is encoded using the Proleptic Gregorian Calendar which extends the
* Gregorian calendar backwards to year one. It is encoded assuming all minutes
* are 60 seconds long, i.e. leap seconds are "smeared" so that no leap second
* table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59.999999999Z.
*
* For examples and further specifications, refer to the
* {@link https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto | Timestamp definition}.
*/
class Timestamp {
/**
* Creates a new timestamp with the current date, with millisecond precision.
*
* @returns a new timestamp representing the current date.
*/
static now() {
return Timestamp.fromMillis(Date.now());
}
/**
* Creates a new timestamp from the given date.
*
* @param date - The date to initialize the `Timestamp` from.
* @returns A new `Timestamp` representing the same point in time as the given
* date.
*/ static fromDate(e) {
return Timestamp.fromMillis(e.getTime());
}
/**
* Creates a new timestamp from the given number of milliseconds.
*
* @param milliseconds - Number of milliseconds since Unix epoch
* 1970-01-01T00:00:00Z.
* @returns A new `Timestamp` representing the same point in time as the given
* number of milliseconds.
*/ static fromMillis(e) {
const t = Math.floor(e / 1e3), n = Math.floor((e - 1e3 * t) * q);
return new Timestamp(t, n);
}
/**
* Creates a new timestamp.
*
* @param seconds - The number of seconds of UTC time since Unix epoch
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59Z inclusive.
* @param nanoseconds - The non-negative fractions of a second at nanosecond
* resolution. Negative second values with fractions must still have
* non-negative nanoseconds values that count forward in time. Must be
* from 0 to 999,999,999 inclusive.
*/ constructor(
/**
* The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
*/
e,
/**
* The fractions of a second at nanosecond resolution.*
*/
t) {
if (this.seconds = e, this.nanoseconds = t, t < 0) throw new FirestoreError(L.INVALID_ARGUMENT, "Timestamp nanoseconds out of range: " + t);
if (t >= 1e9) throw new FirestoreError(L.INVALID_ARGUMENT, "Timestamp nanoseconds out of range: " + t);
if (e < k) throw new FirestoreError(L.INVALID_ARGUMENT, "Timestamp seconds out of range: " + e);
// This will break in the year 10,000.
if (e >= 253402300800) throw new FirestoreError(L.INVALID_ARGUMENT, "Timestamp seconds out of range: " + e);
}
/**
* Converts a `Timestamp` to a JavaScript `Date` object. This conversion
* causes a loss of precision since `Date` objects only support millisecond
* precision.
*
* @returns JavaScript `Date` object representing the same point in time as
* this `Timestamp`, with millisecond precision.
*/ toDate() {
return new Date(this.toMillis());
}
/**
* Converts a `Timestamp` to a numeric timestamp (in milliseconds since
* epoch). This operation causes a loss of precision.
*
* @returns The point in time corresponding to this timestamp, represented as
* the number of milliseconds since Unix epoch 1970-01-01T00:00:00Z.
*/ toMillis() {
return 1e3 * this.seconds + this.nanoseconds / q;
}
_compareTo(e) {
return this.seconds === e.seconds ? __PRIVATE_primitiveComparator(this.nanoseconds, e.nanoseconds) : __PRIVATE_primitiveComparator(this.seconds, e.seconds);
}
/**
* Returns true if this `Timestamp` is equal to the provided one.
*
* @param other - The `Timestamp` to compare against.
* @returns true if this `Timestamp` is equal to the provided one.
*/ isEqual(e) {
return e.seconds === this.seconds && e.nanoseconds === this.nanoseconds;
}
/** Returns a textual representation of this `Timestamp`. */ toString() {
return "Timestamp(seconds=" + this.seconds + ", nanoseconds=" + this.nanoseconds + ")";
}
/** Returns a JSON-serializable representation of this `Timestamp`. */ toJSON() {
return {
seconds: this.seconds,
nanoseconds: this.nanoseconds
};
}
/**
* Converts this object to a primitive string, which allows `Timestamp` objects
* to be compared using the `>`, `<=`, `>=` and `>` operators.
*/ valueOf() {
// This method returns a string of the form <seconds>.<nanoseconds> where
// <seconds> is translated to have a non-negative value and both <seconds>
// and <nanoseconds> are left-padded with zeroes to be a consistent length.
// Strings with this format then have a lexicographical ordering that matches
// the expected ordering. The <seconds> translation is done to avoid having
// a leading negative sign (i.e. a leading '-' character) in its string
// representation, which would affect its lexicographical ordering.
const e = this.seconds - k;
// Note: Up to 12 decimal digits are required to represent all valid
// 'seconds' values.
return String(e).padStart(12, "0") + "." + String(this.nanoseconds).padStart(9, "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.
*/
/**
* A version of a document in Firestore. This corresponds to the version
* timestamp, such as update_time or read_time.
*/ class SnapshotVersion {
static fromTimestamp(e) {
return new SnapshotVersion(e);
}
static min() {
return new SnapshotVersion(new Timestamp(0, 0));
}
static max() {
return new SnapshotVersion(new Timestamp(253402300799, 999999999));
}
constructor(e) {
this.timestamp = e;
}
compareTo(e) {
return this.timestamp._compareTo(e.timestamp);
}
isEqual(e) {
return this.timestamp.isEqual(e.timestamp);
}
/** Returns a number representation of the version for use in spec tests. */ toMicroseconds() {
// Convert to microseconds.
return 1e6 * this.timestamp.seconds + this.timestamp.nanoseconds / 1e3;
}
toString() {
return "SnapshotVersion(" + this.timestamp.toString() + ")";
}
toTimestamp() {
return this.timestamp;
}
}
/**
* @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 Q = "__name__";
/**
* Path represents an ordered sequence of string segments.
*/ class BasePath {
constructor(e, t, n) {
void 0 === t ? t = 0 : t > e.length && fail(637, {
offset: t,
range: e.length
}), void 0 === n ? n = e.length - t : n > e.length - t && fail(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 p.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();
}
/**
* 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 FirestoreError(L.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 $ = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
/**
* A dot-separated path for navigating sub-objects within a document.
* @internal
*/ class FieldPath$1 extends BasePath {
construct(e, t, n) {
return new FieldPath$1(e, t, n);
}
/**
* Returns true if the string could be used as a segment in a field path
* without escaping.
*/ static isValidIdentifier(e) {
return $.test(e);
}
canonicalString() {
return this.toArray().map((e => (e = e.replace(/\\/g, "\\\\").replace(/`/g, "\\`"),
FieldPath$1.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) === Q;
}
/**
* The field designating the key of a document.
*/ static keyField() {
return new FieldPath$1([ Q ]);
}
/**
* 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 FirestoreError(L.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 FirestoreError(L.INVALID_ARGUMENT, "Path has trailing escape character: " + e);
const t = e[r + 1];
if ("\\" !== t && "." !== t && "`" !== t) throw new FirestoreError(L.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 FirestoreError(L.INVALID_ARGUMENT, "Unterminated ` in path: " + e);
return new FieldPath$1(t);
}
static emptyPath() {
return new FieldPath$1([]);
}
}
/**
* @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 2021 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 initial mutation batch id for each index. Gets updated during index
* backfill.
*/ const U = -1;
/**
* The initial sequ