UNPKG

61.6 kBJavaScriptView Raw
1import { getApp, _getProvider, _registerComponent, registerVersion } from '@firebase/app';
2import { __awaiter, __generator, __assign } from 'tslib';
3import { Logger } from '@firebase/logger';
4import { ErrorFactory, calculateBackoffMillis, FirebaseError, validateIndexedDBOpenable, isIndexedDBAvailable, isBrowserExtension, areCookiesEnabled, getModularInstance, deepEqual } from '@firebase/util';
5import { Component } from '@firebase/component';
6import '@firebase/installations';
7
8/**
9 * @license
10 * Copyright 2019 Google LLC
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 */
24/**
25 * Type constant for Firebase Analytics.
26 */
27var ANALYTICS_TYPE = 'analytics';
28// Key to attach FID to in gtag params.
29var GA_FID_KEY = 'firebase_id';
30var ORIGIN_KEY = 'origin';
31var FETCH_TIMEOUT_MILLIS = 60 * 1000;
32var DYNAMIC_CONFIG_URL = 'https://firebase.googleapis.com/v1alpha/projects/-/apps/{app-id}/webConfig';
33var GTAG_URL = 'https://www.googletagmanager.com/gtag/js';
34
35/**
36 * @license
37 * Copyright 2019 Google LLC
38 *
39 * Licensed under the Apache License, Version 2.0 (the "License");
40 * you may not use this file except in compliance with the License.
41 * You may obtain a copy of the License at
42 *
43 * http://www.apache.org/licenses/LICENSE-2.0
44 *
45 * Unless required by applicable law or agreed to in writing, software
46 * distributed under the License is distributed on an "AS IS" BASIS,
47 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48 * See the License for the specific language governing permissions and
49 * limitations under the License.
50 */
51var logger = new Logger('@firebase/analytics');
52
53/**
54 * @license
55 * Copyright 2019 Google LLC
56 *
57 * Licensed under the Apache License, Version 2.0 (the "License");
58 * you may not use this file except in compliance with the License.
59 * You may obtain a copy of the License at
60 *
61 * http://www.apache.org/licenses/LICENSE-2.0
62 *
63 * Unless required by applicable law or agreed to in writing, software
64 * distributed under the License is distributed on an "AS IS" BASIS,
65 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
66 * See the License for the specific language governing permissions and
67 * limitations under the License.
68 */
69/**
70 * Makeshift polyfill for Promise.allSettled(). Resolves when all promises
71 * have either resolved or rejected.
72 *
73 * @param promises Array of promises to wait for.
74 */
75function promiseAllSettled(promises) {
76 return Promise.all(promises.map(function (promise) { return promise.catch(function (e) { return e; }); }));
77}
78/**
79 * Inserts gtag script tag into the page to asynchronously download gtag.
80 * @param dataLayerName Name of datalayer (most often the default, "_dataLayer").
81 */
82function insertScriptTag(dataLayerName, measurementId) {
83 var script = document.createElement('script');
84 // We are not providing an analyticsId in the URL because it would trigger a `page_view`
85 // without fid. We will initialize ga-id using gtag (config) command together with fid.
86 script.src = GTAG_URL + "?l=" + dataLayerName + "&id=" + measurementId;
87 script.async = true;
88 document.head.appendChild(script);
89}
90/**
91 * Get reference to, or create, global datalayer.
92 * @param dataLayerName Name of datalayer (most often the default, "_dataLayer").
93 */
94function getOrCreateDataLayer(dataLayerName) {
95 // Check for existing dataLayer and create if needed.
96 var dataLayer = [];
97 if (Array.isArray(window[dataLayerName])) {
98 dataLayer = window[dataLayerName];
99 }
100 else {
101 window[dataLayerName] = dataLayer;
102 }
103 return dataLayer;
104}
105/**
106 * Wrapped gtag logic when gtag is called with 'config' command.
107 *
108 * @param gtagCore Basic gtag function that just appends to dataLayer.
109 * @param initializationPromisesMap Map of appIds to their initialization promises.
110 * @param dynamicConfigPromisesList Array of dynamic config fetch promises.
111 * @param measurementIdToAppId Map of GA measurementIDs to corresponding Firebase appId.
112 * @param measurementId GA Measurement ID to set config for.
113 * @param gtagParams Gtag config params to set.
114 */
115function gtagOnConfig(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, measurementId, gtagParams) {
116 return __awaiter(this, void 0, void 0, function () {
117 var correspondingAppId, dynamicConfigResults, foundConfig, e_1;
118 return __generator(this, function (_a) {
119 switch (_a.label) {
120 case 0:
121 correspondingAppId = measurementIdToAppId[measurementId];
122 _a.label = 1;
123 case 1:
124 _a.trys.push([1, 7, , 8]);
125 if (!correspondingAppId) return [3 /*break*/, 3];
126 return [4 /*yield*/, initializationPromisesMap[correspondingAppId]];
127 case 2:
128 _a.sent();
129 return [3 /*break*/, 6];
130 case 3: return [4 /*yield*/, promiseAllSettled(dynamicConfigPromisesList)];
131 case 4:
132 dynamicConfigResults = _a.sent();
133 foundConfig = dynamicConfigResults.find(function (config) { return config.measurementId === measurementId; });
134 if (!foundConfig) return [3 /*break*/, 6];
135 return [4 /*yield*/, initializationPromisesMap[foundConfig.appId]];
136 case 5:
137 _a.sent();
138 _a.label = 6;
139 case 6: return [3 /*break*/, 8];
140 case 7:
141 e_1 = _a.sent();
142 logger.error(e_1);
143 return [3 /*break*/, 8];
144 case 8:
145 gtagCore("config" /* CONFIG */, measurementId, gtagParams);
146 return [2 /*return*/];
147 }
148 });
149 });
150}
151/**
152 * Wrapped gtag logic when gtag is called with 'event' command.
153 *
154 * @param gtagCore Basic gtag function that just appends to dataLayer.
155 * @param initializationPromisesMap Map of appIds to their initialization promises.
156 * @param dynamicConfigPromisesList Array of dynamic config fetch promises.
157 * @param measurementId GA Measurement ID to log event to.
158 * @param gtagParams Params to log with this event.
159 */
160function gtagOnEvent(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementId, gtagParams) {
161 return __awaiter(this, void 0, void 0, function () {
162 var initializationPromisesToWaitFor, gaSendToList, dynamicConfigResults, _loop_1, _i, gaSendToList_1, sendToId, state_1, e_2;
163 return __generator(this, function (_a) {
164 switch (_a.label) {
165 case 0:
166 _a.trys.push([0, 4, , 5]);
167 initializationPromisesToWaitFor = [];
168 if (!(gtagParams && gtagParams['send_to'])) return [3 /*break*/, 2];
169 gaSendToList = gtagParams['send_to'];
170 // Make it an array if is isn't, so it can be dealt with the same way.
171 if (!Array.isArray(gaSendToList)) {
172 gaSendToList = [gaSendToList];
173 }
174 return [4 /*yield*/, promiseAllSettled(dynamicConfigPromisesList)];
175 case 1:
176 dynamicConfigResults = _a.sent();
177 _loop_1 = function (sendToId) {
178 // Any fetched dynamic measurement ID that matches this 'send_to' ID
179 var foundConfig = dynamicConfigResults.find(function (config) { return config.measurementId === sendToId; });
180 var initializationPromise = foundConfig && initializationPromisesMap[foundConfig.appId];
181 if (initializationPromise) {
182 initializationPromisesToWaitFor.push(initializationPromise);
183 }
184 else {
185 // Found an item in 'send_to' that is not associated
186 // directly with an FID, possibly a group. Empty this array,
187 // exit the loop early, and let it get populated below.
188 initializationPromisesToWaitFor = [];
189 return "break";
190 }
191 };
192 for (_i = 0, gaSendToList_1 = gaSendToList; _i < gaSendToList_1.length; _i++) {
193 sendToId = gaSendToList_1[_i];
194 state_1 = _loop_1(sendToId);
195 if (state_1 === "break")
196 break;
197 }
198 _a.label = 2;
199 case 2:
200 // This will be unpopulated if there was no 'send_to' field , or
201 // if not all entries in the 'send_to' field could be mapped to
202 // a FID. In these cases, wait on all pending initialization promises.
203 if (initializationPromisesToWaitFor.length === 0) {
204 initializationPromisesToWaitFor = Object.values(initializationPromisesMap);
205 }
206 // Run core gtag function with args after all relevant initialization
207 // promises have been resolved.
208 return [4 /*yield*/, Promise.all(initializationPromisesToWaitFor)];
209 case 3:
210 // Run core gtag function with args after all relevant initialization
211 // promises have been resolved.
212 _a.sent();
213 // Workaround for http://b/141370449 - third argument cannot be undefined.
214 gtagCore("event" /* EVENT */, measurementId, gtagParams || {});
215 return [3 /*break*/, 5];
216 case 4:
217 e_2 = _a.sent();
218 logger.error(e_2);
219 return [3 /*break*/, 5];
220 case 5: return [2 /*return*/];
221 }
222 });
223 });
224}
225/**
226 * Wraps a standard gtag function with extra code to wait for completion of
227 * relevant initialization promises before sending requests.
228 *
229 * @param gtagCore Basic gtag function that just appends to dataLayer.
230 * @param initializationPromisesMap Map of appIds to their initialization promises.
231 * @param dynamicConfigPromisesList Array of dynamic config fetch promises.
232 * @param measurementIdToAppId Map of GA measurementIDs to corresponding Firebase appId.
233 */
234function wrapGtag(gtagCore,
235/**
236 * Allows wrapped gtag calls to wait on whichever intialization promises are required,
237 * depending on the contents of the gtag params' `send_to` field, if any.
238 */
239initializationPromisesMap,
240/**
241 * Wrapped gtag calls sometimes require all dynamic config fetches to have returned
242 * before determining what initialization promises (which include FIDs) to wait for.
243 */
244dynamicConfigPromisesList,
245/**
246 * Wrapped gtag config calls can narrow down which initialization promise (with FID)
247 * to wait for if the measurementId is already fetched, by getting the corresponding appId,
248 * which is the key for the initialization promises map.
249 */
250measurementIdToAppId) {
251 /**
252 * Wrapper around gtag that ensures FID is sent with gtag calls.
253 * @param command Gtag command type.
254 * @param idOrNameOrParams Measurement ID if command is EVENT/CONFIG, params if command is SET.
255 * @param gtagParams Params if event is EVENT/CONFIG.
256 */
257 function gtagWrapper(command, idOrNameOrParams, gtagParams) {
258 return __awaiter(this, void 0, void 0, function () {
259 var e_3;
260 return __generator(this, function (_a) {
261 switch (_a.label) {
262 case 0:
263 _a.trys.push([0, 6, , 7]);
264 if (!(command === "event" /* EVENT */)) return [3 /*break*/, 2];
265 // If EVENT, second arg must be measurementId.
266 return [4 /*yield*/, gtagOnEvent(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, idOrNameOrParams, gtagParams)];
267 case 1:
268 // If EVENT, second arg must be measurementId.
269 _a.sent();
270 return [3 /*break*/, 5];
271 case 2:
272 if (!(command === "config" /* CONFIG */)) return [3 /*break*/, 4];
273 // If CONFIG, second arg must be measurementId.
274 return [4 /*yield*/, gtagOnConfig(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, idOrNameOrParams, gtagParams)];
275 case 3:
276 // If CONFIG, second arg must be measurementId.
277 _a.sent();
278 return [3 /*break*/, 5];
279 case 4:
280 if (command === "consent" /* CONSENT */) {
281 // If CONFIG, second arg must be measurementId.
282 gtagCore("consent" /* CONSENT */, 'update', gtagParams);
283 }
284 else {
285 // If SET, second arg must be params.
286 gtagCore("set" /* SET */, idOrNameOrParams);
287 }
288 _a.label = 5;
289 case 5: return [3 /*break*/, 7];
290 case 6:
291 e_3 = _a.sent();
292 logger.error(e_3);
293 return [3 /*break*/, 7];
294 case 7: return [2 /*return*/];
295 }
296 });
297 });
298 }
299 return gtagWrapper;
300}
301/**
302 * Creates global gtag function or wraps existing one if found.
303 * This wrapped function attaches Firebase instance ID (FID) to gtag 'config' and
304 * 'event' calls that belong to the GAID associated with this Firebase instance.
305 *
306 * @param initializationPromisesMap Map of appIds to their initialization promises.
307 * @param dynamicConfigPromisesList Array of dynamic config fetch promises.
308 * @param measurementIdToAppId Map of GA measurementIDs to corresponding Firebase appId.
309 * @param dataLayerName Name of global GA datalayer array.
310 * @param gtagFunctionName Name of global gtag function ("gtag" if not user-specified).
311 */
312function wrapOrCreateGtag(initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, dataLayerName, gtagFunctionName) {
313 // Create a basic core gtag function
314 var gtagCore = function () {
315 var _args = [];
316 for (var _i = 0; _i < arguments.length; _i++) {
317 _args[_i] = arguments[_i];
318 }
319 // Must push IArguments object, not an array.
320 window[dataLayerName].push(arguments);
321 };
322 // Replace it with existing one if found
323 if (window[gtagFunctionName] &&
324 typeof window[gtagFunctionName] === 'function') {
325 // @ts-ignore
326 gtagCore = window[gtagFunctionName];
327 }
328 window[gtagFunctionName] = wrapGtag(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId);
329 return {
330 gtagCore: gtagCore,
331 wrappedGtag: window[gtagFunctionName]
332 };
333}
334/**
335 * Returns first script tag in DOM matching our gtag url pattern.
336 */
337function findGtagScriptOnPage() {
338 var scriptTags = window.document.getElementsByTagName('script');
339 for (var _i = 0, _a = Object.values(scriptTags); _i < _a.length; _i++) {
340 var tag = _a[_i];
341 if (tag.src && tag.src.includes(GTAG_URL)) {
342 return tag;
343 }
344 }
345 return null;
346}
347
348/**
349 * @license
350 * Copyright 2019 Google LLC
351 *
352 * Licensed under the Apache License, Version 2.0 (the "License");
353 * you may not use this file except in compliance with the License.
354 * You may obtain a copy of the License at
355 *
356 * http://www.apache.org/licenses/LICENSE-2.0
357 *
358 * Unless required by applicable law or agreed to in writing, software
359 * distributed under the License is distributed on an "AS IS" BASIS,
360 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
361 * See the License for the specific language governing permissions and
362 * limitations under the License.
363 */
364var _a;
365var ERRORS = (_a = {},
366 _a["already-exists" /* ALREADY_EXISTS */] = 'A Firebase Analytics instance with the appId {$id} ' +
367 ' already exists. ' +
368 'Only one Firebase Analytics instance can be created for each appId.',
369 _a["already-initialized" /* ALREADY_INITIALIZED */] = 'initializeAnalytics() cannot be called again with different options than those ' +
370 'it was initially called with. It can be called again with the same options to ' +
371 'return the existing instance, or getAnalytics() can be used ' +
372 'to get a reference to the already-intialized instance.',
373 _a["already-initialized-settings" /* ALREADY_INITIALIZED_SETTINGS */] = 'Firebase Analytics has already been initialized.' +
374 'settings() must be called before initializing any Analytics instance' +
375 'or it will have no effect.',
376 _a["interop-component-reg-failed" /* INTEROP_COMPONENT_REG_FAILED */] = 'Firebase Analytics Interop Component failed to instantiate: {$reason}',
377 _a["invalid-analytics-context" /* INVALID_ANALYTICS_CONTEXT */] = 'Firebase Analytics is not supported in this environment. ' +
378 'Wrap initialization of analytics in analytics.isSupported() ' +
379 'to prevent initialization in unsupported environments. Details: {$errorInfo}',
380 _a["indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */] = 'IndexedDB unavailable or restricted in this environment. ' +
381 'Wrap initialization of analytics in analytics.isSupported() ' +
382 'to prevent initialization in unsupported environments. Details: {$errorInfo}',
383 _a["fetch-throttle" /* FETCH_THROTTLE */] = 'The config fetch request timed out while in an exponential backoff state.' +
384 ' Unix timestamp in milliseconds when fetch request throttling ends: {$throttleEndTimeMillis}.',
385 _a["config-fetch-failed" /* CONFIG_FETCH_FAILED */] = 'Dynamic config fetch failed: [{$httpStatus}] {$responseMessage}',
386 _a["no-api-key" /* NO_API_KEY */] = 'The "apiKey" field is empty in the local Firebase config. Firebase Analytics requires this field to' +
387 'contain a valid API key.',
388 _a["no-app-id" /* NO_APP_ID */] = 'The "appId" field is empty in the local Firebase config. Firebase Analytics requires this field to' +
389 'contain a valid app ID.',
390 _a);
391var ERROR_FACTORY = new ErrorFactory('analytics', 'Analytics', ERRORS);
392
393/**
394 * @license
395 * Copyright 2020 Google LLC
396 *
397 * Licensed under the Apache License, Version 2.0 (the "License");
398 * you may not use this file except in compliance with the License.
399 * You may obtain a copy of the License at
400 *
401 * http://www.apache.org/licenses/LICENSE-2.0
402 *
403 * Unless required by applicable law or agreed to in writing, software
404 * distributed under the License is distributed on an "AS IS" BASIS,
405 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
406 * See the License for the specific language governing permissions and
407 * limitations under the License.
408 */
409/**
410 * Backoff factor for 503 errors, which we want to be conservative about
411 * to avoid overloading servers. Each retry interval will be
412 * BASE_INTERVAL_MILLIS * LONG_RETRY_FACTOR ^ retryCount, so the second one
413 * will be ~30 seconds (with fuzzing).
414 */
415var LONG_RETRY_FACTOR = 30;
416/**
417 * Base wait interval to multiplied by backoffFactor^backoffCount.
418 */
419var BASE_INTERVAL_MILLIS = 1000;
420/**
421 * Stubbable retry data storage class.
422 */
423var RetryData = /** @class */ (function () {
424 function RetryData(throttleMetadata, intervalMillis) {
425 if (throttleMetadata === void 0) { throttleMetadata = {}; }
426 if (intervalMillis === void 0) { intervalMillis = BASE_INTERVAL_MILLIS; }
427 this.throttleMetadata = throttleMetadata;
428 this.intervalMillis = intervalMillis;
429 }
430 RetryData.prototype.getThrottleMetadata = function (appId) {
431 return this.throttleMetadata[appId];
432 };
433 RetryData.prototype.setThrottleMetadata = function (appId, metadata) {
434 this.throttleMetadata[appId] = metadata;
435 };
436 RetryData.prototype.deleteThrottleMetadata = function (appId) {
437 delete this.throttleMetadata[appId];
438 };
439 return RetryData;
440}());
441var defaultRetryData = new RetryData();
442/**
443 * Set GET request headers.
444 * @param apiKey App API key.
445 */
446function getHeaders(apiKey) {
447 return new Headers({
448 Accept: 'application/json',
449 'x-goog-api-key': apiKey
450 });
451}
452/**
453 * Fetches dynamic config from backend.
454 * @param app Firebase app to fetch config for.
455 */
456function fetchDynamicConfig(appFields) {
457 var _a;
458 return __awaiter(this, void 0, void 0, function () {
459 var appId, apiKey, request, appUrl, response, errorMessage, jsonResponse;
460 return __generator(this, function (_b) {
461 switch (_b.label) {
462 case 0:
463 appId = appFields.appId, apiKey = appFields.apiKey;
464 request = {
465 method: 'GET',
466 headers: getHeaders(apiKey)
467 };
468 appUrl = DYNAMIC_CONFIG_URL.replace('{app-id}', appId);
469 return [4 /*yield*/, fetch(appUrl, request)];
470 case 1:
471 response = _b.sent();
472 if (!(response.status !== 200 && response.status !== 304)) return [3 /*break*/, 6];
473 errorMessage = '';
474 _b.label = 2;
475 case 2:
476 _b.trys.push([2, 4, , 5]);
477 return [4 /*yield*/, response.json()];
478 case 3:
479 jsonResponse = (_b.sent());
480 if ((_a = jsonResponse.error) === null || _a === void 0 ? void 0 : _a.message) {
481 errorMessage = jsonResponse.error.message;
482 }
483 return [3 /*break*/, 5];
484 case 4:
485 _b.sent();
486 return [3 /*break*/, 5];
487 case 5: throw ERROR_FACTORY.create("config-fetch-failed" /* CONFIG_FETCH_FAILED */, {
488 httpStatus: response.status,
489 responseMessage: errorMessage
490 });
491 case 6: return [2 /*return*/, response.json()];
492 }
493 });
494 });
495}
496/**
497 * Fetches dynamic config from backend, retrying if failed.
498 * @param app Firebase app to fetch config for.
499 */
500function fetchDynamicConfigWithRetry(app,
501// retryData and timeoutMillis are parameterized to allow passing a different value for testing.
502retryData, timeoutMillis) {
503 if (retryData === void 0) { retryData = defaultRetryData; }
504 return __awaiter(this, void 0, void 0, function () {
505 var _a, appId, apiKey, measurementId, throttleMetadata, signal;
506 var _this = this;
507 return __generator(this, function (_b) {
508 _a = app.options, appId = _a.appId, apiKey = _a.apiKey, measurementId = _a.measurementId;
509 if (!appId) {
510 throw ERROR_FACTORY.create("no-app-id" /* NO_APP_ID */);
511 }
512 if (!apiKey) {
513 if (measurementId) {
514 return [2 /*return*/, {
515 measurementId: measurementId,
516 appId: appId
517 }];
518 }
519 throw ERROR_FACTORY.create("no-api-key" /* NO_API_KEY */);
520 }
521 throttleMetadata = retryData.getThrottleMetadata(appId) || {
522 backoffCount: 0,
523 throttleEndTimeMillis: Date.now()
524 };
525 signal = new AnalyticsAbortSignal();
526 setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
527 return __generator(this, function (_a) {
528 // Note a very low delay, eg < 10ms, can elapse before listeners are initialized.
529 signal.abort();
530 return [2 /*return*/];
531 });
532 }); }, timeoutMillis !== undefined ? timeoutMillis : FETCH_TIMEOUT_MILLIS);
533 return [2 /*return*/, attemptFetchDynamicConfigWithRetry({ appId: appId, apiKey: apiKey, measurementId: measurementId }, throttleMetadata, signal, retryData)];
534 });
535 });
536}
537/**
538 * Runs one retry attempt.
539 * @param appFields Necessary app config fields.
540 * @param throttleMetadata Ongoing metadata to determine throttling times.
541 * @param signal Abort signal.
542 */
543function attemptFetchDynamicConfigWithRetry(appFields, _a, signal, retryData // for testing
544) {
545 var _b, _c;
546 var throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount;
547 if (retryData === void 0) { retryData = defaultRetryData; }
548 return __awaiter(this, void 0, void 0, function () {
549 var appId, measurementId, e_1, response, e_2, error, backoffMillis, throttleMetadata;
550 return __generator(this, function (_d) {
551 switch (_d.label) {
552 case 0:
553 appId = appFields.appId, measurementId = appFields.measurementId;
554 _d.label = 1;
555 case 1:
556 _d.trys.push([1, 3, , 4]);
557 return [4 /*yield*/, setAbortableTimeout(signal, throttleEndTimeMillis)];
558 case 2:
559 _d.sent();
560 return [3 /*break*/, 4];
561 case 3:
562 e_1 = _d.sent();
563 if (measurementId) {
564 logger.warn("Timed out fetching this Firebase app's measurement ID from the server." +
565 (" Falling back to the measurement ID " + measurementId) +
566 (" provided in the \"measurementId\" field in the local Firebase config. [" + ((_b = e_1) === null || _b === void 0 ? void 0 : _b.message) + "]"));
567 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
568 }
569 throw e_1;
570 case 4:
571 _d.trys.push([4, 6, , 7]);
572 return [4 /*yield*/, fetchDynamicConfig(appFields)];
573 case 5:
574 response = _d.sent();
575 // Note the SDK only clears throttle state if response is success or non-retriable.
576 retryData.deleteThrottleMetadata(appId);
577 return [2 /*return*/, response];
578 case 6:
579 e_2 = _d.sent();
580 error = e_2;
581 if (!isRetriableError(error)) {
582 retryData.deleteThrottleMetadata(appId);
583 if (measurementId) {
584 logger.warn("Failed to fetch this Firebase app's measurement ID from the server." +
585 (" Falling back to the measurement ID " + measurementId) +
586 (" provided in the \"measurementId\" field in the local Firebase config. [" + (error === null || error === void 0 ? void 0 : error.message) + "]"));
587 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
588 }
589 else {
590 throw e_2;
591 }
592 }
593 backoffMillis = Number((_c = error === null || error === void 0 ? void 0 : error.customData) === null || _c === void 0 ? void 0 : _c.httpStatus) === 503
594 ? calculateBackoffMillis(backoffCount, retryData.intervalMillis, LONG_RETRY_FACTOR)
595 : calculateBackoffMillis(backoffCount, retryData.intervalMillis);
596 throttleMetadata = {
597 throttleEndTimeMillis: Date.now() + backoffMillis,
598 backoffCount: backoffCount + 1
599 };
600 // Persists state.
601 retryData.setThrottleMetadata(appId, throttleMetadata);
602 logger.debug("Calling attemptFetch again in " + backoffMillis + " millis");
603 return [2 /*return*/, attemptFetchDynamicConfigWithRetry(appFields, throttleMetadata, signal, retryData)];
604 case 7: return [2 /*return*/];
605 }
606 });
607 });
608}
609/**
610 * Supports waiting on a backoff by:
611 *
612 * <ul>
613 * <li>Promisifying setTimeout, so we can set a timeout in our Promise chain</li>
614 * <li>Listening on a signal bus for abort events, just like the Fetch API</li>
615 * <li>Failing in the same way the Fetch API fails, so timing out a live request and a throttled
616 * request appear the same.</li>
617 * </ul>
618 *
619 * <p>Visible for testing.
620 */
621function setAbortableTimeout(signal, throttleEndTimeMillis) {
622 return new Promise(function (resolve, reject) {
623 // Derives backoff from given end time, normalizing negative numbers to zero.
624 var backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0);
625 var timeout = setTimeout(resolve, backoffMillis);
626 // Adds listener, rather than sets onabort, because signal is a shared object.
627 signal.addEventListener(function () {
628 clearTimeout(timeout);
629 // If the request completes before this timeout, the rejection has no effect.
630 reject(ERROR_FACTORY.create("fetch-throttle" /* FETCH_THROTTLE */, {
631 throttleEndTimeMillis: throttleEndTimeMillis
632 }));
633 });
634 });
635}
636/**
637 * Returns true if the {@link Error} indicates a fetch request may succeed later.
638 */
639function isRetriableError(e) {
640 if (!(e instanceof FirebaseError) || !e.customData) {
641 return false;
642 }
643 // Uses string index defined by ErrorData, which FirebaseError implements.
644 var httpStatus = Number(e.customData['httpStatus']);
645 return (httpStatus === 429 ||
646 httpStatus === 500 ||
647 httpStatus === 503 ||
648 httpStatus === 504);
649}
650/**
651 * Shims a minimal AbortSignal (copied from Remote Config).
652 *
653 * <p>AbortController's AbortSignal conveniently decouples fetch timeout logic from other aspects
654 * of networking, such as retries. Firebase doesn't use AbortController enough to justify a
655 * polyfill recommendation, like we do with the Fetch API, but this minimal shim can easily be
656 * swapped out if/when we do.
657 */
658var AnalyticsAbortSignal = /** @class */ (function () {
659 function AnalyticsAbortSignal() {
660 this.listeners = [];
661 }
662 AnalyticsAbortSignal.prototype.addEventListener = function (listener) {
663 this.listeners.push(listener);
664 };
665 AnalyticsAbortSignal.prototype.abort = function () {
666 this.listeners.forEach(function (listener) { return listener(); });
667 };
668 return AnalyticsAbortSignal;
669}());
670
671/**
672 * @license
673 * Copyright 2019 Google LLC
674 *
675 * Licensed under the Apache License, Version 2.0 (the "License");
676 * you may not use this file except in compliance with the License.
677 * You may obtain a copy of the License at
678 *
679 * http://www.apache.org/licenses/LICENSE-2.0
680 *
681 * Unless required by applicable law or agreed to in writing, software
682 * distributed under the License is distributed on an "AS IS" BASIS,
683 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
684 * See the License for the specific language governing permissions and
685 * limitations under the License.
686 */
687/**
688 * Event parameters to set on 'gtag' during initialization.
689 */
690var defaultEventParametersForInit;
691/**
692 * Logs an analytics event through the Firebase SDK.
693 *
694 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
695 * @param eventName Google Analytics event name, choose from standard list or use a custom string.
696 * @param eventParams Analytics event parameters.
697 */
698function logEvent$1(gtagFunction, initializationPromise, eventName, eventParams, options) {
699 return __awaiter(this, void 0, void 0, function () {
700 var measurementId, params;
701 return __generator(this, function (_a) {
702 switch (_a.label) {
703 case 0:
704 if (!(options && options.global)) return [3 /*break*/, 1];
705 gtagFunction("event" /* EVENT */, eventName, eventParams);
706 return [2 /*return*/];
707 case 1: return [4 /*yield*/, initializationPromise];
708 case 2:
709 measurementId = _a.sent();
710 params = __assign(__assign({}, eventParams), { 'send_to': measurementId });
711 gtagFunction("event" /* EVENT */, eventName, params);
712 _a.label = 3;
713 case 3: return [2 /*return*/];
714 }
715 });
716 });
717}
718/**
719 * Set screen_name parameter for this Google Analytics ID.
720 *
721 * @deprecated Use {@link logEvent} with `eventName` as 'screen_view' and add relevant `eventParams`.
722 * See {@link https://firebase.google.com/docs/analytics/screenviews | Track Screenviews}.
723 *
724 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
725 * @param screenName Screen name string to set.
726 */
727function setCurrentScreen$1(gtagFunction, initializationPromise, screenName, options) {
728 return __awaiter(this, void 0, void 0, function () {
729 var measurementId;
730 return __generator(this, function (_a) {
731 switch (_a.label) {
732 case 0:
733 if (!(options && options.global)) return [3 /*break*/, 1];
734 gtagFunction("set" /* SET */, { 'screen_name': screenName });
735 return [2 /*return*/, Promise.resolve()];
736 case 1: return [4 /*yield*/, initializationPromise];
737 case 2:
738 measurementId = _a.sent();
739 gtagFunction("config" /* CONFIG */, measurementId, {
740 update: true,
741 'screen_name': screenName
742 });
743 _a.label = 3;
744 case 3: return [2 /*return*/];
745 }
746 });
747 });
748}
749/**
750 * Set user_id parameter for this Google Analytics ID.
751 *
752 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
753 * @param id User ID string to set
754 */
755function setUserId$1(gtagFunction, initializationPromise, id, options) {
756 return __awaiter(this, void 0, void 0, function () {
757 var measurementId;
758 return __generator(this, function (_a) {
759 switch (_a.label) {
760 case 0:
761 if (!(options && options.global)) return [3 /*break*/, 1];
762 gtagFunction("set" /* SET */, { 'user_id': id });
763 return [2 /*return*/, Promise.resolve()];
764 case 1: return [4 /*yield*/, initializationPromise];
765 case 2:
766 measurementId = _a.sent();
767 gtagFunction("config" /* CONFIG */, measurementId, {
768 update: true,
769 'user_id': id
770 });
771 _a.label = 3;
772 case 3: return [2 /*return*/];
773 }
774 });
775 });
776}
777/**
778 * Set all other user properties other than user_id and screen_name.
779 *
780 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
781 * @param properties Map of user properties to set
782 */
783function setUserProperties$1(gtagFunction, initializationPromise, properties, options) {
784 return __awaiter(this, void 0, void 0, function () {
785 var flatProperties, _i, _a, key, measurementId;
786 return __generator(this, function (_b) {
787 switch (_b.label) {
788 case 0:
789 if (!(options && options.global)) return [3 /*break*/, 1];
790 flatProperties = {};
791 for (_i = 0, _a = Object.keys(properties); _i < _a.length; _i++) {
792 key = _a[_i];
793 // use dot notation for merge behavior in gtag.js
794 flatProperties["user_properties." + key] = properties[key];
795 }
796 gtagFunction("set" /* SET */, flatProperties);
797 return [2 /*return*/, Promise.resolve()];
798 case 1: return [4 /*yield*/, initializationPromise];
799 case 2:
800 measurementId = _b.sent();
801 gtagFunction("config" /* CONFIG */, measurementId, {
802 update: true,
803 'user_properties': properties
804 });
805 _b.label = 3;
806 case 3: return [2 /*return*/];
807 }
808 });
809 });
810}
811/**
812 * Set whether collection is enabled for this ID.
813 *
814 * @param enabled If true, collection is enabled for this ID.
815 */
816function setAnalyticsCollectionEnabled$1(initializationPromise, enabled) {
817 return __awaiter(this, void 0, void 0, function () {
818 var measurementId;
819 return __generator(this, function (_a) {
820 switch (_a.label) {
821 case 0: return [4 /*yield*/, initializationPromise];
822 case 1:
823 measurementId = _a.sent();
824 window["ga-disable-" + measurementId] = !enabled;
825 return [2 /*return*/];
826 }
827 });
828 });
829}
830/**
831 * Consent parameters to default to during 'gtag' initialization.
832 */
833var defaultConsentSettingsForInit;
834/**
835 * Sets the variable {@link defaultConsentSettingsForInit} for use in the initialization of
836 * analytics.
837 *
838 * @param consentSettings Maps the applicable end user consent state for gtag.js.
839 */
840function _setConsentDefaultForInit(consentSettings) {
841 defaultConsentSettingsForInit = consentSettings;
842}
843/**
844 * Sets the variable `defaultEventParametersForInit` for use in the initialization of
845 * analytics.
846 *
847 * @param customParams Any custom params the user may pass to gtag.js.
848 */
849function _setDefaultEventParametersForInit(customParams) {
850 defaultEventParametersForInit = customParams;
851}
852
853/**
854 * @license
855 * Copyright 2020 Google LLC
856 *
857 * Licensed under the Apache License, Version 2.0 (the "License");
858 * you may not use this file except in compliance with the License.
859 * You may obtain a copy of the License at
860 *
861 * http://www.apache.org/licenses/LICENSE-2.0
862 *
863 * Unless required by applicable law or agreed to in writing, software
864 * distributed under the License is distributed on an "AS IS" BASIS,
865 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
866 * See the License for the specific language governing permissions and
867 * limitations under the License.
868 */
869function validateIndexedDB() {
870 var _a;
871 return __awaiter(this, void 0, void 0, function () {
872 var e_1;
873 return __generator(this, function (_b) {
874 switch (_b.label) {
875 case 0:
876 if (!!isIndexedDBAvailable()) return [3 /*break*/, 1];
877 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
878 errorInfo: 'IndexedDB is not available in this environment.'
879 }).message);
880 return [2 /*return*/, false];
881 case 1:
882 _b.trys.push([1, 3, , 4]);
883 return [4 /*yield*/, validateIndexedDBOpenable()];
884 case 2:
885 _b.sent();
886 return [3 /*break*/, 4];
887 case 3:
888 e_1 = _b.sent();
889 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
890 errorInfo: (_a = e_1) === null || _a === void 0 ? void 0 : _a.toString()
891 }).message);
892 return [2 /*return*/, false];
893 case 4: return [2 /*return*/, true];
894 }
895 });
896 });
897}
898/**
899 * Initialize the analytics instance in gtag.js by calling config command with fid.
900 *
901 * NOTE: We combine analytics initialization and setting fid together because we want fid to be
902 * part of the `page_view` event that's sent during the initialization
903 * @param app Firebase app
904 * @param gtagCore The gtag function that's not wrapped.
905 * @param dynamicConfigPromisesList Array of all dynamic config promises.
906 * @param measurementIdToAppId Maps measurementID to appID.
907 * @param installations _FirebaseInstallationsInternal instance.
908 *
909 * @returns Measurement ID.
910 */
911function _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCore, dataLayerName, options) {
912 var _a;
913 return __awaiter(this, void 0, void 0, function () {
914 var dynamicConfigPromise, fidPromise, _b, dynamicConfig, fid, configProperties;
915 return __generator(this, function (_c) {
916 switch (_c.label) {
917 case 0:
918 dynamicConfigPromise = fetchDynamicConfigWithRetry(app);
919 // Once fetched, map measurementIds to appId, for ease of lookup in wrapped gtag function.
920 dynamicConfigPromise
921 .then(function (config) {
922 measurementIdToAppId[config.measurementId] = config.appId;
923 if (app.options.measurementId &&
924 config.measurementId !== app.options.measurementId) {
925 logger.warn("The measurement ID in the local Firebase config (" + app.options.measurementId + ")" +
926 (" does not match the measurement ID fetched from the server (" + config.measurementId + ").") +
927 " To ensure analytics events are always sent to the correct Analytics property," +
928 " update the" +
929 " measurement ID field in the local config or remove it from the local config.");
930 }
931 })
932 .catch(function (e) { return logger.error(e); });
933 // Add to list to track state of all dynamic config promises.
934 dynamicConfigPromisesList.push(dynamicConfigPromise);
935 fidPromise = validateIndexedDB().then(function (envIsValid) {
936 if (envIsValid) {
937 return installations.getId();
938 }
939 else {
940 return undefined;
941 }
942 });
943 return [4 /*yield*/, Promise.all([
944 dynamicConfigPromise,
945 fidPromise
946 ])];
947 case 1:
948 _b = _c.sent(), dynamicConfig = _b[0], fid = _b[1];
949 // Detect if user has already put the gtag <script> tag on this page.
950 if (!findGtagScriptOnPage()) {
951 insertScriptTag(dataLayerName, dynamicConfig.measurementId);
952 }
953 // Detects if there are consent settings that need to be configured.
954 if (defaultConsentSettingsForInit) {
955 gtagCore("consent" /* CONSENT */, 'default', defaultConsentSettingsForInit);
956 _setConsentDefaultForInit(undefined);
957 }
958 // This command initializes gtag.js and only needs to be called once for the entire web app,
959 // but since it is idempotent, we can call it multiple times.
960 // We keep it together with other initialization logic for better code structure.
961 // eslint-disable-next-line @typescript-eslint/no-explicit-any
962 gtagCore('js', new Date());
963 configProperties = (_a = options === null || options === void 0 ? void 0 : options.config) !== null && _a !== void 0 ? _a : {};
964 // guard against developers accidentally setting properties with prefix `firebase_`
965 configProperties[ORIGIN_KEY] = 'firebase';
966 configProperties.update = true;
967 if (fid != null) {
968 configProperties[GA_FID_KEY] = fid;
969 }
970 // It should be the first config command called on this GA-ID
971 // Initialize this GA-ID and set FID on it using the gtag config API.
972 // Note: This will trigger a page_view event unless 'send_page_view' is set to false in
973 // `configProperties`.
974 gtagCore("config" /* CONFIG */, dynamicConfig.measurementId, configProperties);
975 // Detects if there is data that will be set on every event logged from the SDK.
976 if (defaultEventParametersForInit) {
977 gtagCore("set" /* SET */, defaultEventParametersForInit);
978 _setDefaultEventParametersForInit(undefined);
979 }
980 return [2 /*return*/, dynamicConfig.measurementId];
981 }
982 });
983 });
984}
985
986/**
987 * @license
988 * Copyright 2019 Google LLC
989 *
990 * Licensed under the Apache License, Version 2.0 (the "License");
991 * you may not use this file except in compliance with the License.
992 * You may obtain a copy of the License at
993 *
994 * http://www.apache.org/licenses/LICENSE-2.0
995 *
996 * Unless required by applicable law or agreed to in writing, software
997 * distributed under the License is distributed on an "AS IS" BASIS,
998 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
999 * See the License for the specific language governing permissions and
1000 * limitations under the License.
1001 */
1002/**
1003 * Analytics Service class.
1004 */
1005var AnalyticsService = /** @class */ (function () {
1006 function AnalyticsService(app) {
1007 this.app = app;
1008 }
1009 AnalyticsService.prototype._delete = function () {
1010 delete initializationPromisesMap[this.app.options.appId];
1011 return Promise.resolve();
1012 };
1013 return AnalyticsService;
1014}());
1015/**
1016 * Maps appId to full initialization promise. Wrapped gtag calls must wait on
1017 * all or some of these, depending on the call's `send_to` param and the status
1018 * of the dynamic config fetches (see below).
1019 */
1020var initializationPromisesMap = {};
1021/**
1022 * List of dynamic config fetch promises. In certain cases, wrapped gtag calls
1023 * wait on all these to be complete in order to determine if it can selectively
1024 * wait for only certain initialization (FID) promises or if it must wait for all.
1025 */
1026var dynamicConfigPromisesList = [];
1027/**
1028 * Maps fetched measurementIds to appId. Populated when the app's dynamic config
1029 * fetch completes. If already populated, gtag config calls can use this to
1030 * selectively wait for only this app's initialization promise (FID) instead of all
1031 * initialization promises.
1032 */
1033var measurementIdToAppId = {};
1034/**
1035 * Name for window global data layer array used by GA: defaults to 'dataLayer'.
1036 */
1037var dataLayerName = 'dataLayer';
1038/**
1039 * Name for window global gtag function used by GA: defaults to 'gtag'.
1040 */
1041var gtagName = 'gtag';
1042/**
1043 * Reproduction of standard gtag function or reference to existing
1044 * gtag function on window object.
1045 */
1046var gtagCoreFunction;
1047/**
1048 * Wrapper around gtag function that ensures FID is sent with all
1049 * relevant event and config calls.
1050 */
1051var wrappedGtagFunction;
1052/**
1053 * Flag to ensure page initialization steps (creation or wrapping of
1054 * dataLayer and gtag script) are only run once per page load.
1055 */
1056var globalInitDone = false;
1057/**
1058 * Configures Firebase Analytics to use custom `gtag` or `dataLayer` names.
1059 * Intended to be used if `gtag.js` script has been installed on
1060 * this page independently of Firebase Analytics, and is using non-default
1061 * names for either the `gtag` function or for `dataLayer`.
1062 * Must be called before calling `getAnalytics()` or it won't
1063 * have any effect.
1064 *
1065 * @public
1066 *
1067 * @param options - Custom gtag and dataLayer names.
1068 */
1069function settings(options) {
1070 if (globalInitDone) {
1071 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
1072 }
1073 if (options.dataLayerName) {
1074 dataLayerName = options.dataLayerName;
1075 }
1076 if (options.gtagName) {
1077 gtagName = options.gtagName;
1078 }
1079}
1080/**
1081 * Returns true if no environment mismatch is found.
1082 * If environment mismatches are found, throws an INVALID_ANALYTICS_CONTEXT
1083 * error that also lists details for each mismatch found.
1084 */
1085function warnOnBrowserContextMismatch() {
1086 var mismatchedEnvMessages = [];
1087 if (isBrowserExtension()) {
1088 mismatchedEnvMessages.push('This is a browser extension environment.');
1089 }
1090 if (!areCookiesEnabled()) {
1091 mismatchedEnvMessages.push('Cookies are not available.');
1092 }
1093 if (mismatchedEnvMessages.length > 0) {
1094 var details = mismatchedEnvMessages
1095 .map(function (message, index) { return "(" + (index + 1) + ") " + message; })
1096 .join(' ');
1097 var err = ERROR_FACTORY.create("invalid-analytics-context" /* INVALID_ANALYTICS_CONTEXT */, {
1098 errorInfo: details
1099 });
1100 logger.warn(err.message);
1101 }
1102}
1103/**
1104 * Analytics instance factory.
1105 * @internal
1106 */
1107function factory(app, installations, options) {
1108 warnOnBrowserContextMismatch();
1109 var appId = app.options.appId;
1110 if (!appId) {
1111 throw ERROR_FACTORY.create("no-app-id" /* NO_APP_ID */);
1112 }
1113 if (!app.options.apiKey) {
1114 if (app.options.measurementId) {
1115 logger.warn("The \"apiKey\" field is empty in the local Firebase config. This is needed to fetch the latest" +
1116 (" measurement ID for this Firebase app. Falling back to the measurement ID " + app.options.measurementId) +
1117 " provided in the \"measurementId\" field in the local Firebase config.");
1118 }
1119 else {
1120 throw ERROR_FACTORY.create("no-api-key" /* NO_API_KEY */);
1121 }
1122 }
1123 if (initializationPromisesMap[appId] != null) {
1124 throw ERROR_FACTORY.create("already-exists" /* ALREADY_EXISTS */, {
1125 id: appId
1126 });
1127 }
1128 if (!globalInitDone) {
1129 // Steps here should only be done once per page: creation or wrapping
1130 // of dataLayer and global gtag function.
1131 getOrCreateDataLayer(dataLayerName);
1132 var _a = wrapOrCreateGtag(initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, dataLayerName, gtagName), wrappedGtag = _a.wrappedGtag, gtagCore = _a.gtagCore;
1133 wrappedGtagFunction = wrappedGtag;
1134 gtagCoreFunction = gtagCore;
1135 globalInitDone = true;
1136 }
1137 // Async but non-blocking.
1138 // This map reflects the completion state of all promises for each appId.
1139 initializationPromisesMap[appId] = _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCoreFunction, dataLayerName, options);
1140 var analyticsInstance = new AnalyticsService(app);
1141 return analyticsInstance;
1142}
1143
1144/* eslint-disable @typescript-eslint/no-explicit-any */
1145/**
1146 * Returns an {@link Analytics} instance for the given app.
1147 *
1148 * @public
1149 *
1150 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1151 */
1152function getAnalytics(app) {
1153 if (app === void 0) { app = getApp(); }
1154 app = getModularInstance(app);
1155 // Dependencies
1156 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1157 if (analyticsProvider.isInitialized()) {
1158 return analyticsProvider.getImmediate();
1159 }
1160 return initializeAnalytics(app);
1161}
1162/**
1163 * Returns an {@link Analytics} instance for the given app.
1164 *
1165 * @public
1166 *
1167 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1168 */
1169function initializeAnalytics(app, options) {
1170 if (options === void 0) { options = {}; }
1171 // Dependencies
1172 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1173 if (analyticsProvider.isInitialized()) {
1174 var existingInstance = analyticsProvider.getImmediate();
1175 if (deepEqual(options, analyticsProvider.getOptions())) {
1176 return existingInstance;
1177 }
1178 else {
1179 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
1180 }
1181 }
1182 var analyticsInstance = analyticsProvider.initialize({ options: options });
1183 return analyticsInstance;
1184}
1185/**
1186 * This is a public static method provided to users that wraps four different checks:
1187 *
1188 * 1. Check if it's not a browser extension environment.
1189 * 2. Check if cookies are enabled in current browser.
1190 * 3. Check if IndexedDB is supported by the browser environment.
1191 * 4. Check if the current browser context is valid for using `IndexedDB.open()`.
1192 *
1193 * @public
1194 *
1195 */
1196function isSupported() {
1197 return __awaiter(this, void 0, void 0, function () {
1198 var isDBOpenable;
1199 return __generator(this, function (_a) {
1200 switch (_a.label) {
1201 case 0:
1202 if (isBrowserExtension()) {
1203 return [2 /*return*/, false];
1204 }
1205 if (!areCookiesEnabled()) {
1206 return [2 /*return*/, false];
1207 }
1208 if (!isIndexedDBAvailable()) {
1209 return [2 /*return*/, false];
1210 }
1211 _a.label = 1;
1212 case 1:
1213 _a.trys.push([1, 3, , 4]);
1214 return [4 /*yield*/, validateIndexedDBOpenable()];
1215 case 2:
1216 isDBOpenable = _a.sent();
1217 return [2 /*return*/, isDBOpenable];
1218 case 3:
1219 _a.sent();
1220 return [2 /*return*/, false];
1221 case 4: return [2 /*return*/];
1222 }
1223 });
1224 });
1225}
1226/**
1227 * Use gtag `config` command to set `screen_name`.
1228 *
1229 * @public
1230 *
1231 * @deprecated Use {@link logEvent} with `eventName` as 'screen_view' and add relevant `eventParams`.
1232 * See {@link https://firebase.google.com/docs/analytics/screenviews | Track Screenviews}.
1233 *
1234 * @param analyticsInstance - The {@link Analytics} instance.
1235 * @param screenName - Screen name to set.
1236 */
1237function setCurrentScreen(analyticsInstance, screenName, options) {
1238 analyticsInstance = getModularInstance(analyticsInstance);
1239 setCurrentScreen$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], screenName, options).catch(function (e) { return logger.error(e); });
1240}
1241/**
1242 * Use gtag `config` command to set `user_id`.
1243 *
1244 * @public
1245 *
1246 * @param analyticsInstance - The {@link Analytics} instance.
1247 * @param id - User ID to set.
1248 */
1249function setUserId(analyticsInstance, id, options) {
1250 analyticsInstance = getModularInstance(analyticsInstance);
1251 setUserId$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], id, options).catch(function (e) { return logger.error(e); });
1252}
1253/**
1254 * Use gtag `config` command to set all params specified.
1255 *
1256 * @public
1257 */
1258function setUserProperties(analyticsInstance, properties, options) {
1259 analyticsInstance = getModularInstance(analyticsInstance);
1260 setUserProperties$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], properties, options).catch(function (e) { return logger.error(e); });
1261}
1262/**
1263 * Sets whether Google Analytics collection is enabled for this app on this device.
1264 * Sets global `window['ga-disable-analyticsId'] = true;`
1265 *
1266 * @public
1267 *
1268 * @param analyticsInstance - The {@link Analytics} instance.
1269 * @param enabled - If true, enables collection, if false, disables it.
1270 */
1271function setAnalyticsCollectionEnabled(analyticsInstance, enabled) {
1272 analyticsInstance = getModularInstance(analyticsInstance);
1273 setAnalyticsCollectionEnabled$1(initializationPromisesMap[analyticsInstance.app.options.appId], enabled).catch(function (e) { return logger.error(e); });
1274}
1275/**
1276 * Adds data that will be set on every event logged from the SDK, including automatic ones.
1277 * With gtag's "set" command, the values passed persist on the current page and are passed with
1278 * all subsequent events.
1279 * @public
1280 * @param customParams - Any custom params the user may pass to gtag.js.
1281 */
1282function setDefaultEventParameters(customParams) {
1283 // Check if reference to existing gtag function on window object exists
1284 if (wrappedGtagFunction) {
1285 wrappedGtagFunction("set" /* SET */, customParams);
1286 }
1287 else {
1288 _setDefaultEventParametersForInit(customParams);
1289 }
1290}
1291/**
1292 * Sends a Google Analytics event with given `eventParams`. This method
1293 * automatically associates this logged event with this Firebase web
1294 * app instance on this device.
1295 * List of official event parameters can be found in the gtag.js
1296 * reference documentation:
1297 * {@link https://developers.google.com/gtagjs/reference/ga4-events
1298 * | the GA4 reference documentation}.
1299 *
1300 * @public
1301 */
1302function logEvent(analyticsInstance, eventName, eventParams, options) {
1303 analyticsInstance = getModularInstance(analyticsInstance);
1304 logEvent$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], eventName, eventParams, options).catch(function (e) { return logger.error(e); });
1305}
1306/**
1307 * Sets the applicable end user consent state for this web app across all gtag references once
1308 * Firebase Analytics is initialized.
1309 *
1310 * Use the {@link ConsentSettings} to specify individual consent type values. By default consent
1311 * types are set to "granted".
1312 * @public
1313 * @param consentSettings - Maps the applicable end user consent state for gtag.js.
1314 */
1315function setConsent(consentSettings) {
1316 // Check if reference to existing gtag function on window object exists
1317 if (wrappedGtagFunction) {
1318 wrappedGtagFunction("consent" /* CONSENT */, 'update', consentSettings);
1319 }
1320 else {
1321 _setConsentDefaultForInit(consentSettings);
1322 }
1323}
1324
1325var name = "@firebase/analytics";
1326var version = "0.8.0";
1327
1328/**
1329 * Firebase Analytics
1330 *
1331 * @packageDocumentation
1332 */
1333function registerAnalytics() {
1334 _registerComponent(new Component(ANALYTICS_TYPE, function (container, _a) {
1335 var analyticsOptions = _a.options;
1336 // getImmediate for FirebaseApp will always succeed
1337 var app = container.getProvider('app').getImmediate();
1338 var installations = container
1339 .getProvider('installations-internal')
1340 .getImmediate();
1341 return factory(app, installations, analyticsOptions);
1342 }, "PUBLIC" /* PUBLIC */));
1343 _registerComponent(new Component('analytics-internal', internalFactory, "PRIVATE" /* PRIVATE */));
1344 registerVersion(name, version);
1345 // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
1346 registerVersion(name, version, 'esm5');
1347 function internalFactory(container) {
1348 try {
1349 var analytics_1 = container.getProvider(ANALYTICS_TYPE).getImmediate();
1350 return {
1351 logEvent: function (eventName, eventParams, options) { return logEvent(analytics_1, eventName, eventParams, options); }
1352 };
1353 }
1354 catch (e) {
1355 throw ERROR_FACTORY.create("interop-component-reg-failed" /* INTEROP_COMPONENT_REG_FAILED */, {
1356 reason: e
1357 });
1358 }
1359 }
1360}
1361registerAnalytics();
1362
1363export { getAnalytics, initializeAnalytics, isSupported, logEvent, setAnalyticsCollectionEnabled, setConsent, setCurrentScreen, setDefaultEventParameters, setUserId, setUserProperties, settings };
1364//# sourceMappingURL=index.esm.js.map