@firebase/performance 0.7.7 → 0.7.8-20250716004940
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.
- package/dist/esm/{index.esm2017.js → index.esm.js} +85 -49
- package/dist/esm/index.esm.js.map +1 -0
- package/dist/esm/src/services/settings_service.d.ts +1 -0
- package/dist/esm/src/services/transport_service.d.ts +3 -2
- package/dist/index.cjs.js +84 -48
- package/dist/index.cjs.js.map +1 -1
- package/dist/src/services/settings_service.d.ts +1 -0
- package/dist/src/services/transport_service.d.ts +3 -2
- package/package.json +10 -10
- package/dist/esm/index.esm2017.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -10,7 +10,7 @@ var component = require('@firebase/component');
|
|
|
10
10
|
require('@firebase/installations');
|
|
11
11
|
|
|
12
12
|
const name = "@firebase/performance";
|
|
13
|
-
const version = "0.7.
|
|
13
|
+
const version = "0.7.8-20250716004940";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @license
|
|
@@ -331,6 +331,9 @@ class SettingsService {
|
|
|
331
331
|
this.logNetworkAfterSampling = false;
|
|
332
332
|
// TTL of config retrieved from remote config in hours.
|
|
333
333
|
this.configTimeToLive = 12;
|
|
334
|
+
// The max number of events to send during a flush. This number is kept low to since Chrome has a
|
|
335
|
+
// shared payload limit for all sendBeacon calls in the same nav context.
|
|
336
|
+
this.logMaxFlushSize = 40;
|
|
334
337
|
}
|
|
335
338
|
getFlTransportFullUrl() {
|
|
336
339
|
return this.flTransportEndpointUrl.concat('?key=', this.transportKey);
|
|
@@ -371,7 +374,7 @@ const MAX_ATTRIBUTE_NAME_LENGTH = 40;
|
|
|
371
374
|
const MAX_ATTRIBUTE_VALUE_LENGTH = 100;
|
|
372
375
|
function getServiceWorkerStatus() {
|
|
373
376
|
const navigator = Api.getInstance().navigator;
|
|
374
|
-
if (navigator
|
|
377
|
+
if (navigator?.serviceWorker) {
|
|
375
378
|
if (navigator.serviceWorker.controller) {
|
|
376
379
|
return 2 /* ServiceWorkerStatus.CONTROLLED */;
|
|
377
380
|
}
|
|
@@ -440,24 +443,21 @@ function isValidCustomAttributeValue(value) {
|
|
|
440
443
|
* limitations under the License.
|
|
441
444
|
*/
|
|
442
445
|
function getAppId(firebaseApp) {
|
|
443
|
-
|
|
444
|
-
const appId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.appId;
|
|
446
|
+
const appId = firebaseApp.options?.appId;
|
|
445
447
|
if (!appId) {
|
|
446
448
|
throw ERROR_FACTORY.create("no app id" /* ErrorCode.NO_APP_ID */);
|
|
447
449
|
}
|
|
448
450
|
return appId;
|
|
449
451
|
}
|
|
450
452
|
function getProjectId(firebaseApp) {
|
|
451
|
-
|
|
452
|
-
const projectId = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.projectId;
|
|
453
|
+
const projectId = firebaseApp.options?.projectId;
|
|
453
454
|
if (!projectId) {
|
|
454
455
|
throw ERROR_FACTORY.create("no project id" /* ErrorCode.NO_PROJECT_ID */);
|
|
455
456
|
}
|
|
456
457
|
return projectId;
|
|
457
458
|
}
|
|
458
459
|
function getApiKey(firebaseApp) {
|
|
459
|
-
|
|
460
|
-
const apiKey = (_a = firebaseApp.options) === null || _a === void 0 ? void 0 : _a.apiKey;
|
|
460
|
+
const apiKey = firebaseApp.options?.apiKey;
|
|
461
461
|
if (!apiKey) {
|
|
462
462
|
throw ERROR_FACTORY.create("no api key" /* ErrorCode.NO_API_KEY */);
|
|
463
463
|
}
|
|
@@ -516,7 +516,7 @@ function getStoredConfig() {
|
|
|
516
516
|
const configResponse = JSON.parse(configStringified);
|
|
517
517
|
return configResponse;
|
|
518
518
|
}
|
|
519
|
-
catch
|
|
519
|
+
catch {
|
|
520
520
|
return;
|
|
521
521
|
}
|
|
522
522
|
}
|
|
@@ -618,6 +618,12 @@ function processConfig(config) {
|
|
|
618
618
|
settingsServiceInstance.tracesSamplingRate =
|
|
619
619
|
DEFAULT_CONFIGS.tracesSamplingRate;
|
|
620
620
|
}
|
|
621
|
+
if (entries.fpr_log_max_flush_size) {
|
|
622
|
+
settingsServiceInstance.logMaxFlushSize = Number(entries.fpr_log_max_flush_size);
|
|
623
|
+
}
|
|
624
|
+
else if (DEFAULT_CONFIGS.logMaxFlushSize) {
|
|
625
|
+
settingsServiceInstance.logMaxFlushSize = DEFAULT_CONFIGS.logMaxFlushSize;
|
|
626
|
+
}
|
|
621
627
|
// Set the per session trace and network logging flags.
|
|
622
628
|
settingsServiceInstance.logTraceAfterSampling = shouldLogAfterSampling(settingsServiceInstance.tracesSamplingRate);
|
|
623
629
|
settingsServiceInstance.logNetworkAfterSampling = shouldLogAfterSampling(settingsServiceInstance.networkRequestsSamplingRate);
|
|
@@ -708,6 +714,9 @@ const DEFAULT_SEND_INTERVAL_MS = 10 * 1000;
|
|
|
708
714
|
const INITIAL_SEND_TIME_DELAY_MS = 5.5 * 1000;
|
|
709
715
|
const MAX_EVENT_COUNT_PER_REQUEST = 1000;
|
|
710
716
|
const DEFAULT_REMAINING_TRIES = 3;
|
|
717
|
+
// Most browsers have a max payload of 64KB for sendbeacon/keep alive payload.
|
|
718
|
+
const MAX_SEND_BEACON_PAYLOAD_SIZE = 65536;
|
|
719
|
+
const TEXT_ENCODER = new TextEncoder();
|
|
711
720
|
let remainingTries = DEFAULT_REMAINING_TRIES;
|
|
712
721
|
/* eslint-enable camelcase */
|
|
713
722
|
let queue = [];
|
|
@@ -735,13 +744,28 @@ function dispatchQueueEvents() {
|
|
|
735
744
|
// The staged events will be used for current logRequest attempt, remaining events will be kept
|
|
736
745
|
// for next attempt.
|
|
737
746
|
const staged = queue.splice(0, MAX_EVENT_COUNT_PER_REQUEST);
|
|
747
|
+
const data = buildPayload(staged);
|
|
748
|
+
postToFlEndpoint(data)
|
|
749
|
+
.then(() => {
|
|
750
|
+
remainingTries = DEFAULT_REMAINING_TRIES;
|
|
751
|
+
})
|
|
752
|
+
.catch(() => {
|
|
753
|
+
// If the request fails for some reason, add the events that were attempted
|
|
754
|
+
// back to the primary queue to retry later.
|
|
755
|
+
queue = [...staged, ...queue];
|
|
756
|
+
remainingTries--;
|
|
757
|
+
consoleLogger.info(`Tries left: ${remainingTries}.`);
|
|
758
|
+
processQueue(DEFAULT_SEND_INTERVAL_MS);
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
function buildPayload(events) {
|
|
738
762
|
/* eslint-disable camelcase */
|
|
739
763
|
// We will pass the JSON serialized event to the backend.
|
|
740
|
-
const log_event =
|
|
764
|
+
const log_event = events.map(evt => ({
|
|
741
765
|
source_extension_json_proto3: evt.message,
|
|
742
766
|
event_time_ms: String(evt.eventTime)
|
|
743
767
|
}));
|
|
744
|
-
const
|
|
768
|
+
const transportBatchLog = {
|
|
745
769
|
request_time_ms: String(Date.now()),
|
|
746
770
|
client_info: {
|
|
747
771
|
client_type: 1, // 1 is JS
|
|
@@ -751,29 +775,23 @@ function dispatchQueueEvents() {
|
|
|
751
775
|
log_event
|
|
752
776
|
};
|
|
753
777
|
/* eslint-enable camelcase */
|
|
754
|
-
|
|
755
|
-
.then(() => {
|
|
756
|
-
remainingTries = DEFAULT_REMAINING_TRIES;
|
|
757
|
-
})
|
|
758
|
-
.catch(() => {
|
|
759
|
-
// If the request fails for some reason, add the events that were attempted
|
|
760
|
-
// back to the primary queue to retry later.
|
|
761
|
-
queue = [...staged, ...queue];
|
|
762
|
-
remainingTries--;
|
|
763
|
-
consoleLogger.info(`Tries left: ${remainingTries}.`);
|
|
764
|
-
processQueue(DEFAULT_SEND_INTERVAL_MS);
|
|
765
|
-
});
|
|
778
|
+
return JSON.stringify(transportBatchLog);
|
|
766
779
|
}
|
|
767
|
-
|
|
780
|
+
/** Sends to Firelog. Atempts to use sendBeacon otherwsise uses fetch. */
|
|
781
|
+
function postToFlEndpoint(body) {
|
|
768
782
|
const flTransportFullUrl = SettingsService.getInstance().getFlTransportFullUrl();
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
783
|
+
const size = TEXT_ENCODER.encode(body).length;
|
|
784
|
+
if (size <= MAX_SEND_BEACON_PAYLOAD_SIZE &&
|
|
785
|
+
navigator.sendBeacon &&
|
|
786
|
+
navigator.sendBeacon(flTransportFullUrl, body)) {
|
|
787
|
+
return Promise.resolve();
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
return fetch(flTransportFullUrl, {
|
|
773
791
|
method: 'POST',
|
|
774
|
-
body
|
|
775
|
-
|
|
776
|
-
|
|
792
|
+
body
|
|
793
|
+
});
|
|
794
|
+
}
|
|
777
795
|
}
|
|
778
796
|
function addToQueue(evt) {
|
|
779
797
|
if (!evt.eventTime || !evt.message) {
|
|
@@ -795,12 +813,33 @@ serializer) {
|
|
|
795
813
|
};
|
|
796
814
|
}
|
|
797
815
|
/**
|
|
798
|
-
* Force flush the queued events. Useful at page unload time to ensure all
|
|
799
|
-
* events
|
|
816
|
+
* Force flush the queued events. Useful at page unload time to ensure all events are uploaded.
|
|
817
|
+
* Flush will attempt to use sendBeacon to send events async and defaults back to fetch as soon as a
|
|
818
|
+
* sendBeacon fails. Firefox
|
|
800
819
|
*/
|
|
801
820
|
function flushQueuedEvents() {
|
|
821
|
+
const flTransportFullUrl = SettingsService.getInstance().getFlTransportFullUrl();
|
|
802
822
|
while (queue.length > 0) {
|
|
803
|
-
|
|
823
|
+
// Send the last events first to prioritize page load traces
|
|
824
|
+
const staged = queue.splice(-SettingsService.getInstance().logMaxFlushSize);
|
|
825
|
+
const body = buildPayload(staged);
|
|
826
|
+
if (navigator.sendBeacon &&
|
|
827
|
+
navigator.sendBeacon(flTransportFullUrl, body)) {
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
queue = [...queue, ...staged];
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (queue.length > 0) {
|
|
836
|
+
const body = buildPayload(queue);
|
|
837
|
+
fetch(flTransportFullUrl, {
|
|
838
|
+
method: 'POST',
|
|
839
|
+
body
|
|
840
|
+
}).catch(() => {
|
|
841
|
+
consoleLogger.info(`Failed flushing queued events.`);
|
|
842
|
+
});
|
|
804
843
|
}
|
|
805
844
|
}
|
|
806
845
|
|
|
@@ -1141,7 +1180,7 @@ class Trace {
|
|
|
1141
1180
|
this.durationUs = Math.floor(duration * 1000);
|
|
1142
1181
|
this.startTimeUs = Math.floor(startTime * 1000);
|
|
1143
1182
|
if (options && options.attributes) {
|
|
1144
|
-
this.customAttributes =
|
|
1183
|
+
this.customAttributes = { ...options.attributes };
|
|
1145
1184
|
}
|
|
1146
1185
|
if (options && options.metrics) {
|
|
1147
1186
|
for (const metricName of Object.keys(options.metrics)) {
|
|
@@ -1175,7 +1214,7 @@ class Trace {
|
|
|
1175
1214
|
*/
|
|
1176
1215
|
putMetric(counter, numAsInteger) {
|
|
1177
1216
|
if (isValidMetricName(counter, this.name)) {
|
|
1178
|
-
this.counters[counter] = convertMetricValueToInteger(numAsInteger
|
|
1217
|
+
this.counters[counter] = convertMetricValueToInteger(numAsInteger ?? 0);
|
|
1179
1218
|
}
|
|
1180
1219
|
else {
|
|
1181
1220
|
throw ERROR_FACTORY.create("invalid custom metric name" /* ErrorCode.INVALID_CUSTOM_METRIC_NAME */, {
|
|
@@ -1229,7 +1268,7 @@ class Trace {
|
|
|
1229
1268
|
delete this.customAttributes[attr];
|
|
1230
1269
|
}
|
|
1231
1270
|
getAttributes() {
|
|
1232
|
-
return
|
|
1271
|
+
return { ...this.customAttributes };
|
|
1233
1272
|
}
|
|
1234
1273
|
setStartTime(startTime) {
|
|
1235
1274
|
this.startTimeUs = startTime;
|
|
@@ -1366,24 +1405,21 @@ function setupOobTraces(performanceController) {
|
|
|
1366
1405
|
});
|
|
1367
1406
|
}
|
|
1368
1407
|
api.onLCP((metric) => {
|
|
1369
|
-
var _a;
|
|
1370
1408
|
webVitalMetrics.lcp = {
|
|
1371
1409
|
value: metric.value,
|
|
1372
|
-
elementAttribution:
|
|
1410
|
+
elementAttribution: metric.attribution?.element
|
|
1373
1411
|
};
|
|
1374
1412
|
});
|
|
1375
1413
|
api.onCLS((metric) => {
|
|
1376
|
-
var _a;
|
|
1377
1414
|
webVitalMetrics.cls = {
|
|
1378
1415
|
value: metric.value,
|
|
1379
|
-
elementAttribution:
|
|
1416
|
+
elementAttribution: metric.attribution?.largestShiftTarget
|
|
1380
1417
|
};
|
|
1381
1418
|
});
|
|
1382
1419
|
api.onINP((metric) => {
|
|
1383
|
-
var _a;
|
|
1384
1420
|
webVitalMetrics.inp = {
|
|
1385
1421
|
value: metric.value,
|
|
1386
|
-
elementAttribution:
|
|
1422
|
+
elementAttribution: metric.attribution?.interactionTarget
|
|
1387
1423
|
};
|
|
1388
1424
|
});
|
|
1389
1425
|
}
|
|
@@ -1456,10 +1492,10 @@ class PerformanceController {
|
|
|
1456
1492
|
if (this.initialized) {
|
|
1457
1493
|
return;
|
|
1458
1494
|
}
|
|
1459
|
-
if (
|
|
1495
|
+
if (settings?.dataCollectionEnabled !== undefined) {
|
|
1460
1496
|
this.dataCollectionEnabled = settings.dataCollectionEnabled;
|
|
1461
1497
|
}
|
|
1462
|
-
if (
|
|
1498
|
+
if (settings?.instrumentationEnabled !== undefined) {
|
|
1463
1499
|
this.instrumentationEnabled = settings.instrumentationEnabled;
|
|
1464
1500
|
}
|
|
1465
1501
|
if (Api.getInstance().requiredApisAvailable()) {
|
|
@@ -1526,7 +1562,7 @@ function initializePerformance(app$1, settings) {
|
|
|
1526
1562
|
if (provider.isInitialized()) {
|
|
1527
1563
|
const existingInstance = provider.getImmediate();
|
|
1528
1564
|
const initialSettings = provider.getOptions();
|
|
1529
|
-
if (util.deepEqual(initialSettings, settings
|
|
1565
|
+
if (util.deepEqual(initialSettings, settings ?? {})) {
|
|
1530
1566
|
return existingInstance;
|
|
1531
1567
|
}
|
|
1532
1568
|
else {
|
|
@@ -1568,8 +1604,8 @@ const factory = (container, { options: settings }) => {
|
|
|
1568
1604
|
function registerPerformance() {
|
|
1569
1605
|
app._registerComponent(new component.Component('performance', factory, "PUBLIC" /* ComponentType.PUBLIC */));
|
|
1570
1606
|
app.registerVersion(name, version);
|
|
1571
|
-
// BUILD_TARGET will be replaced by values like
|
|
1572
|
-
app.registerVersion(name, version, '
|
|
1607
|
+
// BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation
|
|
1608
|
+
app.registerVersion(name, version, 'cjs2020');
|
|
1573
1609
|
}
|
|
1574
1610
|
registerPerformance();
|
|
1575
1611
|
|