UNPKG

@firebase/firestore

Version:

This is the [Cloud Firestore](https://firebase.google.com/docs/firestore/) component of the [Firebase JS SDK](https://www.npmjs.com/package/firebase).

1,286 lines (1,270 loc) • 1.05 MB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var firebase = _interopDefault(require('@firebase/app')); var tslib = require('tslib'); var logger = require('@firebase/logger'); var util = require('@firebase/util'); var component = require('@firebase/component'); var util$1 = require('util'); var grpc = require('grpc'); var protoLoader = require('@grpc/proto-loader'); var path = require('path'); require('protobufjs'); /** * @license * Copyright 2017 Google Inc. * * 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. */ var SDK_VERSION = firebase.SDK_VERSION; /** * @license * Copyright 2017 Google Inc. * * 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. */ var logClient = new logger.Logger('@firebase/firestore'); var LogLevel; (function (LogLevel) { LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; LogLevel[LogLevel["ERROR"] = 1] = "ERROR"; LogLevel[LogLevel["SILENT"] = 2] = "SILENT"; })(LogLevel || (LogLevel = {})); // Helper methods are needed because variables can't be exported as read/write function getLogLevel() { if (logClient.logLevel === logger.LogLevel.DEBUG) { return LogLevel.DEBUG; } else if (logClient.logLevel === logger.LogLevel.SILENT) { return LogLevel.SILENT; } else { return LogLevel.ERROR; } } function setLogLevel(newLevel) { /** * Map the new log level to the associated Firebase Log Level */ switch (newLevel) { case LogLevel.DEBUG: logClient.logLevel = logger.LogLevel.DEBUG; break; case LogLevel.ERROR: logClient.logLevel = logger.LogLevel.ERROR; break; case LogLevel.SILENT: logClient.logLevel = logger.LogLevel.SILENT; break; default: logClient.error("Firestore (" + SDK_VERSION + "): Invalid value passed to `setLogLevel`"); } } function debug(tag, msg) { var obj = []; for (var _i = 2; _i < arguments.length; _i++) { obj[_i - 2] = arguments[_i]; } if (logClient.logLevel <= logger.LogLevel.DEBUG) { var args = obj.map(argToString); logClient.debug.apply(logClient, tslib.__spreadArrays(["Firestore (" + SDK_VERSION + ") [" + tag + "]: " + msg], args)); } } function error(msg) { var obj = []; for (var _i = 1; _i < arguments.length; _i++) { obj[_i - 1] = arguments[_i]; } if (logClient.logLevel <= logger.LogLevel.ERROR) { var args = obj.map(argToString); logClient.error.apply(logClient, tslib.__spreadArrays(["Firestore (" + SDK_VERSION + "): " + msg], args)); } } /** * Converts an additional log parameter to a string representation. */ function argToString(obj) { if (typeof obj === 'string') { return obj; } else { var platform = PlatformSupport.getPlatform(); try { return platform.formatJSON(obj); } catch (e) { // Converting to JSON failed, just log the object directly return obj; } } } /** * @license * Copyright 2017 Google Inc. * * 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. */ /** * Unconditionally fails, throwing an Error with the given message. * * Returns any so it can be used in expressions: * @example * let futureVar = fail('not implemented yet'); */ function fail(failure) { // Log the failure in addition to throw an exception, just in case the // exception is swallowed. var message = "FIRESTORE (" + SDK_VERSION + ") INTERNAL ASSERTION FAILED: " + failure; error(message); // 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 new Error(message); } /** * Fails if the given assertion condition is false, throwing an Error with the * given message if it did. */ function assert(assertion, message) { if (!assertion) { fail(message); } } /** * @license * Copyright 2017 Google Inc. * * 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 singleton helpers where setup code can inject a platform at runtime. * setPlatform needs to be set before Firestore is used and must be set exactly * once. */ var PlatformSupport = /** @class */ (function () { function PlatformSupport() { } PlatformSupport.setPlatform = function (platform) { if (PlatformSupport.platform) { fail('Platform already defined'); } PlatformSupport.platform = platform; }; PlatformSupport.getPlatform = function () { if (!PlatformSupport.platform) { fail('Platform not set'); } return PlatformSupport.platform; }; return PlatformSupport; }()); /** * Returns the representation of an empty "proto" byte string for the * platform. */ function emptyByteString() { return PlatformSupport.getPlatform().emptyByteString; } /** * @license * Copyright 2017 Google Inc. * * 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. */ var Code = { // 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 can not 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 class used for Firestore-generated errors. Ideally we should be * using FirebaseError, but integrating with it is overly arduous at the moment, * so we define our own compatible error class (with a `name` of 'FirebaseError' * and compatible `code` and `message` fields.) */ var FirestoreError = /** @class */ (function (_super) { tslib.__extends(FirestoreError, _super); function FirestoreError(code, message) { var _this = _super.call(this, message) || this; _this.code = code; _this.message = message; _this.name = 'FirebaseError'; // 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 = function () { return _this.name + ": [code=" + _this.code + "]: " + _this.message; }; return _this; } return FirestoreError; }(Error)); /** * @license * Copyright 2017 Google Inc. * * 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. */ /** * Helper function to prevent instantiation through the constructor. * * This method creates a new constructor that throws when it's invoked. * The prototype of that constructor is then set to the prototype of the hidden * "class" to expose all the prototype methods and allow for instanceof * checks. * * To also make all the static methods available, all properties of the * original constructor are copied to the new constructor. */ function makeConstructorPrivate(cls, optionalMessage) { function PublicConstructor() { var error = 'This constructor is private.'; if (optionalMessage) { error += ' '; error += optionalMessage; } throw new FirestoreError(Code.INVALID_ARGUMENT, error); } // Make sure instanceof checks work and all methods are exposed on the public // constructor PublicConstructor.prototype = cls.prototype; // Copy any static methods/members for (var staticProperty in cls) { if (cls.hasOwnProperty(staticProperty)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any PublicConstructor[staticProperty] = cls[staticProperty]; } } // eslint-disable-next-line @typescript-eslint/no-explicit-any return PublicConstructor; } /** * @license * Copyright 2017 Google Inc. * * 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 contains(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } /** Returns the given value if it's defined or the defaultValue otherwise. */ function defaulted(value, defaultValue) { return value !== undefined ? value : defaultValue; } function forEachNumber(obj, fn) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var num = Number(key); if (!isNaN(num)) { fn(num, obj[key]); } } } } function values(obj) { var vs = []; forEach(obj, function (_, v) { return vs.push(v); }); return vs; } function forEach(obj, fn) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { fn(key, obj[key]); } } } function isEmpty(obj) { assert(obj != null && typeof obj === 'object', 'isEmpty() expects object parameter.'); for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { return false; } } return true; } function shallowCopy(obj) { assert(obj && typeof obj === 'object', 'shallowCopy() expects object parameter.'); var result = {}; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { result[key] = obj[key]; } } return result; } /** * @license * Copyright 2017 Google Inc. * * 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. */ /** * Validates that no arguments were passed in the invocation of functionName. * * Forward the magic "arguments" variable as second parameter on which the * parameter validation is performed: * validateNoArgs('myFunction', arguments); */ function validateNoArgs(functionName, args) { if (args.length !== 0) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() does not support arguments, " + 'but was called with ' + formatPlural(args.length, 'argument') + '.'); } } /** * Validates the invocation of functionName has the exact number of arguments. * * Forward the magic "arguments" variable as second parameter on which the * parameter validation is performed: * validateExactNumberOfArgs('myFunction', arguments, 2); */ function validateExactNumberOfArgs(functionName, args, numberOfArgs) { if (args.length !== numberOfArgs) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires " + formatPlural(numberOfArgs, 'argument') + ', but was called with ' + formatPlural(args.length, 'argument') + '.'); } } /** * Validates the invocation of functionName has at least the provided number of * arguments (but can have many more). * * Forward the magic "arguments" variable as second parameter on which the * parameter validation is performed: * validateAtLeastNumberOfArgs('myFunction', arguments, 2); */ function validateAtLeastNumberOfArgs(functionName, args, minNumberOfArgs) { if (args.length < minNumberOfArgs) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires at least " + formatPlural(minNumberOfArgs, 'argument') + ', but was called with ' + formatPlural(args.length, 'argument') + '.'); } } /** * Validates the invocation of functionName has number of arguments between * the values provided. * * Forward the magic "arguments" variable as second parameter on which the * parameter validation is performed: * validateBetweenNumberOfArgs('myFunction', arguments, 2, 3); */ function validateBetweenNumberOfArgs(functionName, args, minNumberOfArgs, maxNumberOfArgs) { if (args.length < minNumberOfArgs || args.length > maxNumberOfArgs) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires between " + minNumberOfArgs + " and " + (maxNumberOfArgs + " arguments, but was called with ") + formatPlural(args.length, 'argument') + '.'); } } /** * Validates the provided argument is an array and has as least the expected * number of elements. */ function validateNamedArrayAtLeastNumberOfElements(functionName, value, name, minNumberOfElements) { if (!(value instanceof Array) || value.length < minNumberOfElements) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires its " + name + " argument to be an " + 'array with at least ' + (formatPlural(minNumberOfElements, 'element') + ".")); } } /** * Validates the provided positional argument has the native JavaScript type * using typeof checks. */ function validateArgType(functionName, type, position, argument) { validateType(functionName, type, ordinal(position) + " argument", argument); } /** * Validates the provided argument has the native JavaScript type using * typeof checks or is undefined. */ function validateOptionalArgType(functionName, type, position, argument) { if (argument !== undefined) { validateArgType(functionName, type, position, argument); } } /** * Validates the provided named option has the native JavaScript type using * typeof checks. */ function validateNamedType(functionName, type, optionName, argument) { validateType(functionName, type, optionName + " option", argument); } /** * Validates the provided named option has the native JavaScript type using * typeof checks or is undefined. */ function validateNamedOptionalType(functionName, type, optionName, argument) { if (argument !== undefined) { validateNamedType(functionName, type, optionName, argument); } } function validateArrayElements(functionName, optionName, typeDescription, argument, validator) { if (!(argument instanceof Array)) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires its " + optionName + " " + ("option to be an array, but it was: " + valueDescription(argument))); } for (var i = 0; i < argument.length; ++i) { if (!validator(argument[i])) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires all " + optionName + " " + ("elements to be " + typeDescription + ", but the value at index " + i + " ") + ("was: " + valueDescription(argument[i]))); } } } function validateOptionalArrayElements(functionName, optionName, typeDescription, argument, validator) { if (argument !== undefined) { validateArrayElements(functionName, optionName, typeDescription, argument, validator); } } /** * Validates that the provided named option equals one of the expected values. */ function validateNamedPropertyEquals(functionName, inputName, optionName, input, expected) { var expectedDescription = []; for (var _i = 0, expected_1 = expected; _i < expected_1.length; _i++) { var val = expected_1[_i]; if (val === input) { return; } expectedDescription.push(valueDescription(val)); } var actualDescription = valueDescription(input); throw new FirestoreError(Code.INVALID_ARGUMENT, "Invalid value " + actualDescription + " provided to function " + functionName + "() for option " + ("\"" + optionName + "\". Acceptable values: " + expectedDescription.join(', '))); } /** * Validates that the provided named option equals one of the expected values or * is undefined. */ function validateNamedOptionalPropertyEquals(functionName, inputName, optionName, input, expected) { if (input !== undefined) { validateNamedPropertyEquals(functionName, inputName, optionName, input, expected); } } /** * Validates that the provided argument is a valid enum. * * @param functionName Function making the validation call. * @param enums Array containing all possible values for the enum. * @param position Position of the argument in `functionName`. * @param argument Arugment to validate. */ function validateStringEnum(functionName, enums, position, argument) { if (!enums.some(function (element) { return element === argument; })) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Invalid value " + valueDescription(argument) + " provided to function " + (functionName + "() for its " + ordinal(position) + " argument. Acceptable ") + ("values: " + enums.join(', '))); } } /** Helper to validate the type of a provided input. */ function validateType(functionName, type, inputName, input) { var valid = false; if (type === 'object') { valid = isPlainObject(input); } else if (type === 'non-empty string') { valid = typeof input === 'string' && input !== ''; } else { valid = typeof input === type; } if (!valid) { var description = valueDescription(input); throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires its " + inputName + " " + ("to be of type " + type + ", but it was: " + description)); } } /** * Returns true if it's a non-null object without a custom prototype * (i.e. excludes Array, Date, etc.). */ function isPlainObject(input) { return (typeof input === 'object' && input !== null && (Object.getPrototypeOf(input) === Object.prototype || Object.getPrototypeOf(input) === null)); } /** Returns a string describing the type / value of the provided input. */ function valueDescription(input) { if (input === undefined) { return 'undefined'; } else if (input === null) { return 'null'; } else if (typeof input === 'string') { if (input.length > 20) { input = input.substring(0, 20) + "..."; } return JSON.stringify(input); } else if (typeof input === 'number' || typeof input === 'boolean') { return '' + input; } else if (typeof input === 'object') { if (input instanceof Array) { return 'an array'; } else { var customObjectName = tryGetCustomObjectType(input); if (customObjectName) { return "a custom " + customObjectName + " object"; } else { return 'an object'; } } } else if (typeof input === 'function') { return 'a function'; } else { return fail('Unknown wrong type: ' + typeof input); } } /** Hacky method to try to get the constructor name for an object. */ function tryGetCustomObjectType(input) { if (input.constructor) { var funcNameRegex = /function\s+([^\s(]+)\s*\(/; var results = funcNameRegex.exec(input.constructor.toString()); if (results && results.length > 1) { return results[1]; } } return null; } /** Validates the provided argument is defined. */ function validateDefined(functionName, position, argument) { if (argument === undefined) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires a valid " + ordinal(position) + " " + "argument, but it was undefined."); } } /** * Validates the provided positional argument is an object, and its keys and * values match the expected keys and types provided in optionTypes. */ function validateOptionNames(functionName, options, optionNames) { forEach(options, function (key, _) { if (optionNames.indexOf(key) < 0) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Unknown option '" + key + "' passed to function " + functionName + "(). " + 'Available options: ' + optionNames.join(', ')); } }); } /** * Helper method to throw an error that the provided argument did not pass * an instanceof check. */ function invalidClassError(functionName, type, position, argument) { var description = valueDescription(argument); return new FirestoreError(Code.INVALID_ARGUMENT, "Function " + functionName + "() requires its " + ordinal(position) + " " + ("argument to be a " + type + ", but it was: " + description)); } function validatePositiveNumber(functionName, position, n) { if (n <= 0) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Function \"" + functionName + "()\" requires its " + ordinal(position) + " argument to be a positive number, but it was: " + n + "."); } } /** Converts a number to its english word representation */ function ordinal(num) { switch (num) { case 1: return 'first'; case 2: return 'second'; case 3: return 'third'; default: return num + 'th'; } } /** * Formats the given word as plural conditionally given the preceding number. */ function formatPlural(num, str) { return num + " " + str + (num === 1 ? '' : 's'); } /** * @license * Copyright 2017 Google Inc. * * 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. */ var AutoId = /** @class */ (function () { function AutoId() { } AutoId.newId = function () { // Alphanumeric characters var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var autoId = ''; for (var i = 0; i < 20; i++) { autoId += chars.charAt(Math.floor(Math.random() * chars.length)); } assert(autoId.length === 20, 'Invalid auto ID: ' + autoId); return autoId; }; return AutoId; }()); function primitiveComparator(left, right) { if (left < right) { return -1; } if (left > right) { return 1; } return 0; } /** Helper to compare nullable (or undefined-able) objects using isEqual(). */ function equals(left, right) { if (left !== null && left !== undefined) { return !!(right && left.isEqual(right)); } else { // HACK: Explicitly cast since TypeScript's type narrowing apparently isn't // smart enough. return left === right; } } /** Helper to compare arrays using isEqual(). */ function arrayEquals(left, right) { if (left.length !== right.length) { return false; } for (var i = 0; i < left.length; i++) { if (!left[i].isEqual(right[i])) { return false; } } return true; } /** * Returns the immediate lexicographically-following string. This is useful to * construct an inclusive range for indexeddb iterators. */ function immediateSuccessor(s) { // Return the input string, with an additional NUL byte appended. return s + '\0'; } /** * @license * Copyright 2017 Google Inc. * * 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. */ /** Helper function to assert Uint8Array is available at runtime. */ function assertUint8ArrayAvailable() { if (typeof Uint8Array === 'undefined') { throw new FirestoreError(Code.UNIMPLEMENTED, 'Uint8Arrays are not available in this environment.'); } } /** Helper function to assert Base64 functions are available at runtime. */ function assertBase64Available() { if (!PlatformSupport.getPlatform().base64Available) { throw new FirestoreError(Code.UNIMPLEMENTED, 'Blobs are unavailable in Firestore in this environment.'); } } /** * Immutable class holding a blob (binary data). * This class is directly exposed in the public API. * * Note that while you can't hide the constructor in JavaScript code, we are * using the hack above to make sure no-one outside this module can call it. */ var Blob = /** @class */ (function () { function Blob(binaryString) { assertBase64Available(); this._binaryString = binaryString; } Blob.fromBase64String = function (base64) { validateExactNumberOfArgs('Blob.fromBase64String', arguments, 1); validateArgType('Blob.fromBase64String', 'string', 1, base64); assertBase64Available(); try { var binaryString = PlatformSupport.getPlatform().atob(base64); return new Blob(binaryString); } catch (e) { throw new FirestoreError(Code.INVALID_ARGUMENT, 'Failed to construct Blob from Base64 string: ' + e); } }; Blob.fromUint8Array = function (array) { validateExactNumberOfArgs('Blob.fromUint8Array', arguments, 1); assertUint8ArrayAvailable(); if (!(array instanceof Uint8Array)) { throw invalidClassError('Blob.fromUint8Array', 'Uint8Array', 1, array); } // We can't call array.map directly because it expects the return type to // be a Uint8Array, whereas we can convert it to a regular array by invoking // map on the Array prototype. var binaryString = Array.prototype.map .call(array, function (char) { return String.fromCharCode(char); }) .join(''); return new Blob(binaryString); }; Blob.prototype.toBase64 = function () { validateExactNumberOfArgs('Blob.toBase64', arguments, 0); assertBase64Available(); return PlatformSupport.getPlatform().btoa(this._binaryString); }; Blob.prototype.toUint8Array = function () { validateExactNumberOfArgs('Blob.toUint8Array', arguments, 0); assertUint8ArrayAvailable(); var buffer = new Uint8Array(this._binaryString.length); for (var i = 0; i < this._binaryString.length; i++) { buffer[i] = this._binaryString.charCodeAt(i); } return buffer; }; Blob.prototype.toString = function () { return 'Blob(base64: ' + this.toBase64() + ')'; }; Blob.prototype.isEqual = function (other) { return this._binaryString === other._binaryString; }; /** * Actually private to JS consumers of our API, so this function is prefixed * with an underscore. */ Blob.prototype._compareTo = function (other) { return primitiveComparator(this._binaryString, other._binaryString); }; return Blob; }()); // Public instance that disallows construction at runtime. This constructor is // used when exporting Blob on firebase.firestore.Blob and will be called Blob // publicly. Internally we still use Blob which has a type checked private // constructor. Note that Blob and PublicBlob can be used interchangeably in // instanceof checks. // For our internal TypeScript code PublicBlob doesn't exist as a type, and so // we need to use Blob as type and export it too. var PublicBlob = makeConstructorPrivate(Blob, 'Use Blob.fromUint8Array() or Blob.fromBase64String() instead.'); /** * @license * Copyright 2017 Google Inc. * * 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. */ var DatabaseInfo = /** @class */ (function () { /** * Constructs a DatabaseInfo using the provided host, databaseId and * persistenceKey. * * @param databaseId The database to use. * @param persistenceKey A unique identifier for this Firestore's local * storage (used in conjunction with the databaseId). * @param host The Firestore backend host to connect to. * @param ssl Whether to use SSL when connecting. * @param forceLongPolling Whether to use the forceLongPolling option * when using WebChannel as the network transport. */ function DatabaseInfo(databaseId, persistenceKey, host, ssl, forceLongPolling) { this.databaseId = databaseId; this.persistenceKey = persistenceKey; this.host = host; this.ssl = ssl; this.forceLongPolling = forceLongPolling; } return DatabaseInfo; }()); /** The default database name for a project. */ var DEFAULT_DATABASE_NAME = '(default)'; /** Represents the database ID a Firestore client is associated with. */ var DatabaseId = /** @class */ (function () { function DatabaseId(projectId, database) { this.projectId = projectId; this.database = database ? database : DEFAULT_DATABASE_NAME; } Object.defineProperty(DatabaseId.prototype, "isDefaultDatabase", { get: function () { return this.database === DEFAULT_DATABASE_NAME; }, enumerable: true, configurable: true }); DatabaseId.prototype.isEqual = function (other) { return (other instanceof DatabaseId && other.projectId === this.projectId && other.database === this.database); }; DatabaseId.prototype.compareTo = function (other) { return (primitiveComparator(this.projectId, other.projectId) || primitiveComparator(this.database, other.database)); }; return DatabaseId; }()); /** * @license * Copyright 2018 Google Inc. * * 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. */ /** * `ListenSequence` is a monotonic sequence. It is initialized with a minimum value to * exceed. All subsequent calls to next will return increasing values. If provided with a * `SequenceNumberSyncer`, it will additionally bump its next value when told of a new value, as * well as write out sequence numbers that it produces via `next()`. */ var ListenSequence = /** @class */ (function () { function ListenSequence(previousValue, sequenceNumberSyncer) { var _this = this; this.previousValue = previousValue; if (sequenceNumberSyncer) { sequenceNumberSyncer.sequenceNumberHandler = function (sequenceNumber) { return _this.setPreviousValue(sequenceNumber); }; this.writeNewSequenceNumber = function (sequenceNumber) { return sequenceNumberSyncer.writeSequenceNumber(sequenceNumber); }; } } ListenSequence.prototype.setPreviousValue = function (externalPreviousValue) { this.previousValue = Math.max(externalPreviousValue, this.previousValue); return this.previousValue; }; ListenSequence.prototype.next = function () { var nextValue = ++this.previousValue; if (this.writeNewSequenceNumber) { this.writeNewSequenceNumber(nextValue); } return nextValue; }; ListenSequence.INVALID = -1; return ListenSequence; }()); /** * @license * Copyright 2017 Google Inc. * * 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. */ var DOCUMENT_KEY_NAME = '__name__'; /** * Path represents an ordered sequence of string segments. */ var BasePath = /** @class */ (function () { function BasePath(segments, offset, length) { if (offset === undefined) { offset = 0; } else if (offset > segments.length) { fail('offset ' + offset + ' out of range ' + segments.length); } if (length === undefined) { length = segments.length - offset; } else if (length > segments.length - offset) { fail('length ' + length + ' out of range ' + (segments.length - offset)); } this.segments = segments; this.offset = offset; this.len = length; } Object.defineProperty(BasePath.prototype, "length", { get: function () { return this.len; }, enumerable: true, configurable: true }); BasePath.prototype.isEqual = function (other) { return BasePath.comparator(this, other) === 0; }; BasePath.prototype.child = function (nameOrPath) { var segments = this.segments.slice(this.offset, this.limit()); if (nameOrPath instanceof BasePath) { nameOrPath.forEach(function (segment) { segments.push(segment); }); } else { segments.push(nameOrPath); } return this.construct(segments); }; /** The index of one past the last segment of the path. */ BasePath.prototype.limit = function () { return this.offset + this.length; }; BasePath.prototype.popFirst = function (size) { size = size === undefined ? 1 : size; assert(this.length >= size, "Can't call popFirst() with less segments"); return this.construct(this.segments, this.offset + size, this.length - size); }; BasePath.prototype.popLast = function () { assert(!this.isEmpty(), "Can't call popLast() on empty path"); return this.construct(this.segments, this.offset, this.length - 1); }; BasePath.prototype.firstSegment = function () { assert(!this.isEmpty(), "Can't call firstSegment() on empty path"); return this.segments[this.offset]; }; BasePath.prototype.lastSegment = function () { return this.get(this.length - 1); }; BasePath.prototype.get = function (index) { assert(index < this.length, 'Index out of range'); return this.segments[this.offset + index]; }; BasePath.prototype.isEmpty = function () { return this.length === 0; }; BasePath.prototype.isPrefixOf = function (other) { if (other.length < this.length) { return false; } for (var i = 0; i < this.length; i++) { if (this.get(i) !== other.get(i)) { return false; } } return true; }; BasePath.prototype.isImmediateParentOf = function (potentialChild) { if (this.length + 1 !== potentialChild.length) { return false; } for (var i = 0; i < this.length; i++) { if (this.get(i) !== potentialChild.get(i)) { return false; } } return true; }; BasePath.prototype.forEach = function (fn) { for (var i = this.offset, end = this.limit(); i < end; i++) { fn(this.segments[i]); } }; BasePath.prototype.toArray = function () { return this.segments.slice(this.offset, this.limit()); }; BasePath.comparator = function (p1, p2) { var len = Math.min(p1.length, p2.length); for (var i = 0; i < len; i++) { var left = p1.get(i); var right = p2.get(i); if (left < right) { return -1; } if (left > right) { return 1; } } if (p1.length < p2.length) { return -1; } if (p1.length > p2.length) { return 1; } return 0; }; return BasePath; }()); /** * A slash-separated path for navigating resources (documents and collections) * within Firestore. */ var ResourcePath = /** @class */ (function (_super) { tslib.__extends(ResourcePath, _super); function ResourcePath() { return _super !== null && _super.apply(this, arguments) || this; } ResourcePath.prototype.construct = function (segments, offset, length) { return new ResourcePath(segments, offset, length); }; ResourcePath.prototype.canonicalString = function () { // 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('/'); }; ResourcePath.prototype.toString = function () { return this.canonicalString(); }; /** * Creates a resource path from the given slash-delimited string. */ ResourcePath.fromString = function (path) { // 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). if (path.indexOf('//') >= 0) { throw new FirestoreError(Code.INVALID_ARGUMENT, "Invalid path (" + path + "). Paths must not contain // in them."); } // We may still have an empty segment at the beginning or end if they had a // leading or trailing slash (which we allow). var segments = path.split('/').filter(function (segment) { return segment.length > 0; }); return new ResourcePath(segments); }; ResourcePath.EMPTY_PATH = new ResourcePath([]); return ResourcePath; }(BasePath)); var identifierRegExp = /^[_a-zA-Z][_a-zA-Z0-9]*$/; /** A dot-separated path for navigating sub-objects within a document. */ var FieldPath = /** @class */ (function (_super) { tslib.__extends(FieldPath, _super); function FieldPath() { return _super !== null && _super.apply(this, arguments) || this; } FieldPath.prototype.construct = function (segments, offset, length) { return new FieldPath(segments, offset, length); }; /** * Returns true if the string could be used as a segment in a field path * without escaping. */ FieldPath.isValidIdentifier = function (segment) { return identifierRegExp.test(segment); }; FieldPath.prototype.canonicalString = function () { return this.toArray() .map(function (str) { str = str.replace('\\