UNPKG

65 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var util = require('@firebase/util');
6var logger$1 = require('@firebase/logger');
7var tslib = require('tslib');
8var app = require('@firebase/app');
9var component = require('@firebase/component');
10require('@firebase/installations');
11
12var name = "@firebase/performance";
13var version = "0.6.6";
14
15/**
16 * @license
17 * Copyright 2020 Google LLC
18 *
19 * Licensed under the Apache License, Version 2.0 (the "License");
20 * you may not use this file except in compliance with the License.
21 * You may obtain a copy of the License at
22 *
23 * http://www.apache.org/licenses/LICENSE-2.0
24 *
25 * Unless required by applicable law or agreed to in writing, software
26 * distributed under the License is distributed on an "AS IS" BASIS,
27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 * See the License for the specific language governing permissions and
29 * limitations under the License.
30 */
31var SDK_VERSION = version;
32/** The prefix for start User Timing marks used for creating Traces. */
33var TRACE_START_MARK_PREFIX = 'FB-PERF-TRACE-START';
34/** The prefix for stop User Timing marks used for creating Traces. */
35var TRACE_STOP_MARK_PREFIX = 'FB-PERF-TRACE-STOP';
36/** The prefix for User Timing measure used for creating Traces. */
37var TRACE_MEASURE_PREFIX = 'FB-PERF-TRACE-MEASURE';
38/** The prefix for out of the box page load Trace name. */
39var OOB_TRACE_PAGE_LOAD_PREFIX = '_wt_';
40var FIRST_PAINT_COUNTER_NAME = '_fp';
41var FIRST_CONTENTFUL_PAINT_COUNTER_NAME = '_fcp';
42var FIRST_INPUT_DELAY_COUNTER_NAME = '_fid';
43var CONFIG_LOCAL_STORAGE_KEY = '@firebase/performance/config';
44var CONFIG_EXPIRY_LOCAL_STORAGE_KEY = '@firebase/performance/configexpire';
45var SERVICE = 'performance';
46var SERVICE_NAME = 'Performance';
47
48/**
49 * @license
50 * Copyright 2020 Google LLC
51 *
52 * Licensed under the Apache License, Version 2.0 (the "License");
53 * you may not use this file except in compliance with the License.
54 * You may obtain a copy of the License at
55 *
56 * http://www.apache.org/licenses/LICENSE-2.0
57 *
58 * Unless required by applicable law or agreed to in writing, software
59 * distributed under the License is distributed on an "AS IS" BASIS,
60 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
61 * See the License for the specific language governing permissions and
62 * limitations under the License.
63 */
64var _a;
65var ERROR_DESCRIPTION_MAP = (_a = {},
66 _a["trace started" /* ErrorCode.TRACE_STARTED_BEFORE */] = 'Trace {$traceName} was started before.',
67 _a["trace stopped" /* ErrorCode.TRACE_STOPPED_BEFORE */] = 'Trace {$traceName} is not running.',
68 _a["nonpositive trace startTime" /* ErrorCode.NONPOSITIVE_TRACE_START_TIME */] = 'Trace {$traceName} startTime should be positive.',
69 _a["nonpositive trace duration" /* ErrorCode.NONPOSITIVE_TRACE_DURATION */] = 'Trace {$traceName} duration should be positive.',
70 _a["no window" /* ErrorCode.NO_WINDOW */] = 'Window is not available.',
71 _a["no app id" /* ErrorCode.NO_APP_ID */] = 'App id is not available.',
72 _a["no project id" /* ErrorCode.NO_PROJECT_ID */] = 'Project id is not available.',
73 _a["no api key" /* ErrorCode.NO_API_KEY */] = 'Api key is not available.',
74 _a["invalid cc log" /* ErrorCode.INVALID_CC_LOG */] = 'Attempted to queue invalid cc event',
75 _a["FB not default" /* ErrorCode.FB_NOT_DEFAULT */] = 'Performance can only start when Firebase app instance is the default one.',
76 _a["RC response not ok" /* ErrorCode.RC_NOT_OK */] = 'RC response is not ok',
77 _a["invalid attribute name" /* ErrorCode.INVALID_ATTRIBUTE_NAME */] = 'Attribute name {$attributeName} is invalid.',
78 _a["invalid attribute value" /* ErrorCode.INVALID_ATTRIBUTE_VALUE */] = 'Attribute value {$attributeValue} is invalid.',
79 _a["invalid custom metric name" /* ErrorCode.INVALID_CUSTOM_METRIC_NAME */] = 'Custom metric name {$customMetricName} is invalid',
80 _a["invalid String merger input" /* ErrorCode.INVALID_STRING_MERGER_PARAMETER */] = 'Input for String merger is invalid, contact support team to resolve.',
81 _a["already initialized" /* ErrorCode.ALREADY_INITIALIZED */] = 'initializePerformance() has already been called with ' +
82 'different options. To avoid this error, call initializePerformance() with the ' +
83 'same options as when it was originally called, or call getPerformance() to return the' +
84 ' already initialized instance.',
85 _a);
86var ERROR_FACTORY = new util.ErrorFactory(SERVICE, SERVICE_NAME, ERROR_DESCRIPTION_MAP);
87
88/**
89 * @license
90 * Copyright 2020 Google LLC
91 *
92 * Licensed under the Apache License, Version 2.0 (the "License");
93 * you may not use this file except in compliance with the License.
94 * You may obtain a copy of the License at
95 *
96 * http://www.apache.org/licenses/LICENSE-2.0
97 *
98 * Unless required by applicable law or agreed to in writing, software
99 * distributed under the License is distributed on an "AS IS" BASIS,
100 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
101 * See the License for the specific language governing permissions and
102 * limitations under the License.
103 */
104var consoleLogger = new logger$1.Logger(SERVICE_NAME);
105consoleLogger.logLevel = logger$1.LogLevel.INFO;
106
107/**
108 * @license
109 * Copyright 2020 Google LLC
110 *
111 * Licensed under the Apache License, Version 2.0 (the "License");
112 * you may not use this file except in compliance with the License.
113 * You may obtain a copy of the License at
114 *
115 * http://www.apache.org/licenses/LICENSE-2.0
116 *
117 * Unless required by applicable law or agreed to in writing, software
118 * distributed under the License is distributed on an "AS IS" BASIS,
119 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120 * See the License for the specific language governing permissions and
121 * limitations under the License.
122 */
123var apiInstance;
124var windowInstance;
125/**
126 * This class holds a reference to various browser related objects injected by
127 * set methods.
128 */
129var Api = /** @class */ (function () {
130 function Api(window) {
131 this.window = window;
132 if (!window) {
133 throw ERROR_FACTORY.create("no window" /* ErrorCode.NO_WINDOW */);
134 }
135 this.performance = window.performance;
136 this.PerformanceObserver = window.PerformanceObserver;
137 this.windowLocation = window.location;
138 this.navigator = window.navigator;
139 this.document = window.document;
140 if (this.navigator && this.navigator.cookieEnabled) {
141 // If user blocks cookies on the browser, accessing localStorage will
142 // throw an exception.
143 this.localStorage = window.localStorage;
144 }
145 if (window.perfMetrics && window.perfMetrics.onFirstInputDelay) {
146 this.onFirstInputDelay = window.perfMetrics.onFirstInputDelay;
147 }
148 }
149 Api.prototype.getUrl = function () {
150 // Do not capture the string query part of url.
151 return this.windowLocation.href.split('?')[0];
152 };
153 Api.prototype.mark = function (name) {
154 if (!this.performance || !this.performance.mark) {
155 return;
156 }
157 this.performance.mark(name);
158 };
159 Api.prototype.measure = function (measureName, mark1, mark2) {
160 if (!this.performance || !this.performance.measure) {
161 return;
162 }
163 this.performance.measure(measureName, mark1, mark2);
164 };
165 Api.prototype.getEntriesByType = function (type) {
166 if (!this.performance || !this.performance.getEntriesByType) {
167 return [];
168 }
169 return this.performance.getEntriesByType(type);
170 };
171 Api.prototype.getEntriesByName = function (name) {
172 if (!this.performance || !this.performance.getEntriesByName) {
173 return [];
174 }
175 return this.performance.getEntriesByName(name);
176 };
177 Api.prototype.getTimeOrigin = function () {
178 // Polyfill the time origin with performance.timing.navigationStart.
179 return (this.performance &&
180 (this.performance.timeOrigin || this.performance.timing.navigationStart));
181 };
182 Api.prototype.requiredApisAvailable = function () {
183 if (!fetch || !Promise || !util.areCookiesEnabled()) {
184 consoleLogger.info('Firebase Performance cannot start if browser does not support fetch and Promise or cookie is disabled.');
185 return false;
186 }
187 if (!util.isIndexedDBAvailable()) {
188 consoleLogger.info('IndexedDB is not supported by current browser');
189 return false;
190 }
191 return true;
192 };
193 Api.prototype.setupObserver = function (entryType, callback) {
194 if (!this.PerformanceObserver) {
195 return;
196 }
197 var observer = new this.PerformanceObserver(function (list) {
198 for (var _i = 0, _a = list.getEntries(); _i < _a.length; _i++) {
199 var entry = _a[_i];
200 // `entry` is a PerformanceEntry instance.
201 callback(entry);
202 }
203 });
204 // Start observing the entry types you care about.
205 observer.observe({ entryTypes: [entryType] });
206 };
207 Api.getInstance = function () {
208 if (apiInstance === undefined) {
209 apiInstance = new Api(windowInstance);
210 }
211 return apiInstance;
212 };
213 return Api;
214}());
215function setupApi(window) {
216 windowInstance = window;
217}
218
219/**
220 * @license
221 * Copyright 2020 Google LLC
222 *
223 * Licensed under the Apache License, Version 2.0 (the "License");
224 * you may not use this file except in compliance with the License.
225 * You may obtain a copy of the License at
226 *
227 * http://www.apache.org/licenses/LICENSE-2.0
228 *
229 * Unless required by applicable law or agreed to in writing, software
230 * distributed under the License is distributed on an "AS IS" BASIS,
231 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
232 * See the License for the specific language governing permissions and
233 * limitations under the License.
234 */
235var iid;
236function getIidPromise(installationsService) {
237 var iidPromise = installationsService.getId();
238 // eslint-disable-next-line @typescript-eslint/no-floating-promises
239 iidPromise.then(function (iidVal) {
240 iid = iidVal;
241 });
242 return iidPromise;
243}
244// This method should be used after the iid is retrieved by getIidPromise method.
245function getIid() {
246 return iid;
247}
248function getAuthTokenPromise(installationsService) {
249 var authTokenPromise = installationsService.getToken();
250 // eslint-disable-next-line @typescript-eslint/no-floating-promises
251 authTokenPromise.then(function (authTokenVal) {
252 });
253 return authTokenPromise;
254}
255
256/**
257 * @license
258 * Copyright 2020 Google LLC
259 *
260 * Licensed under the Apache License, Version 2.0 (the "License");
261 * you may not use this file except in compliance with the License.
262 * You may obtain a copy of the License at
263 *
264 * http://www.apache.org/licenses/LICENSE-2.0
265 *
266 * Unless required by applicable law or agreed to in writing, software
267 * distributed under the License is distributed on an "AS IS" BASIS,
268 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
269 * See the License for the specific language governing permissions and
270 * limitations under the License.
271 */
272function mergeStrings(part1, part2) {
273 var sizeDiff = part1.length - part2.length;
274 if (sizeDiff < 0 || sizeDiff > 1) {
275 throw ERROR_FACTORY.create("invalid String merger input" /* ErrorCode.INVALID_STRING_MERGER_PARAMETER */);
276 }
277 var resultArray = [];
278 for (var i = 0; i < part1.length; i++) {
279 resultArray.push(part1.charAt(i));
280 if (part2.length > i) {
281 resultArray.push(part2.charAt(i));
282 }
283 }
284 return resultArray.join('');
285}
286
287/**
288 * @license
289 * Copyright 2019 Google LLC
290 *
291 * Licensed under the Apache License, Version 2.0 (the "License");
292 * you may not use this file except in compliance with the License.
293 * You may obtain a copy of the License at
294 *
295 * http://www.apache.org/licenses/LICENSE-2.0
296 *
297 * Unless required by applicable law or agreed to in writing, software
298 * distributed under the License is distributed on an "AS IS" BASIS,
299 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
300 * See the License for the specific language governing permissions and
301 * limitations under the License.
302 */
303var settingsServiceInstance;
304var SettingsService = /** @class */ (function () {
305 function SettingsService() {
306 // The variable which controls logging of automatic traces and HTTP/S network monitoring.
307 this.instrumentationEnabled = true;
308 // The variable which controls logging of custom traces.
309 this.dataCollectionEnabled = true;
310 // Configuration flags set through remote config.
311 this.loggingEnabled = false;
312 // Sampling rate between 0 and 1.
313 this.tracesSamplingRate = 1;
314 this.networkRequestsSamplingRate = 1;
315 // Address of logging service.
316 this.logEndPointUrl = 'https://firebaselogging.googleapis.com/v0cc/log?format=json_proto';
317 // Performance event transport endpoint URL which should be compatible with proto3.
318 // New Address for transport service, not configurable via Remote Config.
319 this.flTransportEndpointUrl = mergeStrings('hts/frbslgigp.ogepscmv/ieo/eaylg', 'tp:/ieaeogn-agolai.o/1frlglgc/o');
320 this.transportKey = mergeStrings('AzSC8r6ReiGqFMyfvgow', 'Iayx0u-XT3vksVM-pIV');
321 // Source type for performance event logs.
322 this.logSource = 462;
323 // Flags which control per session logging of traces and network requests.
324 this.logTraceAfterSampling = false;
325 this.logNetworkAfterSampling = false;
326 // TTL of config retrieved from remote config in hours.
327 this.configTimeToLive = 12;
328 }
329 SettingsService.prototype.getFlTransportFullUrl = function () {
330 return this.flTransportEndpointUrl.concat('?key=', this.transportKey);
331 };
332 SettingsService.getInstance = function () {
333 if (settingsServiceInstance === undefined) {
334 settingsServiceInstance = new SettingsService();
335 }
336 return settingsServiceInstance;
337 };
338 return SettingsService;
339}());
340
341/**
342 * @license
343 * Copyright 2020 Google LLC
344 *
345 * Licensed under the Apache License, Version 2.0 (the "License");
346 * you may not use this file except in compliance with the License.
347 * You may obtain a copy of the License at
348 *
349 * http://www.apache.org/licenses/LICENSE-2.0
350 *
351 * Unless required by applicable law or agreed to in writing, software
352 * distributed under the License is distributed on an "AS IS" BASIS,
353 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
354 * See the License for the specific language governing permissions and
355 * limitations under the License.
356 */
357var VisibilityState;
358(function (VisibilityState) {
359 VisibilityState[VisibilityState["UNKNOWN"] = 0] = "UNKNOWN";
360 VisibilityState[VisibilityState["VISIBLE"] = 1] = "VISIBLE";
361 VisibilityState[VisibilityState["HIDDEN"] = 2] = "HIDDEN";
362})(VisibilityState || (VisibilityState = {}));
363var RESERVED_ATTRIBUTE_PREFIXES = ['firebase_', 'google_', 'ga_'];
364var ATTRIBUTE_FORMAT_REGEX = new RegExp('^[a-zA-Z]\\w*$');
365var MAX_ATTRIBUTE_NAME_LENGTH = 40;
366var MAX_ATTRIBUTE_VALUE_LENGTH = 100;
367function getServiceWorkerStatus() {
368 var navigator = Api.getInstance().navigator;
369 if (navigator === null || navigator === void 0 ? void 0 : navigator.serviceWorker) {
370 if (navigator.serviceWorker.controller) {
371 return 2 /* ServiceWorkerStatus.CONTROLLED */;
372 }
373 else {
374 return 3 /* ServiceWorkerStatus.UNCONTROLLED */;
375 }
376 }
377 else {
378 return 1 /* ServiceWorkerStatus.UNSUPPORTED */;
379 }
380}
381function getVisibilityState() {
382 var document = Api.getInstance().document;
383 var visibilityState = document.visibilityState;
384 switch (visibilityState) {
385 case 'visible':
386 return VisibilityState.VISIBLE;
387 case 'hidden':
388 return VisibilityState.HIDDEN;
389 default:
390 return VisibilityState.UNKNOWN;
391 }
392}
393function getEffectiveConnectionType() {
394 var navigator = Api.getInstance().navigator;
395 var navigatorConnection = navigator.connection;
396 var effectiveType = navigatorConnection && navigatorConnection.effectiveType;
397 switch (effectiveType) {
398 case 'slow-2g':
399 return 1 /* EffectiveConnectionType.CONNECTION_SLOW_2G */;
400 case '2g':
401 return 2 /* EffectiveConnectionType.CONNECTION_2G */;
402 case '3g':
403 return 3 /* EffectiveConnectionType.CONNECTION_3G */;
404 case '4g':
405 return 4 /* EffectiveConnectionType.CONNECTION_4G */;
406 default:
407 return 0 /* EffectiveConnectionType.UNKNOWN */;
408 }
409}
410function isValidCustomAttributeName(name) {
411 if (name.length === 0 || name.length > MAX_ATTRIBUTE_NAME_LENGTH) {
412 return false;
413 }
414 var matchesReservedPrefix = RESERVED_ATTRIBUTE_PREFIXES.some(function (prefix) {
415 return name.startsWith(prefix);
416 });
417 return !matchesReservedPrefix && !!name.match(ATTRIBUTE_FORMAT_REGEX);
418}
419function isValidCustomAttributeValue(value) {
420 return value.length !== 0 && value.length <= MAX_ATTRIBUTE_VALUE_LENGTH;
421}
422
423/**
424 * @license
425 * Copyright 2020 Google LLC
426 *
427 * Licensed under the Apache License, Version 2.0 (the "License");
428 * you may not use this file except in compliance with the License.
429 * You may obtain a copy of the License at
430 *
431 * http://www.apache.org/licenses/LICENSE-2.0
432 *
433 * Unless required by applicable law or agreed to in writing, software
434 * distributed under the License is distributed on an "AS IS" BASIS,
435 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
436 * See the License for the specific language governing permissions and
437 * limitations under the License.
438 */
439function getAppId(firebaseApp) {
440 var _a;
441 var appId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.appId;
442 if (!appId) {
443 throw ERROR_FACTORY.create("no app id" /* ErrorCode.NO_APP_ID */);
444 }
445 return appId;
446}
447function getProjectId(firebaseApp) {
448 var _a;
449 var projectId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.projectId;
450 if (!projectId) {
451 throw ERROR_FACTORY.create("no project id" /* ErrorCode.NO_PROJECT_ID */);
452 }
453 return projectId;
454}
455function getApiKey(firebaseApp) {
456 var _a;
457 var apiKey = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.apiKey;
458 if (!apiKey) {
459 throw ERROR_FACTORY.create("no api key" /* ErrorCode.NO_API_KEY */);
460 }
461 return apiKey;
462}
463
464/**
465 * @license
466 * Copyright 2020 Google LLC
467 *
468 * Licensed under the Apache License, Version 2.0 (the "License");
469 * you may not use this file except in compliance with the License.
470 * You may obtain a copy of the License at
471 *
472 * http://www.apache.org/licenses/LICENSE-2.0
473 *
474 * Unless required by applicable law or agreed to in writing, software
475 * distributed under the License is distributed on an "AS IS" BASIS,
476 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
477 * See the License for the specific language governing permissions and
478 * limitations under the License.
479 */
480var REMOTE_CONFIG_SDK_VERSION = '0.0.1';
481// These values will be used if the remote config object is successfully
482// retrieved, but the template does not have these fields.
483var DEFAULT_CONFIGS = {
484 loggingEnabled: true
485};
486var FIS_AUTH_PREFIX = 'FIREBASE_INSTALLATIONS_AUTH';
487function getConfig(performanceController, iid) {
488 var config = getStoredConfig();
489 if (config) {
490 processConfig(config);
491 return Promise.resolve();
492 }
493 return getRemoteConfig(performanceController, iid)
494 .then(processConfig)
495 .then(function (config) { return storeConfig(config); },
496 /** Do nothing for error, use defaults set in settings service. */
497 function () { });
498}
499function getStoredConfig() {
500 var localStorage = Api.getInstance().localStorage;
501 if (!localStorage) {
502 return;
503 }
504 var expiryString = localStorage.getItem(CONFIG_EXPIRY_LOCAL_STORAGE_KEY);
505 if (!expiryString || !configValid(expiryString)) {
506 return;
507 }
508 var configStringified = localStorage.getItem(CONFIG_LOCAL_STORAGE_KEY);
509 if (!configStringified) {
510 return;
511 }
512 try {
513 var configResponse = JSON.parse(configStringified);
514 return configResponse;
515 }
516 catch (_a) {
517 return;
518 }
519}
520function storeConfig(config) {
521 var localStorage = Api.getInstance().localStorage;
522 if (!config || !localStorage) {
523 return;
524 }
525 localStorage.setItem(CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config));
526 localStorage.setItem(CONFIG_EXPIRY_LOCAL_STORAGE_KEY, String(Date.now() +
527 SettingsService.getInstance().configTimeToLive * 60 * 60 * 1000));
528}
529var COULD_NOT_GET_CONFIG_MSG = 'Could not fetch config, will use default configs';
530function getRemoteConfig(performanceController, iid) {
531 // Perf needs auth token only to retrieve remote config.
532 return getAuthTokenPromise(performanceController.installations)
533 .then(function (authToken) {
534 var projectId = getProjectId(performanceController.app);
535 var apiKey = getApiKey(performanceController.app);
536 var configEndPoint = "https://firebaseremoteconfig.googleapis.com/v1/projects/".concat(projectId, "/namespaces/fireperf:fetch?key=").concat(apiKey);
537 var request = new Request(configEndPoint, {
538 method: 'POST',
539 headers: { Authorization: "".concat(FIS_AUTH_PREFIX, " ").concat(authToken) },
540 /* eslint-disable camelcase */
541 body: JSON.stringify({
542 app_instance_id: iid,
543 app_instance_id_token: authToken,
544 app_id: getAppId(performanceController.app),
545 app_version: SDK_VERSION,
546 sdk_version: REMOTE_CONFIG_SDK_VERSION
547 })
548 /* eslint-enable camelcase */
549 });
550 return fetch(request).then(function (response) {
551 if (response.ok) {
552 return response.json();
553 }
554 // In case response is not ok. This will be caught by catch.
555 throw ERROR_FACTORY.create("RC response not ok" /* ErrorCode.RC_NOT_OK */);
556 });
557 })
558 .catch(function () {
559 consoleLogger.info(COULD_NOT_GET_CONFIG_MSG);
560 return undefined;
561 });
562}
563/**
564 * Processes config coming either from calling RC or from local storage.
565 * This method only runs if call is successful or config in storage
566 * is valid.
567 */
568function processConfig(config) {
569 if (!config) {
570 return config;
571 }
572 var settingsServiceInstance = SettingsService.getInstance();
573 var entries = config.entries || {};
574 if (entries.fpr_enabled !== undefined) {
575 // TODO: Change the assignment of loggingEnabled once the received type is
576 // known.
577 settingsServiceInstance.loggingEnabled =
578 String(entries.fpr_enabled) === 'true';
579 }
580 else {
581 // Config retrieved successfully, but there is no fpr_enabled in template.
582 // Use secondary configs value.
583 settingsServiceInstance.loggingEnabled = DEFAULT_CONFIGS.loggingEnabled;
584 }
585 if (entries.fpr_log_source) {
586 settingsServiceInstance.logSource = Number(entries.fpr_log_source);
587 }
588 else if (DEFAULT_CONFIGS.logSource) {
589 settingsServiceInstance.logSource = DEFAULT_CONFIGS.logSource;
590 }
591 if (entries.fpr_log_endpoint_url) {
592 settingsServiceInstance.logEndPointUrl = entries.fpr_log_endpoint_url;
593 }
594 else if (DEFAULT_CONFIGS.logEndPointUrl) {
595 settingsServiceInstance.logEndPointUrl = DEFAULT_CONFIGS.logEndPointUrl;
596 }
597 // Key from Remote Config has to be non-empty string, otherwsie use local value.
598 if (entries.fpr_log_transport_key) {
599 settingsServiceInstance.transportKey = entries.fpr_log_transport_key;
600 }
601 else if (DEFAULT_CONFIGS.transportKey) {
602 settingsServiceInstance.transportKey = DEFAULT_CONFIGS.transportKey;
603 }
604 if (entries.fpr_vc_network_request_sampling_rate !== undefined) {
605 settingsServiceInstance.networkRequestsSamplingRate = Number(entries.fpr_vc_network_request_sampling_rate);
606 }
607 else if (DEFAULT_CONFIGS.networkRequestsSamplingRate !== undefined) {
608 settingsServiceInstance.networkRequestsSamplingRate =
609 DEFAULT_CONFIGS.networkRequestsSamplingRate;
610 }
611 if (entries.fpr_vc_trace_sampling_rate !== undefined) {
612 settingsServiceInstance.tracesSamplingRate = Number(entries.fpr_vc_trace_sampling_rate);
613 }
614 else if (DEFAULT_CONFIGS.tracesSamplingRate !== undefined) {
615 settingsServiceInstance.tracesSamplingRate =
616 DEFAULT_CONFIGS.tracesSamplingRate;
617 }
618 // Set the per session trace and network logging flags.
619 settingsServiceInstance.logTraceAfterSampling = shouldLogAfterSampling(settingsServiceInstance.tracesSamplingRate);
620 settingsServiceInstance.logNetworkAfterSampling = shouldLogAfterSampling(settingsServiceInstance.networkRequestsSamplingRate);
621 return config;
622}
623function configValid(expiry) {
624 return Number(expiry) > Date.now();
625}
626function shouldLogAfterSampling(samplingRate) {
627 return Math.random() <= samplingRate;
628}
629
630/**
631 * @license
632 * Copyright 2020 Google LLC
633 *
634 * Licensed under the Apache License, Version 2.0 (the "License");
635 * you may not use this file except in compliance with the License.
636 * You may obtain a copy of the License at
637 *
638 * http://www.apache.org/licenses/LICENSE-2.0
639 *
640 * Unless required by applicable law or agreed to in writing, software
641 * distributed under the License is distributed on an "AS IS" BASIS,
642 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
643 * See the License for the specific language governing permissions and
644 * limitations under the License.
645 */
646var initializationStatus = 1 /* InitializationStatus.notInitialized */;
647var initializationPromise;
648function getInitializationPromise(performanceController) {
649 initializationStatus = 2 /* InitializationStatus.initializationPending */;
650 initializationPromise =
651 initializationPromise || initializePerf(performanceController);
652 return initializationPromise;
653}
654function isPerfInitialized() {
655 return initializationStatus === 3 /* InitializationStatus.initialized */;
656}
657function initializePerf(performanceController) {
658 return getDocumentReadyComplete()
659 .then(function () { return getIidPromise(performanceController.installations); })
660 .then(function (iid) { return getConfig(performanceController, iid); })
661 .then(function () { return changeInitializationStatus(); }, function () { return changeInitializationStatus(); });
662}
663/**
664 * Returns a promise which resolves whenever the document readystate is complete or
665 * immediately if it is called after page load complete.
666 */
667function getDocumentReadyComplete() {
668 var document = Api.getInstance().document;
669 return new Promise(function (resolve) {
670 if (document && document.readyState !== 'complete') {
671 var handler_1 = function () {
672 if (document.readyState === 'complete') {
673 document.removeEventListener('readystatechange', handler_1);
674 resolve();
675 }
676 };
677 document.addEventListener('readystatechange', handler_1);
678 }
679 else {
680 resolve();
681 }
682 });
683}
684function changeInitializationStatus() {
685 initializationStatus = 3 /* InitializationStatus.initialized */;
686}
687
688/**
689 * @license
690 * Copyright 2020 Google LLC
691 *
692 * Licensed under the Apache License, Version 2.0 (the "License");
693 * you may not use this file except in compliance with the License.
694 * You may obtain a copy of the License at
695 *
696 * http://www.apache.org/licenses/LICENSE-2.0
697 *
698 * Unless required by applicable law or agreed to in writing, software
699 * distributed under the License is distributed on an "AS IS" BASIS,
700 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
701 * See the License for the specific language governing permissions and
702 * limitations under the License.
703 */
704var DEFAULT_SEND_INTERVAL_MS = 10 * 1000;
705var INITIAL_SEND_TIME_DELAY_MS = 5.5 * 1000;
706// If end point does not work, the call will be tried for these many times.
707var DEFAULT_REMAINING_TRIES = 3;
708var MAX_EVENT_COUNT_PER_REQUEST = 1000;
709var remainingTries = DEFAULT_REMAINING_TRIES;
710/* eslint-enable camelcase */
711var queue = [];
712var isTransportSetup = false;
713function setupTransportService() {
714 if (!isTransportSetup) {
715 processQueue(INITIAL_SEND_TIME_DELAY_MS);
716 isTransportSetup = true;
717 }
718}
719function processQueue(timeOffset) {
720 setTimeout(function () {
721 // If there is no remainingTries left, stop retrying.
722 if (remainingTries === 0) {
723 return;
724 }
725 // If there are no events to process, wait for DEFAULT_SEND_INTERVAL_MS and try again.
726 if (!queue.length) {
727 return processQueue(DEFAULT_SEND_INTERVAL_MS);
728 }
729 dispatchQueueEvents();
730 }, timeOffset);
731}
732function dispatchQueueEvents() {
733 // Extract events up to the maximum cap of single logRequest from top of "official queue".
734 // The staged events will be used for current logRequest attempt, remaining events will be kept
735 // for next attempt.
736 var staged = queue.splice(0, MAX_EVENT_COUNT_PER_REQUEST);
737 /* eslint-disable camelcase */
738 // We will pass the JSON serialized event to the backend.
739 var log_event = staged.map(function (evt) { return ({
740 source_extension_json_proto3: evt.message,
741 event_time_ms: String(evt.eventTime)
742 }); });
743 var data = {
744 request_time_ms: String(Date.now()),
745 client_info: {
746 client_type: 1,
747 js_client_info: {}
748 },
749 log_source: SettingsService.getInstance().logSource,
750 log_event: log_event
751 };
752 /* eslint-enable camelcase */
753 sendEventsToFl(data, staged).catch(function () {
754 // If the request fails for some reason, add the events that were attempted
755 // back to the primary queue to retry later.
756 queue = tslib.__spreadArray(tslib.__spreadArray([], staged, true), queue, true);
757 remainingTries--;
758 consoleLogger.info("Tries left: ".concat(remainingTries, "."));
759 processQueue(DEFAULT_SEND_INTERVAL_MS);
760 });
761}
762function sendEventsToFl(data, staged) {
763 return postToFlEndpoint(data)
764 .then(function (res) {
765 if (!res.ok) {
766 consoleLogger.info('Call to Firebase backend failed.');
767 }
768 return res.json();
769 })
770 .then(function (res) {
771 // Find the next call wait time from the response.
772 var transportWait = Number(res.nextRequestWaitMillis);
773 var requestOffset = DEFAULT_SEND_INTERVAL_MS;
774 if (!isNaN(transportWait)) {
775 requestOffset = Math.max(transportWait, requestOffset);
776 }
777 // Delete request if response include RESPONSE_ACTION_UNKNOWN or DELETE_REQUEST action.
778 // Otherwise, retry request using normal scheduling if response include RETRY_REQUEST_LATER.
779 var logResponseDetails = res.logResponseDetails;
780 if (Array.isArray(logResponseDetails) &&
781 logResponseDetails.length > 0 &&
782 logResponseDetails[0].responseAction === 'RETRY_REQUEST_LATER') {
783 queue = tslib.__spreadArray(tslib.__spreadArray([], staged, true), queue, true);
784 consoleLogger.info("Retry transport request later.");
785 }
786 remainingTries = DEFAULT_REMAINING_TRIES;
787 // Schedule the next process.
788 processQueue(requestOffset);
789 });
790}
791function postToFlEndpoint(data) {
792 var flTransportFullUrl = SettingsService.getInstance().getFlTransportFullUrl();
793 return fetch(flTransportFullUrl, {
794 method: 'POST',
795 body: JSON.stringify(data)
796 });
797}
798function addToQueue(evt) {
799 if (!evt.eventTime || !evt.message) {
800 throw ERROR_FACTORY.create("invalid cc log" /* ErrorCode.INVALID_CC_LOG */);
801 }
802 // Add the new event to the queue.
803 queue = tslib.__spreadArray(tslib.__spreadArray([], queue, true), [evt], false);
804}
805/** Log handler for cc service to send the performance logs to the server. */
806function transportHandler(
807// eslint-disable-next-line @typescript-eslint/no-explicit-any
808serializer) {
809 return function () {
810 var args = [];
811 for (var _i = 0; _i < arguments.length; _i++) {
812 args[_i] = arguments[_i];
813 }
814 var message = serializer.apply(void 0, args);
815 addToQueue({
816 message: message,
817 eventTime: Date.now()
818 });
819 };
820}
821
822/**
823 * @license
824 * Copyright 2020 Google LLC
825 *
826 * Licensed under the Apache License, Version 2.0 (the "License");
827 * you may not use this file except in compliance with the License.
828 * You may obtain a copy of the License at
829 *
830 * http://www.apache.org/licenses/LICENSE-2.0
831 *
832 * Unless required by applicable law or agreed to in writing, software
833 * distributed under the License is distributed on an "AS IS" BASIS,
834 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
835 * See the License for the specific language governing permissions and
836 * limitations under the License.
837 */
838/* eslint-enble camelcase */
839var logger;
840// This method is not called before initialization.
841function sendLog(resource, resourceType) {
842 if (!logger) {
843 logger = transportHandler(serializer);
844 }
845 logger(resource, resourceType);
846}
847function logTrace(trace) {
848 var settingsService = SettingsService.getInstance();
849 // Do not log if trace is auto generated and instrumentation is disabled.
850 if (!settingsService.instrumentationEnabled && trace.isAuto) {
851 return;
852 }
853 // Do not log if trace is custom and data collection is disabled.
854 if (!settingsService.dataCollectionEnabled && !trace.isAuto) {
855 return;
856 }
857 // Do not log if required apis are not available.
858 if (!Api.getInstance().requiredApisAvailable()) {
859 return;
860 }
861 // Only log the page load auto traces if page is visible.
862 if (trace.isAuto && getVisibilityState() !== VisibilityState.VISIBLE) {
863 return;
864 }
865 if (isPerfInitialized()) {
866 sendTraceLog(trace);
867 }
868 else {
869 // Custom traces can be used before the initialization but logging
870 // should wait until after.
871 getInitializationPromise(trace.performanceController).then(function () { return sendTraceLog(trace); }, function () { return sendTraceLog(trace); });
872 }
873}
874function sendTraceLog(trace) {
875 if (!getIid()) {
876 return;
877 }
878 var settingsService = SettingsService.getInstance();
879 if (!settingsService.loggingEnabled ||
880 !settingsService.logTraceAfterSampling) {
881 return;
882 }
883 setTimeout(function () { return sendLog(trace, 1 /* ResourceType.Trace */); }, 0);
884}
885function logNetworkRequest(networkRequest) {
886 var settingsService = SettingsService.getInstance();
887 // Do not log network requests if instrumentation is disabled.
888 if (!settingsService.instrumentationEnabled) {
889 return;
890 }
891 // Do not log the js sdk's call to transport service domain to avoid unnecessary cycle.
892 // Need to blacklist both old and new endpoints to avoid migration gap.
893 var networkRequestUrl = networkRequest.url;
894 // Blacklist old log endpoint and new transport endpoint.
895 // Because Performance SDK doesn't instrument requests sent from SDK itself.
896 var logEndpointUrl = settingsService.logEndPointUrl.split('?')[0];
897 var flEndpointUrl = settingsService.flTransportEndpointUrl.split('?')[0];
898 if (networkRequestUrl === logEndpointUrl ||
899 networkRequestUrl === flEndpointUrl) {
900 return;
901 }
902 if (!settingsService.loggingEnabled ||
903 !settingsService.logNetworkAfterSampling) {
904 return;
905 }
906 setTimeout(function () { return sendLog(networkRequest, 0 /* ResourceType.NetworkRequest */); }, 0);
907}
908function serializer(resource, resourceType) {
909 if (resourceType === 0 /* ResourceType.NetworkRequest */) {
910 return serializeNetworkRequest(resource);
911 }
912 return serializeTrace(resource);
913}
914function serializeNetworkRequest(networkRequest) {
915 var networkRequestMetric = {
916 url: networkRequest.url,
917 http_method: networkRequest.httpMethod || 0,
918 http_response_code: 200,
919 response_payload_bytes: networkRequest.responsePayloadBytes,
920 client_start_time_us: networkRequest.startTimeUs,
921 time_to_response_initiated_us: networkRequest.timeToResponseInitiatedUs,
922 time_to_response_completed_us: networkRequest.timeToResponseCompletedUs
923 };
924 var perfMetric = {
925 application_info: getApplicationInfo(networkRequest.performanceController.app),
926 network_request_metric: networkRequestMetric
927 };
928 return JSON.stringify(perfMetric);
929}
930function serializeTrace(trace) {
931 var traceMetric = {
932 name: trace.name,
933 is_auto: trace.isAuto,
934 client_start_time_us: trace.startTimeUs,
935 duration_us: trace.durationUs
936 };
937 if (Object.keys(trace.counters).length !== 0) {
938 traceMetric.counters = trace.counters;
939 }
940 var customAttributes = trace.getAttributes();
941 if (Object.keys(customAttributes).length !== 0) {
942 traceMetric.custom_attributes = customAttributes;
943 }
944 var perfMetric = {
945 application_info: getApplicationInfo(trace.performanceController.app),
946 trace_metric: traceMetric
947 };
948 return JSON.stringify(perfMetric);
949}
950function getApplicationInfo(firebaseApp) {
951 return {
952 google_app_id: getAppId(firebaseApp),
953 app_instance_id: getIid(),
954 web_app_info: {
955 sdk_version: SDK_VERSION,
956 page_url: Api.getInstance().getUrl(),
957 service_worker_status: getServiceWorkerStatus(),
958 visibility_state: getVisibilityState(),
959 effective_connection_type: getEffectiveConnectionType()
960 },
961 application_process_state: 0
962 };
963}
964
965/**
966 * @license
967 * Copyright 2020 Google LLC
968 *
969 * Licensed under the Apache License, Version 2.0 (the "License");
970 * you may not use this file except in compliance with the License.
971 * You may obtain a copy of the License at
972 *
973 * http://www.apache.org/licenses/LICENSE-2.0
974 *
975 * Unless required by applicable law or agreed to in writing, software
976 * distributed under the License is distributed on an "AS IS" BASIS,
977 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
978 * See the License for the specific language governing permissions and
979 * limitations under the License.
980 */
981var MAX_METRIC_NAME_LENGTH = 100;
982var RESERVED_AUTO_PREFIX = '_';
983var oobMetrics = [
984 FIRST_PAINT_COUNTER_NAME,
985 FIRST_CONTENTFUL_PAINT_COUNTER_NAME,
986 FIRST_INPUT_DELAY_COUNTER_NAME
987];
988/**
989 * Returns true if the metric is custom and does not start with reserved prefix, or if
990 * the metric is one of out of the box page load trace metrics.
991 */
992function isValidMetricName(name, traceName) {
993 if (name.length === 0 || name.length > MAX_METRIC_NAME_LENGTH) {
994 return false;
995 }
996 return ((traceName &&
997 traceName.startsWith(OOB_TRACE_PAGE_LOAD_PREFIX) &&
998 oobMetrics.indexOf(name) > -1) ||
999 !name.startsWith(RESERVED_AUTO_PREFIX));
1000}
1001/**
1002 * Converts the provided value to an integer value to be used in case of a metric.
1003 * @param providedValue Provided number value of the metric that needs to be converted to an integer.
1004 *
1005 * @returns Converted integer number to be set for the metric.
1006 */
1007function convertMetricValueToInteger(providedValue) {
1008 var valueAsInteger = Math.floor(providedValue);
1009 if (valueAsInteger < providedValue) {
1010 consoleLogger.info("Metric value should be an Integer, setting the value as : ".concat(valueAsInteger, "."));
1011 }
1012 return valueAsInteger;
1013}
1014
1015/**
1016 * @license
1017 * Copyright 2020 Google LLC
1018 *
1019 * Licensed under the Apache License, Version 2.0 (the "License");
1020 * you may not use this file except in compliance with the License.
1021 * You may obtain a copy of the License at
1022 *
1023 * http://www.apache.org/licenses/LICENSE-2.0
1024 *
1025 * Unless required by applicable law or agreed to in writing, software
1026 * distributed under the License is distributed on an "AS IS" BASIS,
1027 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1028 * See the License for the specific language governing permissions and
1029 * limitations under the License.
1030 */
1031var Trace = /** @class */ (function () {
1032 /**
1033 * @param performanceController The performance controller running.
1034 * @param name The name of the trace.
1035 * @param isAuto If the trace is auto-instrumented.
1036 * @param traceMeasureName The name of the measure marker in user timing specification. This field
1037 * is only set when the trace is built for logging when the user directly uses the user timing
1038 * api (performance.mark and performance.measure).
1039 */
1040 function Trace(performanceController, name, isAuto, traceMeasureName) {
1041 if (isAuto === void 0) { isAuto = false; }
1042 this.performanceController = performanceController;
1043 this.name = name;
1044 this.isAuto = isAuto;
1045 this.state = 1 /* TraceState.UNINITIALIZED */;
1046 this.customAttributes = {};
1047 this.counters = {};
1048 this.api = Api.getInstance();
1049 this.randomId = Math.floor(Math.random() * 1000000);
1050 if (!this.isAuto) {
1051 this.traceStartMark = "".concat(TRACE_START_MARK_PREFIX, "-").concat(this.randomId, "-").concat(this.name);
1052 this.traceStopMark = "".concat(TRACE_STOP_MARK_PREFIX, "-").concat(this.randomId, "-").concat(this.name);
1053 this.traceMeasure =
1054 traceMeasureName ||
1055 "".concat(TRACE_MEASURE_PREFIX, "-").concat(this.randomId, "-").concat(this.name);
1056 if (traceMeasureName) {
1057 // For the case of direct user timing traces, no start stop will happen. The measure object
1058 // is already available.
1059 this.calculateTraceMetrics();
1060 }
1061 }
1062 }
1063 /**
1064 * Starts a trace. The measurement of the duration starts at this point.
1065 */
1066 Trace.prototype.start = function () {
1067 if (this.state !== 1 /* TraceState.UNINITIALIZED */) {
1068 throw ERROR_FACTORY.create("trace started" /* ErrorCode.TRACE_STARTED_BEFORE */, {
1069 traceName: this.name
1070 });
1071 }
1072 this.api.mark(this.traceStartMark);
1073 this.state = 2 /* TraceState.RUNNING */;
1074 };
1075 /**
1076 * Stops the trace. The measurement of the duration of the trace stops at this point and trace
1077 * is logged.
1078 */
1079 Trace.prototype.stop = function () {
1080 if (this.state !== 2 /* TraceState.RUNNING */) {
1081 throw ERROR_FACTORY.create("trace stopped" /* ErrorCode.TRACE_STOPPED_BEFORE */, {
1082 traceName: this.name
1083 });
1084 }
1085 this.state = 3 /* TraceState.TERMINATED */;
1086 this.api.mark(this.traceStopMark);
1087 this.api.measure(this.traceMeasure, this.traceStartMark, this.traceStopMark);
1088 this.calculateTraceMetrics();
1089 logTrace(this);
1090 };
1091 /**
1092 * Records a trace with predetermined values. If this method is used a trace is created and logged
1093 * directly. No need to use start and stop methods.
1094 * @param startTime Trace start time since epoch in millisec
1095 * @param duration The duraction of the trace in millisec
1096 * @param options An object which can optionally hold maps of custom metrics and custom attributes
1097 */
1098 Trace.prototype.record = function (startTime, duration, options) {
1099 if (startTime <= 0) {
1100 throw ERROR_FACTORY.create("nonpositive trace startTime" /* ErrorCode.NONPOSITIVE_TRACE_START_TIME */, {
1101 traceName: this.name
1102 });
1103 }
1104 if (duration <= 0) {
1105 throw ERROR_FACTORY.create("nonpositive trace duration" /* ErrorCode.NONPOSITIVE_TRACE_DURATION */, {
1106 traceName: this.name
1107 });
1108 }
1109 this.durationUs = Math.floor(duration * 1000);
1110 this.startTimeUs = Math.floor(startTime * 1000);
1111 if (options && options.attributes) {
1112 this.customAttributes = tslib.__assign({}, options.attributes);
1113 }
1114 if (options && options.metrics) {
1115 for (var _i = 0, _a = Object.keys(options.metrics); _i < _a.length; _i++) {
1116 var metricName = _a[_i];
1117 if (!isNaN(Number(options.metrics[metricName]))) {
1118 this.counters[metricName] = Math.floor(Number(options.metrics[metricName]));
1119 }
1120 }
1121 }
1122 logTrace(this);
1123 };
1124 /**
1125 * Increments a custom metric by a certain number or 1 if number not specified. Will create a new
1126 * custom metric if one with the given name does not exist. The value will be floored down to an
1127 * integer.
1128 * @param counter Name of the custom metric
1129 * @param numAsInteger Increment by value
1130 */
1131 Trace.prototype.incrementMetric = function (counter, numAsInteger) {
1132 if (numAsInteger === void 0) { numAsInteger = 1; }
1133 if (this.counters[counter] === undefined) {
1134 this.putMetric(counter, numAsInteger);
1135 }
1136 else {
1137 this.putMetric(counter, this.counters[counter] + numAsInteger);
1138 }
1139 };
1140 /**
1141 * Sets a custom metric to a specified value. Will create a new custom metric if one with the
1142 * given name does not exist. The value will be floored down to an integer.
1143 * @param counter Name of the custom metric
1144 * @param numAsInteger Set custom metric to this value
1145 */
1146 Trace.prototype.putMetric = function (counter, numAsInteger) {
1147 if (isValidMetricName(counter, this.name)) {
1148 this.counters[counter] = convertMetricValueToInteger(numAsInteger !== null && numAsInteger !== void 0 ? numAsInteger : 0);
1149 }
1150 else {
1151 throw ERROR_FACTORY.create("invalid custom metric name" /* ErrorCode.INVALID_CUSTOM_METRIC_NAME */, {
1152 customMetricName: counter
1153 });
1154 }
1155 };
1156 /**
1157 * Returns the value of the custom metric by that name. If a custom metric with that name does
1158 * not exist will return zero.
1159 * @param counter
1160 */
1161 Trace.prototype.getMetric = function (counter) {
1162 return this.counters[counter] || 0;
1163 };
1164 /**
1165 * Sets a custom attribute of a trace to a certain value.
1166 * @param attr
1167 * @param value
1168 */
1169 Trace.prototype.putAttribute = function (attr, value) {
1170 var isValidName = isValidCustomAttributeName(attr);
1171 var isValidValue = isValidCustomAttributeValue(value);
1172 if (isValidName && isValidValue) {
1173 this.customAttributes[attr] = value;
1174 return;
1175 }
1176 // Throw appropriate error when the attribute name or value is invalid.
1177 if (!isValidName) {
1178 throw ERROR_FACTORY.create("invalid attribute name" /* ErrorCode.INVALID_ATTRIBUTE_NAME */, {
1179 attributeName: attr
1180 });
1181 }
1182 if (!isValidValue) {
1183 throw ERROR_FACTORY.create("invalid attribute value" /* ErrorCode.INVALID_ATTRIBUTE_VALUE */, {
1184 attributeValue: value
1185 });
1186 }
1187 };
1188 /**
1189 * Retrieves the value a custom attribute of a trace is set to.
1190 * @param attr
1191 */
1192 Trace.prototype.getAttribute = function (attr) {
1193 return this.customAttributes[attr];
1194 };
1195 Trace.prototype.removeAttribute = function (attr) {
1196 if (this.customAttributes[attr] === undefined) {
1197 return;
1198 }
1199 delete this.customAttributes[attr];
1200 };
1201 Trace.prototype.getAttributes = function () {
1202 return tslib.__assign({}, this.customAttributes);
1203 };
1204 Trace.prototype.setStartTime = function (startTime) {
1205 this.startTimeUs = startTime;
1206 };
1207 Trace.prototype.setDuration = function (duration) {
1208 this.durationUs = duration;
1209 };
1210 /**
1211 * Calculates and assigns the duration and start time of the trace using the measure performance
1212 * entry.
1213 */
1214 Trace.prototype.calculateTraceMetrics = function () {
1215 var perfMeasureEntries = this.api.getEntriesByName(this.traceMeasure);
1216 var perfMeasureEntry = perfMeasureEntries && perfMeasureEntries[0];
1217 if (perfMeasureEntry) {
1218 this.durationUs = Math.floor(perfMeasureEntry.duration * 1000);
1219 this.startTimeUs = Math.floor((perfMeasureEntry.startTime + this.api.getTimeOrigin()) * 1000);
1220 }
1221 };
1222 /**
1223 * @param navigationTimings A single element array which contains the navigationTIming object of
1224 * the page load
1225 * @param paintTimings A array which contains paintTiming object of the page load
1226 * @param firstInputDelay First input delay in millisec
1227 */
1228 Trace.createOobTrace = function (performanceController, navigationTimings, paintTimings, firstInputDelay) {
1229 var route = Api.getInstance().getUrl();
1230 if (!route) {
1231 return;
1232 }
1233 var trace = new Trace(performanceController, OOB_TRACE_PAGE_LOAD_PREFIX + route, true);
1234 var timeOriginUs = Math.floor(Api.getInstance().getTimeOrigin() * 1000);
1235 trace.setStartTime(timeOriginUs);
1236 // navigationTimings includes only one element.
1237 if (navigationTimings && navigationTimings[0]) {
1238 trace.setDuration(Math.floor(navigationTimings[0].duration * 1000));
1239 trace.putMetric('domInteractive', Math.floor(navigationTimings[0].domInteractive * 1000));
1240 trace.putMetric('domContentLoadedEventEnd', Math.floor(navigationTimings[0].domContentLoadedEventEnd * 1000));
1241 trace.putMetric('loadEventEnd', Math.floor(navigationTimings[0].loadEventEnd * 1000));
1242 }
1243 var FIRST_PAINT = 'first-paint';
1244 var FIRST_CONTENTFUL_PAINT = 'first-contentful-paint';
1245 if (paintTimings) {
1246 var firstPaint = paintTimings.find(function (paintObject) { return paintObject.name === FIRST_PAINT; });
1247 if (firstPaint && firstPaint.startTime) {
1248 trace.putMetric(FIRST_PAINT_COUNTER_NAME, Math.floor(firstPaint.startTime * 1000));
1249 }
1250 var firstContentfulPaint = paintTimings.find(function (paintObject) { return paintObject.name === FIRST_CONTENTFUL_PAINT; });
1251 if (firstContentfulPaint && firstContentfulPaint.startTime) {
1252 trace.putMetric(FIRST_CONTENTFUL_PAINT_COUNTER_NAME, Math.floor(firstContentfulPaint.startTime * 1000));
1253 }
1254 if (firstInputDelay) {
1255 trace.putMetric(FIRST_INPUT_DELAY_COUNTER_NAME, Math.floor(firstInputDelay * 1000));
1256 }
1257 }
1258 logTrace(trace);
1259 };
1260 Trace.createUserTimingTrace = function (performanceController, measureName) {
1261 var trace = new Trace(performanceController, measureName, false, measureName);
1262 logTrace(trace);
1263 };
1264 return Trace;
1265}());
1266
1267/**
1268 * @license
1269 * Copyright 2020 Google LLC
1270 *
1271 * Licensed under the Apache License, Version 2.0 (the "License");
1272 * you may not use this file except in compliance with the License.
1273 * You may obtain a copy of the License at
1274 *
1275 * http://www.apache.org/licenses/LICENSE-2.0
1276 *
1277 * Unless required by applicable law or agreed to in writing, software
1278 * distributed under the License is distributed on an "AS IS" BASIS,
1279 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1280 * See the License for the specific language governing permissions and
1281 * limitations under the License.
1282 */
1283function createNetworkRequestEntry(performanceController, entry) {
1284 var performanceEntry = entry;
1285 if (!performanceEntry || performanceEntry.responseStart === undefined) {
1286 return;
1287 }
1288 var timeOrigin = Api.getInstance().getTimeOrigin();
1289 var startTimeUs = Math.floor((performanceEntry.startTime + timeOrigin) * 1000);
1290 var timeToResponseInitiatedUs = performanceEntry.responseStart
1291 ? Math.floor((performanceEntry.responseStart - performanceEntry.startTime) * 1000)
1292 : undefined;
1293 var timeToResponseCompletedUs = Math.floor((performanceEntry.responseEnd - performanceEntry.startTime) * 1000);
1294 // Remove the query params from logged network request url.
1295 var url = performanceEntry.name && performanceEntry.name.split('?')[0];
1296 var networkRequest = {
1297 performanceController: performanceController,
1298 url: url,
1299 responsePayloadBytes: performanceEntry.transferSize,
1300 startTimeUs: startTimeUs,
1301 timeToResponseInitiatedUs: timeToResponseInitiatedUs,
1302 timeToResponseCompletedUs: timeToResponseCompletedUs
1303 };
1304 logNetworkRequest(networkRequest);
1305}
1306
1307/**
1308 * @license
1309 * Copyright 2020 Google LLC
1310 *
1311 * Licensed under the Apache License, Version 2.0 (the "License");
1312 * you may not use this file except in compliance with the License.
1313 * You may obtain a copy of the License at
1314 *
1315 * http://www.apache.org/licenses/LICENSE-2.0
1316 *
1317 * Unless required by applicable law or agreed to in writing, software
1318 * distributed under the License is distributed on an "AS IS" BASIS,
1319 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320 * See the License for the specific language governing permissions and
1321 * limitations under the License.
1322 */
1323var FID_WAIT_TIME_MS = 5000;
1324function setupOobResources(performanceController) {
1325 // Do not initialize unless iid is available.
1326 if (!getIid()) {
1327 return;
1328 }
1329 // The load event might not have fired yet, and that means performance navigation timing
1330 // object has a duration of 0. The setup should run after all current tasks in js queue.
1331 setTimeout(function () { return setupOobTraces(performanceController); }, 0);
1332 setTimeout(function () { return setupNetworkRequests(performanceController); }, 0);
1333 setTimeout(function () { return setupUserTimingTraces(performanceController); }, 0);
1334}
1335function setupNetworkRequests(performanceController) {
1336 var api = Api.getInstance();
1337 var resources = api.getEntriesByType('resource');
1338 for (var _i = 0, resources_1 = resources; _i < resources_1.length; _i++) {
1339 var resource = resources_1[_i];
1340 createNetworkRequestEntry(performanceController, resource);
1341 }
1342 api.setupObserver('resource', function (entry) {
1343 return createNetworkRequestEntry(performanceController, entry);
1344 });
1345}
1346function setupOobTraces(performanceController) {
1347 var api = Api.getInstance();
1348 var navigationTimings = api.getEntriesByType('navigation');
1349 var paintTimings = api.getEntriesByType('paint');
1350 // If First Input Desly polyfill is added to the page, report the fid value.
1351 // https://github.com/GoogleChromeLabs/first-input-delay
1352 if (api.onFirstInputDelay) {
1353 // If the fid call back is not called for certain time, continue without it.
1354 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1355 var timeoutId_1 = setTimeout(function () {
1356 Trace.createOobTrace(performanceController, navigationTimings, paintTimings);
1357 timeoutId_1 = undefined;
1358 }, FID_WAIT_TIME_MS);
1359 api.onFirstInputDelay(function (fid) {
1360 if (timeoutId_1) {
1361 clearTimeout(timeoutId_1);
1362 Trace.createOobTrace(performanceController, navigationTimings, paintTimings, fid);
1363 }
1364 });
1365 }
1366 else {
1367 Trace.createOobTrace(performanceController, navigationTimings, paintTimings);
1368 }
1369}
1370function setupUserTimingTraces(performanceController) {
1371 var api = Api.getInstance();
1372 // Run through the measure performance entries collected up to this point.
1373 var measures = api.getEntriesByType('measure');
1374 for (var _i = 0, measures_1 = measures; _i < measures_1.length; _i++) {
1375 var measure = measures_1[_i];
1376 createUserTimingTrace(performanceController, measure);
1377 }
1378 // Setup an observer to capture the measures from this point on.
1379 api.setupObserver('measure', function (entry) {
1380 return createUserTimingTrace(performanceController, entry);
1381 });
1382}
1383function createUserTimingTrace(performanceController, measure) {
1384 var measureName = measure.name;
1385 // Do not create a trace, if the user timing marks and measures are created by the sdk itself.
1386 if (measureName.substring(0, TRACE_MEASURE_PREFIX.length) ===
1387 TRACE_MEASURE_PREFIX) {
1388 return;
1389 }
1390 Trace.createUserTimingTrace(performanceController, measureName);
1391}
1392
1393/**
1394 * @license
1395 * Copyright 2020 Google LLC
1396 *
1397 * Licensed under the Apache License, Version 2.0 (the "License");
1398 * you may not use this file except in compliance with the License.
1399 * You may obtain a copy of the License at
1400 *
1401 * http://www.apache.org/licenses/LICENSE-2.0
1402 *
1403 * Unless required by applicable law or agreed to in writing, software
1404 * distributed under the License is distributed on an "AS IS" BASIS,
1405 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1406 * See the License for the specific language governing permissions and
1407 * limitations under the License.
1408 */
1409var PerformanceController = /** @class */ (function () {
1410 function PerformanceController(app, installations) {
1411 this.app = app;
1412 this.installations = installations;
1413 this.initialized = false;
1414 }
1415 /**
1416 * This method *must* be called internally as part of creating a
1417 * PerformanceController instance.
1418 *
1419 * Currently it's not possible to pass the settings object through the
1420 * constructor using Components, so this method exists to be called with the
1421 * desired settings, to ensure nothing is collected without the user's
1422 * consent.
1423 */
1424 PerformanceController.prototype._init = function (settings) {
1425 var _this = this;
1426 if (this.initialized) {
1427 return;
1428 }
1429 if ((settings === null || settings === void 0 ? void 0 : settings.dataCollectionEnabled) !== undefined) {
1430 this.dataCollectionEnabled = settings.dataCollectionEnabled;
1431 }
1432 if ((settings === null || settings === void 0 ? void 0 : settings.instrumentationEnabled) !== undefined) {
1433 this.instrumentationEnabled = settings.instrumentationEnabled;
1434 }
1435 if (Api.getInstance().requiredApisAvailable()) {
1436 util.validateIndexedDBOpenable()
1437 .then(function (isAvailable) {
1438 if (isAvailable) {
1439 setupTransportService();
1440 getInitializationPromise(_this).then(function () { return setupOobResources(_this); }, function () { return setupOobResources(_this); });
1441 _this.initialized = true;
1442 }
1443 })
1444 .catch(function (error) {
1445 consoleLogger.info("Environment doesn't support IndexedDB: ".concat(error));
1446 });
1447 }
1448 else {
1449 consoleLogger.info('Firebase Performance cannot start if the browser does not support ' +
1450 '"Fetch" and "Promise", or cookies are disabled.');
1451 }
1452 };
1453 Object.defineProperty(PerformanceController.prototype, "instrumentationEnabled", {
1454 get: function () {
1455 return SettingsService.getInstance().instrumentationEnabled;
1456 },
1457 set: function (val) {
1458 SettingsService.getInstance().instrumentationEnabled = val;
1459 },
1460 enumerable: false,
1461 configurable: true
1462 });
1463 Object.defineProperty(PerformanceController.prototype, "dataCollectionEnabled", {
1464 get: function () {
1465 return SettingsService.getInstance().dataCollectionEnabled;
1466 },
1467 set: function (val) {
1468 SettingsService.getInstance().dataCollectionEnabled = val;
1469 },
1470 enumerable: false,
1471 configurable: true
1472 });
1473 return PerformanceController;
1474}());
1475
1476/**
1477 * The Firebase Performance Monitoring Web SDK.
1478 * This SDK does not work in a Node.js environment.
1479 *
1480 * @packageDocumentation
1481 */
1482var DEFAULT_ENTRY_NAME = '[DEFAULT]';
1483/**
1484 * Returns a {@link FirebasePerformance} instance for the given app.
1485 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1486 * @public
1487 */
1488function getPerformance(app$1) {
1489 if (app$1 === void 0) { app$1 = app.getApp(); }
1490 app$1 = util.getModularInstance(app$1);
1491 var provider = app._getProvider(app$1, 'performance');
1492 var perfInstance = provider.getImmediate();
1493 return perfInstance;
1494}
1495/**
1496 * Returns a {@link FirebasePerformance} instance for the given app. Can only be called once.
1497 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1498 * @param settings - Optional settings for the {@link FirebasePerformance} instance.
1499 * @public
1500 */
1501function initializePerformance(app$1, settings) {
1502 app$1 = util.getModularInstance(app$1);
1503 var provider = app._getProvider(app$1, 'performance');
1504 // throw if an instance was already created.
1505 // It could happen if initializePerformance() is called more than once, or getPerformance() is called first.
1506 if (provider.isInitialized()) {
1507 var existingInstance = provider.getImmediate();
1508 var initialSettings = provider.getOptions();
1509 if (util.deepEqual(initialSettings, settings !== null && settings !== void 0 ? settings : {})) {
1510 return existingInstance;
1511 }
1512 else {
1513 throw ERROR_FACTORY.create("already initialized" /* ErrorCode.ALREADY_INITIALIZED */);
1514 }
1515 }
1516 var perfInstance = provider.initialize({
1517 options: settings
1518 });
1519 return perfInstance;
1520}
1521/**
1522 * Returns a new `PerformanceTrace` instance.
1523 * @param performance - The {@link FirebasePerformance} instance to use.
1524 * @param name - The name of the trace.
1525 * @public
1526 */
1527function trace(performance, name) {
1528 performance = util.getModularInstance(performance);
1529 return new Trace(performance, name);
1530}
1531var factory = function (container, _a) {
1532 var settings = _a.options;
1533 // Dependencies
1534 var app = container.getProvider('app').getImmediate();
1535 var installations = container
1536 .getProvider('installations-internal')
1537 .getImmediate();
1538 if (app.name !== DEFAULT_ENTRY_NAME) {
1539 throw ERROR_FACTORY.create("FB not default" /* ErrorCode.FB_NOT_DEFAULT */);
1540 }
1541 if (typeof window === 'undefined') {
1542 throw ERROR_FACTORY.create("no window" /* ErrorCode.NO_WINDOW */);
1543 }
1544 setupApi(window);
1545 var perfInstance = new PerformanceController(app, installations);
1546 perfInstance._init(settings);
1547 return perfInstance;
1548};
1549function registerPerformance() {
1550 app._registerComponent(new component.Component('performance', factory, "PUBLIC" /* ComponentType.PUBLIC */));
1551 app.registerVersion(name, version);
1552 // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
1553 app.registerVersion(name, version, 'cjs5');
1554}
1555registerPerformance();
1556
1557exports.getPerformance = getPerformance;
1558exports.initializePerformance = initializePerformance;
1559exports.trace = trace;
1560//# sourceMappingURL=index.cjs.js.map