{"version":3,"file":"firebase-database.js","sources":["../../node_modules/tslib/tslib.es6.js","../util/src/crypt.ts","../util/src/constants.ts","../util/src/assert.ts","../util/src/deepCopy.ts","../util/src/deferred.ts","../util/src/environment.ts","../util/src/errors.ts","../util/src/json.ts","../util/src/jwt.ts","../util/src/obj.ts","../util/src/sha1.ts","../util/src/validation.ts","../util/src/utf8.ts","../logger/src/logger.ts","../component/src/component.ts","../database/src/core/storage/DOMStorageWrapper.ts","../database/src/core/storage/MemoryStorage.ts","../database/src/core/storage/storage.ts","../database/src/core/util/util.ts","../database/src/core/util/Path.ts","../database/src/realtime/Constants.ts","../database/src/core/RepoInfo.ts","../database/src/core/util/libs/parser.ts","../database/src/core/util/validation.ts","../database/src/api/onDisconnect.ts","../database/src/api/TransactionResult.ts","../database/src/core/util/NextPushId.ts","../database/src/core/snap/Node.ts","../database/src/core/snap/indexes/Index.ts","../database/src/core/snap/indexes/KeyIndex.ts","../database/src/core/snap/snap.ts","../database/src/core/snap/LeafNode.ts","../database/src/core/snap/indexes/PriorityIndex.ts","../database/src/core/util/SortedMap.ts","../database/src/core/snap/childSet.ts","../database/src/core/snap/IndexMap.ts","../database/src/core/snap/ChildrenNode.ts","../database/src/core/snap/comparators.ts","../database/src/core/snap/nodeFromJSON.ts","../database/src/core/snap/indexes/ValueIndex.ts","../database/src/core/snap/indexes/PathIndex.ts","../database/src/api/DataSnapshot.ts","../database/src/core/view/Event.ts","../database/src/core/view/EventRegistration.ts","../database/src/api/Query.ts","../database/src/core/SparseSnapshotTree.ts","../database/src/core/util/ServerValues.ts","../database/src/core/operation/Operation.ts","../database/src/core/operation/AckUserWrite.ts","../database/src/core/util/ImmutableTree.ts","../database/src/core/operation/ListenComplete.ts","../database/src/core/operation/Overwrite.ts","../database/src/core/operation/Merge.ts","../database/src/core/view/CacheNode.ts","../database/src/core/view/ViewCache.ts","../database/src/core/view/Change.ts","../database/src/core/view/filter/IndexedFilter.ts","../database/src/core/view/ChildChangeAccumulator.ts","../database/src/core/view/CompleteChildSource.ts","../database/src/core/view/ViewProcessor.ts","../database/src/core/view/EventGenerator.ts","../database/src/core/view/View.ts","../database/src/core/SyncPoint.ts","../database/src/core/CompoundWrite.ts","../database/src/core/WriteTree.ts","../database/src/core/SyncTree.ts","../database/src/core/SnapshotHolder.ts","../database/src/core/AuthTokenProvider.ts","../database/src/core/stats/StatsCollection.ts","../database/src/core/stats/StatsManager.ts","../database/src/core/stats/StatsListener.ts","../database/src/core/stats/StatsReporter.ts","../database/src/core/view/EventQueue.ts","../database/src/core/util/EventEmitter.ts","../database/src/core/util/VisibilityMonitor.ts","../database/src/core/util/OnlineMonitor.ts","../database/src/realtime/polling/PacketReceiver.ts","../database/src/realtime/BrowserPollConnection.ts","../database/src/core/version.ts","../database/src/realtime/WebSocketConnection.ts","../database/src/realtime/TransportManager.ts","../database/src/realtime/Connection.ts","../database/src/core/ServerActions.ts","../database/src/core/PersistentConnection.ts","../database/src/core/ReadonlyRestClient.ts","../util/src/query.ts","../database/src/core/Repo.ts","../database/src/core/view/filter/RangedFilter.ts","../database/src/core/view/filter/LimitedFilter.ts","../database/src/core/view/QueryParams.ts","../database/src/api/Reference.ts","../database/src/core/util/Tree.ts","../database/src/core/Repo_transaction.ts","../database/src/core/RepoManager.ts","../database/src/api/Database.ts","../database/src/api/internal.ts","../database/src/api/test_access.ts","../database/index.ts"],"sourcesContent":["/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation. All rights reserved.\r\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\nthis file except in compliance with the License. You may obtain a copy of the\r\nLicense at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\nMERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\nSee the Apache Version 2.0 License for specific language governing permissions\r\nand limitations under the License.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n};\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, privateMap) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to get private field on non-instance\");\r\n }\r\n return privateMap.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, privateMap, value) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to set private field on non-instance\");\r\n }\r\n privateMap.set(receiver, value);\r\n return value;\r\n}\r\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nconst stringToByteArray = function(str: string): number[] {\n // TODO(user): Use native implementations if/when available\n const out: number[] = [];\n let p = 0;\n for (let i = 0; i < str.length; i++) {\n let c = str.charCodeAt(i);\n if (c < 128) {\n out[p++] = c;\n } else if (c < 2048) {\n out[p++] = (c >> 6) | 192;\n out[p++] = (c & 63) | 128;\n } else if (\n (c & 0xfc00) === 0xd800 &&\n i + 1 < str.length &&\n (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00\n ) {\n // Surrogate Pair\n c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff);\n out[p++] = (c >> 18) | 240;\n out[p++] = ((c >> 12) & 63) | 128;\n out[p++] = ((c >> 6) & 63) | 128;\n out[p++] = (c & 63) | 128;\n } else {\n out[p++] = (c >> 12) | 224;\n out[p++] = ((c >> 6) & 63) | 128;\n out[p++] = (c & 63) | 128;\n }\n }\n return out;\n};\n\n/**\n * Turns an array of numbers into the string given by the concatenation of the\n * characters to which the numbers correspond.\n * @param bytes Array of numbers representing characters.\n * @return Stringification of the array.\n */\nconst byteArrayToString = function(bytes: number[]): string {\n // TODO(user): Use native implementations if/when available\n const out: string[] = [];\n let pos = 0,\n c = 0;\n while (pos < bytes.length) {\n const c1 = bytes[pos++];\n if (c1 < 128) {\n out[c++] = String.fromCharCode(c1);\n } else if (c1 > 191 && c1 < 224) {\n const c2 = bytes[pos++];\n out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));\n } else if (c1 > 239 && c1 < 365) {\n // Surrogate Pair\n const c2 = bytes[pos++];\n const c3 = bytes[pos++];\n const c4 = bytes[pos++];\n const u =\n (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) -\n 0x10000;\n out[c++] = String.fromCharCode(0xd800 + (u >> 10));\n out[c++] = String.fromCharCode(0xdc00 + (u & 1023));\n } else {\n const c2 = bytes[pos++];\n const c3 = bytes[pos++];\n out[c++] = String.fromCharCode(\n ((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)\n );\n }\n }\n return out.join('');\n};\n\ninterface Base64 {\n byteToCharMap_: { [key: number]: string } | null;\n charToByteMap_: { [key: string]: number } | null;\n byteToCharMapWebSafe_: { [key: number]: string } | null;\n charToByteMapWebSafe_: { [key: string]: number } | null;\n ENCODED_VALS_BASE: string;\n readonly ENCODED_VALS: string;\n readonly ENCODED_VALS_WEBSAFE: string;\n HAS_NATIVE_SUPPORT: boolean;\n encodeByteArray(input: number[] | Uint8Array, webSafe?: boolean): string;\n encodeString(input: string, webSafe?: boolean): string;\n decodeString(input: string, webSafe: boolean): string;\n decodeStringToByteArray(input: string, webSafe: boolean): number[];\n init_(): void;\n}\n\n// We define it as an object literal instead of a class because a class compiled down to es5 can't\n// be treeshaked. https://github.com/rollup/rollup/issues/1691\n// Static lookup maps, lazily populated by init_()\nexport const base64: Base64 = {\n /**\n * Maps bytes to characters.\n */\n byteToCharMap_: null,\n\n /**\n * Maps characters to bytes.\n */\n charToByteMap_: null,\n\n /**\n * Maps bytes to websafe characters.\n * @private\n */\n byteToCharMapWebSafe_: null,\n\n /**\n * Maps websafe characters to bytes.\n * @private\n */\n charToByteMapWebSafe_: null,\n\n /**\n * Our default alphabet, shared between\n * ENCODED_VALS and ENCODED_VALS_WEBSAFE\n */\n ENCODED_VALS_BASE:\n 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789',\n\n /**\n * Our default alphabet. Value 64 (=) is special; it means \"nothing.\"\n */\n get ENCODED_VALS() {\n return this.ENCODED_VALS_BASE + '+/=';\n },\n\n /**\n * Our websafe alphabet.\n */\n get ENCODED_VALS_WEBSAFE() {\n return this.ENCODED_VALS_BASE + '-_.';\n },\n\n /**\n * Whether this browser supports the atob and btoa functions. This extension\n * started at Mozilla but is now implemented by many browsers. We use the\n * ASSUME_* variables to avoid pulling in the full useragent detection library\n * but still allowing the standard per-browser compilations.\n *\n */\n HAS_NATIVE_SUPPORT: typeof atob === 'function',\n\n /**\n * Base64-encode an array of bytes.\n *\n * @param input An array of bytes (numbers with\n * value in [0, 255]) to encode.\n * @param webSafe Boolean indicating we should use the\n * alternative alphabet.\n * @return The base64 encoded string.\n */\n encodeByteArray(input: number[] | Uint8Array, webSafe?: boolean): string {\n if (!Array.isArray(input)) {\n throw Error('encodeByteArray takes an array as a parameter');\n }\n\n this.init_();\n\n const byteToCharMap = webSafe\n ? this.byteToCharMapWebSafe_!\n : this.byteToCharMap_!;\n\n const output = [];\n\n for (let i = 0; i < input.length; i += 3) {\n const byte1 = input[i];\n const haveByte2 = i + 1 < input.length;\n const byte2 = haveByte2 ? input[i + 1] : 0;\n const haveByte3 = i + 2 < input.length;\n const byte3 = haveByte3 ? input[i + 2] : 0;\n\n const outByte1 = byte1 >> 2;\n const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);\n let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6);\n let outByte4 = byte3 & 0x3f;\n\n if (!haveByte3) {\n outByte4 = 64;\n\n if (!haveByte2) {\n outByte3 = 64;\n }\n }\n\n output.push(\n byteToCharMap[outByte1],\n byteToCharMap[outByte2],\n byteToCharMap[outByte3],\n byteToCharMap[outByte4]\n );\n }\n\n return output.join('');\n },\n\n /**\n * Base64-encode a string.\n *\n * @param input A string to encode.\n * @param webSafe If true, we should use the\n * alternative alphabet.\n * @return The base64 encoded string.\n */\n encodeString(input: string, webSafe?: boolean): string {\n // Shortcut for Mozilla browsers that implement\n // a native base64 encoder in the form of \"btoa/atob\"\n if (this.HAS_NATIVE_SUPPORT && !webSafe) {\n return btoa(input);\n }\n return this.encodeByteArray(stringToByteArray(input), webSafe);\n },\n\n /**\n * Base64-decode a string.\n *\n * @param input to decode.\n * @param webSafe True if we should use the\n * alternative alphabet.\n * @return string representing the decoded value.\n */\n decodeString(input: string, webSafe: boolean): string {\n // Shortcut for Mozilla browsers that implement\n // a native base64 encoder in the form of \"btoa/atob\"\n if (this.HAS_NATIVE_SUPPORT && !webSafe) {\n return atob(input);\n }\n return byteArrayToString(this.decodeStringToByteArray(input, webSafe));\n },\n\n /**\n * Base64-decode a string.\n *\n * In base-64 decoding, groups of four characters are converted into three\n * bytes. If the encoder did not apply padding, the input length may not\n * be a multiple of 4.\n *\n * In this case, the last group will have fewer than 4 characters, and\n * padding will be inferred. If the group has one or two characters, it decodes\n * to one byte. If the group has three characters, it decodes to two bytes.\n *\n * @param input Input to decode.\n * @param webSafe True if we should use the web-safe alphabet.\n * @return bytes representing the decoded value.\n */\n decodeStringToByteArray(input: string, webSafe: boolean): number[] {\n this.init_();\n\n const charToByteMap = webSafe\n ? this.charToByteMapWebSafe_!\n : this.charToByteMap_!;\n\n const output: number[] = [];\n\n for (let i = 0; i < input.length; ) {\n const byte1 = charToByteMap[input.charAt(i++)];\n\n const haveByte2 = i < input.length;\n const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0;\n ++i;\n\n const haveByte3 = i < input.length;\n const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64;\n ++i;\n\n const haveByte4 = i < input.length;\n const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64;\n ++i;\n\n if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) {\n throw Error();\n }\n\n const outByte1 = (byte1 << 2) | (byte2 >> 4);\n output.push(outByte1);\n\n if (byte3 !== 64) {\n const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2);\n output.push(outByte2);\n\n if (byte4 !== 64) {\n const outByte3 = ((byte3 << 6) & 0xc0) | byte4;\n output.push(outByte3);\n }\n }\n }\n\n return output;\n },\n\n /**\n * Lazy static initialization function. Called before\n * accessing any of the static map variables.\n * @private\n */\n init_() {\n if (!this.byteToCharMap_) {\n this.byteToCharMap_ = {};\n this.charToByteMap_ = {};\n this.byteToCharMapWebSafe_ = {};\n this.charToByteMapWebSafe_ = {};\n\n // We want quick mappings back and forth, so we precompute two maps.\n for (let i = 0; i < this.ENCODED_VALS.length; i++) {\n this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i);\n this.charToByteMap_[this.byteToCharMap_[i]] = i;\n this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i);\n this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i;\n\n // Be forgiving when decoding and correctly decode both encodings.\n if (i >= this.ENCODED_VALS_BASE.length) {\n this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i;\n this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i;\n }\n }\n }\n }\n};\n\n/**\n * URL-safe base64 encoding\n */\nexport const base64Encode = function(str: string): string {\n const utf8Bytes = stringToByteArray(str);\n return base64.encodeByteArray(utf8Bytes, true);\n};\n\n/**\n * URL-safe base64 decoding\n *\n * NOTE: DO NOT use the global atob() function - it does NOT support the\n * base64Url variant encoding.\n *\n * @param str To be decoded\n * @return Decoded result, if possible\n */\nexport const base64Decode = function(str: string): string | null {\n try {\n return base64.decodeString(str, true);\n } catch (e) {\n console.error('base64Decode failed: ', e);\n }\n return null;\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Firebase constants. Some of these (@defines) can be overridden at compile-time.\n */\n\nexport const CONSTANTS = {\n /**\n * @define {boolean} Whether this is the client Node.js SDK.\n */\n NODE_CLIENT: false,\n /**\n * @define {boolean} Whether this is the Admin Node.js SDK.\n */\n NODE_ADMIN: false,\n\n /**\n * Firebase SDK Version\n */\n SDK_VERSION: '${JSCORE_VERSION}'\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CONSTANTS } from './constants';\n\n/**\n * Throws an error if the provided assertion is falsy\n */\nexport const assert = function(assertion: unknown, message: string): void {\n if (!assertion) {\n throw assertionError(message);\n }\n};\n\n/**\n * Returns an Error object suitable for throwing.\n */\nexport const assertionError = function(message: string): Error {\n return new Error(\n 'Firebase Database (' +\n CONSTANTS.SDK_VERSION +\n ') INTERNAL ASSERT FAILED: ' +\n message\n );\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Do a deep-copy of basic JavaScript Objects or Arrays.\n */\nexport function deepCopy(value: T): T {\n return deepExtend(undefined, value) as T;\n}\n\n/**\n * Copy properties from source to target (recursively allows extension\n * of Objects and Arrays). Scalar values in the target are over-written.\n * If target is undefined, an object of the appropriate type will be created\n * (and returned).\n *\n * We recursively copy all child properties of plain Objects in the source- so\n * that namespace- like dictionaries are merged.\n *\n * Note that the target can be a function, in which case the properties in\n * the source Object are copied onto it as static properties of the Function.\n */\nexport function deepExtend(target: unknown, source: unknown): unknown {\n if (!(source instanceof Object)) {\n return source;\n }\n\n switch (source.constructor) {\n case Date:\n // Treat Dates like scalars; if the target date object had any child\n // properties - they will be lost!\n const dateValue = source as Date;\n return new Date(dateValue.getTime());\n\n case Object:\n if (target === undefined) {\n target = {};\n }\n break;\n case Array:\n // Always copy the array source and overwrite the target.\n target = [];\n break;\n\n default:\n // Not a plain Object - treat it as a scalar.\n return source;\n }\n\n for (const prop in source) {\n if (!source.hasOwnProperty(prop)) {\n continue;\n }\n (target as { [key: string]: unknown })[prop] = deepExtend(\n (target as { [key: string]: unknown })[prop],\n (source as { [key: string]: unknown })[prop]\n );\n }\n\n return target;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport class Deferred {\n promise: Promise;\n reject: (value?: unknown) => void = () => {};\n resolve: (value?: unknown) => void = () => {};\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve as (value?: unknown) => void;\n this.reject = reject as (value?: unknown) => void;\n });\n }\n\n /**\n * Our API internals are not promiseified and cannot because our callback APIs have subtle expectations around\n * invoking promises inline, which Promises are forbidden to do. This method accepts an optional node-style callback\n * and returns a node-style callback which will resolve or reject the Deferred's promise.\n */\n wrapCallback(\n callback?: (error?: unknown, value?: unknown) => void\n ): (error: unknown, value?: unknown) => void {\n return (error, value?) => {\n if (error) {\n this.reject(error);\n } else {\n this.resolve(value);\n }\n if (typeof callback === 'function') {\n // Attaching noop handler just in case developer wasn't expecting\n // promises\n this.promise.catch(() => {});\n\n // Some of our callbacks don't expect a value and our own tests\n // assert that the parameter length is 1\n if (callback.length === 1) {\n callback(error);\n } else {\n callback(error, value);\n }\n }\n };\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CONSTANTS } from './constants';\n\n/**\n * Returns navigator.userAgent string or '' if it's not defined.\n * @return user agent string\n */\nexport function getUA(): string {\n if (\n typeof navigator !== 'undefined' &&\n typeof navigator['userAgent'] === 'string'\n ) {\n return navigator['userAgent'];\n } else {\n return '';\n }\n}\n\n/**\n * Detect Cordova / PhoneGap / Ionic frameworks on a mobile device.\n *\n * Deliberately does not rely on checking `file://` URLs (as this fails PhoneGap\n * in the Ripple emulator) nor Cordova `onDeviceReady`, which would normally\n * wait for a callback.\n */\nexport function isMobileCordova(): boolean {\n return (\n typeof window !== 'undefined' &&\n // @ts-ignore Setting up an broadly applicable index signature for Window\n // just to deal with this case would probably be a bad idea.\n !!(window['cordova'] || window['phonegap'] || window['PhoneGap']) &&\n /ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test(getUA())\n );\n}\n\n/**\n * Detect Node.js.\n *\n * @return true if Node.js environment is detected.\n */\n// Node detection logic from: https://github.com/iliakan/detect-node/\nexport function isNode(): boolean {\n try {\n return (\n Object.prototype.toString.call(global.process) === '[object process]'\n );\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Detect Browser Environment\n */\nexport function isBrowser(): boolean {\n return typeof self === 'object' && self.self === self;\n}\n\n/**\n * Detect browser extensions (Chrome and Firefox at least).\n */\ninterface BrowserRuntime {\n id?: unknown;\n}\ndeclare const chrome: { runtime?: BrowserRuntime };\ndeclare const browser: { runtime?: BrowserRuntime };\nexport function isBrowserExtension(): boolean {\n const runtime =\n typeof chrome === 'object'\n ? chrome.runtime\n : typeof browser === 'object'\n ? browser.runtime\n : undefined;\n return typeof runtime === 'object' && runtime.id !== undefined;\n}\n\n/**\n * Detect React Native.\n *\n * @return true if ReactNative environment is detected.\n */\nexport function isReactNative(): boolean {\n return (\n typeof navigator === 'object' && navigator['product'] === 'ReactNative'\n );\n}\n\n/** Detects Electron apps. */\nexport function isElectron(): boolean {\n return getUA().indexOf('Electron/') >= 0;\n}\n\n/** Detects Internet Explorer. */\nexport function isIE(): boolean {\n const ua = getUA();\n return ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0;\n}\n\n/** Detects Universal Windows Platform apps. */\nexport function isUWP(): boolean {\n return getUA().indexOf('MSAppHost/') >= 0;\n}\n\n/**\n * Detect whether the current SDK build is the Node version.\n *\n * @return true if it's the Node SDK build.\n */\nexport function isNodeSdk(): boolean {\n return CONSTANTS.NODE_CLIENT === true || CONSTANTS.NODE_ADMIN === true;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n/**\n * @fileoverview Standardized Firebase Error.\n *\n * Usage:\n *\n * // Typescript string literals for type-safe codes\n * type Err =\n * 'unknown' |\n * 'object-not-found'\n * ;\n *\n * // Closure enum for type-safe error codes\n * // at-enum {string}\n * var Err = {\n * UNKNOWN: 'unknown',\n * OBJECT_NOT_FOUND: 'object-not-found',\n * }\n *\n * let errors: Map = {\n * 'generic-error': \"Unknown error\",\n * 'file-not-found': \"Could not find file: {$file}\",\n * };\n *\n * // Type-safe function - must pass a valid error code as param.\n * let error = new ErrorFactory('service', 'Service', errors);\n *\n * ...\n * throw error.create(Err.GENERIC);\n * ...\n * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName});\n * ...\n * // Service: Could not file file: foo.txt (service/file-not-found).\n *\n * catch (e) {\n * assert(e.message === \"Could not find file: foo.txt.\");\n * if (e.code === 'service/file-not-found') {\n * console.log(\"Could not read file: \" + e['file']);\n * }\n * }\n */\n\nexport type ErrorMap = {\n readonly [K in ErrorCode]: string;\n};\n\nconst ERROR_NAME = 'FirebaseError';\n\nexport interface StringLike {\n toString(): string;\n}\n\nexport interface ErrorData {\n [key: string]: StringLike | undefined;\n}\n\nexport interface FirebaseError extends Error, ErrorData {\n // Unique code for error - format is service/error-code-string.\n readonly code: string;\n\n // Developer-friendly error message.\n readonly message: string;\n\n // Always 'FirebaseError'.\n readonly name: typeof ERROR_NAME;\n\n // Where available - stack backtrace in a string.\n readonly stack?: string;\n}\n\n// Based on code from:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types\nexport class FirebaseError extends Error {\n readonly name = ERROR_NAME;\n\n constructor(readonly code: string, message: string) {\n super(message);\n\n // Fix For ES5\n // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, FirebaseError.prototype);\n\n // Maintains proper stack trace for where our error was thrown.\n // Only available on V8.\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ErrorFactory.prototype.create);\n }\n }\n}\n\nexport class ErrorFactory<\n ErrorCode extends string,\n ErrorParams extends { readonly [K in ErrorCode]?: ErrorData } = {}\n> {\n constructor(\n private readonly service: string,\n private readonly serviceName: string,\n private readonly errors: ErrorMap\n ) {}\n\n create(\n code: K,\n ...data: K extends keyof ErrorParams ? [ErrorParams[K]] : []\n ): FirebaseError {\n const customData = (data[0] as ErrorData) || {};\n const fullCode = `${this.service}/${code}`;\n const template = this.errors[code];\n\n const message = template ? replaceTemplate(template, customData) : 'Error';\n // Service Name: Error message (service/code).\n const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`;\n\n const error = new FirebaseError(fullCode, fullMessage);\n\n // Keys with an underscore at the end of their name are not included in\n // error.data for some reason.\n // TODO: Replace with Object.entries when lib is updated to es2017.\n for (const key of Object.keys(customData)) {\n if (key.slice(-1) !== '_') {\n if (key in error) {\n console.warn(\n `Overwriting FirebaseError base field \"${key}\" can cause unexpected behavior.`\n );\n }\n error[key] = customData[key];\n }\n }\n\n return error;\n }\n}\n\nfunction replaceTemplate(template: string, data: ErrorData): string {\n return template.replace(PATTERN, (_, key) => {\n const value = data[key];\n return value != null ? value.toString() : `<${key}?>`;\n });\n}\n\nconst PATTERN = /\\{\\$([^}]+)}/g;\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Evaluates a JSON string into a javascript object.\n *\n * @param {string} str A string containing JSON.\n * @return {*} The javascript object representing the specified JSON.\n */\nexport function jsonEval(str: string): unknown {\n return JSON.parse(str);\n}\n\n/**\n * Returns JSON representing a javascript object.\n * @param {*} data Javascript object to be stringified.\n * @return {string} The JSON contents of the object.\n */\nexport function stringify(data: unknown): string {\n return JSON.stringify(data);\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { base64Decode } from './crypt';\nimport { jsonEval } from './json';\n\ninterface Claims {\n [key: string]: {};\n}\n\ninterface DecodedToken {\n header: object;\n claims: Claims;\n data: object;\n signature: string;\n}\n\n/**\n * Decodes a Firebase auth. token into constituent parts.\n *\n * Notes:\n * - May return with invalid / incomplete claims if there's no native base64 decoding support.\n * - Doesn't check if the token is actually valid.\n */\nexport const decode = function(token: string): DecodedToken {\n let header = {},\n claims: Claims = {},\n data = {},\n signature = '';\n\n try {\n const parts = token.split('.');\n header = jsonEval(base64Decode(parts[0]) || '') as object;\n claims = jsonEval(base64Decode(parts[1]) || '') as Claims;\n signature = parts[2];\n data = claims['d'] || {};\n delete claims['d'];\n } catch (e) {}\n\n return {\n header,\n claims,\n data,\n signature\n };\n};\n\ninterface DecodedToken {\n header: object;\n claims: Claims;\n data: object;\n signature: string;\n}\n\n/**\n * Decodes a Firebase auth. token and checks the validity of its time-based claims. Will return true if the\n * token is within the time window authorized by the 'nbf' (not-before) and 'iat' (issued-at) claims.\n *\n * Notes:\n * - May return a false negative if there's no native base64 decoding support.\n * - Doesn't check if the token is actually valid.\n */\nexport const isValidTimestamp = function(token: string): boolean {\n const claims: Claims = decode(token).claims;\n const now: number = Math.floor(new Date().getTime() / 1000);\n let validSince: number = 0,\n validUntil: number = 0;\n\n if (typeof claims === 'object') {\n if (claims.hasOwnProperty('nbf')) {\n validSince = claims['nbf'] as number;\n } else if (claims.hasOwnProperty('iat')) {\n validSince = claims['iat'] as number;\n }\n\n if (claims.hasOwnProperty('exp')) {\n validUntil = claims['exp'] as number;\n } else {\n // token will expire after 24h by default\n validUntil = validSince + 86400;\n }\n }\n\n return (\n !!now &&\n !!validSince &&\n !!validUntil &&\n now >= validSince &&\n now <= validUntil\n );\n};\n\n/**\n * Decodes a Firebase auth. token and returns its issued at time if valid, null otherwise.\n *\n * Notes:\n * - May return null if there's no native base64 decoding support.\n * - Doesn't check if the token is actually valid.\n */\nexport const issuedAtTime = function(token: string): number | null {\n const claims: Claims = decode(token).claims;\n if (typeof claims === 'object' && claims.hasOwnProperty('iat')) {\n return claims['iat'] as number;\n }\n return null;\n};\n\n/**\n * Decodes a Firebase auth. token and checks the validity of its format. Expects a valid issued-at time.\n *\n * Notes:\n * - May return a false negative if there's no native base64 decoding support.\n * - Doesn't check if the token is actually valid.\n */\nexport const isValidFormat = function(token: string): boolean {\n const decoded = decode(token),\n claims = decoded.claims;\n\n return !!claims && typeof claims === 'object' && claims.hasOwnProperty('iat');\n};\n\n/**\n * Attempts to peer into an auth token and determine if it's an admin auth token by looking at the claims portion.\n *\n * Notes:\n * - May return a false negative if there's no native base64 decoding support.\n * - Doesn't check if the token is actually valid.\n */\nexport const isAdmin = function(token: string): boolean {\n const claims: Claims = decode(token).claims;\n return typeof claims === 'object' && claims['admin'] === true;\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport function contains(obj: T, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function safeGet(\n obj: T,\n key: K\n): T[K] | undefined {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n return obj[key];\n } else {\n return undefined;\n }\n}\n\nexport function isEmpty(obj: object): obj is {} {\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n return false;\n }\n }\n return true;\n}\n\nexport function map(\n obj: { [key in K]: V },\n fn: (value: V, key: K, obj: { [key in K]: V }) => U,\n contextObj?: unknown\n): { [key in K]: U } {\n const res: Partial<{ [key in K]: U }> = {};\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n res[key] = fn.call(contextObj, obj[key], key, obj);\n }\n }\n return res as { [key in K]: U };\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview SHA-1 cryptographic hash.\n * Variable names follow the notation in FIPS PUB 180-3:\n * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.\n *\n * Usage:\n * var sha1 = new sha1();\n * sha1.update(bytes);\n * var hash = sha1.digest();\n *\n * Performance:\n * Chrome 23: ~400 Mbit/s\n * Firefox 16: ~250 Mbit/s\n *\n */\n\n/**\n * SHA-1 cryptographic hash constructor.\n *\n * The properties declared here are discussed in the above algorithm document.\n * @constructor\n * @final\n * @struct\n */\nexport class Sha1 {\n /**\n * Holds the previous values of accumulated variables a-e in the compress_\n * function.\n * @private\n */\n private chain_: number[] = [];\n\n /**\n * A buffer holding the partially computed hash result.\n * @private\n */\n private buf_: number[] = [];\n\n /**\n * An array of 80 bytes, each a part of the message to be hashed. Referred to\n * as the message schedule in the docs.\n * @private\n */\n private W_: number[] = [];\n\n /**\n * Contains data needed to pad messages less than 64 bytes.\n * @private\n */\n private pad_: number[] = [];\n\n /**\n * @private {number}\n */\n private inbuf_: number = 0;\n\n /**\n * @private {number}\n */\n private total_: number = 0;\n\n blockSize: number;\n\n constructor() {\n this.blockSize = 512 / 8;\n\n this.pad_[0] = 128;\n for (let i = 1; i < this.blockSize; ++i) {\n this.pad_[i] = 0;\n }\n\n this.reset();\n }\n\n reset(): void {\n this.chain_[0] = 0x67452301;\n this.chain_[1] = 0xefcdab89;\n this.chain_[2] = 0x98badcfe;\n this.chain_[3] = 0x10325476;\n this.chain_[4] = 0xc3d2e1f0;\n\n this.inbuf_ = 0;\n this.total_ = 0;\n }\n\n /**\n * Internal compress helper function.\n * @param buf Block to compress.\n * @param offset Offset of the block in the buffer.\n * @private\n */\n compress_(buf: number[] | Uint8Array | string, offset?: number): void {\n if (!offset) {\n offset = 0;\n }\n\n const W = this.W_;\n\n // get 16 big endian words\n if (typeof buf === 'string') {\n for (let i = 0; i < 16; i++) {\n // TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS\n // have a bug that turns the post-increment ++ operator into pre-increment\n // during JIT compilation. We have code that depends heavily on SHA-1 for\n // correctness and which is affected by this bug, so I've removed all uses\n // of post-increment ++ in which the result value is used. We can revert\n // this change once the Safari bug\n // (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and\n // most clients have been updated.\n W[i] =\n (buf.charCodeAt(offset) << 24) |\n (buf.charCodeAt(offset + 1) << 16) |\n (buf.charCodeAt(offset + 2) << 8) |\n buf.charCodeAt(offset + 3);\n offset += 4;\n }\n } else {\n for (let i = 0; i < 16; i++) {\n W[i] =\n (buf[offset] << 24) |\n (buf[offset + 1] << 16) |\n (buf[offset + 2] << 8) |\n buf[offset + 3];\n offset += 4;\n }\n }\n\n // expand to 80 words\n for (let i = 16; i < 80; i++) {\n const t = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];\n W[i] = ((t << 1) | (t >>> 31)) & 0xffffffff;\n }\n\n let a = this.chain_[0];\n let b = this.chain_[1];\n let c = this.chain_[2];\n let d = this.chain_[3];\n let e = this.chain_[4];\n let f, k;\n\n // TODO(user): Try to unroll this loop to speed up the computation.\n for (let i = 0; i < 80; i++) {\n if (i < 40) {\n if (i < 20) {\n f = d ^ (b & (c ^ d));\n k = 0x5a827999;\n } else {\n f = b ^ c ^ d;\n k = 0x6ed9eba1;\n }\n } else {\n if (i < 60) {\n f = (b & c) | (d & (b | c));\n k = 0x8f1bbcdc;\n } else {\n f = b ^ c ^ d;\n k = 0xca62c1d6;\n }\n }\n\n const t = (((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff;\n e = d;\n d = c;\n c = ((b << 30) | (b >>> 2)) & 0xffffffff;\n b = a;\n a = t;\n }\n\n this.chain_[0] = (this.chain_[0] + a) & 0xffffffff;\n this.chain_[1] = (this.chain_[1] + b) & 0xffffffff;\n this.chain_[2] = (this.chain_[2] + c) & 0xffffffff;\n this.chain_[3] = (this.chain_[3] + d) & 0xffffffff;\n this.chain_[4] = (this.chain_[4] + e) & 0xffffffff;\n }\n\n update(bytes?: number[] | Uint8Array | string, length?: number): void {\n // TODO(johnlenz): tighten the function signature and remove this check\n if (bytes == null) {\n return;\n }\n\n if (length === undefined) {\n length = bytes.length;\n }\n\n const lengthMinusBlock = length - this.blockSize;\n let n = 0;\n // Using local instead of member variables gives ~5% speedup on Firefox 16.\n const buf = this.buf_;\n let inbuf = this.inbuf_;\n\n // The outer while loop should execute at most twice.\n while (n < length) {\n // When we have no data in the block to top up, we can directly process the\n // input buffer (assuming it contains sufficient data). This gives ~25%\n // speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that\n // the data is provided in large chunks (or in multiples of 64 bytes).\n if (inbuf === 0) {\n while (n <= lengthMinusBlock) {\n this.compress_(bytes, n);\n n += this.blockSize;\n }\n }\n\n if (typeof bytes === 'string') {\n while (n < length) {\n buf[inbuf] = bytes.charCodeAt(n);\n ++inbuf;\n ++n;\n if (inbuf === this.blockSize) {\n this.compress_(buf);\n inbuf = 0;\n // Jump to the outer loop so we use the full-block optimization.\n break;\n }\n }\n } else {\n while (n < length) {\n buf[inbuf] = bytes[n];\n ++inbuf;\n ++n;\n if (inbuf === this.blockSize) {\n this.compress_(buf);\n inbuf = 0;\n // Jump to the outer loop so we use the full-block optimization.\n break;\n }\n }\n }\n }\n\n this.inbuf_ = inbuf;\n this.total_ += length;\n }\n\n /** @override */\n digest(): number[] {\n const digest: number[] = [];\n let totalBits = this.total_ * 8;\n\n // Add pad 0x80 0x00*.\n if (this.inbuf_ < 56) {\n this.update(this.pad_, 56 - this.inbuf_);\n } else {\n this.update(this.pad_, this.blockSize - (this.inbuf_ - 56));\n }\n\n // Add # bits.\n for (let i = this.blockSize - 1; i >= 56; i--) {\n this.buf_[i] = totalBits & 255;\n totalBits /= 256; // Don't use bit-shifting here!\n }\n\n this.compress_(this.buf_);\n\n let n = 0;\n for (let i = 0; i < 5; i++) {\n for (let j = 24; j >= 0; j -= 8) {\n digest[n] = (this.chain_[i] >> j) & 255;\n ++n;\n }\n }\n return digest;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Check to make sure the appropriate number of arguments are provided for a public function.\n * Throws an error if it fails.\n *\n * @param fnName The function name\n * @param minCount The minimum number of arguments to allow for the function call\n * @param maxCount The maximum number of argument to allow for the function call\n * @param argCount The actual number of arguments provided.\n */\nexport const validateArgCount = function(\n fnName: string,\n minCount: number,\n maxCount: number,\n argCount: number\n): void {\n let argError;\n if (argCount < minCount) {\n argError = 'at least ' + minCount;\n } else if (argCount > maxCount) {\n argError = maxCount === 0 ? 'none' : 'no more than ' + maxCount;\n }\n if (argError) {\n const error =\n fnName +\n ' failed: Was called with ' +\n argCount +\n (argCount === 1 ? ' argument.' : ' arguments.') +\n ' Expects ' +\n argError +\n '.';\n throw new Error(error);\n }\n};\n\n/**\n * Generates a string to prefix an error message about failed argument validation\n *\n * @param fnName The function name\n * @param argumentNumber The index of the argument\n * @param optional Whether or not the argument is optional\n * @return The prefix to add to the error thrown for validation.\n */\nexport function errorPrefix(\n fnName: string,\n argumentNumber: number,\n optional: boolean\n): string {\n let argName = '';\n switch (argumentNumber) {\n case 1:\n argName = optional ? 'first' : 'First';\n break;\n case 2:\n argName = optional ? 'second' : 'Second';\n break;\n case 3:\n argName = optional ? 'third' : 'Third';\n break;\n case 4:\n argName = optional ? 'fourth' : 'Fourth';\n break;\n default:\n throw new Error(\n 'errorPrefix called with argumentNumber > 4. Need to update it?'\n );\n }\n\n let error = fnName + ' failed: ';\n\n error += argName + ' argument ';\n return error;\n}\n\n/**\n * @param fnName\n * @param argumentNumber\n * @param namespace\n * @param optional\n */\nexport function validateNamespace(\n fnName: string,\n argumentNumber: number,\n namespace: string,\n optional: boolean\n): void {\n if (optional && !namespace) {\n return;\n }\n if (typeof namespace !== 'string') {\n //TODO: I should do more validation here. We only allow certain chars in namespaces.\n throw new Error(\n errorPrefix(fnName, argumentNumber, optional) +\n 'must be a valid firebase namespace.'\n );\n }\n}\n\nexport function validateCallback(\n fnName: string,\n argumentNumber: number,\n callback: Function,\n optional: boolean\n): void {\n if (optional && !callback) {\n return;\n }\n if (typeof callback !== 'function') {\n throw new Error(\n errorPrefix(fnName, argumentNumber, optional) +\n 'must be a valid function.'\n );\n }\n}\n\nexport function validateContextObject(\n fnName: string,\n argumentNumber: number,\n context: unknown,\n optional: boolean\n): void {\n if (optional && !context) {\n return;\n }\n if (typeof context !== 'object' || context === null) {\n throw new Error(\n errorPrefix(fnName, argumentNumber, optional) +\n 'must be a valid context object.'\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from './assert';\n\n// Code originally came from goog.crypt.stringToUtf8ByteArray, but for some reason they\n// automatically replaced '\\r\\n' with '\\n', and they didn't handle surrogate pairs,\n// so it's been modified.\n\n// Note that not all Unicode characters appear as single characters in JavaScript strings.\n// fromCharCode returns the UTF-16 encoding of a character - so some Unicode characters\n// use 2 characters in Javascript. All 4-byte UTF-8 characters begin with a first\n// character in the range 0xD800 - 0xDBFF (the first character of a so-called surrogate\n// pair).\n// See http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3\n\n/**\n * @param {string} str\n * @return {Array}\n */\nexport const stringToByteArray = function(str: string): number[] {\n const out: number[] = [];\n let p = 0;\n for (let i = 0; i < str.length; i++) {\n let c = str.charCodeAt(i);\n\n // Is this the lead surrogate in a surrogate pair?\n if (c >= 0xd800 && c <= 0xdbff) {\n const high = c - 0xd800; // the high 10 bits.\n i++;\n assert(i < str.length, 'Surrogate pair missing trail surrogate.');\n const low = str.charCodeAt(i) - 0xdc00; // the low 10 bits.\n c = 0x10000 + (high << 10) + low;\n }\n\n if (c < 128) {\n out[p++] = c;\n } else if (c < 2048) {\n out[p++] = (c >> 6) | 192;\n out[p++] = (c & 63) | 128;\n } else if (c < 65536) {\n out[p++] = (c >> 12) | 224;\n out[p++] = ((c >> 6) & 63) | 128;\n out[p++] = (c & 63) | 128;\n } else {\n out[p++] = (c >> 18) | 240;\n out[p++] = ((c >> 12) & 63) | 128;\n out[p++] = ((c >> 6) & 63) | 128;\n out[p++] = (c & 63) | 128;\n }\n }\n return out;\n};\n\n/**\n * Calculate length without actually converting; useful for doing cheaper validation.\n * @param {string} str\n * @return {number}\n */\nexport const stringLength = function(str: string): number {\n let p = 0;\n for (let i = 0; i < str.length; i++) {\n const c = str.charCodeAt(i);\n if (c < 128) {\n p++;\n } else if (c < 2048) {\n p += 2;\n } else if (c >= 0xd800 && c <= 0xdbff) {\n // Lead surrogate of a surrogate pair. The pair together will take 4 bytes to represent.\n p += 4;\n i++; // skip trail surrogate.\n } else {\n p += 3;\n }\n }\n return p;\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A container for all of the Logger instances\n */\nexport const instances: Logger[] = [];\n\n/**\n * The JS SDK supports 5 log levels and also allows a user the ability to\n * silence the logs altogether.\n *\n * The order is a follows:\n * DEBUG < VERBOSE < INFO < WARN < ERROR\n *\n * All of the log types above the current log level will be captured (i.e. if\n * you set the log level to `INFO`, errors will still be logged, but `DEBUG` and\n * `VERBOSE` logs will not)\n */\nexport enum LogLevel {\n DEBUG,\n VERBOSE,\n INFO,\n WARN,\n ERROR,\n SILENT\n}\n\n/**\n * The default log level\n */\nconst defaultLogLevel: LogLevel = LogLevel.INFO;\n\n/**\n * We allow users the ability to pass their own log handler. We will pass the\n * type of log, the current log level, and any other arguments passed (i.e. the\n * messages that the user wants to log) to this function.\n */\nexport type LogHandler = (\n loggerInstance: Logger,\n logType: LogLevel,\n ...args: unknown[]\n) => void;\n\n/**\n * The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR\n * messages on to their corresponding console counterparts (if the log method\n * is supported by the current log level)\n */\nconst defaultLogHandler: LogHandler = (instance, logType, ...args): void => {\n if (logType < instance.logLevel) {\n return;\n }\n const now = new Date().toISOString();\n switch (logType) {\n /**\n * By default, `console.debug` is not displayed in the developer console (in\n * chrome). To avoid forcing users to have to opt-in to these logs twice\n * (i.e. once for firebase, and once in the console), we are sending `DEBUG`\n * logs to the `console.log` function.\n */\n case LogLevel.DEBUG:\n console.log(`[${now}] ${instance.name}:`, ...args);\n break;\n case LogLevel.VERBOSE:\n console.log(`[${now}] ${instance.name}:`, ...args);\n break;\n case LogLevel.INFO:\n console.info(`[${now}] ${instance.name}:`, ...args);\n break;\n case LogLevel.WARN:\n console.warn(`[${now}] ${instance.name}:`, ...args);\n break;\n case LogLevel.ERROR:\n console.error(`[${now}] ${instance.name}:`, ...args);\n break;\n default:\n throw new Error(\n `Attempted to log a message with an invalid logType (value: ${logType})`\n );\n }\n};\n\nexport class Logger {\n /**\n * Gives you an instance of a Logger to capture messages according to\n * Firebase's logging scheme.\n *\n * @param name The name that the logs will be associated with\n */\n constructor(public name: string) {\n /**\n * Capture the current instance for later use\n */\n instances.push(this);\n }\n\n /**\n * The log level of the given Logger instance.\n */\n private _logLevel = defaultLogLevel;\n get logLevel(): LogLevel {\n return this._logLevel;\n }\n set logLevel(val: LogLevel) {\n if (!(val in LogLevel)) {\n throw new TypeError('Invalid value assigned to `logLevel`');\n }\n this._logLevel = val;\n }\n\n /**\n * The log handler for the Logger instance.\n */\n private _logHandler: LogHandler = defaultLogHandler;\n get logHandler(): LogHandler {\n return this._logHandler;\n }\n set logHandler(val: LogHandler) {\n if (typeof val !== 'function') {\n throw new TypeError('Value assigned to `logHandler` must be a function');\n }\n this._logHandler = val;\n }\n\n /**\n * The functions below are all based on the `console` interface\n */\n\n debug(...args: unknown[]): void {\n this._logHandler(this, LogLevel.DEBUG, ...args);\n }\n log(...args: unknown[]): void {\n this._logHandler(this, LogLevel.VERBOSE, ...args);\n }\n info(...args: unknown[]): void {\n this._logHandler(this, LogLevel.INFO, ...args);\n }\n warn(...args: unknown[]): void {\n this._logHandler(this, LogLevel.WARN, ...args);\n }\n error(...args: unknown[]): void {\n this._logHandler(this, LogLevel.ERROR, ...args);\n }\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n InstantiationMode,\n InstanceFactory,\n ComponentType,\n Dictionary,\n Name\n} from './types';\n\n/**\n * Component for service name T, e.g. `auth`, `auth-internal`\n */\nexport class Component {\n multipleInstances = false;\n /**\n * Properties to be added to the service namespace\n */\n serviceProps: Dictionary = {};\n\n instantiationMode = InstantiationMode.LAZY;\n\n /**\n *\n * @param name The public service name, e.g. app, auth, firestore, database\n * @param instanceFactory Service factory responsible for creating the public interface\n * @param type whether the service provided by the component is public or private\n */\n constructor(\n readonly name: T,\n readonly instanceFactory: InstanceFactory,\n readonly type: ComponentType\n ) {}\n\n setInstantiationMode(mode: InstantiationMode): this {\n this.instantiationMode = mode;\n return this;\n }\n\n setMultipleInstances(multipleInstances: boolean): this {\n this.multipleInstances = multipleInstances;\n return this;\n }\n\n setServiceProps(props: Dictionary): this {\n this.serviceProps = props;\n return this;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { jsonEval, stringify } from '@firebase/util';\n\n/**\n * Wraps a DOM Storage object and:\n * - automatically encode objects as JSON strings before storing them to allow us to store arbitrary types.\n * - prefixes names with \"firebase:\" to avoid collisions with app data.\n *\n * We automatically (see storage.js) create two such wrappers, one for sessionStorage,\n * and one for localStorage.\n *\n * @constructor\n */\nexport class DOMStorageWrapper {\n // Use a prefix to avoid collisions with other stuff saved by the app.\n private prefix_ = 'firebase:';\n\n /**\n * @param {Storage} domStorage_ The underlying storage object (e.g. localStorage or sessionStorage)\n */\n constructor(private domStorage_: Storage) {}\n\n /**\n * @param {string} key The key to save the value under\n * @param {?Object} value The value being stored, or null to remove the key.\n */\n set(key: string, value: unknown | null) {\n if (value == null) {\n this.domStorage_.removeItem(this.prefixedName_(key));\n } else {\n this.domStorage_.setItem(this.prefixedName_(key), stringify(value));\n }\n }\n\n /**\n * @param {string} key\n * @return {*} The value that was stored under this key, or null\n */\n get(key: string): unknown {\n const storedVal = this.domStorage_.getItem(this.prefixedName_(key));\n if (storedVal == null) {\n return null;\n } else {\n return jsonEval(storedVal);\n }\n }\n\n /**\n * @param {string} key\n */\n remove(key: string) {\n this.domStorage_.removeItem(this.prefixedName_(key));\n }\n\n isInMemoryStorage: boolean;\n\n /**\n * @param {string} name\n * @return {string}\n */\n prefixedName_(name: string): string {\n return this.prefix_ + name;\n }\n\n toString(): string {\n return this.domStorage_.toString();\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { contains } from '@firebase/util';\n\n/**\n * An in-memory storage implementation that matches the API of DOMStorageWrapper\n * (TODO: create interface for both to implement).\n *\n * @constructor\n */\nexport class MemoryStorage {\n private cache_: { [k: string]: unknown } = {};\n\n set(key: string, value: unknown | null) {\n if (value == null) {\n delete this.cache_[key];\n } else {\n this.cache_[key] = value;\n }\n }\n\n get(key: string): unknown {\n if (contains(this.cache_, key)) {\n return this.cache_[key];\n }\n return null;\n }\n\n remove(key: string) {\n delete this.cache_[key];\n }\n\n isInMemoryStorage = true;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DOMStorageWrapper } from './DOMStorageWrapper';\nimport { MemoryStorage } from './MemoryStorage';\n\ndeclare const window: Window;\n\n/**\n * Helper to create a DOMStorageWrapper or else fall back to MemoryStorage.\n * TODO: Once MemoryStorage and DOMStorageWrapper have a shared interface this method annotation should change\n * to reflect this type\n *\n * @param {string} domStorageName Name of the underlying storage object\n * (e.g. 'localStorage' or 'sessionStorage').\n * @return {?} Turning off type information until a common interface is defined.\n */\nconst createStoragefor = function(\n domStorageName: string\n): DOMStorageWrapper | MemoryStorage {\n try {\n // NOTE: just accessing \"localStorage\" or \"window['localStorage']\" may throw a security exception,\n // so it must be inside the try/catch.\n if (\n typeof window !== 'undefined' &&\n typeof window[domStorageName] !== 'undefined'\n ) {\n // Need to test cache. Just because it's here doesn't mean it works\n const domStorage = window[domStorageName];\n domStorage.setItem('firebase:sentinel', 'cache');\n domStorage.removeItem('firebase:sentinel');\n return new DOMStorageWrapper(domStorage);\n }\n } catch (e) {}\n\n // Failed to create wrapper. Just return in-memory storage.\n // TODO: log?\n return new MemoryStorage();\n};\n\n/** A storage object that lasts across sessions */\nexport const PersistentStorage = createStoragefor('localStorage');\n\n/** A storage object that only lasts one session */\nexport const SessionStorage = createStoragefor('sessionStorage');\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Query } from '../../api/Query';\nimport {\n assert,\n base64,\n Sha1,\n stringToByteArray,\n stringify,\n isNodeSdk\n} from '@firebase/util';\nimport { SessionStorage } from '../storage/storage';\nimport { Logger, LogLevel } from '@firebase/logger';\n\ndeclare const window: Window;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ndeclare const Windows: any;\n\nconst logClient = new Logger('@firebase/database');\n\n/**\n * Returns a locally-unique ID (generated by just incrementing up from 0 each time its called).\n * @type {function(): number} Generated ID.\n */\nexport const LUIDGenerator: () => number = (function() {\n let id = 1;\n return function() {\n return id++;\n };\n})();\n\n/**\n * Sha1 hash of the input string\n * @param {!string} str The string to hash\n * @return {!string} The resulting hash\n */\nexport const sha1 = function(str: string): string {\n const utf8Bytes = stringToByteArray(str);\n const sha1 = new Sha1();\n sha1.update(utf8Bytes);\n const sha1Bytes = sha1.digest();\n return base64.encodeByteArray(sha1Bytes);\n};\n\n/**\n * @param {...*} varArgs\n * @return {string}\n * @private\n */\nconst buildLogMessage_ = function(...varArgs: unknown[]): string {\n let message = '';\n for (let i = 0; i < varArgs.length; i++) {\n const arg = varArgs[i];\n if (\n Array.isArray(arg) ||\n (arg &&\n typeof arg === 'object' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (arg as any).length === 'number')\n ) {\n message += buildLogMessage_.apply(null, arg);\n } else if (typeof arg === 'object') {\n message += stringify(arg);\n } else {\n message += arg;\n }\n message += ' ';\n }\n\n return message;\n};\n\n/**\n * Use this for all debug messages in Firebase.\n * @type {?function(string)}\n */\nexport let logger: ((a: string) => void) | null = null;\n\n/**\n * Flag to check for log availability on first log message\n * @type {boolean}\n * @private\n */\nlet firstLog_ = true;\n\n/**\n * The implementation of Firebase.enableLogging (defined here to break dependencies)\n * @param {boolean|?function(string)} logger_ A flag to turn on logging, or a custom logger\n * @param {boolean=} persistent Whether or not to persist logging settings across refreshes\n */\nexport const enableLogging = function(\n logger_?: boolean | ((a: string) => void) | null,\n persistent?: boolean\n) {\n assert(\n !persistent || logger_ === true || logger_ === false,\n \"Can't turn on custom loggers persistently.\"\n );\n if (logger_ === true) {\n logClient.logLevel = LogLevel.VERBOSE;\n logger = logClient.log.bind(logClient);\n if (persistent) {\n SessionStorage.set('logging_enabled', true);\n }\n } else if (typeof logger_ === 'function') {\n logger = logger_;\n } else {\n logger = null;\n SessionStorage.remove('logging_enabled');\n }\n};\n\n/**\n *\n * @param {...(string|Arguments)} varArgs\n */\nexport const log = function(...varArgs: unknown[]) {\n if (firstLog_ === true) {\n firstLog_ = false;\n if (logger === null && SessionStorage.get('logging_enabled') === true) {\n enableLogging(true);\n }\n }\n\n if (logger) {\n const message = buildLogMessage_.apply(null, varArgs);\n logger(message);\n }\n};\n\n/**\n * @param {!string} prefix\n * @return {function(...[*])}\n */\nexport const logWrapper = function(\n prefix: string\n): (...varArgs: unknown[]) => void {\n return function(...varArgs: unknown[]) {\n log(prefix, ...varArgs);\n };\n};\n\n/**\n * @param {...string} varArgs\n */\nexport const error = function(...varArgs: string[]) {\n const message = 'FIREBASE INTERNAL ERROR: ' + buildLogMessage_(...varArgs);\n logClient.error(message);\n};\n\n/**\n * @param {...string} varArgs\n */\nexport const fatal = function(...varArgs: string[]) {\n const message = `FIREBASE FATAL ERROR: ${buildLogMessage_(...varArgs)}`;\n logClient.error(message);\n throw new Error(message);\n};\n\n/**\n * @param {...*} varArgs\n */\nexport const warn = function(...varArgs: unknown[]) {\n const message = 'FIREBASE WARNING: ' + buildLogMessage_(...varArgs);\n logClient.warn(message);\n};\n\n/**\n * Logs a warning if the containing page uses https. Called when a call to new Firebase\n * does not use https.\n */\nexport const warnIfPageIsSecure = function() {\n // Be very careful accessing browser globals. Who knows what may or may not exist.\n if (\n typeof window !== 'undefined' &&\n window.location &&\n window.location.protocol &&\n window.location.protocol.indexOf('https:') !== -1\n ) {\n warn(\n 'Insecure Firebase access from a secure page. ' +\n 'Please use https in calls to new Firebase().'\n );\n }\n};\n\n/**\n * @param {!String} methodName\n */\nexport const warnAboutUnsupportedMethod = function(methodName: string) {\n warn(\n methodName +\n ' is unsupported and will likely change soon. ' +\n 'Please do not use.'\n );\n};\n\n/**\n * Returns true if data is NaN, or +/- Infinity.\n * @param {*} data\n * @return {boolean}\n */\nexport const isInvalidJSONNumber = function(data: unknown): boolean {\n return (\n typeof data === 'number' &&\n (data !== data || // NaN\n data === Number.POSITIVE_INFINITY ||\n data === Number.NEGATIVE_INFINITY)\n );\n};\n\n/**\n * @param {function()} fn\n */\nexport const executeWhenDOMReady = function(fn: () => void) {\n if (isNodeSdk() || document.readyState === 'complete') {\n fn();\n } else {\n // Modeled after jQuery. Try DOMContentLoaded and onreadystatechange (which\n // fire before onload), but fall back to onload.\n\n let called = false;\n const wrappedFn = function() {\n if (!document.body) {\n setTimeout(wrappedFn, Math.floor(10));\n return;\n }\n\n if (!called) {\n called = true;\n fn();\n }\n };\n\n if (document.addEventListener) {\n document.addEventListener('DOMContentLoaded', wrappedFn, false);\n // fallback to onload.\n window.addEventListener('load', wrappedFn, false);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } else if ((document as any).attachEvent) {\n // IE.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (document as any).attachEvent('onreadystatechange', () => {\n if (document.readyState === 'complete') {\n wrappedFn();\n }\n });\n // fallback to onload.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (window as any).attachEvent('onload', wrappedFn);\n\n // jQuery has an extra hack for IE that we could employ (based on\n // http://javascript.nwbox.com/IEContentLoaded/) But it looks really old.\n // I'm hoping we don't need it.\n }\n }\n};\n\n/**\n * Minimum key name. Invalid for actual data, used as a marker to sort before any valid names\n * @type {!string}\n */\nexport const MIN_NAME = '[MIN_NAME]';\n\n/**\n * Maximum key name. Invalid for actual data, used as a marker to sort above any valid names\n * @type {!string}\n */\nexport const MAX_NAME = '[MAX_NAME]';\n\n/**\n * Compares valid Firebase key names, plus min and max name\n * @param {!string} a\n * @param {!string} b\n * @return {!number}\n */\nexport const nameCompare = function(a: string, b: string): number {\n if (a === b) {\n return 0;\n } else if (a === MIN_NAME || b === MAX_NAME) {\n return -1;\n } else if (b === MIN_NAME || a === MAX_NAME) {\n return 1;\n } else {\n const aAsInt = tryParseInt(a),\n bAsInt = tryParseInt(b);\n\n if (aAsInt !== null) {\n if (bAsInt !== null) {\n return aAsInt - bAsInt === 0 ? a.length - b.length : aAsInt - bAsInt;\n } else {\n return -1;\n }\n } else if (bAsInt !== null) {\n return 1;\n } else {\n return a < b ? -1 : 1;\n }\n }\n};\n\n/**\n * @param {!string} a\n * @param {!string} b\n * @return {!number} comparison result.\n */\nexport const stringCompare = function(a: string, b: string): number {\n if (a === b) {\n return 0;\n } else if (a < b) {\n return -1;\n } else {\n return 1;\n }\n};\n\n/**\n * @param {string} key\n * @param {Object} obj\n * @return {*}\n */\nexport const requireKey = function(\n key: string,\n obj: { [k: string]: unknown }\n): unknown {\n if (obj && key in obj) {\n return obj[key];\n } else {\n throw new Error(\n 'Missing required key (' + key + ') in object: ' + stringify(obj)\n );\n }\n};\n\n/**\n * @param {*} obj\n * @return {string}\n */\nexport const ObjectToUniqueKey = function(obj: unknown): string {\n if (typeof obj !== 'object' || obj === null) {\n return stringify(obj);\n }\n\n const keys = [];\n // eslint-disable-next-line guard-for-in\n for (const k in obj) {\n keys.push(k);\n }\n\n // Export as json, but with the keys sorted.\n keys.sort();\n let key = '{';\n for (let i = 0; i < keys.length; i++) {\n if (i !== 0) {\n key += ',';\n }\n key += stringify(keys[i]);\n key += ':';\n key += ObjectToUniqueKey(obj[keys[i]]);\n }\n\n key += '}';\n return key;\n};\n\n/**\n * Splits a string into a number of smaller segments of maximum size\n * @param {!string} str The string\n * @param {!number} segsize The maximum number of chars in the string.\n * @return {Array.} The string, split into appropriately-sized chunks\n */\nexport const splitStringBySize = function(\n str: string,\n segsize: number\n): string[] {\n const len = str.length;\n\n if (len <= segsize) {\n return [str];\n }\n\n const dataSegs = [];\n for (let c = 0; c < len; c += segsize) {\n if (c + segsize > len) {\n dataSegs.push(str.substring(c, len));\n } else {\n dataSegs.push(str.substring(c, c + segsize));\n }\n }\n return dataSegs;\n};\n\n/**\n * Apply a function to each (key, value) pair in an object or\n * apply a function to each (index, value) pair in an array\n * @param obj The object or array to iterate over\n * @param fn The function to apply\n */\nexport function each(obj: object, fn: (k: string, v: unknown) => void) {\n for (const key in obj) {\n if (obj.hasOwnProperty(key)) {\n fn(key, obj[key]);\n }\n }\n}\n\n/**\n * Like goog.bind, but doesn't bother to create a closure if opt_context is null/undefined.\n * @param {function(*)} callback Callback function.\n * @param {?Object=} context Optional context to bind to.\n * @return {function(*)}\n */\nexport const bindCallback = function(\n callback: (a: unknown) => void,\n context?: object | null\n): Function {\n return context ? callback.bind(context) : callback;\n};\n\n/**\n * Borrowed from http://hg.secondlife.com/llsd/src/tip/js/typedarray.js (MIT License)\n * I made one modification at the end and removed the NaN / Infinity\n * handling (since it seemed broken [caused an overflow] and we don't need it). See MJL comments.\n * @param {!number} v A double\n * @return {string}\n */\nexport const doubleToIEEE754String = function(v: number): string {\n assert(!isInvalidJSONNumber(v), 'Invalid JSON number'); // MJL\n\n const ebits = 11,\n fbits = 52;\n const bias = (1 << (ebits - 1)) - 1;\n let s, e, f, ln, i;\n\n // Compute sign, exponent, fraction\n // Skip NaN / Infinity handling --MJL.\n if (v === 0) {\n e = 0;\n f = 0;\n s = 1 / v === -Infinity ? 1 : 0;\n } else {\n s = v < 0;\n v = Math.abs(v);\n\n if (v >= Math.pow(2, 1 - bias)) {\n // Normalized\n ln = Math.min(Math.floor(Math.log(v) / Math.LN2), bias);\n e = ln + bias;\n f = Math.round(v * Math.pow(2, fbits - ln) - Math.pow(2, fbits));\n } else {\n // Denormalized\n e = 0;\n f = Math.round(v / Math.pow(2, 1 - bias - fbits));\n }\n }\n\n // Pack sign, exponent, fraction\n const bits = [];\n for (i = fbits; i; i -= 1) {\n bits.push(f % 2 ? 1 : 0);\n f = Math.floor(f / 2);\n }\n for (i = ebits; i; i -= 1) {\n bits.push(e % 2 ? 1 : 0);\n e = Math.floor(e / 2);\n }\n bits.push(s ? 1 : 0);\n bits.reverse();\n const str = bits.join('');\n\n // Return the data as a hex string. --MJL\n let hexByteString = '';\n for (i = 0; i < 64; i += 8) {\n let hexByte = parseInt(str.substr(i, 8), 2).toString(16);\n if (hexByte.length === 1) {\n hexByte = '0' + hexByte;\n }\n hexByteString = hexByteString + hexByte;\n }\n return hexByteString.toLowerCase();\n};\n\n/**\n * Used to detect if we're in a Chrome content script (which executes in an\n * isolated environment where long-polling doesn't work).\n * @return {boolean}\n */\nexport const isChromeExtensionContentScript = function(): boolean {\n return !!(\n typeof window === 'object' &&\n window['chrome'] &&\n window['chrome']['extension'] &&\n !/^chrome/.test(window.location.href)\n );\n};\n\n/**\n * Used to detect if we're in a Windows 8 Store app.\n * @return {boolean}\n */\nexport const isWindowsStoreApp = function(): boolean {\n // Check for the presence of a couple WinRT globals\n return typeof Windows === 'object' && typeof Windows.UI === 'object';\n};\n\n/**\n * Converts a server error code to a Javascript Error\n * @param {!string} code\n * @param {!Query} query\n * @return {Error}\n */\nexport const errorForServerCode = function(code: string, query: Query): Error {\n let reason = 'Unknown Error';\n if (code === 'too_big') {\n reason =\n 'The data requested exceeds the maximum size ' +\n 'that can be accessed with a single request.';\n } else if (code === 'permission_denied') {\n reason = \"Client doesn't have permission to access the desired data.\";\n } else if (code === 'unavailable') {\n reason = 'The service is unavailable';\n }\n\n const error = new Error(\n code + ' at ' + query.path.toString() + ': ' + reason\n );\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (error as any).code = code.toUpperCase();\n return error;\n};\n\n/**\n * Used to test for integer-looking strings\n * @type {RegExp}\n * @private\n */\nexport const INTEGER_REGEXP_ = new RegExp('^-?(0*)\\\\d{1,10}$');\n\n/**\n * If the string contains a 32-bit integer, return it. Else return null.\n * @param {!string} str\n * @return {?number}\n */\nexport const tryParseInt = function(str: string): number | null {\n if (INTEGER_REGEXP_.test(str)) {\n const intVal = Number(str);\n if (intVal >= -2147483648 && intVal <= 2147483647) {\n return intVal;\n }\n }\n return null;\n};\n\n/**\n * Helper to run some code but catch any exceptions and re-throw them later.\n * Useful for preventing user callbacks from breaking internal code.\n *\n * Re-throwing the exception from a setTimeout is a little evil, but it's very\n * convenient (we don't have to try to figure out when is a safe point to\n * re-throw it), and the behavior seems reasonable:\n *\n * * If you aren't pausing on exceptions, you get an error in the console with\n * the correct stack trace.\n * * If you're pausing on all exceptions, the debugger will pause on your\n * exception and then again when we rethrow it.\n * * If you're only pausing on uncaught exceptions, the debugger will only pause\n * on us re-throwing it.\n *\n * @param {!function()} fn The code to guard.\n */\nexport const exceptionGuard = function(fn: () => void) {\n try {\n fn();\n } catch (e) {\n // Re-throw exception when it's safe.\n setTimeout(() => {\n // It used to be that \"throw e\" would result in a good console error with\n // relevant context, but as of Chrome 39, you just get the firebase.js\n // file/line number where we re-throw it, which is useless. So we log\n // e.stack explicitly.\n const stack = e.stack || '';\n warn('Exception was thrown by user callback.', stack);\n throw e;\n }, Math.floor(0));\n }\n};\n\n/**\n * Helper function to safely call opt_callback with the specified arguments. It:\n * 1. Turns into a no-op if opt_callback is null or undefined.\n * 2. Wraps the call inside exceptionGuard to prevent exceptions from breaking our state.\n *\n * @param {?Function=} callback Optional onComplete callback.\n * @param {...*} varArgs Arbitrary args to be passed to opt_onComplete\n */\nexport const callUserCallback = function(\n callback?: Function | null,\n ...varArgs: unknown[]\n) {\n if (typeof callback === 'function') {\n exceptionGuard(() => {\n callback(...varArgs);\n });\n }\n};\n\n/**\n * @return {boolean} true if we think we're currently being crawled.\n */\nexport const beingCrawled = function(): boolean {\n const userAgent =\n (typeof window === 'object' &&\n window['navigator'] &&\n window['navigator']['userAgent']) ||\n '';\n\n // For now we whitelist the most popular crawlers. We should refine this to be the set of crawlers we\n // believe to support JavaScript/AJAX rendering.\n // NOTE: Google Webmaster Tools doesn't really belong, but their \"This is how a visitor to your website\n // would have seen the page\" is flaky if we don't treat it as a crawler.\n return (\n userAgent.search(\n /googlebot|google webmaster tools|bingbot|yahoo! slurp|baiduspider|yandexbot|duckduckbot/i\n ) >= 0\n );\n};\n\n/**\n * Export a property of an object using a getter function.\n *\n * @param {!Object} object\n * @param {string} name\n * @param {!function(): *} fnGet\n */\nexport const exportPropGetter = function(\n object: object,\n name: string,\n fnGet: () => unknown\n) {\n Object.defineProperty(object, name, { get: fnGet });\n};\n\n/**\n * Same as setTimeout() except on Node.JS it will /not/ prevent the process from exiting.\n *\n * It is removed with clearTimeout() as normal.\n *\n * @param {Function} fn Function to run.\n * @param {number} time Milliseconds to wait before running.\n * @return {number|Object} The setTimeout() return value.\n */\nexport const setTimeoutNonBlocking = function(\n fn: Function,\n time: number\n): number | object {\n const timeout: number | object = setTimeout(fn, time);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof timeout === 'object' && (timeout as any)['unref']) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (timeout as any)['unref']();\n }\n return timeout;\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { nameCompare } from './util';\nimport { stringLength } from '@firebase/util';\n/**\n * An immutable object representing a parsed path. It's immutable so that you\n * can pass them around to other functions without worrying about them changing\n * it.\n */\n\nexport class Path {\n private pieces_: string[];\n private pieceNum_: number;\n\n /**\n * Singleton to represent an empty path\n *\n * @const\n */\n static get Empty() {\n return new Path('');\n }\n\n /**\n * @param {string|Array.} pathOrString Path string to parse,\n * or another path, or the raw tokens array\n * @param {number=} pieceNum\n */\n constructor(pathOrString: string | string[], pieceNum?: number) {\n if (pieceNum === void 0) {\n this.pieces_ = (pathOrString as string).split('/');\n\n // Remove empty pieces.\n let copyTo = 0;\n for (let i = 0; i < this.pieces_.length; i++) {\n if (this.pieces_[i].length > 0) {\n this.pieces_[copyTo] = this.pieces_[i];\n copyTo++;\n }\n }\n this.pieces_.length = copyTo;\n\n this.pieceNum_ = 0;\n } else {\n this.pieces_ = pathOrString as string[];\n this.pieceNum_ = pieceNum;\n }\n }\n\n getFront(): string | null {\n if (this.pieceNum_ >= this.pieces_.length) {\n return null;\n }\n\n return this.pieces_[this.pieceNum_];\n }\n\n /**\n * @return {number} The number of segments in this path\n */\n getLength(): number {\n return this.pieces_.length - this.pieceNum_;\n }\n\n /**\n * @return {!Path}\n */\n popFront(): Path {\n let pieceNum = this.pieceNum_;\n if (pieceNum < this.pieces_.length) {\n pieceNum++;\n }\n return new Path(this.pieces_, pieceNum);\n }\n\n /**\n * @return {?string}\n */\n getBack(): string | null {\n if (this.pieceNum_ < this.pieces_.length) {\n return this.pieces_[this.pieces_.length - 1];\n }\n\n return null;\n }\n\n toString(): string {\n let pathString = '';\n for (let i = this.pieceNum_; i < this.pieces_.length; i++) {\n if (this.pieces_[i] !== '') {\n pathString += '/' + this.pieces_[i];\n }\n }\n\n return pathString || '/';\n }\n\n toUrlEncodedString(): string {\n let pathString = '';\n for (let i = this.pieceNum_; i < this.pieces_.length; i++) {\n if (this.pieces_[i] !== '') {\n pathString += '/' + encodeURIComponent(String(this.pieces_[i]));\n }\n }\n\n return pathString || '/';\n }\n\n /**\n * Shallow copy of the parts of the path.\n *\n * @param {number=} begin\n * @return {!Array}\n */\n slice(begin: number = 0): string[] {\n return this.pieces_.slice(this.pieceNum_ + begin);\n }\n\n /**\n * @return {?Path}\n */\n parent(): Path | null {\n if (this.pieceNum_ >= this.pieces_.length) {\n return null;\n }\n\n const pieces = [];\n for (let i = this.pieceNum_; i < this.pieces_.length - 1; i++) {\n pieces.push(this.pieces_[i]);\n }\n\n return new Path(pieces, 0);\n }\n\n /**\n * @param {string|!Path} childPathObj\n * @return {!Path}\n */\n child(childPathObj: string | Path): Path {\n const pieces = [];\n for (let i = this.pieceNum_; i < this.pieces_.length; i++) {\n pieces.push(this.pieces_[i]);\n }\n\n if (childPathObj instanceof Path) {\n for (\n let i = childPathObj.pieceNum_;\n i < childPathObj.pieces_.length;\n i++\n ) {\n pieces.push(childPathObj.pieces_[i]);\n }\n } else {\n const childPieces = childPathObj.split('/');\n for (let i = 0; i < childPieces.length; i++) {\n if (childPieces[i].length > 0) {\n pieces.push(childPieces[i]);\n }\n }\n }\n\n return new Path(pieces, 0);\n }\n\n /**\n * @return {boolean} True if there are no segments in this path\n */\n isEmpty(): boolean {\n return this.pieceNum_ >= this.pieces_.length;\n }\n\n /**\n * @param {!Path} outerPath\n * @param {!Path} innerPath\n * @return {!Path} The path from outerPath to innerPath\n */\n static relativePath(outerPath: Path, innerPath: Path): Path {\n const outer = outerPath.getFront(),\n inner = innerPath.getFront();\n if (outer === null) {\n return innerPath;\n } else if (outer === inner) {\n return Path.relativePath(outerPath.popFront(), innerPath.popFront());\n } else {\n throw new Error(\n 'INTERNAL ERROR: innerPath (' +\n innerPath +\n ') is not within ' +\n 'outerPath (' +\n outerPath +\n ')'\n );\n }\n }\n\n /**\n * @param {!Path} left\n * @param {!Path} right\n * @return {number} -1, 0, 1 if left is less, equal, or greater than the right.\n */\n static comparePaths(left: Path, right: Path): number {\n const leftKeys = left.slice();\n const rightKeys = right.slice();\n for (let i = 0; i < leftKeys.length && i < rightKeys.length; i++) {\n const cmp = nameCompare(leftKeys[i], rightKeys[i]);\n if (cmp !== 0) {\n return cmp;\n }\n }\n if (leftKeys.length === rightKeys.length) {\n return 0;\n }\n return leftKeys.length < rightKeys.length ? -1 : 1;\n }\n\n /**\n *\n * @param {Path} other\n * @return {boolean} true if paths are the same.\n */\n equals(other: Path): boolean {\n if (this.getLength() !== other.getLength()) {\n return false;\n }\n\n for (\n let i = this.pieceNum_, j = other.pieceNum_;\n i <= this.pieces_.length;\n i++, j++\n ) {\n if (this.pieces_[i] !== other.pieces_[j]) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n *\n * @param {!Path} other\n * @return {boolean} True if this path is a parent (or the same as) other\n */\n contains(other: Path): boolean {\n let i = this.pieceNum_;\n let j = other.pieceNum_;\n if (this.getLength() > other.getLength()) {\n return false;\n }\n while (i < this.pieces_.length) {\n if (this.pieces_[i] !== other.pieces_[j]) {\n return false;\n }\n ++i;\n ++j;\n }\n return true;\n }\n} // end Path\n\n/**\n * Dynamic (mutable) path used to count path lengths.\n *\n * This class is used to efficiently check paths for valid\n * length (in UTF8 bytes) and depth (used in path validation).\n *\n * Throws Error exception if path is ever invalid.\n *\n * The definition of a path always begins with '/'.\n */\nexport class ValidationPath {\n /** @type {!Array} */\n private parts_: string[];\n /** @type {number} Initialize to number of '/' chars needed in path. */\n private byteLength_: number;\n\n /**\n * @param {!Path} path Initial Path.\n * @param {string} errorPrefix_ Prefix for any error messages.\n */\n constructor(path: Path, private errorPrefix_: string) {\n /** @type {!Array} */\n this.parts_ = path.slice();\n /** @type {number} Initialize to number of '/' chars needed in path. */\n this.byteLength_ = Math.max(1, this.parts_.length);\n\n for (let i = 0; i < this.parts_.length; i++) {\n this.byteLength_ += stringLength(this.parts_[i]);\n }\n this.checkValid_();\n }\n\n /** @const {number} Maximum key depth. */\n static get MAX_PATH_DEPTH() {\n return 32;\n }\n\n /** @const {number} Maximum number of (UTF8) bytes in a Firebase path. */\n static get MAX_PATH_LENGTH_BYTES() {\n return 768;\n }\n\n /** @param {string} child */\n push(child: string) {\n // Count the needed '/'\n if (this.parts_.length > 0) {\n this.byteLength_ += 1;\n }\n this.parts_.push(child);\n this.byteLength_ += stringLength(child);\n this.checkValid_();\n }\n\n pop() {\n const last = this.parts_.pop();\n this.byteLength_ -= stringLength(last);\n // Un-count the previous '/'\n if (this.parts_.length > 0) {\n this.byteLength_ -= 1;\n }\n }\n\n private checkValid_() {\n if (this.byteLength_ > ValidationPath.MAX_PATH_LENGTH_BYTES) {\n throw new Error(\n this.errorPrefix_ +\n 'has a key path longer than ' +\n ValidationPath.MAX_PATH_LENGTH_BYTES +\n ' bytes (' +\n this.byteLength_ +\n ').'\n );\n }\n if (this.parts_.length > ValidationPath.MAX_PATH_DEPTH) {\n throw new Error(\n this.errorPrefix_ +\n 'path specified exceeds the maximum depth that can be written (' +\n ValidationPath.MAX_PATH_DEPTH +\n ') or object contains a cycle ' +\n this.toErrorString()\n );\n }\n }\n\n /**\n * String for use in error messages - uses '.' notation for path.\n *\n * @return {string}\n */\n toErrorString(): string {\n if (this.parts_.length === 0) {\n return '';\n }\n return \"in property '\" + this.parts_.join('.') + \"'\";\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nexport const PROTOCOL_VERSION = '5';\n\nexport const VERSION_PARAM = 'v';\n\nexport const TRANSPORT_SESSION_PARAM = 's';\n\nexport const REFERER_PARAM = 'r';\n\nexport const FORGE_REF = 'f';\n\nexport const FORGE_DOMAIN = 'firebaseio.com';\n\nexport const LAST_SESSION_PARAM = 'ls';\n\nexport const WEBSOCKET = 'websocket';\n\nexport const LONG_POLLING = 'long_polling';\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { PersistentStorage } from './storage/storage';\nimport { LONG_POLLING, WEBSOCKET } from '../realtime/Constants';\nimport { each } from './util/util';\n\n/**\n * A class that holds metadata about a Repo object\n *\n * @constructor\n */\nexport class RepoInfo {\n host: string;\n domain: string;\n internalHost: string;\n\n /**\n * @param {string} host Hostname portion of the url for the repo\n * @param {boolean} secure Whether or not this repo is accessed over ssl\n * @param {string} namespace The namespace represented by the repo\n * @param {boolean} webSocketOnly Whether to prefer websockets over all other transports (used by Nest).\n * @param {string=} persistenceKey Override the default session persistence storage key\n */\n constructor(\n host: string,\n public secure: boolean,\n public namespace: string,\n public webSocketOnly: boolean,\n public persistenceKey: string = '',\n public includeNamespaceInQueryParams: boolean = false\n ) {\n this.host = host.toLowerCase();\n this.domain = this.host.substr(this.host.indexOf('.') + 1);\n this.internalHost =\n (PersistentStorage.get('host:' + host) as string) || this.host;\n }\n\n needsQueryParam(): boolean {\n return (\n this.host !== this.internalHost ||\n this.isCustomHost() ||\n this.includeNamespaceInQueryParams\n );\n }\n\n isCacheableHost(): boolean {\n return this.internalHost.substr(0, 2) === 's-';\n }\n\n isDemoHost() {\n return this.domain === 'firebaseio-demo.com';\n }\n\n isCustomHost() {\n return (\n this.domain !== 'firebaseio.com' && this.domain !== 'firebaseio-demo.com'\n );\n }\n\n updateHost(newHost: string) {\n if (newHost !== this.internalHost) {\n this.internalHost = newHost;\n if (this.isCacheableHost()) {\n PersistentStorage.set('host:' + this.host, this.internalHost);\n }\n }\n }\n\n /**\n * Returns the websocket URL for this repo\n * @param {string} type of connection\n * @param {Object} params list\n * @return {string} The URL for this repo\n */\n connectionURL(type: string, params: { [k: string]: string }): string {\n assert(typeof type === 'string', 'typeof type must == string');\n assert(typeof params === 'object', 'typeof params must == object');\n\n let connURL: string;\n if (type === WEBSOCKET) {\n connURL =\n (this.secure ? 'wss://' : 'ws://') + this.internalHost + '/.ws?';\n } else if (type === LONG_POLLING) {\n connURL =\n (this.secure ? 'https://' : 'http://') + this.internalHost + '/.lp?';\n } else {\n throw new Error('Unknown connection type: ' + type);\n }\n if (this.needsQueryParam()) {\n params['ns'] = this.namespace;\n }\n\n const pairs: string[] = [];\n\n each(params, (key: string, value: string) => {\n pairs.push(key + '=' + value);\n });\n\n return connURL + pairs.join('&');\n }\n\n /** @return {string} */\n toString(): string {\n let str = this.toURLString();\n if (this.persistenceKey) {\n str += '<' + this.persistenceKey + '>';\n }\n return str;\n }\n\n /** @return {string} */\n toURLString(): string {\n return (this.secure ? 'https://' : 'http://') + this.host;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path } from '../Path';\nimport { RepoInfo } from '../../RepoInfo';\nimport { warnIfPageIsSecure, warn, fatal } from '../util';\n\n/**\n * @param {!string} pathString\n * @return {string}\n */\nfunction decodePath(pathString: string): string {\n let pathStringDecoded = '';\n const pieces = pathString.split('/');\n for (let i = 0; i < pieces.length; i++) {\n if (pieces[i].length > 0) {\n let piece = pieces[i];\n try {\n piece = decodeURIComponent(piece.replace(/\\+/g, ' '));\n } catch (e) {}\n pathStringDecoded += '/' + piece;\n }\n }\n return pathStringDecoded;\n}\n\n/**\n * @param {!string} queryString\n * @return {!{[key:string]:string}} key value hash\n */\nfunction decodeQuery(queryString: string): { [key: string]: string } {\n const results = {};\n if (queryString.charAt(0) === '?') {\n queryString = queryString.substring(1);\n }\n for (const segment of queryString.split('&')) {\n if (segment.length === 0) {\n continue;\n }\n const kv = segment.split('=');\n if (kv.length === 2) {\n results[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]);\n } else {\n warn(`Invalid query segment '${segment}' in query '${queryString}'`);\n }\n }\n return results;\n}\n\n/**\n *\n * @param {!string} dataURL\n * @return {{repoInfo: !RepoInfo, path: !Path}}\n */\nexport const parseRepoInfo = function(\n dataURL: string\n): { repoInfo: RepoInfo; path: Path } {\n const parsedUrl = parseDatabaseURL(dataURL),\n namespace = parsedUrl.namespace;\n\n if (parsedUrl.domain === 'firebase') {\n fatal(\n parsedUrl.host +\n ' is no longer supported. ' +\n 'Please use .firebaseio.com instead'\n );\n }\n\n // Catch common error of uninitialized namespace value.\n if (\n (!namespace || namespace === 'undefined') &&\n parsedUrl.domain !== 'localhost'\n ) {\n fatal(\n 'Cannot parse Firebase url. Please use https://.firebaseio.com'\n );\n }\n\n if (!parsedUrl.secure) {\n warnIfPageIsSecure();\n }\n\n const webSocketOnly = parsedUrl.scheme === 'ws' || parsedUrl.scheme === 'wss';\n\n return {\n repoInfo: new RepoInfo(\n parsedUrl.host,\n parsedUrl.secure,\n namespace,\n webSocketOnly,\n /*persistenceKey=*/ '',\n /*includeNamespaceInQueryParams=*/ namespace !== parsedUrl.subdomain\n ),\n path: new Path(parsedUrl.pathString)\n };\n};\n\n/**\n *\n * @param {!string} dataURL\n * @return {{host: string, port: number, domain: string, subdomain: string, secure: boolean, scheme: string, pathString: string, namespace: string}}\n */\nexport const parseDatabaseURL = function(\n dataURL: string\n): {\n host: string;\n port: number;\n domain: string;\n subdomain: string;\n secure: boolean;\n scheme: string;\n pathString: string;\n namespace: string;\n} {\n // Default to empty strings in the event of a malformed string.\n let host = '',\n domain = '',\n subdomain = '',\n pathString = '',\n namespace = '';\n\n // Always default to SSL, unless otherwise specified.\n let secure = true,\n scheme = 'https',\n port = 443;\n\n // Don't do any validation here. The caller is responsible for validating the result of parsing.\n if (typeof dataURL === 'string') {\n // Parse scheme.\n let colonInd = dataURL.indexOf('//');\n if (colonInd >= 0) {\n scheme = dataURL.substring(0, colonInd - 1);\n dataURL = dataURL.substring(colonInd + 2);\n }\n\n // Parse host, path, and query string.\n let slashInd = dataURL.indexOf('/');\n if (slashInd === -1) {\n slashInd = dataURL.length;\n }\n let questionMarkInd = dataURL.indexOf('?');\n if (questionMarkInd === -1) {\n questionMarkInd = dataURL.length;\n }\n host = dataURL.substring(0, Math.min(slashInd, questionMarkInd));\n if (slashInd < questionMarkInd) {\n // For pathString, questionMarkInd will always come after slashInd\n pathString = decodePath(dataURL.substring(slashInd, questionMarkInd));\n }\n const queryParams = decodeQuery(\n dataURL.substring(Math.min(dataURL.length, questionMarkInd))\n );\n\n // If we have a port, use scheme for determining if it's secure.\n colonInd = host.indexOf(':');\n if (colonInd >= 0) {\n secure = scheme === 'https' || scheme === 'wss';\n port = parseInt(host.substring(colonInd + 1), 10);\n } else {\n colonInd = dataURL.length;\n }\n\n const parts = host.split('.');\n if (parts.length === 3) {\n // Normalize namespaces to lowercase to share storage / connection.\n domain = parts[1];\n subdomain = parts[0].toLowerCase();\n // We interpret the subdomain of a 3 component URL as the namespace name.\n namespace = subdomain;\n } else if (parts.length === 2) {\n domain = parts[0];\n } else if (parts[0].slice(0, colonInd).toLowerCase() === 'localhost') {\n domain = 'localhost';\n }\n // Always treat the value of the `ns` as the namespace name if it is present.\n if ('ns' in queryParams) {\n namespace = queryParams['ns'];\n }\n }\n\n return {\n host,\n port,\n domain,\n subdomain,\n secure,\n scheme,\n pathString,\n namespace\n };\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path, ValidationPath } from './Path';\nimport {\n contains,\n safeGet,\n errorPrefix as errorPrefixFxn,\n stringLength\n} from '@firebase/util';\nimport { isInvalidJSONNumber, each } from './util';\n\nimport { RepoInfo } from '../RepoInfo';\n\n/**\n * True for invalid Firebase keys\n * @type {RegExp}\n * @private\n */\nexport const INVALID_KEY_REGEX_ = /[\\[\\].#$\\/\\u0000-\\u001F\\u007F]/;\n\n/**\n * True for invalid Firebase paths.\n * Allows '/' in paths.\n * @type {RegExp}\n * @private\n */\nexport const INVALID_PATH_REGEX_ = /[\\[\\].#$\\u0000-\\u001F\\u007F]/;\n\n/**\n * Maximum number of characters to allow in leaf value\n * @type {number}\n * @private\n */\nexport const MAX_LEAF_SIZE_ = 10 * 1024 * 1024;\n\n/**\n * @param {*} key\n * @return {boolean}\n */\nexport const isValidKey = function(key: unknown): boolean {\n return (\n typeof key === 'string' && key.length !== 0 && !INVALID_KEY_REGEX_.test(key)\n );\n};\n\n/**\n * @param {string} pathString\n * @return {boolean}\n */\nexport const isValidPathString = function(pathString: string): boolean {\n return (\n typeof pathString === 'string' &&\n pathString.length !== 0 &&\n !INVALID_PATH_REGEX_.test(pathString)\n );\n};\n\n/**\n * @param {string} pathString\n * @return {boolean}\n */\nexport const isValidRootPathString = function(pathString: string): boolean {\n if (pathString) {\n // Allow '/.info/' at the beginning.\n pathString = pathString.replace(/^\\/*\\.info(\\/|$)/, '/');\n }\n\n return isValidPathString(pathString);\n};\n\n/**\n * @param {*} priority\n * @return {boolean}\n */\nexport const isValidPriority = function(priority: unknown): boolean {\n return (\n priority === null ||\n typeof priority === 'string' ||\n (typeof priority === 'number' && !isInvalidJSONNumber(priority)) ||\n (priority &&\n typeof priority === 'object' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n contains(priority as any, '.sv'))\n );\n};\n\n/**\n * Pre-validate a datum passed as an argument to Firebase function.\n *\n * @param {string} fnName\n * @param {number} argumentNumber\n * @param {*} data\n * @param {!Path} path\n * @param {boolean} optional\n */\nexport const validateFirebaseDataArg = function(\n fnName: string,\n argumentNumber: number,\n data: unknown,\n path: Path,\n optional: boolean\n) {\n if (optional && data === undefined) {\n return;\n }\n\n validateFirebaseData(\n errorPrefixFxn(fnName, argumentNumber, optional),\n data,\n path\n );\n};\n\n/**\n * Validate a data object client-side before sending to server.\n *\n * @param {string} errorPrefix\n * @param {*} data\n * @param {!Path|!ValidationPath} path_\n */\nexport const validateFirebaseData = function(\n errorPrefix: string,\n data: unknown,\n path_: Path | ValidationPath\n) {\n const path =\n path_ instanceof Path ? new ValidationPath(path_, errorPrefix) : path_;\n\n if (data === undefined) {\n throw new Error(errorPrefix + 'contains undefined ' + path.toErrorString());\n }\n if (typeof data === 'function') {\n throw new Error(\n errorPrefix +\n 'contains a function ' +\n path.toErrorString() +\n ' with contents = ' +\n data.toString()\n );\n }\n if (isInvalidJSONNumber(data)) {\n throw new Error(\n errorPrefix + 'contains ' + data.toString() + ' ' + path.toErrorString()\n );\n }\n\n // Check max leaf size, but try to avoid the utf8 conversion if we can.\n if (\n typeof data === 'string' &&\n data.length > MAX_LEAF_SIZE_ / 3 &&\n stringLength(data) > MAX_LEAF_SIZE_\n ) {\n throw new Error(\n errorPrefix +\n 'contains a string greater than ' +\n MAX_LEAF_SIZE_ +\n ' utf8 bytes ' +\n path.toErrorString() +\n \" ('\" +\n data.substring(0, 50) +\n \"...')\"\n );\n }\n\n // TODO = Perf = Consider combining the recursive validation of keys into NodeFromJSON\n // to save extra walking of large objects.\n if (data && typeof data === 'object') {\n let hasDotValue = false;\n let hasActualChild = false;\n each(data, (key: string, value: unknown) => {\n if (key === '.value') {\n hasDotValue = true;\n } else if (key !== '.priority' && key !== '.sv') {\n hasActualChild = true;\n if (!isValidKey(key)) {\n throw new Error(\n errorPrefix +\n ' contains an invalid key (' +\n key +\n ') ' +\n path.toErrorString() +\n '. Keys must be non-empty strings ' +\n 'and can\\'t contain \".\", \"#\", \"$\", \"/\", \"[\", or \"]\"'\n );\n }\n }\n\n path.push(key);\n validateFirebaseData(errorPrefix, value, path);\n path.pop();\n });\n\n if (hasDotValue && hasActualChild) {\n throw new Error(\n errorPrefix +\n ' contains \".value\" child ' +\n path.toErrorString() +\n ' in addition to actual children.'\n );\n }\n }\n};\n\n/**\n * Pre-validate paths passed in the firebase function.\n *\n * @param {string} errorPrefix\n * @param {Array} mergePaths\n */\nexport const validateFirebaseMergePaths = function(\n errorPrefix: string,\n mergePaths: Path[]\n) {\n let i, curPath;\n for (i = 0; i < mergePaths.length; i++) {\n curPath = mergePaths[i];\n const keys = curPath.slice();\n for (let j = 0; j < keys.length; j++) {\n if (keys[j] === '.priority' && j === keys.length - 1) {\n // .priority is OK\n } else if (!isValidKey(keys[j])) {\n throw new Error(\n errorPrefix +\n 'contains an invalid key (' +\n keys[j] +\n ') in path ' +\n curPath.toString() +\n '. Keys must be non-empty strings ' +\n 'and can\\'t contain \".\", \"#\", \"$\", \"/\", \"[\", or \"]\"'\n );\n }\n }\n }\n\n // Check that update keys are not descendants of each other.\n // We rely on the property that sorting guarantees that ancestors come\n // right before descendants.\n mergePaths.sort(Path.comparePaths);\n let prevPath: Path | null = null;\n for (i = 0; i < mergePaths.length; i++) {\n curPath = mergePaths[i];\n if (prevPath !== null && prevPath.contains(curPath)) {\n throw new Error(\n errorPrefix +\n 'contains a path ' +\n prevPath.toString() +\n ' that is ancestor of another path ' +\n curPath.toString()\n );\n }\n prevPath = curPath;\n }\n};\n\n/**\n * pre-validate an object passed as an argument to firebase function (\n * must be an object - e.g. for firebase.update()).\n *\n * @param {string} fnName\n * @param {number} argumentNumber\n * @param {*} data\n * @param {!Path} path\n * @param {boolean} optional\n */\nexport const validateFirebaseMergeDataArg = function(\n fnName: string,\n argumentNumber: number,\n data: unknown,\n path: Path,\n optional: boolean\n) {\n if (optional && data === undefined) {\n return;\n }\n\n const errorPrefix = errorPrefixFxn(fnName, argumentNumber, optional);\n\n if (!(data && typeof data === 'object') || Array.isArray(data)) {\n throw new Error(\n errorPrefix + ' must be an object containing the children to replace.'\n );\n }\n\n const mergePaths: Path[] = [];\n each(data, (key: string, value: unknown) => {\n const curPath = new Path(key);\n validateFirebaseData(errorPrefix, value, path.child(curPath));\n if (curPath.getBack() === '.priority') {\n if (!isValidPriority(value)) {\n throw new Error(\n errorPrefix +\n \"contains an invalid value for '\" +\n curPath.toString() +\n \"', which must be a valid \" +\n 'Firebase priority (a string, finite number, server value, or null).'\n );\n }\n }\n mergePaths.push(curPath);\n });\n validateFirebaseMergePaths(errorPrefix, mergePaths);\n};\n\nexport const validatePriority = function(\n fnName: string,\n argumentNumber: number,\n priority: unknown,\n optional: boolean\n) {\n if (optional && priority === undefined) {\n return;\n }\n if (isInvalidJSONNumber(priority)) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'is ' +\n priority.toString() +\n ', but must be a valid Firebase priority (a string, finite number, ' +\n 'server value, or null).'\n );\n }\n // Special case to allow importing data with a .sv.\n if (!isValidPriority(priority)) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must be a valid Firebase priority ' +\n '(a string, finite number, server value, or null).'\n );\n }\n};\n\nexport const validateEventType = function(\n fnName: string,\n argumentNumber: number,\n eventType: string,\n optional: boolean\n) {\n if (optional && eventType === undefined) {\n return;\n }\n\n switch (eventType) {\n case 'value':\n case 'child_added':\n case 'child_removed':\n case 'child_changed':\n case 'child_moved':\n break;\n default:\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must be a valid event type = \"value\", \"child_added\", \"child_removed\", ' +\n '\"child_changed\", or \"child_moved\".'\n );\n }\n};\n\nexport const validateKey = function(\n fnName: string,\n argumentNumber: number,\n key: string,\n optional: boolean\n) {\n if (optional && key === undefined) {\n return;\n }\n if (!isValidKey(key)) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'was an invalid key = \"' +\n key +\n '\". Firebase keys must be non-empty strings and ' +\n 'can\\'t contain \".\", \"#\", \"$\", \"/\", \"[\", or \"]\").'\n );\n }\n};\n\nexport const validatePathString = function(\n fnName: string,\n argumentNumber: number,\n pathString: string,\n optional: boolean\n) {\n if (optional && pathString === undefined) {\n return;\n }\n\n if (!isValidPathString(pathString)) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'was an invalid path = \"' +\n pathString +\n '\". Paths must be non-empty strings and ' +\n 'can\\'t contain \".\", \"#\", \"$\", \"[\", or \"]\"'\n );\n }\n};\n\nexport const validateRootPathString = function(\n fnName: string,\n argumentNumber: number,\n pathString: string,\n optional: boolean\n) {\n if (pathString) {\n // Allow '/.info/' at the beginning.\n pathString = pathString.replace(/^\\/*\\.info(\\/|$)/, '/');\n }\n\n validatePathString(fnName, argumentNumber, pathString, optional);\n};\n\nexport const validateWritablePath = function(fnName: string, path: Path) {\n if (path.getFront() === '.info') {\n throw new Error(fnName + \" failed = Can't modify data under /.info/\");\n }\n};\n\nexport const validateUrl = function(\n fnName: string,\n argumentNumber: number,\n parsedUrl: { repoInfo: RepoInfo; path: Path }\n) {\n // TODO = Validate server better.\n const pathString = parsedUrl.path.toString();\n if (\n !(typeof parsedUrl.repoInfo.host === 'string') ||\n parsedUrl.repoInfo.host.length === 0 ||\n (!isValidKey(parsedUrl.repoInfo.namespace) &&\n parsedUrl.repoInfo.host.split(':')[0] !== 'localhost') ||\n (pathString.length !== 0 && !isValidRootPathString(pathString))\n ) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, false) +\n 'must be a valid firebase URL and ' +\n 'the path can\\'t contain \".\", \"#\", \"$\", \"[\", or \"]\".'\n );\n }\n};\n\nexport const validateCredential = function(\n fnName: string,\n argumentNumber: number,\n cred: unknown,\n optional: boolean\n) {\n if (optional && cred === undefined) {\n return;\n }\n if (!(typeof cred === 'string')) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must be a valid credential (a string).'\n );\n }\n};\n\nexport const validateBoolean = function(\n fnName: string,\n argumentNumber: number,\n bool: unknown,\n optional: boolean\n) {\n if (optional && bool === undefined) {\n return;\n }\n if (typeof bool !== 'boolean') {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) + 'must be a boolean.'\n );\n }\n};\n\nexport const validateString = function(\n fnName: string,\n argumentNumber: number,\n string: unknown,\n optional: boolean\n) {\n if (optional && string === undefined) {\n return;\n }\n if (!(typeof string === 'string')) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must be a valid string.'\n );\n }\n};\n\nexport const validateObject = function(\n fnName: string,\n argumentNumber: number,\n obj: unknown,\n optional: boolean\n) {\n if (optional && obj === undefined) {\n return;\n }\n if (!(obj && typeof obj === 'object') || obj === null) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must be a valid object.'\n );\n }\n};\n\nexport const validateObjectContainsKey = function(\n fnName: string,\n argumentNumber: number,\n obj: unknown,\n key: string,\n optional: boolean,\n optType?: string\n) {\n const objectContainsKey =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n obj && typeof obj === 'object' && contains(obj as any, key);\n\n if (!objectContainsKey) {\n if (optional) {\n return;\n } else {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must contain the key \"' +\n key +\n '\"'\n );\n }\n }\n\n if (optType) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const val = safeGet(obj as any, key);\n if (\n (optType === 'number' && !(typeof val === 'number')) ||\n (optType === 'string' && !(typeof val === 'string')) ||\n (optType === 'boolean' && !(typeof val === 'boolean')) ||\n (optType === 'function' && !(typeof val === 'function')) ||\n (optType === 'object' && !(typeof val === 'object') && val)\n ) {\n if (optional) {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'contains invalid value for key \"' +\n key +\n '\" (must be of type \"' +\n optType +\n '\")'\n );\n } else {\n throw new Error(\n errorPrefixFxn(fnName, argumentNumber, optional) +\n 'must contain the key \"' +\n key +\n '\" with type \"' +\n optType +\n '\"'\n );\n }\n }\n }\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { validateArgCount, validateCallback, Deferred } from '@firebase/util';\nimport {\n validateWritablePath,\n validateFirebaseDataArg,\n validatePriority,\n validateFirebaseMergeDataArg\n} from '../core/util/validation';\nimport { warn } from '../core/util/util';\n\nimport { Repo } from '../core/Repo';\nimport { Path } from '../core/util/Path';\nimport { Indexable } from '../core/util/misc';\n\n/**\n * @constructor\n */\nexport class OnDisconnect {\n /**\n * @param {!Repo} repo_\n * @param {!Path} path_\n */\n constructor(private repo_: Repo, private path_: Path) {}\n\n /**\n * @param {function(?Error)=} onComplete\n * @return {!firebase.Promise}\n */\n cancel(onComplete?: (a: Error | null) => void): Promise {\n validateArgCount('OnDisconnect.cancel', 0, 1, arguments.length);\n validateCallback('OnDisconnect.cancel', 1, onComplete, true);\n const deferred = new Deferred();\n this.repo_.onDisconnectCancel(\n this.path_,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {function(?Error)=} onComplete\n * @return {!firebase.Promise}\n */\n remove(onComplete?: (a: Error | null) => void): Promise {\n validateArgCount('OnDisconnect.remove', 0, 1, arguments.length);\n validateWritablePath('OnDisconnect.remove', this.path_);\n validateCallback('OnDisconnect.remove', 1, onComplete, true);\n const deferred = new Deferred();\n this.repo_.onDisconnectSet(\n this.path_,\n null,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {*} value\n * @param {function(?Error)=} onComplete\n * @return {!firebase.Promise}\n */\n set(value: unknown, onComplete?: (a: Error | null) => void): Promise {\n validateArgCount('OnDisconnect.set', 1, 2, arguments.length);\n validateWritablePath('OnDisconnect.set', this.path_);\n validateFirebaseDataArg('OnDisconnect.set', 1, value, this.path_, false);\n validateCallback('OnDisconnect.set', 2, onComplete, true);\n const deferred = new Deferred();\n this.repo_.onDisconnectSet(\n this.path_,\n value,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {*} value\n * @param {number|string|null} priority\n * @param {function(?Error)=} onComplete\n * @return {!firebase.Promise}\n */\n setWithPriority(\n value: unknown,\n priority: number | string | null,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('OnDisconnect.setWithPriority', 2, 3, arguments.length);\n validateWritablePath('OnDisconnect.setWithPriority', this.path_);\n validateFirebaseDataArg(\n 'OnDisconnect.setWithPriority',\n 1,\n value,\n this.path_,\n false\n );\n validatePriority('OnDisconnect.setWithPriority', 2, priority, false);\n validateCallback('OnDisconnect.setWithPriority', 3, onComplete, true);\n\n const deferred = new Deferred();\n this.repo_.onDisconnectSetWithPriority(\n this.path_,\n value,\n priority,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {!Object} objectToMerge\n * @param {function(?Error)=} onComplete\n * @return {!firebase.Promise}\n */\n update(\n objectToMerge: Indexable,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('OnDisconnect.update', 1, 2, arguments.length);\n validateWritablePath('OnDisconnect.update', this.path_);\n if (Array.isArray(objectToMerge)) {\n const newObjectToMerge: { [k: string]: unknown } = {};\n for (let i = 0; i < objectToMerge.length; ++i) {\n newObjectToMerge['' + i] = objectToMerge[i];\n }\n objectToMerge = newObjectToMerge;\n warn(\n 'Passing an Array to firebase.database.onDisconnect().update() is deprecated. Use set() if you want to overwrite the ' +\n 'existing data, or an Object with integer keys if you really do want to only update some of the children.'\n );\n }\n validateFirebaseMergeDataArg(\n 'OnDisconnect.update',\n 1,\n objectToMerge,\n this.path_,\n false\n );\n validateCallback('OnDisconnect.update', 2, onComplete, true);\n const deferred = new Deferred();\n this.repo_.onDisconnectUpdate(\n this.path_,\n objectToMerge,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DataSnapshot } from './DataSnapshot';\nimport { validateArgCount } from '@firebase/util';\n\nexport class TransactionResult {\n /**\n * A type for the resolve value of Firebase.transaction.\n * @constructor\n * @dict\n * @param {boolean} committed\n * @param {DataSnapshot} snapshot\n */\n constructor(public committed: boolean, public snapshot: DataSnapshot) {}\n\n // Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary\n // for end-users\n toJSON(): object {\n validateArgCount('TransactionResult.toJSON', 0, 1, arguments.length);\n return { committed: this.committed, snapshot: this.snapshot.toJSON() };\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\n\n/**\n * Fancy ID generator that creates 20-character string identifiers with the\n * following properties:\n *\n * 1. They're based on timestamp so that they sort *after* any existing ids.\n * 2. They contain 72-bits of random data after the timestamp so that IDs won't\n * collide with other clients' IDs.\n * 3. They sort *lexicographically* (so the timestamp is converted to characters\n * that will sort properly).\n * 4. They're monotonically increasing. Even if you generate more than one in\n * the same timestamp, the latter ones will sort after the former ones. We do\n * this by using the previous random bits but \"incrementing\" them by 1 (only\n * in the case of a timestamp collision).\n */\nexport const nextPushId = (function() {\n // Modeled after base64 web-safe chars, but ordered by ASCII.\n const PUSH_CHARS =\n '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';\n\n // Timestamp of last push, used to prevent local collisions if you push twice\n // in one ms.\n let lastPushTime = 0;\n\n // We generate 72-bits of randomness which get turned into 12 characters and\n // appended to the timestamp to prevent collisions with other clients. We\n // store the last characters we generated because in the event of a collision,\n // we'll use those same characters except \"incremented\" by one.\n const lastRandChars: number[] = [];\n\n return function(now: number) {\n const duplicateTime = now === lastPushTime;\n lastPushTime = now;\n\n let i;\n const timeStampChars = new Array(8);\n for (i = 7; i >= 0; i--) {\n timeStampChars[i] = PUSH_CHARS.charAt(now % 64);\n // NOTE: Can't use << here because javascript will convert to int and lose\n // the upper bits.\n now = Math.floor(now / 64);\n }\n assert(now === 0, 'Cannot push at time == 0');\n\n let id = timeStampChars.join('');\n\n if (!duplicateTime) {\n for (i = 0; i < 12; i++) {\n lastRandChars[i] = Math.floor(Math.random() * 64);\n }\n } else {\n // If the timestamp hasn't changed since last push, use the same random\n // number, except incremented by 1.\n for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {\n lastRandChars[i] = 0;\n }\n lastRandChars[i]++;\n }\n for (i = 0; i < 12; i++) {\n id += PUSH_CHARS.charAt(lastRandChars[i]);\n }\n assert(id.length === 20, 'nextPushId: Length should be 20.');\n\n return id;\n };\n})();\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path } from '../util/Path';\nimport { Index } from './indexes/Index';\n\n/**\n * Node is an interface defining the common functionality for nodes in\n * a DataSnapshot.\n *\n * @interface\n */\nexport interface Node {\n /**\n * Whether this node is a leaf node.\n * @return {boolean} Whether this is a leaf node.\n */\n isLeafNode(): boolean;\n\n /**\n * Gets the priority of the node.\n * @return {!Node} The priority of the node.\n */\n getPriority(): Node;\n\n /**\n * Returns a duplicate node with the new priority.\n * @param {!Node} newPriorityNode New priority to set for the node.\n * @return {!Node} Node with new priority.\n */\n updatePriority(newPriorityNode: Node): Node;\n\n /**\n * Returns the specified immediate child, or null if it doesn't exist.\n * @param {string} childName The name of the child to retrieve.\n * @return {!Node} The retrieved child, or an empty node.\n */\n getImmediateChild(childName: string): Node;\n\n /**\n * Returns a child by path, or null if it doesn't exist.\n * @param {!Path} path The path of the child to retrieve.\n * @return {!Node} The retrieved child or an empty node.\n */\n getChild(path: Path): Node;\n\n /**\n * Returns the name of the child immediately prior to the specified childNode, or null.\n * @param {!string} childName The name of the child to find the predecessor of.\n * @param {!Node} childNode The node to find the predecessor of.\n * @param {!Index} index The index to use to determine the predecessor\n * @return {?string} The name of the predecessor child, or null if childNode is the first child.\n */\n getPredecessorChildName(\n childName: string,\n childNode: Node,\n index: Index\n ): string | null;\n\n /**\n * Returns a duplicate node, with the specified immediate child updated.\n * Any value in the node will be removed.\n * @param {string} childName The name of the child to update.\n * @param {!Node} newChildNode The new child node\n * @return {!Node} The updated node.\n */\n updateImmediateChild(childName: string, newChildNode: Node): Node;\n\n /**\n * Returns a duplicate node, with the specified child updated. Any value will\n * be removed.\n * @param {!Path} path The path of the child to update.\n * @param {!Node} newChildNode The new child node, which may be an empty node\n * @return {!Node} The updated node.\n */\n updateChild(path: Path, newChildNode: Node): Node;\n\n /**\n * True if the immediate child specified exists\n * @param {!string} childName\n * @return {boolean}\n */\n hasChild(childName: string): boolean;\n\n /**\n * @return {boolean} True if this node has no value or children.\n */\n isEmpty(): boolean;\n\n /**\n * @return {number} The number of children of this node.\n */\n numChildren(): number;\n\n /**\n * Calls action for each child.\n * @param {!Index} index\n * @param {function(string, !Node)} action Action to be called for\n * each child. It's passed the child name and the child node.\n * @return {*} The first truthy value return by action, or the last falsey one\n */\n forEachChild(index: Index, action: (a: string, b: Node) => void): unknown;\n\n /**\n * @param exportFormat True for export format (also wire protocol format).\n * @return Value of this node as JSON.\n */\n val(exportFormat?: boolean): unknown;\n\n /**\n * @return {string} hash representing the node contents.\n */\n hash(): string;\n\n /**\n * @param {!Node} other Another node\n * @return {!number} -1 for less than, 0 for equal, 1 for greater than other\n */\n compareTo(other: Node): number;\n\n /**\n * @param {!Node} other\n * @return {boolean} Whether or not this snapshot equals other\n */\n equals(other: Node): boolean;\n\n /**\n * @param {!Index} indexDefinition\n * @return {!Node} This node, with the specified index now available\n */\n withIndex(indexDefinition: Index): Node;\n\n /**\n * @param {!Index} indexDefinition\n * @return {boolean}\n */\n isIndexed(indexDefinition: Index): boolean;\n}\n\n/**\n *\n * @param {!string} name\n * @param {!Node} node\n * @constructor\n * @struct\n */\nexport class NamedNode {\n constructor(public name: string, public node: Node) {}\n\n /**\n *\n * @param {!string} name\n * @param {!Node} node\n * @return {NamedNode}\n */\n static Wrap(name: string, node: Node) {\n return new NamedNode(name, node);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Node, NamedNode } from '../Node';\nimport { MIN_NAME, MAX_NAME } from '../../util/util';\nimport { Comparator } from '../../util/SortedMap';\n\n/**\n *\n * @constructor\n */\nexport abstract class Index {\n /**\n * @param {!NamedNode} a\n * @param {!NamedNode} b\n * @return {number}\n */\n abstract compare(a: NamedNode, b: NamedNode): number;\n\n /**\n * @param {!Node} node\n * @return {boolean}\n */\n abstract isDefinedOn(node: Node): boolean;\n\n /**\n * @return {function(!NamedNode, !NamedNode):number} A standalone comparison function for\n * this index\n */\n getCompare(): Comparator {\n return this.compare.bind(this);\n }\n\n /**\n * Given a before and after value for a node, determine if the indexed value has changed. Even if they are different,\n * it's possible that the changes are isolated to parts of the snapshot that are not indexed.\n *\n * @param {!Node} oldNode\n * @param {!Node} newNode\n * @return {boolean} True if the portion of the snapshot being indexed changed between oldNode and newNode\n */\n indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n const oldWrapped = new NamedNode(MIN_NAME, oldNode);\n const newWrapped = new NamedNode(MIN_NAME, newNode);\n return this.compare(oldWrapped, newWrapped) !== 0;\n }\n\n /**\n * @return {!NamedNode} a node wrapper that will sort equal to or less than\n * any other node wrapper, using this index\n */\n minPost(): NamedNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (NamedNode as any).MIN;\n }\n\n /**\n * @return {!NamedNode} a node wrapper that will sort greater than or equal to\n * any other node wrapper, using this index\n */\n abstract maxPost(): NamedNode;\n\n /**\n * @param {*} indexValue\n * @param {string} name\n * @return {!NamedNode}\n */\n abstract makePost(indexValue: unknown, name: string): NamedNode;\n\n /**\n * @return {!string} String representation for inclusion in a query spec\n */\n abstract toString(): string;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Index } from './Index';\nimport { Node, NamedNode } from '../Node';\nimport { nameCompare, MAX_NAME } from '../../util/util';\nimport { assert, assertionError } from '@firebase/util';\nimport { ChildrenNode } from '../ChildrenNode';\n\nlet __EMPTY_NODE: ChildrenNode;\n\nexport class KeyIndex extends Index {\n static get __EMPTY_NODE() {\n return __EMPTY_NODE;\n }\n\n static set __EMPTY_NODE(val) {\n __EMPTY_NODE = val;\n }\n\n /**\n * @inheritDoc\n */\n compare(a: NamedNode, b: NamedNode): number {\n return nameCompare(a.name, b.name);\n }\n\n /**\n * @inheritDoc\n */\n isDefinedOn(node: Node): boolean {\n // We could probably return true here (since every node has a key), but it's never called\n // so just leaving unimplemented for now.\n throw assertionError('KeyIndex.isDefinedOn not expected to be called.');\n }\n\n /**\n * @inheritDoc\n */\n indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n return false; // The key for a node never changes.\n }\n\n /**\n * @inheritDoc\n */\n minPost() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (NamedNode as any).MIN;\n }\n\n /**\n * @inheritDoc\n */\n maxPost(): NamedNode {\n // TODO: This should really be created once and cached in a static property, but\n // NamedNode isn't defined yet, so I can't use it in a static. Bleh.\n return new NamedNode(MAX_NAME, __EMPTY_NODE);\n }\n\n /**\n * @param {*} indexValue\n * @param {string} name\n * @return {!NamedNode}\n */\n makePost(indexValue: string, name: string): NamedNode {\n assert(\n typeof indexValue === 'string',\n 'KeyIndex indexValue must always be a string.'\n );\n // We just use empty node, but it'll never be compared, since our comparator only looks at name.\n return new NamedNode(indexValue, __EMPTY_NODE);\n }\n\n /**\n * @return {!string} String representation for inclusion in a query spec\n */\n toString(): string {\n return '.key';\n }\n}\n\nexport const KEY_INDEX = new KeyIndex();\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, contains } from '@firebase/util';\nimport { doubleToIEEE754String } from '../util/util';\n\nimport { Node } from './Node';\nimport { Indexable } from '../util/misc';\n\nlet MAX_NODE: Node;\n\nexport function setMaxNode(val: Node) {\n MAX_NODE = val;\n}\n\n/**\n * @param {(!string|!number)} priority\n * @return {!string}\n */\nexport const priorityHashText = function(priority: string | number): string {\n if (typeof priority === 'number') {\n return 'number:' + doubleToIEEE754String(priority);\n } else {\n return 'string:' + priority;\n }\n};\n\n/**\n * Validates that a priority snapshot Node is valid.\n *\n * @param {!Node} priorityNode\n */\nexport const validatePriorityNode = function(priorityNode: Node) {\n if (priorityNode.isLeafNode()) {\n const val = priorityNode.val();\n assert(\n typeof val === 'string' ||\n typeof val === 'number' ||\n (typeof val === 'object' && contains(val as Indexable, '.sv')),\n 'Priority must be a string or number.'\n );\n } else {\n assert(\n priorityNode === MAX_NODE || priorityNode.isEmpty(),\n 'priority of unexpected type.'\n );\n }\n // Don't call getPriority() on MAX_NODE to avoid hitting assertion.\n assert(\n priorityNode === MAX_NODE || priorityNode.getPriority().isEmpty(),\n \"Priority nodes can't have a priority of their own.\"\n );\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { doubleToIEEE754String, sha1 } from '../util/util';\nimport { priorityHashText, validatePriorityNode } from './snap';\nimport { Node } from './Node';\nimport { Path } from '../util/Path';\nimport { Index } from './indexes/Index';\nimport { ChildrenNodeConstructor } from './ChildrenNode';\nimport { Indexable } from '../util/misc';\n\nlet __childrenNodeConstructor: ChildrenNodeConstructor;\n\n/**\n * LeafNode is a class for storing leaf nodes in a DataSnapshot. It\n * implements Node and stores the value of the node (a string,\n * number, or boolean) accessible via getValue().\n */\nexport class LeafNode implements Node {\n static set __childrenNodeConstructor(val: ChildrenNodeConstructor) {\n __childrenNodeConstructor = val;\n }\n\n static get __childrenNodeConstructor() {\n return __childrenNodeConstructor;\n }\n\n /**\n * The sort order for comparing leaf nodes of different types. If two leaf nodes have\n * the same type, the comparison falls back to their value\n * @type {Array.}\n * @const\n */\n static VALUE_TYPE_ORDER = ['object', 'boolean', 'number', 'string'];\n\n private lazyHash_: string | null = null;\n\n /**\n * @implements {Node}\n * @param {!(string|number|boolean|Object)} value_ The value to store in this leaf node.\n * The object type is possible in the event of a deferred value\n * @param {!Node=} priorityNode_ The priority of this node.\n */\n constructor(\n private readonly value_: string | number | boolean | Indexable,\n private priorityNode_: Node = LeafNode.__childrenNodeConstructor.EMPTY_NODE\n ) {\n assert(\n this.value_ !== undefined && this.value_ !== null,\n \"LeafNode shouldn't be created with null/undefined value.\"\n );\n\n validatePriorityNode(this.priorityNode_);\n }\n\n /** @inheritDoc */\n isLeafNode(): boolean {\n return true;\n }\n\n /** @inheritDoc */\n getPriority(): Node {\n return this.priorityNode_;\n }\n\n /** @inheritDoc */\n updatePriority(newPriorityNode: Node): Node {\n return new LeafNode(this.value_, newPriorityNode);\n }\n\n /** @inheritDoc */\n getImmediateChild(childName: string): Node {\n // Hack to treat priority as a regular child\n if (childName === '.priority') {\n return this.priorityNode_;\n } else {\n return LeafNode.__childrenNodeConstructor.EMPTY_NODE;\n }\n }\n\n /** @inheritDoc */\n getChild(path: Path): Node {\n if (path.isEmpty()) {\n return this;\n } else if (path.getFront() === '.priority') {\n return this.priorityNode_;\n } else {\n return LeafNode.__childrenNodeConstructor.EMPTY_NODE;\n }\n }\n\n /**\n * @inheritDoc\n */\n hasChild(): boolean {\n return false;\n }\n\n /** @inheritDoc */\n getPredecessorChildName(childName: string, childNode: Node): null {\n return null;\n }\n\n /** @inheritDoc */\n updateImmediateChild(childName: string, newChildNode: Node): Node {\n if (childName === '.priority') {\n return this.updatePriority(newChildNode);\n } else if (newChildNode.isEmpty() && childName !== '.priority') {\n return this;\n } else {\n return LeafNode.__childrenNodeConstructor.EMPTY_NODE.updateImmediateChild(\n childName,\n newChildNode\n ).updatePriority(this.priorityNode_);\n }\n }\n\n /** @inheritDoc */\n updateChild(path: Path, newChildNode: Node): Node {\n const front = path.getFront();\n if (front === null) {\n return newChildNode;\n } else if (newChildNode.isEmpty() && front !== '.priority') {\n return this;\n } else {\n assert(\n front !== '.priority' || path.getLength() === 1,\n '.priority must be the last token in a path'\n );\n\n return this.updateImmediateChild(\n front,\n LeafNode.__childrenNodeConstructor.EMPTY_NODE.updateChild(\n path.popFront(),\n newChildNode\n )\n );\n }\n }\n\n /** @inheritDoc */\n isEmpty(): boolean {\n return false;\n }\n\n /** @inheritDoc */\n numChildren(): number {\n return 0;\n }\n\n /** @inheritDoc */\n forEachChild(index: Index, action: (s: string, n: Node) => void): boolean {\n return false;\n }\n\n /**\n * @inheritDoc\n */\n val(exportFormat?: boolean): {} {\n if (exportFormat && !this.getPriority().isEmpty()) {\n return {\n '.value': this.getValue(),\n '.priority': this.getPriority().val()\n };\n } else {\n return this.getValue();\n }\n }\n\n /** @inheritDoc */\n hash(): string {\n if (this.lazyHash_ === null) {\n let toHash = '';\n if (!this.priorityNode_.isEmpty()) {\n toHash +=\n 'priority:' +\n priorityHashText(this.priorityNode_.val() as number | string) +\n ':';\n }\n\n const type = typeof this.value_;\n toHash += type + ':';\n if (type === 'number') {\n toHash += doubleToIEEE754String(this.value_ as number);\n } else {\n toHash += this.value_;\n }\n this.lazyHash_ = sha1(toHash);\n }\n return this.lazyHash_;\n }\n\n /**\n * Returns the value of the leaf node.\n * @return {Object|string|number|boolean} The value of the node.\n */\n getValue(): Indexable | string | number | boolean {\n return this.value_;\n }\n\n /**\n * @inheritDoc\n */\n compareTo(other: Node): number {\n if (other === LeafNode.__childrenNodeConstructor.EMPTY_NODE) {\n return 1;\n } else if (other instanceof LeafNode.__childrenNodeConstructor) {\n return -1;\n } else {\n assert(other.isLeafNode(), 'Unknown node type');\n return this.compareToLeafNode_(other as LeafNode);\n }\n }\n\n /**\n * Comparison specifically for two leaf nodes\n * @param {!LeafNode} otherLeaf\n * @return {!number}\n * @private\n */\n private compareToLeafNode_(otherLeaf: LeafNode): number {\n const otherLeafType = typeof otherLeaf.value_;\n const thisLeafType = typeof this.value_;\n const otherIndex = LeafNode.VALUE_TYPE_ORDER.indexOf(otherLeafType);\n const thisIndex = LeafNode.VALUE_TYPE_ORDER.indexOf(thisLeafType);\n assert(otherIndex >= 0, 'Unknown leaf type: ' + otherLeafType);\n assert(thisIndex >= 0, 'Unknown leaf type: ' + thisLeafType);\n if (otherIndex === thisIndex) {\n // Same type, compare values\n if (thisLeafType === 'object') {\n // Deferred value nodes are all equal, but we should also never get to this point...\n return 0;\n } else {\n // Note that this works because true > false, all others are number or string comparisons\n if (this.value_ < otherLeaf.value_) {\n return -1;\n } else if (this.value_ === otherLeaf.value_) {\n return 0;\n } else {\n return 1;\n }\n }\n } else {\n return thisIndex - otherIndex;\n }\n }\n\n /**\n * @inheritDoc\n */\n withIndex(): Node {\n return this;\n }\n\n /**\n * @inheritDoc\n */\n isIndexed(): boolean {\n return true;\n }\n\n /**\n * @inheritDoc\n */\n equals(other: Node): boolean {\n /**\n * @inheritDoc\n */\n if (other === this) {\n return true;\n } else if (other.isLeafNode()) {\n const otherLeaf = other as LeafNode;\n return (\n this.value_ === otherLeaf.value_ &&\n this.priorityNode_.equals(otherLeaf.priorityNode_)\n );\n } else {\n return false;\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Index } from './Index';\nimport { nameCompare, MAX_NAME } from '../../util/util';\nimport { NamedNode, Node } from '../Node';\nimport { LeafNode } from '../LeafNode';\n\nlet nodeFromJSON: (a: unknown) => Node;\nlet MAX_NODE: Node;\n\nexport function setNodeFromJSON(val: (a: unknown) => Node) {\n nodeFromJSON = val;\n}\n\nexport function setMaxNode(val: Node) {\n MAX_NODE = val;\n}\n\n/**\n * @constructor\n * @extends {Index}\n * @private\n */\nexport class PriorityIndex extends Index {\n /**\n * @inheritDoc\n */\n compare(a: NamedNode, b: NamedNode): number {\n const aPriority = a.node.getPriority();\n const bPriority = b.node.getPriority();\n const indexCmp = aPriority.compareTo(bPriority);\n if (indexCmp === 0) {\n return nameCompare(a.name, b.name);\n } else {\n return indexCmp;\n }\n }\n\n /**\n * @inheritDoc\n */\n isDefinedOn(node: Node): boolean {\n return !node.getPriority().isEmpty();\n }\n\n /**\n * @inheritDoc\n */\n indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n return !oldNode.getPriority().equals(newNode.getPriority());\n }\n\n /**\n * @inheritDoc\n */\n minPost(): NamedNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (NamedNode as any).MIN;\n }\n\n /**\n * @inheritDoc\n */\n maxPost(): NamedNode {\n return new NamedNode(MAX_NAME, new LeafNode('[PRIORITY-POST]', MAX_NODE));\n }\n\n /**\n * @param {*} indexValue\n * @param {string} name\n * @return {!NamedNode}\n */\n makePost(indexValue: unknown, name: string): NamedNode {\n const priorityNode = nodeFromJSON(indexValue);\n return new NamedNode(name, new LeafNode('[PRIORITY-POST]', priorityNode));\n }\n\n /**\n * @return {!string} String representation for inclusion in a query spec\n */\n toString(): string {\n return '.priority';\n }\n}\n\nexport const PRIORITY_INDEX = new PriorityIndex();\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview Implementation of an immutable SortedMap using a Left-leaning\n * Red-Black Tree, adapted from the implementation in Mugs\n * (http://mads379.github.com/mugs/) by Mads Hartmann Jensen\n * (mads379@gmail.com).\n *\n * Original paper on Left-leaning Red-Black Trees:\n * http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf\n *\n * Invariant 1: No red node has a red child\n * Invariant 2: Every leaf path has the same number of black nodes\n * Invariant 3: Only the left child can be red (left leaning)\n */\n\n// TODO: There are some improvements I'd like to make to improve memory / perf:\n// * Create two prototypes, LLRedNode and LLBlackNode, instead of storing a\n// color property in every node.\n// TODO: It would also be good (and possibly necessary) to create a base\n// interface for LLRBNode and LLRBEmptyNode.\n\nexport type Comparator = (key1: K, key2: K) => number;\n\n/**\n * An iterator over an LLRBNode.\n */\nexport class SortedMapIterator {\n /** @private\n * @type {Array.}\n */\n private nodeStack_: Array | LLRBEmptyNode> = [];\n\n /**\n * @template K, V, T\n * @param {LLRBNode|LLRBEmptyNode} node Node to iterate.\n * @param {?K} startKey\n * @param {function(K, K): number} comparator\n * @param {boolean} isReverse_ Whether or not to iterate in reverse\n * @param {(function(K, V):T)=} resultGenerator_\n */\n constructor(\n node: LLRBNode | LLRBEmptyNode,\n startKey: K | null,\n comparator: Comparator,\n private isReverse_: boolean,\n private resultGenerator_: ((k: K, v: V) => T) | null = null\n ) {\n let cmp = 1;\n while (!node.isEmpty()) {\n node = node as LLRBNode;\n cmp = startKey ? comparator(node.key, startKey) : 1;\n // flip the comparison if we're going in reverse\n if (isReverse_) {\n cmp *= -1;\n }\n\n if (cmp < 0) {\n // This node is less than our start key. ignore it\n if (this.isReverse_) {\n node = node.left;\n } else {\n node = node.right;\n }\n } else if (cmp === 0) {\n // This node is exactly equal to our start key. Push it on the stack, but stop iterating;\n this.nodeStack_.push(node);\n break;\n } else {\n // This node is greater than our start key, add it to the stack and move to the next one\n this.nodeStack_.push(node);\n if (this.isReverse_) {\n node = node.right;\n } else {\n node = node.left;\n }\n }\n }\n }\n\n getNext(): T {\n if (this.nodeStack_.length === 0) {\n return null;\n }\n\n let node = this.nodeStack_.pop();\n let result: T;\n if (this.resultGenerator_) {\n result = this.resultGenerator_(node.key, node.value);\n } else {\n result = ({ key: node.key, value: node.value } as unknown) as T;\n }\n\n if (this.isReverse_) {\n node = node.left;\n while (!node.isEmpty()) {\n this.nodeStack_.push(node);\n node = node.right;\n }\n } else {\n node = node.right;\n while (!node.isEmpty()) {\n this.nodeStack_.push(node);\n node = node.left;\n }\n }\n\n return result;\n }\n\n hasNext(): boolean {\n return this.nodeStack_.length > 0;\n }\n\n peek(): T {\n if (this.nodeStack_.length === 0) {\n return null;\n }\n\n const node = this.nodeStack_[this.nodeStack_.length - 1];\n if (this.resultGenerator_) {\n return this.resultGenerator_(node.key, node.value);\n } else {\n return ({ key: node.key, value: node.value } as unknown) as T;\n }\n }\n}\n\n/**\n * Represents a node in a Left-leaning Red-Black tree.\n */\nexport class LLRBNode {\n color: boolean;\n left: LLRBNode | LLRBEmptyNode;\n right: LLRBNode | LLRBEmptyNode;\n\n /**\n * @template K, V\n * @param {!K} key Key associated with this node.\n * @param {!V} value Value associated with this node.\n * @param {?boolean} color Whether this node is red.\n * @param {?(LLRBNode|LLRBEmptyNode)=} left Left child.\n * @param {?(LLRBNode|LLRBEmptyNode)=} right Right child.\n */\n constructor(\n public key: K,\n public value: V,\n color: boolean | null,\n left?: LLRBNode | LLRBEmptyNode | null,\n right?: LLRBNode | LLRBEmptyNode | null\n ) {\n this.color = color != null ? color : LLRBNode.RED;\n this.left =\n left != null ? left : (SortedMap.EMPTY_NODE as LLRBEmptyNode);\n this.right =\n right != null ? right : (SortedMap.EMPTY_NODE as LLRBEmptyNode);\n }\n\n static RED = true;\n static BLACK = false;\n\n /**\n * Returns a copy of the current node, optionally replacing pieces of it.\n *\n * @param {?K} key New key for the node, or null.\n * @param {?V} value New value for the node, or null.\n * @param {?boolean} color New color for the node, or null.\n * @param {?LLRBNode|LLRBEmptyNode} left New left child for the node, or null.\n * @param {?LLRBNode|LLRBEmptyNode} right New right child for the node, or null.\n * @return {!LLRBNode} The node copy.\n */\n copy(\n key: K | null,\n value: V | null,\n color: boolean | null,\n left: LLRBNode | LLRBEmptyNode | null,\n right: LLRBNode | LLRBEmptyNode | null\n ): LLRBNode {\n return new LLRBNode(\n key != null ? key : this.key,\n value != null ? value : this.value,\n color != null ? color : this.color,\n left != null ? left : this.left,\n right != null ? right : this.right\n );\n }\n\n /**\n * @return {number} The total number of nodes in the tree.\n */\n count(): number {\n return this.left.count() + 1 + this.right.count();\n }\n\n /**\n * @return {boolean} True if the tree is empty.\n */\n isEmpty(): boolean {\n return false;\n }\n\n /**\n * Traverses the tree in key order and calls the specified action function\n * for each node.\n *\n * @param {function(!K, !V):*} action Callback function to be called for each\n * node. If it returns true, traversal is aborted.\n * @return {*} The first truthy value returned by action, or the last falsey\n * value returned by action\n */\n inorderTraversal(action: (k: K, v: V) => unknown): boolean {\n return (\n this.left.inorderTraversal(action) ||\n !!action(this.key, this.value) ||\n this.right.inorderTraversal(action)\n );\n }\n\n /**\n * Traverses the tree in reverse key order and calls the specified action function\n * for each node.\n *\n * @param {function(!Object, !Object)} action Callback function to be called for each\n * node. If it returns true, traversal is aborted.\n * @return {*} True if traversal was aborted.\n */\n reverseTraversal(action: (k: K, v: V) => void): boolean {\n return (\n this.right.reverseTraversal(action) ||\n action(this.key, this.value) ||\n this.left.reverseTraversal(action)\n );\n }\n\n /**\n * @return {!Object} The minimum node in the tree.\n * @private\n */\n private min_(): LLRBNode {\n if (this.left.isEmpty()) {\n return this;\n } else {\n return (this.left as LLRBNode).min_();\n }\n }\n\n /**\n * @return {!K} The maximum key in the tree.\n */\n minKey(): K {\n return this.min_().key;\n }\n\n /**\n * @return {!K} The maximum key in the tree.\n */\n maxKey(): K {\n if (this.right.isEmpty()) {\n return this.key;\n } else {\n return this.right.maxKey();\n }\n }\n\n /**\n *\n * @param {!Object} key Key to insert.\n * @param {!Object} value Value to insert.\n * @param {Comparator} comparator Comparator.\n * @return {!LLRBNode} New tree, with the key/value added.\n */\n insert(key: K, value: V, comparator: Comparator): LLRBNode {\n let n: LLRBNode = this;\n const cmp = comparator(key, n.key);\n if (cmp < 0) {\n n = n.copy(null, null, null, n.left.insert(key, value, comparator), null);\n } else if (cmp === 0) {\n n = n.copy(null, value, null, null, null);\n } else {\n n = n.copy(\n null,\n null,\n null,\n null,\n n.right.insert(key, value, comparator)\n );\n }\n return n.fixUp_();\n }\n\n /**\n * @private\n * @return {!LLRBNode|LLRBEmptyNode} New tree, with the minimum key removed.\n */\n private removeMin_(): LLRBNode | LLRBEmptyNode {\n if (this.left.isEmpty()) {\n return SortedMap.EMPTY_NODE as LLRBEmptyNode;\n }\n let n: LLRBNode = this;\n if (!n.left.isRed_() && !n.left.left.isRed_()) {\n n = n.moveRedLeft_();\n }\n n = n.copy(null, null, null, (n.left as LLRBNode).removeMin_(), null);\n return n.fixUp_();\n }\n\n /**\n * @param {!Object} key The key of the item to remove.\n * @param {Comparator} comparator Comparator.\n * @return {!LLRBNode|LLRBEmptyNode} New tree, with the specified item removed.\n */\n remove(\n key: K,\n comparator: Comparator\n ): LLRBNode | LLRBEmptyNode {\n let n, smallest;\n n = this;\n if (comparator(key, n.key) < 0) {\n if (!n.left.isEmpty() && !n.left.isRed_() && !n.left.left.isRed_()) {\n n = n.moveRedLeft_();\n }\n n = n.copy(null, null, null, n.left.remove(key, comparator), null);\n } else {\n if (n.left.isRed_()) {\n n = n.rotateRight_();\n }\n if (!n.right.isEmpty() && !n.right.isRed_() && !n.right.left.isRed_()) {\n n = n.moveRedRight_();\n }\n if (comparator(key, n.key) === 0) {\n if (n.right.isEmpty()) {\n return SortedMap.EMPTY_NODE as LLRBEmptyNode;\n } else {\n smallest = (n.right as LLRBNode).min_();\n n = n.copy(\n smallest.key,\n smallest.value,\n null,\n null,\n (n.right as LLRBNode).removeMin_()\n );\n }\n }\n n = n.copy(null, null, null, null, n.right.remove(key, comparator));\n }\n return n.fixUp_();\n }\n\n /**\n * @private\n * @return {boolean} Whether this is a RED node.\n */\n isRed_(): boolean {\n return this.color;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree after performing any needed rotations.\n */\n private fixUp_(): LLRBNode {\n let n: LLRBNode = this;\n if (n.right.isRed_() && !n.left.isRed_()) {\n n = n.rotateLeft_();\n }\n if (n.left.isRed_() && n.left.left.isRed_()) {\n n = n.rotateRight_();\n }\n if (n.left.isRed_() && n.right.isRed_()) {\n n = n.colorFlip_();\n }\n return n;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree, after moveRedLeft.\n */\n private moveRedLeft_(): LLRBNode {\n let n = this.colorFlip_();\n if (n.right.left.isRed_()) {\n n = n.copy(\n null,\n null,\n null,\n null,\n (n.right as LLRBNode).rotateRight_()\n );\n n = n.rotateLeft_();\n n = n.colorFlip_();\n }\n return n;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree, after moveRedRight.\n */\n private moveRedRight_(): LLRBNode {\n let n = this.colorFlip_();\n if (n.left.left.isRed_()) {\n n = n.rotateRight_();\n n = n.colorFlip_();\n }\n return n;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree, after rotateLeft.\n */\n private rotateLeft_(): LLRBNode {\n const nl = this.copy(null, null, LLRBNode.RED, null, this.right.left);\n return this.right.copy(null, null, this.color, nl, null) as LLRBNode;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree, after rotateRight.\n */\n private rotateRight_(): LLRBNode {\n const nr = this.copy(null, null, LLRBNode.RED, this.left.right, null);\n return this.left.copy(null, null, this.color, null, nr) as LLRBNode;\n }\n\n /**\n * @private\n * @return {!LLRBNode} New tree, after colorFlip.\n */\n private colorFlip_(): LLRBNode {\n const left = this.left.copy(null, null, !this.left.color, null, null);\n const right = this.right.copy(null, null, !this.right.color, null, null);\n return this.copy(null, null, !this.color, left, right);\n }\n\n /**\n * For testing.\n *\n * @private\n * @return {boolean} True if all is well.\n */\n private checkMaxDepth_(): boolean {\n const blackDepth = this.check_();\n return Math.pow(2.0, blackDepth) <= this.count() + 1;\n }\n\n /**\n * @private\n * @return {number} Not sure what this returns exactly. :-).\n */\n check_(): number {\n if (this.isRed_() && this.left.isRed_()) {\n throw new Error(\n 'Red node has red child(' + this.key + ',' + this.value + ')'\n );\n }\n if (this.right.isRed_()) {\n throw new Error(\n 'Right child of (' + this.key + ',' + this.value + ') is red'\n );\n }\n const blackDepth = this.left.check_();\n if (blackDepth !== this.right.check_()) {\n throw new Error('Black depths differ');\n } else {\n return blackDepth + (this.isRed_() ? 0 : 1);\n }\n }\n}\n\n/**\n * Represents an empty node (a leaf node in the Red-Black Tree).\n */\nexport class LLRBEmptyNode {\n key: K;\n value: V;\n left: LLRBNode | LLRBEmptyNode;\n right: LLRBNode | LLRBEmptyNode;\n color: boolean;\n\n /**\n * Returns a copy of the current node.\n *\n * @return {!LLRBEmptyNode} The node copy.\n */\n copy(\n key: K | null,\n value: V | null,\n color: boolean | null,\n left: LLRBNode | LLRBEmptyNode | null,\n right: LLRBNode | LLRBEmptyNode | null\n ): LLRBEmptyNode {\n return this;\n }\n\n /**\n * Returns a copy of the tree, with the specified key/value added.\n *\n * @param {!K} key Key to be added.\n * @param {!V} value Value to be added.\n * @param {Comparator} comparator Comparator.\n * @return {!LLRBNode} New tree, with item added.\n */\n insert(key: K, value: V, comparator: Comparator): LLRBNode {\n return new LLRBNode(key, value, null);\n }\n\n /**\n * Returns a copy of the tree, with the specified key removed.\n *\n * @param {!K} key The key to remove.\n * @param {Comparator} comparator Comparator.\n * @return {!LLRBEmptyNode} New tree, with item removed.\n */\n remove(key: K, comparator: Comparator): LLRBEmptyNode {\n return this;\n }\n\n /**\n * @return {number} The total number of nodes in the tree.\n */\n count(): number {\n return 0;\n }\n\n /**\n * @return {boolean} True if the tree is empty.\n */\n isEmpty(): boolean {\n return true;\n }\n\n /**\n * Traverses the tree in key order and calls the specified action function\n * for each node.\n *\n * @param {function(!K, !V):*} action Callback function to be called for each\n * node. If it returns true, traversal is aborted.\n * @return {boolean} True if traversal was aborted.\n */\n inorderTraversal(action: (k: K, v: V) => unknown): boolean {\n return false;\n }\n\n /**\n * Traverses the tree in reverse key order and calls the specified action function\n * for each node.\n *\n * @param {function(!K, !V)} action Callback function to be called for each\n * node. If it returns true, traversal is aborted.\n * @return {boolean} True if traversal was aborted.\n */\n reverseTraversal(action: (k: K, v: V) => void): boolean {\n return false;\n }\n\n /**\n * @return {null}\n */\n minKey(): null {\n return null;\n }\n\n /**\n * @return {null}\n */\n maxKey(): null {\n return null;\n }\n\n /**\n * @private\n * @return {number} Not sure what this returns exactly. :-).\n */\n check_(): number {\n return 0;\n }\n\n /**\n * @private\n * @return {boolean} Whether this node is red.\n */\n isRed_() {\n return false;\n }\n}\n\n/**\n * An immutable sorted map implementation, based on a Left-leaning Red-Black\n * tree.\n */\nexport class SortedMap {\n /**\n * Always use the same empty node, to reduce memory.\n * @const\n */\n static EMPTY_NODE = new LLRBEmptyNode();\n\n /**\n * @template K, V\n * @param {function(K, K):number} comparator_ Key comparator.\n * @param {LLRBNode=} root_ (Optional) Root node for the map.\n */\n constructor(\n private comparator_: Comparator,\n private root_:\n | LLRBNode\n | LLRBEmptyNode = SortedMap.EMPTY_NODE as LLRBEmptyNode\n ) {}\n\n /**\n * Returns a copy of the map, with the specified key/value added or replaced.\n * (TODO: We should perhaps rename this method to 'put')\n *\n * @param {!K} key Key to be added.\n * @param {!V} value Value to be added.\n * @return {!SortedMap.} New map, with item added.\n */\n insert(key: K, value: V): SortedMap {\n return new SortedMap(\n this.comparator_,\n this.root_\n .insert(key, value, this.comparator_)\n .copy(null, null, LLRBNode.BLACK, null, null)\n );\n }\n\n /**\n * Returns a copy of the map, with the specified key removed.\n *\n * @param {!K} key The key to remove.\n * @return {!SortedMap.} New map, with item removed.\n */\n remove(key: K): SortedMap {\n return new SortedMap(\n this.comparator_,\n this.root_\n .remove(key, this.comparator_)\n .copy(null, null, LLRBNode.BLACK, null, null)\n );\n }\n\n /**\n * Returns the value of the node with the given key, or null.\n *\n * @param {!K} key The key to look up.\n * @return {?V} The value of the node with the given key, or null if the\n * key doesn't exist.\n */\n get(key: K): V | null {\n let cmp;\n let node = this.root_;\n while (!node.isEmpty()) {\n cmp = this.comparator_(key, node.key);\n if (cmp === 0) {\n return node.value;\n } else if (cmp < 0) {\n node = node.left;\n } else if (cmp > 0) {\n node = node.right;\n }\n }\n return null;\n }\n\n /**\n * Returns the key of the item *before* the specified key, or null if key is the first item.\n * @param {K} key The key to find the predecessor of\n * @return {?K} The predecessor key.\n */\n getPredecessorKey(key: K): K | null {\n let cmp,\n node = this.root_,\n rightParent = null;\n while (!node.isEmpty()) {\n cmp = this.comparator_(key, node.key);\n if (cmp === 0) {\n if (!node.left.isEmpty()) {\n node = node.left;\n while (!node.right.isEmpty()) {\n node = node.right;\n }\n return node.key;\n } else if (rightParent) {\n return rightParent.key;\n } else {\n return null; // first item.\n }\n } else if (cmp < 0) {\n node = node.left;\n } else if (cmp > 0) {\n rightParent = node;\n node = node.right;\n }\n }\n\n throw new Error(\n 'Attempted to find predecessor key for a nonexistent key. What gives?'\n );\n }\n\n /**\n * @return {boolean} True if the map is empty.\n */\n isEmpty(): boolean {\n return this.root_.isEmpty();\n }\n\n /**\n * @return {number} The total number of nodes in the map.\n */\n count(): number {\n return this.root_.count();\n }\n\n /**\n * @return {?K} The minimum key in the map.\n */\n minKey(): K | null {\n return this.root_.minKey();\n }\n\n /**\n * @return {?K} The maximum key in the map.\n */\n maxKey(): K | null {\n return this.root_.maxKey();\n }\n\n /**\n * Traverses the map in key order and calls the specified action function\n * for each key/value pair.\n *\n * @param {function(!K, !V):*} action Callback function to be called\n * for each key/value pair. If action returns true, traversal is aborted.\n * @return {*} The first truthy value returned by action, or the last falsey\n * value returned by action\n */\n inorderTraversal(action: (k: K, v: V) => unknown): boolean {\n return this.root_.inorderTraversal(action);\n }\n\n /**\n * Traverses the map in reverse key order and calls the specified action function\n * for each key/value pair.\n *\n * @param {function(!Object, !Object)} action Callback function to be called\n * for each key/value pair. If action returns true, traversal is aborted.\n * @return {*} True if the traversal was aborted.\n */\n reverseTraversal(action: (k: K, v: V) => void): boolean {\n return this.root_.reverseTraversal(action);\n }\n\n /**\n * Returns an iterator over the SortedMap.\n * @template T\n * @param {(function(K, V):T)=} resultGenerator\n * @return {SortedMapIterator.} The iterator.\n */\n getIterator(\n resultGenerator?: (k: K, v: V) => T\n ): SortedMapIterator {\n return new SortedMapIterator(\n this.root_,\n null,\n this.comparator_,\n false,\n resultGenerator\n );\n }\n\n getIteratorFrom(\n key: K,\n resultGenerator?: (k: K, v: V) => T\n ): SortedMapIterator {\n return new SortedMapIterator(\n this.root_,\n key,\n this.comparator_,\n false,\n resultGenerator\n );\n }\n\n getReverseIteratorFrom(\n key: K,\n resultGenerator?: (k: K, v: V) => T\n ): SortedMapIterator {\n return new SortedMapIterator(\n this.root_,\n key,\n this.comparator_,\n true,\n resultGenerator\n );\n }\n\n getReverseIterator(\n resultGenerator?: (k: K, v: V) => T\n ): SortedMapIterator {\n return new SortedMapIterator(\n this.root_,\n null,\n this.comparator_,\n true,\n resultGenerator\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LLRBNode, SortedMap } from '../util/SortedMap';\n\nimport { NamedNode } from './Node';\n\nconst LOG_2 = Math.log(2);\n\n/**\n * @constructor\n */\nclass Base12Num {\n count: number;\n private current_: number;\n private bits_: number;\n\n /**\n * @param {number} length\n */\n constructor(length: number) {\n const logBase2 = (num: number) =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n parseInt((Math.log(num) / LOG_2) as any, 10);\n const bitMask = (bits: number) => parseInt(Array(bits + 1).join('1'), 2);\n this.count = logBase2(length + 1);\n this.current_ = this.count - 1;\n const mask = bitMask(this.count);\n this.bits_ = (length + 1) & mask;\n }\n\n /**\n * @return {boolean}\n */\n nextBitIsOne(): boolean {\n //noinspection JSBitwiseOperatorUsage\n const result = !(this.bits_ & (0x1 << this.current_));\n this.current_--;\n return result;\n }\n}\n\n/**\n * Takes a list of child nodes and constructs a SortedSet using the given comparison\n * function\n *\n * Uses the algorithm described in the paper linked here:\n * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.1458\n *\n * @template K, V\n * @param {Array.} childList Unsorted list of children\n * @param {function(!NamedNode, !NamedNode):number} cmp The comparison method to be used\n * @param {(function(NamedNode):K)=} keyFn An optional function to extract K from a node wrapper, if K's\n * type is not NamedNode\n * @param {(function(K, K):number)=} mapSortFn An optional override for comparator used by the generated sorted map\n * @return {SortedMap.}\n */\nexport const buildChildSet = function(\n childList: NamedNode[],\n cmp: (a: NamedNode, b: NamedNode) => number,\n keyFn?: (a: NamedNode) => K,\n mapSortFn?: (a: K, b: K) => number\n): SortedMap {\n childList.sort(cmp);\n\n const buildBalancedTree = function(\n low: number,\n high: number\n ): LLRBNode | null {\n const length = high - low;\n let namedNode: NamedNode;\n let key: K;\n if (length === 0) {\n return null;\n } else if (length === 1) {\n namedNode = childList[low];\n key = keyFn ? keyFn(namedNode) : ((namedNode as unknown) as K);\n return new LLRBNode(\n key,\n (namedNode.node as unknown) as V,\n LLRBNode.BLACK,\n null,\n null\n );\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const middle = parseInt((length / 2) as any, 10) + low;\n const left = buildBalancedTree(low, middle);\n const right = buildBalancedTree(middle + 1, high);\n namedNode = childList[middle];\n key = keyFn ? keyFn(namedNode) : ((namedNode as unknown) as K);\n return new LLRBNode(\n key,\n (namedNode.node as unknown) as V,\n LLRBNode.BLACK,\n left,\n right\n );\n }\n };\n\n const buildFrom12Array = function(base12: Base12Num): LLRBNode {\n let node: LLRBNode = null;\n let root = null;\n let index = childList.length;\n\n const buildPennant = function(chunkSize: number, color: boolean) {\n const low = index - chunkSize;\n const high = index;\n index -= chunkSize;\n const childTree = buildBalancedTree(low + 1, high);\n const namedNode = childList[low];\n const key: K = keyFn ? keyFn(namedNode) : ((namedNode as unknown) as K);\n attachPennant(\n new LLRBNode(\n key,\n (namedNode.node as unknown) as V,\n color,\n null,\n childTree\n )\n );\n };\n\n const attachPennant = function(pennant: LLRBNode) {\n if (node) {\n node.left = pennant;\n node = pennant;\n } else {\n root = pennant;\n node = pennant;\n }\n };\n\n for (let i = 0; i < base12.count; ++i) {\n const isOne = base12.nextBitIsOne();\n // The number of nodes taken in each slice is 2^(arr.length - (i + 1))\n const chunkSize = Math.pow(2, base12.count - (i + 1));\n if (isOne) {\n buildPennant(chunkSize, LLRBNode.BLACK);\n } else {\n // current == 2\n buildPennant(chunkSize, LLRBNode.BLACK);\n buildPennant(chunkSize, LLRBNode.RED);\n }\n }\n return root;\n };\n\n const base12 = new Base12Num(childList.length);\n const root = buildFrom12Array(base12);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new SortedMap(mapSortFn || (cmp as any), root);\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, contains, map, safeGet } from '@firebase/util';\nimport { buildChildSet } from './childSet';\n\nimport { NamedNode, Node } from './Node';\nimport { PRIORITY_INDEX } from './indexes/PriorityIndex';\nimport { KEY_INDEX } from './indexes/KeyIndex';\nimport { SortedMap } from '../util/SortedMap';\nimport { Index } from './indexes/Index';\n\nlet _defaultIndexMap: IndexMap;\n\nconst fallbackObject = {};\n\nexport class IndexMap {\n /**\n * The default IndexMap for nodes without a priority\n */\n static get Default(): IndexMap {\n assert(\n fallbackObject && PRIORITY_INDEX,\n 'ChildrenNode.ts has not been loaded'\n );\n _defaultIndexMap =\n _defaultIndexMap ||\n new IndexMap(\n { '.priority': fallbackObject },\n { '.priority': PRIORITY_INDEX }\n );\n return _defaultIndexMap;\n }\n\n constructor(\n private indexes_: {\n [k: string]: SortedMap | /*FallbackType*/ object;\n },\n private indexSet_: { [k: string]: Index }\n ) {}\n\n get(indexKey: string): SortedMap | null {\n const sortedMap = safeGet(this.indexes_, indexKey);\n if (!sortedMap) {\n throw new Error('No index defined for ' + indexKey);\n }\n\n if (sortedMap instanceof SortedMap) {\n return sortedMap;\n } else {\n // The index exists, but it falls back to just name comparison. Return null so that the calling code uses the\n // regular child map\n return null;\n }\n }\n\n hasIndex(indexDefinition: Index): boolean {\n return contains(this.indexSet_, indexDefinition.toString());\n }\n\n addIndex(\n indexDefinition: Index,\n existingChildren: SortedMap\n ): IndexMap {\n assert(\n indexDefinition !== KEY_INDEX,\n \"KeyIndex always exists and isn't meant to be added to the IndexMap.\"\n );\n const childList = [];\n let sawIndexedValue = false;\n const iter = existingChildren.getIterator(NamedNode.Wrap);\n let next = iter.getNext();\n while (next) {\n sawIndexedValue =\n sawIndexedValue || indexDefinition.isDefinedOn(next.node);\n childList.push(next);\n next = iter.getNext();\n }\n let newIndex;\n if (sawIndexedValue) {\n newIndex = buildChildSet(childList, indexDefinition.getCompare());\n } else {\n newIndex = fallbackObject;\n }\n const indexName = indexDefinition.toString();\n const newIndexSet = { ...this.indexSet_ };\n newIndexSet[indexName] = indexDefinition;\n const newIndexes = { ...this.indexes_ };\n newIndexes[indexName] = newIndex;\n return new IndexMap(newIndexes, newIndexSet);\n }\n\n /**\n * Ensure that this node is properly tracked in any indexes that we're maintaining\n */\n addToIndexes(\n namedNode: NamedNode,\n existingChildren: SortedMap\n ): IndexMap {\n const newIndexes = map(\n this.indexes_,\n (indexedChildren: SortedMap, indexName: string) => {\n const index = safeGet(this.indexSet_, indexName);\n assert(index, 'Missing index implementation for ' + indexName);\n if (indexedChildren === fallbackObject) {\n // Check to see if we need to index everything\n if (index.isDefinedOn(namedNode.node)) {\n // We need to build this index\n const childList = [];\n const iter = existingChildren.getIterator(NamedNode.Wrap);\n let next = iter.getNext();\n while (next) {\n if (next.name !== namedNode.name) {\n childList.push(next);\n }\n next = iter.getNext();\n }\n childList.push(namedNode);\n return buildChildSet(childList, index.getCompare());\n } else {\n // No change, this remains a fallback\n return fallbackObject;\n }\n } else {\n const existingSnap = existingChildren.get(namedNode.name);\n let newChildren = indexedChildren;\n if (existingSnap) {\n newChildren = newChildren.remove(\n new NamedNode(namedNode.name, existingSnap)\n );\n }\n return newChildren.insert(namedNode, namedNode.node);\n }\n }\n );\n return new IndexMap(newIndexes, this.indexSet_);\n }\n\n /**\n * Create a new IndexMap instance with the given value removed\n */\n removeFromIndexes(\n namedNode: NamedNode,\n existingChildren: SortedMap\n ): IndexMap {\n const newIndexes = map(\n this.indexes_,\n (indexedChildren: SortedMap) => {\n if (indexedChildren === fallbackObject) {\n // This is the fallback. Just return it, nothing to do in this case\n return indexedChildren;\n } else {\n const existingSnap = existingChildren.get(namedNode.name);\n if (existingSnap) {\n return indexedChildren.remove(\n new NamedNode(namedNode.name, existingSnap)\n );\n } else {\n // No record of this child\n return indexedChildren;\n }\n }\n }\n );\n return new IndexMap(newIndexes, this.indexSet_);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { sha1, MAX_NAME, MIN_NAME } from '../util/util';\nimport { SortedMap, SortedMapIterator } from '../util/SortedMap';\nimport { Node, NamedNode } from './Node';\nimport { validatePriorityNode, priorityHashText, setMaxNode } from './snap';\nimport {\n PRIORITY_INDEX,\n setMaxNode as setPriorityMaxNode\n} from './indexes/PriorityIndex';\nimport { KEY_INDEX, KeyIndex } from './indexes/KeyIndex';\nimport { IndexMap } from './IndexMap';\nimport { LeafNode } from './LeafNode';\nimport { NAME_COMPARATOR } from './comparators';\nimport { Index } from './indexes/Index';\nimport { Path } from '../util/Path';\n\nexport interface ChildrenNodeConstructor {\n new (\n children_: SortedMap,\n priorityNode_: Node | null,\n indexMap_: IndexMap\n ): ChildrenNode;\n EMPTY_NODE: ChildrenNode;\n}\n\n// TODO: For memory savings, don't store priorityNode_ if it's empty.\n\nlet EMPTY_NODE: ChildrenNode;\n\n/**\n * ChildrenNode is a class for storing internal nodes in a DataSnapshot\n * (i.e. nodes with children). It implements Node and stores the\n * list of children in the children property, sorted by child name.\n *\n * @constructor\n * @implements {Node}\n */\nexport class ChildrenNode implements Node {\n private lazyHash_: string | null = null;\n\n static get EMPTY_NODE(): ChildrenNode {\n return (\n EMPTY_NODE ||\n (EMPTY_NODE = new ChildrenNode(\n new SortedMap(NAME_COMPARATOR),\n null,\n IndexMap.Default\n ))\n );\n }\n\n /**\n *\n * @param {!SortedMap.} children_ List of children\n * of this node..\n * @param {?Node} priorityNode_ The priority of this node (as a snapshot node).\n * @param {!IndexMap} indexMap_\n */\n constructor(\n private readonly children_: SortedMap,\n private readonly priorityNode_: Node | null,\n private indexMap_: IndexMap\n ) {\n /**\n * Note: The only reason we allow null priority is for EMPTY_NODE, since we can't use\n * EMPTY_NODE as the priority of EMPTY_NODE. We might want to consider making EMPTY_NODE its own\n * class instead of an empty ChildrenNode.\n */\n if (this.priorityNode_) {\n validatePriorityNode(this.priorityNode_);\n }\n\n if (this.children_.isEmpty()) {\n assert(\n !this.priorityNode_ || this.priorityNode_.isEmpty(),\n 'An empty node cannot have a priority'\n );\n }\n }\n\n /** @inheritDoc */\n isLeafNode(): boolean {\n return false;\n }\n\n /** @inheritDoc */\n getPriority(): Node {\n return this.priorityNode_ || EMPTY_NODE;\n }\n\n /** @inheritDoc */\n updatePriority(newPriorityNode: Node): Node {\n if (this.children_.isEmpty()) {\n // Don't allow priorities on empty nodes\n return this;\n } else {\n return new ChildrenNode(this.children_, newPriorityNode, this.indexMap_);\n }\n }\n\n /** @inheritDoc */\n getImmediateChild(childName: string): Node {\n // Hack to treat priority as a regular child\n if (childName === '.priority') {\n return this.getPriority();\n } else {\n const child = this.children_.get(childName);\n return child === null ? EMPTY_NODE : child;\n }\n }\n\n /** @inheritDoc */\n getChild(path: Path): Node {\n const front = path.getFront();\n if (front === null) {\n return this;\n }\n\n return this.getImmediateChild(front).getChild(path.popFront());\n }\n\n /** @inheritDoc */\n hasChild(childName: string): boolean {\n return this.children_.get(childName) !== null;\n }\n\n /** @inheritDoc */\n updateImmediateChild(childName: string, newChildNode: Node): Node {\n assert(newChildNode, 'We should always be passing snapshot nodes');\n if (childName === '.priority') {\n return this.updatePriority(newChildNode);\n } else {\n const namedNode = new NamedNode(childName, newChildNode);\n let newChildren, newIndexMap;\n if (newChildNode.isEmpty()) {\n newChildren = this.children_.remove(childName);\n newIndexMap = this.indexMap_.removeFromIndexes(\n namedNode,\n this.children_\n );\n } else {\n newChildren = this.children_.insert(childName, newChildNode);\n newIndexMap = this.indexMap_.addToIndexes(namedNode, this.children_);\n }\n\n const newPriority = newChildren.isEmpty()\n ? EMPTY_NODE\n : this.priorityNode_;\n return new ChildrenNode(newChildren, newPriority, newIndexMap);\n }\n }\n\n /** @inheritDoc */\n updateChild(path: Path, newChildNode: Node): Node {\n const front = path.getFront();\n if (front === null) {\n return newChildNode;\n } else {\n assert(\n path.getFront() !== '.priority' || path.getLength() === 1,\n '.priority must be the last token in a path'\n );\n const newImmediateChild = this.getImmediateChild(front).updateChild(\n path.popFront(),\n newChildNode\n );\n return this.updateImmediateChild(front, newImmediateChild);\n }\n }\n\n /** @inheritDoc */\n isEmpty(): boolean {\n return this.children_.isEmpty();\n }\n\n /** @inheritDoc */\n numChildren(): number {\n return this.children_.count();\n }\n\n /**\n * @private\n * @type {RegExp}\n */\n private static INTEGER_REGEXP_ = /^(0|[1-9]\\d*)$/;\n\n /** @inheritDoc */\n val(exportFormat?: boolean): object {\n if (this.isEmpty()) {\n return null;\n }\n\n const obj: { [k: string]: unknown } = {};\n let numKeys = 0,\n maxKey = 0,\n allIntegerKeys = true;\n this.forEachChild(PRIORITY_INDEX, (key: string, childNode: Node) => {\n obj[key] = childNode.val(exportFormat);\n\n numKeys++;\n if (allIntegerKeys && ChildrenNode.INTEGER_REGEXP_.test(key)) {\n maxKey = Math.max(maxKey, Number(key));\n } else {\n allIntegerKeys = false;\n }\n });\n\n if (!exportFormat && allIntegerKeys && maxKey < 2 * numKeys) {\n // convert to array.\n const array: unknown[] = [];\n // eslint-disable-next-line guard-for-in\n for (const key in obj) {\n array[(key as unknown) as number] = obj[key];\n }\n\n return array;\n } else {\n if (exportFormat && !this.getPriority().isEmpty()) {\n obj['.priority'] = this.getPriority().val();\n }\n return obj;\n }\n }\n\n /** @inheritDoc */\n hash(): string {\n if (this.lazyHash_ === null) {\n let toHash = '';\n if (!this.getPriority().isEmpty()) {\n toHash +=\n 'priority:' +\n priorityHashText(this.getPriority().val() as string | number) +\n ':';\n }\n\n this.forEachChild(PRIORITY_INDEX, (key, childNode) => {\n const childHash = childNode.hash();\n if (childHash !== '') {\n toHash += ':' + key + ':' + childHash;\n }\n });\n\n this.lazyHash_ = toHash === '' ? '' : sha1(toHash);\n }\n return this.lazyHash_;\n }\n\n /** @inheritDoc */\n getPredecessorChildName(\n childName: string,\n childNode: Node,\n index: Index\n ): string {\n const idx = this.resolveIndex_(index);\n if (idx) {\n const predecessor = idx.getPredecessorKey(\n new NamedNode(childName, childNode)\n );\n return predecessor ? predecessor.name : null;\n } else {\n return this.children_.getPredecessorKey(childName);\n }\n }\n\n /**\n * @param {!Index} indexDefinition\n * @return {?string}\n */\n getFirstChildName(indexDefinition: Index): string | null {\n const idx = this.resolveIndex_(indexDefinition);\n if (idx) {\n const minKey = idx.minKey();\n return minKey && minKey.name;\n } else {\n return this.children_.minKey();\n }\n }\n\n /**\n * @param {!Index} indexDefinition\n * @return {?NamedNode}\n */\n getFirstChild(indexDefinition: Index): NamedNode | null {\n const minKey = this.getFirstChildName(indexDefinition);\n if (minKey) {\n return new NamedNode(minKey, this.children_.get(minKey));\n } else {\n return null;\n }\n }\n\n /**\n * Given an index, return the key name of the largest value we have, according to that index\n * @param {!Index} indexDefinition\n * @return {?string}\n */\n getLastChildName(indexDefinition: Index): string | null {\n const idx = this.resolveIndex_(indexDefinition);\n if (idx) {\n const maxKey = idx.maxKey();\n return maxKey && maxKey.name;\n } else {\n return this.children_.maxKey();\n }\n }\n\n /**\n * @param {!Index} indexDefinition\n * @return {?NamedNode}\n */\n getLastChild(indexDefinition: Index): NamedNode | null {\n const maxKey = this.getLastChildName(indexDefinition);\n if (maxKey) {\n return new NamedNode(maxKey, this.children_.get(maxKey));\n } else {\n return null;\n }\n }\n\n /**\n * @inheritDoc\n */\n forEachChild(\n index: Index,\n action: (key: string, node: Node) => boolean | void\n ): boolean {\n const idx = this.resolveIndex_(index);\n if (idx) {\n return idx.inorderTraversal(wrappedNode => {\n return action(wrappedNode.name, wrappedNode.node);\n });\n } else {\n return this.children_.inorderTraversal(action);\n }\n }\n\n /**\n * @param {!Index} indexDefinition\n * @return {SortedMapIterator}\n */\n getIterator(\n indexDefinition: Index\n ): SortedMapIterator {\n return this.getIteratorFrom(indexDefinition.minPost(), indexDefinition);\n }\n\n /**\n *\n * @param {!NamedNode} startPost\n * @param {!Index} indexDefinition\n * @return {!SortedMapIterator}\n */\n getIteratorFrom(\n startPost: NamedNode,\n indexDefinition: Index\n ): SortedMapIterator {\n const idx = this.resolveIndex_(indexDefinition);\n if (idx) {\n return idx.getIteratorFrom(startPost, key => key);\n } else {\n const iterator = this.children_.getIteratorFrom(\n startPost.name,\n NamedNode.Wrap\n );\n let next = iterator.peek();\n while (next != null && indexDefinition.compare(next, startPost) < 0) {\n iterator.getNext();\n next = iterator.peek();\n }\n return iterator;\n }\n }\n\n /**\n * @param {!Index} indexDefinition\n * @return {!SortedMapIterator}\n */\n getReverseIterator(\n indexDefinition: Index\n ): SortedMapIterator {\n return this.getReverseIteratorFrom(\n indexDefinition.maxPost(),\n indexDefinition\n );\n }\n\n /**\n * @param {!NamedNode} endPost\n * @param {!Index} indexDefinition\n * @return {!SortedMapIterator}\n */\n getReverseIteratorFrom(\n endPost: NamedNode,\n indexDefinition: Index\n ): SortedMapIterator {\n const idx = this.resolveIndex_(indexDefinition);\n if (idx) {\n return idx.getReverseIteratorFrom(endPost, key => {\n return key;\n });\n } else {\n const iterator = this.children_.getReverseIteratorFrom(\n endPost.name,\n NamedNode.Wrap\n );\n let next = iterator.peek();\n while (next != null && indexDefinition.compare(next, endPost) > 0) {\n iterator.getNext();\n next = iterator.peek();\n }\n return iterator;\n }\n }\n\n /**\n * @inheritDoc\n */\n compareTo(other: ChildrenNode): number {\n if (this.isEmpty()) {\n if (other.isEmpty()) {\n return 0;\n } else {\n return -1;\n }\n } else if (other.isLeafNode() || other.isEmpty()) {\n return 1;\n } else if (other === MAX_NODE) {\n return -1;\n } else {\n // Must be another node with children.\n return 0;\n }\n }\n\n /**\n * @inheritDoc\n */\n withIndex(indexDefinition: Index): Node {\n if (\n indexDefinition === KEY_INDEX ||\n this.indexMap_.hasIndex(indexDefinition)\n ) {\n return this;\n } else {\n const newIndexMap = this.indexMap_.addIndex(\n indexDefinition,\n this.children_\n );\n return new ChildrenNode(this.children_, this.priorityNode_, newIndexMap);\n }\n }\n\n /**\n * @inheritDoc\n */\n isIndexed(index: Index): boolean {\n return index === KEY_INDEX || this.indexMap_.hasIndex(index);\n }\n\n /**\n * @inheritDoc\n */\n equals(other: Node): boolean {\n if (other === this) {\n return true;\n } else if (other.isLeafNode()) {\n return false;\n } else {\n const otherChildrenNode = other as ChildrenNode;\n if (!this.getPriority().equals(otherChildrenNode.getPriority())) {\n return false;\n } else if (\n this.children_.count() === otherChildrenNode.children_.count()\n ) {\n const thisIter = this.getIterator(PRIORITY_INDEX);\n const otherIter = otherChildrenNode.getIterator(PRIORITY_INDEX);\n let thisCurrent = thisIter.getNext();\n let otherCurrent = otherIter.getNext();\n while (thisCurrent && otherCurrent) {\n if (\n thisCurrent.name !== otherCurrent.name ||\n !thisCurrent.node.equals(otherCurrent.node)\n ) {\n return false;\n }\n thisCurrent = thisIter.getNext();\n otherCurrent = otherIter.getNext();\n }\n return thisCurrent === null && otherCurrent === null;\n } else {\n return false;\n }\n }\n }\n\n /**\n * Returns a SortedMap ordered by index, or null if the default (by-key) ordering can be used\n * instead.\n *\n * @private\n * @param {!Index} indexDefinition\n * @return {?SortedMap.}\n */\n private resolveIndex_(\n indexDefinition: Index\n ): SortedMap | null {\n if (indexDefinition === KEY_INDEX) {\n return null;\n } else {\n return this.indexMap_.get(indexDefinition.toString());\n }\n }\n}\n\n/**\n * @constructor\n * @extends {ChildrenNode}\n * @private\n */\nexport class MaxNode extends ChildrenNode {\n constructor() {\n super(\n new SortedMap(NAME_COMPARATOR),\n ChildrenNode.EMPTY_NODE,\n IndexMap.Default\n );\n }\n\n compareTo(other: Node): number {\n if (other === this) {\n return 0;\n } else {\n return 1;\n }\n }\n\n equals(other: Node): boolean {\n // Not that we every compare it, but MAX_NODE is only ever equal to itself\n return other === this;\n }\n\n getPriority(): MaxNode {\n return this;\n }\n\n getImmediateChild(childName: string): ChildrenNode {\n return ChildrenNode.EMPTY_NODE;\n }\n\n isEmpty(): boolean {\n return false;\n }\n}\n\n/**\n * Marker that will sort higher than any other snapshot.\n * @type {!MAX_NODE}\n * @const\n */\nexport const MAX_NODE = new MaxNode();\n\n/**\n * Document NamedNode extensions\n */\ndeclare module './Node' {\n interface NamedNode {\n MIN: NamedNode;\n MAX: NamedNode;\n }\n}\n\nObject.defineProperties(NamedNode, {\n MIN: {\n value: new NamedNode(MIN_NAME, ChildrenNode.EMPTY_NODE)\n },\n MAX: {\n value: new NamedNode(MAX_NAME, MAX_NODE)\n }\n});\n\n/**\n * Reference Extensions\n */\nKeyIndex.__EMPTY_NODE = ChildrenNode.EMPTY_NODE;\nLeafNode.__childrenNodeConstructor = ChildrenNode;\nsetMaxNode(MAX_NODE);\nsetPriorityMaxNode(MAX_NODE);\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { nameCompare } from '../util/util';\nimport { NamedNode } from './Node';\n\nexport function NAME_ONLY_COMPARATOR(left: NamedNode, right: NamedNode) {\n return nameCompare(left.name, right.name);\n}\n\nexport function NAME_COMPARATOR(left: string, right: string) {\n return nameCompare(left, right);\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ChildrenNode } from './ChildrenNode';\nimport { LeafNode } from './LeafNode';\nimport { NamedNode, Node } from './Node';\nimport { contains, assert } from '@firebase/util';\n\nimport { buildChildSet } from './childSet';\nimport { NAME_COMPARATOR, NAME_ONLY_COMPARATOR } from './comparators';\nimport { IndexMap } from './IndexMap';\nimport { PRIORITY_INDEX, setNodeFromJSON } from './indexes/PriorityIndex';\nimport { SortedMap } from '../util/SortedMap';\nimport { each } from '../util/util';\nimport { Indexable } from '../util/misc';\n\nconst USE_HINZE = true;\n\n/**\n * Constructs a snapshot node representing the passed JSON and returns it.\n * @param {*} json JSON to create a node for.\n * @param {?string|?number=} priority Optional priority to use. This will be ignored if the\n * passed JSON contains a .priority property.\n * @return {!Node}\n */\nexport function nodeFromJSON(\n json: unknown | null,\n priority: unknown = null\n): Node {\n if (json === null) {\n return ChildrenNode.EMPTY_NODE;\n }\n\n if (typeof json === 'object' && '.priority' in json) {\n priority = json['.priority'];\n }\n\n assert(\n priority === null ||\n typeof priority === 'string' ||\n typeof priority === 'number' ||\n (typeof priority === 'object' && '.sv' in (priority as object)),\n 'Invalid priority type found: ' + typeof priority\n );\n\n if (typeof json === 'object' && '.value' in json && json['.value'] !== null) {\n json = json['.value'];\n }\n\n // Valid leaf nodes include non-objects or server-value wrapper objects\n if (typeof json !== 'object' || '.sv' in json) {\n const jsonLeaf = json as string | number | boolean | Indexable;\n return new LeafNode(jsonLeaf, nodeFromJSON(priority));\n }\n\n if (!(json instanceof Array) && USE_HINZE) {\n const children: NamedNode[] = [];\n let childrenHavePriority = false;\n const hinzeJsonObj = json;\n each(hinzeJsonObj, (key, child) => {\n if (key.substring(0, 1) !== '.') {\n // Ignore metadata nodes\n const childNode = nodeFromJSON(child);\n if (!childNode.isEmpty()) {\n childrenHavePriority =\n childrenHavePriority || !childNode.getPriority().isEmpty();\n children.push(new NamedNode(key, childNode));\n }\n }\n });\n\n if (children.length === 0) {\n return ChildrenNode.EMPTY_NODE;\n }\n\n const childSet = buildChildSet(\n children,\n NAME_ONLY_COMPARATOR,\n namedNode => namedNode.name,\n NAME_COMPARATOR\n ) as SortedMap;\n if (childrenHavePriority) {\n const sortedChildSet = buildChildSet(\n children,\n PRIORITY_INDEX.getCompare()\n );\n return new ChildrenNode(\n childSet,\n nodeFromJSON(priority),\n new IndexMap(\n { '.priority': sortedChildSet },\n { '.priority': PRIORITY_INDEX }\n )\n );\n } else {\n return new ChildrenNode(\n childSet,\n nodeFromJSON(priority),\n IndexMap.Default\n );\n }\n } else {\n let node: Node = ChildrenNode.EMPTY_NODE;\n each(json, (key: string, childData: unknown) => {\n if (contains(json as object, key)) {\n if (key.substring(0, 1) !== '.') {\n // ignore metadata nodes.\n const childNode = nodeFromJSON(childData);\n if (childNode.isLeafNode() || !childNode.isEmpty()) {\n node = node.updateImmediateChild(key, childNode);\n }\n }\n }\n });\n\n return node.updatePriority(nodeFromJSON(priority));\n }\n}\n\nsetNodeFromJSON(nodeFromJSON);\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Index } from './Index';\nimport { NamedNode, Node } from '../Node';\nimport { nameCompare } from '../../util/util';\nimport { nodeFromJSON } from '../nodeFromJSON';\n\n/**\n * @constructor\n * @extends {Index}\n * @private\n */\nexport class ValueIndex extends Index {\n /**\n * @inheritDoc\n */\n compare(a: NamedNode, b: NamedNode): number {\n const indexCmp = a.node.compareTo(b.node);\n if (indexCmp === 0) {\n return nameCompare(a.name, b.name);\n } else {\n return indexCmp;\n }\n }\n\n /**\n * @inheritDoc\n */\n isDefinedOn(node: Node): boolean {\n return true;\n }\n\n /**\n * @inheritDoc\n */\n indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n return !oldNode.equals(newNode);\n }\n\n /**\n * @inheritDoc\n */\n minPost(): NamedNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (NamedNode as any).MIN;\n }\n\n /**\n * @inheritDoc\n */\n maxPost(): NamedNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (NamedNode as any).MAX;\n }\n\n /**\n * @param {*} indexValue\n * @param {string} name\n * @return {!NamedNode}\n */\n makePost(indexValue: object, name: string): NamedNode {\n const valueNode = nodeFromJSON(indexValue);\n return new NamedNode(name, valueNode);\n }\n\n /**\n * @return {!string} String representation for inclusion in a query spec\n */\n toString(): string {\n return '.value';\n }\n}\n\nexport const VALUE_INDEX = new ValueIndex();\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { nameCompare, MAX_NAME } from '../../util/util';\nimport { Index } from './Index';\nimport { ChildrenNode, MAX_NODE } from '../ChildrenNode';\nimport { NamedNode, Node } from '../Node';\nimport { nodeFromJSON } from '../nodeFromJSON';\nimport { Path } from '../../util/Path';\n\n/**\n * @param {!Path} indexPath\n * @constructor\n * @extends {Index}\n */\nexport class PathIndex extends Index {\n constructor(private indexPath_: Path) {\n super();\n\n assert(\n !indexPath_.isEmpty() && indexPath_.getFront() !== '.priority',\n \"Can't create PathIndex with empty path or .priority key\"\n );\n }\n\n /**\n * @param {!Node} snap\n * @return {!Node}\n * @protected\n */\n protected extractChild(snap: Node): Node {\n return snap.getChild(this.indexPath_);\n }\n\n /**\n * @inheritDoc\n */\n isDefinedOn(node: Node): boolean {\n return !node.getChild(this.indexPath_).isEmpty();\n }\n\n /**\n * @inheritDoc\n */\n compare(a: NamedNode, b: NamedNode): number {\n const aChild = this.extractChild(a.node);\n const bChild = this.extractChild(b.node);\n const indexCmp = aChild.compareTo(bChild);\n if (indexCmp === 0) {\n return nameCompare(a.name, b.name);\n } else {\n return indexCmp;\n }\n }\n\n /**\n * @inheritDoc\n */\n makePost(indexValue: object, name: string): NamedNode {\n const valueNode = nodeFromJSON(indexValue);\n const node = ChildrenNode.EMPTY_NODE.updateChild(\n this.indexPath_,\n valueNode\n );\n return new NamedNode(name, node);\n }\n\n /**\n * @inheritDoc\n */\n maxPost(): NamedNode {\n const node = ChildrenNode.EMPTY_NODE.updateChild(this.indexPath_, MAX_NODE);\n return new NamedNode(MAX_NAME, node);\n }\n\n /**\n * @inheritDoc\n */\n toString(): string {\n return this.indexPath_.slice().join('/');\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { validateArgCount, validateCallback } from '@firebase/util';\nimport { validatePathString } from '../core/util/validation';\nimport { Path } from '../core/util/Path';\nimport { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';\nimport { Node } from '../core/snap/Node';\nimport { Reference } from './Reference';\nimport { Index } from '../core/snap/indexes/Index';\nimport { ChildrenNode } from '../core/snap/ChildrenNode';\n\n/**\n * Class representing a firebase data snapshot. It wraps a SnapshotNode and\n * surfaces the public methods (val, forEach, etc.) we want to expose.\n */\nexport class DataSnapshot {\n /**\n * @param {!Node} node_ A SnapshotNode to wrap.\n * @param {!Reference} ref_ The ref of the location this snapshot came from.\n * @param {!Index} index_ The iteration order for this snapshot\n */\n constructor(\n private readonly node_: Node,\n private readonly ref_: Reference,\n private readonly index_: Index\n ) {}\n\n /**\n * Retrieves the snapshot contents as JSON. Returns null if the snapshot is\n * empty.\n *\n * @return {*} JSON representation of the DataSnapshot contents, or null if empty.\n */\n val(): unknown {\n validateArgCount('DataSnapshot.val', 0, 0, arguments.length);\n return this.node_.val();\n }\n\n /**\n * Returns the snapshot contents as JSON, including priorities of node. Suitable for exporting\n * the entire node contents.\n * @return {*} JSON representation of the DataSnapshot contents, or null if empty.\n */\n exportVal(): unknown {\n validateArgCount('DataSnapshot.exportVal', 0, 0, arguments.length);\n return this.node_.val(true);\n }\n\n // Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary\n // for end-users\n toJSON(): unknown {\n // Optional spacer argument is unnecessary because we're depending on recursion rather than stringifying the content\n validateArgCount('DataSnapshot.toJSON', 0, 1, arguments.length);\n return this.exportVal();\n }\n\n /**\n * Returns whether the snapshot contains a non-null value.\n *\n * @return {boolean} Whether the snapshot contains a non-null value, or is empty.\n */\n exists(): boolean {\n validateArgCount('DataSnapshot.exists', 0, 0, arguments.length);\n return !this.node_.isEmpty();\n }\n\n /**\n * Returns a DataSnapshot of the specified child node's contents.\n *\n * @param {!string} childPathString Path to a child.\n * @return {!DataSnapshot} DataSnapshot for child node.\n */\n child(childPathString: string): DataSnapshot {\n validateArgCount('DataSnapshot.child', 0, 1, arguments.length);\n // Ensure the childPath is a string (can be a number)\n childPathString = String(childPathString);\n validatePathString('DataSnapshot.child', 1, childPathString, false);\n\n const childPath = new Path(childPathString);\n const childRef = this.ref_.child(childPath);\n return new DataSnapshot(\n this.node_.getChild(childPath),\n childRef,\n PRIORITY_INDEX\n );\n }\n\n /**\n * Returns whether the snapshot contains a child at the specified path.\n *\n * @param {!string} childPathString Path to a child.\n * @return {boolean} Whether the child exists.\n */\n hasChild(childPathString: string): boolean {\n validateArgCount('DataSnapshot.hasChild', 1, 1, arguments.length);\n validatePathString('DataSnapshot.hasChild', 1, childPathString, false);\n\n const childPath = new Path(childPathString);\n return !this.node_.getChild(childPath).isEmpty();\n }\n\n /**\n * Returns the priority of the object, or null if no priority was set.\n *\n * @return {string|number|null} The priority.\n */\n getPriority(): string | number | null {\n validateArgCount('DataSnapshot.getPriority', 0, 0, arguments.length);\n\n // typecast here because we never return deferred values or internal priorities (MAX_PRIORITY)\n return this.node_.getPriority().val() as string | number | null;\n }\n\n /**\n * Iterates through child nodes and calls the specified action for each one.\n *\n * @param {function(!DataSnapshot)} action Callback function to be called\n * for each child.\n * @return {boolean} True if forEach was canceled by action returning true for\n * one of the child nodes.\n */\n forEach(action: (d: DataSnapshot) => boolean | void): boolean {\n validateArgCount('DataSnapshot.forEach', 1, 1, arguments.length);\n validateCallback('DataSnapshot.forEach', 1, action, false);\n\n if (this.node_.isLeafNode()) {\n return false;\n }\n\n const childrenNode = this.node_ as ChildrenNode;\n // Sanitize the return value to a boolean. ChildrenNode.forEachChild has a weird return type...\n return !!childrenNode.forEachChild(this.index_, (key, node) => {\n return action(\n new DataSnapshot(node, this.ref_.child(key), PRIORITY_INDEX)\n );\n });\n }\n\n /**\n * Returns whether this DataSnapshot has children.\n * @return {boolean} True if the DataSnapshot contains 1 or more child nodes.\n */\n hasChildren(): boolean {\n validateArgCount('DataSnapshot.hasChildren', 0, 0, arguments.length);\n\n if (this.node_.isLeafNode()) {\n return false;\n } else {\n return !this.node_.isEmpty();\n }\n }\n\n get key() {\n return this.ref_.getKey();\n }\n\n /**\n * Returns the number of children for this DataSnapshot.\n * @return {number} The number of children that this DataSnapshot contains.\n */\n numChildren(): number {\n validateArgCount('DataSnapshot.numChildren', 0, 0, arguments.length);\n\n return this.node_.numChildren();\n }\n\n /**\n * @return {Reference} The Firebase reference for the location this snapshot's data came from.\n */\n getRef(): Reference {\n validateArgCount('DataSnapshot.ref', 0, 0, arguments.length);\n\n return this.ref_;\n }\n\n get ref() {\n return this.getRef();\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { stringify } from '@firebase/util';\nimport { Path } from '../util/Path';\nimport { EventRegistration } from './EventRegistration';\nimport { DataSnapshot } from '../../api/DataSnapshot';\n\n/**\n * Encapsulates the data needed to raise an event\n * @interface\n */\nexport interface Event {\n /**\n * @return {!Path}\n */\n getPath(): Path;\n\n /**\n * @return {!string}\n */\n getEventType(): string;\n\n /**\n * @return {!function()}\n */\n getEventRunner(): () => void;\n\n /**\n * @return {!string}\n */\n toString(): string;\n}\n\nexport type EventType =\n | 'value'\n | ' child_added'\n | ' child_changed'\n | ' child_moved'\n | ' child_removed';\n\n/**\n * Encapsulates the data needed to raise an event\n * @implements {Event}\n */\nexport class DataEvent implements Event {\n /**\n * @param {!string} eventType One of: value, child_added, child_changed, child_moved, child_removed\n * @param {!EventRegistration} eventRegistration The function to call to with the event data. User provided\n * @param {!DataSnapshot} snapshot The data backing the event\n * @param {?string=} prevName Optional, the name of the previous child for child_* events.\n */\n constructor(\n public eventType: EventType,\n public eventRegistration: EventRegistration,\n public snapshot: DataSnapshot,\n public prevName?: string | null\n ) {}\n\n /**\n * @inheritDoc\n */\n getPath(): Path {\n const ref = this.snapshot.getRef();\n if (this.eventType === 'value') {\n return ref.path;\n } else {\n return ref.getParent().path;\n }\n }\n\n /**\n * @inheritDoc\n */\n getEventType(): string {\n return this.eventType;\n }\n\n /**\n * @inheritDoc\n */\n getEventRunner(): () => void {\n return this.eventRegistration.getEventRunner(this);\n }\n\n /**\n * @inheritDoc\n */\n toString(): string {\n return (\n this.getPath().toString() +\n ':' +\n this.eventType +\n ':' +\n stringify(this.snapshot.exportVal())\n );\n }\n}\n\nexport class CancelEvent implements Event {\n /**\n * @param {EventRegistration} eventRegistration\n * @param {Error} error\n * @param {!Path} path\n */\n constructor(\n public eventRegistration: EventRegistration,\n public error: Error,\n public path: Path\n ) {}\n\n /**\n * @inheritDoc\n */\n getPath(): Path {\n return this.path;\n }\n\n /**\n * @inheritDoc\n */\n getEventType(): string {\n return 'cancel';\n }\n\n /**\n * @inheritDoc\n */\n getEventRunner(): () => void {\n return this.eventRegistration.getEventRunner(this);\n }\n\n /**\n * @inheritDoc\n */\n toString(): string {\n return this.path.toString() + ':cancel';\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { DataSnapshot } from '../../api/DataSnapshot';\nimport { DataEvent, CancelEvent, Event, EventType } from './Event';\nimport { contains, assert } from '@firebase/util';\n\nimport { Path } from '../util/Path';\nimport { Change } from './Change';\nimport { Query } from '../../api/Query';\n\n/**\n * An EventRegistration is basically an event type ('value', 'child_added', etc.) and a callback\n * to be notified of that type of event.\n *\n * That said, it can also contain a cancel callback to be notified if the event is canceled. And\n * currently, this code is organized around the idea that you would register multiple child_ callbacks\n * together, as a single EventRegistration. Though currently we don't do that.\n */\nexport interface EventRegistration {\n /**\n * True if this container has a callback to trigger for this event type\n * @param {!string} eventType\n * @return {boolean}\n */\n respondsTo(eventType: string): boolean;\n\n /**\n * @param {!Change} change\n * @param {!Query} query\n * @return {!Event}\n */\n createEvent(change: Change, query: Query): Event;\n\n /**\n * Given event data, return a function to trigger the user's callback\n * @param {!Event} eventData\n * @return {function()}\n */\n getEventRunner(eventData: Event): () => void;\n\n /**\n * @param {!Error} error\n * @param {!Path} path\n * @return {?CancelEvent}\n */\n createCancelEvent(error: Error, path: Path): CancelEvent | null;\n\n /**\n * @param {!EventRegistration} other\n * @return {boolean}\n */\n matches(other: EventRegistration): boolean;\n\n /**\n * False basically means this is a \"dummy\" callback container being used as a sentinel\n * to remove all callback containers of a particular type. (e.g. if the user does\n * ref.off('value') without specifying a specific callback).\n *\n * (TODO: Rework this, since it's hacky)\n *\n * @return {boolean}\n */\n hasAnyCallback(): boolean;\n}\n\n/**\n * Represents registration for 'value' events.\n */\nexport class ValueEventRegistration implements EventRegistration {\n /**\n * @param {?function(!DataSnapshot)} callback_\n * @param {?function(Error)} cancelCallback_\n * @param {?Object} context_\n */\n constructor(\n private callback_: ((d: DataSnapshot) => void) | null,\n private cancelCallback_: ((e: Error) => void) | null,\n private context_: {} | null\n ) {}\n\n /**\n * @inheritDoc\n */\n respondsTo(eventType: string): boolean {\n return eventType === 'value';\n }\n\n /**\n * @inheritDoc\n */\n createEvent(change: Change, query: Query): DataEvent {\n const index = query.getQueryParams().getIndex();\n return new DataEvent(\n 'value',\n this,\n new DataSnapshot(change.snapshotNode, query.getRef(), index)\n );\n }\n\n /**\n * @inheritDoc\n */\n getEventRunner(eventData: CancelEvent | DataEvent): () => void {\n const ctx = this.context_;\n if (eventData.getEventType() === 'cancel') {\n assert(\n this.cancelCallback_,\n 'Raising a cancel event on a listener with no cancel callback'\n );\n const cancelCB = this.cancelCallback_;\n return function() {\n // We know that error exists, we checked above that this is a cancel event\n cancelCB.call(ctx, (eventData as CancelEvent).error);\n };\n } else {\n const cb = this.callback_;\n return function() {\n cb.call(ctx, (eventData as DataEvent).snapshot);\n };\n }\n }\n\n /**\n * @inheritDoc\n */\n createCancelEvent(error: Error, path: Path): CancelEvent | null {\n if (this.cancelCallback_) {\n return new CancelEvent(this, error, path);\n } else {\n return null;\n }\n }\n\n /**\n * @inheritDoc\n */\n matches(other: EventRegistration): boolean {\n if (!(other instanceof ValueEventRegistration)) {\n return false;\n } else if (!other.callback_ || !this.callback_) {\n // If no callback specified, we consider it to match any callback.\n return true;\n } else {\n return (\n other.callback_ === this.callback_ && other.context_ === this.context_\n );\n }\n }\n\n /**\n * @inheritDoc\n */\n hasAnyCallback(): boolean {\n return this.callback_ !== null;\n }\n}\n\n/**\n * Represents the registration of 1 or more child_xxx events.\n *\n * Currently, it is always exactly 1 child_xxx event, but the idea is we might let you\n * register a group of callbacks together in the future.\n *\n * @constructor\n * @implements {EventRegistration}\n */\nexport class ChildEventRegistration implements EventRegistration {\n /**\n * @param {?Object.} callbacks_\n * @param {?function(Error)} cancelCallback_\n * @param {Object=} context_\n */\n constructor(\n private callbacks_: {\n [k: string]: (d: DataSnapshot, s?: string | null) => void;\n } | null,\n private cancelCallback_: ((e: Error) => void) | null,\n private context_?: {}\n ) {}\n\n /**\n * @inheritDoc\n */\n respondsTo(eventType: string): boolean {\n let eventToCheck =\n eventType === 'children_added' ? 'child_added' : eventType;\n eventToCheck =\n eventToCheck === 'children_removed' ? 'child_removed' : eventToCheck;\n return contains(this.callbacks_, eventToCheck);\n }\n\n /**\n * @inheritDoc\n */\n createCancelEvent(error: Error, path: Path): CancelEvent | null {\n if (this.cancelCallback_) {\n return new CancelEvent(this, error, path);\n } else {\n return null;\n }\n }\n\n /**\n * @inheritDoc\n */\n createEvent(change: Change, query: Query): DataEvent {\n assert(change.childName != null, 'Child events should have a childName.');\n const ref = query.getRef().child(/** @type {!string} */ change.childName);\n const index = query.getQueryParams().getIndex();\n return new DataEvent(\n change.type as EventType,\n this,\n new DataSnapshot(change.snapshotNode, ref, index),\n change.prevName\n );\n }\n\n /**\n * @inheritDoc\n */\n getEventRunner(eventData: CancelEvent | DataEvent): () => void {\n const ctx = this.context_;\n if (eventData.getEventType() === 'cancel') {\n assert(\n this.cancelCallback_,\n 'Raising a cancel event on a listener with no cancel callback'\n );\n const cancelCB = this.cancelCallback_;\n return function() {\n // We know that error exists, we checked above that this is a cancel event\n cancelCB.call(ctx, (eventData as CancelEvent).error);\n };\n } else {\n const cb = this.callbacks_[(eventData as DataEvent).eventType];\n return function() {\n cb.call(\n ctx,\n (eventData as DataEvent).snapshot,\n (eventData as DataEvent).prevName\n );\n };\n }\n }\n\n /**\n * @inheritDoc\n */\n matches(other: EventRegistration): boolean {\n if (other instanceof ChildEventRegistration) {\n if (!this.callbacks_ || !other.callbacks_) {\n return true;\n } else if (this.context_ === other.context_) {\n const otherKeys = Object.keys(other.callbacks_);\n const thisKeys = Object.keys(this.callbacks_);\n const otherCount = otherKeys.length;\n const thisCount = thisKeys.length;\n if (otherCount === thisCount) {\n // If count is 1, do an exact match on eventType, if either is defined but null, it's a match.\n // If event types don't match, not a match\n // If count is not 1, exact match across all\n\n if (otherCount === 1) {\n const otherKey = otherKeys[0];\n const thisKey = thisKeys[0];\n return (\n thisKey === otherKey &&\n (!other.callbacks_[otherKey] ||\n !this.callbacks_[thisKey] ||\n other.callbacks_[otherKey] === this.callbacks_[thisKey])\n );\n } else {\n // Exact match on each key.\n return thisKeys.every(\n eventType =>\n other.callbacks_[eventType] === this.callbacks_[eventType]\n );\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * @inheritDoc\n */\n hasAnyCallback(): boolean {\n return this.callbacks_ !== null;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n assert,\n errorPrefix,\n validateArgCount,\n validateCallback,\n validateContextObject,\n Deferred\n} from '@firebase/util';\nimport { KEY_INDEX } from '../core/snap/indexes/KeyIndex';\nimport { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';\nimport { VALUE_INDEX } from '../core/snap/indexes/ValueIndex';\nimport { PathIndex } from '../core/snap/indexes/PathIndex';\nimport { MIN_NAME, MAX_NAME, ObjectToUniqueKey } from '../core/util/util';\nimport { Path } from '../core/util/Path';\nimport {\n isValidPriority,\n validateEventType,\n validatePathString,\n validateFirebaseDataArg,\n validateKey\n} from '../core/util/validation';\n\nimport {\n ValueEventRegistration,\n ChildEventRegistration,\n EventRegistration\n} from '../core/view/EventRegistration';\n\nimport { Repo } from '../core/Repo';\nimport { QueryParams } from '../core/view/QueryParams';\nimport { Reference } from './Reference';\nimport { DataSnapshot } from './DataSnapshot';\n\nlet __referenceConstructor: new (repo: Repo, path: Path) => Query;\n\nexport interface SnapshotCallback {\n (a: DataSnapshot, b?: string | null): unknown;\n}\n\n/**\n * A Query represents a filter to be applied to a firebase location. This object purely represents the\n * query expression (and exposes our public API to build the query). The actual query logic is in ViewBase.js.\n *\n * Since every Firebase reference is a query, Firebase inherits from this object.\n */\nexport class Query {\n static set __referenceConstructor(val) {\n __referenceConstructor = val;\n }\n\n static get __referenceConstructor() {\n assert(__referenceConstructor, 'Reference.ts has not been loaded');\n return __referenceConstructor;\n }\n\n constructor(\n public repo: Repo,\n public path: Path,\n private queryParams_: QueryParams,\n private orderByCalled_: boolean\n ) {}\n\n /**\n * Validates start/end values for queries.\n * @param {!QueryParams} params\n * @private\n */\n private static validateQueryEndpoints_(params: QueryParams) {\n let startNode = null;\n let endNode = null;\n if (params.hasStart()) {\n startNode = params.getIndexStartValue();\n }\n if (params.hasEnd()) {\n endNode = params.getIndexEndValue();\n }\n\n if (params.getIndex() === KEY_INDEX) {\n const tooManyArgsError =\n 'Query: When ordering by key, you may only pass one argument to ' +\n 'startAt(), endAt(), or equalTo().';\n const wrongArgTypeError =\n 'Query: When ordering by key, the argument passed to startAt(), endAt(),' +\n 'or equalTo() must be a string.';\n if (params.hasStart()) {\n const startName = params.getIndexStartName();\n if (startName !== MIN_NAME) {\n throw new Error(tooManyArgsError);\n } else if (typeof startNode !== 'string') {\n throw new Error(wrongArgTypeError);\n }\n }\n if (params.hasEnd()) {\n const endName = params.getIndexEndName();\n if (endName !== MAX_NAME) {\n throw new Error(tooManyArgsError);\n } else if (typeof endNode !== 'string') {\n throw new Error(wrongArgTypeError);\n }\n }\n } else if (params.getIndex() === PRIORITY_INDEX) {\n if (\n (startNode != null && !isValidPriority(startNode)) ||\n (endNode != null && !isValidPriority(endNode))\n ) {\n throw new Error(\n 'Query: When ordering by priority, the first argument passed to startAt(), ' +\n 'endAt(), or equalTo() must be a valid priority value (null, a number, or a string).'\n );\n }\n } else {\n assert(\n params.getIndex() instanceof PathIndex ||\n params.getIndex() === VALUE_INDEX,\n 'unknown index type.'\n );\n if (\n (startNode != null && typeof startNode === 'object') ||\n (endNode != null && typeof endNode === 'object')\n ) {\n throw new Error(\n 'Query: First argument passed to startAt(), endAt(), or equalTo() cannot be ' +\n 'an object.'\n );\n }\n }\n }\n\n /**\n * Validates that limit* has been called with the correct combination of parameters\n * @param {!QueryParams} params\n * @private\n */\n private static validateLimit_(params: QueryParams) {\n if (\n params.hasStart() &&\n params.hasEnd() &&\n params.hasLimit() &&\n !params.hasAnchoredLimit()\n ) {\n throw new Error(\n \"Query: Can't combine startAt(), endAt(), and limit(). Use limitToFirst() or limitToLast() instead.\"\n );\n }\n }\n\n /**\n * Validates that no other order by call has been made\n * @param {!string} fnName\n * @private\n */\n private validateNoPreviousOrderByCall_(fnName: string) {\n if (this.orderByCalled_ === true) {\n throw new Error(fnName + \": You can't combine multiple orderBy calls.\");\n }\n }\n\n /**\n * @return {!QueryParams}\n */\n getQueryParams(): QueryParams {\n return this.queryParams_;\n }\n\n /**\n * @return {!Reference}\n */\n getRef(): Reference {\n validateArgCount('Query.ref', 0, 0, arguments.length);\n // This is a slight hack. We cannot goog.require('fb.api.Firebase'), since Firebase requires fb.api.Query.\n // However, we will always export 'Firebase' to the global namespace, so it's guaranteed to exist by the time this\n // method gets called.\n return new Query.__referenceConstructor(this.repo, this.path) as Reference;\n }\n\n /**\n * @param {!string} eventType\n * @param {!function(DataSnapshot, string=)} callback\n * @param {(function(Error)|Object)=} cancelCallbackOrContext\n * @param {Object=} context\n * @return {!function(DataSnapshot, string=)}\n */\n on(\n eventType: string,\n callback: SnapshotCallback,\n cancelCallbackOrContext?: ((a: Error) => unknown) | object | null,\n context?: object | null\n ): SnapshotCallback {\n validateArgCount('Query.on', 2, 4, arguments.length);\n validateEventType('Query.on', 1, eventType, false);\n validateCallback('Query.on', 2, callback, false);\n\n const ret = Query.getCancelAndContextArgs_(\n 'Query.on',\n cancelCallbackOrContext,\n context\n );\n\n if (eventType === 'value') {\n this.onValueEvent(callback, ret.cancel, ret.context);\n } else {\n const callbacks: { [k: string]: typeof callback } = {};\n callbacks[eventType] = callback;\n this.onChildEvent(callbacks, ret.cancel, ret.context);\n }\n return callback;\n }\n\n /**\n * @param {!function(!DataSnapshot)} callback\n * @param {?function(Error)} cancelCallback\n * @param {?Object} context\n * @protected\n */\n protected onValueEvent(\n callback: (a: DataSnapshot) => void,\n cancelCallback: ((a: Error) => void) | null,\n context: object | null\n ) {\n const container = new ValueEventRegistration(\n callback,\n cancelCallback || null,\n context || null\n );\n this.repo.addEventCallbackForQuery(this, container);\n }\n\n /**\n * @param {!Object.} callbacks\n * @param {?function(Error)} cancelCallback\n * @param {?Object} context\n * @protected\n */\n onChildEvent(\n callbacks: { [k: string]: SnapshotCallback },\n cancelCallback: ((a: Error) => unknown) | null,\n context: object | null\n ) {\n const container = new ChildEventRegistration(\n callbacks,\n cancelCallback,\n context\n );\n this.repo.addEventCallbackForQuery(this, container);\n }\n\n /**\n * @param {string=} eventType\n * @param {(function(!DataSnapshot, ?string=))=} callback\n * @param {Object=} context\n */\n off(\n eventType?: string,\n callback?: SnapshotCallback,\n context?: object | null\n ): void {\n validateArgCount('Query.off', 0, 3, arguments.length);\n validateEventType('Query.off', 1, eventType, true);\n validateCallback('Query.off', 2, callback, true);\n validateContextObject('Query.off', 3, context, true);\n\n let container: EventRegistration | null = null;\n let callbacks: { [k: string]: typeof callback } | null = null;\n if (eventType === 'value') {\n const valueCallback = callback || null;\n container = new ValueEventRegistration(\n valueCallback,\n null,\n context || null\n );\n } else if (eventType) {\n if (callback) {\n callbacks = {};\n callbacks[eventType] = callback;\n }\n container = new ChildEventRegistration(callbacks, null, context || null);\n }\n this.repo.removeEventCallbackForQuery(this, container);\n }\n\n /**\n * Attaches a listener, waits for the first event, and then removes the listener\n * @param {!string} eventType\n * @param {!function(!DataSnapshot, string=)} userCallback\n * @param failureCallbackOrContext\n * @param context\n * @return {!firebase.Promise}\n */\n once(\n eventType: string,\n userCallback?: SnapshotCallback,\n failureCallbackOrContext?: ((a: Error) => void) | object | null,\n context?: object | null\n ): Promise {\n validateArgCount('Query.once', 1, 4, arguments.length);\n validateEventType('Query.once', 1, eventType, false);\n validateCallback('Query.once', 2, userCallback, true);\n\n const ret = Query.getCancelAndContextArgs_(\n 'Query.once',\n failureCallbackOrContext,\n context\n );\n\n // TODO: Implement this more efficiently (in particular, use 'get' wire protocol for 'value' event)\n // TODO: consider actually wiring the callbacks into the promise. We cannot do this without a breaking change\n // because the API currently expects callbacks will be called synchronously if the data is cached, but this is\n // against the Promise specification.\n let firstCall = true;\n const deferred = new Deferred();\n\n // A dummy error handler in case a user wasn't expecting promises\n deferred.promise.catch(() => {});\n\n const onceCallback = (snapshot: DataSnapshot) => {\n // NOTE: Even though we unsubscribe, we may get called multiple times if a single action (e.g. set() with JSON)\n // triggers multiple events (e.g. child_added or child_changed).\n if (firstCall) {\n firstCall = false;\n this.off(eventType, onceCallback);\n\n if (userCallback) {\n userCallback.bind(ret.context)(snapshot);\n }\n deferred.resolve(snapshot);\n }\n };\n\n this.on(\n eventType,\n onceCallback,\n /*cancel=*/ err => {\n this.off(eventType, onceCallback);\n\n if (ret.cancel) {\n ret.cancel.bind(ret.context)(err);\n }\n deferred.reject(err);\n }\n );\n return deferred.promise;\n }\n\n /**\n * Set a limit and anchor it to the start of the window.\n * @param {!number} limit\n * @return {!Query}\n */\n limitToFirst(limit: number): Query {\n validateArgCount('Query.limitToFirst', 1, 1, arguments.length);\n if (\n typeof limit !== 'number' ||\n Math.floor(limit) !== limit ||\n limit <= 0\n ) {\n throw new Error(\n 'Query.limitToFirst: First argument must be a positive integer.'\n );\n }\n if (this.queryParams_.hasLimit()) {\n throw new Error(\n 'Query.limitToFirst: Limit was already set (by another call to limit, ' +\n 'limitToFirst, or limitToLast).'\n );\n }\n\n return new Query(\n this.repo,\n this.path,\n this.queryParams_.limitToFirst(limit),\n this.orderByCalled_\n );\n }\n\n /**\n * Set a limit and anchor it to the end of the window.\n * @param {!number} limit\n * @return {!Query}\n */\n limitToLast(limit: number): Query {\n validateArgCount('Query.limitToLast', 1, 1, arguments.length);\n if (\n typeof limit !== 'number' ||\n Math.floor(limit) !== limit ||\n limit <= 0\n ) {\n throw new Error(\n 'Query.limitToLast: First argument must be a positive integer.'\n );\n }\n if (this.queryParams_.hasLimit()) {\n throw new Error(\n 'Query.limitToLast: Limit was already set (by another call to limit, ' +\n 'limitToFirst, or limitToLast).'\n );\n }\n\n return new Query(\n this.repo,\n this.path,\n this.queryParams_.limitToLast(limit),\n this.orderByCalled_\n );\n }\n\n /**\n * Given a child path, return a new query ordered by the specified grandchild path.\n * @param {!string} path\n * @return {!Query}\n */\n orderByChild(path: string): Query {\n validateArgCount('Query.orderByChild', 1, 1, arguments.length);\n if (path === '$key') {\n throw new Error(\n 'Query.orderByChild: \"$key\" is invalid. Use Query.orderByKey() instead.'\n );\n } else if (path === '$priority') {\n throw new Error(\n 'Query.orderByChild: \"$priority\" is invalid. Use Query.orderByPriority() instead.'\n );\n } else if (path === '$value') {\n throw new Error(\n 'Query.orderByChild: \"$value\" is invalid. Use Query.orderByValue() instead.'\n );\n }\n validatePathString('Query.orderByChild', 1, path, false);\n this.validateNoPreviousOrderByCall_('Query.orderByChild');\n const parsedPath = new Path(path);\n if (parsedPath.isEmpty()) {\n throw new Error(\n 'Query.orderByChild: cannot pass in empty path. Use Query.orderByValue() instead.'\n );\n }\n const index = new PathIndex(parsedPath);\n const newParams = this.queryParams_.orderBy(index);\n Query.validateQueryEndpoints_(newParams);\n\n return new Query(this.repo, this.path, newParams, /*orderByCalled=*/ true);\n }\n\n /**\n * Return a new query ordered by the KeyIndex\n * @return {!Query}\n */\n orderByKey(): Query {\n validateArgCount('Query.orderByKey', 0, 0, arguments.length);\n this.validateNoPreviousOrderByCall_('Query.orderByKey');\n const newParams = this.queryParams_.orderBy(KEY_INDEX);\n Query.validateQueryEndpoints_(newParams);\n return new Query(this.repo, this.path, newParams, /*orderByCalled=*/ true);\n }\n\n /**\n * Return a new query ordered by the PriorityIndex\n * @return {!Query}\n */\n orderByPriority(): Query {\n validateArgCount('Query.orderByPriority', 0, 0, arguments.length);\n this.validateNoPreviousOrderByCall_('Query.orderByPriority');\n const newParams = this.queryParams_.orderBy(PRIORITY_INDEX);\n Query.validateQueryEndpoints_(newParams);\n return new Query(this.repo, this.path, newParams, /*orderByCalled=*/ true);\n }\n\n /**\n * Return a new query ordered by the ValueIndex\n * @return {!Query}\n */\n orderByValue(): Query {\n validateArgCount('Query.orderByValue', 0, 0, arguments.length);\n this.validateNoPreviousOrderByCall_('Query.orderByValue');\n const newParams = this.queryParams_.orderBy(VALUE_INDEX);\n Query.validateQueryEndpoints_(newParams);\n return new Query(this.repo, this.path, newParams, /*orderByCalled=*/ true);\n }\n\n /**\n * @param {number|string|boolean|null} value\n * @param {?string=} name\n * @return {!Query}\n */\n startAt(\n value: number | string | boolean | null = null,\n name?: string | null\n ): Query {\n validateArgCount('Query.startAt', 0, 2, arguments.length);\n validateFirebaseDataArg('Query.startAt', 1, value, this.path, true);\n validateKey('Query.startAt', 2, name, true);\n\n const newParams = this.queryParams_.startAt(value, name);\n Query.validateLimit_(newParams);\n Query.validateQueryEndpoints_(newParams);\n if (this.queryParams_.hasStart()) {\n throw new Error(\n 'Query.startAt: Starting point was already set (by another call to startAt ' +\n 'or equalTo).'\n );\n }\n\n // Calling with no params tells us to start at the beginning.\n if (value === undefined) {\n value = null;\n name = null;\n }\n return new Query(this.repo, this.path, newParams, this.orderByCalled_);\n }\n\n /**\n * @param {number|string|boolean|null} value\n * @param {?string=} name\n * @return {!Query}\n */\n endAt(\n value: number | string | boolean | null = null,\n name?: string | null\n ): Query {\n validateArgCount('Query.endAt', 0, 2, arguments.length);\n validateFirebaseDataArg('Query.endAt', 1, value, this.path, true);\n validateKey('Query.endAt', 2, name, true);\n\n const newParams = this.queryParams_.endAt(value, name);\n Query.validateLimit_(newParams);\n Query.validateQueryEndpoints_(newParams);\n if (this.queryParams_.hasEnd()) {\n throw new Error(\n 'Query.endAt: Ending point was already set (by another call to endAt or ' +\n 'equalTo).'\n );\n }\n\n return new Query(this.repo, this.path, newParams, this.orderByCalled_);\n }\n\n /**\n * Load the selection of children with exactly the specified value, and, optionally,\n * the specified name.\n * @param {number|string|boolean|null} value\n * @param {string=} name\n * @return {!Query}\n */\n equalTo(value: number | string | boolean | null, name?: string) {\n validateArgCount('Query.equalTo', 1, 2, arguments.length);\n validateFirebaseDataArg('Query.equalTo', 1, value, this.path, false);\n validateKey('Query.equalTo', 2, name, true);\n if (this.queryParams_.hasStart()) {\n throw new Error(\n 'Query.equalTo: Starting point was already set (by another call to startAt or ' +\n 'equalTo).'\n );\n }\n if (this.queryParams_.hasEnd()) {\n throw new Error(\n 'Query.equalTo: Ending point was already set (by another call to endAt or ' +\n 'equalTo).'\n );\n }\n return this.startAt(value, name).endAt(value, name);\n }\n\n /**\n * @return {!string} URL for this location.\n */\n toString(): string {\n validateArgCount('Query.toString', 0, 0, arguments.length);\n\n return this.repo.toString() + this.path.toUrlEncodedString();\n }\n\n // Do not create public documentation. This is intended to make JSON serialization work but is otherwise unnecessary\n // for end-users.\n toJSON() {\n // An optional spacer argument is unnecessary for a string.\n validateArgCount('Query.toJSON', 0, 1, arguments.length);\n return this.toString();\n }\n\n /**\n * An object representation of the query parameters used by this Query.\n * @return {!Object}\n */\n queryObject(): object {\n return this.queryParams_.getQueryObject();\n }\n\n /**\n * @return {!string}\n */\n queryIdentifier(): string {\n const obj = this.queryObject();\n const id = ObjectToUniqueKey(obj);\n return id === '{}' ? 'default' : id;\n }\n\n /**\n * Return true if this query and the provided query are equivalent; otherwise, return false.\n * @param {Query} other\n * @return {boolean}\n */\n isEqual(other: Query): boolean {\n validateArgCount('Query.isEqual', 1, 1, arguments.length);\n if (!(other instanceof Query)) {\n const error =\n 'Query.isEqual failed: First argument must be an instance of firebase.database.Query.';\n throw new Error(error);\n }\n\n const sameRepo = this.repo === other.repo;\n const samePath = this.path.equals(other.path);\n const sameQueryIdentifier =\n this.queryIdentifier() === other.queryIdentifier();\n\n return sameRepo && samePath && sameQueryIdentifier;\n }\n\n /**\n * Helper used by .on and .once to extract the context and or cancel arguments.\n * @param {!string} fnName The function name (on or once)\n * @param {(function(Error)|Object)=} cancelOrContext\n * @param {Object=} context\n * @return {{cancel: ?function(Error), context: ?Object}}\n * @private\n */\n private static getCancelAndContextArgs_(\n fnName: string,\n cancelOrContext?: ((a: Error) => void) | object | null,\n context?: object | null\n ): { cancel: ((a: Error) => void) | null; context: object | null } {\n const ret: {\n cancel: ((a: Error) => void) | null;\n context: object | null;\n } = { cancel: null, context: null };\n if (cancelOrContext && context) {\n ret.cancel = cancelOrContext as (a: Error) => void;\n validateCallback(fnName, 3, ret.cancel, true);\n\n ret.context = context;\n validateContextObject(fnName, 4, ret.context, true);\n } else if (cancelOrContext) {\n // we have either a cancel callback or a context.\n if (typeof cancelOrContext === 'object' && cancelOrContext !== null) {\n // it's a context!\n ret.context = cancelOrContext;\n } else if (typeof cancelOrContext === 'function') {\n ret.cancel = cancelOrContext as (a: Error) => void;\n } else {\n throw new Error(\n errorPrefix(fnName, 3, true) +\n ' must either be a cancel callback or a context object.'\n );\n }\n }\n return ret;\n }\n\n get ref(): Reference {\n return this.getRef();\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path } from './util/Path';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { Node } from './snap/Node';\n\n/**\n * Helper class to store a sparse set of snapshots.\n */\nexport class SparseSnapshotTree {\n private value: Node | null = null;\n\n private readonly children: Map = new Map();\n\n /**\n * Gets the node stored at the given path if one exists.\n *\n * @param path Path to look up snapshot for.\n * @return The retrieved node, or null.\n */\n find(path: Path): Node | null {\n if (this.value != null) {\n return this.value.getChild(path);\n } else if (!path.isEmpty() && this.children.size > 0) {\n const childKey = path.getFront();\n path = path.popFront();\n if (this.children.has(childKey)) {\n const childTree = this.children.get(childKey);\n return childTree.find(path);\n } else {\n return null;\n }\n } else {\n return null;\n }\n }\n\n /**\n * Stores the given node at the specified path. If there is already a node\n * at a shallower path, it merges the new data into that snapshot node.\n *\n * @param path Path to look up snapshot for.\n * @param data The new data, or null.\n */\n remember(path: Path, data: Node) {\n if (path.isEmpty()) {\n this.value = data;\n this.children.clear();\n } else if (this.value !== null) {\n this.value = this.value.updateChild(path, data);\n } else {\n const childKey = path.getFront();\n if (!this.children.has(childKey)) {\n this.children.set(childKey, new SparseSnapshotTree());\n }\n\n const child = this.children.get(childKey);\n path = path.popFront();\n child.remember(path, data);\n }\n }\n\n /**\n * Purge the data at path from the cache.\n *\n * @param path Path to look up snapshot for.\n * @return True if this node should now be removed.\n */\n forget(path: Path): boolean {\n if (path.isEmpty()) {\n this.value = null;\n this.children.clear();\n return true;\n } else {\n if (this.value !== null) {\n if (this.value.isLeafNode()) {\n // We're trying to forget a node that doesn't exist\n return false;\n } else {\n const value = this.value;\n this.value = null;\n\n const self = this;\n value.forEachChild(PRIORITY_INDEX, (key, tree) => {\n self.remember(new Path(key), tree);\n });\n\n return this.forget(path);\n }\n } else if (this.children.size > 0) {\n const childKey = path.getFront();\n path = path.popFront();\n if (this.children.has(childKey)) {\n const safeToRemove = this.children.get(childKey).forget(path);\n if (safeToRemove) {\n this.children.delete(childKey);\n }\n }\n\n return this.children.size === 0;\n } else {\n return true;\n }\n }\n }\n\n /**\n * Recursively iterates through all of the stored tree and calls the\n * callback on each one.\n *\n * @param prefixPath Path to look up node for.\n * @param func The function to invoke for each tree.\n */\n forEachTree(prefixPath: Path, func: (a: Path, b: Node) => unknown) {\n if (this.value !== null) {\n func(prefixPath, this.value);\n } else {\n this.forEachChild((key, tree) => {\n const path = new Path(prefixPath.toString() + '/' + key);\n tree.forEachTree(path, func);\n });\n }\n }\n\n /**\n * Iterates through each immediate child and triggers the callback.\n *\n * @param func The function to invoke for each child.\n */\n forEachChild(func: (a: string, b: SparseSnapshotTree) => void) {\n this.children.forEach((tree, key) => {\n func(key, tree);\n });\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { Path } from './Path';\nimport { SparseSnapshotTree } from '../SparseSnapshotTree';\nimport { LeafNode } from '../snap/LeafNode';\nimport { nodeFromJSON } from '../snap/nodeFromJSON';\nimport { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';\nimport { Node } from '../snap/Node';\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { Indexable } from './misc';\n\n/**\n * Generate placeholders for deferred values.\n * @param {?Object} values\n * @return {!Object}\n */\nexport const generateWithValues = function(\n values: {\n [k: string]: unknown;\n } | null\n): { [k: string]: unknown } {\n values = values || {};\n values['timestamp'] = values['timestamp'] || new Date().getTime();\n return values;\n};\n\n/**\n * Value to use when firing local events. When writing server values, fire\n * local events with an approximate value, otherwise return value as-is.\n * @param {(Object|string|number|boolean)} value\n * @param {!Object} serverValues\n * @return {!(string|number|boolean)}\n */\nexport const resolveDeferredValue = function(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: { [k: string]: any } | string | number | boolean,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n serverValues: { [k: string]: any }\n): string | number | boolean {\n if (!value || typeof value !== 'object') {\n return value as string | number | boolean;\n } else {\n assert('.sv' in value, 'Unexpected leaf node or priority contents');\n return serverValues[value['.sv']];\n }\n};\n\n/**\n * Recursively replace all deferred values and priorities in the tree with the\n * specified generated replacement values.\n * @param {!SparseSnapshotTree} tree\n * @param {!Object} serverValues\n * @return {!SparseSnapshotTree}\n */\nexport const resolveDeferredValueTree = function(\n tree: SparseSnapshotTree,\n serverValues: object\n): SparseSnapshotTree {\n const resolvedTree = new SparseSnapshotTree();\n tree.forEachTree(new Path(''), (path, node) => {\n resolvedTree.remember(\n path,\n resolveDeferredValueSnapshot(node, serverValues)\n );\n });\n return resolvedTree;\n};\n\n/**\n * Recursively replace all deferred values and priorities in the node with the\n * specified generated replacement values. If there are no server values in the node,\n * it'll be returned as-is.\n * @param {!Node} node\n * @param {!Object} serverValues\n * @return {!Node}\n */\nexport const resolveDeferredValueSnapshot = function(\n node: Node,\n serverValues: object\n): Node {\n const rawPri = node.getPriority().val() as\n | Indexable\n | boolean\n | null\n | number\n | string;\n const priority = resolveDeferredValue(rawPri, serverValues);\n let newNode: Node;\n\n if (node.isLeafNode()) {\n const leafNode = node as LeafNode;\n const value = resolveDeferredValue(leafNode.getValue(), serverValues);\n if (\n value !== leafNode.getValue() ||\n priority !== leafNode.getPriority().val()\n ) {\n return new LeafNode(value, nodeFromJSON(priority));\n } else {\n return node;\n }\n } else {\n const childrenNode = node as ChildrenNode;\n newNode = childrenNode;\n if (priority !== childrenNode.getPriority().val()) {\n newNode = newNode.updatePriority(new LeafNode(priority));\n }\n childrenNode.forEachChild(PRIORITY_INDEX, (childName, childNode) => {\n const newChildNode = resolveDeferredValueSnapshot(\n childNode,\n serverValues\n );\n if (newChildNode !== childNode) {\n newNode = newNode.updateImmediateChild(childName, newChildNode);\n }\n });\n return newNode;\n }\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { Path } from '../util/Path';\n\n/**\n *\n * @enum\n */\nexport enum OperationType {\n OVERWRITE,\n MERGE,\n ACK_USER_WRITE,\n LISTEN_COMPLETE\n}\n\n/**\n * @interface\n */\nexport interface Operation {\n /**\n * @type {!OperationSource}\n */\n source: OperationSource;\n\n /**\n * @type {!OperationType}\n */\n type: OperationType;\n\n /**\n * @type {!Path}\n */\n path: Path;\n\n /**\n * @param {string} childName\n * @return {?Operation}\n */\n operationForChild(childName: string): Operation | null;\n}\n\n/**\n * @param {boolean} fromUser\n * @param {boolean} fromServer\n * @param {?string} queryId\n * @param {boolean} tagged\n * @constructor\n */\nexport class OperationSource {\n constructor(\n public fromUser: boolean,\n public fromServer: boolean,\n public queryId: string | null,\n public tagged: boolean\n ) {\n assert(!tagged || fromServer, 'Tagged queries must be from server.');\n }\n /**\n * @const\n * @type {!OperationSource}\n */\n static User = new OperationSource(\n /*fromUser=*/ true,\n false,\n null,\n /*tagged=*/ false\n );\n\n /**\n * @const\n * @type {!OperationSource}\n */\n static Server = new OperationSource(\n false,\n /*fromServer=*/ true,\n null,\n /*tagged=*/ false\n );\n\n /**\n * @param {string} queryId\n * @return {!OperationSource}\n */\n static forServerTaggedQuery = function(queryId: string): OperationSource {\n return new OperationSource(\n false,\n /*fromServer=*/ true,\n queryId,\n /*tagged=*/ true\n );\n };\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { Path } from '../util/Path';\nimport { Operation, OperationSource, OperationType } from './Operation';\nimport { ImmutableTree } from '../util/ImmutableTree';\n\nexport class AckUserWrite implements Operation {\n /** @inheritDoc */\n type = OperationType.ACK_USER_WRITE;\n\n /** @inheritDoc */\n source = OperationSource.User;\n\n /**\n *\n * @param {!Path} path\n * @param {!ImmutableTree} affectedTree A tree containing true for each affected path. Affected paths can't overlap.\n * @param {!boolean} revert\n */\n constructor(\n /** @inheritDoc */ public path: Path,\n /** @inheritDoc */ public affectedTree: ImmutableTree,\n /** @inheritDoc */ public revert: boolean\n ) {}\n\n /**\n * @inheritDoc\n */\n operationForChild(childName: string): AckUserWrite {\n if (!this.path.isEmpty()) {\n assert(\n this.path.getFront() === childName,\n 'operationForChild called for unrelated child.'\n );\n return new AckUserWrite(\n this.path.popFront(),\n this.affectedTree,\n this.revert\n );\n } else if (this.affectedTree.value != null) {\n assert(\n this.affectedTree.children.isEmpty(),\n 'affectedTree should not have overlapping affected paths.'\n );\n // All child locations are affected as well; just return same operation.\n return this;\n } else {\n const childTree = this.affectedTree.subtree(new Path(childName));\n return new AckUserWrite(Path.Empty, childTree, this.revert);\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { SortedMap } from './SortedMap';\nimport { Path } from './Path';\nimport { stringCompare, each } from './util';\n\nlet emptyChildrenSingleton: SortedMap>;\n\n/**\n * Singleton empty children collection.\n *\n * @const\n * @type {!SortedMap.>}\n */\nconst EmptyChildren = (): SortedMap> => {\n if (!emptyChildrenSingleton) {\n emptyChildrenSingleton = new SortedMap>(\n stringCompare\n );\n }\n return emptyChildrenSingleton;\n};\n\n/**\n * A tree with immutable elements.\n */\nexport class ImmutableTree {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n static Empty = new ImmutableTree(null);\n\n /**\n * @template T\n * @param {!Object.} obj\n * @return {!ImmutableTree.}\n */\n static fromObject(obj: { [k: string]: T }): ImmutableTree {\n let tree: ImmutableTree = ImmutableTree.Empty;\n each(obj, (childPath: string, childSnap: T) => {\n tree = tree.set(new Path(childPath), childSnap);\n });\n return tree;\n }\n\n /**\n * @template T\n * @param {?T} value\n * @param {SortedMap.>=} children\n */\n constructor(\n public readonly value: T | null,\n public readonly children: SortedMap<\n string,\n ImmutableTree\n > = EmptyChildren()\n ) {}\n\n /**\n * True if the value is empty and there are no children\n * @return {boolean}\n */\n isEmpty(): boolean {\n return this.value === null && this.children.isEmpty();\n }\n\n /**\n * Given a path and predicate, return the first node and the path to that node\n * where the predicate returns true.\n *\n * TODO Do a perf test -- If we're creating a bunch of {path: value:} objects\n * on the way back out, it may be better to pass down a pathSoFar obj.\n *\n * @param {!Path} relativePath The remainder of the path\n * @param {function(T):boolean} predicate The predicate to satisfy to return a\n * node\n * @return {?{path:!Path, value:!T}}\n */\n findRootMostMatchingPathAndValue(\n relativePath: Path,\n predicate: (a: T) => boolean\n ): { path: Path; value: T } | null {\n if (this.value != null && predicate(this.value)) {\n return { path: Path.Empty, value: this.value };\n } else {\n if (relativePath.isEmpty()) {\n return null;\n } else {\n const front = relativePath.getFront();\n const child = this.children.get(front);\n if (child !== null) {\n const childExistingPathAndValue = child.findRootMostMatchingPathAndValue(\n relativePath.popFront(),\n predicate\n );\n if (childExistingPathAndValue != null) {\n const fullPath = new Path(front).child(\n childExistingPathAndValue.path\n );\n return { path: fullPath, value: childExistingPathAndValue.value };\n } else {\n return null;\n }\n } else {\n return null;\n }\n }\n }\n }\n\n /**\n * Find, if it exists, the shortest subpath of the given path that points a defined\n * value in the tree\n * @param {!Path} relativePath\n * @return {?{path: !Path, value: !T}}\n */\n findRootMostValueAndPath(\n relativePath: Path\n ): { path: Path; value: T } | null {\n return this.findRootMostMatchingPathAndValue(relativePath, () => true);\n }\n\n /**\n * @param {!Path} relativePath\n * @return {!ImmutableTree.} The subtree at the given path\n */\n subtree(relativePath: Path): ImmutableTree {\n if (relativePath.isEmpty()) {\n return this;\n } else {\n const front = relativePath.getFront();\n const childTree = this.children.get(front);\n if (childTree !== null) {\n return childTree.subtree(relativePath.popFront());\n } else {\n return ImmutableTree.Empty;\n }\n }\n }\n\n /**\n * Sets a value at the specified path.\n *\n * @param {!Path} relativePath Path to set value at.\n * @param {?T} toSet Value to set.\n * @return {!ImmutableTree.} Resulting tree.\n */\n set(relativePath: Path, toSet: T | null): ImmutableTree {\n if (relativePath.isEmpty()) {\n return new ImmutableTree(toSet, this.children);\n } else {\n const front = relativePath.getFront();\n const child = this.children.get(front) || ImmutableTree.Empty;\n const newChild = child.set(relativePath.popFront(), toSet);\n const newChildren = this.children.insert(front, newChild);\n return new ImmutableTree(this.value, newChildren);\n }\n }\n\n /**\n * Removes the value at the specified path.\n *\n * @param {!Path} relativePath Path to value to remove.\n * @return {!ImmutableTree.} Resulting tree.\n */\n remove(relativePath: Path): ImmutableTree {\n if (relativePath.isEmpty()) {\n if (this.children.isEmpty()) {\n return ImmutableTree.Empty;\n } else {\n return new ImmutableTree(null, this.children);\n }\n } else {\n const front = relativePath.getFront();\n const child = this.children.get(front);\n if (child) {\n const newChild = child.remove(relativePath.popFront());\n let newChildren;\n if (newChild.isEmpty()) {\n newChildren = this.children.remove(front);\n } else {\n newChildren = this.children.insert(front, newChild);\n }\n if (this.value === null && newChildren.isEmpty()) {\n return ImmutableTree.Empty;\n } else {\n return new ImmutableTree(this.value, newChildren);\n }\n } else {\n return this;\n }\n }\n }\n\n /**\n * Gets a value from the tree.\n *\n * @param {!Path} relativePath Path to get value for.\n * @return {?T} Value at path, or null.\n */\n get(relativePath: Path): T | null {\n if (relativePath.isEmpty()) {\n return this.value;\n } else {\n const front = relativePath.getFront();\n const child = this.children.get(front);\n if (child) {\n return child.get(relativePath.popFront());\n } else {\n return null;\n }\n }\n }\n\n /**\n * Replace the subtree at the specified path with the given new tree.\n *\n * @param {!Path} relativePath Path to replace subtree for.\n * @param {!ImmutableTree} newTree New tree.\n * @return {!ImmutableTree} Resulting tree.\n */\n setTree(relativePath: Path, newTree: ImmutableTree): ImmutableTree {\n if (relativePath.isEmpty()) {\n return newTree;\n } else {\n const front = relativePath.getFront();\n const child = this.children.get(front) || ImmutableTree.Empty;\n const newChild = child.setTree(relativePath.popFront(), newTree);\n let newChildren;\n if (newChild.isEmpty()) {\n newChildren = this.children.remove(front);\n } else {\n newChildren = this.children.insert(front, newChild);\n }\n return new ImmutableTree(this.value, newChildren);\n }\n }\n\n /**\n * Performs a depth first fold on this tree. Transforms a tree into a single\n * value, given a function that operates on the path to a node, an optional\n * current value, and a map of child names to folded subtrees\n * @template V\n * @param {function(Path, ?T, Object.):V} fn\n * @return {V}\n */\n fold(fn: (path: Path, value: T, children: { [k: string]: V }) => V): V {\n return this.fold_(Path.Empty, fn);\n }\n\n /**\n * Recursive helper for public-facing fold() method\n * @template V\n * @param {!Path} pathSoFar\n * @param {function(Path, ?T, Object.):V} fn\n * @return {V}\n * @private\n */\n private fold_(\n pathSoFar: Path,\n fn: (path: Path, value: T | null, children: { [k: string]: V }) => V\n ): V {\n const accum: { [k: string]: V } = {};\n this.children.inorderTraversal(\n (childKey: string, childTree: ImmutableTree) => {\n accum[childKey] = childTree.fold_(pathSoFar.child(childKey), fn);\n }\n );\n return fn(pathSoFar, this.value, accum);\n }\n\n /**\n * Find the first matching value on the given path. Return the result of applying f to it.\n * @template V\n * @param {!Path} path\n * @param {!function(!Path, !T):?V} f\n * @return {?V}\n */\n findOnPath(path: Path, f: (path: Path, value: T) => V | null): V | null {\n return this.findOnPath_(path, Path.Empty, f);\n }\n\n private findOnPath_(\n pathToFollow: Path,\n pathSoFar: Path,\n f: (path: Path, value: T) => V | null\n ): V | null {\n const result = this.value ? f(pathSoFar, this.value) : false;\n if (result) {\n return result;\n } else {\n if (pathToFollow.isEmpty()) {\n return null;\n } else {\n const front = pathToFollow.getFront()!;\n const nextChild = this.children.get(front);\n if (nextChild) {\n return nextChild.findOnPath_(\n pathToFollow.popFront(),\n pathSoFar.child(front),\n f\n );\n } else {\n return null;\n }\n }\n }\n }\n\n /**\n *\n * @param {!Path} path\n * @param {!function(!Path, !T)} f\n * @returns {!ImmutableTree.}\n */\n foreachOnPath(\n path: Path,\n f: (path: Path, value: T) => void\n ): ImmutableTree {\n return this.foreachOnPath_(path, Path.Empty, f);\n }\n\n private foreachOnPath_(\n pathToFollow: Path,\n currentRelativePath: Path,\n f: (path: Path, value: T) => void\n ): ImmutableTree {\n if (pathToFollow.isEmpty()) {\n return this;\n } else {\n if (this.value) {\n f(currentRelativePath, this.value);\n }\n const front = pathToFollow.getFront();\n const nextChild = this.children.get(front);\n if (nextChild) {\n return nextChild.foreachOnPath_(\n pathToFollow.popFront(),\n currentRelativePath.child(front),\n f\n );\n } else {\n return ImmutableTree.Empty;\n }\n }\n }\n\n /**\n * Calls the given function for each node in the tree that has a value.\n *\n * @param {function(!Path, !T)} f A function to be called with\n * the path from the root of the tree to a node, and the value at that node.\n * Called in depth-first order.\n */\n foreach(f: (path: Path, value: T) => void) {\n this.foreach_(Path.Empty, f);\n }\n\n private foreach_(\n currentRelativePath: Path,\n f: (path: Path, value: T) => void\n ) {\n this.children.inorderTraversal((childName, childTree) => {\n childTree.foreach_(currentRelativePath.child(childName), f);\n });\n if (this.value) {\n f(currentRelativePath, this.value);\n }\n }\n\n /**\n *\n * @param {function(string, !T)} f\n */\n foreachChild(f: (name: string, value: T) => void) {\n this.children.inorderTraversal(\n (childName: string, childTree: ImmutableTree) => {\n if (childTree.value) {\n f(childName, childTree.value);\n }\n }\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path } from '../util/Path';\nimport { Operation, OperationSource, OperationType } from './Operation';\n\n/**\n * @param {!OperationSource} source\n * @param {!Path} path\n * @constructor\n * @implements {Operation}\n */\nexport class ListenComplete implements Operation {\n /** @inheritDoc */\n type = OperationType.LISTEN_COMPLETE;\n\n constructor(public source: OperationSource, public path: Path) {}\n\n operationForChild(childName: string): ListenComplete {\n if (this.path.isEmpty()) {\n return new ListenComplete(this.source, Path.Empty);\n } else {\n return new ListenComplete(this.source, this.path.popFront());\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Operation, OperationSource, OperationType } from './Operation';\nimport { Path } from '../util/Path';\nimport { Node } from '../snap/Node';\n\n/**\n * @param {!OperationSource} source\n * @param {!Path} path\n * @param {!Node} snap\n * @constructor\n * @implements {Operation}\n */\nexport class Overwrite implements Operation {\n /** @inheritDoc */\n type = OperationType.OVERWRITE;\n\n constructor(\n public source: OperationSource,\n public path: Path,\n public snap: Node\n ) {}\n\n operationForChild(childName: string): Overwrite {\n if (this.path.isEmpty()) {\n return new Overwrite(\n this.source,\n Path.Empty,\n this.snap.getImmediateChild(childName)\n );\n } else {\n return new Overwrite(this.source, this.path.popFront(), this.snap);\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Operation, OperationSource, OperationType } from './Operation';\nimport { Overwrite } from './Overwrite';\nimport { Path } from '../util/Path';\nimport { assert } from '@firebase/util';\nimport { ImmutableTree } from '../util/ImmutableTree';\nimport { Node } from '../snap/Node';\n\n/**\n * @param {!OperationSource} source\n * @param {!Path} path\n * @param {!ImmutableTree.} children\n * @constructor\n * @implements {Operation}\n */\nexport class Merge implements Operation {\n /** @inheritDoc */\n type = OperationType.MERGE;\n\n constructor(\n /** @inheritDoc */ public source: OperationSource,\n /** @inheritDoc */ public path: Path,\n /** @inheritDoc */ public children: ImmutableTree\n ) {}\n\n /**\n * @inheritDoc\n */\n operationForChild(childName: string): Operation {\n if (this.path.isEmpty()) {\n const childTree = this.children.subtree(new Path(childName));\n if (childTree.isEmpty()) {\n // This child is unaffected\n return null;\n } else if (childTree.value) {\n // We have a snapshot for the child in question. This becomes an overwrite of the child.\n return new Overwrite(this.source, Path.Empty, childTree.value);\n } else {\n // This is a merge at a deeper level\n return new Merge(this.source, Path.Empty, childTree);\n }\n } else {\n assert(\n this.path.getFront() === childName,\n \"Can't get a merge for a child not on the path of the operation\"\n );\n return new Merge(this.source, this.path.popFront(), this.children);\n }\n }\n\n /**\n * @inheritDoc\n */\n toString(): string {\n return (\n 'Operation(' +\n this.path +\n ': ' +\n this.source.toString() +\n ' merge: ' +\n this.children.toString() +\n ')'\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Node } from '../snap/Node';\nimport { Path } from '../util/Path';\n\n/**\n * A cache node only stores complete children. Additionally it holds a flag whether the node can be considered fully\n * initialized in the sense that we know at one point in time this represented a valid state of the world, e.g.\n * initialized with data from the server, or a complete overwrite by the client. The filtered flag also tracks\n * whether a node potentially had children removed due to a filter.\n */\nexport class CacheNode {\n /**\n * @param {!Node} node_\n * @param {boolean} fullyInitialized_\n * @param {boolean} filtered_\n */\n constructor(\n private node_: Node,\n private fullyInitialized_: boolean,\n private filtered_: boolean\n ) {}\n\n /**\n * Returns whether this node was fully initialized with either server data or a complete overwrite by the client\n * @return {boolean}\n */\n isFullyInitialized(): boolean {\n return this.fullyInitialized_;\n }\n\n /**\n * Returns whether this node is potentially missing children due to a filter applied to the node\n * @return {boolean}\n */\n isFiltered(): boolean {\n return this.filtered_;\n }\n\n /**\n * @param {!Path} path\n * @return {boolean}\n */\n isCompleteForPath(path: Path): boolean {\n if (path.isEmpty()) {\n return this.isFullyInitialized() && !this.filtered_;\n }\n\n const childKey = path.getFront();\n return this.isCompleteForChild(childKey);\n }\n\n /**\n * @param {!string} key\n * @return {boolean}\n */\n isCompleteForChild(key: string): boolean {\n return (\n (this.isFullyInitialized() && !this.filtered_) || this.node_.hasChild(key)\n );\n }\n\n /**\n * @return {!Node}\n */\n getNode(): Node {\n return this.node_;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { CacheNode } from './CacheNode';\nimport { Node } from '../snap/Node';\n\n/**\n * Stores the data we have cached for a view.\n *\n * serverSnap is the cached server data, eventSnap is the cached event data (server data plus any local writes).\n *\n * @constructor\n */\nexport class ViewCache {\n /**\n *\n * @param {!CacheNode} eventCache_\n * @param {!CacheNode} serverCache_\n */\n constructor(\n private readonly eventCache_: CacheNode,\n private readonly serverCache_: CacheNode\n ) {}\n\n /**\n * @const\n * @type {ViewCache}\n */\n static Empty = new ViewCache(\n new CacheNode(\n ChildrenNode.EMPTY_NODE,\n /*fullyInitialized=*/ false,\n /*filtered=*/ false\n ),\n new CacheNode(\n ChildrenNode.EMPTY_NODE,\n /*fullyInitialized=*/ false,\n /*filtered=*/ false\n )\n );\n\n /**\n * @param {!Node} eventSnap\n * @param {boolean} complete\n * @param {boolean} filtered\n * @return {!ViewCache}\n */\n updateEventSnap(\n eventSnap: Node,\n complete: boolean,\n filtered: boolean\n ): ViewCache {\n return new ViewCache(\n new CacheNode(eventSnap, complete, filtered),\n this.serverCache_\n );\n }\n\n /**\n * @param {!Node} serverSnap\n * @param {boolean} complete\n * @param {boolean} filtered\n * @return {!ViewCache}\n */\n updateServerSnap(\n serverSnap: Node,\n complete: boolean,\n filtered: boolean\n ): ViewCache {\n return new ViewCache(\n this.eventCache_,\n new CacheNode(serverSnap, complete, filtered)\n );\n }\n\n /**\n * @return {!CacheNode}\n */\n getEventCache(): CacheNode {\n return this.eventCache_;\n }\n\n /**\n * @return {?Node}\n */\n getCompleteEventSnap(): Node | null {\n return this.eventCache_.isFullyInitialized()\n ? this.eventCache_.getNode()\n : null;\n }\n\n /**\n * @return {!CacheNode}\n */\n getServerCache(): CacheNode {\n return this.serverCache_;\n }\n\n /**\n * @return {?Node}\n */\n getCompleteServerSnap(): Node | null {\n return this.serverCache_.isFullyInitialized()\n ? this.serverCache_.getNode()\n : null;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Node } from '../snap/Node';\n\n/**\n * @constructor\n * @struct\n * @param {!string} type The event type\n * @param {!Node} snapshotNode The data\n * @param {string=} childName The name for this child, if it's a child event\n * @param {Node=} oldSnap Used for intermediate processing of child changed events\n * @param {string=} prevName The name for the previous child, if applicable\n */\nexport class Change {\n constructor(\n public type: string,\n public snapshotNode: Node,\n public childName?: string,\n public oldSnap?: Node,\n public prevName?: string | null\n ) {}\n\n /**\n * @param {!Node} snapshot\n * @return {!Change}\n */\n static valueChange(snapshot: Node): Change {\n return new Change(Change.VALUE, snapshot);\n }\n\n /**\n * @param {string} childKey\n * @param {!Node} snapshot\n * @return {!Change}\n */\n static childAddedChange(childKey: string, snapshot: Node): Change {\n return new Change(Change.CHILD_ADDED, snapshot, childKey);\n }\n\n /**\n * @param {string} childKey\n * @param {!Node} snapshot\n * @return {!Change}\n */\n static childRemovedChange(childKey: string, snapshot: Node): Change {\n return new Change(Change.CHILD_REMOVED, snapshot, childKey);\n }\n\n /**\n * @param {string} childKey\n * @param {!Node} newSnapshot\n * @param {!Node} oldSnapshot\n * @return {!Change}\n */\n static childChangedChange(\n childKey: string,\n newSnapshot: Node,\n oldSnapshot: Node\n ): Change {\n return new Change(Change.CHILD_CHANGED, newSnapshot, childKey, oldSnapshot);\n }\n\n /**\n * @param {string} childKey\n * @param {!Node} snapshot\n * @return {!Change}\n */\n static childMovedChange(childKey: string, snapshot: Node): Change {\n return new Change(Change.CHILD_MOVED, snapshot, childKey);\n }\n\n //event types\n /** Event type for a child added */\n static CHILD_ADDED = 'child_added';\n\n /** Event type for a child removed */\n static CHILD_REMOVED = 'child_removed';\n\n /** Event type for a child changed */\n static CHILD_CHANGED = 'child_changed';\n\n /** Event type for a child moved */\n static CHILD_MOVED = 'child_moved';\n\n /** Event type for a value change */\n static VALUE = 'value';\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { Change } from '../Change';\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { PRIORITY_INDEX } from '../../snap/indexes/PriorityIndex';\nimport { NodeFilter } from './NodeFilter';\nimport { Index } from '../../snap/indexes/Index';\nimport { Path } from '../../util/Path';\nimport { CompleteChildSource } from '../CompleteChildSource';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\nimport { Node } from '../../snap/Node';\n\n/**\n * Doesn't really filter nodes but applies an index to the node and keeps track of any changes\n *\n * @constructor\n * @implements {NodeFilter}\n * @param {!Index} index\n */\nexport class IndexedFilter implements NodeFilter {\n constructor(private readonly index_: Index) {}\n\n updateChild(\n snap: Node,\n key: string,\n newChild: Node,\n affectedPath: Path,\n source: CompleteChildSource,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n assert(\n snap.isIndexed(this.index_),\n 'A node must be indexed if only a child is updated'\n );\n const oldChild = snap.getImmediateChild(key);\n // Check if anything actually changed.\n if (\n oldChild.getChild(affectedPath).equals(newChild.getChild(affectedPath))\n ) {\n // There's an edge case where a child can enter or leave the view because affectedPath was set to null.\n // In this case, affectedPath will appear null in both the old and new snapshots. So we need\n // to avoid treating these cases as \"nothing changed.\"\n if (oldChild.isEmpty() === newChild.isEmpty()) {\n // Nothing changed.\n\n // This assert should be valid, but it's expensive (can dominate perf testing) so don't actually do it.\n //assert(oldChild.equals(newChild), 'Old and new snapshots should be equal.');\n return snap;\n }\n }\n\n if (optChangeAccumulator != null) {\n if (newChild.isEmpty()) {\n if (snap.hasChild(key)) {\n optChangeAccumulator.trackChildChange(\n Change.childRemovedChange(key, oldChild)\n );\n } else {\n assert(\n snap.isLeafNode(),\n 'A child remove without an old child only makes sense on a leaf node'\n );\n }\n } else if (oldChild.isEmpty()) {\n optChangeAccumulator.trackChildChange(\n Change.childAddedChange(key, newChild)\n );\n } else {\n optChangeAccumulator.trackChildChange(\n Change.childChangedChange(key, newChild, oldChild)\n );\n }\n }\n if (snap.isLeafNode() && newChild.isEmpty()) {\n return snap;\n } else {\n // Make sure the node is indexed\n return snap.updateImmediateChild(key, newChild).withIndex(this.index_);\n }\n }\n\n /**\n * @inheritDoc\n */\n updateFullNode(\n oldSnap: Node,\n newSnap: Node,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n if (optChangeAccumulator != null) {\n if (!oldSnap.isLeafNode()) {\n oldSnap.forEachChild(PRIORITY_INDEX, (key, childNode) => {\n if (!newSnap.hasChild(key)) {\n optChangeAccumulator.trackChildChange(\n Change.childRemovedChange(key, childNode)\n );\n }\n });\n }\n if (!newSnap.isLeafNode()) {\n newSnap.forEachChild(PRIORITY_INDEX, (key, childNode) => {\n if (oldSnap.hasChild(key)) {\n const oldChild = oldSnap.getImmediateChild(key);\n if (!oldChild.equals(childNode)) {\n optChangeAccumulator.trackChildChange(\n Change.childChangedChange(key, childNode, oldChild)\n );\n }\n } else {\n optChangeAccumulator.trackChildChange(\n Change.childAddedChange(key, childNode)\n );\n }\n });\n }\n }\n return newSnap.withIndex(this.index_);\n }\n\n /**\n * @inheritDoc\n */\n updatePriority(oldSnap: Node, newPriority: Node): Node {\n if (oldSnap.isEmpty()) {\n return ChildrenNode.EMPTY_NODE;\n } else {\n return oldSnap.updatePriority(newPriority);\n }\n }\n\n /**\n * @inheritDoc\n */\n filtersNodes(): boolean {\n return false;\n }\n\n /**\n * @inheritDoc\n */\n getIndexedFilter(): IndexedFilter {\n return this;\n }\n\n /**\n * @inheritDoc\n */\n getIndex(): Index {\n return this.index_;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Change } from './Change';\nimport { assert, assertionError } from '@firebase/util';\n\nexport class ChildChangeAccumulator {\n private readonly changeMap: Map = new Map();\n\n trackChildChange(change: Change) {\n const type = change.type;\n const childKey = change.childName!;\n assert(\n type === Change.CHILD_ADDED ||\n type === Change.CHILD_CHANGED ||\n type === Change.CHILD_REMOVED,\n 'Only child changes supported for tracking'\n );\n assert(\n childKey !== '.priority',\n 'Only non-priority child changes can be tracked.'\n );\n const oldChange = this.changeMap.get(childKey);\n if (oldChange) {\n const oldType = oldChange.type;\n if (type === Change.CHILD_ADDED && oldType === Change.CHILD_REMOVED) {\n this.changeMap.set(\n childKey,\n Change.childChangedChange(\n childKey,\n change.snapshotNode,\n oldChange.snapshotNode\n )\n );\n } else if (\n type === Change.CHILD_REMOVED &&\n oldType === Change.CHILD_ADDED\n ) {\n this.changeMap.delete(childKey);\n } else if (\n type === Change.CHILD_REMOVED &&\n oldType === Change.CHILD_CHANGED\n ) {\n this.changeMap.set(\n childKey,\n Change.childRemovedChange(childKey, oldChange.oldSnap)\n );\n } else if (\n type === Change.CHILD_CHANGED &&\n oldType === Change.CHILD_ADDED\n ) {\n this.changeMap.set(\n childKey,\n Change.childAddedChange(childKey, change.snapshotNode)\n );\n } else if (\n type === Change.CHILD_CHANGED &&\n oldType === Change.CHILD_CHANGED\n ) {\n this.changeMap.set(\n childKey,\n Change.childChangedChange(\n childKey,\n change.snapshotNode,\n oldChange.oldSnap\n )\n );\n } else {\n throw assertionError(\n 'Illegal combination of changes: ' +\n change +\n ' occurred after ' +\n oldChange\n );\n }\n } else {\n this.changeMap.set(childKey, change);\n }\n }\n\n getChanges(): Change[] {\n return Array.from(this.changeMap.values());\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheNode } from './CacheNode';\nimport { NamedNode, Node } from '../snap/Node';\nimport { Index } from '../snap/indexes/Index';\nimport { WriteTreeRef } from '../WriteTree';\nimport { ViewCache } from './ViewCache';\n\n/**\n * Since updates to filtered nodes might require nodes to be pulled in from \"outside\" the node, this interface\n * can help to get complete children that can be pulled in.\n * A class implementing this interface takes potentially multiple sources (e.g. user writes, server data from\n * other views etc.) to try it's best to get a complete child that might be useful in pulling into the view.\n *\n * @interface\n */\nexport interface CompleteChildSource {\n /**\n * @param {!string} childKey\n * @return {?Node}\n */\n getCompleteChild(childKey: string): Node | null;\n\n /**\n * @param {!Index} index\n * @param {!NamedNode} child\n * @param {boolean} reverse\n * @return {?NamedNode}\n */\n getChildAfterChild(\n index: Index,\n child: NamedNode,\n reverse: boolean\n ): NamedNode | null;\n}\n\n/**\n * An implementation of CompleteChildSource that never returns any additional children\n *\n * @private\n * @constructor\n * @implements CompleteChildSource\n */\n// eslint-disable-next-line @typescript-eslint/class-name-casing\nexport class NoCompleteChildSource_ implements CompleteChildSource {\n /**\n * @inheritDoc\n */\n getCompleteChild(childKey?: string): Node | null {\n return null;\n }\n\n /**\n * @inheritDoc\n */\n getChildAfterChild(\n index?: Index,\n child?: NamedNode,\n reverse?: boolean\n ): NamedNode | null {\n return null;\n }\n}\n\n/**\n * Singleton instance.\n * @const\n * @type {!CompleteChildSource}\n */\nexport const NO_COMPLETE_CHILD_SOURCE = new NoCompleteChildSource_();\n\n/**\n * An implementation of CompleteChildSource that uses a WriteTree in addition to any other server data or\n * old event caches available to calculate complete children.\n *\n *\n * @implements CompleteChildSource\n */\nexport class WriteTreeCompleteChildSource implements CompleteChildSource {\n /**\n * @param {!WriteTreeRef} writes_\n * @param {!ViewCache} viewCache_\n * @param {?Node} optCompleteServerCache_\n */\n constructor(\n private writes_: WriteTreeRef,\n private viewCache_: ViewCache,\n private optCompleteServerCache_: Node | null = null\n ) {}\n\n /**\n * @inheritDoc\n */\n getCompleteChild(childKey: string): Node | null {\n const node = this.viewCache_.getEventCache();\n if (node.isCompleteForChild(childKey)) {\n return node.getNode().getImmediateChild(childKey);\n } else {\n const serverNode =\n this.optCompleteServerCache_ != null\n ? new CacheNode(this.optCompleteServerCache_, true, false)\n : this.viewCache_.getServerCache();\n return this.writes_.calcCompleteChild(childKey, serverNode);\n }\n }\n\n /**\n * @inheritDoc\n */\n getChildAfterChild(\n index: Index,\n child: NamedNode,\n reverse: boolean\n ): NamedNode | null {\n const completeServerData =\n this.optCompleteServerCache_ != null\n ? this.optCompleteServerCache_\n : this.viewCache_.getCompleteServerSnap();\n const nodes = this.writes_.calcIndexedSlice(\n completeServerData,\n child,\n 1,\n reverse,\n index\n );\n if (nodes.length === 0) {\n return null;\n } else {\n return nodes[0];\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Operation, OperationType } from '../operation/Operation';\nimport { assert, assertionError } from '@firebase/util';\nimport { ChildChangeAccumulator } from './ChildChangeAccumulator';\nimport { Change } from './Change';\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { KEY_INDEX } from '../snap/indexes/KeyIndex';\nimport { ImmutableTree } from '../util/ImmutableTree';\nimport { Path } from '../util/Path';\nimport {\n WriteTreeCompleteChildSource,\n NO_COMPLETE_CHILD_SOURCE,\n CompleteChildSource\n} from './CompleteChildSource';\nimport { ViewCache } from './ViewCache';\nimport { NodeFilter } from './filter/NodeFilter';\nimport { WriteTreeRef } from '../WriteTree';\nimport { Overwrite } from '../operation/Overwrite';\nimport { Merge } from '../operation/Merge';\nimport { AckUserWrite } from '../operation/AckUserWrite';\nimport { Node } from '../snap/Node';\n\n/**\n * @constructor\n * @struct\n */\nexport class ProcessorResult {\n /**\n * @param {!ViewCache} viewCache\n * @param {!Array.} changes\n */\n constructor(\n public readonly viewCache: ViewCache,\n public readonly changes: Change[]\n ) {}\n}\n\n/**\n * @constructor\n */\nexport class ViewProcessor {\n /**\n * @param {!NodeFilter} filter_\n */\n constructor(private readonly filter_: NodeFilter) {}\n\n /**\n * @param {!ViewCache} viewCache\n */\n assertIndexed(viewCache: ViewCache) {\n assert(\n viewCache\n .getEventCache()\n .getNode()\n .isIndexed(this.filter_.getIndex()),\n 'Event snap not indexed'\n );\n assert(\n viewCache\n .getServerCache()\n .getNode()\n .isIndexed(this.filter_.getIndex()),\n 'Server snap not indexed'\n );\n }\n\n /**\n * @param {!ViewCache} oldViewCache\n * @param {!Operation} operation\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeCache\n * @return {!ProcessorResult}\n */\n applyOperation(\n oldViewCache: ViewCache,\n operation: Operation,\n writesCache: WriteTreeRef,\n completeCache: Node | null\n ): ProcessorResult {\n const accumulator = new ChildChangeAccumulator();\n let newViewCache, filterServerNode;\n if (operation.type === OperationType.OVERWRITE) {\n const overwrite = operation as Overwrite;\n if (overwrite.source.fromUser) {\n newViewCache = this.applyUserOverwrite_(\n oldViewCache,\n overwrite.path,\n overwrite.snap,\n writesCache,\n completeCache,\n accumulator\n );\n } else {\n assert(overwrite.source.fromServer, 'Unknown source.');\n // We filter the node if it's a tagged update or the node has been previously filtered and the\n // update is not at the root in which case it is ok (and necessary) to mark the node unfiltered\n // again\n filterServerNode =\n overwrite.source.tagged ||\n (oldViewCache.getServerCache().isFiltered() &&\n !overwrite.path.isEmpty());\n newViewCache = this.applyServerOverwrite_(\n oldViewCache,\n overwrite.path,\n overwrite.snap,\n writesCache,\n completeCache,\n filterServerNode,\n accumulator\n );\n }\n } else if (operation.type === OperationType.MERGE) {\n const merge = operation as Merge;\n if (merge.source.fromUser) {\n newViewCache = this.applyUserMerge_(\n oldViewCache,\n merge.path,\n merge.children,\n writesCache,\n completeCache,\n accumulator\n );\n } else {\n assert(merge.source.fromServer, 'Unknown source.');\n // We filter the node if it's a tagged update or the node has been previously filtered\n filterServerNode =\n merge.source.tagged || oldViewCache.getServerCache().isFiltered();\n newViewCache = this.applyServerMerge_(\n oldViewCache,\n merge.path,\n merge.children,\n writesCache,\n completeCache,\n filterServerNode,\n accumulator\n );\n }\n } else if (operation.type === OperationType.ACK_USER_WRITE) {\n const ackUserWrite = operation as AckUserWrite;\n if (!ackUserWrite.revert) {\n newViewCache = this.ackUserWrite_(\n oldViewCache,\n ackUserWrite.path,\n ackUserWrite.affectedTree,\n writesCache,\n completeCache,\n accumulator\n );\n } else {\n newViewCache = this.revertUserWrite_(\n oldViewCache,\n ackUserWrite.path,\n writesCache,\n completeCache,\n accumulator\n );\n }\n } else if (operation.type === OperationType.LISTEN_COMPLETE) {\n newViewCache = this.listenComplete_(\n oldViewCache,\n operation.path,\n writesCache,\n accumulator\n );\n } else {\n throw assertionError('Unknown operation type: ' + operation.type);\n }\n const changes = accumulator.getChanges();\n ViewProcessor.maybeAddValueEvent_(oldViewCache, newViewCache, changes);\n return new ProcessorResult(newViewCache, changes);\n }\n\n /**\n * @param {!ViewCache} oldViewCache\n * @param {!ViewCache} newViewCache\n * @param {!Array.} accumulator\n * @private\n */\n private static maybeAddValueEvent_(\n oldViewCache: ViewCache,\n newViewCache: ViewCache,\n accumulator: Change[]\n ) {\n const eventSnap = newViewCache.getEventCache();\n if (eventSnap.isFullyInitialized()) {\n const isLeafOrEmpty =\n eventSnap.getNode().isLeafNode() || eventSnap.getNode().isEmpty();\n const oldCompleteSnap = oldViewCache.getCompleteEventSnap();\n if (\n accumulator.length > 0 ||\n !oldViewCache.getEventCache().isFullyInitialized() ||\n (isLeafOrEmpty &&\n !eventSnap.getNode().equals(/** @type {!Node} */ oldCompleteSnap)) ||\n !eventSnap\n .getNode()\n .getPriority()\n .equals(oldCompleteSnap.getPriority())\n ) {\n accumulator.push(\n Change.valueChange(\n /** @type {!Node} */ newViewCache.getCompleteEventSnap()\n )\n );\n }\n }\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} changePath\n * @param {!WriteTreeRef} writesCache\n * @param {!CompleteChildSource} source\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private generateEventCacheAfterServerEvent_(\n viewCache: ViewCache,\n changePath: Path,\n writesCache: WriteTreeRef,\n source: CompleteChildSource,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n const oldEventSnap = viewCache.getEventCache();\n if (writesCache.shadowingWrite(changePath) != null) {\n // we have a shadowing write, ignore changes\n return viewCache;\n } else {\n let newEventCache, serverNode;\n if (changePath.isEmpty()) {\n // TODO: figure out how this plays with \"sliding ack windows\"\n assert(\n viewCache.getServerCache().isFullyInitialized(),\n 'If change path is empty, we must have complete server data'\n );\n if (viewCache.getServerCache().isFiltered()) {\n // We need to special case this, because we need to only apply writes to complete children, or\n // we might end up raising events for incomplete children. If the server data is filtered deep\n // writes cannot be guaranteed to be complete\n const serverCache = viewCache.getCompleteServerSnap();\n const completeChildren =\n serverCache instanceof ChildrenNode\n ? serverCache\n : ChildrenNode.EMPTY_NODE;\n const completeEventChildren = writesCache.calcCompleteEventChildren(\n completeChildren\n );\n newEventCache = this.filter_.updateFullNode(\n viewCache.getEventCache().getNode(),\n completeEventChildren,\n accumulator\n );\n } else {\n const completeNode = writesCache.calcCompleteEventCache(\n viewCache.getCompleteServerSnap()\n );\n newEventCache = this.filter_.updateFullNode(\n viewCache.getEventCache().getNode(),\n completeNode,\n accumulator\n );\n }\n } else {\n const childKey = changePath.getFront();\n if (childKey === '.priority') {\n assert(\n changePath.getLength() === 1,\n \"Can't have a priority with additional path components\"\n );\n const oldEventNode = oldEventSnap.getNode();\n serverNode = viewCache.getServerCache().getNode();\n // we might have overwrites for this priority\n const updatedPriority = writesCache.calcEventCacheAfterServerOverwrite(\n changePath,\n oldEventNode,\n serverNode\n );\n if (updatedPriority != null) {\n newEventCache = this.filter_.updatePriority(\n oldEventNode,\n updatedPriority\n );\n } else {\n // priority didn't change, keep old node\n newEventCache = oldEventSnap.getNode();\n }\n } else {\n const childChangePath = changePath.popFront();\n // update child\n let newEventChild;\n if (oldEventSnap.isCompleteForChild(childKey)) {\n serverNode = viewCache.getServerCache().getNode();\n const eventChildUpdate = writesCache.calcEventCacheAfterServerOverwrite(\n changePath,\n oldEventSnap.getNode(),\n serverNode\n );\n if (eventChildUpdate != null) {\n newEventChild = oldEventSnap\n .getNode()\n .getImmediateChild(childKey)\n .updateChild(childChangePath, eventChildUpdate);\n } else {\n // Nothing changed, just keep the old child\n newEventChild = oldEventSnap\n .getNode()\n .getImmediateChild(childKey);\n }\n } else {\n newEventChild = writesCache.calcCompleteChild(\n childKey,\n viewCache.getServerCache()\n );\n }\n if (newEventChild != null) {\n newEventCache = this.filter_.updateChild(\n oldEventSnap.getNode(),\n childKey,\n newEventChild,\n childChangePath,\n source,\n accumulator\n );\n } else {\n // no complete child available or no change\n newEventCache = oldEventSnap.getNode();\n }\n }\n }\n return viewCache.updateEventSnap(\n newEventCache,\n oldEventSnap.isFullyInitialized() || changePath.isEmpty(),\n this.filter_.filtersNodes()\n );\n }\n }\n\n /**\n * @param {!ViewCache} oldViewCache\n * @param {!Path} changePath\n * @param {!Node} changedSnap\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeCache\n * @param {boolean} filterServerNode\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n applyServerOverwrite_(\n oldViewCache: ViewCache,\n changePath: Path,\n changedSnap: Node,\n writesCache: WriteTreeRef,\n completeCache: Node | null,\n filterServerNode: boolean,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n const oldServerSnap = oldViewCache.getServerCache();\n let newServerCache;\n const serverFilter = filterServerNode\n ? this.filter_\n : this.filter_.getIndexedFilter();\n if (changePath.isEmpty()) {\n newServerCache = serverFilter.updateFullNode(\n oldServerSnap.getNode(),\n changedSnap,\n null\n );\n } else if (serverFilter.filtersNodes() && !oldServerSnap.isFiltered()) {\n // we want to filter the server node, but we didn't filter the server node yet, so simulate a full update\n const newServerNode = oldServerSnap\n .getNode()\n .updateChild(changePath, changedSnap);\n newServerCache = serverFilter.updateFullNode(\n oldServerSnap.getNode(),\n newServerNode,\n null\n );\n } else {\n const childKey = changePath.getFront();\n if (\n !oldServerSnap.isCompleteForPath(changePath) &&\n changePath.getLength() > 1\n ) {\n // We don't update incomplete nodes with updates intended for other listeners\n return oldViewCache;\n }\n const childChangePath = changePath.popFront();\n const childNode = oldServerSnap.getNode().getImmediateChild(childKey);\n const newChildNode = childNode.updateChild(childChangePath, changedSnap);\n if (childKey === '.priority') {\n newServerCache = serverFilter.updatePriority(\n oldServerSnap.getNode(),\n newChildNode\n );\n } else {\n newServerCache = serverFilter.updateChild(\n oldServerSnap.getNode(),\n childKey,\n newChildNode,\n childChangePath,\n NO_COMPLETE_CHILD_SOURCE,\n null\n );\n }\n }\n const newViewCache = oldViewCache.updateServerSnap(\n newServerCache,\n oldServerSnap.isFullyInitialized() || changePath.isEmpty(),\n serverFilter.filtersNodes()\n );\n const source = new WriteTreeCompleteChildSource(\n writesCache,\n newViewCache,\n completeCache\n );\n return this.generateEventCacheAfterServerEvent_(\n newViewCache,\n changePath,\n writesCache,\n source,\n accumulator\n );\n }\n\n /**\n * @param {!ViewCache} oldViewCache\n * @param {!Path} changePath\n * @param {!Node} changedSnap\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeCache\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n applyUserOverwrite_(\n oldViewCache: ViewCache,\n changePath: Path,\n changedSnap: Node,\n writesCache: WriteTreeRef,\n completeCache: Node | null,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n const oldEventSnap = oldViewCache.getEventCache();\n let newViewCache, newEventCache;\n const source = new WriteTreeCompleteChildSource(\n writesCache,\n oldViewCache,\n completeCache\n );\n if (changePath.isEmpty()) {\n newEventCache = this.filter_.updateFullNode(\n oldViewCache.getEventCache().getNode(),\n changedSnap,\n accumulator\n );\n newViewCache = oldViewCache.updateEventSnap(\n newEventCache,\n true,\n this.filter_.filtersNodes()\n );\n } else {\n const childKey = changePath.getFront();\n if (childKey === '.priority') {\n newEventCache = this.filter_.updatePriority(\n oldViewCache.getEventCache().getNode(),\n changedSnap\n );\n newViewCache = oldViewCache.updateEventSnap(\n newEventCache,\n oldEventSnap.isFullyInitialized(),\n oldEventSnap.isFiltered()\n );\n } else {\n const childChangePath = changePath.popFront();\n const oldChild = oldEventSnap.getNode().getImmediateChild(childKey);\n let newChild;\n if (childChangePath.isEmpty()) {\n // Child overwrite, we can replace the child\n newChild = changedSnap;\n } else {\n const childNode = source.getCompleteChild(childKey);\n if (childNode != null) {\n if (\n childChangePath.getBack() === '.priority' &&\n childNode.getChild(childChangePath.parent()).isEmpty()\n ) {\n // This is a priority update on an empty node. If this node exists on the server, the\n // server will send down the priority in the update, so ignore for now\n newChild = childNode;\n } else {\n newChild = childNode.updateChild(childChangePath, changedSnap);\n }\n } else {\n // There is no complete child node available\n newChild = ChildrenNode.EMPTY_NODE;\n }\n }\n if (!oldChild.equals(newChild)) {\n const newEventSnap = this.filter_.updateChild(\n oldEventSnap.getNode(),\n childKey,\n newChild,\n childChangePath,\n source,\n accumulator\n );\n newViewCache = oldViewCache.updateEventSnap(\n newEventSnap,\n oldEventSnap.isFullyInitialized(),\n this.filter_.filtersNodes()\n );\n } else {\n newViewCache = oldViewCache;\n }\n }\n }\n return newViewCache;\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {string} childKey\n * @return {boolean}\n * @private\n */\n private static cacheHasChild_(\n viewCache: ViewCache,\n childKey: string\n ): boolean {\n return viewCache.getEventCache().isCompleteForChild(childKey);\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} path\n * @param {ImmutableTree.} changedChildren\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} serverCache\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private applyUserMerge_(\n viewCache: ViewCache,\n path: Path,\n changedChildren: ImmutableTree,\n writesCache: WriteTreeRef,\n serverCache: Node | null,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n // HACK: In the case of a limit query, there may be some changes that bump things out of the\n // window leaving room for new items. It's important we process these changes first, so we\n // iterate the changes twice, first processing any that affect items currently in view.\n // TODO: I consider an item \"in view\" if cacheHasChild is true, which checks both the server\n // and event snap. I'm not sure if this will result in edge cases when a child is in one but\n // not the other.\n let curViewCache = viewCache;\n changedChildren.foreach((relativePath, childNode) => {\n const writePath = path.child(relativePath);\n if (ViewProcessor.cacheHasChild_(viewCache, writePath.getFront())) {\n curViewCache = this.applyUserOverwrite_(\n curViewCache,\n writePath,\n childNode,\n writesCache,\n serverCache,\n accumulator\n );\n }\n });\n\n changedChildren.foreach((relativePath, childNode) => {\n const writePath = path.child(relativePath);\n if (!ViewProcessor.cacheHasChild_(viewCache, writePath.getFront())) {\n curViewCache = this.applyUserOverwrite_(\n curViewCache,\n writePath,\n childNode,\n writesCache,\n serverCache,\n accumulator\n );\n }\n });\n\n return curViewCache;\n }\n\n /**\n * @param {!Node} node\n * @param {ImmutableTree.} merge\n * @return {!Node}\n * @private\n */\n private applyMerge_(node: Node, merge: ImmutableTree): Node {\n merge.foreach((relativePath, childNode) => {\n node = node.updateChild(relativePath, childNode);\n });\n return node;\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} path\n * @param {!ImmutableTree.} changedChildren\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} serverCache\n * @param {boolean} filterServerNode\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private applyServerMerge_(\n viewCache: ViewCache,\n path: Path,\n changedChildren: ImmutableTree,\n writesCache: WriteTreeRef,\n serverCache: Node | null,\n filterServerNode: boolean,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n // If we don't have a cache yet, this merge was intended for a previously listen in the same location. Ignore it and\n // wait for the complete data update coming soon.\n if (\n viewCache\n .getServerCache()\n .getNode()\n .isEmpty() &&\n !viewCache.getServerCache().isFullyInitialized()\n ) {\n return viewCache;\n }\n\n // HACK: In the case of a limit query, there may be some changes that bump things out of the\n // window leaving room for new items. It's important we process these changes first, so we\n // iterate the changes twice, first processing any that affect items currently in view.\n // TODO: I consider an item \"in view\" if cacheHasChild is true, which checks both the server\n // and event snap. I'm not sure if this will result in edge cases when a child is in one but\n // not the other.\n let curViewCache = viewCache;\n let viewMergeTree;\n if (path.isEmpty()) {\n viewMergeTree = changedChildren;\n } else {\n viewMergeTree = ImmutableTree.Empty.setTree(path, changedChildren);\n }\n const serverNode = viewCache.getServerCache().getNode();\n viewMergeTree.children.inorderTraversal((childKey, childTree) => {\n if (serverNode.hasChild(childKey)) {\n const serverChild = viewCache\n .getServerCache()\n .getNode()\n .getImmediateChild(childKey);\n const newChild = this.applyMerge_(serverChild, childTree);\n curViewCache = this.applyServerOverwrite_(\n curViewCache,\n new Path(childKey),\n newChild,\n writesCache,\n serverCache,\n filterServerNode,\n accumulator\n );\n }\n });\n viewMergeTree.children.inorderTraversal((childKey, childMergeTree) => {\n const isUnknownDeepMerge =\n !viewCache.getServerCache().isCompleteForChild(childKey) &&\n childMergeTree.value == null;\n if (!serverNode.hasChild(childKey) && !isUnknownDeepMerge) {\n const serverChild = viewCache\n .getServerCache()\n .getNode()\n .getImmediateChild(childKey);\n const newChild = this.applyMerge_(serverChild, childMergeTree);\n curViewCache = this.applyServerOverwrite_(\n curViewCache,\n new Path(childKey),\n newChild,\n writesCache,\n serverCache,\n filterServerNode,\n accumulator\n );\n }\n });\n\n return curViewCache;\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} ackPath\n * @param {!ImmutableTree} affectedTree\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeCache\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private ackUserWrite_(\n viewCache: ViewCache,\n ackPath: Path,\n affectedTree: ImmutableTree,\n writesCache: WriteTreeRef,\n completeCache: Node | null,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n if (writesCache.shadowingWrite(ackPath) != null) {\n return viewCache;\n }\n\n // Only filter server node if it is currently filtered\n const filterServerNode = viewCache.getServerCache().isFiltered();\n\n // Essentially we'll just get our existing server cache for the affected paths and re-apply it as a server update\n // now that it won't be shadowed.\n const serverCache = viewCache.getServerCache();\n if (affectedTree.value != null) {\n // This is an overwrite.\n if (\n (ackPath.isEmpty() && serverCache.isFullyInitialized()) ||\n serverCache.isCompleteForPath(ackPath)\n ) {\n return this.applyServerOverwrite_(\n viewCache,\n ackPath,\n serverCache.getNode().getChild(ackPath),\n writesCache,\n completeCache,\n filterServerNode,\n accumulator\n );\n } else if (ackPath.isEmpty()) {\n // This is a goofy edge case where we are acking data at this location but don't have full data. We\n // should just re-apply whatever we have in our cache as a merge.\n let changedChildren = ImmutableTree.Empty;\n serverCache.getNode().forEachChild(KEY_INDEX, (name, node) => {\n changedChildren = changedChildren.set(new Path(name), node);\n });\n return this.applyServerMerge_(\n viewCache,\n ackPath,\n changedChildren,\n writesCache,\n completeCache,\n filterServerNode,\n accumulator\n );\n } else {\n return viewCache;\n }\n } else {\n // This is a merge.\n let changedChildren = ImmutableTree.Empty;\n affectedTree.foreach((mergePath, value) => {\n const serverCachePath = ackPath.child(mergePath);\n if (serverCache.isCompleteForPath(serverCachePath)) {\n changedChildren = changedChildren.set(\n mergePath,\n serverCache.getNode().getChild(serverCachePath)\n );\n }\n });\n return this.applyServerMerge_(\n viewCache,\n ackPath,\n changedChildren,\n writesCache,\n completeCache,\n filterServerNode,\n accumulator\n );\n }\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} path\n * @param {!WriteTreeRef} writesCache\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private listenComplete_(\n viewCache: ViewCache,\n path: Path,\n writesCache: WriteTreeRef,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n const oldServerNode = viewCache.getServerCache();\n const newViewCache = viewCache.updateServerSnap(\n oldServerNode.getNode(),\n oldServerNode.isFullyInitialized() || path.isEmpty(),\n oldServerNode.isFiltered()\n );\n return this.generateEventCacheAfterServerEvent_(\n newViewCache,\n path,\n writesCache,\n NO_COMPLETE_CHILD_SOURCE,\n accumulator\n );\n }\n\n /**\n * @param {!ViewCache} viewCache\n * @param {!Path} path\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeServerCache\n * @param {!ChildChangeAccumulator} accumulator\n * @return {!ViewCache}\n * @private\n */\n private revertUserWrite_(\n viewCache: ViewCache,\n path: Path,\n writesCache: WriteTreeRef,\n completeServerCache: Node | null,\n accumulator: ChildChangeAccumulator\n ): ViewCache {\n let complete;\n if (writesCache.shadowingWrite(path) != null) {\n return viewCache;\n } else {\n const source = new WriteTreeCompleteChildSource(\n writesCache,\n viewCache,\n completeServerCache\n );\n const oldEventCache = viewCache.getEventCache().getNode();\n let newEventCache;\n if (path.isEmpty() || path.getFront() === '.priority') {\n let newNode;\n if (viewCache.getServerCache().isFullyInitialized()) {\n newNode = writesCache.calcCompleteEventCache(\n viewCache.getCompleteServerSnap()\n );\n } else {\n const serverChildren = viewCache.getServerCache().getNode();\n assert(\n serverChildren instanceof ChildrenNode,\n 'serverChildren would be complete if leaf node'\n );\n newNode = writesCache.calcCompleteEventChildren(\n serverChildren as ChildrenNode\n );\n }\n newNode = newNode as Node;\n newEventCache = this.filter_.updateFullNode(\n oldEventCache,\n newNode,\n accumulator\n );\n } else {\n const childKey = path.getFront();\n let newChild = writesCache.calcCompleteChild(\n childKey,\n viewCache.getServerCache()\n );\n if (\n newChild == null &&\n viewCache.getServerCache().isCompleteForChild(childKey)\n ) {\n newChild = oldEventCache.getImmediateChild(childKey);\n }\n if (newChild != null) {\n newEventCache = this.filter_.updateChild(\n oldEventCache,\n childKey,\n newChild,\n path.popFront(),\n source,\n accumulator\n );\n } else if (\n viewCache\n .getEventCache()\n .getNode()\n .hasChild(childKey)\n ) {\n // No complete child available, delete the existing one, if any\n newEventCache = this.filter_.updateChild(\n oldEventCache,\n childKey,\n ChildrenNode.EMPTY_NODE,\n path.popFront(),\n source,\n accumulator\n );\n } else {\n newEventCache = oldEventCache;\n }\n if (\n newEventCache.isEmpty() &&\n viewCache.getServerCache().isFullyInitialized()\n ) {\n // We might have reverted all child writes. Maybe the old event was a leaf node\n complete = writesCache.calcCompleteEventCache(\n viewCache.getCompleteServerSnap()\n );\n if (complete.isLeafNode()) {\n newEventCache = this.filter_.updateFullNode(\n newEventCache,\n complete,\n accumulator\n );\n }\n }\n }\n complete =\n viewCache.getServerCache().isFullyInitialized() ||\n writesCache.shadowingWrite(Path.Empty) != null;\n return viewCache.updateEventSnap(\n newEventCache,\n complete,\n this.filter_.filtersNodes()\n );\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { NamedNode, Node } from '../snap/Node';\nimport { Change } from './Change';\nimport { assertionError } from '@firebase/util';\nimport { Query } from '../../api/Query';\nimport { Index } from '../snap/indexes/Index';\nimport { EventRegistration } from './EventRegistration';\nimport { Event } from './Event';\n\n/**\n * An EventGenerator is used to convert \"raw\" changes (Change) as computed by the\n * CacheDiffer into actual events (Event) that can be raised. See generateEventsForChanges()\n * for details.\n *\n * @constructor\n */\nexport class EventGenerator {\n private index_: Index;\n\n /**\n *\n * @param {!Query} query_\n */\n constructor(private query_: Query) {\n /**\n * @private\n * @type {!Index}\n */\n this.index_ = this.query_.getQueryParams().getIndex();\n }\n\n /**\n * Given a set of raw changes (no moved events and prevName not specified yet), and a set of\n * EventRegistrations that should be notified of these changes, generate the actual events to be raised.\n *\n * Notes:\n * - child_moved events will be synthesized at this time for any child_changed events that affect\n * our index.\n * - prevName will be calculated based on the index ordering.\n *\n * @param {!Array.} changes\n * @param {!Node} eventCache\n * @param {!Array.} eventRegistrations\n * @return {!Array.}\n */\n generateEventsForChanges(\n changes: Change[],\n eventCache: Node,\n eventRegistrations: EventRegistration[]\n ): Event[] {\n const events: Event[] = [];\n const moves: Change[] = [];\n\n changes.forEach(change => {\n if (\n change.type === Change.CHILD_CHANGED &&\n this.index_.indexedValueChanged(\n change.oldSnap as Node,\n change.snapshotNode\n )\n ) {\n moves.push(\n Change.childMovedChange(\n change.childName as string,\n change.snapshotNode\n )\n );\n }\n });\n\n this.generateEventsForType_(\n events,\n Change.CHILD_REMOVED,\n changes,\n eventRegistrations,\n eventCache\n );\n this.generateEventsForType_(\n events,\n Change.CHILD_ADDED,\n changes,\n eventRegistrations,\n eventCache\n );\n this.generateEventsForType_(\n events,\n Change.CHILD_MOVED,\n moves,\n eventRegistrations,\n eventCache\n );\n this.generateEventsForType_(\n events,\n Change.CHILD_CHANGED,\n changes,\n eventRegistrations,\n eventCache\n );\n this.generateEventsForType_(\n events,\n Change.VALUE,\n changes,\n eventRegistrations,\n eventCache\n );\n\n return events;\n }\n\n /**\n * Given changes of a single change type, generate the corresponding events.\n *\n * @param {!Array.} events\n * @param {!string} eventType\n * @param {!Array.} changes\n * @param {!Array.} registrations\n * @param {!Node} eventCache\n * @private\n */\n private generateEventsForType_(\n events: Event[],\n eventType: string,\n changes: Change[],\n registrations: EventRegistration[],\n eventCache: Node\n ) {\n const filteredChanges = changes.filter(change => change.type === eventType);\n\n filteredChanges.sort(this.compareChanges_.bind(this));\n filteredChanges.forEach(change => {\n const materializedChange = this.materializeSingleChange_(\n change,\n eventCache\n );\n registrations.forEach(registration => {\n if (registration.respondsTo(change.type)) {\n events.push(\n registration.createEvent(materializedChange, this.query_)\n );\n }\n });\n });\n }\n\n /**\n * @param {!Change} change\n * @param {!Node} eventCache\n * @return {!Change}\n * @private\n */\n private materializeSingleChange_(change: Change, eventCache: Node): Change {\n if (change.type === 'value' || change.type === 'child_removed') {\n return change;\n } else {\n change.prevName = eventCache.getPredecessorChildName(\n /** @type {!string} */\n change.childName,\n change.snapshotNode,\n this.index_\n );\n return change;\n }\n }\n\n /**\n * @param {!Change} a\n * @param {!Change} b\n * @return {number}\n * @private\n */\n private compareChanges_(a: Change, b: Change) {\n if (a.childName == null || b.childName == null) {\n throw assertionError('Should only compare child_ events.');\n }\n const aWrapped = new NamedNode(a.childName, a.snapshotNode);\n const bWrapped = new NamedNode(b.childName, b.snapshotNode);\n return this.index_.compare(aWrapped, bWrapped);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexedFilter } from './filter/IndexedFilter';\nimport { ViewProcessor } from './ViewProcessor';\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { CacheNode } from './CacheNode';\nimport { ViewCache } from './ViewCache';\nimport { EventGenerator } from './EventGenerator';\nimport { assert } from '@firebase/util';\nimport { Operation, OperationType } from '../operation/Operation';\nimport { Change } from './Change';\nimport { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';\nimport { Query } from '../../api/Query';\nimport { EventRegistration } from './EventRegistration';\nimport { Node } from '../snap/Node';\nimport { Path } from '../util/Path';\nimport { WriteTreeRef } from '../WriteTree';\nimport { CancelEvent, Event } from './Event';\n\n/**\n * A view represents a specific location and query that has 1 or more event registrations.\n *\n * It does several things:\n * - Maintains the list of event registrations for this location/query.\n * - Maintains a cache of the data visible for this location/query.\n * - Applies new operations (via applyOperation), updates the cache, and based on the event\n * registrations returns the set of events to be raised.\n * @constructor\n */\nexport class View {\n private processor_: ViewProcessor;\n private viewCache_: ViewCache;\n private eventRegistrations_: EventRegistration[] = [];\n private eventGenerator_: EventGenerator;\n\n /**\n *\n * @param {!Query} query_\n * @param {!ViewCache} initialViewCache\n */\n constructor(private query_: Query, initialViewCache: ViewCache) {\n const params = this.query_.getQueryParams();\n\n const indexFilter = new IndexedFilter(params.getIndex());\n const filter = params.getNodeFilter();\n\n /**\n * @type {ViewProcessor}\n * @private\n */\n this.processor_ = new ViewProcessor(filter);\n\n const initialServerCache = initialViewCache.getServerCache();\n const initialEventCache = initialViewCache.getEventCache();\n\n // Don't filter server node with other filter than index, wait for tagged listen\n const serverSnap = indexFilter.updateFullNode(\n ChildrenNode.EMPTY_NODE,\n initialServerCache.getNode(),\n null\n );\n const eventSnap = filter.updateFullNode(\n ChildrenNode.EMPTY_NODE,\n initialEventCache.getNode(),\n null\n );\n const newServerCache = new CacheNode(\n serverSnap,\n initialServerCache.isFullyInitialized(),\n indexFilter.filtersNodes()\n );\n const newEventCache = new CacheNode(\n eventSnap,\n initialEventCache.isFullyInitialized(),\n filter.filtersNodes()\n );\n\n /**\n * @type {!ViewCache}\n * @private\n */\n this.viewCache_ = new ViewCache(newEventCache, newServerCache);\n\n /**\n * @type {!EventGenerator}\n * @private\n */\n this.eventGenerator_ = new EventGenerator(this.query_);\n }\n\n /**\n * @return {!Query}\n */\n getQuery(): Query {\n return this.query_;\n }\n\n /**\n * @return {?Node}\n */\n getServerCache(): Node | null {\n return this.viewCache_.getServerCache().getNode();\n }\n\n /**\n * @param {!Path} path\n * @return {?Node}\n */\n getCompleteServerCache(path: Path): Node | null {\n const cache = this.viewCache_.getCompleteServerSnap();\n if (cache) {\n // If this isn't a \"loadsAllData\" view, then cache isn't actually a complete cache and\n // we need to see if it contains the child we're interested in.\n if (\n this.query_.getQueryParams().loadsAllData() ||\n (!path.isEmpty() && !cache.getImmediateChild(path.getFront()).isEmpty())\n ) {\n return cache.getChild(path);\n }\n }\n return null;\n }\n\n /**\n * @return {boolean}\n */\n isEmpty(): boolean {\n return this.eventRegistrations_.length === 0;\n }\n\n /**\n * @param {!EventRegistration} eventRegistration\n */\n addEventRegistration(eventRegistration: EventRegistration) {\n this.eventRegistrations_.push(eventRegistration);\n }\n\n /**\n * @param {?EventRegistration} eventRegistration If null, remove all callbacks.\n * @param {Error=} cancelError If a cancelError is provided, appropriate cancel events will be returned.\n * @return {!Array.} Cancel events, if cancelError was provided.\n */\n removeEventRegistration(\n eventRegistration: EventRegistration | null,\n cancelError?: Error\n ): Event[] {\n const cancelEvents: CancelEvent[] = [];\n if (cancelError) {\n assert(\n eventRegistration == null,\n 'A cancel should cancel all event registrations.'\n );\n const path = this.query_.path;\n this.eventRegistrations_.forEach(registration => {\n cancelError /** @type {!Error} */ = cancelError;\n const maybeEvent = registration.createCancelEvent(cancelError, path);\n if (maybeEvent) {\n cancelEvents.push(maybeEvent);\n }\n });\n }\n\n if (eventRegistration) {\n let remaining = [];\n for (let i = 0; i < this.eventRegistrations_.length; ++i) {\n const existing = this.eventRegistrations_[i];\n if (!existing.matches(eventRegistration)) {\n remaining.push(existing);\n } else if (eventRegistration.hasAnyCallback()) {\n // We're removing just this one\n remaining = remaining.concat(this.eventRegistrations_.slice(i + 1));\n break;\n }\n }\n this.eventRegistrations_ = remaining;\n } else {\n this.eventRegistrations_ = [];\n }\n return cancelEvents;\n }\n\n /**\n * Applies the given Operation, updates our cache, and returns the appropriate events.\n *\n * @param {!Operation} operation\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} completeServerCache\n * @return {!Array.}\n */\n applyOperation(\n operation: Operation,\n writesCache: WriteTreeRef,\n completeServerCache: Node | null\n ): Event[] {\n if (\n operation.type === OperationType.MERGE &&\n operation.source.queryId !== null\n ) {\n assert(\n this.viewCache_.getCompleteServerSnap(),\n 'We should always have a full cache before handling merges'\n );\n assert(\n this.viewCache_.getCompleteEventSnap(),\n 'Missing event cache, even though we have a server cache'\n );\n }\n\n const oldViewCache = this.viewCache_;\n const result = this.processor_.applyOperation(\n oldViewCache,\n operation,\n writesCache,\n completeServerCache\n );\n this.processor_.assertIndexed(result.viewCache);\n\n assert(\n result.viewCache.getServerCache().isFullyInitialized() ||\n !oldViewCache.getServerCache().isFullyInitialized(),\n 'Once a server snap is complete, it should never go back'\n );\n\n this.viewCache_ = result.viewCache;\n\n return this.generateEventsForChanges_(\n result.changes,\n result.viewCache.getEventCache().getNode(),\n null\n );\n }\n\n /**\n * @param {!EventRegistration} registration\n * @return {!Array.}\n */\n getInitialEvents(registration: EventRegistration): Event[] {\n const eventSnap = this.viewCache_.getEventCache();\n const initialChanges: Change[] = [];\n if (!eventSnap.getNode().isLeafNode()) {\n const eventNode = eventSnap.getNode() as ChildrenNode;\n eventNode.forEachChild(PRIORITY_INDEX, (key, childNode) => {\n initialChanges.push(Change.childAddedChange(key, childNode));\n });\n }\n if (eventSnap.isFullyInitialized()) {\n initialChanges.push(Change.valueChange(eventSnap.getNode()));\n }\n return this.generateEventsForChanges_(\n initialChanges,\n eventSnap.getNode(),\n registration\n );\n }\n\n /**\n * @private\n * @param {!Array.} changes\n * @param {!Node} eventCache\n * @param {EventRegistration=} eventRegistration\n * @return {!Array.}\n */\n generateEventsForChanges_(\n changes: Change[],\n eventCache: Node,\n eventRegistration?: EventRegistration\n ): Event[] {\n const registrations = eventRegistration\n ? [eventRegistration]\n : this.eventRegistrations_;\n return this.eventGenerator_.generateEventsForChanges(\n changes,\n eventCache,\n registrations\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { CacheNode } from './view/CacheNode';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { assert } from '@firebase/util';\nimport { ViewCache } from './view/ViewCache';\nimport { View } from './view/View';\nimport { Operation } from './operation/Operation';\nimport { WriteTreeRef } from './WriteTree';\nimport { Query } from '../api/Query';\nimport { EventRegistration } from './view/EventRegistration';\nimport { Node } from './snap/Node';\nimport { Path } from './util/Path';\nimport { Event } from './view/Event';\nimport { Reference, ReferenceConstructor } from '../api/Reference';\n\nlet __referenceConstructor: ReferenceConstructor;\n\n/**\n * SyncPoint represents a single location in a SyncTree with 1 or more event registrations, meaning we need to\n * maintain 1 or more Views at this location to cache server data and raise appropriate events for server changes\n * and user writes (set, transaction, update).\n *\n * It's responsible for:\n * - Maintaining the set of 1 or more views necessary at this location (a SyncPoint with 0 views should be removed).\n * - Proxying user / server operations to the views as appropriate (i.e. applyServerOverwrite,\n * applyUserOverwrite, etc.)\n */\nexport class SyncPoint {\n static set __referenceConstructor(val: ReferenceConstructor) {\n assert(\n !__referenceConstructor,\n '__referenceConstructor has already been defined'\n );\n __referenceConstructor = val;\n }\n\n static get __referenceConstructor() {\n assert(__referenceConstructor, 'Reference.ts has not been loaded');\n return __referenceConstructor;\n }\n\n /**\n * The Views being tracked at this location in the tree, stored as a map where the key is a\n * queryId and the value is the View for that query.\n *\n * NOTE: This list will be quite small (usually 1, but perhaps 2 or 3; any more is an odd use case).\n */\n private readonly views: Map = new Map();\n\n isEmpty(): boolean {\n return this.views.size === 0;\n }\n\n applyOperation(\n operation: Operation,\n writesCache: WriteTreeRef,\n optCompleteServerCache: Node | null\n ): Event[] {\n const queryId = operation.source.queryId;\n if (queryId !== null) {\n const view = this.views.get(queryId);\n assert(view != null, 'SyncTree gave us an op for an invalid query.');\n return view.applyOperation(\n operation,\n writesCache,\n optCompleteServerCache\n );\n } else {\n let events: Event[] = [];\n\n for (const view of this.views.values()) {\n events = events.concat(\n view.applyOperation(operation, writesCache, optCompleteServerCache)\n );\n }\n\n return events;\n }\n }\n\n /**\n * Add an event callback for the specified query.\n *\n * @param {!Query} query\n * @param {!EventRegistration} eventRegistration\n * @param {!WriteTreeRef} writesCache\n * @param {?Node} serverCache Complete server cache, if we have it.\n * @param {boolean} serverCacheComplete\n * @return {!Array.} Events to raise.\n */\n addEventRegistration(\n query: Query,\n eventRegistration: EventRegistration,\n writesCache: WriteTreeRef,\n serverCache: Node | null,\n serverCacheComplete: boolean\n ): Event[] {\n const queryId = query.queryIdentifier();\n let view = this.views.get(queryId);\n if (!view) {\n // TODO: make writesCache take flag for complete server node\n let eventCache = writesCache.calcCompleteEventCache(\n serverCacheComplete ? serverCache : null\n );\n let eventCacheComplete = false;\n if (eventCache) {\n eventCacheComplete = true;\n } else if (serverCache instanceof ChildrenNode) {\n eventCache = writesCache.calcCompleteEventChildren(serverCache);\n eventCacheComplete = false;\n } else {\n eventCache = ChildrenNode.EMPTY_NODE;\n eventCacheComplete = false;\n }\n const viewCache = new ViewCache(\n new CacheNode(\n /** @type {!Node} */ eventCache,\n eventCacheComplete,\n false\n ),\n new CacheNode(\n /** @type {!Node} */ serverCache,\n serverCacheComplete,\n false\n )\n );\n view = new View(query, viewCache);\n this.views.set(queryId, view);\n }\n\n // This is guaranteed to exist now, we just created anything that was missing\n view.addEventRegistration(eventRegistration);\n return view.getInitialEvents(eventRegistration);\n }\n\n /**\n * Remove event callback(s). Return cancelEvents if a cancelError is specified.\n *\n * If query is the default query, we'll check all views for the specified eventRegistration.\n * If eventRegistration is null, we'll remove all callbacks for the specified view(s).\n *\n * @param {!Query} query\n * @param {?EventRegistration} eventRegistration If null, remove all callbacks.\n * @param {Error=} cancelError If a cancelError is provided, appropriate cancel events will be returned.\n * @return {{removed:!Array., events:!Array.}} removed queries and any cancel events\n */\n removeEventRegistration(\n query: Query,\n eventRegistration: EventRegistration | null,\n cancelError?: Error\n ): { removed: Query[]; events: Event[] } {\n const queryId = query.queryIdentifier();\n const removed: Query[] = [];\n let cancelEvents: Event[] = [];\n const hadCompleteView = this.hasCompleteView();\n if (queryId === 'default') {\n // When you do ref.off(...), we search all views for the registration to remove.\n for (const [viewQueryId, view] of this.views.entries()) {\n cancelEvents = cancelEvents.concat(\n view.removeEventRegistration(eventRegistration, cancelError)\n );\n if (view.isEmpty()) {\n this.views.delete(viewQueryId);\n\n // We'll deal with complete views later.\n if (\n !view\n .getQuery()\n .getQueryParams()\n .loadsAllData()\n ) {\n removed.push(view.getQuery());\n }\n }\n }\n } else {\n // remove the callback from the specific view.\n const view = this.views.get(queryId);\n if (view) {\n cancelEvents = cancelEvents.concat(\n view.removeEventRegistration(eventRegistration, cancelError)\n );\n if (view.isEmpty()) {\n this.views.delete(queryId);\n\n // We'll deal with complete views later.\n if (\n !view\n .getQuery()\n .getQueryParams()\n .loadsAllData()\n ) {\n removed.push(view.getQuery());\n }\n }\n }\n }\n\n if (hadCompleteView && !this.hasCompleteView()) {\n // We removed our last complete view.\n removed.push(\n new SyncPoint.__referenceConstructor(query.repo, query.path)\n );\n }\n\n return { removed, events: cancelEvents };\n }\n\n getQueryViews(): View[] {\n const result = [];\n for (const view of this.views.values()) {\n if (\n !view\n .getQuery()\n .getQueryParams()\n .loadsAllData()\n ) {\n result.push(view);\n }\n }\n return result;\n }\n\n /**\n * @param path The path to the desired complete snapshot\n * @return A complete cache, if it exists\n */\n getCompleteServerCache(path: Path): Node | null {\n let serverCache: Node | null = null;\n for (const view of this.views.values()) {\n serverCache = serverCache || view.getCompleteServerCache(path);\n }\n return serverCache;\n }\n\n viewForQuery(query: Query): View | null {\n const params = query.getQueryParams();\n if (params.loadsAllData()) {\n return this.getCompleteView();\n } else {\n const queryId = query.queryIdentifier();\n return this.views.get(queryId);\n }\n }\n\n viewExistsForQuery(query: Query): boolean {\n return this.viewForQuery(query) != null;\n }\n\n hasCompleteView(): boolean {\n return this.getCompleteView() != null;\n }\n\n getCompleteView(): View | null {\n for (const view of this.views.values()) {\n if (\n view\n .getQuery()\n .getQueryParams()\n .loadsAllData()\n ) {\n return view;\n }\n }\n return null;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ImmutableTree } from './util/ImmutableTree';\nimport { Path } from './util/Path';\nimport { Node, NamedNode } from './snap/Node';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { assert } from '@firebase/util';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { each } from './util/util';\n\n/**\n * This class holds a collection of writes that can be applied to nodes in unison. It abstracts away the logic with\n * dealing with priority writes and multiple nested writes. At any given path there is only allowed to be one write\n * modifying that path. Any write to an existing path or shadowing an existing path will modify that existing write\n * to reflect the write added.\n */\nexport class CompoundWrite {\n constructor(private writeTree_: ImmutableTree) {}\n\n static Empty = new CompoundWrite(new ImmutableTree(null));\n\n addWrite(path: Path, node: Node): CompoundWrite {\n if (path.isEmpty()) {\n return new CompoundWrite(new ImmutableTree(node));\n } else {\n const rootmost = this.writeTree_.findRootMostValueAndPath(path);\n if (rootmost != null) {\n const rootMostPath = rootmost.path;\n let value = rootmost.value;\n const relativePath = Path.relativePath(rootMostPath, path);\n value = value.updateChild(relativePath, node);\n return new CompoundWrite(this.writeTree_.set(rootMostPath, value));\n } else {\n const subtree = new ImmutableTree(node);\n const newWriteTree = this.writeTree_.setTree(path, subtree);\n return new CompoundWrite(newWriteTree);\n }\n }\n }\n\n addWrites(path: Path, updates: { [name: string]: Node }): CompoundWrite {\n let newWrite = this as CompoundWrite;\n each(updates, (childKey: string, node: Node) => {\n newWrite = newWrite.addWrite(path.child(childKey), node);\n });\n return newWrite;\n }\n\n /**\n * Will remove a write at the given path and deeper paths. This will not modify a write at a higher\n * location, which must be removed by calling this method with that path.\n *\n * @param path The path at which a write and all deeper writes should be removed\n * @return {!CompoundWrite} The new CompoundWrite with the removed path\n */\n removeWrite(path: Path): CompoundWrite {\n if (path.isEmpty()) {\n return CompoundWrite.Empty;\n } else {\n const newWriteTree = this.writeTree_.setTree(path, ImmutableTree.Empty);\n return new CompoundWrite(newWriteTree);\n }\n }\n\n /**\n * Returns whether this CompoundWrite will fully overwrite a node at a given location and can therefore be\n * considered \"complete\".\n *\n * @param path The path to check for\n * @return Whether there is a complete write at that path\n */\n hasCompleteWrite(path: Path): boolean {\n return this.getCompleteNode(path) != null;\n }\n\n /**\n * Returns a node for a path if and only if the node is a \"complete\" overwrite at that path. This will not aggregate\n * writes from deeper paths, but will return child nodes from a more shallow path.\n *\n * @param path The path to get a complete write\n * @return The node if complete at that path, or null otherwise.\n */\n getCompleteNode(path: Path): Node | null {\n const rootmost = this.writeTree_.findRootMostValueAndPath(path);\n if (rootmost != null) {\n return this.writeTree_\n .get(rootmost.path)\n .getChild(Path.relativePath(rootmost.path, path));\n } else {\n return null;\n }\n }\n\n /**\n * Returns all children that are guaranteed to be a complete overwrite.\n *\n * @return A list of all complete children.\n */\n getCompleteChildren(): NamedNode[] {\n const children: NamedNode[] = [];\n const node = this.writeTree_.value;\n if (node != null) {\n // If it's a leaf node, it has no children; so nothing to do.\n if (!node.isLeafNode()) {\n (node as ChildrenNode).forEachChild(\n PRIORITY_INDEX,\n (childName, childNode) => {\n children.push(new NamedNode(childName, childNode));\n }\n );\n }\n } else {\n this.writeTree_.children.inorderTraversal((childName, childTree) => {\n if (childTree.value != null) {\n children.push(new NamedNode(childName, childTree.value));\n }\n });\n }\n return children;\n }\n\n childCompoundWrite(path: Path): CompoundWrite {\n if (path.isEmpty()) {\n return this;\n } else {\n const shadowingNode = this.getCompleteNode(path);\n if (shadowingNode != null) {\n return new CompoundWrite(new ImmutableTree(shadowingNode));\n } else {\n return new CompoundWrite(this.writeTree_.subtree(path));\n }\n }\n }\n\n /**\n * Returns true if this CompoundWrite is empty and therefore does not modify any nodes.\n * @return Whether this CompoundWrite is empty\n */\n isEmpty(): boolean {\n return this.writeTree_.isEmpty();\n }\n\n /**\n * Applies this CompoundWrite to a node. The node is returned with all writes from this CompoundWrite applied to the\n * node\n * @param node The node to apply this CompoundWrite to\n * @return The node with all writes applied\n */\n apply(node: Node): Node {\n return applySubtreeWrite(Path.Empty, this.writeTree_, node);\n }\n}\n\nfunction applySubtreeWrite(\n relativePath: Path,\n writeTree: ImmutableTree,\n node: Node\n): Node {\n if (writeTree.value != null) {\n // Since there a write is always a leaf, we're done here\n return node.updateChild(relativePath, writeTree.value);\n } else {\n let priorityWrite = null;\n writeTree.children.inorderTraversal((childKey, childTree) => {\n if (childKey === '.priority') {\n // Apply priorities at the end so we don't update priorities for either empty nodes or forget\n // to apply priorities to empty nodes that are later filled\n assert(\n childTree.value !== null,\n 'Priority writes must always be leaf nodes'\n );\n priorityWrite = childTree.value;\n } else {\n node = applySubtreeWrite(relativePath.child(childKey), childTree, node);\n }\n });\n // If there was a priority write, we only apply it if the node is not empty\n if (!node.getChild(relativePath).isEmpty() && priorityWrite !== null) {\n node = node.updateChild(relativePath.child('.priority'), priorityWrite);\n }\n return node;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { safeGet, assert, assertionError } from '@firebase/util';\n\nimport { Path } from './util/Path';\nimport { CompoundWrite } from './CompoundWrite';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { NamedNode, Node } from './snap/Node';\nimport { CacheNode } from './view/CacheNode';\nimport { Index } from './snap/indexes/Index';\nimport { each } from './util/util';\n\n/**\n * Defines a single user-initiated write operation. May be the result of a set(), transaction(), or update() call. In\n * the case of a set() or transaction, snap wil be non-null. In the case of an update(), children will be non-null.\n */\nexport interface WriteRecord {\n writeId: number;\n path: Path;\n snap?: Node | null;\n children?: { [k: string]: Node } | null;\n visible: boolean;\n}\n\n/**\n * WriteTree tracks all pending user-initiated writes and has methods to calculate the result of merging them\n * with underlying server data (to create \"event cache\" data). Pending writes are added with addOverwrite()\n * and addMerge(), and removed with removeWrite().\n *\n * @constructor\n */\nexport class WriteTree {\n /**\n * A tree tracking the result of applying all visible writes. This does not include transactions with\n * applyLocally=false or writes that are completely shadowed by other writes.\n *\n * @type {!CompoundWrite}\n * @private\n */\n private visibleWrites_: CompoundWrite = CompoundWrite.Empty;\n\n /**\n * A list of all pending writes, regardless of visibility and shadowed-ness. Used to calculate arbitrary\n * sets of the changed data, such as hidden writes (from transactions) or changes with certain writes excluded (also\n * used by transactions).\n *\n * @type {!Array.}\n * @private\n */\n private allWrites_: WriteRecord[] = [];\n\n private lastWriteId_ = -1;\n\n /**\n * Create a new WriteTreeRef for the given path. For use with a new sync point at the given path.\n *\n * @param {!Path} path\n * @return {!WriteTreeRef}\n */\n childWrites(path: Path): WriteTreeRef {\n return new WriteTreeRef(path, this);\n }\n\n /**\n * Record a new overwrite from user code.\n *\n * @param {!Path} path\n * @param {!Node} snap\n * @param {!number} writeId\n * @param {boolean=} visible This is set to false by some transactions. It should be excluded from event caches\n */\n addOverwrite(path: Path, snap: Node, writeId: number, visible?: boolean) {\n assert(\n writeId > this.lastWriteId_,\n 'Stacking an older write on top of newer ones'\n );\n if (visible === undefined) {\n visible = true;\n }\n this.allWrites_.push({\n path,\n snap,\n writeId,\n visible\n });\n\n if (visible) {\n this.visibleWrites_ = this.visibleWrites_.addWrite(path, snap);\n }\n this.lastWriteId_ = writeId;\n }\n\n /**\n * Record a new merge from user code.\n *\n * @param {!Path} path\n * @param {!Object.} changedChildren\n * @param {!number} writeId\n */\n addMerge(\n path: Path,\n changedChildren: { [k: string]: Node },\n writeId: number\n ) {\n assert(\n writeId > this.lastWriteId_,\n 'Stacking an older merge on top of newer ones'\n );\n this.allWrites_.push({\n path,\n children: changedChildren,\n writeId,\n visible: true\n });\n\n this.visibleWrites_ = this.visibleWrites_.addWrites(path, changedChildren);\n this.lastWriteId_ = writeId;\n }\n\n /**\n * @param {!number} writeId\n * @return {?WriteRecord}\n */\n getWrite(writeId: number): WriteRecord | null {\n for (let i = 0; i < this.allWrites_.length; i++) {\n const record = this.allWrites_[i];\n if (record.writeId === writeId) {\n return record;\n }\n }\n return null;\n }\n\n /**\n * Remove a write (either an overwrite or merge) that has been successfully acknowledge by the server. Recalculates\n * the tree if necessary. We return true if it may have been visible, meaning views need to reevaluate.\n *\n * @param {!number} writeId\n * @return {boolean} true if the write may have been visible (meaning we'll need to reevaluate / raise\n * events as a result).\n */\n removeWrite(writeId: number): boolean {\n // Note: disabling this check. It could be a transaction that preempted another transaction, and thus was applied\n // out of order.\n //const validClear = revert || this.allWrites_.length === 0 || writeId <= this.allWrites_[0].writeId;\n //assert(validClear, \"Either we don't have this write, or it's the first one in the queue\");\n\n const idx = this.allWrites_.findIndex(s => {\n return s.writeId === writeId;\n });\n assert(idx >= 0, 'removeWrite called with nonexistent writeId.');\n const writeToRemove = this.allWrites_[idx];\n this.allWrites_.splice(idx, 1);\n\n let removedWriteWasVisible = writeToRemove.visible;\n let removedWriteOverlapsWithOtherWrites = false;\n\n let i = this.allWrites_.length - 1;\n\n while (removedWriteWasVisible && i >= 0) {\n const currentWrite = this.allWrites_[i];\n if (currentWrite.visible) {\n if (\n i >= idx &&\n this.recordContainsPath_(currentWrite, writeToRemove.path)\n ) {\n // The removed write was completely shadowed by a subsequent write.\n removedWriteWasVisible = false;\n } else if (writeToRemove.path.contains(currentWrite.path)) {\n // Either we're covering some writes or they're covering part of us (depending on which came first).\n removedWriteOverlapsWithOtherWrites = true;\n }\n }\n i--;\n }\n\n if (!removedWriteWasVisible) {\n return false;\n } else if (removedWriteOverlapsWithOtherWrites) {\n // There's some shadowing going on. Just rebuild the visible writes from scratch.\n this.resetTree_();\n return true;\n } else {\n // There's no shadowing. We can safely just remove the write(s) from visibleWrites.\n if (writeToRemove.snap) {\n this.visibleWrites_ = this.visibleWrites_.removeWrite(\n writeToRemove.path\n );\n } else {\n const children = writeToRemove.children;\n each(children, (childName: string) => {\n this.visibleWrites_ = this.visibleWrites_.removeWrite(\n writeToRemove.path.child(childName)\n );\n });\n }\n return true;\n }\n }\n\n /**\n * Return a complete snapshot for the given path if there's visible write data at that path, else null.\n * No server data is considered.\n *\n * @param {!Path} path\n * @return {?Node}\n */\n getCompleteWriteData(path: Path): Node | null {\n return this.visibleWrites_.getCompleteNode(path);\n }\n\n /**\n * Given optional, underlying server data, and an optional set of constraints (exclude some sets, include hidden\n * writes), attempt to calculate a complete snapshot for the given path\n *\n * @param {!Path} treePath\n * @param {?Node} completeServerCache\n * @param {Array.=} writeIdsToExclude An optional set to be excluded\n * @param {boolean=} includeHiddenWrites Defaults to false, whether or not to layer on writes with visible set to false\n * @return {?Node}\n */\n calcCompleteEventCache(\n treePath: Path,\n completeServerCache: Node | null,\n writeIdsToExclude?: number[],\n includeHiddenWrites?: boolean\n ): Node | null {\n if (!writeIdsToExclude && !includeHiddenWrites) {\n const shadowingNode = this.visibleWrites_.getCompleteNode(treePath);\n if (shadowingNode != null) {\n return shadowingNode;\n } else {\n const subMerge = this.visibleWrites_.childCompoundWrite(treePath);\n if (subMerge.isEmpty()) {\n return completeServerCache;\n } else if (\n completeServerCache == null &&\n !subMerge.hasCompleteWrite(Path.Empty)\n ) {\n // We wouldn't have a complete snapshot, since there's no underlying data and no complete shadow\n return null;\n } else {\n const layeredCache = completeServerCache || ChildrenNode.EMPTY_NODE;\n return subMerge.apply(layeredCache);\n }\n }\n } else {\n const merge = this.visibleWrites_.childCompoundWrite(treePath);\n if (!includeHiddenWrites && merge.isEmpty()) {\n return completeServerCache;\n } else {\n // If the server cache is null, and we don't have a complete cache, we need to return null\n if (\n !includeHiddenWrites &&\n completeServerCache == null &&\n !merge.hasCompleteWrite(Path.Empty)\n ) {\n return null;\n } else {\n const filter = function(write: WriteRecord) {\n return (\n (write.visible || includeHiddenWrites) &&\n (!writeIdsToExclude ||\n !~writeIdsToExclude.indexOf(write.writeId)) &&\n (write.path.contains(treePath) || treePath.contains(write.path))\n );\n };\n const mergeAtPath = WriteTree.layerTree_(\n this.allWrites_,\n filter,\n treePath\n );\n const layeredCache = completeServerCache || ChildrenNode.EMPTY_NODE;\n return mergeAtPath.apply(layeredCache);\n }\n }\n }\n }\n\n /**\n * With optional, underlying server data, attempt to return a children node of children that we have complete data for.\n * Used when creating new views, to pre-fill their complete event children snapshot.\n *\n * @param {!Path} treePath\n * @param {?ChildrenNode} completeServerChildren\n * @return {!ChildrenNode}\n */\n calcCompleteEventChildren(\n treePath: Path,\n completeServerChildren: ChildrenNode | null\n ) {\n let completeChildren = ChildrenNode.EMPTY_NODE as Node;\n const topLevelSet = this.visibleWrites_.getCompleteNode(treePath);\n if (topLevelSet) {\n if (!topLevelSet.isLeafNode()) {\n // we're shadowing everything. Return the children.\n topLevelSet.forEachChild(PRIORITY_INDEX, (childName, childSnap) => {\n completeChildren = completeChildren.updateImmediateChild(\n childName,\n childSnap\n );\n });\n }\n return completeChildren;\n } else if (completeServerChildren) {\n // Layer any children we have on top of this\n // We know we don't have a top-level set, so just enumerate existing children\n const merge = this.visibleWrites_.childCompoundWrite(treePath);\n completeServerChildren.forEachChild(\n PRIORITY_INDEX,\n (childName, childNode) => {\n const node = merge\n .childCompoundWrite(new Path(childName))\n .apply(childNode);\n completeChildren = completeChildren.updateImmediateChild(\n childName,\n node\n );\n }\n );\n // Add any complete children we have from the set\n merge.getCompleteChildren().forEach(namedNode => {\n completeChildren = completeChildren.updateImmediateChild(\n namedNode.name,\n namedNode.node\n );\n });\n return completeChildren;\n } else {\n // We don't have anything to layer on top of. Layer on any children we have\n // Note that we can return an empty snap if we have a defined delete\n const merge = this.visibleWrites_.childCompoundWrite(treePath);\n merge.getCompleteChildren().forEach(namedNode => {\n completeChildren = completeChildren.updateImmediateChild(\n namedNode.name,\n namedNode.node\n );\n });\n return completeChildren;\n }\n }\n\n /**\n * Given that the underlying server data has updated, determine what, if anything, needs to be\n * applied to the event cache.\n *\n * Possibilities:\n *\n * 1. No writes are shadowing. Events should be raised, the snap to be applied comes from the server data\n *\n * 2. Some write is completely shadowing. No events to be raised\n *\n * 3. Is partially shadowed. Events\n *\n * Either existingEventSnap or existingServerSnap must exist\n *\n * @param {!Path} treePath\n * @param {!Path} childPath\n * @param {?Node} existingEventSnap\n * @param {?Node} existingServerSnap\n * @return {?Node}\n */\n calcEventCacheAfterServerOverwrite(\n treePath: Path,\n childPath: Path,\n existingEventSnap: Node | null,\n existingServerSnap: Node | null\n ): Node | null {\n assert(\n existingEventSnap || existingServerSnap,\n 'Either existingEventSnap or existingServerSnap must exist'\n );\n const path = treePath.child(childPath);\n if (this.visibleWrites_.hasCompleteWrite(path)) {\n // At this point we can probably guarantee that we're in case 2, meaning no events\n // May need to check visibility while doing the findRootMostValueAndPath call\n return null;\n } else {\n // No complete shadowing. We're either partially shadowing or not shadowing at all.\n const childMerge = this.visibleWrites_.childCompoundWrite(path);\n if (childMerge.isEmpty()) {\n // We're not shadowing at all. Case 1\n return existingServerSnap.getChild(childPath);\n } else {\n // This could be more efficient if the serverNode + updates doesn't change the eventSnap\n // However this is tricky to find out, since user updates don't necessary change the server\n // snap, e.g. priority updates on empty nodes, or deep deletes. Another special case is if the server\n // adds nodes, but doesn't change any existing writes. It is therefore not enough to\n // only check if the updates change the serverNode.\n // Maybe check if the merge tree contains these special cases and only do a full overwrite in that case?\n return childMerge.apply(existingServerSnap.getChild(childPath));\n }\n }\n }\n\n /**\n * Returns a complete child for a given server snap after applying all user writes or null if there is no\n * complete child for this ChildKey.\n *\n * @param {!Path} treePath\n * @param {!string} childKey\n * @param {!CacheNode} existingServerSnap\n * @return {?Node}\n */\n calcCompleteChild(\n treePath: Path,\n childKey: string,\n existingServerSnap: CacheNode\n ): Node | null {\n const path = treePath.child(childKey);\n const shadowingNode = this.visibleWrites_.getCompleteNode(path);\n if (shadowingNode != null) {\n return shadowingNode;\n } else {\n if (existingServerSnap.isCompleteForChild(childKey)) {\n const childMerge = this.visibleWrites_.childCompoundWrite(path);\n return childMerge.apply(\n existingServerSnap.getNode().getImmediateChild(childKey)\n );\n } else {\n return null;\n }\n }\n }\n\n /**\n * Returns a node if there is a complete overwrite for this path. More specifically, if there is a write at\n * a higher path, this will return the child of that write relative to the write and this path.\n * Returns null if there is no write at this path.\n */\n shadowingWrite(path: Path): Node | null {\n return this.visibleWrites_.getCompleteNode(path);\n }\n\n /**\n * This method is used when processing child remove events on a query. If we can, we pull in children that were outside\n * the window, but may now be in the window.\n */\n calcIndexedSlice(\n treePath: Path,\n completeServerData: Node | null,\n startPost: NamedNode,\n count: number,\n reverse: boolean,\n index: Index\n ): NamedNode[] {\n let toIterate: Node;\n const merge = this.visibleWrites_.childCompoundWrite(treePath);\n const shadowingNode = merge.getCompleteNode(Path.Empty);\n if (shadowingNode != null) {\n toIterate = shadowingNode;\n } else if (completeServerData != null) {\n toIterate = merge.apply(completeServerData);\n } else {\n // no children to iterate on\n return [];\n }\n toIterate = toIterate.withIndex(index);\n if (!toIterate.isEmpty() && !toIterate.isLeafNode()) {\n const nodes = [];\n const cmp = index.getCompare();\n const iter = reverse\n ? (toIterate as ChildrenNode).getReverseIteratorFrom(startPost, index)\n : (toIterate as ChildrenNode).getIteratorFrom(startPost, index);\n let next = iter.getNext();\n while (next && nodes.length < count) {\n if (cmp(next, startPost) !== 0) {\n nodes.push(next);\n }\n next = iter.getNext();\n }\n return nodes;\n } else {\n return [];\n }\n }\n\n private recordContainsPath_(writeRecord: WriteRecord, path: Path): boolean {\n if (writeRecord.snap) {\n return writeRecord.path.contains(path);\n } else {\n for (const childName in writeRecord.children) {\n if (\n writeRecord.children.hasOwnProperty(childName) &&\n writeRecord.path.child(childName).contains(path)\n ) {\n return true;\n }\n }\n return false;\n }\n }\n\n /**\n * Re-layer the writes and merges into a tree so we can efficiently calculate event snapshots\n */\n private resetTree_() {\n this.visibleWrites_ = WriteTree.layerTree_(\n this.allWrites_,\n WriteTree.DefaultFilter_,\n Path.Empty\n );\n if (this.allWrites_.length > 0) {\n this.lastWriteId_ = this.allWrites_[this.allWrites_.length - 1].writeId;\n } else {\n this.lastWriteId_ = -1;\n }\n }\n\n /**\n * The default filter used when constructing the tree. Keep everything that's visible.\n */\n private static DefaultFilter_(write: WriteRecord) {\n return write.visible;\n }\n\n /**\n * Static method. Given an array of WriteRecords, a filter for which ones to include, and a path, construct the tree of\n * event data at that path.\n */\n private static layerTree_(\n writes: WriteRecord[],\n filter: (w: WriteRecord) => boolean,\n treeRoot: Path\n ): CompoundWrite {\n let compoundWrite = CompoundWrite.Empty;\n for (let i = 0; i < writes.length; ++i) {\n const write = writes[i];\n // Theory, a later set will either:\n // a) abort a relevant transaction, so no need to worry about excluding it from calculating that transaction\n // b) not be relevant to a transaction (separate branch), so again will not affect the data for that transaction\n if (filter(write)) {\n const writePath = write.path;\n let relativePath;\n if (write.snap) {\n if (treeRoot.contains(writePath)) {\n relativePath = Path.relativePath(treeRoot, writePath);\n compoundWrite = compoundWrite.addWrite(relativePath, write.snap);\n } else if (writePath.contains(treeRoot)) {\n relativePath = Path.relativePath(writePath, treeRoot);\n compoundWrite = compoundWrite.addWrite(\n Path.Empty,\n write.snap.getChild(relativePath)\n );\n } else {\n // There is no overlap between root path and write path, ignore write\n }\n } else if (write.children) {\n if (treeRoot.contains(writePath)) {\n relativePath = Path.relativePath(treeRoot, writePath);\n compoundWrite = compoundWrite.addWrites(\n relativePath,\n write.children\n );\n } else if (writePath.contains(treeRoot)) {\n relativePath = Path.relativePath(writePath, treeRoot);\n if (relativePath.isEmpty()) {\n compoundWrite = compoundWrite.addWrites(\n Path.Empty,\n write.children\n );\n } else {\n const child = safeGet(write.children, relativePath.getFront());\n if (child) {\n // There exists a child in this node that matches the root path\n const deepNode = child.getChild(relativePath.popFront());\n compoundWrite = compoundWrite.addWrite(Path.Empty, deepNode);\n }\n }\n } else {\n // There is no overlap between root path and write path, ignore write\n }\n } else {\n throw assertionError('WriteRecord should have .snap or .children');\n }\n }\n }\n return compoundWrite;\n }\n}\n\n/**\n * A WriteTreeRef wraps a WriteTree and a path, for convenient access to a particular subtree. All of the methods\n * just proxy to the underlying WriteTree.\n *\n * @constructor\n */\nexport class WriteTreeRef {\n /**\n * The path to this particular write tree ref. Used for calling methods on writeTree_ while exposing a simpler\n * interface to callers.\n *\n * @type {!Path}\n * @private\n * @const\n */\n private readonly treePath_: Path;\n\n /**\n * * A reference to the actual tree of write data. All methods are pass-through to the tree, but with the appropriate\n * path prefixed.\n *\n * This lets us make cheap references to points in the tree for sync points without having to copy and maintain all of\n * the data.\n *\n * @type {!WriteTree}\n * @private\n * @const\n */\n private readonly writeTree_: WriteTree;\n\n /**\n * @param {!Path} path\n * @param {!WriteTree} writeTree\n */\n constructor(path: Path, writeTree: WriteTree) {\n this.treePath_ = path;\n this.writeTree_ = writeTree;\n }\n\n /**\n * If possible, returns a complete event cache, using the underlying server data if possible. In addition, can be used\n * to get a cache that includes hidden writes, and excludes arbitrary writes. Note that customizing the returned node\n * can lead to a more expensive calculation.\n *\n * @param {?Node} completeServerCache\n * @param {Array.=} writeIdsToExclude Optional writes to exclude.\n * @param {boolean=} includeHiddenWrites Defaults to false, whether or not to layer on writes with visible set to false\n * @return {?Node}\n */\n calcCompleteEventCache(\n completeServerCache: Node | null,\n writeIdsToExclude?: number[],\n includeHiddenWrites?: boolean\n ): Node | null {\n return this.writeTree_.calcCompleteEventCache(\n this.treePath_,\n completeServerCache,\n writeIdsToExclude,\n includeHiddenWrites\n );\n }\n\n /**\n * If possible, returns a children node containing all of the complete children we have data for. The returned data is a\n * mix of the given server data and write data.\n *\n * @param {?ChildrenNode} completeServerChildren\n * @return {!ChildrenNode}\n */\n calcCompleteEventChildren(\n completeServerChildren: ChildrenNode | null\n ): ChildrenNode {\n return this.writeTree_.calcCompleteEventChildren(\n this.treePath_,\n completeServerChildren\n ) as ChildrenNode;\n }\n\n /**\n * Given that either the underlying server data has updated or the outstanding writes have updated, determine what,\n * if anything, needs to be applied to the event cache.\n *\n * Possibilities:\n *\n * 1. No writes are shadowing. Events should be raised, the snap to be applied comes from the server data\n *\n * 2. Some write is completely shadowing. No events to be raised\n *\n * 3. Is partially shadowed. Events should be raised\n *\n * Either existingEventSnap or existingServerSnap must exist, this is validated via an assert\n *\n * @param {!Path} path\n * @param {?Node} existingEventSnap\n * @param {?Node} existingServerSnap\n * @return {?Node}\n */\n calcEventCacheAfterServerOverwrite(\n path: Path,\n existingEventSnap: Node | null,\n existingServerSnap: Node | null\n ): Node | null {\n return this.writeTree_.calcEventCacheAfterServerOverwrite(\n this.treePath_,\n path,\n existingEventSnap,\n existingServerSnap\n );\n }\n\n /**\n * Returns a node if there is a complete overwrite for this path. More specifically, if there is a write at\n * a higher path, this will return the child of that write relative to the write and this path.\n * Returns null if there is no write at this path.\n *\n * @param {!Path} path\n * @return {?Node}\n */\n shadowingWrite(path: Path): Node | null {\n return this.writeTree_.shadowingWrite(this.treePath_.child(path));\n }\n\n /**\n * This method is used when processing child remove events on a query. If we can, we pull in children that were outside\n * the window, but may now be in the window\n *\n * @param {?Node} completeServerData\n * @param {!NamedNode} startPost\n * @param {!number} count\n * @param {boolean} reverse\n * @param {!Index} index\n * @return {!Array.}\n */\n calcIndexedSlice(\n completeServerData: Node | null,\n startPost: NamedNode,\n count: number,\n reverse: boolean,\n index: Index\n ): NamedNode[] {\n return this.writeTree_.calcIndexedSlice(\n this.treePath_,\n completeServerData,\n startPost,\n count,\n reverse,\n index\n );\n }\n\n /**\n * Returns a complete child for a given server snap after applying all user writes or null if there is no\n * complete child for this ChildKey.\n *\n * @param {!string} childKey\n * @param {!CacheNode} existingServerCache\n * @return {?Node}\n */\n calcCompleteChild(\n childKey: string,\n existingServerCache: CacheNode\n ): Node | null {\n return this.writeTree_.calcCompleteChild(\n this.treePath_,\n childKey,\n existingServerCache\n );\n }\n\n /**\n * Return a WriteTreeRef for a child.\n *\n * @param {string} childName\n * @return {!WriteTreeRef}\n */\n child(childName: string): WriteTreeRef {\n return new WriteTreeRef(this.treePath_.child(childName), this.writeTree_);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\nimport { errorForServerCode, each } from './util/util';\nimport { AckUserWrite } from './operation/AckUserWrite';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { ImmutableTree } from './util/ImmutableTree';\nimport { ListenComplete } from './operation/ListenComplete';\nimport { Merge } from './operation/Merge';\nimport { Operation, OperationSource } from './operation/Operation';\nimport { Overwrite } from './operation/Overwrite';\nimport { Path } from './util/Path';\nimport { SyncPoint } from './SyncPoint';\nimport { WriteTree, WriteTreeRef } from './WriteTree';\nimport { Query } from '../api/Query';\nimport { Node } from './snap/Node';\nimport { Event } from './view/Event';\nimport { EventRegistration } from './view/EventRegistration';\nimport { View } from './view/View';\n\n/**\n * @typedef {{\n * startListening: function(\n * !Query,\n * ?number,\n * function():string,\n * function(!string, *):!Array.\n * ):!Array.,\n *\n * stopListening: function(!Query, ?number)\n * }}\n */\nexport interface ListenProvider {\n startListening(\n query: Query,\n tag: number | null,\n hashFn: () => string,\n onComplete: (a: string, b?: unknown) => Event[]\n ): Event[];\n\n stopListening(a: Query, b: number | null): void;\n}\n\n/**\n * SyncTree is the central class for managing event callback registration, data caching, views\n * (query processing), and event generation. There are typically two SyncTree instances for\n * each Repo, one for the normal Firebase data, and one for the .info data.\n *\n * It has a number of responsibilities, including:\n * - Tracking all user event callbacks (registered via addEventRegistration() and removeEventRegistration()).\n * - Applying and caching data changes for user set(), transaction(), and update() calls\n * (applyUserOverwrite(), applyUserMerge()).\n * - Applying and caching data changes for server data changes (applyServerOverwrite(),\n * applyServerMerge()).\n * - Generating user-facing events for server and user changes (all of the apply* methods\n * return the set of events that need to be raised as a result).\n * - Maintaining the appropriate set of server listens to ensure we are always subscribed\n * to the correct set of paths and queries to satisfy the current set of user event\n * callbacks (listens are started/stopped using the provided listenProvider).\n *\n * NOTE: Although SyncTree tracks event callbacks and calculates events to raise, the actual\n * events are returned to the caller rather than raised synchronously.\n *\n * @constructor\n */\nexport class SyncTree {\n /**\n * Tree of SyncPoints. There's a SyncPoint at any location that has 1 or more views.\n */\n private syncPointTree_: ImmutableTree = ImmutableTree.Empty;\n\n /**\n * A tree of all pending user writes (user-initiated set()'s, transaction()'s, update()'s, etc.).\n */\n private pendingWriteTree_ = new WriteTree();\n\n private readonly tagToQueryMap: Map = new Map();\n private readonly queryToTagMap: Map = new Map();\n\n /**\n * @param {!ListenProvider} listenProvider_ Used by SyncTree to start / stop listening\n * to server data.\n */\n constructor(private listenProvider_: ListenProvider) {}\n\n /**\n * Apply the data changes for a user-generated set() or transaction() call.\n *\n * @return Events to raise.\n */\n applyUserOverwrite(\n path: Path,\n newData: Node,\n writeId: number,\n visible?: boolean\n ): Event[] {\n // Record pending write.\n this.pendingWriteTree_.addOverwrite(path, newData, writeId, visible);\n\n if (!visible) {\n return [];\n } else {\n return this.applyOperationToSyncPoints_(\n new Overwrite(OperationSource.User, path, newData)\n );\n }\n }\n\n /**\n * Apply the data from a user-generated update() call\n *\n * @return Events to raise.\n */\n applyUserMerge(\n path: Path,\n changedChildren: { [k: string]: Node },\n writeId: number\n ): Event[] {\n // Record pending merge.\n this.pendingWriteTree_.addMerge(path, changedChildren, writeId);\n\n const changeTree = ImmutableTree.fromObject(changedChildren);\n\n return this.applyOperationToSyncPoints_(\n new Merge(OperationSource.User, path, changeTree)\n );\n }\n\n /**\n * Acknowledge a pending user write that was previously registered with applyUserOverwrite() or applyUserMerge().\n *\n * @param revert True if the given write failed and needs to be reverted\n * @return Events to raise.\n */\n ackUserWrite(writeId: number, revert: boolean = false) {\n const write = this.pendingWriteTree_.getWrite(writeId);\n const needToReevaluate = this.pendingWriteTree_.removeWrite(writeId);\n if (!needToReevaluate) {\n return [];\n } else {\n let affectedTree = ImmutableTree.Empty;\n if (write.snap != null) {\n // overwrite\n affectedTree = affectedTree.set(Path.Empty, true);\n } else {\n each(write.children, (pathString: string, node: Node) => {\n affectedTree = affectedTree.set(new Path(pathString), node);\n });\n }\n return this.applyOperationToSyncPoints_(\n new AckUserWrite(write.path, affectedTree, revert)\n );\n }\n }\n\n /**\n * Apply new server data for the specified path..\n *\n * @return Events to raise.\n */\n applyServerOverwrite(path: Path, newData: Node): Event[] {\n return this.applyOperationToSyncPoints_(\n new Overwrite(OperationSource.Server, path, newData)\n );\n }\n\n /**\n * Apply new server data to be merged in at the specified path.\n *\n * @return Events to raise.\n */\n applyServerMerge(\n path: Path,\n changedChildren: { [k: string]: Node }\n ): Event[] {\n const changeTree = ImmutableTree.fromObject(changedChildren);\n\n return this.applyOperationToSyncPoints_(\n new Merge(OperationSource.Server, path, changeTree)\n );\n }\n\n /**\n * Apply a listen complete for a query\n *\n * @return Events to raise.\n */\n applyListenComplete(path: Path): Event[] {\n return this.applyOperationToSyncPoints_(\n new ListenComplete(OperationSource.Server, path)\n );\n }\n\n /**\n * Apply new server data for the specified tagged query.\n *\n * @return Events to raise.\n */\n applyTaggedQueryOverwrite(path: Path, snap: Node, tag: number): Event[] {\n const queryKey = this.queryKeyForTag_(tag);\n if (queryKey != null) {\n const r = SyncTree.parseQueryKey_(queryKey);\n const queryPath = r.path,\n queryId = r.queryId;\n const relativePath = Path.relativePath(queryPath, path);\n const op = new Overwrite(\n OperationSource.forServerTaggedQuery(queryId),\n relativePath,\n snap\n );\n return this.applyTaggedOperation_(queryPath, op);\n } else {\n // Query must have been removed already\n return [];\n }\n }\n\n /**\n * Apply server data to be merged in for the specified tagged query.\n *\n * @return Events to raise.\n */\n applyTaggedQueryMerge(\n path: Path,\n changedChildren: { [k: string]: Node },\n tag: number\n ): Event[] {\n const queryKey = this.queryKeyForTag_(tag);\n if (queryKey) {\n const r = SyncTree.parseQueryKey_(queryKey);\n const queryPath = r.path,\n queryId = r.queryId;\n const relativePath = Path.relativePath(queryPath, path);\n const changeTree = ImmutableTree.fromObject(changedChildren);\n const op = new Merge(\n OperationSource.forServerTaggedQuery(queryId),\n relativePath,\n changeTree\n );\n return this.applyTaggedOperation_(queryPath, op);\n } else {\n // We've already removed the query. No big deal, ignore the update\n return [];\n }\n }\n\n /**\n * Apply a listen complete for a tagged query\n *\n * @return Events to raise.\n */\n applyTaggedListenComplete(path: Path, tag: number): Event[] {\n const queryKey = this.queryKeyForTag_(tag);\n if (queryKey) {\n const r = SyncTree.parseQueryKey_(queryKey);\n const queryPath = r.path,\n queryId = r.queryId;\n const relativePath = Path.relativePath(queryPath, path);\n const op = new ListenComplete(\n OperationSource.forServerTaggedQuery(queryId),\n relativePath\n );\n return this.applyTaggedOperation_(queryPath, op);\n } else {\n // We've already removed the query. No big deal, ignore the update\n return [];\n }\n }\n\n /**\n * Add an event callback for the specified query.\n *\n * @return Events to raise.\n */\n addEventRegistration(\n query: Query,\n eventRegistration: EventRegistration\n ): Event[] {\n const path = query.path;\n\n let serverCache: Node | null = null;\n let foundAncestorDefaultView = false;\n // Any covering writes will necessarily be at the root, so really all we need to find is the server cache.\n // Consider optimizing this once there's a better understanding of what actual behavior will be.\n this.syncPointTree_.foreachOnPath(path, (pathToSyncPoint, sp) => {\n const relativePath = Path.relativePath(pathToSyncPoint, path);\n serverCache = serverCache || sp.getCompleteServerCache(relativePath);\n foundAncestorDefaultView =\n foundAncestorDefaultView || sp.hasCompleteView();\n });\n let syncPoint = this.syncPointTree_.get(path);\n if (!syncPoint) {\n syncPoint = new SyncPoint();\n this.syncPointTree_ = this.syncPointTree_.set(path, syncPoint);\n } else {\n foundAncestorDefaultView =\n foundAncestorDefaultView || syncPoint.hasCompleteView();\n serverCache = serverCache || syncPoint.getCompleteServerCache(Path.Empty);\n }\n\n let serverCacheComplete;\n if (serverCache != null) {\n serverCacheComplete = true;\n } else {\n serverCacheComplete = false;\n serverCache = ChildrenNode.EMPTY_NODE;\n const subtree = this.syncPointTree_.subtree(path);\n subtree.foreachChild((childName, childSyncPoint) => {\n const completeCache = childSyncPoint.getCompleteServerCache(Path.Empty);\n if (completeCache) {\n serverCache = serverCache.updateImmediateChild(\n childName,\n completeCache\n );\n }\n });\n }\n\n const viewAlreadyExists = syncPoint.viewExistsForQuery(query);\n if (!viewAlreadyExists && !query.getQueryParams().loadsAllData()) {\n // We need to track a tag for this query\n const queryKey = SyncTree.makeQueryKey_(query);\n assert(\n !this.queryToTagMap.has(queryKey),\n 'View does not exist, but we have a tag'\n );\n const tag = SyncTree.getNextQueryTag_();\n this.queryToTagMap.set(queryKey, tag);\n this.tagToQueryMap.set(tag, queryKey);\n }\n const writesCache = this.pendingWriteTree_.childWrites(path);\n let events = syncPoint.addEventRegistration(\n query,\n eventRegistration,\n writesCache,\n serverCache,\n serverCacheComplete\n );\n if (!viewAlreadyExists && !foundAncestorDefaultView) {\n const view /** @type !View */ = syncPoint.viewForQuery(query);\n events = events.concat(this.setupListener_(query, view));\n }\n return events;\n }\n\n /**\n * Remove event callback(s).\n *\n * If query is the default query, we'll check all queries for the specified eventRegistration.\n * If eventRegistration is null, we'll remove all callbacks for the specified query/queries.\n *\n * @param eventRegistration If null, all callbacks are removed.\n * @param cancelError If a cancelError is provided, appropriate cancel events will be returned.\n * @return Cancel events, if cancelError was provided.\n */\n removeEventRegistration(\n query: Query,\n eventRegistration: EventRegistration | null,\n cancelError?: Error\n ): Event[] {\n // Find the syncPoint first. Then deal with whether or not it has matching listeners\n const path = query.path;\n const maybeSyncPoint = this.syncPointTree_.get(path);\n let cancelEvents: Event[] = [];\n // A removal on a default query affects all queries at that location. A removal on an indexed query, even one without\n // other query constraints, does *not* affect all queries at that location. So this check must be for 'default', and\n // not loadsAllData().\n if (\n maybeSyncPoint &&\n (query.queryIdentifier() === 'default' ||\n maybeSyncPoint.viewExistsForQuery(query))\n ) {\n /**\n * @type {{removed: !Array., events: !Array.}}\n */\n const removedAndEvents = maybeSyncPoint.removeEventRegistration(\n query,\n eventRegistration,\n cancelError\n );\n if (maybeSyncPoint.isEmpty()) {\n this.syncPointTree_ = this.syncPointTree_.remove(path);\n }\n const removed = removedAndEvents.removed;\n cancelEvents = removedAndEvents.events;\n // We may have just removed one of many listeners and can short-circuit this whole process\n // We may also not have removed a default listener, in which case all of the descendant listeners should already be\n // properly set up.\n //\n // Since indexed queries can shadow if they don't have other query constraints, check for loadsAllData(), instead of\n // queryId === 'default'\n const removingDefault =\n -1 !==\n removed.findIndex(query => {\n return query.getQueryParams().loadsAllData();\n });\n const covered = this.syncPointTree_.findOnPath(\n path,\n (relativePath, parentSyncPoint) => {\n return parentSyncPoint.hasCompleteView();\n }\n );\n\n if (removingDefault && !covered) {\n const subtree = this.syncPointTree_.subtree(path);\n // There are potentially child listeners. Determine what if any listens we need to send before executing the\n // removal\n if (!subtree.isEmpty()) {\n // We need to fold over our subtree and collect the listeners to send\n const newViews = this.collectDistinctViewsForSubTree_(subtree);\n\n // Ok, we've collected all the listens we need. Set them up.\n for (let i = 0; i < newViews.length; ++i) {\n const view = newViews[i],\n newQuery = view.getQuery();\n const listener = this.createListenerForView_(view);\n this.listenProvider_.startListening(\n SyncTree.queryForListening_(newQuery),\n this.tagForQuery_(newQuery),\n listener.hashFn,\n listener.onComplete\n );\n }\n } else {\n // There's nothing below us, so nothing we need to start listening on\n }\n }\n // If we removed anything and we're not covered by a higher up listen, we need to stop listening on this query\n // The above block has us covered in terms of making sure we're set up on listens lower in the tree.\n // Also, note that if we have a cancelError, it's already been removed at the provider level.\n if (!covered && removed.length > 0 && !cancelError) {\n // If we removed a default, then we weren't listening on any of the other queries here. Just cancel the one\n // default. Otherwise, we need to iterate through and cancel each individual query\n if (removingDefault) {\n // We don't tag default listeners\n const defaultTag: number | null = null;\n this.listenProvider_.stopListening(\n SyncTree.queryForListening_(query),\n defaultTag\n );\n } else {\n removed.forEach((queryToRemove: Query) => {\n const tagToRemove = this.queryToTagMap.get(\n SyncTree.makeQueryKey_(queryToRemove)\n );\n this.listenProvider_.stopListening(\n SyncTree.queryForListening_(queryToRemove),\n tagToRemove\n );\n });\n }\n }\n // Now, clear all of the tags we're tracking for the removed listens\n this.removeTags_(removed);\n } else {\n // No-op, this listener must've been already removed\n }\n return cancelEvents;\n }\n\n /**\n * Returns a complete cache, if we have one, of the data at a particular path. The location must have a listener above\n * it, but as this is only used by transaction code, that should always be the case anyways.\n *\n * Note: this method will *include* hidden writes from transaction with applyLocally set to false.\n *\n * @param path The path to the data we want\n * @param writeIdsToExclude A specific set to be excluded\n */\n calcCompleteEventCache(\n path: Path,\n writeIdsToExclude?: number[]\n ): Node | null {\n const includeHiddenSets = true;\n const writeTree = this.pendingWriteTree_;\n const serverCache = this.syncPointTree_.findOnPath(\n path,\n (pathSoFar, syncPoint) => {\n const relativePath = Path.relativePath(pathSoFar, path);\n const serverCache = syncPoint.getCompleteServerCache(relativePath);\n if (serverCache) {\n return serverCache;\n }\n }\n );\n return writeTree.calcCompleteEventCache(\n path,\n serverCache,\n writeIdsToExclude,\n includeHiddenSets\n );\n }\n\n /**\n * This collapses multiple unfiltered views into a single view, since we only need a single\n * listener for them.\n */\n private collectDistinctViewsForSubTree_(\n subtree: ImmutableTree\n ): View[] {\n return subtree.fold(\n (relativePath, maybeChildSyncPoint, childMap) => {\n if (maybeChildSyncPoint && maybeChildSyncPoint.hasCompleteView()) {\n const completeView = maybeChildSyncPoint.getCompleteView();\n return [completeView];\n } else {\n // No complete view here, flatten any deeper listens into an array\n let views: View[] = [];\n if (maybeChildSyncPoint) {\n views = maybeChildSyncPoint.getQueryViews();\n }\n each(childMap, (_key: string, childViews: View[]) => {\n views = views.concat(childViews);\n });\n return views;\n }\n }\n );\n }\n\n private removeTags_(queries: Query[]) {\n for (let j = 0; j < queries.length; ++j) {\n const removedQuery = queries[j];\n if (!removedQuery.getQueryParams().loadsAllData()) {\n // We should have a tag for this\n const removedQueryKey = SyncTree.makeQueryKey_(removedQuery);\n const removedQueryTag = this.queryToTagMap.get(removedQueryKey);\n this.queryToTagMap.delete(removedQueryKey);\n this.tagToQueryMap.delete(removedQueryTag);\n }\n }\n }\n\n /**\n * Normalizes a query to a query we send the server for listening\n *\n * @return The normalized query\n */\n private static queryForListening_(query: Query): Query {\n if (\n query.getQueryParams().loadsAllData() &&\n !query.getQueryParams().isDefault()\n ) {\n // We treat queries that load all data as default queries\n // Cast is necessary because ref() technically returns Firebase which is actually fb.api.Firebase which inherits\n // from Query\n return query.getRef()!;\n } else {\n return query;\n }\n }\n\n /**\n * For a given new listen, manage the de-duplication of outstanding subscriptions.\n *\n * @return This method can return events to support synchronous data sources\n */\n private setupListener_(query: Query, view: View): Event[] {\n const path = query.path;\n const tag = this.tagForQuery_(query);\n const listener = this.createListenerForView_(view);\n\n const events = this.listenProvider_.startListening(\n SyncTree.queryForListening_(query),\n tag,\n listener.hashFn,\n listener.onComplete\n );\n\n const subtree = this.syncPointTree_.subtree(path);\n // The root of this subtree has our query. We're here because we definitely need to send a listen for that, but we\n // may need to shadow other listens as well.\n if (tag) {\n assert(\n !subtree.value.hasCompleteView(),\n \"If we're adding a query, it shouldn't be shadowed\"\n );\n } else {\n // Shadow everything at or below this location, this is a default listener.\n const queriesToStop = subtree.fold(\n (relativePath, maybeChildSyncPoint, childMap) => {\n if (\n !relativePath.isEmpty() &&\n maybeChildSyncPoint &&\n maybeChildSyncPoint.hasCompleteView()\n ) {\n return [maybeChildSyncPoint.getCompleteView().getQuery()];\n } else {\n // No default listener here, flatten any deeper queries into an array\n let queries: Query[] = [];\n if (maybeChildSyncPoint) {\n queries = queries.concat(\n maybeChildSyncPoint.getQueryViews().map(view => view.getQuery())\n );\n }\n each(childMap, (_key: string, childQueries: Query[]) => {\n queries = queries.concat(childQueries);\n });\n return queries;\n }\n }\n );\n for (let i = 0; i < queriesToStop.length; ++i) {\n const queryToStop = queriesToStop[i];\n this.listenProvider_.stopListening(\n SyncTree.queryForListening_(queryToStop),\n this.tagForQuery_(queryToStop)\n );\n }\n }\n return events;\n }\n\n private createListenerForView_(\n view: View\n ): { hashFn(): string; onComplete(a: string, b?: unknown): Event[] } {\n const query = view.getQuery();\n const tag = this.tagForQuery_(query);\n\n return {\n hashFn: () => {\n const cache = view.getServerCache() || ChildrenNode.EMPTY_NODE;\n return cache.hash();\n },\n onComplete: (status: string): Event[] => {\n if (status === 'ok') {\n if (tag) {\n return this.applyTaggedListenComplete(query.path, tag);\n } else {\n return this.applyListenComplete(query.path);\n }\n } else {\n // If a listen failed, kill all of the listeners here, not just the one that triggered the error.\n // Note that this may need to be scoped to just this listener if we change permissions on filtered children\n const error = errorForServerCode(status, query);\n return this.removeEventRegistration(\n query,\n /*eventRegistration*/ null,\n error\n );\n }\n }\n };\n }\n\n /**\n * Given a query, computes a \"queryKey\" suitable for use in our queryToTagMap_.\n */\n private static makeQueryKey_(query: Query): string {\n return query.path.toString() + '$' + query.queryIdentifier();\n }\n\n /**\n * Given a queryKey (created by makeQueryKey), parse it back into a path and queryId.\n */\n private static parseQueryKey_(\n queryKey: string\n ): { queryId: string; path: Path } {\n const splitIndex = queryKey.indexOf('$');\n assert(\n splitIndex !== -1 && splitIndex < queryKey.length - 1,\n 'Bad queryKey.'\n );\n return {\n queryId: queryKey.substr(splitIndex + 1),\n path: new Path(queryKey.substr(0, splitIndex))\n };\n }\n\n /**\n * Return the query associated with the given tag, if we have one\n */\n private queryKeyForTag_(tag: number): string | null {\n return this.tagToQueryMap.get(tag);\n }\n\n /**\n * Return the tag associated with the given query.\n */\n private tagForQuery_(query: Query): number | null {\n const queryKey = SyncTree.makeQueryKey_(query);\n return this.queryToTagMap.get(queryKey);\n }\n\n /**\n * Static tracker for next query tag.\n */\n private static nextQueryTag_ = 1;\n\n /**\n * Static accessor for query tags.\n */\n private static getNextQueryTag_(): number {\n return SyncTree.nextQueryTag_++;\n }\n\n /**\n * A helper method to apply tagged operations\n */\n private applyTaggedOperation_(\n queryPath: Path,\n operation: Operation\n ): Event[] {\n const syncPoint = this.syncPointTree_.get(queryPath);\n assert(syncPoint, \"Missing sync point for query tag that we're tracking\");\n const writesCache = this.pendingWriteTree_.childWrites(queryPath);\n return syncPoint.applyOperation(\n operation,\n writesCache,\n /*serverCache=*/ null\n );\n }\n\n /**\n * A helper method that visits all descendant and ancestor SyncPoints, applying the operation.\n *\n * NOTES:\n * - Descendant SyncPoints will be visited first (since we raise events depth-first).\n *\n * - We call applyOperation() on each SyncPoint passing three things:\n * 1. A version of the Operation that has been made relative to the SyncPoint location.\n * 2. A WriteTreeRef of any writes we have cached at the SyncPoint location.\n * 3. A snapshot Node with cached server data, if we have it.\n *\n * - We concatenate all of the events returned by each SyncPoint and return the result.\n */\n private applyOperationToSyncPoints_(operation: Operation): Event[] {\n return this.applyOperationHelper_(\n operation,\n this.syncPointTree_,\n /*serverCache=*/ null,\n this.pendingWriteTree_.childWrites(Path.Empty)\n );\n }\n\n /**\n * Recursive helper for applyOperationToSyncPoints_\n */\n private applyOperationHelper_(\n operation: Operation,\n syncPointTree: ImmutableTree,\n serverCache: Node | null,\n writesCache: WriteTreeRef\n ): Event[] {\n if (operation.path.isEmpty()) {\n return this.applyOperationDescendantsHelper_(\n operation,\n syncPointTree,\n serverCache,\n writesCache\n );\n } else {\n const syncPoint = syncPointTree.get(Path.Empty);\n\n // If we don't have cached server data, see if we can get it from this SyncPoint.\n if (serverCache == null && syncPoint != null) {\n serverCache = syncPoint.getCompleteServerCache(Path.Empty);\n }\n\n let events: Event[] = [];\n const childName = operation.path.getFront();\n const childOperation = operation.operationForChild(childName);\n const childTree = syncPointTree.children.get(childName);\n if (childTree && childOperation) {\n const childServerCache = serverCache\n ? serverCache.getImmediateChild(childName)\n : null;\n const childWritesCache = writesCache.child(childName);\n events = events.concat(\n this.applyOperationHelper_(\n childOperation,\n childTree,\n childServerCache,\n childWritesCache\n )\n );\n }\n\n if (syncPoint) {\n events = events.concat(\n syncPoint.applyOperation(operation, writesCache, serverCache)\n );\n }\n\n return events;\n }\n }\n\n /**\n * Recursive helper for applyOperationToSyncPoints_\n */\n private applyOperationDescendantsHelper_(\n operation: Operation,\n syncPointTree: ImmutableTree,\n serverCache: Node | null,\n writesCache: WriteTreeRef\n ): Event[] {\n const syncPoint = syncPointTree.get(Path.Empty);\n\n // If we don't have cached server data, see if we can get it from this SyncPoint.\n if (serverCache == null && syncPoint != null) {\n serverCache = syncPoint.getCompleteServerCache(Path.Empty);\n }\n\n let events: Event[] = [];\n syncPointTree.children.inorderTraversal((childName, childTree) => {\n const childServerCache = serverCache\n ? serverCache.getImmediateChild(childName)\n : null;\n const childWritesCache = writesCache.child(childName);\n const childOperation = operation.operationForChild(childName);\n if (childOperation) {\n events = events.concat(\n this.applyOperationDescendantsHelper_(\n childOperation,\n childTree,\n childServerCache,\n childWritesCache\n )\n );\n }\n });\n\n if (syncPoint) {\n events = events.concat(\n syncPoint.applyOperation(operation, writesCache, serverCache)\n );\n }\n\n return events;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Path } from './util/Path';\nimport { Node } from './snap/Node';\n\n/**\n * Mutable object which basically just stores a reference to the \"latest\" immutable snapshot.\n *\n * @constructor\n */\nexport class SnapshotHolder {\n private rootNode_: Node = ChildrenNode.EMPTY_NODE;\n\n getNode(path: Path): Node {\n return this.rootNode_.getChild(path);\n }\n\n updateSnapshot(path: Path, newSnapshotNode: Node) {\n this.rootNode_ = this.rootNode_.updateChild(path, newSnapshotNode);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseAuthTokenData } from '@firebase/app-types/private';\nimport {\n FirebaseAuthInternal,\n FirebaseAuthInternalName\n} from '@firebase/auth-interop-types';\nimport { Provider } from '@firebase/component';\nimport { log, warn } from './util/util';\nimport { FirebaseApp } from '@firebase/app-types';\n\n/**\n * Abstraction around FirebaseApp's token fetching capabilities.\n */\nexport class AuthTokenProvider {\n private auth_: FirebaseAuthInternal | null = null;\n constructor(\n private app_: FirebaseApp,\n private authProvider_: Provider\n ) {\n this.auth_ = authProvider_.getImmediate({ optional: true });\n if (!this.auth_) {\n authProvider_.get().then(auth => (this.auth_ = auth));\n }\n }\n\n /**\n * @param {boolean} forceRefresh\n * @return {!Promise}\n */\n getToken(forceRefresh: boolean): Promise {\n if (!this.auth_) {\n return Promise.resolve(null);\n }\n\n return this.auth_.getToken(forceRefresh).catch(error => {\n // TODO: Need to figure out all the cases this is raised and whether\n // this makes sense.\n if (error && error.code === 'auth/token-not-initialized') {\n log('Got auth/token-not-initialized error. Treating as null token.');\n return null;\n } else {\n return Promise.reject(error);\n }\n });\n }\n\n addTokenChangeListener(listener: (token: string | null) => void) {\n // TODO: We might want to wrap the listener and call it with no args to\n // avoid a leaky abstraction, but that makes removing the listener harder.\n if (this.auth_) {\n this.auth_.addAuthTokenListener(listener);\n } else {\n setTimeout(() => listener(null), 0);\n this.authProvider_\n .get()\n .then(auth => auth.addAuthTokenListener(listener));\n }\n }\n\n removeTokenChangeListener(listener: (token: string | null) => void) {\n this.authProvider_\n .get()\n .then(auth => auth.removeAuthTokenListener(listener));\n }\n\n notifyForInvalidToken() {\n let errorMessage =\n 'Provided authentication credentials for the app named \"' +\n this.app_.name +\n '\" are invalid. This usually indicates your app was not ' +\n 'initialized correctly. ';\n if ('credential' in this.app_.options) {\n errorMessage +=\n 'Make sure the \"credential\" property provided to initializeApp() ' +\n 'is authorized to access the specified \"databaseURL\" and is from the correct ' +\n 'project.';\n } else if ('serviceAccount' in this.app_.options) {\n errorMessage +=\n 'Make sure the \"serviceAccount\" property provided to initializeApp() ' +\n 'is authorized to access the specified \"databaseURL\" and is from the correct ' +\n 'project.';\n } else {\n errorMessage +=\n 'Make sure the \"apiKey\" and \"databaseURL\" properties provided to ' +\n 'initializeApp() match the values provided for your app at ' +\n 'https://console.firebase.google.com/.';\n }\n warn(errorMessage);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { deepCopy, contains } from '@firebase/util';\n\n/**\n * Tracks a collection of stats.\n *\n * @constructor\n */\nexport class StatsCollection {\n private counters_: { [k: string]: number } = {};\n\n incrementCounter(name: string, amount: number = 1) {\n if (!contains(this.counters_, name)) {\n this.counters_[name] = 0;\n }\n\n this.counters_[name] += amount;\n }\n\n get() {\n return deepCopy(this.counters_);\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { StatsCollection } from './StatsCollection';\nimport { RepoInfo } from '../RepoInfo';\n\nexport class StatsManager {\n private static collections_: { [k: string]: StatsCollection } = {};\n private static reporters_: { [k: string]: unknown } = {};\n\n static getCollection(repoInfo: RepoInfo): StatsCollection {\n const hashString = repoInfo.toString();\n\n if (!this.collections_[hashString]) {\n this.collections_[hashString] = new StatsCollection();\n }\n\n return this.collections_[hashString];\n }\n\n static getOrCreateReporter(\n repoInfo: RepoInfo,\n creatorFunction: () => T\n ): T {\n const hashString = repoInfo.toString();\n\n if (!this.reporters_[hashString]) {\n this.reporters_[hashString] = creatorFunction();\n }\n\n return this.reporters_[hashString] as T;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { StatsCollection } from './StatsCollection';\nimport { each } from '../util/util';\n\n/**\n * Returns the delta from the previous call to get stats.\n *\n * @param collection_ The collection to \"listen\" to.\n * @constructor\n */\nexport class StatsListener {\n private last_: { [k: string]: number } | null = null;\n\n constructor(private collection_: StatsCollection) {}\n\n get(): { [k: string]: number } {\n const newStats = this.collection_.get();\n\n const delta = { ...newStats };\n if (this.last_) {\n each(this.last_, (stat: string, value: number) => {\n delta[stat] = delta[stat] - value;\n });\n }\n this.last_ = newStats;\n\n return delta;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { contains } from '@firebase/util';\nimport { setTimeoutNonBlocking, each } from '../util/util';\nimport { StatsListener } from './StatsListener';\nimport { StatsCollection } from './StatsCollection';\nimport { ServerActions } from '../ServerActions';\n\n// Assuming some apps may have a short amount of time on page, and a bulk of firebase operations probably\n// happen on page load, we try to report our first set of stats pretty quickly, but we wait at least 10\n// seconds to try to ensure the Firebase connection is established / settled.\nconst FIRST_STATS_MIN_TIME = 10 * 1000;\nconst FIRST_STATS_MAX_TIME = 30 * 1000;\n\n// We'll continue to report stats on average every 5 minutes.\nconst REPORT_STATS_INTERVAL = 5 * 60 * 1000;\n\n/**\n * @constructor\n */\nexport class StatsReporter {\n private statsListener_: StatsListener;\n private statsToReport_: { [k: string]: boolean } = {};\n\n /**\n * @param collection\n * @param server_\n */\n constructor(collection: StatsCollection, private server_: ServerActions) {\n this.statsListener_ = new StatsListener(collection);\n\n const timeout =\n FIRST_STATS_MIN_TIME +\n (FIRST_STATS_MAX_TIME - FIRST_STATS_MIN_TIME) * Math.random();\n setTimeoutNonBlocking(this.reportStats_.bind(this), Math.floor(timeout));\n }\n\n includeStat(stat: string) {\n this.statsToReport_[stat] = true;\n }\n\n private reportStats_() {\n const stats = this.statsListener_.get();\n const reportedStats: typeof stats = {};\n let haveStatsToReport = false;\n\n each(stats, (stat: string, value: number) => {\n if (value > 0 && contains(this.statsToReport_, stat)) {\n reportedStats[stat] = value;\n haveStatsToReport = true;\n }\n });\n\n if (haveStatsToReport) {\n this.server_.reportStats(reportedStats);\n }\n\n // queue our next run.\n setTimeoutNonBlocking(\n this.reportStats_.bind(this),\n Math.floor(Math.random() * 2 * REPORT_STATS_INTERVAL)\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Path } from '../util/Path';\nimport { log, logger, exceptionGuard } from '../util/util';\nimport { Event } from './Event';\n\n/**\n * The event queue serves a few purposes:\n * 1. It ensures we maintain event order in the face of event callbacks doing operations that result in more\n * events being queued.\n * 2. raiseQueuedEvents() handles being called reentrantly nicely. That is, if in the course of raising events,\n * raiseQueuedEvents() is called again, the \"inner\" call will pick up raising events where the \"outer\" call\n * left off, ensuring that the events are still raised synchronously and in order.\n * 3. You can use raiseEventsAtPath and raiseEventsForChangedPath to ensure only relevant previously-queued\n * events are raised synchronously.\n *\n * NOTE: This can all go away if/when we move to async events.\n *\n * @constructor\n */\nexport class EventQueue {\n /**\n * @private\n * @type {!Array.}\n */\n private eventLists_: EventList[] = [];\n\n /**\n * Tracks recursion depth of raiseQueuedEvents_, for debugging purposes.\n * @private\n * @type {!number}\n */\n private recursionDepth_ = 0;\n\n /**\n * @param {!Array.} eventDataList The new events to queue.\n */\n queueEvents(eventDataList: Event[]) {\n // We group events by path, storing them in a single EventList, to make it easier to skip over them quickly.\n let currList = null;\n for (let i = 0; i < eventDataList.length; i++) {\n const eventData = eventDataList[i];\n const eventPath = eventData.getPath();\n if (currList !== null && !eventPath.equals(currList.getPath())) {\n this.eventLists_.push(currList);\n currList = null;\n }\n\n if (currList === null) {\n currList = new EventList(eventPath);\n }\n\n currList.add(eventData);\n }\n if (currList) {\n this.eventLists_.push(currList);\n }\n }\n\n /**\n * Queues the specified events and synchronously raises all events (including previously queued ones)\n * for the specified path.\n *\n * It is assumed that the new events are all for the specified path.\n *\n * @param {!Path} path The path to raise events for.\n * @param {!Array.} eventDataList The new events to raise.\n */\n raiseEventsAtPath(path: Path, eventDataList: Event[]) {\n this.queueEvents(eventDataList);\n this.raiseQueuedEventsMatchingPredicate_((eventPath: Path) =>\n eventPath.equals(path)\n );\n }\n\n /**\n * Queues the specified events and synchronously raises all events (including previously queued ones) for\n * locations related to the specified change path (i.e. all ancestors and descendants).\n *\n * It is assumed that the new events are all related (ancestor or descendant) to the specified path.\n *\n * @param {!Path} changedPath The path to raise events for.\n * @param {!Array.} eventDataList The events to raise\n */\n raiseEventsForChangedPath(changedPath: Path, eventDataList: Event[]) {\n this.queueEvents(eventDataList);\n\n this.raiseQueuedEventsMatchingPredicate_((eventPath: Path) => {\n return eventPath.contains(changedPath) || changedPath.contains(eventPath);\n });\n }\n\n /**\n * @param {!function(!Path):boolean} predicate\n * @private\n */\n private raiseQueuedEventsMatchingPredicate_(\n predicate: (path: Path) => boolean\n ) {\n this.recursionDepth_++;\n\n let sentAll = true;\n for (let i = 0; i < this.eventLists_.length; i++) {\n const eventList = this.eventLists_[i];\n if (eventList) {\n const eventPath = eventList.getPath();\n if (predicate(eventPath)) {\n this.eventLists_[i].raise();\n this.eventLists_[i] = null;\n } else {\n sentAll = false;\n }\n }\n }\n\n if (sentAll) {\n this.eventLists_ = [];\n }\n\n this.recursionDepth_--;\n }\n}\n\n/**\n * @param {!Path} path\n * @constructor\n */\nexport class EventList {\n /**\n * @type {!Array.}\n * @private\n */\n private events_: Event[] = [];\n\n constructor(private readonly path_: Path) {}\n\n /**\n * @param {!Event} eventData\n */\n add(eventData: Event) {\n this.events_.push(eventData);\n }\n\n /**\n * Iterates through the list and raises each event\n */\n raise() {\n for (let i = 0; i < this.events_.length; i++) {\n const eventData = this.events_[i];\n if (eventData !== null) {\n this.events_[i] = null;\n const eventFn = eventData.getEventRunner();\n if (logger) {\n log('event: ' + eventData.toString());\n }\n exceptionGuard(eventFn);\n }\n }\n }\n\n /**\n * @return {!Path}\n */\n getPath(): Path {\n return this.path_;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert } from '@firebase/util';\n\n/**\n * Base class to be used if you want to emit events. Call the constructor with\n * the set of allowed event names.\n */\nexport abstract class EventEmitter {\n private listeners_: {\n [eventType: string]: Array<{\n callback(...args: unknown[]): void;\n context: unknown;\n }>;\n } = {};\n\n /**\n * @param {!Array.} allowedEvents_\n */\n constructor(private allowedEvents_: string[]) {\n assert(\n Array.isArray(allowedEvents_) && allowedEvents_.length > 0,\n 'Requires a non-empty array'\n );\n }\n\n /**\n * To be overridden by derived classes in order to fire an initial event when\n * somebody subscribes for data.\n *\n * @param {!string} eventType\n * @return {Array.<*>} Array of parameters to trigger initial event with.\n */\n abstract getInitialEvent(eventType: string): unknown[];\n\n /**\n * To be called by derived classes to trigger events.\n * @param {!string} eventType\n * @param {...*} varArgs\n */\n protected trigger(eventType: string, ...varArgs: unknown[]) {\n if (Array.isArray(this.listeners_[eventType])) {\n // Clone the list, since callbacks could add/remove listeners.\n const listeners = [...this.listeners_[eventType]];\n\n for (let i = 0; i < listeners.length; i++) {\n listeners[i].callback.apply(listeners[i].context, varArgs);\n }\n }\n }\n\n on(eventType: string, callback: (a: unknown) => void, context: unknown) {\n this.validateEventType_(eventType);\n this.listeners_[eventType] = this.listeners_[eventType] || [];\n this.listeners_[eventType].push({ callback, context });\n\n const eventData = this.getInitialEvent(eventType);\n if (eventData) {\n callback.apply(context, eventData);\n }\n }\n\n off(eventType: string, callback: (a: unknown) => void, context: unknown) {\n this.validateEventType_(eventType);\n const listeners = this.listeners_[eventType] || [];\n for (let i = 0; i < listeners.length; i++) {\n if (\n listeners[i].callback === callback &&\n (!context || context === listeners[i].context)\n ) {\n listeners.splice(i, 1);\n return;\n }\n }\n }\n\n private validateEventType_(eventType: string) {\n assert(\n this.allowedEvents_.find(et => {\n return et === eventType;\n }),\n 'Unknown event: ' + eventType\n );\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { EventEmitter } from './EventEmitter';\nimport { assert } from '@firebase/util';\n\ndeclare const document: Document;\n\n/**\n * @extends {EventEmitter}\n */\nexport class VisibilityMonitor extends EventEmitter {\n private visible_: boolean;\n\n static getInstance() {\n return new VisibilityMonitor();\n }\n\n constructor() {\n super(['visible']);\n let hidden: string;\n let visibilityChange: string;\n if (\n typeof document !== 'undefined' &&\n typeof document.addEventListener !== 'undefined'\n ) {\n if (typeof document['hidden'] !== 'undefined') {\n // Opera 12.10 and Firefox 18 and later support\n visibilityChange = 'visibilitychange';\n hidden = 'hidden';\n } else if (typeof document['mozHidden'] !== 'undefined') {\n visibilityChange = 'mozvisibilitychange';\n hidden = 'mozHidden';\n } else if (typeof document['msHidden'] !== 'undefined') {\n visibilityChange = 'msvisibilitychange';\n hidden = 'msHidden';\n } else if (typeof document['webkitHidden'] !== 'undefined') {\n visibilityChange = 'webkitvisibilitychange';\n hidden = 'webkitHidden';\n }\n }\n\n // Initially, we always assume we are visible. This ensures that in browsers\n // without page visibility support or in cases where we are never visible\n // (e.g. chrome extension), we act as if we are visible, i.e. don't delay\n // reconnects\n this.visible_ = true;\n\n if (visibilityChange) {\n document.addEventListener(\n visibilityChange,\n () => {\n const visible = !document[hidden];\n if (visible !== this.visible_) {\n this.visible_ = visible;\n this.trigger('visible', visible);\n }\n },\n false\n );\n }\n }\n\n /**\n * @param {!string} eventType\n * @return {Array.}\n */\n getInitialEvent(eventType: string): boolean[] {\n assert(eventType === 'visible', 'Unknown event type: ' + eventType);\n return [this.visible_];\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, isMobileCordova } from '@firebase/util';\nimport { EventEmitter } from './EventEmitter';\n\n/**\n * Monitors online state (as reported by window.online/offline events).\n *\n * The expectation is that this could have many false positives (thinks we are online\n * when we're not), but no false negatives. So we can safely use it to determine when\n * we definitely cannot reach the internet.\n *\n * @extends {EventEmitter}\n */\nexport class OnlineMonitor extends EventEmitter {\n private online_ = true;\n\n static getInstance() {\n return new OnlineMonitor();\n }\n\n constructor() {\n super(['online']);\n\n // We've had repeated complaints that Cordova apps can get stuck \"offline\", e.g.\n // https://forum.ionicframework.com/t/firebase-connection-is-lost-and-never-come-back/43810\n // It would seem that the 'online' event does not always fire consistently. So we disable it\n // for Cordova.\n if (\n typeof window !== 'undefined' &&\n typeof window.addEventListener !== 'undefined' &&\n !isMobileCordova()\n ) {\n window.addEventListener(\n 'online',\n () => {\n if (!this.online_) {\n this.online_ = true;\n this.trigger('online', true);\n }\n },\n false\n );\n\n window.addEventListener(\n 'offline',\n () => {\n if (this.online_) {\n this.online_ = false;\n this.trigger('online', false);\n }\n },\n false\n );\n }\n }\n\n /**\n * @param {!string} eventType\n * @return {Array.}\n */\n getInitialEvent(eventType: string): boolean[] {\n assert(eventType === 'online', 'Unknown event type: ' + eventType);\n return [this.online_];\n }\n\n /**\n * @return {boolean}\n */\n currentlyOnline(): boolean {\n return this.online_;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { exceptionGuard } from '../../core/util/util';\n\n/**\n * This class ensures the packets from the server arrive in order\n * This class takes data from the server and ensures it gets passed into the callbacks in order.\n * @constructor\n */\nexport class PacketReceiver {\n pendingResponses: unknown[] = [];\n currentResponseNum = 0;\n closeAfterResponse = -1;\n onClose: (() => void) | null = null;\n\n /**\n * @param onMessage_\n */\n constructor(private onMessage_: (a: {}) => void) {}\n\n closeAfter(responseNum: number, callback: () => void) {\n this.closeAfterResponse = responseNum;\n this.onClose = callback;\n if (this.closeAfterResponse < this.currentResponseNum) {\n this.onClose();\n this.onClose = null;\n }\n }\n\n /**\n * Each message from the server comes with a response number, and an array of data. The responseNumber\n * allows us to ensure that we process them in the right order, since we can't be guaranteed that all\n * browsers will respond in the same order as the requests we sent\n * @param {number} requestNum\n * @param {Array} data\n */\n handleResponse(requestNum: number, data: unknown[]) {\n this.pendingResponses[requestNum] = data;\n while (this.pendingResponses[this.currentResponseNum]) {\n const toProcess = this.pendingResponses[\n this.currentResponseNum\n ] as unknown[];\n delete this.pendingResponses[this.currentResponseNum];\n for (let i = 0; i < toProcess.length; ++i) {\n if (toProcess[i]) {\n exceptionGuard(() => {\n this.onMessage_(toProcess[i]);\n });\n }\n }\n if (this.currentResponseNum === this.closeAfterResponse) {\n if (this.onClose) {\n this.onClose();\n this.onClose = null;\n }\n break;\n }\n this.currentResponseNum++;\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n executeWhenDOMReady,\n isChromeExtensionContentScript,\n isWindowsStoreApp,\n log,\n logWrapper,\n LUIDGenerator,\n splitStringBySize\n} from '../core/util/util';\nimport { StatsManager } from '../core/stats/StatsManager';\nimport { PacketReceiver } from './polling/PacketReceiver';\nimport {\n FORGE_DOMAIN,\n FORGE_REF,\n LAST_SESSION_PARAM,\n LONG_POLLING,\n PROTOCOL_VERSION,\n REFERER_PARAM,\n TRANSPORT_SESSION_PARAM,\n VERSION_PARAM\n} from './Constants';\nimport { base64Encode, stringify, isNodeSdk } from '@firebase/util';\n\nimport { Transport } from './Transport';\nimport { RepoInfo } from '../core/RepoInfo';\nimport { StatsCollection } from '../core/stats/StatsCollection';\n\n// URL query parameters associated with longpolling\nexport const FIREBASE_LONGPOLL_START_PARAM = 'start';\nexport const FIREBASE_LONGPOLL_CLOSE_COMMAND = 'close';\nexport const FIREBASE_LONGPOLL_COMMAND_CB_NAME = 'pLPCommand';\nexport const FIREBASE_LONGPOLL_DATA_CB_NAME = 'pRTLPCB';\nexport const FIREBASE_LONGPOLL_ID_PARAM = 'id';\nexport const FIREBASE_LONGPOLL_PW_PARAM = 'pw';\nexport const FIREBASE_LONGPOLL_SERIAL_PARAM = 'ser';\nexport const FIREBASE_LONGPOLL_CALLBACK_ID_PARAM = 'cb';\nexport const FIREBASE_LONGPOLL_SEGMENT_NUM_PARAM = 'seg';\nexport const FIREBASE_LONGPOLL_SEGMENTS_IN_PACKET = 'ts';\nexport const FIREBASE_LONGPOLL_DATA_PARAM = 'd';\nexport const FIREBASE_LONGPOLL_DISCONN_FRAME_PARAM = 'disconn';\nexport const FIREBASE_LONGPOLL_DISCONN_FRAME_REQUEST_PARAM = 'dframe';\n\n//Data size constants.\n//TODO: Perf: the maximum length actually differs from browser to browser.\n// We should check what browser we're on and set accordingly.\nconst MAX_URL_DATA_SIZE = 1870;\nconst SEG_HEADER_SIZE = 30; //ie: &seg=8299234&ts=982389123&d=\nconst MAX_PAYLOAD_SIZE = MAX_URL_DATA_SIZE - SEG_HEADER_SIZE;\n\n/**\n * Keepalive period\n * send a fresh request at minimum every 25 seconds. Opera has a maximum request\n * length of 30 seconds that we can't exceed.\n * @const\n * @type {number}\n */\nconst KEEPALIVE_REQUEST_INTERVAL = 25000;\n\n/**\n * How long to wait before aborting a long-polling connection attempt.\n * @const\n * @type {number}\n */\nconst LP_CONNECT_TIMEOUT = 30000;\n\n/**\n * This class manages a single long-polling connection.\n *\n * @constructor\n * @implements {Transport}\n */\nexport class BrowserPollConnection implements Transport {\n bytesSent = 0;\n bytesReceived = 0;\n urlFn: (params: object) => string;\n scriptTagHolder: FirebaseIFrameScriptHolder;\n myDisconnFrame: HTMLIFrameElement;\n curSegmentNum: number;\n myPacketOrderer: PacketReceiver;\n id: string;\n password: string;\n private log_: (...a: unknown[]) => void;\n private stats_: StatsCollection;\n private everConnected_ = false;\n private isClosed_: boolean;\n private connectTimeoutTimer_: number | null;\n private onDisconnect_: ((a?: boolean) => void) | null;\n\n /**\n * @param {string} connId An identifier for this connection, used for logging\n * @param {RepoInfo} repoInfo The info for the endpoint to send data to.\n * @param {string=} transportSessionId Optional transportSessionid if we are reconnecting for an existing\n * transport session\n * @param {string=} lastSessionId Optional lastSessionId if the PersistentConnection has already created a\n * connection previously\n */\n constructor(\n public connId: string,\n public repoInfo: RepoInfo,\n public transportSessionId?: string,\n public lastSessionId?: string\n ) {\n this.log_ = logWrapper(connId);\n this.stats_ = StatsManager.getCollection(repoInfo);\n this.urlFn = (params: { [k: string]: string }) =>\n repoInfo.connectionURL(LONG_POLLING, params);\n }\n\n /**\n *\n * @param {function(Object)} onMessage Callback when messages arrive\n * @param {function()} onDisconnect Callback with connection lost.\n */\n open(onMessage: (msg: {}) => void, onDisconnect: (a?: boolean) => void) {\n this.curSegmentNum = 0;\n this.onDisconnect_ = onDisconnect;\n this.myPacketOrderer = new PacketReceiver(onMessage);\n this.isClosed_ = false;\n\n this.connectTimeoutTimer_ = setTimeout(() => {\n this.log_('Timed out trying to connect.');\n // Make sure we clear the host cache\n this.onClosed_();\n this.connectTimeoutTimer_ = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }, Math.floor(LP_CONNECT_TIMEOUT)) as any;\n\n // Ensure we delay the creation of the iframe until the DOM is loaded.\n executeWhenDOMReady(() => {\n if (this.isClosed_) {\n return;\n }\n\n //Set up a callback that gets triggered once a connection is set up.\n this.scriptTagHolder = new FirebaseIFrameScriptHolder(\n (...args) => {\n const [command, arg1, arg2, arg3, arg4] = args;\n this.incrementIncomingBytes_(args);\n if (!this.scriptTagHolder) {\n return; // we closed the connection.\n }\n\n if (this.connectTimeoutTimer_) {\n clearTimeout(this.connectTimeoutTimer_);\n this.connectTimeoutTimer_ = null;\n }\n this.everConnected_ = true;\n if (command === FIREBASE_LONGPOLL_START_PARAM) {\n this.id = arg1 as string;\n this.password = arg2 as string;\n } else if (command === FIREBASE_LONGPOLL_CLOSE_COMMAND) {\n // Don't clear the host cache. We got a response from the server, so we know it's reachable\n if (arg1) {\n // We aren't expecting any more data (other than what the server's already in the process of sending us\n // through our already open polls), so don't send any more.\n this.scriptTagHolder.sendNewPolls = false;\n\n // arg1 in this case is the last response number sent by the server. We should try to receive\n // all of the responses up to this one before closing\n this.myPacketOrderer.closeAfter(arg1 as number, () => {\n this.onClosed_();\n });\n } else {\n this.onClosed_();\n }\n } else {\n throw new Error('Unrecognized command received: ' + command);\n }\n },\n (...args) => {\n const [pN, data] = args;\n this.incrementIncomingBytes_(args);\n this.myPacketOrderer.handleResponse(pN as number, data as unknown[]);\n },\n () => {\n this.onClosed_();\n },\n this.urlFn\n );\n\n //Send the initial request to connect. The serial number is simply to keep the browser from pulling previous results\n //from cache.\n const urlParams: { [k: string]: string | number } = {};\n urlParams[FIREBASE_LONGPOLL_START_PARAM] = 't';\n urlParams[FIREBASE_LONGPOLL_SERIAL_PARAM] = Math.floor(\n Math.random() * 100000000\n );\n if (this.scriptTagHolder.uniqueCallbackIdentifier) {\n urlParams[\n FIREBASE_LONGPOLL_CALLBACK_ID_PARAM\n ] = this.scriptTagHolder.uniqueCallbackIdentifier;\n }\n urlParams[VERSION_PARAM] = PROTOCOL_VERSION;\n if (this.transportSessionId) {\n urlParams[TRANSPORT_SESSION_PARAM] = this.transportSessionId;\n }\n if (this.lastSessionId) {\n urlParams[LAST_SESSION_PARAM] = this.lastSessionId;\n }\n if (\n typeof location !== 'undefined' &&\n location.href &&\n location.href.indexOf(FORGE_DOMAIN) !== -1\n ) {\n urlParams[REFERER_PARAM] = FORGE_REF;\n }\n const connectURL = this.urlFn(urlParams);\n this.log_('Connecting via long-poll to ' + connectURL);\n this.scriptTagHolder.addTag(connectURL, () => {\n /* do nothing */\n });\n });\n }\n\n /**\n * Call this when a handshake has completed successfully and we want to consider the connection established\n */\n start() {\n this.scriptTagHolder.startLongPoll(this.id, this.password);\n this.addDisconnectPingFrame(this.id, this.password);\n }\n\n private static forceAllow_: boolean;\n\n /**\n * Forces long polling to be considered as a potential transport\n */\n static forceAllow() {\n BrowserPollConnection.forceAllow_ = true;\n }\n\n private static forceDisallow_: boolean;\n\n /**\n * Forces longpolling to not be considered as a potential transport\n */\n static forceDisallow() {\n BrowserPollConnection.forceDisallow_ = true;\n }\n\n // Static method, use string literal so it can be accessed in a generic way\n static isAvailable() {\n if (isNodeSdk()) {\n return false;\n } else if (BrowserPollConnection.forceAllow_) {\n return true;\n } else {\n // NOTE: In React-Native there's normally no 'document', but if you debug a React-Native app in\n // the Chrome debugger, 'document' is defined, but document.createElement is null (2015/06/08).\n return (\n !BrowserPollConnection.forceDisallow_ &&\n typeof document !== 'undefined' &&\n document.createElement != null &&\n !isChromeExtensionContentScript() &&\n !isWindowsStoreApp()\n );\n }\n }\n\n /**\n * No-op for polling\n */\n markConnectionHealthy() {}\n\n /**\n * Stops polling and cleans up the iframe\n * @private\n */\n private shutdown_() {\n this.isClosed_ = true;\n\n if (this.scriptTagHolder) {\n this.scriptTagHolder.close();\n this.scriptTagHolder = null;\n }\n\n //remove the disconnect frame, which will trigger an XHR call to the server to tell it we're leaving.\n if (this.myDisconnFrame) {\n document.body.removeChild(this.myDisconnFrame);\n this.myDisconnFrame = null;\n }\n\n if (this.connectTimeoutTimer_) {\n clearTimeout(this.connectTimeoutTimer_);\n this.connectTimeoutTimer_ = null;\n }\n }\n\n /**\n * Triggered when this transport is closed\n * @private\n */\n private onClosed_() {\n if (!this.isClosed_) {\n this.log_('Longpoll is closing itself');\n this.shutdown_();\n\n if (this.onDisconnect_) {\n this.onDisconnect_(this.everConnected_);\n this.onDisconnect_ = null;\n }\n }\n }\n\n /**\n * External-facing close handler. RealTime has requested we shut down. Kill our connection and tell the server\n * that we've left.\n */\n close() {\n if (!this.isClosed_) {\n this.log_('Longpoll is being closed.');\n this.shutdown_();\n }\n }\n\n /**\n * Send the JSON object down to the server. It will need to be stringified, base64 encoded, and then\n * broken into chunks (since URLs have a small maximum length).\n * @param {!Object} data The JSON data to transmit.\n */\n send(data: {}) {\n const dataStr = stringify(data);\n this.bytesSent += dataStr.length;\n this.stats_.incrementCounter('bytes_sent', dataStr.length);\n\n //first, lets get the base64-encoded data\n const base64data = base64Encode(dataStr);\n\n //We can only fit a certain amount in each URL, so we need to split this request\n //up into multiple pieces if it doesn't fit in one request.\n const dataSegs = splitStringBySize(base64data, MAX_PAYLOAD_SIZE);\n\n //Enqueue each segment for transmission. We assign each chunk a sequential ID and a total number\n //of segments so that we can reassemble the packet on the server.\n for (let i = 0; i < dataSegs.length; i++) {\n this.scriptTagHolder.enqueueSegment(\n this.curSegmentNum,\n dataSegs.length,\n dataSegs[i]\n );\n this.curSegmentNum++;\n }\n }\n\n /**\n * This is how we notify the server that we're leaving.\n * We aren't able to send requests with DHTML on a window close event, but we can\n * trigger XHR requests in some browsers (everything but Opera basically).\n * @param {!string} id\n * @param {!string} pw\n */\n addDisconnectPingFrame(id: string, pw: string) {\n if (isNodeSdk()) {\n return;\n }\n this.myDisconnFrame = document.createElement('iframe');\n const urlParams: { [k: string]: string } = {};\n urlParams[FIREBASE_LONGPOLL_DISCONN_FRAME_REQUEST_PARAM] = 't';\n urlParams[FIREBASE_LONGPOLL_ID_PARAM] = id;\n urlParams[FIREBASE_LONGPOLL_PW_PARAM] = pw;\n this.myDisconnFrame.src = this.urlFn(urlParams);\n this.myDisconnFrame.style.display = 'none';\n\n document.body.appendChild(this.myDisconnFrame);\n }\n\n /**\n * Used to track the bytes received by this client\n * @param {*} args\n * @private\n */\n private incrementIncomingBytes_(args: unknown) {\n // TODO: This is an annoying perf hit just to track the number of incoming bytes. Maybe it should be opt-in.\n const bytesReceived = stringify(args).length;\n this.bytesReceived += bytesReceived;\n this.stats_.incrementCounter('bytes_received', bytesReceived);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/interface-name-prefix\nexport interface IFrameElement extends HTMLIFrameElement {\n doc: Document;\n}\n\n/*********************************************************************************************\n * A wrapper around an iframe that is used as a long-polling script holder.\n * @constructor\n *********************************************************************************************/\nexport class FirebaseIFrameScriptHolder {\n //We maintain a count of all of the outstanding requests, because if we have too many active at once it can cause\n //problems in some browsers.\n outstandingRequests = new Set();\n\n //A queue of the pending segments waiting for transmission to the server.\n pendingSegs: Array<{ seg: number; ts: number; d: unknown }> = [];\n\n //A serial number. We use this for two things:\n // 1) A way to ensure the browser doesn't cache responses to polls\n // 2) A way to make the server aware when long-polls arrive in a different order than we started them. The\n // server needs to release both polls in this case or it will cause problems in Opera since Opera can only execute\n // JSONP code in the order it was added to the iframe.\n currentSerial = Math.floor(Math.random() * 100000000);\n\n // This gets set to false when we're \"closing down\" the connection (e.g. we're switching transports but there's still\n // incoming data from the server that we're waiting for).\n sendNewPolls = true;\n\n uniqueCallbackIdentifier: number;\n myIFrame: IFrameElement;\n alive: boolean;\n myID: string;\n myPW: string;\n commandCB: (command: string, ...args: unknown[]) => void;\n onMessageCB: (...args: unknown[]) => void;\n\n /**\n * @param commandCB - The callback to be called when control commands are recevied from the server.\n * @param onMessageCB - The callback to be triggered when responses arrive from the server.\n * @param onDisconnect - The callback to be triggered when this tag holder is closed\n * @param urlFn - A function that provides the URL of the endpoint to send data to.\n */\n constructor(\n commandCB: (command: string, ...args: unknown[]) => void,\n onMessageCB: (...args: unknown[]) => void,\n public onDisconnect: () => void,\n public urlFn: (a: object) => string\n ) {\n if (!isNodeSdk()) {\n //Each script holder registers a couple of uniquely named callbacks with the window. These are called from the\n //iframes where we put the long-polling script tags. We have two callbacks:\n // 1) Command Callback - Triggered for control issues, like starting a connection.\n // 2) Message Callback - Triggered when new data arrives.\n this.uniqueCallbackIdentifier = LUIDGenerator();\n window[\n FIREBASE_LONGPOLL_COMMAND_CB_NAME + this.uniqueCallbackIdentifier\n ] = commandCB;\n window[\n FIREBASE_LONGPOLL_DATA_CB_NAME + this.uniqueCallbackIdentifier\n ] = onMessageCB;\n\n //Create an iframe for us to add script tags to.\n this.myIFrame = FirebaseIFrameScriptHolder.createIFrame_();\n\n // Set the iframe's contents.\n let script = '';\n // if we set a javascript url, it's IE and we need to set the document domain. The javascript url is sufficient\n // for ie9, but ie8 needs to do it again in the document itself.\n if (\n this.myIFrame.src &&\n this.myIFrame.src.substr(0, 'javascript:'.length) === 'javascript:'\n ) {\n const currentDomain = document.domain;\n script = '';\n }\n const iframeContents = '' + script + '';\n try {\n this.myIFrame.doc.open();\n this.myIFrame.doc.write(iframeContents);\n this.myIFrame.doc.close();\n } catch (e) {\n log('frame writing exception');\n if (e.stack) {\n log(e.stack);\n }\n log(e);\n }\n } else {\n this.commandCB = commandCB;\n this.onMessageCB = onMessageCB;\n }\n }\n\n /**\n * Each browser has its own funny way to handle iframes. Here we mush them all together into one object that I can\n * actually use.\n * @private\n * @return {Element}\n */\n private static createIFrame_(): IFrameElement {\n const iframe = document.createElement('iframe') as IFrameElement;\n iframe.style.display = 'none';\n\n // This is necessary in order to initialize the document inside the iframe\n if (document.body) {\n document.body.appendChild(iframe);\n try {\n // If document.domain has been modified in IE, this will throw an error, and we need to set the\n // domain of the iframe's document manually. We can do this via a javascript: url as the src attribute\n // Also note that we must do this *after* the iframe has been appended to the page. Otherwise it doesn't work.\n const a = iframe.contentWindow.document;\n if (!a) {\n // Apologies for the log-spam, I need to do something to keep closure from optimizing out the assignment above.\n log('No IE domain setting required');\n }\n } catch (e) {\n const domain = document.domain;\n iframe.src =\n \"javascript:void((function(){document.open();document.domain='\" +\n domain +\n \"';document.close();})())\";\n }\n } else {\n // LongPollConnection attempts to delay initialization until the document is ready, so hopefully this\n // never gets hit.\n throw 'Document body has not initialized. Wait to initialize Firebase until after the document is ready.';\n }\n\n // Get the document of the iframe in a browser-specific way.\n if (iframe.contentDocument) {\n iframe.doc = iframe.contentDocument; // Firefox, Opera, Safari\n } else if (iframe.contentWindow) {\n iframe.doc = iframe.contentWindow.document; // Internet Explorer\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } else if ((iframe as any).document) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n iframe.doc = (iframe as any).document; //others?\n }\n\n return iframe;\n }\n\n /**\n * Cancel all outstanding queries and remove the frame.\n */\n close() {\n //Mark this iframe as dead, so no new requests are sent.\n this.alive = false;\n\n if (this.myIFrame) {\n //We have to actually remove all of the html inside this iframe before removing it from the\n //window, or IE will continue loading and executing the script tags we've already added, which\n //can lead to some errors being thrown. Setting innerHTML seems to be the easiest way to do this.\n this.myIFrame.doc.body.innerHTML = '';\n setTimeout(() => {\n if (this.myIFrame !== null) {\n document.body.removeChild(this.myIFrame);\n this.myIFrame = null;\n }\n }, Math.floor(0));\n }\n\n // Protect from being called recursively.\n const onDisconnect = this.onDisconnect;\n if (onDisconnect) {\n this.onDisconnect = null;\n onDisconnect();\n }\n }\n\n /**\n * Actually start the long-polling session by adding the first script tag(s) to the iframe.\n * @param {!string} id - The ID of this connection\n * @param {!string} pw - The password for this connection\n */\n startLongPoll(id: string, pw: string) {\n this.myID = id;\n this.myPW = pw;\n this.alive = true;\n\n //send the initial request. If there are requests queued, make sure that we transmit as many as we are currently able to.\n while (this.newRequest_()) {}\n }\n\n /**\n * This is called any time someone might want a script tag to be added. It adds a script tag when there aren't\n * too many outstanding requests and we are still alive.\n *\n * If there are outstanding packet segments to send, it sends one. If there aren't, it sends a long-poll anyways if\n * needed.\n */\n private newRequest_() {\n // We keep one outstanding request open all the time to receive data, but if we need to send data\n // (pendingSegs.length > 0) then we create a new request to send the data. The server will automatically\n // close the old request.\n if (\n this.alive &&\n this.sendNewPolls &&\n this.outstandingRequests.size < (this.pendingSegs.length > 0 ? 2 : 1)\n ) {\n //construct our url\n this.currentSerial++;\n const urlParams: { [k: string]: string | number } = {};\n urlParams[FIREBASE_LONGPOLL_ID_PARAM] = this.myID;\n urlParams[FIREBASE_LONGPOLL_PW_PARAM] = this.myPW;\n urlParams[FIREBASE_LONGPOLL_SERIAL_PARAM] = this.currentSerial;\n let theURL = this.urlFn(urlParams);\n //Now add as much data as we can.\n let curDataString = '';\n let i = 0;\n\n while (this.pendingSegs.length > 0) {\n //first, lets see if the next segment will fit.\n const nextSeg = this.pendingSegs[0];\n if (\n (nextSeg.d as unknown[]).length +\n SEG_HEADER_SIZE +\n curDataString.length <=\n MAX_URL_DATA_SIZE\n ) {\n //great, the segment will fit. Lets append it.\n const theSeg = this.pendingSegs.shift();\n curDataString =\n curDataString +\n '&' +\n FIREBASE_LONGPOLL_SEGMENT_NUM_PARAM +\n i +\n '=' +\n theSeg.seg +\n '&' +\n FIREBASE_LONGPOLL_SEGMENTS_IN_PACKET +\n i +\n '=' +\n theSeg.ts +\n '&' +\n FIREBASE_LONGPOLL_DATA_PARAM +\n i +\n '=' +\n theSeg.d;\n i++;\n } else {\n break;\n }\n }\n\n theURL = theURL + curDataString;\n this.addLongPollTag_(theURL, this.currentSerial);\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * Queue a packet for transmission to the server.\n * @param segnum - A sequential id for this packet segment used for reassembly\n * @param totalsegs - The total number of segments in this packet\n * @param data - The data for this segment.\n */\n enqueueSegment(segnum: number, totalsegs: number, data: unknown) {\n //add this to the queue of segments to send.\n this.pendingSegs.push({ seg: segnum, ts: totalsegs, d: data });\n\n //send the data immediately if there isn't already data being transmitted, unless\n //startLongPoll hasn't been called yet.\n if (this.alive) {\n this.newRequest_();\n }\n }\n\n /**\n * Add a script tag for a regular long-poll request.\n * @param {!string} url - The URL of the script tag.\n * @param {!number} serial - The serial number of the request.\n * @private\n */\n private addLongPollTag_(url: string, serial: number) {\n //remember that we sent this request.\n this.outstandingRequests.add(serial);\n\n const doNewRequest = () => {\n this.outstandingRequests.delete(serial);\n this.newRequest_();\n };\n\n // If this request doesn't return on its own accord (by the server sending us some data), we'll\n // create a new one after the KEEPALIVE interval to make sure we always keep a fresh request open.\n const keepaliveTimeout = setTimeout(\n doNewRequest,\n Math.floor(KEEPALIVE_REQUEST_INTERVAL)\n );\n\n const readyStateCB = () => {\n // Request completed. Cancel the keepalive.\n clearTimeout(keepaliveTimeout);\n\n // Trigger a new request so we can continue receiving data.\n doNewRequest();\n };\n\n this.addTag(url, readyStateCB);\n }\n\n /**\n * Add an arbitrary script tag to the iframe.\n * @param {!string} url - The URL for the script tag source.\n * @param {!function()} loadCB - A callback to be triggered once the script has loaded.\n */\n addTag(url: string, loadCB: () => void) {\n if (isNodeSdk()) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this as any).doNodeLongPoll(url, loadCB);\n } else {\n setTimeout(() => {\n try {\n // if we're already closed, don't add this poll\n if (!this.sendNewPolls) {\n return;\n }\n const newScript = this.myIFrame.doc.createElement('script');\n newScript.type = 'text/javascript';\n newScript.async = true;\n newScript.src = url;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n newScript.onload = (newScript as any).onreadystatechange = function() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const rstate = (newScript as any).readyState;\n if (!rstate || rstate === 'loaded' || rstate === 'complete') {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n newScript.onload = (newScript as any).onreadystatechange = null;\n if (newScript.parentNode) {\n newScript.parentNode.removeChild(newScript);\n }\n loadCB();\n }\n };\n newScript.onerror = () => {\n log('Long-poll script failed to load: ' + url);\n this.sendNewPolls = false;\n this.close();\n };\n this.myIFrame.doc.body.appendChild(newScript);\n } catch (e) {\n // TODO: we should make this error visible somehow\n }\n }, Math.floor(1));\n }\n }\n}\n","/**\n * @license\n * Copyright 2019 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/** The semver (www.semver.org) version of the SDK. */\nexport let SDK_VERSION = '';\n\n// SDK_VERSION should be set before any database instance is created\nexport function setSDKVersion(version: string): void {\n SDK_VERSION = version;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RepoInfo } from '../core/RepoInfo';\nimport {\n assert,\n CONSTANTS as ENV_CONSTANTS,\n jsonEval,\n stringify,\n isNodeSdk\n} from '@firebase/util';\nimport { logWrapper, splitStringBySize } from '../core/util/util';\nimport { StatsManager } from '../core/stats/StatsManager';\nimport {\n FORGE_DOMAIN,\n FORGE_REF,\n LAST_SESSION_PARAM,\n PROTOCOL_VERSION,\n REFERER_PARAM,\n TRANSPORT_SESSION_PARAM,\n VERSION_PARAM,\n WEBSOCKET\n} from './Constants';\nimport { PersistentStorage } from '../core/storage/storage';\nimport { Transport } from './Transport';\nimport { StatsCollection } from '../core/stats/StatsCollection';\nimport { SDK_VERSION } from '../core/version';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ndeclare const MozWebSocket: any;\n\nconst WEBSOCKET_MAX_FRAME_SIZE = 16384;\nconst WEBSOCKET_KEEPALIVE_INTERVAL = 45000;\n\nlet WebSocketImpl = null;\nif (typeof MozWebSocket !== 'undefined') {\n WebSocketImpl = MozWebSocket;\n} else if (typeof WebSocket !== 'undefined') {\n WebSocketImpl = WebSocket;\n}\n\nexport function setWebSocketImpl(impl) {\n WebSocketImpl = impl;\n}\n\n/**\n * Create a new websocket connection with the given callbacks.\n * @constructor\n * @implements {Transport}\n */\nexport class WebSocketConnection implements Transport {\n keepaliveTimer: number | null = null;\n frames: string[] | null = null;\n totalFrames = 0;\n bytesSent = 0;\n bytesReceived = 0;\n connURL: string;\n onDisconnect: (a?: boolean) => void;\n onMessage: (msg: {}) => void;\n mySock: WebSocket | null;\n private log_: (...a: unknown[]) => void;\n private stats_: StatsCollection;\n private everConnected_: boolean;\n private isClosed_: boolean;\n\n /**\n * @param {string} connId identifier for this transport\n * @param {RepoInfo} repoInfo The info for the websocket endpoint.\n * @param {string=} transportSessionId Optional transportSessionId if this is connecting to an existing transport\n * session\n * @param {string=} lastSessionId Optional lastSessionId if there was a previous connection\n */\n constructor(\n public connId: string,\n repoInfo: RepoInfo,\n transportSessionId?: string,\n lastSessionId?: string\n ) {\n this.log_ = logWrapper(this.connId);\n this.stats_ = StatsManager.getCollection(repoInfo);\n this.connURL = WebSocketConnection.connectionURL_(\n repoInfo,\n transportSessionId,\n lastSessionId\n );\n }\n\n /**\n * @param {RepoInfo} repoInfo The info for the websocket endpoint.\n * @param {string=} transportSessionId Optional transportSessionId if this is connecting to an existing transport\n * session\n * @param {string=} lastSessionId Optional lastSessionId if there was a previous connection\n * @return {string} connection url\n * @private\n */\n private static connectionURL_(\n repoInfo: RepoInfo,\n transportSessionId?: string,\n lastSessionId?: string\n ): string {\n const urlParams: { [k: string]: string } = {};\n urlParams[VERSION_PARAM] = PROTOCOL_VERSION;\n\n if (\n !isNodeSdk() &&\n typeof location !== 'undefined' &&\n location.href &&\n location.href.indexOf(FORGE_DOMAIN) !== -1\n ) {\n urlParams[REFERER_PARAM] = FORGE_REF;\n }\n if (transportSessionId) {\n urlParams[TRANSPORT_SESSION_PARAM] = transportSessionId;\n }\n if (lastSessionId) {\n urlParams[LAST_SESSION_PARAM] = lastSessionId;\n }\n return repoInfo.connectionURL(WEBSOCKET, urlParams);\n }\n\n /**\n *\n * @param onMessage Callback when messages arrive\n * @param onDisconnect Callback with connection lost.\n */\n open(onMessage: (msg: {}) => void, onDisconnect: (a?: boolean) => void) {\n this.onDisconnect = onDisconnect;\n this.onMessage = onMessage;\n\n this.log_('Websocket connecting to ' + this.connURL);\n\n this.everConnected_ = false;\n // Assume failure until proven otherwise.\n PersistentStorage.set('previous_websocket_failure', true);\n\n try {\n if (isNodeSdk()) {\n const device = ENV_CONSTANTS.NODE_ADMIN ? 'AdminNode' : 'Node';\n // UA Format: Firebase////\n const options: { [k: string]: object } = {\n headers: {\n 'User-Agent': `Firebase/${PROTOCOL_VERSION}/${SDK_VERSION}/${process.platform}/${device}`\n }\n };\n\n // Plumb appropriate http_proxy environment variable into faye-websocket if it exists.\n const env = process['env'];\n const proxy =\n this.connURL.indexOf('wss://') === 0\n ? env['HTTPS_PROXY'] || env['https_proxy']\n : env['HTTP_PROXY'] || env['http_proxy'];\n\n if (proxy) {\n options['proxy'] = { origin: proxy };\n }\n\n this.mySock = new WebSocketImpl(this.connURL, [], options);\n } else {\n this.mySock = new WebSocketImpl(this.connURL);\n }\n } catch (e) {\n this.log_('Error instantiating WebSocket.');\n const error = e.message || e.data;\n if (error) {\n this.log_(error);\n }\n this.onClosed_();\n return;\n }\n\n this.mySock.onopen = () => {\n this.log_('Websocket connected.');\n this.everConnected_ = true;\n };\n\n this.mySock.onclose = () => {\n this.log_('Websocket connection was disconnected.');\n this.mySock = null;\n this.onClosed_();\n };\n\n this.mySock.onmessage = m => {\n this.handleIncomingFrame(m as {});\n };\n\n this.mySock.onerror = e => {\n this.log_('WebSocket error. Closing connection.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const error = (e as any).message || (e as any).data;\n if (error) {\n this.log_(error);\n }\n this.onClosed_();\n };\n }\n\n /**\n * No-op for websockets, we don't need to do anything once the connection is confirmed as open\n */\n start() {}\n\n static forceDisallow_: boolean;\n\n static forceDisallow() {\n WebSocketConnection.forceDisallow_ = true;\n }\n\n static isAvailable(): boolean {\n let isOldAndroid = false;\n if (typeof navigator !== 'undefined' && navigator.userAgent) {\n const oldAndroidRegex = /Android ([0-9]{0,}\\.[0-9]{0,})/;\n const oldAndroidMatch = navigator.userAgent.match(oldAndroidRegex);\n if (oldAndroidMatch && oldAndroidMatch.length > 1) {\n if (parseFloat(oldAndroidMatch[1]) < 4.4) {\n isOldAndroid = true;\n }\n }\n }\n\n return (\n !isOldAndroid &&\n WebSocketImpl !== null &&\n !WebSocketConnection.forceDisallow_\n );\n }\n\n /**\n * Number of response before we consider the connection \"healthy.\"\n * @type {number}\n */\n static responsesRequiredToBeHealthy = 2;\n\n /**\n * Time to wait for the connection te become healthy before giving up.\n * @type {number}\n */\n static healthyTimeout = 30000;\n\n /**\n * Returns true if we previously failed to connect with this transport.\n * @return {boolean}\n */\n static previouslyFailed(): boolean {\n // If our persistent storage is actually only in-memory storage,\n // we default to assuming that it previously failed to be safe.\n return (\n PersistentStorage.isInMemoryStorage ||\n PersistentStorage.get('previous_websocket_failure') === true\n );\n }\n\n markConnectionHealthy() {\n PersistentStorage.remove('previous_websocket_failure');\n }\n\n private appendFrame_(data: string) {\n this.frames.push(data);\n if (this.frames.length === this.totalFrames) {\n const fullMess = this.frames.join('');\n this.frames = null;\n const jsonMess = jsonEval(fullMess) as object;\n\n //handle the message\n this.onMessage(jsonMess);\n }\n }\n\n /**\n * @param {number} frameCount The number of frames we are expecting from the server\n * @private\n */\n private handleNewFrameCount_(frameCount: number) {\n this.totalFrames = frameCount;\n this.frames = [];\n }\n\n /**\n * Attempts to parse a frame count out of some text. If it can't, assumes a value of 1\n * @param {!String} data\n * @return {?String} Any remaining data to be process, or null if there is none\n * @private\n */\n private extractFrameCount_(data: string): string | null {\n assert(this.frames === null, 'We already have a frame buffer');\n // TODO: The server is only supposed to send up to 9999 frames (i.e. length <= 4), but that isn't being enforced\n // currently. So allowing larger frame counts (length <= 6). See https://app.asana.com/0/search/8688598998380/8237608042508\n if (data.length <= 6) {\n const frameCount = Number(data);\n if (!isNaN(frameCount)) {\n this.handleNewFrameCount_(frameCount);\n return null;\n }\n }\n this.handleNewFrameCount_(1);\n return data;\n }\n\n /**\n * Process a websocket frame that has arrived from the server.\n * @param mess The frame data\n */\n handleIncomingFrame(mess: { [k: string]: unknown }) {\n if (this.mySock === null) {\n return; // Chrome apparently delivers incoming packets even after we .close() the connection sometimes.\n }\n const data = mess['data'] as string;\n this.bytesReceived += data.length;\n this.stats_.incrementCounter('bytes_received', data.length);\n\n this.resetKeepAlive();\n\n if (this.frames !== null) {\n // we're buffering\n this.appendFrame_(data);\n } else {\n // try to parse out a frame count, otherwise, assume 1 and process it\n const remainingData = this.extractFrameCount_(data);\n if (remainingData !== null) {\n this.appendFrame_(remainingData);\n }\n }\n }\n\n /**\n * Send a message to the server\n * @param {Object} data The JSON object to transmit\n */\n send(data: {}) {\n this.resetKeepAlive();\n\n const dataStr = stringify(data);\n this.bytesSent += dataStr.length;\n this.stats_.incrementCounter('bytes_sent', dataStr.length);\n\n //We can only fit a certain amount in each websocket frame, so we need to split this request\n //up into multiple pieces if it doesn't fit in one request.\n\n const dataSegs = splitStringBySize(dataStr, WEBSOCKET_MAX_FRAME_SIZE);\n\n //Send the length header\n if (dataSegs.length > 1) {\n this.sendString_(String(dataSegs.length));\n }\n\n //Send the actual data in segments.\n for (let i = 0; i < dataSegs.length; i++) {\n this.sendString_(dataSegs[i]);\n }\n }\n\n private shutdown_() {\n this.isClosed_ = true;\n if (this.keepaliveTimer) {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = null;\n }\n\n if (this.mySock) {\n this.mySock.close();\n this.mySock = null;\n }\n }\n\n private onClosed_() {\n if (!this.isClosed_) {\n this.log_('WebSocket is closing itself');\n this.shutdown_();\n\n // since this is an internal close, trigger the close listener\n if (this.onDisconnect) {\n this.onDisconnect(this.everConnected_);\n this.onDisconnect = null;\n }\n }\n }\n\n /**\n * External-facing close handler.\n * Close the websocket and kill the connection.\n */\n close() {\n if (!this.isClosed_) {\n this.log_('WebSocket is being closed');\n this.shutdown_();\n }\n }\n\n /**\n * Kill the current keepalive timer and start a new one, to ensure that it always fires N seconds after\n * the last activity.\n */\n resetKeepAlive() {\n clearInterval(this.keepaliveTimer);\n this.keepaliveTimer = setInterval(() => {\n //If there has been no websocket activity for a while, send a no-op\n if (this.mySock) {\n this.sendString_('0');\n }\n this.resetKeepAlive();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }, Math.floor(WEBSOCKET_KEEPALIVE_INTERVAL)) as any;\n }\n\n /**\n * Send a string over the websocket.\n *\n * @param {string} str String to send.\n * @private\n */\n private sendString_(str: string) {\n // Firefox seems to sometimes throw exceptions (NS_ERROR_UNEXPECTED) from websocket .send()\n // calls for some unknown reason. We treat these as an error and disconnect.\n // See https://app.asana.com/0/58926111402292/68021340250410\n try {\n this.mySock.send(str);\n } catch (e) {\n this.log_(\n 'Exception thrown from WebSocket.send():',\n e.message || e.data,\n 'Closing connection.'\n );\n setTimeout(this.onClosed_.bind(this), 0);\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { BrowserPollConnection } from './BrowserPollConnection';\nimport { WebSocketConnection } from './WebSocketConnection';\nimport { warn, each } from '../core/util/util';\nimport { TransportConstructor } from './Transport';\nimport { RepoInfo } from '../core/RepoInfo';\n\n/**\n * Currently simplistic, this class manages what transport a Connection should use at various stages of its\n * lifecycle.\n *\n * It starts with longpolling in a browser, and httppolling on node. It then upgrades to websockets if\n * they are available.\n * @constructor\n */\nexport class TransportManager {\n private transports_: TransportConstructor[];\n\n /**\n * @const\n * @type {!Array.}\n */\n static get ALL_TRANSPORTS() {\n return [BrowserPollConnection, WebSocketConnection];\n }\n\n /**\n * @param {!RepoInfo} repoInfo Metadata around the namespace we're connecting to\n */\n constructor(repoInfo: RepoInfo) {\n this.initTransports_(repoInfo);\n }\n\n /**\n * @param {!RepoInfo} repoInfo\n * @private\n */\n private initTransports_(repoInfo: RepoInfo) {\n const isWebSocketsAvailable: boolean =\n WebSocketConnection && WebSocketConnection['isAvailable']();\n let isSkipPollConnection =\n isWebSocketsAvailable && !WebSocketConnection.previouslyFailed();\n\n if (repoInfo.webSocketOnly) {\n if (!isWebSocketsAvailable) {\n warn(\n \"wss:// URL used, but browser isn't known to support websockets. Trying anyway.\"\n );\n }\n\n isSkipPollConnection = true;\n }\n\n if (isSkipPollConnection) {\n this.transports_ = [WebSocketConnection];\n } else {\n const transports = (this.transports_ = [] as TransportConstructor[]);\n for (const transport of TransportManager.ALL_TRANSPORTS) {\n if (transport && transport['isAvailable']()) {\n transports.push(transport);\n }\n }\n }\n }\n\n /**\n * @return {function(new:Transport, !string, !RepoInfo, string=, string=)} The constructor for the\n * initial transport to use\n */\n initialTransport(): TransportConstructor {\n if (this.transports_.length > 0) {\n return this.transports_[0];\n } else {\n throw new Error('No transports available');\n }\n }\n\n /**\n * @return {?function(new:Transport, function(),function(), string=)} The constructor for the next\n * transport, or null\n */\n upgradeTransport(): TransportConstructor | null {\n if (this.transports_.length > 1) {\n return this.transports_[1];\n } else {\n return null;\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n error,\n logWrapper,\n requireKey,\n setTimeoutNonBlocking,\n warn\n} from '../core/util/util';\nimport { PersistentStorage } from '../core/storage/storage';\nimport { PROTOCOL_VERSION } from './Constants';\nimport { TransportManager } from './TransportManager';\nimport { RepoInfo } from '../core/RepoInfo';\nimport { Transport, TransportConstructor } from './Transport';\nimport { Indexable } from '../core/util/misc';\n\n// Abort upgrade attempt if it takes longer than 60s.\nconst UPGRADE_TIMEOUT = 60000;\n\n// For some transports (WebSockets), we need to \"validate\" the transport by exchanging a few requests and responses.\n// If we haven't sent enough requests within 5s, we'll start sending noop ping requests.\nconst DELAY_BEFORE_SENDING_EXTRA_REQUESTS = 5000;\n\n// If the initial data sent triggers a lot of bandwidth (i.e. it's a large put or a listen for a large amount of data)\n// then we may not be able to exchange our ping/pong requests within the healthy timeout. So if we reach the timeout\n// but we've sent/received enough bytes, we don't cancel the connection.\nconst BYTES_SENT_HEALTHY_OVERRIDE = 10 * 1024;\nconst BYTES_RECEIVED_HEALTHY_OVERRIDE = 100 * 1024;\n\nconst enum RealtimeState {\n CONNECTING,\n CONNECTED,\n DISCONNECTED\n}\n\nconst MESSAGE_TYPE = 't';\nconst MESSAGE_DATA = 'd';\nconst CONTROL_SHUTDOWN = 's';\nconst CONTROL_RESET = 'r';\nconst CONTROL_ERROR = 'e';\nconst CONTROL_PONG = 'o';\nconst SWITCH_ACK = 'a';\nconst END_TRANSMISSION = 'n';\nconst PING = 'p';\n\nconst SERVER_HELLO = 'h';\n\n/**\n * Creates a new real-time connection to the server using whichever method works\n * best in the current browser.\n *\n * @constructor\n */\nexport class Connection {\n connectionCount = 0;\n pendingDataMessages: unknown[] = [];\n sessionId: string;\n\n private conn_: Transport;\n private healthyTimeout_: number;\n private isHealthy_: boolean;\n private log_: (...args: unknown[]) => void;\n private primaryResponsesRequired_: number;\n private rx_: Transport;\n private secondaryConn_: Transport;\n private secondaryResponsesRequired_: number;\n private state_ = RealtimeState.CONNECTING;\n private transportManager_: TransportManager;\n private tx_: Transport;\n\n /**\n * @param {!string} id - an id for this connection\n * @param {!RepoInfo} repoInfo_ - the info for the endpoint to connect to\n * @param {function(Object)} onMessage_ - the callback to be triggered when a server-push message arrives\n * @param {function(number, string)} onReady_ - the callback to be triggered when this connection is ready to send messages.\n * @param {function()} onDisconnect_ - the callback to be triggered when a connection was lost\n * @param {function(string)} onKill_ - the callback to be triggered when this connection has permanently shut down.\n * @param {string=} lastSessionId - last session id in persistent connection. is used to clean up old session in real-time server\n */\n constructor(\n public id: string,\n private repoInfo_: RepoInfo,\n private onMessage_: (a: {}) => void,\n private onReady_: (a: number, b: string) => void,\n private onDisconnect_: () => void,\n private onKill_: (a: string) => void,\n public lastSessionId?: string\n ) {\n this.log_ = logWrapper('c:' + this.id + ':');\n this.transportManager_ = new TransportManager(repoInfo_);\n this.log_('Connection created');\n this.start_();\n }\n\n /**\n * Starts a connection attempt\n * @private\n */\n private start_(): void {\n const conn = this.transportManager_.initialTransport();\n this.conn_ = new conn(\n this.nextTransportId_(),\n this.repoInfo_,\n undefined,\n this.lastSessionId\n );\n\n // For certain transports (WebSockets), we need to send and receive several messages back and forth before we\n // can consider the transport healthy.\n this.primaryResponsesRequired_ = conn['responsesRequiredToBeHealthy'] || 0;\n\n const onMessageReceived = this.connReceiver_(this.conn_);\n const onConnectionLost = this.disconnReceiver_(this.conn_);\n this.tx_ = this.conn_;\n this.rx_ = this.conn_;\n this.secondaryConn_ = null;\n this.isHealthy_ = false;\n\n /*\n * Firefox doesn't like when code from one iframe tries to create another iframe by way of the parent frame.\n * This can occur in the case of a redirect, i.e. we guessed wrong on what server to connect to and received a reset.\n * Somehow, setTimeout seems to make this ok. That doesn't make sense from a security perspective, since you should\n * still have the context of your originating frame.\n */\n setTimeout(() => {\n // this.conn_ gets set to null in some of the tests. Check to make sure it still exists before using it\n this.conn_ && this.conn_.open(onMessageReceived, onConnectionLost);\n }, Math.floor(0));\n\n const healthyTimeoutMS = conn['healthyTimeout'] || 0;\n if (healthyTimeoutMS > 0) {\n this.healthyTimeout_ = setTimeoutNonBlocking(() => {\n this.healthyTimeout_ = null;\n if (!this.isHealthy_) {\n if (\n this.conn_ &&\n this.conn_.bytesReceived > BYTES_RECEIVED_HEALTHY_OVERRIDE\n ) {\n this.log_(\n 'Connection exceeded healthy timeout but has received ' +\n this.conn_.bytesReceived +\n ' bytes. Marking connection healthy.'\n );\n this.isHealthy_ = true;\n this.conn_.markConnectionHealthy();\n } else if (\n this.conn_ &&\n this.conn_.bytesSent > BYTES_SENT_HEALTHY_OVERRIDE\n ) {\n this.log_(\n 'Connection exceeded healthy timeout but has sent ' +\n this.conn_.bytesSent +\n ' bytes. Leaving connection alive.'\n );\n // NOTE: We don't want to mark it healthy, since we have no guarantee that the bytes have made it to\n // the server.\n } else {\n this.log_('Closing unhealthy connection after timeout.');\n this.close();\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }, Math.floor(healthyTimeoutMS)) as any;\n }\n }\n\n /**\n * @return {!string}\n * @private\n */\n private nextTransportId_(): string {\n return 'c:' + this.id + ':' + this.connectionCount++;\n }\n\n private disconnReceiver_(conn) {\n return everConnected => {\n if (conn === this.conn_) {\n this.onConnectionLost_(everConnected);\n } else if (conn === this.secondaryConn_) {\n this.log_('Secondary connection lost.');\n this.onSecondaryConnectionLost_();\n } else {\n this.log_('closing an old connection');\n }\n };\n }\n\n private connReceiver_(conn: Transport) {\n return (message: Indexable) => {\n if (this.state_ !== RealtimeState.DISCONNECTED) {\n if (conn === this.rx_) {\n this.onPrimaryMessageReceived_(message);\n } else if (conn === this.secondaryConn_) {\n this.onSecondaryMessageReceived_(message);\n } else {\n this.log_('message on old connection');\n }\n }\n };\n }\n\n /**\n *\n * @param {Object} dataMsg An arbitrary data message to be sent to the server\n */\n sendRequest(dataMsg: object) {\n // wrap in a data message envelope and send it on\n const msg = { t: 'd', d: dataMsg };\n this.sendData_(msg);\n }\n\n tryCleanupConnection() {\n if (this.tx_ === this.secondaryConn_ && this.rx_ === this.secondaryConn_) {\n this.log_(\n 'cleaning up and promoting a connection: ' + this.secondaryConn_.connId\n );\n this.conn_ = this.secondaryConn_;\n this.secondaryConn_ = null;\n // the server will shutdown the old connection\n }\n }\n\n private onSecondaryControl_(controlData: { [k: string]: unknown }) {\n if (MESSAGE_TYPE in controlData) {\n const cmd = controlData[MESSAGE_TYPE] as string;\n if (cmd === SWITCH_ACK) {\n this.upgradeIfSecondaryHealthy_();\n } else if (cmd === CONTROL_RESET) {\n // Most likely the session wasn't valid. Abandon the switch attempt\n this.log_('Got a reset on secondary, closing it');\n this.secondaryConn_.close();\n // If we were already using this connection for something, than we need to fully close\n if (\n this.tx_ === this.secondaryConn_ ||\n this.rx_ === this.secondaryConn_\n ) {\n this.close();\n }\n } else if (cmd === CONTROL_PONG) {\n this.log_('got pong on secondary.');\n this.secondaryResponsesRequired_--;\n this.upgradeIfSecondaryHealthy_();\n }\n }\n }\n\n private onSecondaryMessageReceived_(parsedData: Indexable) {\n const layer: string = requireKey('t', parsedData) as string;\n const data: unknown = requireKey('d', parsedData);\n if (layer === 'c') {\n this.onSecondaryControl_(data as Indexable);\n } else if (layer === 'd') {\n // got a data message, but we're still second connection. Need to buffer it up\n this.pendingDataMessages.push(data);\n } else {\n throw new Error('Unknown protocol layer: ' + layer);\n }\n }\n\n private upgradeIfSecondaryHealthy_() {\n if (this.secondaryResponsesRequired_ <= 0) {\n this.log_('Secondary connection is healthy.');\n this.isHealthy_ = true;\n this.secondaryConn_.markConnectionHealthy();\n this.proceedWithUpgrade_();\n } else {\n // Send a ping to make sure the connection is healthy.\n this.log_('sending ping on secondary.');\n this.secondaryConn_.send({ t: 'c', d: { t: PING, d: {} } });\n }\n }\n\n private proceedWithUpgrade_() {\n // tell this connection to consider itself open\n this.secondaryConn_.start();\n // send ack\n this.log_('sending client ack on secondary');\n this.secondaryConn_.send({ t: 'c', d: { t: SWITCH_ACK, d: {} } });\n\n // send end packet on primary transport, switch to sending on this one\n // can receive on this one, buffer responses until end received on primary transport\n this.log_('Ending transmission on primary');\n this.conn_.send({ t: 'c', d: { t: END_TRANSMISSION, d: {} } });\n this.tx_ = this.secondaryConn_;\n\n this.tryCleanupConnection();\n }\n\n private onPrimaryMessageReceived_(parsedData: { [k: string]: unknown }) {\n // Must refer to parsedData properties in quotes, so closure doesn't touch them.\n const layer: string = requireKey('t', parsedData) as string;\n const data: unknown = requireKey('d', parsedData);\n if (layer === 'c') {\n this.onControl_(data as { [k: string]: unknown });\n } else if (layer === 'd') {\n this.onDataMessage_(data);\n }\n }\n\n private onDataMessage_(message: unknown) {\n this.onPrimaryResponse_();\n\n // We don't do anything with data messages, just kick them up a level\n this.onMessage_(message);\n }\n\n private onPrimaryResponse_() {\n if (!this.isHealthy_) {\n this.primaryResponsesRequired_--;\n if (this.primaryResponsesRequired_ <= 0) {\n this.log_('Primary connection is healthy.');\n this.isHealthy_ = true;\n this.conn_.markConnectionHealthy();\n }\n }\n }\n\n private onControl_(controlData: { [k: string]: unknown }) {\n const cmd: string = requireKey(MESSAGE_TYPE, controlData) as string;\n if (MESSAGE_DATA in controlData) {\n const payload = controlData[MESSAGE_DATA];\n if (cmd === SERVER_HELLO) {\n this.onHandshake_(\n payload as {\n ts: number;\n v: string;\n h: string;\n s: string;\n }\n );\n } else if (cmd === END_TRANSMISSION) {\n this.log_('recvd end transmission on primary');\n this.rx_ = this.secondaryConn_;\n for (let i = 0; i < this.pendingDataMessages.length; ++i) {\n this.onDataMessage_(this.pendingDataMessages[i]);\n }\n this.pendingDataMessages = [];\n this.tryCleanupConnection();\n } else if (cmd === CONTROL_SHUTDOWN) {\n // This was previously the 'onKill' callback passed to the lower-level connection\n // payload in this case is the reason for the shutdown. Generally a human-readable error\n this.onConnectionShutdown_(payload as string);\n } else if (cmd === CONTROL_RESET) {\n // payload in this case is the host we should contact\n this.onReset_(payload as string);\n } else if (cmd === CONTROL_ERROR) {\n error('Server Error: ' + payload);\n } else if (cmd === CONTROL_PONG) {\n this.log_('got pong on primary.');\n this.onPrimaryResponse_();\n this.sendPingOnPrimaryIfNecessary_();\n } else {\n error('Unknown control packet command: ' + cmd);\n }\n }\n }\n\n /**\n *\n * @param {Object} handshake The handshake data returned from the server\n * @private\n */\n private onHandshake_(handshake: {\n ts: number;\n v: string;\n h: string;\n s: string;\n }): void {\n const timestamp = handshake.ts;\n const version = handshake.v;\n const host = handshake.h;\n this.sessionId = handshake.s;\n this.repoInfo_.updateHost(host);\n // if we've already closed the connection, then don't bother trying to progress further\n if (this.state_ === RealtimeState.CONNECTING) {\n this.conn_.start();\n this.onConnectionEstablished_(this.conn_, timestamp);\n if (PROTOCOL_VERSION !== version) {\n warn('Protocol version mismatch detected');\n }\n // TODO: do we want to upgrade? when? maybe a delay?\n this.tryStartUpgrade_();\n }\n }\n\n private tryStartUpgrade_() {\n const conn = this.transportManager_.upgradeTransport();\n if (conn) {\n this.startUpgrade_(conn);\n }\n }\n\n private startUpgrade_(conn: TransportConstructor) {\n this.secondaryConn_ = new conn(\n this.nextTransportId_(),\n this.repoInfo_,\n this.sessionId\n );\n // For certain transports (WebSockets), we need to send and receive several messages back and forth before we\n // can consider the transport healthy.\n this.secondaryResponsesRequired_ =\n conn['responsesRequiredToBeHealthy'] || 0;\n\n const onMessage = this.connReceiver_(this.secondaryConn_);\n const onDisconnect = this.disconnReceiver_(this.secondaryConn_);\n this.secondaryConn_.open(onMessage, onDisconnect);\n\n // If we haven't successfully upgraded after UPGRADE_TIMEOUT, give up and kill the secondary.\n setTimeoutNonBlocking(() => {\n if (this.secondaryConn_) {\n this.log_('Timed out trying to upgrade.');\n this.secondaryConn_.close();\n }\n }, Math.floor(UPGRADE_TIMEOUT));\n }\n\n private onReset_(host: string) {\n this.log_('Reset packet received. New host: ' + host);\n this.repoInfo_.updateHost(host);\n // TODO: if we're already \"connected\", we need to trigger a disconnect at the next layer up.\n // We don't currently support resets after the connection has already been established\n if (this.state_ === RealtimeState.CONNECTED) {\n this.close();\n } else {\n // Close whatever connections we have open and start again.\n this.closeConnections_();\n this.start_();\n }\n }\n\n private onConnectionEstablished_(conn: Transport, timestamp: number) {\n this.log_('Realtime connection established.');\n this.conn_ = conn;\n this.state_ = RealtimeState.CONNECTED;\n\n if (this.onReady_) {\n this.onReady_(timestamp, this.sessionId);\n this.onReady_ = null;\n }\n\n // If after 5 seconds we haven't sent enough requests to the server to get the connection healthy,\n // send some pings.\n if (this.primaryResponsesRequired_ === 0) {\n this.log_('Primary connection is healthy.');\n this.isHealthy_ = true;\n } else {\n setTimeoutNonBlocking(() => {\n this.sendPingOnPrimaryIfNecessary_();\n }, Math.floor(DELAY_BEFORE_SENDING_EXTRA_REQUESTS));\n }\n }\n\n private sendPingOnPrimaryIfNecessary_() {\n // If the connection isn't considered healthy yet, we'll send a noop ping packet request.\n if (!this.isHealthy_ && this.state_ === RealtimeState.CONNECTED) {\n this.log_('sending ping on primary.');\n this.sendData_({ t: 'c', d: { t: PING, d: {} } });\n }\n }\n\n private onSecondaryConnectionLost_() {\n const conn = this.secondaryConn_;\n this.secondaryConn_ = null;\n if (this.tx_ === conn || this.rx_ === conn) {\n // we are relying on this connection already in some capacity. Therefore, a failure is real\n this.close();\n }\n }\n\n /**\n *\n * @param {boolean} everConnected Whether or not the connection ever reached a server. Used to determine if\n * we should flush the host cache\n * @private\n */\n private onConnectionLost_(everConnected: boolean) {\n this.conn_ = null;\n\n // NOTE: IF you're seeing a Firefox error for this line, I think it might be because it's getting\n // called on window close and RealtimeState.CONNECTING is no longer defined. Just a guess.\n if (!everConnected && this.state_ === RealtimeState.CONNECTING) {\n this.log_('Realtime connection failed.');\n // Since we failed to connect at all, clear any cached entry for this namespace in case the machine went away\n if (this.repoInfo_.isCacheableHost()) {\n PersistentStorage.remove('host:' + this.repoInfo_.host);\n // reset the internal host to what we would show the user, i.e. .firebaseio.com\n this.repoInfo_.internalHost = this.repoInfo_.host;\n }\n } else if (this.state_ === RealtimeState.CONNECTED) {\n this.log_('Realtime connection lost.');\n }\n\n this.close();\n }\n\n /**\n *\n * @param {string} reason\n * @private\n */\n private onConnectionShutdown_(reason: string) {\n this.log_('Connection shutdown command received. Shutting down...');\n\n if (this.onKill_) {\n this.onKill_(reason);\n this.onKill_ = null;\n }\n\n // We intentionally don't want to fire onDisconnect (kill is a different case),\n // so clear the callback.\n this.onDisconnect_ = null;\n\n this.close();\n }\n\n private sendData_(data: object) {\n if (this.state_ !== RealtimeState.CONNECTED) {\n throw 'Connection is not connected';\n } else {\n this.tx_.send(data);\n }\n }\n\n /**\n * Cleans up this connection, calling the appropriate callbacks\n */\n close() {\n if (this.state_ !== RealtimeState.DISCONNECTED) {\n this.log_('Closing realtime connection.');\n this.state_ = RealtimeState.DISCONNECTED;\n\n this.closeConnections_();\n\n if (this.onDisconnect_) {\n this.onDisconnect_();\n this.onDisconnect_ = null;\n }\n }\n }\n\n /**\n *\n * @private\n */\n private closeConnections_() {\n this.log_('Shutting down all connections');\n if (this.conn_) {\n this.conn_.close();\n this.conn_ = null;\n }\n\n if (this.secondaryConn_) {\n this.secondaryConn_.close();\n this.secondaryConn_ = null;\n }\n\n if (this.healthyTimeout_) {\n clearTimeout(this.healthyTimeout_);\n this.healthyTimeout_ = null;\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Query } from '../api/Query';\n\n/**\n * Interface defining the set of actions that can be performed against the Firebase server\n * (basically corresponds to our wire protocol).\n *\n * @interface\n */\nexport abstract class ServerActions {\n /**\n * @param {!Query} query\n * @param {function():string} currentHashFn\n * @param {?number} tag\n * @param {function(string, *)} onComplete\n */\n abstract listen(\n query: Query,\n currentHashFn: () => string,\n tag: number | null,\n onComplete: (a: string, b: unknown) => void\n ): void;\n\n /**\n * Remove a listen.\n *\n * @param {!Query} query\n * @param {?number} tag\n */\n abstract unlisten(query: Query, tag: number | null): void;\n\n /**\n * @param {string} pathString\n * @param {*} data\n * @param {function(string, string)=} onComplete\n * @param {string=} hash\n */\n put(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void,\n hash?: string\n ) {}\n\n /**\n * @param {string} pathString\n * @param {*} data\n * @param {function(string, ?string)} onComplete\n * @param {string=} hash\n */\n merge(\n pathString: string,\n data: unknown,\n onComplete: (a: string, b: string | null) => void,\n hash?: string\n ) {}\n\n /**\n * Refreshes the auth token for the current connection.\n * @param {string} token The authentication token\n */\n refreshAuthToken(token: string) {}\n\n /**\n * @param {string} pathString\n * @param {*} data\n * @param {function(string, string)=} onComplete\n */\n onDisconnectPut(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void\n ) {}\n\n /**\n * @param {string} pathString\n * @param {*} data\n * @param {function(string, string)=} onComplete\n */\n onDisconnectMerge(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void\n ) {}\n\n /**\n * @param {string} pathString\n * @param {function(string, string)=} onComplete\n */\n onDisconnectCancel(\n pathString: string,\n onComplete?: (a: string, b: string) => void\n ) {}\n\n /**\n * @param {Object.} stats\n */\n reportStats(stats: { [k: string]: unknown }) {}\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n contains,\n isEmpty,\n safeGet,\n CONSTANTS,\n stringify,\n assert,\n isAdmin,\n isValidFormat,\n isMobileCordova,\n isReactNative,\n isNodeSdk\n} from '@firebase/util';\n\nimport { error, log, logWrapper, warn, ObjectToUniqueKey } from './util/util';\nimport { Path } from './util/Path';\nimport { VisibilityMonitor } from './util/VisibilityMonitor';\nimport { OnlineMonitor } from './util/OnlineMonitor';\n\nimport { Connection } from '../realtime/Connection';\n\nimport { ServerActions } from './ServerActions';\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { RepoInfo } from './RepoInfo';\nimport { Query } from '../api/Query';\nimport { SDK_VERSION } from './version';\n\nconst RECONNECT_MIN_DELAY = 1000;\nconst RECONNECT_MAX_DELAY_DEFAULT = 60 * 5 * 1000; // 5 minutes in milliseconds (Case: 1858)\nconst RECONNECT_MAX_DELAY_FOR_ADMINS = 30 * 1000; // 30 seconds for admin clients (likely to be a backend server)\nconst RECONNECT_DELAY_MULTIPLIER = 1.3;\nconst RECONNECT_DELAY_RESET_TIMEOUT = 30000; // Reset delay back to MIN_DELAY after being connected for 30sec.\nconst SERVER_KILL_INTERRUPT_REASON = 'server_kill';\n\n// If auth fails repeatedly, we'll assume something is wrong and log a warning / back off.\nconst INVALID_AUTH_TOKEN_THRESHOLD = 3;\n\ninterface ListenSpec {\n onComplete(s: string, p?: unknown): void;\n\n hashFn(): string;\n\n query: Query;\n tag: number | null;\n}\n\ninterface OnDisconnectRequest {\n pathString: string;\n action: string;\n data: unknown;\n onComplete?: (a: string, b: string) => void;\n}\n\ninterface OutstandingPut {\n action: string;\n request: object;\n queued?: boolean;\n onComplete: (a: string, b?: string) => void;\n}\n\n/**\n * Firebase connection. Abstracts wire protocol and handles reconnecting.\n *\n * NOTE: All JSON objects sent to the realtime connection must have property names enclosed\n * in quotes to make sure the closure compiler does not minify them.\n */\nexport class PersistentConnection extends ServerActions {\n // Used for diagnostic logging.\n id = PersistentConnection.nextPersistentConnectionId_++;\n private log_ = logWrapper('p:' + this.id + ':');\n\n private interruptReasons_: { [reason: string]: boolean } = {};\n /** Map> */\n private readonly listens: Map<\n /* path */ string,\n Map\n > = new Map();\n private outstandingPuts_: OutstandingPut[] = [];\n private outstandingPutCount_ = 0;\n private onDisconnectRequestQueue_: OnDisconnectRequest[] = [];\n private connected_ = false;\n private reconnectDelay_ = RECONNECT_MIN_DELAY;\n private maxReconnectDelay_ = RECONNECT_MAX_DELAY_DEFAULT;\n private securityDebugCallback_: ((a: object) => void) | null = null;\n lastSessionId: string | null = null;\n\n private establishConnectionTimer_: number | null = null;\n\n private visible_: boolean = false;\n\n // Before we get connected, we keep a queue of pending messages to send.\n private requestCBHash_: { [k: number]: (a: unknown) => void } = {};\n private requestNumber_ = 0;\n\n private realtime_: {\n sendRequest(a: object): void;\n close(): void;\n } | null = null;\n\n private authToken_: string | null = null;\n private forceTokenRefresh_ = false;\n private invalidAuthTokenCount_ = 0;\n\n private firstConnection_ = true;\n private lastConnectionAttemptTime_: number | null = null;\n private lastConnectionEstablishedTime_: number | null = null;\n\n private static nextPersistentConnectionId_ = 0;\n\n /**\n * Counter for number of connections created. Mainly used for tagging in the logs\n */\n private static nextConnectionId_ = 0;\n\n /**\n * @implements {ServerActions}\n * @param repoInfo_ Data about the namespace we are connecting to\n * @param onDataUpdate_ A callback for new data from the server\n */\n constructor(\n private repoInfo_: RepoInfo,\n private onDataUpdate_: (\n a: string,\n b: unknown,\n c: boolean,\n d: number | null\n ) => void,\n private onConnectStatus_: (a: boolean) => void,\n private onServerInfoUpdate_: (a: unknown) => void,\n private authTokenProvider_: AuthTokenProvider,\n private authOverride_?: object | null\n ) {\n super();\n\n if (authOverride_ && !isNodeSdk()) {\n throw new Error(\n 'Auth override specified in options, but not supported on non Node.js platforms'\n );\n }\n this.scheduleConnect_(0);\n\n VisibilityMonitor.getInstance().on('visible', this.onVisible_, this);\n\n if (repoInfo_.host.indexOf('fblocal') === -1) {\n OnlineMonitor.getInstance().on('online', this.onOnline_, this);\n }\n }\n\n protected sendRequest(\n action: string,\n body: unknown,\n onResponse?: (a: unknown) => void\n ) {\n const curReqNum = ++this.requestNumber_;\n\n const msg = { r: curReqNum, a: action, b: body };\n this.log_(stringify(msg));\n assert(\n this.connected_,\n \"sendRequest call when we're not connected not allowed.\"\n );\n this.realtime_.sendRequest(msg);\n if (onResponse) {\n this.requestCBHash_[curReqNum] = onResponse;\n }\n }\n\n /**\n * @inheritDoc\n */\n listen(\n query: Query,\n currentHashFn: () => string,\n tag: number | null,\n onComplete: (a: string, b: unknown) => void\n ) {\n const queryId = query.queryIdentifier();\n const pathString = query.path.toString();\n this.log_('Listen called for ' + pathString + ' ' + queryId);\n if (!this.listens.has(pathString)) {\n this.listens.set(pathString, new Map());\n }\n assert(\n query.getQueryParams().isDefault() ||\n !query.getQueryParams().loadsAllData(),\n 'listen() called for non-default but complete query'\n );\n assert(\n !this.listens.get(pathString)!.has(queryId),\n 'listen() called twice for same path/queryId.'\n );\n const listenSpec: ListenSpec = {\n onComplete,\n hashFn: currentHashFn,\n query,\n tag\n };\n this.listens.get(pathString)!.set(queryId, listenSpec);\n\n if (this.connected_) {\n this.sendListen_(listenSpec);\n }\n }\n\n private sendListen_(listenSpec: ListenSpec) {\n const query = listenSpec.query;\n const pathString = query.path.toString();\n const queryId = query.queryIdentifier();\n this.log_('Listen on ' + pathString + ' for ' + queryId);\n const req: { [k: string]: unknown } = { /*path*/ p: pathString };\n\n const action = 'q';\n\n // Only bother to send query if it's non-default.\n if (listenSpec.tag) {\n req['q'] = query.queryObject();\n req['t'] = listenSpec.tag;\n }\n\n req[/*hash*/ 'h'] = listenSpec.hashFn();\n\n this.sendRequest(action, req, (message: { [k: string]: unknown }) => {\n const payload: unknown = message[/*data*/ 'd'];\n const status = message[/*status*/ 's'] as string;\n\n // print warnings in any case...\n PersistentConnection.warnOnListenWarnings_(payload, query);\n\n const currentListenSpec =\n this.listens.get(pathString) &&\n this.listens.get(pathString)!.get(queryId);\n // only trigger actions if the listen hasn't been removed and readded\n if (currentListenSpec === listenSpec) {\n this.log_('listen response', message);\n\n if (status !== 'ok') {\n this.removeListen_(pathString, queryId);\n }\n\n if (listenSpec.onComplete) {\n listenSpec.onComplete(status, payload);\n }\n }\n });\n }\n\n private static warnOnListenWarnings_(payload: unknown, query: Query) {\n if (payload && typeof payload === 'object' && contains(payload, 'w')) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const warnings = safeGet(payload as any, 'w');\n if (Array.isArray(warnings) && ~warnings.indexOf('no_index')) {\n const indexSpec =\n '\".indexOn\": \"' +\n query\n .getQueryParams()\n .getIndex()\n .toString() +\n '\"';\n const indexPath = query.path.toString();\n warn(\n `Using an unspecified index. Your data will be downloaded and ` +\n `filtered on the client. Consider adding ${indexSpec} at ` +\n `${indexPath} to your security rules for better performance.`\n );\n }\n }\n }\n\n /**\n * @inheritDoc\n */\n refreshAuthToken(token: string) {\n this.authToken_ = token;\n this.log_('Auth token refreshed');\n if (this.authToken_) {\n this.tryAuth();\n } else {\n //If we're connected we want to let the server know to unauthenticate us. If we're not connected, simply delete\n //the credential so we dont become authenticated next time we connect.\n if (this.connected_) {\n this.sendRequest('unauth', {}, () => {});\n }\n }\n\n this.reduceReconnectDelayIfAdminCredential_(token);\n }\n\n private reduceReconnectDelayIfAdminCredential_(credential: string) {\n // NOTE: This isn't intended to be bulletproof (a malicious developer can always just modify the client).\n // Additionally, we don't bother resetting the max delay back to the default if auth fails / expires.\n const isFirebaseSecret = credential && credential.length === 40;\n if (isFirebaseSecret || isAdmin(credential)) {\n this.log_(\n 'Admin auth credential detected. Reducing max reconnect time.'\n );\n this.maxReconnectDelay_ = RECONNECT_MAX_DELAY_FOR_ADMINS;\n }\n }\n\n /**\n * Attempts to authenticate with the given credentials. If the authentication attempt fails, it's triggered like\n * a auth revoked (the connection is closed).\n */\n tryAuth() {\n if (this.connected_ && this.authToken_) {\n const token = this.authToken_;\n const authMethod = isValidFormat(token) ? 'auth' : 'gauth';\n const requestData: { [k: string]: unknown } = { cred: token };\n if (this.authOverride_ === null) {\n requestData['noauth'] = true;\n } else if (typeof this.authOverride_ === 'object') {\n requestData['authvar'] = this.authOverride_;\n }\n this.sendRequest(\n authMethod,\n requestData,\n (res: { [k: string]: unknown }) => {\n const status = res[/*status*/ 's'] as string;\n const data = (res[/*data*/ 'd'] as string) || 'error';\n\n if (this.authToken_ === token) {\n if (status === 'ok') {\n this.invalidAuthTokenCount_ = 0;\n } else {\n // Triggers reconnect and force refresh for auth token\n this.onAuthRevoked_(status, data);\n }\n }\n }\n );\n }\n }\n\n /**\n * @inheritDoc\n */\n unlisten(query: Query, tag: number | null) {\n const pathString = query.path.toString();\n const queryId = query.queryIdentifier();\n\n this.log_('Unlisten called for ' + pathString + ' ' + queryId);\n\n assert(\n query.getQueryParams().isDefault() ||\n !query.getQueryParams().loadsAllData(),\n 'unlisten() called for non-default but complete query'\n );\n const listen = this.removeListen_(pathString, queryId);\n if (listen && this.connected_) {\n this.sendUnlisten_(pathString, queryId, query.queryObject(), tag);\n }\n }\n\n private sendUnlisten_(\n pathString: string,\n queryId: string,\n queryObj: object,\n tag: number | null\n ) {\n this.log_('Unlisten on ' + pathString + ' for ' + queryId);\n\n const req: { [k: string]: unknown } = { /*path*/ p: pathString };\n const action = 'n';\n // Only bother sending queryId if it's non-default.\n if (tag) {\n req['q'] = queryObj;\n req['t'] = tag;\n }\n\n this.sendRequest(action, req);\n }\n\n /**\n * @inheritDoc\n */\n onDisconnectPut(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void\n ) {\n if (this.connected_) {\n this.sendOnDisconnect_('o', pathString, data, onComplete);\n } else {\n this.onDisconnectRequestQueue_.push({\n pathString,\n action: 'o',\n data,\n onComplete\n });\n }\n }\n\n /**\n * @inheritDoc\n */\n onDisconnectMerge(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void\n ) {\n if (this.connected_) {\n this.sendOnDisconnect_('om', pathString, data, onComplete);\n } else {\n this.onDisconnectRequestQueue_.push({\n pathString,\n action: 'om',\n data,\n onComplete\n });\n }\n }\n\n /**\n * @inheritDoc\n */\n onDisconnectCancel(\n pathString: string,\n onComplete?: (a: string, b: string) => void\n ) {\n if (this.connected_) {\n this.sendOnDisconnect_('oc', pathString, null, onComplete);\n } else {\n this.onDisconnectRequestQueue_.push({\n pathString,\n action: 'oc',\n data: null,\n onComplete\n });\n }\n }\n\n private sendOnDisconnect_(\n action: string,\n pathString: string,\n data: unknown,\n onComplete: (a: string, b: string) => void\n ) {\n const request = { /*path*/ p: pathString, /*data*/ d: data };\n this.log_('onDisconnect ' + action, request);\n this.sendRequest(action, request, (response: { [k: string]: unknown }) => {\n if (onComplete) {\n setTimeout(() => {\n onComplete(\n response[/*status*/ 's'] as string,\n response[/* data */ 'd'] as string\n );\n }, Math.floor(0));\n }\n });\n }\n\n /**\n * @inheritDoc\n */\n put(\n pathString: string,\n data: unknown,\n onComplete?: (a: string, b: string) => void,\n hash?: string\n ) {\n this.putInternal('p', pathString, data, onComplete, hash);\n }\n\n /**\n * @inheritDoc\n */\n merge(\n pathString: string,\n data: unknown,\n onComplete: (a: string, b: string | null) => void,\n hash?: string\n ) {\n this.putInternal('m', pathString, data, onComplete, hash);\n }\n\n putInternal(\n action: string,\n pathString: string,\n data: unknown,\n onComplete: (a: string, b: string | null) => void,\n hash?: string\n ) {\n const request: { [k: string]: unknown } = {\n /*path*/ p: pathString,\n /*data*/ d: data\n };\n\n if (hash !== undefined) {\n request[/*hash*/ 'h'] = hash;\n }\n\n // TODO: Only keep track of the most recent put for a given path?\n this.outstandingPuts_.push({\n action,\n request,\n onComplete\n });\n\n this.outstandingPutCount_++;\n const index = this.outstandingPuts_.length - 1;\n\n if (this.connected_) {\n this.sendPut_(index);\n } else {\n this.log_('Buffering put: ' + pathString);\n }\n }\n\n private sendPut_(index: number) {\n const action = this.outstandingPuts_[index].action;\n const request = this.outstandingPuts_[index].request;\n const onComplete = this.outstandingPuts_[index].onComplete;\n this.outstandingPuts_[index].queued = this.connected_;\n\n this.sendRequest(action, request, (message: { [k: string]: unknown }) => {\n this.log_(action + ' response', message);\n\n delete this.outstandingPuts_[index];\n this.outstandingPutCount_--;\n\n // Clean up array occasionally.\n if (this.outstandingPutCount_ === 0) {\n this.outstandingPuts_ = [];\n }\n\n if (onComplete) {\n onComplete(\n message[/*status*/ 's'] as string,\n message[/* data */ 'd'] as string\n );\n }\n });\n }\n\n /**\n * @inheritDoc\n */\n reportStats(stats: { [k: string]: unknown }) {\n // If we're not connected, we just drop the stats.\n if (this.connected_) {\n const request = { /*counters*/ c: stats };\n this.log_('reportStats', request);\n\n this.sendRequest(/*stats*/ 's', request, result => {\n const status = result[/*status*/ 's'];\n if (status !== 'ok') {\n const errorReason = result[/* data */ 'd'];\n this.log_('reportStats', 'Error sending stats: ' + errorReason);\n }\n });\n }\n }\n\n private onDataMessage_(message: { [k: string]: unknown }) {\n if ('r' in message) {\n // this is a response\n this.log_('from server: ' + stringify(message));\n const reqNum = message['r'] as string;\n const onResponse = this.requestCBHash_[reqNum];\n if (onResponse) {\n delete this.requestCBHash_[reqNum];\n onResponse(message[/*body*/ 'b']);\n }\n } else if ('error' in message) {\n throw 'A server-side error has occurred: ' + message['error'];\n } else if ('a' in message) {\n // a and b are action and body, respectively\n this.onDataPush_(message['a'] as string, message['b'] as {});\n }\n }\n\n private onDataPush_(action: string, body: { [k: string]: unknown }) {\n this.log_('handleServerMessage', action, body);\n if (action === 'd') {\n this.onDataUpdate_(\n body[/*path*/ 'p'] as string,\n body[/*data*/ 'd'],\n /*isMerge*/ false,\n body['t'] as number\n );\n } else if (action === 'm') {\n this.onDataUpdate_(\n body[/*path*/ 'p'] as string,\n body[/*data*/ 'd'],\n /*isMerge=*/ true,\n body['t'] as number\n );\n } else if (action === 'c') {\n this.onListenRevoked_(\n body[/*path*/ 'p'] as string,\n body[/*query*/ 'q'] as unknown[]\n );\n } else if (action === 'ac') {\n this.onAuthRevoked_(\n body[/*status code*/ 's'] as string,\n body[/* explanation */ 'd'] as string\n );\n } else if (action === 'sd') {\n this.onSecurityDebugPacket_(body);\n } else {\n error(\n 'Unrecognized action received from server: ' +\n stringify(action) +\n '\\nAre you using the latest client?'\n );\n }\n }\n\n private onReady_(timestamp: number, sessionId: string) {\n this.log_('connection ready');\n this.connected_ = true;\n this.lastConnectionEstablishedTime_ = new Date().getTime();\n this.handleTimestamp_(timestamp);\n this.lastSessionId = sessionId;\n if (this.firstConnection_) {\n this.sendConnectStats_();\n }\n this.restoreState_();\n this.firstConnection_ = false;\n this.onConnectStatus_(true);\n }\n\n private scheduleConnect_(timeout: number) {\n assert(\n !this.realtime_,\n \"Scheduling a connect when we're already connected/ing?\"\n );\n\n if (this.establishConnectionTimer_) {\n clearTimeout(this.establishConnectionTimer_);\n }\n\n // NOTE: Even when timeout is 0, it's important to do a setTimeout to work around an infuriating \"Security Error\" in\n // Firefox when trying to write to our long-polling iframe in some scenarios (e.g. Forge or our unit tests).\n\n this.establishConnectionTimer_ = setTimeout(() => {\n this.establishConnectionTimer_ = null;\n this.establishConnection_();\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }, Math.floor(timeout)) as any;\n }\n\n private onVisible_(visible: boolean) {\n // NOTE: Tabbing away and back to a window will defeat our reconnect backoff, but I think that's fine.\n if (\n visible &&\n !this.visible_ &&\n this.reconnectDelay_ === this.maxReconnectDelay_\n ) {\n this.log_('Window became visible. Reducing delay.');\n this.reconnectDelay_ = RECONNECT_MIN_DELAY;\n\n if (!this.realtime_) {\n this.scheduleConnect_(0);\n }\n }\n this.visible_ = visible;\n }\n\n private onOnline_(online: boolean) {\n if (online) {\n this.log_('Browser went online.');\n this.reconnectDelay_ = RECONNECT_MIN_DELAY;\n if (!this.realtime_) {\n this.scheduleConnect_(0);\n }\n } else {\n this.log_('Browser went offline. Killing connection.');\n if (this.realtime_) {\n this.realtime_.close();\n }\n }\n }\n\n private onRealtimeDisconnect_() {\n this.log_('data client disconnected');\n this.connected_ = false;\n this.realtime_ = null;\n\n // Since we don't know if our sent transactions succeeded or not, we need to cancel them.\n this.cancelSentTransactions_();\n\n // Clear out the pending requests.\n this.requestCBHash_ = {};\n\n if (this.shouldReconnect_()) {\n if (!this.visible_) {\n this.log_(\"Window isn't visible. Delaying reconnect.\");\n this.reconnectDelay_ = this.maxReconnectDelay_;\n this.lastConnectionAttemptTime_ = new Date().getTime();\n } else if (this.lastConnectionEstablishedTime_) {\n // If we've been connected long enough, reset reconnect delay to minimum.\n const timeSinceLastConnectSucceeded =\n new Date().getTime() - this.lastConnectionEstablishedTime_;\n if (timeSinceLastConnectSucceeded > RECONNECT_DELAY_RESET_TIMEOUT) {\n this.reconnectDelay_ = RECONNECT_MIN_DELAY;\n }\n this.lastConnectionEstablishedTime_ = null;\n }\n\n const timeSinceLastConnectAttempt =\n new Date().getTime() - this.lastConnectionAttemptTime_;\n let reconnectDelay = Math.max(\n 0,\n this.reconnectDelay_ - timeSinceLastConnectAttempt\n );\n reconnectDelay = Math.random() * reconnectDelay;\n\n this.log_('Trying to reconnect in ' + reconnectDelay + 'ms');\n this.scheduleConnect_(reconnectDelay);\n\n // Adjust reconnect delay for next time.\n this.reconnectDelay_ = Math.min(\n this.maxReconnectDelay_,\n this.reconnectDelay_ * RECONNECT_DELAY_MULTIPLIER\n );\n }\n this.onConnectStatus_(false);\n }\n\n private establishConnection_() {\n if (this.shouldReconnect_()) {\n this.log_('Making a connection attempt');\n this.lastConnectionAttemptTime_ = new Date().getTime();\n this.lastConnectionEstablishedTime_ = null;\n const onDataMessage = this.onDataMessage_.bind(this);\n const onReady = this.onReady_.bind(this);\n const onDisconnect = this.onRealtimeDisconnect_.bind(this);\n const connId = this.id + ':' + PersistentConnection.nextConnectionId_++;\n const self = this;\n const lastSessionId = this.lastSessionId;\n let canceled = false;\n let connection: Connection | null = null;\n const closeFn = function() {\n if (connection) {\n connection.close();\n } else {\n canceled = true;\n onDisconnect();\n }\n };\n const sendRequestFn = function(msg: object) {\n assert(\n connection,\n \"sendRequest call when we're not connected not allowed.\"\n );\n connection.sendRequest(msg);\n };\n\n this.realtime_ = {\n close: closeFn,\n sendRequest: sendRequestFn\n };\n\n const forceRefresh = this.forceTokenRefresh_;\n this.forceTokenRefresh_ = false;\n\n // First fetch auth token, and establish connection after fetching the token was successful\n this.authTokenProvider_\n .getToken(forceRefresh)\n .then(result => {\n if (!canceled) {\n log('getToken() completed. Creating connection.');\n self.authToken_ = result && result.accessToken;\n connection = new Connection(\n connId,\n self.repoInfo_,\n onDataMessage,\n onReady,\n onDisconnect,\n /* onKill= */ reason => {\n warn(reason + ' (' + self.repoInfo_.toString() + ')');\n self.interrupt(SERVER_KILL_INTERRUPT_REASON);\n },\n lastSessionId\n );\n } else {\n log('getToken() completed but was canceled');\n }\n })\n .then(null, error => {\n self.log_('Failed to get token: ' + error);\n if (!canceled) {\n if (CONSTANTS.NODE_ADMIN) {\n // This may be a critical error for the Admin Node.js SDK, so log a warning.\n // But getToken() may also just have temporarily failed, so we still want to\n // continue retrying.\n warn(error);\n }\n closeFn();\n }\n });\n }\n }\n\n interrupt(reason: string) {\n log('Interrupting connection for reason: ' + reason);\n this.interruptReasons_[reason] = true;\n if (this.realtime_) {\n this.realtime_.close();\n } else {\n if (this.establishConnectionTimer_) {\n clearTimeout(this.establishConnectionTimer_);\n this.establishConnectionTimer_ = null;\n }\n if (this.connected_) {\n this.onRealtimeDisconnect_();\n }\n }\n }\n\n resume(reason: string) {\n log('Resuming connection for reason: ' + reason);\n delete this.interruptReasons_[reason];\n if (isEmpty(this.interruptReasons_)) {\n this.reconnectDelay_ = RECONNECT_MIN_DELAY;\n if (!this.realtime_) {\n this.scheduleConnect_(0);\n }\n }\n }\n\n private handleTimestamp_(timestamp: number) {\n const delta = timestamp - new Date().getTime();\n this.onServerInfoUpdate_({ serverTimeOffset: delta });\n }\n\n private cancelSentTransactions_() {\n for (let i = 0; i < this.outstandingPuts_.length; i++) {\n const put = this.outstandingPuts_[i];\n if (put && /*hash*/ 'h' in put.request && put.queued) {\n if (put.onComplete) {\n put.onComplete('disconnect');\n }\n\n delete this.outstandingPuts_[i];\n this.outstandingPutCount_--;\n }\n }\n\n // Clean up array occasionally.\n if (this.outstandingPutCount_ === 0) {\n this.outstandingPuts_ = [];\n }\n }\n\n private onListenRevoked_(pathString: string, query?: unknown[]) {\n // Remove the listen and manufacture a \"permission_denied\" error for the failed listen.\n let queryId;\n if (!query) {\n queryId = 'default';\n } else {\n queryId = query.map(q => ObjectToUniqueKey(q)).join('$');\n }\n const listen = this.removeListen_(pathString, queryId);\n if (listen && listen.onComplete) {\n listen.onComplete('permission_denied');\n }\n }\n\n private removeListen_(pathString: string, queryId: string): ListenSpec {\n const normalizedPathString = new Path(pathString).toString(); // normalize path.\n let listen;\n if (this.listens.has(normalizedPathString)) {\n const map = this.listens.get(normalizedPathString)!;\n listen = map.get(queryId);\n map.delete(queryId);\n if (map.size === 0) {\n this.listens.delete(normalizedPathString);\n }\n } else {\n // all listens for this path has already been removed\n listen = undefined;\n }\n return listen;\n }\n\n private onAuthRevoked_(statusCode: string, explanation: string) {\n log('Auth token revoked: ' + statusCode + '/' + explanation);\n this.authToken_ = null;\n this.forceTokenRefresh_ = true;\n this.realtime_.close();\n if (statusCode === 'invalid_token' || statusCode === 'permission_denied') {\n // We'll wait a couple times before logging the warning / increasing the\n // retry period since oauth tokens will report as \"invalid\" if they're\n // just expired. Plus there may be transient issues that resolve themselves.\n this.invalidAuthTokenCount_++;\n if (this.invalidAuthTokenCount_ >= INVALID_AUTH_TOKEN_THRESHOLD) {\n // Set a long reconnect delay because recovery is unlikely\n this.reconnectDelay_ = RECONNECT_MAX_DELAY_FOR_ADMINS;\n\n // Notify the auth token provider that the token is invalid, which will log\n // a warning\n this.authTokenProvider_.notifyForInvalidToken();\n }\n }\n }\n\n private onSecurityDebugPacket_(body: { [k: string]: unknown }) {\n if (this.securityDebugCallback_) {\n this.securityDebugCallback_(body);\n } else {\n if ('msg' in body) {\n console.log(\n 'FIREBASE: ' + (body['msg'] as string).replace('\\n', '\\nFIREBASE: ')\n );\n }\n }\n }\n\n private restoreState_() {\n //Re-authenticate ourselves if we have a credential stored.\n this.tryAuth();\n\n // Puts depend on having received the corresponding data update from the server before they complete, so we must\n // make sure to send listens before puts.\n for (const queries of this.listens.values()) {\n for (const listenSpec of queries.values()) {\n this.sendListen_(listenSpec);\n }\n }\n\n for (let i = 0; i < this.outstandingPuts_.length; i++) {\n if (this.outstandingPuts_[i]) {\n this.sendPut_(i);\n }\n }\n\n while (this.onDisconnectRequestQueue_.length) {\n const request = this.onDisconnectRequestQueue_.shift();\n this.sendOnDisconnect_(\n request.action,\n request.pathString,\n request.data,\n request.onComplete\n );\n }\n }\n\n /**\n * Sends client stats for first connection\n */\n private sendConnectStats_() {\n const stats: { [k: string]: number } = {};\n\n let clientName = 'js';\n if (CONSTANTS.NODE_ADMIN) {\n clientName = 'admin_node';\n } else if (CONSTANTS.NODE_CLIENT) {\n clientName = 'node';\n }\n\n stats['sdk.' + clientName + '.' + SDK_VERSION.replace(/\\./g, '-')] = 1;\n\n if (isMobileCordova()) {\n stats['framework.cordova'] = 1;\n } else if (isReactNative()) {\n stats['framework.reactnative'] = 1;\n }\n this.reportStats(stats);\n }\n\n private shouldReconnect_(): boolean {\n const online = OnlineMonitor.getInstance().currentlyOnline();\n return isEmpty(this.interruptReasons_) && online;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, jsonEval, safeGet, querystring } from '@firebase/util';\nimport { logWrapper, warn } from './util/util';\n\nimport { ServerActions } from './ServerActions';\nimport { RepoInfo } from './RepoInfo';\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { Query } from '../api/Query';\n\n/**\n * An implementation of ServerActions that communicates with the server via REST requests.\n * This is mostly useful for compatibility with crawlers, where we don't want to spin up a full\n * persistent connection (using WebSockets or long-polling)\n */\nexport class ReadonlyRestClient extends ServerActions {\n reportStats(stats: { [k: string]: unknown }): void {\n throw new Error('Method not implemented.');\n }\n\n /** @private {function(...[*])} */\n private log_: (...args: unknown[]) => void = logWrapper('p:rest:');\n\n /**\n * We don't actually need to track listens, except to prevent us calling an onComplete for a listen\n * that's been removed. :-/\n *\n * @private {!Object.}\n */\n private listens_: { [k: string]: object } = {};\n\n /**\n * @param {!Query} query\n * @param {?number=} tag\n * @return {string}\n * @private\n */\n static getListenId_(query: Query, tag?: number | null): string {\n if (tag !== undefined) {\n return 'tag$' + tag;\n } else {\n assert(\n query.getQueryParams().isDefault(),\n \"should have a tag if it's not a default query.\"\n );\n return query.path.toString();\n }\n }\n\n /**\n * @param {!RepoInfo} repoInfo_ Data about the namespace we are connecting to\n * @param {function(string, *, boolean, ?number)} onDataUpdate_ A callback for new data from the server\n * @param {AuthTokenProvider} authTokenProvider_\n * @implements {ServerActions}\n */\n constructor(\n private repoInfo_: RepoInfo,\n private onDataUpdate_: (\n a: string,\n b: unknown,\n c: boolean,\n d: number | null\n ) => void,\n private authTokenProvider_: AuthTokenProvider\n ) {\n super();\n }\n\n /** @inheritDoc */\n listen(\n query: Query,\n currentHashFn: () => string,\n tag: number | null,\n onComplete: (a: string, b: unknown) => void\n ) {\n const pathString = query.path.toString();\n this.log_(\n 'Listen called for ' + pathString + ' ' + query.queryIdentifier()\n );\n\n // Mark this listener so we can tell if it's removed.\n const listenId = ReadonlyRestClient.getListenId_(query, tag);\n const thisListen = {};\n this.listens_[listenId] = thisListen;\n\n const queryStringParameters = query\n .getQueryParams()\n .toRestQueryStringParameters();\n\n this.restRequest_(\n pathString + '.json',\n queryStringParameters,\n (error, result) => {\n let data = result;\n\n if (error === 404) {\n data = null;\n error = null;\n }\n\n if (error === null) {\n this.onDataUpdate_(pathString, data, /*isMerge=*/ false, tag);\n }\n\n if (safeGet(this.listens_, listenId) === thisListen) {\n let status;\n if (!error) {\n status = 'ok';\n } else if (error === 401) {\n status = 'permission_denied';\n } else {\n status = 'rest_error:' + error;\n }\n\n onComplete(status, null);\n }\n }\n );\n }\n\n /** @inheritDoc */\n unlisten(query: Query, tag: number | null) {\n const listenId = ReadonlyRestClient.getListenId_(query, tag);\n delete this.listens_[listenId];\n }\n\n /** @inheritDoc */\n refreshAuthToken(token: string) {\n // no-op since we just always call getToken.\n }\n\n /**\n * Performs a REST request to the given path, with the provided query string parameters,\n * and any auth credentials we have.\n *\n * @param {!string} pathString\n * @param {!Object.} queryStringParameters\n * @param {?function(?number, *=)} callback\n * @private\n */\n private restRequest_(\n pathString: string,\n queryStringParameters: { [k: string]: string | number } = {},\n callback: ((a: number | null, b?: unknown) => void) | null\n ) {\n queryStringParameters['format'] = 'export';\n\n this.authTokenProvider_\n .getToken(/*forceRefresh=*/ false)\n .then(authTokenData => {\n const authToken = authTokenData && authTokenData.accessToken;\n if (authToken) {\n queryStringParameters['auth'] = authToken;\n }\n\n const url =\n (this.repoInfo_.secure ? 'https://' : 'http://') +\n this.repoInfo_.host +\n pathString +\n '?' +\n 'ns=' +\n this.repoInfo_.namespace +\n querystring(queryStringParameters);\n\n this.log_('Sending REST request for ' + url);\n const xhr = new XMLHttpRequest();\n xhr.onreadystatechange = () => {\n if (callback && xhr.readyState === 4) {\n this.log_(\n 'REST Response for ' + url + ' received. status:',\n xhr.status,\n 'response:',\n xhr.responseText\n );\n let res = null;\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n res = jsonEval(xhr.responseText);\n } catch (e) {\n warn(\n 'Failed to parse JSON response for ' +\n url +\n ': ' +\n xhr.responseText\n );\n }\n callback(null, res);\n } else {\n // 401 and 404 are expected.\n if (xhr.status !== 401 && xhr.status !== 404) {\n warn(\n 'Got unsuccessful REST response for ' +\n url +\n ' Status: ' +\n xhr.status\n );\n }\n callback(xhr.status);\n }\n callback = null;\n }\n };\n\n xhr.open('GET', url, /*asynchronous=*/ true);\n xhr.send();\n });\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Returns a querystring-formatted string (e.g. &arg=val&arg2=val2) from a\n * params object (e.g. {arg: 'val', arg2: 'val2'})\n * Note: You must prepend it with ? when adding it to a URL.\n */\nexport function querystring(querystringParams: {\n [key: string]: string | number;\n}): string {\n const params = [];\n for (const [key, value] of Object.entries(querystringParams)) {\n if (Array.isArray(value)) {\n value.forEach(arrayVal => {\n params.push(\n encodeURIComponent(key) + '=' + encodeURIComponent(arrayVal)\n );\n });\n } else {\n params.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));\n }\n }\n return params.length ? '&' + params.join('&') : '';\n}\n\n/**\n * Decodes a querystring (e.g. ?arg=val&arg2=val2) into a params object\n * (e.g. {arg: 'val', arg2: 'val2'})\n */\nexport function querystringDecode(querystring: string): object {\n const obj: { [key: string]: unknown } = {};\n const tokens = querystring.replace(/^\\?/, '').split('&');\n\n tokens.forEach(token => {\n if (token) {\n const key = token.split('=');\n obj[key[0]] = key[1];\n }\n });\n return obj;\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n generateWithValues,\n resolveDeferredValueSnapshot,\n resolveDeferredValueTree\n} from './util/ServerValues';\nimport { nodeFromJSON } from './snap/nodeFromJSON';\nimport { Path } from './util/Path';\nimport { SparseSnapshotTree } from './SparseSnapshotTree';\nimport { SyncTree } from './SyncTree';\nimport { SnapshotHolder } from './SnapshotHolder';\nimport { stringify, map, isEmpty } from '@firebase/util';\nimport { beingCrawled, each, exceptionGuard, warn, log } from './util/util';\n\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { StatsManager } from './stats/StatsManager';\nimport { StatsReporter } from './stats/StatsReporter';\nimport { StatsListener } from './stats/StatsListener';\nimport { EventQueue } from './view/EventQueue';\nimport { PersistentConnection } from './PersistentConnection';\nimport { ReadonlyRestClient } from './ReadonlyRestClient';\nimport { FirebaseApp } from '@firebase/app-types';\nimport { RepoInfo } from './RepoInfo';\nimport { Database } from '../api/Database';\nimport { ServerActions } from './ServerActions';\nimport { Query } from '../api/Query';\nimport { EventRegistration } from './view/EventRegistration';\nimport { StatsCollection } from './stats/StatsCollection';\nimport { Event } from './view/Event';\nimport { Node } from './snap/Node';\nimport { FirebaseAuthInternalName } from '@firebase/auth-interop-types';\nimport { Provider } from '@firebase/component';\nimport { Indexable } from './util/misc';\n\nconst INTERRUPT_REASON = 'repo_interrupt';\n\n/**\n * A connection to a single data repository.\n */\nexport class Repo {\n dataUpdateCount = 0;\n private infoSyncTree_: SyncTree;\n private serverSyncTree_: SyncTree;\n\n private stats_: StatsCollection;\n private statsListener_: StatsListener | null = null;\n private eventQueue_ = new EventQueue();\n private nextWriteId_ = 1;\n private server_: ServerActions;\n private statsReporter_: StatsReporter;\n private transactionsInit_: () => void;\n private infoData_: SnapshotHolder;\n private abortTransactions_: (path: Path) => Path;\n private rerunTransactions_: (changedPath: Path) => Path;\n private interceptServerDataCallback_:\n | ((a: string, b: unknown) => void)\n | null = null;\n private __database: Database;\n\n /** A list of data pieces and paths to be set when this client disconnects. */\n private onDisconnect_ = new SparseSnapshotTree();\n\n // TODO: This should be @private but it's used by test_access.js and internal.js\n persistentConnection_: PersistentConnection | null = null;\n\n constructor(\n public repoInfo_: RepoInfo,\n forceRestClient: boolean,\n public app: FirebaseApp,\n authProvider: Provider\n ) {\n const authTokenProvider = new AuthTokenProvider(app, authProvider);\n\n this.stats_ = StatsManager.getCollection(repoInfo_);\n\n if (forceRestClient || beingCrawled()) {\n this.server_ = new ReadonlyRestClient(\n this.repoInfo_,\n this.onDataUpdate_.bind(this),\n authTokenProvider\n );\n\n // Minor hack: Fire onConnect immediately, since there's no actual connection.\n setTimeout(this.onConnectStatus_.bind(this, true), 0);\n } else {\n const authOverride = app.options['databaseAuthVariableOverride'];\n // Validate authOverride\n if (typeof authOverride !== 'undefined' && authOverride !== null) {\n if (typeof authOverride !== 'object') {\n throw new Error(\n 'Only objects are supported for option databaseAuthVariableOverride'\n );\n }\n try {\n stringify(authOverride);\n } catch (e) {\n throw new Error('Invalid authOverride provided: ' + e);\n }\n }\n\n this.persistentConnection_ = new PersistentConnection(\n this.repoInfo_,\n this.onDataUpdate_.bind(this),\n this.onConnectStatus_.bind(this),\n this.onServerInfoUpdate_.bind(this),\n authTokenProvider,\n authOverride\n );\n\n this.server_ = this.persistentConnection_;\n }\n\n authTokenProvider.addTokenChangeListener(token => {\n this.server_.refreshAuthToken(token);\n });\n\n // In the case of multiple Repos for the same repoInfo (i.e. there are multiple Firebase.Contexts being used),\n // we only want to create one StatsReporter. As such, we'll report stats over the first Repo created.\n this.statsReporter_ = StatsManager.getOrCreateReporter(\n repoInfo_,\n () => new StatsReporter(this.stats_, this.server_)\n );\n\n this.transactionsInit_();\n\n // Used for .info.\n this.infoData_ = new SnapshotHolder();\n this.infoSyncTree_ = new SyncTree({\n startListening: (query, tag, currentHashFn, onComplete) => {\n let infoEvents: Event[] = [];\n const node = this.infoData_.getNode(query.path);\n // This is possibly a hack, but we have different semantics for .info endpoints. We don't raise null events\n // on initial data...\n if (!node.isEmpty()) {\n infoEvents = this.infoSyncTree_.applyServerOverwrite(\n query.path,\n node\n );\n setTimeout(() => {\n onComplete('ok');\n }, 0);\n }\n return infoEvents;\n },\n stopListening: () => {}\n });\n this.updateInfo_('connected', false);\n\n this.serverSyncTree_ = new SyncTree({\n startListening: (query, tag, currentHashFn, onComplete) => {\n this.server_.listen(query, currentHashFn, tag, (status, data) => {\n const events = onComplete(status, data);\n this.eventQueue_.raiseEventsForChangedPath(query.path, events);\n });\n // No synchronous events for network-backed sync trees\n return [];\n },\n stopListening: (query, tag) => {\n this.server_.unlisten(query, tag);\n }\n });\n }\n\n /**\n * @return The URL corresponding to the root of this Firebase.\n */\n toString(): string {\n return (\n (this.repoInfo_.secure ? 'https://' : 'http://') + this.repoInfo_.host\n );\n }\n\n /**\n * @return The namespace represented by the repo.\n */\n name(): string {\n return this.repoInfo_.namespace;\n }\n\n /**\n * @return The time in milliseconds, taking the server offset into account if we have one.\n */\n serverTime(): number {\n const offsetNode = this.infoData_.getNode(\n new Path('.info/serverTimeOffset')\n );\n const offset = (offsetNode.val() as number) || 0;\n return new Date().getTime() + offset;\n }\n\n /**\n * Generate ServerValues using some variables from the repo object.\n */\n generateServerValues(): Indexable {\n return generateWithValues({\n timestamp: this.serverTime()\n });\n }\n\n /**\n * Called by realtime when we get new messages from the server.\n */\n private onDataUpdate_(\n pathString: string,\n data: unknown,\n isMerge: boolean,\n tag: number | null\n ) {\n // For testing.\n this.dataUpdateCount++;\n const path = new Path(pathString);\n data = this.interceptServerDataCallback_\n ? this.interceptServerDataCallback_(pathString, data)\n : data;\n let events = [];\n if (tag) {\n if (isMerge) {\n const taggedChildren = map(\n data as { [k: string]: unknown },\n (raw: unknown) => nodeFromJSON(raw)\n );\n events = this.serverSyncTree_.applyTaggedQueryMerge(\n path,\n taggedChildren,\n tag\n );\n } else {\n const taggedSnap = nodeFromJSON(data);\n events = this.serverSyncTree_.applyTaggedQueryOverwrite(\n path,\n taggedSnap,\n tag\n );\n }\n } else if (isMerge) {\n const changedChildren = map(\n data as { [k: string]: unknown },\n (raw: unknown) => nodeFromJSON(raw)\n );\n events = this.serverSyncTree_.applyServerMerge(path, changedChildren);\n } else {\n const snap = nodeFromJSON(data);\n events = this.serverSyncTree_.applyServerOverwrite(path, snap);\n }\n let affectedPath = path;\n if (events.length > 0) {\n // Since we have a listener outstanding for each transaction, receiving any events\n // is a proxy for some change having occurred.\n affectedPath = this.rerunTransactions_(path);\n }\n this.eventQueue_.raiseEventsForChangedPath(affectedPath, events);\n }\n\n // TODO: This should be @private but it's used by test_access.js and internal.js\n interceptServerData_(callback: ((a: string, b: unknown) => unknown) | null) {\n this.interceptServerDataCallback_ = callback;\n }\n\n private onConnectStatus_(connectStatus: boolean) {\n this.updateInfo_('connected', connectStatus);\n if (connectStatus === false) {\n this.runOnDisconnectEvents_();\n }\n }\n\n private onServerInfoUpdate_(updates: object) {\n each(updates, (key: string, value: unknown) => {\n this.updateInfo_(key, value);\n });\n }\n\n private updateInfo_(pathString: string, value: unknown) {\n const path = new Path('/.info/' + pathString);\n const newNode = nodeFromJSON(value);\n this.infoData_.updateSnapshot(path, newNode);\n const events = this.infoSyncTree_.applyServerOverwrite(path, newNode);\n this.eventQueue_.raiseEventsForChangedPath(path, events);\n }\n\n private getNextWriteId_(): number {\n return this.nextWriteId_++;\n }\n\n setWithPriority(\n path: Path,\n newVal: unknown,\n newPriority: number | string | null,\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n this.log_('set', {\n path: path.toString(),\n value: newVal,\n priority: newPriority\n });\n\n // TODO: Optimize this behavior to either (a) store flag to skip resolving where possible and / or\n // (b) store unresolved paths on JSON parse\n const serverValues = this.generateServerValues();\n const newNodeUnresolved = nodeFromJSON(newVal, newPriority);\n const newNode = resolveDeferredValueSnapshot(\n newNodeUnresolved,\n serverValues\n );\n\n const writeId = this.getNextWriteId_();\n const events = this.serverSyncTree_.applyUserOverwrite(\n path,\n newNode,\n writeId,\n true\n );\n this.eventQueue_.queueEvents(events);\n this.server_.put(\n path.toString(),\n newNodeUnresolved.val(/*export=*/ true),\n (status, errorReason) => {\n const success = status === 'ok';\n if (!success) {\n warn('set at ' + path + ' failed: ' + status);\n }\n\n const clearEvents = this.serverSyncTree_.ackUserWrite(\n writeId,\n !success\n );\n this.eventQueue_.raiseEventsForChangedPath(path, clearEvents);\n this.callOnCompleteCallback(onComplete, status, errorReason);\n }\n );\n const affectedPath = this.abortTransactions_(path);\n this.rerunTransactions_(affectedPath);\n // We queued the events above, so just flush the queue here\n this.eventQueue_.raiseEventsForChangedPath(affectedPath, []);\n }\n\n update(\n path: Path,\n childrenToMerge: { [k: string]: unknown },\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n this.log_('update', { path: path.toString(), value: childrenToMerge });\n\n // Start with our existing data and merge each child into it.\n let empty = true;\n const serverValues = this.generateServerValues();\n const changedChildren: { [k: string]: Node } = {};\n each(childrenToMerge, (changedKey: string, changedValue: unknown) => {\n empty = false;\n const newNodeUnresolved = nodeFromJSON(changedValue);\n changedChildren[changedKey] = resolveDeferredValueSnapshot(\n newNodeUnresolved,\n serverValues\n );\n });\n\n if (!empty) {\n const writeId = this.getNextWriteId_();\n const events = this.serverSyncTree_.applyUserMerge(\n path,\n changedChildren,\n writeId\n );\n this.eventQueue_.queueEvents(events);\n this.server_.merge(\n path.toString(),\n childrenToMerge,\n (status, errorReason) => {\n const success = status === 'ok';\n if (!success) {\n warn('update at ' + path + ' failed: ' + status);\n }\n\n const clearEvents = this.serverSyncTree_.ackUserWrite(\n writeId,\n !success\n );\n const affectedPath =\n clearEvents.length > 0 ? this.rerunTransactions_(path) : path;\n this.eventQueue_.raiseEventsForChangedPath(affectedPath, clearEvents);\n this.callOnCompleteCallback(onComplete, status, errorReason);\n }\n );\n\n each(childrenToMerge, (changedPath: string) => {\n const affectedPath = this.abortTransactions_(path.child(changedPath));\n this.rerunTransactions_(affectedPath);\n });\n\n // We queued the events above, so just flush the queue here\n this.eventQueue_.raiseEventsForChangedPath(path, []);\n } else {\n log(\"update() called with empty data. Don't do anything.\");\n this.callOnCompleteCallback(onComplete, 'ok');\n }\n }\n\n /**\n * Applies all of the changes stored up in the onDisconnect_ tree.\n */\n private runOnDisconnectEvents_() {\n this.log_('onDisconnectEvents');\n\n const serverValues = this.generateServerValues();\n const resolvedOnDisconnectTree = resolveDeferredValueTree(\n this.onDisconnect_,\n serverValues\n );\n let events: Event[] = [];\n\n resolvedOnDisconnectTree.forEachTree(Path.Empty, (path, snap) => {\n events = events.concat(\n this.serverSyncTree_.applyServerOverwrite(path, snap)\n );\n const affectedPath = this.abortTransactions_(path);\n this.rerunTransactions_(affectedPath);\n });\n\n this.onDisconnect_ = new SparseSnapshotTree();\n this.eventQueue_.raiseEventsForChangedPath(Path.Empty, events);\n }\n\n onDisconnectCancel(\n path: Path,\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n this.server_.onDisconnectCancel(path.toString(), (status, errorReason) => {\n if (status === 'ok') {\n this.onDisconnect_.forget(path);\n }\n this.callOnCompleteCallback(onComplete, status, errorReason);\n });\n }\n\n onDisconnectSet(\n path: Path,\n value: unknown,\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n const newNode = nodeFromJSON(value);\n this.server_.onDisconnectPut(\n path.toString(),\n newNode.val(/*export=*/ true),\n (status, errorReason) => {\n if (status === 'ok') {\n this.onDisconnect_.remember(path, newNode);\n }\n this.callOnCompleteCallback(onComplete, status, errorReason);\n }\n );\n }\n\n onDisconnectSetWithPriority(\n path: Path,\n value: unknown,\n priority: unknown,\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n const newNode = nodeFromJSON(value, priority);\n this.server_.onDisconnectPut(\n path.toString(),\n newNode.val(/*export=*/ true),\n (status, errorReason) => {\n if (status === 'ok') {\n this.onDisconnect_.remember(path, newNode);\n }\n this.callOnCompleteCallback(onComplete, status, errorReason);\n }\n );\n }\n\n onDisconnectUpdate(\n path: Path,\n childrenToMerge: { [k: string]: unknown },\n onComplete: ((status: Error | null, errorReason?: string) => void) | null\n ) {\n if (isEmpty(childrenToMerge)) {\n log(\n \"onDisconnect().update() called with empty data. Don't do anything.\"\n );\n this.callOnCompleteCallback(onComplete, 'ok');\n return;\n }\n\n this.server_.onDisconnectMerge(\n path.toString(),\n childrenToMerge,\n (status, errorReason) => {\n if (status === 'ok') {\n each(childrenToMerge, (childName: string, childNode: unknown) => {\n const newChildNode = nodeFromJSON(childNode);\n this.onDisconnect_.remember(path.child(childName), newChildNode);\n });\n }\n this.callOnCompleteCallback(onComplete, status, errorReason);\n }\n );\n }\n\n addEventCallbackForQuery(query: Query, eventRegistration: EventRegistration) {\n let events;\n if (query.path.getFront() === '.info') {\n events = this.infoSyncTree_.addEventRegistration(\n query,\n eventRegistration\n );\n } else {\n events = this.serverSyncTree_.addEventRegistration(\n query,\n eventRegistration\n );\n }\n this.eventQueue_.raiseEventsAtPath(query.path, events);\n }\n\n removeEventCallbackForQuery(\n query: Query,\n eventRegistration: EventRegistration\n ) {\n // These are guaranteed not to raise events, since we're not passing in a cancelError. However, we can future-proof\n // a little bit by handling the return values anyways.\n let events;\n if (query.path.getFront() === '.info') {\n events = this.infoSyncTree_.removeEventRegistration(\n query,\n eventRegistration\n );\n } else {\n events = this.serverSyncTree_.removeEventRegistration(\n query,\n eventRegistration\n );\n }\n this.eventQueue_.raiseEventsAtPath(query.path, events);\n }\n\n interrupt() {\n if (this.persistentConnection_) {\n this.persistentConnection_.interrupt(INTERRUPT_REASON);\n }\n }\n\n resume() {\n if (this.persistentConnection_) {\n this.persistentConnection_.resume(INTERRUPT_REASON);\n }\n }\n\n stats(showDelta: boolean = false) {\n if (typeof console === 'undefined') {\n return;\n }\n\n let stats: { [k: string]: unknown };\n if (showDelta) {\n if (!this.statsListener_) {\n this.statsListener_ = new StatsListener(this.stats_);\n }\n stats = this.statsListener_.get();\n } else {\n stats = this.stats_.get();\n }\n\n const longestName = Object.keys(stats).reduce(\n (previousValue, currentValue) =>\n Math.max(currentValue.length, previousValue),\n 0\n );\n\n each(stats, (stat: string, value: unknown) => {\n let paddedStat = stat;\n // pad stat names to be the same length (plus 2 extra spaces).\n for (let i = stat.length; i < longestName + 2; i++) {\n paddedStat += ' ';\n }\n console.log(paddedStat + value);\n });\n }\n\n statsIncrementCounter(metric: string) {\n this.stats_.incrementCounter(metric);\n this.statsReporter_.includeStat(metric);\n }\n\n private log_(...varArgs: unknown[]) {\n let prefix = '';\n if (this.persistentConnection_) {\n prefix = this.persistentConnection_.id + ':';\n }\n log(prefix, ...varArgs);\n }\n\n callOnCompleteCallback(\n callback: ((status: Error | null, errorReason?: string) => void) | null,\n status: string,\n errorReason?: string | null\n ) {\n if (callback) {\n exceptionGuard(() => {\n if (status === 'ok') {\n callback(null);\n } else {\n const code = (status || 'error').toUpperCase();\n let message = code;\n if (errorReason) {\n message += ': ' + errorReason;\n }\n\n const error = new Error(message);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (error as any).code = code;\n callback(error);\n }\n });\n }\n }\n\n get database(): Database {\n return this.__database || (this.__database = new Database(this));\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { IndexedFilter } from './IndexedFilter';\nimport { PRIORITY_INDEX } from '../../snap/indexes/PriorityIndex';\nimport { NamedNode, Node } from '../../../core/snap/Node';\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { NodeFilter } from './NodeFilter';\nimport { QueryParams } from '../QueryParams';\nimport { Index } from '../../snap/indexes/Index';\nimport { Path } from '../../util/Path';\nimport { CompleteChildSource } from '../CompleteChildSource';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\n\n/**\n * Filters nodes by range and uses an IndexFilter to track any changes after filtering the node\n *\n * @constructor\n * @implements {NodeFilter}\n */\nexport class RangedFilter implements NodeFilter {\n /**\n * @type {!IndexedFilter}\n * @const\n * @private\n */\n private indexedFilter_: IndexedFilter;\n\n /**\n * @const\n * @type {!Index}\n * @private\n */\n private index_: Index;\n\n /**\n * @const\n * @type {!NamedNode}\n * @private\n */\n private startPost_: NamedNode;\n\n /**\n * @const\n * @type {!NamedNode}\n * @private\n */\n private endPost_: NamedNode;\n\n /**\n * @param {!QueryParams} params\n */\n constructor(params: QueryParams) {\n this.indexedFilter_ = new IndexedFilter(params.getIndex());\n this.index_ = params.getIndex();\n this.startPost_ = RangedFilter.getStartPost_(params);\n this.endPost_ = RangedFilter.getEndPost_(params);\n }\n\n /**\n * @return {!NamedNode}\n */\n getStartPost(): NamedNode {\n return this.startPost_;\n }\n\n /**\n * @return {!NamedNode}\n */\n getEndPost(): NamedNode {\n return this.endPost_;\n }\n\n /**\n * @param {!NamedNode} node\n * @return {boolean}\n */\n matches(node: NamedNode): boolean {\n return (\n this.index_.compare(this.getStartPost(), node) <= 0 &&\n this.index_.compare(node, this.getEndPost()) <= 0\n );\n }\n\n /**\n * @inheritDoc\n */\n updateChild(\n snap: Node,\n key: string,\n newChild: Node,\n affectedPath: Path,\n source: CompleteChildSource,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n if (!this.matches(new NamedNode(key, newChild))) {\n newChild = ChildrenNode.EMPTY_NODE;\n }\n return this.indexedFilter_.updateChild(\n snap,\n key,\n newChild,\n affectedPath,\n source,\n optChangeAccumulator\n );\n }\n\n /**\n * @inheritDoc\n */\n updateFullNode(\n oldSnap: Node,\n newSnap: Node,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n if (newSnap.isLeafNode()) {\n // Make sure we have a children node with the correct index, not a leaf node;\n newSnap = ChildrenNode.EMPTY_NODE;\n }\n let filtered = newSnap.withIndex(this.index_);\n // Don't support priorities on queries\n filtered = filtered.updatePriority(ChildrenNode.EMPTY_NODE);\n const self = this;\n newSnap.forEachChild(PRIORITY_INDEX, (key, childNode) => {\n if (!self.matches(new NamedNode(key, childNode))) {\n filtered = filtered.updateImmediateChild(key, ChildrenNode.EMPTY_NODE);\n }\n });\n return this.indexedFilter_.updateFullNode(\n oldSnap,\n filtered,\n optChangeAccumulator\n );\n }\n\n /**\n * @inheritDoc\n */\n updatePriority(oldSnap: Node, newPriority: Node): Node {\n // Don't support priorities on queries\n return oldSnap;\n }\n\n /**\n * @inheritDoc\n */\n filtersNodes(): boolean {\n return true;\n }\n\n /**\n * @inheritDoc\n */\n getIndexedFilter(): IndexedFilter {\n return this.indexedFilter_;\n }\n\n /**\n * @inheritDoc\n */\n getIndex(): Index {\n return this.index_;\n }\n\n /**\n * @param {!QueryParams} params\n * @return {!NamedNode}\n * @private\n */\n private static getStartPost_(params: QueryParams): NamedNode {\n if (params.hasStart()) {\n const startName = params.getIndexStartName();\n return params.getIndex().makePost(params.getIndexStartValue(), startName);\n } else {\n return params.getIndex().minPost();\n }\n }\n\n /**\n * @param {!QueryParams} params\n * @return {!NamedNode}\n * @private\n */\n private static getEndPost_(params: QueryParams): NamedNode {\n if (params.hasEnd()) {\n const endName = params.getIndexEndName();\n return params.getIndex().makePost(params.getIndexEndValue(), endName);\n } else {\n return params.getIndex().maxPost();\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RangedFilter } from './RangedFilter';\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { Node, NamedNode } from '../../snap/Node';\nimport { assert } from '@firebase/util';\nimport { Change } from '../Change';\nimport { NodeFilter } from './NodeFilter';\nimport { Index } from '../../snap/indexes/Index';\nimport { IndexedFilter } from './IndexedFilter';\nimport { QueryParams } from '../QueryParams';\nimport { Path } from '../../util/Path';\nimport { CompleteChildSource } from '../CompleteChildSource';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\n\n/**\n * Applies a limit and a range to a node and uses RangedFilter to do the heavy lifting where possible\n *\n * @constructor\n * @implements {NodeFilter}\n */\nexport class LimitedFilter implements NodeFilter {\n /**\n * @const\n * @type {RangedFilter}\n * @private\n */\n private readonly rangedFilter_: RangedFilter;\n\n /**\n * @const\n * @type {!Index}\n * @private\n */\n private readonly index_: Index;\n\n /**\n * @const\n * @type {number}\n * @private\n */\n private readonly limit_: number;\n\n /**\n * @const\n * @type {boolean}\n * @private\n */\n private readonly reverse_: boolean;\n\n /**\n * @param {!QueryParams} params\n */\n constructor(params: QueryParams) {\n this.rangedFilter_ = new RangedFilter(params);\n this.index_ = params.getIndex();\n this.limit_ = params.getLimit();\n this.reverse_ = !params.isViewFromLeft();\n }\n\n /**\n * @inheritDoc\n */\n updateChild(\n snap: Node,\n key: string,\n newChild: Node,\n affectedPath: Path,\n source: CompleteChildSource,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n if (!this.rangedFilter_.matches(new NamedNode(key, newChild))) {\n newChild = ChildrenNode.EMPTY_NODE;\n }\n if (snap.getImmediateChild(key).equals(newChild)) {\n // No change\n return snap;\n } else if (snap.numChildren() < this.limit_) {\n return this.rangedFilter_\n .getIndexedFilter()\n .updateChild(\n snap,\n key,\n newChild,\n affectedPath,\n source,\n optChangeAccumulator\n );\n } else {\n return this.fullLimitUpdateChild_(\n snap,\n key,\n newChild,\n source,\n optChangeAccumulator\n );\n }\n }\n\n /**\n * @inheritDoc\n */\n updateFullNode(\n oldSnap: Node,\n newSnap: Node,\n optChangeAccumulator: ChildChangeAccumulator | null\n ): Node {\n let filtered;\n if (newSnap.isLeafNode() || newSnap.isEmpty()) {\n // Make sure we have a children node with the correct index, not a leaf node;\n filtered = ChildrenNode.EMPTY_NODE.withIndex(this.index_);\n } else {\n if (\n this.limit_ * 2 < newSnap.numChildren() &&\n newSnap.isIndexed(this.index_)\n ) {\n // Easier to build up a snapshot, since what we're given has more than twice the elements we want\n filtered = ChildrenNode.EMPTY_NODE.withIndex(this.index_);\n // anchor to the startPost, endPost, or last element as appropriate\n let iterator;\n if (this.reverse_) {\n iterator = (newSnap as ChildrenNode).getReverseIteratorFrom(\n this.rangedFilter_.getEndPost(),\n this.index_\n );\n } else {\n iterator = (newSnap as ChildrenNode).getIteratorFrom(\n this.rangedFilter_.getStartPost(),\n this.index_\n );\n }\n let count = 0;\n while (iterator.hasNext() && count < this.limit_) {\n const next = iterator.getNext();\n let inRange;\n if (this.reverse_) {\n inRange =\n this.index_.compare(this.rangedFilter_.getStartPost(), next) <= 0;\n } else {\n inRange =\n this.index_.compare(next, this.rangedFilter_.getEndPost()) <= 0;\n }\n if (inRange) {\n filtered = filtered.updateImmediateChild(next.name, next.node);\n count++;\n } else {\n // if we have reached the end post, we cannot keep adding elemments\n break;\n }\n }\n } else {\n // The snap contains less than twice the limit. Faster to delete from the snap than build up a new one\n filtered = newSnap.withIndex(this.index_);\n // Don't support priorities on queries\n filtered = filtered.updatePriority(\n ChildrenNode.EMPTY_NODE\n ) as ChildrenNode;\n let startPost;\n let endPost;\n let cmp;\n let iterator;\n if (this.reverse_) {\n iterator = filtered.getReverseIterator(this.index_);\n startPost = this.rangedFilter_.getEndPost();\n endPost = this.rangedFilter_.getStartPost();\n const indexCompare = this.index_.getCompare();\n cmp = (a: NamedNode, b: NamedNode) => indexCompare(b, a);\n } else {\n iterator = filtered.getIterator(this.index_);\n startPost = this.rangedFilter_.getStartPost();\n endPost = this.rangedFilter_.getEndPost();\n cmp = this.index_.getCompare();\n }\n\n let count = 0;\n let foundStartPost = false;\n while (iterator.hasNext()) {\n const next = iterator.getNext();\n if (!foundStartPost && cmp(startPost, next) <= 0) {\n // start adding\n foundStartPost = true;\n }\n const inRange =\n foundStartPost && count < this.limit_ && cmp(next, endPost) <= 0;\n if (inRange) {\n count++;\n } else {\n filtered = filtered.updateImmediateChild(\n next.name,\n ChildrenNode.EMPTY_NODE\n );\n }\n }\n }\n }\n return this.rangedFilter_\n .getIndexedFilter()\n .updateFullNode(oldSnap, filtered, optChangeAccumulator);\n }\n\n /**\n * @inheritDoc\n */\n updatePriority(oldSnap: Node, newPriority: Node): Node {\n // Don't support priorities on queries\n return oldSnap;\n }\n\n /**\n * @inheritDoc\n */\n filtersNodes(): boolean {\n return true;\n }\n\n /**\n * @inheritDoc\n */\n getIndexedFilter(): IndexedFilter {\n return this.rangedFilter_.getIndexedFilter();\n }\n\n /**\n * @inheritDoc\n */\n getIndex(): Index {\n return this.index_;\n }\n\n /**\n * @param {!Node} snap\n * @param {string} childKey\n * @param {!Node} childSnap\n * @param {!CompleteChildSource} source\n * @param {?ChildChangeAccumulator} changeAccumulator\n * @return {!Node}\n * @private\n */\n private fullLimitUpdateChild_(\n snap: Node,\n childKey: string,\n childSnap: Node,\n source: CompleteChildSource,\n changeAccumulator: ChildChangeAccumulator | null\n ): Node {\n // TODO: rename all cache stuff etc to general snap terminology\n let cmp;\n if (this.reverse_) {\n const indexCmp = this.index_.getCompare();\n cmp = (a: NamedNode, b: NamedNode) => indexCmp(b, a);\n } else {\n cmp = this.index_.getCompare();\n }\n const oldEventCache = snap as ChildrenNode;\n assert(oldEventCache.numChildren() === this.limit_, '');\n const newChildNamedNode = new NamedNode(childKey, childSnap);\n const windowBoundary = this.reverse_\n ? oldEventCache.getFirstChild(this.index_)\n : (oldEventCache.getLastChild(this.index_) as NamedNode);\n const inRange = this.rangedFilter_.matches(newChildNamedNode);\n if (oldEventCache.hasChild(childKey)) {\n const oldChildSnap = oldEventCache.getImmediateChild(childKey);\n let nextChild = source.getChildAfterChild(\n this.index_,\n windowBoundary,\n this.reverse_\n );\n while (\n nextChild != null &&\n (nextChild.name === childKey || oldEventCache.hasChild(nextChild.name))\n ) {\n // There is a weird edge case where a node is updated as part of a merge in the write tree, but hasn't\n // been applied to the limited filter yet. Ignore this next child which will be updated later in\n // the limited filter...\n nextChild = source.getChildAfterChild(\n this.index_,\n nextChild,\n this.reverse_\n );\n }\n const compareNext =\n nextChild == null ? 1 : cmp(nextChild, newChildNamedNode);\n const remainsInWindow =\n inRange && !childSnap.isEmpty() && compareNext >= 0;\n if (remainsInWindow) {\n if (changeAccumulator != null) {\n changeAccumulator.trackChildChange(\n Change.childChangedChange(childKey, childSnap, oldChildSnap)\n );\n }\n return oldEventCache.updateImmediateChild(childKey, childSnap);\n } else {\n if (changeAccumulator != null) {\n changeAccumulator.trackChildChange(\n Change.childRemovedChange(childKey, oldChildSnap)\n );\n }\n const newEventCache = oldEventCache.updateImmediateChild(\n childKey,\n ChildrenNode.EMPTY_NODE\n );\n const nextChildInRange =\n nextChild != null && this.rangedFilter_.matches(nextChild);\n if (nextChildInRange) {\n if (changeAccumulator != null) {\n changeAccumulator.trackChildChange(\n Change.childAddedChange(nextChild.name, nextChild.node)\n );\n }\n return newEventCache.updateImmediateChild(\n nextChild.name,\n nextChild.node\n );\n } else {\n return newEventCache;\n }\n }\n } else if (childSnap.isEmpty()) {\n // we're deleting a node, but it was not in the window, so ignore it\n return snap;\n } else if (inRange) {\n if (cmp(windowBoundary, newChildNamedNode) >= 0) {\n if (changeAccumulator != null) {\n changeAccumulator.trackChildChange(\n Change.childRemovedChange(windowBoundary.name, windowBoundary.node)\n );\n changeAccumulator.trackChildChange(\n Change.childAddedChange(childKey, childSnap)\n );\n }\n return oldEventCache\n .updateImmediateChild(childKey, childSnap)\n .updateImmediateChild(windowBoundary.name, ChildrenNode.EMPTY_NODE);\n } else {\n return snap;\n }\n } else {\n return snap;\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, stringify } from '@firebase/util';\nimport { MIN_NAME, MAX_NAME } from '../util/util';\nimport { KEY_INDEX } from '../snap/indexes/KeyIndex';\nimport { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';\nimport { VALUE_INDEX } from '../snap/indexes/ValueIndex';\nimport { PathIndex } from '../snap/indexes/PathIndex';\nimport { IndexedFilter } from './filter/IndexedFilter';\nimport { LimitedFilter } from './filter/LimitedFilter';\nimport { RangedFilter } from './filter/RangedFilter';\nimport { NodeFilter } from './filter/NodeFilter';\nimport { Index } from '../snap/indexes/Index';\n\n/**\n * This class is an immutable-from-the-public-api struct containing a set of query parameters defining a\n * range to be returned for a particular location. It is assumed that validation of parameters is done at the\n * user-facing API level, so it is not done here.\n * @constructor\n */\nexport class QueryParams {\n private limitSet_ = false;\n private startSet_ = false;\n private startNameSet_ = false;\n private endSet_ = false;\n private endNameSet_ = false;\n\n private limit_ = 0;\n private viewFrom_ = '';\n private indexStartValue_: unknown | null = null;\n private indexStartName_ = '';\n private indexEndValue_: unknown | null = null;\n private indexEndName_ = '';\n\n private index_ = PRIORITY_INDEX;\n\n /**\n * Wire Protocol Constants\n * @const\n * @enum {string}\n * @private\n */\n private static readonly WIRE_PROTOCOL_CONSTANTS_ = {\n INDEX_START_VALUE: 'sp',\n INDEX_START_NAME: 'sn',\n INDEX_END_VALUE: 'ep',\n INDEX_END_NAME: 'en',\n LIMIT: 'l',\n VIEW_FROM: 'vf',\n VIEW_FROM_LEFT: 'l',\n VIEW_FROM_RIGHT: 'r',\n INDEX: 'i'\n };\n\n /**\n * REST Query Constants\n * @const\n * @enum {string}\n * @private\n */\n private static readonly REST_QUERY_CONSTANTS_ = {\n ORDER_BY: 'orderBy',\n PRIORITY_INDEX: '$priority',\n VALUE_INDEX: '$value',\n KEY_INDEX: '$key',\n START_AT: 'startAt',\n END_AT: 'endAt',\n LIMIT_TO_FIRST: 'limitToFirst',\n LIMIT_TO_LAST: 'limitToLast'\n };\n\n /**\n * Default, empty query parameters\n * @type {!QueryParams}\n * @const\n */\n static readonly DEFAULT = new QueryParams();\n\n /**\n * @return {boolean}\n */\n hasStart(): boolean {\n return this.startSet_;\n }\n\n /**\n * @return {boolean} True if it would return from left.\n */\n isViewFromLeft(): boolean {\n if (this.viewFrom_ === '') {\n // limit(), rather than limitToFirst or limitToLast was called.\n // This means that only one of startSet_ and endSet_ is true. Use them\n // to calculate which side of the view to anchor to. If neither is set,\n // anchor to the end.\n return this.startSet_;\n } else {\n return (\n this.viewFrom_ === QueryParams.WIRE_PROTOCOL_CONSTANTS_.VIEW_FROM_LEFT\n );\n }\n }\n\n /**\n * Only valid to call if hasStart() returns true\n * @return {*}\n */\n getIndexStartValue(): unknown {\n assert(this.startSet_, 'Only valid if start has been set');\n return this.indexStartValue_;\n }\n\n /**\n * Only valid to call if hasStart() returns true.\n * Returns the starting key name for the range defined by these query parameters\n * @return {!string}\n */\n getIndexStartName(): string {\n assert(this.startSet_, 'Only valid if start has been set');\n if (this.startNameSet_) {\n return this.indexStartName_;\n } else {\n return MIN_NAME;\n }\n }\n\n /**\n * @return {boolean}\n */\n hasEnd(): boolean {\n return this.endSet_;\n }\n\n /**\n * Only valid to call if hasEnd() returns true.\n * @return {*}\n */\n getIndexEndValue(): unknown {\n assert(this.endSet_, 'Only valid if end has been set');\n return this.indexEndValue_;\n }\n\n /**\n * Only valid to call if hasEnd() returns true.\n * Returns the end key name for the range defined by these query parameters\n * @return {!string}\n */\n getIndexEndName(): string {\n assert(this.endSet_, 'Only valid if end has been set');\n if (this.endNameSet_) {\n return this.indexEndName_;\n } else {\n return MAX_NAME;\n }\n }\n\n /**\n * @return {boolean}\n */\n hasLimit(): boolean {\n return this.limitSet_;\n }\n\n /**\n * @return {boolean} True if a limit has been set and it has been explicitly anchored\n */\n hasAnchoredLimit(): boolean {\n return this.limitSet_ && this.viewFrom_ !== '';\n }\n\n /**\n * Only valid to call if hasLimit() returns true\n * @return {!number}\n */\n getLimit(): number {\n assert(this.limitSet_, 'Only valid if limit has been set');\n return this.limit_;\n }\n\n /**\n * @return {!Index}\n */\n getIndex(): Index {\n return this.index_;\n }\n\n /**\n * @return {!QueryParams}\n * @private\n */\n private copy_(): QueryParams {\n const copy = new QueryParams();\n copy.limitSet_ = this.limitSet_;\n copy.limit_ = this.limit_;\n copy.startSet_ = this.startSet_;\n copy.indexStartValue_ = this.indexStartValue_;\n copy.startNameSet_ = this.startNameSet_;\n copy.indexStartName_ = this.indexStartName_;\n copy.endSet_ = this.endSet_;\n copy.indexEndValue_ = this.indexEndValue_;\n copy.endNameSet_ = this.endNameSet_;\n copy.indexEndName_ = this.indexEndName_;\n copy.index_ = this.index_;\n copy.viewFrom_ = this.viewFrom_;\n return copy;\n }\n\n /**\n * @param {!number} newLimit\n * @return {!QueryParams}\n */\n limit(newLimit: number): QueryParams {\n const newParams = this.copy_();\n newParams.limitSet_ = true;\n newParams.limit_ = newLimit;\n newParams.viewFrom_ = '';\n return newParams;\n }\n\n /**\n * @param {!number} newLimit\n * @return {!QueryParams}\n */\n limitToFirst(newLimit: number): QueryParams {\n const newParams = this.copy_();\n newParams.limitSet_ = true;\n newParams.limit_ = newLimit;\n newParams.viewFrom_ = QueryParams.WIRE_PROTOCOL_CONSTANTS_.VIEW_FROM_LEFT;\n return newParams;\n }\n\n /**\n * @param {!number} newLimit\n * @return {!QueryParams}\n */\n limitToLast(newLimit: number): QueryParams {\n const newParams = this.copy_();\n newParams.limitSet_ = true;\n newParams.limit_ = newLimit;\n newParams.viewFrom_ = QueryParams.WIRE_PROTOCOL_CONSTANTS_.VIEW_FROM_RIGHT;\n return newParams;\n }\n\n /**\n * @param {*} indexValue\n * @param {?string=} key\n * @return {!QueryParams}\n */\n startAt(indexValue: unknown, key?: string | null): QueryParams {\n const newParams = this.copy_();\n newParams.startSet_ = true;\n if (indexValue === undefined) {\n indexValue = null;\n }\n newParams.indexStartValue_ = indexValue;\n if (key != null) {\n newParams.startNameSet_ = true;\n newParams.indexStartName_ = key;\n } else {\n newParams.startNameSet_ = false;\n newParams.indexStartName_ = '';\n }\n return newParams;\n }\n\n /**\n * @param {*} indexValue\n * @param {?string=} key\n * @return {!QueryParams}\n */\n endAt(indexValue: unknown, key?: string | null): QueryParams {\n const newParams = this.copy_();\n newParams.endSet_ = true;\n if (indexValue === undefined) {\n indexValue = null;\n }\n newParams.indexEndValue_ = indexValue;\n if (key !== undefined) {\n newParams.endNameSet_ = true;\n newParams.indexEndName_ = key;\n } else {\n newParams.endNameSet_ = false;\n newParams.indexEndName_ = '';\n }\n return newParams;\n }\n\n /**\n * @param {!Index} index\n * @return {!QueryParams}\n */\n orderBy(index: Index): QueryParams {\n const newParams = this.copy_();\n newParams.index_ = index;\n return newParams;\n }\n\n /**\n * @return {!Object}\n */\n getQueryObject(): {} {\n const WIRE_PROTOCOL_CONSTANTS = QueryParams.WIRE_PROTOCOL_CONSTANTS_;\n const obj: { [k: string]: unknown } = {};\n if (this.startSet_) {\n obj[WIRE_PROTOCOL_CONSTANTS.INDEX_START_VALUE] = this.indexStartValue_;\n if (this.startNameSet_) {\n obj[WIRE_PROTOCOL_CONSTANTS.INDEX_START_NAME] = this.indexStartName_;\n }\n }\n if (this.endSet_) {\n obj[WIRE_PROTOCOL_CONSTANTS.INDEX_END_VALUE] = this.indexEndValue_;\n if (this.endNameSet_) {\n obj[WIRE_PROTOCOL_CONSTANTS.INDEX_END_NAME] = this.indexEndName_;\n }\n }\n if (this.limitSet_) {\n obj[WIRE_PROTOCOL_CONSTANTS.LIMIT] = this.limit_;\n let viewFrom = this.viewFrom_;\n if (viewFrom === '') {\n if (this.isViewFromLeft()) {\n viewFrom = WIRE_PROTOCOL_CONSTANTS.VIEW_FROM_LEFT;\n } else {\n viewFrom = WIRE_PROTOCOL_CONSTANTS.VIEW_FROM_RIGHT;\n }\n }\n obj[WIRE_PROTOCOL_CONSTANTS.VIEW_FROM] = viewFrom;\n }\n // For now, priority index is the default, so we only specify if it's some other index\n if (this.index_ !== PRIORITY_INDEX) {\n obj[WIRE_PROTOCOL_CONSTANTS.INDEX] = this.index_.toString();\n }\n return obj;\n }\n\n /**\n * @return {boolean}\n */\n loadsAllData(): boolean {\n return !(this.startSet_ || this.endSet_ || this.limitSet_);\n }\n\n /**\n * @return {boolean}\n */\n isDefault(): boolean {\n return this.loadsAllData() && this.index_ === PRIORITY_INDEX;\n }\n\n /**\n * @return {!NodeFilter}\n */\n getNodeFilter(): NodeFilter {\n if (this.loadsAllData()) {\n return new IndexedFilter(this.getIndex());\n } else if (this.hasLimit()) {\n return new LimitedFilter(this);\n } else {\n return new RangedFilter(this);\n }\n }\n\n /**\n * Returns a set of REST query string parameters representing this query.\n *\n * @return {!Object.} query string parameters\n */\n toRestQueryStringParameters(): { [k: string]: string | number } {\n const REST_CONSTANTS = QueryParams.REST_QUERY_CONSTANTS_;\n const qs: { [k: string]: string | number } = {};\n\n if (this.isDefault()) {\n return qs;\n }\n\n let orderBy;\n if (this.index_ === PRIORITY_INDEX) {\n orderBy = REST_CONSTANTS.PRIORITY_INDEX;\n } else if (this.index_ === VALUE_INDEX) {\n orderBy = REST_CONSTANTS.VALUE_INDEX;\n } else if (this.index_ === KEY_INDEX) {\n orderBy = REST_CONSTANTS.KEY_INDEX;\n } else {\n assert(this.index_ instanceof PathIndex, 'Unrecognized index type!');\n orderBy = this.index_.toString();\n }\n qs[REST_CONSTANTS.ORDER_BY] = stringify(orderBy);\n\n if (this.startSet_) {\n qs[REST_CONSTANTS.START_AT] = stringify(this.indexStartValue_);\n if (this.startNameSet_) {\n qs[REST_CONSTANTS.START_AT] += ',' + stringify(this.indexStartName_);\n }\n }\n\n if (this.endSet_) {\n qs[REST_CONSTANTS.END_AT] = stringify(this.indexEndValue_);\n if (this.endNameSet_) {\n qs[REST_CONSTANTS.END_AT] += ',' + stringify(this.indexEndName_);\n }\n }\n\n if (this.limitSet_) {\n if (this.isViewFromLeft()) {\n qs[REST_CONSTANTS.LIMIT_TO_FIRST] = this.limit_;\n } else {\n qs[REST_CONSTANTS.LIMIT_TO_LAST] = this.limit_;\n }\n }\n\n return qs;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OnDisconnect } from './onDisconnect';\nimport { TransactionResult } from './TransactionResult';\nimport { warn } from '../core/util/util';\nimport { nextPushId } from '../core/util/NextPushId';\nimport { Query } from './Query';\nimport { Repo } from '../core/Repo';\nimport { Path } from '../core/util/Path';\nimport { QueryParams } from '../core/view/QueryParams';\nimport {\n validateRootPathString,\n validatePathString,\n validateFirebaseMergeDataArg,\n validateBoolean,\n validatePriority,\n validateFirebaseDataArg,\n validateWritablePath\n} from '../core/util/validation';\nimport { validateArgCount, validateCallback, Deferred } from '@firebase/util';\n\nimport { SyncPoint } from '../core/SyncPoint';\nimport { Database } from './Database';\nimport { DataSnapshot } from './DataSnapshot';\nimport * as types from '@firebase/database-types';\n\nexport interface ReferenceConstructor {\n new (repo: Repo, path: Path): Reference;\n}\n\nexport class Reference extends Query {\n then: Promise['then'];\n catch: Promise['catch'];\n\n /**\n * Call options:\n * new Reference(Repo, Path) or\n * new Reference(url: string, string|RepoManager)\n *\n * Externally - this is the firebase.database.Reference type.\n *\n * @param {!Repo} repo\n * @param {(!Path)} path\n * @extends {Query}\n */\n constructor(repo: Repo, path: Path) {\n if (!(repo instanceof Repo)) {\n throw new Error(\n 'new Reference() no longer supported - use app.database().'\n );\n }\n\n // call Query's constructor, passing in the repo and path.\n super(repo, path, QueryParams.DEFAULT, false);\n }\n\n /** @return {?string} */\n getKey(): string | null {\n validateArgCount('Reference.key', 0, 0, arguments.length);\n\n if (this.path.isEmpty()) {\n return null;\n } else {\n return this.path.getBack();\n }\n }\n\n /**\n * @param {!(string|Path)} pathString\n * @return {!Reference}\n */\n child(pathString: string | Path): Reference {\n validateArgCount('Reference.child', 1, 1, arguments.length);\n if (typeof pathString === 'number') {\n pathString = String(pathString);\n } else if (!(pathString instanceof Path)) {\n if (this.path.getFront() === null) {\n validateRootPathString('Reference.child', 1, pathString, false);\n } else {\n validatePathString('Reference.child', 1, pathString, false);\n }\n }\n\n return new Reference(this.repo, this.path.child(pathString));\n }\n\n /** @return {?Reference} */\n getParent(): Reference | null {\n validateArgCount('Reference.parent', 0, 0, arguments.length);\n\n const parentPath = this.path.parent();\n return parentPath === null ? null : new Reference(this.repo, parentPath);\n }\n\n /** @return {!Reference} */\n getRoot(): Reference {\n validateArgCount('Reference.root', 0, 0, arguments.length);\n\n let ref: Reference = this;\n while (ref.getParent() !== null) {\n ref = ref.getParent();\n }\n return ref;\n }\n\n /** @return {!Database} */\n databaseProp(): Database {\n return this.repo.database;\n }\n\n /**\n * @param {*} newVal\n * @param {function(?Error)=} onComplete\n * @return {!Promise}\n */\n set(\n newVal: unknown,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('Reference.set', 1, 2, arguments.length);\n validateWritablePath('Reference.set', this.path);\n validateFirebaseDataArg('Reference.set', 1, newVal, this.path, false);\n validateCallback('Reference.set', 2, onComplete, true);\n\n const deferred = new Deferred();\n this.repo.setWithPriority(\n this.path,\n newVal,\n /*priority=*/ null,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {!Object} objectToMerge\n * @param {function(?Error)=} onComplete\n * @return {!Promise}\n */\n update(\n objectToMerge: object,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('Reference.update', 1, 2, arguments.length);\n validateWritablePath('Reference.update', this.path);\n\n if (Array.isArray(objectToMerge)) {\n const newObjectToMerge: { [k: string]: unknown } = {};\n for (let i = 0; i < objectToMerge.length; ++i) {\n newObjectToMerge['' + i] = objectToMerge[i];\n }\n objectToMerge = newObjectToMerge;\n warn(\n 'Passing an Array to Firebase.update() is deprecated. ' +\n 'Use set() if you want to overwrite the existing data, or ' +\n 'an Object with integer keys if you really do want to ' +\n 'only update some of the children.'\n );\n }\n validateFirebaseMergeDataArg(\n 'Reference.update',\n 1,\n objectToMerge,\n this.path,\n false\n );\n validateCallback('Reference.update', 2, onComplete, true);\n const deferred = new Deferred();\n this.repo.update(\n this.path,\n objectToMerge as { [k: string]: unknown },\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {*} newVal\n * @param {string|number|null} newPriority\n * @param {function(?Error)=} onComplete\n * @return {!Promise}\n */\n setWithPriority(\n newVal: unknown,\n newPriority: string | number | null,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('Reference.setWithPriority', 2, 3, arguments.length);\n validateWritablePath('Reference.setWithPriority', this.path);\n validateFirebaseDataArg(\n 'Reference.setWithPriority',\n 1,\n newVal,\n this.path,\n false\n );\n validatePriority('Reference.setWithPriority', 2, newPriority, false);\n validateCallback('Reference.setWithPriority', 3, onComplete, true);\n\n if (this.getKey() === '.length' || this.getKey() === '.keys') {\n throw 'Reference.setWithPriority failed: ' +\n this.getKey() +\n ' is a read-only object.';\n }\n\n const deferred = new Deferred();\n this.repo.setWithPriority(\n this.path,\n newVal,\n newPriority,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {function(?Error)=} onComplete\n * @return {!Promise}\n */\n remove(onComplete?: (a: Error | null) => void): Promise {\n validateArgCount('Reference.remove', 0, 1, arguments.length);\n validateWritablePath('Reference.remove', this.path);\n validateCallback('Reference.remove', 1, onComplete, true);\n\n return this.set(null, onComplete);\n }\n\n /**\n * @param {function(*):*} transactionUpdate\n * @param {(function(?Error, boolean, ?DataSnapshot))=} onComplete\n * @param {boolean=} applyLocally\n * @return {!Promise}\n */\n transaction(\n transactionUpdate: (a: unknown) => unknown,\n onComplete?: (a: Error | null, b: boolean, c: DataSnapshot | null) => void,\n applyLocally?: boolean\n ): Promise {\n validateArgCount('Reference.transaction', 1, 3, arguments.length);\n validateWritablePath('Reference.transaction', this.path);\n validateCallback('Reference.transaction', 1, transactionUpdate, false);\n validateCallback('Reference.transaction', 2, onComplete, true);\n // NOTE: applyLocally is an internal-only option for now. We need to decide if we want to keep it and how\n // to expose it.\n validateBoolean('Reference.transaction', 3, applyLocally, true);\n\n if (this.getKey() === '.length' || this.getKey() === '.keys') {\n throw 'Reference.transaction failed: ' +\n this.getKey() +\n ' is a read-only object.';\n }\n\n if (applyLocally === undefined) {\n applyLocally = true;\n }\n\n const deferred = new Deferred();\n if (typeof onComplete === 'function') {\n deferred.promise.catch(() => {});\n }\n\n const promiseComplete = function(\n error: Error,\n committed: boolean,\n snapshot: DataSnapshot\n ) {\n if (error) {\n deferred.reject(error);\n } else {\n deferred.resolve(new TransactionResult(committed, snapshot));\n }\n if (typeof onComplete === 'function') {\n onComplete(error, committed, snapshot);\n }\n };\n this.repo.startTransaction(\n this.path,\n transactionUpdate,\n promiseComplete,\n applyLocally\n );\n\n return deferred.promise;\n }\n\n /**\n * @param {string|number|null} priority\n * @param {function(?Error)=} onComplete\n * @return {!Promise}\n */\n setPriority(\n priority: string | number | null,\n onComplete?: (a: Error | null) => void\n ): Promise {\n validateArgCount('Reference.setPriority', 1, 2, arguments.length);\n validateWritablePath('Reference.setPriority', this.path);\n validatePriority('Reference.setPriority', 1, priority, false);\n validateCallback('Reference.setPriority', 2, onComplete, true);\n\n const deferred = new Deferred();\n this.repo.setWithPriority(\n this.path.child('.priority'),\n priority,\n null,\n deferred.wrapCallback(onComplete)\n );\n return deferred.promise;\n }\n\n /**\n * @param {*=} value\n * @param {function(?Error)=} onComplete\n * @return {!Reference}\n */\n push(value?: unknown, onComplete?: (a: Error | null) => void): Reference {\n validateArgCount('Reference.push', 0, 2, arguments.length);\n validateWritablePath('Reference.push', this.path);\n validateFirebaseDataArg('Reference.push', 1, value, this.path, true);\n validateCallback('Reference.push', 2, onComplete, true);\n\n const now = this.repo.serverTime();\n const name = nextPushId(now);\n\n // push() returns a ThennableReference whose promise is fulfilled with a regular Reference.\n // We use child() to create handles to two different references. The first is turned into a\n // ThennableReference below by adding then() and catch() methods and is used as the\n // return value of push(). The second remains a regular Reference and is used as the fulfilled\n // value of the first ThennableReference.\n const thennablePushRef = this.child(name);\n const pushRef = this.child(name);\n\n let promise;\n if (value != null) {\n promise = thennablePushRef.set(value, onComplete).then(() => pushRef);\n } else {\n promise = Promise.resolve(pushRef);\n }\n\n thennablePushRef.then = promise.then.bind(promise);\n thennablePushRef.catch = promise.then.bind(promise, undefined);\n\n if (typeof onComplete === 'function') {\n promise.catch(() => {});\n }\n\n return thennablePushRef;\n }\n\n /**\n * @return {!OnDisconnect}\n */\n onDisconnect(): OnDisconnect {\n validateWritablePath('Reference.onDisconnect', this.path);\n return new OnDisconnect(this.repo, this.path);\n }\n\n get database(): Database {\n return this.databaseProp();\n }\n\n get key(): string | null {\n return this.getKey();\n }\n\n get parent(): Reference | null {\n return this.getParent();\n }\n\n get root(): Reference {\n return this.getRoot();\n }\n}\n\n/**\n * Define reference constructor in various modules\n *\n * We are doing this here to avoid several circular\n * dependency issues\n */\nQuery.__referenceConstructor = Reference;\nSyncPoint.__referenceConstructor = Reference;\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, contains, safeGet } from '@firebase/util';\nimport { Path } from './Path';\n\nimport { each } from './util';\n\n/**\n * Node in a Tree.\n */\nexport class TreeNode {\n // TODO: Consider making accessors that create children and value lazily or\n // separate Internal / Leaf 'types'.\n children: { [name: string]: TreeNode } = {};\n childCount = 0;\n value: T | null = null;\n}\n\n/**\n * A light-weight tree, traversable by path. Nodes can have both values and children.\n * Nodes are not enumerated (by forEachChild) unless they have a value or non-empty\n * children.\n */\nexport class Tree {\n /**\n * @template T\n * @param {string=} name_ Optional name of the node.\n * @param {Tree=} parent_ Optional parent node.\n * @param {TreeNode=} node_ Optional node to wrap.\n */\n constructor(\n private name_: string = '',\n private parent_: Tree | null = null,\n private node_: TreeNode = new TreeNode()\n ) {}\n\n /**\n * Returns a sub-Tree for the given path.\n *\n * @param {!(string|Path)} pathObj Path to look up.\n * @return {!Tree.} Tree for path.\n */\n subTree(pathObj: string | Path): Tree {\n // TODO: Require pathObj to be Path?\n let path = pathObj instanceof Path ? pathObj : new Path(pathObj);\n let child = this as Tree,\n next = path.getFront();\n while (next !== null) {\n const childNode = safeGet(child.node_.children, next) || new TreeNode();\n child = new Tree(next, child, childNode);\n path = path.popFront();\n next = path.getFront();\n }\n\n return child;\n }\n\n /**\n * Returns the data associated with this tree node.\n *\n * @return {?T} The data or null if no data exists.\n */\n getValue(): T | null {\n return this.node_.value;\n }\n\n /**\n * Sets data to this tree node.\n *\n * @param {!T} value Value to set.\n */\n setValue(value: T) {\n assert(typeof value !== 'undefined', 'Cannot set value to undefined');\n this.node_.value = value;\n this.updateParents_();\n }\n\n /**\n * Clears the contents of the tree node (its value and all children).\n */\n clear() {\n this.node_.value = null;\n this.node_.children = {};\n this.node_.childCount = 0;\n this.updateParents_();\n }\n\n /**\n * @return {boolean} Whether the tree has any children.\n */\n hasChildren(): boolean {\n return this.node_.childCount > 0;\n }\n\n /**\n * @return {boolean} Whether the tree is empty (no value or children).\n */\n isEmpty(): boolean {\n return this.getValue() === null && !this.hasChildren();\n }\n\n /**\n * Calls action for each child of this tree node.\n *\n * @param {function(!Tree.)} action Action to be called for each child.\n */\n forEachChild(action: (tree: Tree) => void) {\n each(this.node_.children, (child: string, childTree: TreeNode) => {\n action(new Tree(child, this, childTree));\n });\n }\n\n /**\n * Does a depth-first traversal of this node's descendants, calling action for each one.\n *\n * @param {function(!Tree.)} action Action to be called for each child.\n * @param {boolean=} includeSelf Whether to call action on this node as well. Defaults to\n * false.\n * @param {boolean=} childrenFirst Whether to call action on children before calling it on\n * parent.\n */\n forEachDescendant(\n action: (tree: Tree) => void,\n includeSelf?: boolean,\n childrenFirst?: boolean\n ) {\n if (includeSelf && !childrenFirst) {\n action(this);\n }\n\n this.forEachChild(child => {\n child.forEachDescendant(action, /*includeSelf=*/ true, childrenFirst);\n });\n\n if (includeSelf && childrenFirst) {\n action(this);\n }\n }\n\n /**\n * Calls action on each ancestor node.\n *\n * @param {function(!Tree.)} action Action to be called on each parent; return\n * true to abort.\n * @param {boolean=} includeSelf Whether to call action on this node as well.\n * @return {boolean} true if the action callback returned true.\n */\n forEachAncestor(\n action: (tree: Tree) => unknown,\n includeSelf?: boolean\n ): boolean {\n let node = includeSelf ? this : this.parent();\n while (node !== null) {\n if (action(node)) {\n return true;\n }\n node = node.parent();\n }\n return false;\n }\n\n /**\n * Does a depth-first traversal of this node's descendants. When a descendant with a value\n * is found, action is called on it and traversal does not continue inside the node.\n * Action is *not* called on this node.\n *\n * @param {function(!Tree.)} action Action to be called for each child.\n */\n forEachImmediateDescendantWithValue(action: (tree: Tree) => void) {\n this.forEachChild(child => {\n if (child.getValue() !== null) {\n action(child);\n } else {\n child.forEachImmediateDescendantWithValue(action);\n }\n });\n }\n\n /**\n * @return {!Path} The path of this tree node, as a Path.\n */\n path(): Path {\n return new Path(\n this.parent_ === null\n ? this.name_\n : this.parent_.path() + '/' + this.name_\n );\n }\n\n /**\n * @return {string} The name of the tree node.\n */\n name(): string {\n return this.name_;\n }\n\n /**\n * @return {?Tree} The parent tree node, or null if this is the root of the tree.\n */\n parent(): Tree | null {\n return this.parent_;\n }\n\n /**\n * Adds or removes this child from its parent based on whether it's empty or not.\n *\n * @private\n */\n private updateParents_() {\n if (this.parent_ !== null) {\n this.parent_.updateChild_(this.name_, this);\n }\n }\n\n /**\n * Adds or removes the passed child to this tree node, depending on whether it's empty.\n *\n * @param {string} childName The name of the child to update.\n * @param {!Tree.} child The child to update.\n * @private\n */\n private updateChild_(childName: string, child: Tree) {\n const childEmpty = child.isEmpty();\n const childExists = contains(this.node_.children, childName);\n if (childEmpty && childExists) {\n delete this.node_.children[childName];\n this.node_.childCount--;\n this.updateParents_();\n } else if (!childEmpty && !childExists) {\n this.node_.children[childName] = child.node_;\n this.node_.childCount++;\n this.updateParents_();\n }\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { assert, contains, safeGet } from '@firebase/util';\nimport { Reference } from '../api/Reference';\nimport { DataSnapshot } from '../api/DataSnapshot';\nimport { Path } from './util/Path';\nimport { Tree } from './util/Tree';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { Node } from './snap/Node';\nimport { LUIDGenerator, warn, exceptionGuard } from './util/util';\nimport { resolveDeferredValueSnapshot } from './util/ServerValues';\nimport { isValidPriority, validateFirebaseData } from './util/validation';\n\nimport { nodeFromJSON } from './snap/nodeFromJSON';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Repo } from './Repo';\nimport { Event } from './view/Event';\n\n// TODO: This is pretty messy. Ideally, a lot of this would move into FirebaseData, or a transaction-specific\n// component used by FirebaseData, but it has ties to user callbacks (transaction update and onComplete) as well\n// as the realtime connection (to send transactions to the server). So that all needs to be decoupled first.\n// For now it's part of Repo, but in its own file.\n\n/**\n * @enum {number}\n */\nexport enum TransactionStatus {\n // We've run the transaction and updated transactionResultData_ with the result, but it isn't currently sent to the\n // server. A transaction will go from RUN -> SENT -> RUN if it comes back from the server as rejected due to\n // mismatched hash.\n RUN,\n\n // We've run the transaction and sent it to the server and it's currently outstanding (hasn't come back as accepted\n // or rejected yet).\n SENT,\n\n // Temporary state used to mark completed transactions (whether successful or aborted). The transaction will be\n // removed when we get a chance to prune completed ones.\n COMPLETED,\n\n // Used when an already-sent transaction needs to be aborted (e.g. due to a conflicting set() call that was made).\n // If it comes back as unsuccessful, we'll abort it.\n SENT_NEEDS_ABORT,\n\n // Temporary state used to mark transactions that need to be aborted.\n NEEDS_ABORT\n}\n\n/**\n * If a transaction does not succeed after 25 retries, we abort it. Among other things this ensure that if there's\n * ever a bug causing a mismatch between client / server hashes for some data, we won't retry indefinitely.\n * @type {number}\n * @const\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo as any).MAX_TRANSACTION_RETRIES_ = 25;\n\n/**\n * @typedef {{\n * path: !Path,\n * update: function(*):*,\n * onComplete: ?function(?Error, boolean, ?DataSnapshot),\n * status: ?TransactionStatus,\n * order: !number,\n * applyLocally: boolean,\n * retryCount: !number,\n * unwatcher: function(),\n * abortReason: ?string,\n * currentWriteId: !number,\n * currentInputSnapshot: ?Node,\n * currentOutputSnapshotRaw: ?Node,\n * currentOutputSnapshotResolved: ?Node\n * }}\n */\ninterface Transaction {\n path: Path;\n update: (a: unknown) => unknown;\n onComplete: (a: Error | null, b: boolean, c: DataSnapshot | null) => void;\n status: TransactionStatus;\n order: number;\n applyLocally: boolean;\n retryCount: number;\n unwatcher: () => void;\n abortReason: string | null;\n currentWriteId: number;\n currentInputSnapshot: Node | null;\n currentOutputSnapshotRaw: Node | null;\n currentOutputSnapshotResolved: Node | null;\n}\n\n/**\n * Setup the transaction data structures\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).transactionsInit_ = function() {\n /**\n * Stores queues of outstanding transactions for Firebase locations.\n *\n * @type {!Tree.>}\n * @private\n */\n this.transactionQueueTree_ = new Tree();\n};\n\ndeclare module './Repo' {\n interface Repo {\n startTransaction(\n path: Path,\n transactionUpdate: (a: unknown) => void,\n onComplete: ((a: Error, b: boolean, c: DataSnapshot) => void) | null,\n applyLocally: boolean\n ): void;\n }\n}\n\n/**\n * Creates a new transaction, adds it to the transactions we're tracking, and sends it to the server if possible.\n *\n * @param {!Path} path Path at which to do transaction.\n * @param {function(*):*} transactionUpdate Update callback.\n * @param {?function(?Error, boolean, ?DataSnapshot)} onComplete Completion callback.\n * @param {boolean} applyLocally Whether or not to make intermediate results visible\n */\nRepo.prototype.startTransaction = function(\n path: Path,\n transactionUpdate: (a: unknown) => unknown,\n onComplete: ((a: Error, b: boolean, c: DataSnapshot) => void) | null,\n applyLocally: boolean\n) {\n this.log_('transaction on ' + path);\n\n // Add a watch to make sure we get server updates.\n const valueCallback = function() {};\n const watchRef = new Reference(this, path);\n watchRef.on('value', valueCallback);\n const unwatcher = function() {\n watchRef.off('value', valueCallback);\n };\n\n // Initialize transaction.\n const transaction: Transaction = {\n path,\n update: transactionUpdate,\n onComplete,\n\n // One of TransactionStatus enums.\n status: null,\n\n // Used when combining transactions at different locations to figure out which one goes first.\n order: LUIDGenerator(),\n\n // Whether to raise local events for this transaction.\n applyLocally,\n\n // Count of how many times we've retried the transaction.\n retryCount: 0,\n\n // Function to call to clean up our .on() listener.\n unwatcher,\n\n // Stores why a transaction was aborted.\n abortReason: null,\n\n currentWriteId: null,\n\n currentInputSnapshot: null,\n\n currentOutputSnapshotRaw: null,\n\n currentOutputSnapshotResolved: null\n };\n\n // Run transaction initially.\n const currentState = this.getLatestState_(path);\n transaction.currentInputSnapshot = currentState;\n const newVal = transaction.update(currentState.val());\n if (newVal === undefined) {\n // Abort transaction.\n transaction.unwatcher();\n transaction.currentOutputSnapshotRaw = null;\n transaction.currentOutputSnapshotResolved = null;\n if (transaction.onComplete) {\n // We just set the input snapshot, so this cast should be safe\n const snapshot = new DataSnapshot(\n transaction.currentInputSnapshot,\n new Reference(this, transaction.path),\n PRIORITY_INDEX\n );\n transaction.onComplete(null, false, snapshot);\n }\n } else {\n validateFirebaseData(\n 'transaction failed: Data returned ',\n newVal,\n transaction.path\n );\n\n // Mark as run and add to our queue.\n transaction.status = TransactionStatus.RUN;\n const queueNode = this.transactionQueueTree_.subTree(path);\n const nodeQueue = queueNode.getValue() || [];\n nodeQueue.push(transaction);\n\n queueNode.setValue(nodeQueue);\n\n // Update visibleData and raise events\n // Note: We intentionally raise events after updating all of our transaction state, since the user could\n // start new transactions from the event callbacks.\n let priorityForNode;\n if (\n typeof newVal === 'object' &&\n newVal !== null &&\n contains(newVal, '.priority')\n ) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n priorityForNode = safeGet(newVal as any, '.priority');\n assert(\n isValidPriority(priorityForNode),\n 'Invalid priority returned by transaction. ' +\n 'Priority must be a valid string, finite number, server value, or null.'\n );\n } else {\n const currentNode =\n this.serverSyncTree_.calcCompleteEventCache(path) ||\n ChildrenNode.EMPTY_NODE;\n priorityForNode = currentNode.getPriority().val();\n }\n priorityForNode /** @type {null|number|string} */ = priorityForNode;\n\n const serverValues = this.generateServerValues();\n const newNodeUnresolved = nodeFromJSON(newVal, priorityForNode);\n const newNode = resolveDeferredValueSnapshot(\n newNodeUnresolved,\n serverValues\n );\n transaction.currentOutputSnapshotRaw = newNodeUnresolved;\n transaction.currentOutputSnapshotResolved = newNode;\n transaction.currentWriteId = this.getNextWriteId_();\n\n const events = this.serverSyncTree_.applyUserOverwrite(\n path,\n newNode,\n transaction.currentWriteId,\n transaction.applyLocally\n );\n this.eventQueue_.raiseEventsForChangedPath(path, events);\n\n this.sendReadyTransactions_();\n }\n};\n\n/**\n * @param {!Path} path\n * @param {Array.=} excludeSets A specific set to exclude\n * @return {Node}\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).getLatestState_ = function(\n path: Path,\n excludeSets?: number[]\n): Node {\n return (\n this.serverSyncTree_.calcCompleteEventCache(path, excludeSets) ||\n ChildrenNode.EMPTY_NODE\n );\n};\n\n/**\n * Sends any already-run transactions that aren't waiting for outstanding transactions to\n * complete.\n *\n * Externally it's called with no arguments, but it calls itself recursively with a particular\n * transactionQueueTree node to recurse through the tree.\n *\n * @param {Tree.>=} node transactionQueueTree node to start at.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).sendReadyTransactions_ = function(\n node: Tree = this.transactionQueueTree_\n) {\n // Before recursing, make sure any completed transactions are removed.\n if (!node) {\n this.pruneCompletedTransactionsBelowNode_(node);\n }\n\n if (node.getValue() !== null) {\n const queue = this.buildTransactionQueue_(node);\n assert(queue.length > 0, 'Sending zero length transaction queue');\n\n const allRun = queue.every(\n (transaction: Transaction) => transaction.status === TransactionStatus.RUN\n );\n\n // If they're all run (and not sent), we can send them. Else, we must wait.\n if (allRun) {\n this.sendTransactionQueue_(node.path(), queue);\n }\n } else if (node.hasChildren()) {\n node.forEachChild(childNode => {\n this.sendReadyTransactions_(childNode);\n });\n }\n};\n\n/**\n * Given a list of run transactions, send them to the server and then handle the result (success or failure).\n *\n * @param {!Path} path The location of the queue.\n * @param {!Array.} queue Queue of transactions under the specified location.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).sendTransactionQueue_ = function(\n path: Path,\n queue: Transaction[]\n) {\n // Mark transactions as sent and increment retry count!\n const setsToIgnore = queue.map(txn => {\n return txn.currentWriteId;\n });\n const latestState = this.getLatestState_(path, setsToIgnore);\n let snapToSend = latestState;\n const latestHash = latestState.hash();\n for (let i = 0; i < queue.length; i++) {\n const txn = queue[i];\n assert(\n txn.status === TransactionStatus.RUN,\n 'tryToSendTransactionQueue_: items in queue should all be run.'\n );\n txn.status = TransactionStatus.SENT;\n txn.retryCount++;\n const relativePath = Path.relativePath(path, txn.path);\n // If we've gotten to this point, the output snapshot must be defined.\n snapToSend = snapToSend.updateChild(\n relativePath /** @type {!Node} */,\n txn.currentOutputSnapshotRaw\n );\n }\n\n const dataToSend = snapToSend.val(true);\n const pathToSend = path;\n\n // Send the put.\n this.server_.put(\n pathToSend.toString(),\n dataToSend,\n (status: string) => {\n this.log_('transaction put response', {\n path: pathToSend.toString(),\n status\n });\n\n let events: Event[] = [];\n if (status === 'ok') {\n // Queue up the callbacks and fire them after cleaning up all of our transaction state, since\n // the callback could trigger more transactions or sets.\n const callbacks = [];\n for (let i = 0; i < queue.length; i++) {\n queue[i].status = TransactionStatus.COMPLETED;\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(queue[i].currentWriteId)\n );\n if (queue[i].onComplete) {\n // We never unset the output snapshot, and given that this transaction is complete, it should be set\n const node = queue[i].currentOutputSnapshotResolved as Node;\n const ref = new Reference(this, queue[i].path);\n const snapshot = new DataSnapshot(node, ref, PRIORITY_INDEX);\n callbacks.push(\n queue[i].onComplete.bind(null, null, true, snapshot)\n );\n }\n queue[i].unwatcher();\n }\n\n // Now remove the completed transactions.\n this.pruneCompletedTransactionsBelowNode_(\n this.transactionQueueTree_.subTree(path)\n );\n // There may be pending transactions that we can now send.\n this.sendReadyTransactions_();\n\n this.eventQueue_.raiseEventsForChangedPath(path, events);\n\n // Finally, trigger onComplete callbacks.\n for (let i = 0; i < callbacks.length; i++) {\n exceptionGuard(callbacks[i]);\n }\n } else {\n // transactions are no longer sent. Update their status appropriately.\n if (status === 'datastale') {\n for (let i = 0; i < queue.length; i++) {\n if (queue[i].status === TransactionStatus.SENT_NEEDS_ABORT) {\n queue[i].status = TransactionStatus.NEEDS_ABORT;\n } else {\n queue[i].status = TransactionStatus.RUN;\n }\n }\n } else {\n warn(\n 'transaction at ' + pathToSend.toString() + ' failed: ' + status\n );\n for (let i = 0; i < queue.length; i++) {\n queue[i].status = TransactionStatus.NEEDS_ABORT;\n queue[i].abortReason = status;\n }\n }\n\n this.rerunTransactions_(path);\n }\n },\n latestHash\n );\n};\n\n/**\n * Finds all transactions dependent on the data at changedPath and reruns them.\n *\n * Should be called any time cached data changes.\n *\n * Return the highest path that was affected by rerunning transactions. This is the path at which events need to\n * be raised for.\n *\n * @param {!Path} changedPath The path in mergedData that changed.\n * @return {!Path} The rootmost path that was affected by rerunning transactions.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).rerunTransactions_ = function(changedPath: Path): Path {\n const rootMostTransactionNode = this.getAncestorTransactionNode_(changedPath);\n const path = rootMostTransactionNode.path();\n\n const queue = this.buildTransactionQueue_(rootMostTransactionNode);\n this.rerunTransactionQueue_(queue, path);\n\n return path;\n};\n\n/**\n * Does all the work of rerunning transactions (as well as cleans up aborted transactions and whatnot).\n *\n * @param {Array.} queue The queue of transactions to run.\n * @param {!Path} path The path the queue is for.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).rerunTransactionQueue_ = function(\n queue: Transaction[],\n path: Path\n) {\n if (queue.length === 0) {\n return; // Nothing to do!\n }\n\n // Queue up the callbacks and fire them after cleaning up all of our transaction state, since\n // the callback could trigger more transactions or sets.\n const callbacks = [];\n let events: Event[] = [];\n // Ignore all of the sets we're going to re-run.\n const txnsToRerun = queue.filter(q => {\n return q.status === TransactionStatus.RUN;\n });\n const setsToIgnore = txnsToRerun.map(q => {\n return q.currentWriteId;\n });\n for (let i = 0; i < queue.length; i++) {\n const transaction = queue[i];\n const relativePath = Path.relativePath(path, transaction.path);\n let abortTransaction = false,\n abortReason;\n assert(\n relativePath !== null,\n 'rerunTransactionsUnderNode_: relativePath should not be null.'\n );\n\n if (transaction.status === TransactionStatus.NEEDS_ABORT) {\n abortTransaction = true;\n abortReason = transaction.abortReason;\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(transaction.currentWriteId, true)\n );\n } else if (transaction.status === TransactionStatus.RUN) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (transaction.retryCount >= (Repo as any).MAX_TRANSACTION_RETRIES_) {\n abortTransaction = true;\n abortReason = 'maxretry';\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(transaction.currentWriteId, true)\n );\n } else {\n // This code reruns a transaction\n const currentNode = this.getLatestState_(\n transaction.path,\n setsToIgnore\n );\n transaction.currentInputSnapshot = currentNode;\n const newData = queue[i].update(currentNode.val());\n if (newData !== undefined) {\n validateFirebaseData(\n 'transaction failed: Data returned ',\n newData,\n transaction.path\n );\n let newDataNode = nodeFromJSON(newData);\n const hasExplicitPriority =\n typeof newData === 'object' &&\n newData != null &&\n contains(newData, '.priority');\n if (!hasExplicitPriority) {\n // Keep the old priority if there wasn't a priority explicitly specified.\n newDataNode = newDataNode.updatePriority(currentNode.getPriority());\n }\n\n const oldWriteId = transaction.currentWriteId;\n const serverValues = this.generateServerValues();\n const newNodeResolved = resolveDeferredValueSnapshot(\n newDataNode,\n serverValues\n );\n\n transaction.currentOutputSnapshotRaw = newDataNode;\n transaction.currentOutputSnapshotResolved = newNodeResolved;\n transaction.currentWriteId = this.getNextWriteId_();\n // Mutates setsToIgnore in place\n setsToIgnore.splice(setsToIgnore.indexOf(oldWriteId), 1);\n events = events.concat(\n this.serverSyncTree_.applyUserOverwrite(\n transaction.path,\n newNodeResolved,\n transaction.currentWriteId,\n transaction.applyLocally\n )\n );\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(oldWriteId, true)\n );\n } else {\n abortTransaction = true;\n abortReason = 'nodata';\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(transaction.currentWriteId, true)\n );\n }\n }\n }\n this.eventQueue_.raiseEventsForChangedPath(path, events);\n events = [];\n if (abortTransaction) {\n // Abort.\n queue[i].status = TransactionStatus.COMPLETED;\n\n // Removing a listener can trigger pruning which can muck with mergedData/visibleData (as it prunes data).\n // So defer the unwatcher until we're done.\n (function(unwatcher) {\n setTimeout(unwatcher, Math.floor(0));\n })(queue[i].unwatcher);\n\n if (queue[i].onComplete) {\n if (abortReason === 'nodata') {\n const ref = new Reference(this, queue[i].path);\n // We set this field immediately, so it's safe to cast to an actual snapshot\n const lastInput /** @type {!Node} */ = queue[i].currentInputSnapshot;\n const snapshot = new DataSnapshot(lastInput, ref, PRIORITY_INDEX);\n callbacks.push(queue[i].onComplete.bind(null, null, false, snapshot));\n } else {\n callbacks.push(\n queue[i].onComplete.bind(null, new Error(abortReason), false, null)\n );\n }\n }\n }\n }\n\n // Clean up completed transactions.\n this.pruneCompletedTransactionsBelowNode_(this.transactionQueueTree_);\n\n // Now fire callbacks, now that we're in a good, known state.\n for (let i = 0; i < callbacks.length; i++) {\n exceptionGuard(callbacks[i]);\n }\n\n // Try to send the transaction result to the server.\n this.sendReadyTransactions_();\n};\n\n/**\n * Returns the rootmost ancestor node of the specified path that has a pending transaction on it, or just returns\n * the node for the given path if there are no pending transactions on any ancestor.\n *\n * @param {!Path} path The location to start at.\n * @return {!Tree.>} The rootmost node with a transaction.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).getAncestorTransactionNode_ = function(\n path: Path\n): Tree {\n let front;\n\n // Start at the root and walk deeper into the tree towards path until we find a node with pending transactions.\n let transactionNode = this.transactionQueueTree_;\n front = path.getFront();\n while (front !== null && transactionNode.getValue() === null) {\n transactionNode = transactionNode.subTree(front);\n path = path.popFront();\n front = path.getFront();\n }\n\n return transactionNode;\n};\n\n/**\n * Builds the queue of all transactions at or below the specified transactionNode.\n *\n * @param {!Tree.>} transactionNode\n * @return {Array.} The generated queue.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).buildTransactionQueue_ = function(\n transactionNode: Tree\n): Transaction[] {\n // Walk any child transaction queues and aggregate them into a single queue.\n const transactionQueue: Transaction[] = [];\n this.aggregateTransactionQueuesForNode_(transactionNode, transactionQueue);\n\n // Sort them by the order the transactions were created.\n transactionQueue.sort((a, b) => {\n return a.order - b.order;\n });\n\n return transactionQueue;\n};\n\n/**\n * @param {!Tree.>} node\n * @param {Array.} queue\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).aggregateTransactionQueuesForNode_ = function(\n node: Tree,\n queue: Transaction[]\n) {\n const nodeQueue = node.getValue();\n if (nodeQueue !== null) {\n for (let i = 0; i < nodeQueue.length; i++) {\n queue.push(nodeQueue[i]);\n }\n }\n\n node.forEachChild(child => {\n this.aggregateTransactionQueuesForNode_(child, queue);\n });\n};\n\n/**\n * Remove COMPLETED transactions at or below this node in the transactionQueueTree_.\n *\n * @param {!Tree.>} node\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).pruneCompletedTransactionsBelowNode_ = function(\n node: Tree\n) {\n const queue = node.getValue();\n if (queue) {\n let to = 0;\n for (let from = 0; from < queue.length; from++) {\n if (queue[from].status !== TransactionStatus.COMPLETED) {\n queue[to] = queue[from];\n to++;\n }\n }\n queue.length = to;\n node.setValue(queue.length > 0 ? queue : null);\n }\n\n node.forEachChild(childNode => {\n this.pruneCompletedTransactionsBelowNode_(childNode);\n });\n};\n\n/**\n * Aborts all transactions on ancestors or descendants of the specified path. Called when doing a set() or update()\n * since we consider them incompatible with transactions.\n *\n * @param {!Path} path Path for which we want to abort related transactions.\n * @return {!Path}\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).abortTransactions_ = function(path: Path): Path {\n const affectedPath = this.getAncestorTransactionNode_(path).path();\n\n const transactionNode = this.transactionQueueTree_.subTree(path);\n\n transactionNode.forEachAncestor((node: Tree) => {\n this.abortTransactionsOnNode_(node);\n });\n\n this.abortTransactionsOnNode_(transactionNode);\n\n transactionNode.forEachDescendant((node: Tree) => {\n this.abortTransactionsOnNode_(node);\n });\n\n return affectedPath;\n};\n\n/**\n * Abort transactions stored in this transaction queue node.\n *\n * @param {!Tree.>} node Node to abort transactions for.\n * @private\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(Repo.prototype as any).abortTransactionsOnNode_ = function(\n node: Tree\n) {\n const queue = node.getValue();\n if (queue !== null) {\n // Queue up the callbacks and fire them after cleaning up all of our transaction state, since\n // the callback could trigger more transactions or sets.\n const callbacks = [];\n\n // Go through queue. Any already-sent transactions must be marked for abort, while the unsent ones\n // can be immediately aborted and removed.\n let events: Event[] = [];\n let lastSent = -1;\n for (let i = 0; i < queue.length; i++) {\n if (queue[i].status === TransactionStatus.SENT_NEEDS_ABORT) {\n // Already marked. No action needed.\n } else if (queue[i].status === TransactionStatus.SENT) {\n assert(\n lastSent === i - 1,\n 'All SENT items should be at beginning of queue.'\n );\n lastSent = i;\n // Mark transaction for abort when it comes back.\n queue[i].status = TransactionStatus.SENT_NEEDS_ABORT;\n queue[i].abortReason = 'set';\n } else {\n assert(\n queue[i].status === TransactionStatus.RUN,\n 'Unexpected transaction status in abort'\n );\n // We can abort it immediately.\n queue[i].unwatcher();\n events = events.concat(\n this.serverSyncTree_.ackUserWrite(queue[i].currentWriteId, true)\n );\n if (queue[i].onComplete) {\n const snapshot: DataSnapshot | null = null;\n callbacks.push(\n queue[i].onComplete.bind(null, new Error('set'), false, snapshot)\n );\n }\n }\n }\n if (lastSent === -1) {\n // We're not waiting for any sent transactions. We can clear the queue.\n node.setValue(null);\n } else {\n // Remove the transactions we aborted.\n queue.length = lastSent + 1;\n }\n\n // Now fire the callbacks.\n this.eventQueue_.raiseEventsForChangedPath(node.path(), events);\n for (let i = 0; i < callbacks.length; i++) {\n exceptionGuard(callbacks[i]);\n }\n }\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { FirebaseApp } from '@firebase/app-types';\nimport { safeGet } from '@firebase/util';\nimport { Repo } from './Repo';\nimport { fatal } from './util/util';\nimport { parseRepoInfo } from './util/libs/parser';\nimport { validateUrl } from './util/validation';\nimport './Repo_transaction';\nimport { Database } from '../api/Database';\nimport { RepoInfo } from './RepoInfo';\nimport { FirebaseAuthInternalName } from '@firebase/auth-interop-types';\nimport { Provider } from '@firebase/component';\n\n/** @const {string} */\nconst DATABASE_URL_OPTION = 'databaseURL';\n\n/**\n * This variable is also defined in the firebase node.js admin SDK. Before\n * modifying this definition, consult the definition in:\n *\n * https://github.com/firebase/firebase-admin-node\n *\n * and make sure the two are consistent.\n */\nconst FIREBASE_DATABASE_EMULATOR_HOST_VAR = 'FIREBASE_DATABASE_EMULATOR_HOST';\n\nlet _staticInstance: RepoManager;\n\n/**\n * Creates and caches Repo instances.\n */\nexport class RepoManager {\n /**\n * @private {!Object.>}\n */\n private repos_: {\n [appName: string]: {\n [dbUrl: string]: Repo;\n };\n } = {};\n\n /**\n * If true, new Repos will be created to use ReadonlyRestClient (for testing purposes).\n * @private {boolean}\n */\n private useRestClient_: boolean = false;\n\n static getInstance(): RepoManager {\n if (!_staticInstance) {\n _staticInstance = new RepoManager();\n }\n return _staticInstance;\n }\n\n // TODO(koss): Remove these functions unless used in tests?\n interrupt() {\n for (const appName of Object.keys(this.repos_)) {\n for (const dbUrl of Object.keys(this.repos_[appName])) {\n this.repos_[appName][dbUrl].interrupt();\n }\n }\n }\n\n resume() {\n for (const appName of Object.keys(this.repos_)) {\n for (const dbUrl of Object.keys(this.repos_[appName])) {\n this.repos_[appName][dbUrl].resume();\n }\n }\n }\n\n /**\n * This function should only ever be called to CREATE a new database instance.\n *\n * @param {!FirebaseApp} app\n * @return {!Database}\n */\n databaseFromApp(\n app: FirebaseApp,\n authProvider: Provider,\n url?: string\n ): Database {\n let dbUrl: string | undefined = url || app.options[DATABASE_URL_OPTION];\n if (dbUrl === undefined) {\n fatal(\n \"Can't determine Firebase Database URL. Be sure to include \" +\n DATABASE_URL_OPTION +\n ' option when calling firebase.initializeApp().'\n );\n }\n\n let parsedUrl = parseRepoInfo(dbUrl);\n let repoInfo = parsedUrl.repoInfo;\n\n let dbEmulatorHost: string | undefined = undefined;\n if (typeof process !== 'undefined') {\n dbEmulatorHost = process.env[FIREBASE_DATABASE_EMULATOR_HOST_VAR];\n }\n if (dbEmulatorHost) {\n dbUrl = `http://${dbEmulatorHost}?ns=${repoInfo.namespace}`;\n parsedUrl = parseRepoInfo(dbUrl);\n repoInfo = parsedUrl.repoInfo;\n }\n\n validateUrl('Invalid Firebase Database URL', 1, parsedUrl);\n if (!parsedUrl.path.isEmpty()) {\n fatal(\n 'Database URL must point to the root of a Firebase Database ' +\n '(not including a child path).'\n );\n }\n\n const repo = this.createRepo(repoInfo, app, authProvider);\n\n return repo.database;\n }\n\n /**\n * Remove the repo and make sure it is disconnected.\n *\n * @param {!Repo} repo\n */\n deleteRepo(repo: Repo) {\n const appRepos = safeGet(this.repos_, repo.app.name);\n // This should never happen...\n if (!appRepos || safeGet(appRepos, repo.repoInfo_.toURLString()) !== repo) {\n fatal(\n `Database ${repo.app.name}(${repo.repoInfo_}) has already been deleted.`\n );\n }\n repo.interrupt();\n delete appRepos[repo.repoInfo_.toURLString()];\n }\n\n /**\n * Ensures a repo doesn't already exist and then creates one using the\n * provided app.\n *\n * @param {!RepoInfo} repoInfo The metadata about the Repo\n * @param {!FirebaseApp} app\n * @return {!Repo} The Repo object for the specified server / repoName.\n */\n createRepo(\n repoInfo: RepoInfo,\n app: FirebaseApp,\n authProvider: Provider\n ): Repo {\n let appRepos = safeGet(this.repos_, app.name);\n\n if (!appRepos) {\n appRepos = {};\n this.repos_[app.name] = appRepos;\n }\n\n let repo = safeGet(appRepos, repoInfo.toURLString());\n if (repo) {\n fatal(\n 'Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.'\n );\n }\n repo = new Repo(repoInfo, this.useRestClient_, app, authProvider);\n appRepos[repoInfo.toURLString()] = repo;\n\n return repo;\n }\n\n /**\n * Forces us to use ReadonlyRestClient instead of PersistentConnection for new Repos.\n * @param {boolean} forceRestClient\n */\n forceRestClient(forceRestClient: boolean) {\n this.useRestClient_ = forceRestClient;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { fatal } from '../core/util/util';\nimport { parseRepoInfo } from '../core/util/libs/parser';\nimport { Path } from '../core/util/Path';\nimport { Reference } from './Reference';\nimport { Repo } from '../core/Repo';\nimport { RepoManager } from '../core/RepoManager';\nimport { validateArgCount } from '@firebase/util';\nimport { validateUrl } from '../core/util/validation';\nimport { FirebaseApp } from '@firebase/app-types';\nimport { FirebaseService } from '@firebase/app-types/private';\nimport { RepoInfo } from '../core/RepoInfo';\nimport { FirebaseDatabase } from '@firebase/database-types';\n\n/**\n * Class representing a firebase database.\n * @implements {FirebaseService}\n */\nexport class Database implements FirebaseService {\n INTERNAL: DatabaseInternals;\n private root_: Reference;\n\n static readonly ServerValue = {\n TIMESTAMP: {\n '.sv': 'timestamp'\n }\n };\n\n /**\n * The constructor should not be called by users of our public API.\n * @param {!Repo} repo_\n */\n constructor(private repo_: Repo) {\n if (!(repo_ instanceof Repo)) {\n fatal(\n \"Don't call new Database() directly - please use firebase.database().\"\n );\n }\n\n /** @type {Reference} */\n this.root_ = new Reference(repo_, Path.Empty);\n\n this.INTERNAL = new DatabaseInternals(this);\n }\n\n get app(): FirebaseApp {\n return this.repo_.app;\n }\n\n /**\n * Returns a reference to the root or to the path specified in the provided\n * argument.\n *\n * @param {string|Reference=} path The relative string path or an existing\n * Reference to a database location.\n * @throws If a Reference is provided, throws if it does not belong to the\n * same project.\n * @return {!Reference} Firebase reference.\n */\n ref(path?: string): Reference;\n ref(path?: Reference): Reference;\n ref(path?: string | Reference): Reference {\n this.checkDeleted_('ref');\n validateArgCount('database.ref', 0, 1, arguments.length);\n\n if (path instanceof Reference) {\n return this.refFromURL(path.toString());\n }\n\n return path !== undefined ? this.root_.child(path) : this.root_;\n }\n\n /**\n * Returns a reference to the root or the path specified in url.\n * We throw a exception if the url is not in the same domain as the\n * current repo.\n * @param {string} url\n * @return {!Reference} Firebase reference.\n */\n refFromURL(url: string): Reference {\n /** @const {string} */\n const apiName = 'database.refFromURL';\n this.checkDeleted_(apiName);\n validateArgCount(apiName, 1, 1, arguments.length);\n const parsedURL = parseRepoInfo(url);\n validateUrl(apiName, 1, parsedURL);\n\n const repoInfo = parsedURL.repoInfo;\n if (repoInfo.host !== (this.repo_.repoInfo_ as RepoInfo).host) {\n fatal(\n apiName +\n ': Host name does not match the current database: ' +\n '(found ' +\n repoInfo.host +\n ' but expected ' +\n (this.repo_.repoInfo_ as RepoInfo).host +\n ')'\n );\n }\n\n return this.ref(parsedURL.path.toString());\n }\n\n /**\n * @param {string} apiName\n */\n private checkDeleted_(apiName: string) {\n if (this.repo_ === null) {\n fatal('Cannot call ' + apiName + ' on a deleted database.');\n }\n }\n\n // Make individual repo go offline.\n goOffline() {\n validateArgCount('database.goOffline', 0, 0, arguments.length);\n this.checkDeleted_('goOffline');\n this.repo_.interrupt();\n }\n\n goOnline() {\n validateArgCount('database.goOnline', 0, 0, arguments.length);\n this.checkDeleted_('goOnline');\n this.repo_.resume();\n }\n}\n\nexport class DatabaseInternals {\n /** @param {!Database} database */\n constructor(public database: Database) {}\n\n /** @return {Promise} */\n async delete(): Promise {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this.database as any).checkDeleted_('delete');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n RepoManager.getInstance().deleteRepo((this.database as any).repo_ as Repo);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this.database as any).repo_ = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (this.database as any).root_ = null;\n this.database.INTERNAL = null;\n this.database = null;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WebSocketConnection } from '../realtime/WebSocketConnection';\nimport { BrowserPollConnection } from '../realtime/BrowserPollConnection';\nimport { Reference } from './Reference';\n\n/**\n * INTERNAL methods for internal-use only (tests, etc.).\n *\n * Customers shouldn't use these or else should be aware that they could break at any time.\n *\n * @const\n */\n\nexport const forceLongPolling = function() {\n WebSocketConnection.forceDisallow();\n BrowserPollConnection.forceAllow();\n};\n\nexport const forceWebSockets = function() {\n BrowserPollConnection.forceDisallow();\n};\n\n/* Used by App Manager */\nexport const isWebSocketsAvailable = function(): boolean {\n return WebSocketConnection['isAvailable']();\n};\n\nexport const setSecurityDebugCallback = function(\n ref: Reference,\n callback: (a: object) => void\n) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (ref.repo.persistentConnection_ as any).securityDebugCallback_ = callback;\n};\n\nexport const stats = function(ref: Reference, showDelta?: boolean) {\n ref.repo.stats(showDelta);\n};\n\nexport const statsIncrementCounter = function(ref: Reference, metric: string) {\n ref.repo.statsIncrementCounter(metric);\n};\n\nexport const dataUpdateCount = function(ref: Reference): number {\n return ref.repo.dataUpdateCount;\n};\n\nexport const interceptServerData = function(\n ref: Reference,\n callback: ((a: string, b: unknown) => void) | null\n) {\n return ref.repo.interceptServerData_(callback);\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RepoInfo } from '../core/RepoInfo';\nimport { PersistentConnection } from '../core/PersistentConnection';\nimport { RepoManager } from '../core/RepoManager';\nimport { Connection } from '../realtime/Connection';\nimport { Query } from './Query';\n\nexport const DataConnection = PersistentConnection;\n\n/**\n * @param {!string} pathString\n * @param {function(*)} onComplete\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(PersistentConnection.prototype as any).simpleListen = function(\n pathString: string,\n onComplete: (a: unknown) => void\n) {\n this.sendRequest('q', { p: pathString }, onComplete);\n};\n\n/**\n * @param {*} data\n * @param {function(*)} onEcho\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\n(PersistentConnection.prototype as any).echo = function(\n data: unknown,\n onEcho: (a: unknown) => void\n) {\n this.sendRequest('echo', { d: data }, onEcho);\n};\n\n// RealTimeConnection properties that we use in tests.\nexport const RealTimeConnection = Connection;\n\n/**\n * @param {function(): string} newHash\n * @return {function()}\n */\nexport const hijackHash = function(newHash: () => string) {\n const oldPut = PersistentConnection.prototype.put;\n PersistentConnection.prototype.put = function(\n pathString,\n data,\n onComplete,\n hash\n ) {\n if (hash !== undefined) {\n hash = newHash();\n }\n oldPut.call(this, pathString, data, onComplete, hash);\n };\n return function() {\n PersistentConnection.prototype.put = oldPut;\n };\n};\n\n/**\n * @type {function(new:RepoInfo, !string, boolean, !string, boolean): undefined}\n */\nexport const ConnectionTarget = RepoInfo;\n\n/**\n * @param {!Query} query\n * @return {!string}\n */\nexport const queryIdentifier = function(query: Query) {\n return query.queryIdentifier();\n};\n\n/**\n * Forces the RepoManager to create Repos that use ReadonlyRestClient instead of PersistentConnection.\n *\n * @param {boolean} forceRestClient\n */\nexport const forceRestClient = function(forceRestClient: boolean) {\n RepoManager.getInstance().forceRestClient(forceRestClient);\n};\n","/**\n * @license\n * Copyright 2017 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport firebase from '@firebase/app';\nimport { FirebaseNamespace } from '@firebase/app-types';\nimport { _FirebaseNamespace } from '@firebase/app-types/private';\nimport { Database } from './src/api/Database';\nimport { DataSnapshot } from './src/api/DataSnapshot';\nimport { Query } from './src/api/Query';\nimport { Reference } from './src/api/Reference';\nimport { enableLogging } from './src/core/util/util';\nimport { RepoManager } from './src/core/RepoManager';\nimport * as INTERNAL from './src/api/internal';\nimport * as TEST_ACCESS from './src/api/test_access';\nimport { isNodeSdk } from '@firebase/util';\nimport * as types from '@firebase/database-types';\nimport { setSDKVersion } from './src/core/version';\nimport { Component, ComponentType } from '@firebase/component';\n\nimport { name, version } from './package.json';\n\nconst ServerValue = Database.ServerValue;\n\nexport function registerDatabase(instance: FirebaseNamespace) {\n // set SDK_VERSION\n setSDKVersion(instance.SDK_VERSION);\n\n // Register the Database Service with the 'firebase' namespace.\n const namespace = (instance as _FirebaseNamespace).INTERNAL.registerComponent(\n new Component(\n 'database',\n (container, url) => {\n /* Dependencies */\n // getImmediate for FirebaseApp will always succeed\n const app = container.getProvider('app').getImmediate();\n const authProvider = container.getProvider('auth-internal');\n\n return RepoManager.getInstance().databaseFromApp(\n app,\n authProvider,\n url\n );\n },\n ComponentType.PUBLIC\n )\n .setServiceProps(\n // firebase.database namespace properties\n {\n Reference,\n Query,\n Database,\n DataSnapshot,\n enableLogging,\n INTERNAL,\n ServerValue,\n TEST_ACCESS\n }\n )\n .setMultipleInstances(true)\n );\n\n instance.registerVersion(name, version);\n\n if (isNodeSdk()) {\n module.exports = namespace;\n }\n}\n\nregisterDatabase(firebase);\n\n// Types to export for the admin SDK\nexport { Database, Query, Reference, enableLogging, ServerValue };\n\nexport { DataSnapshot } from './src/api/DataSnapshot';\nexport { OnDisconnect } from './src/api/onDisconnect';\n\ndeclare module '@firebase/app-types' {\n interface FirebaseNamespace {\n database?: {\n (app?: FirebaseApp): types.FirebaseDatabase;\n enableLogging: typeof types.enableLogging;\n ServerValue: types.ServerValue;\n Database: typeof types.FirebaseDatabase;\n };\n }\n interface FirebaseApp {\n database?(databaseURL?: string): types.FirebaseDatabase;\n }\n}\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","hasOwnProperty","__extends","__","this","constructor","prototype","create","__assign","assign","t","s","i","n","arguments","length","call","apply","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","adopt","then","__generator","body","f","y","g","_","label","sent","trys","ops","verb","throw","return","Symbol","iterator","v","op","TypeError","pop","push","__values","o","m","__read","r","ar","error","__spread","concat","stringToByteArray","str","out","c","charCodeAt","base64Decode","base64","decodeString","console","CONSTANTS","NODE_CLIENT","NODE_ADMIN","SDK_VERSION","assert","assertion","message","assertionError","Error","byteToCharMap_","charToByteMap_","byteToCharMapWebSafe_","charToByteMapWebSafe_","ENCODED_VALS_BASE","ENCODED_VALS","ENCODED_VALS_WEBSAFE","HAS_NATIVE_SUPPORT","atob","encodeByteArray","input","webSafe","isArray","init_","byteToCharMap","output","byte1","haveByte2","byte2","haveByte3","byte3","outByte1","outByte2","outByte3","outByte4","join","encodeString","btoa","bytes","pos","c1","String","fromCharCode","c2","u","c3","byteArrayToString","decodeStringToByteArray","charToByteMap","charAt","byte4","deepCopy","deepExtend","target","source","Date","dateValue","getTime","undefined","prop","Deferred","callback","_this","promise","catch","isMobileCordova","window","test","navigator","isNodeSdk","code","_super","FirebaseError","captureStackTrace","ErrorFactory","_i","data","customData","fullCode","service","template","errors","replace","PATTERN","key","toString","replaceTemplate","fullMessage","serviceName","_b","keys","_a","slice","warn","jsonEval","JSON","parse","stringify","decode","token","header","claims","signature","parts","split","contains","obj","safeGet","isEmpty","map","fn","contextObj","res","Sha1","chain_","inbuf_","total_","buf","offset","W","W_","k","a","lengthMinusBlock","blockSize","buf_","inbuf","compress_","digest","totalBits","update","pad_","j","reset","validateArgCount","fnName","minCount","maxCount","argCount","argError","errorPrefix","argumentNumber","optional","argName","validateCallback","validateContextObject","context","stringLength","LogLevel","defaultLogHandler","instance","logType","args","logLevel","now","toISOString","DEBUG","VERBOSE","log","name","INFO","info","WARN","ERROR","defaultLogLevel","Logger","_logLevel","val","_logHandler","Component","mode","instantiationMode","multipleInstances","props","serviceProps","instanceFactory","type","DOMStorageWrapper","domStorage_","removeItem","prefixedName_","setItem","storedVal","getItem","prefix_","MemoryStorage","cache_","createStoragefor","domStorageName","domStorage","sha1","utf8Bytes","high","sha1Bytes","enableLogging","logger_","persistent","logClient","logger","bind","SessionStorage","set","remove","varArgs","firstLog_","get","buildLogMessage_","logWrapper","prefix","fatal","isInvalidJSONNumber","Number","POSITIVE_INFINITY","NEGATIVE_INFINITY","stringCompare","requireKey","splitStringBySize","segsize","len","dataSegs","substring","id","PersistentStorage","LUIDGenerator","arg","MIN_NAME","MAX_NAME","nameCompare","aAsInt","tryParseInt","bAsInt","ObjectToUniqueKey","sort","each","doubleToIEEE754String","ln","Infinity","Math","abs","pow","min","floor","LN2","round","bits","reverse","hexByteString","hexByte","parseInt","substr","toLowerCase","exceptionGuard","setTimeout","stack","setTimeoutNonBlocking","time","timeout","INTEGER_REGEXP_","RegExp","intVal","Path","pieceNum_","pieces_","pieceNum","pathString","encodeURIComponent","begin","pieces","childPathObj","childPieces","outerPath","innerPath","outer","getFront","inner","relativePath","popFront","left","right","leftKeys","rightKeys","cmp","other","getLength","pathOrString","copyTo","ValidationPath","child","parts_","byteLength_","checkValid_","last","MAX_PATH_LENGTH_BYTES","errorPrefix_","MAX_PATH_DEPTH","toErrorString","path","max","FORGE_DOMAIN","WEBSOCKET","LONG_POLLING","RepoInfo","host","internalHost","isCustomHost","includeNamespaceInQueryParams","domain","newHost","isCacheableHost","params","connURL","secure","needsQueryParam","namespace","pairs","toURLString","persistenceKey","webSocketOnly","indexOf","parseRepoInfo","dataURL","parsedUrl","parseDatabaseURL","location","protocol","scheme","repoInfo","subdomain","isValidKey","INVALID_KEY_REGEX_","isValidPathString","INVALID_PATH_REGEX_","isValidPriority","priority","validateFirebaseDataArg","validateFirebaseData","errorPrefixFxn","validateFirebaseMergeDataArg","mergePaths","curPath","getBack","comparePaths","prevPath","validateFirebaseMergePaths","validatePriority","validateEventType","eventType","validateKey","validatePathString","validateWritablePath","validateUrl","isValidRootPathString","port","colonInd","slashInd","questionMarkInd","pathStringDecoded","piece","decodeURIComponent","decodePath","queryParams","queryString","results","segment","kv","decodeQuery","MAX_LEAF_SIZE_","path_","hasDotValue_1","hasActualChild_1","OnDisconnect","onComplete","deferred","repo_","onDisconnectCancel","wrapCallback","onDisconnectSet","onDisconnectSetWithPriority","objectToMerge","newObjectToMerge","onDisconnectUpdate","TransactionResult","committed","snapshot","toJSON","PUSH_CHARS","lastPushTime","lastRandChars","nextPushId","duplicateTime","timeStampChars","random","NamedNode","node","__EMPTY_NODE","Index","compare","oldNode","newNode","oldWrapped","newWrapped","MIN","KeyIndex","indexValue","MAX_NODE","KEY_INDEX","priorityHashText","validatePriorityNode","priorityNode","isLeafNode","getPriority","__childrenNodeConstructor","nodeFromJSON","LeafNode","priorityNode_","newPriorityNode","value_","childName","EMPTY_NODE","childNode","newChildNode","updatePriority","updateImmediateChild","front","updateChild","index","action","exportFormat",".value","getValue",".priority","lazyHash_","toHash","compareToLeafNode_","otherLeaf","otherLeafType","thisLeafType","otherIndex","VALUE_TYPE_ORDER","thisIndex","equals","PRIORITY_INDEX","PriorityIndex","aPriority","bPriority","indexCmp","compareTo","SortedMapIterator","nodeStack_","resultGenerator_","isReverse_","startKey","comparator","LLRBNode","color","count","inorderTraversal","reverseTraversal","min_","maxKey","copy","insert","fixUp_","SortedMap","isRed_","moveRedLeft_","removeMin_","smallest","rotateRight_","moveRedRight_","rotateLeft_","colorFlip_","nl","RED","nr","blackDepth","check_","LLRBEmptyNode","comparator_","root_","BLACK","rightParent","minKey","resultGenerator","LOG_2","Base12Num","bits_","current_","num","mask","_defaultIndexMap","buildChildSet","childList","keyFn","mapSortFn","buildBalancedTree","low","namedNode","middle","root","base12","buildPennant","chunkSize","childTree","attachPennant","pennant","isOne","nextBitIsOne","buildFrom12Array","fallbackObject","IndexMap","indexKey","sortedMap","indexes_","indexDefinition","indexSet_","existingChildren","newIndex","sawIndexedValue","iter","getIterator","Wrap","getNext","isDefinedOn","getCompare","indexName","newIndexSet","newIndexes","indexedChildren","existingSnap","newChildren","NAME_ONLY_COMPARATOR","NAME_COMPARATOR","ChildrenNode","Default","children_","indexMap_","getImmediateChild","getChild","newIndexMap","removeFromIndexes","addToIndexes","newPriority","newImmediateChild","numKeys","allIntegerKeys","forEachChild","array","toHash_1","childHash","hash","idx","resolveIndex_","predecessor","getPredecessorKey","getFirstChildName","getLastChildName","wrappedNode","getIteratorFrom","minPost","startPost","peek","getReverseIteratorFrom","maxPost","endPost","hasIndex","addIndex","otherChildrenNode","thisIter","otherIter","thisCurrent","otherCurrent","MaxNode","defineProperties","MAX","USE_HINZE","json","node_1","childData","children_1","childrenHavePriority_1","childSet","sortedChildSet","VALUE_INDEX","ValueIndex","valueNode","PathIndex","snap","indexPath_","aChild","extractChild","bChild","DataSnapshot","node_","exportVal","childPathString","childPath","childRef","ref_","index_","getKey","numChildren","getRef","DataEvent","ref","getParent","eventRegistration","getEventRunner","getPath","prevName","CancelEvent","ValueEventRegistration","change","query","getQueryParams","getIndex","snapshotNode","eventData","ctx","context_","getEventType","cancelCallback_","cancelCB_1","cb_1","callback_","__referenceConstructor","ChildEventRegistration","eventToCheck","callbacks_","cancelCB_2","cb_2","otherKeys","thisKeys","otherCount","every","otherKey","thisKey","Query","startNode","endNode","hasStart","getIndexStartValue","hasEnd","getIndexEndValue","tooManyArgsError","wrongArgTypeError","getIndexStartName","getIndexEndName","hasLimit","hasAnchoredLimit","orderByCalled_","queryParams_","repo","cancelCallbackOrContext","ret","getCancelAndContextArgs_","onValueEvent","cancel","callbacks","onChildEvent","cancelCallback","container","addEventCallbackForQuery","removeEventCallbackForQuery","userCallback","failureCallbackOrContext","firstCall","onceCallback","off","on","err","limit","limitToFirst","limitToLast","validateNoPreviousOrderByCall_","parsedPath","newParams","orderBy","validateQueryEndpoints_","startAt","validateLimit_","endAt","toUrlEncodedString","getQueryObject","queryObject","sameRepo","samePath","sameQueryIdentifier","queryIdentifier","cancelOrContext","SparseSnapshotTree","children","size","childKey","has","find","clear","remember","self_1","tree","forget","delete","prefixPath","func","forEachTree","forEach","Map","resolveDeferredValue","serverValues","OperationType","resolveDeferredValueSnapshot","rawPri","leafNode","childrenNode","OperationSource","queryId","fromUser","fromServer","tagged","emptyChildrenSingleton","AckUserWrite","affectedTree","subtree","Empty","revert","ACK_USER_WRITE","User","ImmutableTree","childSnap","predicate","childExistingPathAndValue","findRootMostMatchingPathAndValue","toSet","newChild","newTree","setTree","fold_","pathSoFar","accum","findOnPath_","pathToFollow","nextChild","foreachOnPath_","currentRelativePath","foreach_","ListenComplete","LISTEN_COMPLETE","Overwrite","OVERWRITE","Merge","MERGE","CacheNode","fullyInitialized_","filtered_","isFullyInitialized","isCompleteForChild","hasChild","ViewCache","eventSnap","complete","filtered","serverCache_","serverSnap","eventCache_","getNode","Change","VALUE","CHILD_ADDED","CHILD_REMOVED","newSnapshot","oldSnapshot","CHILD_CHANGED","CHILD_MOVED","oldSnap","IndexedFilter","affectedPath","optChangeAccumulator","isIndexed","oldChild","trackChildChange","childRemovedChange","childAddedChange","childChangedChange","withIndex","newSnap","ChildChangeAccumulator","oldChange","changeMap","oldType","from","values","NO_COMPLETE_CHILD_SOURCE","NoCompleteChildSource_","WriteTreeCompleteChildSource","viewCache_","getEventCache","serverNode","optCompleteServerCache_","getServerCache","writes_","calcCompleteChild","completeServerData","getCompleteServerSnap","nodes","calcIndexedSlice","viewCache","changes","ViewProcessor","filter_","oldViewCache","operation","writesCache","completeCache","newViewCache","filterServerNode","accumulator","overwrite","applyUserOverwrite_","isFiltered","applyServerOverwrite_","merge","applyUserMerge_","applyServerMerge_","ackUserWrite","revertUserWrite_","ackUserWrite_","listenComplete_","getChanges","maybeAddValueEvent_","ProcessorResult","isLeafOrEmpty","oldCompleteSnap","getCompleteEventSnap","valueChange","changePath","oldEventSnap","shadowingWrite","newEventCache","serverCache","completeChildren","completeEventChildren","calcCompleteEventChildren","updateFullNode","completeNode","calcCompleteEventCache","oldEventNode","updatedPriority","calcEventCacheAfterServerOverwrite","childChangePath","newEventChild","eventChildUpdate","updateEventSnap","filtersNodes","changedSnap","newServerCache","oldServerSnap","serverFilter","getIndexedFilter","newServerNode","isCompleteForPath","updateServerSnap","generateEventCacheAfterServerEvent_","getCompleteChild","parent","newEventSnap","changedChildren","curViewCache","foreach","writePath","cacheHasChild_","viewMergeTree","serverChild","applyMerge_","childMergeTree","isUnknownDeepMerge","ackPath","changedChildren_1","changedChildren_2","mergePath","serverCachePath","oldServerNode","completeServerCache","oldEventCache","serverChildren","EventGenerator","eventCache","eventRegistrations","events","moves","indexedValueChanged","childMovedChange","generateEventsForType_","registrations","filteredChanges","filter","compareChanges_","materializedChange","materializeSingleChange_","registration","respondsTo","createEvent","query_","getPredecessorChildName","aWrapped","bWrapped","View","cache","loadsAllData","eventRegistrations_","cancelError","cancelEvents","path_1","maybeEvent","createCancelEvent","remaining","existing","matches","hasAnyCallback","processor_","applyOperation","assertIndexed","generateEventsForChanges_","initialChanges","eventGenerator_","generateEventsForChanges","initialViewCache","indexFilter","getNodeFilter","initialServerCache","initialEventCache","SyncPoint","views","optCompleteServerCache","view","serverCacheComplete","eventCacheComplete","addEventRegistration","getInitialEvents","removed","hadCompleteView","hasCompleteView","entries","_d","viewQueryId","removeEventRegistration","getQuery","getCompleteServerCache","getCompleteView","viewForQuery","CompoundWrite","rootmost","writeTree_","findRootMostValueAndPath","rootMostPath","updates","newWrite","addWrite","getCompleteNode","shadowingNode","applySubtreeWrite","writeTree","priorityWrite_1","WriteTree","WriteTreeRef","writeId","visible","lastWriteId_","allWrites_","visibleWrites_","addWrites","record","findIndex","writeToRemove","splice","removedWriteWasVisible","removedWriteOverlapsWithOtherWrites","currentWrite","recordContainsPath_","resetTree_","removeWrite","treePath","writeIdsToExclude","includeHiddenWrites","childCompoundWrite","hasCompleteWrite","mergeAtPath","layerTree_","write","layeredCache","subMerge","completeServerChildren","topLevelSet","merge_1","getCompleteChildren","existingEventSnap","existingServerSnap","childMerge","toIterate","writeRecord","DefaultFilter_","writes","treeRoot","compoundWrite","deepNode","treePath_","existingServerCache","SyncTree","newData","pendingWriteTree_","addOverwrite","applyOperationToSyncPoints_","addMerge","changeTree","fromObject","getWrite","affectedTree_1","Server","tag","queryKey","queryKeyForTag_","parseQueryKey_","queryPath","forServerTaggedQuery","applyTaggedOperation_","foundAncestorDefaultView","syncPointTree_","foreachOnPath","pathToSyncPoint","sp","syncPoint","foreachChild","childSyncPoint","viewAlreadyExists","viewExistsForQuery","makeQueryKey_","queryToTagMap","getNextQueryTag_","tagToQueryMap","childWrites","setupListener_","maybeSyncPoint","removedAndEvents","removingDefault","covered","findOnPath","parentSyncPoint","newViews","collectDistinctViewsForSubTree_","newQuery","listener","createListenerForView_","listenProvider_","startListening","queryForListening_","tagForQuery_","hashFn","stopListening","queryToRemove","tagToRemove","removeTags_","fold","maybeChildSyncPoint","childMap","views_1","getQueryViews","_key","childViews","queries","removedQuery","removedQueryKey","removedQueryTag","isDefault","queriesToStop","queries_1","childQueries","queryToStop","status","applyTaggedListenComplete","applyListenComplete","reason","toUpperCase","errorForServerCode","splitIndex","nextQueryTag_","applyOperationHelper_","syncPointTree","applyOperationDescendantsHelper_","childOperation","operationForChild","childServerCache","childWritesCache","SnapshotHolder","rootNode_","newSnapshotNode","AuthTokenProvider","forceRefresh","auth_","getToken","addAuthTokenListener","authProvider_","auth","removeAuthTokenListener","errorMessage","app_","options","getImmediate","StatsCollection","amount","counters_","StatsManager","hashString","collections_","creatorFunction","reporters_","StatsListener","newStats","collection_","delta","last_","stat","StatsReporter","statsToReport_","stats","statsListener_","reportedStats","haveStatsToReport","server_","reportStats","reportStats_","collection","EventQueue","eventDataList","currList","eventPath","eventLists_","EventList","add","queueEvents","raiseQueuedEventsMatchingPredicate_","changedPath","recursionDepth_","sentAll","eventList","raise","events_","eventFn","EventEmitter","listeners_","listeners","validateEventType_","getInitialEvent","allowedEvents_","et","VisibilityMonitor","visible_","hidden","visibilityChange","document","addEventListener","trigger","OnlineMonitor","online_","PacketReceiver","responseNum","closeAfterResponse","onClose","currentResponseNum","requestNum","pendingResponses","toProcess","this_1","onMessage_","BrowserPollConnection","onMessage","onDisconnect","curSegmentNum","onDisconnect_","myPacketOrderer","isClosed_","connectTimeoutTimer_","log_","onClosed_","readyState","called_1","wrappedFn_1","attachEvent","executeWhenDOMReady","scriptTagHolder","FirebaseIFrameScriptHolder","command","arg1","arg2","incrementIncomingBytes_","clearTimeout","everConnected_","password","sendNewPolls","closeAfter","pN","handleResponse","urlFn","urlParams","start","uniqueCallbackIdentifier","transportSessionId","lastSessionId","href","connectURL","addTag","startLongPoll","addDisconnectPingFrame","forceAllow_","forceDisallow_","createElement","Windows","UI","close","myDisconnFrame","removeChild","shutdown_","dataStr","bytesSent","stats_","incrementCounter","base64data","base64Encode","MAX_URL_DATA_SIZE","enqueueSegment","pw","dframe","src","style","display","appendChild","bytesReceived","connId","getCollection","connectionURL","iframe","contentWindow","contentDocument","doc","alive","myIFrame","innerHTML","myID","myPW","newRequest_","outstandingRequests","pendingSegs","currentSerial","theURL","curDataString","theSeg","shift","seg","ts","addLongPollTag_","segnum","totalsegs","url","serial","doNewRequest","keepaliveTimeout","loadCB","newScript_1","async","onload","onreadystatechange","rstate","parentNode","onerror","commandCB","onMessageCB","Set","createIFrame_","script","iframeContents","open","WebSocketImpl","MozWebSocket","WebSocket","WebSocketConnection","device","ENV_CONSTANTS","headers","User-Agent","process","platform","env","proxy","origin","mySock","onopen","onclose","onmessage","handleIncomingFrame","isOldAndroid","userAgent","oldAndroidMatch","match","parseFloat","isInMemoryStorage","frames","totalFrames","fullMess","jsonMess","frameCount","isNaN","handleNewFrameCount_","mess","resetKeepAlive","appendFrame_","remainingData","extractFrameCount_","sendString_","keepaliveTimer","clearInterval","setInterval","send","connectionURL_","TransportManager","isWebSocketsAvailable","isSkipPollConnection","previouslyFailed","transports_","transports","ALL_TRANSPORTS","transport","initTransports_","Connection","conn","transportManager_","initialTransport","conn_","nextTransportId_","repoInfo_","primaryResponsesRequired_","onMessageReceived","connReceiver_","onConnectionLost","disconnReceiver_","tx_","rx_","secondaryConn_","isHealthy_","healthyTimeoutMS","healthyTimeout_","markConnectionHealthy","connectionCount","everConnected","onConnectionLost_","onSecondaryConnectionLost_","state_","onPrimaryMessageReceived_","onSecondaryMessageReceived_","dataMsg","msg","sendData_","controlData","cmd","upgradeIfSecondaryHealthy_","secondaryResponsesRequired_","parsedData","layer","onSecondaryControl_","pendingDataMessages","proceedWithUpgrade_","tryCleanupConnection","onControl_","onDataMessage_","onPrimaryResponse_","payload","onHandshake_","onConnectionShutdown_","onReset_","sendPingOnPrimaryIfNecessary_","handshake","timestamp","version","h","sessionId","updateHost","onConnectionEstablished_","tryStartUpgrade_","upgradeTransport","startUpgrade_","closeConnections_","start_","onReady_","onKill_","ServerActions","PersistentConnection","onResponse","curReqNum","requestNumber_","connected_","realtime_","sendRequest","requestCBHash_","currentHashFn","listens","listenSpec","sendListen_","req","warnOnListenWarnings_","removeListen_","warnings","indexSpec","indexPath","authToken_","tryAuth","reduceReconnectDelayIfAdminCredential_","credential","isAdmin","maxReconnectDelay_","token_1","authMethod","isValidFormat","requestData","cred","authOverride_","invalidAuthTokenCount_","onAuthRevoked_","sendUnlisten_","queryObj","sendOnDisconnect_","onDisconnectRequestQueue_","request","response","putInternal","outstandingPuts_","outstandingPutCount_","sendPut_","queued","errorReason","reqNum","onDataPush_","onDataUpdate_","onListenRevoked_","onSecurityDebugPacket_","lastConnectionEstablishedTime_","handleTimestamp_","firstConnection_","sendConnectStats_","restoreState_","onConnectStatus_","establishConnectionTimer_","establishConnection_","reconnectDelay_","scheduleConnect_","online","cancelSentTransactions_","shouldReconnect_","lastConnectionAttemptTime_","timeSinceLastConnectAttempt","reconnectDelay","onDataMessage_1","onReady_1","onDisconnect_1","onRealtimeDisconnect_","connId_1","nextConnectionId_","lastSessionId_1","canceled_1","connection_1","closeFn_1","forceTokenRefresh_","authTokenProvider_","accessToken","interrupt","interruptReasons_","onServerInfoUpdate_","serverTimeOffset","put","q","listen","normalizedPathString","statusCode","explanation","notifyForInvalidToken","securityDebugCallback_","_c","_e","getInstance","currentlyOnline","nextPersistentConnectionId_","onVisible_","onOnline_","ReadonlyRestClient","listenId","getListenId_","thisListen","listens_","queryStringParameters","toRestQueryStringParameters","restRequest_","authTokenData","authToken","querystringParams","arrayVal","querystring","xhr","XMLHttpRequest","responseText","INTERRUPT_REASON","Repo","infoData_","generateWithValues","serverTime","isMerge","dataUpdateCount","interceptServerDataCallback_","taggedChildren","raw","serverSyncTree_","applyTaggedQueryMerge","taggedSnap","applyTaggedQueryOverwrite","applyServerMerge","applyServerOverwrite","rerunTransactions_","eventQueue_","raiseEventsForChangedPath","connectStatus","updateInfo_","runOnDisconnectEvents_","updateSnapshot","infoSyncTree_","nextWriteId_","newVal","generateServerValues","newNodeUnresolved","getNextWriteId_","applyUserOverwrite","success","clearEvents","callOnCompleteCallback","abortTransactions_","childrenToMerge","empty","changedKey","changedValue","writeId_1","applyUserMerge","resolvedOnDisconnectTree","resolvedTree","resolveDeferredValueTree","onDisconnectPut","onDisconnectMerge","raiseEventsAtPath","persistentConnection_","resume","showDelta","longestName","reduce","previousValue","currentValue","paddedStat","metric","statsReporter_","includeStat","__database","Database","forceRestClient","app","authProvider","authTokenProvider","search","authOverride","addTokenChangeListener","refreshAuthToken","getOrCreateReporter","transactionsInit_","infoEvents","unlisten","RangedFilter","startPost_","endPost_","getStartPost","getEndPost","indexedFilter_","self","startName","makePost","endName","getStartPost_","getEndPost_","LimitedFilter","rangedFilter_","limit_","fullLimitUpdateChild_","reverse_","hasNext","getReverseIterator","indexCompare_1","foundStartPost","changeAccumulator","indexCmp_1","newChildNamedNode","windowBoundary","getFirstChild","getLastChild","inRange","oldChildSnap","getChildAfterChild","compareNext","getLimit","isViewFromLeft","QueryParams","startSet_","viewFrom_","WIRE_PROTOCOL_CONSTANTS_","VIEW_FROM_LEFT","indexStartValue_","startNameSet_","indexStartName_","endSet_","indexEndValue_","endNameSet_","indexEndName_","limitSet_","newLimit","copy_","VIEW_FROM_RIGHT","WIRE_PROTOCOL_CONSTANTS","INDEX_START_VALUE","INDEX_START_NAME","INDEX_END_VALUE","INDEX_END_NAME","LIMIT","viewFrom","VIEW_FROM","INDEX","REST_CONSTANTS","REST_QUERY_CONSTANTS_","qs","ORDER_BY","START_AT","END_AT","LIMIT_TO_FIRST","LIMIT_TO_LAST","Reference","validateRootPathString","parentPath","database","setWithPriority","transactionUpdate","applyLocally","bool","validateBoolean","startTransaction","thennablePushRef","pushRef","databaseProp","getRoot","DEFAULT","TransactionStatus","Tree","pathObj","TreeNode","updateParents_","childCount","hasChildren","includeSelf","childrenFirst","forEachDescendant","forEachImmediateDescendantWithValue","parent_","name_","updateChild_","childEmpty","childExists","MAX_TRANSACTION_RETRIES_","transactionQueueTree_","valueCallback","watchRef","transaction","order","retryCount","unwatcher","abortReason","currentWriteId","currentInputSnapshot","currentOutputSnapshotRaw","currentOutputSnapshotResolved","currentState","getLatestState_","RUN","queueNode","subTree","nodeQueue","setValue","priorityForNode","sendReadyTransactions_","excludeSets","pruneCompletedTransactionsBelowNode_","queue","buildTransactionQueue_","sendTransactionQueue_","setsToIgnore","txn","latestState","snapToSend","latestHash","SENT","dataToSend","pathToSend","COMPLETED","SENT_NEEDS_ABORT","NEEDS_ABORT","rootMostTransactionNode","getAncestorTransactionNode_","rerunTransactionQueue_","abortTransaction","currentNode","newDataNode","oldWriteId","newNodeResolved","lastInput","transactionNode","transactionQueue","aggregateTransactionQueuesForNode_","to","forEachAncestor","abortTransactionsOnNode_","lastSent","_staticInstance","DATABASE_URL_OPTION","RepoManager","repos_","appName","dbUrl","dbEmulatorHost","createRepo","appRepos","useRestClient_","checkDeleted_","refFromURL","apiName","parsedURL","TIMESTAMP",".sv","INTERNAL","DatabaseInternals","deleteRepo","forceDisallow","forceAllow","statsIncrementCounter","interceptServerData_","DataConnection","simpleListen","echo","onEcho","RealTimeConnection","ConnectionTarget","newHash","oldPut","ServerValue","firebase","registerComponent","getProvider","databaseFromApp","setServiceProps","TEST_ACCESS","setMultipleInstances","registerVersion"],"mappings":"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"}