UNPKG

@firebase/firestore

Version:

The Cloud Firestore component of the Firebase JS SDK.

1,304 lines (1,256 loc) • 975 kB
import { _registerComponent, registerVersion, _isFirebaseServerApp, _getProvider, getApp, _removeServiceInstance, SDK_VERSION } from '@firebase/app'; import { Component } from '@firebase/component'; import { Logger, LogLevel } from '@firebase/logger'; import { FirebaseError, isCloudWorkstation, pingServer, updateEmulatorBanner, deepEqual, createMockUserToken, getModularInstance, getDefaultEmulatorHostnameAndPort, getGlobal, isIndexedDBAvailable, getUA, isSafari, isSafariOrWebkit } from '@firebase/util'; import { Integer, Md5 } from '@firebase/webchannel-wrapper/bloom-blob'; import { XhrIo, EventType, ErrorCode, createWebChannelTransport, getStatEventTarget, WebChannel, Event, Stat } from '@firebase/webchannel-wrapper/webchannel-blob'; const F = "@firebase/firestore", M = "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 x = "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 O = new Logger("@firebase/firestore"); // Helper methods are needed because variables can't be exported as read/write function __PRIVATE_getLogLevel() { return O.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) { O.setLogLevel(e); } function __PRIVATE_logDebug(e, ...t) { if (O.logLevel <= LogLevel.DEBUG) { const n = t.map(__PRIVATE_argToString); O.debug(`Firestore (${x}): ${e}`, ...n); } } function __PRIVATE_logError(e, ...t) { if (O.logLevel <= LogLevel.ERROR) { const n = t.map(__PRIVATE_argToString); O.error(`Firestore (${x}): ${e}`, ...n); } } /** * @internal */ function __PRIVATE_logWarn(e, ...t) { if (O.logLevel <= LogLevel.WARN) { const n = t.map(__PRIVATE_argToString); O.warn(`Firestore (${x}): ${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 (${x}) 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 N = { // 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 FirebaseError { /** @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, _isFirebaseServerApp(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 B = -62135596800, L = 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) * L); 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(N.INVALID_ARGUMENT, "Timestamp nanoseconds out of range: " + t); if (t >= 1e9) throw new FirestoreError(N.INVALID_ARGUMENT, "Timestamp nanoseconds out of range: " + t); if (e < B) throw new FirestoreError(N.INVALID_ARGUMENT, "Timestamp seconds out of range: " + e); // This will break in the year 10,000. if (e >= 253402300800) throw new FirestoreError(N.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 / L; } _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 - B; // 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 k = "__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 Integer.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(N.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 q = /^[_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 q.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) === k; } /** * The field designating the key of a document. */ static keyField() { return new FieldPath$1([ k ]); } /** * 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(N.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(N.INVALID_ARGUMENT, "Path has trailing escape character: " + e); const t = e[r + 1]; if ("\\" !== t && "." !== t && "`" !== t) throw new FirestoreError(N.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(N.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 Q = -1; /** * The initial sequence number for each index. Gets updated during index * backfill. */ /** * An index definition for field indexes in Firestore. * * Every ind