@firebase/performance 0.6.12-canary.2ec1c7682 → 0.6.12-canary.3c1559b7e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,11 @@
1
1
  import { ErrorFactory, areCookiesEnabled, isIndexedDBAvailable, validateIndexedDBOpenable, getModularInstance, deepEqual } from '@firebase/util';
2
2
  import { Logger, LogLevel } from '@firebase/logger';
3
- import { onLCP, onINP, onCLS } from 'web-vitals/attribution';
4
3
  import { _getProvider, getApp, _registerComponent, registerVersion } from '@firebase/app';
5
4
  import { Component } from '@firebase/component';
6
5
  import '@firebase/installations';
7
6
 
8
7
  const name = "@firebase/performance";
9
- const version = "0.6.12-canary.2ec1c7682";
8
+ const version = "0.6.12-canary.3c1559b7e";
10
9
 
11
10
  /**
12
11
  * @license
@@ -36,12 +35,6 @@ const OOB_TRACE_PAGE_LOAD_PREFIX = '_wt_';
36
35
  const FIRST_PAINT_COUNTER_NAME = '_fp';
37
36
  const FIRST_CONTENTFUL_PAINT_COUNTER_NAME = '_fcp';
38
37
  const FIRST_INPUT_DELAY_COUNTER_NAME = '_fid';
39
- const LARGEST_CONTENTFUL_PAINT_METRIC_NAME = '_lcp';
40
- const LARGEST_CONTENTFUL_PAINT_ATTRIBUTE_NAME = 'lcp_element';
41
- const INTERACTION_TO_NEXT_PAINT_METRIC_NAME = '_inp';
42
- const INTERACTION_TO_NEXT_PAINT_ATTRIBUTE_NAME = 'inp_interactionTarget';
43
- const CUMULATIVE_LAYOUT_SHIFT_METRIC_NAME = '_cls';
44
- const CUMULATIVE_LAYOUT_SHIFT_ATTRIBUTE_NAME = 'cls_largestShiftTarget';
45
38
  const CONFIG_LOCAL_STORAGE_KEY = '@firebase/performance/config';
46
39
  const CONFIG_EXPIRY_LOCAL_STORAGE_KEY = '@firebase/performance/configexpire';
47
40
  const SERVICE = 'performance';
@@ -146,9 +139,6 @@ class Api {
146
139
  if (window.perfMetrics && window.perfMetrics.onFirstInputDelay) {
147
140
  this.onFirstInputDelay = window.perfMetrics.onFirstInputDelay;
148
141
  }
149
- this.onLCP = onLCP;
150
- this.onINP = onINP;
151
- this.onCLS = onCLS;
152
142
  }
153
143
  getUrl() {
154
144
  // Do not capture the string query part of url.
@@ -702,8 +692,9 @@ function changeInitializationStatus() {
702
692
  */
703
693
  const DEFAULT_SEND_INTERVAL_MS = 10 * 1000;
704
694
  const INITIAL_SEND_TIME_DELAY_MS = 5.5 * 1000;
705
- const MAX_EVENT_COUNT_PER_REQUEST = 1000;
695
+ // If end point does not work, the call will be tried for these many times.
706
696
  const DEFAULT_REMAINING_TRIES = 3;
697
+ const MAX_EVENT_COUNT_PER_REQUEST = 1000;
707
698
  let remainingTries = DEFAULT_REMAINING_TRIES;
708
699
  /* eslint-enable camelcase */
709
700
  let queue = [];
@@ -720,10 +711,11 @@ function processQueue(timeOffset) {
720
711
  if (remainingTries === 0) {
721
712
  return;
722
713
  }
723
- if (queue.length > 0) {
724
- dispatchQueueEvents();
714
+ // If there are no events to process, wait for DEFAULT_SEND_INTERVAL_MS and try again.
715
+ if (!queue.length) {
716
+ return processQueue(DEFAULT_SEND_INTERVAL_MS);
725
717
  }
726
- processQueue(DEFAULT_SEND_INTERVAL_MS);
718
+ dispatchQueueEvents();
727
719
  }, timeOffset);
728
720
  }
729
721
  function dispatchQueueEvents() {
@@ -747,11 +739,7 @@ function dispatchQueueEvents() {
747
739
  log_event
748
740
  };
749
741
  /* eslint-enable camelcase */
750
- postToFlEndpoint(data)
751
- .then(() => {
752
- remainingTries = DEFAULT_REMAINING_TRIES;
753
- })
754
- .catch(() => {
742
+ sendEventsToFl(data, staged).catch(() => {
755
743
  // If the request fails for some reason, add the events that were attempted
756
744
  // back to the primary queue to retry later.
757
745
  queue = [...staged, ...queue];
@@ -760,16 +748,41 @@ function dispatchQueueEvents() {
760
748
  processQueue(DEFAULT_SEND_INTERVAL_MS);
761
749
  });
762
750
  }
751
+ function sendEventsToFl(data, staged) {
752
+ return postToFlEndpoint(data)
753
+ .then(res => {
754
+ if (!res.ok) {
755
+ consoleLogger.info('Call to Firebase backend failed.');
756
+ }
757
+ return res.json();
758
+ })
759
+ .then(res => {
760
+ // Find the next call wait time from the response.
761
+ const transportWait = Number(res.nextRequestWaitMillis);
762
+ let requestOffset = DEFAULT_SEND_INTERVAL_MS;
763
+ if (!isNaN(transportWait)) {
764
+ requestOffset = Math.max(transportWait, requestOffset);
765
+ }
766
+ // Delete request if response include RESPONSE_ACTION_UNKNOWN or DELETE_REQUEST action.
767
+ // Otherwise, retry request using normal scheduling if response include RETRY_REQUEST_LATER.
768
+ const logResponseDetails = res.logResponseDetails;
769
+ if (Array.isArray(logResponseDetails) &&
770
+ logResponseDetails.length > 0 &&
771
+ logResponseDetails[0].responseAction === 'RETRY_REQUEST_LATER') {
772
+ queue = [...staged, ...queue];
773
+ consoleLogger.info(`Retry transport request later.`);
774
+ }
775
+ remainingTries = DEFAULT_REMAINING_TRIES;
776
+ // Schedule the next process.
777
+ processQueue(requestOffset);
778
+ });
779
+ }
763
780
  function postToFlEndpoint(data) {
764
781
  const flTransportFullUrl = SettingsService.getInstance().getFlTransportFullUrl();
765
- const body = JSON.stringify(data);
766
- return navigator.sendBeacon && navigator.sendBeacon(flTransportFullUrl, body)
767
- ? Promise.resolve()
768
- : fetch(flTransportFullUrl, {
769
- method: 'POST',
770
- body,
771
- keepalive: true
772
- }).then();
782
+ return fetch(flTransportFullUrl, {
783
+ method: 'POST',
784
+ body: JSON.stringify(data)
785
+ });
773
786
  }
774
787
  function addToQueue(evt) {
775
788
  if (!evt.eventTime || !evt.message) {
@@ -790,15 +803,6 @@ serializer) {
790
803
  });
791
804
  };
792
805
  }
793
- /**
794
- * Force flush the queued events. Useful at page unload time to ensure all
795
- * events are uploaded.
796
- */
797
- function flushQueuedEvents() {
798
- while (queue.length > 0) {
799
- dispatchQueueEvents();
800
- }
801
- }
802
806
 
803
807
  /**
804
808
  * @license
@@ -817,16 +821,12 @@ function flushQueuedEvents() {
817
821
  * limitations under the License.
818
822
  */
819
823
  let logger;
820
- //
821
824
  // This method is not called before initialization.
822
825
  function sendLog(resource, resourceType) {
823
826
  if (!logger) {
824
- logger = {
825
- send: transportHandler(serializer),
826
- flush: flushQueuedEvents
827
- };
827
+ logger = transportHandler(serializer);
828
828
  }
829
- logger.send(resource, resourceType);
829
+ logger(resource, resourceType);
830
830
  }
831
831
  function logTrace(trace) {
832
832
  const settingsService = SettingsService.getInstance();
@@ -842,6 +842,10 @@ function logTrace(trace) {
842
842
  if (!Api.getInstance().requiredApisAvailable()) {
843
843
  return;
844
844
  }
845
+ // Only log the page load auto traces if page is visible.
846
+ if (trace.isAuto && getVisibilityState() !== VisibilityState.VISIBLE) {
847
+ return;
848
+ }
845
849
  if (isPerfInitialized()) {
846
850
  sendTraceLog(trace);
847
851
  }
@@ -851,11 +855,6 @@ function logTrace(trace) {
851
855
  getInitializationPromise(trace.performanceController).then(() => sendTraceLog(trace), () => sendTraceLog(trace));
852
856
  }
853
857
  }
854
- function flushLogs() {
855
- if (logger) {
856
- logger.flush();
857
- }
858
- }
859
858
  function sendTraceLog(trace) {
860
859
  if (!getIid()) {
861
860
  return;
@@ -865,7 +864,7 @@ function sendTraceLog(trace) {
865
864
  !settingsService.logTraceAfterSampling) {
866
865
  return;
867
866
  }
868
- sendLog(trace, 1 /* ResourceType.Trace */);
867
+ setTimeout(() => sendLog(trace, 1 /* ResourceType.Trace */), 0);
869
868
  }
870
869
  function logNetworkRequest(networkRequest) {
871
870
  const settingsService = SettingsService.getInstance();
@@ -888,7 +887,7 @@ function logNetworkRequest(networkRequest) {
888
887
  !settingsService.logNetworkAfterSampling) {
889
888
  return;
890
889
  }
891
- sendLog(networkRequest, 0 /* ResourceType.NetworkRequest */);
890
+ setTimeout(() => sendLog(networkRequest, 0 /* ResourceType.NetworkRequest */), 0);
892
891
  }
893
892
  function serializer(resource, resourceType) {
894
893
  if (resourceType === 0 /* ResourceType.NetworkRequest */) {
@@ -948,46 +947,6 @@ function getApplicationInfo(firebaseApp) {
948
947
  }
949
948
  /* eslint-enable camelcase */
950
949
 
951
- /**
952
- * @license
953
- * Copyright 2020 Google LLC
954
- *
955
- * Licensed under the Apache License, Version 2.0 (the "License");
956
- * you may not use this file except in compliance with the License.
957
- * You may obtain a copy of the License at
958
- *
959
- * http://www.apache.org/licenses/LICENSE-2.0
960
- *
961
- * Unless required by applicable law or agreed to in writing, software
962
- * distributed under the License is distributed on an "AS IS" BASIS,
963
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
964
- * See the License for the specific language governing permissions and
965
- * limitations under the License.
966
- */
967
- function createNetworkRequestEntry(performanceController, entry) {
968
- const performanceEntry = entry;
969
- if (!performanceEntry || performanceEntry.responseStart === undefined) {
970
- return;
971
- }
972
- const timeOrigin = Api.getInstance().getTimeOrigin();
973
- const startTimeUs = Math.floor((performanceEntry.startTime + timeOrigin) * 1000);
974
- const timeToResponseInitiatedUs = performanceEntry.responseStart
975
- ? Math.floor((performanceEntry.responseStart - performanceEntry.startTime) * 1000)
976
- : undefined;
977
- const timeToResponseCompletedUs = Math.floor((performanceEntry.responseEnd - performanceEntry.startTime) * 1000);
978
- // Remove the query params from logged network request url.
979
- const url = performanceEntry.name && performanceEntry.name.split('?')[0];
980
- const networkRequest = {
981
- performanceController,
982
- url,
983
- responsePayloadBytes: performanceEntry.transferSize,
984
- startTimeUs,
985
- timeToResponseInitiatedUs,
986
- timeToResponseCompletedUs
987
- };
988
- logNetworkRequest(networkRequest);
989
- }
990
-
991
950
  /**
992
951
  * @license
993
952
  * Copyright 2020 Google LLC
@@ -1009,10 +968,7 @@ const RESERVED_AUTO_PREFIX = '_';
1009
968
  const oobMetrics = [
1010
969
  FIRST_PAINT_COUNTER_NAME,
1011
970
  FIRST_CONTENTFUL_PAINT_COUNTER_NAME,
1012
- FIRST_INPUT_DELAY_COUNTER_NAME,
1013
- LARGEST_CONTENTFUL_PAINT_METRIC_NAME,
1014
- CUMULATIVE_LAYOUT_SHIFT_METRIC_NAME,
1015
- INTERACTION_TO_NEXT_PAINT_METRIC_NAME
971
+ FIRST_INPUT_DELAY_COUNTER_NAME
1016
972
  ];
1017
973
  /**
1018
974
  * Returns true if the metric is custom and does not start with reserved prefix, or if
@@ -1251,7 +1207,7 @@ class Trace {
1251
1207
  * @param paintTimings A array which contains paintTiming object of the page load
1252
1208
  * @param firstInputDelay First input delay in millisec
1253
1209
  */
1254
- static createOobTrace(performanceController, navigationTimings, paintTimings, webVitalMetrics, firstInputDelay) {
1210
+ static createOobTrace(performanceController, navigationTimings, paintTimings, firstInputDelay) {
1255
1211
  const route = Api.getInstance().getUrl();
1256
1212
  if (!route) {
1257
1213
  return;
@@ -1281,21 +1237,7 @@ class Trace {
1281
1237
  trace.putMetric(FIRST_INPUT_DELAY_COUNTER_NAME, Math.floor(firstInputDelay * 1000));
1282
1238
  }
1283
1239
  }
1284
- this.addWebVitalMetric(trace, LARGEST_CONTENTFUL_PAINT_METRIC_NAME, LARGEST_CONTENTFUL_PAINT_ATTRIBUTE_NAME, webVitalMetrics.lcp);
1285
- this.addWebVitalMetric(trace, CUMULATIVE_LAYOUT_SHIFT_METRIC_NAME, CUMULATIVE_LAYOUT_SHIFT_ATTRIBUTE_NAME, webVitalMetrics.cls);
1286
- this.addWebVitalMetric(trace, INTERACTION_TO_NEXT_PAINT_METRIC_NAME, INTERACTION_TO_NEXT_PAINT_ATTRIBUTE_NAME, webVitalMetrics.inp);
1287
- // Page load logs are sent at unload time and so should be logged and
1288
- // flushed immediately.
1289
1240
  logTrace(trace);
1290
- flushLogs();
1291
- }
1292
- static addWebVitalMetric(trace, metricKey, attributeKey, metric) {
1293
- if (metric) {
1294
- trace.putMetric(metricKey, Math.floor(metric.value * 1000));
1295
- if (metric.elementAttribution) {
1296
- trace.putAttribute(attributeKey, metric.elementAttribution);
1297
- }
1298
- }
1299
1241
  }
1300
1242
  static createUserTimingTrace(performanceController, measureName) {
1301
1243
  const trace = new Trace(performanceController, measureName, false, measureName);
@@ -1319,17 +1261,54 @@ class Trace {
1319
1261
  * See the License for the specific language governing permissions and
1320
1262
  * limitations under the License.
1321
1263
  */
1322
- let webVitalMetrics = {};
1323
- let sentPageLoadTrace = false;
1324
- let firstInputDelay;
1264
+ function createNetworkRequestEntry(performanceController, entry) {
1265
+ const performanceEntry = entry;
1266
+ if (!performanceEntry || performanceEntry.responseStart === undefined) {
1267
+ return;
1268
+ }
1269
+ const timeOrigin = Api.getInstance().getTimeOrigin();
1270
+ const startTimeUs = Math.floor((performanceEntry.startTime + timeOrigin) * 1000);
1271
+ const timeToResponseInitiatedUs = performanceEntry.responseStart
1272
+ ? Math.floor((performanceEntry.responseStart - performanceEntry.startTime) * 1000)
1273
+ : undefined;
1274
+ const timeToResponseCompletedUs = Math.floor((performanceEntry.responseEnd - performanceEntry.startTime) * 1000);
1275
+ // Remove the query params from logged network request url.
1276
+ const url = performanceEntry.name && performanceEntry.name.split('?')[0];
1277
+ const networkRequest = {
1278
+ performanceController,
1279
+ url,
1280
+ responsePayloadBytes: performanceEntry.transferSize,
1281
+ startTimeUs,
1282
+ timeToResponseInitiatedUs,
1283
+ timeToResponseCompletedUs
1284
+ };
1285
+ logNetworkRequest(networkRequest);
1286
+ }
1287
+
1288
+ /**
1289
+ * @license
1290
+ * Copyright 2020 Google LLC
1291
+ *
1292
+ * Licensed under the Apache License, Version 2.0 (the "License");
1293
+ * you may not use this file except in compliance with the License.
1294
+ * You may obtain a copy of the License at
1295
+ *
1296
+ * http://www.apache.org/licenses/LICENSE-2.0
1297
+ *
1298
+ * Unless required by applicable law or agreed to in writing, software
1299
+ * distributed under the License is distributed on an "AS IS" BASIS,
1300
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1301
+ * See the License for the specific language governing permissions and
1302
+ * limitations under the License.
1303
+ */
1304
+ const FID_WAIT_TIME_MS = 5000;
1325
1305
  function setupOobResources(performanceController) {
1326
1306
  // Do not initialize unless iid is available.
1327
1307
  if (!getIid()) {
1328
1308
  return;
1329
1309
  }
1330
- // The load event might not have fired yet, and that means performance
1331
- // navigation timing object has a duration of 0. The setup should run after
1332
- // all current tasks in js queue.
1310
+ // The load event might not have fired yet, and that means performance navigation timing
1311
+ // object has a duration of 0. The setup should run after all current tasks in js queue.
1333
1312
  setTimeout(() => setupOobTraces(performanceController), 0);
1334
1313
  setTimeout(() => setupNetworkRequests(performanceController), 0);
1335
1314
  setTimeout(() => setupUserTimingTraces(performanceController), 0);
@@ -1344,44 +1323,27 @@ function setupNetworkRequests(performanceController) {
1344
1323
  }
1345
1324
  function setupOobTraces(performanceController) {
1346
1325
  const api = Api.getInstance();
1347
- // Better support for Safari
1348
- if ('onpagehide' in window) {
1349
- api.document.addEventListener('pagehide', () => sendOobTrace(performanceController));
1350
- }
1351
- else {
1352
- api.document.addEventListener('unload', () => sendOobTrace(performanceController));
1353
- }
1354
- api.document.addEventListener('visibilitychange', () => {
1355
- if (api.document.visibilityState === 'hidden') {
1356
- sendOobTrace(performanceController);
1357
- }
1358
- });
1326
+ const navigationTimings = api.getEntriesByType('navigation');
1327
+ const paintTimings = api.getEntriesByType('paint');
1328
+ // If First Input Delay polyfill is added to the page, report the fid value.
1329
+ // https://github.com/GoogleChromeLabs/first-input-delay
1359
1330
  if (api.onFirstInputDelay) {
1331
+ // If the fid call back is not called for certain time, continue without it.
1332
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1333
+ let timeoutId = setTimeout(() => {
1334
+ Trace.createOobTrace(performanceController, navigationTimings, paintTimings);
1335
+ timeoutId = undefined;
1336
+ }, FID_WAIT_TIME_MS);
1360
1337
  api.onFirstInputDelay((fid) => {
1361
- firstInputDelay = fid;
1338
+ if (timeoutId) {
1339
+ clearTimeout(timeoutId);
1340
+ Trace.createOobTrace(performanceController, navigationTimings, paintTimings, fid);
1341
+ }
1362
1342
  });
1363
1343
  }
1364
- api.onLCP((metric) => {
1365
- var _a;
1366
- webVitalMetrics.lcp = {
1367
- value: metric.value,
1368
- elementAttribution: (_a = metric.attribution) === null || _a === void 0 ? void 0 : _a.element
1369
- };
1370
- });
1371
- api.onCLS((metric) => {
1372
- var _a;
1373
- webVitalMetrics.cls = {
1374
- value: metric.value,
1375
- elementAttribution: (_a = metric.attribution) === null || _a === void 0 ? void 0 : _a.largestShiftTarget
1376
- };
1377
- });
1378
- api.onINP((metric) => {
1379
- var _a;
1380
- webVitalMetrics.inp = {
1381
- value: metric.value,
1382
- elementAttribution: (_a = metric.attribution) === null || _a === void 0 ? void 0 : _a.interactionTarget
1383
- };
1384
- });
1344
+ else {
1345
+ Trace.createOobTrace(performanceController, navigationTimings, paintTimings);
1346
+ }
1385
1347
  }
1386
1348
  function setupUserTimingTraces(performanceController) {
1387
1349
  const api = Api.getInstance();
@@ -1395,27 +1357,13 @@ function setupUserTimingTraces(performanceController) {
1395
1357
  }
1396
1358
  function createUserTimingTrace(performanceController, measure) {
1397
1359
  const measureName = measure.name;
1398
- // Do not create a trace, if the user timing marks and measures are created by
1399
- // the sdk itself.
1360
+ // Do not create a trace, if the user timing marks and measures are created by the sdk itself.
1400
1361
  if (measureName.substring(0, TRACE_MEASURE_PREFIX.length) ===
1401
1362
  TRACE_MEASURE_PREFIX) {
1402
1363
  return;
1403
1364
  }
1404
1365
  Trace.createUserTimingTrace(performanceController, measureName);
1405
1366
  }
1406
- function sendOobTrace(performanceController) {
1407
- if (!sentPageLoadTrace) {
1408
- sentPageLoadTrace = true;
1409
- const api = Api.getInstance();
1410
- const navigationTimings = api.getEntriesByType('navigation');
1411
- const paintTimings = api.getEntriesByType('paint');
1412
- // On page unload web vitals may be updated so queue the oob trace creation
1413
- // so that these updates have time to be included.
1414
- setTimeout(() => {
1415
- Trace.createOobTrace(performanceController, navigationTimings, paintTimings, webVitalMetrics, firstInputDelay);
1416
- }, 0);
1417
- }
1418
- }
1419
1367
 
1420
1368
  /**
1421
1369
  * @license