UNPKG

58.4 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 SET, second arg must be params.
281 gtagCore("set" /* SET */, idOrNameOrParams);
282 _a.label = 5;
283 case 5: return [3 /*break*/, 7];
284 case 6:
285 e_3 = _a.sent();
286 logger.error(e_3);
287 return [3 /*break*/, 7];
288 case 7: return [2 /*return*/];
289 }
290 });
291 });
292 }
293 return gtagWrapper;
294}
295/**
296 * Creates global gtag function or wraps existing one if found.
297 * This wrapped function attaches Firebase instance ID (FID) to gtag 'config' and
298 * 'event' calls that belong to the GAID associated with this Firebase instance.
299 *
300 * @param initializationPromisesMap Map of appIds to their initialization promises.
301 * @param dynamicConfigPromisesList Array of dynamic config fetch promises.
302 * @param measurementIdToAppId Map of GA measurementIDs to corresponding Firebase appId.
303 * @param dataLayerName Name of global GA datalayer array.
304 * @param gtagFunctionName Name of global gtag function ("gtag" if not user-specified).
305 */
306function wrapOrCreateGtag(initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, dataLayerName, gtagFunctionName) {
307 // Create a basic core gtag function
308 var gtagCore = function () {
309 var _args = [];
310 for (var _i = 0; _i < arguments.length; _i++) {
311 _args[_i] = arguments[_i];
312 }
313 // Must push IArguments object, not an array.
314 window[dataLayerName].push(arguments);
315 };
316 // Replace it with existing one if found
317 if (window[gtagFunctionName] &&
318 typeof window[gtagFunctionName] === 'function') {
319 // @ts-ignore
320 gtagCore = window[gtagFunctionName];
321 }
322 window[gtagFunctionName] = wrapGtag(gtagCore, initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId);
323 return {
324 gtagCore: gtagCore,
325 wrappedGtag: window[gtagFunctionName]
326 };
327}
328/**
329 * Returns first script tag in DOM matching our gtag url pattern.
330 */
331function findGtagScriptOnPage() {
332 var scriptTags = window.document.getElementsByTagName('script');
333 for (var _i = 0, _a = Object.values(scriptTags); _i < _a.length; _i++) {
334 var tag = _a[_i];
335 if (tag.src && tag.src.includes(GTAG_URL)) {
336 return tag;
337 }
338 }
339 return null;
340}
341
342/**
343 * @license
344 * Copyright 2019 Google LLC
345 *
346 * Licensed under the Apache License, Version 2.0 (the "License");
347 * you may not use this file except in compliance with the License.
348 * You may obtain a copy of the License at
349 *
350 * http://www.apache.org/licenses/LICENSE-2.0
351 *
352 * Unless required by applicable law or agreed to in writing, software
353 * distributed under the License is distributed on an "AS IS" BASIS,
354 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
355 * See the License for the specific language governing permissions and
356 * limitations under the License.
357 */
358var _a;
359var ERRORS = (_a = {},
360 _a["already-exists" /* ALREADY_EXISTS */] = 'A Firebase Analytics instance with the appId {$id} ' +
361 ' already exists. ' +
362 'Only one Firebase Analytics instance can be created for each appId.',
363 _a["already-initialized" /* ALREADY_INITIALIZED */] = 'initializeAnalytics() cannot be called again with different options than those ' +
364 'it was initially called with. It can be called again with the same options to ' +
365 'return the existing instance, or getAnalytics() can be used ' +
366 'to get a reference to the already-intialized instance.',
367 _a["already-initialized-settings" /* ALREADY_INITIALIZED_SETTINGS */] = 'Firebase Analytics has already been initialized.' +
368 'settings() must be called before initializing any Analytics instance' +
369 'or it will have no effect.',
370 _a["interop-component-reg-failed" /* INTEROP_COMPONENT_REG_FAILED */] = 'Firebase Analytics Interop Component failed to instantiate: {$reason}',
371 _a["invalid-analytics-context" /* INVALID_ANALYTICS_CONTEXT */] = 'Firebase Analytics is not supported in this environment. ' +
372 'Wrap initialization of analytics in analytics.isSupported() ' +
373 'to prevent initialization in unsupported environments. Details: {$errorInfo}',
374 _a["indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */] = 'IndexedDB unavailable or restricted in this environment. ' +
375 'Wrap initialization of analytics in analytics.isSupported() ' +
376 'to prevent initialization in unsupported environments. Details: {$errorInfo}',
377 _a["fetch-throttle" /* FETCH_THROTTLE */] = 'The config fetch request timed out while in an exponential backoff state.' +
378 ' Unix timestamp in milliseconds when fetch request throttling ends: {$throttleEndTimeMillis}.',
379 _a["config-fetch-failed" /* CONFIG_FETCH_FAILED */] = 'Dynamic config fetch failed: [{$httpStatus}] {$responseMessage}',
380 _a["no-api-key" /* NO_API_KEY */] = 'The "apiKey" field is empty in the local Firebase config. Firebase Analytics requires this field to' +
381 'contain a valid API key.',
382 _a["no-app-id" /* NO_APP_ID */] = 'The "appId" field is empty in the local Firebase config. Firebase Analytics requires this field to' +
383 'contain a valid app ID.',
384 _a);
385var ERROR_FACTORY = new ErrorFactory('analytics', 'Analytics', ERRORS);
386
387/**
388 * @license
389 * Copyright 2020 Google LLC
390 *
391 * Licensed under the Apache License, Version 2.0 (the "License");
392 * you may not use this file except in compliance with the License.
393 * You may obtain a copy of the License at
394 *
395 * http://www.apache.org/licenses/LICENSE-2.0
396 *
397 * Unless required by applicable law or agreed to in writing, software
398 * distributed under the License is distributed on an "AS IS" BASIS,
399 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
400 * See the License for the specific language governing permissions and
401 * limitations under the License.
402 */
403/**
404 * Backoff factor for 503 errors, which we want to be conservative about
405 * to avoid overloading servers. Each retry interval will be
406 * BASE_INTERVAL_MILLIS * LONG_RETRY_FACTOR ^ retryCount, so the second one
407 * will be ~30 seconds (with fuzzing).
408 */
409var LONG_RETRY_FACTOR = 30;
410/**
411 * Base wait interval to multiplied by backoffFactor^backoffCount.
412 */
413var BASE_INTERVAL_MILLIS = 1000;
414/**
415 * Stubbable retry data storage class.
416 */
417var RetryData = /** @class */ (function () {
418 function RetryData(throttleMetadata, intervalMillis) {
419 if (throttleMetadata === void 0) { throttleMetadata = {}; }
420 if (intervalMillis === void 0) { intervalMillis = BASE_INTERVAL_MILLIS; }
421 this.throttleMetadata = throttleMetadata;
422 this.intervalMillis = intervalMillis;
423 }
424 RetryData.prototype.getThrottleMetadata = function (appId) {
425 return this.throttleMetadata[appId];
426 };
427 RetryData.prototype.setThrottleMetadata = function (appId, metadata) {
428 this.throttleMetadata[appId] = metadata;
429 };
430 RetryData.prototype.deleteThrottleMetadata = function (appId) {
431 delete this.throttleMetadata[appId];
432 };
433 return RetryData;
434}());
435var defaultRetryData = new RetryData();
436/**
437 * Set GET request headers.
438 * @param apiKey App API key.
439 */
440function getHeaders(apiKey) {
441 return new Headers({
442 Accept: 'application/json',
443 'x-goog-api-key': apiKey
444 });
445}
446/**
447 * Fetches dynamic config from backend.
448 * @param app Firebase app to fetch config for.
449 */
450function fetchDynamicConfig(appFields) {
451 var _a;
452 return __awaiter(this, void 0, void 0, function () {
453 var appId, apiKey, request, appUrl, response, errorMessage, jsonResponse;
454 return __generator(this, function (_b) {
455 switch (_b.label) {
456 case 0:
457 appId = appFields.appId, apiKey = appFields.apiKey;
458 request = {
459 method: 'GET',
460 headers: getHeaders(apiKey)
461 };
462 appUrl = DYNAMIC_CONFIG_URL.replace('{app-id}', appId);
463 return [4 /*yield*/, fetch(appUrl, request)];
464 case 1:
465 response = _b.sent();
466 if (!(response.status !== 200 && response.status !== 304)) return [3 /*break*/, 6];
467 errorMessage = '';
468 _b.label = 2;
469 case 2:
470 _b.trys.push([2, 4, , 5]);
471 return [4 /*yield*/, response.json()];
472 case 3:
473 jsonResponse = (_b.sent());
474 if ((_a = jsonResponse.error) === null || _a === void 0 ? void 0 : _a.message) {
475 errorMessage = jsonResponse.error.message;
476 }
477 return [3 /*break*/, 5];
478 case 4:
479 _b.sent();
480 return [3 /*break*/, 5];
481 case 5: throw ERROR_FACTORY.create("config-fetch-failed" /* CONFIG_FETCH_FAILED */, {
482 httpStatus: response.status,
483 responseMessage: errorMessage
484 });
485 case 6: return [2 /*return*/, response.json()];
486 }
487 });
488 });
489}
490/**
491 * Fetches dynamic config from backend, retrying if failed.
492 * @param app Firebase app to fetch config for.
493 */
494function fetchDynamicConfigWithRetry(app,
495// retryData and timeoutMillis are parameterized to allow passing a different value for testing.
496retryData, timeoutMillis) {
497 if (retryData === void 0) { retryData = defaultRetryData; }
498 return __awaiter(this, void 0, void 0, function () {
499 var _a, appId, apiKey, measurementId, throttleMetadata, signal;
500 var _this = this;
501 return __generator(this, function (_b) {
502 _a = app.options, appId = _a.appId, apiKey = _a.apiKey, measurementId = _a.measurementId;
503 if (!appId) {
504 throw ERROR_FACTORY.create("no-app-id" /* NO_APP_ID */);
505 }
506 if (!apiKey) {
507 if (measurementId) {
508 return [2 /*return*/, {
509 measurementId: measurementId,
510 appId: appId
511 }];
512 }
513 throw ERROR_FACTORY.create("no-api-key" /* NO_API_KEY */);
514 }
515 throttleMetadata = retryData.getThrottleMetadata(appId) || {
516 backoffCount: 0,
517 throttleEndTimeMillis: Date.now()
518 };
519 signal = new AnalyticsAbortSignal();
520 setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
521 return __generator(this, function (_a) {
522 // Note a very low delay, eg < 10ms, can elapse before listeners are initialized.
523 signal.abort();
524 return [2 /*return*/];
525 });
526 }); }, timeoutMillis !== undefined ? timeoutMillis : FETCH_TIMEOUT_MILLIS);
527 return [2 /*return*/, attemptFetchDynamicConfigWithRetry({ appId: appId, apiKey: apiKey, measurementId: measurementId }, throttleMetadata, signal, retryData)];
528 });
529 });
530}
531/**
532 * Runs one retry attempt.
533 * @param appFields Necessary app config fields.
534 * @param throttleMetadata Ongoing metadata to determine throttling times.
535 * @param signal Abort signal.
536 */
537function attemptFetchDynamicConfigWithRetry(appFields, _a, signal, retryData // for testing
538) {
539 var _b, _c;
540 var throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount;
541 if (retryData === void 0) { retryData = defaultRetryData; }
542 return __awaiter(this, void 0, void 0, function () {
543 var appId, measurementId, e_1, response, e_2, error, backoffMillis, throttleMetadata;
544 return __generator(this, function (_d) {
545 switch (_d.label) {
546 case 0:
547 appId = appFields.appId, measurementId = appFields.measurementId;
548 _d.label = 1;
549 case 1:
550 _d.trys.push([1, 3, , 4]);
551 return [4 /*yield*/, setAbortableTimeout(signal, throttleEndTimeMillis)];
552 case 2:
553 _d.sent();
554 return [3 /*break*/, 4];
555 case 3:
556 e_1 = _d.sent();
557 if (measurementId) {
558 logger.warn("Timed out fetching this Firebase app's measurement ID from the server." +
559 (" Falling back to the measurement ID " + measurementId) +
560 (" provided in the \"measurementId\" field in the local Firebase config. [" + ((_b = e_1) === null || _b === void 0 ? void 0 : _b.message) + "]"));
561 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
562 }
563 throw e_1;
564 case 4:
565 _d.trys.push([4, 6, , 7]);
566 return [4 /*yield*/, fetchDynamicConfig(appFields)];
567 case 5:
568 response = _d.sent();
569 // Note the SDK only clears throttle state if response is success or non-retriable.
570 retryData.deleteThrottleMetadata(appId);
571 return [2 /*return*/, response];
572 case 6:
573 e_2 = _d.sent();
574 error = e_2;
575 if (!isRetriableError(error)) {
576 retryData.deleteThrottleMetadata(appId);
577 if (measurementId) {
578 logger.warn("Failed to fetch this Firebase app's measurement ID from the server." +
579 (" Falling back to the measurement ID " + measurementId) +
580 (" provided in the \"measurementId\" field in the local Firebase config. [" + (error === null || error === void 0 ? void 0 : error.message) + "]"));
581 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
582 }
583 else {
584 throw e_2;
585 }
586 }
587 backoffMillis = Number((_c = error === null || error === void 0 ? void 0 : error.customData) === null || _c === void 0 ? void 0 : _c.httpStatus) === 503
588 ? calculateBackoffMillis(backoffCount, retryData.intervalMillis, LONG_RETRY_FACTOR)
589 : calculateBackoffMillis(backoffCount, retryData.intervalMillis);
590 throttleMetadata = {
591 throttleEndTimeMillis: Date.now() + backoffMillis,
592 backoffCount: backoffCount + 1
593 };
594 // Persists state.
595 retryData.setThrottleMetadata(appId, throttleMetadata);
596 logger.debug("Calling attemptFetch again in " + backoffMillis + " millis");
597 return [2 /*return*/, attemptFetchDynamicConfigWithRetry(appFields, throttleMetadata, signal, retryData)];
598 case 7: return [2 /*return*/];
599 }
600 });
601 });
602}
603/**
604 * Supports waiting on a backoff by:
605 *
606 * <ul>
607 * <li>Promisifying setTimeout, so we can set a timeout in our Promise chain</li>
608 * <li>Listening on a signal bus for abort events, just like the Fetch API</li>
609 * <li>Failing in the same way the Fetch API fails, so timing out a live request and a throttled
610 * request appear the same.</li>
611 * </ul>
612 *
613 * <p>Visible for testing.
614 */
615function setAbortableTimeout(signal, throttleEndTimeMillis) {
616 return new Promise(function (resolve, reject) {
617 // Derives backoff from given end time, normalizing negative numbers to zero.
618 var backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0);
619 var timeout = setTimeout(resolve, backoffMillis);
620 // Adds listener, rather than sets onabort, because signal is a shared object.
621 signal.addEventListener(function () {
622 clearTimeout(timeout);
623 // If the request completes before this timeout, the rejection has no effect.
624 reject(ERROR_FACTORY.create("fetch-throttle" /* FETCH_THROTTLE */, {
625 throttleEndTimeMillis: throttleEndTimeMillis
626 }));
627 });
628 });
629}
630/**
631 * Returns true if the {@link Error} indicates a fetch request may succeed later.
632 */
633function isRetriableError(e) {
634 if (!(e instanceof FirebaseError) || !e.customData) {
635 return false;
636 }
637 // Uses string index defined by ErrorData, which FirebaseError implements.
638 var httpStatus = Number(e.customData['httpStatus']);
639 return (httpStatus === 429 ||
640 httpStatus === 500 ||
641 httpStatus === 503 ||
642 httpStatus === 504);
643}
644/**
645 * Shims a minimal AbortSignal (copied from Remote Config).
646 *
647 * <p>AbortController's AbortSignal conveniently decouples fetch timeout logic from other aspects
648 * of networking, such as retries. Firebase doesn't use AbortController enough to justify a
649 * polyfill recommendation, like we do with the Fetch API, but this minimal shim can easily be
650 * swapped out if/when we do.
651 */
652var AnalyticsAbortSignal = /** @class */ (function () {
653 function AnalyticsAbortSignal() {
654 this.listeners = [];
655 }
656 AnalyticsAbortSignal.prototype.addEventListener = function (listener) {
657 this.listeners.push(listener);
658 };
659 AnalyticsAbortSignal.prototype.abort = function () {
660 this.listeners.forEach(function (listener) { return listener(); });
661 };
662 return AnalyticsAbortSignal;
663}());
664
665/**
666 * @license
667 * Copyright 2020 Google LLC
668 *
669 * Licensed under the Apache License, Version 2.0 (the "License");
670 * you may not use this file except in compliance with the License.
671 * You may obtain a copy of the License at
672 *
673 * http://www.apache.org/licenses/LICENSE-2.0
674 *
675 * Unless required by applicable law or agreed to in writing, software
676 * distributed under the License is distributed on an "AS IS" BASIS,
677 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
678 * See the License for the specific language governing permissions and
679 * limitations under the License.
680 */
681function validateIndexedDB() {
682 var _a;
683 return __awaiter(this, void 0, void 0, function () {
684 var e_1;
685 return __generator(this, function (_b) {
686 switch (_b.label) {
687 case 0:
688 if (!!isIndexedDBAvailable()) return [3 /*break*/, 1];
689 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
690 errorInfo: 'IndexedDB is not available in this environment.'
691 }).message);
692 return [2 /*return*/, false];
693 case 1:
694 _b.trys.push([1, 3, , 4]);
695 return [4 /*yield*/, validateIndexedDBOpenable()];
696 case 2:
697 _b.sent();
698 return [3 /*break*/, 4];
699 case 3:
700 e_1 = _b.sent();
701 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
702 errorInfo: (_a = e_1) === null || _a === void 0 ? void 0 : _a.toString()
703 }).message);
704 return [2 /*return*/, false];
705 case 4: return [2 /*return*/, true];
706 }
707 });
708 });
709}
710/**
711 * Initialize the analytics instance in gtag.js by calling config command with fid.
712 *
713 * NOTE: We combine analytics initialization and setting fid together because we want fid to be
714 * part of the `page_view` event that's sent during the initialization
715 * @param app Firebase app
716 * @param gtagCore The gtag function that's not wrapped.
717 * @param dynamicConfigPromisesList Array of all dynamic config promises.
718 * @param measurementIdToAppId Maps measurementID to appID.
719 * @param installations _FirebaseInstallationsInternal instance.
720 *
721 * @returns Measurement ID.
722 */
723function _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCore, dataLayerName, options) {
724 var _a;
725 return __awaiter(this, void 0, void 0, function () {
726 var dynamicConfigPromise, fidPromise, _b, dynamicConfig, fid, configProperties;
727 return __generator(this, function (_c) {
728 switch (_c.label) {
729 case 0:
730 dynamicConfigPromise = fetchDynamicConfigWithRetry(app);
731 // Once fetched, map measurementIds to appId, for ease of lookup in wrapped gtag function.
732 dynamicConfigPromise
733 .then(function (config) {
734 measurementIdToAppId[config.measurementId] = config.appId;
735 if (app.options.measurementId &&
736 config.measurementId !== app.options.measurementId) {
737 logger.warn("The measurement ID in the local Firebase config (" + app.options.measurementId + ")" +
738 (" does not match the measurement ID fetched from the server (" + config.measurementId + ").") +
739 " To ensure analytics events are always sent to the correct Analytics property," +
740 " update the" +
741 " measurement ID field in the local config or remove it from the local config.");
742 }
743 })
744 .catch(function (e) { return logger.error(e); });
745 // Add to list to track state of all dynamic config promises.
746 dynamicConfigPromisesList.push(dynamicConfigPromise);
747 fidPromise = validateIndexedDB().then(function (envIsValid) {
748 if (envIsValid) {
749 return installations.getId();
750 }
751 else {
752 return undefined;
753 }
754 });
755 return [4 /*yield*/, Promise.all([
756 dynamicConfigPromise,
757 fidPromise
758 ])];
759 case 1:
760 _b = _c.sent(), dynamicConfig = _b[0], fid = _b[1];
761 // Detect if user has already put the gtag <script> tag on this page.
762 if (!findGtagScriptOnPage()) {
763 insertScriptTag(dataLayerName, dynamicConfig.measurementId);
764 }
765 // This command initializes gtag.js and only needs to be called once for the entire web app,
766 // but since it is idempotent, we can call it multiple times.
767 // We keep it together with other initialization logic for better code structure.
768 // eslint-disable-next-line @typescript-eslint/no-explicit-any
769 gtagCore('js', new Date());
770 configProperties = (_a = options === null || options === void 0 ? void 0 : options.config) !== null && _a !== void 0 ? _a : {};
771 // guard against developers accidentally setting properties with prefix `firebase_`
772 configProperties[ORIGIN_KEY] = 'firebase';
773 configProperties.update = true;
774 if (fid != null) {
775 configProperties[GA_FID_KEY] = fid;
776 }
777 // It should be the first config command called on this GA-ID
778 // Initialize this GA-ID and set FID on it using the gtag config API.
779 // Note: This will trigger a page_view event unless 'send_page_view' is set to false in
780 // `configProperties`.
781 gtagCore("config" /* CONFIG */, dynamicConfig.measurementId, configProperties);
782 return [2 /*return*/, dynamicConfig.measurementId];
783 }
784 });
785 });
786}
787
788/**
789 * @license
790 * Copyright 2019 Google LLC
791 *
792 * Licensed under the Apache License, Version 2.0 (the "License");
793 * you may not use this file except in compliance with the License.
794 * You may obtain a copy of the License at
795 *
796 * http://www.apache.org/licenses/LICENSE-2.0
797 *
798 * Unless required by applicable law or agreed to in writing, software
799 * distributed under the License is distributed on an "AS IS" BASIS,
800 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
801 * See the License for the specific language governing permissions and
802 * limitations under the License.
803 */
804/**
805 * Analytics Service class.
806 */
807var AnalyticsService = /** @class */ (function () {
808 function AnalyticsService(app) {
809 this.app = app;
810 }
811 AnalyticsService.prototype._delete = function () {
812 delete initializationPromisesMap[this.app.options.appId];
813 return Promise.resolve();
814 };
815 return AnalyticsService;
816}());
817/**
818 * Maps appId to full initialization promise. Wrapped gtag calls must wait on
819 * all or some of these, depending on the call's `send_to` param and the status
820 * of the dynamic config fetches (see below).
821 */
822var initializationPromisesMap = {};
823/**
824 * List of dynamic config fetch promises. In certain cases, wrapped gtag calls
825 * wait on all these to be complete in order to determine if it can selectively
826 * wait for only certain initialization (FID) promises or if it must wait for all.
827 */
828var dynamicConfigPromisesList = [];
829/**
830 * Maps fetched measurementIds to appId. Populated when the app's dynamic config
831 * fetch completes. If already populated, gtag config calls can use this to
832 * selectively wait for only this app's initialization promise (FID) instead of all
833 * initialization promises.
834 */
835var measurementIdToAppId = {};
836/**
837 * Name for window global data layer array used by GA: defaults to 'dataLayer'.
838 */
839var dataLayerName = 'dataLayer';
840/**
841 * Name for window global gtag function used by GA: defaults to 'gtag'.
842 */
843var gtagName = 'gtag';
844/**
845 * Reproduction of standard gtag function or reference to existing
846 * gtag function on window object.
847 */
848var gtagCoreFunction;
849/**
850 * Wrapper around gtag function that ensures FID is sent with all
851 * relevant event and config calls.
852 */
853var wrappedGtagFunction;
854/**
855 * Flag to ensure page initialization steps (creation or wrapping of
856 * dataLayer and gtag script) are only run once per page load.
857 */
858var globalInitDone = false;
859/**
860 * Configures Firebase Analytics to use custom `gtag` or `dataLayer` names.
861 * Intended to be used if `gtag.js` script has been installed on
862 * this page independently of Firebase Analytics, and is using non-default
863 * names for either the `gtag` function or for `dataLayer`.
864 * Must be called before calling `getAnalytics()` or it won't
865 * have any effect.
866 *
867 * @public
868 *
869 * @param options - Custom gtag and dataLayer names.
870 */
871function settings(options) {
872 if (globalInitDone) {
873 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
874 }
875 if (options.dataLayerName) {
876 dataLayerName = options.dataLayerName;
877 }
878 if (options.gtagName) {
879 gtagName = options.gtagName;
880 }
881}
882/**
883 * Returns true if no environment mismatch is found.
884 * If environment mismatches are found, throws an INVALID_ANALYTICS_CONTEXT
885 * error that also lists details for each mismatch found.
886 */
887function warnOnBrowserContextMismatch() {
888 var mismatchedEnvMessages = [];
889 if (isBrowserExtension()) {
890 mismatchedEnvMessages.push('This is a browser extension environment.');
891 }
892 if (!areCookiesEnabled()) {
893 mismatchedEnvMessages.push('Cookies are not available.');
894 }
895 if (mismatchedEnvMessages.length > 0) {
896 var details = mismatchedEnvMessages
897 .map(function (message, index) { return "(" + (index + 1) + ") " + message; })
898 .join(' ');
899 var err = ERROR_FACTORY.create("invalid-analytics-context" /* INVALID_ANALYTICS_CONTEXT */, {
900 errorInfo: details
901 });
902 logger.warn(err.message);
903 }
904}
905/**
906 * Analytics instance factory.
907 * @internal
908 */
909function factory(app, installations, options) {
910 warnOnBrowserContextMismatch();
911 var appId = app.options.appId;
912 if (!appId) {
913 throw ERROR_FACTORY.create("no-app-id" /* NO_APP_ID */);
914 }
915 if (!app.options.apiKey) {
916 if (app.options.measurementId) {
917 logger.warn("The \"apiKey\" field is empty in the local Firebase config. This is needed to fetch the latest" +
918 (" measurement ID for this Firebase app. Falling back to the measurement ID " + app.options.measurementId) +
919 " provided in the \"measurementId\" field in the local Firebase config.");
920 }
921 else {
922 throw ERROR_FACTORY.create("no-api-key" /* NO_API_KEY */);
923 }
924 }
925 if (initializationPromisesMap[appId] != null) {
926 throw ERROR_FACTORY.create("already-exists" /* ALREADY_EXISTS */, {
927 id: appId
928 });
929 }
930 if (!globalInitDone) {
931 // Steps here should only be done once per page: creation or wrapping
932 // of dataLayer and global gtag function.
933 getOrCreateDataLayer(dataLayerName);
934 var _a = wrapOrCreateGtag(initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, dataLayerName, gtagName), wrappedGtag = _a.wrappedGtag, gtagCore = _a.gtagCore;
935 wrappedGtagFunction = wrappedGtag;
936 gtagCoreFunction = gtagCore;
937 globalInitDone = true;
938 }
939 // Async but non-blocking.
940 // This map reflects the completion state of all promises for each appId.
941 initializationPromisesMap[appId] = _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCoreFunction, dataLayerName, options);
942 var analyticsInstance = new AnalyticsService(app);
943 return analyticsInstance;
944}
945
946/**
947 * @license
948 * Copyright 2019 Google LLC
949 *
950 * Licensed under the Apache License, Version 2.0 (the "License");
951 * you may not use this file except in compliance with the License.
952 * You may obtain a copy of the License at
953 *
954 * http://www.apache.org/licenses/LICENSE-2.0
955 *
956 * Unless required by applicable law or agreed to in writing, software
957 * distributed under the License is distributed on an "AS IS" BASIS,
958 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
959 * See the License for the specific language governing permissions and
960 * limitations under the License.
961 */
962/**
963 * Logs an analytics event through the Firebase SDK.
964 *
965 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
966 * @param eventName Google Analytics event name, choose from standard list or use a custom string.
967 * @param eventParams Analytics event parameters.
968 */
969function logEvent$1(gtagFunction, initializationPromise, eventName, eventParams, options) {
970 return __awaiter(this, void 0, void 0, function () {
971 var measurementId, params;
972 return __generator(this, function (_a) {
973 switch (_a.label) {
974 case 0:
975 if (!(options && options.global)) return [3 /*break*/, 1];
976 gtagFunction("event" /* EVENT */, eventName, eventParams);
977 return [2 /*return*/];
978 case 1: return [4 /*yield*/, initializationPromise];
979 case 2:
980 measurementId = _a.sent();
981 params = __assign(__assign({}, eventParams), { 'send_to': measurementId });
982 gtagFunction("event" /* EVENT */, eventName, params);
983 _a.label = 3;
984 case 3: return [2 /*return*/];
985 }
986 });
987 });
988}
989/**
990 * Set screen_name parameter for this Google Analytics ID.
991 *
992 * @deprecated Use {@link logEvent} with `eventName` as 'screen_view' and add relevant `eventParams`.
993 * See {@link https://firebase.google.com/docs/analytics/screenviews | Track Screenviews}.
994 *
995 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
996 * @param screenName Screen name string to set.
997 */
998function setCurrentScreen$1(gtagFunction, initializationPromise, screenName, options) {
999 return __awaiter(this, void 0, void 0, function () {
1000 var measurementId;
1001 return __generator(this, function (_a) {
1002 switch (_a.label) {
1003 case 0:
1004 if (!(options && options.global)) return [3 /*break*/, 1];
1005 gtagFunction("set" /* SET */, { 'screen_name': screenName });
1006 return [2 /*return*/, Promise.resolve()];
1007 case 1: return [4 /*yield*/, initializationPromise];
1008 case 2:
1009 measurementId = _a.sent();
1010 gtagFunction("config" /* CONFIG */, measurementId, {
1011 update: true,
1012 'screen_name': screenName
1013 });
1014 _a.label = 3;
1015 case 3: return [2 /*return*/];
1016 }
1017 });
1018 });
1019}
1020/**
1021 * Set user_id parameter for this Google Analytics ID.
1022 *
1023 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
1024 * @param id User ID string to set
1025 */
1026function setUserId$1(gtagFunction, initializationPromise, id, options) {
1027 return __awaiter(this, void 0, void 0, function () {
1028 var measurementId;
1029 return __generator(this, function (_a) {
1030 switch (_a.label) {
1031 case 0:
1032 if (!(options && options.global)) return [3 /*break*/, 1];
1033 gtagFunction("set" /* SET */, { 'user_id': id });
1034 return [2 /*return*/, Promise.resolve()];
1035 case 1: return [4 /*yield*/, initializationPromise];
1036 case 2:
1037 measurementId = _a.sent();
1038 gtagFunction("config" /* CONFIG */, measurementId, {
1039 update: true,
1040 'user_id': id
1041 });
1042 _a.label = 3;
1043 case 3: return [2 /*return*/];
1044 }
1045 });
1046 });
1047}
1048/**
1049 * Set all other user properties other than user_id and screen_name.
1050 *
1051 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
1052 * @param properties Map of user properties to set
1053 */
1054function setUserProperties$1(gtagFunction, initializationPromise, properties, options) {
1055 return __awaiter(this, void 0, void 0, function () {
1056 var flatProperties, _i, _a, key, measurementId;
1057 return __generator(this, function (_b) {
1058 switch (_b.label) {
1059 case 0:
1060 if (!(options && options.global)) return [3 /*break*/, 1];
1061 flatProperties = {};
1062 for (_i = 0, _a = Object.keys(properties); _i < _a.length; _i++) {
1063 key = _a[_i];
1064 // use dot notation for merge behavior in gtag.js
1065 flatProperties["user_properties." + key] = properties[key];
1066 }
1067 gtagFunction("set" /* SET */, flatProperties);
1068 return [2 /*return*/, Promise.resolve()];
1069 case 1: return [4 /*yield*/, initializationPromise];
1070 case 2:
1071 measurementId = _b.sent();
1072 gtagFunction("config" /* CONFIG */, measurementId, {
1073 update: true,
1074 'user_properties': properties
1075 });
1076 _b.label = 3;
1077 case 3: return [2 /*return*/];
1078 }
1079 });
1080 });
1081}
1082/**
1083 * Set whether collection is enabled for this ID.
1084 *
1085 * @param enabled If true, collection is enabled for this ID.
1086 */
1087function setAnalyticsCollectionEnabled$1(initializationPromise, enabled) {
1088 return __awaiter(this, void 0, void 0, function () {
1089 var measurementId;
1090 return __generator(this, function (_a) {
1091 switch (_a.label) {
1092 case 0: return [4 /*yield*/, initializationPromise];
1093 case 1:
1094 measurementId = _a.sent();
1095 window["ga-disable-" + measurementId] = !enabled;
1096 return [2 /*return*/];
1097 }
1098 });
1099 });
1100}
1101
1102/* eslint-disable @typescript-eslint/no-explicit-any */
1103/**
1104 * Returns an {@link Analytics} instance for the given app.
1105 *
1106 * @public
1107 *
1108 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1109 */
1110function getAnalytics(app) {
1111 if (app === void 0) { app = getApp(); }
1112 app = getModularInstance(app);
1113 // Dependencies
1114 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1115 if (analyticsProvider.isInitialized()) {
1116 return analyticsProvider.getImmediate();
1117 }
1118 return initializeAnalytics(app);
1119}
1120/**
1121 * Returns an {@link Analytics} instance for the given app.
1122 *
1123 * @public
1124 *
1125 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1126 */
1127function initializeAnalytics(app, options) {
1128 if (options === void 0) { options = {}; }
1129 // Dependencies
1130 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1131 if (analyticsProvider.isInitialized()) {
1132 var existingInstance = analyticsProvider.getImmediate();
1133 if (deepEqual(options, analyticsProvider.getOptions())) {
1134 return existingInstance;
1135 }
1136 else {
1137 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
1138 }
1139 }
1140 var analyticsInstance = analyticsProvider.initialize({ options: options });
1141 return analyticsInstance;
1142}
1143/**
1144 * This is a public static method provided to users that wraps four different checks:
1145 *
1146 * 1. Check if it's not a browser extension environment.
1147 * 2. Check if cookies are enabled in current browser.
1148 * 3. Check if IndexedDB is supported by the browser environment.
1149 * 4. Check if the current browser context is valid for using `IndexedDB.open()`.
1150 *
1151 * @public
1152 *
1153 */
1154function isSupported() {
1155 return __awaiter(this, void 0, void 0, function () {
1156 var isDBOpenable;
1157 return __generator(this, function (_a) {
1158 switch (_a.label) {
1159 case 0:
1160 if (isBrowserExtension()) {
1161 return [2 /*return*/, false];
1162 }
1163 if (!areCookiesEnabled()) {
1164 return [2 /*return*/, false];
1165 }
1166 if (!isIndexedDBAvailable()) {
1167 return [2 /*return*/, false];
1168 }
1169 _a.label = 1;
1170 case 1:
1171 _a.trys.push([1, 3, , 4]);
1172 return [4 /*yield*/, validateIndexedDBOpenable()];
1173 case 2:
1174 isDBOpenable = _a.sent();
1175 return [2 /*return*/, isDBOpenable];
1176 case 3:
1177 _a.sent();
1178 return [2 /*return*/, false];
1179 case 4: return [2 /*return*/];
1180 }
1181 });
1182 });
1183}
1184/**
1185 * Use gtag `config` command to set `screen_name`.
1186 *
1187 * @public
1188 *
1189 * @deprecated Use {@link logEvent} with `eventName` as 'screen_view' and add relevant `eventParams`.
1190 * See {@link https://firebase.google.com/docs/analytics/screenviews | Track Screenviews}.
1191 *
1192 * @param analyticsInstance - The {@link Analytics} instance.
1193 * @param screenName - Screen name to set.
1194 */
1195function setCurrentScreen(analyticsInstance, screenName, options) {
1196 analyticsInstance = getModularInstance(analyticsInstance);
1197 setCurrentScreen$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], screenName, options).catch(function (e) { return logger.error(e); });
1198}
1199/**
1200 * Use gtag `config` command to set `user_id`.
1201 *
1202 * @public
1203 *
1204 * @param analyticsInstance - The {@link Analytics} instance.
1205 * @param id - User ID to set.
1206 */
1207function setUserId(analyticsInstance, id, options) {
1208 analyticsInstance = getModularInstance(analyticsInstance);
1209 setUserId$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], id, options).catch(function (e) { return logger.error(e); });
1210}
1211/**
1212 * Use gtag `config` command to set all params specified.
1213 *
1214 * @public
1215 */
1216function setUserProperties(analyticsInstance, properties, options) {
1217 analyticsInstance = getModularInstance(analyticsInstance);
1218 setUserProperties$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], properties, options).catch(function (e) { return logger.error(e); });
1219}
1220/**
1221 * Sets whether Google Analytics collection is enabled for this app on this device.
1222 * Sets global `window['ga-disable-analyticsId'] = true;`
1223 *
1224 * @public
1225 *
1226 * @param analyticsInstance - The {@link Analytics} instance.
1227 * @param enabled - If true, enables collection, if false, disables it.
1228 */
1229function setAnalyticsCollectionEnabled(analyticsInstance, enabled) {
1230 analyticsInstance = getModularInstance(analyticsInstance);
1231 setAnalyticsCollectionEnabled$1(initializationPromisesMap[analyticsInstance.app.options.appId], enabled).catch(function (e) { return logger.error(e); });
1232}
1233/**
1234 * Sends a Google Analytics event with given `eventParams`. This method
1235 * automatically associates this logged event with this Firebase web
1236 * app instance on this device.
1237 * List of official event parameters can be found in the gtag.js
1238 * reference documentation:
1239 * {@link https://developers.google.com/gtagjs/reference/ga4-events
1240 * | the GA4 reference documentation}.
1241 *
1242 * @public
1243 */
1244function logEvent(analyticsInstance, eventName, eventParams, options) {
1245 analyticsInstance = getModularInstance(analyticsInstance);
1246 logEvent$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], eventName, eventParams, options).catch(function (e) { return logger.error(e); });
1247}
1248
1249var name = "@firebase/analytics";
1250var version = "0.7.11";
1251
1252/**
1253 * Firebase Analytics
1254 *
1255 * @packageDocumentation
1256 */
1257function registerAnalytics() {
1258 _registerComponent(new Component(ANALYTICS_TYPE, function (container, _a) {
1259 var analyticsOptions = _a.options;
1260 // getImmediate for FirebaseApp will always succeed
1261 var app = container.getProvider('app').getImmediate();
1262 var installations = container
1263 .getProvider('installations-internal')
1264 .getImmediate();
1265 return factory(app, installations, analyticsOptions);
1266 }, "PUBLIC" /* PUBLIC */));
1267 _registerComponent(new Component('analytics-internal', internalFactory, "PRIVATE" /* PRIVATE */));
1268 registerVersion(name, version);
1269 // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
1270 registerVersion(name, version, 'esm5');
1271 function internalFactory(container) {
1272 try {
1273 var analytics_1 = container.getProvider(ANALYTICS_TYPE).getImmediate();
1274 return {
1275 logEvent: function (eventName, eventParams, options) { return logEvent(analytics_1, eventName, eventParams, options); }
1276 };
1277 }
1278 catch (e) {
1279 throw ERROR_FACTORY.create("interop-component-reg-failed" /* INTEROP_COMPONENT_REG_FAILED */, {
1280 reason: e
1281 });
1282 }
1283 }
1284}
1285registerAnalytics();
1286
1287export { getAnalytics, initializeAnalytics, isSupported, logEvent, setAnalyticsCollectionEnabled, setCurrentScreen, setUserId, setUserProperties, settings };
1288//# sourceMappingURL=index.esm.js.map