@depup/firebase__performance 0.7.10-depup.0

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