1import { registerVersion, _registerComponent, _getProvider, getApp } from 'https://www.gstatic.com/firebasejs/9.6.4/firebase-app.js'; 2 3/** 4 * @license 5 * Copyright 2017 Google LLC 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19/** 20 * This method checks if indexedDB is supported by current browser/service worker context 21 * @return true if indexedDB is supported by current browser/service worker context 22 */ 23function isIndexedDBAvailable() { 24 return typeof indexedDB === 'object'; 25} 26/** 27 * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject 28 * if errors occur during the database open operation. 29 * 30 * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox 31 * private browsing) 32 */ 33function validateIndexedDBOpenable() { 34 return new Promise((resolve, reject) => { 35 try { 36 let preExist = true; 37 const DB_CHECK_NAME = 'validate-browser-context-for-indexeddb-analytics-module'; 38 const request = self.indexedDB.open(DB_CHECK_NAME); 39 request.onsuccess = () => { 40 request.result.close(); 41 // delete database only when it doesn't pre-exist 42 if (!preExist) { 43 self.indexedDB.deleteDatabase(DB_CHECK_NAME); 44 } 45 resolve(true); 46 }; 47 request.onupgradeneeded = () => { 48 preExist = false; 49 }; 50 request.onerror = () => { 51 var _a; 52 reject(((_a = request.error) === null || _a === void 0 ? void 0 : _a.message) || ''); 53 }; 54 } 55 catch (error) { 56 reject(error); 57 } 58 }); 59} 60/** 61 * 62 * This method checks whether cookie is enabled within current browser 63 * @return true if cookie is enabled within current browser 64 */ 65function areCookiesEnabled() { 66 if (typeof navigator === 'undefined' || !navigator.cookieEnabled) { 67 return false; 68 } 69 return true; 70} 71 72/** 73 * @license 74 * Copyright 2017 Google LLC 75 * 76 * Licensed under the Apache License, Version 2.0 (the "License"); 77 * you may not use this file except in compliance with the License. 78 * You may obtain a copy of the License at 79 * 80 * http://www.apache.org/licenses/LICENSE-2.0 81 * 82 * Unless required by applicable law or agreed to in writing, software 83 * distributed under the License is distributed on an "AS IS" BASIS, 84 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 * See the License for the specific language governing permissions and 86 * limitations under the License. 87 */ 88/** 89 * @fileoverview Standardized Firebase Error. 90 * 91 * Usage: 92 * 93 * // Typescript string literals for type-safe codes 94 * type Err = 95 * 'unknown' | 96 * 'object-not-found' 97 * ; 98 * 99 * // Closure enum for type-safe error codes 100 * // at-enum {string} 101 * var Err = { 102 * UNKNOWN: 'unknown', 103 * OBJECT_NOT_FOUND: 'object-not-found', 104 * } 105 * 106 * let errors: Map<Err, string> = { 107 * 'generic-error': "Unknown error", 108 * 'file-not-found': "Could not find file: {$file}", 109 * }; 110 * 111 * // Type-safe function - must pass a valid error code as param. 112 * let error = new ErrorFactory<Err>('service', 'Service', errors); 113 * 114 * ... 115 * throw error.create(Err.GENERIC); 116 * ... 117 * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); 118 * ... 119 * // Service: Could not file file: foo.txt (service/file-not-found). 120 * 121 * catch (e) { 122 * assert(e.message === "Could not find file: foo.txt."); 123 * if (e.code === 'service/file-not-found') { 124 * console.log("Could not read file: " + e['file']); 125 * } 126 * } 127 */ 128const ERROR_NAME = 'FirebaseError'; 129// Based on code from: 130// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types
131class FirebaseError extends Error { 132 constructor( 133 /** The error code for this error. */ 134 code, message, 135 /** Custom data for this error. */ 136 customData) { 137 super(message); 138 this.code = code; 139 this.customData = customData; 140 /** The custom name for all FirebaseErrors. */ 141 this.name = ERROR_NAME; 142 // Fix For ES5 143 // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work 144 Object.setPrototypeOf(this, FirebaseError.prototype); 145 // Maintains proper stack trace for where our error was thrown. 146 // Only available on V8. 147 if (Error.captureStackTrace) { 148 Error.captureStackTrace(this, ErrorFactory.prototype.create); 149 } 150 } 151} 152class ErrorFactory { 153 constructor(service, serviceName, errors) { 154 this.service = service; 155 this.serviceName = serviceName; 156 this.errors = errors; 157 } 158 create(code, ...data) { 159 const customData = data[0] || {}; 160 const fullCode = `${this.service}/${code}`; 161 const template = this.errors[code]; 162 const message = template ? replaceTemplate(template, customData) : 'Error'; 163 // Service Name: Error message (service/code). 164 const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`; 165 const error = new FirebaseError(fullCode, fullMessage, customData); 166 return error; 167 } 168} 169function replaceTemplate(template, data) { 170 return template.replace(PATTERN, (_, key) => { 171 const value = data[key]; 172 return value != null ? String(value) : `<${key}?>`; 173 }); 174} 175const PATTERN = /\{\$([^}]+)}/g; 176/** 177 * Deep equal two objects. Support Arrays and Objects. 178 */ 179function deepEqual(a, b) { 180 if (a === b) { 181 return true; 182 } 183 const aKeys = Object.keys(a); 184 const bKeys = Object.keys(b); 185 for (const k of aKeys) { 186 if (!bKeys.includes(k)) { 187 return false; 188 } 189 const aProp = a[k]; 190 const bProp = b[k]; 191 if (isObject(aProp) && isObject(bProp)) { 192 if (!deepEqual(aProp, bProp)) { 193 return false; 194 } 195 } 196 else if (aProp !== bProp) { 197 return false; 198 } 199 } 200 for (const k of bKeys) { 201 if (!aKeys.includes(k)) { 202 return false; 203 } 204 } 205 return true; 206} 207function isObject(thing) { 208 return thing !== null && typeof thing === 'object'; 209} 210 211/** 212 * @license 213 * Copyright 2021 Google LLC 214 * 215 * Licensed under the Apache License, Version 2.0 (the "License"); 216 * you may not use this file except in compliance with the License. 217 * You may obtain a copy of the License at 218 * 219 * http://www.apache.org/licenses/LICENSE-2.0 220 * 221 * Unless required by applicable law or agreed to in writing, software 222 * distributed under the License is distributed on an "AS IS" BASIS, 223 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 224 * See the License for the specific language governing permissions and 225 * limitations under the License. 226 */ 227function getModularInstance(service) { 228 if (service && service._delegate) { 229 return service._delegate; 230 } 231 else { 232 return service; 233 } 234} 235 236/** 237 * @license 238 * Copyright 2017 Google LLC 239 * 240 * Licensed under the Apache License, Version 2.0 (the "License"); 241 * you may not use this file except in compliance with the License. 242 * You may obtain a copy of the License at 243 * 244 * http://www.apache.org/licenses/LICENSE-2.0 245 * 246 * Unless required by applicable law or agreed to in writing, software 247 * distributed under the License is distributed on an "AS IS" BASIS, 248 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 249 * See the License for the specific language governing permissions and 250 * limitations under the License. 251 */ 252/** 253 * The JS SDK supports 5 log levels and also allows a user the ability to 254 * silence the logs altogether. 255 * 256 * The order is a follows: 257 * DEBUG < VERBOSE < INFO < WARN < ERROR 258 * 259 * All of the log types above the current log level will be captured (i.e. if 260 * you set the log level to `INFO`, errors will still be logged, but `DEBUG` and 261 * `VERBOSE` logs will not) 262 */ 263var LogLevel; 264(function (LogLevel) { 265 LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG"; 266 LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE"; 267 LogLevel[LogLevel["INFO"] = 2] = "INFO"; 268 LogLevel[LogLevel["WARN"] = 3] = "WARN";
vendor: 4,622 bytes, lines 269-404
269 LogLevel[LogLevel["ERROR"] = 4] = "ERROR"; 270 LogLevel[LogLevel["SILENT"] = 5] = "SILENT"; 271})(LogLevel || (LogLevel = {})); 272const levelStringToEnum = { 273 'debug': LogLevel.DEBUG, 274 'verbose': LogLevel.VERBOSE, 275 'info': LogLevel.INFO, 276 'warn': LogLevel.WARN, 277 'error': LogLevel.ERROR, 278 'silent': LogLevel.SILENT 279}; 280/** 281 * The default log level 282 */ 283const defaultLogLevel = LogLevel.INFO; 284/** 285 * By default, `console.debug` is not displayed in the developer console (in 286 * chrome). To avoid forcing users to have to opt-in to these logs twice 287 * (i.e. once for firebase, and once in the console), we are sending `DEBUG` 288 * logs to the `console.log` function. 289 */ 290const ConsoleMethod = { 291 [LogLevel.DEBUG]: 'log', 292 [LogLevel.VERBOSE]: 'log', 293 [LogLevel.INFO]: 'info', 294 [LogLevel.WARN]: 'warn', 295 [LogLevel.ERROR]: 'error' 296}; 297/** 298 * The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR 299 * messages on to their corresponding console counterparts (if the log method 300 * is supported by the current log level) 301 */ 302const defaultLogHandler = (instance, logType, ...args) => { 303 if (logType < instance.logLevel) { 304 return; 305 } 306 const now = new Date().toISOString(); 307 const method = ConsoleMethod[logType]; 308 if (method) { 309 console[method](`[${now}] ${instance.name}:`, ...args); 310 } 311 else { 312 throw new Error(`Attempted to log a message with an invalid logType (value: ${logType})`); 313 } 314}; 315class Logger { 316 /** 317 * Gives you an instance of a Logger to capture messages according to 318 * Firebase's logging scheme. 319 * 320 * @param name The name that the logs will be associated with 321 */ 322 constructor(name) { 323 this.name = name; 324 /** 325 * The log level of the given Logger instance. 326 */ 327 this._logLevel = defaultLogLevel; 328 /** 329 * The main (internal) log handler for the Logger instance. 330 * Can be set to a new function in internal package code but not by user. 331 */ 332 this._logHandler = defaultLogHandler; 333 /** 334 * The optional, additional, user-defined log handler for the Logger instance. 335 */ 336 this._userLogHandler = null; 337 } 338 get logLevel() { 339 return this._logLevel; 340 } 341 set logLevel(val) { 342 if (!(val in LogLevel)) { 343 throw new TypeError(`Invalid value "${val}" assigned to \`logLevel\``); 344 } 345 this._logLevel = val; 346 } 347 // Workaround for setter/getter having to be the same type. 348 setLogLevel(val) { 349 this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val; 350 } 351 get logHandler() { 352 return this._logHandler; 353 } 354 set logHandler(val) { 355 if (typeof val !== 'function') { 356 throw new TypeError('Value assigned to `logHandler` must be a function'); 357 } 358 this._logHandler = val; 359 } 360 get userLogHandler() { 361 return this._userLogHandler; 362 } 363 set userLogHandler(val) { 364 this._userLogHandler = val; 365 } 366 /** 367 * The functions below are all based on the `console` interface 368 */ 369 debug(...args) { 370 this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args); 371 this._logHandler(this, LogLevel.DEBUG, ...args); 372 } 373 log(...args) { 374 this._userLogHandler && 375 this._userLogHandler(this, LogLevel.VERBOSE, ...args); 376 this._logHandler(this, LogLevel.VERBOSE, ...args); 377 } 378 info(...args) { 379 this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args); 380 this._logHandler(this, LogLevel.INFO, ...args); 381 } 382 warn(...args) { 383 this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args); 384 this._logHandler(this, LogLevel.WARN, ...args); 385 } 386 error(...args) { 387 this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args); 388 this._logHandler(this, LogLevel.ERROR, ...args); 389 } 390} 391 392/** 393 * Component for service name T, e.g. `auth`, `auth-internal` 394 */ 395class Component { 396 /** 397 * 398 * @param name The public service name, e.g. app, auth, firestore, database 399 * @param instanceFactory Service factory responsible for creating the public interface 400 * @param type whether the service provided by the component is public or private 401 */ 402 constructor(name, instanceFactory, type) { 403 this.name = name; 404 this.instanceFactory = instanceFactory;
vendor: 6,182 bytes, lines 405-673
405 this.type = type; 406 this.multipleInstances = false; 407 /** 408 * Properties to be added to the service namespace 409 */ 410 this.serviceProps = {}; 411 this.instantiationMode = "LAZY" /* LAZY */; 412 this.onInstanceCreated = null; 413 } 414 setInstantiationMode(mode) { 415 this.instantiationMode = mode; 416 return this; 417 } 418 setMultipleInstances(multipleInstances) { 419 this.multipleInstances = multipleInstances; 420 return this; 421 } 422 setServiceProps(props) { 423 this.serviceProps = props; 424 return this; 425 } 426 setInstanceCreatedCallback(callback) { 427 this.onInstanceCreated = callback; 428 return this; 429 } 430} 431 432function toArray(arr) { 433 return Array.prototype.slice.call(arr); 434} 435 436function promisifyRequest(request) { 437 return new Promise(function(resolve, reject) { 438 request.onsuccess = function() { 439 resolve(request.result); 440 }; 441 442 request.onerror = function() { 443 reject(request.error); 444 }; 445 }); 446} 447 448function promisifyRequestCall(obj, method, args) { 449 var request; 450 var p = new Promise(function(resolve, reject) { 451 request = obj[method].apply(obj, args); 452 promisifyRequest(request).then(resolve, reject); 453 }); 454 455 p.request = request; 456 return p; 457} 458 459function promisifyCursorRequestCall(obj, method, args) { 460 var p = promisifyRequestCall(obj, method, args); 461 return p.then(function(value) { 462 if (!value) return; 463 return new Cursor(value, p.request); 464 }); 465} 466 467function proxyProperties(ProxyClass, targetProp, properties) { 468 properties.forEach(function(prop) { 469 Object.defineProperty(ProxyClass.prototype, prop, { 470 get: function() { 471 return this[targetProp][prop]; 472 }, 473 set: function(val) { 474 this[targetProp][prop] = val; 475 } 476 }); 477 }); 478} 479 480function proxyRequestMethods(ProxyClass, targetProp, Constructor, properties) { 481 properties.forEach(function(prop) { 482 if (!(prop in Constructor.prototype)) return; 483 ProxyClass.prototype[prop] = function() { 484 return promisifyRequestCall(this[targetProp], prop, arguments); 485 }; 486 }); 487} 488 489function proxyMethods(ProxyClass, targetProp, Constructor, properties) { 490 properties.forEach(function(prop) { 491 if (!(prop in Constructor.prototype)) return; 492 ProxyClass.prototype[prop] = function() { 493 return this[targetProp][prop].apply(this[targetProp], arguments); 494 }; 495 }); 496} 497 498function proxyCursorRequestMethods(ProxyClass, targetProp, Constructor, properties) { 499 properties.forEach(function(prop) { 500 if (!(prop in Constructor.prototype)) return; 501 ProxyClass.prototype[prop] = function() { 502 return promisifyCursorRequestCall(this[targetProp], prop, arguments); 503 }; 504 }); 505} 506 507function Index(index) { 508 this._index = index; 509} 510 511proxyProperties(Index, '_index', [ 512 'name', 513 'keyPath', 514 'multiEntry', 515 'unique' 516]); 517 518proxyRequestMethods(Index, '_index', IDBIndex, [ 519 'get', 520 'getKey', 521 'getAll', 522 'getAllKeys', 523 'count' 524]); 525 526proxyCursorRequestMethods(Index, '_index', IDBIndex, [ 527 'openCursor', 528 'openKeyCursor' 529]); 530 531function Cursor(cursor, request) { 532 this._cursor = cursor; 533 this._request = request; 534} 535 536proxyProperties(Cursor, '_cursor', [ 537 'direction', 538 'key', 539 'primaryKey', 540 'value' 541]); 542 543proxyRequestMethods(Cursor, '_cursor', IDBCursor, [ 544 'update', 545 'delete' 546]); 547 548// proxy 'next' methods 549['advance', 'continue', 'continuePrimaryKey'].forEach(function(methodName) { 550 if (!(methodName in IDBCursor.prototype)) return; 551 Cursor.prototype[methodName] = function() { 552 var cursor = this; 553 var args = arguments; 554 return Promise.resolve().then(function() { 555 cursor._cursor[methodName].apply(cursor._cursor, args); 556 return promisifyRequest(cursor._request).then(function(value) { 557 if (!value) return; 558 return new Cursor(value, cursor._request); 559 }); 560 }); 561 }; 562}); 563 564function ObjectStore(store) { 565 this._store = store; 566} 567 568ObjectStore.prototype.createIndex = function() { 569 return new Index(this._store.createIndex.apply(this._store, arguments)); 570}; 571 572ObjectStore.prototype.index = function() { 573 return new Index(this._store.index.apply(this._store, arguments)); 574}; 575 576proxyProperties(ObjectStore, '_store', [ 577 'name', 578 'keyPath', 579 'indexNames', 580 'autoIncrement' 581]); 582 583proxyRequestMethods(ObjectStore, '_store', IDBObjectStore, [ 584 'put', 585 'add', 586 'delete', 587 'clear', 588 'get', 589 'getAll', 590 'getKey', 591 'getAllKeys', 592 'count' 593]); 594 595proxyCursorRequestMethods(ObjectStore, '_store', IDBObjectStore, [ 596 'openCursor', 597 'openKeyCursor' 598]); 599 600proxyMethods(ObjectStore, '_store', IDBObjectStore, [ 601 'deleteIndex' 602]); 603 604function Transaction(idbTransaction) { 605 this._tx = idbTransaction; 606 this.complete = new Promise(function(resolve, reject) { 607 idbTransaction.oncomplete = function() { 608 resolve(); 609 }; 610 idbTransaction.onerror = function() { 611 reject(idbTransaction.error); 612 }; 613 idbTransaction.onabort = function() { 614 reject(idbTransaction.error); 615 }; 616 }); 617} 618 619Transaction.prototype.objectStore = function() { 620 return new ObjectStore(this._tx.objectStore.apply(this._tx, arguments)); 621}; 622 623proxyProperties(Transaction, '_tx', [ 624 'objectStoreNames', 625 'mode' 626]); 627 628proxyMethods(Transaction, '_tx', IDBTransaction, [ 629 'abort' 630]); 631 632function UpgradeDB(db, oldVersion, transaction) { 633 this._db = db; 634 this.oldVersion = oldVersion; 635 this.transaction = new Transaction(transaction); 636} 637 638UpgradeDB.prototype.createObjectStore = function() { 639 return new ObjectStore(this._db.createObjectStore.apply(this._db, arguments)); 640}; 641 642proxyProperties(UpgradeDB, '_db', [ 643 'name', 644 'version', 645 'objectStoreNames' 646]); 647 648proxyMethods(UpgradeDB, '_db', IDBDatabase, [ 649 'deleteObjectStore', 650 'close' 651]); 652 653function DB(db) { 654 this._db = db; 655} 656 657DB.prototype.transaction = function() { 658 return new Transaction(this._db.transaction.apply(this._db, arguments)); 659}; 660 661proxyProperties(DB, '_db', [ 662 'name', 663 'version', 664 'objectStoreNames' 665]); 666 667proxyMethods(DB, '_db', IDBDatabase, [ 668 'close' 669]); 670 671// Add cursor iterators 672// TODO: remove this once browsers do the right thing with promises 673['openCursor', 'openKeyCursor'].forEach(function(funcName) {
674 [ObjectStore, Index].forEach(function(Constructor) { 675 // Don't create iterateKeyCursor if openKeyCursor doesn't exist. 676 if (!(funcName in Constructor.prototype)) return; 677 678 Constructor.prototype[funcName.replace('open', 'iterate')] = function() { 679 var args = toArray(arguments); 680 var callback = args[args.length - 1]; 681 var nativeObject = this._store || this._index; 682 var request = nativeObject[funcName].apply(nativeObject, args.slice(0, -1)); 683 request.onsuccess = function() { 684 callback(request.result); 685 }; 686 }; 687 }); 688}); 689 690// polyfill getAll 691[Index, ObjectStore].forEach(function(Constructor) { 692 if (Constructor.prototype.getAll) return; 693 Constructor.prototype.getAll = function(query, count) { 694 var instance = this; 695 var items = []; 696 697 return new Promise(function(resolve) { 698 instance.iterateCursor(query, function(cursor) { 699 if (!cursor) { 700 resolve(items); 701 return; 702 } 703 items.push(cursor.value); 704 705 if (count !== undefined && items.length == count) { 706 resolve(items); 707 return; 708 } 709 cursor.continue(); 710 }); 711 }); 712 }; 713}); 714 715function openDb(name, version, upgradeCallback) { 716 var p = promisifyRequestCall(indexedDB, 'open', [name, version]); 717 var request = p.request; 718 719 if (request) { 720 request.onupgradeneeded = function(event) { 721 if (upgradeCallback) { 722 upgradeCallback(new UpgradeDB(request.result, event.oldVersion, request.transaction)); 723 } 724 }; 725 } 726 727 return p.then(function(db) { 728 return new DB(db); 729 }); 730} 731 732const name$1 = "@firebase/installations"; 733const version$1 = "0.5.5"; 734 735/** 736 * @license 737 * Copyright 2019 Google LLC 738 * 739 * Licensed under the Apache License, Version 2.0 (the "License"); 740 * you may not use this file except in compliance with the License. 741 * You may obtain a copy of the License at 742 * 743 * http://www.apache.org/licenses/LICENSE-2.0 744 * 745 * Unless required by applicable law or agreed to in writing, software 746 * distributed under the License is distributed on an "AS IS" BASIS, 747 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 748 * See the License for the specific language governing permissions and 749 * limitations under the License. 750 */ 751const PENDING_TIMEOUT_MS = 10000; 752const PACKAGE_VERSION = `w:${version$1}`; 753const INTERNAL_AUTH_VERSION = 'FIS_v2'; 754const INSTALLATIONS_API_URL = 'https://firebaseinstallations.googleapis.com/v1'; 755const TOKEN_EXPIRATION_BUFFER = 60 * 60 * 1000; // One hour 756const SERVICE$1 = 'installations'; 757const SERVICE_NAME$1 = 'Installations'; 758 759/** 760 * @license 761 * Copyright 2019 Google LLC 762 * 763 * Licensed under the Apache License, Version 2.0 (the "License"); 764 * you may not use this file except in compliance with the License. 765 * You may obtain a copy of the License at 766 * 767 * http://www.apache.org/licenses/LICENSE-2.0 768 * 769 * Unless required by applicable law or agreed to in writing, software 770 * distributed under the License is distributed on an "AS IS" BASIS, 771 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 772 * See the License for the specific language governing permissions and 773 * limitations under the License. 774 */ 775const ERROR_DESCRIPTION_MAP$1 = { 776 ["missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */]: 'Missing App configuration value: "{$valueName}"', 777 ["not-registered" /* NOT_REGISTERED */]: 'Firebase Installation is not registered.', 778 ["installation-not-found" /* INSTALLATION_NOT_FOUND */]: 'Firebase Installation not found.', 779 ["request-failed" /* REQUEST_FAILED */]: '{$requestName} request failed with error "{$serverCode} {$serverStatus}: {$serverMessage}"', 780 ["app-offline" /* APP_OFFLINE */]: 'Could not process request. Application offline.', 781 ["delete-pending-registration" /* DELETE_PENDING_REGISTRATION */]: "Can't delete installation while there is a pending registration request." 782}; 783const ERROR_FACTORY$1 = new ErrorFactory(SERVICE$1, SERVICE_NAME$1, ERROR_DESCRIPTION_MAP$1); 784/** Returns true if error is a FirebaseError that is based on an error from the server. */ 785function isServerError(error) { 786 return (error instanceof FirebaseError && 787 error.code.includes("request-failed" /* REQUEST_FAILED */)
vendor: 8,416 bytes, lines 787-1017
787); 788} 789 790/** 791 * @license 792 * Copyright 2019 Google LLC 793 * 794 * Licensed under the Apache License, Version 2.0 (the "License"); 795 * you may not use this file except in compliance with the License. 796 * You may obtain a copy of the License at 797 * 798 * http://www.apache.org/licenses/LICENSE-2.0 799 * 800 * Unless required by applicable law or agreed to in writing, software 801 * distributed under the License is distributed on an "AS IS" BASIS, 802 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 803 * See the License for the specific language governing permissions and 804 * limitations under the License. 805 */ 806function getInstallationsEndpoint({ projectId }) { 807 return `${INSTALLATIONS_API_URL}/projects/${projectId}/installations`; 808} 809function extractAuthTokenInfoFromResponse(response) { 810 return { 811 token: response.token, 812 requestStatus: 2 /* COMPLETED */, 813 expiresIn: getExpiresInFromResponseExpiresIn(response.expiresIn), 814 creationTime: Date.now() 815 }; 816} 817async function getErrorFromResponse(requestName, response) { 818 const responseJson = await response.json(); 819 const errorData = responseJson.error; 820 return ERROR_FACTORY$1.create("request-failed" /* REQUEST_FAILED */, { 821 requestName, 822 serverCode: errorData.code, 823 serverMessage: errorData.message, 824 serverStatus: errorData.status 825 }); 826} 827function getHeaders({ apiKey }) { 828 return new Headers({ 829 'Content-Type': 'application/json', 830 Accept: 'application/json', 831 'x-goog-api-key': apiKey 832 }); 833} 834function getHeadersWithAuth(appConfig, { refreshToken }) { 835 const headers = getHeaders(appConfig); 836 headers.append('Authorization', getAuthorizationHeader(refreshToken)); 837 return headers; 838} 839/** 840 * Calls the passed in fetch wrapper and returns the response. 841 * If the returned response has a status of 5xx, re-runs the function once and 842 * returns the response. 843 */ 844async function retryIfServerError(fn) { 845 const result = await fn(); 846 if (result.status >= 500 && result.status < 600) { 847 // Internal Server Error. Retry request. 848 return fn(); 849 } 850 return result; 851} 852function getExpiresInFromResponseExpiresIn(responseExpiresIn) { 853 // This works because the server will never respond with fractions of a second. 854 return Number(responseExpiresIn.replace('s', '000')); 855} 856function getAuthorizationHeader(refreshToken) { 857 return `${INTERNAL_AUTH_VERSION} ${refreshToken}`; 858} 859 860/** 861 * @license 862 * Copyright 2019 Google LLC 863 * 864 * Licensed under the Apache License, Version 2.0 (the "License"); 865 * you may not use this file except in compliance with the License. 866 * You may obtain a copy of the License at 867 * 868 * http://www.apache.org/licenses/LICENSE-2.0 869 * 870 * Unless required by applicable law or agreed to in writing, software 871 * distributed under the License is distributed on an "AS IS" BASIS, 872 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 873 * See the License for the specific language governing permissions and 874 * limitations under the License. 875 */ 876async function createInstallationRequest(appConfig, { fid }) { 877 const endpoint = getInstallationsEndpoint(appConfig); 878 const headers = getHeaders(appConfig); 879 const body = { 880 fid, 881 authVersion: INTERNAL_AUTH_VERSION, 882 appId: appConfig.appId, 883 sdkVersion: PACKAGE_VERSION 884 }; 885 const request = { 886 method: 'POST', 887 headers, 888 body: JSON.stringify(body) 889 }; 890 const response = await retryIfServerError(() => fetch(endpoint, request)); 891 if (response.ok) { 892 const responseValue = await response.json(); 893 const registeredInstallationEntry = { 894 fid: responseValue.fid || fid, 895 registrationStatus: 2 /* COMPLETED */, 896 refreshToken: responseValue.refreshToken, 897 authToken: extractAuthTokenInfoFromResponse(responseValue.authToken) 898 }; 899 return registeredInstallationEntry; 900 } 901 else { 902 throw await getErrorFromResponse('Create Installation', response); 903 } 904} 905 906/** 907 * @license 908 * Copyright 2019 Google LLC 909 * 910 * Licensed under the Apache License, Version 2.0 (the "License"); 911 * you may not use this file except in compliance with the License. 912 * You may obtain a copy of the License at 913 * 914 * http://www.apache.org/licenses/LICENSE-2.0 915 * 916 * Unless required by applicable law or agreed to in writing, software 917 * distributed under the License is distributed on an "AS IS" BASIS, 918 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 919 * See the License for the specific language governing permissions and 920 * limitations under the License. 921 */ 922/** Returns a promise that resolves after given time passes. */ 923function sleep(ms) { 924 return new Promise(resolve => { 925 setTimeout(resolve, ms); 926 }); 927} 928 929/** 930 * @license 931 * Copyright 2019 Google LLC 932 * 933 * Licensed under the Apache License, Version 2.0 (the "License"); 934 * you may not use this file except in compliance with the License. 935 * You may obtain a copy of the License at 936 * 937 * http://www.apache.org/licenses/LICENSE-2.0 938 * 939 * Unless required by applicable law or agreed to in writing, software 940 * distributed under the License is distributed on an "AS IS" BASIS, 941 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 942 * See the License for the specific language governing permissions and 943 * limitations under the License. 944 */ 945function bufferToBase64UrlSafe(array) { 946 const b64 = btoa(String.fromCharCode(...array)); 947 return b64.replace(/\+/g, '-').replace(/\//g, '_'); 948} 949 950/** 951 * @license 952 * Copyright 2019 Google LLC 953 * 954 * Licensed under the Apache License, Version 2.0 (the "License"); 955 * you may not use this file except in compliance with the License. 956 * You may obtain a copy of the License at 957 * 958 * http://www.apache.org/licenses/LICENSE-2.0 959 * 960 * Unless required by applicable law or agreed to in writing, software 961 * distributed under the License is distributed on an "AS IS" BASIS, 962 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 963 * See the License for the specific language governing permissions and 964 * limitations under the License. 965 */ 966const VALID_FID_PATTERN = /^[cdef][\w-]{21}$/; 967const INVALID_FID = ''; 968/** 969 * Generates a new FID using random values from Web Crypto API. 970 * Returns an empty string if FID generation fails for any reason. 971 */ 972function generateFid() { 973 try { 974 // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 975 // bytes. our implementation generates a 17 byte array instead. 976 const fidByteArray = new Uint8Array(17); 977 const crypto = self.crypto || self.msCrypto; 978 crypto.getRandomValues(fidByteArray); 979 // Replace the first 4 random bits with the constant FID header of 0b0111. 980 fidByteArray[0] = 0b01110000 + (fidByteArray[0] % 0b00010000); 981 const fid = encode(fidByteArray); 982 return VALID_FID_PATTERN.test(fid) ? fid : INVALID_FID; 983 } 984 catch (_a) { 985 // FID generation errored 986 return INVALID_FID; 987 } 988} 989/** Converts a FID Uint8Array to a base64 string representation. */ 990function encode(fidByteArray) { 991 const b64String = bufferToBase64UrlSafe(fidByteArray); 992 // Remove the 23rd character that was added because of the extra 4 bits at the 993 // end of our 17 byte array, and the '=' padding. 994 return b64String.substr(0, 22); 995} 996 997/** 998 * @license 999 * Copyright 2019 Google LLC 1000 * 1001 * Licensed under the Apache License, Version 2.0 (the "License"); 1002 * you may not use this file except in compliance with the License. 1003 * You may obtain a copy of the License at 1004 * 1005 * http://www.apache.org/licenses/LICENSE-2.0 1006 * 1007 * Unless required by applicable law or agreed to in writing, software 1008 * distributed under the License is distributed on an "AS IS" BASIS, 1009 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1010 * See the License for the specific language governing permissions and 1011 * limitations under the License. 1012 */ 1013/** Returns a string key that can be used to identify the app. */ 1014function getKey(appConfig) { 1015 return `${appConfig.appName}!${appConfig.appId}`; 1016} 1017
1018/** 1019 * @license 1020 * Copyright 2019 Google LLC 1021 * 1022 * Licensed under the Apache License, Version 2.0 (the "License"); 1023 * you may not use this file except in compliance with the License. 1024 * You may obtain a copy of the License at 1025 * 1026 * http://www.apache.org/licenses/LICENSE-2.0 1027 * 1028 * Unless required by applicable law or agreed to in writing, software 1029 * distributed under the License is distributed on an "AS IS" BASIS, 1030 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1031 * See the License for the specific language governing permissions and 1032 * limitations under the License. 1033 */ 1034const fidChangeCallbacks = new Map(); 1035/** 1036 * Calls the onIdChange callbacks with the new FID value, and broadcasts the 1037 * change to other tabs. 1038 */ 1039function fidChanged(appConfig, fid) { 1040 const key = getKey(appConfig); 1041 callFidChangeCallbacks(key, fid); 1042 broadcastFidChange(key, fid); 1043} 1044function callFidChangeCallbacks(key, fid) { 1045 const callbacks = fidChangeCallbacks.get(key); 1046 if (!callbacks) { 1047 return; 1048 } 1049 for (const callback of callbacks) { 1050 callback(fid); 1051 } 1052} 1053function broadcastFidChange(key, fid) { 1054 const channel = getBroadcastChannel(); 1055 if (channel) { 1056 channel.postMessage({ key, fid }); 1057 } 1058 closeBroadcastChannel(); 1059} 1060let broadcastChannel = null; 1061/** Opens and returns a BroadcastChannel if it is supported by the browser. */ 1062function getBroadcastChannel() { 1063 if (!broadcastChannel && 'BroadcastChannel' in self) { 1064 broadcastChannel = new BroadcastChannel('[Firebase] FID Change'); 1065 broadcastChannel.onmessage = e => { 1066 callFidChangeCallbacks(e.data.key, e.data.fid); 1067 }; 1068 } 1069 return broadcastChannel; 1070} 1071function closeBroadcastChannel() { 1072 if (fidChangeCallbacks.size === 0 && broadcastChannel) { 1073 broadcastChannel.close(); 1074 broadcastChannel = null; 1075 } 1076} 1077 1078/** 1079 * @license 1080 * Copyright 2019 Google LLC 1081 * 1082 * Licensed under the Apache License, Version 2.0 (the "License"); 1083 * you may not use this file except in compliance with the License. 1084 * You may obtain a copy of the License at 1085 * 1086 * http://www.apache.org/licenses/LICENSE-2.0 1087 * 1088 * Unless required by applicable law or agreed to in writing, software 1089 * distributed under the License is distributed on an "AS IS" BASIS, 1090 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1091 * See the License for the specific language governing permissions and 1092 * limitations under the License. 1093 */ 1094const DATABASE_NAME = 'firebase-installations-database'; 1095const DATABASE_VERSION = 1; 1096const OBJECT_STORE_NAME = 'firebase-installations-store'; 1097let dbPromise = null; 1098function getDbPromise() { 1099 if (!dbPromise) { 1100 dbPromise = openDb(DATABASE_NAME, DATABASE_VERSION, upgradeDB => { 1101 // We don't use 'break' in this switch statement, the fall-through 1102 // behavior is what we want, because if there are multiple versions between 1103 // the old version and the current version, we want ALL the migrations 1104 // that correspond to those versions to run, not only the last one. 1105 // eslint-disable-next-line default-case 1106 switch (upgradeDB.oldVersion) { 1107 case 0: 1108 upgradeDB.createObjectStore(OBJECT_STORE_NAME); 1109 } 1110 }); 1111 } 1112 return dbPromise; 1113} 1114/** Assigns or overwrites the record for the given key with the given value. */ 1115async function set(appConfig, value) { 1116 const key = getKey(appConfig); 1117 const db = await getDbPromise(); 1118 const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); 1119 const objectStore = tx.objectStore(OBJECT_STORE_NAME); 1120 const oldValue = await objectStore.get(key); 1121 await objectStore.put(value, key); 1122 await tx.complete; 1123 if (!oldValue || oldValue.fid !== value.fid) { 1124 fidChanged(appConfig, value.fid); 1125 } 1126 return value; 1127} 1128/** Removes record(s) from the objectStore that match the given key. */ 1129async function remove(appConfig) {
vendor: 6,733 bytes, lines 1130-1304
1130 const key = getKey(appConfig); 1131 const db = await getDbPromise(); 1132 const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); 1133 await tx.objectStore(OBJECT_STORE_NAME).delete(key); 1134 await tx.complete; 1135} 1136/** 1137 * Atomically updates a record with the result of updateFn, which gets 1138 * called with the current value. If newValue is undefined, the record is 1139 * deleted instead. 1140 * @return Updated value 1141 */ 1142async function update(appConfig, updateFn) { 1143 const key = getKey(appConfig); 1144 const db = await getDbPromise(); 1145 const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite'); 1146 const store = tx.objectStore(OBJECT_STORE_NAME); 1147 const oldValue = await store.get(key); 1148 const newValue = updateFn(oldValue); 1149 if (newValue === undefined) { 1150 await store.delete(key); 1151 } 1152 else { 1153 await store.put(newValue, key); 1154 } 1155 await tx.complete; 1156 if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) { 1157 fidChanged(appConfig, newValue.fid); 1158 } 1159 return newValue; 1160} 1161 1162/** 1163 * @license 1164 * Copyright 2019 Google LLC 1165 * 1166 * Licensed under the Apache License, Version 2.0 (the "License"); 1167 * you may not use this file except in compliance with the License. 1168 * You may obtain a copy of the License at 1169 * 1170 * http://www.apache.org/licenses/LICENSE-2.0 1171 * 1172 * Unless required by applicable law or agreed to in writing, software 1173 * distributed under the License is distributed on an "AS IS" BASIS, 1174 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1175 * See the License for the specific language governing permissions and 1176 * limitations under the License. 1177 */ 1178/** 1179 * Updates and returns the InstallationEntry from the database. 1180 * Also triggers a registration request if it is necessary and possible. 1181 */ 1182async function getInstallationEntry(appConfig) { 1183 let registrationPromise; 1184 const installationEntry = await update(appConfig, oldEntry => { 1185 const installationEntry = updateOrCreateInstallationEntry(oldEntry); 1186 const entryWithPromise = triggerRegistrationIfNecessary(appConfig, installationEntry); 1187 registrationPromise = entryWithPromise.registrationPromise; 1188 return entryWithPromise.installationEntry; 1189 }); 1190 if (installationEntry.fid === INVALID_FID) { 1191 // FID generation failed. Waiting for the FID from the server. 1192 return { installationEntry: await registrationPromise }; 1193 } 1194 return { 1195 installationEntry, 1196 registrationPromise 1197 }; 1198} 1199/** 1200 * Creates a new Installation Entry if one does not exist. 1201 * Also clears timed out pending requests. 1202 */ 1203function updateOrCreateInstallationEntry(oldEntry) { 1204 const entry = oldEntry || { 1205 fid: generateFid(), 1206 registrationStatus: 0 /* NOT_STARTED */ 1207 }; 1208 return clearTimedOutRequest(entry); 1209} 1210/** 1211 * If the Firebase Installation is not registered yet, this will trigger the 1212 * registration and return an InProgressInstallationEntry. 1213 * 1214 * If registrationPromise does not exist, the installationEntry is guaranteed 1215 * to be registered. 1216 */ 1217function triggerRegistrationIfNecessary(appConfig, installationEntry) { 1218 if (installationEntry.registrationStatus === 0 /* NOT_STARTED */) { 1219 if (!navigator.onLine) { 1220 // Registration required but app is offline. 1221 const registrationPromiseWithError = Promise.reject(ERROR_FACTORY$1.create("app-offline" /* APP_OFFLINE */)); 1222 return { 1223 installationEntry, 1224 registrationPromise: registrationPromiseWithError 1225 }; 1226 } 1227 // Try registering. Change status to IN_PROGRESS. 1228 const inProgressEntry = { 1229 fid: installationEntry.fid, 1230 registrationStatus: 1 /* IN_PROGRESS */, 1231 registrationTime: Date.now() 1232 }; 1233 const registrationPromise = registerInstallation(appConfig, inProgressEntry); 1234 return { installationEntry: inProgressEntry, registrationPromise }; 1235 } 1236 else if (installationEntry.registrationStatus === 1 /* IN_PROGRESS */) { 1237 return { 1238 installationEntry, 1239 registrationPromise: waitUntilFidRegistration(appConfig) 1240 }; 1241 } 1242 else { 1243 return { installationEntry }; 1244 } 1245} 1246/** This will be executed only once for each new Firebase Installation. */ 1247async function registerInstallation(appConfig, installationEntry) { 1248 try { 1249 const registeredInstallationEntry = await createInstallationRequest(appConfig, installationEntry); 1250 return set(appConfig, registeredInstallationEntry); 1251 } 1252 catch (e) { 1253 if (isServerError(e) && e.customData.serverCode === 409) { 1254 // Server returned a "FID can not be used" error. 1255 // Generate a new ID next time. 1256 await remove(appConfig); 1257 } 1258 else { 1259 // Registration failed. Set FID as not registered. 1260 await set(appConfig, { 1261 fid: installationEntry.fid, 1262 registrationStatus: 0 /* NOT_STARTED */ 1263 }); 1264 } 1265 throw e; 1266 } 1267} 1268/** Call if FID registration is pending in another request. */ 1269async function waitUntilFidRegistration(appConfig) { 1270 // Unfortunately, there is no way of reliably observing when a value in 1271 // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), 1272 // so we need to poll. 1273 let entry = await updateInstallationRequest(appConfig); 1274 while (entry.registrationStatus === 1 /* IN_PROGRESS */) { 1275 // createInstallation request still in progress. 1276 await sleep(100); 1277 entry = await updateInstallationRequest(appConfig); 1278 } 1279 if (entry.registrationStatus === 0 /* NOT_STARTED */) { 1280 // The request timed out or failed in a different call. Try again. 1281 const { installationEntry, registrationPromise } = await getInstallationEntry(appConfig); 1282 if (registrationPromise) { 1283 return registrationPromise; 1284 } 1285 else { 1286 // if there is no registrationPromise, entry is registered. 1287 return installationEntry; 1288 } 1289 } 1290 return entry; 1291} 1292/** 1293 * Called only if there is a CreateInstallation request in progress. 1294 * 1295 * Updates the InstallationEntry in the DB based on the status of the 1296 * CreateInstallation request. 1297 * 1298 * Returns the updated InstallationEntry. 1299 */ 1300function updateInstallationRequest(appConfig) { 1301 return update(appConfig, oldEntry => { 1302 if (!oldEntry) { 1303 throw ERROR_FACTORY$1.create("installation-not-found" /* INSTALLATION_NOT_FOUND */); 1304 }
1305 return clearTimedOutRequest(oldEntry); 1306 }); 1307} 1308function clearTimedOutRequest(entry) { 1309 if (hasInstallationRequestTimedOut(entry)) { 1310 return { 1311 fid: entry.fid, 1312 registrationStatus: 0 /* NOT_STARTED */ 1313 }; 1314 } 1315 return entry; 1316} 1317function hasInstallationRequestTimedOut(installationEntry) { 1318 return (installationEntry.registrationStatus === 1 /* IN_PROGRESS */ && 1319 installationEntry.registrationTime + PENDING_TIMEOUT_MS < Date.now()); 1320} 1321 1322/** 1323 * @license 1324 * Copyright 2019 Google LLC 1325 * 1326 * Licensed under the Apache License, Version 2.0 (the "License"); 1327 * you may not use this file except in compliance with the License. 1328 * You may obtain a copy of the License at 1329 * 1330 * http://www.apache.org/licenses/LICENSE-2.0 1331 * 1332 * Unless required by applicable law or agreed to in writing, software 1333 * distributed under the License is distributed on an "AS IS" BASIS, 1334 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1335 * See the License for the specific language governing permissions and 1336 * limitations under the License. 1337 */ 1338async function generateAuthTokenRequest({ appConfig, platformLoggerProvider }, installationEntry) { 1339 const endpoint = getGenerateAuthTokenEndpoint(appConfig, installationEntry); 1340 const headers = getHeadersWithAuth(appConfig, installationEntry); 1341 // If platform logger exists, add the platform info string to the header. 1342 const platformLogger = platformLoggerProvider.getImmediate({ 1343 optional: true 1344 }); 1345 if (platformLogger) { 1346 headers.append('x-firebase-client', platformLogger.getPlatformInfoString()); 1347 } 1348 const body = { 1349 installation: { 1350 sdkVersion: PACKAGE_VERSION 1351 } 1352 }; 1353 const request = { 1354 method: 'POST', 1355 headers, 1356 body: JSON.stringify(body) 1357 }; 1358 const response = await retryIfServerError(() => fetch(endpoint, request)); 1359 if (response.ok) { 1360 const responseValue = await response.json();
vendor: 4,317 bytes, lines 1361-1468
1361 const completedAuthToken = extractAuthTokenInfoFromResponse(responseValue); 1362 return completedAuthToken; 1363 } 1364 else { 1365 throw await getErrorFromResponse('Generate Auth Token', response); 1366 } 1367} 1368function getGenerateAuthTokenEndpoint(appConfig, { fid }) { 1369 return `${getInstallationsEndpoint(appConfig)}/${fid}/authTokens:generate`; 1370} 1371 1372/** 1373 * @license 1374 * Copyright 2019 Google LLC 1375 * 1376 * Licensed under the Apache License, Version 2.0 (the "License"); 1377 * you may not use this file except in compliance with the License. 1378 * You may obtain a copy of the License at 1379 * 1380 * http://www.apache.org/licenses/LICENSE-2.0 1381 * 1382 * Unless required by applicable law or agreed to in writing, software 1383 * distributed under the License is distributed on an "AS IS" BASIS, 1384 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1385 * See the License for the specific language governing permissions and 1386 * limitations under the License. 1387 */ 1388/** 1389 * Returns a valid authentication token for the installation. Generates a new 1390 * token if one doesn't exist, is expired or about to expire. 1391 * 1392 * Should only be called if the Firebase Installation is registered. 1393 */ 1394async function refreshAuthToken(installations, forceRefresh = false) { 1395 let tokenPromise; 1396 const entry = await update(installations.appConfig, oldEntry => { 1397 if (!isEntryRegistered(oldEntry)) { 1398 throw ERROR_FACTORY$1.create("not-registered" /* NOT_REGISTERED */); 1399 } 1400 const oldAuthToken = oldEntry.authToken; 1401 if (!forceRefresh && isAuthTokenValid(oldAuthToken)) { 1402 // There is a valid token in the DB. 1403 return oldEntry; 1404 } 1405 else if (oldAuthToken.requestStatus === 1 /* IN_PROGRESS */) { 1406 // There already is a token request in progress. 1407 tokenPromise = waitUntilAuthTokenRequest(installations, forceRefresh); 1408 return oldEntry; 1409 } 1410 else { 1411 // No token or token expired. 1412 if (!navigator.onLine) { 1413 throw ERROR_FACTORY$1.create("app-offline" /* APP_OFFLINE */); 1414 } 1415 const inProgressEntry = makeAuthTokenRequestInProgressEntry(oldEntry); 1416 tokenPromise = fetchAuthTokenFromServer(installations, inProgressEntry); 1417 return inProgressEntry; 1418 } 1419 }); 1420 const authToken = tokenPromise 1421 ? await tokenPromise 1422 : entry.authToken; 1423 return authToken; 1424} 1425/** 1426 * Call only if FID is registered and Auth Token request is in progress. 1427 * 1428 * Waits until the current pending request finishes. If the request times out, 1429 * tries once in this thread as well. 1430 */ 1431async function waitUntilAuthTokenRequest(installations, forceRefresh) { 1432 // Unfortunately, there is no way of reliably observing when a value in 1433 // IndexedDB changes (yet, see https://github.com/WICG/indexed-db-observers), 1434 // so we need to poll. 1435 let entry = await updateAuthTokenRequest(installations.appConfig); 1436 while (entry.authToken.requestStatus === 1 /* IN_PROGRESS */) { 1437 // generateAuthToken still in progress. 1438 await sleep(100); 1439 entry = await updateAuthTokenRequest(installations.appConfig); 1440 } 1441 const authToken = entry.authToken; 1442 if (authToken.requestStatus === 0 /* NOT_STARTED */) { 1443 // The request timed out or failed in a different call. Try again. 1444 return refreshAuthToken(installations, forceRefresh); 1445 } 1446 else { 1447 return authToken; 1448 } 1449} 1450/** 1451 * Called only if there is a GenerateAuthToken request in progress. 1452 * 1453 * Updates the InstallationEntry in the DB based on the status of the 1454 * GenerateAuthToken request. 1455 * 1456 * Returns the updated InstallationEntry. 1457 */ 1458function updateAuthTokenRequest(appConfig) { 1459 return update(appConfig, oldEntry => { 1460 if (!isEntryRegistered(oldEntry)) { 1461 throw ERROR_FACTORY$1.create("not-registered" /* NOT_REGISTERED */); 1462 } 1463 const oldAuthToken = oldEntry.authToken; 1464 if (hasAuthTokenRequestTimedOut(oldAuthToken)) { 1465 return Object.assign(Object.assign({}, oldEntry), { authToken: { requestStatus: 0 /* NOT_STARTED */ } }); 1466 } 1467 return oldEntry; 1468 });
1469} 1470async function fetchAuthTokenFromServer(installations, installationEntry) { 1471 try { 1472 const authToken = await generateAuthTokenRequest(installations, installationEntry); 1473 const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken }); 1474 await set(installations.appConfig, updatedInstallationEntry); 1475 return authToken; 1476 } 1477 catch (e) { 1478 if (isServerError(e) && 1479 (e.customData.serverCode === 401 || e.customData.serverCode === 404)) { 1480 // Server returned a "FID not found" or a "Invalid authentication" error. 1481 // Generate a new ID next time. 1482 await remove(installations.appConfig); 1483 } 1484 else { 1485 const updatedInstallationEntry = Object.assign(Object.assign({}, installationEntry), { authToken: { requestStatus: 0 /* NOT_STARTED */ } }); 1486 await set(installations.appConfig, updatedInstallationEntry); 1487 } 1488 throw e; 1489 } 1490} 1491function isEntryRegistered(installationEntry) { 1492 return (installationEntry !== undefined && 1493 installationEntry.registrationStatus === 2 /* COMPLETED */); 1494} 1495function isAuthTokenValid(authToken) { 1496 return (authToken.requestStatus === 2 /* COMPLETED */ && 1497 !isAuthTokenExpired(authToken)); 1498} 1499function isAuthTokenExpired(authToken) { 1500 const now = Date.now(); 1501 return (now < authToken.creationTime || 1502 authToken.creationTime + authToken.expiresIn < now + TOKEN_EXPIRATION_BUFFER); 1503} 1504/** Returns an updated InstallationEntry with an InProgressAuthToken. */ 1505function makeAuthTokenRequestInProgressEntry(oldEntry) { 1506 const inProgressAuthToken = { 1507 requestStatus: 1 /* IN_PROGRESS */, 1508 requestTime: Date.now() 1509 }; 1510 return Object.assign(Object.assign({}, oldEntry), { authToken: inProgressAuthToken }); 1511} 1512function hasAuthTokenRequestTimedOut(authToken) { 1513 return (authToken.requestStatus === 1 /* IN_PROGRESS */ && 1514 authToken.requestTime + PENDING_TIMEOUT_MS < Date.now()); 1515} 1516 1517/** 1518 * @license 1519 * Copyright 2019 Google LLC 1520 * 1521 * Licensed under the Apache License, Version 2.0 (the "License"); 1522 * you may not use this file except in compliance with the License. 1523 * You may obtain a copy of the License at 1524 * 1525 * http://www.apache.org/licenses/LICENSE-2.0 1526 * 1527 * Unless required by applicable law or agreed to in writing, software 1528 * distributed under the License is distributed on an "AS IS" BASIS, 1529 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1530 * See the License for the specific language governing permissions and 1531 * limitations under the License. 1532 */ 1533/** 1534 * Creates a Firebase Installation if there isn't one for the app and 1535 * returns the Installation ID. 1536 * @param installations - The `Installations` instance. 1537 * 1538 * @public 1539 */ 1540async function getId(installations) { 1541 const installationsImpl = installations; 1542 const { installationEntry, registrationPromise } = await getInstallationEntry(installationsImpl.appConfig); 1543 if (registrationPromise) { 1544 registrationPromise.catch(console.error); 1545 } 1546 else { 1547 // If the installation is already registered, update the authentication 1548 // token if needed. 1549 refreshAuthToken(installationsImpl).catch(console.error); 1550 } 1551 return installationEntry.fid; 1552} 1553 1554/** 1555 * @license 1556 * Copyright 2019 Google LLC 1557 * 1558 * Licensed under the Apache License, Version 2.0 (the "License"); 1559 * you may not use this file except in compliance with the License. 1560 * You may obtain a copy of the License at 1561 * 1562 * http://www.apache.org/licenses/LICENSE-2.0 1563 * 1564 * Unless required by applicable law or agreed to in writing, software 1565 * distributed under the License is distributed on an "AS IS" BASIS, 1566 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1567 * See the License for the specific language governing permissions and 1568 * limitations under the License. 1569 */ 1570/** 1571 * Returns a Firebase Installations auth token, identifying the current 1572 * Firebase Installation. 1573 * @param installations - The `Installations` instance. 1574 * @param forceRefresh - Force refresh regardless of token expiration. 1575 * 1576 * @public 1577 */ 1578async function getToken(installations, forceRefresh = false) { 1579 const installationsImpl = installations; 1580 await completeInstallationRegistration(installationsImpl.appConfig); 1581 // At this point we either have a Registered Installation in the DB, or we've 1582 // already thrown an error. 1583 const authToken = await refreshAuthToken(installationsImpl, forceRefresh); 1584 return authToken.token; 1585} 1586async function completeInstallationRegistration(appConfig) { 1587 const { registrationPromise } = await getInstallationEntry(appConfig); 1588 if (registrationPromise) { 1589 // A createInstallation request is in progress. Wait until it finishes. 1590 await registrationPromise; 1591 } 1592} 1593 1594/** 1595 * @license 1596 * Copyright 2019 Google LLC 1597 * 1598 * Licensed under the Apache License, Version 2.0 (the "License");
1599 * you may not use this file except in compliance with the License. 1600 * You may obtain a copy of the License at 1601 * 1602 * http://www.apache.org/licenses/LICENSE-2.0 1603 * 1604 * Unless required by applicable law or agreed to in writing, software 1605 * distributed under the License is distributed on an "AS IS" BASIS, 1606 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1607 * See the License for the specific language governing permissions and 1608 * limitations under the License. 1609 */ 1610function extractAppConfig(app) { 1611 if (!app || !app.options) { 1612 throw getMissingValueError('App Configuration'); 1613 } 1614 if (!app.name) { 1615 throw getMissingValueError('App Name'); 1616 } 1617 // Required app config keys 1618 const configKeys = [ 1619 'projectId', 1620 'apiKey', 1621 'appId' 1622 ]; 1623 for (const keyName of configKeys) { 1624 if (!app.options[keyName]) { 1625 throw getMissingValueError(keyName); 1626 } 1627 } 1628 return { 1629 appName: app.name, 1630 projectId: app.options.projectId, 1631 apiKey: app.options.apiKey, 1632 appId: app.options.appId 1633 }; 1634} 1635function getMissingValueError(valueName) { 1636 return ERROR_FACTORY$1.create("missing-app-config-values" /* MISSING_APP_CONFIG_VALUES */, { 1637 valueName 1638 }); 1639} 1640 1641/** 1642 * @license 1643 * Copyright 2020 Google LLC 1644 * 1645 * Licensed under the Apache License, Version 2.0 (the "License"); 1646 * you may not use this file except in compliance with the License. 1647 * You may obtain a copy of the License at 1648 * 1649 * http://www.apache.org/licenses/LICENSE-2.0 1650 * 1651 * Unless required by applicable law or agreed to in writing, software 1652 * distributed under the License is distributed on an "AS IS" BASIS, 1653 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1654 * See the License for the specific language governing permissions and 1655 * limitations under the License. 1656 */ 1657const INSTALLATIONS_NAME = 'installations'; 1658const INSTALLATIONS_NAME_INTERNAL = 'installations-internal'; 1659const publicFactory = (container) => { 1660 const app = container.getProvider('app').getImmediate(); 1661 // Throws if app isn't configured properly. 1662 const appConfig = extractAppConfig(app); 1663 const platformLoggerProvider = _getProvider(app, 'platform-logger'); 1664 const installationsImpl = { 1665 app, 1666 appConfig, 1667 platformLoggerProvider, 1668 _delete: () => Promise.resolve() 1669 }; 1670 return installationsImpl; 1671}; 1672const internalFactory = (container) => { 1673 const app = container.getProvider('app').getImmediate(); 1674 // Internal FIS instance relies on public FIS instance. 1675 const installations = _getProvider(app, INSTALLATIONS_NAME).getImmediate(); 1676 const installationsInternal = { 1677 getId: () => getId(installations), 1678 getToken: (forceRefresh) => getToken(installations, forceRefresh) 1679 }; 1680 return installationsInternal; 1681}; 1682function registerInstallations() { 1683 _registerComponent(new Component(INSTALLATIONS_NAME, publicFactory, "PUBLIC" /* PUBLIC */)); 1684 _registerComponent(new Component(INSTALLATIONS_NAME_INTERNAL, internalFactory, "PRIVATE" /* PRIVATE */)); 1685} 1686 1687/** 1688 * Firebase Installations 1689 * 1690 * @packageDocumentation 1691 */ 1692registerInstallations(); 1693registerVersion(name$1, version$1); 1694// BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation 1695registerVersion(name$1, version$1, 'esm2017'); 1696 1697const name = "@firebase/performance"; 1698const version = "0.5.5"; 1699 1700/** 1701 * @license 1702 * Copyright 2020 Google LLC 1703 * 1704 * Licensed under the Apache License, Version 2.0 (the "License"); 1705 * you may not use this file except in compliance with the License. 1706 * You may obtain a copy of the License at 1707 * 1708 * http://www.apache.org/licenses/LICENSE-2.0 1709 * 1710 * Unless required by applicable law or agreed to in writing, software 1711 * distributed under the License is distributed on an "AS IS" BASIS, 1712 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1713 * See the License for the specific language governing permissions and 1714 * limitations under the License. 1715 */ 1716const SDK_VERSION = version; 1717/** The prefix for start User Timing marks used for creating Traces. */ 1718const TRACE_START_MARK_PREFIX = 'FB-PERF-TRACE-START'; 1719/** The prefix for stop User Timing marks used for creating Traces. */ 1720const TRACE_STOP_MARK_PREFIX = 'FB-PERF-TRACE-STOP'; 1721/** The prefix for User Timing measure used for creating Traces. */ 1722const TRACE_MEASURE_PREFIX = 'FB-PERF-TRACE-MEASURE'; 1723/** The prefix for out of the box page load Trace name. */ 1724const OOB_TRACE_PAGE_LOAD_PREFIX = '_wt_'; 1725const FIRST_PAINT_COUNTER_NAME = '_fp'; 1726const FIRST_CONTENTFUL_PAINT_COUNTER_NAME = '_fcp'; 1727const FIRST_INPUT_DELAY_COUNTER_NAME = '_fid'; 1728const CONFIG_LOCAL_STORAGE_KEY = '@firebase/performance/config'; 1729const CONFIG_EXPIRY_LOCAL_STORAGE_KEY = '@firebase/performance/configexpire'; 1730const SERVICE = 'performance';
vendor: 21,815 bytes, lines 1731-2277
1731const SERVICE_NAME = 'Performance'; 1732 1733/** 1734 * @license 1735 * Copyright 2020 Google LLC 1736 * 1737 * Licensed under the Apache License, Version 2.0 (the "License"); 1738 * you may not use this file except in compliance with the License. 1739 * You may obtain a copy of the License at 1740 * 1741 * http://www.apache.org/licenses/LICENSE-2.0 1742 * 1743 * Unless required by applicable law or agreed to in writing, software 1744 * distributed under the License is distributed on an "AS IS" BASIS, 1745 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1746 * See the License for the specific language governing permissions and 1747 * limitations under the License. 1748 */ 1749const ERROR_DESCRIPTION_MAP = { 1750 ["trace started" /* TRACE_STARTED_BEFORE */]: 'Trace {$traceName} was started before.', 1751 ["trace stopped" /* TRACE_STOPPED_BEFORE */]: 'Trace {$traceName} is not running.', 1752 ["nonpositive trace startTime" /* NONPOSITIVE_TRACE_START_TIME */]: 'Trace {$traceName} startTime should be positive.', 1753 ["nonpositive trace duration" /* NONPOSITIVE_TRACE_DURATION */]: 'Trace {$traceName} duration should be positive.', 1754 ["no window" /* NO_WINDOW */]: 'Window is not available.', 1755 ["no app id" /* NO_APP_ID */]: 'App id is not available.', 1756 ["no project id" /* NO_PROJECT_ID */]: 'Project id is not available.', 1757 ["no api key" /* NO_API_KEY */]: 'Api key is not available.', 1758 ["invalid cc log" /* INVALID_CC_LOG */]: 'Attempted to queue invalid cc event', 1759 ["FB not default" /* FB_NOT_DEFAULT */]: 'Performance can only start when Firebase app instance is the default one.', 1760 ["RC response not ok" /* RC_NOT_OK */]: 'RC response is not ok', 1761 ["invalid attribute name" /* INVALID_ATTRIBUTE_NAME */]: 'Attribute name {$attributeName} is invalid.', 1762 ["invalid attribute value" /* INVALID_ATTRIBUTE_VALUE */]: 'Attribute value {$attributeValue} is invalid.', 1763 ["invalid custom metric name" /* INVALID_CUSTOM_METRIC_NAME */]: 'Custom metric name {$customMetricName} is invalid', 1764 ["invalid String merger input" /* INVALID_STRING_MERGER_PARAMETER */]: 'Input for String merger is invalid, contact support team to resolve.', 1765 ["already initialized" /* ALREADY_INITIALIZED */]: 'initializePerformance() has already been called with ' + 1766 'different options. To avoid this error, call initializePerformance() with the ' + 1767 'same options as when it was originally called, or call getPerformance() to return the' + 1768 ' already initialized instance.' 1769}; 1770const ERROR_FACTORY = new ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP); 1771 1772/** 1773 * @license 1774 * Copyright 2020 Google LLC 1775 * 1776 * Licensed under the Apache License, Version 2.0 (the "License"); 1777 * you may not use this file except in compliance with the License. 1778 * You may obtain a copy of the License at 1779 * 1780 * http://www.apache.org/licenses/LICENSE-2.0 1781 * 1782 * Unless required by applicable law or agreed to in writing, software 1783 * distributed under the License is distributed on an "AS IS" BASIS, 1784 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1785 * See the License for the specific language governing permissions and 1786 * limitations under the License. 1787 */ 1788const consoleLogger = new Logger(SERVICE_NAME); 1789consoleLogger.logLevel = LogLevel.INFO; 1790 1791/** 1792 * @license 1793 * Copyright 2020 Google LLC 1794 * 1795 * Licensed under the Apache License, Version 2.0 (the "License"); 1796 * you may not use this file except in compliance with the License. 1797 * You may obtain a copy of the License at 1798 * 1799 * http://www.apache.org/licenses/LICENSE-2.0 1800 * 1801 * Unless required by applicable law or agreed to in writing, software 1802 * distributed under the License is distributed on an "AS IS" BASIS, 1803 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1804 * See the License for the specific language governing permissions and 1805 * limitations under the License. 1806 */ 1807let apiInstance; 1808let windowInstance; 1809/** 1810 * This class holds a reference to various browser related objects injected by 1811 * set methods. 1812 */ 1813class Api { 1814 constructor(window) { 1815 this.window = window; 1816 if (!window) { 1817 throw ERROR_FACTORY.create("no window" /* NO_WINDOW */); 1818 } 1819 this.performance = window.performance; 1820 this.PerformanceObserver = window.PerformanceObserver; 1821 this.windowLocation = window.location; 1822 this.navigator = window.navigator; 1823 this.document = window.document; 1824 if (this.navigator && this.navigator.cookieEnabled) { 1825 // If user blocks cookies on the browser, accessing localStorage will 1826 // throw an exception. 1827 this.localStorage = window.localStorage; 1828 } 1829 if (window.perfMetrics && window.perfMetrics.onFirstInputDelay) { 1830 this.onFirstInputDelay = window.perfMetrics.onFirstInputDelay; 1831 } 1832 } 1833 getUrl() { 1834 // Do not capture the string query part of url. 1835 return this.windowLocation.href.split('?')[0]; 1836 } 1837 mark(name) { 1838 if (!this.performance || !this.performance.mark) { 1839 return; 1840 } 1841 this.performance.mark(name); 1842 } 1843 measure(measureName, mark1, mark2) { 1844 if (!this.performance || !this.performance.measure) { 1845 return; 1846 } 1847 this.performance.measure(measureName, mark1, mark2); 1848 } 1849 getEntriesByType(type) { 1850 if (!this.performance || !this.performance.getEntriesByType) { 1851 return []; 1852 } 1853 return this.performance.getEntriesByType(type); 1854 } 1855 getEntriesByName(name) { 1856 if (!this.performance || !this.performance.getEntriesByName) { 1857 return []; 1858 } 1859 return this.performance.getEntriesByName(name); 1860 } 1861 getTimeOrigin() { 1862 // Polyfill the time origin with performance.timing.navigationStart. 1863 return (this.performance && 1864 (this.performance.timeOrigin || this.performance.timing.navigationStart)); 1865 } 1866 requiredApisAvailable() { 1867 if (!fetch || !Promise || !areCookiesEnabled()) { 1868 consoleLogger.info('Firebase Performance cannot start if browser does not support fetch and Promise or cookie is disabled.'); 1869 return false; 1870 } 1871 if (!isIndexedDBAvailable()) { 1872 consoleLogger.info('IndexedDB is not supported by current browswer'); 1873 return false; 1874 } 1875 return true; 1876 } 1877 setupObserver(entryType, callback) { 1878 if (!this.PerformanceObserver) { 1879 return; 1880 } 1881 const observer = new this.PerformanceObserver(list => { 1882 for (const entry of list.getEntries()) { 1883 // `entry` is a PerformanceEntry instance. 1884 callback(entry); 1885 } 1886 }); 1887 // Start observing the entry types you care about. 1888 observer.observe({ entryTypes: [entryType] }); 1889 } 1890 static getInstance() { 1891 if (apiInstance === undefined) { 1892 apiInstance = new Api(windowInstance); 1893 } 1894 return apiInstance; 1895 } 1896} 1897function setupApi(window) { 1898 windowInstance = window; 1899} 1900 1901/** 1902 * @license 1903 * Copyright 2020 Google LLC 1904 * 1905 * Licensed under the Apache License, Version 2.0 (the "License"); 1906 * you may not use this file except in compliance with the License. 1907 * You may obtain a copy of the License at 1908 * 1909 * http://www.apache.org/licenses/LICENSE-2.0 1910 * 1911 * Unless required by applicable law or agreed to in writing, software 1912 * distributed under the License is distributed on an "AS IS" BASIS, 1913 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1914 * See the License for the specific language governing permissions and 1915 * limitations under the License. 1916 */ 1917let iid; 1918function getIidPromise(installationsService) { 1919 const iidPromise = installationsService.getId(); 1920 // eslint-disable-next-line @typescript-eslint/no-floating-promises 1921 iidPromise.then((iidVal) => { 1922 iid = iidVal; 1923 }); 1924 return iidPromise; 1925} 1926// This method should be used after the iid is retrieved by getIidPromise method. 1927function getIid() { 1928 return iid; 1929} 1930function getAuthTokenPromise(installationsService) { 1931 const authTokenPromise = installationsService.getToken(); 1932 // eslint-disable-next-line @typescript-eslint/no-floating-promises 1933 authTokenPromise.then((authTokenVal) => { 1934 }); 1935 return authTokenPromise; 1936} 1937 1938/** 1939 * @license 1940 * Copyright 2020 Google LLC 1941 * 1942 * Licensed under the Apache License, Version 2.0 (the "License"); 1943 * you may not use this file except in compliance with the License. 1944 * You may obtain a copy of the License at 1945 * 1946 * http://www.apache.org/licenses/LICENSE-2.0 1947 * 1948 * Unless required by applicable law or agreed to in writing, software 1949 * distributed under the License is distributed on an "AS IS" BASIS, 1950 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1951 * See the License for the specific language governing permissions and 1952 * limitations under the License. 1953 */ 1954function mergeStrings(part1, part2) { 1955 const sizeDiff = part1.length - part2.length; 1956 if (sizeDiff < 0 || sizeDiff > 1) { 1957 throw ERROR_FACTORY.create("invalid String merger input" /* INVALID_STRING_MERGER_PARAMETER */); 1958 } 1959 const resultArray = []; 1960 for (let i = 0; i < part1.length; i++) { 1961 resultArray.push(part1.charAt(i)); 1962 if (part2.length > i) { 1963 resultArray.push(part2.charAt(i)); 1964 } 1965 } 1966 return resultArray.join(''); 1967} 1968 1969/** 1970 * @license 1971 * Copyright 2019 Google LLC 1972 * 1973 * Licensed under the Apache License, Version 2.0 (the "License"); 1974 * you may not use this file except in compliance with the License. 1975 * You may obtain a copy of the License at 1976 * 1977 * http://www.apache.org/licenses/LICENSE-2.0 1978 * 1979 * Unless required by applicable law or agreed to in writing, software 1980 * distributed under the License is distributed on an "AS IS" BASIS, 1981 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1982 * See the License for the specific language governing permissions and 1983 * limitations under the License. 1984 */ 1985let settingsServiceInstance; 1986class SettingsService { 1987 constructor() { 1988 // The variable which controls logging of automatic traces and HTTP/S network monitoring. 1989 this.instrumentationEnabled = true; 1990 // The variable which controls logging of custom traces. 1991 this.dataCollectionEnabled = true; 1992 // Configuration flags set through remote config. 1993 this.loggingEnabled = false; 1994 // Sampling rate between 0 and 1. 1995 this.tracesSamplingRate = 1; 1996 this.networkRequestsSamplingRate = 1; 1997 // Address of logging service. 1998 this.logEndPointUrl = 'https://firebaselogging.googleapis.com/v0cc/log?format=json_proto'; 1999 // Performance event transport endpoint URL which should be compatible with proto3. 2000 // New Address for transport service, not configurable via Remote Config. 2001 this.flTransportEndpointUrl = mergeStrings('hts/frbslgigp.ogepscmv/ieo/eaylg', 'tp:/ieaeogn-agolai.o/1frlglgc/o'); 2002 this.transportKey = mergeStrings('AzSC8r6ReiGqFMyfvgow', 'Iayx0u-XT3vksVM-pIV'); 2003 // Source type for performance event logs. 2004 this.logSource = 462; 2005 // Flags which control per session logging of traces and network requests. 2006 this.logTraceAfterSampling = false; 2007 this.logNetworkAfterSampling = false; 2008 // TTL of config retrieved from remote config in hours. 2009 this.configTimeToLive = 12; 2010 } 2011 getFlTransportFullUrl() { 2012 return this.flTransportEndpointUrl.concat('?key=', this.transportKey); 2013 } 2014 static getInstance() { 2015 if (settingsServiceInstance === undefined) { 2016 settingsServiceInstance = new SettingsService(); 2017 } 2018 return settingsServiceInstance; 2019 } 2020} 2021 2022/** 2023 * @license 2024 * Copyright 2020 Google LLC 2025 * 2026 * Licensed under the Apache License, Version 2.0 (the "License"); 2027 * you may not use this file except in compliance with the License. 2028 * You may obtain a copy of the License at 2029 * 2030 * http://www.apache.org/licenses/LICENSE-2.0 2031 * 2032 * Unless required by applicable law or agreed to in writing, software 2033 * distributed under the License is distributed on an "AS IS" BASIS, 2034 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2035 * See the License for the specific language governing permissions and 2036 * limitations under the License. 2037 */ 2038var VisibilityState; 2039(function (VisibilityState) { 2040 VisibilityState[VisibilityState["UNKNOWN"] = 0] = "UNKNOWN"; 2041 VisibilityState[VisibilityState["VISIBLE"] = 1] = "VISIBLE"; 2042 VisibilityState[VisibilityState["HIDDEN"] = 2] = "HIDDEN"; 2043})(VisibilityState || (VisibilityState = {})); 2044const RESERVED_ATTRIBUTE_PREFIXES = ['firebase_', 'google_', 'ga_']; 2045const ATTRIBUTE_FORMAT_REGEX = new RegExp('^[a-zA-Z]\\w*$'); 2046const MAX_ATTRIBUTE_NAME_LENGTH = 40; 2047const MAX_ATTRIBUTE_VALUE_LENGTH = 100; 2048function getServiceWorkerStatus() { 2049 const navigator = Api.getInstance().navigator; 2050 if ('serviceWorker' in navigator) { 2051 if (navigator.serviceWorker.controller) { 2052 return 2 /* CONTROLLED */; 2053 } 2054 else { 2055 return 3 /* UNCONTROLLED */; 2056 } 2057 } 2058 else { 2059 return 1 /* UNSUPPORTED */; 2060 } 2061} 2062function getVisibilityState() { 2063 const document = Api.getInstance().document; 2064 const visibilityState = document.visibilityState; 2065 switch (visibilityState) { 2066 case 'visible': 2067 return VisibilityState.VISIBLE; 2068 case 'hidden': 2069 return VisibilityState.HIDDEN; 2070 default: 2071 return VisibilityState.UNKNOWN; 2072 } 2073} 2074function getEffectiveConnectionType() { 2075 const navigator = Api.getInstance().navigator; 2076 const navigatorConnection = navigator.connection; 2077 const effectiveType = navigatorConnection && navigatorConnection.effectiveType; 2078 switch (effectiveType) { 2079 case 'slow-2g': 2080 return 1 /* CONNECTION_SLOW_2G */; 2081 case '2g': 2082 return 2 /* CONNECTION_2G */; 2083 case '3g': 2084 return 3 /* CONNECTION_3G */; 2085 case '4g': 2086 return 4 /* CONNECTION_4G */; 2087 default: 2088 return 0 /* UNKNOWN */; 2089 } 2090} 2091function isValidCustomAttributeName(name) { 2092 if (name.length === 0 || name.length > MAX_ATTRIBUTE_NAME_LENGTH) { 2093 return false; 2094 } 2095 const matchesReservedPrefix = RESERVED_ATTRIBUTE_PREFIXES.some(prefix => name.startsWith(prefix)); 2096 return !matchesReservedPrefix && !!name.match(ATTRIBUTE_FORMAT_REGEX); 2097} 2098function isValidCustomAttributeValue(value) { 2099 return value.length !== 0 && value.length <= MAX_ATTRIBUTE_VALUE_LENGTH; 2100} 2101 2102/** 2103 * @license 2104 * Copyright 2020 Google LLC 2105 * 2106 * Licensed under the Apache License, Version 2.0 (the "License"); 2107 * you may not use this file except in compliance with the License. 2108 * You may obtain a copy of the License at 2109 * 2110 * http://www.apache.org/licenses/LICENSE-2.0 2111 * 2112 * Unless required by applicable law or agreed to in writing, software 2113 * distributed under the License is distributed on an "AS IS" BASIS, 2114 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2115 * See the License for the specific language governing permissions and 2116 * limitations under the License. 2117 */ 2118function getAppId(firebaseApp) { 2119 var _a; 2120 const appId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.appId; 2121 if (!appId) { 2122 throw ERROR_FACTORY.create("no app id" /* NO_APP_ID */); 2123 } 2124 return appId; 2125} 2126function getProjectId(firebaseApp) { 2127 var _a; 2128 const projectId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.projectId; 2129 if (!projectId) { 2130 throw ERROR_FACTORY.create("no project id" /* NO_PROJECT_ID */); 2131 } 2132 return projectId; 2133} 2134function getApiKey(firebaseApp) { 2135 var _a; 2136 const apiKey = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.apiKey; 2137 if (!apiKey) { 2138 throw ERROR_FACTORY.create("no api key" /* NO_API_KEY */); 2139 } 2140 return apiKey; 2141} 2142 2143/** 2144 * @license 2145 * Copyright 2020 Google LLC 2146 * 2147 * Licensed under the Apache License, Version 2.0 (the "License"); 2148 * you may not use this file except in compliance with the License. 2149 * You may obtain a copy of the License at 2150 * 2151 * http://www.apache.org/licenses/LICENSE-2.0 2152 * 2153 * Unless required by applicable law or agreed to in writing, software 2154 * distributed under the License is distributed on an "AS IS" BASIS, 2155 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2156 * See the License for the specific language governing permissions and 2157 * limitations under the License. 2158 */ 2159const REMOTE_CONFIG_SDK_VERSION = '0.0.1'; 2160// These values will be used if the remote config object is successfully 2161// retrieved, but the template does not have these fields. 2162const DEFAULT_CONFIGS = { 2163 loggingEnabled: true 2164}; 2165const FIS_AUTH_PREFIX = 'FIREBASE_INSTALLATIONS_AUTH'; 2166function getConfig(performanceController, iid) { 2167 const config = getStoredConfig(); 2168 if (config) { 2169 processConfig(config); 2170 return Promise.resolve(); 2171 } 2172 return getRemoteConfig(performanceController, iid) 2173 .then(processConfig) 2174 .then(config => storeConfig(config), 2175 /** Do nothing for error, use defaults set in settings service. */ 2176 () => { }); 2177} 2178function getStoredConfig() { 2179 const localStorage = Api.getInstance().localStorage; 2180 if (!localStorage) { 2181 return; 2182 } 2183 const expiryString = localStorage.getItem(CONFIG_EXPIRY_LOCAL_STORAGE_KEY); 2184 if (!expiryString || !configValid(expiryString)) { 2185 return; 2186 } 2187 const configStringified = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY); 2188 if (!configStringified) { 2189 return; 2190 } 2191 try { 2192 const configResponse = JSON.parse(configStringified); 2193 return configResponse; 2194 } 2195 catch (_a) { 2196 return; 2197 } 2198} 2199function storeConfig(config) { 2200 const localStorage = Api.getInstance().localStorage; 2201 if (!config || !localStorage) { 2202 return; 2203 } 2204 localStorage.setItem(CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config)); 2205 localStorage.setItem(CONFIG_EXPIRY_LOCAL_STORAGE_KEY, String(Date.now() + 2206 SettingsService.getInstance().configTimeToLive * 60 * 60 * 1000)); 2207} 2208const COULD_NOT_GET_CONFIG_MSG = 'Could not fetch config, will use default configs'; 2209function getRemoteConfig(performanceController, iid) { 2210 // Perf needs auth token only to retrieve remote config. 2211 return getAuthTokenPromise(performanceController.installations) 2212 .then(authToken => { 2213 const projectId = getProjectId(performanceController.app); 2214 const apiKey = getApiKey(performanceController.app); 2215 const configEndPoint = `https://firebaseremoteconfig.googleapis.com/v1/projects/${projectId}/namespaces/fireperf:fetch?key=${apiKey}`; 2216 const request = new Request(configEndPoint, { 2217 method: 'POST', 2218 headers: { Authorization: `${FIS_AUTH_PREFIX} ${authToken}` }, 2219 /* eslint-disable camelcase */ 2220 body: JSON.stringify({ 2221 app_instance_id: iid, 2222 app_instance_id_token: authToken, 2223 app_id: getAppId(performanceController.app), 2224 app_version: SDK_VERSION, 2225 sdk_version: REMOTE_CONFIG_SDK_VERSION 2226 }) 2227 /* eslint-enable camelcase */ 2228 }); 2229 return fetch(request).then(response => { 2230 if (response.ok) { 2231 return response.json(); 2232 } 2233 // In case response is not ok. This will be caught by catch. 2234 throw ERROR_FACTORY.create("RC response not ok" /* RC_NOT_OK */); 2235 }); 2236 }) 2237 .catch(() => { 2238 consoleLogger.info(COULD_NOT_GET_CONFIG_MSG); 2239 return undefined; 2240 }); 2241} 2242/** 2243 * Processes config coming either from calling RC or from local storage. 2244 * This method only runs if call is successful or config in storage 2245 * is valid. 2246 */ 2247function processConfig(config) { 2248 if (!config) { 2249 return config; 2250 } 2251 const settingsServiceInstance = SettingsService.getInstance(); 2252 const entries = config.entries || {}; 2253 if (entries.fpr_enabled !== undefined) { 2254 // TODO: Change the assignment of loggingEnabled once the received type is 2255 // known. 2256 settingsServiceInstance.loggingEnabled = 2257 String(entries.fpr_enabled) === 'true'; 2258 } 2259 else { 2260 // Config retrieved successfully, but there is no fpr_enabled in template. 2261 // Use secondary configs value. 2262 settingsServiceInstance.loggingEnabled = DEFAULT_CONFIGS.loggingEnabled; 2263 } 2264 if (entries.fpr_log_source) { 2265 settingsServiceInstance.logSource = Number(entries.fpr_log_source); 2266 } 2267 if (entries.fpr_log_endpoint_url) { 2268 settingsServiceInstance.logEndPointUrl = entries.fpr_log_endpoint_url; 2269 } 2270 // Key from Remote Config has to be non-empty string, otherwsie use local value. 2271 if (entries.fpr_log_transport_key) { 2272 settingsServiceInstance.transportKey = entries.fpr_log_transport_key; 2273 } 2274 if (entries.fpr_vc_network_request_sampling_rate !== undefined) { 2275 settingsServiceInstance.networkRequestsSamplingRate = Number(entries.fpr_vc_network_request_sampling_rate); 2276 } 2277 if (entries.fpr_vc_trace_sampling_rate !== undefined) {
2278 settingsServiceInstance.tracesSamplingRate = Number(entries.fpr_vc_trace_sampling_rate); 2279 } 2280 // Set the per session trace and network logging flags. 2281 settingsServiceInstance.logTraceAfterSampling = shouldLogAfterSampling(settingsServiceInstance.tracesSamplingRate); 2282 settingsServiceInstance.logNetworkAfterSampling = shouldLogAfterSampling(settingsServiceInstance.networkRequestsSamplingRate); 2283 return config; 2284} 2285function configValid(expiry) { 2286 return Number(expiry) > Date.now(); 2287} 2288function shouldLogAfterSampling(samplingRate) { 2289 return Math.random() <= samplingRate; 2290} 2291 2292/** 2293 * @license 2294 * Copyright 2020 Google LLC 2295 * 2296 * Licensed under the Apache License, Version 2.0 (the "License"); 2297 * you may not use this file except in compliance with the License. 2298 * You may obtain a copy of the License at 2299 * 2300 * http://www.apache.org/licenses/LICENSE-2.0 2301 * 2302 * Unless required by applicable law or agreed to in writing, software 2303 * distributed under the License is distributed on an "AS IS" BASIS, 2304 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2305 * See the License for the specific language governing permissions and 2306 * limitations under the License. 2307 */ 2308let initializationStatus = 1 /* notInitialized */; 2309let initializationPromise; 2310function getInitializationPromise(performanceController) { 2311 initializationStatus = 2 /* initializationPending */; 2312 initializationPromise = 2313 initializationPromise || initializePerf(performanceController); 2314 return initializationPromise; 2315} 2316function isPerfInitialized() { 2317 return initializationStatus === 3 /* initialized */; 2318} 2319function initializePerf(performanceController) { 2320 return getDocumentReadyComplete() 2321 .then(() => getIidPromise(performanceController.installations)) 2322 .then(iid => getConfig(performanceController, iid)) 2323 .then(() => changeInitializationStatus(), () => changeInitializationStatus()); 2324} 2325/** 2326 * Returns a promise which resolves whenever the document readystate is complete or 2327 * immediately if it is called after page load complete. 2328 */ 2329function getDocumentReadyComplete() { 2330 const document = Api.getInstance().document; 2331 return new Promise(resolve => { 2332 if (document && document.readyState !== 'complete') { 2333 const handler = () => { 2334 if (document.readyState === 'complete') { 2335 document.removeEventListener('readystatechange', handler); 2336 resolve(); 2337 } 2338 }; 2339 document.addEventListener('readystatechange', handler); 2340 } 2341 else { 2342 resolve(); 2343 } 2344 }); 2345} 2346function changeInitializationStatus() { 2347 initializationStatus = 3 /* initialized */; 2348} 2349 2350/** 2351 * @license 2352 * Copyright 2020 Google LLC 2353 * 2354 * Licensed under the Apache License, Version 2.0 (the "License"); 2355 * you may not use this file except in compliance with the License. 2356 * You may obtain a copy of the License at 2357 * 2358 * http://www.apache.org/licenses/LICENSE-2.0 2359 * 2360 * Unless required by applicable law or agreed to in writing, software 2361 * distributed under the License is distributed on an "AS IS" BASIS, 2362 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2363 * See the License for the specific language governing permissions and 2364 * limitations under the License. 2365 */ 2366const DEFAULT_SEND_INTERVAL_MS = 10 * 1000; 2367const INITIAL_SEND_TIME_DELAY_MS = 5.5 * 1000; 2368// If end point does not work, the call will be tried for these many times. 2369const DEFAULT_REMAINING_TRIES = 3; 2370const MAX_EVENT_COUNT_PER_REQUEST = 1000; 2371let remainingTries = DEFAULT_REMAINING_TRIES; 2372/* eslint-enable camelcase */ 2373let queue = []; 2374let isTransportSetup = false; 2375function setupTransportService() { 2376 if (!isTransportSetup) { 2377 processQueue(INITIAL_SEND_TIME_DELAY_MS); 2378 isTransportSetup = true; 2379 } 2380} 2381function processQueue(timeOffset) { 2382 setTimeout(() => { 2383 // If there is no remainingTries left, stop retrying. 2384 if (remainingTries === 0) { 2385 return; 2386 } 2387 // If there are no events to process, wait for DEFAULT_SEND_INTERVAL_MS and try again. 2388 if (!queue.length) { 2389 return processQueue(DEFAULT_SEND_INTERVAL_MS); 2390 } 2391 dispatchQueueEvents(); 2392 }, timeOffset); 2393} 2394function dispatchQueueEvents() { 2395 // Extract events up to the maximum cap of single logRequest from top of "official queue". 2396 // The staged events will be used for current logRequest attempt, remaining events will be kept 2397 // for next attempt. 2398 const staged = queue.splice(0, MAX_EVENT_COUNT_PER_REQUEST); 2399 /* eslint-disable camelcase */ 2400 // We will pass the JSON serialized event to the backend. 2401 const log_event = staged.map(evt => ({ 2402 source_extension_json_proto3: evt.message, 2403 event_time_ms: String(evt.eventTime) 2404 })); 2405 const data = { 2406 request_time_ms: String(Date.now()), 2407 client_info: { 2408 client_type: 1, 2409 js_client_info: {} 2410 }, 2411 log_source: SettingsService.getInstance().logSource, 2412 log_event 2413 }; 2414 /* eslint-enable camelcase */ 2415 sendEventsToFl(data, staged).catch(() => { 2416 // If the request fails for some reason, add the events that were attempted 2417 // back to the primary queue to retry later. 2418 queue = [...staged, ...queue]; 2419 remainingTries--; 2420 consoleLogger.info(`Tries left: ${remainingTries}.`); 2421 processQueue(DEFAULT_SEND_INTERVAL_MS); 2422 });
2423} 2424function sendEventsToFl(data, staged) { 2425 return postToFlEndpoint(data) 2426 .then(res => { 2427 if (!res.ok) { 2428 consoleLogger.info('Call to Firebase backend failed.'); 2429 } 2430 return res.json(); 2431 }) 2432 .then(res => { 2433 // Find the next call wait time from the response. 2434 const transportWait = Number(res.nextRequestWaitMillis); 2435 let requestOffset = DEFAULT_SEND_INTERVAL_MS; 2436 if (!isNaN(transportWait)) { 2437 requestOffset = Math.max(transportWait, requestOffset); 2438 } 2439 // Delete request if response include RESPONSE_ACTION_UNKNOWN or DELETE_REQUEST action. 2440 // Otherwise, retry request using normal scheduling if response include RETRY_REQUEST_LATER. 2441 const logResponseDetails = res.logResponseDetails; 2442 if (Array.isArray(logResponseDetails) && 2443 logResponseDetails.length > 0 && 2444 logResponseDetails[0].responseAction === 'RETRY_REQUEST_LATER') { 2445 queue = [...staged, ...queue]; 2446 consoleLogger.info(`Retry transport request later.`); 2447 } 2448 remainingTries = DEFAULT_REMAINING_TRIES; 2449 // Schedule the next process. 2450 processQueue(requestOffset); 2451 }); 2452} 2453function postToFlEndpoint(data) { 2454 const flTransportFullUrl = SettingsService.getInstance().getFlTransportFullUrl(); 2455 return fetch(flTransportFullUrl, { 2456 method: 'POST', 2457 body: JSON.stringify(data) 2458 }); 2459} 2460function addToQueue(evt) { 2461 if (!evt.eventTime || !evt.message) { 2462 throw ERROR_FACTORY.create("invalid cc log" /* INVALID_CC_LOG */); 2463 } 2464 // Add the new event to the queue. 2465 queue = [...queue, evt]; 2466} 2467/** Log handler for cc service to send the performance logs to the server. */ 2468function transportHandler( 2469// eslint-disable-next-line @typescript-eslint/no-explicit-any 2470serializer) { 2471 return (...args) => { 2472 const message = serializer(...args); 2473 addToQueue({ 2474 message, 2475 eventTime: Date.now() 2476 }); 2477 }; 2478} 2479 2480/** 2481 * @license 2482 * Copyright 2020 Google LLC 2483 * 2484 * Licensed under the Apache License, Version 2.0 (the "License"); 2485 * you may not use this file except in compliance with the License. 2486 * You may obtain a copy of the License at 2487 * 2488 * http://www.apache.org/licenses/LICENSE-2.0 2489 * 2490 * Unless required by applicable law or agreed to in writing, software 2491 * distributed under the License is distributed on an "AS IS" BASIS, 2492 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2493 * See the License for the specific language governing permissions and 2494 * limitations under the License. 2495 */ 2496/* eslint-enble camelcase */ 2497let logger; 2498// This method is not called before initialization. 2499function sendLog(resource, resourceType) { 2500 if (!logger) { 2501 logger = transportHandler(serializer); 2502 } 2503 logger(resource, resourceType); 2504} 2505function logTrace(trace) { 2506 const settingsService = SettingsService.getInstance(); 2507 // Do not log if trace is auto generated and instrumentation is disabled. 2508 if (!settingsService.instrumentationEnabled && trace.isAuto) { 2509 return; 2510 } 2511 // Do not log if trace is custom and data collection is disabled. 2512 if (!settingsService.dataCollectionEnabled && !trace.isAuto) { 2513 return; 2514 } 2515 // Do not log if required apis are not available. 2516 if (!Api.getInstance().requiredApisAvailable()) { 2517 return; 2518 } 2519 // Only log the page load auto traces if page is visible. 2520 if (trace.isAuto && getVisibilityState() !== VisibilityState.VISIBLE) { 2521 return; 2522 } 2523 if (isPerfInitialized()) { 2524 sendTraceLog(trace); 2525 } 2526 else { 2527 // Custom traces can be used before the initialization but logging 2528 // should wait until after. 2529 getInitializationPromise(trace.performanceController).then(() => sendTraceLog(trace), () => sendTraceLog(trace)); 2530 } 2531} 2532function sendTraceLog(trace) { 2533 if (!getIid()) { 2534 return; 2535 } 2536 const settingsService = SettingsService.getInstance(); 2537 if (!settingsService.loggingEnabled ||
2538 !settingsService.logTraceAfterSampling) { 2539 return; 2540 } 2541 setTimeout(() => sendLog(trace, 1 /* Trace */), 0); 2542} 2543function logNetworkRequest(networkRequest) { 2544 const settingsService = SettingsService.getInstance(); 2545 // Do not log network requests if instrumentation is disabled. 2546 if (!settingsService.instrumentationEnabled) { 2547 return; 2548 } 2549 // Do not log the js sdk's call to transport service domain to avoid unnecessary cycle. 2550 // Need to blacklist both old and new endpoints to avoid migration gap. 2551 const networkRequestUrl = networkRequest.url; 2552 // Blacklist old log endpoint and new transport endpoint. 2553 // Because Performance SDK doesn't instrument requests sent from SDK itself. 2554 const logEndpointUrl = settingsService.logEndPointUrl.split('?')[0]; 2555 const flEndpointUrl = settingsService.flTransportEndpointUrl.split('?')[0]; 2556 if (networkRequestUrl === logEndpointUrl || 2557 networkRequestUrl === flEndpointUrl) { 2558 return; 2559 } 2560 if (!settingsService.loggingEnabled || 2561 !settingsService.logNetworkAfterSampling) { 2562 return; 2563 } 2564 setTimeout(() => sendLog(networkRequest, 0 /* NetworkRequest */), 0); 2565} 2566function serializer(resource, resourceType) { 2567 if (resourceType === 0 /* NetworkRequest */) { 2568 return serializeNetworkRequest(resource); 2569 } 2570 return serializeTrace(resource); 2571} 2572function serializeNetworkRequest(networkRequest) { 2573 const networkRequestMetric = { 2574 url: networkRequest.url, 2575 http_method: networkRequest.httpMethod || 0, 2576 http_response_code: 200, 2577 response_payload_bytes: networkRequest.responsePayloadBytes, 2578 client_start_time_us: networkRequest.startTimeUs, 2579 time_to_response_initiated_us: networkRequest.timeToResponseInitiatedUs, 2580 time_to_response_completed_us: networkRequest.timeToResponseCompletedUs 2581 }; 2582 const perfMetric = { 2583 application_info: getApplicationInfo(networkRequest.performanceController.app), 2584 network_request_metric: networkRequestMetric 2585 }; 2586 return JSON.stringify(perfMetric); 2587} 2588function serializeTrace(trace) { 2589 const traceMetric = { 2590 name: trace.name, 2591 is_auto: trace.isAuto, 2592 client_start_time_us: trace.startTimeUs, 2593 duration_us: trace.durationUs 2594 }; 2595 if (Object.keys(trace.counters).length !== 0) { 2596 traceMetric.counters = trace.counters; 2597 } 2598 const customAttributes = trace.getAttributes(); 2599 if (Object.keys(customAttributes).length !== 0) { 2600 traceMetric.custom_attributes = customAttributes; 2601 } 2602 const perfMetric = { 2603 application_info: getApplicationInfo(trace.performanceController.app), 2604 trace_metric: traceMetric 2605 }; 2606 return JSON.stringify(perfMetric); 2607} 2608function getApplicationInfo(firebaseApp) { 2609 return { 2610 google_app_id: getAppId(firebaseApp), 2611 app_instance_id: getIid(), 2612 web_app_info: { 2613 sdk_version: SDK_VERSION, 2614 page_url: Api.getInstance().getUrl(), 2615 service_worker_status: getServiceWorkerStatus(), 2616 visibility_state: getVisibilityState(), 2617 effective_connection_type: getEffectiveConnectionType() 2618 }, 2619 application_process_state: 0 2620 }; 2621} 2622 2623/** 2624 * @license 2625 * Copyright 2020 Google LLC 2626 * 2627 * Licensed under the Apache License, Version 2.0 (the "License"); 2628 * you may not use this file except in compliance with the License. 2629 * You may obtain a copy of the License at 2630 * 2631 * http://www.apache.org/licenses/LICENSE-2.0 2632 * 2633 * Unless required by applicable law or agreed to in writing, software 2634 * distributed under the License is distributed on an "AS IS" BASIS, 2635 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2636 * See the License for the specific language governing permissions and 2637 * limitations under the License. 2638 */ 2639const MAX_METRIC_NAME_LENGTH = 100; 2640const RESERVED_AUTO_PREFIX = '_'; 2641const oobMetrics = [ 2642 FIRST_PAINT_COUNTER_NAME, 2643 FIRST_CONTENTFUL_PAINT_COUNTER_NAME, 2644 FIRST_INPUT_DELAY_COUNTER_NAME 2645]; 2646/** 2647 * Returns true if the metric is custom and does not start with reserved prefix, or if 2648 * the metric is one of out of the box page load trace metrics. 2649 */ 2650function isValidMetricName(name, traceName) { 2651 if (name.length === 0 || name.length > MAX_METRIC_NAME_LENGTH) { 2652 return false; 2653 } 2654 return ((traceName && 2655 traceName.startsWith(OOB_TRACE_PAGE_LOAD_PREFIX) && 2656 oobMetrics.indexOf(name) > -1) || 2657 !name.startsWith(RESERVED_AUTO_PREFIX)); 2658} 2659/** 2660 * Converts the provided value to an integer value to be used in case of a metric. 2661 * @param providedValue Provided number value of the metric that needs to be converted to an integer. 2662 * 2663 * @returns Converted integer number to be set for the metric. 2664 */ 2665function convertMetricValueToInteger(providedValue) { 2666 const valueAsInteger = Math.floor(providedValue); 2667 if (valueAsInteger < providedValue) { 2668 consoleLogger.info(`Metric value should be an Integer, setting the value as : ${valueAsInteger}.`); 2669 } 2670 return valueAsInteger; 2671} 2672
2673/** 2674 * @license 2675 * Copyright 2020 Google LLC 2676 * 2677 * Licensed under the Apache License, Version 2.0 (the "License"); 2678 * you may not use this file except in compliance with the License. 2679 * You may obtain a copy of the License at 2680 * 2681 * http://www.apache.org/licenses/LICENSE-2.0 2682 * 2683 * Unless required by applicable law or agreed to in writing, software 2684 * distributed under the License is distributed on an "AS IS" BASIS, 2685 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2686 * See the License for the specific language governing permissions and 2687 * limitations under the License. 2688 */ 2689class Trace { 2690 /** 2691 * @param performanceController The performance controller running. 2692 * @param name The name of the trace. 2693 * @param isAuto If the trace is auto-instrumented. 2694 * @param traceMeasureName The name of the measure marker in user timing specification. This field 2695 * is only set when the trace is built for logging when the user directly uses the user timing 2696 * api (performance.mark and performance.measure). 2697 */ 2698 constructor(performanceController, name, isAuto = false, traceMeasureName) { 2699 this.performanceController = performanceController; 2700 this.name = name; 2701 this.isAuto = isAuto; 2702 this.state = 1 /* UNINITIALIZED */; 2703 this.customAttributes = {}; 2704 this.counters = {}; 2705 this.api = Api.getInstance(); 2706 this.randomId = Math.floor(Math.random() * 1000000); 2707 if (!this.isAuto) { 2708 this.traceStartMark = `${TRACE_START_MARK_PREFIX}-${this.randomId}-${this.name}`; 2709 this.traceStopMark = `${TRACE_STOP_MARK_PREFIX}-${this.randomId}-${this.name}`; 2710 this.traceMeasure = 2711 traceMeasureName || 2712 `${TRACE_MEASURE_PREFIX}-${this.randomId}-${this.name}`; 2713 if (traceMeasureName) { 2714 // For the case of direct user timing traces, no start stop will happen. The measure object 2715 // is already available. 2716 this.calculateTraceMetrics(); 2717 } 2718 } 2719 } 2720 /** 2721 * Starts a trace. The measurement of the duration starts at this point. 2722 */ 2723 start() { 2724 if (this.state !== 1 /* UNINITIALIZED */) { 2725 throw ERROR_FACTORY.create("trace started" /* TRACE_STARTED_BEFORE */, { 2726 traceName: this.name 2727 }); 2728 } 2729 this.api.mark(this.traceStartMark); 2730 this.state = 2 /* RUNNING */; 2731 } 2732 /** 2733 * Stops the trace. The measurement of the duration of the trace stops at this point and trace 2734 * is logged. 2735 */ 2736 stop() { 2737 if (this.state !== 2 /* RUNNING */) { 2738 throw ERROR_FACTORY.create("trace stopped" /* TRACE_STOPPED_BEFORE */, { 2739 traceName: this.name 2740 }); 2741 } 2742 this.state = 3 /* TERMINATED */; 2743 this.api.mark(this.traceStopMark); 2744 this.api.measure(this.traceMeasure, this.traceStartMark, this.traceStopMark); 2745 this.calculateTraceMetrics(); 2746 logTrace(this); 2747 } 2748 /** 2749 * Records a trace with predetermined values. If this method is used a trace is created and logged 2750 * directly. No need to use start and stop methods. 2751 * @param startTime Trace start time since epoch in millisec 2752 * @param duration The duraction of the trace in millisec 2753 * @param options An object which can optionally hold maps of custom metrics and custom attributes 2754 */ 2755 record(startTime, duration, options) { 2756 if (startTime <= 0) { 2757 throw ERROR_FACTORY.create("nonpositive trace startTime" /* NONPOSITIVE_TRACE_START_TIME */, { 2758 traceName: this.name 2759 }); 2760 } 2761 if (duration <= 0) { 2762 throw ERROR_FACTORY.create("nonpositive trace duration" /* NONPOSITIVE_TRACE_DURATION */, { 2763 traceName: this.name 2764 }); 2765 } 2766 this.durationUs = Math.floor(duration * 1000); 2767 this.startTimeUs = Math.floor(startTime * 1000); 2768 if (options && options.attributes) { 2769 this.customAttributes = Object.assign({}, options.attributes); 2770 } 2771 if (options && options.metrics) { 2772 for (const metric of Object.keys(options.metrics)) { 2773 if (!isNaN(Number(options.metrics[metric]))) { 2774 this.counters[metric] = Number(Math.floor(options.metrics[metric])); 2775 } 2776 } 2777 } 2778 logTrace(this); 2779 } 2780 /**
2781 * Increments a custom metric by a certain number or 1 if number not specified. Will create a new 2782 * custom metric if one with the given name does not exist. The value will be floored down to an 2783 * integer. 2784 * @param counter Name of the custom metric 2785 * @param numAsInteger Increment by value 2786 */ 2787 incrementMetric(counter, numAsInteger = 1) { 2788 if (this.counters[counter] === undefined) { 2789 this.putMetric(counter, numAsInteger); 2790 } 2791 else { 2792 this.putMetric(counter, this.counters[counter] + numAsInteger); 2793 } 2794 } 2795 /** 2796 * Sets a custom metric to a specified value. Will create a new custom metric if one with the 2797 * given name does not exist. The value will be floored down to an integer. 2798 * @param counter Name of the custom metric 2799 * @param numAsInteger Set custom metric to this value 2800 */ 2801 putMetric(counter, numAsInteger) { 2802 if (isValidMetricName(counter, this.name)) { 2803 this.counters[counter] = convertMetricValueToInteger(numAsInteger); 2804 } 2805 else { 2806 throw ERROR_FACTORY.create("invalid custom metric name" /* INVALID_CUSTOM_METRIC_NAME */, { 2807 customMetricName: counter 2808 }); 2809 } 2810 } 2811 /** 2812 * Returns the value of the custom metric by that name. If a custom metric with that name does 2813 * not exist will return zero. 2814 * @param counter 2815 */ 2816 getMetric(counter) { 2817 return this.counters[counter] || 0; 2818 } 2819 /** 2820 * Sets a custom attribute of a trace to a certain value. 2821 * @param attr 2822 * @param value 2823 */ 2824 putAttribute(attr, value) { 2825 const isValidName = isValidCustomAttributeName(attr); 2826 const isValidValue = isValidCustomAttributeValue(value); 2827 if (isValidName && isValidValue) { 2828 this.customAttributes[attr] = value; 2829 return; 2830 } 2831 // Throw appropriate error when the attribute name or value is invalid. 2832 if (!isValidName) { 2833 throw ERROR_FACTORY.create("invalid attribute name" /* INVALID_ATTRIBUTE_NAME */, { 2834 attributeName: attr 2835 }); 2836 } 2837 if (!isValidValue) { 2838 throw ERROR_FACTORY.create("invalid attribute value" /* INVALID_ATTRIBUTE_VALUE */, { 2839 attributeValue: value 2840 }); 2841 } 2842 } 2843 /** 2844 * Retrieves the value a custom attribute of a trace is set to. 2845 * @param attr 2846 */ 2847 getAttribute(attr) { 2848 return this.customAttributes[attr]; 2849 } 2850 removeAttribute(attr) { 2851 if (this.customAttributes[attr] === undefined) { 2852 return; 2853 } 2854 delete this.customAttributes[attr]; 2855 } 2856 getAttributes() { 2857 return Object.assign({}, this.customAttributes); 2858 } 2859 setStartTime(startTime) { 2860 this.startTimeUs = startTime; 2861 } 2862 setDuration(duration) { 2863 this.durationUs = duration; 2864 } 2865 /** 2866 * Calculates and assigns the duration and start time of the trace using the measure performance 2867 * entry. 2868 */ 2869 calculateTraceMetrics() { 2870 const perfMeasureEntries = this.api.getEntriesByName(this.traceMeasure); 2871 const perfMeasureEntry = perfMeasureEntries && perfMeasureEntries[0]; 2872 if (perfMeasureEntry) { 2873 this.durationUs = Math.floor(perfMeasureEntry.duration * 1000); 2874 this.startTimeUs = Math.floor((perfMeasureEntry.startTime + this.api.getTimeOrigin()) * 1000); 2875 } 2876 } 2877 /** 2878 * @param navigationTimings A single element array which contains the navigationTIming object of 2879 * the page load 2880 * @param paintTimings A array which contains paintTiming object of the page load 2881 * @param firstInputDelay First input delay in millisec 2882 */ 2883 static createOobTrace(performanceController, navigationTimings, paintTimings, firstInputDelay) { 2884 const route = Api.getInstance().getUrl(); 2885 if (!route) { 2886 return; 2887 } 2888 const trace = new Trace(performanceController, OOB_TRACE_PAGE_LOAD_PREFIX + route, true); 2889 const timeOriginUs = Math.floor(Api.getInstance().getTimeOrigin() * 1000); 2890 trace.setStartTime(timeOriginUs); 2891 // navigationTimings includes only one element. 2892 if (navigationTimings && navigationTimings[0]) { 2893 trace.setDuration(Math.floor(navigationTimings[0].duration * 1000)); 2894 trace.putMetric('domInteractive', Math.floor(navigationTimings[0].domInteractive * 1000)); 2895 trace.putMetric('domContentLoadedEventEnd', Math.floor(navigationTimings[0].domContentLoadedEventEnd * 1000)); 2896 trace.putMetric('loadEventEnd', Math.floor(navigationTimings[0].loadEventEnd * 1000)); 2897 } 2898 const FIRST_PAINT = 'first-paint'; 2899 const FIRST_CONTENTFUL_PAINT = 'first-contentful-paint'; 2900 if (paintTimings) { 2901 const firstPaint = paintTimings.find(paintObject => paintObject.name === FIRST_PAINT); 2902 if (firstPaint && firstPaint.startTime) { 2903 trace.putMetric(FIRST_PAINT_COUNTER_NAME, Math.floor(firstPaint.startTime * 1000)); 2904 } 2905 const firstContentfulPaint = paintTimings.find(paintObject => paintObject.name === FIRST_CONTENTFUL_PAINT); 2906 if (firstContentfulPaint && firstContentfulPaint.startTime) { 2907 trace.putMetric(FIRST_CONTENTFUL_PAINT_COUNTER_NAME, Math.floor(firstContentfulPaint.startTime * 1000)); 2908 } 2909 if (firstInputDelay) { 2910 trace.putMetric(FIRST_INPUT_DELAY_COUNTER_NAME, Math.floor(firstInputDelay * 1000)); 2911 } 2912 } 2913 logTrace(trace); 2914 } 2915 static createUserTimingTrace(performanceController, measureName) { 2916 const trace = new Trace(performanceController, measureName, false, measureName); 2917 logTrace(trace); 2918 } 2919} 2920 2921/** 2922 * @license 2923 * Copyright 2020 Google LLC 2924 * 2925 * Licensed under the Apache License, Version 2.0 (the "License");
2926 * you may not use this file except in compliance with the License. 2927 * You may obtain a copy of the License at 2928 * 2929 * http://www.apache.org/licenses/LICENSE-2.0 2930 * 2931 * Unless required by applicable law or agreed to in writing, software 2932 * distributed under the License is distributed on an "AS IS" BASIS, 2933 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2934 * See the License for the specific language governing permissions and 2935 * limitations under the License. 2936 */ 2937function createNetworkRequestEntry(performanceController, entry) { 2938 const performanceEntry = entry; 2939 if (!performanceEntry || performanceEntry.responseStart === undefined) { 2940 return; 2941 } 2942 const timeOrigin = Api.getInstance().getTimeOrigin(); 2943 const startTimeUs = Math.floor((performanceEntry.startTime + timeOrigin) * 1000); 2944 const timeToResponseInitiatedUs = performanceEntry.responseStart 2945 ? Math.floor((performanceEntry.responseStart - performanceEntry.startTime) * 1000) 2946 : undefined; 2947 const timeToResponseCompletedUs = Math.floor((performanceEntry.responseEnd - performanceEntry.startTime) * 1000); 2948 // Remove the query params from logged network request url. 2949 const url = performanceEntry.name && performanceEntry.name.split('?')[0]; 2950 const networkRequest = { 2951 performanceController, 2952 url, 2953 responsePayloadBytes: performanceEntry.transferSize, 2954 startTimeUs, 2955 timeToResponseInitiatedUs, 2956 timeToResponseCompletedUs 2957 }; 2958 logNetworkRequest(networkRequest); 2959} 2960 2961/** 2962 * @license 2963 * Copyright 2020 Google LLC 2964 * 2965 * Licensed under the Apache License, Version 2.0 (the "License"); 2966 * you may not use this file except in compliance with the License. 2967 * You may obtain a copy of the License at 2968 * 2969 * http://www.apache.org/licenses/LICENSE-2.0 2970 * 2971 * Unless required by applicable law or agreed to in writing, software 2972 * distributed under the License is distributed on an "AS IS" BASIS, 2973 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2974 * See the License for the specific language governing permissions and 2975 * limitations under the License. 2976 */ 2977const FID_WAIT_TIME_MS = 5000; 2978function setupOobResources(performanceController) { 2979 // Do not initialize unless iid is available. 2980 if (!getIid()) { 2981 return; 2982 } 2983 // The load event might not have fired yet, and that means performance navigation timing 2984 // object has a duration of 0. The setup should run after all current tasks in js queue. 2985 setTimeout(() => setupOobTraces(performanceController), 0); 2986 setTimeout(() => setupNetworkRequests(performanceController), 0); 2987 setTimeout(() => setupUserTimingTraces(performanceController), 0); 2988} 2989function setupNetworkRequests(performanceController) { 2990 const api = Api.getInstance(); 2991 const resources = api.getEntriesByType('resource'); 2992 for (const resource of resources) { 2993 createNetworkRequestEntry(performanceController, resource); 2994 } 2995 api.setupObserver('resource', entry => createNetworkRequestEntry(performanceController, entry)); 2996} 2997function setupOobTraces(performanceController) { 2998 const api = Api.getInstance(); 2999 const navigationTimings = api.getEntriesByType('navigation'); 3000 const paintTimings = api.getEntriesByType('paint'); 3001 // If First Input Desly polyfill is added to the page, report the fid value. 3002 // https://github.com/GoogleChromeLabs/first-input-delay 3003 if (api.onFirstInputDelay) { 3004 // If the fid call back is not called for certain time, continue without it. 3005 // eslint-disable-next-line @typescript-eslint/no-explicit-any 3006 let timeoutId = setTimeout(() => { 3007 Trace.createOobTrace(performanceController, navigationTimings, paintTimings); 3008 timeoutId = undefined; 3009 }, FID_WAIT_TIME_MS); 3010 api.onFirstInputDelay((fid) => { 3011 if (timeoutId) { 3012 clearTimeout(timeoutId); 3013 Trace.createOobTrace(performanceController, navigationTimings, paintTimings, fid); 3014 } 3015 }); 3016 } 3017 else { 3018 Trace.createOobTrace(performanceController, navigationTimings, paintTimings); 3019 } 3020} 3021function setupUserTimingTraces(performanceController) { 3022 const api = Api.getInstance(); 3023 // Run through the measure performance entries collected up to this point. 3024 const measures = api.getEntriesByType('measure'); 3025 for (const measure of measures) { 3026 createUserTimingTrace(performanceController, measure); 3027 } 3028 // Setup an observer to capture the measures from this point on. 3029 api.setupObserver('measure', entry => createUserTimingTrace(performanceController, entry)); 3030} 3031function createUserTimingTrace(performanceController, measure) { 3032 const measureName = measure.name;
3033 // Do not create a trace, if the user timing marks and measures are created by the sdk itself. 3034 if (measureName.substring(0, TRACE_MEASURE_PREFIX.length) === 3035 TRACE_MEASURE_PREFIX) { 3036 return; 3037 } 3038 Trace.createUserTimingTrace(performanceController, measureName); 3039} 3040 3041/** 3042 * @license 3043 * Copyright 2020 Google LLC 3044 * 3045 * Licensed under the Apache License, Version 2.0 (the "License"); 3046 * you may not use this file except in compliance with the License. 3047 * You may obtain a copy of the License at 3048 * 3049 * http://www.apache.org/licenses/LICENSE-2.0 3050 * 3051 * Unless required by applicable law or agreed to in writing, software 3052 * distributed under the License is distributed on an "AS IS" BASIS, 3053 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3054 * See the License for the specific language governing permissions and 3055 * limitations under the License. 3056 */ 3057class PerformanceController { 3058 constructor(app, installations) { 3059 this.app = app; 3060 this.installations = installations; 3061 this.initialized = false; 3062 } 3063 /** 3064 * This method *must* be called internally as part of creating a 3065 * PerformanceController instance. 3066 * 3067 * Currently it's not possible to pass the settings object through the 3068 * constructor using Components, so this method exists to be called with the 3069 * desired settings, to ensure nothing is collected without the user's 3070 * consent. 3071 */ 3072 _init(settings) { 3073 if (this.initialized) { 3074 return; 3075 } 3076 if ((settings === null || settings === void 0 ? void 0 : settings.dataCollectionEnabled) !== undefined) { 3077 this.dataCollectionEnabled = settings.dataCollectionEnabled; 3078 } 3079 if ((settings === null || settings === void 0 ? void 0 : settings.instrumentationEnabled) !== undefined) { 3080 this.instrumentationEnabled = settings.instrumentationEnabled; 3081 } 3082 if (Api.getInstance().requiredApisAvailable()) { 3083 validateIndexedDBOpenable() 3084 .then(isAvailable => { 3085 if (isAvailable) { 3086 setupTransportService(); 3087 getInitializationPromise(this).then(() => setupOobResources(this), () => setupOobResources(this)); 3088 this.initialized = true; 3089 } 3090 }) 3091 .catch(error => { 3092 consoleLogger.info(`Environment doesn't support IndexedDB: ${error}`); 3093 }); 3094 } 3095 else { 3096 consoleLogger.info('Firebase Performance cannot start if the browser does not support ' + 3097 '"Fetch" and "Promise", or cookies are disabled.'); 3098 } 3099 } 3100 set instrumentationEnabled(val) { 3101 SettingsService.getInstance().instrumentationEnabled = val; 3102 } 3103 get instrumentationEnabled() { 3104 return SettingsService.getInstance().instrumentationEnabled; 3105 } 3106 set dataCollectionEnabled(val) { 3107 SettingsService.getInstance().dataCollectionEnabled = val; 3108 } 3109 get dataCollectionEnabled() { 3110 return SettingsService.getInstance().dataCollectionEnabled; 3111 } 3112} 3113 3114/** 3115 * Firebase Performance Monitoring 3116 * 3117 * @packageDocumentation 3118 */ 3119const DEFAULT_ENTRY_NAME = '[DEFAULT]'; 3120/** 3121 * Returns a {@link FirebasePerformance} instance for the given app. 3122 * @param app - The {@link https://www.gstatic.com/firebasejs/9.6.4/firebase-app.js#FirebaseApp} to use. 3123 * @public 3124 */ 3125function getPerformance(app = getApp()) { 3126 app = getModularInstance(app); 3127 const provider = _getProvider(app, 'performance'); 3128 const perfInstance = provider.getImmediate(); 3129 return perfInstance; 3130} 3131/** 3132 * Returns a {@link FirebasePerformance} instance for the given app. Can only be called once. 3133 * @param app - The {@link https://www.gstatic.com/firebasejs/9.6.4/firebase-app.js#FirebaseApp} to use. 3134 * @param settings - Optional settings for the {@link FirebasePerformance} instance. 3135 * @public 3136 */ 3137function initializePerformance(app, settings) { 3138 app = getModularInstance(app); 3139 const provider = _getProvider(app, 'performance'); 3140 // throw if an instance was already created. 3141 // It could happen if initializePerformance() is called more than once, or getPerformance() is called first. 3142 if (provider.isInitialized()) { 3143 const existingInstance = provider.getImmediate(); 3144 const initialSettings = provider.getOptions(); 3145 if (deepEqual(initialSettings, settings !== null && settings !== void 0 ? settings : {})) { 3146 return existingInstance; 3147 } 3148 else { 3149 throw ERROR_FACTORY.create("already initialized" /* ALREADY_INITIALIZED */); 3150 } 3151 } 3152 const perfInstance = provider.initialize({ 3153 options: settings 3154 });
vendor: 1,443 bytes, lines 3155-3194
3155 return perfInstance; 3156} 3157/** 3158 * Returns a new `PerformanceTrace` instance. 3159 * @param performance - The {@link FirebasePerformance} instance to use. 3160 * @param name - The name of the trace. 3161 * @public 3162 */ 3163function trace(performance, name) { 3164 performance = getModularInstance(performance); 3165 return new Trace(performance, name); 3166} 3167const factory = (container, { options: settings }) => { 3168 // Dependencies 3169 const app = container.getProvider('app').getImmediate(); 3170 const installations = container 3171 .getProvider('installations-internal') 3172 .getImmediate(); 3173 if (app.name !== DEFAULT_ENTRY_NAME) { 3174 throw ERROR_FACTORY.create("FB not default" /* FB_NOT_DEFAULT */); 3175 } 3176 if (typeof window === 'undefined') { 3177 throw ERROR_FACTORY.create("no window" /* NO_WINDOW */); 3178 } 3179 setupApi(window); 3180 const perfInstance = new PerformanceController(app, installations); 3181 perfInstance._init(settings); 3182 return perfInstance; 3183}; 3184function registerPerformance() { 3185 _registerComponent(new Component('performance', factory, "PUBLIC" /* PUBLIC */)); 3186 registerVersion(name, version); 3187 // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation 3188 registerVersion(name, version, 'esm2017'); 3189} 3190registerPerformance(); 3191 3192export { getPerformance, initializePerformance, trace }; 3193 3194//# sourceMappingURL=firebase-performance.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.