{"version":3,"file":"firebase-performance.js","sources":["../util/src/errors.ts","../util/src/obj.ts","../util/src/compat.ts","../logger/src/logger.ts","../component/src/component.ts","../../node_modules/idb/build/wrap-idb-value.js","../../node_modules/idb/build/index.js","../installations/src/util/constants.ts","../installations/src/util/errors.ts","../installations/src/functions/common.ts","../installations/src/util/sleep.ts","../installations/src/helpers/generate-fid.ts","../installations/src/helpers/buffer-to-base64-url-safe.ts","../installations/src/util/get-key.ts","../installations/src/helpers/fid-changed.ts","../installations/src/helpers/idb-manager.ts","../installations/src/helpers/get-installation-entry.ts","../installations/src/functions/create-installation-request.ts","../installations/src/functions/generate-auth-token-request.ts","../installations/src/helpers/refresh-auth-token.ts","../installations/src/api/get-token.ts","../installations/src/helpers/extract-app-config.ts","../installations/src/functions/config.ts","../installations/src/api/get-id.ts","../installations/src/index.ts","../performance/src/utils/errors.ts","../performance/src/constants.ts","../performance/src/utils/console_logger.ts","../performance/src/services/api_service.ts","../performance/src/services/iid_service.ts","../performance/src/services/settings_service.ts","../util/src/environment.ts","../performance/src/utils/string_merger.ts","../performance/src/utils/attributes_utils.ts","../performance/src/utils/app_utils.ts","../performance/src/services/remote_config_service.ts","../performance/src/services/initialization_service.ts","../performance/src/services/transport_service.ts","../performance/src/services/perf_logger.ts","../performance/src/utils/metric_utils.ts","../performance/src/resources/trace.ts","../performance/src/resources/network_request.ts","../performance/src/services/oob_resources_service.ts","../performance/src/controllers/perf.ts","../performance/src/index.ts"],"sourcesContent":["/**\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 * @fileoverview Standardized Firebase Error.\n *\n * Usage:\n *\n * // Typescript string literals for type-safe codes\n * type Err =\n * 'unknown' |\n * 'object-not-found'\n * ;\n *\n * // Closure enum for type-safe error codes\n * // at-enum {string}\n * var Err = {\n * UNKNOWN: 'unknown',\n * OBJECT_NOT_FOUND: 'object-not-found',\n * }\n *\n * let errors: Map = {\n * 'generic-error': \"Unknown error\",\n * 'file-not-found': \"Could not find file: {$file}\",\n * };\n *\n * // Type-safe function - must pass a valid error code as param.\n * let error = new ErrorFactory('service', 'Service', errors);\n *\n * ...\n * throw error.create(Err.GENERIC);\n * ...\n * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName});\n * ...\n * // Service: Could not file file: foo.txt (service/file-not-found).\n *\n * catch (e) {\n * assert(e.message === \"Could not find file: foo.txt.\");\n * if ((e as FirebaseError)?.code === 'service/file-not-found') {\n * console.log(\"Could not read file: \" + e['file']);\n * }\n * }\n */\n\nexport type ErrorMap = {\n readonly [K in ErrorCode]: string;\n};\n\nconst ERROR_NAME = 'FirebaseError';\n\nexport interface StringLike {\n toString(): string;\n}\n\nexport interface ErrorData {\n [key: string]: unknown;\n}\n\n// Based on code from:\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types\nexport class FirebaseError extends Error {\n /** The custom name for all FirebaseErrors. */\n readonly name: string = ERROR_NAME;\n\n constructor(\n /** The error code for this error. */\n readonly code: string,\n message: string,\n /** Custom data for this error. */\n public customData?: Record\n ) {\n super(message);\n\n // Fix For ES5\n // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, FirebaseError.prototype);\n\n // Maintains proper stack trace for where our error was thrown.\n // Only available on V8.\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ErrorFactory.prototype.create);\n }\n }\n}\n\nexport class ErrorFactory<\n ErrorCode extends string,\n ErrorParams extends { readonly [K in ErrorCode]?: ErrorData } = {}\n> {\n constructor(\n private readonly service: string,\n private readonly serviceName: string,\n private readonly errors: ErrorMap\n ) {}\n\n create(\n code: K,\n ...data: K extends keyof ErrorParams ? [ErrorParams[K]] : []\n ): FirebaseError {\n const customData = (data[0] as ErrorData) || {};\n const fullCode = `${this.service}/${code}`;\n const template = this.errors[code];\n\n const message = template ? replaceTemplate(template, customData) : 'Error';\n // Service Name: Error message (service/code).\n const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`;\n\n const error = new FirebaseError(fullCode, fullMessage, customData);\n\n return error;\n }\n}\n\nfunction replaceTemplate(template: string, data: ErrorData): string {\n return template.replace(PATTERN, (_, key) => {\n const value = data[key];\n return value != null ? String(value) : `<${key}?>`;\n });\n}\n\nconst PATTERN = /\\{\\$([^}]+)}/g;\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(obj: T, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexport function safeGet(\n obj: T,\n key: K\n): T[K] | undefined {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n return obj[key];\n } else {\n return undefined;\n }\n}\n\nexport function isEmpty(obj: object): obj is {} {\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n return false;\n }\n }\n return true;\n}\n\nexport function map(\n obj: { [key in K]: V },\n fn: (value: V, key: K, obj: { [key in K]: V }) => U,\n contextObj?: unknown\n): { [key in K]: U } {\n const res: Partial<{ [key in K]: U }> = {};\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n res[key] = fn.call(contextObj, obj[key], key, obj);\n }\n }\n return res as { [key in K]: U };\n}\n\n/**\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)[k];\n const bProp = (b as Record)[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 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 {\n _delegate: T;\n}\n\nexport function getModularInstance(\n service: Compat | ExpService\n): ExpService {\n if (service && (service as Compat)._delegate) {\n return (service as Compat)._delegate;\n } else {\n return service as ExpService;\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 */\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 {\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 | 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,\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): this {\n this.onInstanceCreated = callback;\n return this;\n }\n}\n","const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey,\n ]));\n}\nconst cursorRequestMap = new WeakMap();\nconst transactionDoneMap = new WeakMap();\nconst transactionStoreNamesMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n promise\n .then((value) => {\n // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval\n // (see wrapFunction).\n if (value instanceof IDBCursor) {\n cursorRequestMap.set(value, request);\n }\n // Catching to avoid \"Uncaught Promise exceptions\"\n })\n .catch(() => { });\n // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Polyfill for objectStoreNames because of Edge.\n if (prop === 'objectStoreNames') {\n return target.objectStoreNames || transactionStoreNamesMap.get(target);\n }\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Edge doesn't support objectStoreNames (booo), so we polyfill it here.\n if (func === IDBDatabase.prototype.transaction &&\n !('objectStoreNames' in IDBTransaction.prototype)) {\n return function (storeNames, ...args) {\n const tx = func.call(unwrap(this), storeNames, ...args);\n transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]);\n return wrap(tx);\n };\n }\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(cursorRequestMap.get(this));\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\nexport { reverseTransformCache as a, instanceOfAny as i, replaceTraps as r, unwrap as u, wrap as w };\n","import { w as wrap, r as replaceTraps } from './wrap-idb-value.js';\nexport { u as unwrap, w as wrap } from './wrap-idb-value.js';\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction));\n });\n }\n if (blocked)\n request.addEventListener('blocked', () => blocked());\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking)\n db.addEventListener('versionchange', () => blocking());\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked)\n request.addEventListener('blocked', () => blocked());\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nexport { deleteDB, openDB };\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 { version } from '../../package.json';\n\nexport const PENDING_TIMEOUT_MS = 10000;\n\nexport const PACKAGE_VERSION = `w:${version}`;\nexport const INTERNAL_AUTH_VERSION = 'FIS_v2';\n\nexport const INSTALLATIONS_API_URL =\n 'https://firebaseinstallations.googleapis.com/v1';\n\nexport const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour\n\nexport const SERVICE = 'installations';\nexport const SERVICE_NAME = 'Installations';\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 { ErrorFactory, FirebaseError } from '@firebase/util';\nimport { SERVICE, SERVICE_NAME } from './constants';\n\nexport const enum ErrorCode {\n MISSING_APP_CONFIG_VALUES = 'missing-app-config-values',\n NOT_REGISTERED = 'not-registered',\n INSTALLATION_NOT_FOUND = 'installation-not-found',\n REQUEST_FAILED = 'request-failed',\n APP_OFFLINE = 'app-offline',\n DELETE_PENDING_REGISTRATION = 'delete-pending-registration'\n}\n\nconst ERROR_DESCRIPTION_MAP: { readonly [key in ErrorCode]: string } = {\n [ErrorCode.MISSING_APP_CONFIG_VALUES]:\n 'Missing App configuration value: \"{$valueName}\"',\n [ErrorCode.NOT_REGISTERED]: 'Firebase Installation is not registered.',\n [ErrorCode.INSTALLATION_NOT_FOUND]: 'Firebase Installation not found.',\n [ErrorCode.REQUEST_FAILED]:\n '{$requestName} request failed with error \"{$serverCode} {$serverStatus}: {$serverMessage}\"',\n [ErrorCode.APP_OFFLINE]: 'Could not process request. Application offline.',\n [ErrorCode.DELETE_PENDING_REGISTRATION]:\n \"Can't delete installation while there is a pending registration request.\"\n};\n\ninterface ErrorParams {\n [ErrorCode.MISSING_APP_CONFIG_VALUES]: {\n valueName: string;\n };\n [ErrorCode.REQUEST_FAILED]: {\n requestName: string;\n [index: string]: string | number; // to make Typescript 3.8 happy\n } & ServerErrorData;\n}\n\nexport const ERROR_FACTORY = new ErrorFactory(\n SERVICE,\n SERVICE_NAME,\n ERROR_DESCRIPTION_MAP\n);\n\nexport interface ServerErrorData {\n serverCode: number;\n serverMessage: string;\n serverStatus: string;\n}\n\nexport type ServerError = FirebaseError & { customData: ServerErrorData };\n\n/** Returns true if error is a FirebaseError that is based on an error from the server. */\nexport function isServerError(error: unknown): error is ServerError {\n return (\n error instanceof FirebaseError &&\n error.code.includes(ErrorCode.REQUEST_FAILED)\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\nimport { FirebaseError } from '@firebase/util';\nimport { GenerateAuthTokenResponse } from '../interfaces/api-response';\nimport {\n CompletedAuthToken,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport {\n INSTALLATIONS_API_URL,\n INTERNAL_AUTH_VERSION\n} from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode } from '../util/errors';\nimport { AppConfig } from '../interfaces/installation-impl';\n\nexport function getInstallationsEndpoint({ projectId }: AppConfig): string {\n return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`;\n}\n\nexport function extractAuthTokenInfoFromResponse(\n response: GenerateAuthTokenResponse\n): CompletedAuthToken {\n return {\n token: response.token,\n requestStatus: RequestStatus.COMPLETED,\n expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn),\n creationTime: Date.now()\n };\n}\n\nexport async function getErrorFromResponse(\n requestName: string,\n response: Response\n): Promise {\n const responseJson: ErrorResponse = await response.json();\n const errorData = responseJson.error;\n return ERROR_FACTORY.create(ErrorCode.REQUEST_FAILED, {\n requestName,\n serverCode: errorData.code,\n serverMessage: errorData.message,\n serverStatus: errorData.status\n });\n}\n\nexport function getHeaders({ apiKey }: AppConfig): Headers {\n return new Headers({\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'x-goog-api-key': apiKey\n });\n}\n\nexport function getHeadersWithAuth(\n appConfig: AppConfig,\n { refreshToken }: RegisteredInstallationEntry\n): Headers {\n const headers = getHeaders(appConfig);\n headers.append('Authorization', getAuthorizationHeader(refreshToken));\n return headers;\n}\n\nexport interface ErrorResponse {\n error: {\n code: number;\n message: string;\n status: string;\n };\n}\n\n/**\n * Calls the passed in fetch wrapper and returns the response.\n * If the returned response has a status of 5xx, re-runs the function once and\n * returns the response.\n */\nexport async function retryIfServerError(\n fn: () => Promise\n): Promise {\n const result = await fn();\n\n if (result.status >= 500 && result.status < 600) {\n // Internal Server Error. Retry request.\n return fn();\n }\n\n return result;\n}\n\nfunction getExpiresInFromResponseExpiresIn(responseExpiresIn: string): number {\n // This works because the server will never respond with fractions of a second.\n return Number(responseExpiresIn.replace('s', '000'));\n}\n\nfunction getAuthorizationHeader(refreshToken: string): string {\n return `${INTERNAL_AUTH_VERSION} ${refreshToken}`;\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/** Returns a promise that resolves after given time passes. */\nexport function sleep(ms: number): Promise {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\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\nimport { bufferToBase64UrlSafe } from './buffer-to-base64-url-safe';\n\nexport const VALID_FID_PATTERN = /^[cdef][\\w-]{21}$/;\nexport const INVALID_FID = '';\n\n/**\n * Generates a new FID using random values from Web Crypto API.\n * Returns an empty string if FID generation fails for any reason.\n */\nexport function generateFid(): string {\n try {\n // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5\n // bytes. our implementation generates a 17 byte array instead.\n const fidByteArray = new Uint8Array(17);\n const crypto =\n self.crypto || (self as unknown as { msCrypto: Crypto }).msCrypto;\n crypto.getRandomValues(fidByteArray);\n\n // Replace the first 4 random bits with the constant FID header of 0b0111.\n fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000);\n\n const fid = encode(fidByteArray);\n\n return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID;\n } catch {\n // FID generation errored\n return INVALID_FID;\n }\n}\n\n/** Converts a FID Uint8Array to a base64 string representation. */\nfunction encode(fidByteArray: Uint8Array): string {\n const b64String = bufferToBase64UrlSafe(fidByteArray);\n\n // Remove the 23rd character that was added because of the extra 4 bits at the\n // end of our 17 byte array, and the '=' padding.\n return b64String.substr(0, 22);\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 function bufferToBase64UrlSafe(array: Uint8Array): string {\n const b64 = btoa(String.fromCharCode(...array));\n return b64.replace(/\\+/g, '-').replace(/\\//g, '_');\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 { AppConfig } from '../interfaces/installation-impl';\n\n/** Returns a string key that can be used to identify the app. */\nexport function getKey(appConfig: AppConfig): string {\n return `${appConfig.appName}!${appConfig.appId}`;\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 { getKey } from '../util/get-key';\nimport { AppConfig } from '../interfaces/installation-impl';\nimport { IdChangeCallbackFn } from '../api';\n\nconst fidChangeCallbacks: Map> = new Map();\n\n/**\n * Calls the onIdChange callbacks with the new FID value, and broadcasts the\n * change to other tabs.\n */\nexport function fidChanged(appConfig: AppConfig, fid: string): void {\n const key = getKey(appConfig);\n\n callFidChangeCallbacks(key, fid);\n broadcastFidChange(key, fid);\n}\n\nexport function addCallback(\n appConfig: AppConfig,\n callback: IdChangeCallbackFn\n): void {\n // Open the broadcast channel if it's not already open,\n // to be able to listen to change events from other tabs.\n getBroadcastChannel();\n\n const key = getKey(appConfig);\n\n let callbackSet = fidChangeCallbacks.get(key);\n if (!callbackSet) {\n callbackSet = new Set();\n fidChangeCallbacks.set(key, callbackSet);\n }\n callbackSet.add(callback);\n}\n\nexport function removeCallback(\n appConfig: AppConfig,\n callback: IdChangeCallbackFn\n): void {\n const key = getKey(appConfig);\n\n const callbackSet = fidChangeCallbacks.get(key);\n\n if (!callbackSet) {\n return;\n }\n\n callbackSet.delete(callback);\n if (callbackSet.size === 0) {\n fidChangeCallbacks.delete(key);\n }\n\n // Close broadcast channel if there are no more callbacks.\n closeBroadcastChannel();\n}\n\nfunction callFidChangeCallbacks(key: string, fid: string): void {\n const callbacks = fidChangeCallbacks.get(key);\n if (!callbacks) {\n return;\n }\n\n for (const callback of callbacks) {\n callback(fid);\n }\n}\n\nfunction broadcastFidChange(key: string, fid: string): void {\n const channel = getBroadcastChannel();\n if (channel) {\n channel.postMessage({ key, fid });\n }\n closeBroadcastChannel();\n}\n\nlet broadcastChannel: BroadcastChannel | null = null;\n/** Opens and returns a BroadcastChannel if it is supported by the browser. */\nfunction getBroadcastChannel(): BroadcastChannel | null {\n if (!broadcastChannel && 'BroadcastChannel' in self) {\n broadcastChannel = new BroadcastChannel('[Firebase] FID Change');\n broadcastChannel.onmessage = e => {\n callFidChangeCallbacks(e.data.key, e.data.fid);\n };\n }\n return broadcastChannel;\n}\n\nfunction closeBroadcastChannel(): void {\n if (fidChangeCallbacks.size === 0 && broadcastChannel) {\n broadcastChannel.close();\n broadcastChannel = null;\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\nimport { DBSchema, IDBPDatabase, openDB } from 'idb';\nimport { AppConfig } from '../interfaces/installation-impl';\nimport { InstallationEntry } from '../interfaces/installation-entry';\nimport { getKey } from '../util/get-key';\nimport { fidChanged } from './fid-changed';\n\nconst DATABASE_NAME = 'firebase-installations-database';\nconst DATABASE_VERSION = 1;\nconst OBJECT_STORE_NAME = 'firebase-installations-store';\n\ninterface InstallationsDB extends DBSchema {\n 'firebase-installations-store': {\n key: string;\n value: InstallationEntry | undefined;\n };\n}\n\nlet dbPromise: Promise> | null = null;\nfunction getDbPromise(): Promise> {\n if (!dbPromise) {\n dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {\n upgrade: (db, oldVersion) => {\n // We don't use 'break' in this switch statement, the fall-through\n // behavior is what we want, because if there are multiple versions between\n // the old version and the current version, we want ALL the migrations\n // that correspond to those versions to run, not only the last one.\n // eslint-disable-next-line default-case\n switch (oldVersion) {\n case 0:\n db.createObjectStore(OBJECT_STORE_NAME);\n }\n }\n });\n }\n return dbPromise;\n}\n\n/** Gets record(s) from the objectStore that match the given key. */\nexport async function get(\n appConfig: AppConfig\n): Promise {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n return db\n .transaction(OBJECT_STORE_NAME)\n .objectStore(OBJECT_STORE_NAME)\n .get(key) as Promise;\n}\n\n/** Assigns or overwrites the record for the given key with the given value. */\nexport async function set(\n appConfig: AppConfig,\n value: ValueType\n): Promise {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n const objectStore = tx.objectStore(OBJECT_STORE_NAME);\n const oldValue = (await objectStore.get(key)) as InstallationEntry;\n await objectStore.put(value, key);\n await tx.done;\n\n if (!oldValue || oldValue.fid !== value.fid) {\n fidChanged(appConfig, value.fid);\n }\n\n return value;\n}\n\n/** Removes record(s) from the objectStore that match the given key. */\nexport async function remove(appConfig: AppConfig): Promise {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n await tx.objectStore(OBJECT_STORE_NAME).delete(key);\n await tx.done;\n}\n\n/**\n * Atomically updates a record with the result of updateFn, which gets\n * called with the current value. If newValue is undefined, the record is\n * deleted instead.\n * @return Updated value\n */\nexport async function update(\n appConfig: AppConfig,\n updateFn: (previousValue: InstallationEntry | undefined) => ValueType\n): Promise {\n const key = getKey(appConfig);\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n const store = tx.objectStore(OBJECT_STORE_NAME);\n const oldValue: InstallationEntry | undefined = (await store.get(\n key\n )) as InstallationEntry;\n const newValue = updateFn(oldValue);\n\n if (newValue === undefined) {\n await store.delete(key);\n } else {\n await store.put(newValue, key);\n }\n await tx.done;\n\n if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) {\n fidChanged(appConfig, newValue.fid);\n }\n\n return newValue;\n}\n\nexport async function clear(): Promise {\n const db = await getDbPromise();\n const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');\n await tx.objectStore(OBJECT_STORE_NAME).clear();\n await tx.done;\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 { createInstallationRequest } from '../functions/create-installation-request';\nimport {\n AppConfig,\n FirebaseInstallationsImpl\n} from '../interfaces/installation-impl';\nimport {\n InProgressInstallationEntry,\n InstallationEntry,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport { PENDING_TIMEOUT_MS } from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode, isServerError } from '../util/errors';\nimport { sleep } from '../util/sleep';\nimport { generateFid, INVALID_FID } from './generate-fid';\nimport { remove, set, update } from './idb-manager';\n\nexport interface InstallationEntryWithRegistrationPromise {\n installationEntry: InstallationEntry;\n /** Exist iff the installationEntry is not registered. */\n registrationPromise?: Promise;\n}\n\n/**\n * Updates and returns the InstallationEntry from the database.\n * Also triggers a registration request if it is necessary and possible.\n */\nexport async function getInstallationEntry(\n installations: FirebaseInstallationsImpl\n): Promise {\n let registrationPromise: Promise | undefined;\n\n const installationEntry = await update(installations.appConfig, oldEntry => {\n const installationEntry = updateOrCreateInstallationEntry(oldEntry);\n const entryWithPromise = triggerRegistrationIfNecessary(\n installations,\n installationEntry\n );\n registrationPromise = entryWithPromise.registrationPromise;\n return entryWithPromise.installationEntry;\n });\n\n if (installationEntry.fid === INVALID_FID) {\n // FID generation failed. Waiting for the FID from the server.\n return { installationEntry: await registrationPromise! };\n }\n\n return {\n installationEntry,\n registrationPromise\n };\n}\n\n/**\n * Creates a new Installation Entry if one does not exist.\n * Also clears timed out pending requests.\n */\nfunction updateOrCreateInstallationEntry(\n oldEntry: InstallationEntry | undefined\n): InstallationEntry {\n const entry: InstallationEntry = oldEntry || {\n fid: generateFid(),\n registrationStatus: RequestStatus.NOT_STARTED\n };\n\n return clearTimedOutRequest(entry);\n}\n\n/**\n * If the Firebase Installation is not registered yet, this will trigger the\n * registration and return an InProgressInstallationEntry.\n *\n * If registrationPromise does not exist, the installationEntry is guaranteed\n * to be registered.\n */\nfunction triggerRegistrationIfNecessary(\n installations: FirebaseInstallationsImpl,\n installationEntry: InstallationEntry\n): InstallationEntryWithRegistrationPromise {\n if (installationEntry.registrationStatus === RequestStatus.NOT_STARTED) {\n if (!navigator.onLine) {\n // Registration required but app is offline.\n const registrationPromiseWithError = Promise.reject(\n ERROR_FACTORY.create(ErrorCode.APP_OFFLINE)\n );\n return {\n installationEntry,\n registrationPromise: registrationPromiseWithError\n };\n }\n\n // Try registering. Change status to IN_PROGRESS.\n const inProgressEntry: InProgressInstallationEntry = {\n fid: installationEntry.fid,\n registrationStatus: RequestStatus.IN_PROGRESS,\n registrationTime: Date.now()\n };\n const registrationPromise = registerInstallation(\n installations,\n inProgressEntry\n );\n return { installationEntry: inProgressEntry, registrationPromise };\n } else if (\n installationEntry.registrationStatus === RequestStatus.IN_PROGRESS\n ) {\n return {\n installationEntry,\n registrationPromise: waitUntilFidRegistration(installations)\n };\n } else {\n return { installationEntry };\n }\n}\n\n/** This will be executed only once for each new Firebase Installation. */\nasync function registerInstallation(\n installations: FirebaseInstallationsImpl,\n installationEntry: InProgressInstallationEntry\n): Promise {\n try {\n const registeredInstallationEntry = await createInstallationRequest(\n installations,\n installationEntry\n );\n return set(installations.appConfig, registeredInstallationEntry);\n } catch (e) {\n if (isServerError(e) && e.customData.serverCode === 409) {\n // Server returned a \"FID can not be used\" error.\n // Generate a new ID next time.\n await remove(installations.appConfig);\n } else {\n // Registration failed. Set FID as not registered.\n await set(installations.appConfig, {\n fid: installationEntry.fid,\n registrationStatus: RequestStatus.NOT_STARTED\n });\n }\n throw e;\n }\n}\n\n/** Call if FID registration is pending in another request. */\nasync function waitUntilFidRegistration(\n installations: FirebaseInstallationsImpl\n): Promise {\n // Unfortunately, there is no way of reliably observing when a value in\n // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),\n // so we need to poll.\n\n let entry: InstallationEntry = await updateInstallationRequest(\n installations.appConfig\n );\n while (entry.registrationStatus === RequestStatus.IN_PROGRESS) {\n // createInstallation request still in progress.\n await sleep(100);\n\n entry = await updateInstallationRequest(installations.appConfig);\n }\n\n if (entry.registrationStatus === RequestStatus.NOT_STARTED) {\n // The request timed out or failed in a different call. Try again.\n const { installationEntry, registrationPromise } =\n await getInstallationEntry(installations);\n\n if (registrationPromise) {\n return registrationPromise;\n } else {\n // if there is no registrationPromise, entry is registered.\n return installationEntry as RegisteredInstallationEntry;\n }\n }\n\n return entry;\n}\n\n/**\n * Called only if there is a CreateInstallation request in progress.\n *\n * Updates the InstallationEntry in the DB based on the status of the\n * CreateInstallation request.\n *\n * Returns the updated InstallationEntry.\n */\nfunction updateInstallationRequest(\n appConfig: AppConfig\n): Promise {\n return update(appConfig, oldEntry => {\n if (!oldEntry) {\n throw ERROR_FACTORY.create(ErrorCode.INSTALLATION_NOT_FOUND);\n }\n return clearTimedOutRequest(oldEntry);\n });\n}\n\nfunction clearTimedOutRequest(entry: InstallationEntry): InstallationEntry {\n if (hasInstallationRequestTimedOut(entry)) {\n return {\n fid: entry.fid,\n registrationStatus: RequestStatus.NOT_STARTED\n };\n }\n\n return entry;\n}\n\nfunction hasInstallationRequestTimedOut(\n installationEntry: InstallationEntry\n): boolean {\n return (\n installationEntry.registrationStatus === RequestStatus.IN_PROGRESS &&\n installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()\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\nimport { CreateInstallationResponse } from '../interfaces/api-response';\nimport {\n InProgressInstallationEntry,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport { INTERNAL_AUTH_VERSION, PACKAGE_VERSION } from '../util/constants';\nimport {\n extractAuthTokenInfoFromResponse,\n getErrorFromResponse,\n getHeaders,\n getInstallationsEndpoint,\n retryIfServerError\n} from './common';\nimport { FirebaseInstallationsImpl } from '../interfaces/installation-impl';\n\nexport async function createInstallationRequest(\n { appConfig, heartbeatServiceProvider }: FirebaseInstallationsImpl,\n { fid }: InProgressInstallationEntry\n): Promise {\n const endpoint = getInstallationsEndpoint(appConfig);\n\n const headers = getHeaders(appConfig);\n\n // If heartbeat service exists, add the heartbeat string to the header.\n const heartbeatService = heartbeatServiceProvider.getImmediate({\n optional: true\n });\n if (heartbeatService) {\n const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();\n if (heartbeatsHeader) {\n headers.append('x-firebase-client', heartbeatsHeader);\n }\n }\n\n const body = {\n fid,\n authVersion: INTERNAL_AUTH_VERSION,\n appId: appConfig.appId,\n sdkVersion: PACKAGE_VERSION\n };\n\n const request: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n };\n\n const response = await retryIfServerError(() => fetch(endpoint, request));\n if (response.ok) {\n const responseValue: CreateInstallationResponse = await response.json();\n const registeredInstallationEntry: RegisteredInstallationEntry = {\n fid: responseValue.fid || fid,\n registrationStatus: RequestStatus.COMPLETED,\n refreshToken: responseValue.refreshToken,\n authToken: extractAuthTokenInfoFromResponse(responseValue.authToken)\n };\n return registeredInstallationEntry;\n } else {\n throw await getErrorFromResponse('Create Installation', response);\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\nimport { GenerateAuthTokenResponse } from '../interfaces/api-response';\nimport {\n CompletedAuthToken,\n RegisteredInstallationEntry\n} from '../interfaces/installation-entry';\nimport { PACKAGE_VERSION } from '../util/constants';\nimport {\n extractAuthTokenInfoFromResponse,\n getErrorFromResponse,\n getHeadersWithAuth,\n getInstallationsEndpoint,\n retryIfServerError\n} from './common';\nimport {\n FirebaseInstallationsImpl,\n AppConfig\n} from '../interfaces/installation-impl';\n\nexport async function generateAuthTokenRequest(\n { appConfig, heartbeatServiceProvider }: FirebaseInstallationsImpl,\n installationEntry: RegisteredInstallationEntry\n): Promise {\n const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry);\n\n const headers = getHeadersWithAuth(appConfig, installationEntry);\n\n // If heartbeat service exists, add the heartbeat string to the header.\n const heartbeatService = heartbeatServiceProvider.getImmediate({\n optional: true\n });\n if (heartbeatService) {\n const heartbeatsHeader = await heartbeatService.getHeartbeatsHeader();\n if (heartbeatsHeader) {\n headers.append('x-firebase-client', heartbeatsHeader);\n }\n }\n\n const body = {\n installation: {\n sdkVersion: PACKAGE_VERSION,\n appId: appConfig.appId\n }\n };\n\n const request: RequestInit = {\n method: 'POST',\n headers,\n body: JSON.stringify(body)\n };\n\n const response = await retryIfServerError(() => fetch(endpoint, request));\n if (response.ok) {\n const responseValue: GenerateAuthTokenResponse = await response.json();\n const completedAuthToken: CompletedAuthToken =\n extractAuthTokenInfoFromResponse(responseValue);\n return completedAuthToken;\n } else {\n throw await getErrorFromResponse('Generate Auth Token', response);\n }\n}\n\nfunction getGenerateAuthTokenEndpoint(\n appConfig: AppConfig,\n { fid }: RegisteredInstallationEntry\n): string {\n return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`;\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 { generateAuthTokenRequest } from '../functions/generate-auth-token-request';\nimport {\n AppConfig,\n FirebaseInstallationsImpl\n} from '../interfaces/installation-impl';\nimport {\n AuthToken,\n CompletedAuthToken,\n InProgressAuthToken,\n InstallationEntry,\n RegisteredInstallationEntry,\n RequestStatus\n} from '../interfaces/installation-entry';\nimport { PENDING_TIMEOUT_MS, TOKEN_EXPIRATION_BUFFER } from '../util/constants';\nimport { ERROR_FACTORY, ErrorCode, isServerError } from '../util/errors';\nimport { sleep } from '../util/sleep';\nimport { remove, set, update } from './idb-manager';\n\n/**\n * Returns a valid authentication token for the installation. Generates a new\n * token if one doesn't exist, is expired or about to expire.\n *\n * Should only be called if the Firebase Installation is registered.\n */\nexport async function refreshAuthToken(\n installations: FirebaseInstallationsImpl,\n forceRefresh = false\n): Promise {\n let tokenPromise: Promise | undefined;\n const entry = await update(installations.appConfig, oldEntry => {\n if (!isEntryRegistered(oldEntry)) {\n throw ERROR_FACTORY.create(ErrorCode.NOT_REGISTERED);\n }\n\n const oldAuthToken = oldEntry.authToken;\n if (!forceRefresh && isAuthTokenValid(oldAuthToken)) {\n // There is a valid token in the DB.\n return oldEntry;\n } else if (oldAuthToken.requestStatus === RequestStatus.IN_PROGRESS) {\n // There already is a token request in progress.\n tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh);\n return oldEntry;\n } else {\n // No token or token expired.\n if (!navigator.onLine) {\n throw ERROR_FACTORY.create(ErrorCode.APP_OFFLINE);\n }\n\n const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry);\n tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry);\n return inProgressEntry;\n }\n });\n\n const authToken = tokenPromise\n ? await tokenPromise\n : (entry.authToken as CompletedAuthToken);\n return authToken;\n}\n\n/**\n * Call only if FID is registered and Auth Token request is in progress.\n *\n * Waits until the current pending request finishes. If the request times out,\n * tries once in this thread as well.\n */\nasync function waitUntilAuthTokenRequest(\n installations: FirebaseInstallationsImpl,\n forceRefresh: boolean\n): Promise {\n // Unfortunately, there is no way of reliably observing when a value in\n // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers),\n // so we need to poll.\n\n let entry = await updateAuthTokenRequest(installations.appConfig);\n while (entry.authToken.requestStatus === RequestStatus.IN_PROGRESS) {\n // generateAuthToken still in progress.\n await sleep(100);\n\n entry = await updateAuthTokenRequest(installations.appConfig);\n }\n\n const authToken = entry.authToken;\n if (authToken.requestStatus === RequestStatus.NOT_STARTED) {\n // The request timed out or failed in a different call. Try again.\n return refreshAuthToken(installations, forceRefresh);\n } else {\n return authToken;\n }\n}\n\n/**\n * Called only if there is a GenerateAuthToken request in progress.\n *\n * Updates the InstallationEntry in the DB based on the status of the\n * GenerateAuthToken request.\n *\n * Returns the updated InstallationEntry.\n */\nfunction updateAuthTokenRequest(\n appConfig: AppConfig\n): Promise {\n return update(appConfig, oldEntry => {\n if (!isEntryRegistered(oldEntry)) {\n throw ERROR_FACTORY.create(ErrorCode.NOT_REGISTERED);\n }\n\n const oldAuthToken = oldEntry.authToken;\n if (hasAuthTokenRequestTimedOut(oldAuthToken)) {\n return {\n ...oldEntry,\n authToken: { requestStatus: RequestStatus.NOT_STARTED }\n };\n }\n\n return oldEntry;\n });\n}\n\nasync function fetchAuthTokenFromServer(\n installations: FirebaseInstallationsImpl,\n installationEntry: RegisteredInstallationEntry\n): Promise {\n try {\n const authToken = await generateAuthTokenRequest(\n installations,\n installationEntry\n );\n const updatedInstallationEntry: RegisteredInstallationEntry = {\n ...installationEntry,\n authToken\n };\n await set(installations.appConfig, updatedInstallationEntry);\n return authToken;\n } catch (e) {\n if (\n isServerError(e) &&\n (e.customData.serverCode === 401 || e.customData.serverCode === 404)\n ) {\n // Server returned a \"FID not found\" or a \"Invalid authentication\" error.\n // Generate a new ID next time.\n await remove(installations.appConfig);\n } else {\n const updatedInstallationEntry: RegisteredInstallationEntry = {\n ...installationEntry,\n authToken: { requestStatus: RequestStatus.NOT_STARTED }\n };\n await set(installations.appConfig, updatedInstallationEntry);\n }\n throw e;\n }\n}\n\nfunction isEntryRegistered(\n installationEntry: InstallationEntry | undefined\n): installationEntry is RegisteredInstallationEntry {\n return (\n installationEntry !== undefined &&\n installationEntry.registrationStatus === RequestStatus.COMPLETED\n );\n}\n\nfunction isAuthTokenValid(authToken: AuthToken): boolean {\n return (\n authToken.requestStatus === RequestStatus.COMPLETED &&\n !isAuthTokenExpired(authToken)\n );\n}\n\nfunction isAuthTokenExpired(authToken: CompletedAuthToken): boolean {\n const now = Date.now();\n return (\n now < authToken.creationTime ||\n authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER\n );\n}\n\n/** Returns an updated InstallationEntry with an InProgressAuthToken. */\nfunction makeAuthTokenRequestInProgressEntry(\n oldEntry: RegisteredInstallationEntry\n): RegisteredInstallationEntry {\n const inProgressAuthToken: InProgressAuthToken = {\n requestStatus: RequestStatus.IN_PROGRESS,\n requestTime: Date.now()\n };\n return {\n ...oldEntry,\n authToken: inProgressAuthToken\n };\n}\n\nfunction hasAuthTokenRequestTimedOut(authToken: AuthToken): boolean {\n return (\n authToken.requestStatus === RequestStatus.IN_PROGRESS &&\n authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()\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\nimport { getInstallationEntry } from '../helpers/get-installation-entry';\nimport { refreshAuthToken } from '../helpers/refresh-auth-token';\nimport { FirebaseInstallationsImpl } from '../interfaces/installation-impl';\nimport { Installations } from '../interfaces/public-types';\n\n/**\n * Returns a Firebase Installations auth token, identifying the current\n * Firebase Installation.\n * @param installations - The `Installations` instance.\n * @param forceRefresh - Force refresh regardless of token expiration.\n *\n * @public\n */\nexport async function getToken(\n installations: Installations,\n forceRefresh = false\n): Promise {\n const installationsImpl = installations as FirebaseInstallationsImpl;\n await completeInstallationRegistration(installationsImpl);\n\n // At this point we either have a Registered Installation in the DB, or we've\n // already thrown an error.\n const authToken = await refreshAuthToken(installationsImpl, forceRefresh);\n return authToken.token;\n}\n\nasync function completeInstallationRegistration(\n installations: FirebaseInstallationsImpl\n): Promise {\n const { registrationPromise } = await getInstallationEntry(installations);\n\n if (registrationPromise) {\n // A createInstallation request is in progress. Wait until it finishes.\n await registrationPromise;\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\nimport { FirebaseApp, FirebaseOptions } from '@firebase/app';\nimport { FirebaseError } from '@firebase/util';\nimport { AppConfig } from '../interfaces/installation-impl';\nimport { ERROR_FACTORY, ErrorCode } from '../util/errors';\n\nexport function extractAppConfig(app: FirebaseApp): AppConfig {\n if (!app || !app.options) {\n throw getMissingValueError('App Configuration');\n }\n\n if (!app.name) {\n throw getMissingValueError('App Name');\n }\n\n // Required app config keys\n const configKeys: Array = [\n 'projectId',\n 'apiKey',\n 'appId'\n ];\n\n for (const keyName of configKeys) {\n if (!app.options[keyName]) {\n throw getMissingValueError(keyName);\n }\n }\n\n return {\n appName: app.name,\n projectId: app.options.projectId!,\n apiKey: app.options.apiKey!,\n appId: app.options.appId!\n };\n}\n\nfunction getMissingValueError(valueName: string): FirebaseError {\n return ERROR_FACTORY.create(ErrorCode.MISSING_APP_CONFIG_VALUES, {\n valueName\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 { _registerComponent, _getProvider } from '@firebase/app';\nimport {\n Component,\n ComponentType,\n InstanceFactory,\n ComponentContainer\n} from '@firebase/component';\nimport { getId, getToken } from '../api/index';\nimport { _FirebaseInstallationsInternal } from '../interfaces/public-types';\nimport { FirebaseInstallationsImpl } from '../interfaces/installation-impl';\nimport { extractAppConfig } from '../helpers/extract-app-config';\n\nconst INSTALLATIONS_NAME = 'installations';\nconst INSTALLATIONS_NAME_INTERNAL = 'installations-internal';\n\nconst publicFactory: InstanceFactory<'installations'> = (\n container: ComponentContainer\n) => {\n const app = container.getProvider('app').getImmediate();\n // Throws if app isn't configured properly.\n const appConfig = extractAppConfig(app);\n const heartbeatServiceProvider = _getProvider(app, 'heartbeat');\n\n const installationsImpl: FirebaseInstallationsImpl = {\n app,\n appConfig,\n heartbeatServiceProvider,\n _delete: () => Promise.resolve()\n };\n return installationsImpl;\n};\n\nconst internalFactory: InstanceFactory<'installations-internal'> = (\n container: ComponentContainer\n) => {\n const app = container.getProvider('app').getImmediate();\n // Internal FIS instance relies on public FIS instance.\n const installations = _getProvider(app, INSTALLATIONS_NAME).getImmediate();\n\n const installationsInternal: _FirebaseInstallationsInternal = {\n getId: () => getId(installations),\n getToken: (forceRefresh?: boolean) => getToken(installations, forceRefresh)\n };\n return installationsInternal;\n};\n\nexport function registerInstallations(): void {\n _registerComponent(\n new Component(INSTALLATIONS_NAME, publicFactory, ComponentType.PUBLIC)\n );\n _registerComponent(\n new Component(\n INSTALLATIONS_NAME_INTERNAL,\n internalFactory,\n ComponentType.PRIVATE\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\nimport { getInstallationEntry } from '../helpers/get-installation-entry';\nimport { refreshAuthToken } from '../helpers/refresh-auth-token';\nimport { FirebaseInstallationsImpl } from '../interfaces/installation-impl';\nimport { Installations } from '../interfaces/public-types';\n\n/**\n * Creates a Firebase Installation if there isn't one for the app and\n * returns the Installation ID.\n * @param installations - The `Installations` instance.\n *\n * @public\n */\nexport async function getId(installations: Installations): Promise {\n const installationsImpl = installations as FirebaseInstallationsImpl;\n const { installationEntry, registrationPromise } = await getInstallationEntry(\n installationsImpl\n );\n\n if (registrationPromise) {\n registrationPromise.catch(console.error);\n } else {\n // If the installation is already registered, update the authentication\n // token if needed.\n refreshAuthToken(installationsImpl).catch(console.error);\n }\n\n return installationEntry.fid;\n}\n","/**\n * Firebase Installations\n *\n * @packageDocumentation\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\nimport { registerInstallations } from './functions/config';\nimport { registerVersion } from '@firebase/app';\nimport { name, version } from '../package.json';\n\nexport * from './api';\nexport * from './interfaces/public-types';\n\nregisterInstallations();\nregisterVersion(name, version);\n// BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation\nregisterVersion(name, version, '__BUILD_TARGET__');\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 { ErrorFactory } from '@firebase/util';\nimport { SERVICE, SERVICE_NAME } from '../constants';\n\nexport const enum ErrorCode {\n TRACE_STARTED_BEFORE = 'trace started',\n TRACE_STOPPED_BEFORE = 'trace stopped',\n NONPOSITIVE_TRACE_START_TIME = 'nonpositive trace startTime',\n NONPOSITIVE_TRACE_DURATION = 'nonpositive trace duration',\n NO_WINDOW = 'no window',\n NO_APP_ID = 'no app id',\n NO_PROJECT_ID = 'no project id',\n NO_API_KEY = 'no api key',\n INVALID_CC_LOG = 'invalid cc log',\n FB_NOT_DEFAULT = 'FB not default',\n RC_NOT_OK = 'RC response not ok',\n INVALID_ATTRIBUTE_NAME = 'invalid attribute name',\n INVALID_ATTRIBUTE_VALUE = 'invalid attribute value',\n INVALID_CUSTOM_METRIC_NAME = 'invalid custom metric name',\n INVALID_STRING_MERGER_PARAMETER = 'invalid String merger input',\n ALREADY_INITIALIZED = 'already initialized'\n}\n\nconst ERROR_DESCRIPTION_MAP: { readonly [key in ErrorCode]: string } = {\n [ErrorCode.TRACE_STARTED_BEFORE]: 'Trace {$traceName} was started before.',\n [ErrorCode.TRACE_STOPPED_BEFORE]: 'Trace {$traceName} is not running.',\n [ErrorCode.NONPOSITIVE_TRACE_START_TIME]:\n 'Trace {$traceName} startTime should be positive.',\n [ErrorCode.NONPOSITIVE_TRACE_DURATION]:\n 'Trace {$traceName} duration should be positive.',\n [ErrorCode.NO_WINDOW]: 'Window is not available.',\n [ErrorCode.NO_APP_ID]: 'App id is not available.',\n [ErrorCode.NO_PROJECT_ID]: 'Project id is not available.',\n [ErrorCode.NO_API_KEY]: 'Api key is not available.',\n [ErrorCode.INVALID_CC_LOG]: 'Attempted to queue invalid cc event',\n [ErrorCode.FB_NOT_DEFAULT]:\n 'Performance can only start when Firebase app instance is the default one.',\n [ErrorCode.RC_NOT_OK]: 'RC response is not ok',\n [ErrorCode.INVALID_ATTRIBUTE_NAME]:\n 'Attribute name {$attributeName} is invalid.',\n [ErrorCode.INVALID_ATTRIBUTE_VALUE]:\n 'Attribute value {$attributeValue} is invalid.',\n [ErrorCode.INVALID_CUSTOM_METRIC_NAME]:\n 'Custom metric name {$customMetricName} is invalid',\n [ErrorCode.INVALID_STRING_MERGER_PARAMETER]:\n 'Input for String merger is invalid, contact support team to resolve.',\n [ErrorCode.ALREADY_INITIALIZED]:\n 'initializePerformance() has already been called with ' +\n 'different options. To avoid this error, call initializePerformance() with the ' +\n 'same options as when it was originally called, or call getPerformance() to return the' +\n ' already initialized instance.'\n};\n\ninterface ErrorParams {\n [ErrorCode.TRACE_STARTED_BEFORE]: { traceName: string };\n [ErrorCode.TRACE_STOPPED_BEFORE]: { traceName: string };\n [ErrorCode.NONPOSITIVE_TRACE_START_TIME]: { traceName: string };\n [ErrorCode.NONPOSITIVE_TRACE_DURATION]: { traceName: string };\n [ErrorCode.INVALID_ATTRIBUTE_NAME]: { attributeName: string };\n [ErrorCode.INVALID_ATTRIBUTE_VALUE]: { attributeValue: string };\n [ErrorCode.INVALID_CUSTOM_METRIC_NAME]: { customMetricName: string };\n}\n\nexport const ERROR_FACTORY = new ErrorFactory(\n SERVICE,\n SERVICE_NAME,\n ERROR_DESCRIPTION_MAP\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 { version } from '../package.json';\n\nexport const SDK_VERSION = version;\n/** The prefix for start User Timing marks used for creating Traces. */\nexport const TRACE_START_MARK_PREFIX = 'FB-PERF-TRACE-START';\n/** The prefix for stop User Timing marks used for creating Traces. */\nexport const TRACE_STOP_MARK_PREFIX = 'FB-PERF-TRACE-STOP';\n/** The prefix for User Timing measure used for creating Traces. */\nexport const TRACE_MEASURE_PREFIX = 'FB-PERF-TRACE-MEASURE';\n/** The prefix for out of the box page load Trace name. */\nexport const OOB_TRACE_PAGE_LOAD_PREFIX = '_wt_';\n\nexport const FIRST_PAINT_COUNTER_NAME = '_fp';\n\nexport const FIRST_CONTENTFUL_PAINT_COUNTER_NAME = '_fcp';\n\nexport const FIRST_INPUT_DELAY_COUNTER_NAME = '_fid';\n\nexport const CONFIG_LOCAL_STORAGE_KEY = '@firebase/performance/config';\n\nexport const CONFIG_EXPIRY_LOCAL_STORAGE_KEY =\n '@firebase/performance/configexpire';\n\nexport const SERVICE = 'performance';\nexport const SERVICE_NAME = 'Performance';\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 { Logger, LogLevel } from '@firebase/logger';\nimport { SERVICE_NAME } from '../constants';\n\nexport const consoleLogger = new Logger(SERVICE_NAME);\nconsoleLogger.logLevel = LogLevel.INFO;\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 { ERROR_FACTORY, ErrorCode } from '../utils/errors';\nimport { isIndexedDBAvailable, areCookiesEnabled } from '@firebase/util';\nimport { consoleLogger } from '../utils/console_logger';\n\ndeclare global {\n interface Window {\n PerformanceObserver: typeof PerformanceObserver;\n perfMetrics?: { onFirstInputDelay(fn: (fid: number) => void): void };\n }\n}\n\nlet apiInstance: Api | undefined;\nlet windowInstance: Window | undefined;\n\nexport type EntryType =\n | 'mark'\n | 'measure'\n | 'paint'\n | 'resource'\n | 'frame'\n | 'navigation';\n\n/**\n * This class holds a reference to various browser related objects injected by\n * set methods.\n */\nexport class Api {\n private readonly performance: Performance;\n /** PreformanceObserver constructor function. */\n private readonly PerformanceObserver: typeof PerformanceObserver;\n private readonly windowLocation: Location;\n readonly onFirstInputDelay?: (fn: (fid: number) => void) => void;\n readonly localStorage?: Storage;\n readonly document: Document;\n readonly navigator: Navigator;\n\n constructor(readonly window?: Window) {\n if (!window) {\n throw ERROR_FACTORY.create(ErrorCode.NO_WINDOW);\n }\n this.performance = window.performance;\n this.PerformanceObserver = window.PerformanceObserver;\n this.windowLocation = window.location;\n this.navigator = window.navigator;\n this.document = window.document;\n if (this.navigator && this.navigator.cookieEnabled) {\n // If user blocks cookies on the browser, accessing localStorage will\n // throw an exception.\n this.localStorage = window.localStorage;\n }\n if (window.perfMetrics && window.perfMetrics.onFirstInputDelay) {\n this.onFirstInputDelay = window.perfMetrics.onFirstInputDelay;\n }\n }\n\n getUrl(): string {\n // Do not capture the string query part of url.\n return this.windowLocation.href.split('?')[0];\n }\n\n mark(name: string): void {\n if (!this.performance || !this.performance.mark) {\n return;\n }\n this.performance.mark(name);\n }\n\n measure(measureName: string, mark1: string, mark2: string): void {\n if (!this.performance || !this.performance.measure) {\n return;\n }\n this.performance.measure(measureName, mark1, mark2);\n }\n\n getEntriesByType(type: EntryType): PerformanceEntry[] {\n if (!this.performance || !this.performance.getEntriesByType) {\n return [];\n }\n return this.performance.getEntriesByType(type);\n }\n\n getEntriesByName(name: string): PerformanceEntry[] {\n if (!this.performance || !this.performance.getEntriesByName) {\n return [];\n }\n return this.performance.getEntriesByName(name);\n }\n\n getTimeOrigin(): number {\n // Polyfill the time origin with performance.timing.navigationStart.\n return (\n this.performance &&\n (this.performance.timeOrigin || this.performance.timing.navigationStart)\n );\n }\n\n requiredApisAvailable(): boolean {\n if (!fetch || !Promise || !areCookiesEnabled()) {\n consoleLogger.info(\n 'Firebase Performance cannot start if browser does not support fetch and Promise or cookie is disabled.'\n );\n return false;\n }\n\n if (!isIndexedDBAvailable()) {\n consoleLogger.info('IndexedDB is not supported by current browswer');\n return false;\n }\n return true;\n }\n\n setupObserver(\n entryType: EntryType,\n callback: (entry: PerformanceEntry) => void\n ): void {\n if (!this.PerformanceObserver) {\n return;\n }\n const observer = new this.PerformanceObserver(list => {\n for (const entry of list.getEntries()) {\n // `entry` is a PerformanceEntry instance.\n callback(entry);\n }\n });\n\n // Start observing the entry types you care about.\n observer.observe({ entryTypes: [entryType] });\n }\n\n static getInstance(): Api {\n if (apiInstance === undefined) {\n apiInstance = new Api(windowInstance);\n }\n return apiInstance;\n }\n}\n\nexport function setupApi(window: Window): void {\n windowInstance = window;\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 { _FirebaseInstallationsInternal } from '@firebase/installations';\n\nlet iid: string | undefined;\nlet authToken: string | undefined;\n\nexport function getIidPromise(\n installationsService: _FirebaseInstallationsInternal\n): Promise {\n const iidPromise = installationsService.getId();\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n iidPromise.then((iidVal: string) => {\n iid = iidVal;\n });\n return iidPromise;\n}\n\n// This method should be used after the iid is retrieved by getIidPromise method.\nexport function getIid(): string | undefined {\n return iid;\n}\n\nexport function getAuthTokenPromise(\n installationsService: _FirebaseInstallationsInternal\n): Promise {\n const authTokenPromise = installationsService.getToken();\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n authTokenPromise.then((authTokenVal: string) => {\n authToken = authTokenVal;\n });\n return authTokenPromise;\n}\n\nexport function getAuthenticationToken(): string | undefined {\n return authToken;\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 { mergeStrings } from '../utils/string_merger';\n\nlet settingsServiceInstance: SettingsService | undefined;\n\nexport class SettingsService {\n // The variable which controls logging of automatic traces and HTTP/S network monitoring.\n instrumentationEnabled = true;\n\n // The variable which controls logging of custom traces.\n dataCollectionEnabled = true;\n\n // Configuration flags set through remote config.\n loggingEnabled = false;\n // Sampling rate between 0 and 1.\n tracesSamplingRate = 1;\n networkRequestsSamplingRate = 1;\n\n // Address of logging service.\n logEndPointUrl =\n 'https://firebaselogging.googleapis.com/v0cc/log?format=json_proto';\n // Performance event transport endpoint URL which should be compatible with proto3.\n // New Address for transport service, not configurable via Remote Config.\n flTransportEndpointUrl = mergeStrings(\n 'hts/frbslgigp.ogepscmv/ieo/eaylg',\n 'tp:/ieaeogn-agolai.o/1frlglgc/o'\n );\n\n transportKey = mergeStrings('AzSC8r6ReiGqFMyfvgow', 'Iayx0u-XT3vksVM-pIV');\n\n // Source type for performance event logs.\n logSource = 462;\n\n // Flags which control per session logging of traces and network requests.\n logTraceAfterSampling = false;\n logNetworkAfterSampling = false;\n\n // TTL of config retrieved from remote config in hours.\n configTimeToLive = 12;\n\n getFlTransportFullUrl(): string {\n return this.flTransportEndpointUrl.concat('?key=', this.transportKey);\n }\n\n static getInstance(): SettingsService {\n if (settingsServiceInstance === undefined) {\n settingsServiceInstance = new SettingsService();\n }\n return settingsServiceInstance;\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';\n\n/**\n * Returns navigator.userAgent string or '' if it's not defined.\n * @return user agent string\n */\nexport function getUA(): string {\n if (\n typeof navigator !== 'undefined' &&\n typeof navigator['userAgent'] === 'string'\n ) {\n return navigator['userAgent'];\n } else {\n return '';\n }\n}\n\n/**\n * Detect Cordova / PhoneGap / Ionic frameworks on a mobile device.\n *\n * Deliberately does not rely on checking `file://` URLs (as this fails PhoneGap\n * in the Ripple emulator) nor Cordova `onDeviceReady`, which would normally\n * wait for a callback.\n */\nexport function isMobileCordova(): boolean {\n return (\n typeof window !== 'undefined' &&\n // @ts-ignore Setting up an broadly applicable index signature for Window\n // just to deal with this case would probably be a bad idea.\n !!(window['cordova'] || window['phonegap'] || window['PhoneGap']) &&\n /ios|iphone|ipod|ipad|android|blackberry|iemobile/i.test(getUA())\n );\n}\n\n/**\n * Detect Node.js.\n *\n * @return true if Node.js environment is detected.\n */\n// Node detection logic from: https://github.com/iliakan/detect-node/\nexport function isNode(): boolean {\n try {\n return (\n Object.prototype.toString.call(global.process) === '[object process]'\n );\n } catch (e) {\n return false;\n }\n}\n\n/**\n * Detect Browser Environment\n */\nexport function isBrowser(): boolean {\n return typeof self === 'object' && self.self === self;\n}\n\n/**\n * Detect browser extensions (Chrome and Firefox at least).\n */\ninterface BrowserRuntime {\n id?: unknown;\n}\ndeclare const chrome: { runtime?: BrowserRuntime };\ndeclare const browser: { runtime?: BrowserRuntime };\nexport function isBrowserExtension(): boolean {\n const runtime =\n typeof chrome === 'object'\n ? chrome.runtime\n : typeof browser === 'object'\n ? browser.runtime\n : undefined;\n return typeof runtime === 'object' && runtime.id !== undefined;\n}\n\n/**\n * Detect React Native.\n *\n * @return true if ReactNative environment is detected.\n */\nexport function isReactNative(): boolean {\n return (\n typeof navigator === 'object' && navigator['product'] === 'ReactNative'\n );\n}\n\n/** Detects Electron apps. */\nexport function isElectron(): boolean {\n return getUA().indexOf('Electron/') >= 0;\n}\n\n/** Detects Internet Explorer. */\nexport function isIE(): boolean {\n const ua = getUA();\n return ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0;\n}\n\n/** Detects Universal Windows Platform apps. */\nexport function isUWP(): boolean {\n return getUA().indexOf('MSAppHost/') >= 0;\n}\n\n/**\n * Detect whether the current SDK build is the Node version.\n *\n * @return true if it's the Node SDK build.\n */\nexport function isNodeSdk(): boolean {\n return CONSTANTS.NODE_CLIENT === true || CONSTANTS.NODE_ADMIN === true;\n}\n\n/** Returns true if we are running in Safari. */\nexport function isSafari(): boolean {\n return (\n !isNode() &&\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 return typeof indexedDB === 'object';\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 {\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/**\n * Polyfill for `globalThis` object.\n * @returns the `globalThis` object for the given environment.\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 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 { ERROR_FACTORY, ErrorCode } from './errors';\n\nexport function mergeStrings(part1: string, part2: string): string {\n const sizeDiff = part1.length - part2.length;\n if (sizeDiff < 0 || sizeDiff > 1) {\n throw ERROR_FACTORY.create(ErrorCode.INVALID_STRING_MERGER_PARAMETER);\n }\n\n const resultArray = [];\n for (let i = 0; i < part1.length; i++) {\n resultArray.push(part1.charAt(i));\n if (part2.length > i) {\n resultArray.push(part2.charAt(i));\n }\n }\n\n return resultArray.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\nimport { Api } from '../services/api_service';\n\n// The values and orders of the following enums should not be changed.\nconst enum ServiceWorkerStatus {\n UNKNOWN = 0,\n UNSUPPORTED = 1,\n CONTROLLED = 2,\n UNCONTROLLED = 3\n}\n\nexport enum VisibilityState {\n UNKNOWN = 0,\n VISIBLE = 1,\n HIDDEN = 2\n}\n\nconst enum EffectiveConnectionType {\n UNKNOWN = 0,\n CONNECTION_SLOW_2G = 1,\n CONNECTION_2G = 2,\n CONNECTION_3G = 3,\n CONNECTION_4G = 4\n}\n\n/**\n * NetworkInformation\n *\n * ref: https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation\n */\ninterface NetworkInformation {\n readonly effectiveType?: 'slow-2g' | '2g' | '3g' | '4g';\n}\n\ninterface NavigatorWithConnection extends Navigator {\n readonly connection: NetworkInformation;\n}\n\nconst RESERVED_ATTRIBUTE_PREFIXES = ['firebase_', 'google_', 'ga_'];\nconst ATTRIBUTE_FORMAT_REGEX = new RegExp('^[a-zA-Z]\\\\w*$');\nconst MAX_ATTRIBUTE_NAME_LENGTH = 40;\nconst MAX_ATTRIBUTE_VALUE_LENGTH = 100;\n\nexport function getServiceWorkerStatus(): ServiceWorkerStatus {\n const navigator = Api.getInstance().navigator;\n if ('serviceWorker' in navigator) {\n if (navigator.serviceWorker.controller) {\n return ServiceWorkerStatus.CONTROLLED;\n } else {\n return ServiceWorkerStatus.UNCONTROLLED;\n }\n } else {\n return ServiceWorkerStatus.UNSUPPORTED;\n }\n}\n\nexport function getVisibilityState(): VisibilityState {\n const document = Api.getInstance().document;\n const visibilityState = document.visibilityState;\n switch (visibilityState) {\n case 'visible':\n return VisibilityState.VISIBLE;\n case 'hidden':\n return VisibilityState.HIDDEN;\n default:\n return VisibilityState.UNKNOWN;\n }\n}\n\nexport function getEffectiveConnectionType(): EffectiveConnectionType {\n const navigator = Api.getInstance().navigator;\n const navigatorConnection = (navigator as NavigatorWithConnection).connection;\n const effectiveType =\n navigatorConnection && navigatorConnection.effectiveType;\n switch (effectiveType) {\n case 'slow-2g':\n return EffectiveConnectionType.CONNECTION_SLOW_2G;\n case '2g':\n return EffectiveConnectionType.CONNECTION_2G;\n case '3g':\n return EffectiveConnectionType.CONNECTION_3G;\n case '4g':\n return EffectiveConnectionType.CONNECTION_4G;\n default:\n return EffectiveConnectionType.UNKNOWN;\n }\n}\n\nexport function isValidCustomAttributeName(name: string): boolean {\n if (name.length === 0 || name.length > MAX_ATTRIBUTE_NAME_LENGTH) {\n return false;\n }\n const matchesReservedPrefix = RESERVED_ATTRIBUTE_PREFIXES.some(prefix =>\n name.startsWith(prefix)\n );\n return !matchesReservedPrefix && !!name.match(ATTRIBUTE_FORMAT_REGEX);\n}\n\nexport function isValidCustomAttributeValue(value: string): boolean {\n return value.length !== 0 && value.length <= MAX_ATTRIBUTE_VALUE_LENGTH;\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 { ERROR_FACTORY, ErrorCode } from './errors';\nimport { FirebaseApp } from '@firebase/app';\n\nexport function getAppId(firebaseApp: FirebaseApp): string {\n const appId = firebaseApp.options?.appId;\n if (!appId) {\n throw ERROR_FACTORY.create(ErrorCode.NO_APP_ID);\n }\n return appId;\n}\n\nexport function getProjectId(firebaseApp: FirebaseApp): string {\n const projectId = firebaseApp.options?.projectId;\n if (!projectId) {\n throw ERROR_FACTORY.create(ErrorCode.NO_PROJECT_ID);\n }\n return projectId;\n}\n\nexport function getApiKey(firebaseApp: FirebaseApp): string {\n const apiKey = firebaseApp.options?.apiKey;\n if (!apiKey) {\n throw ERROR_FACTORY.create(ErrorCode.NO_API_KEY);\n }\n return apiKey;\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 {\n CONFIG_EXPIRY_LOCAL_STORAGE_KEY,\n CONFIG_LOCAL_STORAGE_KEY,\n SDK_VERSION\n} from '../constants';\nimport { consoleLogger } from '../utils/console_logger';\nimport { ERROR_FACTORY, ErrorCode } from '../utils/errors';\n\nimport { Api } from './api_service';\nimport { getAuthTokenPromise } from './iid_service';\nimport { SettingsService } from './settings_service';\nimport { PerformanceController } from '../controllers/perf';\nimport { getProjectId, getApiKey, getAppId } from '../utils/app_utils';\n\nconst REMOTE_CONFIG_SDK_VERSION = '0.0.1';\n\ninterface SecondaryConfig {\n loggingEnabled?: boolean;\n logSource?: number;\n logEndPointUrl?: string;\n transportKey?: string;\n tracesSamplingRate?: number;\n networkRequestsSamplingRate?: number;\n}\n\n// These values will be used if the remote config object is successfully\n// retrieved, but the template does not have these fields.\nconst DEFAULT_CONFIGS: SecondaryConfig = {\n loggingEnabled: true\n};\n\n/* eslint-disable camelcase */\ninterface RemoteConfigTemplate {\n fpr_enabled?: string;\n fpr_log_source?: string;\n fpr_log_endpoint_url?: string;\n fpr_log_transport_key?: string;\n fpr_log_transport_web_percent?: string;\n fpr_vc_network_request_sampling_rate?: string;\n fpr_vc_trace_sampling_rate?: string;\n fpr_vc_session_sampling_rate?: string;\n}\n/* eslint-enable camelcase */\n\ninterface RemoteConfigResponse {\n entries?: RemoteConfigTemplate;\n state?: string;\n}\n\nconst FIS_AUTH_PREFIX = 'FIREBASE_INSTALLATIONS_AUTH';\n\nexport function getConfig(\n performanceController: PerformanceController,\n iid: string\n): Promise {\n const config = getStoredConfig();\n if (config) {\n processConfig(config);\n return Promise.resolve();\n }\n\n return getRemoteConfig(performanceController, iid)\n .then(processConfig)\n .then(\n config => storeConfig(config),\n /** Do nothing for error, use defaults set in settings service. */\n () => {}\n );\n}\n\nfunction getStoredConfig(): RemoteConfigResponse | undefined {\n const localStorage = Api.getInstance().localStorage;\n if (!localStorage) {\n return;\n }\n const expiryString = localStorage.getItem(CONFIG_EXPIRY_LOCAL_STORAGE_KEY);\n if (!expiryString || !configValid(expiryString)) {\n return;\n }\n\n const configStringified = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY);\n if (!configStringified) {\n return;\n }\n try {\n const configResponse: RemoteConfigResponse = JSON.parse(configStringified);\n return configResponse;\n } catch {\n return;\n }\n}\n\nfunction storeConfig(config: RemoteConfigResponse | undefined): void {\n const localStorage = Api.getInstance().localStorage;\n if (!config || !localStorage) {\n return;\n }\n\n localStorage.setItem(CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config));\n localStorage.setItem(\n CONFIG_EXPIRY_LOCAL_STORAGE_KEY,\n String(\n Date.now() +\n SettingsService.getInstance().configTimeToLive * 60 * 60 * 1000\n )\n );\n}\n\nconst COULD_NOT_GET_CONFIG_MSG =\n 'Could not fetch config, will use default configs';\n\nfunction getRemoteConfig(\n performanceController: PerformanceController,\n iid: string\n): Promise {\n // Perf needs auth token only to retrieve remote config.\n return getAuthTokenPromise(performanceController.installations)\n .then(authToken => {\n const projectId = getProjectId(performanceController.app);\n const apiKey = getApiKey(performanceController.app);\n const configEndPoint = `https://firebaseremoteconfig.googleapis.com/v1/projects/${projectId}/namespaces/fireperf:fetch?key=${apiKey}`;\n const request = new Request(configEndPoint, {\n method: 'POST',\n headers: { Authorization: `${FIS_AUTH_PREFIX} ${authToken}` },\n /* eslint-disable camelcase */\n body: JSON.stringify({\n app_instance_id: iid,\n app_instance_id_token: authToken,\n app_id: getAppId(performanceController.app),\n app_version: SDK_VERSION,\n sdk_version: REMOTE_CONFIG_SDK_VERSION\n })\n /* eslint-enable camelcase */\n });\n return fetch(request).then(response => {\n if (response.ok) {\n return response.json() as RemoteConfigResponse;\n }\n // In case response is not ok. This will be caught by catch.\n throw ERROR_FACTORY.create(ErrorCode.RC_NOT_OK);\n });\n })\n .catch(() => {\n consoleLogger.info(COULD_NOT_GET_CONFIG_MSG);\n return undefined;\n });\n}\n\n/**\n * Processes config coming either from calling RC or from local storage.\n * This method only runs if call is successful or config in storage\n * is valid.\n */\nfunction processConfig(\n config?: RemoteConfigResponse\n): RemoteConfigResponse | undefined {\n if (!config) {\n return config;\n }\n const settingsServiceInstance = SettingsService.getInstance();\n const entries = config.entries || {};\n if (entries.fpr_enabled !== undefined) {\n // TODO: Change the assignment of loggingEnabled once the received type is\n // known.\n settingsServiceInstance.loggingEnabled =\n String(entries.fpr_enabled) === 'true';\n } else if (DEFAULT_CONFIGS.loggingEnabled !== undefined) {\n // Config retrieved successfully, but there is no fpr_enabled in template.\n // Use secondary configs value.\n settingsServiceInstance.loggingEnabled = DEFAULT_CONFIGS.loggingEnabled;\n }\n if (entries.fpr_log_source) {\n settingsServiceInstance.logSource = Number(entries.fpr_log_source);\n } else if (DEFAULT_CONFIGS.logSource) {\n settingsServiceInstance.logSource = DEFAULT_CONFIGS.logSource;\n }\n\n if (entries.fpr_log_endpoint_url) {\n settingsServiceInstance.logEndPointUrl = entries.fpr_log_endpoint_url;\n } else if (DEFAULT_CONFIGS.logEndPointUrl) {\n settingsServiceInstance.logEndPointUrl = DEFAULT_CONFIGS.logEndPointUrl;\n }\n\n // Key from Remote Config has to be non-empty string, otherwsie use local value.\n if (entries.fpr_log_transport_key) {\n settingsServiceInstance.transportKey = entries.fpr_log_transport_key;\n } else if (DEFAULT_CONFIGS.transportKey) {\n settingsServiceInstance.transportKey = DEFAULT_CONFIGS.transportKey;\n }\n\n if (entries.fpr_vc_network_request_sampling_rate !== undefined) {\n settingsServiceInstance.networkRequestsSamplingRate = Number(\n entries.fpr_vc_network_request_sampling_rate\n );\n } else if (DEFAULT_CONFIGS.networkRequestsSamplingRate !== undefined) {\n settingsServiceInstance.networkRequestsSamplingRate =\n DEFAULT_CONFIGS.networkRequestsSamplingRate;\n }\n if (entries.fpr_vc_trace_sampling_rate !== undefined) {\n settingsServiceInstance.tracesSamplingRate = Number(\n entries.fpr_vc_trace_sampling_rate\n );\n } else if (DEFAULT_CONFIGS.tracesSamplingRate !== undefined) {\n settingsServiceInstance.tracesSamplingRate =\n DEFAULT_CONFIGS.tracesSamplingRate;\n }\n // Set the per session trace and network logging flags.\n settingsServiceInstance.logTraceAfterSampling = shouldLogAfterSampling(\n settingsServiceInstance.tracesSamplingRate\n );\n settingsServiceInstance.logNetworkAfterSampling = shouldLogAfterSampling(\n settingsServiceInstance.networkRequestsSamplingRate\n );\n return config;\n}\n\nfunction configValid(expiry: string): boolean {\n return Number(expiry) > Date.now();\n}\n\nfunction shouldLogAfterSampling(samplingRate: number): boolean {\n return Math.random() <= samplingRate;\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 { getIidPromise } from './iid_service';\nimport { getConfig } from './remote_config_service';\nimport { Api } from './api_service';\nimport { PerformanceController } from '../controllers/perf';\n\nconst enum InitializationStatus {\n notInitialized = 1,\n initializationPending,\n initialized\n}\n\nlet initializationStatus = InitializationStatus.notInitialized;\n\nlet initializationPromise: Promise | undefined;\n\nexport function getInitializationPromise(\n performanceController: PerformanceController\n): Promise {\n initializationStatus = InitializationStatus.initializationPending;\n\n initializationPromise =\n initializationPromise || initializePerf(performanceController);\n\n return initializationPromise;\n}\n\nexport function isPerfInitialized(): boolean {\n return initializationStatus === InitializationStatus.initialized;\n}\n\nfunction initializePerf(\n performanceController: PerformanceController\n): Promise {\n return getDocumentReadyComplete()\n .then(() => getIidPromise(performanceController.installations))\n .then(iid => getConfig(performanceController, iid))\n .then(\n () => changeInitializationStatus(),\n () => changeInitializationStatus()\n );\n}\n\n/**\n * Returns a promise which resolves whenever the document readystate is complete or\n * immediately if it is called after page load complete.\n */\nfunction getDocumentReadyComplete(): Promise {\n const document = Api.getInstance().document;\n return new Promise(resolve => {\n if (document && document.readyState !== 'complete') {\n const handler = (): void => {\n if (document.readyState === 'complete') {\n document.removeEventListener('readystatechange', handler);\n resolve();\n }\n };\n document.addEventListener('readystatechange', handler);\n } else {\n resolve();\n }\n });\n}\n\nfunction changeInitializationStatus(): void {\n initializationStatus = InitializationStatus.initialized;\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 { SettingsService } from './settings_service';\nimport { ERROR_FACTORY, ErrorCode } from '../utils/errors';\nimport { consoleLogger } from '../utils/console_logger';\n\nconst DEFAULT_SEND_INTERVAL_MS = 10 * 1000;\nconst INITIAL_SEND_TIME_DELAY_MS = 5.5 * 1000;\n// If end point does not work, the call will be tried for these many times.\nconst DEFAULT_REMAINING_TRIES = 3;\nconst MAX_EVENT_COUNT_PER_REQUEST = 1000;\nlet remainingTries = DEFAULT_REMAINING_TRIES;\n\ninterface LogResponseDetails {\n responseAction?: string;\n}\n\ninterface BatchEvent {\n message: string;\n eventTime: number;\n}\n\n/* eslint-disable camelcase */\n// CC/Fl accepted log format.\ninterface TransportBatchLogFormat {\n request_time_ms: string;\n client_info: ClientInfo;\n log_source: number;\n log_event: Log[];\n}\n\ninterface ClientInfo {\n client_type: number;\n js_client_info: {};\n}\n\ninterface Log {\n source_extension_json_proto3: string;\n event_time_ms: string;\n}\n/* eslint-enable camelcase */\n\nlet queue: BatchEvent[] = [];\n\nlet isTransportSetup: boolean = false;\n\nexport function setupTransportService(): void {\n if (!isTransportSetup) {\n processQueue(INITIAL_SEND_TIME_DELAY_MS);\n isTransportSetup = true;\n }\n}\n\n/**\n * Utilized by testing to clean up message queue and un-initialize transport service.\n */\nexport function resetTransportService(): void {\n isTransportSetup = false;\n queue = [];\n}\n\nfunction processQueue(timeOffset: number): void {\n setTimeout(() => {\n // If there is no remainingTries left, stop retrying.\n if (remainingTries === 0) {\n return;\n }\n\n // If there are no events to process, wait for DEFAULT_SEND_INTERVAL_MS and try again.\n if (!queue.length) {\n return processQueue(DEFAULT_SEND_INTERVAL_MS);\n }\n\n dispatchQueueEvents();\n }, timeOffset);\n}\n\nfunction dispatchQueueEvents(): void {\n // Extract events up to the maximum cap of single logRequest from top of \"official queue\".\n // The staged events will be used for current logRequest attempt, remaining events will be kept\n // for next attempt.\n const staged = queue.splice(0, MAX_EVENT_COUNT_PER_REQUEST);\n\n /* eslint-disable camelcase */\n // We will pass the JSON serialized event to the backend.\n const log_event: Log[] = staged.map(evt => ({\n source_extension_json_proto3: evt.message,\n event_time_ms: String(evt.eventTime)\n }));\n\n const data: TransportBatchLogFormat = {\n request_time_ms: String(Date.now()),\n client_info: {\n client_type: 1, // 1 is JS\n js_client_info: {}\n },\n log_source: SettingsService.getInstance().logSource,\n log_event\n };\n /* eslint-enable camelcase */\n\n sendEventsToFl(data, staged).catch(() => {\n // If the request fails for some reason, add the events that were attempted\n // back to the primary queue to retry later.\n queue = [...staged, ...queue];\n remainingTries--;\n consoleLogger.info(`Tries left: ${remainingTries}.`);\n processQueue(DEFAULT_SEND_INTERVAL_MS);\n });\n}\n\nfunction sendEventsToFl(\n data: TransportBatchLogFormat,\n staged: BatchEvent[]\n): Promise {\n return postToFlEndpoint(data)\n .then(res => {\n if (!res.ok) {\n consoleLogger.info('Call to Firebase backend failed.');\n }\n return res.json();\n })\n .then(res => {\n // Find the next call wait time from the response.\n const transportWait = Number(res.nextRequestWaitMillis);\n let requestOffset = DEFAULT_SEND_INTERVAL_MS;\n if (!isNaN(transportWait)) {\n requestOffset = Math.max(transportWait, requestOffset);\n }\n\n // Delete request if response include RESPONSE_ACTION_UNKNOWN or DELETE_REQUEST action.\n // Otherwise, retry request using normal scheduling if response include RETRY_REQUEST_LATER.\n const logResponseDetails: LogResponseDetails[] = res.logResponseDetails;\n if (\n Array.isArray(logResponseDetails) &&\n logResponseDetails.length > 0 &&\n logResponseDetails[0].responseAction === 'RETRY_REQUEST_LATER'\n ) {\n queue = [...staged, ...queue];\n consoleLogger.info(`Retry transport request later.`);\n }\n\n remainingTries = DEFAULT_REMAINING_TRIES;\n // Schedule the next process.\n processQueue(requestOffset);\n });\n}\n\nfunction postToFlEndpoint(data: TransportBatchLogFormat): Promise {\n const flTransportFullUrl =\n SettingsService.getInstance().getFlTransportFullUrl();\n return fetch(flTransportFullUrl, {\n method: 'POST',\n body: JSON.stringify(data)\n });\n}\n\nfunction addToQueue(evt: BatchEvent): void {\n if (!evt.eventTime || !evt.message) {\n throw ERROR_FACTORY.create(ErrorCode.INVALID_CC_LOG);\n }\n // Add the new event to the queue.\n queue = [...queue, evt];\n}\n\n/** Log handler for cc service to send the performance logs to the server. */\nexport function transportHandler(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n serializer: (...args: any[]) => string\n): (...args: unknown[]) => void {\n return (...args) => {\n const message = serializer(...args);\n addToQueue({\n message,\n eventTime: Date.now()\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 { getIid } from './iid_service';\nimport { NetworkRequest } from '../resources/network_request';\nimport { Trace } from '../resources/trace';\nimport { Api } from './api_service';\nimport { SettingsService } from './settings_service';\nimport {\n getServiceWorkerStatus,\n getVisibilityState,\n VisibilityState,\n getEffectiveConnectionType\n} from '../utils/attributes_utils';\nimport {\n isPerfInitialized,\n getInitializationPromise\n} from './initialization_service';\nimport { transportHandler } from './transport_service';\nimport { SDK_VERSION } from '../constants';\nimport { FirebaseApp } from '@firebase/app';\nimport { getAppId } from '../utils/app_utils';\n\nconst enum ResourceType {\n NetworkRequest,\n Trace\n}\n\n/* eslint-disable camelcase */\ninterface ApplicationInfo {\n google_app_id: string;\n app_instance_id?: string;\n web_app_info: WebAppInfo;\n application_process_state: number;\n}\n\ninterface WebAppInfo {\n sdk_version: string;\n page_url: string;\n service_worker_status: number;\n visibility_state: number;\n effective_connection_type: number;\n}\n\ninterface PerfNetworkLog {\n application_info: ApplicationInfo;\n network_request_metric: NetworkRequestMetric;\n}\n\ninterface PerfTraceLog {\n application_info: ApplicationInfo;\n trace_metric: TraceMetric;\n}\n\ninterface NetworkRequestMetric {\n url: string;\n http_method: number;\n http_response_code: number;\n response_payload_bytes?: number;\n client_start_time_us?: number;\n time_to_response_initiated_us?: number;\n time_to_response_completed_us?: number;\n}\n\ninterface TraceMetric {\n name: string;\n is_auto: boolean;\n client_start_time_us: number;\n duration_us: number;\n counters?: { [key: string]: number };\n custom_attributes?: { [key: string]: string };\n}\n\n/* eslint-enble camelcase */\n\nlet logger: (\n resource: NetworkRequest | Trace,\n resourceType: ResourceType\n) => void | undefined;\n// This method is not called before initialization.\nfunction sendLog(\n resource: NetworkRequest | Trace,\n resourceType: ResourceType\n): void {\n if (!logger) {\n logger = transportHandler(serializer);\n }\n logger(resource, resourceType);\n}\n\nexport function logTrace(trace: Trace): void {\n const settingsService = SettingsService.getInstance();\n // Do not log if trace is auto generated and instrumentation is disabled.\n if (!settingsService.instrumentationEnabled && trace.isAuto) {\n return;\n }\n // Do not log if trace is custom and data collection is disabled.\n if (!settingsService.dataCollectionEnabled && !trace.isAuto) {\n return;\n }\n // Do not log if required apis are not available.\n if (!Api.getInstance().requiredApisAvailable()) {\n return;\n }\n\n // Only log the page load auto traces if page is visible.\n if (trace.isAuto && getVisibilityState() !== VisibilityState.VISIBLE) {\n return;\n }\n\n if (isPerfInitialized()) {\n sendTraceLog(trace);\n } else {\n // Custom traces can be used before the initialization but logging\n // should wait until after.\n getInitializationPromise(trace.performanceController).then(\n () => sendTraceLog(trace),\n () => sendTraceLog(trace)\n );\n }\n}\n\nfunction sendTraceLog(trace: Trace): void {\n if (!getIid()) {\n return;\n }\n\n const settingsService = SettingsService.getInstance();\n if (\n !settingsService.loggingEnabled ||\n !settingsService.logTraceAfterSampling\n ) {\n return;\n }\n\n setTimeout(() => sendLog(trace, ResourceType.Trace), 0);\n}\n\nexport function logNetworkRequest(networkRequest: NetworkRequest): void {\n const settingsService = SettingsService.getInstance();\n // Do not log network requests if instrumentation is disabled.\n if (!settingsService.instrumentationEnabled) {\n return;\n }\n\n // Do not log the js sdk's call to transport service domain to avoid unnecessary cycle.\n // Need to blacklist both old and new endpoints to avoid migration gap.\n const networkRequestUrl = networkRequest.url;\n\n // Blacklist old log endpoint and new transport endpoint.\n // Because Performance SDK doesn't instrument requests sent from SDK itself.\n const logEndpointUrl = settingsService.logEndPointUrl.split('?')[0];\n const flEndpointUrl = settingsService.flTransportEndpointUrl.split('?')[0];\n if (\n networkRequestUrl === logEndpointUrl ||\n networkRequestUrl === flEndpointUrl\n ) {\n return;\n }\n\n if (\n !settingsService.loggingEnabled ||\n !settingsService.logNetworkAfterSampling\n ) {\n return;\n }\n\n setTimeout(() => sendLog(networkRequest, ResourceType.NetworkRequest), 0);\n}\n\nfunction serializer(\n resource: NetworkRequest | Trace,\n resourceType: ResourceType\n): string {\n if (resourceType === ResourceType.NetworkRequest) {\n return serializeNetworkRequest(resource as NetworkRequest);\n }\n return serializeTrace(resource as Trace);\n}\n\nfunction serializeNetworkRequest(networkRequest: NetworkRequest): string {\n const networkRequestMetric: NetworkRequestMetric = {\n url: networkRequest.url,\n http_method: networkRequest.httpMethod || 0,\n http_response_code: 200,\n response_payload_bytes: networkRequest.responsePayloadBytes,\n client_start_time_us: networkRequest.startTimeUs,\n time_to_response_initiated_us: networkRequest.timeToResponseInitiatedUs,\n time_to_response_completed_us: networkRequest.timeToResponseCompletedUs\n };\n const perfMetric: PerfNetworkLog = {\n application_info: getApplicationInfo(\n networkRequest.performanceController.app\n ),\n network_request_metric: networkRequestMetric\n };\n return JSON.stringify(perfMetric);\n}\n\nfunction serializeTrace(trace: Trace): string {\n const traceMetric: TraceMetric = {\n name: trace.name,\n is_auto: trace.isAuto,\n client_start_time_us: trace.startTimeUs,\n duration_us: trace.durationUs\n };\n\n if (Object.keys(trace.counters).length !== 0) {\n traceMetric.counters = trace.counters;\n }\n const customAttributes = trace.getAttributes();\n if (Object.keys(customAttributes).length !== 0) {\n traceMetric.custom_attributes = customAttributes;\n }\n\n const perfMetric: PerfTraceLog = {\n application_info: getApplicationInfo(trace.performanceController.app),\n trace_metric: traceMetric\n };\n return JSON.stringify(perfMetric);\n}\n\nfunction getApplicationInfo(firebaseApp: FirebaseApp): ApplicationInfo {\n return {\n google_app_id: getAppId(firebaseApp),\n app_instance_id: getIid(),\n web_app_info: {\n sdk_version: SDK_VERSION,\n page_url: Api.getInstance().getUrl(),\n service_worker_status: getServiceWorkerStatus(),\n visibility_state: getVisibilityState(),\n effective_connection_type: getEffectiveConnectionType()\n },\n application_process_state: 0\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 {\n FIRST_PAINT_COUNTER_NAME,\n FIRST_CONTENTFUL_PAINT_COUNTER_NAME,\n FIRST_INPUT_DELAY_COUNTER_NAME,\n OOB_TRACE_PAGE_LOAD_PREFIX\n} from '../constants';\nimport { consoleLogger } from '../utils/console_logger';\n\nconst MAX_METRIC_NAME_LENGTH = 100;\nconst RESERVED_AUTO_PREFIX = '_';\nconst oobMetrics = [\n FIRST_PAINT_COUNTER_NAME,\n FIRST_CONTENTFUL_PAINT_COUNTER_NAME,\n FIRST_INPUT_DELAY_COUNTER_NAME\n];\n\n/**\n * Returns true if the metric is custom and does not start with reserved prefix, or if\n * the metric is one of out of the box page load trace metrics.\n */\nexport function isValidMetricName(name: string, traceName?: string): boolean {\n if (name.length === 0 || name.length > MAX_METRIC_NAME_LENGTH) {\n return false;\n }\n return (\n (traceName &&\n traceName.startsWith(OOB_TRACE_PAGE_LOAD_PREFIX) &&\n oobMetrics.indexOf(name) > -1) ||\n !name.startsWith(RESERVED_AUTO_PREFIX)\n );\n}\n\n/**\n * Converts the provided value to an integer value to be used in case of a metric.\n * @param providedValue Provided number value of the metric that needs to be converted to an integer.\n *\n * @returns Converted integer number to be set for the metric.\n */\nexport function convertMetricValueToInteger(providedValue: number): number {\n const valueAsInteger: number = Math.floor(providedValue);\n if (valueAsInteger < providedValue) {\n consoleLogger.info(\n `Metric value should be an Integer, setting the value as : ${valueAsInteger}.`\n );\n }\n return valueAsInteger;\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 {\n TRACE_START_MARK_PREFIX,\n TRACE_STOP_MARK_PREFIX,\n TRACE_MEASURE_PREFIX,\n OOB_TRACE_PAGE_LOAD_PREFIX,\n FIRST_PAINT_COUNTER_NAME,\n FIRST_CONTENTFUL_PAINT_COUNTER_NAME,\n FIRST_INPUT_DELAY_COUNTER_NAME\n} from '../constants';\nimport { Api } from '../services/api_service';\nimport { logTrace } from '../services/perf_logger';\nimport { ERROR_FACTORY, ErrorCode } from '../utils/errors';\nimport {\n isValidCustomAttributeName,\n isValidCustomAttributeValue\n} from '../utils/attributes_utils';\nimport {\n isValidMetricName,\n convertMetricValueToInteger\n} from '../utils/metric_utils';\nimport { PerformanceTrace } from '../public_types';\nimport { PerformanceController } from '../controllers/perf';\n\nconst enum TraceState {\n UNINITIALIZED = 1,\n RUNNING,\n TERMINATED\n}\n\nexport class Trace implements PerformanceTrace {\n private state: TraceState = TraceState.UNINITIALIZED;\n startTimeUs!: number;\n durationUs!: number;\n private customAttributes: { [key: string]: string } = {};\n counters: { [counterName: string]: number } = {};\n private api = Api.getInstance();\n private randomId = Math.floor(Math.random() * 1000000);\n private traceStartMark!: string;\n private traceStopMark!: string;\n private traceMeasure!: string;\n\n /**\n * @param performanceController The performance controller running.\n * @param name The name of the trace.\n * @param isAuto If the trace is auto-instrumented.\n * @param traceMeasureName The name of the measure marker in user timing specification. This field\n * is only set when the trace is built for logging when the user directly uses the user timing\n * api (performance.mark and performance.measure).\n */\n constructor(\n readonly performanceController: PerformanceController,\n readonly name: string,\n readonly isAuto = false,\n traceMeasureName?: string\n ) {\n if (!this.isAuto) {\n this.traceStartMark = `${TRACE_START_MARK_PREFIX}-${this.randomId}-${this.name}`;\n this.traceStopMark = `${TRACE_STOP_MARK_PREFIX}-${this.randomId}-${this.name}`;\n this.traceMeasure =\n traceMeasureName ||\n `${TRACE_MEASURE_PREFIX}-${this.randomId}-${this.name}`;\n\n if (traceMeasureName) {\n // For the case of direct user timing traces, no start stop will happen. The measure object\n // is already available.\n this.calculateTraceMetrics();\n }\n }\n }\n\n /**\n * Starts a trace. The measurement of the duration starts at this point.\n */\n start(): void {\n if (this.state !== TraceState.UNINITIALIZED) {\n throw ERROR_FACTORY.create(ErrorCode.TRACE_STARTED_BEFORE, {\n traceName: this.name\n });\n }\n this.api.mark(this.traceStartMark);\n this.state = TraceState.RUNNING;\n }\n\n /**\n * Stops the trace. The measurement of the duration of the trace stops at this point and trace\n * is logged.\n */\n stop(): void {\n if (this.state !== TraceState.RUNNING) {\n throw ERROR_FACTORY.create(ErrorCode.TRACE_STOPPED_BEFORE, {\n traceName: this.name\n });\n }\n this.state = TraceState.TERMINATED;\n this.api.mark(this.traceStopMark);\n this.api.measure(\n this.traceMeasure,\n this.traceStartMark,\n this.traceStopMark\n );\n this.calculateTraceMetrics();\n logTrace(this);\n }\n\n /**\n * Records a trace with predetermined values. If this method is used a trace is created and logged\n * directly. No need to use start and stop methods.\n * @param startTime Trace start time since epoch in millisec\n * @param duration The duraction of the trace in millisec\n * @param options An object which can optionally hold maps of custom metrics and custom attributes\n */\n record(\n startTime: number,\n duration: number,\n options?: {\n metrics?: { [key: string]: number };\n attributes?: { [key: string]: string };\n }\n ): void {\n if (startTime <= 0) {\n throw ERROR_FACTORY.create(ErrorCode.NONPOSITIVE_TRACE_START_TIME, {\n traceName: this.name\n });\n }\n if (duration <= 0) {\n throw ERROR_FACTORY.create(ErrorCode.NONPOSITIVE_TRACE_DURATION, {\n traceName: this.name\n });\n }\n\n this.durationUs = Math.floor(duration * 1000);\n this.startTimeUs = Math.floor(startTime * 1000);\n if (options && options.attributes) {\n this.customAttributes = { ...options.attributes };\n }\n if (options && options.metrics) {\n for (const metricName of Object.keys(options.metrics)) {\n if (!isNaN(Number(options.metrics[metricName]))) {\n this.counters[metricName] = Math.floor(\n Number(options.metrics[metricName])\n );\n }\n }\n }\n logTrace(this);\n }\n\n /**\n * Increments a custom metric by a certain number or 1 if number not specified. Will create a new\n * custom metric if one with the given name does not exist. The value will be floored down to an\n * integer.\n * @param counter Name of the custom metric\n * @param numAsInteger Increment by value\n */\n incrementMetric(counter: string, numAsInteger = 1): void {\n if (this.counters[counter] === undefined) {\n this.putMetric(counter, numAsInteger);\n } else {\n this.putMetric(counter, this.counters[counter] + numAsInteger);\n }\n }\n\n /**\n * Sets a custom metric to a specified value. Will create a new custom metric if one with the\n * given name does not exist. The value will be floored down to an integer.\n * @param counter Name of the custom metric\n * @param numAsInteger Set custom metric to this value\n */\n putMetric(counter: string, numAsInteger: number): void {\n if (isValidMetricName(counter, this.name)) {\n this.counters[counter] = convertMetricValueToInteger(numAsInteger ?? 0);\n } else {\n throw ERROR_FACTORY.create(ErrorCode.INVALID_CUSTOM_METRIC_NAME, {\n customMetricName: counter\n });\n }\n }\n\n /**\n * Returns the value of the custom metric by that name. If a custom metric with that name does\n * not exist will return zero.\n * @param counter\n */\n getMetric(counter: string): number {\n return this.counters[counter] || 0;\n }\n\n /**\n * Sets a custom attribute of a trace to a certain value.\n * @param attr\n * @param value\n */\n putAttribute(attr: string, value: string): void {\n const isValidName = isValidCustomAttributeName(attr);\n const isValidValue = isValidCustomAttributeValue(value);\n if (isValidName && isValidValue) {\n this.customAttributes[attr] = value;\n return;\n }\n // Throw appropriate error when the attribute name or value is invalid.\n if (!isValidName) {\n throw ERROR_FACTORY.create(ErrorCode.INVALID_ATTRIBUTE_NAME, {\n attributeName: attr\n });\n }\n if (!isValidValue) {\n throw ERROR_FACTORY.create(ErrorCode.INVALID_ATTRIBUTE_VALUE, {\n attributeValue: value\n });\n }\n }\n\n /**\n * Retrieves the value a custom attribute of a trace is set to.\n * @param attr\n */\n getAttribute(attr: string): string | undefined {\n return this.customAttributes[attr];\n }\n\n removeAttribute(attr: string): void {\n if (this.customAttributes[attr] === undefined) {\n return;\n }\n delete this.customAttributes[attr];\n }\n\n getAttributes(): { [key: string]: string } {\n return { ...this.customAttributes };\n }\n\n private setStartTime(startTime: number): void {\n this.startTimeUs = startTime;\n }\n\n private setDuration(duration: number): void {\n this.durationUs = duration;\n }\n\n /**\n * Calculates and assigns the duration and start time of the trace using the measure performance\n * entry.\n */\n private calculateTraceMetrics(): void {\n const perfMeasureEntries = this.api.getEntriesByName(this.traceMeasure);\n const perfMeasureEntry = perfMeasureEntries && perfMeasureEntries[0];\n if (perfMeasureEntry) {\n this.durationUs = Math.floor(perfMeasureEntry.duration * 1000);\n this.startTimeUs = Math.floor(\n (perfMeasureEntry.startTime + this.api.getTimeOrigin()) * 1000\n );\n }\n }\n\n /**\n * @param navigationTimings A single element array which contains the navigationTIming object of\n * the page load\n * @param paintTimings A array which contains paintTiming object of the page load\n * @param firstInputDelay First input delay in millisec\n */\n static createOobTrace(\n performanceController: PerformanceController,\n navigationTimings: PerformanceNavigationTiming[],\n paintTimings: PerformanceEntry[],\n firstInputDelay?: number\n ): void {\n const route = Api.getInstance().getUrl();\n if (!route) {\n return;\n }\n const trace = new Trace(\n performanceController,\n OOB_TRACE_PAGE_LOAD_PREFIX + route,\n true\n );\n const timeOriginUs = Math.floor(Api.getInstance().getTimeOrigin() * 1000);\n trace.setStartTime(timeOriginUs);\n\n // navigationTimings includes only one element.\n if (navigationTimings && navigationTimings[0]) {\n trace.setDuration(Math.floor(navigationTimings[0].duration * 1000));\n trace.putMetric(\n 'domInteractive',\n Math.floor(navigationTimings[0].domInteractive * 1000)\n );\n trace.putMetric(\n 'domContentLoadedEventEnd',\n Math.floor(navigationTimings[0].domContentLoadedEventEnd * 1000)\n );\n trace.putMetric(\n 'loadEventEnd',\n Math.floor(navigationTimings[0].loadEventEnd * 1000)\n );\n }\n\n const FIRST_PAINT = 'first-paint';\n const FIRST_CONTENTFUL_PAINT = 'first-contentful-paint';\n if (paintTimings) {\n const firstPaint = paintTimings.find(\n paintObject => paintObject.name === FIRST_PAINT\n );\n if (firstPaint && firstPaint.startTime) {\n trace.putMetric(\n FIRST_PAINT_COUNTER_NAME,\n Math.floor(firstPaint.startTime * 1000)\n );\n }\n const firstContentfulPaint = paintTimings.find(\n paintObject => paintObject.name === FIRST_CONTENTFUL_PAINT\n );\n if (firstContentfulPaint && firstContentfulPaint.startTime) {\n trace.putMetric(\n FIRST_CONTENTFUL_PAINT_COUNTER_NAME,\n Math.floor(firstContentfulPaint.startTime * 1000)\n );\n }\n\n if (firstInputDelay) {\n trace.putMetric(\n FIRST_INPUT_DELAY_COUNTER_NAME,\n Math.floor(firstInputDelay * 1000)\n );\n }\n }\n\n logTrace(trace);\n }\n\n static createUserTimingTrace(\n performanceController: PerformanceController,\n measureName: string\n ): void {\n const trace = new Trace(\n performanceController,\n measureName,\n false,\n measureName\n );\n logTrace(trace);\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 { Api } from '../services/api_service';\nimport { logNetworkRequest } from '../services/perf_logger';\nimport { PerformanceController } from '../controllers/perf';\n\n// The order of values of this enum should not be changed.\nexport const enum HttpMethod {\n HTTP_METHOD_UNKNOWN = 0,\n GET = 1,\n PUT = 2,\n POST = 3,\n DELETE = 4,\n HEAD = 5,\n PATCH = 6,\n OPTIONS = 7,\n TRACE = 8,\n CONNECT = 9\n}\n\n// Durations are in microseconds.\nexport interface NetworkRequest {\n performanceController: PerformanceController;\n url: string;\n httpMethod?: HttpMethod;\n requestPayloadBytes?: number;\n responsePayloadBytes?: number;\n httpResponseCode?: number;\n responseContentType?: string;\n startTimeUs?: number;\n timeToRequestCompletedUs?: number;\n timeToResponseInitiatedUs?: number;\n timeToResponseCompletedUs?: number;\n}\n\nexport function createNetworkRequestEntry(\n performanceController: PerformanceController,\n entry: PerformanceEntry\n): void {\n const performanceEntry = entry as PerformanceResourceTiming;\n if (!performanceEntry || performanceEntry.responseStart === undefined) {\n return;\n }\n const timeOrigin = Api.getInstance().getTimeOrigin();\n const startTimeUs = Math.floor(\n (performanceEntry.startTime + timeOrigin) * 1000\n );\n const timeToResponseInitiatedUs = performanceEntry.responseStart\n ? Math.floor(\n (performanceEntry.responseStart - performanceEntry.startTime) * 1000\n )\n : undefined;\n const timeToResponseCompletedUs = Math.floor(\n (performanceEntry.responseEnd - performanceEntry.startTime) * 1000\n );\n // Remove the query params from logged network request url.\n const url = performanceEntry.name && performanceEntry.name.split('?')[0];\n const networkRequest: NetworkRequest = {\n performanceController,\n url,\n responsePayloadBytes: performanceEntry.transferSize,\n startTimeUs,\n timeToResponseInitiatedUs,\n timeToResponseCompletedUs\n };\n\n logNetworkRequest(networkRequest);\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 { Api } from './api_service';\nimport { Trace } from '../resources/trace';\nimport { createNetworkRequestEntry } from '../resources/network_request';\nimport { TRACE_MEASURE_PREFIX } from '../constants';\nimport { getIid } from './iid_service';\nimport { PerformanceController } from '../controllers/perf';\n\nconst FID_WAIT_TIME_MS = 5000;\n\nexport function setupOobResources(\n performanceController: PerformanceController\n): void {\n // Do not initialize unless iid is available.\n if (!getIid()) {\n return;\n }\n // The load event might not have fired yet, and that means performance navigation timing\n // object has a duration of 0. The setup should run after all current tasks in js queue.\n setTimeout(() => setupOobTraces(performanceController), 0);\n setTimeout(() => setupNetworkRequests(performanceController), 0);\n setTimeout(() => setupUserTimingTraces(performanceController), 0);\n}\n\nfunction setupNetworkRequests(\n performanceController: PerformanceController\n): void {\n const api = Api.getInstance();\n const resources = api.getEntriesByType('resource');\n for (const resource of resources) {\n createNetworkRequestEntry(performanceController, resource);\n }\n api.setupObserver('resource', entry =>\n createNetworkRequestEntry(performanceController, entry)\n );\n}\n\nfunction setupOobTraces(performanceController: PerformanceController): void {\n const api = Api.getInstance();\n const navigationTimings = api.getEntriesByType(\n 'navigation'\n ) as PerformanceNavigationTiming[];\n const paintTimings = api.getEntriesByType('paint');\n // If First Input Desly polyfill is added to the page, report the fid value.\n // https://github.com/GoogleChromeLabs/first-input-delay\n if (api.onFirstInputDelay) {\n // If the fid call back is not called for certain time, continue without it.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let timeoutId: any = setTimeout(() => {\n Trace.createOobTrace(\n performanceController,\n navigationTimings,\n paintTimings\n );\n timeoutId = undefined;\n }, FID_WAIT_TIME_MS);\n api.onFirstInputDelay((fid: number) => {\n if (timeoutId) {\n clearTimeout(timeoutId);\n Trace.createOobTrace(\n performanceController,\n navigationTimings,\n paintTimings,\n fid\n );\n }\n });\n } else {\n Trace.createOobTrace(\n performanceController,\n navigationTimings,\n paintTimings\n );\n }\n}\n\nfunction setupUserTimingTraces(\n performanceController: PerformanceController\n): void {\n const api = Api.getInstance();\n // Run through the measure performance entries collected up to this point.\n const measures = api.getEntriesByType('measure');\n for (const measure of measures) {\n createUserTimingTrace(performanceController, measure);\n }\n // Setup an observer to capture the measures from this point on.\n api.setupObserver('measure', entry =>\n createUserTimingTrace(performanceController, entry)\n );\n}\n\nfunction createUserTimingTrace(\n performanceController: PerformanceController,\n measure: PerformanceEntry\n): void {\n const measureName = measure.name;\n // Do not create a trace, if the user timing marks and measures are created by the sdk itself.\n if (\n measureName.substring(0, TRACE_MEASURE_PREFIX.length) ===\n TRACE_MEASURE_PREFIX\n ) {\n return;\n }\n Trace.createUserTimingTrace(performanceController, measureName);\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 { setupOobResources } from '../services/oob_resources_service';\nimport { SettingsService } from '../services/settings_service';\nimport { getInitializationPromise } from '../services/initialization_service';\nimport { Api } from '../services/api_service';\nimport { FirebaseApp } from '@firebase/app';\nimport { _FirebaseInstallationsInternal } from '@firebase/installations';\nimport { PerformanceSettings, FirebasePerformance } from '../public_types';\nimport { validateIndexedDBOpenable } from '@firebase/util';\nimport { setupTransportService } from '../services/transport_service';\nimport { consoleLogger } from '../utils/console_logger';\n\nexport class PerformanceController implements FirebasePerformance {\n private initialized: boolean = false;\n\n constructor(\n readonly app: FirebaseApp,\n readonly installations: _FirebaseInstallationsInternal\n ) {}\n\n /**\n * This method *must* be called internally as part of creating a\n * PerformanceController instance.\n *\n * Currently it's not possible to pass the settings object through the\n * constructor using Components, so this method exists to be called with the\n * desired settings, to ensure nothing is collected without the user's\n * consent.\n */\n _init(settings?: PerformanceSettings): void {\n if (this.initialized) {\n return;\n }\n\n if (settings?.dataCollectionEnabled !== undefined) {\n this.dataCollectionEnabled = settings.dataCollectionEnabled;\n }\n if (settings?.instrumentationEnabled !== undefined) {\n this.instrumentationEnabled = settings.instrumentationEnabled;\n }\n\n if (Api.getInstance().requiredApisAvailable()) {\n validateIndexedDBOpenable()\n .then(isAvailable => {\n if (isAvailable) {\n setupTransportService();\n getInitializationPromise(this).then(\n () => setupOobResources(this),\n () => setupOobResources(this)\n );\n this.initialized = true;\n }\n })\n .catch(error => {\n consoleLogger.info(`Environment doesn't support IndexedDB: ${error}`);\n });\n } else {\n consoleLogger.info(\n 'Firebase Performance cannot start if the browser does not support ' +\n '\"Fetch\" and \"Promise\", or cookies are disabled.'\n );\n }\n }\n\n set instrumentationEnabled(val: boolean) {\n SettingsService.getInstance().instrumentationEnabled = val;\n }\n get instrumentationEnabled(): boolean {\n return SettingsService.getInstance().instrumentationEnabled;\n }\n\n set dataCollectionEnabled(val: boolean) {\n SettingsService.getInstance().dataCollectionEnabled = val;\n }\n get dataCollectionEnabled(): boolean {\n return SettingsService.getInstance().dataCollectionEnabled;\n }\n}\n","/**\n * Firebase Performance Monitoring\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 {\n FirebasePerformance,\n PerformanceSettings,\n PerformanceTrace\n} from './public_types';\nimport { ERROR_FACTORY, ErrorCode } from './utils/errors';\nimport { setupApi } from './services/api_service';\nimport { PerformanceController } from './controllers/perf';\nimport {\n _registerComponent,\n _getProvider,\n registerVersion,\n FirebaseApp,\n getApp\n} from '@firebase/app';\nimport {\n InstanceFactory,\n ComponentContainer,\n Component,\n ComponentType\n} from '@firebase/component';\nimport { name, version } from '../package.json';\nimport { Trace } from './resources/trace';\nimport '@firebase/installations';\nimport { deepEqual, getModularInstance } from '@firebase/util';\n\nconst DEFAULT_ENTRY_NAME = '[DEFAULT]';\n\n/**\n * Returns a {@link FirebasePerformance} instance for the given app.\n * @param app - The {@link @firebase/app#FirebaseApp} to use.\n * @public\n */\nexport function getPerformance(\n app: FirebaseApp = getApp()\n): FirebasePerformance {\n app = getModularInstance(app);\n const provider = _getProvider(app, 'performance');\n const perfInstance = provider.getImmediate() as PerformanceController;\n return perfInstance;\n}\n\n/**\n * Returns a {@link FirebasePerformance} instance for the given app. Can only be called once.\n * @param app - The {@link @firebase/app#FirebaseApp} to use.\n * @param settings - Optional settings for the {@link FirebasePerformance} instance.\n * @public\n */\nexport function initializePerformance(\n app: FirebaseApp,\n settings?: PerformanceSettings\n): FirebasePerformance {\n app = getModularInstance(app);\n const provider = _getProvider(app, 'performance');\n\n // throw if an instance was already created.\n // It could happen if initializePerformance() is called more than once, or getPerformance() is called first.\n if (provider.isInitialized()) {\n const existingInstance = provider.getImmediate();\n const initialSettings = provider.getOptions() as PerformanceSettings;\n if (deepEqual(initialSettings, settings ?? {})) {\n return existingInstance;\n } else {\n throw ERROR_FACTORY.create(ErrorCode.ALREADY_INITIALIZED);\n }\n }\n\n const perfInstance = provider.initialize({\n options: settings\n }) as PerformanceController;\n return perfInstance;\n}\n\n/**\n * Returns a new `PerformanceTrace` instance.\n * @param performance - The {@link FirebasePerformance} instance to use.\n * @param name - The name of the trace.\n * @public\n */\nexport function trace(\n performance: FirebasePerformance,\n name: string\n): PerformanceTrace {\n performance = getModularInstance(performance);\n return new Trace(performance as PerformanceController, name);\n}\n\nconst factory: InstanceFactory<'performance'> = (\n container: ComponentContainer,\n { options: settings }: { options?: PerformanceSettings }\n) => {\n // Dependencies\n const app = container.getProvider('app').getImmediate();\n const installations = container\n .getProvider('installations-internal')\n .getImmediate();\n\n if (app.name !== DEFAULT_ENTRY_NAME) {\n throw ERROR_FACTORY.create(ErrorCode.FB_NOT_DEFAULT);\n }\n if (typeof window === 'undefined') {\n throw ERROR_FACTORY.create(ErrorCode.NO_WINDOW);\n }\n setupApi(window);\n const perfInstance = new PerformanceController(app, installations);\n perfInstance._init(settings);\n\n return perfInstance;\n};\n\nfunction registerPerformance(): void {\n _registerComponent(\n new Component('performance', factory, ComponentType.PUBLIC)\n );\n registerVersion(name, version);\n // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation\n registerVersion(name, version, '__BUILD_TARGET__');\n}\n\nregisterPerformance();\n\nexport { FirebasePerformance, PerformanceSettings, PerformanceTrace };\n"],"names":["FirebaseError","Error","constructor","code","message","customData","super","this","name","Object","setPrototypeOf","prototype","captureStackTrace","ErrorFactory","create","service","serviceName","errors","data","fullCode","template","replace","PATTERN","_","key","value","String","replaceTemplate","fullMessage","deepEqual","a","b","aKeys","keys","bKeys","k","includes","aProp","bProp","isObject","thing","getModularInstance","_delegate","LogLevel","levelStringToEnum","debug","DEBUG","verbose","VERBOSE","info","INFO","warn","WARN","error","ERROR","silent","SILENT","defaultLogLevel","ConsoleMethod","defaultLogHandler","instance","logType","args","logLevel","now","Date","toISOString","method","console","Component","instanceFactory","type","multipleInstances","serviceProps","instantiationMode","onInstanceCreated","setInstantiationMode","mode","setMultipleInstances","setServiceProps","props","setInstanceCreatedCallback","callback","idbProxyableTypes","cursorAdvanceMethods","cursorRequestMap","WeakMap","transactionDoneMap","transactionStoreNamesMap","transformCache","reverseTransformCache","idbProxyTraps","get","target","prop","receiver","IDBTransaction","objectStoreNames","undefined","objectStore","wrap","set","has","wrapFunction","func","IDBDatabase","transaction","IDBCursor","advance","continue","continuePrimaryKey","apply","unwrap","storeNames","tx","call","sort","transformCachableValue","done","Promise","resolve","reject","unlisten","removeEventListener","complete","DOMException","addEventListener","cacheDonePromiseForTransaction","object","IDBObjectStore","IDBIndex","some","c","Proxy","IDBRequest","request","promise","success","result","then","catch","promisifyRequest","newValue","readMethods","writeMethods","cachedMethods","Map","getMethod","targetFuncName","useIndex","isWrite","async","storeName","store","index","shift","all","oldTraps","PACKAGE_VERSION","version","ERROR_FACTORY","isServerError","getInstallationsEndpoint","projectId","extractAuthTokenInfoFromResponse","response","token","requestStatus","expiresIn","responseExpiresIn","Number","creationTime","getErrorFromResponse","requestName","errorData","json","serverCode","serverMessage","serverStatus","status","getHeaders","apiKey","Headers","Accept","getHeadersWithAuth","appConfig","refreshToken","headers","append","getAuthorizationHeader","retryIfServerError","fn","sleep","ms","setTimeout","VALID_FID_PATTERN","generateFid","fidByteArray","Uint8Array","self","crypto","msCrypto","getRandomValues","fid","array","btoa","fromCharCode","substr","encode","test","_a","getKey","appName","appId","fidChangeCallbacks","fidChanged","callFidChangeCallbacks","channel","broadcastChannel","BroadcastChannel","onmessage","e","getBroadcastChannel","postMessage","size","close","broadcastFidChange","callbacks","OBJECT_STORE_NAME","dbPromise","getDbPromise","blocked","upgrade","blocking","terminated","indexedDB","open","openPromise","event","oldVersion","newVersion","db","openDB","createObjectStore","oldValue","put","remove","delete","update","updateFn","getInstallationEntry","installations","registrationPromise","installationEntry","oldEntry","clearTimedOutRequest","registrationStatus","updateOrCreateInstallationEntry","entryWithPromise","navigator","onLine","inProgressEntry","registrationTime","registeredInstallationEntry","heartbeatServiceProvider","endpoint","heartbeatService","getImmediate","optional","heartbeatsHeader","getHeartbeatsHeader","body","authVersion","sdkVersion","JSON","stringify","fetch","ok","responseValue","authToken","createInstallationRequest","registerInstallation","waitUntilFidRegistration","triggerRegistrationIfNecessary","entry","updateInstallationRequest","generateAuthTokenRequest","getGenerateAuthTokenEndpoint","installation","refreshAuthToken","forceRefresh","tokenPromise","isEntryRegistered","oldAuthToken","isAuthTokenExpired","isAuthTokenValid","updateAuthTokenRequest","waitUntilAuthTokenRequest","inProgressAuthToken","requestTime","assign","makeAuthTokenRequestInProgressEntry","updatedInstallationEntry","fetchAuthTokenFromServer","getToken","installationsImpl","completeInstallationRegistration","getMissingValueError","valueName","internalFactory","container","app","getProvider","_getProvider","getId","_registerComponent","options","configKeys","keyName","extractAppConfig","_delete","registerVersion","consoleLogger","_logLevel","_logHandler","_userLogHandler","val","TypeError","setLogLevel","logHandler","userLogHandler","log","apiInstance","windowInstance","iid","settingsServiceInstance","Api","window","performance","PerformanceObserver","windowLocation","location","document","cookieEnabled","localStorage","perfMetrics","onFirstInputDelay","getUrl","href","split","mark","measure","measureName","mark1","mark2","getEntriesByType","getEntriesByName","getTimeOrigin","timeOrigin","timing","navigationStart","requiredApisAvailable","setupObserver","entryType","list","getEntries","observe","entryTypes","static","getIid","mergeStrings","part1","part2","sizeDiff","length","resultArray","i","push","charAt","join","SettingsService","instrumentationEnabled","dataCollectionEnabled","loggingEnabled","tracesSamplingRate","networkRequestsSamplingRate","logEndPointUrl","flTransportEndpointUrl","transportKey","logSource","logTraceAfterSampling","logNetworkAfterSampling","configTimeToLive","getFlTransportFullUrl","concat","VisibilityState","RESERVED_ATTRIBUTE_PREFIXES","ATTRIBUTE_FORMAT_REGEX","RegExp","getServiceWorkerStatus","getInstance","serviceWorker","controller","getVisibilityState","visibilityState","VISIBLE","HIDDEN","UNKNOWN","getEffectiveConnectionType","navigatorConnection","connection","effectiveType","getAppId","firebaseApp","DEFAULT_CONFIGS","getConfig","performanceController","config","expiryString","getItem","expiry","configStringified","parse","getStoredConfig","processConfig","installationsService","authTokenPromise","authTokenVal","getAuthTokenPromise","getProjectId","getApiKey","Request","Authorization","app_instance_id","app_instance_id_token","app_id","app_version","sdk_version","getRemoteConfig","setItem","storeConfig","entries","fpr_enabled","fpr_log_source","fpr_log_endpoint_url","fpr_log_transport_key","fpr_vc_network_request_sampling_rate","fpr_vc_trace_sampling_rate","shouldLogAfterSampling","samplingRate","Math","random","initializationPromise","initializationStatus","getInitializationPromise","readyState","handler","getDocumentReadyComplete","iidPromise","iidVal","getIidPromise","changeInitializationStatus","initializePerf","logger","remainingTries","queue","isTransportSetup","processQueue","timeOffset","staged","splice","log_event","map","evt","source_extension_json_proto3","event_time_ms","eventTime","flTransportFullUrl","postToFlEndpoint","res","transportWait","nextRequestWaitMillis","requestOffset","isNaN","max","logResponseDetails","Array","isArray","responseAction","sendEventsToFl","request_time_ms","client_info","client_type","js_client_info","log_source","dispatchQueueEvents","transportHandler","serializer","addToQueue","sendLog","resource","resourceType","logTrace","trace","settingsService","isAuto","sendTraceLog","networkRequest","networkRequestMetric","url","http_method","httpMethod","http_response_code","response_payload_bytes","responsePayloadBytes","client_start_time_us","startTimeUs","time_to_response_initiated_us","timeToResponseInitiatedUs","time_to_response_completed_us","timeToResponseCompletedUs","perfMetric","application_info","getApplicationInfo","network_request_metric","serializeNetworkRequest","traceMetric","is_auto","duration_us","durationUs","counters","customAttributes","getAttributes","custom_attributes","trace_metric","serializeTrace","google_app_id","web_app_info","page_url","service_worker_status","visibility_state","effective_connection_type","application_process_state","oobMetrics","Trace","traceMeasureName","state","api","randomId","floor","traceStartMark","traceStopMark","traceMeasure","calculateTraceMetrics","start","traceName","stop","record","startTime","duration","attributes","metrics","metricName","incrementMetric","counter","numAsInteger","putMetric","startsWith","indexOf","isValidMetricName","customMetricName","providedValue","valueAsInteger","convertMetricValueToInteger","getMetric","putAttribute","attr","isValidName","prefix","match","isValidCustomAttributeName","isValidValue","isValidCustomAttributeValue","attributeName","attributeValue","getAttribute","removeAttribute","setStartTime","setDuration","perfMeasureEntries","perfMeasureEntry","navigationTimings","paintTimings","firstInputDelay","route","timeOriginUs","domInteractive","domContentLoadedEventEnd","loadEventEnd","firstPaint","find","paintObject","firstContentfulPaint","createNetworkRequestEntry","performanceEntry","responseStart","responseEnd","networkRequestUrl","logEndpointUrl","flEndpointUrl","logNetworkRequest","transferSize","setupOobResources","timeoutId","createOobTrace","clearTimeout","setupOobTraces","resources","setupNetworkRequests","measures","createUserTimingTrace","setupUserTimingTraces","substring","PerformanceController","initialized","_init","settings","preExist","DB_CHECK_NAME","onsuccess","deleteDatabase","onupgradeneeded","onerror","isAvailable","getPerformance","getApp","initializePerformance","provider","isInitialized","existingInstance","getOptions","initialize","setupApi","perfInstance"],"mappings":"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","preExistingComment":"firebase-performance.js.map"}