HEX
Server: nginx/1.28.3
System: Linux lightweb-s1 5.15.0-173-generic #183-Ubuntu SMP Fri Mar 6 13:29:34 UTC 2026 x86_64
User: dawonefr-98 (1071)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: /home/dnlightw-124/dn.lightweb.kr/node_modules/firebase/firebase-database.js.map
{"version":3,"file":"firebase-database.js","sources":["../util/dist/postinstall.mjs","../util/src/constants.ts","../util/src/assert.ts","../util/src/crypt.ts","../util/src/deepCopy.ts","../util/src/defaults.ts","../util/src/global.ts","../util/src/deferred.ts","../util/src/environment.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","../util/src/compat.ts","../component/src/component.ts","../component/src/constants.ts","../component/src/provider.ts","../component/src/component_container.ts","../logger/src/logger.ts","../database/src/core/version.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/AppCheckTokenProvider.ts","../database/src/core/AuthTokenProvider.ts","../database/src/realtime/Constants.ts","../database/src/core/RepoInfo.ts","../database/src/core/stats/StatsCollection.ts","../database/src/core/stats/StatsManager.ts","../database/src/realtime/polling/PacketReceiver.ts","../database/src/realtime/BrowserPollConnection.ts","../database/src/realtime/WebSocketConnection.ts","../database/src/realtime/TransportManager.ts","../database/src/realtime/Connection.ts","../database/src/core/ServerActions.ts","../database/src/core/util/EventEmitter.ts","../database/src/core/util/OnlineMonitor.ts","../database/src/core/util/Path.ts","../database/src/core/util/VisibilityMonitor.ts","../database/src/core/PersistentConnection.ts","../database/src/core/snap/Node.ts","../database/src/core/snap/indexes/Index.ts","../database/src/core/snap/indexes/KeyIndex.ts","../database/src/core/util/SortedMap.ts","../database/src/core/snap/comparators.ts","../database/src/core/snap/snap.ts","../database/src/core/snap/LeafNode.ts","../database/src/core/snap/indexes/PriorityIndex.ts","../database/src/core/snap/childSet.ts","../database/src/core/snap/IndexMap.ts","../database/src/core/snap/ChildrenNode.ts","../database/src/core/snap/nodeFromJSON.ts","../database/src/core/snap/indexes/PathIndex.ts","../database/src/core/snap/indexes/ValueIndex.ts","../database/src/core/view/Change.ts","../database/src/core/view/filter/IndexedFilter.ts","../database/src/core/view/filter/RangedFilter.ts","../database/src/core/view/filter/LimitedFilter.ts","../database/src/core/view/QueryParams.ts","../database/src/core/ReadonlyRestClient.ts","../util/src/query.ts","../database/src/core/SnapshotHolder.ts","../database/src/core/SparseSnapshotTree.ts","../database/src/core/stats/StatsListener.ts","../database/src/core/stats/StatsReporter.ts","../database/src/core/operation/Operation.ts","../database/src/core/operation/AckUserWrite.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/EventGenerator.ts","../database/src/core/view/ViewCache.ts","../database/src/core/util/ImmutableTree.ts","../database/src/core/CompoundWrite.ts","../database/src/core/WriteTree.ts","../database/src/core/view/ChildChangeAccumulator.ts","../database/src/core/view/CompleteChildSource.ts","../database/src/core/view/ViewProcessor.ts","../database/src/core/view/View.ts","../database/src/core/SyncPoint.ts","../database/src/core/SyncTree.ts","../database/src/core/util/ServerValues.ts","../database/src/core/util/Tree.ts","../database/src/core/util/validation.ts","../database/src/core/view/EventQueue.ts","../database/src/core/Repo.ts","../database/src/core/util/libs/parser.ts","../database/src/core/util/NextPushId.ts","../database/src/core/view/Event.ts","../database/src/core/view/EventRegistration.ts","../database/src/api/OnDisconnect.ts","../database/src/api/Reference_impl.ts","../database/src/api/Database.ts","../util/src/emulator.ts","../database/src/api/ServerValue.ts","../database/src/api/Transaction.ts","../database/src/api/test_access.ts","../database/src/internal/index.ts","../database/src/register.ts","../database/src/index.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2025 Google LLC\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// This value is retrieved and hardcoded by the NPM postinstall script\nconst getDefaultsFromPostinstall = () => undefined;\n\nexport { getDefaultsFromPostinstall };\n","/**\n * @license\n * Copyright 2017 Google LLC\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 LLC\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 LLC\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_()\n// TODO(dlarocque): Define this as a class, since we no longer target ES5.\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 new DecodeBase64StringError();\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 * An error encountered while decoding base64 string.\n */\nexport class DecodeBase64StringError extends Error {\n  readonly name = 'DecodeBase64StringError';\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 encoding (without \".\" padding in the end).\n * e.g. Used in JSON Web Token (JWT) parts.\n */\nexport const base64urlEncodeWithoutPadding = function (str: string): string {\n  // Use base64url encoding and remove padding in the end (dot characters).\n  return base64Encode(str).replace(/\\./g, '');\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 LLC\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<T>(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 *\n * Note: we don't merge __proto__ to prevent prototype pollution\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    // use isValidKey to guard against prototype pollution. See https://snyk.io/vuln/SNYK-JS-LODASH-450202\n    if (!source.hasOwnProperty(prop) || !isValidKey(prop)) {\n      continue;\n    }\n    (target as Record<string, unknown>)[prop] = deepExtend(\n      (target as Record<string, unknown>)[prop],\n      (source as Record<string, unknown>)[prop]\n    );\n  }\n\n  return target;\n}\n\nfunction isValidKey(key: string): boolean {\n  return key !== '__proto__';\n}\n","/**\n * @license\n * Copyright 2022 Google LLC\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 { getGlobal } from './global';\nimport { getDefaultsFromPostinstall } from './postinstall';\n\n/**\n * Keys for experimental properties on the `FirebaseDefaults` object.\n * @public\n */\nexport type ExperimentalKey = 'authTokenSyncURL' | 'authIdTokenMaxAge';\n\n/**\n * An object that can be injected into the environment as __FIREBASE_DEFAULTS__,\n * either as a property of globalThis, a shell environment variable, or a\n * cookie.\n *\n * This object can be used to automatically configure and initialize\n * a Firebase app as well as any emulators.\n *\n * @public\n */\nexport interface FirebaseDefaults {\n  config?: Record<string, string>;\n  emulatorHosts?: Record<string, string>;\n  _authTokenSyncURL?: string;\n  _authIdTokenMaxAge?: number;\n  /**\n   * Override Firebase's runtime environment detection and\n   * force the SDK to act as if it were in the specified environment.\n   */\n  forceEnvironment?: 'browser' | 'node';\n  [key: string]: unknown;\n}\n\ndeclare global {\n  // Need `var` for this to work.\n  // eslint-disable-next-line no-var\n  var __FIREBASE_DEFAULTS__: FirebaseDefaults | undefined;\n}\n\nconst getDefaultsFromGlobal = (): FirebaseDefaults | undefined =>\n  getGlobal().__FIREBASE_DEFAULTS__;\n\n/**\n * Attempt to read defaults from a JSON string provided to\n * process(.)env(.)__FIREBASE_DEFAULTS__ or a JSON file whose path is in\n * process(.)env(.)__FIREBASE_DEFAULTS_PATH__\n * The dots are in parens because certain compilers (Vite?) cannot\n * handle seeing that variable in comments.\n * See https://github.com/firebase/firebase-js-sdk/issues/6838\n */\nconst getDefaultsFromEnvVariable = (): FirebaseDefaults | undefined => {\n  if (typeof process === 'undefined' || typeof process.env === 'undefined') {\n    return;\n  }\n  const defaultsJsonString = process.env.__FIREBASE_DEFAULTS__;\n  if (defaultsJsonString) {\n    return JSON.parse(defaultsJsonString);\n  }\n};\n\nconst getDefaultsFromCookie = (): FirebaseDefaults | undefined => {\n  if (typeof document === 'undefined') {\n    return;\n  }\n  let match;\n  try {\n    match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/);\n  } catch (e) {\n    // Some environments such as Angular Universal SSR have a\n    // `document` object but error on accessing `document.cookie`.\n    return;\n  }\n  const decoded = match && base64Decode(match[1]);\n  return decoded && JSON.parse(decoded);\n};\n\n/**\n * Get the __FIREBASE_DEFAULTS__ object. It checks in order:\n * (1) if such an object exists as a property of `globalThis`\n * (2) if such an object was provided on a shell environment variable\n * (3) if such an object exists in a cookie\n * @public\n */\nexport const getDefaults = (): FirebaseDefaults | undefined => {\n  try {\n    return (\n      getDefaultsFromPostinstall() ||\n      getDefaultsFromGlobal() ||\n      getDefaultsFromEnvVariable() ||\n      getDefaultsFromCookie()\n    );\n  } catch (e) {\n    /**\n     * Catch-all for being unable to get __FIREBASE_DEFAULTS__ due\n     * to any environment case we have not accounted for. Log to\n     * info instead of swallowing so we can find these unknown cases\n     * and add paths for them if needed.\n     */\n    console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`);\n    return;\n  }\n};\n\n/**\n * Returns emulator host stored in the __FIREBASE_DEFAULTS__ object\n * for the given product.\n * @returns a URL host formatted like `127.0.0.1:9999` or `[::1]:4000` if available\n * @public\n */\nexport const getDefaultEmulatorHost = (\n  productName: string\n): string | undefined => getDefaults()?.emulatorHosts?.[productName];\n\n/**\n * Returns emulator hostname and port stored in the __FIREBASE_DEFAULTS__ object\n * for the given product.\n * @returns a pair of hostname and port like `[\"::1\", 4000]` if available\n * @public\n */\nexport const getDefaultEmulatorHostnameAndPort = (\n  productName: string\n): [hostname: string, port: number] | undefined => {\n  const host = getDefaultEmulatorHost(productName);\n  if (!host) {\n    return undefined;\n  }\n  const separatorIndex = host.lastIndexOf(':'); // Finding the last since IPv6 addr also has colons.\n  if (separatorIndex <= 0 || separatorIndex + 1 === host.length) {\n    throw new Error(`Invalid host ${host} with no separate hostname and port!`);\n  }\n  // eslint-disable-next-line no-restricted-globals\n  const port = parseInt(host.substring(separatorIndex + 1), 10);\n  if (host[0] === '[') {\n    // Bracket-quoted `[ipv6addr]:port` => return \"ipv6addr\" (without brackets).\n    return [host.substring(1, separatorIndex - 1), port];\n  } else {\n    return [host.substring(0, separatorIndex), port];\n  }\n};\n\n/**\n * Returns Firebase app config stored in the __FIREBASE_DEFAULTS__ object.\n * @public\n */\nexport const getDefaultAppConfig = (): Record<string, string> | undefined =>\n  getDefaults()?.config;\n\n/**\n * Returns an experimental setting on the __FIREBASE_DEFAULTS__ object (properties\n * prefixed by \"_\")\n * @public\n */\nexport const getExperimentalSetting = <T extends ExperimentalKey>(\n  name: T\n): FirebaseDefaults[`_${T}`] =>\n  getDefaults()?.[`_${name}`] as FirebaseDefaults[`_${T}`];\n","/**\n * @license\n * Copyright 2022 Google LLC\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 * Polyfill for `globalThis` object.\n * @returns the `globalThis` object for the given environment.\n * @public\n */\nexport function getGlobal(): typeof globalThis {\n  if (typeof self !== 'undefined') {\n    return self;\n  }\n  if (typeof window !== 'undefined') {\n    return window;\n  }\n  if (typeof global !== 'undefined') {\n    return global;\n  }\n  throw new Error('Unable to locate global object.');\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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<R> {\n  promise: Promise<R>;\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 promisified 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 LLC\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';\nimport { getDefaults } from './defaults';\n\n/**\n * Type placeholder for `WorkerGlobalScope` from `webworker`\n */\ndeclare class WorkerGlobalScope {}\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 or specified.\n */\n// Node detection logic from: https://github.com/iliakan/detect-node/\nexport function isNode(): boolean {\n  const forceEnvironment = getDefaults()?.forceEnvironment;\n  if (forceEnvironment === 'node') {\n    return true;\n  } else if (forceEnvironment === 'browser') {\n    return false;\n  }\n\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 * Note: This will return true for certain test frameworks that are incompletely\n * mimicking a browser, and should not lead to assuming all browser APIs are\n * available.\n */\nexport function isBrowser(): boolean {\n  return typeof window !== 'undefined' || isWebWorker();\n}\n\n/**\n * Detect Web Worker context.\n */\nexport function isWebWorker(): boolean {\n  return (\n    typeof WorkerGlobalScope !== 'undefined' &&\n    typeof self !== 'undefined' &&\n    self instanceof WorkerGlobalScope\n  );\n}\n\n/**\n * Detect Cloudflare Worker context.\n */\nexport function isCloudflareWorker(): boolean {\n  return (\n    typeof navigator !== 'undefined' &&\n    navigator.userAgent === 'Cloudflare-Workers'\n  );\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/** Returns true if we are running in Safari. */\nexport function isSafari(): boolean {\n  return (\n    !isNode() &&\n    !!navigator.userAgent &&\n    navigator.userAgent.includes('Safari') &&\n    !navigator.userAgent.includes('Chrome')\n  );\n}\n\n/**\n * This method checks if indexedDB is supported by current browser/service worker context\n * @return true if indexedDB is supported by current browser/service worker context\n */\nexport function isIndexedDBAvailable(): boolean {\n  try {\n    return typeof indexedDB === 'object';\n  } catch (e) {\n    return false;\n  }\n}\n\n/**\n * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject\n * if errors occur during the database open operation.\n *\n * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox\n * private browsing)\n */\nexport function validateIndexedDBOpenable(): Promise<boolean> {\n  return new Promise((resolve, reject) => {\n    try {\n      let preExist: boolean = true;\n      const DB_CHECK_NAME =\n        'validate-browser-context-for-indexeddb-analytics-module';\n      const request = self.indexedDB.open(DB_CHECK_NAME);\n      request.onsuccess = () => {\n        request.result.close();\n        // delete database only when it doesn't pre-exist\n        if (!preExist) {\n          self.indexedDB.deleteDatabase(DB_CHECK_NAME);\n        }\n        resolve(true);\n      };\n      request.onupgradeneeded = () => {\n        preExist = false;\n      };\n\n      request.onerror = () => {\n        reject(request.error?.message || '');\n      };\n    } catch (error) {\n      reject(error);\n    }\n  });\n}\n\n/**\n *\n * This method checks whether cookie is enabled within current browser\n * @return true if cookie is enabled within current browser\n */\nexport function areCookiesEnabled(): boolean {\n  if (typeof navigator === 'undefined' || !navigator.cookieEnabled) {\n    return false;\n  }\n  return true;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 LLC\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 LLC\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<T extends object>(obj: T, key: string): boolean {\n  return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function safeGet<T extends object, K extends keyof T>(\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<K extends string, V, U>(\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/**\n * Deep equal two objects. Support Arrays and Objects.\n */\nexport function deepEqual(a: object, b: object): boolean {\n  if (a === b) {\n    return true;\n  }\n\n  const aKeys = Object.keys(a);\n  const bKeys = Object.keys(b);\n  for (const k of aKeys) {\n    if (!bKeys.includes(k)) {\n      return false;\n    }\n\n    const aProp = (a as Record<string, unknown>)[k];\n    const bProp = (b as Record<string, unknown>)[k];\n    if (isObject(aProp) && isObject(bProp)) {\n      if (!deepEqual(aProp, bProp)) {\n        return false;\n      }\n    } else if (aProp !== bProp) {\n      return false;\n    }\n  }\n\n  for (const k of bKeys) {\n    if (!aKeys.includes(k)) {\n      return false;\n    }\n  }\n  return true;\n}\n\nfunction isObject(thing: unknown): thing is object {\n  return thing !== null && typeof thing === 'object';\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 LLC\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 argName The name of the argument\n * @return The prefix to add to the error thrown for validation.\n */\nexport function errorPrefix(fnName: string, argName: string): string {\n  return `${fnName} failed: ${argName} argument `;\n}\n\n/**\n * @param fnName\n * @param argumentNumber\n * @param namespace\n * @param optional\n */\nexport function validateNamespace(\n  fnName: string,\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, 'namespace') + 'must be a valid firebase namespace.'\n    );\n  }\n}\n\nexport function validateCallback(\n  fnName: string,\n  argumentName: string,\n  // eslint-disable-next-line @typescript-eslint/ban-types\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, argumentName) + 'must be a valid function.'\n    );\n  }\n}\n\nexport function validateContextObject(\n  fnName: string,\n  argumentName: string,\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, argumentName) + 'must be a valid context object.'\n    );\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 2021 Google LLC\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 interface Compat<T> {\n  _delegate: T;\n}\n\nexport function getModularInstance<ExpService>(\n  service: Compat<ExpService> | ExpService\n): ExpService {\n  if (service && (service as Compat<ExpService>)._delegate) {\n    return (service as Compat<ExpService>)._delegate;\n  } else {\n    return service as ExpService;\n  }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\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  onInstanceCreatedCallback\n} from './types';\n\n/**\n * Component for service name T, e.g. `auth`, `auth-internal`\n */\nexport class Component<T extends Name = Name> {\n  multipleInstances = false;\n  /**\n   * Properties to be added to the service namespace\n   */\n  serviceProps: Dictionary = {};\n\n  instantiationMode = InstantiationMode.LAZY;\n\n  onInstanceCreated: onInstanceCreatedCallback<T> | null = null;\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<T>,\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  setInstanceCreatedCallback(callback: onInstanceCreatedCallback<T>): this {\n    this.onInstanceCreated = callback;\n    return this;\n  }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\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 DEFAULT_ENTRY_NAME = '[DEFAULT]';\n","/**\n * @license\n * Copyright 2019 Google LLC\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 { Deferred } from '@firebase/util';\nimport { ComponentContainer } from './component_container';\nimport { DEFAULT_ENTRY_NAME } from './constants';\nimport {\n  InitializeOptions,\n  InstantiationMode,\n  Name,\n  NameServiceMapping,\n  OnInitCallBack\n} from './types';\nimport { Component } from './component';\n\n/**\n * Provider for instance for service name T, e.g. 'auth', 'auth-internal'\n * NameServiceMapping[T] is an alias for the type of the instance\n */\nexport class Provider<T extends Name> {\n  private component: Component<T> | null = null;\n  private readonly instances: Map<string, NameServiceMapping[T]> = new Map();\n  private readonly instancesDeferred: Map<\n    string,\n    Deferred<NameServiceMapping[T]>\n  > = new Map();\n  private readonly instancesOptions: Map<string, Record<string, unknown>> =\n    new Map();\n  private onInitCallbacks: Map<string, Set<OnInitCallBack<T>>> = new Map();\n\n  constructor(\n    private readonly name: T,\n    private readonly container: ComponentContainer\n  ) {}\n\n  /**\n   * @param identifier A provider can provide multiple instances of a service\n   * if this.component.multipleInstances is true.\n   */\n  get(identifier?: string): Promise<NameServiceMapping[T]> {\n    // if multipleInstances is not supported, use the default name\n    const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier);\n\n    if (!this.instancesDeferred.has(normalizedIdentifier)) {\n      const deferred = new Deferred<NameServiceMapping[T]>();\n      this.instancesDeferred.set(normalizedIdentifier, deferred);\n\n      if (\n        this.isInitialized(normalizedIdentifier) ||\n        this.shouldAutoInitialize()\n      ) {\n        // initialize the service if it can be auto-initialized\n        try {\n          const instance = this.getOrInitializeService({\n            instanceIdentifier: normalizedIdentifier\n          });\n          if (instance) {\n            deferred.resolve(instance);\n          }\n        } catch (e) {\n          // when the instance factory throws an exception during get(), it should not cause\n          // a fatal error. We just return the unresolved promise in this case.\n        }\n      }\n    }\n\n    return this.instancesDeferred.get(normalizedIdentifier)!.promise;\n  }\n\n  /**\n   *\n   * @param options.identifier A provider can provide multiple instances of a service\n   * if this.component.multipleInstances is true.\n   * @param options.optional If optional is false or not provided, the method throws an error when\n   * the service is not immediately available.\n   * If optional is true, the method returns null if the service is not immediately available.\n   */\n  getImmediate(options: {\n    identifier?: string;\n    optional: true;\n  }): NameServiceMapping[T] | null;\n  getImmediate(options?: {\n    identifier?: string;\n    optional?: false;\n  }): NameServiceMapping[T];\n  getImmediate(options?: {\n    identifier?: string;\n    optional?: boolean;\n  }): NameServiceMapping[T] | null {\n    // if multipleInstances is not supported, use the default name\n    const normalizedIdentifier = this.normalizeInstanceIdentifier(\n      options?.identifier\n    );\n    const optional = options?.optional ?? false;\n\n    if (\n      this.isInitialized(normalizedIdentifier) ||\n      this.shouldAutoInitialize()\n    ) {\n      try {\n        return this.getOrInitializeService({\n          instanceIdentifier: normalizedIdentifier\n        });\n      } catch (e) {\n        if (optional) {\n          return null;\n        } else {\n          throw e;\n        }\n      }\n    } else {\n      // In case a component is not initialized and should/cannot be auto-initialized at the moment, return null if the optional flag is set, or throw\n      if (optional) {\n        return null;\n      } else {\n        throw Error(`Service ${this.name} is not available`);\n      }\n    }\n  }\n\n  getComponent(): Component<T> | null {\n    return this.component;\n  }\n\n  setComponent(component: Component<T>): void {\n    if (component.name !== this.name) {\n      throw Error(\n        `Mismatching Component ${component.name} for Provider ${this.name}.`\n      );\n    }\n\n    if (this.component) {\n      throw Error(`Component for ${this.name} has already been provided`);\n    }\n\n    this.component = component;\n\n    // return early without attempting to initialize the component if the component requires explicit initialization (calling `Provider.initialize()`)\n    if (!this.shouldAutoInitialize()) {\n      return;\n    }\n\n    // if the service is eager, initialize the default instance\n    if (isComponentEager(component)) {\n      try {\n        this.getOrInitializeService({ instanceIdentifier: DEFAULT_ENTRY_NAME });\n      } catch (e) {\n        // when the instance factory for an eager Component throws an exception during the eager\n        // initialization, it should not cause a fatal error.\n        // TODO: Investigate if we need to make it configurable, because some component may want to cause\n        // a fatal error in this case?\n      }\n    }\n\n    // Create service instances for the pending promises and resolve them\n    // NOTE: if this.multipleInstances is false, only the default instance will be created\n    // and all promises with resolve with it regardless of the identifier.\n    for (const [\n      instanceIdentifier,\n      instanceDeferred\n    ] of this.instancesDeferred.entries()) {\n      const normalizedIdentifier =\n        this.normalizeInstanceIdentifier(instanceIdentifier);\n\n      try {\n        // `getOrInitializeService()` should always return a valid instance since a component is guaranteed. use ! to make typescript happy.\n        const instance = this.getOrInitializeService({\n          instanceIdentifier: normalizedIdentifier\n        })!;\n        instanceDeferred.resolve(instance);\n      } catch (e) {\n        // when the instance factory throws an exception, it should not cause\n        // a fatal error. We just leave the promise unresolved.\n      }\n    }\n  }\n\n  clearInstance(identifier: string = DEFAULT_ENTRY_NAME): void {\n    this.instancesDeferred.delete(identifier);\n    this.instancesOptions.delete(identifier);\n    this.instances.delete(identifier);\n  }\n\n  // app.delete() will call this method on every provider to delete the services\n  // TODO: should we mark the provider as deleted?\n  async delete(): Promise<void> {\n    const services = Array.from(this.instances.values());\n\n    await Promise.all([\n      ...services\n        .filter(service => 'INTERNAL' in service) // legacy services\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        .map(service => (service as any).INTERNAL!.delete()),\n      ...services\n        .filter(service => '_delete' in service) // modularized services\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        .map(service => (service as any)._delete())\n    ]);\n  }\n\n  isComponentSet(): boolean {\n    return this.component != null;\n  }\n\n  isInitialized(identifier: string = DEFAULT_ENTRY_NAME): boolean {\n    return this.instances.has(identifier);\n  }\n\n  getOptions(identifier: string = DEFAULT_ENTRY_NAME): Record<string, unknown> {\n    return this.instancesOptions.get(identifier) || {};\n  }\n\n  initialize(opts: InitializeOptions = {}): NameServiceMapping[T] {\n    const { options = {} } = opts;\n    const normalizedIdentifier = this.normalizeInstanceIdentifier(\n      opts.instanceIdentifier\n    );\n    if (this.isInitialized(normalizedIdentifier)) {\n      throw Error(\n        `${this.name}(${normalizedIdentifier}) has already been initialized`\n      );\n    }\n\n    if (!this.isComponentSet()) {\n      throw Error(`Component ${this.name} has not been registered yet`);\n    }\n\n    const instance = this.getOrInitializeService({\n      instanceIdentifier: normalizedIdentifier,\n      options\n    })!;\n\n    // resolve any pending promise waiting for the service instance\n    for (const [\n      instanceIdentifier,\n      instanceDeferred\n    ] of this.instancesDeferred.entries()) {\n      const normalizedDeferredIdentifier =\n        this.normalizeInstanceIdentifier(instanceIdentifier);\n      if (normalizedIdentifier === normalizedDeferredIdentifier) {\n        instanceDeferred.resolve(instance);\n      }\n    }\n\n    return instance;\n  }\n\n  /**\n   *\n   * @param callback - a function that will be invoked  after the provider has been initialized by calling provider.initialize().\n   * The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program.\n   *\n   * @param identifier An optional instance identifier\n   * @returns a function to unregister the callback\n   */\n  onInit(callback: OnInitCallBack<T>, identifier?: string): () => void {\n    const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier);\n    const existingCallbacks =\n      this.onInitCallbacks.get(normalizedIdentifier) ??\n      new Set<OnInitCallBack<T>>();\n    existingCallbacks.add(callback);\n    this.onInitCallbacks.set(normalizedIdentifier, existingCallbacks);\n\n    const existingInstance = this.instances.get(normalizedIdentifier);\n    if (existingInstance) {\n      callback(existingInstance, normalizedIdentifier);\n    }\n\n    return () => {\n      existingCallbacks.delete(callback);\n    };\n  }\n\n  /**\n   * Invoke onInit callbacks synchronously\n   * @param instance the service instance`\n   */\n  private invokeOnInitCallbacks(\n    instance: NameServiceMapping[T],\n    identifier: string\n  ): void {\n    const callbacks = this.onInitCallbacks.get(identifier);\n    if (!callbacks) {\n      return;\n    }\n    for (const callback of callbacks) {\n      try {\n        callback(instance, identifier);\n      } catch {\n        // ignore errors in the onInit callback\n      }\n    }\n  }\n\n  private getOrInitializeService({\n    instanceIdentifier,\n    options = {}\n  }: {\n    instanceIdentifier: string;\n    options?: Record<string, unknown>;\n  }): NameServiceMapping[T] | null {\n    let instance = this.instances.get(instanceIdentifier);\n    if (!instance && this.component) {\n      instance = this.component.instanceFactory(this.container, {\n        instanceIdentifier: normalizeIdentifierForFactory(instanceIdentifier),\n        options\n      });\n      this.instances.set(instanceIdentifier, instance!);\n      this.instancesOptions.set(instanceIdentifier, options);\n\n      /**\n       * Invoke onInit listeners.\n       * Note this.component.onInstanceCreated is different, which is used by the component creator,\n       * while onInit listeners are registered by consumers of the provider.\n       */\n      this.invokeOnInitCallbacks(instance!, instanceIdentifier);\n\n      /**\n       * Order is important\n       * onInstanceCreated() should be called after this.instances.set(instanceIdentifier, instance); which\n       * makes `isInitialized()` return true.\n       */\n      if (this.component.onInstanceCreated) {\n        try {\n          this.component.onInstanceCreated(\n            this.container,\n            instanceIdentifier,\n            instance!\n          );\n        } catch {\n          // ignore errors in the onInstanceCreatedCallback\n        }\n      }\n    }\n\n    return instance || null;\n  }\n\n  private normalizeInstanceIdentifier(\n    identifier: string = DEFAULT_ENTRY_NAME\n  ): string {\n    if (this.component) {\n      return this.component.multipleInstances ? identifier : DEFAULT_ENTRY_NAME;\n    } else {\n      return identifier; // assume multiple instances are supported before the component is provided.\n    }\n  }\n\n  private shouldAutoInitialize(): boolean {\n    return (\n      !!this.component &&\n      this.component.instantiationMode !== InstantiationMode.EXPLICIT\n    );\n  }\n}\n\n// undefined should be passed to the service factory for the default instance\nfunction normalizeIdentifierForFactory(identifier: string): string | undefined {\n  return identifier === DEFAULT_ENTRY_NAME ? undefined : identifier;\n}\n\nfunction isComponentEager<T extends Name>(component: Component<T>): boolean {\n  return component.instantiationMode === InstantiationMode.EAGER;\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\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 { Provider } from './provider';\nimport { Component } from './component';\nimport { Name } from './types';\n\n/**\n * ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal`\n */\nexport class ComponentContainer {\n  private readonly providers = new Map<string, Provider<Name>>();\n\n  constructor(private readonly name: string) {}\n\n  /**\n   *\n   * @param component Component being added\n   * @param overwrite When a component with the same name has already been registered,\n   * if overwrite is true: overwrite the existing component with the new component and create a new\n   * provider with the new component. It can be useful in tests where you want to use different mocks\n   * for different tests.\n   * if overwrite is false: throw an exception\n   */\n  addComponent<T extends Name>(component: Component<T>): void {\n    const provider = this.getProvider(component.name);\n    if (provider.isComponentSet()) {\n      throw new Error(\n        `Component ${component.name} has already been registered with ${this.name}`\n      );\n    }\n\n    provider.setComponent(component);\n  }\n\n  addOrOverwriteComponent<T extends Name>(component: Component<T>): void {\n    const provider = this.getProvider(component.name);\n    if (provider.isComponentSet()) {\n      // delete the existing provider from the container, so we can register the new component\n      this.providers.delete(component.name);\n    }\n\n    this.addComponent(component);\n  }\n\n  /**\n   * getProvider provides a type safe interface where it can only be called with a field name\n   * present in NameServiceMapping interface.\n   *\n   * Firebase SDKs providing services should extend NameServiceMapping interface to register\n   * themselves.\n   */\n  getProvider<T extends Name>(name: T): Provider<T> {\n    if (this.providers.has(name)) {\n      return this.providers.get(name) as unknown as Provider<T>;\n    }\n\n    // create a Provider for a service that hasn't registered with Firebase\n    const provider = new Provider<T>(name, this);\n    this.providers.set(name, provider as unknown as Provider<Name>);\n\n    return provider as Provider<T>;\n  }\n\n  getProviders(): Array<Provider<Name>> {\n    return Array.from(this.providers.values());\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 type LogLevelString =\n  | 'debug'\n  | 'verbose'\n  | 'info'\n  | 'warn'\n  | 'error'\n  | 'silent';\n\nexport interface LogOptions {\n  level: LogLevelString;\n}\n\nexport type LogCallback = (callbackParams: LogCallbackParams) => void;\n\nexport interface LogCallbackParams {\n  level: LogLevelString;\n  message: string;\n  args: unknown[];\n  type: string;\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\nconst levelStringToEnum: { [key in LogLevelString]: LogLevel } = {\n  'debug': LogLevel.DEBUG,\n  'verbose': LogLevel.VERBOSE,\n  'info': LogLevel.INFO,\n  'warn': LogLevel.WARN,\n  'error': LogLevel.ERROR,\n  'silent': LogLevel.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 * 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 */\nconst ConsoleMethod = {\n  [LogLevel.DEBUG]: 'log',\n  [LogLevel.VERBOSE]: 'log',\n  [LogLevel.INFO]: 'info',\n  [LogLevel.WARN]: 'warn',\n  [LogLevel.ERROR]: 'error'\n};\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  const method = ConsoleMethod[logType as keyof typeof ConsoleMethod];\n  if (method) {\n    console[method as 'log' | 'info' | 'warn' | 'error'](\n      `[${now}]  ${instance.name}:`,\n      ...args\n    );\n  } else {\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\n  get logLevel(): LogLevel {\n    return this._logLevel;\n  }\n\n  set logLevel(val: LogLevel) {\n    if (!(val in LogLevel)) {\n      throw new TypeError(`Invalid value \"${val}\" assigned to \\`logLevel\\``);\n    }\n    this._logLevel = val;\n  }\n\n  // Workaround for setter/getter having to be the same type.\n  setLogLevel(val: LogLevel | LogLevelString): void {\n    this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val;\n  }\n\n  /**\n   * The main (internal) log handler for the Logger instance.\n   * Can be set to a new function in internal package code but not by user.\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 optional, additional, user-defined log handler for the Logger instance.\n   */\n  private _userLogHandler: LogHandler | null = null;\n  get userLogHandler(): LogHandler | null {\n    return this._userLogHandler;\n  }\n  set userLogHandler(val: LogHandler | null) {\n    this._userLogHandler = val;\n  }\n\n  /**\n   * The functions below are all based on the `console` interface\n   */\n\n  debug(...args: unknown[]): void {\n    this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args);\n    this._logHandler(this, LogLevel.DEBUG, ...args);\n  }\n  log(...args: unknown[]): void {\n    this._userLogHandler &&\n      this._userLogHandler(this, LogLevel.VERBOSE, ...args);\n    this._logHandler(this, LogLevel.VERBOSE, ...args);\n  }\n  info(...args: unknown[]): void {\n    this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args);\n    this._logHandler(this, LogLevel.INFO, ...args);\n  }\n  warn(...args: unknown[]): void {\n    this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args);\n    this._logHandler(this, LogLevel.WARN, ...args);\n  }\n  error(...args: unknown[]): void {\n    this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args);\n    this._logHandler(this, LogLevel.ERROR, ...args);\n  }\n}\n\nexport function setLogLevel(level: LogLevelString | LogLevel): void {\n  instances.forEach(inst => {\n    inst.setLogLevel(level);\n  });\n}\n\nexport function setUserLogHandler(\n  logCallback: LogCallback | null,\n  options?: LogOptions\n): void {\n  for (const instance of instances) {\n    let customLogLevel: LogLevel | null = null;\n    if (options && options.level) {\n      customLogLevel = levelStringToEnum[options.level];\n    }\n    if (logCallback === null) {\n      instance.userLogHandler = null;\n    } else {\n      instance.userLogHandler = (\n        instance: Logger,\n        level: LogLevel,\n        ...args: unknown[]\n      ) => {\n        const message = args\n          .map(arg => {\n            if (arg == null) {\n              return null;\n            } else if (typeof arg === 'string') {\n              return arg;\n            } else if (typeof arg === 'number' || typeof arg === 'boolean') {\n              return arg.toString();\n            } else if (arg instanceof Error) {\n              return arg.message;\n            } else {\n              try {\n                return JSON.stringify(arg);\n              } catch (ignored) {\n                return null;\n              }\n            }\n          })\n          .filter(arg => arg)\n          .join(' ');\n        if (level >= (customLogLevel ?? instance.logLevel)) {\n          logCallback({\n            level: LogLevel[level].toLowerCase() as LogLevelString,\n            message,\n            args,\n            type: instance.name\n          });\n        }\n      };\n    }\n  }\n}\n","/**\n * @license\n * Copyright 2019 Google LLC\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/**\n * SDK_VERSION should be set before any database instance is created\n * @internal\n */\nexport function setSDKVersion(version: string): void {\n  SDK_VERSION = version;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 */\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 domStorage_ - The underlying storage object (e.g. localStorage or sessionStorage)\n   */\n  constructor(private domStorage_: Storage) {}\n\n  /**\n   * @param key - The key to save the value under\n   * @param 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   * @returns 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  remove(key: string) {\n    this.domStorage_.removeItem(this.prefixedName_(key));\n  }\n\n  isInMemoryStorage: boolean;\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 LLC\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 */\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 LLC\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 domStorageName - Name of the underlying storage object\n *   (e.g. 'localStorage' or 'sessionStorage').\n * @returns 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 LLC\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 { Logger, LogLevel } from '@firebase/logger';\nimport {\n  assert,\n  base64,\n  Sha1,\n  stringToByteArray,\n  stringify,\n  isNodeSdk\n} from '@firebase/util';\n\nimport { SessionStorage } from '../storage/storage';\nimport { QueryContext } from '../view/EventRegistration';\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 */\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 str - The string to hash\n * @returns {!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\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 */\nexport let logger: ((a: string) => void) | null = null;\n\n/**\n * Flag to check for log availability on first log message\n */\nlet firstLog_ = true;\n\n/**\n * The implementation of Firebase.enableLogging (defined here to break dependencies)\n * @param logger_ - A flag to turn on logging, or a custom logger\n * @param 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\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\nexport const logWrapper = function (\n  prefix: string\n): (...varArgs: unknown[]) => void {\n  return function (...varArgs: unknown[]) {\n    log(prefix, ...varArgs);\n  };\n};\n\nexport const error = function (...varArgs: string[]) {\n  const message = 'FIREBASE INTERNAL ERROR: ' + buildLogMessage_(...varArgs);\n  logClient.error(message);\n};\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\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\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 */\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\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 */\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 */\nexport const MAX_NAME = '[MAX_NAME]';\n\n/**\n * Compares valid Firebase key names, plus min and max name\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 * @returns {!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\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\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 str - The string\n * @param segsize - The maximum number of chars in the string.\n * @returns 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 callback - Callback function.\n * @param context - Optional context to bind to.\n *\n */\nexport const bindCallback = function (\n  callback: (a: unknown) => void,\n  context?: object | null\n): (a: unknown) => void {\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 v - A double\n *\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 */\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 */\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 */\nexport function errorForServerCode(code: string, query: QueryContext): 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 */\nexport const INTEGER_REGEXP_ = new RegExp('^-?(0*)\\\\d{1,10}$');\n\n/**\n * For use in keys, the minimum possible 32-bit integer.\n */\nexport const INTEGER_32_MIN = -2147483648;\n\n/**\n * For use in keys, the maximum possible 32-bit integer.\n */\nexport const INTEGER_32_MAX = 2147483647;\n\n/**\n * If the string contains a 32-bit integer, return it.  Else return null.\n */\nexport const tryParseInt = function (str: string): number | null {\n  if (INTEGER_REGEXP_.test(str)) {\n    const intVal = Number(str);\n    if (intVal >= INTEGER_32_MIN && intVal <= INTEGER_32_MAX) {\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 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 callback - Optional onComplete callback.\n * @param varArgs - Arbitrary args to be passed to opt_onComplete\n */\nexport const callUserCallback = function (\n  // eslint-disable-next-line @typescript-eslint/ban-types\n  callback?: Function | null,\n  ...varArgs: unknown[]\n) {\n  if (typeof callback === 'function') {\n    exceptionGuard(() => {\n      callback(...varArgs);\n    });\n  }\n};\n\n/**\n * @returns {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 */\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 fn - Function to run.\n * @param time - Milliseconds to wait before running.\n * @returns The setTimeout() return value.\n */\nexport const setTimeoutNonBlocking = function (\n  fn: () => void,\n  time: number\n): number | object {\n  const timeout: number | object = setTimeout(fn, time);\n  // Note: at the time of this comment, unrefTimer is under the unstable set of APIs. Run with --unstable to enable the API.\n  if (\n    typeof timeout === 'number' &&\n    // @ts-ignore Is only defined in Deno environments.\n    typeof Deno !== 'undefined' &&\n    // @ts-ignore Deno and unrefTimer are only defined in Deno environments.\n    Deno['unrefTimer']\n  ) {\n    // @ts-ignore Deno and unrefTimer are only defined in Deno environments.\n    Deno.unrefTimer(timeout);\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  } else 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\n  return timeout;\n};\n","/**\n * @license\n * Copyright 2021 Google LLC\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, _isFirebaseServerApp } from '@firebase/app'; // eslint-disable-line import/no-extraneous-dependencies\nimport {\n  AppCheckInternalComponentName,\n  AppCheckTokenListener,\n  AppCheckTokenResult,\n  FirebaseAppCheckInternal\n} from '@firebase/app-check-interop-types';\nimport { Provider } from '@firebase/component';\n\nimport { warn } from './util/util';\n\n/**\n * Abstraction around AppCheck's token fetching capabilities.\n */\nexport class AppCheckTokenProvider {\n  private appCheck?: FirebaseAppCheckInternal;\n  private serverAppAppCheckToken?: string;\n  private appName: string;\n  constructor(\n    app: FirebaseApp,\n    private appCheckProvider?: Provider<AppCheckInternalComponentName>\n  ) {\n    this.appName = app.name;\n    if (_isFirebaseServerApp(app) && app.settings.appCheckToken) {\n      this.serverAppAppCheckToken = app.settings.appCheckToken;\n    }\n    this.appCheck = appCheckProvider?.getImmediate({ optional: true });\n    if (!this.appCheck) {\n      appCheckProvider?.get().then(appCheck => (this.appCheck = appCheck));\n    }\n  }\n\n  getToken(forceRefresh?: boolean): Promise<AppCheckTokenResult> {\n    if (this.serverAppAppCheckToken) {\n      if (forceRefresh) {\n        throw new Error(\n          'Attempted reuse of `FirebaseServerApp.appCheckToken` after previous usage failed.'\n        );\n      }\n      return Promise.resolve({ token: this.serverAppAppCheckToken });\n    }\n    if (!this.appCheck) {\n      return new Promise<AppCheckTokenResult>((resolve, reject) => {\n        // Support delayed initialization of FirebaseAppCheck. This allows our\n        // customers to initialize the RTDB SDK before initializing Firebase\n        // AppCheck and ensures that all requests are authenticated if a token\n        // becomes available before the timeout below expires.\n        setTimeout(() => {\n          if (this.appCheck) {\n            this.getToken(forceRefresh).then(resolve, reject);\n          } else {\n            resolve(null);\n          }\n        }, 0);\n      });\n    }\n    return this.appCheck.getToken(forceRefresh);\n  }\n\n  addTokenChangeListener(listener: AppCheckTokenListener) {\n    this.appCheckProvider\n      ?.get()\n      .then(appCheck => appCheck.addTokenListener(listener));\n  }\n\n  notifyForInvalidToken(): void {\n    warn(\n      `Provided AppCheck credentials for the app named \"${this.appName}\" ` +\n        'are invalid. This usually indicates your app was not initialized correctly.'\n    );\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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';\n\nimport { log, warn } from './util/util';\n\nexport interface AuthTokenProvider {\n  getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData>;\n  addTokenChangeListener(listener: (token: string | null) => void): void;\n  removeTokenChangeListener(listener: (token: string | null) => void): void;\n  notifyForInvalidToken(): void;\n}\n\n/**\n * Abstraction around FirebaseApp's token fetching capabilities.\n */\nexport class FirebaseAuthTokenProvider implements AuthTokenProvider {\n  private auth_: FirebaseAuthInternal | null = null;\n\n  constructor(\n    private appName_: string,\n    private firebaseOptions_: object,\n    private authProvider_: Provider<FirebaseAuthInternalName>\n  ) {\n    this.auth_ = authProvider_.getImmediate({ optional: true });\n    if (!this.auth_) {\n      authProvider_.onInit(auth => (this.auth_ = auth));\n    }\n  }\n\n  getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData> {\n    if (!this.auth_) {\n      return new Promise<FirebaseAuthTokenData>((resolve, reject) => {\n        // Support delayed initialization of FirebaseAuth. This allows our\n        // customers to initialize the RTDB SDK before initializing Firebase\n        // Auth and ensures that all requests are authenticated if a token\n        // becomes available before the timeout below expires.\n        setTimeout(() => {\n          if (this.auth_) {\n            this.getToken(forceRefresh).then(resolve, reject);\n          } else {\n            resolve(null);\n          }\n        }, 0);\n      });\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): 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      this.authProvider_\n        .get()\n        .then(auth => auth.addAuthTokenListener(listener));\n    }\n  }\n\n  removeTokenChangeListener(listener: (token: string | null) => void): void {\n    this.authProvider_\n      .get()\n      .then(auth => auth.removeAuthTokenListener(listener));\n  }\n\n  notifyForInvalidToken(): void {\n    let errorMessage =\n      'Provided authentication credentials for the app named \"' +\n      this.appName_ +\n      '\" are invalid. This usually indicates your app was not ' +\n      'initialized correctly. ';\n    if ('credential' in this.firebaseOptions_) {\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.firebaseOptions_) {\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/* AuthTokenProvider that supplies a constant token. Used by Admin SDK or mockUserToken with emulators. */\nexport class EmulatorTokenProvider implements AuthTokenProvider {\n  /** A string that is treated as an admin access token by the RTDB emulator. Used by Admin SDK. */\n  static OWNER = 'owner';\n\n  constructor(private accessToken: string) {}\n\n  getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData> {\n    return Promise.resolve({\n      accessToken: this.accessToken\n    });\n  }\n\n  addTokenChangeListener(listener: (token: string | null) => void): void {\n    // Invoke the listener immediately to match the behavior in Firebase Auth\n    // (see packages/auth/src/auth.js#L1807)\n    listener(this.accessToken);\n  }\n\n  removeTokenChangeListener(listener: (token: string | null) => void): void {}\n\n  notifyForInvalidToken(): void {}\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\n// Matches console.firebase.google.com, firebase-console-*.corp.google.com and\n// firebase.corp.google.com\nexport const FORGE_DOMAIN_RE =\n  /(console\\.firebase|firebase-console-\\w+\\.corp|firebase\\.corp)\\.google\\.com/;\n\nexport const LAST_SESSION_PARAM = 'ls';\n\nexport const APPLICATION_ID_PARAM = 'p';\n\nexport const APP_CHECK_TOKEN_PARAM = 'ac';\n\nexport const WEBSOCKET = 'websocket';\n\nexport const LONG_POLLING = 'long_polling';\n","/**\n * @license\n * Copyright 2017 Google LLC\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, EmulatorMockTokenOptions } from '@firebase/util';\n\nimport { LONG_POLLING, WEBSOCKET } from '../realtime/Constants';\n\nimport { PersistentStorage } from './storage/storage';\nimport { each } from './util/util';\n\nexport interface RepoInfoEmulatorOptions {\n  mockUserToken?: string | EmulatorMockTokenOptions;\n}\n\n/**\n * A class that holds metadata about a Repo object\n */\nexport class RepoInfo {\n  private _host: string;\n  private _domain: string;\n  internalHost: string;\n\n  /**\n   * @param host - Hostname portion of the url for the repo\n   * @param secure - Whether or not this repo is accessed over ssl\n   * @param namespace - The namespace represented by the repo\n   * @param webSocketOnly - Whether to prefer websockets over all other transports (used by Nest).\n   * @param nodeAdmin - Whether this instance uses Admin SDK credentials\n   * @param persistenceKey - Override the default session persistence storage key\n   */\n  constructor(\n    host: string,\n    public readonly secure: boolean,\n    public readonly namespace: string,\n    public readonly webSocketOnly: boolean,\n    public readonly nodeAdmin: boolean = false,\n    public readonly persistenceKey: string = '',\n    public readonly includeNamespaceInQueryParams: boolean = false,\n    public readonly isUsingEmulator: boolean = false,\n    public readonly emulatorOptions: RepoInfoEmulatorOptions | null = null\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  isCacheableHost(): boolean {\n    return this.internalHost.substr(0, 2) === 's-';\n  }\n\n  isCustomHost() {\n    return (\n      this._domain !== 'firebaseio.com' &&\n      this._domain !== 'firebaseio-demo.com'\n    );\n  }\n\n  get host() {\n    return this._host;\n  }\n\n  set host(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  toString(): string {\n    let str = this.toURLString();\n    if (this.persistenceKey) {\n      str += '<' + this.persistenceKey + '>';\n    }\n    return str;\n  }\n\n  toURLString(): string {\n    const protocol = this.secure ? 'https://' : 'http://';\n    const query = this.includeNamespaceInQueryParams\n      ? `?ns=${this.namespace}`\n      : '';\n    return `${protocol}${this.host}/${query}`;\n  }\n}\n\nfunction repoInfoNeedsQueryParam(repoInfo: RepoInfo): boolean {\n  return (\n    repoInfo.host !== repoInfo.internalHost ||\n    repoInfo.isCustomHost() ||\n    repoInfo.includeNamespaceInQueryParams\n  );\n}\n\n/**\n * Returns the websocket URL for this repo\n * @param repoInfo - RepoInfo object\n * @param type - of connection\n * @param params - list\n * @returns The URL for this repo\n */\nexport function repoInfoConnectionURL(\n  repoInfo: RepoInfo,\n  type: string,\n  params: { [k: string]: string }\n): 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      (repoInfo.secure ? 'wss://' : 'ws://') + repoInfo.internalHost + '/.ws?';\n  } else if (type === LONG_POLLING) {\n    connURL =\n      (repoInfo.secure ? 'https://' : 'http://') +\n      repoInfo.internalHost +\n      '/.lp?';\n  } else {\n    throw new Error('Unknown connection type: ' + type);\n  }\n  if (repoInfoNeedsQueryParam(repoInfo)) {\n    params['ns'] = repoInfo.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 * @license\n * Copyright 2017 Google LLC\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 */\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 LLC\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 '../RepoInfo';\n\nimport { StatsCollection } from './StatsCollection';\n\nconst collections: { [k: string]: StatsCollection } = {};\nconst reporters: { [k: string]: unknown } = {};\n\nexport function statsManagerGetCollection(repoInfo: RepoInfo): StatsCollection {\n  const hashString = repoInfo.toString();\n\n  if (!collections[hashString]) {\n    collections[hashString] = new StatsCollection();\n  }\n\n  return collections[hashString];\n}\n\nexport function statsManagerGetOrCreateReporter<T>(\n  repoInfo: RepoInfo,\n  creatorFunction: () => T\n): T {\n  const hashString = repoInfo.toString();\n\n  if (!reporters[hashString]) {\n    reporters[hashString] = creatorFunction();\n  }\n\n  return reporters[hashString] as T;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 */\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   */\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 LLC\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 { base64Encode, isNodeSdk, stringify } from '@firebase/util';\n\nimport { RepoInfo, repoInfoConnectionURL } from '../core/RepoInfo';\nimport { StatsCollection } from '../core/stats/StatsCollection';\nimport { statsManagerGetCollection } from '../core/stats/StatsManager';\nimport {\n  executeWhenDOMReady,\n  isChromeExtensionContentScript,\n  isWindowsStoreApp,\n  log,\n  logWrapper,\n  LUIDGenerator,\n  splitStringBySize\n} from '../core/util/util';\n\nimport {\n  APP_CHECK_TOKEN_PARAM,\n  APPLICATION_ID_PARAM,\n  FORGE_DOMAIN_RE,\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 { PacketReceiver } from './polling/PacketReceiver';\nimport { Transport } from './Transport';\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 */\nconst KEEPALIVE_REQUEST_INTERVAL = 25000;\n\n/**\n * How long to wait before aborting a long-polling connection attempt.\n */\nconst LP_CONNECT_TIMEOUT = 30000;\n\n/**\n * This class manages a single long-polling connection.\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 connId An identifier for this connection, used for logging\n   * @param repoInfo The info for the endpoint to send data to.\n   * @param applicationId The Firebase App ID for this project.\n   * @param appCheckToken The AppCheck token for this client.\n   * @param authToken The AuthToken to use for this connection.\n   * @param transportSessionId Optional transportSessionid if we are\n   * reconnecting for an existing transport session\n   * @param lastSessionId Optional lastSessionId if the PersistentConnection has\n   * already created a connection previously\n   */\n  constructor(\n    public connId: string,\n    public repoInfo: RepoInfo,\n    private applicationId?: string,\n    private appCheckToken?: string,\n    private authToken?: string,\n    public transportSessionId?: string,\n    public lastSessionId?: string\n  ) {\n    this.log_ = logWrapper(connId);\n    this.stats_ = statsManagerGetCollection(repoInfo);\n    this.urlFn = (params: { [k: string]: string }) => {\n      // Always add the token if we have one.\n      if (this.appCheckToken) {\n        params[APP_CHECK_TOKEN_PARAM] = this.appCheckToken;\n      }\n      return repoInfoConnectionURL(repoInfo, LONG_POLLING, params);\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.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[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 (this.applicationId) {\n        urlParams[APPLICATION_ID_PARAM] = this.applicationId;\n      }\n      if (this.appCheckToken) {\n        urlParams[APP_CHECK_TOKEN_PARAM] = this.appCheckToken;\n      }\n      if (\n        typeof location !== 'undefined' &&\n        location.hostname &&\n        FORGE_DOMAIN_RE.test(location.hostname)\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  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  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   */\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   */\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 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   */\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   */\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/naming-convention\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 *********************************************************************************************/\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<number>();\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 received 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[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 = '<script>document.domain=\"' + currentDomain + '\";</script>';\n      }\n      const iframeContents = '<html><body>' + script + '</body></html>';\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   */\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 textContent seems to be the safest way to do this.\n      this.myIFrame.doc.body.textContent = '';\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 id - The ID of this connection\n   * @param 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 url - The URL of the script tag.\n   * @param serial - The serial number of the request.\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 url - The URL for the script tag source.\n   * @param 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 =\n            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 2017 Google LLC\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, isNodeSdk, jsonEval, stringify } from '@firebase/util';\n\nimport { RepoInfo, repoInfoConnectionURL } from '../core/RepoInfo';\nimport { StatsCollection } from '../core/stats/StatsCollection';\nimport { statsManagerGetCollection } from '../core/stats/StatsManager';\nimport { PersistentStorage } from '../core/storage/storage';\nimport { logWrapper, splitStringBySize } from '../core/util/util';\nimport { SDK_VERSION } from '../core/version';\n\nimport {\n  APPLICATION_ID_PARAM,\n  APP_CHECK_TOKEN_PARAM,\n  FORGE_DOMAIN_RE,\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 { Transport } from './Transport';\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 */\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  private nodeAdmin: boolean;\n\n  /**\n   * @param connId identifier for this transport\n   * @param repoInfo The info for the websocket endpoint.\n   * @param applicationId The Firebase App ID for this project.\n   * @param appCheckToken The App Check Token for this client.\n   * @param authToken The Auth Token for this client.\n   * @param transportSessionId Optional transportSessionId if this is connecting\n   * to an existing transport session\n   * @param lastSessionId Optional lastSessionId if there was a previous\n   * connection\n   */\n  constructor(\n    public connId: string,\n    repoInfo: RepoInfo,\n    private applicationId?: string,\n    private appCheckToken?: string,\n    private authToken?: string,\n    transportSessionId?: string,\n    lastSessionId?: string\n  ) {\n    this.log_ = logWrapper(this.connId);\n    this.stats_ = statsManagerGetCollection(repoInfo);\n    this.connURL = WebSocketConnection.connectionURL_(\n      repoInfo,\n      transportSessionId,\n      lastSessionId,\n      appCheckToken,\n      applicationId\n    );\n    this.nodeAdmin = repoInfo.nodeAdmin;\n  }\n\n  /**\n   * @param repoInfo - The info for the websocket endpoint.\n   * @param transportSessionId - Optional transportSessionId if this is connecting to an existing transport\n   *                                         session\n   * @param lastSessionId - Optional lastSessionId if there was a previous connection\n   * @returns connection url\n   */\n  private static connectionURL_(\n    repoInfo: RepoInfo,\n    transportSessionId?: string,\n    lastSessionId?: string,\n    appCheckToken?: string,\n    applicationId?: 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.hostname &&\n      FORGE_DOMAIN_RE.test(location.hostname)\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    if (appCheckToken) {\n      urlParams[APP_CHECK_TOKEN_PARAM] = appCheckToken;\n    }\n    if (applicationId) {\n      urlParams[APPLICATION_ID_PARAM] = applicationId;\n    }\n\n    return repoInfoConnectionURL(repoInfo, WEBSOCKET, urlParams);\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      let options: { [k: string]: object };\n      if (isNodeSdk()) {\n        const device = this.nodeAdmin ? 'AdminNode' : 'Node';\n        // UA Format: Firebase/<wire_protocol>/<sdk_version>/<platform>/<device>\n        options = {\n          headers: {\n            'User-Agent': `Firebase/${PROTOCOL_VERSION}/${SDK_VERSION}/${process.platform}/${device}`,\n            'X-Firebase-GMPID': this.applicationId || ''\n          }\n        };\n\n        // If using Node with admin creds, AppCheck-related checks are unnecessary.\n        // Note that we send the credentials here even if they aren't admin credentials, which is\n        // not a problem.\n        // Note that this header is just used to bypass appcheck, and the token should still be sent\n        // through the websocket connection once it is established.\n        if (this.authToken) {\n          options.headers['Authorization'] = `Bearer ${this.authToken}`;\n        }\n        if (this.appCheckToken) {\n          options.headers['X-Firebase-AppCheck'] = this.appCheckToken;\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    } 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   */\n  static responsesRequiredToBeHealthy = 2;\n\n  /**\n   * Time to wait for the connection te become healthy before giving up.\n   */\n  static healthyTimeout = 30000;\n\n  /**\n   * Returns true if we previously failed to connect with this transport.\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 frameCount - The number of frames we are expecting from the server\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   * @returns Any remaining data to be process, or null if there is none\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 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 str - String to send.\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 LLC\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 { warn } from '../core/util/util';\n\nimport { BrowserPollConnection } from './BrowserPollConnection';\nimport { TransportConstructor } from './Transport';\nimport { WebSocketConnection } from './WebSocketConnection';\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 */\nexport class TransportManager {\n  private transports_: TransportConstructor[];\n\n  // Keeps track of whether the TransportManager has already chosen a transport to use\n  static globalTransportInitialized_ = false;\n\n  static get ALL_TRANSPORTS() {\n    return [BrowserPollConnection, WebSocketConnection];\n  }\n\n  /**\n   * Returns whether transport has been selected to ensure WebSocketConnection or BrowserPollConnection are not called after\n   * TransportManager has already set up transports_\n   */\n  static get IS_TRANSPORT_INITIALIZED() {\n    return this.globalTransportInitialized_;\n  }\n\n  /**\n   * @param repoInfo - Metadata around the namespace we're connecting to\n   */\n  constructor(repoInfo: RepoInfo) {\n    this.initTransports_(repoInfo);\n  }\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      TransportManager.globalTransportInitialized_ = true;\n    }\n  }\n\n  /**\n   * @returns The constructor for the 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   * @returns The constructor for the next 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 LLC\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 { PersistentStorage } from '../core/storage/storage';\nimport { Indexable } from '../core/util/misc';\nimport {\n  error,\n  logWrapper,\n  requireKey,\n  setTimeoutNonBlocking,\n  warn\n} from '../core/util/util';\n\nimport { PROTOCOL_VERSION } from './Constants';\nimport { Transport, TransportConstructor } from './Transport';\nimport { TransportManager } from './TransportManager';\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 */\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 id - an id for this connection\n   * @param repoInfo_ - the info for the endpoint to connect to\n   * @param applicationId_ - the Firebase App ID for this project\n   * @param appCheckToken_ - The App Check Token for this device.\n   * @param authToken_ - The auth token for this session.\n   * @param onMessage_ - the callback to be triggered when a server-push message arrives\n   * @param onReady_ - the callback to be triggered when this connection is ready to send messages.\n   * @param onDisconnect_ - the callback to be triggered when a connection was lost\n   * @param onKill_ - the callback to be triggered when this connection has permanently shut down.\n   * @param 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 applicationId_: string | undefined,\n    private appCheckToken_: string | undefined,\n    private authToken_: string | undefined,\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   */\n  private start_(): void {\n    const conn = this.transportManager_.initialTransport();\n    this.conn_ = new conn(\n      this.nextTransportId_(),\n      this.repoInfo_,\n      this.applicationId_,\n      this.appCheckToken_,\n      this.authToken_,\n      null,\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  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   * @param 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        const handshakePayload = {\n          ...(payload as {\n            ts: number;\n            v: string;\n            h: string;\n            s: string;\n          })\n        };\n        if (this.repoInfo_.isUsingEmulator) {\n          // Upon connecting, the emulator will pass the hostname that it's aware of, but we prefer the user's set hostname via `connectDatabaseEmulator` over what the emulator passes.\n          handshakePayload.h = this.repoInfo_.host;\n        }\n        this.onHandshake_(handshakePayload);\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   * @param handshake - The handshake data returned from the server\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_.host = 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.applicationId_,\n      this.appCheckToken_,\n      this.authToken_,\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_.host = 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   * @param everConnected - Whether or not the connection ever reached a server. Used to determine if\n   * we should flush the host cache\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. <ns>.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  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  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 LLC\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 { QueryContext } from './view/EventRegistration';\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  abstract listen(\n    query: QueryContext,\n    currentHashFn: () => string,\n    tag: number | null,\n    onComplete: (a: string, b: unknown) => void\n  ): void;\n\n  /**\n   * Remove a listen.\n   */\n  abstract unlisten(query: QueryContext, tag: number | null): void;\n\n  /**\n   * Get the server value satisfying this query.\n   */\n  abstract get(query: QueryContext): Promise<string>;\n\n  put(\n    pathString: string,\n    data: unknown,\n    onComplete?: (a: string, b: string) => void,\n    hash?: string\n  ) {}\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 token - The authentication token\n   */\n  refreshAuthToken(token: string) {}\n\n  /**\n   * Refreshes the app check token for the current connection.\n   * @param token The app check token\n   */\n  refreshAppCheckToken(token: string) {}\n\n  onDisconnectPut(\n    pathString: string,\n    data: unknown,\n    onComplete?: (a: string, b: string) => void\n  ) {}\n\n  onDisconnectMerge(\n    pathString: string,\n    data: unknown,\n    onComplete?: (a: string, b: string) => void\n  ) {}\n\n  onDisconnectCancel(\n    pathString: string,\n    onComplete?: (a: string, b: string) => void\n  ) {}\n\n  reportStats(stats: { [k: string]: unknown }) {}\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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  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   * @returns {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   */\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 LLC\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';\n\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 */\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  getInitialEvent(eventType: string): boolean[] {\n    assert(eventType === 'online', 'Unknown event type: ' + eventType);\n    return [this.online_];\n  }\n\n  currentlyOnline(): boolean {\n    return this.online_;\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { stringLength } from '@firebase/util';\n\nimport { nameCompare } from './util';\n\n/** Maximum key depth. */\nconst MAX_PATH_DEPTH = 32;\n\n/** Maximum number of (UTF8) bytes in a Firebase path. */\nconst MAX_PATH_LENGTH_BYTES = 768;\n\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  pieces_: string[];\n  pieceNum_: number;\n\n  /**\n   * @param pathOrString - Path string to parse, or another path, or the raw\n   * tokens array\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  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\nexport function newEmptyPath(): Path {\n  return new Path('');\n}\n\nexport function pathGetFront(path: Path): string | null {\n  if (path.pieceNum_ >= path.pieces_.length) {\n    return null;\n  }\n\n  return path.pieces_[path.pieceNum_];\n}\n\n/**\n * @returns The number of segments in this path\n */\nexport function pathGetLength(path: Path): number {\n  return path.pieces_.length - path.pieceNum_;\n}\n\nexport function pathPopFront(path: Path): Path {\n  let pieceNum = path.pieceNum_;\n  if (pieceNum < path.pieces_.length) {\n    pieceNum++;\n  }\n  return new Path(path.pieces_, pieceNum);\n}\n\nexport function pathGetBack(path: Path): string | null {\n  if (path.pieceNum_ < path.pieces_.length) {\n    return path.pieces_[path.pieces_.length - 1];\n  }\n\n  return null;\n}\n\nexport function pathToUrlEncodedString(path: Path): string {\n  let pathString = '';\n  for (let i = path.pieceNum_; i < path.pieces_.length; i++) {\n    if (path.pieces_[i] !== '') {\n      pathString += '/' + encodeURIComponent(String(path.pieces_[i]));\n    }\n  }\n\n  return pathString || '/';\n}\n\n/**\n * Shallow copy of the parts of the path.\n *\n */\nexport function pathSlice(path: Path, begin: number = 0): string[] {\n  return path.pieces_.slice(path.pieceNum_ + begin);\n}\n\nexport function pathParent(path: Path): Path | null {\n  if (path.pieceNum_ >= path.pieces_.length) {\n    return null;\n  }\n\n  const pieces = [];\n  for (let i = path.pieceNum_; i < path.pieces_.length - 1; i++) {\n    pieces.push(path.pieces_[i]);\n  }\n\n  return new Path(pieces, 0);\n}\n\nexport function pathChild(path: Path, childPathObj: string | Path): Path {\n  const pieces = [];\n  for (let i = path.pieceNum_; i < path.pieces_.length; i++) {\n    pieces.push(path.pieces_[i]);\n  }\n\n  if (childPathObj instanceof Path) {\n    for (let i = childPathObj.pieceNum_; i < childPathObj.pieces_.length; i++) {\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 * @returns True if there are no segments in this path\n */\nexport function pathIsEmpty(path: Path): boolean {\n  return path.pieceNum_ >= path.pieces_.length;\n}\n\n/**\n * @returns The path from outerPath to innerPath\n */\nexport function newRelativePath(outerPath: Path, innerPath: Path): Path {\n  const outer = pathGetFront(outerPath),\n    inner = pathGetFront(innerPath);\n  if (outer === null) {\n    return innerPath;\n  } else if (outer === inner) {\n    return newRelativePath(pathPopFront(outerPath), pathPopFront(innerPath));\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 * @returns -1, 0, 1 if left is less, equal, or greater than the right.\n */\nexport function pathCompare(left: Path, right: Path): number {\n  const leftKeys = pathSlice(left, 0);\n  const rightKeys = pathSlice(right, 0);\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 * @returns true if paths are the same.\n */\nexport function pathEquals(path: Path, other: Path): boolean {\n  if (pathGetLength(path) !== pathGetLength(other)) {\n    return false;\n  }\n\n  for (\n    let i = path.pieceNum_, j = other.pieceNum_;\n    i <= path.pieces_.length;\n    i++, j++\n  ) {\n    if (path.pieces_[i] !== other.pieces_[j]) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\n/**\n * @returns True if this path is a parent of (or the same as) other\n */\nexport function pathContains(path: Path, other: Path): boolean {\n  let i = path.pieceNum_;\n  let j = other.pieceNum_;\n  if (pathGetLength(path) > pathGetLength(other)) {\n    return false;\n  }\n  while (i < path.pieces_.length) {\n    if (path.pieces_[i] !== other.pieces_[j]) {\n      return false;\n    }\n    ++i;\n    ++j;\n  }\n  return true;\n}\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  parts_: string[];\n  /** Initialize to number of '/' chars needed in path. */\n  byteLength_: number;\n\n  /**\n   * @param path - Initial Path.\n   * @param errorPrefix_ - Prefix for any error messages.\n   */\n  constructor(path: Path, public errorPrefix_: string) {\n    this.parts_ = pathSlice(path, 0);\n    /** 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    validationPathCheckValid(this);\n  }\n}\n\nexport function validationPathPush(\n  validationPath: ValidationPath,\n  child: string\n): void {\n  // Count the needed '/'\n  if (validationPath.parts_.length > 0) {\n    validationPath.byteLength_ += 1;\n  }\n  validationPath.parts_.push(child);\n  validationPath.byteLength_ += stringLength(child);\n  validationPathCheckValid(validationPath);\n}\n\nexport function validationPathPop(validationPath: ValidationPath): void {\n  const last = validationPath.parts_.pop();\n  validationPath.byteLength_ -= stringLength(last);\n  // Un-count the previous '/'\n  if (validationPath.parts_.length > 0) {\n    validationPath.byteLength_ -= 1;\n  }\n}\n\nfunction validationPathCheckValid(validationPath: ValidationPath): void {\n  if (validationPath.byteLength_ > MAX_PATH_LENGTH_BYTES) {\n    throw new Error(\n      validationPath.errorPrefix_ +\n        'has a key path longer than ' +\n        MAX_PATH_LENGTH_BYTES +\n        ' bytes (' +\n        validationPath.byteLength_ +\n        ').'\n    );\n  }\n  if (validationPath.parts_.length > MAX_PATH_DEPTH) {\n    throw new Error(\n      validationPath.errorPrefix_ +\n        'path specified exceeds the maximum depth that can be written (' +\n        MAX_PATH_DEPTH +\n        ') or object contains a cycle ' +\n        validationPathToErrorString(validationPath)\n    );\n  }\n}\n\n/**\n * String for use in error messages - uses '.' notation for path.\n */\nexport function validationPathToErrorString(\n  validationPath: ValidationPath\n): string {\n  if (validationPath.parts_.length === 0) {\n    return '';\n  }\n  return \"in property '\" + validationPath.parts_.join('.') + \"'\";\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { EventEmitter } from './EventEmitter';\n\ndeclare const document: Document;\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  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 LLC\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  contains,\n  Deferred,\n  isEmpty,\n  isMobileCordova,\n  isNodeSdk,\n  isReactNative,\n  isValidFormat,\n  safeGet,\n  stringify,\n  isAdmin\n} from '@firebase/util';\n\nimport { Connection } from '../realtime/Connection';\n\nimport { AppCheckTokenProvider } from './AppCheckTokenProvider';\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { RepoInfo } from './RepoInfo';\nimport { ServerActions } from './ServerActions';\nimport { OnlineMonitor } from './util/OnlineMonitor';\nimport { Path } from './util/Path';\nimport { error, log, logWrapper, warn, ObjectToUniqueKey } from './util/util';\nimport { VisibilityMonitor } from './util/VisibilityMonitor';\nimport { SDK_VERSION } from './version';\nimport { QueryContext } from './view/EventRegistration';\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_TOKEN_THRESHOLD = 3;\n\ninterface ListenSpec {\n  onComplete(s: string, p?: unknown): void;\n\n  hashFn(): string;\n\n  query: QueryContext;\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\ninterface OutstandingGet {\n  request: object;\n  onComplete: (response: { [k: string]: unknown }) => 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  private readonly listens: Map<\n    /* path */ string,\n    Map</* queryId */ string, ListenSpec>\n  > = new Map();\n  private outstandingPuts_: OutstandingPut[] = [];\n  private outstandingGets_: OutstandingGet[] = [];\n  private outstandingPutCount_ = 0;\n  private outstandingGetCount_ = 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 appCheckToken_: string | null = null;\n  private forceTokenRefresh_ = false;\n  private invalidAuthTokenCount_ = 0;\n  private invalidAppCheckTokenCount_ = 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   * @param repoInfo_ - Data about the namespace we are connecting to\n   * @param applicationId_ - The Firebase App ID for this project\n   * @param onDataUpdate_ - A callback for new data from the server\n   */\n  constructor(\n    private repoInfo_: RepoInfo,\n    private applicationId_: string,\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 appCheckTokenProvider_: AppCheckTokenProvider,\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\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  get(query: QueryContext): Promise<string> {\n    this.initConnection_();\n\n    const deferred = new Deferred<string>();\n    const request = {\n      p: query._path.toString(),\n      q: query._queryObject\n    };\n    const outstandingGet = {\n      action: 'g',\n      request,\n      onComplete: (message: { [k: string]: unknown }) => {\n        const payload = message['d'] as string;\n        if (message['s'] === 'ok') {\n          deferred.resolve(payload);\n        } else {\n          deferred.reject(payload);\n        }\n      }\n    };\n    this.outstandingGets_.push(outstandingGet);\n    this.outstandingGetCount_++;\n    const index = this.outstandingGets_.length - 1;\n\n    if (this.connected_) {\n      this.sendGet_(index);\n    }\n\n    return deferred.promise;\n  }\n\n  listen(\n    query: QueryContext,\n    currentHashFn: () => string,\n    tag: number | null,\n    onComplete: (a: string, b: unknown) => void\n  ) {\n    this.initConnection_();\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._queryParams.isDefault() || !query._queryParams.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 sendGet_(index: number) {\n    const get = this.outstandingGets_[index];\n    this.sendRequest('g', get.request, (message: { [k: string]: unknown }) => {\n      delete this.outstandingGets_[index];\n      this.outstandingGetCount_--;\n      if (this.outstandingGetCount_ === 0) {\n        this.outstandingGets_ = [];\n      }\n      if (get.onComplete) {\n        get.onComplete(message);\n      }\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: QueryContext) {\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\": \"' + query._queryParams.getIndex().toString() + '\"';\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  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  refreshAppCheckToken(token: string | null) {\n    this.appCheckToken_ = token;\n    this.log_('App check token refreshed');\n    if (this.appCheckToken_) {\n      this.tryAppCheck();\n    } else {\n      //If we're connected we want to let the server know to unauthenticate us.\n      //If we're not connected, simply delete the credential so we dont become\n      // authenticated next time we connect.\n      if (this.connected_) {\n        this.sendRequest('unappeck', {}, () => {});\n      }\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   * Attempts to authenticate with the given token. If the authentication\n   * attempt fails, it's triggered like the token was revoked (the connection is\n   * closed).\n   */\n  tryAppCheck() {\n    if (this.connected_ && this.appCheckToken_) {\n      this.sendRequest(\n        'appcheck',\n        { 'token': this.appCheckToken_ },\n        (res: { [k: string]: unknown }) => {\n          const status = res[/*status*/ 's'] as string;\n          const data = (res[/*data*/ 'd'] as string) || 'error';\n          if (status === 'ok') {\n            this.invalidAppCheckTokenCount_ = 0;\n          } else {\n            this.onAppCheckRevoked_(status, data);\n          }\n        }\n      );\n    }\n  }\n\n  /**\n   * @inheritDoc\n   */\n  unlisten(query: QueryContext, 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._queryParams.isDefault() || !query._queryParams.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  onDisconnectPut(\n    pathString: string,\n    data: unknown,\n    onComplete?: (a: string, b: string) => void\n  ) {\n    this.initConnection_();\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  onDisconnectMerge(\n    pathString: string,\n    data: unknown,\n    onComplete?: (a: string, b: string) => void\n  ) {\n    this.initConnection_();\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  onDisconnectCancel(\n    pathString: string,\n    onComplete?: (a: string, b: string) => void\n  ) {\n    this.initConnection_();\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  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  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    this.initConnection_();\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  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 === 'apc') {\n      this.onAppCheckRevoked_(\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 initConnection_() {\n    if (!this.realtime_ && this.firstConnection_) {\n      this.scheduleConnect_(0);\n    }\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 = Math.max(\n        0,\n        new Date().getTime() - this.lastConnectionAttemptTime_\n      );\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 async 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 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      try {\n        // First fetch auth and app check token, and establish connection after\n        // fetching the token was successful\n        const [authToken, appCheckToken] = await Promise.all([\n          this.authTokenProvider_.getToken(forceRefresh),\n          this.appCheckTokenProvider_.getToken(forceRefresh)\n        ]);\n\n        if (!canceled) {\n          log('getToken() completed. Creating connection.');\n          this.authToken_ = authToken && authToken.accessToken;\n          this.appCheckToken_ = appCheckToken && appCheckToken.token;\n          connection = new Connection(\n            connId,\n            this.repoInfo_,\n            this.applicationId_,\n            this.appCheckToken_,\n            this.authToken_,\n            onDataMessage,\n            onReady,\n            onDisconnect,\n            /* onKill= */ reason => {\n              warn(reason + ' (' + this.repoInfo_.toString() + ')');\n              this.interrupt(SERVER_KILL_INTERRUPT_REASON);\n            },\n            lastSessionId\n          );\n        } else {\n          log('getToken() completed but was canceled');\n        }\n      } catch (error) {\n        this.log_('Failed to get token: ' + error);\n        if (!canceled) {\n          if (this.repoInfo_.nodeAdmin) {\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_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 onAppCheckRevoked_(statusCode: string, explanation: string) {\n    log('App check token revoked: ' + statusCode + '/' + explanation);\n    this.appCheckToken_ = null;\n    this.forceTokenRefresh_ = true;\n    // Note: We don't close the connection as the developer may not have\n    // enforcement enabled. The backend closes connections with enforcements.\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.invalidAppCheckTokenCount_++;\n      if (this.invalidAppCheckTokenCount_ >= INVALID_TOKEN_THRESHOLD) {\n        this.appCheckTokenProvider_.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    this.tryAppCheck();\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    for (let i = 0; i < this.outstandingGets_.length; i++) {\n      if (this.outstandingGets_[i]) {\n        this.sendGet_(i);\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 (isNodeSdk()) {\n      if (this.repoInfo_.nodeAdmin) {\n        clientName = 'admin_node';\n      } else {\n        clientName = 'node';\n      }\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 LLC\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';\n\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   * @returns Whether this is a leaf node.\n   */\n  isLeafNode(): boolean;\n\n  /**\n   * Gets the priority of the node.\n   * @returns The priority of the node.\n   */\n  getPriority(): Node;\n\n  /**\n   * Returns a duplicate node with the new priority.\n   * @param newPriorityNode - New priority to set for the node.\n   * @returns 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 childName - The name of the child to retrieve.\n   * @returns 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 - The path of the child to retrieve.\n   * @returns 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 childName - The name of the child to find the predecessor of.\n   * @param childNode - The node to find the predecessor of.\n   * @param index - The index to use to determine the predecessor\n   * @returns 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 childName - The name of the child to update.\n   * @param newChildNode - The new child node\n   * @returns 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 - The path of the child to update.\n   * @param newChildNode - The new child node, which may be an empty node\n   * @returns The updated node.\n   */\n  updateChild(path: Path, newChildNode: Node): Node;\n\n  /**\n   * True if the immediate child specified exists\n   */\n  hasChild(childName: string): boolean;\n\n  /**\n   * @returns True if this node has no value or children.\n   */\n  isEmpty(): boolean;\n\n  /**\n   * @returns The number of children of this node.\n   */\n  numChildren(): number;\n\n  /**\n   * Calls action for each child.\n   * @param action - Action to be called for\n   * each child.  It's passed the child name and the child node.\n   * @returns 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   * @returns Value of this node as JSON.\n   */\n  val(exportFormat?: boolean): unknown;\n\n  /**\n   * @returns hash representing the node contents.\n   */\n  hash(): string;\n\n  /**\n   * @param other - Another node\n   * @returns -1 for less than, 0 for equal, 1 for greater than other\n   */\n  compareTo(other: Node): number;\n\n  /**\n   * @returns Whether or not this snapshot equals other\n   */\n  equals(other: Node): boolean;\n\n  /**\n   * @returns This node, with the specified index now available\n   */\n  withIndex(indexDefinition: Index): Node;\n\n  isIndexed(indexDefinition: Index): boolean;\n}\n\nexport class NamedNode {\n  constructor(public name: string, public node: Node) {}\n\n  static Wrap(name: string, node: Node) {\n    return new NamedNode(name, node);\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { Comparator } from '../../util/SortedMap';\nimport { MIN_NAME } from '../../util/util';\nimport { Node, NamedNode } from '../Node';\n\nexport abstract class Index {\n  abstract compare(a: NamedNode, b: NamedNode): number;\n\n  abstract isDefinedOn(node: Node): boolean;\n\n  /**\n   * @returns A standalone comparison function for\n   * this index\n   */\n  getCompare(): Comparator<NamedNode> {\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   *\n   * @returns 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   * @returns 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   * @returns 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  abstract makePost(indexValue: unknown, name: string): NamedNode;\n\n  /**\n   * @returns String representation for inclusion in a query spec\n   */\n  abstract toString(): string;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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, assertionError } from '@firebase/util';\n\nimport { nameCompare, MAX_NAME } from '../../util/util';\nimport { ChildrenNode } from '../ChildrenNode';\nimport { Node, NamedNode } from '../Node';\n\nimport { Index } from './Index';\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  compare(a: NamedNode, b: NamedNode): number {\n    return nameCompare(a.name, b.name);\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  indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n    return false; // The key for a node never changes.\n  }\n  minPost() {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return (NamedNode as any).MIN;\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  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   * @returns 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 LLC\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<K> = (key1: K, key2: K) => number;\n\n/**\n * An iterator over an LLRBNode.\n */\nexport class SortedMapIterator<K, V, T> {\n  private nodeStack_: Array<LLRBNode<K, V> | LLRBEmptyNode<K, V>> = [];\n\n  /**\n   * @param node - Node to iterate.\n   * @param isReverse_ - Whether or not to iterate in reverse\n   */\n  constructor(\n    node: LLRBNode<K, V> | LLRBEmptyNode<K, V>,\n    startKey: K | null,\n    comparator: Comparator<K>,\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<K, V>;\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<K, V> {\n  color: boolean;\n  left: LLRBNode<K, V> | LLRBEmptyNode<K, V>;\n  right: LLRBNode<K, V> | LLRBEmptyNode<K, V>;\n\n  /**\n   * @param key - Key associated with this node.\n   * @param value - Value associated with this node.\n   * @param color - Whether this node is red.\n   * @param left - Left child.\n   * @param right - Right child.\n   */\n  constructor(\n    public key: K,\n    public value: V,\n    color: boolean | null,\n    left?: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null,\n    right?: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null\n  ) {\n    this.color = color != null ? color : LLRBNode.RED;\n    this.left =\n      left != null ? left : (SortedMap.EMPTY_NODE as LLRBEmptyNode<K, V>);\n    this.right =\n      right != null ? right : (SortedMap.EMPTY_NODE as LLRBEmptyNode<K, V>);\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 key - New key for the node, or null.\n   * @param value - New value for the node, or null.\n   * @param color - New color for the node, or null.\n   * @param left - New left child for the node, or null.\n   * @param right - New right child for the node, or null.\n   * @returns The node copy.\n   */\n  copy(\n    key: K | null,\n    value: V | null,\n    color: boolean | null,\n    left: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null,\n    right: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null\n  ): LLRBNode<K, V> {\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   * @returns 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   * @returns 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 action - Callback function to be called for each\n   *   node.  If it returns true, traversal is aborted.\n   * @returns 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 action - Callback function to be called for each\n   * node.  If it returns true, traversal is aborted.\n   * @returns 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   * @returns The minimum node in the tree.\n   */\n  private min_(): LLRBNode<K, V> {\n    if (this.left.isEmpty()) {\n      return this;\n    } else {\n      return (this.left as LLRBNode<K, V>).min_();\n    }\n  }\n\n  /**\n   * @returns The maximum key in the tree.\n   */\n  minKey(): K {\n    return this.min_().key;\n  }\n\n  /**\n   * @returns 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   * @param key - Key to insert.\n   * @param value - Value to insert.\n   * @param comparator - Comparator.\n   * @returns New tree, with the key/value added.\n   */\n  insert(key: K, value: V, comparator: Comparator<K>): LLRBNode<K, V> {\n    let n: LLRBNode<K, V> = 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   * @returns New tree, with the minimum key removed.\n   */\n  private removeMin_(): LLRBNode<K, V> | LLRBEmptyNode<K, V> {\n    if (this.left.isEmpty()) {\n      return SortedMap.EMPTY_NODE as LLRBEmptyNode<K, V>;\n    }\n    let n: LLRBNode<K, V> = 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<K, V>).removeMin_(), null);\n    return n.fixUp_();\n  }\n\n  /**\n   * @param key - The key of the item to remove.\n   * @param comparator - Comparator.\n   * @returns New tree, with the specified item removed.\n   */\n  remove(\n    key: K,\n    comparator: Comparator<K>\n  ): LLRBNode<K, V> | LLRBEmptyNode<K, V> {\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<K, V>;\n        } else {\n          smallest = (n.right as LLRBNode<K, V>).min_();\n          n = n.copy(\n            smallest.key,\n            smallest.value,\n            null,\n            null,\n            (n.right as LLRBNode<K, V>).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   * @returns Whether this is a RED node.\n   */\n  isRed_(): boolean {\n    return this.color;\n  }\n\n  /**\n   * @returns New tree after performing any needed rotations.\n   */\n  private fixUp_(): LLRBNode<K, V> {\n    let n: LLRBNode<K, V> = 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   * @returns New tree, after moveRedLeft.\n   */\n  private moveRedLeft_(): LLRBNode<K, V> {\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<K, V>).rotateRight_()\n      );\n      n = n.rotateLeft_();\n      n = n.colorFlip_();\n    }\n    return n;\n  }\n\n  /**\n   * @returns New tree, after moveRedRight.\n   */\n  private moveRedRight_(): LLRBNode<K, V> {\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   * @returns New tree, after rotateLeft.\n   */\n  private rotateLeft_(): LLRBNode<K, V> {\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<K, V>;\n  }\n\n  /**\n   * @returns New tree, after rotateRight.\n   */\n  private rotateRight_(): LLRBNode<K, V> {\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<K, V>;\n  }\n\n  /**\n   * @returns Newt ree, after colorFlip.\n   */\n  private colorFlip_(): LLRBNode<K, V> {\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   * @returns 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  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<K, V> {\n  key: K;\n  value: V;\n  left: LLRBNode<K, V> | LLRBEmptyNode<K, V>;\n  right: LLRBNode<K, V> | LLRBEmptyNode<K, V>;\n  color: boolean;\n\n  /**\n   * Returns a copy of the current node.\n   *\n   * @returns The node copy.\n   */\n  copy(\n    key: K | null,\n    value: V | null,\n    color: boolean | null,\n    left: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null,\n    right: LLRBNode<K, V> | LLRBEmptyNode<K, V> | null\n  ): LLRBEmptyNode<K, V> {\n    return this;\n  }\n\n  /**\n   * Returns a copy of the tree, with the specified key/value added.\n   *\n   * @param key - Key to be added.\n   * @param value - Value to be added.\n   * @param comparator - Comparator.\n   * @returns New tree, with item added.\n   */\n  insert(key: K, value: V, comparator: Comparator<K>): LLRBNode<K, V> {\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 key - The key to remove.\n   * @param comparator - Comparator.\n   * @returns New tree, with item removed.\n   */\n  remove(key: K, comparator: Comparator<K>): LLRBEmptyNode<K, V> {\n    return this;\n  }\n\n  /**\n   * @returns The total number of nodes in the tree.\n   */\n  count(): number {\n    return 0;\n  }\n\n  /**\n   * @returns 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 action - Callback function to be called for each\n   * node.  If it returns true, traversal is aborted.\n   * @returns 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 action - Callback function to be called for each\n   * node.  If it returns true, traversal is aborted.\n   * @returns True if traversal was aborted.\n   */\n  reverseTraversal(action: (k: K, v: V) => void): boolean {\n    return false;\n  }\n\n  minKey(): null {\n    return null;\n  }\n\n  maxKey(): null {\n    return null;\n  }\n\n  check_(): number {\n    return 0;\n  }\n\n  /**\n   * @returns 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<K, V> {\n  /**\n   * Always use the same empty node, to reduce memory.\n   */\n  static EMPTY_NODE = new LLRBEmptyNode();\n\n  /**\n   * @param comparator_ - Key comparator.\n   * @param root_ - Optional root node for the map.\n   */\n  constructor(\n    private comparator_: Comparator<K>,\n    private root_:\n      | LLRBNode<K, V>\n      | LLRBEmptyNode<K, V> = SortedMap.EMPTY_NODE as LLRBEmptyNode<K, V>\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 key - Key to be added.\n   * @param value - Value to be added.\n   * @returns New map, with item added.\n   */\n  insert(key: K, value: V): SortedMap<K, V> {\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 key - The key to remove.\n   * @returns New map, with item removed.\n   */\n  remove(key: K): SortedMap<K, V> {\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 key - The key to look up.\n   * @returns 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 key - The key to find the predecessor of\n   * @returns 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   * @returns True if the map is empty.\n   */\n  isEmpty(): boolean {\n    return this.root_.isEmpty();\n  }\n\n  /**\n   * @returns The total number of nodes in the map.\n   */\n  count(): number {\n    return this.root_.count();\n  }\n\n  /**\n   * @returns The minimum key in the map.\n   */\n  minKey(): K | null {\n    return this.root_.minKey();\n  }\n\n  /**\n   * @returns 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 action - Callback function to be called\n   * for each key/value pair.  If action returns true, traversal is aborted.\n   * @returns 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 action - Callback function to be called\n   * for each key/value pair.  If action returns true, traversal is aborted.\n   * @returns 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   * @returns The iterator.\n   */\n  getIterator<T>(\n    resultGenerator?: (k: K, v: V) => T\n  ): SortedMapIterator<K, V, T> {\n    return new SortedMapIterator(\n      this.root_,\n      null,\n      this.comparator_,\n      false,\n      resultGenerator\n    );\n  }\n\n  getIteratorFrom<T>(\n    key: K,\n    resultGenerator?: (k: K, v: V) => T\n  ): SortedMapIterator<K, V, T> {\n    return new SortedMapIterator(\n      this.root_,\n      key,\n      this.comparator_,\n      false,\n      resultGenerator\n    );\n  }\n\n  getReverseIteratorFrom<T>(\n    key: K,\n    resultGenerator?: (k: K, v: V) => T\n  ): SortedMapIterator<K, V, T> {\n    return new SortedMapIterator(\n      this.root_,\n      key,\n      this.comparator_,\n      true,\n      resultGenerator\n    );\n  }\n\n  getReverseIterator<T>(\n    resultGenerator?: (k: K, v: V) => T\n  ): SortedMapIterator<K, V, T> {\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 LLC\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';\n\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 LLC\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';\n\nimport { Indexable } from '../util/misc';\nimport { doubleToIEEE754String } from '../util/util';\n\nimport { Node } from './Node';\n\nlet MAX_NODE: Node;\n\nexport function setMaxNode(val: Node) {\n  MAX_NODE = val;\n}\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 */\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 LLC\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\nimport { Indexable } from '../util/misc';\nimport {\n  Path,\n  pathGetFront,\n  pathGetLength,\n  pathIsEmpty,\n  pathPopFront\n} from '../util/Path';\nimport { doubleToIEEE754String, sha1 } from '../util/util';\n\nimport { ChildrenNodeConstructor } from './ChildrenNode';\nimport { Index } from './indexes/Index';\nimport { Node } from './Node';\nimport { priorityHashText, validatePriorityNode } from './snap';\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   */\n  static VALUE_TYPE_ORDER = ['object', 'boolean', 'number', 'string'];\n\n  private lazyHash_: string | null = null;\n\n  /**\n   * @param value_ - The value to store in this leaf node. The object type is\n   * possible in the event of a deferred value\n   * @param 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 (pathIsEmpty(path)) {\n      return this;\n    } else if (pathGetFront(path) === '.priority') {\n      return this.priorityNode_;\n    } else {\n      return LeafNode.__childrenNodeConstructor.EMPTY_NODE;\n    }\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 = pathGetFront(path);\n    if (front === null) {\n      return newChildNode;\n    } else if (newChildNode.isEmpty() && front !== '.priority') {\n      return this;\n    } else {\n      assert(\n        front !== '.priority' || pathGetLength(path) === 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          pathPopFront(path),\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  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   * @returns The value of the node.\n   */\n  getValue(): Indexable | string | number | boolean {\n    return this.value_;\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   */\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  withIndex(): Node {\n    return this;\n  }\n  isIndexed(): boolean {\n    return true;\n  }\n  equals(other: Node): boolean {\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 LLC\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, MAX_NAME } from '../../util/util';\nimport { LeafNode } from '../LeafNode';\nimport { NamedNode, Node } from '../Node';\n\nimport { Index } from './Index';\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\nexport class PriorityIndex extends Index {\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  isDefinedOn(node: Node): boolean {\n    return !node.getPriority().isEmpty();\n  }\n  indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n    return !oldNode.getPriority().equals(newNode.getPriority());\n  }\n  minPost(): NamedNode {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return (NamedNode as any).MIN;\n  }\n  maxPost(): NamedNode {\n    return new NamedNode(MAX_NAME, new LeafNode('[PRIORITY-POST]', MAX_NODE));\n  }\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   * @returns 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 LLC\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\nclass Base12Num {\n  count: number;\n  private current_: number;\n  private bits_: number;\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  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 * @param childList - Unsorted list of children\n * @param cmp - The comparison method to be used\n * @param keyFn - An optional function to extract K from a node wrapper, if K's\n * type is not NamedNode\n * @param mapSortFn - An optional override for comparator used by the generated sorted map\n */\nexport const buildChildSet = function <K, V>(\n  childList: NamedNode[],\n  cmp: (a: NamedNode, b: NamedNode) => number,\n  keyFn?: (a: NamedNode) => K,\n  mapSortFn?: (a: K, b: K) => number\n): SortedMap<K, V> {\n  childList.sort(cmp);\n\n  const buildBalancedTree = function (\n    low: number,\n    high: number\n  ): LLRBNode<K, V> | 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<K, V> {\n    let node: LLRBNode<K, V> = 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<K, V>) {\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<K, V>(mapSortFn || (cmp as any), root);\n};\n","/**\n * @license\n * Copyright 2017 Google LLC\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';\n\nimport { SortedMap } from '../util/SortedMap';\n\nimport { buildChildSet } from './childSet';\nimport { Index } from './indexes/Index';\nimport { KEY_INDEX } from './indexes/KeyIndex';\nimport { PRIORITY_INDEX } from './indexes/PriorityIndex';\nimport { NamedNode, Node } from './Node';\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<NamedNode, Node> | /*FallbackType*/ object;\n    },\n    private indexSet_: { [k: string]: Index }\n  ) {}\n\n  get(indexKey: string): SortedMap<NamedNode, Node> | 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<string, Node>\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<string, Node>\n  ): IndexMap {\n    const newIndexes = map(\n      this.indexes_,\n      (indexedChildren: SortedMap<NamedNode, Node>, 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<string, Node>\n  ): IndexMap {\n    const newIndexes = map(\n      this.indexes_,\n      (indexedChildren: SortedMap<NamedNode, Node>) => {\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 LLC\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\nimport { Path, pathGetFront, pathGetLength, pathPopFront } from '../util/Path';\nimport { SortedMap, SortedMapIterator } from '../util/SortedMap';\nimport { MAX_NAME, MIN_NAME, sha1 } from '../util/util';\n\nimport { NAME_COMPARATOR } from './comparators';\nimport { Index } from './indexes/Index';\nimport { KEY_INDEX, KeyIndex } from './indexes/KeyIndex';\nimport {\n  PRIORITY_INDEX,\n  setMaxNode as setPriorityMaxNode\n} from './indexes/PriorityIndex';\nimport { IndexMap } from './IndexMap';\nimport { LeafNode } from './LeafNode';\nimport { NamedNode, Node } from './Node';\nimport { priorityHashText, setMaxNode, validatePriorityNode } from './snap';\n\nexport interface ChildrenNodeConstructor {\n  new (\n    children_: SortedMap<string, Node>,\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 */\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<string, Node>(NAME_COMPARATOR),\n        null,\n        IndexMap.Default\n      ))\n    );\n  }\n\n  /**\n   * @param children_ - List of children of this node..\n   * @param priorityNode_ - The priority of this node (as a snapshot node).\n   */\n  constructor(\n    private readonly children_: SortedMap<string, Node>,\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 = pathGetFront(path);\n    if (front === null) {\n      return this;\n    }\n\n    return this.getImmediateChild(front).getChild(pathPopFront(path));\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 = pathGetFront(path);\n    if (front === null) {\n      return newChildNode;\n    } else {\n      assert(\n        pathGetFront(path) !== '.priority' || pathGetLength(path) === 1,\n        '.priority must be the last token in a path'\n      );\n      const newImmediateChild = this.getImmediateChild(front).updateChild(\n        pathPopFront(path),\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  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  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  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   */\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  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  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  getIterator(\n    indexDefinition: Index\n  ): SortedMapIterator<string | NamedNode, Node, NamedNode> {\n    return this.getIteratorFrom(indexDefinition.minPost(), indexDefinition);\n  }\n\n  getIteratorFrom(\n    startPost: NamedNode,\n    indexDefinition: Index\n  ): SortedMapIterator<string | NamedNode, Node, NamedNode> {\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  getReverseIterator(\n    indexDefinition: Index\n  ): SortedMapIterator<string | NamedNode, Node, NamedNode> {\n    return this.getReverseIteratorFrom(\n      indexDefinition.maxPost(),\n      indexDefinition\n    );\n  }\n\n  getReverseIteratorFrom(\n    endPost: NamedNode,\n    indexDefinition: Index\n  ): SortedMapIterator<string | NamedNode, Node, NamedNode> {\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  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  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  isIndexed(index: Index): boolean {\n    return index === KEY_INDEX || this.indexMap_.hasIndex(index);\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   */\n  private resolveIndex_(\n    indexDefinition: Index\n  ): SortedMap<NamedNode, Node> | null {\n    if (indexDefinition === KEY_INDEX) {\n      return null;\n    } else {\n      return this.indexMap_.get(indexDefinition.toString());\n    }\n  }\n}\n\nexport class MaxNode extends ChildrenNode {\n  constructor() {\n    super(\n      new SortedMap<string, Node>(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 */\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 LLC\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, assert } from '@firebase/util';\n\nimport { Indexable } from '../util/misc';\nimport { SortedMap } from '../util/SortedMap';\nimport { each } from '../util/util';\n\nimport { ChildrenNode } from './ChildrenNode';\nimport { buildChildSet } from './childSet';\nimport { NAME_COMPARATOR, NAME_ONLY_COMPARATOR } from './comparators';\nimport { PRIORITY_INDEX, setNodeFromJSON } from './indexes/PriorityIndex';\nimport { IndexMap } from './IndexMap';\nimport { LeafNode } from './LeafNode';\nimport { NamedNode, Node } from './Node';\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 priority - Optional priority to use.  This will be ignored if the\n * passed JSON contains a .priority property.\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<string, Node>;\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 LLC\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\nimport { Path, pathGetFront, pathIsEmpty, pathSlice } from '../../util/Path';\nimport { MAX_NAME, nameCompare } from '../../util/util';\nimport { ChildrenNode, MAX_NODE } from '../ChildrenNode';\nimport { NamedNode, Node } from '../Node';\nimport { nodeFromJSON } from '../nodeFromJSON';\n\nimport { Index } from './Index';\n\nexport class PathIndex extends Index {\n  constructor(private indexPath_: Path) {\n    super();\n\n    assert(\n      !pathIsEmpty(indexPath_) && pathGetFront(indexPath_) !== '.priority',\n      \"Can't create PathIndex with empty path or .priority key\"\n    );\n  }\n\n  protected extractChild(snap: Node): Node {\n    return snap.getChild(this.indexPath_);\n  }\n  isDefinedOn(node: Node): boolean {\n    return !node.getChild(this.indexPath_).isEmpty();\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  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  maxPost(): NamedNode {\n    const node = ChildrenNode.EMPTY_NODE.updateChild(this.indexPath_, MAX_NODE);\n    return new NamedNode(MAX_NAME, node);\n  }\n  toString(): string {\n    return pathSlice(this.indexPath_, 0).join('/');\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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, Node } from '../Node';\nimport { nodeFromJSON } from '../nodeFromJSON';\n\nimport { Index } from './Index';\n\nexport class ValueIndex extends Index {\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  isDefinedOn(node: Node): boolean {\n    return true;\n  }\n  indexedValueChanged(oldNode: Node, newNode: Node): boolean {\n    return !oldNode.equals(newNode);\n  }\n  minPost(): NamedNode {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return (NamedNode as any).MIN;\n  }\n  maxPost(): NamedNode {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    return (NamedNode as any).MAX;\n  }\n\n  makePost(indexValue: object, name: string): NamedNode {\n    const valueNode = nodeFromJSON(indexValue);\n    return new NamedNode(name, valueNode);\n  }\n\n  /**\n   * @returns 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 LLC\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\nexport const enum ChangeType {\n  /** Event type for a child added */\n  CHILD_ADDED = 'child_added',\n  /** Event type for a child removed */\n  CHILD_REMOVED = 'child_removed',\n  /** Event type for a child changed */\n  CHILD_CHANGED = 'child_changed',\n  /** Event type for a child moved */\n  CHILD_MOVED = 'child_moved',\n  /** Event type for a value change */\n  VALUE = 'value'\n}\n\nexport interface Change {\n  /** @param type - The event type */\n  type: ChangeType;\n  /** @param snapshotNode - The data */\n  snapshotNode: Node;\n  /** @param childName - The name for this child, if it's a child even */\n  childName?: string;\n  /** @param oldSnap - Used for intermediate processing of child changed events */\n  oldSnap?: Node;\n  /**  * @param prevName - The name for the previous child, if applicable */\n  prevName?: string | null;\n}\n\nexport function changeValue(snapshotNode: Node): Change {\n  return { type: ChangeType.VALUE, snapshotNode };\n}\n\nexport function changeChildAdded(\n  childName: string,\n  snapshotNode: Node\n): Change {\n  return { type: ChangeType.CHILD_ADDED, snapshotNode, childName };\n}\n\nexport function changeChildRemoved(\n  childName: string,\n  snapshotNode: Node\n): Change {\n  return { type: ChangeType.CHILD_REMOVED, snapshotNode, childName };\n}\n\nexport function changeChildChanged(\n  childName: string,\n  snapshotNode: Node,\n  oldSnap: Node\n): Change {\n  return {\n    type: ChangeType.CHILD_CHANGED,\n    snapshotNode,\n    childName,\n    oldSnap\n  };\n}\n\nexport function changeChildMoved(\n  childName: string,\n  snapshotNode: Node\n): Change {\n  return { type: ChangeType.CHILD_MOVED, snapshotNode, childName };\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { Index } from '../../snap/indexes/Index';\nimport { PRIORITY_INDEX } from '../../snap/indexes/PriorityIndex';\nimport { Node } from '../../snap/Node';\nimport { Path } from '../../util/Path';\nimport {\n  changeChildAdded,\n  changeChildChanged,\n  changeChildRemoved\n} from '../Change';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\nimport { CompleteChildSource } from '../CompleteChildSource';\n\nimport { NodeFilter } from './NodeFilter';\n\n/**\n * Doesn't really filter nodes but applies an index to the node and keeps track of any changes\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            changeChildRemoved(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(changeChildAdded(key, newChild));\n      } else {\n        optChangeAccumulator.trackChildChange(\n          changeChildChanged(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  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              changeChildRemoved(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                changeChildChanged(key, childNode, oldChild)\n              );\n            }\n          } else {\n            optChangeAccumulator.trackChildChange(\n              changeChildAdded(key, childNode)\n            );\n          }\n        });\n      }\n    }\n    return newSnap.withIndex(this.index_);\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  filtersNodes(): boolean {\n    return false;\n  }\n  getIndexedFilter(): IndexedFilter {\n    return this;\n  }\n  getIndex(): Index {\n    return this.index_;\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 '../../../core/snap/Node';\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { Index } from '../../snap/indexes/Index';\nimport { PRIORITY_INDEX } from '../../snap/indexes/PriorityIndex';\nimport { Path } from '../../util/Path';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\nimport { CompleteChildSource } from '../CompleteChildSource';\nimport { QueryParams } from '../QueryParams';\n\nimport { IndexedFilter } from './IndexedFilter';\nimport { NodeFilter } from './NodeFilter';\n\n/**\n * Filters nodes by range and uses an IndexFilter to track any changes after filtering the node\n */\nexport class RangedFilter implements NodeFilter {\n  private indexedFilter_: IndexedFilter;\n\n  private index_: Index;\n\n  private startPost_: NamedNode;\n\n  private endPost_: NamedNode;\n\n  private startIsInclusive_: boolean;\n\n  private endIsInclusive_: boolean;\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    this.startIsInclusive_ = !params.startAfterSet_;\n    this.endIsInclusive_ = !params.endBeforeSet_;\n  }\n\n  getStartPost(): NamedNode {\n    return this.startPost_;\n  }\n\n  getEndPost(): NamedNode {\n    return this.endPost_;\n  }\n\n  matches(node: NamedNode): boolean {\n    const isWithinStart = this.startIsInclusive_\n      ? this.index_.compare(this.getStartPost(), node) <= 0\n      : this.index_.compare(this.getStartPost(), node) < 0;\n    const isWithinEnd = this.endIsInclusive_\n      ? this.index_.compare(node, this.getEndPost()) <= 0\n      : this.index_.compare(node, this.getEndPost()) < 0;\n    return isWithinStart && isWithinEnd;\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  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  updatePriority(oldSnap: Node, newPriority: Node): Node {\n    // Don't support priorities on queries\n    return oldSnap;\n  }\n  filtersNodes(): boolean {\n    return true;\n  }\n  getIndexedFilter(): IndexedFilter {\n    return this.indexedFilter_;\n  }\n  getIndex(): Index {\n    return this.index_;\n  }\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  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 LLC\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\nimport { ChildrenNode } from '../../snap/ChildrenNode';\nimport { Index } from '../../snap/indexes/Index';\nimport { NamedNode, Node } from '../../snap/Node';\nimport { Path } from '../../util/Path';\nimport {\n  changeChildAdded,\n  changeChildChanged,\n  changeChildRemoved\n} from '../Change';\nimport { ChildChangeAccumulator } from '../ChildChangeAccumulator';\nimport { CompleteChildSource } from '../CompleteChildSource';\nimport { QueryParams } from '../QueryParams';\n\nimport { IndexedFilter } from './IndexedFilter';\nimport { NodeFilter } from './NodeFilter';\nimport { RangedFilter } from './RangedFilter';\n\n/**\n * Applies a limit and a range to a node and uses RangedFilter to do the heavy lifting where possible\n */\nexport class LimitedFilter implements NodeFilter {\n  private readonly rangedFilter_: RangedFilter;\n\n  private readonly index_: Index;\n\n  private readonly limit_: number;\n\n  private readonly reverse_: boolean;\n\n  private readonly startIsInclusive_: boolean;\n\n  private readonly endIsInclusive_: boolean;\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    this.startIsInclusive_ = !params.startAfterSet_;\n    this.endIsInclusive_ = !params.endBeforeSet_;\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  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          if (!this.withinDirectionalStart(next)) {\n            // if we have not reached the start, skip to the next element\n            continue;\n          } else if (!this.withinDirectionalEnd(next)) {\n            // if we have reached the end, stop adding elements\n            break;\n          } else {\n            filtered = filtered.updateImmediateChild(next.name, next.node);\n            count++;\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\n        let iterator;\n        if (this.reverse_) {\n          iterator = filtered.getReverseIterator(this.index_);\n        } else {\n          iterator = filtered.getIterator(this.index_);\n        }\n\n        let count = 0;\n        while (iterator.hasNext()) {\n          const next = iterator.getNext();\n          const inRange =\n            count < this.limit_ &&\n            this.withinDirectionalStart(next) &&\n            this.withinDirectionalEnd(next);\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  updatePriority(oldSnap: Node, newPriority: Node): Node {\n    // Don't support priorities on queries\n    return oldSnap;\n  }\n  filtersNodes(): boolean {\n    return true;\n  }\n  getIndexedFilter(): IndexedFilter {\n    return this.rangedFilter_.getIndexedFilter();\n  }\n  getIndex(): Index {\n    return this.index_;\n  }\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            changeChildChanged(childKey, childSnap, oldChildSnap)\n          );\n        }\n        return oldEventCache.updateImmediateChild(childKey, childSnap);\n      } else {\n        if (changeAccumulator != null) {\n          changeAccumulator.trackChildChange(\n            changeChildRemoved(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              changeChildAdded(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            changeChildRemoved(windowBoundary.name, windowBoundary.node)\n          );\n          changeAccumulator.trackChildChange(\n            changeChildAdded(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  private withinDirectionalStart = (node: NamedNode) =>\n    this.reverse_ ? this.withinEndPost(node) : this.withinStartPost(node);\n\n  private withinDirectionalEnd = (node: NamedNode) =>\n    this.reverse_ ? this.withinStartPost(node) : this.withinEndPost(node);\n\n  private withinStartPost = (node: NamedNode) => {\n    const compareRes = this.index_.compare(\n      this.rangedFilter_.getStartPost(),\n      node\n    );\n    return this.startIsInclusive_ ? compareRes <= 0 : compareRes < 0;\n  };\n\n  private withinEndPost = (node: NamedNode) => {\n    const compareRes = this.index_.compare(\n      node,\n      this.rangedFilter_.getEndPost()\n    );\n    return this.endIsInclusive_ ? compareRes <= 0 : compareRes < 0;\n  };\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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';\n\nimport { Index } from '../snap/indexes/Index';\nimport { KEY_INDEX } from '../snap/indexes/KeyIndex';\nimport { PathIndex } from '../snap/indexes/PathIndex';\nimport { PRIORITY_INDEX, PriorityIndex } from '../snap/indexes/PriorityIndex';\nimport { VALUE_INDEX } from '../snap/indexes/ValueIndex';\nimport { MAX_NAME, MIN_NAME } from '../util/util';\n\nimport { IndexedFilter } from './filter/IndexedFilter';\nimport { LimitedFilter } from './filter/LimitedFilter';\nimport { NodeFilter } from './filter/NodeFilter';\nimport { RangedFilter } from './filter/RangedFilter';\n\n/**\n * Wire Protocol Constants\n */\nconst enum WIRE_PROTOCOL_CONSTANTS {\n  INDEX_START_VALUE = 'sp',\n  INDEX_START_NAME = 'sn',\n  INDEX_START_IS_INCLUSIVE = 'sin',\n  INDEX_END_VALUE = 'ep',\n  INDEX_END_NAME = 'en',\n  INDEX_END_IS_INCLUSIVE = 'ein',\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 */\nconst enum REST_QUERY_CONSTANTS {\n  ORDER_BY = 'orderBy',\n  PRIORITY_INDEX = '$priority',\n  VALUE_INDEX = '$value',\n  KEY_INDEX = '$key',\n  START_AFTER = 'startAfter',\n  START_AT = 'startAt',\n  END_AT = 'endAt',\n  END_BEFORE = 'endBefore',\n  LIMIT_TO_FIRST = 'limitToFirst',\n  LIMIT_TO_LAST = 'limitToLast'\n}\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 *\n * @internal\n */\nexport class QueryParams {\n  limitSet_ = false;\n  startSet_ = false;\n  startNameSet_ = false;\n  startAfterSet_ = false; // can only be true if startSet_ is true\n  endSet_ = false;\n  endNameSet_ = false;\n  endBeforeSet_ = false; // can only be true if endSet_ is true\n  limit_ = 0;\n  viewFrom_ = '';\n  indexStartValue_: unknown | null = null;\n  indexStartName_ = '';\n  indexEndValue_: unknown | null = null;\n  indexEndName_ = '';\n  index_: PriorityIndex = PRIORITY_INDEX;\n\n  hasStart(): boolean {\n    return this.startSet_;\n  }\n\n  /**\n   * @returns 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 this.viewFrom_ === WIRE_PROTOCOL_CONSTANTS.VIEW_FROM_LEFT;\n    }\n  }\n\n  /**\n   * Only valid to call if hasStart() returns true\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   */\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  hasEnd(): boolean {\n    return this.endSet_;\n  }\n\n  /**\n   * Only valid to call if hasEnd() returns true.\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   */\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  hasLimit(): boolean {\n    return this.limitSet_;\n  }\n\n  /**\n   * @returns 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   */\n  getLimit(): number {\n    assert(this.limitSet_, 'Only valid if limit has been set');\n    return this.limit_;\n  }\n\n  getIndex(): Index {\n    return this.index_;\n  }\n\n  loadsAllData(): boolean {\n    return !(this.startSet_ || this.endSet_ || this.limitSet_);\n  }\n\n  isDefault(): boolean {\n    return this.loadsAllData() && this.index_ === PRIORITY_INDEX;\n  }\n\n  copy(): QueryParams {\n    const copy = new QueryParams();\n    copy.limitSet_ = this.limitSet_;\n    copy.limit_ = this.limit_;\n    copy.startSet_ = this.startSet_;\n    copy.startAfterSet_ = this.startAfterSet_;\n    copy.indexStartValue_ = this.indexStartValue_;\n    copy.startNameSet_ = this.startNameSet_;\n    copy.indexStartName_ = this.indexStartName_;\n    copy.endSet_ = this.endSet_;\n    copy.endBeforeSet_ = this.endBeforeSet_;\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\nexport function queryParamsGetNodeFilter(queryParams: QueryParams): NodeFilter {\n  if (queryParams.loadsAllData()) {\n    return new IndexedFilter(queryParams.getIndex());\n  } else if (queryParams.hasLimit()) {\n    return new LimitedFilter(queryParams);\n  } else {\n    return new RangedFilter(queryParams);\n  }\n}\n\nexport function queryParamsLimit(\n  queryParams: QueryParams,\n  newLimit: number\n): QueryParams {\n  const newParams = queryParams.copy();\n  newParams.limitSet_ = true;\n  newParams.limit_ = newLimit;\n  newParams.viewFrom_ = '';\n  return newParams;\n}\n\nexport function queryParamsLimitToFirst(\n  queryParams: QueryParams,\n  newLimit: number\n): QueryParams {\n  const newParams = queryParams.copy();\n  newParams.limitSet_ = true;\n  newParams.limit_ = newLimit;\n  newParams.viewFrom_ = WIRE_PROTOCOL_CONSTANTS.VIEW_FROM_LEFT;\n  return newParams;\n}\n\nexport function queryParamsLimitToLast(\n  queryParams: QueryParams,\n  newLimit: number\n): QueryParams {\n  const newParams = queryParams.copy();\n  newParams.limitSet_ = true;\n  newParams.limit_ = newLimit;\n  newParams.viewFrom_ = WIRE_PROTOCOL_CONSTANTS.VIEW_FROM_RIGHT;\n  return newParams;\n}\n\nexport function queryParamsStartAt(\n  queryParams: QueryParams,\n  indexValue: unknown,\n  key?: string | null\n): QueryParams {\n  const newParams = queryParams.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\nexport function queryParamsStartAfter(\n  queryParams: QueryParams,\n  indexValue: unknown,\n  key?: string | null\n): QueryParams {\n  let params: QueryParams;\n  if (queryParams.index_ === KEY_INDEX || !!key) {\n    params = queryParamsStartAt(queryParams, indexValue, key);\n  } else {\n    params = queryParamsStartAt(queryParams, indexValue, MAX_NAME);\n  }\n  params.startAfterSet_ = true;\n  return params;\n}\n\nexport function queryParamsEndAt(\n  queryParams: QueryParams,\n  indexValue: unknown,\n  key?: string | null\n): QueryParams {\n  const newParams = queryParams.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\nexport function queryParamsEndBefore(\n  queryParams: QueryParams,\n  indexValue: unknown,\n  key?: string | null\n): QueryParams {\n  let params: QueryParams;\n  if (queryParams.index_ === KEY_INDEX || !!key) {\n    params = queryParamsEndAt(queryParams, indexValue, key);\n  } else {\n    params = queryParamsEndAt(queryParams, indexValue, MIN_NAME);\n  }\n  params.endBeforeSet_ = true;\n  return params;\n}\n\nexport function queryParamsOrderBy(\n  queryParams: QueryParams,\n  index: Index\n): QueryParams {\n  const newParams = queryParams.copy();\n  newParams.index_ = index;\n  return newParams;\n}\n\n/**\n * Returns a set of REST query string parameters representing this query.\n *\n * @returns query string parameters\n */\nexport function queryParamsToRestQueryStringParameters(\n  queryParams: QueryParams\n): Record<string, string | number> {\n  const qs: Record<string, string | number> = {};\n\n  if (queryParams.isDefault()) {\n    return qs;\n  }\n\n  let orderBy;\n  if (queryParams.index_ === PRIORITY_INDEX) {\n    orderBy = REST_QUERY_CONSTANTS.PRIORITY_INDEX;\n  } else if (queryParams.index_ === VALUE_INDEX) {\n    orderBy = REST_QUERY_CONSTANTS.VALUE_INDEX;\n  } else if (queryParams.index_ === KEY_INDEX) {\n    orderBy = REST_QUERY_CONSTANTS.KEY_INDEX;\n  } else {\n    assert(queryParams.index_ instanceof PathIndex, 'Unrecognized index type!');\n    orderBy = queryParams.index_.toString();\n  }\n  qs[REST_QUERY_CONSTANTS.ORDER_BY] = stringify(orderBy);\n\n  if (queryParams.startSet_) {\n    const startParam = queryParams.startAfterSet_\n      ? REST_QUERY_CONSTANTS.START_AFTER\n      : REST_QUERY_CONSTANTS.START_AT;\n    qs[startParam] = stringify(queryParams.indexStartValue_);\n    if (queryParams.startNameSet_) {\n      qs[startParam] += ',' + stringify(queryParams.indexStartName_);\n    }\n  }\n\n  if (queryParams.endSet_) {\n    const endParam = queryParams.endBeforeSet_\n      ? REST_QUERY_CONSTANTS.END_BEFORE\n      : REST_QUERY_CONSTANTS.END_AT;\n    qs[endParam] = stringify(queryParams.indexEndValue_);\n    if (queryParams.endNameSet_) {\n      qs[endParam] += ',' + stringify(queryParams.indexEndName_);\n    }\n  }\n\n  if (queryParams.limitSet_) {\n    if (queryParams.isViewFromLeft()) {\n      qs[REST_QUERY_CONSTANTS.LIMIT_TO_FIRST] = queryParams.limit_;\n    } else {\n      qs[REST_QUERY_CONSTANTS.LIMIT_TO_LAST] = queryParams.limit_;\n    }\n  }\n\n  return qs;\n}\n\nexport function queryParamsGetQueryObject(\n  queryParams: QueryParams\n): Record<string, unknown> {\n  const obj: Record<string, unknown> = {};\n  if (queryParams.startSet_) {\n    obj[WIRE_PROTOCOL_CONSTANTS.INDEX_START_VALUE] =\n      queryParams.indexStartValue_;\n    if (queryParams.startNameSet_) {\n      obj[WIRE_PROTOCOL_CONSTANTS.INDEX_START_NAME] =\n        queryParams.indexStartName_;\n    }\n    obj[WIRE_PROTOCOL_CONSTANTS.INDEX_START_IS_INCLUSIVE] =\n      !queryParams.startAfterSet_;\n  }\n  if (queryParams.endSet_) {\n    obj[WIRE_PROTOCOL_CONSTANTS.INDEX_END_VALUE] = queryParams.indexEndValue_;\n    if (queryParams.endNameSet_) {\n      obj[WIRE_PROTOCOL_CONSTANTS.INDEX_END_NAME] = queryParams.indexEndName_;\n    }\n    obj[WIRE_PROTOCOL_CONSTANTS.INDEX_END_IS_INCLUSIVE] =\n      !queryParams.endBeforeSet_;\n  }\n  if (queryParams.limitSet_) {\n    obj[WIRE_PROTOCOL_CONSTANTS.LIMIT] = queryParams.limit_;\n    let viewFrom = queryParams.viewFrom_;\n    if (viewFrom === '') {\n      if (queryParams.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 (queryParams.index_ !== PRIORITY_INDEX) {\n    obj[WIRE_PROTOCOL_CONSTANTS.INDEX] = queryParams.index_.toString();\n  }\n  return obj;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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  jsonEval,\n  safeGet,\n  querystring,\n  Deferred\n} from '@firebase/util';\n\nimport { AppCheckTokenProvider } from './AppCheckTokenProvider';\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { RepoInfo } from './RepoInfo';\nimport { ServerActions } from './ServerActions';\nimport { logWrapper, warn } from './util/util';\nimport { QueryContext } from './view/EventRegistration';\nimport { queryParamsToRestQueryStringParameters } from './view/QueryParams';\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 listens_: { [k: string]: object } = {};\n\n  static getListenId_(query: QueryContext, tag?: number | null): string {\n    if (tag !== undefined) {\n      return 'tag$' + tag;\n    } else {\n      assert(\n        query._queryParams.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_ - 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 authTokenProvider_: AuthTokenProvider,\n    private appCheckTokenProvider_: AppCheckTokenProvider\n  ) {\n    super();\n  }\n\n  /** @inheritDoc */\n  listen(\n    query: QueryContext,\n    currentHashFn: () => string,\n    tag: number | null,\n    onComplete: (a: string, b: unknown) => void\n  ) {\n    const pathString = query._path.toString();\n    this.log_('Listen called for ' + pathString + ' ' + query._queryIdentifier);\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 = queryParamsToRestQueryStringParameters(\n      query._queryParams\n    );\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: QueryContext, tag: number | null) {\n    const listenId = ReadonlyRestClient.getListenId_(query, tag);\n    delete this.listens_[listenId];\n  }\n\n  get(query: QueryContext): Promise<string> {\n    const queryStringParameters = queryParamsToRestQueryStringParameters(\n      query._queryParams\n    );\n\n    const pathString = query._path.toString();\n\n    const deferred = new Deferred<string>();\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_(\n            pathString,\n            data,\n            /*isMerge=*/ false,\n            /*tag=*/ null\n          );\n          deferred.resolve(data as string);\n        } else {\n          deferred.reject(new Error(data as string));\n        }\n      }\n    );\n    return deferred.promise;\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  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    return Promise.all([\n      this.authTokenProvider_.getToken(/*forceRefresh=*/ false),\n      this.appCheckTokenProvider_.getToken(/*forceRefresh=*/ false)\n    ]).then(([authToken, appCheckToken]) => {\n      if (authToken && authToken.accessToken) {\n        queryStringParameters['auth'] = authToken.accessToken;\n      }\n      if (appCheckToken && appCheckToken.token) {\n        queryStringParameters['ac'] = appCheckToken.token;\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 LLC\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): Record<string, string> {\n  const obj: Record<string, string> = {};\n  const tokens = querystring.replace(/^\\?/, '').split('&');\n\n  tokens.forEach(token => {\n    if (token) {\n      const [key, value] = token.split('=');\n      obj[decodeURIComponent(key)] = decodeURIComponent(value);\n    }\n  });\n  return obj;\n}\n\n/**\n * Extract the query string part of a URL, including the leading question mark (if present).\n */\nexport function extractQuerystring(url: string): string {\n  const queryStart = url.indexOf('?');\n  if (!queryStart) {\n    return '';\n  }\n  const fragmentStart = url.indexOf('#', queryStart);\n  return url.substring(\n    queryStart,\n    fragmentStart > 0 ? fragmentStart : undefined\n  );\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { Node } from './snap/Node';\nimport { Path } from './util/Path';\n\n/**\n * Mutable object which basically just stores a reference to the \"latest\" immutable snapshot.\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 LLC\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 { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { Node } from './snap/Node';\nimport { Path, pathGetFront, pathIsEmpty, pathPopFront } from './util/Path';\n\n/**\n * Helper class to store a sparse set of snapshots.\n */\nexport interface SparseSnapshotTree {\n  value: Node | null;\n  readonly children: Map<string, SparseSnapshotTree>;\n}\n\nexport function newSparseSnapshotTree(): SparseSnapshotTree {\n  return {\n    value: null,\n    children: new Map()\n  };\n}\n\n/**\n * Gets the node stored at the given path if one exists.\n * Only seems to be used in tests.\n *\n * @param path - Path to look up snapshot for.\n * @returns The retrieved node, or null.\n */\nexport function sparseSnapshotTreeFind(\n  sparseSnapshotTree: SparseSnapshotTree,\n  path: Path\n): Node | null {\n  if (sparseSnapshotTree.value != null) {\n    return sparseSnapshotTree.value.getChild(path);\n  } else if (!pathIsEmpty(path) && sparseSnapshotTree.children.size > 0) {\n    const childKey = pathGetFront(path);\n    path = pathPopFront(path);\n    if (sparseSnapshotTree.children.has(childKey)) {\n      const childTree = sparseSnapshotTree.children.get(childKey);\n      return sparseSnapshotTreeFind(childTree, 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 */\nexport function sparseSnapshotTreeRemember(\n  sparseSnapshotTree: SparseSnapshotTree,\n  path: Path,\n  data: Node\n): void {\n  if (pathIsEmpty(path)) {\n    sparseSnapshotTree.value = data;\n    sparseSnapshotTree.children.clear();\n  } else if (sparseSnapshotTree.value !== null) {\n    sparseSnapshotTree.value = sparseSnapshotTree.value.updateChild(path, data);\n  } else {\n    const childKey = pathGetFront(path);\n    if (!sparseSnapshotTree.children.has(childKey)) {\n      sparseSnapshotTree.children.set(childKey, newSparseSnapshotTree());\n    }\n\n    const child = sparseSnapshotTree.children.get(childKey);\n    path = pathPopFront(path);\n    sparseSnapshotTreeRemember(child, 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 * @returns True if this node should now be removed.\n */\nexport function sparseSnapshotTreeForget(\n  sparseSnapshotTree: SparseSnapshotTree,\n  path: Path\n): boolean {\n  if (pathIsEmpty(path)) {\n    sparseSnapshotTree.value = null;\n    sparseSnapshotTree.children.clear();\n    return true;\n  } else {\n    if (sparseSnapshotTree.value !== null) {\n      if (sparseSnapshotTree.value.isLeafNode()) {\n        // We're trying to forget a node that doesn't exist\n        return false;\n      } else {\n        const value = sparseSnapshotTree.value;\n        sparseSnapshotTree.value = null;\n\n        value.forEachChild(PRIORITY_INDEX, (key, tree) => {\n          sparseSnapshotTreeRemember(sparseSnapshotTree, new Path(key), tree);\n        });\n\n        return sparseSnapshotTreeForget(sparseSnapshotTree, path);\n      }\n    } else if (sparseSnapshotTree.children.size > 0) {\n      const childKey = pathGetFront(path);\n      path = pathPopFront(path);\n      if (sparseSnapshotTree.children.has(childKey)) {\n        const safeToRemove = sparseSnapshotTreeForget(\n          sparseSnapshotTree.children.get(childKey),\n          path\n        );\n        if (safeToRemove) {\n          sparseSnapshotTree.children.delete(childKey);\n        }\n      }\n\n      return sparseSnapshotTree.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 */\nexport function sparseSnapshotTreeForEachTree(\n  sparseSnapshotTree: SparseSnapshotTree,\n  prefixPath: Path,\n  func: (a: Path, b: Node) => unknown\n): void {\n  if (sparseSnapshotTree.value !== null) {\n    func(prefixPath, sparseSnapshotTree.value);\n  } else {\n    sparseSnapshotTreeForEachChild(sparseSnapshotTree, (key, tree) => {\n      const path = new Path(prefixPath.toString() + '/' + key);\n      sparseSnapshotTreeForEachTree(tree, path, func);\n    });\n  }\n}\n\n/**\n * Iterates through each immediate child and triggers the callback.\n * Only seems to be used in tests.\n *\n * @param func - The function to invoke for each child.\n */\nexport function sparseSnapshotTreeForEachChild(\n  sparseSnapshotTree: SparseSnapshotTree,\n  func: (a: string, b: SparseSnapshotTree) => void\n): void {\n  sparseSnapshotTree.children.forEach((tree, key) => {\n    func(key, tree);\n  });\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { each } from '../util/util';\n\nimport { StatsCollection } from './StatsCollection';\n\n/**\n * Returns the delta from the previous call to get stats.\n *\n * @param collection_ - The collection to \"listen\" to.\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 LLC\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\nimport { ServerActions } from '../ServerActions';\nimport { setTimeoutNonBlocking, each } from '../util/util';\n\nimport { StatsCollection } from './StatsCollection';\nimport { StatsListener } from './StatsListener';\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\nexport class StatsReporter {\n  private statsListener_: StatsListener;\n  statsToReport_: { [k: string]: boolean } = {};\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  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\nexport function statsReporterIncludeStat(\n  reporter: StatsReporter,\n  stat: string\n) {\n  reporter.statsToReport_[stat] = true;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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';\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  source: OperationSource;\n\n  type: OperationType;\n\n  path: Path;\n\n  operationForChild(childName: string): Operation | null;\n}\n\nexport interface OperationSource {\n  fromUser: boolean;\n  fromServer: boolean;\n  queryId: string | null;\n  tagged: boolean;\n}\n\nexport function newOperationSourceUser(): OperationSource {\n  return {\n    fromUser: true,\n    fromServer: false,\n    queryId: null,\n    tagged: false\n  };\n}\n\nexport function newOperationSourceServer(): OperationSource {\n  return {\n    fromUser: false,\n    fromServer: true,\n    queryId: null,\n    tagged: false\n  };\n}\n\nexport function newOperationSourceServerTaggedQuery(\n  queryId: string\n): OperationSource {\n  return {\n    fromUser: false,\n    fromServer: true,\n    queryId,\n    tagged: true\n  };\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ImmutableTree } from '../util/ImmutableTree';\nimport {\n  newEmptyPath,\n  Path,\n  pathGetFront,\n  pathIsEmpty,\n  pathPopFront\n} from '../util/Path';\n\nimport { newOperationSourceUser, Operation, OperationType } from './Operation';\n\nexport class AckUserWrite implements Operation {\n  /** @inheritDoc */\n  type = OperationType.ACK_USER_WRITE;\n\n  /** @inheritDoc */\n  source = newOperationSourceUser();\n\n  /**\n   * @param affectedTree - A tree containing true for each affected path. Affected paths can't overlap.\n   */\n  constructor(\n    /** @inheritDoc */ public path: Path,\n    /** @inheritDoc */ public affectedTree: ImmutableTree<boolean>,\n    /** @inheritDoc */ public revert: boolean\n  ) {}\n  operationForChild(childName: string): AckUserWrite {\n    if (!pathIsEmpty(this.path)) {\n      assert(\n        pathGetFront(this.path) === childName,\n        'operationForChild called for unrelated child.'\n      );\n      return new AckUserWrite(\n        pathPopFront(this.path),\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(newEmptyPath(), childTree, this.revert);\n    }\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { newEmptyPath, Path, pathIsEmpty, pathPopFront } from '../util/Path';\n\nimport { Operation, OperationSource, OperationType } from './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 (pathIsEmpty(this.path)) {\n      return new ListenComplete(this.source, newEmptyPath());\n    } else {\n      return new ListenComplete(this.source, pathPopFront(this.path));\n    }\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { newEmptyPath, Path, pathIsEmpty, pathPopFront } from '../util/Path';\n\nimport { Operation, OperationSource, OperationType } from './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 (pathIsEmpty(this.path)) {\n      return new Overwrite(\n        this.source,\n        newEmptyPath(),\n        this.snap.getImmediateChild(childName)\n      );\n    } else {\n      return new Overwrite(this.source, pathPopFront(this.path), this.snap);\n    }\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { Node } from '../snap/Node';\nimport { ImmutableTree } from '../util/ImmutableTree';\nimport {\n  newEmptyPath,\n  Path,\n  pathGetFront,\n  pathIsEmpty,\n  pathPopFront\n} from '../util/Path';\n\nimport { Operation, OperationSource, OperationType } from './Operation';\nimport { Overwrite } from './Overwrite';\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<Node>\n  ) {}\n  operationForChild(childName: string): Operation {\n    if (pathIsEmpty(this.path)) {\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, newEmptyPath(), childTree.value);\n      } else {\n        // This is a merge at a deeper level\n        return new Merge(this.source, newEmptyPath(), childTree);\n      }\n    } else {\n      assert(\n        pathGetFront(this.path) === childName,\n        \"Can't get a merge for a child not on the path of the operation\"\n      );\n      return new Merge(this.source, pathPopFront(this.path), this.children);\n    }\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 LLC\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, pathGetFront, pathIsEmpty } 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  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   */\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   */\n  isFiltered(): boolean {\n    return this.filtered_;\n  }\n\n  isCompleteForPath(path: Path): boolean {\n    if (pathIsEmpty(path)) {\n      return this.isFullyInitialized() && !this.filtered_;\n    }\n\n    const childKey = pathGetFront(path);\n    return this.isCompleteForChild(childKey);\n  }\n\n  isCompleteForChild(key: string): boolean {\n    return (\n      (this.isFullyInitialized() && !this.filtered_) || this.node_.hasChild(key)\n    );\n  }\n\n  getNode(): Node {\n    return this.node_;\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { assertionError } from '@firebase/util';\n\nimport { Index } from '../snap/indexes/Index';\nimport { NamedNode, Node } from '../snap/Node';\n\nimport { Change, ChangeType, changeChildMoved } from './Change';\nimport { Event } from './Event';\nimport { EventRegistration, QueryContext } from './EventRegistration';\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 */\nexport class EventGenerator {\n  index_: Index;\n\n  constructor(public query_: QueryContext) {\n    this.index_ = this.query_._queryParams.getIndex();\n  }\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 */\nexport function eventGeneratorGenerateEventsForChanges(\n  eventGenerator: EventGenerator,\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 === ChangeType.CHILD_CHANGED &&\n      eventGenerator.index_.indexedValueChanged(\n        change.oldSnap as Node,\n        change.snapshotNode\n      )\n    ) {\n      moves.push(changeChildMoved(change.childName, change.snapshotNode));\n    }\n  });\n\n  eventGeneratorGenerateEventsForType(\n    eventGenerator,\n    events,\n    ChangeType.CHILD_REMOVED,\n    changes,\n    eventRegistrations,\n    eventCache\n  );\n  eventGeneratorGenerateEventsForType(\n    eventGenerator,\n    events,\n    ChangeType.CHILD_ADDED,\n    changes,\n    eventRegistrations,\n    eventCache\n  );\n  eventGeneratorGenerateEventsForType(\n    eventGenerator,\n    events,\n    ChangeType.CHILD_MOVED,\n    moves,\n    eventRegistrations,\n    eventCache\n  );\n  eventGeneratorGenerateEventsForType(\n    eventGenerator,\n    events,\n    ChangeType.CHILD_CHANGED,\n    changes,\n    eventRegistrations,\n    eventCache\n  );\n  eventGeneratorGenerateEventsForType(\n    eventGenerator,\n    events,\n    ChangeType.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 */\nfunction eventGeneratorGenerateEventsForType(\n  eventGenerator: EventGenerator,\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((a, b) =>\n    eventGeneratorCompareChanges(eventGenerator, a, b)\n  );\n  filteredChanges.forEach(change => {\n    const materializedChange = eventGeneratorMaterializeSingleChange(\n      eventGenerator,\n      change,\n      eventCache\n    );\n    registrations.forEach(registration => {\n      if (registration.respondsTo(change.type)) {\n        events.push(\n          registration.createEvent(materializedChange, eventGenerator.query_)\n        );\n      }\n    });\n  });\n}\n\nfunction eventGeneratorMaterializeSingleChange(\n  eventGenerator: EventGenerator,\n  change: Change,\n  eventCache: Node\n): Change {\n  if (change.type === 'value' || change.type === 'child_removed') {\n    return change;\n  } else {\n    change.prevName = eventCache.getPredecessorChildName(\n      change.childName,\n      change.snapshotNode,\n      eventGenerator.index_\n    );\n    return change;\n  }\n}\n\nfunction eventGeneratorCompareChanges(\n  eventGenerator: EventGenerator,\n  a: Change,\n  b: Change\n) {\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 eventGenerator.index_.compare(aWrapped, bWrapped);\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { CacheNode } from './CacheNode';\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 */\nexport interface ViewCache {\n  readonly eventCache: CacheNode;\n  readonly serverCache: CacheNode;\n}\n\nexport function newViewCache(\n  eventCache: CacheNode,\n  serverCache: CacheNode\n): ViewCache {\n  return { eventCache, serverCache };\n}\n\nexport function viewCacheUpdateEventSnap(\n  viewCache: ViewCache,\n  eventSnap: Node,\n  complete: boolean,\n  filtered: boolean\n): ViewCache {\n  return newViewCache(\n    new CacheNode(eventSnap, complete, filtered),\n    viewCache.serverCache\n  );\n}\n\nexport function viewCacheUpdateServerSnap(\n  viewCache: ViewCache,\n  serverSnap: Node,\n  complete: boolean,\n  filtered: boolean\n): ViewCache {\n  return newViewCache(\n    viewCache.eventCache,\n    new CacheNode(serverSnap, complete, filtered)\n  );\n}\n\nexport function viewCacheGetCompleteEventSnap(\n  viewCache: ViewCache\n): Node | null {\n  return viewCache.eventCache.isFullyInitialized()\n    ? viewCache.eventCache.getNode()\n    : null;\n}\n\nexport function viewCacheGetCompleteServerSnap(\n  viewCache: ViewCache\n): Node | null {\n  return viewCache.serverCache.isFullyInitialized()\n    ? viewCache.serverCache.getNode()\n    : null;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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  newEmptyPath,\n  Path,\n  pathChild,\n  pathGetFront,\n  pathIsEmpty,\n  pathPopFront\n} from './Path';\nimport { SortedMap } from './SortedMap';\nimport { each, stringCompare } from './util';\n\nlet emptyChildrenSingleton: SortedMap<string, ImmutableTree<null>>;\n\n/**\n * Singleton empty children collection.\n *\n */\nconst EmptyChildren = (): SortedMap<string, ImmutableTree<null>> => {\n  if (!emptyChildrenSingleton) {\n    emptyChildrenSingleton = new SortedMap<string, ImmutableTree<null>>(\n      stringCompare\n    );\n  }\n  return emptyChildrenSingleton;\n};\n\n/**\n * A tree with immutable elements.\n */\nexport class ImmutableTree<T> {\n  static fromObject<T>(obj: { [k: string]: T }): ImmutableTree<T> {\n    let tree: ImmutableTree<T> = new ImmutableTree<T>(null);\n    each(obj, (childPath: string, childSnap: T) => {\n      tree = tree.set(new Path(childPath), childSnap);\n    });\n    return tree;\n  }\n\n  constructor(\n    public readonly value: T | null,\n    public readonly children: SortedMap<\n      string,\n      ImmutableTree<T>\n    > = EmptyChildren()\n  ) {}\n\n  /**\n   * True if the value is empty and there are no children\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:}`\n   * objects on the way back out, it may be better to pass down a pathSoFar obj.\n   *\n   * @param relativePath - The remainder of the path\n   * @param predicate - The predicate to satisfy to return a node\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: newEmptyPath(), value: this.value };\n    } else {\n      if (pathIsEmpty(relativePath)) {\n        return null;\n      } else {\n        const front = pathGetFront(relativePath);\n        const child = this.children.get(front);\n        if (child !== null) {\n          const childExistingPathAndValue =\n            child.findRootMostMatchingPathAndValue(\n              pathPopFront(relativePath),\n              predicate\n            );\n          if (childExistingPathAndValue != null) {\n            const fullPath = pathChild(\n              new Path(front),\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   */\n  findRootMostValueAndPath(\n    relativePath: Path\n  ): { path: Path; value: T } | null {\n    return this.findRootMostMatchingPathAndValue(relativePath, () => true);\n  }\n\n  /**\n   * @returns The subtree at the given path\n   */\n  subtree(relativePath: Path): ImmutableTree<T> {\n    if (pathIsEmpty(relativePath)) {\n      return this;\n    } else {\n      const front = pathGetFront(relativePath);\n      const childTree = this.children.get(front);\n      if (childTree !== null) {\n        return childTree.subtree(pathPopFront(relativePath));\n      } else {\n        return new ImmutableTree<T>(null);\n      }\n    }\n  }\n\n  /**\n   * Sets a value at the specified path.\n   *\n   * @param relativePath - Path to set value at.\n   * @param toSet - Value to set.\n   * @returns Resulting tree.\n   */\n  set(relativePath: Path, toSet: T | null): ImmutableTree<T> {\n    if (pathIsEmpty(relativePath)) {\n      return new ImmutableTree(toSet, this.children);\n    } else {\n      const front = pathGetFront(relativePath);\n      const child = this.children.get(front) || new ImmutableTree<T>(null);\n      const newChild = child.set(pathPopFront(relativePath), 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 relativePath - Path to value to remove.\n   * @returns Resulting tree.\n   */\n  remove(relativePath: Path): ImmutableTree<T> {\n    if (pathIsEmpty(relativePath)) {\n      if (this.children.isEmpty()) {\n        return new ImmutableTree<T>(null);\n      } else {\n        return new ImmutableTree(null, this.children);\n      }\n    } else {\n      const front = pathGetFront(relativePath);\n      const child = this.children.get(front);\n      if (child) {\n        const newChild = child.remove(pathPopFront(relativePath));\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 new ImmutableTree<T>(null);\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 relativePath - Path to get value for.\n   * @returns Value at path, or null.\n   */\n  get(relativePath: Path): T | null {\n    if (pathIsEmpty(relativePath)) {\n      return this.value;\n    } else {\n      const front = pathGetFront(relativePath);\n      const child = this.children.get(front);\n      if (child) {\n        return child.get(pathPopFront(relativePath));\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 relativePath - Path to replace subtree for.\n   * @param newTree - New tree.\n   * @returns Resulting tree.\n   */\n  setTree(relativePath: Path, newTree: ImmutableTree<T>): ImmutableTree<T> {\n    if (pathIsEmpty(relativePath)) {\n      return newTree;\n    } else {\n      const front = pathGetFront(relativePath);\n      const child = this.children.get(front) || new ImmutableTree<T>(null);\n      const newChild = child.setTree(pathPopFront(relativePath), 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   */\n  fold<V>(fn: (path: Path, value: T, children: { [k: string]: V }) => V): V {\n    return this.fold_(newEmptyPath(), fn);\n  }\n\n  /**\n   * Recursive helper for public-facing fold() method\n   */\n  private fold_<V>(\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<T>) => {\n        accum[childKey] = childTree.fold_(pathChild(pathSoFar, 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   */\n  findOnPath<V>(path: Path, f: (path: Path, value: T) => V | null): V | null {\n    return this.findOnPath_(path, newEmptyPath(), f);\n  }\n\n  private findOnPath_<V>(\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 (pathIsEmpty(pathToFollow)) {\n        return null;\n      } else {\n        const front = pathGetFront(pathToFollow)!;\n        const nextChild = this.children.get(front);\n        if (nextChild) {\n          return nextChild.findOnPath_(\n            pathPopFront(pathToFollow),\n            pathChild(pathSoFar, front),\n            f\n          );\n        } else {\n          return null;\n        }\n      }\n    }\n  }\n\n  foreachOnPath(\n    path: Path,\n    f: (path: Path, value: T) => void\n  ): ImmutableTree<T> {\n    return this.foreachOnPath_(path, newEmptyPath(), f);\n  }\n\n  private foreachOnPath_(\n    pathToFollow: Path,\n    currentRelativePath: Path,\n    f: (path: Path, value: T) => void\n  ): ImmutableTree<T> {\n    if (pathIsEmpty(pathToFollow)) {\n      return this;\n    } else {\n      if (this.value) {\n        f(currentRelativePath, this.value);\n      }\n      const front = pathGetFront(pathToFollow);\n      const nextChild = this.children.get(front);\n      if (nextChild) {\n        return nextChild.foreachOnPath_(\n          pathPopFront(pathToFollow),\n          pathChild(currentRelativePath, front),\n          f\n        );\n      } else {\n        return new ImmutableTree<T>(null);\n      }\n    }\n  }\n\n  /**\n   * Calls the given function for each node in the tree that has a value.\n   *\n   * @param f - A function to be called with the path from the root of the tree to\n   * a node, and the value at that node. Called in depth-first order.\n   */\n  foreach(f: (path: Path, value: T) => void) {\n    this.foreach_(newEmptyPath(), 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_(pathChild(currentRelativePath, childName), f);\n    });\n    if (this.value) {\n      f(currentRelativePath, this.value);\n    }\n  }\n\n  foreachChild(f: (name: string, value: T) => void) {\n    this.children.inorderTraversal(\n      (childName: string, childTree: ImmutableTree<T>) => {\n        if (childTree.value) {\n          f(childName, childTree.value);\n        }\n      }\n    );\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { NamedNode, Node } from './snap/Node';\nimport { ImmutableTree } from './util/ImmutableTree';\nimport {\n  newEmptyPath,\n  newRelativePath,\n  Path,\n  pathChild,\n  pathIsEmpty\n} from './util/Path';\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(public writeTree_: ImmutableTree<Node>) {}\n\n  static empty(): CompoundWrite {\n    return new CompoundWrite(new ImmutableTree(null));\n  }\n}\n\nexport function compoundWriteAddWrite(\n  compoundWrite: CompoundWrite,\n  path: Path,\n  node: Node\n): CompoundWrite {\n  if (pathIsEmpty(path)) {\n    return new CompoundWrite(new ImmutableTree(node));\n  } else {\n    const rootmost = compoundWrite.writeTree_.findRootMostValueAndPath(path);\n    if (rootmost != null) {\n      const rootMostPath = rootmost.path;\n      let value = rootmost.value;\n      const relativePath = newRelativePath(rootMostPath, path);\n      value = value.updateChild(relativePath, node);\n      return new CompoundWrite(\n        compoundWrite.writeTree_.set(rootMostPath, value)\n      );\n    } else {\n      const subtree = new ImmutableTree(node);\n      const newWriteTree = compoundWrite.writeTree_.setTree(path, subtree);\n      return new CompoundWrite(newWriteTree);\n    }\n  }\n}\n\nexport function compoundWriteAddWrites(\n  compoundWrite: CompoundWrite,\n  path: Path,\n  updates: { [name: string]: Node }\n): CompoundWrite {\n  let newWrite = compoundWrite;\n  each(updates, (childKey: string, node: Node) => {\n    newWrite = compoundWriteAddWrite(newWrite, pathChild(path, childKey), node);\n  });\n  return newWrite;\n}\n\n/**\n * Will remove a write at the given path and deeper paths. This will <em>not</em> modify a write at a higher\n * location, which must be removed by calling this method with that path.\n *\n * @param compoundWrite - The CompoundWrite to remove.\n * @param path - The path at which a write and all deeper writes should be removed\n * @returns The new CompoundWrite with the removed path\n */\nexport function compoundWriteRemoveWrite(\n  compoundWrite: CompoundWrite,\n  path: Path\n): CompoundWrite {\n  if (pathIsEmpty(path)) {\n    return CompoundWrite.empty();\n  } else {\n    const newWriteTree = compoundWrite.writeTree_.setTree(\n      path,\n      new ImmutableTree<Node>(null)\n    );\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 compoundWrite - The CompoundWrite to check.\n * @param path - The path to check for\n * @returns Whether there is a complete write at that path\n */\nexport function compoundWriteHasCompleteWrite(\n  compoundWrite: CompoundWrite,\n  path: Path\n): boolean {\n  return compoundWriteGetCompleteNode(compoundWrite, 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 compoundWrite - The CompoundWrite to get the node from.\n * @param path - The path to get a complete write\n * @returns The node if complete at that path, or null otherwise.\n */\nexport function compoundWriteGetCompleteNode(\n  compoundWrite: CompoundWrite,\n  path: Path\n): Node | null {\n  const rootmost = compoundWrite.writeTree_.findRootMostValueAndPath(path);\n  if (rootmost != null) {\n    return compoundWrite.writeTree_\n      .get(rootmost.path)\n      .getChild(newRelativePath(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 * @param compoundWrite - The CompoundWrite to get children from.\n * @returns A list of all complete children.\n */\nexport function compoundWriteGetCompleteChildren(\n  compoundWrite: CompoundWrite\n): NamedNode[] {\n  const children: NamedNode[] = [];\n  const node = compoundWrite.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    compoundWrite.writeTree_.children.inorderTraversal(\n      (childName, childTree) => {\n        if (childTree.value != null) {\n          children.push(new NamedNode(childName, childTree.value));\n        }\n      }\n    );\n  }\n  return children;\n}\n\nexport function compoundWriteChildCompoundWrite(\n  compoundWrite: CompoundWrite,\n  path: Path\n): CompoundWrite {\n  if (pathIsEmpty(path)) {\n    return compoundWrite;\n  } else {\n    const shadowingNode = compoundWriteGetCompleteNode(compoundWrite, path);\n    if (shadowingNode != null) {\n      return new CompoundWrite(new ImmutableTree(shadowingNode));\n    } else {\n      return new CompoundWrite(compoundWrite.writeTree_.subtree(path));\n    }\n  }\n}\n\n/**\n * Returns true if this CompoundWrite is empty and therefore does not modify any nodes.\n * @returns Whether this CompoundWrite is empty\n */\nexport function compoundWriteIsEmpty(compoundWrite: CompoundWrite): boolean {\n  return compoundWrite.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 * @returns The node with all writes applied\n */\nexport function compoundWriteApply(\n  compoundWrite: CompoundWrite,\n  node: Node\n): Node {\n  return applySubtreeWrite(newEmptyPath(), compoundWrite.writeTree_, node);\n}\n\nfunction applySubtreeWrite(\n  relativePath: Path,\n  writeTree: ImmutableTree<Node>,\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(\n          pathChild(relativePath, childKey),\n          childTree,\n          node\n        );\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(\n        pathChild(relativePath, '.priority'),\n        priorityWrite\n      );\n    }\n    return node;\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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, assertionError, safeGet } from '@firebase/util';\n\nimport {\n  CompoundWrite,\n  compoundWriteAddWrite,\n  compoundWriteAddWrites,\n  compoundWriteApply,\n  compoundWriteChildCompoundWrite,\n  compoundWriteGetCompleteChildren,\n  compoundWriteGetCompleteNode,\n  compoundWriteHasCompleteWrite,\n  compoundWriteIsEmpty,\n  compoundWriteRemoveWrite\n} from './CompoundWrite';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Index } from './snap/indexes/Index';\nimport { PRIORITY_INDEX } from './snap/indexes/PriorityIndex';\nimport { NamedNode, Node } from './snap/Node';\nimport {\n  newEmptyPath,\n  newRelativePath,\n  Path,\n  pathChild,\n  pathContains,\n  pathGetFront,\n  pathIsEmpty,\n  pathPopFront\n} from './util/Path';\nimport { each } from './util/util';\nimport { CacheNode } from './view/CacheNode';\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 will 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 * Create a new WriteTreeRef for the given path. For use with a new sync point at the given path.\n *\n */\nexport function writeTreeChildWrites(\n  writeTree: WriteTree,\n  path: Path\n): WriteTreeRef {\n  return newWriteTreeRef(path, writeTree);\n}\n\n/**\n * Record a new overwrite from user code.\n *\n * @param visible - This is set to false by some transactions. It should be excluded from event caches\n */\nexport function writeTreeAddOverwrite(\n  writeTree: WriteTree,\n  path: Path,\n  snap: Node,\n  writeId: number,\n  visible?: boolean\n) {\n  assert(\n    writeId > writeTree.lastWriteId,\n    'Stacking an older write on top of newer ones'\n  );\n  if (visible === undefined) {\n    visible = true;\n  }\n  writeTree.allWrites.push({\n    path,\n    snap,\n    writeId,\n    visible\n  });\n\n  if (visible) {\n    writeTree.visibleWrites = compoundWriteAddWrite(\n      writeTree.visibleWrites,\n      path,\n      snap\n    );\n  }\n  writeTree.lastWriteId = writeId;\n}\n\n/**\n * Record a new merge from user code.\n */\nexport function writeTreeAddMerge(\n  writeTree: WriteTree,\n  path: Path,\n  changedChildren: { [k: string]: Node },\n  writeId: number\n) {\n  assert(\n    writeId > writeTree.lastWriteId,\n    'Stacking an older merge on top of newer ones'\n  );\n  writeTree.allWrites.push({\n    path,\n    children: changedChildren,\n    writeId,\n    visible: true\n  });\n\n  writeTree.visibleWrites = compoundWriteAddWrites(\n    writeTree.visibleWrites,\n    path,\n    changedChildren\n  );\n  writeTree.lastWriteId = writeId;\n}\n\nexport function writeTreeGetWrite(\n  writeTree: WriteTree,\n  writeId: number\n): WriteRecord | null {\n  for (let i = 0; i < writeTree.allWrites.length; i++) {\n    const record = writeTree.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 * @returns true if the write may have been visible (meaning we'll need to reevaluate / raise\n * events as a result).\n */\nexport function writeTreeRemoveWrite(\n  writeTree: WriteTree,\n  writeId: number\n): 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 = writeTree.allWrites.findIndex(s => {\n    return s.writeId === writeId;\n  });\n  assert(idx >= 0, 'removeWrite called with nonexistent writeId.');\n  const writeToRemove = writeTree.allWrites[idx];\n  writeTree.allWrites.splice(idx, 1);\n\n  let removedWriteWasVisible = writeToRemove.visible;\n  let removedWriteOverlapsWithOtherWrites = false;\n\n  let i = writeTree.allWrites.length - 1;\n\n  while (removedWriteWasVisible && i >= 0) {\n    const currentWrite = writeTree.allWrites[i];\n    if (currentWrite.visible) {\n      if (\n        i >= idx &&\n        writeTreeRecordContainsPath_(currentWrite, writeToRemove.path)\n      ) {\n        // The removed write was completely shadowed by a subsequent write.\n        removedWriteWasVisible = false;\n      } else if (pathContains(writeToRemove.path, 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    writeTreeResetTree_(writeTree);\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      writeTree.visibleWrites = compoundWriteRemoveWrite(\n        writeTree.visibleWrites,\n        writeToRemove.path\n      );\n    } else {\n      const children = writeToRemove.children;\n      each(children, (childName: string) => {\n        writeTree.visibleWrites = compoundWriteRemoveWrite(\n          writeTree.visibleWrites,\n          pathChild(writeToRemove.path, childName)\n        );\n      });\n    }\n    return true;\n  }\n}\n\nfunction writeTreeRecordContainsPath_(\n  writeRecord: WriteRecord,\n  path: Path\n): boolean {\n  if (writeRecord.snap) {\n    return pathContains(writeRecord.path, path);\n  } else {\n    for (const childName in writeRecord.children) {\n      if (\n        writeRecord.children.hasOwnProperty(childName) &&\n        pathContains(pathChild(writeRecord.path, childName), 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 */\nfunction writeTreeResetTree_(writeTree: WriteTree) {\n  writeTree.visibleWrites = writeTreeLayerTree_(\n    writeTree.allWrites,\n    writeTreeDefaultFilter_,\n    newEmptyPath()\n  );\n  if (writeTree.allWrites.length > 0) {\n    writeTree.lastWriteId =\n      writeTree.allWrites[writeTree.allWrites.length - 1].writeId;\n  } else {\n    writeTree.lastWriteId = -1;\n  }\n}\n\n/**\n * The default filter used when constructing the tree. Keep everything that's visible.\n */\nfunction writeTreeDefaultFilter_(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 */\nfunction writeTreeLayerTree_(\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: Path;\n      if (write.snap) {\n        if (pathContains(treeRoot, writePath)) {\n          relativePath = newRelativePath(treeRoot, writePath);\n          compoundWrite = compoundWriteAddWrite(\n            compoundWrite,\n            relativePath,\n            write.snap\n          );\n        } else if (pathContains(writePath, treeRoot)) {\n          relativePath = newRelativePath(writePath, treeRoot);\n          compoundWrite = compoundWriteAddWrite(\n            compoundWrite,\n            newEmptyPath(),\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 (pathContains(treeRoot, writePath)) {\n          relativePath = newRelativePath(treeRoot, writePath);\n          compoundWrite = compoundWriteAddWrites(\n            compoundWrite,\n            relativePath,\n            write.children\n          );\n        } else if (pathContains(writePath, treeRoot)) {\n          relativePath = newRelativePath(writePath, treeRoot);\n          if (pathIsEmpty(relativePath)) {\n            compoundWrite = compoundWriteAddWrites(\n              compoundWrite,\n              newEmptyPath(),\n              write.children\n            );\n          } else {\n            const child = safeGet(write.children, pathGetFront(relativePath));\n            if (child) {\n              // There exists a child in this node that matches the root path\n              const deepNode = child.getChild(pathPopFront(relativePath));\n              compoundWrite = compoundWriteAddWrite(\n                compoundWrite,\n                newEmptyPath(),\n                deepNode\n              );\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 * 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 */\nexport function writeTreeGetCompleteWriteData(\n  writeTree: WriteTree,\n  path: Path\n): Node | null {\n  return compoundWriteGetCompleteNode(writeTree.visibleWrites, 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 writeIdsToExclude - An optional set to be excluded\n * @param includeHiddenWrites - Defaults to false, whether or not to layer on writes with visible set to false\n */\nexport function writeTreeCalcCompleteEventCache(\n  writeTree: WriteTree,\n  treePath: Path,\n  completeServerCache: Node | null,\n  writeIdsToExclude?: number[],\n  includeHiddenWrites?: boolean\n): Node | null {\n  if (!writeIdsToExclude && !includeHiddenWrites) {\n    const shadowingNode = compoundWriteGetCompleteNode(\n      writeTree.visibleWrites,\n      treePath\n    );\n    if (shadowingNode != null) {\n      return shadowingNode;\n    } else {\n      const subMerge = compoundWriteChildCompoundWrite(\n        writeTree.visibleWrites,\n        treePath\n      );\n      if (compoundWriteIsEmpty(subMerge)) {\n        return completeServerCache;\n      } else if (\n        completeServerCache == null &&\n        !compoundWriteHasCompleteWrite(subMerge, newEmptyPath())\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 compoundWriteApply(subMerge, layeredCache);\n      }\n    }\n  } else {\n    const merge = compoundWriteChildCompoundWrite(\n      writeTree.visibleWrites,\n      treePath\n    );\n    if (!includeHiddenWrites && compoundWriteIsEmpty(merge)) {\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        !compoundWriteHasCompleteWrite(merge, newEmptyPath())\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            (pathContains(write.path, treePath) ||\n              pathContains(treePath, write.path))\n          );\n        };\n        const mergeAtPath = writeTreeLayerTree_(\n          writeTree.allWrites,\n          filter,\n          treePath\n        );\n        const layeredCache = completeServerCache || ChildrenNode.EMPTY_NODE;\n        return compoundWriteApply(mergeAtPath, 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 */\nexport function writeTreeCalcCompleteEventChildren(\n  writeTree: WriteTree,\n  treePath: Path,\n  completeServerChildren: ChildrenNode | null\n) {\n  let completeChildren = ChildrenNode.EMPTY_NODE as Node;\n  const topLevelSet = compoundWriteGetCompleteNode(\n    writeTree.visibleWrites,\n    treePath\n  );\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 = compoundWriteChildCompoundWrite(\n      writeTree.visibleWrites,\n      treePath\n    );\n    completeServerChildren.forEachChild(\n      PRIORITY_INDEX,\n      (childName, childNode) => {\n        const node = compoundWriteApply(\n          compoundWriteChildCompoundWrite(merge, new Path(childName)),\n          childNode\n        );\n        completeChildren = completeChildren.updateImmediateChild(\n          childName,\n          node\n        );\n      }\n    );\n    // Add any complete children we have from the set\n    compoundWriteGetCompleteChildren(merge).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 = compoundWriteChildCompoundWrite(\n      writeTree.visibleWrites,\n      treePath\n    );\n    compoundWriteGetCompleteChildren(merge).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 */\nexport function writeTreeCalcEventCacheAfterServerOverwrite(\n  writeTree: WriteTree,\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 = pathChild(treePath, childPath);\n  if (compoundWriteHasCompleteWrite(writeTree.visibleWrites, 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 = compoundWriteChildCompoundWrite(\n      writeTree.visibleWrites,\n      path\n    );\n    if (compoundWriteIsEmpty(childMerge)) {\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 compoundWriteApply(\n        childMerge,\n        existingServerSnap.getChild(childPath)\n      );\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 */\nexport function writeTreeCalcCompleteChild(\n  writeTree: WriteTree,\n  treePath: Path,\n  childKey: string,\n  existingServerSnap: CacheNode\n): Node | null {\n  const path = pathChild(treePath, childKey);\n  const shadowingNode = compoundWriteGetCompleteNode(\n    writeTree.visibleWrites,\n    path\n  );\n  if (shadowingNode != null) {\n    return shadowingNode;\n  } else {\n    if (existingServerSnap.isCompleteForChild(childKey)) {\n      const childMerge = compoundWriteChildCompoundWrite(\n        writeTree.visibleWrites,\n        path\n      );\n      return compoundWriteApply(\n        childMerge,\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 */\nexport function writeTreeShadowingWrite(\n  writeTree: WriteTree,\n  path: Path\n): Node | null {\n  return compoundWriteGetCompleteNode(writeTree.visibleWrites, 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 */\nexport function writeTreeCalcIndexedSlice(\n  writeTree: WriteTree,\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 = compoundWriteChildCompoundWrite(\n    writeTree.visibleWrites,\n    treePath\n  );\n  const shadowingNode = compoundWriteGetCompleteNode(merge, newEmptyPath());\n  if (shadowingNode != null) {\n    toIterate = shadowingNode;\n  } else if (completeServerData != null) {\n    toIterate = compoundWriteApply(merge, 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\nexport function newWriteTree(): WriteTree {\n  return {\n    visibleWrites: CompoundWrite.empty(),\n    allWrites: [],\n    lastWriteId: -1\n  };\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 */\nexport interface 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  visibleWrites: CompoundWrite;\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  allWrites: WriteRecord[];\n\n  lastWriteId: number;\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 writeIdsToExclude - Optional writes to exclude.\n * @param includeHiddenWrites - Defaults to false, whether or not to layer on writes with visible set to false\n */\nexport function writeTreeRefCalcCompleteEventCache(\n  writeTreeRef: WriteTreeRef,\n  completeServerCache: Node | null,\n  writeIdsToExclude?: number[],\n  includeHiddenWrites?: boolean\n): Node | null {\n  return writeTreeCalcCompleteEventCache(\n    writeTreeRef.writeTree,\n    writeTreeRef.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 */\nexport function writeTreeRefCalcCompleteEventChildren(\n  writeTreeRef: WriteTreeRef,\n  completeServerChildren: ChildrenNode | null\n): ChildrenNode {\n  return writeTreeCalcCompleteEventChildren(\n    writeTreeRef.writeTree,\n    writeTreeRef.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 *\n */\nexport function writeTreeRefCalcEventCacheAfterServerOverwrite(\n  writeTreeRef: WriteTreeRef,\n  path: Path,\n  existingEventSnap: Node | null,\n  existingServerSnap: Node | null\n): Node | null {\n  return writeTreeCalcEventCacheAfterServerOverwrite(\n    writeTreeRef.writeTree,\n    writeTreeRef.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 */\nexport function writeTreeRefShadowingWrite(\n  writeTreeRef: WriteTreeRef,\n  path: Path\n): Node | null {\n  return writeTreeShadowingWrite(\n    writeTreeRef.writeTree,\n    pathChild(writeTreeRef.treePath, path)\n  );\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 */\nexport function writeTreeRefCalcIndexedSlice(\n  writeTreeRef: WriteTreeRef,\n  completeServerData: Node | null,\n  startPost: NamedNode,\n  count: number,\n  reverse: boolean,\n  index: Index\n): NamedNode[] {\n  return writeTreeCalcIndexedSlice(\n    writeTreeRef.writeTree,\n    writeTreeRef.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 */\nexport function writeTreeRefCalcCompleteChild(\n  writeTreeRef: WriteTreeRef,\n  childKey: string,\n  existingServerCache: CacheNode\n): Node | null {\n  return writeTreeCalcCompleteChild(\n    writeTreeRef.writeTree,\n    writeTreeRef.treePath,\n    childKey,\n    existingServerCache\n  );\n}\n\n/**\n * Return a WriteTreeRef for a child.\n */\nexport function writeTreeRefChild(\n  writeTreeRef: WriteTreeRef,\n  childName: string\n): WriteTreeRef {\n  return newWriteTreeRef(\n    pathChild(writeTreeRef.treePath, childName),\n    writeTreeRef.writeTree\n  );\n}\n\nexport function newWriteTreeRef(\n  path: Path,\n  writeTree: WriteTree\n): WriteTreeRef {\n  return {\n    treePath: path,\n    writeTree\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 */\nexport interface 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  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  readonly writeTree: WriteTree;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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, assertionError } from '@firebase/util';\n\nimport {\n  Change,\n  ChangeType,\n  changeChildAdded,\n  changeChildChanged,\n  changeChildRemoved\n} from './Change';\n\nexport class ChildChangeAccumulator {\n  private readonly changeMap: Map<string, Change> = new Map();\n\n  trackChildChange(change: Change) {\n    const type = change.type;\n    const childKey = change.childName!;\n    assert(\n      type === ChangeType.CHILD_ADDED ||\n        type === ChangeType.CHILD_CHANGED ||\n        type === ChangeType.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 (\n        type === ChangeType.CHILD_ADDED &&\n        oldType === ChangeType.CHILD_REMOVED\n      ) {\n        this.changeMap.set(\n          childKey,\n          changeChildChanged(\n            childKey,\n            change.snapshotNode,\n            oldChange.snapshotNode\n          )\n        );\n      } else if (\n        type === ChangeType.CHILD_REMOVED &&\n        oldType === ChangeType.CHILD_ADDED\n      ) {\n        this.changeMap.delete(childKey);\n      } else if (\n        type === ChangeType.CHILD_REMOVED &&\n        oldType === ChangeType.CHILD_CHANGED\n      ) {\n        this.changeMap.set(\n          childKey,\n          changeChildRemoved(childKey, oldChange.oldSnap)\n        );\n      } else if (\n        type === ChangeType.CHILD_CHANGED &&\n        oldType === ChangeType.CHILD_ADDED\n      ) {\n        this.changeMap.set(\n          childKey,\n          changeChildAdded(childKey, change.snapshotNode)\n        );\n      } else if (\n        type === ChangeType.CHILD_CHANGED &&\n        oldType === ChangeType.CHILD_CHANGED\n      ) {\n        this.changeMap.set(\n          childKey,\n          changeChildChanged(childKey, change.snapshotNode, oldChange.oldSnap)\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 LLC\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 '../snap/indexes/Index';\nimport { NamedNode, Node } from '../snap/Node';\nimport {\n  WriteTreeRef,\n  writeTreeRefCalcCompleteChild,\n  writeTreeRefCalcIndexedSlice\n} from '../WriteTree';\n\nimport { CacheNode } from './CacheNode';\nimport { ViewCache, viewCacheGetCompleteServerSnap } 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  getCompleteChild(childKey: string): Node | null;\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// eslint-disable-next-line @typescript-eslint/naming-convention\nexport class NoCompleteChildSource_ implements CompleteChildSource {\n  getCompleteChild(childKey?: string): Node | null {\n    return null;\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 */\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 */\nexport class WriteTreeCompleteChildSource implements CompleteChildSource {\n  constructor(\n    private writes_: WriteTreeRef,\n    private viewCache_: ViewCache,\n    private optCompleteServerCache_: Node | null = null\n  ) {}\n  getCompleteChild(childKey: string): Node | null {\n    const node = this.viewCache_.eventCache;\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_.serverCache;\n      return writeTreeRefCalcCompleteChild(this.writes_, childKey, serverNode);\n    }\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        : viewCacheGetCompleteServerSnap(this.viewCache_);\n    const nodes = writeTreeRefCalcIndexedSlice(\n      this.writes_,\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 LLC\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, assertionError } from '@firebase/util';\n\nimport { AckUserWrite } from '../operation/AckUserWrite';\nimport { Merge } from '../operation/Merge';\nimport { Operation, OperationType } from '../operation/Operation';\nimport { Overwrite } from '../operation/Overwrite';\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { KEY_INDEX } from '../snap/indexes/KeyIndex';\nimport { Node } from '../snap/Node';\nimport { ImmutableTree } from '../util/ImmutableTree';\nimport {\n  newEmptyPath,\n  Path,\n  pathChild,\n  pathGetBack,\n  pathGetFront,\n  pathGetLength,\n  pathIsEmpty,\n  pathParent,\n  pathPopFront\n} from '../util/Path';\nimport {\n  WriteTreeRef,\n  writeTreeRefCalcCompleteChild,\n  writeTreeRefCalcCompleteEventCache,\n  writeTreeRefCalcCompleteEventChildren,\n  writeTreeRefCalcEventCacheAfterServerOverwrite,\n  writeTreeRefShadowingWrite\n} from '../WriteTree';\n\nimport { Change, changeValue } from './Change';\nimport { ChildChangeAccumulator } from './ChildChangeAccumulator';\nimport {\n  CompleteChildSource,\n  NO_COMPLETE_CHILD_SOURCE,\n  WriteTreeCompleteChildSource\n} from './CompleteChildSource';\nimport { NodeFilter } from './filter/NodeFilter';\nimport {\n  ViewCache,\n  viewCacheGetCompleteEventSnap,\n  viewCacheGetCompleteServerSnap,\n  viewCacheUpdateEventSnap,\n  viewCacheUpdateServerSnap\n} from './ViewCache';\n\nexport interface ProcessorResult {\n  readonly viewCache: ViewCache;\n  readonly changes: Change[];\n}\n\nexport interface ViewProcessor {\n  readonly filter: NodeFilter;\n}\n\nexport function newViewProcessor(filter: NodeFilter): ViewProcessor {\n  return { filter };\n}\n\nexport function viewProcessorAssertIndexed(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache\n): void {\n  assert(\n    viewCache.eventCache.getNode().isIndexed(viewProcessor.filter.getIndex()),\n    'Event snap not indexed'\n  );\n  assert(\n    viewCache.serverCache.getNode().isIndexed(viewProcessor.filter.getIndex()),\n    'Server snap not indexed'\n  );\n}\n\nexport function viewProcessorApplyOperation(\n  viewProcessor: ViewProcessor,\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 = viewProcessorApplyUserOverwrite(\n        viewProcessor,\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.serverCache.isFiltered() && !pathIsEmpty(overwrite.path));\n      newViewCache = viewProcessorApplyServerOverwrite(\n        viewProcessor,\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 = viewProcessorApplyUserMerge(\n        viewProcessor,\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.serverCache.isFiltered();\n      newViewCache = viewProcessorApplyServerMerge(\n        viewProcessor,\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 = viewProcessorAckUserWrite(\n        viewProcessor,\n        oldViewCache,\n        ackUserWrite.path,\n        ackUserWrite.affectedTree,\n        writesCache,\n        completeCache,\n        accumulator\n      );\n    } else {\n      newViewCache = viewProcessorRevertUserWrite(\n        viewProcessor,\n        oldViewCache,\n        ackUserWrite.path,\n        writesCache,\n        completeCache,\n        accumulator\n      );\n    }\n  } else if (operation.type === OperationType.LISTEN_COMPLETE) {\n    newViewCache = viewProcessorListenComplete(\n      viewProcessor,\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  viewProcessorMaybeAddValueEvent(oldViewCache, newViewCache, changes);\n  return { viewCache: newViewCache, changes };\n}\n\nfunction viewProcessorMaybeAddValueEvent(\n  oldViewCache: ViewCache,\n  newViewCache: ViewCache,\n  accumulator: Change[]\n): void {\n  const eventSnap = newViewCache.eventCache;\n  if (eventSnap.isFullyInitialized()) {\n    const isLeafOrEmpty =\n      eventSnap.getNode().isLeafNode() || eventSnap.getNode().isEmpty();\n    const oldCompleteSnap = viewCacheGetCompleteEventSnap(oldViewCache);\n    if (\n      accumulator.length > 0 ||\n      !oldViewCache.eventCache.isFullyInitialized() ||\n      (isLeafOrEmpty && !eventSnap.getNode().equals(oldCompleteSnap)) ||\n      !eventSnap.getNode().getPriority().equals(oldCompleteSnap.getPriority())\n    ) {\n      accumulator.push(\n        changeValue(viewCacheGetCompleteEventSnap(newViewCache))\n      );\n    }\n  }\n}\n\nfunction viewProcessorGenerateEventCacheAfterServerEvent(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  changePath: Path,\n  writesCache: WriteTreeRef,\n  source: CompleteChildSource,\n  accumulator: ChildChangeAccumulator\n): ViewCache {\n  const oldEventSnap = viewCache.eventCache;\n  if (writeTreeRefShadowingWrite(writesCache, changePath) != null) {\n    // we have a shadowing write, ignore changes\n    return viewCache;\n  } else {\n    let newEventCache, serverNode;\n    if (pathIsEmpty(changePath)) {\n      // TODO: figure out how this plays with \"sliding ack windows\"\n      assert(\n        viewCache.serverCache.isFullyInitialized(),\n        'If change path is empty, we must have complete server data'\n      );\n      if (viewCache.serverCache.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 = viewCacheGetCompleteServerSnap(viewCache);\n        const completeChildren =\n          serverCache instanceof ChildrenNode\n            ? serverCache\n            : ChildrenNode.EMPTY_NODE;\n        const completeEventChildren = writeTreeRefCalcCompleteEventChildren(\n          writesCache,\n          completeChildren\n        );\n        newEventCache = viewProcessor.filter.updateFullNode(\n          viewCache.eventCache.getNode(),\n          completeEventChildren,\n          accumulator\n        );\n      } else {\n        const completeNode = writeTreeRefCalcCompleteEventCache(\n          writesCache,\n          viewCacheGetCompleteServerSnap(viewCache)\n        );\n        newEventCache = viewProcessor.filter.updateFullNode(\n          viewCache.eventCache.getNode(),\n          completeNode,\n          accumulator\n        );\n      }\n    } else {\n      const childKey = pathGetFront(changePath);\n      if (childKey === '.priority') {\n        assert(\n          pathGetLength(changePath) === 1,\n          \"Can't have a priority with additional path components\"\n        );\n        const oldEventNode = oldEventSnap.getNode();\n        serverNode = viewCache.serverCache.getNode();\n        // we might have overwrites for this priority\n        const updatedPriority = writeTreeRefCalcEventCacheAfterServerOverwrite(\n          writesCache,\n          changePath,\n          oldEventNode,\n          serverNode\n        );\n        if (updatedPriority != null) {\n          newEventCache = viewProcessor.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 = pathPopFront(changePath);\n        // update child\n        let newEventChild;\n        if (oldEventSnap.isCompleteForChild(childKey)) {\n          serverNode = viewCache.serverCache.getNode();\n          const eventChildUpdate =\n            writeTreeRefCalcEventCacheAfterServerOverwrite(\n              writesCache,\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.getNode().getImmediateChild(childKey);\n          }\n        } else {\n          newEventChild = writeTreeRefCalcCompleteChild(\n            writesCache,\n            childKey,\n            viewCache.serverCache\n          );\n        }\n        if (newEventChild != null) {\n          newEventCache = viewProcessor.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 viewCacheUpdateEventSnap(\n      viewCache,\n      newEventCache,\n      oldEventSnap.isFullyInitialized() || pathIsEmpty(changePath),\n      viewProcessor.filter.filtersNodes()\n    );\n  }\n}\n\nfunction viewProcessorApplyServerOverwrite(\n  viewProcessor: ViewProcessor,\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.serverCache;\n  let newServerCache;\n  const serverFilter = filterServerNode\n    ? viewProcessor.filter\n    : viewProcessor.filter.getIndexedFilter();\n  if (pathIsEmpty(changePath)) {\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 = pathGetFront(changePath);\n    if (\n      !oldServerSnap.isCompleteForPath(changePath) &&\n      pathGetLength(changePath) > 1\n    ) {\n      // We don't update incomplete nodes with updates intended for other listeners\n      return oldViewCache;\n    }\n    const childChangePath = pathPopFront(changePath);\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 = viewCacheUpdateServerSnap(\n    oldViewCache,\n    newServerCache,\n    oldServerSnap.isFullyInitialized() || pathIsEmpty(changePath),\n    serverFilter.filtersNodes()\n  );\n  const source = new WriteTreeCompleteChildSource(\n    writesCache,\n    newViewCache,\n    completeCache\n  );\n  return viewProcessorGenerateEventCacheAfterServerEvent(\n    viewProcessor,\n    newViewCache,\n    changePath,\n    writesCache,\n    source,\n    accumulator\n  );\n}\n\nfunction viewProcessorApplyUserOverwrite(\n  viewProcessor: ViewProcessor,\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.eventCache;\n  let newViewCache, newEventCache;\n  const source = new WriteTreeCompleteChildSource(\n    writesCache,\n    oldViewCache,\n    completeCache\n  );\n  if (pathIsEmpty(changePath)) {\n    newEventCache = viewProcessor.filter.updateFullNode(\n      oldViewCache.eventCache.getNode(),\n      changedSnap,\n      accumulator\n    );\n    newViewCache = viewCacheUpdateEventSnap(\n      oldViewCache,\n      newEventCache,\n      true,\n      viewProcessor.filter.filtersNodes()\n    );\n  } else {\n    const childKey = pathGetFront(changePath);\n    if (childKey === '.priority') {\n      newEventCache = viewProcessor.filter.updatePriority(\n        oldViewCache.eventCache.getNode(),\n        changedSnap\n      );\n      newViewCache = viewCacheUpdateEventSnap(\n        oldViewCache,\n        newEventCache,\n        oldEventSnap.isFullyInitialized(),\n        oldEventSnap.isFiltered()\n      );\n    } else {\n      const childChangePath = pathPopFront(changePath);\n      const oldChild = oldEventSnap.getNode().getImmediateChild(childKey);\n      let newChild;\n      if (pathIsEmpty(childChangePath)) {\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            pathGetBack(childChangePath) === '.priority' &&\n            childNode.getChild(pathParent(childChangePath)).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 = viewProcessor.filter.updateChild(\n          oldEventSnap.getNode(),\n          childKey,\n          newChild,\n          childChangePath,\n          source,\n          accumulator\n        );\n        newViewCache = viewCacheUpdateEventSnap(\n          oldViewCache,\n          newEventSnap,\n          oldEventSnap.isFullyInitialized(),\n          viewProcessor.filter.filtersNodes()\n        );\n      } else {\n        newViewCache = oldViewCache;\n      }\n    }\n  }\n  return newViewCache;\n}\n\nfunction viewProcessorCacheHasChild(\n  viewCache: ViewCache,\n  childKey: string\n): boolean {\n  return viewCache.eventCache.isCompleteForChild(childKey);\n}\n\nfunction viewProcessorApplyUserMerge(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  path: Path,\n  changedChildren: ImmutableTree<Node>,\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 = pathChild(path, relativePath);\n    if (viewProcessorCacheHasChild(viewCache, pathGetFront(writePath))) {\n      curViewCache = viewProcessorApplyUserOverwrite(\n        viewProcessor,\n        curViewCache,\n        writePath,\n        childNode,\n        writesCache,\n        serverCache,\n        accumulator\n      );\n    }\n  });\n\n  changedChildren.foreach((relativePath, childNode) => {\n    const writePath = pathChild(path, relativePath);\n    if (!viewProcessorCacheHasChild(viewCache, pathGetFront(writePath))) {\n      curViewCache = viewProcessorApplyUserOverwrite(\n        viewProcessor,\n        curViewCache,\n        writePath,\n        childNode,\n        writesCache,\n        serverCache,\n        accumulator\n      );\n    }\n  });\n\n  return curViewCache;\n}\n\nfunction viewProcessorApplyMerge(\n  viewProcessor: ViewProcessor,\n  node: Node,\n  merge: ImmutableTree<Node>\n): Node {\n  merge.foreach((relativePath, childNode) => {\n    node = node.updateChild(relativePath, childNode);\n  });\n  return node;\n}\n\nfunction viewProcessorApplyServerMerge(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  path: Path,\n  changedChildren: ImmutableTree<Node>,\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.serverCache.getNode().isEmpty() &&\n    !viewCache.serverCache.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: ImmutableTree<Node>;\n  if (pathIsEmpty(path)) {\n    viewMergeTree = changedChildren;\n  } else {\n    viewMergeTree = new ImmutableTree<Node>(null).setTree(\n      path,\n      changedChildren\n    );\n  }\n  const serverNode = viewCache.serverCache.getNode();\n  viewMergeTree.children.inorderTraversal((childKey, childTree) => {\n    if (serverNode.hasChild(childKey)) {\n      const serverChild = viewCache.serverCache\n        .getNode()\n        .getImmediateChild(childKey);\n      const newChild = viewProcessorApplyMerge(\n        viewProcessor,\n        serverChild,\n        childTree\n      );\n      curViewCache = viewProcessorApplyServerOverwrite(\n        viewProcessor,\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.serverCache.isCompleteForChild(childKey) &&\n      childMergeTree.value === null;\n    if (!serverNode.hasChild(childKey) && !isUnknownDeepMerge) {\n      const serverChild = viewCache.serverCache\n        .getNode()\n        .getImmediateChild(childKey);\n      const newChild = viewProcessorApplyMerge(\n        viewProcessor,\n        serverChild,\n        childMergeTree\n      );\n      curViewCache = viewProcessorApplyServerOverwrite(\n        viewProcessor,\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\nfunction viewProcessorAckUserWrite(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  ackPath: Path,\n  affectedTree: ImmutableTree<boolean>,\n  writesCache: WriteTreeRef,\n  completeCache: Node | null,\n  accumulator: ChildChangeAccumulator\n): ViewCache {\n  if (writeTreeRefShadowingWrite(writesCache, ackPath) != null) {\n    return viewCache;\n  }\n\n  // Only filter server node if it is currently filtered\n  const filterServerNode = viewCache.serverCache.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.serverCache;\n  if (affectedTree.value != null) {\n    // This is an overwrite.\n    if (\n      (pathIsEmpty(ackPath) && serverCache.isFullyInitialized()) ||\n      serverCache.isCompleteForPath(ackPath)\n    ) {\n      return viewProcessorApplyServerOverwrite(\n        viewProcessor,\n        viewCache,\n        ackPath,\n        serverCache.getNode().getChild(ackPath),\n        writesCache,\n        completeCache,\n        filterServerNode,\n        accumulator\n      );\n    } else if (pathIsEmpty(ackPath)) {\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 = new ImmutableTree<Node>(null);\n      serverCache.getNode().forEachChild(KEY_INDEX, (name, node) => {\n        changedChildren = changedChildren.set(new Path(name), node);\n      });\n      return viewProcessorApplyServerMerge(\n        viewProcessor,\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 = new ImmutableTree<Node>(null);\n    affectedTree.foreach((mergePath, value) => {\n      const serverCachePath = pathChild(ackPath, mergePath);\n      if (serverCache.isCompleteForPath(serverCachePath)) {\n        changedChildren = changedChildren.set(\n          mergePath,\n          serverCache.getNode().getChild(serverCachePath)\n        );\n      }\n    });\n    return viewProcessorApplyServerMerge(\n      viewProcessor,\n      viewCache,\n      ackPath,\n      changedChildren,\n      writesCache,\n      completeCache,\n      filterServerNode,\n      accumulator\n    );\n  }\n}\n\nfunction viewProcessorListenComplete(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  path: Path,\n  writesCache: WriteTreeRef,\n  accumulator: ChildChangeAccumulator\n): ViewCache {\n  const oldServerNode = viewCache.serverCache;\n  const newViewCache = viewCacheUpdateServerSnap(\n    viewCache,\n    oldServerNode.getNode(),\n    oldServerNode.isFullyInitialized() || pathIsEmpty(path),\n    oldServerNode.isFiltered()\n  );\n  return viewProcessorGenerateEventCacheAfterServerEvent(\n    viewProcessor,\n    newViewCache,\n    path,\n    writesCache,\n    NO_COMPLETE_CHILD_SOURCE,\n    accumulator\n  );\n}\n\nfunction viewProcessorRevertUserWrite(\n  viewProcessor: ViewProcessor,\n  viewCache: ViewCache,\n  path: Path,\n  writesCache: WriteTreeRef,\n  completeServerCache: Node | null,\n  accumulator: ChildChangeAccumulator\n): ViewCache {\n  let complete;\n  if (writeTreeRefShadowingWrite(writesCache, path) != null) {\n    return viewCache;\n  } else {\n    const source = new WriteTreeCompleteChildSource(\n      writesCache,\n      viewCache,\n      completeServerCache\n    );\n    const oldEventCache = viewCache.eventCache.getNode();\n    let newEventCache;\n    if (pathIsEmpty(path) || pathGetFront(path) === '.priority') {\n      let newNode;\n      if (viewCache.serverCache.isFullyInitialized()) {\n        newNode = writeTreeRefCalcCompleteEventCache(\n          writesCache,\n          viewCacheGetCompleteServerSnap(viewCache)\n        );\n      } else {\n        const serverChildren = viewCache.serverCache.getNode();\n        assert(\n          serverChildren instanceof ChildrenNode,\n          'serverChildren would be complete if leaf node'\n        );\n        newNode = writeTreeRefCalcCompleteEventChildren(\n          writesCache,\n          serverChildren as ChildrenNode\n        );\n      }\n      newNode = newNode as Node;\n      newEventCache = viewProcessor.filter.updateFullNode(\n        oldEventCache,\n        newNode,\n        accumulator\n      );\n    } else {\n      const childKey = pathGetFront(path);\n      let newChild = writeTreeRefCalcCompleteChild(\n        writesCache,\n        childKey,\n        viewCache.serverCache\n      );\n      if (\n        newChild == null &&\n        viewCache.serverCache.isCompleteForChild(childKey)\n      ) {\n        newChild = oldEventCache.getImmediateChild(childKey);\n      }\n      if (newChild != null) {\n        newEventCache = viewProcessor.filter.updateChild(\n          oldEventCache,\n          childKey,\n          newChild,\n          pathPopFront(path),\n          source,\n          accumulator\n        );\n      } else if (viewCache.eventCache.getNode().hasChild(childKey)) {\n        // No complete child available, delete the existing one, if any\n        newEventCache = viewProcessor.filter.updateChild(\n          oldEventCache,\n          childKey,\n          ChildrenNode.EMPTY_NODE,\n          pathPopFront(path),\n          source,\n          accumulator\n        );\n      } else {\n        newEventCache = oldEventCache;\n      }\n      if (\n        newEventCache.isEmpty() &&\n        viewCache.serverCache.isFullyInitialized()\n      ) {\n        // We might have reverted all child writes. Maybe the old event was a leaf node\n        complete = writeTreeRefCalcCompleteEventCache(\n          writesCache,\n          viewCacheGetCompleteServerSnap(viewCache)\n        );\n        if (complete.isLeafNode()) {\n          newEventCache = viewProcessor.filter.updateFullNode(\n            newEventCache,\n            complete,\n            accumulator\n          );\n        }\n      }\n    }\n    complete =\n      viewCache.serverCache.isFullyInitialized() ||\n      writeTreeRefShadowingWrite(writesCache, newEmptyPath()) != null;\n    return viewCacheUpdateEventSnap(\n      viewCache,\n      newEventCache,\n      complete,\n      viewProcessor.filter.filtersNodes()\n    );\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { Operation, OperationType } from '../operation/Operation';\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';\nimport { Node } from '../snap/Node';\nimport { Path, pathGetFront, pathIsEmpty } from '../util/Path';\nimport { WriteTreeRef } from '../WriteTree';\n\nimport { CacheNode } from './CacheNode';\nimport { Change, changeChildAdded, changeValue } from './Change';\nimport { CancelEvent, Event } from './Event';\nimport {\n  EventGenerator,\n  eventGeneratorGenerateEventsForChanges\n} from './EventGenerator';\nimport { EventRegistration, QueryContext } from './EventRegistration';\nimport { IndexedFilter } from './filter/IndexedFilter';\nimport { queryParamsGetNodeFilter } from './QueryParams';\nimport {\n  newViewCache,\n  ViewCache,\n  viewCacheGetCompleteEventSnap,\n  viewCacheGetCompleteServerSnap\n} from './ViewCache';\nimport {\n  newViewProcessor,\n  ViewProcessor,\n  viewProcessorApplyOperation,\n  viewProcessorAssertIndexed\n} from './ViewProcessor';\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 */\nexport class View {\n  processor_: ViewProcessor;\n  viewCache_: ViewCache;\n  eventRegistrations_: EventRegistration[] = [];\n  eventGenerator_: EventGenerator;\n\n  constructor(private query_: QueryContext, initialViewCache: ViewCache) {\n    const params = this.query_._queryParams;\n\n    const indexFilter = new IndexedFilter(params.getIndex());\n    const filter = queryParamsGetNodeFilter(params);\n\n    this.processor_ = newViewProcessor(filter);\n\n    const initialServerCache = initialViewCache.serverCache;\n    const initialEventCache = initialViewCache.eventCache;\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    this.viewCache_ = newViewCache(newEventCache, newServerCache);\n    this.eventGenerator_ = new EventGenerator(this.query_);\n  }\n\n  get query(): QueryContext {\n    return this.query_;\n  }\n}\n\nexport function viewGetServerCache(view: View): Node | null {\n  return view.viewCache_.serverCache.getNode();\n}\n\nexport function viewGetCompleteNode(view: View): Node | null {\n  return viewCacheGetCompleteEventSnap(view.viewCache_);\n}\n\nexport function viewGetCompleteServerCache(\n  view: View,\n  path: Path\n): Node | null {\n  const cache = viewCacheGetCompleteServerSnap(view.viewCache_);\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      view.query._queryParams.loadsAllData() ||\n      (!pathIsEmpty(path) &&\n        !cache.getImmediateChild(pathGetFront(path)).isEmpty())\n    ) {\n      return cache.getChild(path);\n    }\n  }\n  return null;\n}\n\nexport function viewIsEmpty(view: View): boolean {\n  return view.eventRegistrations_.length === 0;\n}\n\nexport function viewAddEventRegistration(\n  view: View,\n  eventRegistration: EventRegistration\n) {\n  view.eventRegistrations_.push(eventRegistration);\n}\n\n/**\n * @param eventRegistration - If null, remove all callbacks.\n * @param cancelError - If a cancelError is provided, appropriate cancel events will be returned.\n * @returns Cancel events, if cancelError was provided.\n */\nexport function viewRemoveEventRegistration(\n  view: View,\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 = view.query._path;\n    view.eventRegistrations_.forEach(registration => {\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 < view.eventRegistrations_.length; ++i) {\n      const existing = view.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(view.eventRegistrations_.slice(i + 1));\n        break;\n      }\n    }\n    view.eventRegistrations_ = remaining;\n  } else {\n    view.eventRegistrations_ = [];\n  }\n  return cancelEvents;\n}\n\n/**\n * Applies the given Operation, updates our cache, and returns the appropriate events.\n */\nexport function viewApplyOperation(\n  view: View,\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      viewCacheGetCompleteServerSnap(view.viewCache_),\n      'We should always have a full cache before handling merges'\n    );\n    assert(\n      viewCacheGetCompleteEventSnap(view.viewCache_),\n      'Missing event cache, even though we have a server cache'\n    );\n  }\n\n  const oldViewCache = view.viewCache_;\n  const result = viewProcessorApplyOperation(\n    view.processor_,\n    oldViewCache,\n    operation,\n    writesCache,\n    completeServerCache\n  );\n  viewProcessorAssertIndexed(view.processor_, result.viewCache);\n\n  assert(\n    result.viewCache.serverCache.isFullyInitialized() ||\n      !oldViewCache.serverCache.isFullyInitialized(),\n    'Once a server snap is complete, it should never go back'\n  );\n\n  view.viewCache_ = result.viewCache;\n\n  return viewGenerateEventsForChanges_(\n    view,\n    result.changes,\n    result.viewCache.eventCache.getNode(),\n    null\n  );\n}\n\nexport function viewGetInitialEvents(\n  view: View,\n  registration: EventRegistration\n): Event[] {\n  const eventSnap = view.viewCache_.eventCache;\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(changeChildAdded(key, childNode));\n    });\n  }\n  if (eventSnap.isFullyInitialized()) {\n    initialChanges.push(changeValue(eventSnap.getNode()));\n  }\n  return viewGenerateEventsForChanges_(\n    view,\n    initialChanges,\n    eventSnap.getNode(),\n    registration\n  );\n}\n\nfunction viewGenerateEventsForChanges_(\n  view: View,\n  changes: Change[],\n  eventCache: Node,\n  eventRegistration?: EventRegistration\n): Event[] {\n  const registrations = eventRegistration\n    ? [eventRegistration]\n    : view.eventRegistrations_;\n  return eventGeneratorGenerateEventsForChanges(\n    view.eventGenerator_,\n    changes,\n    eventCache,\n    registrations\n  );\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ReferenceConstructor } from '../api/Reference';\n\nimport { Operation } from './operation/Operation';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Node } from './snap/Node';\nimport { Path } from './util/Path';\nimport { CacheNode } from './view/CacheNode';\nimport { Event } from './view/Event';\nimport { EventRegistration, QueryContext } from './view/EventRegistration';\nimport {\n  View,\n  viewAddEventRegistration,\n  viewApplyOperation,\n  viewGetCompleteServerCache,\n  viewGetInitialEvents,\n  viewIsEmpty,\n  viewRemoveEventRegistration\n} from './view/View';\nimport { newViewCache } from './view/ViewCache';\nimport {\n  WriteTreeRef,\n  writeTreeRefCalcCompleteEventCache,\n  writeTreeRefCalcCompleteEventChildren\n} from './WriteTree';\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  /**\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  readonly views: Map<string, View> = new Map();\n}\n\nexport function syncPointSetReferenceConstructor(\n  val: ReferenceConstructor\n): void {\n  assert(\n    !referenceConstructor,\n    '__referenceConstructor has already been defined'\n  );\n  referenceConstructor = val;\n}\n\nfunction syncPointGetReferenceConstructor(): ReferenceConstructor {\n  assert(referenceConstructor, 'Reference.ts has not been loaded');\n  return referenceConstructor;\n}\n\nexport function syncPointIsEmpty(syncPoint: SyncPoint): boolean {\n  return syncPoint.views.size === 0;\n}\n\nexport function syncPointApplyOperation(\n  syncPoint: SyncPoint,\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 = syncPoint.views.get(queryId);\n    assert(view != null, 'SyncTree gave us an op for an invalid query.');\n    return viewApplyOperation(\n      view,\n      operation,\n      writesCache,\n      optCompleteServerCache\n    );\n  } else {\n    let events: Event[] = [];\n\n    for (const view of syncPoint.views.values()) {\n      events = events.concat(\n        viewApplyOperation(view, operation, writesCache, optCompleteServerCache)\n      );\n    }\n\n    return events;\n  }\n}\n\n/**\n * Get a view for the specified query.\n *\n * @param query - The query to return a view for\n * @param writesCache\n * @param serverCache\n * @param serverCacheComplete\n * @returns Events to raise.\n */\nexport function syncPointGetView(\n  syncPoint: SyncPoint,\n  query: QueryContext,\n  writesCache: WriteTreeRef,\n  serverCache: Node | null,\n  serverCacheComplete: boolean\n): View {\n  const queryId = query._queryIdentifier;\n  const view = syncPoint.views.get(queryId);\n  if (!view) {\n    // TODO: make writesCache take flag for complete server node\n    let eventCache = writeTreeRefCalcCompleteEventCache(\n      writesCache,\n      serverCacheComplete ? serverCache : null\n    );\n    let eventCacheComplete = false;\n    if (eventCache) {\n      eventCacheComplete = true;\n    } else if (serverCache instanceof ChildrenNode) {\n      eventCache = writeTreeRefCalcCompleteEventChildren(\n        writesCache,\n        serverCache\n      );\n      eventCacheComplete = false;\n    } else {\n      eventCache = ChildrenNode.EMPTY_NODE;\n      eventCacheComplete = false;\n    }\n    const viewCache = newViewCache(\n      new CacheNode(eventCache, eventCacheComplete, false),\n      new CacheNode(serverCache, serverCacheComplete, false)\n    );\n    return new View(query, viewCache);\n  }\n  return view;\n}\n\n/**\n * Add an event callback for the specified query.\n *\n * @param query\n * @param eventRegistration\n * @param writesCache\n * @param serverCache - Complete server cache, if we have it.\n * @param serverCacheComplete\n * @returns Events to raise.\n */\nexport function syncPointAddEventRegistration(\n  syncPoint: SyncPoint,\n  query: QueryContext,\n  eventRegistration: EventRegistration,\n  writesCache: WriteTreeRef,\n  serverCache: Node | null,\n  serverCacheComplete: boolean\n): Event[] {\n  const view = syncPointGetView(\n    syncPoint,\n    query,\n    writesCache,\n    serverCache,\n    serverCacheComplete\n  );\n  if (!syncPoint.views.has(query._queryIdentifier)) {\n    syncPoint.views.set(query._queryIdentifier, view);\n  }\n  // This is guaranteed to exist now, we just created anything that was missing\n  viewAddEventRegistration(view, eventRegistration);\n  return viewGetInitialEvents(view, 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 eventRegistration - If null, remove all callbacks.\n * @param cancelError - If a cancelError is provided, appropriate cancel events will be returned.\n * @returns removed queries and any cancel events\n */\nexport function syncPointRemoveEventRegistration(\n  syncPoint: SyncPoint,\n  query: QueryContext,\n  eventRegistration: EventRegistration | null,\n  cancelError?: Error\n): { removed: QueryContext[]; events: Event[] } {\n  const queryId = query._queryIdentifier;\n  const removed: QueryContext[] = [];\n  let cancelEvents: Event[] = [];\n  const hadCompleteView = syncPointHasCompleteView(syncPoint);\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 syncPoint.views.entries()) {\n      cancelEvents = cancelEvents.concat(\n        viewRemoveEventRegistration(view, eventRegistration, cancelError)\n      );\n      if (viewIsEmpty(view)) {\n        syncPoint.views.delete(viewQueryId);\n\n        // We'll deal with complete views later.\n        if (!view.query._queryParams.loadsAllData()) {\n          removed.push(view.query);\n        }\n      }\n    }\n  } else {\n    // remove the callback from the specific view.\n    const view = syncPoint.views.get(queryId);\n    if (view) {\n      cancelEvents = cancelEvents.concat(\n        viewRemoveEventRegistration(view, eventRegistration, cancelError)\n      );\n      if (viewIsEmpty(view)) {\n        syncPoint.views.delete(queryId);\n\n        // We'll deal with complete views later.\n        if (!view.query._queryParams.loadsAllData()) {\n          removed.push(view.query);\n        }\n      }\n    }\n  }\n\n  if (hadCompleteView && !syncPointHasCompleteView(syncPoint)) {\n    // We removed our last complete view.\n    removed.push(\n      new (syncPointGetReferenceConstructor())(query._repo, query._path)\n    );\n  }\n\n  return { removed, events: cancelEvents };\n}\n\nexport function syncPointGetQueryViews(syncPoint: SyncPoint): View[] {\n  const result = [];\n  for (const view of syncPoint.views.values()) {\n    if (!view.query._queryParams.loadsAllData()) {\n      result.push(view);\n    }\n  }\n  return result;\n}\n\n/**\n * @param path - The path to the desired complete snapshot\n * @returns A complete cache, if it exists\n */\nexport function syncPointGetCompleteServerCache(\n  syncPoint: SyncPoint,\n  path: Path\n): Node | null {\n  let serverCache: Node | null = null;\n  for (const view of syncPoint.views.values()) {\n    serverCache = serverCache || viewGetCompleteServerCache(view, path);\n  }\n  return serverCache;\n}\n\nexport function syncPointViewForQuery(\n  syncPoint: SyncPoint,\n  query: QueryContext\n): View | null {\n  const params = query._queryParams;\n  if (params.loadsAllData()) {\n    return syncPointGetCompleteView(syncPoint);\n  } else {\n    const queryId = query._queryIdentifier;\n    return syncPoint.views.get(queryId);\n  }\n}\n\nexport function syncPointViewExistsForQuery(\n  syncPoint: SyncPoint,\n  query: QueryContext\n): boolean {\n  return syncPointViewForQuery(syncPoint, query) != null;\n}\n\nexport function syncPointHasCompleteView(syncPoint: SyncPoint): boolean {\n  return syncPointGetCompleteView(syncPoint) != null;\n}\n\nexport function syncPointGetCompleteView(syncPoint: SyncPoint): View | null {\n  for (const view of syncPoint.views.values()) {\n    if (view.query._queryParams.loadsAllData()) {\n      return view;\n    }\n  }\n  return null;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ReferenceConstructor } from '../api/Reference';\n\nimport { AckUserWrite } from './operation/AckUserWrite';\nimport { ListenComplete } from './operation/ListenComplete';\nimport { Merge } from './operation/Merge';\nimport {\n  newOperationSourceServer,\n  newOperationSourceServerTaggedQuery,\n  newOperationSourceUser,\n  Operation\n} from './operation/Operation';\nimport { Overwrite } from './operation/Overwrite';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Node } from './snap/Node';\nimport {\n  SyncPoint,\n  syncPointAddEventRegistration,\n  syncPointApplyOperation,\n  syncPointGetCompleteServerCache,\n  syncPointGetCompleteView,\n  syncPointGetQueryViews,\n  syncPointGetView,\n  syncPointHasCompleteView,\n  syncPointIsEmpty,\n  syncPointRemoveEventRegistration,\n  syncPointViewExistsForQuery,\n  syncPointViewForQuery\n} from './SyncPoint';\nimport { ImmutableTree } from './util/ImmutableTree';\nimport {\n  newEmptyPath,\n  newRelativePath,\n  Path,\n  pathGetFront,\n  pathIsEmpty\n} from './util/Path';\nimport { each, errorForServerCode } from './util/util';\nimport { CacheNode } from './view/CacheNode';\nimport { Event } from './view/Event';\nimport { EventRegistration, QueryContext } from './view/EventRegistration';\nimport { View, viewGetCompleteNode, viewGetServerCache } from './view/View';\nimport {\n  newWriteTree,\n  WriteTree,\n  writeTreeAddMerge,\n  writeTreeAddOverwrite,\n  writeTreeCalcCompleteEventCache,\n  writeTreeChildWrites,\n  writeTreeGetWrite,\n  WriteTreeRef,\n  writeTreeRefChild,\n  writeTreeRemoveWrite\n} from './WriteTree';\n\nlet referenceConstructor: ReferenceConstructor;\n\nexport function syncTreeSetReferenceConstructor(\n  val: ReferenceConstructor\n): void {\n  assert(\n    !referenceConstructor,\n    '__referenceConstructor has already been defined'\n  );\n  referenceConstructor = val;\n}\n\nfunction syncTreeGetReferenceConstructor(): ReferenceConstructor {\n  assert(referenceConstructor, 'Reference.ts has not been loaded');\n  return referenceConstructor;\n}\n\nexport interface ListenProvider {\n  startListening(\n    query: QueryContext,\n    tag: number | null,\n    hashFn: () => string,\n    onComplete: (a: string, b?: unknown) => Event[]\n  ): Event[];\n\n  stopListening(a: QueryContext, b: number | null): void;\n}\n\n/**\n * Static tracker for next query tag.\n */\nlet syncTreeNextQueryTag_ = 1;\n\nexport function resetSyncTreeTag() {\n  syncTreeNextQueryTag_ = 1;\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 */\nexport class SyncTree {\n  /**\n   * Tree of SyncPoints.  There's a SyncPoint at any location that has 1 or more views.\n   */\n  syncPointTree_: ImmutableTree<SyncPoint> = new ImmutableTree<SyncPoint>(null);\n\n  /**\n   * A tree of all pending user writes (user-initiated set()'s, transaction()'s, update()'s, etc.).\n   */\n  pendingWriteTree_: WriteTree = newWriteTree();\n\n  readonly tagToQueryMap: Map<number, string> = new Map();\n  readonly queryToTagMap: Map<string, number> = new Map();\n\n  /**\n   * @param listenProvider_ - Used by SyncTree to start / stop listening\n   *   to server data.\n   */\n  constructor(public listenProvider_: ListenProvider) {}\n}\n\n/**\n * Apply the data changes for a user-generated set() or transaction() call.\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyUserOverwrite(\n  syncTree: SyncTree,\n  path: Path,\n  newData: Node,\n  writeId: number,\n  visible?: boolean\n): Event[] {\n  // Record pending write.\n  writeTreeAddOverwrite(\n    syncTree.pendingWriteTree_,\n    path,\n    newData,\n    writeId,\n    visible\n  );\n\n  if (!visible) {\n    return [];\n  } else {\n    return syncTreeApplyOperationToSyncPoints_(\n      syncTree,\n      new Overwrite(newOperationSourceUser(), path, newData)\n    );\n  }\n}\n\n/**\n * Apply the data from a user-generated update() call\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyUserMerge(\n  syncTree: SyncTree,\n  path: Path,\n  changedChildren: { [k: string]: Node },\n  writeId: number\n): Event[] {\n  // Record pending merge.\n  writeTreeAddMerge(syncTree.pendingWriteTree_, path, changedChildren, writeId);\n\n  const changeTree = ImmutableTree.fromObject(changedChildren);\n\n  return syncTreeApplyOperationToSyncPoints_(\n    syncTree,\n    new Merge(newOperationSourceUser(), 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 * @returns Events to raise.\n */\nexport function syncTreeAckUserWrite(\n  syncTree: SyncTree,\n  writeId: number,\n  revert: boolean = false\n) {\n  const write = writeTreeGetWrite(syncTree.pendingWriteTree_, writeId);\n  const needToReevaluate = writeTreeRemoveWrite(\n    syncTree.pendingWriteTree_,\n    writeId\n  );\n  if (!needToReevaluate) {\n    return [];\n  } else {\n    let affectedTree = new ImmutableTree<boolean>(null);\n    if (write.snap != null) {\n      // overwrite\n      affectedTree = affectedTree.set(newEmptyPath(), true);\n    } else {\n      each(write.children, (pathString: string) => {\n        affectedTree = affectedTree.set(new Path(pathString), true);\n      });\n    }\n    return syncTreeApplyOperationToSyncPoints_(\n      syncTree,\n      new AckUserWrite(write.path, affectedTree, revert)\n    );\n  }\n}\n\n/**\n * Apply new server data for the specified path..\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyServerOverwrite(\n  syncTree: SyncTree,\n  path: Path,\n  newData: Node\n): Event[] {\n  return syncTreeApplyOperationToSyncPoints_(\n    syncTree,\n    new Overwrite(newOperationSourceServer(), path, newData)\n  );\n}\n\n/**\n * Apply new server data to be merged in at the specified path.\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyServerMerge(\n  syncTree: SyncTree,\n  path: Path,\n  changedChildren: { [k: string]: Node }\n): Event[] {\n  const changeTree = ImmutableTree.fromObject(changedChildren);\n\n  return syncTreeApplyOperationToSyncPoints_(\n    syncTree,\n    new Merge(newOperationSourceServer(), path, changeTree)\n  );\n}\n\n/**\n * Apply a listen complete for a query\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyListenComplete(\n  syncTree: SyncTree,\n  path: Path\n): Event[] {\n  return syncTreeApplyOperationToSyncPoints_(\n    syncTree,\n    new ListenComplete(newOperationSourceServer(), path)\n  );\n}\n\n/**\n * Apply a listen complete for a tagged query\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyTaggedListenComplete(\n  syncTree: SyncTree,\n  path: Path,\n  tag: number\n): Event[] {\n  const queryKey = syncTreeQueryKeyForTag_(syncTree, tag);\n  if (queryKey) {\n    const r = syncTreeParseQueryKey_(queryKey);\n    const queryPath = r.path,\n      queryId = r.queryId;\n    const relativePath = newRelativePath(queryPath, path);\n    const op = new ListenComplete(\n      newOperationSourceServerTaggedQuery(queryId),\n      relativePath\n    );\n    return syncTreeApplyTaggedOperation_(syncTree, queryPath, op);\n  } else {\n    // We've already removed the query. No big deal, ignore the update\n    return [];\n  }\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 * @param skipListenerDedup - When performing a `get()`, we don't add any new listeners, so no\n *  deduping needs to take place. This flag allows toggling of that behavior\n * @returns Cancel events, if cancelError was provided.\n */\nexport function syncTreeRemoveEventRegistration(\n  syncTree: SyncTree,\n  query: QueryContext,\n  eventRegistration: EventRegistration | null,\n  cancelError?: Error,\n  skipListenerDedup = false\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 = syncTree.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      syncPointViewExistsForQuery(maybeSyncPoint, query))\n  ) {\n    const removedAndEvents = syncPointRemoveEventRegistration(\n      maybeSyncPoint,\n      query,\n      eventRegistration,\n      cancelError\n    );\n    if (syncPointIsEmpty(maybeSyncPoint)) {\n      syncTree.syncPointTree_ = syncTree.syncPointTree_.remove(path);\n    }\n\n    const removed = removedAndEvents.removed;\n    cancelEvents = removedAndEvents.events;\n\n    if (!skipListenerDedup) {\n      /**\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\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._queryParams.loadsAllData();\n        });\n      const covered = syncTree.syncPointTree_.findOnPath(\n        path,\n        (relativePath, parentSyncPoint) =>\n          syncPointHasCompleteView(parentSyncPoint)\n      );\n\n      if (removingDefault && !covered) {\n        const subtree = syncTree.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 = syncTreeCollectDistinctViewsForSubTree_(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.query;\n            const listener = syncTreeCreateListenerForView_(syncTree, view);\n            syncTree.listenProvider_.startListening(\n              syncTreeQueryForListening_(newQuery),\n              syncTreeTagForQuery(syncTree, newQuery),\n              listener.hashFn,\n              listener.onComplete\n            );\n          }\n        }\n        // Otherwise there's nothing below us, so nothing we need to start listening on\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          syncTree.listenProvider_.stopListening(\n            syncTreeQueryForListening_(query),\n            defaultTag\n          );\n        } else {\n          removed.forEach((queryToRemove: QueryContext) => {\n            const tagToRemove = syncTree.queryToTagMap.get(\n              syncTreeMakeQueryKey_(queryToRemove)\n            );\n            syncTree.listenProvider_.stopListening(\n              syncTreeQueryForListening_(queryToRemove),\n              tagToRemove\n            );\n          });\n        }\n      }\n    }\n    // Now, clear all of the tags we're tracking for the removed listens\n    syncTreeRemoveTags_(syncTree, removed);\n  } else {\n    // No-op, this listener must've been already removed\n  }\n  return cancelEvents;\n}\n\n/**\n * Apply new server data for the specified tagged query.\n *\n * @returns Events to raise.\n */\nexport function syncTreeApplyTaggedQueryOverwrite(\n  syncTree: SyncTree,\n  path: Path,\n  snap: Node,\n  tag: number\n): Event[] {\n  const queryKey = syncTreeQueryKeyForTag_(syncTree, tag);\n  if (queryKey != null) {\n    const r = syncTreeParseQueryKey_(queryKey);\n    const queryPath = r.path,\n      queryId = r.queryId;\n    const relativePath = newRelativePath(queryPath, path);\n    const op = new Overwrite(\n      newOperationSourceServerTaggedQuery(queryId),\n      relativePath,\n      snap\n    );\n    return syncTreeApplyTaggedOperation_(syncTree, 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 * @returns Events to raise.\n */\nexport function syncTreeApplyTaggedQueryMerge(\n  syncTree: SyncTree,\n  path: Path,\n  changedChildren: { [k: string]: Node },\n  tag: number\n): Event[] {\n  const queryKey = syncTreeQueryKeyForTag_(syncTree, tag);\n  if (queryKey) {\n    const r = syncTreeParseQueryKey_(queryKey);\n    const queryPath = r.path,\n      queryId = r.queryId;\n    const relativePath = newRelativePath(queryPath, path);\n    const changeTree = ImmutableTree.fromObject(changedChildren);\n    const op = new Merge(\n      newOperationSourceServerTaggedQuery(queryId),\n      relativePath,\n      changeTree\n    );\n    return syncTreeApplyTaggedOperation_(syncTree, 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 * @returns Events to raise.\n */\nexport function syncTreeAddEventRegistration(\n  syncTree: SyncTree,\n  query: QueryContext,\n  eventRegistration: EventRegistration,\n  skipSetupListener = false\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  syncTree.syncPointTree_.foreachOnPath(path, (pathToSyncPoint, sp) => {\n    const relativePath = newRelativePath(pathToSyncPoint, path);\n    serverCache =\n      serverCache || syncPointGetCompleteServerCache(sp, relativePath);\n    foundAncestorDefaultView =\n      foundAncestorDefaultView || syncPointHasCompleteView(sp);\n  });\n  let syncPoint = syncTree.syncPointTree_.get(path);\n  if (!syncPoint) {\n    syncPoint = new SyncPoint();\n    syncTree.syncPointTree_ = syncTree.syncPointTree_.set(path, syncPoint);\n  } else {\n    foundAncestorDefaultView =\n      foundAncestorDefaultView || syncPointHasCompleteView(syncPoint);\n    serverCache =\n      serverCache || syncPointGetCompleteServerCache(syncPoint, newEmptyPath());\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 = syncTree.syncPointTree_.subtree(path);\n    subtree.foreachChild((childName, childSyncPoint) => {\n      const completeCache = syncPointGetCompleteServerCache(\n        childSyncPoint,\n        newEmptyPath()\n      );\n      if (completeCache) {\n        serverCache = serverCache.updateImmediateChild(\n          childName,\n          completeCache\n        );\n      }\n    });\n  }\n\n  const viewAlreadyExists = syncPointViewExistsForQuery(syncPoint, query);\n  if (!viewAlreadyExists && !query._queryParams.loadsAllData()) {\n    // We need to track a tag for this query\n    const queryKey = syncTreeMakeQueryKey_(query);\n    assert(\n      !syncTree.queryToTagMap.has(queryKey),\n      'View does not exist, but we have a tag'\n    );\n    const tag = syncTreeGetNextQueryTag_();\n    syncTree.queryToTagMap.set(queryKey, tag);\n    syncTree.tagToQueryMap.set(tag, queryKey);\n  }\n  const writesCache = writeTreeChildWrites(syncTree.pendingWriteTree_, path);\n  let events = syncPointAddEventRegistration(\n    syncPoint,\n    query,\n    eventRegistration,\n    writesCache,\n    serverCache,\n    serverCacheComplete\n  );\n  if (!viewAlreadyExists && !foundAncestorDefaultView && !skipSetupListener) {\n    const view = syncPointViewForQuery(syncPoint, query);\n    events = events.concat(syncTreeSetupListener_(syncTree, query, view));\n  }\n  return events;\n}\n\n/**\n * Returns a complete cache, if we have one, of the data at a particular path. If the location does not have a\n * listener above it, we will get a false \"null\". This shouldn't be a problem because transactions will always\n * have a listener above, and atomic operations would correctly show a jitter of <increment value> ->\n *     <incremented total> as the write is applied locally and then acknowledged at the server.\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 */\nexport function syncTreeCalcCompleteEventCache(\n  syncTree: SyncTree,\n  path: Path,\n  writeIdsToExclude?: number[]\n): Node {\n  const includeHiddenSets = true;\n  const writeTree = syncTree.pendingWriteTree_;\n  const serverCache = syncTree.syncPointTree_.findOnPath(\n    path,\n    (pathSoFar, syncPoint) => {\n      const relativePath = newRelativePath(pathSoFar, path);\n      const serverCache = syncPointGetCompleteServerCache(\n        syncPoint,\n        relativePath\n      );\n      if (serverCache) {\n        return serverCache;\n      }\n    }\n  );\n  return writeTreeCalcCompleteEventCache(\n    writeTree,\n    path,\n    serverCache,\n    writeIdsToExclude,\n    includeHiddenSets\n  );\n}\n\nexport function syncTreeGetServerValue(\n  syncTree: SyncTree,\n  query: QueryContext\n): Node | null {\n  const path = query._path;\n  let serverCache: Node | null = null;\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  syncTree.syncPointTree_.foreachOnPath(path, (pathToSyncPoint, sp) => {\n    const relativePath = newRelativePath(pathToSyncPoint, path);\n    serverCache =\n      serverCache || syncPointGetCompleteServerCache(sp, relativePath);\n  });\n  let syncPoint = syncTree.syncPointTree_.get(path);\n  if (!syncPoint) {\n    syncPoint = new SyncPoint();\n    syncTree.syncPointTree_ = syncTree.syncPointTree_.set(path, syncPoint);\n  } else {\n    serverCache =\n      serverCache || syncPointGetCompleteServerCache(syncPoint, newEmptyPath());\n  }\n  const serverCacheComplete = serverCache != null;\n  const serverCacheNode: CacheNode | null = serverCacheComplete\n    ? new CacheNode(serverCache, true, false)\n    : null;\n  const writesCache: WriteTreeRef | null = writeTreeChildWrites(\n    syncTree.pendingWriteTree_,\n    query._path\n  );\n  const view: View = syncPointGetView(\n    syncPoint,\n    query,\n    writesCache,\n    serverCacheComplete ? serverCacheNode.getNode() : ChildrenNode.EMPTY_NODE,\n    serverCacheComplete\n  );\n  return viewGetCompleteNode(view);\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 */\nfunction syncTreeApplyOperationToSyncPoints_(\n  syncTree: SyncTree,\n  operation: Operation\n): Event[] {\n  return syncTreeApplyOperationHelper_(\n    operation,\n    syncTree.syncPointTree_,\n    /*serverCache=*/ null,\n    writeTreeChildWrites(syncTree.pendingWriteTree_, newEmptyPath())\n  );\n}\n\n/**\n * Recursive helper for applyOperationToSyncPoints_\n */\nfunction syncTreeApplyOperationHelper_(\n  operation: Operation,\n  syncPointTree: ImmutableTree<SyncPoint>,\n  serverCache: Node | null,\n  writesCache: WriteTreeRef\n): Event[] {\n  if (pathIsEmpty(operation.path)) {\n    return syncTreeApplyOperationDescendantsHelper_(\n      operation,\n      syncPointTree,\n      serverCache,\n      writesCache\n    );\n  } else {\n    const syncPoint = syncPointTree.get(newEmptyPath());\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 = syncPointGetCompleteServerCache(syncPoint, newEmptyPath());\n    }\n\n    let events: Event[] = [];\n    const childName = pathGetFront(operation.path);\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 = writeTreeRefChild(writesCache, childName);\n      events = events.concat(\n        syncTreeApplyOperationHelper_(\n          childOperation,\n          childTree,\n          childServerCache,\n          childWritesCache\n        )\n      );\n    }\n\n    if (syncPoint) {\n      events = events.concat(\n        syncPointApplyOperation(syncPoint, operation, writesCache, serverCache)\n      );\n    }\n\n    return events;\n  }\n}\n\n/**\n * Recursive helper for applyOperationToSyncPoints_\n */\nfunction syncTreeApplyOperationDescendantsHelper_(\n  operation: Operation,\n  syncPointTree: ImmutableTree<SyncPoint>,\n  serverCache: Node | null,\n  writesCache: WriteTreeRef\n): Event[] {\n  const syncPoint = syncPointTree.get(newEmptyPath());\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 = syncPointGetCompleteServerCache(syncPoint, newEmptyPath());\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 = writeTreeRefChild(writesCache, childName);\n    const childOperation = operation.operationForChild(childName);\n    if (childOperation) {\n      events = events.concat(\n        syncTreeApplyOperationDescendantsHelper_(\n          childOperation,\n          childTree,\n          childServerCache,\n          childWritesCache\n        )\n      );\n    }\n  });\n\n  if (syncPoint) {\n    events = events.concat(\n      syncPointApplyOperation(syncPoint, operation, writesCache, serverCache)\n    );\n  }\n\n  return events;\n}\n\nfunction syncTreeCreateListenerForView_(\n  syncTree: SyncTree,\n  view: View\n): { hashFn(): string; onComplete(a: string, b?: unknown): Event[] } {\n  const query = view.query;\n  const tag = syncTreeTagForQuery(syncTree, query);\n\n  return {\n    hashFn: () => {\n      const cache = viewGetServerCache(view) || ChildrenNode.EMPTY_NODE;\n      return cache.hash();\n    },\n    onComplete: (status: string): Event[] => {\n      if (status === 'ok') {\n        if (tag) {\n          return syncTreeApplyTaggedListenComplete(syncTree, query._path, tag);\n        } else {\n          return syncTreeApplyListenComplete(syncTree, 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 syncTreeRemoveEventRegistration(\n          syncTree,\n          query,\n          /*eventRegistration*/ null,\n          error\n        );\n      }\n    }\n  };\n}\n\n/**\n * Return the tag associated with the given query.\n */\nexport function syncTreeTagForQuery(\n  syncTree: SyncTree,\n  query: QueryContext\n): number | null {\n  const queryKey = syncTreeMakeQueryKey_(query);\n  return syncTree.queryToTagMap.get(queryKey);\n}\n\n/**\n * Given a query, computes a \"queryKey\" suitable for use in our queryToTagMap_.\n */\nfunction syncTreeMakeQueryKey_(query: QueryContext): string {\n  return query._path.toString() + '$' + query._queryIdentifier;\n}\n\n/**\n * Return the query associated with the given tag, if we have one\n */\nfunction syncTreeQueryKeyForTag_(\n  syncTree: SyncTree,\n  tag: number\n): string | null {\n  return syncTree.tagToQueryMap.get(tag);\n}\n\n/**\n * Given a queryKey (created by makeQueryKey), parse it back into a path and queryId.\n */\nfunction syncTreeParseQueryKey_(queryKey: string): {\n  queryId: string;\n  path: Path;\n} {\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 * A helper method to apply tagged operations\n */\nfunction syncTreeApplyTaggedOperation_(\n  syncTree: SyncTree,\n  queryPath: Path,\n  operation: Operation\n): Event[] {\n  const syncPoint = syncTree.syncPointTree_.get(queryPath);\n  assert(syncPoint, \"Missing sync point for query tag that we're tracking\");\n  const writesCache = writeTreeChildWrites(\n    syncTree.pendingWriteTree_,\n    queryPath\n  );\n  return syncPointApplyOperation(syncPoint, operation, writesCache, null);\n}\n\n/**\n * This collapses multiple unfiltered views into a single view, since we only need a single\n * listener for them.\n */\nfunction syncTreeCollectDistinctViewsForSubTree_(\n  subtree: ImmutableTree<SyncPoint>\n): View[] {\n  return subtree.fold<View[]>((relativePath, maybeChildSyncPoint, childMap) => {\n    if (maybeChildSyncPoint && syncPointHasCompleteView(maybeChildSyncPoint)) {\n      const completeView = syncPointGetCompleteView(maybeChildSyncPoint);\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 = syncPointGetQueryViews(maybeChildSyncPoint);\n      }\n      each(childMap, (_key: string, childViews: View[]) => {\n        views = views.concat(childViews);\n      });\n      return views;\n    }\n  });\n}\n\n/**\n * Normalizes a query to a query we send the server for listening\n *\n * @returns The normalized query\n */\nfunction syncTreeQueryForListening_(query: QueryContext): QueryContext {\n  if (query._queryParams.loadsAllData() && !query._queryParams.isDefault()) {\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 new (syncTreeGetReferenceConstructor())(query._repo, query._path);\n  } else {\n    return query;\n  }\n}\n\nfunction syncTreeRemoveTags_(syncTree: SyncTree, queries: QueryContext[]) {\n  for (let j = 0; j < queries.length; ++j) {\n    const removedQuery = queries[j];\n    if (!removedQuery._queryParams.loadsAllData()) {\n      // We should have a tag for this\n      const removedQueryKey = syncTreeMakeQueryKey_(removedQuery);\n      const removedQueryTag = syncTree.queryToTagMap.get(removedQueryKey);\n      syncTree.queryToTagMap.delete(removedQueryKey);\n      syncTree.tagToQueryMap.delete(removedQueryTag);\n    }\n  }\n}\n\n/**\n * Static accessor for query tags.\n */\nfunction syncTreeGetNextQueryTag_(): number {\n  return syncTreeNextQueryTag_++;\n}\n\n/**\n * For a given new listen, manage the de-duplication of outstanding subscriptions.\n *\n * @returns This method can return events to support synchronous data sources\n */\nfunction syncTreeSetupListener_(\n  syncTree: SyncTree,\n  query: QueryContext,\n  view: View\n): Event[] {\n  const path = query._path;\n  const tag = syncTreeTagForQuery(syncTree, query);\n  const listener = syncTreeCreateListenerForView_(syncTree, view);\n\n  const events = syncTree.listenProvider_.startListening(\n    syncTreeQueryForListening_(query),\n    tag,\n    listener.hashFn,\n    listener.onComplete\n  );\n\n  const subtree = syncTree.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      !syncPointHasCompleteView(subtree.value),\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<QueryContext[]>(\n      (relativePath, maybeChildSyncPoint, childMap) => {\n        if (\n          !pathIsEmpty(relativePath) &&\n          maybeChildSyncPoint &&\n          syncPointHasCompleteView(maybeChildSyncPoint)\n        ) {\n          return [syncPointGetCompleteView(maybeChildSyncPoint).query];\n        } else {\n          // No default listener here, flatten any deeper queries into an array\n          let queries: QueryContext[] = [];\n          if (maybeChildSyncPoint) {\n            queries = queries.concat(\n              syncPointGetQueryViews(maybeChildSyncPoint).map(\n                view => view.query\n              )\n            );\n          }\n          each(childMap, (_key: string, childQueries: QueryContext[]) => {\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      syncTree.listenProvider_.stopListening(\n        syncTreeQueryForListening_(queryToStop),\n        syncTreeTagForQuery(syncTree, queryToStop)\n      );\n    }\n  }\n  return events;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { ChildrenNode } from '../snap/ChildrenNode';\nimport { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';\nimport { LeafNode } from '../snap/LeafNode';\nimport { Node } from '../snap/Node';\nimport { nodeFromJSON } from '../snap/nodeFromJSON';\nimport { SyncTree, syncTreeCalcCompleteEventCache } from '../SyncTree';\n\nimport { Indexable } from './misc';\nimport { Path, pathChild } from './Path';\n\n/* It's critical for performance that we do not calculate actual values from a SyncTree\n * unless and until the value is needed. Because we expose both a SyncTree and Node\n * version of deferred value resolution, we ned a wrapper class that will let us share\n * code.\n *\n * @see https://github.com/firebase/firebase-js-sdk/issues/2487\n */\ninterface ValueProvider {\n  getImmediateChild(childName: string): ValueProvider;\n  node(): Node;\n}\n\nclass ExistingValueProvider implements ValueProvider {\n  constructor(readonly node_: Node) {}\n\n  getImmediateChild(childName: string): ValueProvider {\n    const child = this.node_.getImmediateChild(childName);\n    return new ExistingValueProvider(child);\n  }\n\n  node(): Node {\n    return this.node_;\n  }\n}\n\nclass DeferredValueProvider implements ValueProvider {\n  private syncTree_: SyncTree;\n  private path_: Path;\n\n  constructor(syncTree: SyncTree, path: Path) {\n    this.syncTree_ = syncTree;\n    this.path_ = path;\n  }\n\n  getImmediateChild(childName: string): ValueProvider {\n    const childPath = pathChild(this.path_, childName);\n    return new DeferredValueProvider(this.syncTree_, childPath);\n  }\n\n  node(): Node {\n    return syncTreeCalcCompleteEventCache(this.syncTree_, this.path_);\n  }\n}\n\n/**\n * Generate placeholders for deferred values.\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 */\nexport const resolveDeferredLeafValue = function (\n  value: { [k: string]: unknown } | string | number | boolean,\n  existingVal: ValueProvider,\n  serverValues: { [k: string]: unknown }\n): string | number | boolean {\n  if (!value || typeof value !== 'object') {\n    return value as string | number | boolean;\n  }\n  assert('.sv' in value, 'Unexpected leaf node or priority contents');\n\n  if (typeof value['.sv'] === 'string') {\n    return resolveScalarDeferredValue(value['.sv'], existingVal, serverValues);\n  } else if (typeof value['.sv'] === 'object') {\n    return resolveComplexDeferredValue(value['.sv'], existingVal, serverValues);\n  } else {\n    assert(false, 'Unexpected server value: ' + JSON.stringify(value, null, 2));\n  }\n};\n\nconst resolveScalarDeferredValue = function (\n  op: string,\n  existing: ValueProvider,\n  serverValues: { [k: string]: unknown }\n): string | number | boolean {\n  switch (op) {\n    case 'timestamp':\n      return serverValues['timestamp'] as string | number | boolean;\n    default:\n      assert(false, 'Unexpected server value: ' + op);\n  }\n};\n\nconst resolveComplexDeferredValue = function (\n  op: object,\n  existing: ValueProvider,\n  unused: { [k: string]: unknown }\n): string | number | boolean {\n  if (!op.hasOwnProperty('increment')) {\n    assert(false, 'Unexpected server value: ' + JSON.stringify(op, null, 2));\n  }\n  const delta = op['increment'];\n  if (typeof delta !== 'number') {\n    assert(false, 'Unexpected increment value: ' + delta);\n  }\n\n  const existingNode = existing.node();\n  assert(\n    existingNode !== null && typeof existingNode !== 'undefined',\n    'Expected ChildrenNode.EMPTY_NODE for nulls'\n  );\n\n  // Incrementing a non-number sets the value to the incremented amount\n  if (!existingNode.isLeafNode()) {\n    return delta;\n  }\n\n  const leaf = existingNode as LeafNode;\n  const existingVal = leaf.getValue();\n  if (typeof existingVal !== 'number') {\n    return delta;\n  }\n\n  // No need to do over/underflow arithmetic here because JS only handles floats under the covers\n  return existingVal + delta;\n};\n\n/**\n * Recursively replace all deferred values and priorities in the tree with the\n * specified generated replacement values.\n * @param path - path to which write is relative\n * @param node - new data written at path\n * @param syncTree - current data\n */\nexport const resolveDeferredValueTree = function (\n  path: Path,\n  node: Node,\n  syncTree: SyncTree,\n  serverValues: Indexable\n): Node {\n  return resolveDeferredValue(\n    node,\n    new DeferredValueProvider(syncTree, path),\n    serverValues\n  );\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 */\nexport const resolveDeferredValueSnapshot = function (\n  node: Node,\n  existing: Node,\n  serverValues: Indexable\n): Node {\n  return resolveDeferredValue(\n    node,\n    new ExistingValueProvider(existing),\n    serverValues\n  );\n};\n\nfunction resolveDeferredValue(\n  node: Node,\n  existingVal: ValueProvider,\n  serverValues: Indexable\n): Node {\n  const rawPri = node.getPriority().val() as\n    | Indexable\n    | boolean\n    | null\n    | number\n    | string;\n  const priority = resolveDeferredLeafValue(\n    rawPri,\n    existingVal.getImmediateChild('.priority'),\n    serverValues\n  );\n  let newNode: Node;\n\n  if (node.isLeafNode()) {\n    const leafNode = node as LeafNode;\n    const value = resolveDeferredLeafValue(\n      leafNode.getValue(),\n      existingVal,\n      serverValues\n    );\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 = resolveDeferredValue(\n        childNode,\n        existingVal.getImmediateChild(childName),\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 LLC\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, safeGet } from '@firebase/util';\n\nimport { Path, pathGetFront, pathPopFront } from './Path';\nimport { each } from './util';\n\n/**\n * Node in a Tree.\n */\nexport interface TreeNode<T> {\n  // TODO: Consider making accessors that create children and value lazily or\n  // separate Internal / Leaf 'types'.\n  children: Record<string, TreeNode<T>>;\n  childCount: number;\n  value?: T;\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<T> {\n  /**\n   * @param name - Optional name of the node.\n   * @param parent - Optional parent node.\n   * @param node - Optional node to wrap.\n   */\n  constructor(\n    readonly name: string = '',\n    readonly parent: Tree<T> | null = null,\n    public node: TreeNode<T> = { children: {}, childCount: 0 }\n  ) {}\n}\n\n/**\n * Returns a sub-Tree for the given path.\n *\n * @param pathObj - Path to look up.\n * @returns Tree for path.\n */\nexport function treeSubTree<T>(tree: Tree<T>, pathObj: string | Path): Tree<T> {\n  // TODO: Require pathObj to be Path?\n  let path = pathObj instanceof Path ? pathObj : new Path(pathObj);\n  let child = tree,\n    next = pathGetFront(path);\n  while (next !== null) {\n    const childNode = safeGet(child.node.children, next) || {\n      children: {},\n      childCount: 0\n    };\n    child = new Tree<T>(next, child, childNode);\n    path = pathPopFront(path);\n    next = pathGetFront(path);\n  }\n\n  return child;\n}\n\n/**\n * Returns the data associated with this tree node.\n *\n * @returns The data or null if no data exists.\n */\nexport function treeGetValue<T>(tree: Tree<T>): T | undefined {\n  return tree.node.value;\n}\n\n/**\n * Sets data to this tree node.\n *\n * @param value - Value to set.\n */\nexport function treeSetValue<T>(tree: Tree<T>, value: T | undefined): void {\n  tree.node.value = value;\n  treeUpdateParents(tree);\n}\n\n/**\n * @returns Whether the tree has any children.\n */\nexport function treeHasChildren<T>(tree: Tree<T>): boolean {\n  return tree.node.childCount > 0;\n}\n\n/**\n * @returns Whether the tree is empty (no value or children).\n */\nexport function treeIsEmpty<T>(tree: Tree<T>): boolean {\n  return treeGetValue(tree) === undefined && !treeHasChildren(tree);\n}\n\n/**\n * Calls action for each child of this tree node.\n *\n * @param action - Action to be called for each child.\n */\nexport function treeForEachChild<T>(\n  tree: Tree<T>,\n  action: (tree: Tree<T>) => void\n): void {\n  each(tree.node.children, (child: string, childTree: TreeNode<T>) => {\n    action(new Tree<T>(child, tree, childTree));\n  });\n}\n\n/**\n * Does a depth-first traversal of this node's descendants, calling action for each one.\n *\n * @param action - Action to be called for each child.\n * @param includeSelf - Whether to call action on this node as well. Defaults to\n *   false.\n * @param childrenFirst - Whether to call action on children before calling it on\n *   parent.\n */\nexport function treeForEachDescendant<T>(\n  tree: Tree<T>,\n  action: (tree: Tree<T>) => void,\n  includeSelf?: boolean,\n  childrenFirst?: boolean\n): void {\n  if (includeSelf && !childrenFirst) {\n    action(tree);\n  }\n\n  treeForEachChild(tree, child => {\n    treeForEachDescendant(child, action, true, childrenFirst);\n  });\n\n  if (includeSelf && childrenFirst) {\n    action(tree);\n  }\n}\n\n/**\n * Calls action on each ancestor node.\n *\n * @param action - Action to be called on each parent; return\n *   true to abort.\n * @param includeSelf - Whether to call action on this node as well.\n * @returns true if the action callback returned true.\n */\nexport function treeForEachAncestor<T>(\n  tree: Tree<T>,\n  action: (tree: Tree<T>) => unknown,\n  includeSelf?: boolean\n): boolean {\n  let node = includeSelf ? tree : tree.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 action - Action to be called for each child.\n */\nexport function treeForEachImmediateDescendantWithValue<T>(\n  tree: Tree<T>,\n  action: (tree: Tree<T>) => void\n): void {\n  treeForEachChild(tree, child => {\n    if (treeGetValue(child) !== undefined) {\n      action(child);\n    } else {\n      treeForEachImmediateDescendantWithValue(child, action);\n    }\n  });\n}\n\n/**\n * @returns The path of this tree node, as a Path.\n */\nexport function treeGetPath<T>(tree: Tree<T>) {\n  return new Path(\n    tree.parent === null\n      ? tree.name\n      : treeGetPath(tree.parent) + '/' + tree.name\n  );\n}\n\n/**\n * Adds or removes this child from its parent based on whether it's empty or not.\n */\nfunction treeUpdateParents<T>(tree: Tree<T>) {\n  if (tree.parent !== null) {\n    treeUpdateChild(tree.parent, tree.name, tree);\n  }\n}\n\n/**\n * Adds or removes the passed child to this tree node, depending on whether it's empty.\n *\n * @param childName - The name of the child to update.\n * @param child - The child to update.\n */\nfunction treeUpdateChild<T>(tree: Tree<T>, childName: string, child: Tree<T>) {\n  const childEmpty = treeIsEmpty(child);\n  const childExists = contains(tree.node.children, childName);\n  if (childEmpty && childExists) {\n    delete tree.node.children[childName];\n    tree.node.childCount--;\n    treeUpdateParents(tree);\n  } else if (!childEmpty && !childExists) {\n    tree.node.children[childName] = child.node;\n    tree.node.childCount++;\n    treeUpdateParents(tree);\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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  errorPrefix as errorPrefixFxn,\n  safeGet,\n  stringLength\n} from '@firebase/util';\n\nimport { RepoInfo } from '../RepoInfo';\n\nimport {\n  Path,\n  pathChild,\n  pathCompare,\n  pathContains,\n  pathGetBack,\n  pathGetFront,\n  pathSlice,\n  ValidationPath,\n  validationPathPop,\n  validationPathPush,\n  validationPathToErrorString\n} from './Path';\nimport { each, isInvalidJSONNumber } from './util';\n\n/**\n * True for invalid Firebase keys\n */\nexport const INVALID_KEY_REGEX_ = /[\\[\\].#$\\/\\u0000-\\u001F\\u007F]/;\n\n/**\n * True for invalid Firebase paths.\n * Allows '/' in paths.\n */\nexport const INVALID_PATH_REGEX_ = /[\\[\\].#$\\u0000-\\u001F\\u007F]/;\n\n/**\n * Maximum number of characters to allow in leaf value\n */\nexport const MAX_LEAF_SIZE_ = 10 * 1024 * 1024;\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\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\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\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 */\nexport const validateFirebaseDataArg = function (\n  fnName: string,\n  value: unknown,\n  path: Path,\n  optional: boolean\n) {\n  if (optional && value === undefined) {\n    return;\n  }\n\n  validateFirebaseData(errorPrefixFxn(fnName, 'value'), value, path);\n};\n\n/**\n * Validate a data object client-side before sending to server.\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(\n      errorPrefix + 'contains undefined ' + validationPathToErrorString(path)\n    );\n  }\n  if (typeof data === 'function') {\n    throw new Error(\n      errorPrefix +\n        'contains a function ' +\n        validationPathToErrorString(path) +\n        ' with contents = ' +\n        data.toString()\n    );\n  }\n  if (isInvalidJSONNumber(data)) {\n    throw new Error(\n      errorPrefix +\n        'contains ' +\n        data.toString() +\n        ' ' +\n        validationPathToErrorString(path)\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        validationPathToErrorString(path) +\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              validationPathToErrorString(path) +\n              '.  Keys must be non-empty strings ' +\n              'and can\\'t contain \".\", \"#\", \"$\", \"/\", \"[\", or \"]\"'\n          );\n        }\n      }\n\n      validationPathPush(path, key);\n      validateFirebaseData(errorPrefix, value, path);\n      validationPathPop(path);\n    });\n\n    if (hasDotValue && hasActualChild) {\n      throw new Error(\n        errorPrefix +\n          ' contains \".value\" child ' +\n          validationPathToErrorString(path) +\n          ' in addition to actual children.'\n      );\n    }\n  }\n};\n\n/**\n * Pre-validate paths passed in the firebase function.\n */\nexport const validateFirebaseMergePaths = function (\n  errorPrefix: string,\n  mergePaths: Path[]\n) {\n  let i, curPath: Path;\n  for (i = 0; i < mergePaths.length; i++) {\n    curPath = mergePaths[i];\n    const keys = pathSlice(curPath);\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(pathCompare);\n  let prevPath: Path | null = null;\n  for (i = 0; i < mergePaths.length; i++) {\n    curPath = mergePaths[i];\n    if (prevPath !== null && pathContains(prevPath, 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 */\nexport const validateFirebaseMergeDataArg = function (\n  fnName: string,\n  data: unknown,\n  path: Path,\n  optional: boolean\n) {\n  if (optional && data === undefined) {\n    return;\n  }\n\n  const errorPrefix = errorPrefixFxn(fnName, 'values');\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, pathChild(path, curPath));\n    if (pathGetBack(curPath) === '.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  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, 'priority') +\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, 'priority') +\n        'must be a valid Firebase priority ' +\n        '(a string, finite number, server value, or null).'\n    );\n  }\n};\n\nexport const validateKey = function (\n  fnName: string,\n  argumentName: string,\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, argumentName) +\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\n/**\n * @internal\n */\nexport const validatePathString = function (\n  fnName: string,\n  argumentName: string,\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, argumentName) +\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  argumentName: string,\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, argumentName, pathString, optional);\n};\n\n/**\n * @internal\n */\nexport const validateWritablePath = function (fnName: string, path: Path) {\n  if (pathGetFront(path) === '.info') {\n    throw new Error(fnName + \" failed = Can't modify data under /.info/\");\n  }\n};\n\nexport const validateUrl = function (\n  fnName: string,\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, 'url') +\n        'must be a valid firebase URL and ' +\n        'the path can\\'t contain \".\", \"#\", \"$\", \"[\", or \"]\".'\n    );\n  }\n};\n\nexport const validateString = function (\n  fnName: string,\n  argumentName: string,\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, argumentName) + 'must be a valid string.'\n    );\n  }\n};\n\nexport const validateObject = function (\n  fnName: string,\n  argumentName: string,\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, argumentName) + 'must be a valid object.'\n    );\n  }\n};\n\nexport const validateObjectContainsKey = function (\n  fnName: string,\n  argumentName: string,\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, argumentName) +\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, argumentName) +\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, argumentName) +\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 LLC\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, pathContains, pathEquals } from '../util/Path';\nimport { exceptionGuard, log, logger } from '../util/util';\n\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 */\nexport class EventQueue {\n  eventLists_: EventList[] = [];\n\n  /**\n   * Tracks recursion depth of raiseQueuedEvents_, for debugging purposes.\n   */\n  recursionDepth_ = 0;\n}\n\n/**\n * @param eventDataList - The new events to queue.\n */\nexport function eventQueueQueueEvents(\n  eventQueue: EventQueue,\n  eventDataList: Event[]\n) {\n  // We group events by path, storing them in a single EventList, to make it easier to skip over them quickly.\n  let currList: EventList | null = null;\n  for (let i = 0; i < eventDataList.length; i++) {\n    const data = eventDataList[i];\n    const path = data.getPath();\n    if (currList !== null && !pathEquals(path, currList.path)) {\n      eventQueue.eventLists_.push(currList);\n      currList = null;\n    }\n\n    if (currList === null) {\n      currList = { events: [], path };\n    }\n\n    currList.events.push(data);\n  }\n  if (currList) {\n    eventQueue.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 - The path to raise events for.\n * @param eventDataList - The new events to raise.\n */\nexport function eventQueueRaiseEventsAtPath(\n  eventQueue: EventQueue,\n  path: Path,\n  eventDataList: Event[]\n) {\n  eventQueueQueueEvents(eventQueue, eventDataList);\n  eventQueueRaiseQueuedEventsMatchingPredicate(eventQueue, eventPath =>\n    pathEquals(eventPath, 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 changedPath - The path to raise events for.\n * @param eventDataList - The events to raise\n */\nexport function eventQueueRaiseEventsForChangedPath(\n  eventQueue: EventQueue,\n  changedPath: Path,\n  eventDataList: Event[]\n) {\n  eventQueueQueueEvents(eventQueue, eventDataList);\n  eventQueueRaiseQueuedEventsMatchingPredicate(\n    eventQueue,\n    eventPath =>\n      pathContains(eventPath, changedPath) ||\n      pathContains(changedPath, eventPath)\n  );\n}\n\nfunction eventQueueRaiseQueuedEventsMatchingPredicate(\n  eventQueue: EventQueue,\n  predicate: (path: Path) => boolean\n) {\n  eventQueue.recursionDepth_++;\n\n  let sentAll = true;\n  for (let i = 0; i < eventQueue.eventLists_.length; i++) {\n    const eventList = eventQueue.eventLists_[i];\n    if (eventList) {\n      const eventPath = eventList.path;\n      if (predicate(eventPath)) {\n        eventListRaise(eventQueue.eventLists_[i]);\n        eventQueue.eventLists_[i] = null;\n      } else {\n        sentAll = false;\n      }\n    }\n  }\n\n  if (sentAll) {\n    eventQueue.eventLists_ = [];\n  }\n\n  eventQueue.recursionDepth_--;\n}\n\ninterface EventList {\n  events: Event[];\n  path: Path;\n}\n\n/**\n * Iterates through the list and raises each event\n */\nfunction eventListRaise(eventList: EventList) {\n  for (let i = 0; i < eventList.events.length; i++) {\n    const eventData = eventList.events[i];\n    if (eventData !== null) {\n      eventList.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 * @license\n * Copyright 2017 Google LLC\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  contains,\n  isEmpty,\n  map,\n  safeGet,\n  stringify\n} from '@firebase/util';\n\nimport { ValueEventRegistration } from '../api/Reference_impl';\n\nimport { AppCheckTokenProvider } from './AppCheckTokenProvider';\nimport { AuthTokenProvider } from './AuthTokenProvider';\nimport { PersistentConnection } from './PersistentConnection';\nimport { ReadonlyRestClient } from './ReadonlyRestClient';\nimport { RepoInfo } from './RepoInfo';\nimport { ServerActions } from './ServerActions';\nimport { ChildrenNode } from './snap/ChildrenNode';\nimport { Node } from './snap/Node';\nimport { nodeFromJSON } from './snap/nodeFromJSON';\nimport { SnapshotHolder } from './SnapshotHolder';\nimport {\n  newSparseSnapshotTree,\n  SparseSnapshotTree,\n  sparseSnapshotTreeForEachTree,\n  sparseSnapshotTreeForget,\n  sparseSnapshotTreeRemember\n} from './SparseSnapshotTree';\nimport { StatsCollection } from './stats/StatsCollection';\nimport { StatsListener } from './stats/StatsListener';\nimport {\n  statsManagerGetCollection,\n  statsManagerGetOrCreateReporter\n} from './stats/StatsManager';\nimport { StatsReporter, statsReporterIncludeStat } from './stats/StatsReporter';\nimport {\n  SyncTree,\n  syncTreeAckUserWrite,\n  syncTreeAddEventRegistration,\n  syncTreeApplyServerMerge,\n  syncTreeApplyServerOverwrite,\n  syncTreeApplyTaggedQueryMerge,\n  syncTreeApplyTaggedQueryOverwrite,\n  syncTreeApplyUserMerge,\n  syncTreeApplyUserOverwrite,\n  syncTreeCalcCompleteEventCache,\n  syncTreeGetServerValue,\n  syncTreeRemoveEventRegistration,\n  syncTreeTagForQuery\n} from './SyncTree';\nimport { Indexable } from './util/misc';\nimport {\n  newEmptyPath,\n  newRelativePath,\n  Path,\n  pathChild,\n  pathGetFront,\n  pathPopFront\n} from './util/Path';\nimport {\n  generateWithValues,\n  resolveDeferredValueSnapshot,\n  resolveDeferredValueTree\n} from './util/ServerValues';\nimport {\n  Tree,\n  treeForEachAncestor,\n  treeForEachChild,\n  treeForEachDescendant,\n  treeGetPath,\n  treeGetValue,\n  treeHasChildren,\n  treeSetValue,\n  treeSubTree\n} from './util/Tree';\nimport {\n  beingCrawled,\n  each,\n  exceptionGuard,\n  log,\n  LUIDGenerator,\n  warn\n} from './util/util';\nimport { isValidPriority, validateFirebaseData } from './util/validation';\nimport { Event } from './view/Event';\nimport {\n  EventQueue,\n  eventQueueQueueEvents,\n  eventQueueRaiseEventsAtPath,\n  eventQueueRaiseEventsForChangedPath\n} from './view/EventQueue';\nimport { EventRegistration, QueryContext } from './view/EventRegistration';\n\nconst INTERRUPT_REASON = 'repo_interrupt';\n\n/**\n * If a transaction does not succeed after 25 retries, we abort it. Among other\n * things this ensure that if there's ever a bug causing a mismatch between\n * client / server hashes for some data, we won't retry indefinitely.\n */\nconst MAX_TRANSACTION_RETRIES = 25;\n\nconst 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\ninterface Transaction {\n  path: Path;\n  update: (a: unknown) => unknown;\n  onComplete: (\n    error: Error | null,\n    committed: boolean,\n    node: Node | null\n  ) => 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 * A connection to a single data repository.\n */\nexport class Repo {\n  /** Key for uniquely identifying this repo, used in RepoManager */\n  readonly key: string;\n\n  dataUpdateCount = 0;\n  infoSyncTree_: SyncTree;\n  serverSyncTree_: SyncTree;\n\n  stats_: StatsCollection;\n  statsListener_: StatsListener | null = null;\n  eventQueue_ = new EventQueue();\n  nextWriteId_ = 1;\n  server_: ServerActions;\n  statsReporter_: StatsReporter;\n  infoData_: SnapshotHolder;\n  interceptServerDataCallback_: ((a: string, b: unknown) => void) | null = null;\n\n  /** A list of data pieces and paths to be set when this client disconnects. */\n  onDisconnect_: SparseSnapshotTree = newSparseSnapshotTree();\n\n  /** Stores queues of outstanding transactions for Firebase locations. */\n  transactionQueueTree_ = new Tree<Transaction[]>();\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    public forceRestClient_: boolean,\n    public authTokenProvider_: AuthTokenProvider,\n    public appCheckProvider_: AppCheckTokenProvider\n  ) {\n    // This key is intentionally not updated if RepoInfo is later changed or replaced\n    this.key = this.repoInfo_.toURLString();\n  }\n\n  /**\n   * @returns 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\nexport function repoStart(\n  repo: Repo,\n  appId: string,\n  authOverride?: object\n): void {\n  repo.stats_ = statsManagerGetCollection(repo.repoInfo_);\n\n  if (repo.forceRestClient_ || beingCrawled()) {\n    repo.server_ = new ReadonlyRestClient(\n      repo.repoInfo_,\n      (\n        pathString: string,\n        data: unknown,\n        isMerge: boolean,\n        tag: number | null\n      ) => {\n        repoOnDataUpdate(repo, pathString, data, isMerge, tag);\n      },\n      repo.authTokenProvider_,\n      repo.appCheckProvider_\n    );\n\n    // Minor hack: Fire onConnect immediately, since there's no actual connection.\n    setTimeout(() => repoOnConnectStatus(repo, /* connectStatus= */ true), 0);\n  } else {\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    repo.persistentConnection_ = new PersistentConnection(\n      repo.repoInfo_,\n      appId,\n      (\n        pathString: string,\n        data: unknown,\n        isMerge: boolean,\n        tag: number | null\n      ) => {\n        repoOnDataUpdate(repo, pathString, data, isMerge, tag);\n      },\n      (connectStatus: boolean) => {\n        repoOnConnectStatus(repo, connectStatus);\n      },\n      (updates: object) => {\n        repoOnServerInfoUpdate(repo, updates);\n      },\n      repo.authTokenProvider_,\n      repo.appCheckProvider_,\n      authOverride\n    );\n\n    repo.server_ = repo.persistentConnection_;\n  }\n\n  repo.authTokenProvider_.addTokenChangeListener(token => {\n    repo.server_.refreshAuthToken(token);\n  });\n\n  repo.appCheckProvider_.addTokenChangeListener(result => {\n    repo.server_.refreshAppCheckToken(result.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  repo.statsReporter_ = statsManagerGetOrCreateReporter(\n    repo.repoInfo_,\n    () => new StatsReporter(repo.stats_, repo.server_)\n  );\n\n  // Used for .info.\n  repo.infoData_ = new SnapshotHolder();\n  repo.infoSyncTree_ = new SyncTree({\n    startListening: (query, tag, currentHashFn, onComplete) => {\n      let infoEvents: Event[] = [];\n      const node = repo.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 = syncTreeApplyServerOverwrite(\n          repo.infoSyncTree_,\n          query._path,\n          node\n        );\n        setTimeout(() => {\n          onComplete('ok');\n        }, 0);\n      }\n      return infoEvents;\n    },\n    stopListening: () => {}\n  });\n  repoUpdateInfo(repo, 'connected', false);\n\n  repo.serverSyncTree_ = new SyncTree({\n    startListening: (query, tag, currentHashFn, onComplete) => {\n      repo.server_.listen(query, currentHashFn, tag, (status, data) => {\n        const events = onComplete(status, data);\n        eventQueueRaiseEventsForChangedPath(\n          repo.eventQueue_,\n          query._path,\n          events\n        );\n      });\n      // No synchronous events for network-backed sync trees\n      return [];\n    },\n    stopListening: (query, tag) => {\n      repo.server_.unlisten(query, tag);\n    }\n  });\n}\n\n/**\n * @returns The time in milliseconds, taking the server offset into account if we have one.\n */\nexport function repoServerTime(repo: Repo): number {\n  const offsetNode = repo.infoData_.getNode(new Path('.info/serverTimeOffset'));\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 */\nexport function repoGenerateServerValues(repo: Repo): Indexable {\n  return generateWithValues({\n    timestamp: repoServerTime(repo)\n  });\n}\n\n/**\n * Called by realtime when we get new messages from the server.\n */\nfunction repoOnDataUpdate(\n  repo: Repo,\n  pathString: string,\n  data: unknown,\n  isMerge: boolean,\n  tag: number | null\n): void {\n  // For testing.\n  repo.dataUpdateCount++;\n  const path = new Path(pathString);\n  data = repo.interceptServerDataCallback_\n    ? repo.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 = syncTreeApplyTaggedQueryMerge(\n        repo.serverSyncTree_,\n        path,\n        taggedChildren,\n        tag\n      );\n    } else {\n      const taggedSnap = nodeFromJSON(data);\n      events = syncTreeApplyTaggedQueryOverwrite(\n        repo.serverSyncTree_,\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 = syncTreeApplyServerMerge(\n      repo.serverSyncTree_,\n      path,\n      changedChildren\n    );\n  } else {\n    const snap = nodeFromJSON(data);\n    events = syncTreeApplyServerOverwrite(repo.serverSyncTree_, 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 = repoRerunTransactions(repo, path);\n  }\n  eventQueueRaiseEventsForChangedPath(repo.eventQueue_, affectedPath, events);\n}\n\n// TODO: This should be @private but it's used by test_access.js and internal.js\nexport function repoInterceptServerData(\n  repo: Repo,\n  callback: ((a: string, b: unknown) => unknown) | null\n): void {\n  repo.interceptServerDataCallback_ = callback;\n}\n\nfunction repoOnConnectStatus(repo: Repo, connectStatus: boolean): void {\n  repoUpdateInfo(repo, 'connected', connectStatus);\n  if (connectStatus === false) {\n    repoRunOnDisconnectEvents(repo);\n  }\n}\n\nfunction repoOnServerInfoUpdate(repo: Repo, updates: object): void {\n  each(updates, (key: string, value: unknown) => {\n    repoUpdateInfo(repo, key, value);\n  });\n}\n\nfunction repoUpdateInfo(repo: Repo, pathString: string, value: unknown): void {\n  const path = new Path('/.info/' + pathString);\n  const newNode = nodeFromJSON(value);\n  repo.infoData_.updateSnapshot(path, newNode);\n  const events = syncTreeApplyServerOverwrite(\n    repo.infoSyncTree_,\n    path,\n    newNode\n  );\n  eventQueueRaiseEventsForChangedPath(repo.eventQueue_, path, events);\n}\n\nfunction repoGetNextWriteId(repo: Repo): number {\n  return repo.nextWriteId_++;\n}\n\n/**\n * The purpose of `getValue` is to return the latest known value\n * satisfying `query`.\n *\n * This method will first check for in-memory cached values\n * belonging to active listeners. If they are found, such values\n * are considered to be the most up-to-date.\n *\n * If the client is not connected, this method will wait until the\n *  repo has established a connection and then request the value for `query`.\n * If the client is not able to retrieve the query result for another reason,\n * it reports an error.\n *\n * @param query - The query to surface a value for.\n */\nexport function repoGetValue(\n  repo: Repo,\n  query: QueryContext,\n  eventRegistration: ValueEventRegistration\n): Promise<Node> {\n  // Only active queries are cached. There is no persisted cache.\n  const cached = syncTreeGetServerValue(repo.serverSyncTree_, query);\n  if (cached != null) {\n    return Promise.resolve(cached);\n  }\n  return repo.server_.get(query).then(\n    payload => {\n      const node = nodeFromJSON(payload).withIndex(\n        query._queryParams.getIndex()\n      );\n      /**\n       * Below we simulate the actions of an `onlyOnce` `onValue()` event where:\n       * Add an event registration,\n       * Update data at the path,\n       * Raise any events,\n       * Cleanup the SyncTree\n       */\n      syncTreeAddEventRegistration(\n        repo.serverSyncTree_,\n        query,\n        eventRegistration,\n        true\n      );\n      let events: Event[];\n      if (query._queryParams.loadsAllData()) {\n        events = syncTreeApplyServerOverwrite(\n          repo.serverSyncTree_,\n          query._path,\n          node\n        );\n      } else {\n        const tag = syncTreeTagForQuery(repo.serverSyncTree_, query);\n        events = syncTreeApplyTaggedQueryOverwrite(\n          repo.serverSyncTree_,\n          query._path,\n          node,\n          tag\n        );\n      }\n      /*\n       * We need to raise events in the scenario where `get()` is called at a parent path, and\n       * while the `get()` is pending, `onValue` is called at a child location. While get() is waiting\n       * for the data, `onValue` will register a new event. Then, get() will come back, and update the syncTree\n       * and its corresponding serverCache, including the child location where `onValue` is called. Then,\n       * `onValue` will receive the event from the server, but look at the syncTree and see that the data received\n       * from the server is already at the SyncPoint, and so the `onValue` callback will never get fired.\n       * Calling `eventQueueRaiseEventsForChangedPath()` is the correct way to propagate the events and\n       * ensure the corresponding child events will get fired.\n       */\n      eventQueueRaiseEventsForChangedPath(\n        repo.eventQueue_,\n        query._path,\n        events\n      );\n      syncTreeRemoveEventRegistration(\n        repo.serverSyncTree_,\n        query,\n        eventRegistration,\n        null,\n        true\n      );\n      return node;\n    },\n    err => {\n      repoLog(repo, 'get for query ' + stringify(query) + ' failed: ' + err);\n      return Promise.reject(new Error(err as string));\n    }\n  );\n}\n\nexport function repoSetWithPriority(\n  repo: Repo,\n  path: Path,\n  newVal: unknown,\n  newPriority: number | string | null,\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  repoLog(repo, '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 = repoGenerateServerValues(repo);\n  const newNodeUnresolved = nodeFromJSON(newVal, newPriority);\n  const existing = syncTreeCalcCompleteEventCache(repo.serverSyncTree_, path);\n  const newNode = resolveDeferredValueSnapshot(\n    newNodeUnresolved,\n    existing,\n    serverValues\n  );\n\n  const writeId = repoGetNextWriteId(repo);\n  const events = syncTreeApplyUserOverwrite(\n    repo.serverSyncTree_,\n    path,\n    newNode,\n    writeId,\n    true\n  );\n  eventQueueQueueEvents(repo.eventQueue_, events);\n  repo.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 = syncTreeAckUserWrite(\n        repo.serverSyncTree_,\n        writeId,\n        !success\n      );\n      eventQueueRaiseEventsForChangedPath(repo.eventQueue_, path, clearEvents);\n      repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n    }\n  );\n  const affectedPath = repoAbortTransactions(repo, path);\n  repoRerunTransactions(repo, affectedPath);\n  // We queued the events above, so just flush the queue here\n  eventQueueRaiseEventsForChangedPath(repo.eventQueue_, affectedPath, []);\n}\n\nexport function repoUpdate(\n  repo: Repo,\n  path: Path,\n  childrenToMerge: { [k: string]: unknown },\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  repoLog(repo, '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 = repoGenerateServerValues(repo);\n  const changedChildren: { [k: string]: Node } = {};\n  each(childrenToMerge, (changedKey: string, changedValue: unknown) => {\n    empty = false;\n    changedChildren[changedKey] = resolveDeferredValueTree(\n      pathChild(path, changedKey),\n      nodeFromJSON(changedValue),\n      repo.serverSyncTree_,\n      serverValues\n    );\n  });\n\n  if (!empty) {\n    const writeId = repoGetNextWriteId(repo);\n    const events = syncTreeApplyUserMerge(\n      repo.serverSyncTree_,\n      path,\n      changedChildren,\n      writeId\n    );\n    eventQueueQueueEvents(repo.eventQueue_, events);\n    repo.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 = syncTreeAckUserWrite(\n          repo.serverSyncTree_,\n          writeId,\n          !success\n        );\n        const affectedPath =\n          clearEvents.length > 0 ? repoRerunTransactions(repo, path) : path;\n        eventQueueRaiseEventsForChangedPath(\n          repo.eventQueue_,\n          affectedPath,\n          clearEvents\n        );\n        repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n      }\n    );\n\n    each(childrenToMerge, (changedPath: string) => {\n      const affectedPath = repoAbortTransactions(\n        repo,\n        pathChild(path, changedPath)\n      );\n      repoRerunTransactions(repo, affectedPath);\n    });\n\n    // We queued the events above, so just flush the queue here\n    eventQueueRaiseEventsForChangedPath(repo.eventQueue_, path, []);\n  } else {\n    log(\"update() called with empty data.  Don't do anything.\");\n    repoCallOnCompleteCallback(repo, onComplete, 'ok', undefined);\n  }\n}\n\n/**\n * Applies all of the changes stored up in the onDisconnect_ tree.\n */\nfunction repoRunOnDisconnectEvents(repo: Repo): void {\n  repoLog(repo, 'onDisconnectEvents');\n\n  const serverValues = repoGenerateServerValues(repo);\n  const resolvedOnDisconnectTree = newSparseSnapshotTree();\n  sparseSnapshotTreeForEachTree(\n    repo.onDisconnect_,\n    newEmptyPath(),\n    (path, node) => {\n      const resolved = resolveDeferredValueTree(\n        path,\n        node,\n        repo.serverSyncTree_,\n        serverValues\n      );\n      sparseSnapshotTreeRemember(resolvedOnDisconnectTree, path, resolved);\n    }\n  );\n  let events: Event[] = [];\n\n  sparseSnapshotTreeForEachTree(\n    resolvedOnDisconnectTree,\n    newEmptyPath(),\n    (path, snap) => {\n      events = events.concat(\n        syncTreeApplyServerOverwrite(repo.serverSyncTree_, path, snap)\n      );\n      const affectedPath = repoAbortTransactions(repo, path);\n      repoRerunTransactions(repo, affectedPath);\n    }\n  );\n\n  repo.onDisconnect_ = newSparseSnapshotTree();\n  eventQueueRaiseEventsForChangedPath(repo.eventQueue_, newEmptyPath(), events);\n}\n\nexport function repoOnDisconnectCancel(\n  repo: Repo,\n  path: Path,\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  repo.server_.onDisconnectCancel(path.toString(), (status, errorReason) => {\n    if (status === 'ok') {\n      sparseSnapshotTreeForget(repo.onDisconnect_, path);\n    }\n    repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n  });\n}\n\nexport function repoOnDisconnectSet(\n  repo: Repo,\n  path: Path,\n  value: unknown,\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  const newNode = nodeFromJSON(value);\n  repo.server_.onDisconnectPut(\n    path.toString(),\n    newNode.val(/*export=*/ true),\n    (status, errorReason) => {\n      if (status === 'ok') {\n        sparseSnapshotTreeRemember(repo.onDisconnect_, path, newNode);\n      }\n      repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n    }\n  );\n}\n\nexport function repoOnDisconnectSetWithPriority(\n  repo: Repo,\n  path: Path,\n  value: unknown,\n  priority: unknown,\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  const newNode = nodeFromJSON(value, priority);\n  repo.server_.onDisconnectPut(\n    path.toString(),\n    newNode.val(/*export=*/ true),\n    (status, errorReason) => {\n      if (status === 'ok') {\n        sparseSnapshotTreeRemember(repo.onDisconnect_, path, newNode);\n      }\n      repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n    }\n  );\n}\n\nexport function repoOnDisconnectUpdate(\n  repo: Repo,\n  path: Path,\n  childrenToMerge: { [k: string]: unknown },\n  onComplete: ((status: Error | null, errorReason?: string) => void) | null\n): void {\n  if (isEmpty(childrenToMerge)) {\n    log(\"onDisconnect().update() called with empty data.  Don't do anything.\");\n    repoCallOnCompleteCallback(repo, onComplete, 'ok', undefined);\n    return;\n  }\n\n  repo.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          sparseSnapshotTreeRemember(\n            repo.onDisconnect_,\n            pathChild(path, childName),\n            newChildNode\n          );\n        });\n      }\n      repoCallOnCompleteCallback(repo, onComplete, status, errorReason);\n    }\n  );\n}\n\nexport function repoAddEventCallbackForQuery(\n  repo: Repo,\n  query: QueryContext,\n  eventRegistration: EventRegistration\n): void {\n  let events;\n  if (pathGetFront(query._path) === '.info') {\n    events = syncTreeAddEventRegistration(\n      repo.infoSyncTree_,\n      query,\n      eventRegistration\n    );\n  } else {\n    events = syncTreeAddEventRegistration(\n      repo.serverSyncTree_,\n      query,\n      eventRegistration\n    );\n  }\n  eventQueueRaiseEventsAtPath(repo.eventQueue_, query._path, events);\n}\n\nexport function repoRemoveEventCallbackForQuery(\n  repo: Repo,\n  query: QueryContext,\n  eventRegistration: EventRegistration\n): void {\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 (pathGetFront(query._path) === '.info') {\n    events = syncTreeRemoveEventRegistration(\n      repo.infoSyncTree_,\n      query,\n      eventRegistration\n    );\n  } else {\n    events = syncTreeRemoveEventRegistration(\n      repo.serverSyncTree_,\n      query,\n      eventRegistration\n    );\n  }\n  eventQueueRaiseEventsAtPath(repo.eventQueue_, query._path, events);\n}\n\nexport function repoInterrupt(repo: Repo): void {\n  if (repo.persistentConnection_) {\n    repo.persistentConnection_.interrupt(INTERRUPT_REASON);\n  }\n}\n\nexport function repoResume(repo: Repo): void {\n  if (repo.persistentConnection_) {\n    repo.persistentConnection_.resume(INTERRUPT_REASON);\n  }\n}\n\nexport function repoStats(repo: Repo, showDelta: boolean = false): void {\n  if (typeof console === 'undefined') {\n    return;\n  }\n\n  let stats: { [k: string]: unknown };\n  if (showDelta) {\n    if (!repo.statsListener_) {\n      repo.statsListener_ = new StatsListener(repo.stats_);\n    }\n    stats = repo.statsListener_.get();\n  } else {\n    stats = repo.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\nexport function repoStatsIncrementCounter(repo: Repo, metric: string): void {\n  repo.stats_.incrementCounter(metric);\n  statsReporterIncludeStat(repo.statsReporter_, metric);\n}\n\nfunction repoLog(repo: Repo, ...varArgs: unknown[]): void {\n  let prefix = '';\n  if (repo.persistentConnection_) {\n    prefix = repo.persistentConnection_.id + ':';\n  }\n  log(prefix, ...varArgs);\n}\n\nexport function repoCallOnCompleteCallback(\n  repo: Repo,\n  callback: ((status: Error | null, errorReason?: string) => void) | null,\n  status: string,\n  errorReason?: string | null\n): void {\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\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/**\n * Creates a new transaction, adds it to the transactions we're tracking, and\n * sends it to the server if possible.\n *\n * @param path - Path at which to do transaction.\n * @param transactionUpdate - Update callback.\n * @param onComplete - Completion callback.\n * @param unwatcher - Function that will be called when the transaction no longer\n * need data updates for `path`.\n * @param applyLocally - Whether or not to make intermediate results visible\n */\nexport function repoStartTransaction(\n  repo: Repo,\n  path: Path,\n  transactionUpdate: (a: unknown) => unknown,\n  onComplete: ((error: Error, committed: boolean, node: Node) => void) | null,\n  unwatcher: () => void,\n  applyLocally: boolean\n): void {\n  repoLog(repo, 'transaction on ' + path);\n\n  // Initialize transaction.\n  const transaction: Transaction = {\n    path,\n    update: transactionUpdate,\n    onComplete,\n    // One of TransactionStatus enums.\n    status: null,\n    // Used when combining transactions at different locations to figure out\n    // which one goes first.\n    order: LUIDGenerator(),\n    // Whether to raise local events for this transaction.\n    applyLocally,\n    // Count of how many times we've retried the transaction.\n    retryCount: 0,\n    // Function to call to clean up our .on() listener.\n    unwatcher,\n    // Stores why a transaction was aborted.\n    abortReason: null,\n    currentWriteId: null,\n    currentInputSnapshot: null,\n    currentOutputSnapshotRaw: null,\n    currentOutputSnapshotResolved: null\n  };\n\n  // Run transaction initially.\n  const currentState = repoGetLatestState(repo, path, undefined);\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      transaction.onComplete(null, false, transaction.currentInputSnapshot);\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 = treeSubTree(repo.transactionQueueTree_, path);\n    const nodeQueue = treeGetValue(queueNode) || [];\n    nodeQueue.push(transaction);\n\n    treeSetValue(queueNode, nodeQueue);\n\n    // Update visibleData and raise events\n    // Note: We intentionally raise events after updating all of our\n    // transaction state, since the user could start new transactions from the\n    // 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        syncTreeCalcCompleteEventCache(repo.serverSyncTree_, path) ||\n        ChildrenNode.EMPTY_NODE;\n      priorityForNode = currentNode.getPriority().val();\n    }\n\n    const serverValues = repoGenerateServerValues(repo);\n    const newNodeUnresolved = nodeFromJSON(newVal, priorityForNode);\n    const newNode = resolveDeferredValueSnapshot(\n      newNodeUnresolved,\n      currentState,\n      serverValues\n    );\n    transaction.currentOutputSnapshotRaw = newNodeUnresolved;\n    transaction.currentOutputSnapshotResolved = newNode;\n    transaction.currentWriteId = repoGetNextWriteId(repo);\n\n    const events = syncTreeApplyUserOverwrite(\n      repo.serverSyncTree_,\n      path,\n      newNode,\n      transaction.currentWriteId,\n      transaction.applyLocally\n    );\n    eventQueueRaiseEventsForChangedPath(repo.eventQueue_, path, events);\n\n    repoSendReadyTransactions(repo, repo.transactionQueueTree_);\n  }\n}\n\n/**\n * @param excludeSets - A specific set to exclude\n */\nfunction repoGetLatestState(\n  repo: Repo,\n  path: Path,\n  excludeSets?: number[]\n): Node {\n  return (\n    syncTreeCalcCompleteEventCache(repo.serverSyncTree_, path, excludeSets) ||\n    ChildrenNode.EMPTY_NODE\n  );\n}\n\n/**\n * Sends any already-run transactions that aren't waiting for outstanding\n * transactions to complete.\n *\n * Externally it's called with no arguments, but it calls itself recursively\n * with a particular transactionQueueTree node to recurse through the tree.\n *\n * @param node - transactionQueueTree node to start at.\n */\nfunction repoSendReadyTransactions(\n  repo: Repo,\n  node: Tree<Transaction[]> = repo.transactionQueueTree_\n): void {\n  // Before recursing, make sure any completed transactions are removed.\n  if (!node) {\n    repoPruneCompletedTransactionsBelowNode(repo, node);\n  }\n\n  if (treeGetValue(node)) {\n    const queue = repoBuildTransactionQueue(repo, 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      repoSendTransactionQueue(repo, treeGetPath(node), queue);\n    }\n  } else if (treeHasChildren(node)) {\n    treeForEachChild(node, childNode => {\n      repoSendReadyTransactions(repo, childNode);\n    });\n  }\n}\n\n/**\n * Given a list of run transactions, send them to the server and then handle\n * the result (success or failure).\n *\n * @param path - The location of the queue.\n * @param queue - Queue of transactions under the specified location.\n */\nfunction repoSendTransactionQueue(\n  repo: Repo,\n  path: Path,\n  queue: Transaction[]\n): void {\n  // Mark transactions as sent and increment retry count!\n  const setsToIgnore = queue.map(txn => {\n    return txn.currentWriteId;\n  });\n  const latestState = repoGetLatestState(repo, 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 = newRelativePath(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  repo.server_.put(\n    pathToSend.toString(),\n    dataToSend,\n    (status: string) => {\n      repoLog(repo, '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\n        // transaction state, since the callback could trigger more\n        // 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            syncTreeAckUserWrite(repo.serverSyncTree_, queue[i].currentWriteId)\n          );\n          if (queue[i].onComplete) {\n            // We never unset the output snapshot, and given that this\n            // transaction is complete, it should be set\n            callbacks.push(() =>\n              queue[i].onComplete(\n                null,\n                true,\n                queue[i].currentOutputSnapshotResolved\n              )\n            );\n          }\n          queue[i].unwatcher();\n        }\n\n        // Now remove the completed transactions.\n        repoPruneCompletedTransactionsBelowNode(\n          repo,\n          treeSubTree(repo.transactionQueueTree_, path)\n        );\n        // There may be pending transactions that we can now send.\n        repoSendReadyTransactions(repo, repo.transactionQueueTree_);\n\n        eventQueueRaiseEventsForChangedPath(repo.eventQueue_, 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        repoRerunTransactions(repo, 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\n * is the path at which events need to be raised for.\n *\n * @param changedPath - The path in mergedData that changed.\n * @returns The rootmost path that was affected by rerunning transactions.\n */\nfunction repoRerunTransactions(repo: Repo, changedPath: Path): Path {\n  const rootMostTransactionNode = repoGetAncestorTransactionNode(\n    repo,\n    changedPath\n  );\n  const path = treeGetPath(rootMostTransactionNode);\n\n  const queue = repoBuildTransactionQueue(repo, rootMostTransactionNode);\n  repoRerunTransactionQueue(repo, queue, path);\n\n  return path;\n}\n\n/**\n * Does all the work of rerunning transactions (as well as cleans up aborted\n * transactions and whatnot).\n *\n * @param queue - The queue of transactions to run.\n * @param path - The path the queue is for.\n */\nfunction repoRerunTransactionQueue(\n  repo: Repo,\n  queue: Transaction[],\n  path: Path\n): void {\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\n  // transaction state, since the callback could trigger more transactions or\n  // 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 = newRelativePath(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        syncTreeAckUserWrite(\n          repo.serverSyncTree_,\n          transaction.currentWriteId,\n          true\n        )\n      );\n    } else if (transaction.status === TransactionStatus.RUN) {\n      if (transaction.retryCount >= MAX_TRANSACTION_RETRIES) {\n        abortTransaction = true;\n        abortReason = 'maxretry';\n        events = events.concat(\n          syncTreeAckUserWrite(\n            repo.serverSyncTree_,\n            transaction.currentWriteId,\n            true\n          )\n        );\n      } else {\n        // This code reruns a transaction\n        const currentNode = repoGetLatestState(\n          repo,\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 = repoGenerateServerValues(repo);\n          const newNodeResolved = resolveDeferredValueSnapshot(\n            newDataNode,\n            currentNode,\n            serverValues\n          );\n\n          transaction.currentOutputSnapshotRaw = newDataNode;\n          transaction.currentOutputSnapshotResolved = newNodeResolved;\n          transaction.currentWriteId = repoGetNextWriteId(repo);\n          // Mutates setsToIgnore in place\n          setsToIgnore.splice(setsToIgnore.indexOf(oldWriteId), 1);\n          events = events.concat(\n            syncTreeApplyUserOverwrite(\n              repo.serverSyncTree_,\n              transaction.path,\n              newNodeResolved,\n              transaction.currentWriteId,\n              transaction.applyLocally\n            )\n          );\n          events = events.concat(\n            syncTreeAckUserWrite(repo.serverSyncTree_, oldWriteId, true)\n          );\n        } else {\n          abortTransaction = true;\n          abortReason = 'nodata';\n          events = events.concat(\n            syncTreeAckUserWrite(\n              repo.serverSyncTree_,\n              transaction.currentWriteId,\n              true\n            )\n          );\n        }\n      }\n    }\n    eventQueueRaiseEventsForChangedPath(repo.eventQueue_, 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\n      // mergedData/visibleData (as it prunes data). So defer the unwatcher\n      // 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          callbacks.push(() =>\n            queue[i].onComplete(null, false, queue[i].currentInputSnapshot)\n          );\n        } else {\n          callbacks.push(() =>\n            queue[i].onComplete(new Error(abortReason), false, null)\n          );\n        }\n      }\n    }\n  }\n\n  // Clean up completed transactions.\n  repoPruneCompletedTransactionsBelowNode(repo, repo.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  repoSendReadyTransactions(repo, repo.transactionQueueTree_);\n}\n\n/**\n * Returns the rootmost ancestor node of the specified path that has a pending\n * transaction on it, or just returns the node for the given path if there are\n * no pending transactions on any ancestor.\n *\n * @param path - The location to start at.\n * @returns The rootmost node with a transaction.\n */\nfunction repoGetAncestorTransactionNode(\n  repo: Repo,\n  path: Path\n): Tree<Transaction[]> {\n  let front;\n\n  // Start at the root and walk deeper into the tree towards path until we\n  // find a node with pending transactions.\n  let transactionNode = repo.transactionQueueTree_;\n  front = pathGetFront(path);\n  while (front !== null && treeGetValue(transactionNode) === undefined) {\n    transactionNode = treeSubTree(transactionNode, front);\n    path = pathPopFront(path);\n    front = pathGetFront(path);\n  }\n\n  return transactionNode;\n}\n\n/**\n * Builds the queue of all transactions at or below the specified\n * transactionNode.\n *\n * @param transactionNode\n * @returns The generated queue.\n */\nfunction repoBuildTransactionQueue(\n  repo: Repo,\n  transactionNode: Tree<Transaction[]>\n): Transaction[] {\n  // Walk any child transaction queues and aggregate them into a single queue.\n  const transactionQueue: Transaction[] = [];\n  repoAggregateTransactionQueuesForNode(\n    repo,\n    transactionNode,\n    transactionQueue\n  );\n\n  // Sort them by the order the transactions were created.\n  transactionQueue.sort((a, b) => a.order - b.order);\n\n  return transactionQueue;\n}\n\nfunction repoAggregateTransactionQueuesForNode(\n  repo: Repo,\n  node: Tree<Transaction[]>,\n  queue: Transaction[]\n): void {\n  const nodeQueue = treeGetValue(node);\n  if (nodeQueue) {\n    for (let i = 0; i < nodeQueue.length; i++) {\n      queue.push(nodeQueue[i]);\n    }\n  }\n\n  treeForEachChild(node, child => {\n    repoAggregateTransactionQueuesForNode(repo, child, queue);\n  });\n}\n\n/**\n * Remove COMPLETED transactions at or below this node in the transactionQueueTree_.\n */\nfunction repoPruneCompletedTransactionsBelowNode(\n  repo: Repo,\n  node: Tree<Transaction[]>\n): void {\n  const queue = treeGetValue(node);\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    treeSetValue(node, queue.length > 0 ? queue : undefined);\n  }\n\n  treeForEachChild(node, childNode => {\n    repoPruneCompletedTransactionsBelowNode(repo, childNode);\n  });\n}\n\n/**\n * Aborts all transactions on ancestors or descendants of the specified path.\n * Called when doing a set() or update() since we consider them incompatible\n * with transactions.\n *\n * @param path - Path for which we want to abort related transactions.\n */\nfunction repoAbortTransactions(repo: Repo, path: Path): Path {\n  const affectedPath = treeGetPath(repoGetAncestorTransactionNode(repo, path));\n\n  const transactionNode = treeSubTree(repo.transactionQueueTree_, path);\n\n  treeForEachAncestor(transactionNode, (node: Tree<Transaction[]>) => {\n    repoAbortTransactionsOnNode(repo, node);\n  });\n\n  repoAbortTransactionsOnNode(repo, transactionNode);\n\n  treeForEachDescendant(transactionNode, (node: Tree<Transaction[]>) => {\n    repoAbortTransactionsOnNode(repo, node);\n  });\n\n  return affectedPath;\n}\n\n/**\n * Abort transactions stored in this transaction queue node.\n *\n * @param node - Node to abort transactions for.\n */\nfunction repoAbortTransactionsOnNode(\n  repo: Repo,\n  node: Tree<Transaction[]>\n): void {\n  const queue = treeGetValue(node);\n  if (queue) {\n    // Queue up the callbacks and fire them after cleaning up all of our\n    // transaction state, since the callback could trigger more transactions\n    // or sets.\n    const callbacks = [];\n\n    // Go through queue.  Any already-sent transactions must be marked for\n    // abort, while the unsent ones 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          syncTreeAckUserWrite(\n            repo.serverSyncTree_,\n            queue[i].currentWriteId,\n            true\n          )\n        );\n        if (queue[i].onComplete) {\n          callbacks.push(\n            queue[i].onComplete.bind(null, new Error('set'), false, null)\n          );\n        }\n      }\n    }\n    if (lastSent === -1) {\n      // We're not waiting for any sent transactions.  We can clear the queue.\n      treeSetValue(node, undefined);\n    } else {\n      // Remove the transactions we aborted.\n      queue.length = lastSent + 1;\n    }\n\n    // Now fire the callbacks.\n    eventQueueRaiseEventsForChangedPath(\n      repo.eventQueue_,\n      treeGetPath(node),\n      events\n    );\n    for (let i = 0; i < callbacks.length; i++) {\n      exceptionGuard(callbacks[i]);\n    }\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 '../../RepoInfo';\nimport { Path } from '../Path';\nimport { warnIfPageIsSecure, warn, fatal } from '../util';\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 * @returns 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\nexport const parseRepoInfo = function (\n  dataURL: string,\n  nodeAdmin: boolean\n): { repoInfo: RepoInfo; path: Path } {\n  const parsedUrl = parseDatabaseURL(dataURL),\n    namespace = parsedUrl.namespace;\n\n  if (parsedUrl.domain === 'firebase.com') {\n    fatal(\n      parsedUrl.host +\n        ' is no longer supported. ' +\n        'Please use <YOUR FIREBASE>.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://<YOUR FIREBASE>.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      nodeAdmin,\n      /*persistenceKey=*/ '',\n      /*includeNamespaceInQueryParams=*/ namespace !== parsedUrl.subdomain\n    ),\n    path: new Path(parsedUrl.pathString)\n  };\n};\n\nexport const parseDatabaseURL = function (dataURL: string): {\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 = host.length;\n    }\n\n    const hostWithoutPort = host.slice(0, colonInd);\n    if (hostWithoutPort.toLowerCase() === 'localhost') {\n      domain = 'localhost';\n    } else if (hostWithoutPort.split('.').length <= 2) {\n      domain = hostWithoutPort;\n    } else {\n      // Interpret the subdomain of a 3 or more component URL as the namespace name.\n      const dotInd = host.indexOf('.');\n      subdomain = host.substring(0, dotInd).toLowerCase();\n      domain = host.substring(dotInd + 1);\n      // Normalize namespaces to lowercase to share storage / connection.\n      namespace = subdomain;\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 LLC\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\nimport {\n  tryParseInt,\n  MAX_NAME,\n  MIN_NAME,\n  INTEGER_32_MIN,\n  INTEGER_32_MAX\n} from '../util/util';\n\n// Modeled after base64 web-safe chars, but ordered by ASCII.\nconst PUSH_CHARS =\n  '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';\n\nconst MIN_PUSH_CHAR = '-';\n\nconst MAX_PUSH_CHAR = 'z';\n\nconst MAX_KEY_LEN = 786;\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  // 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\nexport const successor = function (key: string) {\n  if (key === '' + INTEGER_32_MAX) {\n    // See https://firebase.google.com/docs/database/web/lists-of-data#data-order\n    return MIN_PUSH_CHAR;\n  }\n  const keyAsInt: number = tryParseInt(key);\n  if (keyAsInt != null) {\n    return '' + (keyAsInt + 1);\n  }\n  const next = new Array(key.length);\n\n  for (let i = 0; i < next.length; i++) {\n    next[i] = key.charAt(i);\n  }\n\n  if (next.length < MAX_KEY_LEN) {\n    next.push(MIN_PUSH_CHAR);\n    return next.join('');\n  }\n\n  let i = next.length - 1;\n\n  while (i >= 0 && next[i] === MAX_PUSH_CHAR) {\n    i--;\n  }\n\n  // `successor` was called on the largest possible key, so return the\n  // MAX_NAME, which sorts larger than all keys.\n  if (i === -1) {\n    return MAX_NAME;\n  }\n\n  const source = next[i];\n  const sourcePlusOne = PUSH_CHARS.charAt(PUSH_CHARS.indexOf(source) + 1);\n  next[i] = sourcePlusOne;\n\n  return next.slice(0, i + 1).join('');\n};\n\n// `key` is assumed to be non-empty.\nexport const predecessor = function (key: string) {\n  if (key === '' + INTEGER_32_MIN) {\n    return MIN_NAME;\n  }\n  const keyAsInt: number = tryParseInt(key);\n  if (keyAsInt != null) {\n    return '' + (keyAsInt - 1);\n  }\n  const next = new Array(key.length);\n  for (let i = 0; i < next.length; i++) {\n    next[i] = key.charAt(i);\n  }\n  // If `key` ends in `MIN_PUSH_CHAR`, the largest key lexicographically\n  // smaller than `key`, is `key[0:key.length - 1]`. The next key smaller\n  // than that, `predecessor(predecessor(key))`, is\n  //\n  // `key[0:key.length - 2] + (key[key.length - 1] - 1) + \\\n  //   { MAX_PUSH_CHAR repeated MAX_KEY_LEN - (key.length - 1) times }\n  //\n  // analogous to increment/decrement for base-10 integers.\n  //\n  // This works because lexicographic comparison works character-by-character,\n  // using length as a tie-breaker if one key is a prefix of the other.\n  if (next[next.length - 1] === MIN_PUSH_CHAR) {\n    if (next.length === 1) {\n      // See https://firebase.google.com/docs/database/web/lists-of-data#orderbykey\n      return '' + INTEGER_32_MAX;\n    }\n    delete next[next.length - 1];\n    return next.join('');\n  }\n  // Replace the last character with it's immediate predecessor, and\n  // fill the suffix of the key with MAX_PUSH_CHAR. This is the\n  // lexicographically largest possible key smaller than `key`.\n  next[next.length - 1] = PUSH_CHARS.charAt(\n    PUSH_CHARS.indexOf(next[next.length - 1]) - 1\n  );\n  return next.join('') + MAX_PUSH_CHAR.repeat(MAX_KEY_LEN - next.length);\n};\n","/**\n * @license\n * Copyright 2017 Google LLC\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';\n\nimport { DataSnapshot as ExpDataSnapshot } from '../../api/Reference_impl';\nimport { Path } from '../util/Path';\n\nimport { EventRegistration } from './EventRegistration';\n\n/**\n * Encapsulates the data needed to raise an event\n * @interface\n */\nexport interface Event {\n  getPath(): Path;\n\n  getEventType(): string;\n\n  getEventRunner(): () => void;\n\n  toString(): string;\n}\n\n/**\n * One of the following strings: \"value\", \"child_added\", \"child_changed\",\n * \"child_removed\", or \"child_moved.\"\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 */\nexport class DataEvent implements Event {\n  /**\n   * @param eventType - One of: value, child_added, child_changed, child_moved, child_removed\n   * @param eventRegistration - The function to call to with the event data. User provided\n   * @param snapshot - The data backing the event\n   * @param 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: ExpDataSnapshot,\n    public prevName?: string | null\n  ) {}\n  getPath(): Path {\n    const ref = this.snapshot.ref;\n    if (this.eventType === 'value') {\n      return ref._path;\n    } else {\n      return ref.parent._path;\n    }\n  }\n  getEventType(): string {\n    return this.eventType;\n  }\n  getEventRunner(): () => void {\n    return this.eventRegistration.getEventRunner(this);\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  constructor(\n    public eventRegistration: EventRegistration,\n    public error: Error,\n    public path: Path\n  ) {}\n  getPath(): Path {\n    return this.path;\n  }\n  getEventType(): string {\n    return 'cancel';\n  }\n  getEventRunner(): () => void {\n    return this.eventRegistration.getEventRunner(this);\n  }\n  toString(): string {\n    return this.path.toString() + ':cancel';\n  }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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\nimport { DataSnapshot } from '../../api/Reference_impl';\nimport { Repo } from '../Repo';\nimport { Path } from '../util/Path';\n\nimport { Change } from './Change';\nimport { CancelEvent, Event } from './Event';\nimport { QueryParams } from './QueryParams';\n\n/**\n * A user callback. Callbacks issues from the Legacy SDK maintain references\n * to the original user-issued callbacks, which allows equality\n * comparison by reference even though this callbacks are wrapped before\n * they can be passed to the firebase@exp SDK.\n *\n * @internal\n */\nexport interface UserCallback {\n  (dataSnapshot: DataSnapshot, previousChildName?: string | null): unknown;\n  userCallback?: unknown;\n  context?: object | null;\n}\n\n/**\n * A wrapper class that converts events from the database@exp SDK to the legacy\n * Database SDK. Events are not converted directly as event registration relies\n * on reference comparison of the original user callback (see `matches()`) and\n * relies on equality of the legacy SDK's `context` object.\n */\nexport class CallbackContext {\n  constructor(\n    private readonly snapshotCallback: UserCallback,\n    private readonly cancelCallback?: (error: Error) => unknown\n  ) {}\n\n  onValue(\n    expDataSnapshot: DataSnapshot,\n    previousChildName?: string | null\n  ): void {\n    this.snapshotCallback.call(null, expDataSnapshot, previousChildName);\n  }\n\n  onCancel(error: Error): void {\n    assert(\n      this.hasCancelCallback,\n      'Raising a cancel event on a listener with no cancel callback'\n    );\n    return this.cancelCallback.call(null, error);\n  }\n\n  get hasCancelCallback(): boolean {\n    return !!this.cancelCallback;\n  }\n\n  matches(other: CallbackContext): boolean {\n    return (\n      this.snapshotCallback === other.snapshotCallback ||\n      (this.snapshotCallback.userCallback !== undefined &&\n        this.snapshotCallback.userCallback ===\n          other.snapshotCallback.userCallback &&\n        this.snapshotCallback.context === other.snapshotCallback.context)\n    );\n  }\n}\n\nexport interface QueryContext {\n  readonly _queryIdentifier: string;\n  readonly _queryObject: object;\n  readonly _repo: Repo;\n  readonly _path: Path;\n  readonly _queryParams: QueryParams;\n}\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   */\n  respondsTo(eventType: string): boolean;\n\n  createEvent(change: Change, query: QueryContext): Event;\n\n  /**\n   * Given event data, return a function to trigger the user's callback\n   */\n  getEventRunner(eventData: Event): () => void;\n\n  createCancelEvent(error: Error, path: Path): CancelEvent | null;\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   */\n  hasAnyCallback(): boolean;\n}\n","/**\n * @license\n * Copyright 2021 Google LLC\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 { Deferred } from '@firebase/util';\n\nimport {\n  Repo,\n  repoOnDisconnectCancel,\n  repoOnDisconnectSet,\n  repoOnDisconnectSetWithPriority,\n  repoOnDisconnectUpdate\n} from '../core/Repo';\nimport { Path } from '../core/util/Path';\nimport {\n  validateFirebaseDataArg,\n  validateFirebaseMergeDataArg,\n  validatePriority,\n  validateWritablePath\n} from '../core/util/validation';\n\n/**\n * The `onDisconnect` class allows you to write or clear data when your client\n * disconnects from the Database server. These updates occur whether your\n * client disconnects cleanly or not, so you can rely on them to clean up data\n * even if a connection is dropped or a client crashes.\n *\n * The `onDisconnect` class is most commonly used to manage presence in\n * applications where it is useful to detect how many clients are connected and\n * when other clients disconnect. See\n * {@link https://firebase.google.com/docs/database/web/offline-capabilities | Enabling Offline Capabilities in JavaScript}\n * for more information.\n *\n * To avoid problems when a connection is dropped before the requests can be\n * transferred to the Database server, these functions should be called before\n * writing any data.\n *\n * Note that `onDisconnect` operations are only triggered once. If you want an\n * operation to occur each time a disconnect occurs, you'll need to re-establish\n * the `onDisconnect` operations each time you reconnect.\n */\nexport class OnDisconnect {\n  /** @hideconstructor */\n  constructor(private _repo: Repo, private _path: Path) {}\n\n  /**\n   * Cancels all previously queued `onDisconnect()` set or update events for this\n   * location and all children.\n   *\n   * If a write has been queued for this location via a `set()` or `update()` at a\n   * parent location, the write at this location will be canceled, though writes\n   * to sibling locations will still occur.\n   *\n   * @returns Resolves when synchronization to the server is complete.\n   */\n  cancel(): Promise<void> {\n    const deferred = new Deferred<void>();\n    repoOnDisconnectCancel(\n      this._repo,\n      this._path,\n      deferred.wrapCallback(() => {})\n    );\n    return deferred.promise;\n  }\n\n  /**\n   * Ensures the data at this location is deleted when the client is disconnected\n   * (due to closing the browser, navigating to a new page, or network issues).\n   *\n   * @returns Resolves when synchronization to the server is complete.\n   */\n  remove(): Promise<void> {\n    validateWritablePath('OnDisconnect.remove', this._path);\n    const deferred = new Deferred<void>();\n    repoOnDisconnectSet(\n      this._repo,\n      this._path,\n      null,\n      deferred.wrapCallback(() => {})\n    );\n    return deferred.promise;\n  }\n\n  /**\n   * Ensures the data at this location is set to the specified value when the\n   * client is disconnected (due to closing the browser, navigating to a new page,\n   * or network issues).\n   *\n   * `set()` is especially useful for implementing \"presence\" systems, where a\n   * value should be changed or cleared when a user disconnects so that they\n   * appear \"offline\" to other users. See\n   * {@link https://firebase.google.com/docs/database/web/offline-capabilities | Enabling Offline Capabilities in JavaScript}\n   * for more information.\n   *\n   * Note that `onDisconnect` operations are only triggered once. If you want an\n   * operation to occur each time a disconnect occurs, you'll need to re-establish\n   * the `onDisconnect` operations each time.\n   *\n   * @param value - The value to be written to this location on disconnect (can\n   * be an object, array, string, number, boolean, or null).\n   * @returns Resolves when synchronization to the Database is complete.\n   */\n  set(value: unknown): Promise<void> {\n    validateWritablePath('OnDisconnect.set', this._path);\n    validateFirebaseDataArg('OnDisconnect.set', value, this._path, false);\n    const deferred = new Deferred<void>();\n    repoOnDisconnectSet(\n      this._repo,\n      this._path,\n      value,\n      deferred.wrapCallback(() => {})\n    );\n    return deferred.promise;\n  }\n\n  /**\n   * Ensures the data at this location is set to the specified value and priority\n   * when the client is disconnected (due to closing the browser, navigating to a\n   * new page, or network issues).\n   *\n   * @param value - The value to be written to this location on disconnect (can\n   * be an object, array, string, number, boolean, or null).\n   * @param priority - The priority to be written (string, number, or null).\n   * @returns Resolves when synchronization to the Database is complete.\n   */\n  setWithPriority(\n    value: unknown,\n    priority: number | string | null\n  ): Promise<void> {\n    validateWritablePath('OnDisconnect.setWithPriority', this._path);\n    validateFirebaseDataArg(\n      'OnDisconnect.setWithPriority',\n      value,\n      this._path,\n      false\n    );\n    validatePriority('OnDisconnect.setWithPriority', priority, false);\n\n    const deferred = new Deferred<void>();\n    repoOnDisconnectSetWithPriority(\n      this._repo,\n      this._path,\n      value,\n      priority,\n      deferred.wrapCallback(() => {})\n    );\n    return deferred.promise;\n  }\n\n  /**\n   * Writes multiple values at this location when the client is disconnected (due\n   * to closing the browser, navigating to a new page, or network issues).\n   *\n   * The `values` argument contains multiple property-value pairs that will be\n   * written to the Database together. Each child property can either be a simple\n   * property (for example, \"name\") or a relative path (for example, \"name/first\")\n   * from the current location to the data to update.\n   *\n   * As opposed to the `set()` method, `update()` can be use to selectively update\n   * only the referenced properties at the current location (instead of replacing\n   * all the child properties at the current location).\n   *\n   * @param values - Object containing multiple values.\n   * @returns Resolves when synchronization to the Database is complete.\n   */\n  update(values: object): Promise<void> {\n    validateWritablePath('OnDisconnect.update', this._path);\n    validateFirebaseMergeDataArg(\n      'OnDisconnect.update',\n      values,\n      this._path,\n      false\n    );\n    const deferred = new Deferred<void>();\n    repoOnDisconnectUpdate(\n      this._repo,\n      this._path,\n      values as Record<string, unknown>,\n      deferred.wrapCallback(() => {})\n    );\n    return deferred.promise;\n  }\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\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, getModularInstance, Deferred } from '@firebase/util';\n\nimport {\n  Repo,\n  repoAddEventCallbackForQuery,\n  repoGetValue,\n  repoRemoveEventCallbackForQuery,\n  repoServerTime,\n  repoSetWithPriority,\n  repoUpdate\n} from '../core/Repo';\nimport { ChildrenNode } from '../core/snap/ChildrenNode';\nimport { Index } from '../core/snap/indexes/Index';\nimport { KEY_INDEX } from '../core/snap/indexes/KeyIndex';\nimport { PathIndex } from '../core/snap/indexes/PathIndex';\nimport { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';\nimport { VALUE_INDEX } from '../core/snap/indexes/ValueIndex';\nimport { Node } from '../core/snap/Node';\nimport { syncPointSetReferenceConstructor } from '../core/SyncPoint';\nimport { syncTreeSetReferenceConstructor } from '../core/SyncTree';\nimport { parseRepoInfo } from '../core/util/libs/parser';\nimport { nextPushId } from '../core/util/NextPushId';\nimport {\n  Path,\n  pathEquals,\n  pathGetBack,\n  pathGetFront,\n  pathChild,\n  pathParent,\n  pathToUrlEncodedString,\n  pathIsEmpty\n} from '../core/util/Path';\nimport {\n  fatal,\n  MAX_NAME,\n  MIN_NAME,\n  ObjectToUniqueKey\n} from '../core/util/util';\nimport {\n  isValidPriority,\n  validateFirebaseDataArg,\n  validateFirebaseMergeDataArg,\n  validateKey,\n  validatePathString,\n  validatePriority,\n  validateRootPathString,\n  validateUrl,\n  validateWritablePath\n} from '../core/util/validation';\nimport { Change } from '../core/view/Change';\nimport { CancelEvent, DataEvent, EventType } from '../core/view/Event';\nimport {\n  CallbackContext,\n  EventRegistration,\n  QueryContext,\n  UserCallback\n} from '../core/view/EventRegistration';\nimport {\n  QueryParams,\n  queryParamsEndAt,\n  queryParamsEndBefore,\n  queryParamsGetQueryObject,\n  queryParamsLimitToFirst,\n  queryParamsLimitToLast,\n  queryParamsOrderBy,\n  queryParamsStartAfter,\n  queryParamsStartAt\n} from '../core/view/QueryParams';\n\nimport { Database } from './Database';\nimport { OnDisconnect } from './OnDisconnect';\nimport {\n  ListenOptions,\n  Query as Query,\n  DatabaseReference,\n  Unsubscribe,\n  ThenableReference\n} from './Reference';\n\n/**\n * @internal\n */\nexport class QueryImpl implements Query, QueryContext {\n  /**\n   * @hideconstructor\n   */\n  constructor(\n    readonly _repo: Repo,\n    readonly _path: Path,\n    readonly _queryParams: QueryParams,\n    readonly _orderByCalled: boolean\n  ) {}\n\n  get key(): string | null {\n    if (pathIsEmpty(this._path)) {\n      return null;\n    } else {\n      return pathGetBack(this._path);\n    }\n  }\n\n  get ref(): DatabaseReference {\n    return new ReferenceImpl(this._repo, this._path);\n  }\n\n  get _queryIdentifier(): string {\n    const obj = queryParamsGetQueryObject(this._queryParams);\n    const id = ObjectToUniqueKey(obj);\n    return id === '{}' ? 'default' : id;\n  }\n\n  /**\n   * An object representation of the query parameters used by this Query.\n   */\n  get _queryObject(): object {\n    return queryParamsGetQueryObject(this._queryParams);\n  }\n\n  isEqual(other: QueryImpl | null): boolean {\n    other = getModularInstance(other);\n    if (!(other instanceof QueryImpl)) {\n      return false;\n    }\n\n    const sameRepo = this._repo === other._repo;\n    const samePath = pathEquals(this._path, other._path);\n    const sameQueryIdentifier =\n      this._queryIdentifier === other._queryIdentifier;\n\n    return sameRepo && samePath && sameQueryIdentifier;\n  }\n\n  toJSON(): string {\n    return this.toString();\n  }\n\n  toString(): string {\n    return this._repo.toString() + pathToUrlEncodedString(this._path);\n  }\n}\n\n/**\n * Validates that no other order by call has been made\n */\nfunction validateNoPreviousOrderByCall(query: QueryImpl, fnName: string) {\n  if (query._orderByCalled === true) {\n    throw new Error(fnName + \": You can't combine multiple orderBy calls.\");\n  }\n}\n\n/**\n * Validates start/end values for queries.\n */\nfunction 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(), startAfter(), ' +\n      'endAt(), endBefore(), 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          'startAfter() endAt(), endBefore(), or equalTo() must be a valid priority value ' +\n          '(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(), startAfter(), endAt(), endBefore(), or ' +\n          'equalTo() cannot be an object.'\n      );\n    }\n  }\n}\n\n/**\n * Validates that limit* has been called with the correct combination of parameters\n */\nfunction 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(), startAfter(), endAt(), endBefore(), and limit(). Use \" +\n        'limitToFirst() or limitToLast() instead.'\n    );\n  }\n}\n/**\n * @internal\n */\nexport class ReferenceImpl extends QueryImpl implements DatabaseReference {\n  /** @hideconstructor */\n  constructor(repo: Repo, path: Path) {\n    super(repo, path, new QueryParams(), false);\n  }\n\n  get parent(): ReferenceImpl | null {\n    const parentPath = pathParent(this._path);\n    return parentPath === null\n      ? null\n      : new ReferenceImpl(this._repo, parentPath);\n  }\n\n  get root(): ReferenceImpl {\n    let ref: ReferenceImpl = this;\n    while (ref.parent !== null) {\n      ref = ref.parent;\n    }\n    return ref;\n  }\n}\n\n/**\n * A `DataSnapshot` contains data from a Database location.\n *\n * Any time you read data from the Database, you receive the data as a\n * `DataSnapshot`. A `DataSnapshot` is passed to the event callbacks you attach\n * with `on()` or `once()`. You can extract the contents of the snapshot as a\n * JavaScript object by calling the `val()` method. Alternatively, you can\n * traverse into the snapshot by calling `child()` to return child snapshots\n * (which you could then call `val()` on).\n *\n * A `DataSnapshot` is an efficiently generated, immutable copy of the data at\n * a Database location. It cannot be modified and will never change (to modify\n * data, you always call the `set()` method on a `Reference` directly).\n */\nexport class DataSnapshot {\n  /**\n   * @param _node - A SnapshotNode to wrap.\n   * @param ref - The location this snapshot came from.\n   * @param _index - The iteration order for this snapshot\n   * @hideconstructor\n   */\n  constructor(\n    readonly _node: Node,\n    /**\n     * The location of this DataSnapshot.\n     */\n    readonly ref: DatabaseReference,\n    readonly _index: Index\n  ) {}\n\n  /**\n   * Gets the priority value of the data in this `DataSnapshot`.\n   *\n   * Applications need not use priority but can order collections by\n   * ordinary properties (see\n   * {@link https://firebase.google.com/docs/database/web/lists-of-data#sorting_and_filtering_data |Sorting and filtering data}\n   * ).\n   */\n  get priority(): string | number | null {\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   * The key (last part of the path) of the location of this `DataSnapshot`.\n   *\n   * The last token in a Database location is considered its key. For example,\n   * \"ada\" is the key for the /users/ada/ node. Accessing the key on any\n   * `DataSnapshot` will return the key for the location that generated it.\n   * However, accessing the key on the root URL of a Database will return\n   * `null`.\n   */\n  get key(): string | null {\n    return this.ref.key;\n  }\n\n  /** Returns the number of child properties of this `DataSnapshot`. */\n  get size(): number {\n    return this._node.numChildren();\n  }\n\n  /**\n   * Gets another `DataSnapshot` for the location at the specified relative path.\n   *\n   * Passing a relative path to the `child()` method of a DataSnapshot returns\n   * another `DataSnapshot` for the location at the specified relative path. The\n   * relative path can either be a simple child name (for example, \"ada\") or a\n   * deeper, slash-separated path (for example, \"ada/name/first\"). If the child\n   * location has no data, an empty `DataSnapshot` (that is, a `DataSnapshot`\n   * whose value is `null`) is returned.\n   *\n   * @param path - A relative path to the location of child data.\n   */\n  child(path: string): DataSnapshot {\n    const childPath = new Path(path);\n    const childRef = child(this.ref, path);\n    return new DataSnapshot(\n      this._node.getChild(childPath),\n      childRef,\n      PRIORITY_INDEX\n    );\n  }\n  /**\n   * Returns true if this `DataSnapshot` contains any data. It is slightly more\n   * efficient than using `snapshot.val() !== null`.\n   */\n  exists(): boolean {\n    return !this._node.isEmpty();\n  }\n\n  /**\n   * Exports the entire contents of the DataSnapshot as a JavaScript object.\n   *\n   * The `exportVal()` method is similar to `val()`, except priority information\n   * is included (if available), making it suitable for backing up your data.\n   *\n   * @returns The DataSnapshot's contents as a JavaScript value (Object,\n   *   Array, string, number, boolean, or `null`).\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  exportVal(): any {\n    return this._node.val(true);\n  }\n\n  /**\n   * Enumerates the top-level children in the `IteratedDataSnapshot`.\n   *\n   * Because of the way JavaScript objects work, the ordering of data in the\n   * JavaScript object returned by `val()` is not guaranteed to match the\n   * ordering on the server nor the ordering of `onChildAdded()` events. That is\n   * where `forEach()` comes in handy. It guarantees the children of a\n   * `DataSnapshot` will be iterated in their query order.\n   *\n   * If no explicit `orderBy*()` method is used, results are returned\n   * ordered by key (unless priorities are used, in which case, results are\n   * returned by priority).\n   *\n   * @param action - A function that will be called for each child DataSnapshot.\n   * The callback can return true to cancel further enumeration.\n   * @returns true if enumeration was canceled due to your callback returning\n   * true.\n   */\n  forEach(action: (child: IteratedDataSnapshot) => boolean | void): boolean {\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, child(this.ref, key), PRIORITY_INDEX)\n      );\n    });\n  }\n\n  /**\n   * Returns true if the specified child path has (non-null) data.\n   *\n   * @param path - A relative path to the location of a potential child.\n   * @returns `true` if data exists at the specified child path; else\n   *  `false`.\n   */\n  hasChild(path: string): boolean {\n    const childPath = new Path(path);\n    return !this._node.getChild(childPath).isEmpty();\n  }\n\n  /**\n   * Returns whether or not the `DataSnapshot` has any non-`null` child\n   * properties.\n   *\n   * You can use `hasChildren()` to determine if a `DataSnapshot` has any\n   * children. If it does, you can enumerate them using `forEach()`. If it\n   * doesn't, then either this snapshot contains a primitive value (which can be\n   * retrieved with `val()`) or it is empty (in which case, `val()` will return\n   * `null`).\n   *\n   * @returns true if this snapshot has any children; else false.\n   */\n  hasChildren(): boolean {\n    if (this._node.isLeafNode()) {\n      return false;\n    } else {\n      return !this._node.isEmpty();\n    }\n  }\n\n  /**\n   * Returns a JSON-serializable representation of this object.\n   */\n  toJSON(): object | null {\n    return this.exportVal();\n  }\n\n  /**\n   * Extracts a JavaScript value from a `DataSnapshot`.\n   *\n   * Depending on the data in a `DataSnapshot`, the `val()` method may return a\n   * scalar type (string, number, or boolean), an array, or an object. It may\n   * also return null, indicating that the `DataSnapshot` is empty (contains no\n   * data).\n   *\n   * @returns The DataSnapshot's contents as a JavaScript value (Object,\n   *   Array, string, number, boolean, or `null`).\n   */\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  val(): any {\n    return this._node.val();\n  }\n}\n\n/**\n * Represents a child snapshot of a `Reference` that is being iterated over. The key will never be undefined.\n */\nexport interface IteratedDataSnapshot extends DataSnapshot {\n  key: string; // key of the location of this snapshot.\n}\n\n/**\n *\n * Returns a `Reference` representing the location in the Database\n * corresponding to the provided path. If no path is provided, the `Reference`\n * will point to the root of the Database.\n *\n * @param db - The database instance to obtain a reference for.\n * @param path - Optional path representing the location the returned\n *   `Reference` will point. If not provided, the returned `Reference` will\n *   point to the root of the Database.\n * @returns If a path is provided, a `Reference`\n *   pointing to the provided path. Otherwise, a `Reference` pointing to the\n *   root of the Database.\n */\nexport function ref(db: Database, path?: string): DatabaseReference {\n  db = getModularInstance(db);\n  db._checkNotDeleted('ref');\n  return path !== undefined ? child(db._root, path) : db._root;\n}\n\n/**\n * Returns a `Reference` representing the location in the Database\n * corresponding to the provided Firebase URL.\n *\n * An exception is thrown if the URL is not a valid Firebase Database URL or it\n * has a different domain than the current `Database` instance.\n *\n * Note that all query parameters (`orderBy`, `limitToLast`, etc.) are ignored\n * and are not applied to the returned `Reference`.\n *\n * @param db - The database instance to obtain a reference for.\n * @param url - The Firebase URL at which the returned `Reference` will\n *   point.\n * @returns A `Reference` pointing to the provided\n *   Firebase URL.\n */\nexport function refFromURL(db: Database, url: string): DatabaseReference {\n  db = getModularInstance(db);\n  db._checkNotDeleted('refFromURL');\n  const parsedURL = parseRepoInfo(url, db._repo.repoInfo_.nodeAdmin);\n  validateUrl('refFromURL', parsedURL);\n\n  const repoInfo = parsedURL.repoInfo;\n  if (\n    !db._repo.repoInfo_.isCustomHost() &&\n    repoInfo.host !== db._repo.repoInfo_.host\n  ) {\n    fatal(\n      'refFromURL' +\n        ': Host name does not match the current database: ' +\n        '(found ' +\n        repoInfo.host +\n        ' but expected ' +\n        db._repo.repoInfo_.host +\n        ')'\n    );\n  }\n\n  return ref(db, parsedURL.path.toString());\n}\n/**\n * Gets a `Reference` for the location at the specified relative path.\n *\n * The relative path can either be a simple child name (for example, \"ada\") or\n * a deeper slash-separated path (for example, \"ada/name/first\").\n *\n * @param parent - The parent location.\n * @param path - A relative path from this location to the desired child\n *   location.\n * @returns The specified child location.\n */\nexport function child(\n  parent: DatabaseReference,\n  path: string\n): DatabaseReference {\n  parent = getModularInstance(parent);\n  if (pathGetFront(parent._path) === null) {\n    validateRootPathString('child', 'path', path, false);\n  } else {\n    validatePathString('child', 'path', path, false);\n  }\n  return new ReferenceImpl(parent._repo, pathChild(parent._path, path));\n}\n\n/**\n * Returns an `OnDisconnect` object - see\n * {@link https://firebase.google.com/docs/database/web/offline-capabilities | Enabling Offline Capabilities in JavaScript}\n * for more information on how to use it.\n *\n * @param ref - The reference to add OnDisconnect triggers for.\n */\nexport function onDisconnect(ref: DatabaseReference): OnDisconnect {\n  ref = getModularInstance(ref) as ReferenceImpl;\n  return new OnDisconnect(ref._repo, ref._path);\n}\n\nexport interface ThenableReferenceImpl\n  extends ReferenceImpl,\n    Pick<Promise<ReferenceImpl>, 'then' | 'catch'> {\n  key: string;\n  parent: ReferenceImpl;\n}\n\n/**\n * Generates a new child location using a unique key and returns its\n * `Reference`.\n *\n * This is the most common pattern for adding data to a collection of items.\n *\n * If you provide a value to `push()`, the value is written to the\n * generated location. If you don't pass a value, nothing is written to the\n * database and the child remains empty (but you can use the `Reference`\n * elsewhere).\n *\n * The unique keys generated by `push()` are ordered by the current time, so the\n * resulting list of items is chronologically sorted. The keys are also\n * designed to be unguessable (they contain 72 random bits of entropy).\n *\n * See {@link https://firebase.google.com/docs/database/web/lists-of-data#append_to_a_list_of_data | Append to a list of data}.\n * See {@link https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html | The 2^120 Ways to Ensure Unique Identifiers}.\n *\n * @param parent - The parent location.\n * @param value - Optional value to be written at the generated location.\n * @returns Combined `Promise` and `Reference`; resolves when write is complete,\n * but can be used immediately as the `Reference` to the child location.\n */\nexport function push(\n  parent: DatabaseReference,\n  value?: unknown\n): ThenableReference {\n  parent = getModularInstance(parent);\n  validateWritablePath('push', parent._path);\n  validateFirebaseDataArg('push', value, parent._path, true);\n  const now = repoServerTime(parent._repo);\n  const name = nextPushId(now);\n\n  // push() returns a ThennableReference whose promise is fulfilled with a\n  // regular Reference. We use child() to create handles to two different\n  // references. The first is turned into a ThennableReference below by adding\n  // then() and catch() methods and is used as the return value of push(). The\n  // second remains a regular Reference and is used as the fulfilled value of\n  // the first ThennableReference.\n  const thenablePushRef: Partial<ThenableReferenceImpl> = child(\n    parent,\n    name\n  ) as ReferenceImpl;\n  const pushRef = child(parent, name) as ReferenceImpl;\n\n  let promise: Promise<ReferenceImpl>;\n  if (value != null) {\n    promise = set(pushRef, value).then(() => pushRef);\n  } else {\n    promise = Promise.resolve(pushRef);\n  }\n\n  thenablePushRef.then = promise.then.bind(promise);\n  thenablePushRef.catch = promise.then.bind(promise, undefined);\n  return thenablePushRef as ThenableReferenceImpl;\n}\n\n/**\n * Removes the data at this Database location.\n *\n * Any data at child locations will also be deleted.\n *\n * The effect of the remove will be visible immediately and the corresponding\n * event 'value' will be triggered. Synchronization of the remove to the\n * Firebase servers will also be started, and the returned Promise will resolve\n * when complete. If provided, the onComplete callback will be called\n * asynchronously after synchronization has finished.\n *\n * @param ref - The location to remove.\n * @returns Resolves when remove on server is complete.\n */\nexport function remove(ref: DatabaseReference): Promise<void> {\n  validateWritablePath('remove', ref._path);\n  return set(ref, null);\n}\n\n/**\n * Writes data to this Database location.\n *\n * This will overwrite any data at this location and all child locations.\n *\n * The effect of the write will be visible immediately, and the corresponding\n * events (\"value\", \"child_added\", etc.) will be triggered. Synchronization of\n * the data to the Firebase servers will also be started, and the returned\n * Promise will resolve when complete. If provided, the `onComplete` callback\n * will be called asynchronously after synchronization has finished.\n *\n * Passing `null` for the new value is equivalent to calling `remove()`; namely,\n * all data at this location and all child locations will be deleted.\n *\n * `set()` will remove any priority stored at this location, so if priority is\n * meant to be preserved, you need to use `setWithPriority()` instead.\n *\n * Note that modifying data with `set()` will cancel any pending transactions\n * at that location, so extreme care should be taken if mixing `set()` and\n * `transaction()` to modify the same data.\n *\n * A single `set()` will generate a single \"value\" event at the location where\n * the `set()` was performed.\n *\n * @param ref - The location to write to.\n * @param value - The value to be written (string, number, boolean, object,\n *   array, or null).\n * @returns Resolves when write to server is complete.\n */\nexport function set(ref: DatabaseReference, value: unknown): Promise<void> {\n  ref = getModularInstance(ref);\n  validateWritablePath('set', ref._path);\n  validateFirebaseDataArg('set', value, ref._path, false);\n  const deferred = new Deferred<void>();\n  repoSetWithPriority(\n    ref._repo,\n    ref._path,\n    value,\n    /*priority=*/ null,\n    deferred.wrapCallback(() => {})\n  );\n  return deferred.promise;\n}\n\n/**\n * Sets a priority for the data at this Database location.\n *\n * Applications need not use priority but can order collections by\n * ordinary properties (see\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sorting_and_filtering_data | Sorting and filtering data}\n * ).\n *\n * @param ref - The location to write to.\n * @param priority - The priority to be written (string, number, or null).\n * @returns Resolves when write to server is complete.\n */\nexport function setPriority(\n  ref: DatabaseReference,\n  priority: string | number | null\n): Promise<void> {\n  ref = getModularInstance(ref);\n  validateWritablePath('setPriority', ref._path);\n  validatePriority('setPriority', priority, false);\n  const deferred = new Deferred<void>();\n  repoSetWithPriority(\n    ref._repo,\n    pathChild(ref._path, '.priority'),\n    priority,\n    null,\n    deferred.wrapCallback(() => {})\n  );\n  return deferred.promise;\n}\n\n/**\n * Writes data the Database location. Like `set()` but also specifies the\n * priority for that data.\n *\n * Applications need not use priority but can order collections by\n * ordinary properties (see\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sorting_and_filtering_data | Sorting and filtering data}\n * ).\n *\n * @param ref - The location to write to.\n * @param value - The value to be written (string, number, boolean, object,\n *   array, or null).\n * @param priority - The priority to be written (string, number, or null).\n * @returns Resolves when write to server is complete.\n */\nexport function setWithPriority(\n  ref: DatabaseReference,\n  value: unknown,\n  priority: string | number | null\n): Promise<void> {\n  validateWritablePath('setWithPriority', ref._path);\n  validateFirebaseDataArg('setWithPriority', value, ref._path, false);\n  validatePriority('setWithPriority', priority, false);\n  if (ref.key === '.length' || ref.key === '.keys') {\n    throw 'setWithPriority failed: ' + ref.key + ' is a read-only object.';\n  }\n\n  const deferred = new Deferred<void>();\n  repoSetWithPriority(\n    ref._repo,\n    ref._path,\n    value,\n    priority,\n    deferred.wrapCallback(() => {})\n  );\n  return deferred.promise;\n}\n\n/**\n * Writes multiple values to the Database at once.\n *\n * The `values` argument contains multiple property-value pairs that will be\n * written to the Database together. Each child property can either be a simple\n * property (for example, \"name\") or a relative path (for example,\n * \"name/first\") from the current location to the data to update.\n *\n * As opposed to the `set()` method, `update()` can be use to selectively update\n * only the referenced properties at the current location (instead of replacing\n * all the child properties at the current location).\n *\n * The effect of the write will be visible immediately, and the corresponding\n * events ('value', 'child_added', etc.) will be triggered. Synchronization of\n * the data to the Firebase servers will also be started, and the returned\n * Promise will resolve when complete. If provided, the `onComplete` callback\n * will be called asynchronously after synchronization has finished.\n *\n * A single `update()` will generate a single \"value\" event at the location\n * where the `update()` was performed, regardless of how many children were\n * modified.\n *\n * Note that modifying data with `update()` will cancel any pending\n * transactions at that location, so extreme care should be taken if mixing\n * `update()` and `transaction()` to modify the same data.\n *\n * Passing `null` to `update()` will remove the data at this location.\n *\n * See\n * {@link https://firebase.googleblog.com/2015/09/introducing-multi-location-updates-and_86.html | Introducing multi-location updates and more}.\n *\n * @param ref - The location to write to.\n * @param values - Object containing multiple values.\n * @returns Resolves when update on server is complete.\n */\nexport function update(ref: DatabaseReference, values: object): Promise<void> {\n  validateFirebaseMergeDataArg('update', values, ref._path, false);\n  const deferred = new Deferred<void>();\n  repoUpdate(\n    ref._repo,\n    ref._path,\n    values as Record<string, unknown>,\n    deferred.wrapCallback(() => {})\n  );\n  return deferred.promise;\n}\n\n/**\n * Gets the most up-to-date result for this query.\n *\n * @param query - The query to run.\n * @returns A `Promise` which resolves to the resulting DataSnapshot if a value is\n * available, or rejects if the client is unable to return a value (e.g., if the\n * server is unreachable and there is nothing cached).\n */\nexport function get(query: Query): Promise<DataSnapshot> {\n  query = getModularInstance(query) as QueryImpl;\n  const callbackContext = new CallbackContext(() => {});\n  const container = new ValueEventRegistration(callbackContext);\n  return repoGetValue(query._repo, query, container).then(node => {\n    return new DataSnapshot(\n      node,\n      new ReferenceImpl(query._repo, query._path),\n      query._queryParams.getIndex()\n    );\n  });\n}\n/**\n * Represents registration for 'value' events.\n */\nexport class ValueEventRegistration implements EventRegistration {\n  constructor(private callbackContext: CallbackContext) {}\n\n  respondsTo(eventType: string): boolean {\n    return eventType === 'value';\n  }\n\n  createEvent(change: Change, query: QueryContext): DataEvent {\n    const index = query._queryParams.getIndex();\n    return new DataEvent(\n      'value',\n      this,\n      new DataSnapshot(\n        change.snapshotNode,\n        new ReferenceImpl(query._repo, query._path),\n        index\n      )\n    );\n  }\n\n  getEventRunner(eventData: CancelEvent | DataEvent): () => void {\n    if (eventData.getEventType() === 'cancel') {\n      return () =>\n        this.callbackContext.onCancel((eventData as CancelEvent).error);\n    } else {\n      return () =>\n        this.callbackContext.onValue((eventData as DataEvent).snapshot, null);\n    }\n  }\n\n  createCancelEvent(error: Error, path: Path): CancelEvent | null {\n    if (this.callbackContext.hasCancelCallback) {\n      return new CancelEvent(this, error, path);\n    } else {\n      return null;\n    }\n  }\n\n  matches(other: EventRegistration): boolean {\n    if (!(other instanceof ValueEventRegistration)) {\n      return false;\n    } else if (!other.callbackContext || !this.callbackContext) {\n      // If no callback specified, we consider it to match any callback.\n      return true;\n    } else {\n      return other.callbackContext.matches(this.callbackContext);\n    }\n  }\n\n  hasAnyCallback(): boolean {\n    return this.callbackContext !== null;\n  }\n}\n\n/**\n * Represents the registration of a child_x event.\n */\nexport class ChildEventRegistration implements EventRegistration {\n  constructor(\n    private eventType: string,\n    private callbackContext: CallbackContext | null\n  ) {}\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 this.eventType === eventToCheck;\n  }\n\n  createCancelEvent(error: Error, path: Path): CancelEvent | null {\n    if (this.callbackContext.hasCancelCallback) {\n      return new CancelEvent(this, error, path);\n    } else {\n      return null;\n    }\n  }\n\n  createEvent(change: Change, query: QueryContext): DataEvent {\n    assert(change.childName != null, 'Child events should have a childName.');\n    const childRef = child(\n      new ReferenceImpl(query._repo, query._path),\n      change.childName\n    );\n    const index = query._queryParams.getIndex();\n    return new DataEvent(\n      change.type as EventType,\n      this,\n      new DataSnapshot(change.snapshotNode, childRef, index),\n      change.prevName\n    );\n  }\n\n  getEventRunner(eventData: CancelEvent | DataEvent): () => void {\n    if (eventData.getEventType() === 'cancel') {\n      return () =>\n        this.callbackContext.onCancel((eventData as CancelEvent).error);\n    } else {\n      return () =>\n        this.callbackContext.onValue(\n          (eventData as DataEvent).snapshot,\n          (eventData as DataEvent).prevName\n        );\n    }\n  }\n\n  matches(other: EventRegistration): boolean {\n    if (other instanceof ChildEventRegistration) {\n      return (\n        this.eventType === other.eventType &&\n        (!this.callbackContext ||\n          !other.callbackContext ||\n          this.callbackContext.matches(other.callbackContext))\n      );\n    }\n\n    return false;\n  }\n\n  hasAnyCallback(): boolean {\n    return !!this.callbackContext;\n  }\n}\n\nfunction addEventListener(\n  query: Query,\n  eventType: EventType,\n  callback: UserCallback,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n) {\n  let cancelCallback: ((error: Error) => unknown) | undefined;\n  if (typeof cancelCallbackOrListenOptions === 'object') {\n    cancelCallback = undefined;\n    options = cancelCallbackOrListenOptions;\n  }\n  if (typeof cancelCallbackOrListenOptions === 'function') {\n    cancelCallback = cancelCallbackOrListenOptions;\n  }\n\n  if (options && options.onlyOnce) {\n    const userCallback = callback;\n    const onceCallback: UserCallback = (dataSnapshot, previousChildName) => {\n      repoRemoveEventCallbackForQuery(query._repo, query, container);\n      userCallback(dataSnapshot, previousChildName);\n    };\n    onceCallback.userCallback = callback.userCallback;\n    onceCallback.context = callback.context;\n    callback = onceCallback;\n  }\n\n  const callbackContext = new CallbackContext(\n    callback,\n    cancelCallback || undefined\n  );\n  const container =\n    eventType === 'value'\n      ? new ValueEventRegistration(callbackContext)\n      : new ChildEventRegistration(eventType, callbackContext);\n  repoAddEventCallbackForQuery(query._repo, query, container);\n  return () => repoRemoveEventCallbackForQuery(query._repo, query, container);\n}\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onValue` event will trigger once with the initial data stored at this\n * location, and then trigger again each time the data changes. The\n * `DataSnapshot` passed to the callback will be for the location at which\n * `on()` was called. It won't trigger until the entire contents has been\n * synchronized. If the location has no data, it will be triggered with an empty\n * `DataSnapshot` (`val()` will return `null`).\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs. The\n * callback will be passed a DataSnapshot.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onValue(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallback?: (error: Error) => unknown\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onValue` event will trigger once with the initial data stored at this\n * location, and then trigger again each time the data changes. The\n * `DataSnapshot` passed to the callback will be for the location at which\n * `on()` was called. It won't trigger until the entire contents has been\n * synchronized. If the location has no data, it will be triggered with an empty\n * `DataSnapshot` (`val()` will return `null`).\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs. The\n * callback will be passed a DataSnapshot.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onValue(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onValue` event will trigger once with the initial data stored at this\n * location, and then trigger again each time the data changes. The\n * `DataSnapshot` passed to the callback will be for the location at which\n * `on()` was called. It won't trigger until the entire contents has been\n * synchronized. If the location has no data, it will be triggered with an empty\n * `DataSnapshot` (`val()` will return `null`).\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs. The\n * callback will be passed a DataSnapshot.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onValue(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallback: (error: Error) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\nexport function onValue(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n): Unsubscribe {\n  return addEventListener(\n    query,\n    'value',\n    callback,\n    cancelCallbackOrListenOptions,\n    options\n  );\n}\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildAdded` event will be triggered once for each initial child at this\n * location, and it will be triggered again every time a new child is added. The\n * `DataSnapshot` passed into the callback will reflect the data for the\n * relevant child. For ordering purposes, it is passed a second argument which\n * is a string containing the key of the previous sibling child by sort order,\n * or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildAdded(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName?: string | null\n  ) => unknown,\n  cancelCallback?: (error: Error) => unknown\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildAdded` event will be triggered once for each initial child at this\n * location, and it will be triggered again every time a new child is added. The\n * `DataSnapshot` passed into the callback will reflect the data for the\n * relevant child. For ordering purposes, it is passed a second argument which\n * is a string containing the key of the previous sibling child by sort order,\n * or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildAdded(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildAdded` event will be triggered once for each initial child at this\n * location, and it will be triggered again every time a new child is added. The\n * `DataSnapshot` passed into the callback will reflect the data for the\n * relevant child. For ordering purposes, it is passed a second argument which\n * is a string containing the key of the previous sibling child by sort order,\n * or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildAdded(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallback: (error: Error) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\nexport function onChildAdded(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n): Unsubscribe {\n  return addEventListener(\n    query,\n    'child_added',\n    callback,\n    cancelCallbackOrListenOptions,\n    options\n  );\n}\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildChanged` event will be triggered when the data stored in a child\n * (or any of its descendants) changes. Note that a single `child_changed` event\n * may represent multiple changes to the child. The `DataSnapshot` passed to the\n * callback will contain the new child contents. For ordering purposes, the\n * callback is also passed a second argument which is a string containing the\n * key of the previous sibling child by sort order, or `null` if it is the first\n * child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildChanged(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallback?: (error: Error) => unknown\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildChanged` event will be triggered when the data stored in a child\n * (or any of its descendants) changes. Note that a single `child_changed` event\n * may represent multiple changes to the child. The `DataSnapshot` passed to the\n * callback will contain the new child contents. For ordering purposes, the\n * callback is also passed a second argument which is a string containing the\n * key of the previous sibling child by sort order, or `null` if it is the first\n * child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildChanged(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildChanged` event will be triggered when the data stored in a child\n * (or any of its descendants) changes. Note that a single `child_changed` event\n * may represent multiple changes to the child. The `DataSnapshot` passed to the\n * callback will contain the new child contents. For ordering purposes, the\n * callback is also passed a second argument which is a string containing the\n * key of the previous sibling child by sort order, or `null` if it is the first\n * child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildChanged(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallback: (error: Error) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\nexport function onChildChanged(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n): Unsubscribe {\n  return addEventListener(\n    query,\n    'child_changed',\n    callback,\n    cancelCallbackOrListenOptions,\n    options\n  );\n}\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildMoved` event will be triggered when a child's sort order changes\n * such that its position relative to its siblings changes. The `DataSnapshot`\n * passed to the callback will be for the data of the child that has moved. It\n * is also passed a second argument which is a string containing the key of the\n * previous sibling child by sort order, or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildMoved(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallback?: (error: Error) => unknown\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildMoved` event will be triggered when a child's sort order changes\n * such that its position relative to its siblings changes. The `DataSnapshot`\n * passed to the callback will be for the data of the child that has moved. It\n * is also passed a second argument which is a string containing the key of the\n * previous sibling child by sort order, or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildMoved(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildMoved` event will be triggered when a child's sort order changes\n * such that its position relative to its siblings changes. The `DataSnapshot`\n * passed to the callback will be for the data of the child that has moved. It\n * is also passed a second argument which is a string containing the key of the\n * previous sibling child by sort order, or `null` if it is the first child.\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildMoved(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallback: (error: Error) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\nexport function onChildMoved(\n  query: Query,\n  callback: (\n    snapshot: DataSnapshot,\n    previousChildName: string | null\n  ) => unknown,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n): Unsubscribe {\n  return addEventListener(\n    query,\n    'child_moved',\n    callback,\n    cancelCallbackOrListenOptions,\n    options\n  );\n}\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildRemoved` event will be triggered once every time a child is\n * removed. The `DataSnapshot` passed into the callback will be the old data for\n * the child that was removed. A child will get removed when either:\n *\n * - a client explicitly calls `remove()` on that child or one of its ancestors\n * - a client calls `set(null)` on that child or one of its ancestors\n * - that child has all of its children removed\n * - there is a query in effect which now filters out the child (because it's\n *   sort order changed or the max limit was hit)\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildRemoved(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallback?: (error: Error) => unknown\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildRemoved` event will be triggered once every time a child is\n * removed. The `DataSnapshot` passed into the callback will be the old data for\n * the child that was removed. A child will get removed when either:\n *\n * - a client explicitly calls `remove()` on that child or one of its ancestors\n * - a client calls `set(null)` on that child or one of its ancestors\n * - that child has all of its children removed\n * - there is a query in effect which now filters out the child (because it's\n *   sort order changed or the max limit was hit)\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildRemoved(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\n/**\n * Listens for data changes at a particular location.\n *\n * This is the primary way to read data from a Database. Your callback\n * will be triggered for the initial data and again whenever the data changes.\n * Invoke the returned unsubscribe callback to stop receiving updates. See\n * {@link https://firebase.google.com/docs/database/web/retrieve-data | Retrieve Data on the Web}\n * for more details.\n *\n * An `onChildRemoved` event will be triggered once every time a child is\n * removed. The `DataSnapshot` passed into the callback will be the old data for\n * the child that was removed. A child will get removed when either:\n *\n * - a client explicitly calls `remove()` on that child or one of its ancestors\n * - a client calls `set(null)` on that child or one of its ancestors\n * - that child has all of its children removed\n * - there is a query in effect which now filters out the child (because it's\n *   sort order changed or the max limit was hit)\n *\n * @param query - The query to run.\n * @param callback - A callback that fires when the specified event occurs.\n * The callback will be passed a DataSnapshot and a string containing the key of\n * the previous child, by sort order, or `null` if it is the first child.\n * @param cancelCallback - An optional callback that will be notified if your\n * event subscription is ever canceled because your client does not have\n * permission to read this data (or it had permission but has now lost it).\n * This callback will be passed an `Error` object indicating why the failure\n * occurred.\n * @param options - An object that can be used to configure `onlyOnce`, which\n * then removes the listener after its first invocation.\n * @returns A function that can be invoked to remove the listener.\n */\nexport function onChildRemoved(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallback: (error: Error) => unknown,\n  options: ListenOptions\n): Unsubscribe;\n\nexport function onChildRemoved(\n  query: Query,\n  callback: (snapshot: DataSnapshot) => unknown,\n  cancelCallbackOrListenOptions?: ((error: Error) => unknown) | ListenOptions,\n  options?: ListenOptions\n): Unsubscribe {\n  return addEventListener(\n    query,\n    'child_removed',\n    callback,\n    cancelCallbackOrListenOptions,\n    options\n  );\n}\n\nexport { EventType };\n\n/**\n * Detaches a callback previously attached with the corresponding `on*()` (`onValue`, `onChildAdded`) listener.\n * Note: This is not the recommended way to remove a listener. Instead, please use the returned callback function from\n * the respective `on*` callbacks.\n *\n * Detach a callback previously attached with `on*()`. Calling `off()` on a parent listener\n * will not automatically remove listeners registered on child nodes, `off()`\n * must also be called on any child listeners to remove the callback.\n *\n * If a callback is not specified, all callbacks for the specified eventType\n * will be removed. Similarly, if no eventType is specified, all callbacks\n * for the `Reference` will be removed.\n *\n * Individual listeners can also be removed by invoking their unsubscribe\n * callbacks.\n *\n * @param query - The query that the listener was registered with.\n * @param eventType - One of the following strings: \"value\", \"child_added\",\n * \"child_changed\", \"child_removed\", or \"child_moved.\" If omitted, all callbacks\n * for the `Reference` will be removed.\n * @param callback - The callback function that was passed to `on()` or\n * `undefined` to remove all callbacks.\n */\nexport function off(\n  query: Query,\n  eventType?: EventType,\n  callback?: (\n    snapshot: DataSnapshot,\n    previousChildName?: string | null\n  ) => unknown\n): void {\n  let container: EventRegistration | null = null;\n  const expCallback = callback ? new CallbackContext(callback) : null;\n  if (eventType === 'value') {\n    container = new ValueEventRegistration(expCallback);\n  } else if (eventType) {\n    container = new ChildEventRegistration(eventType, expCallback);\n  }\n  repoRemoveEventCallbackForQuery(query._repo, query, container);\n}\n\n/** Describes the different query constraints available in this SDK. */\nexport type QueryConstraintType =\n  | 'endAt'\n  | 'endBefore'\n  | 'startAt'\n  | 'startAfter'\n  | 'limitToFirst'\n  | 'limitToLast'\n  | 'orderByChild'\n  | 'orderByKey'\n  | 'orderByPriority'\n  | 'orderByValue'\n  | 'equalTo';\n\n/**\n * A `QueryConstraint` is used to narrow the set of documents returned by a\n * Database query. `QueryConstraint`s are created by invoking {@link endAt},\n * {@link endBefore}, {@link startAt}, {@link startAfter}, {@link\n * limitToFirst}, {@link limitToLast}, {@link orderByChild},\n * {@link orderByChild}, {@link orderByKey} , {@link orderByPriority} ,\n * {@link orderByValue}  or {@link equalTo} and\n * can then be passed to {@link query} to create a new query instance that\n * also contains this `QueryConstraint`.\n */\nexport abstract class QueryConstraint {\n  /** The type of this query constraints */\n  abstract readonly type: QueryConstraintType;\n\n  /**\n   * Takes the provided `Query` and returns a copy of the `Query` with this\n   * `QueryConstraint` applied.\n   */\n  abstract _apply<T>(query: QueryImpl): QueryImpl;\n}\n\nclass QueryEndAtConstraint extends QueryConstraint {\n  readonly type = 'endAt';\n\n  constructor(\n    private readonly _value: number | string | boolean | null,\n    private readonly _key?: string\n  ) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateFirebaseDataArg('endAt', this._value, query._path, true);\n    const newParams = queryParamsEndAt(\n      query._queryParams,\n      this._value,\n      this._key\n    );\n    validateLimit(newParams);\n    validateQueryEndpoints(newParams);\n    if (query._queryParams.hasEnd()) {\n      throw new Error(\n        'endAt: Starting point was already set (by another call to endAt, ' +\n          'endBefore or equalTo).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a `QueryConstraint` with the specified ending point.\n *\n * Using `startAt()`, `startAfter()`, `endBefore()`, `endAt()` and `equalTo()`\n * allows you to choose arbitrary starting and ending points for your queries.\n *\n * The ending point is inclusive, so children with exactly the specified value\n * will be included in the query. The optional key argument can be used to\n * further limit the range of the query. If it is specified, then children that\n * have exactly the specified value must also have a key name less than or equal\n * to the specified key.\n *\n * You can read more about `endAt()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#filtering_data | Filtering data}.\n *\n * @param value - The value to end at. The argument type depends on which\n * `orderBy*()` function was used in this query. Specify a value that matches\n * the `orderBy*()` type. When used in combination with `orderByKey()`, the\n * value must be a string.\n * @param key - The child key to end at, among the children with the previously\n * specified priority. This argument is only allowed if ordering by child,\n * value, or priority.\n */\nexport function endAt(\n  value: number | string | boolean | null,\n  key?: string\n): QueryConstraint {\n  validateKey('endAt', 'key', key, true);\n  return new QueryEndAtConstraint(value, key);\n}\n\nclass QueryEndBeforeConstraint extends QueryConstraint {\n  readonly type = 'endBefore';\n\n  constructor(\n    private readonly _value: number | string | boolean | null,\n    private readonly _key?: string\n  ) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateFirebaseDataArg('endBefore', this._value, query._path, false);\n    const newParams = queryParamsEndBefore(\n      query._queryParams,\n      this._value,\n      this._key\n    );\n    validateLimit(newParams);\n    validateQueryEndpoints(newParams);\n    if (query._queryParams.hasEnd()) {\n      throw new Error(\n        'endBefore: Starting point was already set (by another call to endAt, ' +\n          'endBefore or equalTo).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a `QueryConstraint` with the specified ending point (exclusive).\n *\n * Using `startAt()`, `startAfter()`, `endBefore()`, `endAt()` and `equalTo()`\n * allows you to choose arbitrary starting and ending points for your queries.\n *\n * The ending point is exclusive. If only a value is provided, children\n * with a value less than the specified value will be included in the query.\n * If a key is specified, then children must have a value less than or equal\n * to the specified value and a key name less than the specified key.\n *\n * @param value - The value to end before. The argument type depends on which\n * `orderBy*()` function was used in this query. Specify a value that matches\n * the `orderBy*()` type. When used in combination with `orderByKey()`, the\n * value must be a string.\n * @param key - The child key to end before, among the children with the\n * previously specified priority. This argument is only allowed if ordering by\n * child, value, or priority.\n */\nexport function endBefore(\n  value: number | string | boolean | null,\n  key?: string\n): QueryConstraint {\n  validateKey('endBefore', 'key', key, true);\n  return new QueryEndBeforeConstraint(value, key);\n}\n\nclass QueryStartAtConstraint extends QueryConstraint {\n  readonly type = 'startAt';\n\n  constructor(\n    private readonly _value: number | string | boolean | null,\n    private readonly _key?: string\n  ) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateFirebaseDataArg('startAt', this._value, query._path, true);\n    const newParams = queryParamsStartAt(\n      query._queryParams,\n      this._value,\n      this._key\n    );\n    validateLimit(newParams);\n    validateQueryEndpoints(newParams);\n    if (query._queryParams.hasStart()) {\n      throw new Error(\n        'startAt: Starting point was already set (by another call to startAt, ' +\n          'startBefore or equalTo).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a `QueryConstraint` with the specified starting point.\n *\n * Using `startAt()`, `startAfter()`, `endBefore()`, `endAt()` and `equalTo()`\n * allows you to choose arbitrary starting and ending points for your queries.\n *\n * The starting point is inclusive, so children with exactly the specified value\n * will be included in the query. The optional key argument can be used to\n * further limit the range of the query. If it is specified, then children that\n * have exactly the specified value must also have a key name greater than or\n * equal to the specified key.\n *\n * You can read more about `startAt()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#filtering_data | Filtering data}.\n *\n * @param value - The value to start at. The argument type depends on which\n * `orderBy*()` function was used in this query. Specify a value that matches\n * the `orderBy*()` type. When used in combination with `orderByKey()`, the\n * value must be a string.\n * @param key - The child key to start at. This argument is only allowed if\n * ordering by child, value, or priority.\n */\nexport function startAt(\n  value: number | string | boolean | null = null,\n  key?: string\n): QueryConstraint {\n  validateKey('startAt', 'key', key, true);\n  return new QueryStartAtConstraint(value, key);\n}\n\nclass QueryStartAfterConstraint extends QueryConstraint {\n  readonly type = 'startAfter';\n\n  constructor(\n    private readonly _value: number | string | boolean | null,\n    private readonly _key?: string\n  ) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateFirebaseDataArg('startAfter', this._value, query._path, false);\n    const newParams = queryParamsStartAfter(\n      query._queryParams,\n      this._value,\n      this._key\n    );\n    validateLimit(newParams);\n    validateQueryEndpoints(newParams);\n    if (query._queryParams.hasStart()) {\n      throw new Error(\n        'startAfter: Starting point was already set (by another call to startAt, ' +\n          'startAfter, or equalTo).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a `QueryConstraint` with the specified starting point (exclusive).\n *\n * Using `startAt()`, `startAfter()`, `endBefore()`, `endAt()` and `equalTo()`\n * allows you to choose arbitrary starting and ending points for your queries.\n *\n * The starting point is exclusive. If only a value is provided, children\n * with a value greater than the specified value will be included in the query.\n * If a key is specified, then children must have a value greater than or equal\n * to the specified value and a a key name greater than the specified key.\n *\n * @param value - The value to start after. The argument type depends on which\n * `orderBy*()` function was used in this query. Specify a value that matches\n * the `orderBy*()` type. When used in combination with `orderByKey()`, the\n * value must be a string.\n * @param key - The child key to start after. This argument is only allowed if\n * ordering by child, value, or priority.\n */\nexport function startAfter(\n  value: number | string | boolean | null,\n  key?: string\n): QueryConstraint {\n  validateKey('startAfter', 'key', key, true);\n  return new QueryStartAfterConstraint(value, key);\n}\n\nclass QueryLimitToFirstConstraint extends QueryConstraint {\n  readonly type = 'limitToFirst';\n\n  constructor(private readonly _limit: number) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    if (query._queryParams.hasLimit()) {\n      throw new Error(\n        'limitToFirst: Limit was already set (by another call to limitToFirst ' +\n          'or limitToLast).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      queryParamsLimitToFirst(query._queryParams, this._limit),\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that if limited to the first specific number\n * of children.\n *\n * The `limitToFirst()` method is used to set a maximum number of children to be\n * synced for a given callback. If we set a limit of 100, we will initially only\n * receive up to 100 `child_added` events. If we have fewer than 100 messages\n * stored in our Database, a `child_added` event will fire for each message.\n * However, if we have over 100 messages, we will only receive a `child_added`\n * event for the first 100 ordered messages. As items change, we will receive\n * `child_removed` events for each item that drops out of the active list so\n * that the total number stays at 100.\n *\n * You can read more about `limitToFirst()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#filtering_data | Filtering data}.\n *\n * @param limit - The maximum number of nodes to include in this query.\n */\nexport function limitToFirst(limit: number): QueryConstraint {\n  if (typeof limit !== 'number' || Math.floor(limit) !== limit || limit <= 0) {\n    throw new Error('limitToFirst: First argument must be a positive integer.');\n  }\n  return new QueryLimitToFirstConstraint(limit);\n}\n\nclass QueryLimitToLastConstraint extends QueryConstraint {\n  readonly type = 'limitToLast';\n\n  constructor(private readonly _limit: number) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    if (query._queryParams.hasLimit()) {\n      throw new Error(\n        'limitToLast: Limit was already set (by another call to limitToFirst ' +\n          'or limitToLast).'\n      );\n    }\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      queryParamsLimitToLast(query._queryParams, this._limit),\n      query._orderByCalled\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that is limited to return only the last\n * specified number of children.\n *\n * The `limitToLast()` method is used to set a maximum number of children to be\n * synced for a given callback. If we set a limit of 100, we will initially only\n * receive up to 100 `child_added` events. If we have fewer than 100 messages\n * stored in our Database, a `child_added` event will fire for each message.\n * However, if we have over 100 messages, we will only receive a `child_added`\n * event for the last 100 ordered messages. As items change, we will receive\n * `child_removed` events for each item that drops out of the active list so\n * that the total number stays at 100.\n *\n * You can read more about `limitToLast()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#filtering_data | Filtering data}.\n *\n * @param limit - The maximum number of nodes to include in this query.\n */\nexport function limitToLast(limit: number): QueryConstraint {\n  if (typeof limit !== 'number' || Math.floor(limit) !== limit || limit <= 0) {\n    throw new Error('limitToLast: First argument must be a positive integer.');\n  }\n\n  return new QueryLimitToLastConstraint(limit);\n}\n\nclass QueryOrderByChildConstraint extends QueryConstraint {\n  readonly type = 'orderByChild';\n\n  constructor(private readonly _path: string) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateNoPreviousOrderByCall(query, 'orderByChild');\n    const parsedPath = new Path(this._path);\n    if (pathIsEmpty(parsedPath)) {\n      throw new Error(\n        'orderByChild: cannot pass in empty path. Use orderByValue() instead.'\n      );\n    }\n    const index = new PathIndex(parsedPath);\n    const newParams = queryParamsOrderBy(query._queryParams, index);\n    validateQueryEndpoints(newParams);\n\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      /*orderByCalled=*/ true\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that orders by the specified child key.\n *\n * Queries can only order by one key at a time. Calling `orderByChild()`\n * multiple times on the same query is an error.\n *\n * Firebase queries allow you to order your data by any child key on the fly.\n * However, if you know in advance what your indexes will be, you can define\n * them via the .indexOn rule in your Security Rules for better performance. See\n * the{@link https://firebase.google.com/docs/database/security/indexing-data}\n * rule for more information.\n *\n * You can read more about `orderByChild()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sort_data | Sort data}.\n *\n * @param path - The path to order by.\n */\nexport function orderByChild(path: string): QueryConstraint {\n  if (path === '$key') {\n    throw new Error(\n      'orderByChild: \"$key\" is invalid.  Use orderByKey() instead.'\n    );\n  } else if (path === '$priority') {\n    throw new Error(\n      'orderByChild: \"$priority\" is invalid.  Use orderByPriority() instead.'\n    );\n  } else if (path === '$value') {\n    throw new Error(\n      'orderByChild: \"$value\" is invalid.  Use orderByValue() instead.'\n    );\n  }\n  validatePathString('orderByChild', 'path', path, false);\n  return new QueryOrderByChildConstraint(path);\n}\n\nclass QueryOrderByKeyConstraint extends QueryConstraint {\n  readonly type = 'orderByKey';\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateNoPreviousOrderByCall(query, 'orderByKey');\n    const newParams = queryParamsOrderBy(query._queryParams, KEY_INDEX);\n    validateQueryEndpoints(newParams);\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      /*orderByCalled=*/ true\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that orders by the key.\n *\n * Sorts the results of a query by their (ascending) key values.\n *\n * You can read more about `orderByKey()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sort_data | Sort data}.\n */\nexport function orderByKey(): QueryConstraint {\n  return new QueryOrderByKeyConstraint();\n}\n\nclass QueryOrderByPriorityConstraint extends QueryConstraint {\n  readonly type = 'orderByPriority';\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateNoPreviousOrderByCall(query, 'orderByPriority');\n    const newParams = queryParamsOrderBy(query._queryParams, PRIORITY_INDEX);\n    validateQueryEndpoints(newParams);\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      /*orderByCalled=*/ true\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that orders by priority.\n *\n * Applications need not use priority but can order collections by\n * ordinary properties (see\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sort_data | Sort data}\n * for alternatives to priority.\n */\nexport function orderByPriority(): QueryConstraint {\n  return new QueryOrderByPriorityConstraint();\n}\n\nclass QueryOrderByValueConstraint extends QueryConstraint {\n  readonly type = 'orderByValue';\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateNoPreviousOrderByCall(query, 'orderByValue');\n    const newParams = queryParamsOrderBy(query._queryParams, VALUE_INDEX);\n    validateQueryEndpoints(newParams);\n    return new QueryImpl(\n      query._repo,\n      query._path,\n      newParams,\n      /*orderByCalled=*/ true\n    );\n  }\n}\n\n/**\n * Creates a new `QueryConstraint` that orders by value.\n *\n * If the children of a query are all scalar values (string, number, or\n * boolean), you can order the results by their (ascending) values.\n *\n * You can read more about `orderByValue()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#sort_data | Sort data}.\n */\nexport function orderByValue(): QueryConstraint {\n  return new QueryOrderByValueConstraint();\n}\n\nclass QueryEqualToValueConstraint extends QueryConstraint {\n  readonly type = 'equalTo';\n\n  constructor(\n    private readonly _value: number | string | boolean | null,\n    private readonly _key?: string\n  ) {\n    super();\n  }\n\n  _apply<T>(query: QueryImpl): QueryImpl {\n    validateFirebaseDataArg('equalTo', this._value, query._path, false);\n    if (query._queryParams.hasStart()) {\n      throw new Error(\n        'equalTo: Starting point was already set (by another call to startAt/startAfter or ' +\n          'equalTo).'\n      );\n    }\n    if (query._queryParams.hasEnd()) {\n      throw new Error(\n        'equalTo: Ending point was already set (by another call to endAt/endBefore or ' +\n          'equalTo).'\n      );\n    }\n    return new QueryEndAtConstraint(this._value, this._key)._apply(\n      new QueryStartAtConstraint(this._value, this._key)._apply(query)\n    );\n  }\n}\n\n/**\n * Creates a `QueryConstraint` that includes children that match the specified\n * value.\n *\n * Using `startAt()`, `startAfter()`, `endBefore()`, `endAt()` and `equalTo()`\n * allows you to choose arbitrary starting and ending points for your queries.\n *\n * The optional key argument can be used to further limit the range of the\n * query. If it is specified, then children that have exactly the specified\n * value must also have exactly the specified key as their key name. This can be\n * used to filter result sets with many matches for the same value.\n *\n * You can read more about `equalTo()` in\n * {@link https://firebase.google.com/docs/database/web/lists-of-data#filtering_data | Filtering data}.\n *\n * @param value - The value to match for. The argument type depends on which\n * `orderBy*()` function was used in this query. Specify a value that matches\n * the `orderBy*()` type. When used in combination with `orderByKey()`, the\n * value must be a string.\n * @param key - The child key to start at, among the children with the\n * previously specified priority. This argument is only allowed if ordering by\n * child, value, or priority.\n */\nexport function equalTo(\n  value: number | string | boolean | null,\n  key?: string\n): QueryConstraint {\n  validateKey('equalTo', 'key', key, true);\n  return new QueryEqualToValueConstraint(value, key);\n}\n\n/**\n * Creates a new immutable instance of `Query` that is extended to also include\n * additional query constraints.\n *\n * @param query - The Query instance to use as a base for the new constraints.\n * @param queryConstraints - The list of `QueryConstraint`s to apply.\n * @throws if any of the provided query constraints cannot be combined with the\n * existing or new constraints.\n */\nexport function query(\n  query: Query,\n  ...queryConstraints: QueryConstraint[]\n): Query {\n  let queryImpl = getModularInstance(query) as QueryImpl;\n  for (const constraint of queryConstraints) {\n    queryImpl = constraint._apply(queryImpl);\n  }\n  return queryImpl;\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 */\nsyncPointSetReferenceConstructor(ReferenceImpl);\nsyncTreeSetReferenceConstructor(ReferenceImpl);\n","/**\n * @license\n * Copyright 2020 Google LLC\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 {\n  _FirebaseService,\n  _getProvider,\n  FirebaseApp,\n  getApp\n} from '@firebase/app';\nimport { AppCheckInternalComponentName } from '@firebase/app-check-interop-types';\nimport { FirebaseAuthInternalName } from '@firebase/auth-interop-types';\nimport { Provider } from '@firebase/component';\nimport {\n  getModularInstance,\n  createMockUserToken,\n  deepEqual,\n  EmulatorMockTokenOptions,\n  getDefaultEmulatorHostnameAndPort\n} from '@firebase/util';\n\nimport { AppCheckTokenProvider } from '../core/AppCheckTokenProvider';\nimport {\n  AuthTokenProvider,\n  EmulatorTokenProvider,\n  FirebaseAuthTokenProvider\n} from '../core/AuthTokenProvider';\nimport { Repo, repoInterrupt, repoResume, repoStart } from '../core/Repo';\nimport { RepoInfo, RepoInfoEmulatorOptions } from '../core/RepoInfo';\nimport { parseRepoInfo } from '../core/util/libs/parser';\nimport { newEmptyPath, pathIsEmpty } from '../core/util/Path';\nimport {\n  warn,\n  fatal,\n  log,\n  enableLogging as enableLoggingImpl\n} from '../core/util/util';\nimport { validateUrl } from '../core/util/validation';\nimport { BrowserPollConnection } from '../realtime/BrowserPollConnection';\nimport { TransportManager } from '../realtime/TransportManager';\nimport { WebSocketConnection } from '../realtime/WebSocketConnection';\n\nimport { ReferenceImpl } from './Reference_impl';\n\nexport { EmulatorMockTokenOptions } from '@firebase/util';\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\n/**\n * Creates and caches `Repo` instances.\n */\nconst repos: {\n  [appName: string]: {\n    [dbUrl: string]: Repo;\n  };\n} = {};\n\n/**\n * If true, any new `Repo` will be created to use `ReadonlyRestClient` (for testing purposes).\n */\nlet useRestClient = false;\n\n/**\n * Update an existing `Repo` in place to point to a new host/port.\n */\nfunction repoManagerApplyEmulatorSettings(\n  repo: Repo,\n  hostAndPort: string,\n  emulatorOptions: RepoInfoEmulatorOptions,\n  tokenProvider?: AuthTokenProvider\n): void {\n  repo.repoInfo_ = new RepoInfo(\n    hostAndPort,\n    /* secure= */ false,\n    repo.repoInfo_.namespace,\n    repo.repoInfo_.webSocketOnly,\n    repo.repoInfo_.nodeAdmin,\n    repo.repoInfo_.persistenceKey,\n    repo.repoInfo_.includeNamespaceInQueryParams,\n    /*isUsingEmulator=*/ true,\n    emulatorOptions\n  );\n\n  if (tokenProvider) {\n    repo.authTokenProvider_ = tokenProvider;\n  }\n}\n\n/**\n * This function should only ever be called to CREATE a new database instance.\n * @internal\n */\nexport function repoManagerDatabaseFromApp(\n  app: FirebaseApp,\n  authProvider: Provider<FirebaseAuthInternalName>,\n  appCheckProvider?: Provider<AppCheckInternalComponentName>,\n  url?: string,\n  nodeAdmin?: boolean\n): Database {\n  let dbUrl: string | undefined = url || app.options.databaseURL;\n  if (dbUrl === undefined) {\n    if (!app.options.projectId) {\n      fatal(\n        \"Can't determine Firebase Database URL. Be sure to include \" +\n          ' a Project ID when calling firebase.initializeApp().'\n      );\n    }\n\n    log('Using default host for project ', app.options.projectId);\n    dbUrl = `${app.options.projectId}-default-rtdb.firebaseio.com`;\n  }\n\n  let parsedUrl = parseRepoInfo(dbUrl, nodeAdmin);\n  let repoInfo = parsedUrl.repoInfo;\n\n  let isEmulator: boolean;\n\n  let dbEmulatorHost: string | undefined = undefined;\n  if (typeof process !== 'undefined' && process.env) {\n    dbEmulatorHost = process.env[FIREBASE_DATABASE_EMULATOR_HOST_VAR];\n  }\n\n  if (dbEmulatorHost) {\n    isEmulator = true;\n    dbUrl = `http://${dbEmulatorHost}?ns=${repoInfo.namespace}`;\n    parsedUrl = parseRepoInfo(dbUrl, nodeAdmin);\n    repoInfo = parsedUrl.repoInfo;\n  } else {\n    isEmulator = !parsedUrl.repoInfo.secure;\n  }\n\n  const authTokenProvider =\n    nodeAdmin && isEmulator\n      ? new EmulatorTokenProvider(EmulatorTokenProvider.OWNER)\n      : new FirebaseAuthTokenProvider(app.name, app.options, authProvider);\n\n  validateUrl('Invalid Firebase Database URL', parsedUrl);\n  if (!pathIsEmpty(parsedUrl.path)) {\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 = repoManagerCreateRepo(\n    repoInfo,\n    app,\n    authTokenProvider,\n    new AppCheckTokenProvider(app, appCheckProvider)\n  );\n  return new Database(repo, app);\n}\n\n/**\n * Remove the repo and make sure it is disconnected.\n *\n */\nfunction repoManagerDeleteRepo(repo: Repo, appName: string): void {\n  const appRepos = repos[appName];\n  // This should never happen...\n  if (!appRepos || appRepos[repo.key] !== repo) {\n    fatal(`Database ${appName}(${repo.repoInfo_}) has already been deleted.`);\n  }\n  repoInterrupt(repo);\n  delete appRepos[repo.key];\n}\n\n/**\n * Ensures a repo doesn't already exist and then creates one using the\n * provided app.\n *\n * @param repoInfo - The metadata about the Repo\n * @returns The Repo object for the specified server / repoName.\n */\nfunction repoManagerCreateRepo(\n  repoInfo: RepoInfo,\n  app: FirebaseApp,\n  authTokenProvider: AuthTokenProvider,\n  appCheckProvider: AppCheckTokenProvider\n): Repo {\n  let appRepos = repos[app.name];\n\n  if (!appRepos) {\n    appRepos = {};\n    repos[app.name] = appRepos;\n  }\n\n  let repo = 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, useRestClient, authTokenProvider, appCheckProvider);\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 */\nexport function repoManagerForceRestClient(forceRestClient: boolean): void {\n  useRestClient = forceRestClient;\n}\n\n/**\n * Class representing a Firebase Realtime Database.\n */\nexport class Database implements _FirebaseService {\n  /** Represents a `Database` instance. */\n  readonly 'type' = 'database';\n\n  /** Track if the instance has been used (root or repo accessed) */\n  _instanceStarted: boolean = false;\n\n  /** Backing state for root_ */\n  private _rootInternal?: ReferenceImpl;\n\n  /** @hideconstructor */\n  constructor(\n    public _repoInternal: Repo,\n    /** The {@link @firebase/app#FirebaseApp} associated with this Realtime Database instance. */\n    readonly app: FirebaseApp\n  ) {}\n\n  get _repo(): Repo {\n    if (!this._instanceStarted) {\n      repoStart(\n        this._repoInternal,\n        this.app.options.appId,\n        this.app.options['databaseAuthVariableOverride']\n      );\n      this._instanceStarted = true;\n    }\n    return this._repoInternal;\n  }\n\n  get _root(): ReferenceImpl {\n    if (!this._rootInternal) {\n      this._rootInternal = new ReferenceImpl(this._repo, newEmptyPath());\n    }\n    return this._rootInternal;\n  }\n\n  _delete(): Promise<void> {\n    if (this._rootInternal !== null) {\n      repoManagerDeleteRepo(this._repo, this.app.name);\n      this._repoInternal = null;\n      this._rootInternal = null;\n    }\n    return Promise.resolve();\n  }\n\n  _checkNotDeleted(apiName: string) {\n    if (this._rootInternal === null) {\n      fatal('Cannot call ' + apiName + ' on a deleted database.');\n    }\n  }\n}\n\nfunction checkTransportInit() {\n  if (TransportManager.IS_TRANSPORT_INITIALIZED) {\n    warn(\n      'Transport has already been initialized. Please call this function before calling ref or setting up a listener'\n    );\n  }\n}\n\n/**\n * Force the use of websockets instead of longPolling.\n */\nexport function forceWebSockets() {\n  checkTransportInit();\n  BrowserPollConnection.forceDisallow();\n}\n\n/**\n * Force the use of longPolling instead of websockets. This will be ignored if websocket protocol is used in databaseURL.\n */\nexport function forceLongPolling() {\n  checkTransportInit();\n  WebSocketConnection.forceDisallow();\n  BrowserPollConnection.forceAllow();\n}\n\n/**\n * Returns the instance of the Realtime Database SDK that is associated with the provided\n * {@link @firebase/app#FirebaseApp}. Initializes a new instance with default settings if\n * no instance exists or if the existing instance uses a custom database URL.\n *\n * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned Realtime\n * Database instance is associated with.\n * @param url - The URL of the Realtime Database instance to connect to. If not\n * provided, the SDK connects to the default instance of the Firebase App.\n * @returns The `Database` instance of the provided app.\n */\nexport function getDatabase(\n  app: FirebaseApp = getApp(),\n  url?: string\n): Database {\n  const db = _getProvider(app, 'database').getImmediate({\n    identifier: url\n  }) as Database;\n  if (!db._instanceStarted) {\n    const emulator = getDefaultEmulatorHostnameAndPort('database');\n    if (emulator) {\n      connectDatabaseEmulator(db, ...emulator);\n    }\n  }\n  return db;\n}\n\n/**\n * Modify the provided instance to communicate with the Realtime Database\n * emulator.\n *\n * <p>Note: This method must be called before performing any other operation.\n *\n * @param db - The instance to modify.\n * @param host - The emulator host (ex: localhost)\n * @param port - The emulator port (ex: 8080)\n * @param options.mockUserToken - the mock auth token to use for unit testing Security Rules\n */\nexport function connectDatabaseEmulator(\n  db: Database,\n  host: string,\n  port: number,\n  options: {\n    mockUserToken?: EmulatorMockTokenOptions | string;\n  } = {}\n): void {\n  db = getModularInstance(db);\n  db._checkNotDeleted('useEmulator');\n  const hostAndPort = `${host}:${port}`;\n  const repo = db._repoInternal;\n  if (db._instanceStarted) {\n    // If the instance has already been started, then silenty fail if this function is called again\n    // with the same parameters. If the parameters differ then assert.\n    if (\n      hostAndPort === db._repoInternal.repoInfo_.host &&\n      deepEqual(options, repo.repoInfo_.emulatorOptions)\n    ) {\n      return;\n    }\n    fatal(\n      'connectDatabaseEmulator() cannot initialize or alter the emulator configuration after the database instance has started.'\n    );\n  }\n\n  let tokenProvider: EmulatorTokenProvider | undefined = undefined;\n  if (repo.repoInfo_.nodeAdmin) {\n    if (options.mockUserToken) {\n      fatal(\n        'mockUserToken is not supported by the Admin SDK. For client access with mock users, please use the \"firebase\" package instead of \"firebase-admin\".'\n      );\n    }\n    tokenProvider = new EmulatorTokenProvider(EmulatorTokenProvider.OWNER);\n  } else if (options.mockUserToken) {\n    const token =\n      typeof options.mockUserToken === 'string'\n        ? options.mockUserToken\n        : createMockUserToken(options.mockUserToken, db.app.options.projectId);\n    tokenProvider = new EmulatorTokenProvider(token);\n  }\n\n  // Modify the repo to apply emulator settings\n  repoManagerApplyEmulatorSettings(repo, hostAndPort, options, tokenProvider);\n}\n\n/**\n * Disconnects from the server (all Database operations will be completed\n * offline).\n *\n * The client automatically maintains a persistent connection to the Database\n * server, which will remain active indefinitely and reconnect when\n * disconnected. However, the `goOffline()` and `goOnline()` methods may be used\n * to control the client connection in cases where a persistent connection is\n * undesirable.\n *\n * While offline, the client will no longer receive data updates from the\n * Database. However, all Database operations performed locally will continue to\n * immediately fire events, allowing your application to continue behaving\n * normally. Additionally, each operation performed locally will automatically\n * be queued and retried upon reconnection to the Database server.\n *\n * To reconnect to the Database and begin receiving remote events, see\n * `goOnline()`.\n *\n * @param db - The instance to disconnect.\n */\nexport function goOffline(db: Database): void {\n  db = getModularInstance(db);\n  db._checkNotDeleted('goOffline');\n  repoInterrupt(db._repo);\n}\n\n/**\n * Reconnects to the server and synchronizes the offline Database state\n * with the server state.\n *\n * This method should be used after disabling the active connection with\n * `goOffline()`. Once reconnected, the client will transmit the proper data\n * and fire the appropriate events so that your client \"catches up\"\n * automatically.\n *\n * @param db - The instance to reconnect.\n */\nexport function goOnline(db: Database): void {\n  db = getModularInstance(db);\n  db._checkNotDeleted('goOnline');\n  repoResume(db._repo);\n}\n\n/**\n * Logs debugging information to the console.\n *\n * @param enabled - Enables logging if `true`, disables logging if `false`.\n * @param persistent - Remembers the logging state between page refreshes if\n * `true`.\n */\nexport function enableLogging(enabled: boolean, persistent?: boolean);\n\n/**\n * Logs debugging information to the console.\n *\n * @param logger - A custom logger function to control how things get logged.\n */\nexport function enableLogging(logger: (message: string) => unknown);\n\nexport function enableLogging(\n  logger: boolean | ((message: string) => unknown),\n  persistent?: boolean\n): void {\n  enableLoggingImpl(logger, persistent);\n}\n","/**\n * @license\n * Copyright 2021 Google LLC\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 { base64urlEncodeWithoutPadding } from './crypt';\n\n// Firebase Auth tokens contain snake_case claims following the JWT standard / convention.\n/* eslint-disable camelcase */\n\nexport type FirebaseSignInProvider =\n  | 'custom'\n  | 'email'\n  | 'password'\n  | 'phone'\n  | 'anonymous'\n  | 'google.com'\n  | 'facebook.com'\n  | 'github.com'\n  | 'twitter.com'\n  | 'microsoft.com'\n  | 'apple.com';\n\ninterface FirebaseIdToken {\n  // Always set to https://securetoken.google.com/PROJECT_ID\n  iss: string;\n\n  // Always set to PROJECT_ID\n  aud: string;\n\n  // The user's unique ID\n  sub: string;\n\n  // The token issue time, in seconds since epoch\n  iat: number;\n\n  // The token expiry time, normally 'iat' + 3600\n  exp: number;\n\n  // The user's unique ID. Must be equal to 'sub'\n  user_id: string;\n\n  // The time the user authenticated, normally 'iat'\n  auth_time: number;\n\n  // The sign in provider, only set when the provider is 'anonymous'\n  provider_id?: 'anonymous';\n\n  // The user's primary email\n  email?: string;\n\n  // The user's email verification status\n  email_verified?: boolean;\n\n  // The user's primary phone number\n  phone_number?: string;\n\n  // The user's display name\n  name?: string;\n\n  // The user's profile photo URL\n  picture?: string;\n\n  // Information on all identities linked to this user\n  firebase: {\n    // The primary sign-in provider\n    sign_in_provider: FirebaseSignInProvider;\n\n    // A map of providers to the user's list of unique identifiers from\n    // each provider\n    identities?: { [provider in FirebaseSignInProvider]?: string[] };\n  };\n\n  // Custom claims set by the developer\n  [claim: string]: unknown;\n\n  uid?: never; // Try to catch a common mistake of \"uid\" (should be \"sub\" instead).\n}\n\nexport type EmulatorMockTokenOptions = ({ user_id: string } | { sub: string }) &\n  Partial<FirebaseIdToken>;\n\nexport function createMockUserToken(\n  token: EmulatorMockTokenOptions,\n  projectId?: string\n): string {\n  if (token.uid) {\n    throw new Error(\n      'The \"uid\" field is no longer supported by mockUserToken. Please use \"sub\" instead for Firebase Auth User ID.'\n    );\n  }\n  // Unsecured JWTs use \"none\" as the algorithm.\n  const header = {\n    alg: 'none',\n    type: 'JWT'\n  };\n\n  const project = projectId || 'demo-project';\n  const iat = token.iat || 0;\n  const sub = token.sub || token.user_id;\n  if (!sub) {\n    throw new Error(\"mockUserToken must contain 'sub' or 'user_id' field!\");\n  }\n\n  const payload: FirebaseIdToken = {\n    // Set all required fields to decent defaults\n    iss: `https://securetoken.google.com/${project}`,\n    aud: project,\n    iat,\n    exp: iat + 3600,\n    auth_time: iat,\n    sub,\n    user_id: sub,\n    firebase: {\n      sign_in_provider: 'custom',\n      identities: {}\n    },\n\n    // Override with user options\n    ...token\n  };\n\n  // Unsecured JWTs use the empty string as a signature.\n  const signature = '';\n  return [\n    base64urlEncodeWithoutPadding(JSON.stringify(header)),\n    base64urlEncodeWithoutPadding(JSON.stringify(payload)),\n    signature\n  ].join('.');\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\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 SERVER_TIMESTAMP = {\n  '.sv': 'timestamp'\n};\n\n/**\n * Returns a placeholder value for auto-populating the current timestamp (time\n * since the Unix epoch, in milliseconds) as determined by the Firebase\n * servers.\n */\nexport function serverTimestamp(): object {\n  return SERVER_TIMESTAMP;\n}\n\n/**\n * Returns a placeholder value that can be used to atomically increment the\n * current database value by the provided delta.\n *\n * @param delta - the amount to modify the current value atomically.\n * @returns A placeholder value for modifying data atomically server-side.\n */\nexport function increment(delta: number): object {\n  return {\n    '.sv': {\n      'increment': delta\n    }\n  };\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\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 { getModularInstance, Deferred } from '@firebase/util';\n\nimport { repoStartTransaction } from '../core/Repo';\nimport { PRIORITY_INDEX } from '../core/snap/indexes/PriorityIndex';\nimport { Node } from '../core/snap/Node';\nimport { validateWritablePath } from '../core/util/validation';\n\nimport { DatabaseReference } from './Reference';\nimport { DataSnapshot, onValue, ReferenceImpl } from './Reference_impl';\n\n/** An options object to configure transactions. */\nexport interface TransactionOptions {\n  /**\n   * By default, events are raised each time the transaction update function\n   * runs. So if it is run multiple times, you may see intermediate states. You\n   * can set this to false to suppress these intermediate states and instead\n   * wait until the transaction has completed before events are raised.\n   */\n  readonly applyLocally?: boolean;\n}\n\n/**\n * A type for the resolve value of {@link runTransaction}.\n */\nexport class TransactionResult {\n  /** @hideconstructor */\n  constructor(\n    /** Whether the transaction was successfully committed. */\n    readonly committed: boolean,\n    /** The resulting data snapshot. */\n    readonly snapshot: DataSnapshot\n  ) {}\n\n  /** Returns a JSON-serializable representation of this object. */\n  toJSON(): object {\n    return { committed: this.committed, snapshot: this.snapshot.toJSON() };\n  }\n}\n\n/**\n * Atomically modifies the data at this location.\n *\n * Atomically modify the data at this location. Unlike a normal `set()`, which\n * just overwrites the data regardless of its previous value, `runTransaction()` is\n * used to modify the existing value to a new value, ensuring there are no\n * conflicts with other clients writing to the same location at the same time.\n *\n * To accomplish this, you pass `runTransaction()` an update function which is\n * used to transform the current value into a new value. If another client\n * writes to the location before your new value is successfully written, your\n * update function will be called again with the new current value, and the\n * write will be retried. This will happen repeatedly until your write succeeds\n * without conflict or you abort the transaction by not returning a value from\n * your update function.\n *\n * Note: Modifying data with `set()` will cancel any pending transactions at\n * that location, so extreme care should be taken if mixing `set()` and\n * `runTransaction()` to update the same data.\n *\n * Note: When using transactions with Security and Firebase Rules in place, be\n * aware that a client needs `.read` access in addition to `.write` access in\n * order to perform a transaction. This is because the client-side nature of\n * transactions requires the client to read the data in order to transactionally\n * update it.\n *\n * @param ref - The location to atomically modify.\n * @param transactionUpdate - A developer-supplied function which will be passed\n * the current data stored at this location (as a JavaScript object). The\n * function should return the new value it would like written (as a JavaScript\n * object). If `undefined` is returned (i.e. you return with no arguments) the\n * transaction will be aborted and the data at this location will not be\n * modified.\n * @param options - An options object to configure transactions.\n * @returns A `Promise` that can optionally be used instead of the `onComplete`\n * callback to handle success and failure.\n */\nexport function runTransaction(\n  ref: DatabaseReference,\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  transactionUpdate: (currentData: any) => unknown,\n  options?: TransactionOptions\n): Promise<TransactionResult> {\n  ref = getModularInstance(ref);\n\n  validateWritablePath('Reference.transaction', ref._path);\n\n  if (ref.key === '.length' || ref.key === '.keys') {\n    throw (\n      'Reference.transaction failed: ' + ref.key + ' is a read-only object.'\n    );\n  }\n\n  const applyLocally = options?.applyLocally ?? true;\n  const deferred = new Deferred<TransactionResult>();\n\n  const promiseComplete = (\n    error: Error | null,\n    committed: boolean,\n    node: Node | null\n  ) => {\n    let dataSnapshot: DataSnapshot | null = null;\n    if (error) {\n      deferred.reject(error);\n    } else {\n      dataSnapshot = new DataSnapshot(\n        node,\n        new ReferenceImpl(ref._repo, ref._path),\n        PRIORITY_INDEX\n      );\n      deferred.resolve(new TransactionResult(committed, dataSnapshot));\n    }\n  };\n\n  // Add a watch to make sure we get server updates.\n  const unwatcher = onValue(ref, () => {});\n\n  repoStartTransaction(\n    ref._repo,\n    ref._path,\n    transactionUpdate,\n    promiseComplete,\n    unwatcher,\n    applyLocally\n  );\n\n  return deferred.promise;\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\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 { PersistentConnection } from '../core/PersistentConnection';\nimport { RepoInfo } from '../core/RepoInfo';\nimport { Connection } from '../realtime/Connection';\n\nimport { repoManagerForceRestClient } from './Database';\n\nexport const DataConnection = PersistentConnection;\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// 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 * @internal\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\nexport const ConnectionTarget = RepoInfo;\n\n/**\n * Forces the RepoManager to create Repos that use ReadonlyRestClient instead of PersistentConnection.\n * @internal\n */\nexport const forceRestClient = function (forceRestClient: boolean) {\n  repoManagerForceRestClient(forceRestClient);\n};\n","/**\n * @license\n * Copyright 2023 Google LLC\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  FirebaseAppCheckInternal,\n  AppCheckInternalComponentName\n} from '@firebase/app-check-interop-types';\nimport { FirebaseApp } from '@firebase/app-types';\nimport {\n  FirebaseAuthInternal,\n  FirebaseAuthInternalName\n} from '@firebase/auth-interop-types';\nimport {\n  Component,\n  ComponentContainer,\n  ComponentType,\n  Provider\n} from '@firebase/component';\n\nimport { repoManagerDatabaseFromApp } from '../api/Database';\nimport { Database } from '../api.standalone';\nimport { setSDKVersion } from '../core/version';\n\n/**\n * Used by console to create a database based on the app,\n * passed database URL and a custom auth implementation.\n * @internal\n * @param app - A valid FirebaseApp-like object\n * @param url - A valid Firebase databaseURL\n * @param version - custom version e.g. firebase-admin version\n * @param customAppCheckImpl - custom app check implementation\n * @param customAuthImpl - custom auth implementation\n */\nexport function _initStandalone({\n  app,\n  url,\n  version,\n  customAuthImpl,\n  customAppCheckImpl,\n  nodeAdmin = false\n}: {\n  app: FirebaseApp;\n  url: string;\n  version: string;\n  customAuthImpl: FirebaseAuthInternal;\n  customAppCheckImpl?: FirebaseAppCheckInternal;\n  nodeAdmin?: boolean;\n}): Database {\n  setSDKVersion(version);\n\n  /**\n   * ComponentContainer('database-standalone') is just a placeholder that doesn't perform\n   * any actual function.\n   */\n  const componentContainer = new ComponentContainer('database-standalone');\n  const authProvider = new Provider<FirebaseAuthInternalName>(\n    'auth-internal',\n    componentContainer\n  );\n  let appCheckProvider: Provider<AppCheckInternalComponentName>;\n  if (customAppCheckImpl) {\n    appCheckProvider = new Provider<AppCheckInternalComponentName>(\n      'app-check-internal',\n      componentContainer\n    );\n    appCheckProvider.setComponent(\n      new Component(\n        'app-check-internal',\n        () => customAppCheckImpl,\n        ComponentType.PRIVATE\n      )\n    );\n  }\n  authProvider.setComponent(\n    new Component('auth-internal', () => customAuthImpl, ComponentType.PRIVATE)\n  );\n\n  return repoManagerDatabaseFromApp(\n    app,\n    authProvider,\n    appCheckProvider,\n    url,\n    nodeAdmin\n  );\n}\n","/**\n * @license\n * Copyright 2021 Google LLC\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 {\n  _registerComponent,\n  registerVersion,\n  SDK_VERSION\n} from '@firebase/app';\nimport { Component, ComponentType } from '@firebase/component';\n\nimport { name, version } from '../package.json';\nimport { setSDKVersion } from '../src/core/version';\n\nimport { repoManagerDatabaseFromApp } from './api/Database';\n\nexport function registerDatabase(variant?: string): void {\n  setSDKVersion(SDK_VERSION);\n  _registerComponent(\n    new Component(\n      'database',\n      (container, { instanceIdentifier: url }) => {\n        const app = container.getProvider('app').getImmediate()!;\n        const authProvider = container.getProvider('auth-internal');\n        const appCheckProvider = container.getProvider('app-check-internal');\n        return repoManagerDatabaseFromApp(\n          app,\n          authProvider,\n          appCheckProvider,\n          url\n        );\n      },\n      ComponentType.PUBLIC\n    ).setMultipleInstances(true)\n  );\n  registerVersion(name, version, variant);\n  // BUILD_TARGET will be replaced by values like esm2017, cjs2017, etc during the compilation\n  registerVersion(name, version, '__BUILD_TARGET__');\n}\n","/**\n * Firebase Realtime Database\n *\n * @packageDocumentation\n */\n\n/**\n * @license\n * Copyright 2020 Google LLC\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 { Database } from './api/Database';\nimport { registerDatabase } from './register';\n\nexport * from './api';\n\nregisterDatabase();\n\ndeclare module '@firebase/component' {\n  interface NameServiceMapping {\n    'database': Database;\n  }\n}\n"],"names":["CONSTANTS","assert","assertion","message","assertionError","Error","stringToByteArray","str","out","p","i","length","c","charCodeAt","base64","byteToCharMap_","charToByteMap_","byteToCharMapWebSafe_","charToByteMapWebSafe_","ENCODED_VALS_BASE","ENCODED_VALS","this","ENCODED_VALS_WEBSAFE","HAS_NATIVE_SUPPORT","atob","encodeByteArray","input","webSafe","Array","isArray","init_","byteToCharMap","output","byte1","haveByte2","byte2","haveByte3","byte3","outByte1","outByte2","outByte3","outByte4","push","join","encodeString","btoa","decodeString","bytes","pos","c1","String","fromCharCode","c2","u","c3","byteArrayToString","decodeStringToByteArray","charToByteMap","charAt","byte4","DecodeBase64StringError","constructor","name","base64Encode","utf8Bytes","base64urlEncodeWithoutPadding","replace","base64Decode","e","console","error","deepCopy","value","deepExtend","undefined","target","source","Object","Date","getTime","prop","hasOwnProperty","getDefaultsFromGlobal","getGlobal","self","window","global","__FIREBASE_DEFAULTS__","getDefaults","process","env","defaultsJsonString","JSON","parse","getDefaultsFromEnvVariable","document","match","cookie","decoded","getDefaultsFromCookie","info","getDefaultEmulatorHostnameAndPort","productName","host","_a","_b","emulatorHosts","getDefaultEmulatorHost","separatorIndex","lastIndexOf","port","parseInt","substring","Deferred","reject","resolve","promise","Promise","wrapCallback","callback","catch","isMobileCordova","test","getUA","navigator","isNodeSdk","jsonEval","stringify","data","decode","token","header","claims","signature","parts","split","contains","obj","key","prototype","call","safeGet","isEmpty","map","fn","contextObj","res","deepEqual","a","b","aKeys","keys","bKeys","k","includes","aProp","bProp","isObject","thing","Sha1","chain_","buf_","W_","pad_","inbuf_","total_","blockSize","reset","compress_","buf","offset","W","t","f","d","update","lengthMinusBlock","n","inbuf","digest","totalBits","j","errorPrefix","fnName","argName","stringLength","getModularInstance","service","_delegate","Component","instanceFactory","type","multipleInstances","serviceProps","instantiationMode","onInstanceCreated","setInstantiationMode","mode","setMultipleInstances","setServiceProps","props","setInstanceCreatedCallback","DEFAULT_ENTRY_NAME","Provider","container","component","instances","Map","instancesDeferred","instancesOptions","onInitCallbacks","get","identifier","normalizedIdentifier","normalizeInstanceIdentifier","has","deferred","set","isInitialized","shouldAutoInitialize","instance","getOrInitializeService","instanceIdentifier","getImmediate","options","optional","getComponent","setComponent","isComponentEager","instanceDeferred","entries","clearInstance","delete","services","from","values","all","filter","INTERNAL","_delete","isComponentSet","getOptions","initialize","opts","onInit","existingCallbacks","Set","add","existingInstance","invokeOnInitCallbacks","callbacks","ComponentContainer","providers","addComponent","provider","getProvider","addOrOverwriteComponent","getProviders","LogLevel","levelStringToEnum","debug","DEBUG","verbose","VERBOSE","INFO","warn","WARN","ERROR","silent","SILENT","defaultLogLevel","ConsoleMethod","defaultLogHandler","logType","args","logLevel","now","toISOString","method","SDK_VERSION","setSDKVersion","version","DOMStorageWrapper","domStorage_","prefix_","removeItem","prefixedName_","setItem","storedVal","getItem","remove","toString","MemoryStorage","cache_","isInMemoryStorage","createStoragefor","domStorageName","domStorage","PersistentStorage","SessionStorage","logClient","Logger","_logLevel","_logHandler","_userLogHandler","val","TypeError","setLogLevel","logHandler","userLogHandler","log","LUIDGenerator","id","sha1","high","sha1Bytes","buildLogMessage_","varArgs","arg","apply","logger","firstLog_","enableLogging","logger_","persistent","bind","logWrapper","prefix","fatal","isInvalidJSONNumber","Number","POSITIVE_INFINITY","NEGATIVE_INFINITY","MIN_NAME","MAX_NAME","nameCompare","aAsInt","tryParseInt","bAsInt","stringCompare","requireKey","ObjectToUniqueKey","sort","splitStringBySize","segsize","len","dataSegs","each","doubleToIEEE754String","v","bias","s","ln","Infinity","Math","abs","pow","min","floor","LN2","round","bits","reverse","hexByteString","hexByte","substr","toLowerCase","INTEGER_REGEXP_","RegExp","intVal","exceptionGuard","setTimeout","stack","setTimeoutNonBlocking","time","timeout","Deno","unrefTimer","AppCheckTokenProvider","app","appCheckProvider","appName","_isFirebaseServerApp","settings","appCheckToken","serverAppAppCheckToken","appCheck","then","getToken","forceRefresh","addTokenChangeListener","listener","addTokenListener","notifyForInvalidToken","FirebaseAuthTokenProvider","appName_","firebaseOptions_","authProvider_","auth_","auth","code","addAuthTokenListener","removeTokenChangeListener","removeAuthTokenListener","errorMessage","EmulatorTokenProvider","accessToken","OWNER","FORGE_DOMAIN_RE","APP_CHECK_TOKEN_PARAM","WEBSOCKET","LONG_POLLING","RepoInfo","secure","namespace","webSocketOnly","nodeAdmin","persistenceKey","includeNamespaceInQueryParams","isUsingEmulator","emulatorOptions","_host","_domain","indexOf","internalHost","isCacheableHost","isCustomHost","newHost","toURLString","protocol","query","repoInfoConnectionURL","repoInfo","params","connURL","repoInfoNeedsQueryParam","pairs","StatsCollection","counters_","incrementCounter","amount","collections","reporters","statsManagerGetCollection","hashString","PacketReceiver","onMessage_","pendingResponses","currentResponseNum","closeAfterResponse","onClose","closeAfter","responseNum","handleResponse","requestNum","toProcess","FIREBASE_LONGPOLL_START_PARAM","BrowserPollConnection","connId","applicationId","authToken","transportSessionId","lastSessionId","bytesSent","bytesReceived","everConnected_","log_","stats_","urlFn","open","onMessage","onDisconnect","curSegmentNum","onDisconnect_","myPacketOrderer","isClosed_","connectTimeoutTimer_","onClosed_","readyState","called","wrappedFn","body","addEventListener","attachEvent","executeWhenDOMReady","scriptTagHolder","FirebaseIFrameScriptHolder","command","arg1","arg2","arg3","arg4","incrementIncomingBytes_","clearTimeout","password","sendNewPolls","pN","urlParams","random","uniqueCallbackIdentifier","location","hostname","connectURL","addTag","start","startLongPoll","addDisconnectPingFrame","forceAllow","forceAllow_","forceDisallow","forceDisallow_","isAvailable","createElement","href","Windows","UI","markConnectionHealthy","shutdown_","close","myDisconnFrame","removeChild","send","dataStr","base64data","MAX_URL_DATA_SIZE","enqueueSegment","pw","src","style","display","appendChild","commandCB","onMessageCB","outstandingRequests","pendingSegs","currentSerial","myIFrame","createIFrame_","script","domain","iframeContents","doc","write","iframe","contentWindow","contentDocument","alive","textContent","myID","myPW","newRequest_","size","theURL","curDataString","theSeg","shift","seg","ts","addLongPollTag_","segnum","totalsegs","url","serial","doNewRequest","keepaliveTimeout","loadCB","newScript","async","onload","onreadystatechange","rstate","parentNode","onerror","WebSocketImpl","MozWebSocket","WebSocket","WebSocketConnection","keepaliveTimer","frames","totalFrames","connectionURL_","mySock","onopen","onclose","onmessage","m","handleIncomingFrame","isOldAndroid","userAgent","oldAndroidRegex","oldAndroidMatch","parseFloat","previouslyFailed","appendFrame_","fullMess","jsonMess","handleNewFrameCount_","frameCount","extractFrameCount_","isNaN","mess","resetKeepAlive","remainingData","sendString_","clearInterval","setInterval","responsesRequiredToBeHealthy","healthyTimeout","TransportManager","ALL_TRANSPORTS","IS_TRANSPORT_INITIALIZED","globalTransportInitialized_","initTransports_","isWebSocketsAvailable","isSkipPollConnection","transports_","transports","transport","initialTransport","upgradeTransport","Connection","repoInfo_","applicationId_","appCheckToken_","authToken_","onReady_","onKill_","connectionCount","pendingDataMessages","state_","transportManager_","start_","conn","conn_","nextTransportId_","primaryResponsesRequired_","onMessageReceived","connReceiver_","onConnectionLost","disconnReceiver_","tx_","rx_","secondaryConn_","isHealthy_","healthyTimeoutMS","healthyTimeout_","everConnected","onConnectionLost_","onSecondaryConnectionLost_","onPrimaryMessageReceived_","onSecondaryMessageReceived_","sendRequest","dataMsg","msg","sendData_","tryCleanupConnection","onSecondaryControl_","controlData","cmd","upgradeIfSecondaryHealthy_","secondaryResponsesRequired_","parsedData","layer","proceedWithUpgrade_","onControl_","onDataMessage_","onPrimaryResponse_","payload","handshakePayload","assign","h","onHandshake_","onConnectionShutdown_","onReset_","sendPingOnPrimaryIfNecessary_","handshake","timestamp","sessionId","onConnectionEstablished_","tryStartUpgrade_","startUpgrade_","closeConnections_","reason","ServerActions","put","pathString","onComplete","hash","merge","refreshAuthToken","refreshAppCheckToken","onDisconnectPut","onDisconnectMerge","onDisconnectCancel","reportStats","stats","EventEmitter","allowedEvents_","listeners_","trigger","eventType","listeners","context","on","validateEventType_","eventData","getInitialEvent","off","splice","find","et","OnlineMonitor","getInstance","super","online_","currentlyOnline","Path","pathOrString","pieceNum","pieces_","copyTo","pieceNum_","newEmptyPath","pathGetFront","path","pathGetLength","pathPopFront","pathGetBack","pathSlice","begin","slice","pathParent","pieces","pathChild","childPathObj","childPieces","pathIsEmpty","newRelativePath","outerPath","innerPath","outer","inner","pathCompare","left","right","leftKeys","rightKeys","cmp","pathEquals","other","pathContains","ValidationPath","errorPrefix_","parts_","byteLength_","max","validationPathCheckValid","validationPath","validationPathToErrorString","VisibilityMonitor","hidden","visibilityChange","visible_","visible","RECONNECT_MIN_DELAY","PersistentConnection","onDataUpdate_","onConnectStatus_","onServerInfoUpdate_","authTokenProvider_","appCheckTokenProvider_","authOverride_","nextPersistentConnectionId_","interruptReasons_","listens","outstandingPuts_","outstandingGets_","outstandingPutCount_","outstandingGetCount_","onDisconnectRequestQueue_","connected_","reconnectDelay_","maxReconnectDelay_","securityDebugCallback_","establishConnectionTimer_","requestCBHash_","requestNumber_","realtime_","forceTokenRefresh_","invalidAuthTokenCount_","invalidAppCheckTokenCount_","firstConnection_","lastConnectionAttemptTime_","lastConnectionEstablishedTime_","onVisible_","onOnline_","action","onResponse","curReqNum","r","initConnection_","outstandingGet","request","_path","q","_queryObject","index","sendGet_","listen","currentHashFn","tag","queryId","_queryIdentifier","_queryParams","isDefault","loadsAllData","listenSpec","hashFn","sendListen_","req","status","warnOnListenWarnings_","removeListen_","warnings","indexSpec","getIndex","indexPath","tryAuth","reduceReconnectDelayIfAdminCredential_","credential","isAdmin","tryAppCheck","authMethod","isValidFormat","requestData","cred","onAuthRevoked_","onAppCheckRevoked_","unlisten","sendUnlisten_","queryObj","sendOnDisconnect_","response","putInternal","sendPut_","queued","result","errorReason","reqNum","onDataPush_","onListenRevoked_","onSecurityDebugPacket_","handleTimestamp_","sendConnectStats_","restoreState_","scheduleConnect_","establishConnection_","online","onRealtimeDisconnect_","cancelSentTransactions_","shouldReconnect_","timeSinceLastConnectAttempt","reconnectDelay","onDataMessage","onReady","nextConnectionId_","canceled","connection","closeFn","sendRequestFn","interrupt","resume","delta","serverTimeOffset","normalizedPathString","statusCode","explanation","queries","isReactNative","NamedNode","node","Wrap","Index","getCompare","compare","indexedValueChanged","oldNode","newNode","oldWrapped","newWrapped","minPost","MIN","__EMPTY_NODE","KeyIndex","isDefinedOn","maxPost","makePost","indexValue","KEY_INDEX","SortedMapIterator","startKey","comparator","isReverse_","resultGenerator_","nodeStack_","getNext","pop","hasNext","peek","LLRBNode","color","RED","SortedMap","EMPTY_NODE","copy","count","inorderTraversal","reverseTraversal","min_","minKey","maxKey","insert","fixUp_","removeMin_","isRed_","moveRedLeft_","smallest","rotateRight_","moveRedRight_","rotateLeft_","colorFlip_","nl","nr","checkMaxDepth_","blackDepth","check_","BLACK","comparator_","root_","getPredecessorKey","rightParent","getIterator","resultGenerator","getIteratorFrom","getReverseIteratorFrom","getReverseIterator","NAME_ONLY_COMPARATOR","NAME_COMPARATOR","MAX_NODE","LLRBEmptyNode","priorityHashText","priority","validatePriorityNode","priorityNode","isLeafNode","getPriority","__childrenNodeConstructor","nodeFromJSON","LeafNode","value_","priorityNode_","lazyHash_","updatePriority","newPriorityNode","getImmediateChild","childName","getChild","hasChild","getPredecessorChildName","childNode","updateImmediateChild","newChildNode","updateChild","front","numChildren","forEachChild","exportFormat","getValue","toHash","compareTo","compareToLeafNode_","otherLeaf","otherLeafType","thisLeafType","otherIndex","VALUE_TYPE_ORDER","thisIndex","withIndex","isIndexed","equals","PRIORITY_INDEX","PriorityIndex","aPriority","bPriority","indexCmp","LOG_2","Base12Num","num","current_","mask","bits_","nextBitIsOne","buildChildSet","childList","keyFn","mapSortFn","buildBalancedTree","low","namedNode","middle","root","base12","buildPennant","chunkSize","childTree","attachPennant","pennant","isOne","buildFrom12Array","_defaultIndexMap","fallbackObject","IndexMap","Default","indexes_","indexSet_","indexKey","sortedMap","hasIndex","indexDefinition","addIndex","existingChildren","sawIndexedValue","iter","newIndex","next","indexName","newIndexSet","newIndexes","addToIndexes","indexedChildren","existingSnap","newChildren","removeFromIndexes","ChildrenNode","children_","indexMap_","child","newIndexMap","newPriority","newImmediateChild","numKeys","allIntegerKeys","array","childHash","idx","resolveIndex_","predecessor","getFirstChildName","getFirstChild","getLastChildName","getLastChild","wrappedNode","startPost","iterator","endPost","otherChildrenNode","thisIter","otherIter","thisCurrent","otherCurrent","MaxNode","defineProperties","MAX","setMaxNode","setPriorityMaxNode","json","childData","children","childrenHavePriority","childSet","sortedChildSet","setNodeFromJSON","PathIndex","indexPath_","extractChild","snap","aChild","bChild","valueNode","VALUE_INDEX","ValueIndex","changeValue","snapshotNode","changeChildAdded","changeChildRemoved","changeChildChanged","oldSnap","IndexedFilter","index_","newChild","affectedPath","optChangeAccumulator","oldChild","trackChildChange","updateFullNode","newSnap","filtersNodes","getIndexedFilter","RangedFilter","indexedFilter_","startPost_","getStartPost_","endPost_","getEndPost_","startIsInclusive_","startAfterSet_","endIsInclusive_","endBeforeSet_","getStartPost","getEndPost","matches","isWithinStart","isWithinEnd","filtered","hasStart","startName","getIndexStartName","getIndexStartValue","hasEnd","endName","getIndexEndName","getIndexEndValue","LimitedFilter","withinDirectionalStart","reverse_","withinEndPost","withinStartPost","withinDirectionalEnd","compareRes","rangedFilter_","limit_","getLimit","isViewFromLeft","fullLimitUpdateChild_","childKey","childSnap","changeAccumulator","oldEventCache","newChildNamedNode","windowBoundary","inRange","oldChildSnap","nextChild","getChildAfterChild","compareNext","newEventCache","QueryParams","limitSet_","startSet_","startNameSet_","endSet_","endNameSet_","viewFrom_","indexStartValue_","indexStartName_","indexEndValue_","indexEndName_","hasLimit","hasAnchoredLimit","queryParamsStartAt","queryParams","newParams","queryParamsEndAt","queryParamsOrderBy","queryParamsToRestQueryStringParameters","qs","orderBy","startParam","endParam","queryParamsGetQueryObject","viewFrom","ReadonlyRestClient","getListenId_","listens_","listenId","thisListen","queryStringParameters","restRequest_","querystring","querystringParams","forEach","arrayVal","encodeURIComponent","xhr","XMLHttpRequest","responseText","SnapshotHolder","rootNode_","getNode","updateSnapshot","newSnapshotNode","newSparseSnapshotTree","sparseSnapshotTreeRemember","sparseSnapshotTree","clear","sparseSnapshotTreeForget","tree","sparseSnapshotTreeForEachTree","prefixPath","func","sparseSnapshotTreeForEachChild","StatsListener","collection_","last_","newStats","stat","StatsReporter","collection","server_","statsToReport_","statsListener_","reportStats_","reportedStats","haveStatsToReport","OperationType","newOperationSourceServerTaggedQuery","fromUser","fromServer","tagged","AckUserWrite","affectedTree","revert","ACK_USER_WRITE","operationForChild","subtree","ListenComplete","LISTEN_COMPLETE","Overwrite","OVERWRITE","Merge","MERGE","CacheNode","node_","fullyInitialized_","filtered_","isFullyInitialized","isFiltered","isCompleteForPath","isCompleteForChild","EventGenerator","query_","eventGeneratorGenerateEventsForType","eventGenerator","events","changes","registrations","eventCache","filteredChanges","change","eventGeneratorCompareChanges","aWrapped","bWrapped","materializedChange","eventGeneratorMaterializeSingleChange","prevName","registration","respondsTo","createEvent","newViewCache","serverCache","viewCacheUpdateEventSnap","viewCache","eventSnap","complete","viewCacheUpdateServerSnap","serverSnap","viewCacheGetCompleteEventSnap","viewCacheGetCompleteServerSnap","emptyChildrenSingleton","ImmutableTree","fromObject","childPath","EmptyChildren","findRootMostMatchingPathAndValue","relativePath","predicate","childExistingPathAndValue","findRootMostValueAndPath","toSet","setTree","newTree","fold","fold_","pathSoFar","accum","findOnPath","findOnPath_","pathToFollow","foreachOnPath","foreachOnPath_","currentRelativePath","foreach","foreach_","foreachChild","CompoundWrite","writeTree_","empty","compoundWriteAddWrite","compoundWrite","rootmost","rootMostPath","newWriteTree","compoundWriteAddWrites","updates","newWrite","compoundWriteRemoveWrite","compoundWriteHasCompleteWrite","compoundWriteGetCompleteNode","compoundWriteGetCompleteChildren","compoundWriteChildCompoundWrite","shadowingNode","compoundWriteIsEmpty","compoundWriteApply","applySubtreeWrite","writeTree","priorityWrite","writeTreeChildWrites","newWriteTreeRef","writeTreeRemoveWrite","writeId","allWrites","findIndex","writeToRemove","removedWriteWasVisible","removedWriteOverlapsWithOtherWrites","currentWrite","writeTreeRecordContainsPath_","writeTreeResetTree_","visibleWrites","writeTreeLayerTree_","writeTreeDefaultFilter_","lastWriteId","writeRecord","writes","treeRoot","writePath","deepNode","writeTreeCalcCompleteEventCache","treePath","completeServerCache","writeIdsToExclude","includeHiddenWrites","subMerge","writeTreeRefCalcCompleteEventCache","writeTreeRef","writeTreeRefCalcCompleteEventChildren","completeServerChildren","writeTreeCalcCompleteEventChildren","completeChildren","topLevelSet","writeTreeRefCalcEventCacheAfterServerOverwrite","existingEventSnap","existingServerSnap","writeTreeCalcEventCacheAfterServerOverwrite","childMerge","writeTreeRefShadowingWrite","writeTreeShadowingWrite","writeTreeRefCalcIndexedSlice","completeServerData","writeTreeCalcIndexedSlice","toIterate","nodes","writeTreeRefCalcCompleteChild","existingServerCache","writeTreeCalcCompleteChild","writeTreeRefChild","ChildChangeAccumulator","changeMap","oldChange","oldType","getChanges","NO_COMPLETE_CHILD_SOURCE","NoCompleteChildSource_","getCompleteChild","WriteTreeCompleteChildSource","writes_","viewCache_","optCompleteServerCache_","serverNode","viewProcessorApplyOperation","viewProcessor","oldViewCache","operation","writesCache","completeCache","accumulator","filterServerNode","overwrite","viewProcessorApplyUserOverwrite","viewProcessorApplyServerOverwrite","viewProcessorApplyUserMerge","changedChildren","curViewCache","viewProcessorCacheHasChild","viewProcessorApplyServerMerge","ackUserWrite","viewProcessorRevertUserWrite","serverChildren","viewProcessorAckUserWrite","ackPath","mergePath","serverCachePath","viewProcessorListenComplete","oldServerNode","viewProcessorGenerateEventCacheAfterServerEvent","viewProcessorMaybeAddValueEvent","isLeafOrEmpty","oldCompleteSnap","changePath","oldEventSnap","completeEventChildren","completeNode","oldEventNode","updatedPriority","childChangePath","newEventChild","eventChildUpdate","changedSnap","oldServerSnap","newServerCache","serverFilter","newServerNode","viewProcessorApplyMerge","viewMergeTree","childMergeTree","isUnknownDeepMerge","View","initialViewCache","eventRegistrations_","indexFilter","queryParamsGetNodeFilter","processor_","newViewProcessor","initialServerCache","initialEventCache","eventGenerator_","viewGetCompleteServerCache","view","cache","viewIsEmpty","viewRemoveEventRegistration","eventRegistration","cancelError","cancelEvents","maybeEvent","createCancelEvent","remaining","existing","hasAnyCallback","concat","viewApplyOperation","viewProcessorAssertIndexed","viewGenerateEventsForChanges_","eventGeneratorGenerateEventsForChanges","eventRegistrations","moves","changeChildMoved","referenceConstructor","SyncPoint","views","syncPointApplyOperation","syncPoint","optCompleteServerCache","syncPointGetView","serverCacheComplete","eventCacheComplete","syncPointAddEventRegistration","viewAddEventRegistration","viewGetInitialEvents","initialChanges","syncPointRemoveEventRegistration","removed","hadCompleteView","syncPointHasCompleteView","viewQueryId","syncPointGetReferenceConstructor","_repo","syncPointGetQueryViews","syncPointGetCompleteServerCache","syncPointViewForQuery","syncPointGetCompleteView","syncPointViewExistsForQuery","syncTreeNextQueryTag_","SyncTree","listenProvider_","syncPointTree_","pendingWriteTree_","tagToQueryMap","queryToTagMap","syncTreeApplyUserOverwrite","syncTree","newData","writeTreeAddOverwrite","syncTreeApplyOperationToSyncPoints_","syncTreeApplyUserMerge","writeTreeAddMerge","changeTree","syncTreeAckUserWrite","writeTreeGetWrite","record","syncTreeApplyServerOverwrite","syncTreeRemoveEventRegistration","skipListenerDedup","maybeSyncPoint","removedAndEvents","syncPointIsEmpty","removingDefault","covered","parentSyncPoint","newViews","syncTreeCollectDistinctViewsForSubTree_","maybeChildSyncPoint","childMap","_key","childViews","newQuery","syncTreeCreateListenerForView_","startListening","syncTreeQueryForListening_","syncTreeTagForQuery","defaultTag","stopListening","queryToRemove","tagToRemove","syncTreeMakeQueryKey_","syncTreeRemoveTags_","removedQuery","removedQueryKey","removedQueryTag","syncTreeApplyTaggedQueryOverwrite","queryKey","syncTreeQueryKeyForTag_","syncTreeParseQueryKey_","queryPath","syncTreeApplyTaggedOperation_","syncTreeAddEventRegistration","skipSetupListener","foundAncestorDefaultView","pathToSyncPoint","sp","childSyncPoint","viewAlreadyExists","syncTreeGetNextQueryTag_","syncTreeSetupListener_","queriesToStop","childQueries","queryToStop","syncTreeCalcCompleteEventCache","syncTreeGetServerValue","serverCacheNode","viewGetCompleteNode","syncTreeApplyOperationHelper_","syncPointTree","syncTreeApplyOperationDescendantsHelper_","childOperation","childServerCache","childWritesCache","viewGetServerCache","syncTreeApplyTaggedListenComplete","syncTreeApplyListenComplete","errorForServerCode","toUpperCase","splitIndex","syncTreeGetReferenceConstructor","ExistingValueProvider","DeferredValueProvider","syncTree_","path_","resolveDeferredLeafValue","existingVal","serverValues","resolveScalarDeferredValue","resolveComplexDeferredValue","op","unused","existingNode","resolveDeferredValueTree","resolveDeferredValue","resolveDeferredValueSnapshot","rawPri","leafNode","childrenNode","Tree","parent","childCount","treeSubTree","pathObj","treeGetValue","treeSetValue","treeUpdateParents","treeHasChildren","treeForEachChild","treeForEachDescendant","includeSelf","childrenFirst","treeGetPath","treeUpdateChild","childEmpty","treeIsEmpty","childExists","INVALID_KEY_REGEX_","INVALID_PATH_REGEX_","MAX_LEAF_SIZE_","isValidKey","isValidPathString","isValidPriority","validateFirebaseDataArg","validateFirebaseData","errorPrefixFxn","hasDotValue","hasActualChild","validationPathPush","validationPathPop","last","validateFirebaseMergeDataArg","mergePaths","curPath","prevPath","validateFirebaseMergePaths","validatePriority","validateKey","argumentName","validatePathString","validateWritablePath","validateUrl","parsedUrl","isValidRootPathString","EventQueue","eventLists_","recursionDepth_","eventQueueQueueEvents","eventQueue","eventDataList","currList","getPath","eventQueueRaiseEventsAtPath","eventQueueRaiseQueuedEventsMatchingPredicate","eventPath","eventQueueRaiseEventsForChangedPath","changedPath","sentAll","eventList","eventListRaise","eventFn","getEventRunner","INTERRUPT_REASON","Repo","forceRestClient_","appCheckProvider_","dataUpdateCount","eventQueue_","nextWriteId_","interceptServerDataCallback_","transactionQueueTree_","persistentConnection_","repoStart","repo","appId","authOverride","search","isMerge","repoOnDataUpdate","repoOnConnectStatus","connectStatus","repoOnServerInfoUpdate","repoUpdateInfo","statsReporter_","statsManagerGetOrCreateReporter","creatorFunction","infoData_","infoSyncTree_","infoEvents","serverSyncTree_","repoServerTime","repoGenerateServerValues","taggedChildren","raw","syncTreeApplyTaggedQueryMerge","taggedSnap","syncTreeApplyServerMerge","repoRerunTransactions","repoRunOnDisconnectEvents","repoLog","resolvedOnDisconnectTree","resolved","repoAbortTransactions","repoGetNextWriteId","repoSetWithPriority","newVal","newNodeUnresolved","success","clearEvents","repoCallOnCompleteCallback","repoOnDisconnectCancel","repoOnDisconnectSet","repoRemoveEventCallbackForQuery","repoInterrupt","repoGetLatestState","excludeSets","repoSendReadyTransactions","repoPruneCompletedTransactionsBelowNode","queue","repoBuildTransactionQueue","every","transaction","repoSendTransactionQueue","setsToIgnore","txn","currentWriteId","latestState","snapToSend","latestHash","retryCount","currentOutputSnapshotRaw","dataToSend","pathToSend","currentOutputSnapshotResolved","unwatcher","abortReason","rootMostTransactionNode","repoGetAncestorTransactionNode","repoRerunTransactionQueue","txnsToRerun","abortTransaction","currentNode","currentInputSnapshot","newDataNode","oldWriteId","newNodeResolved","applyLocally","transactionNode","transactionQueue","repoAggregateTransactionQueuesForNode","order","nodeQueue","to","treeForEachAncestor","repoAbortTransactionsOnNode","lastSent","parseRepoInfo","dataURL","parseDatabaseURL","scheme","subdomain","colonInd","slashInd","questionMarkInd","decodePath","pathStringDecoded","piece","decodeURIComponent","decodeQuery","queryString","results","segment","kv","hostWithoutPort","dotInd","PUSH_CHARS","nextPushId","lastPushTime","lastRandChars","duplicateTime","timeStampChars","DataEvent","snapshot","ref","getEventType","exportVal","CancelEvent","CallbackContext","snapshotCallback","cancelCallback","onValue","expDataSnapshot","previousChildName","onCancel","hasCancelCallback","userCallback","OnDisconnect","cancel","setWithPriority","repoOnDisconnectSetWithPriority","repoOnDisconnectUpdate","childrenToMerge","QueryImpl","_orderByCalled","ReferenceImpl","isEqual","sameRepo","samePath","sameQueryIdentifier","toJSON","pathToUrlEncodedString","validateNoPreviousOrderByCall","validateQueryEndpoints","startNode","endNode","tooManyArgsError","wrongArgTypeError","validateLimit","parentPath","DataSnapshot","_node","_index","childRef","exists","hasChildren","db","_checkNotDeleted","_root","refFromURL","parsedURL","thenablePushRef","pushRef","setPriority","repoUpdate","changedKey","changedValue","callbackContext","ValueEventRegistration","repoGetValue","cached","err","ChildEventRegistration","eventToCheck","cancelCallbackOrListenOptions","onlyOnce","onceCallback","dataSnapshot","repoAddEventCallbackForQuery","onChildAdded","onChildChanged","onChildMoved","onChildRemoved","expCallback","QueryConstraint","QueryEndAtConstraint","_value","_apply","endAt","QueryEndBeforeConstraint","queryParamsEndBefore","endBefore","QueryStartAtConstraint","startAt","QueryStartAfterConstraint","queryParamsStartAfter","startAfter","QueryLimitToFirstConstraint","_limit","queryParamsLimitToFirst","newLimit","limitToFirst","limit","QueryLimitToLastConstraint","queryParamsLimitToLast","limitToLast","QueryOrderByChildConstraint","parsedPath","orderByChild","QueryOrderByKeyConstraint","orderByKey","QueryOrderByPriorityConstraint","orderByPriority","QueryOrderByValueConstraint","orderByValue","QueryEqualToValueConstraint","equalTo","queryConstraints","queryImpl","constraint","syncPointSetReferenceConstructor","syncTreeSetReferenceConstructor","repos","useRestClient","repoManagerDatabaseFromApp","authProvider","dbUrl","databaseURL","projectId","isEmulator","dbEmulatorHost","authTokenProvider","repoManagerCreateRepo","appRepos","Database","_repoInternal","_instanceStarted","_rootInternal","repoManagerDeleteRepo","apiName","checkTransportInit","forceWebSockets","forceLongPolling","getDatabase","getApp","_getProvider","emulator","connectDatabaseEmulator","hostAndPort","tokenProvider","mockUserToken","createMockUserToken","uid","project","iat","sub","user_id","iss","aud","exp","auth_time","firebase","sign_in_provider","identities","alg","repoManagerApplyEmulatorSettings","goOffline","goOnline","repoResume","enableLoggingImpl","SERVER_TIMESTAMP","serverTimestamp","increment","TransactionResult","committed","runTransaction","transactionUpdate","repoStartTransaction","currentState","queueNode","priorityForNode","simpleListen","echo","onEcho","hijackHash","newHash","oldPut","forceRestClient","repoManagerForceRestClient","_initStandalone","customAuthImpl","customAppCheckImpl","componentContainer","registerDatabase","variant","_registerComponent","registerVersion"],"mappings":"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","preExistingComment":"firebase-database.js.map"}