UNPKG

57.7 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 throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount;
540 if (retryData === void 0) { retryData = defaultRetryData; }
541 return __awaiter(this, void 0, void 0, function () {
542 var appId, measurementId, e_1, response, e_2, backoffMillis, throttleMetadata;
543 return __generator(this, function (_b) {
544 switch (_b.label) {
545 case 0:
546 appId = appFields.appId, measurementId = appFields.measurementId;
547 _b.label = 1;
548 case 1:
549 _b.trys.push([1, 3, , 4]);
550 return [4 /*yield*/, setAbortableTimeout(signal, throttleEndTimeMillis)];
551 case 2:
552 _b.sent();
553 return [3 /*break*/, 4];
554 case 3:
555 e_1 = _b.sent();
556 if (measurementId) {
557 logger.warn("Timed out fetching this Firebase app's measurement ID from the server." +
558 (" Falling back to the measurement ID " + measurementId) +
559 (" provided in the \"measurementId\" field in the local Firebase config. [" + e_1.message + "]"));
560 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
561 }
562 throw e_1;
563 case 4:
564 _b.trys.push([4, 6, , 7]);
565 return [4 /*yield*/, fetchDynamicConfig(appFields)];
566 case 5:
567 response = _b.sent();
568 // Note the SDK only clears throttle state if response is success or non-retriable.
569 retryData.deleteThrottleMetadata(appId);
570 return [2 /*return*/, response];
571 case 6:
572 e_2 = _b.sent();
573 if (!isRetriableError(e_2)) {
574 retryData.deleteThrottleMetadata(appId);
575 if (measurementId) {
576 logger.warn("Failed to fetch this Firebase app's measurement ID from the server." +
577 (" Falling back to the measurement ID " + measurementId) +
578 (" provided in the \"measurementId\" field in the local Firebase config. [" + e_2.message + "]"));
579 return [2 /*return*/, { appId: appId, measurementId: measurementId }];
580 }
581 else {
582 throw e_2;
583 }
584 }
585 backoffMillis = Number(e_2.customData.httpStatus) === 503
586 ? calculateBackoffMillis(backoffCount, retryData.intervalMillis, LONG_RETRY_FACTOR)
587 : calculateBackoffMillis(backoffCount, retryData.intervalMillis);
588 throttleMetadata = {
589 throttleEndTimeMillis: Date.now() + backoffMillis,
590 backoffCount: backoffCount + 1
591 };
592 // Persists state.
593 retryData.setThrottleMetadata(appId, throttleMetadata);
594 logger.debug("Calling attemptFetch again in " + backoffMillis + " millis");
595 return [2 /*return*/, attemptFetchDynamicConfigWithRetry(appFields, throttleMetadata, signal, retryData)];
596 case 7: return [2 /*return*/];
597 }
598 });
599 });
600}
601/**
602 * Supports waiting on a backoff by:
603 *
604 * <ul>
605 * <li>Promisifying setTimeout, so we can set a timeout in our Promise chain</li>
606 * <li>Listening on a signal bus for abort events, just like the Fetch API</li>
607 * <li>Failing in the same way the Fetch API fails, so timing out a live request and a throttled
608 * request appear the same.</li>
609 * </ul>
610 *
611 * <p>Visible for testing.
612 */
613function setAbortableTimeout(signal, throttleEndTimeMillis) {
614 return new Promise(function (resolve, reject) {
615 // Derives backoff from given end time, normalizing negative numbers to zero.
616 var backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0);
617 var timeout = setTimeout(resolve, backoffMillis);
618 // Adds listener, rather than sets onabort, because signal is a shared object.
619 signal.addEventListener(function () {
620 clearTimeout(timeout);
621 // If the request completes before this timeout, the rejection has no effect.
622 reject(ERROR_FACTORY.create("fetch-throttle" /* FETCH_THROTTLE */, {
623 throttleEndTimeMillis: throttleEndTimeMillis
624 }));
625 });
626 });
627}
628/**
629 * Returns true if the {@link Error} indicates a fetch request may succeed later.
630 */
631function isRetriableError(e) {
632 if (!(e instanceof FirebaseError) || !e.customData) {
633 return false;
634 }
635 // Uses string index defined by ErrorData, which FirebaseError implements.
636 var httpStatus = Number(e.customData['httpStatus']);
637 return (httpStatus === 429 ||
638 httpStatus === 500 ||
639 httpStatus === 503 ||
640 httpStatus === 504);
641}
642/**
643 * Shims a minimal AbortSignal (copied from Remote Config).
644 *
645 * <p>AbortController's AbortSignal conveniently decouples fetch timeout logic from other aspects
646 * of networking, such as retries. Firebase doesn't use AbortController enough to justify a
647 * polyfill recommendation, like we do with the Fetch API, but this minimal shim can easily be
648 * swapped out if/when we do.
649 */
650var AnalyticsAbortSignal = /** @class */ (function () {
651 function AnalyticsAbortSignal() {
652 this.listeners = [];
653 }
654 AnalyticsAbortSignal.prototype.addEventListener = function (listener) {
655 this.listeners.push(listener);
656 };
657 AnalyticsAbortSignal.prototype.abort = function () {
658 this.listeners.forEach(function (listener) { return listener(); });
659 };
660 return AnalyticsAbortSignal;
661}());
662
663/**
664 * @license
665 * Copyright 2020 Google LLC
666 *
667 * Licensed under the Apache License, Version 2.0 (the "License");
668 * you may not use this file except in compliance with the License.
669 * You may obtain a copy of the License at
670 *
671 * http://www.apache.org/licenses/LICENSE-2.0
672 *
673 * Unless required by applicable law or agreed to in writing, software
674 * distributed under the License is distributed on an "AS IS" BASIS,
675 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
676 * See the License for the specific language governing permissions and
677 * limitations under the License.
678 */
679function validateIndexedDB() {
680 return __awaiter(this, void 0, void 0, function () {
681 var e_1;
682 return __generator(this, function (_a) {
683 switch (_a.label) {
684 case 0:
685 if (!!isIndexedDBAvailable()) return [3 /*break*/, 1];
686 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
687 errorInfo: 'IndexedDB is not available in this environment.'
688 }).message);
689 return [2 /*return*/, false];
690 case 1:
691 _a.trys.push([1, 3, , 4]);
692 return [4 /*yield*/, validateIndexedDBOpenable()];
693 case 2:
694 _a.sent();
695 return [3 /*break*/, 4];
696 case 3:
697 e_1 = _a.sent();
698 logger.warn(ERROR_FACTORY.create("indexeddb-unavailable" /* INDEXEDDB_UNAVAILABLE */, {
699 errorInfo: e_1
700 }).message);
701 return [2 /*return*/, false];
702 case 4: return [2 /*return*/, true];
703 }
704 });
705 });
706}
707/**
708 * Initialize the analytics instance in gtag.js by calling config command with fid.
709 *
710 * NOTE: We combine analytics initialization and setting fid together because we want fid to be
711 * part of the `page_view` event that's sent during the initialization
712 * @param app Firebase app
713 * @param gtagCore The gtag function that's not wrapped.
714 * @param dynamicConfigPromisesList Array of all dynamic config promises.
715 * @param measurementIdToAppId Maps measurementID to appID.
716 * @param installations _FirebaseInstallationsInternal instance.
717 *
718 * @returns Measurement ID.
719 */
720function _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCore, dataLayerName, options) {
721 var _a;
722 return __awaiter(this, void 0, void 0, function () {
723 var dynamicConfigPromise, fidPromise, _b, dynamicConfig, fid, configProperties;
724 return __generator(this, function (_c) {
725 switch (_c.label) {
726 case 0:
727 dynamicConfigPromise = fetchDynamicConfigWithRetry(app);
728 // Once fetched, map measurementIds to appId, for ease of lookup in wrapped gtag function.
729 dynamicConfigPromise
730 .then(function (config) {
731 measurementIdToAppId[config.measurementId] = config.appId;
732 if (app.options.measurementId &&
733 config.measurementId !== app.options.measurementId) {
734 logger.warn("The measurement ID in the local Firebase config (" + app.options.measurementId + ")" +
735 (" does not match the measurement ID fetched from the server (" + config.measurementId + ").") +
736 " To ensure analytics events are always sent to the correct Analytics property," +
737 " update the" +
738 " measurement ID field in the local config or remove it from the local config.");
739 }
740 })
741 .catch(function (e) { return logger.error(e); });
742 // Add to list to track state of all dynamic config promises.
743 dynamicConfigPromisesList.push(dynamicConfigPromise);
744 fidPromise = validateIndexedDB().then(function (envIsValid) {
745 if (envIsValid) {
746 return installations.getId();
747 }
748 else {
749 return undefined;
750 }
751 });
752 return [4 /*yield*/, Promise.all([
753 dynamicConfigPromise,
754 fidPromise
755 ])];
756 case 1:
757 _b = _c.sent(), dynamicConfig = _b[0], fid = _b[1];
758 // Detect if user has already put the gtag <script> tag on this page.
759 if (!findGtagScriptOnPage()) {
760 insertScriptTag(dataLayerName, dynamicConfig.measurementId);
761 }
762 // This command initializes gtag.js and only needs to be called once for the entire web app,
763 // but since it is idempotent, we can call it multiple times.
764 // We keep it together with other initialization logic for better code structure.
765 // eslint-disable-next-line @typescript-eslint/no-explicit-any
766 gtagCore('js', new Date());
767 configProperties = (_a = options === null || options === void 0 ? void 0 : options.config) !== null && _a !== void 0 ? _a : {};
768 // guard against developers accidentally setting properties with prefix `firebase_`
769 configProperties[ORIGIN_KEY] = 'firebase';
770 configProperties.update = true;
771 if (fid != null) {
772 configProperties[GA_FID_KEY] = fid;
773 }
774 // It should be the first config command called on this GA-ID
775 // Initialize this GA-ID and set FID on it using the gtag config API.
776 // Note: This will trigger a page_view event unless 'send_page_view' is set to false in
777 // `configProperties`.
778 gtagCore("config" /* CONFIG */, dynamicConfig.measurementId, configProperties);
779 return [2 /*return*/, dynamicConfig.measurementId];
780 }
781 });
782 });
783}
784
785/**
786 * @license
787 * Copyright 2019 Google LLC
788 *
789 * Licensed under the Apache License, Version 2.0 (the "License");
790 * you may not use this file except in compliance with the License.
791 * You may obtain a copy of the License at
792 *
793 * http://www.apache.org/licenses/LICENSE-2.0
794 *
795 * Unless required by applicable law or agreed to in writing, software
796 * distributed under the License is distributed on an "AS IS" BASIS,
797 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
798 * See the License for the specific language governing permissions and
799 * limitations under the License.
800 */
801/**
802 * Analytics Service class.
803 */
804var AnalyticsService = /** @class */ (function () {
805 function AnalyticsService(app) {
806 this.app = app;
807 }
808 AnalyticsService.prototype._delete = function () {
809 delete initializationPromisesMap[this.app.options.appId];
810 return Promise.resolve();
811 };
812 return AnalyticsService;
813}());
814/**
815 * Maps appId to full initialization promise. Wrapped gtag calls must wait on
816 * all or some of these, depending on the call's `send_to` param and the status
817 * of the dynamic config fetches (see below).
818 */
819var initializationPromisesMap = {};
820/**
821 * List of dynamic config fetch promises. In certain cases, wrapped gtag calls
822 * wait on all these to be complete in order to determine if it can selectively
823 * wait for only certain initialization (FID) promises or if it must wait for all.
824 */
825var dynamicConfigPromisesList = [];
826/**
827 * Maps fetched measurementIds to appId. Populated when the app's dynamic config
828 * fetch completes. If already populated, gtag config calls can use this to
829 * selectively wait for only this app's initialization promise (FID) instead of all
830 * initialization promises.
831 */
832var measurementIdToAppId = {};
833/**
834 * Name for window global data layer array used by GA: defaults to 'dataLayer'.
835 */
836var dataLayerName = 'dataLayer';
837/**
838 * Name for window global gtag function used by GA: defaults to 'gtag'.
839 */
840var gtagName = 'gtag';
841/**
842 * Reproduction of standard gtag function or reference to existing
843 * gtag function on window object.
844 */
845var gtagCoreFunction;
846/**
847 * Wrapper around gtag function that ensures FID is sent with all
848 * relevant event and config calls.
849 */
850var wrappedGtagFunction;
851/**
852 * Flag to ensure page initialization steps (creation or wrapping of
853 * dataLayer and gtag script) are only run once per page load.
854 */
855var globalInitDone = false;
856/**
857 * Configures Firebase Analytics to use custom `gtag` or `dataLayer` names.
858 * Intended to be used if `gtag.js` script has been installed on
859 * this page independently of Firebase Analytics, and is using non-default
860 * names for either the `gtag` function or for `dataLayer`.
861 * Must be called before calling `getAnalytics()` or it won't
862 * have any effect.
863 *
864 * @public
865 *
866 * @param options - Custom gtag and dataLayer names.
867 */
868function settings(options) {
869 if (globalInitDone) {
870 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
871 }
872 if (options.dataLayerName) {
873 dataLayerName = options.dataLayerName;
874 }
875 if (options.gtagName) {
876 gtagName = options.gtagName;
877 }
878}
879/**
880 * Returns true if no environment mismatch is found.
881 * If environment mismatches are found, throws an INVALID_ANALYTICS_CONTEXT
882 * error that also lists details for each mismatch found.
883 */
884function warnOnBrowserContextMismatch() {
885 var mismatchedEnvMessages = [];
886 if (isBrowserExtension()) {
887 mismatchedEnvMessages.push('This is a browser extension environment.');
888 }
889 if (!areCookiesEnabled()) {
890 mismatchedEnvMessages.push('Cookies are not available.');
891 }
892 if (mismatchedEnvMessages.length > 0) {
893 var details = mismatchedEnvMessages
894 .map(function (message, index) { return "(" + (index + 1) + ") " + message; })
895 .join(' ');
896 var err = ERROR_FACTORY.create("invalid-analytics-context" /* INVALID_ANALYTICS_CONTEXT */, {
897 errorInfo: details
898 });
899 logger.warn(err.message);
900 }
901}
902/**
903 * Analytics instance factory.
904 * @internal
905 */
906function factory(app, installations, options) {
907 warnOnBrowserContextMismatch();
908 var appId = app.options.appId;
909 if (!appId) {
910 throw ERROR_FACTORY.create("no-app-id" /* NO_APP_ID */);
911 }
912 if (!app.options.apiKey) {
913 if (app.options.measurementId) {
914 logger.warn("The \"apiKey\" field is empty in the local Firebase config. This is needed to fetch the latest" +
915 (" measurement ID for this Firebase app. Falling back to the measurement ID " + app.options.measurementId) +
916 " provided in the \"measurementId\" field in the local Firebase config.");
917 }
918 else {
919 throw ERROR_FACTORY.create("no-api-key" /* NO_API_KEY */);
920 }
921 }
922 if (initializationPromisesMap[appId] != null) {
923 throw ERROR_FACTORY.create("already-exists" /* ALREADY_EXISTS */, {
924 id: appId
925 });
926 }
927 if (!globalInitDone) {
928 // Steps here should only be done once per page: creation or wrapping
929 // of dataLayer and global gtag function.
930 getOrCreateDataLayer(dataLayerName);
931 var _a = wrapOrCreateGtag(initializationPromisesMap, dynamicConfigPromisesList, measurementIdToAppId, dataLayerName, gtagName), wrappedGtag = _a.wrappedGtag, gtagCore = _a.gtagCore;
932 wrappedGtagFunction = wrappedGtag;
933 gtagCoreFunction = gtagCore;
934 globalInitDone = true;
935 }
936 // Async but non-blocking.
937 // This map reflects the completion state of all promises for each appId.
938 initializationPromisesMap[appId] = _initializeAnalytics(app, dynamicConfigPromisesList, measurementIdToAppId, installations, gtagCoreFunction, dataLayerName, options);
939 var analyticsInstance = new AnalyticsService(app);
940 return analyticsInstance;
941}
942
943/**
944 * @license
945 * Copyright 2019 Google LLC
946 *
947 * Licensed under the Apache License, Version 2.0 (the "License");
948 * you may not use this file except in compliance with the License.
949 * You may obtain a copy of the License at
950 *
951 * http://www.apache.org/licenses/LICENSE-2.0
952 *
953 * Unless required by applicable law or agreed to in writing, software
954 * distributed under the License is distributed on an "AS IS" BASIS,
955 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
956 * See the License for the specific language governing permissions and
957 * limitations under the License.
958 */
959/**
960 * Logs an analytics event through the Firebase SDK.
961 *
962 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
963 * @param eventName Google Analytics event name, choose from standard list or use a custom string.
964 * @param eventParams Analytics event parameters.
965 */
966function logEvent$1(gtagFunction, initializationPromise, eventName, eventParams, options) {
967 return __awaiter(this, void 0, void 0, function () {
968 var measurementId, params;
969 return __generator(this, function (_a) {
970 switch (_a.label) {
971 case 0:
972 if (!(options && options.global)) return [3 /*break*/, 1];
973 gtagFunction("event" /* EVENT */, eventName, eventParams);
974 return [2 /*return*/];
975 case 1: return [4 /*yield*/, initializationPromise];
976 case 2:
977 measurementId = _a.sent();
978 params = __assign(__assign({}, eventParams), { 'send_to': measurementId });
979 gtagFunction("event" /* EVENT */, eventName, params);
980 _a.label = 3;
981 case 3: return [2 /*return*/];
982 }
983 });
984 });
985}
986/**
987 * Set screen_name parameter for this Google Analytics ID.
988 *
989 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
990 * @param screenName Screen name string to set.
991 */
992function setCurrentScreen$1(gtagFunction, initializationPromise, screenName, options) {
993 return __awaiter(this, void 0, void 0, function () {
994 var measurementId;
995 return __generator(this, function (_a) {
996 switch (_a.label) {
997 case 0:
998 if (!(options && options.global)) return [3 /*break*/, 1];
999 gtagFunction("set" /* SET */, { 'screen_name': screenName });
1000 return [2 /*return*/, Promise.resolve()];
1001 case 1: return [4 /*yield*/, initializationPromise];
1002 case 2:
1003 measurementId = _a.sent();
1004 gtagFunction("config" /* CONFIG */, measurementId, {
1005 update: true,
1006 'screen_name': screenName
1007 });
1008 _a.label = 3;
1009 case 3: return [2 /*return*/];
1010 }
1011 });
1012 });
1013}
1014/**
1015 * Set user_id parameter for this Google Analytics ID.
1016 *
1017 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
1018 * @param id User ID string to set
1019 */
1020function setUserId$1(gtagFunction, initializationPromise, id, options) {
1021 return __awaiter(this, void 0, void 0, function () {
1022 var measurementId;
1023 return __generator(this, function (_a) {
1024 switch (_a.label) {
1025 case 0:
1026 if (!(options && options.global)) return [3 /*break*/, 1];
1027 gtagFunction("set" /* SET */, { 'user_id': id });
1028 return [2 /*return*/, Promise.resolve()];
1029 case 1: return [4 /*yield*/, initializationPromise];
1030 case 2:
1031 measurementId = _a.sent();
1032 gtagFunction("config" /* CONFIG */, measurementId, {
1033 update: true,
1034 'user_id': id
1035 });
1036 _a.label = 3;
1037 case 3: return [2 /*return*/];
1038 }
1039 });
1040 });
1041}
1042/**
1043 * Set all other user properties other than user_id and screen_name.
1044 *
1045 * @param gtagFunction Wrapped gtag function that waits for fid to be set before sending an event
1046 * @param properties Map of user properties to set
1047 */
1048function setUserProperties$1(gtagFunction, initializationPromise, properties, options) {
1049 return __awaiter(this, void 0, void 0, function () {
1050 var flatProperties, _i, _a, key, measurementId;
1051 return __generator(this, function (_b) {
1052 switch (_b.label) {
1053 case 0:
1054 if (!(options && options.global)) return [3 /*break*/, 1];
1055 flatProperties = {};
1056 for (_i = 0, _a = Object.keys(properties); _i < _a.length; _i++) {
1057 key = _a[_i];
1058 // use dot notation for merge behavior in gtag.js
1059 flatProperties["user_properties." + key] = properties[key];
1060 }
1061 gtagFunction("set" /* SET */, flatProperties);
1062 return [2 /*return*/, Promise.resolve()];
1063 case 1: return [4 /*yield*/, initializationPromise];
1064 case 2:
1065 measurementId = _b.sent();
1066 gtagFunction("config" /* CONFIG */, measurementId, {
1067 update: true,
1068 'user_properties': properties
1069 });
1070 _b.label = 3;
1071 case 3: return [2 /*return*/];
1072 }
1073 });
1074 });
1075}
1076/**
1077 * Set whether collection is enabled for this ID.
1078 *
1079 * @param enabled If true, collection is enabled for this ID.
1080 */
1081function setAnalyticsCollectionEnabled$1(initializationPromise, enabled) {
1082 return __awaiter(this, void 0, void 0, function () {
1083 var measurementId;
1084 return __generator(this, function (_a) {
1085 switch (_a.label) {
1086 case 0: return [4 /*yield*/, initializationPromise];
1087 case 1:
1088 measurementId = _a.sent();
1089 window["ga-disable-" + measurementId] = !enabled;
1090 return [2 /*return*/];
1091 }
1092 });
1093 });
1094}
1095
1096/* eslint-disable @typescript-eslint/no-explicit-any */
1097/**
1098 * Returns an {@link Analytics} instance for the given app.
1099 *
1100 * @public
1101 *
1102 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1103 */
1104function getAnalytics(app) {
1105 if (app === void 0) { app = getApp(); }
1106 app = getModularInstance(app);
1107 // Dependencies
1108 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1109 if (analyticsProvider.isInitialized()) {
1110 return analyticsProvider.getImmediate();
1111 }
1112 return initializeAnalytics(app);
1113}
1114/**
1115 * Returns an {@link Analytics} instance for the given app.
1116 *
1117 * @public
1118 *
1119 * @param app - The {@link @firebase/app#FirebaseApp} to use.
1120 */
1121function initializeAnalytics(app, options) {
1122 if (options === void 0) { options = {}; }
1123 // Dependencies
1124 var analyticsProvider = _getProvider(app, ANALYTICS_TYPE);
1125 if (analyticsProvider.isInitialized()) {
1126 var existingInstance = analyticsProvider.getImmediate();
1127 if (deepEqual(options, analyticsProvider.getOptions())) {
1128 return existingInstance;
1129 }
1130 else {
1131 throw ERROR_FACTORY.create("already-initialized" /* ALREADY_INITIALIZED */);
1132 }
1133 }
1134 var analyticsInstance = analyticsProvider.initialize({ options: options });
1135 return analyticsInstance;
1136}
1137/**
1138 * This is a public static method provided to users that wraps four different checks:
1139 *
1140 * 1. Check if it's not a browser extension environment.
1141 * 2. Check if cookies are enabled in current browser.
1142 * 3. Check if IndexedDB is supported by the browser environment.
1143 * 4. Check if the current browser context is valid for using `IndexedDB.open()`.
1144 *
1145 * @public
1146 *
1147 */
1148function isSupported() {
1149 return __awaiter(this, void 0, void 0, function () {
1150 var isDBOpenable;
1151 return __generator(this, function (_a) {
1152 switch (_a.label) {
1153 case 0:
1154 if (isBrowserExtension()) {
1155 return [2 /*return*/, false];
1156 }
1157 if (!areCookiesEnabled()) {
1158 return [2 /*return*/, false];
1159 }
1160 if (!isIndexedDBAvailable()) {
1161 return [2 /*return*/, false];
1162 }
1163 _a.label = 1;
1164 case 1:
1165 _a.trys.push([1, 3, , 4]);
1166 return [4 /*yield*/, validateIndexedDBOpenable()];
1167 case 2:
1168 isDBOpenable = _a.sent();
1169 return [2 /*return*/, isDBOpenable];
1170 case 3:
1171 _a.sent();
1172 return [2 /*return*/, false];
1173 case 4: return [2 /*return*/];
1174 }
1175 });
1176 });
1177}
1178/**
1179 * Use gtag `config` command to set `screen_name`.
1180 *
1181 * @public
1182 *
1183 * @param analyticsInstance - The {@link Analytics} instance.
1184 * @param screenName - Screen name to set.
1185 */
1186function setCurrentScreen(analyticsInstance, screenName, options) {
1187 analyticsInstance = getModularInstance(analyticsInstance);
1188 setCurrentScreen$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], screenName, options).catch(function (e) { return logger.error(e); });
1189}
1190/**
1191 * Use gtag `config` command to set `user_id`.
1192 *
1193 * @public
1194 *
1195 * @param analyticsInstance - The {@link Analytics} instance.
1196 * @param id - User ID to set.
1197 */
1198function setUserId(analyticsInstance, id, options) {
1199 analyticsInstance = getModularInstance(analyticsInstance);
1200 setUserId$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], id, options).catch(function (e) { return logger.error(e); });
1201}
1202/**
1203 * Use gtag `config` command to set all params specified.
1204 *
1205 * @public
1206 */
1207function setUserProperties(analyticsInstance, properties, options) {
1208 analyticsInstance = getModularInstance(analyticsInstance);
1209 setUserProperties$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], properties, options).catch(function (e) { return logger.error(e); });
1210}
1211/**
1212 * Sets whether Google Analytics collection is enabled for this app on this device.
1213 * Sets global `window['ga-disable-analyticsId'] = true;`
1214 *
1215 * @public
1216 *
1217 * @param analyticsInstance - The {@link Analytics} instance.
1218 * @param enabled - If true, enables collection, if false, disables it.
1219 */
1220function setAnalyticsCollectionEnabled(analyticsInstance, enabled) {
1221 analyticsInstance = getModularInstance(analyticsInstance);
1222 setAnalyticsCollectionEnabled$1(initializationPromisesMap[analyticsInstance.app.options.appId], enabled).catch(function (e) { return logger.error(e); });
1223}
1224/**
1225 * Sends a Google Analytics event with given `eventParams`. This method
1226 * automatically associates this logged event with this Firebase web
1227 * app instance on this device.
1228 * List of official event parameters can be found in the gtag.js
1229 * reference documentation:
1230 * {@link https://developers.google.com/gtagjs/reference/ga4-events
1231 * | the GA4 reference documentation}.
1232 *
1233 * @public
1234 */
1235function logEvent(analyticsInstance, eventName, eventParams, options) {
1236 analyticsInstance = getModularInstance(analyticsInstance);
1237 logEvent$1(wrappedGtagFunction, initializationPromisesMap[analyticsInstance.app.options.appId], eventName, eventParams, options).catch(function (e) { return logger.error(e); });
1238}
1239
1240var name = "@firebase/analytics";
1241var version = "0.7.5";
1242
1243/**
1244 * Firebase Analytics
1245 *
1246 * @packageDocumentation
1247 */
1248function registerAnalytics() {
1249 _registerComponent(new Component(ANALYTICS_TYPE, function (container, _a) {
1250 var analyticsOptions = _a.options;
1251 // getImmediate for FirebaseApp will always succeed
1252 var app = container.getProvider('app').getImmediate();
1253 var installations = container
1254 .getProvider('installations-internal')
1255 .getImmediate();
1256 return factory(app, installations, analyticsOptions);
1257 }, "PUBLIC" /* PUBLIC */));
1258 _registerComponent(new Component('analytics-internal', internalFactory, "PRIVATE" /* PRIVATE */));
1259 registerVersion(name, version);
1260 // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
1261 registerVersion(name, version, 'esm5');
1262 function internalFactory(container) {
1263 try {
1264 var analytics_1 = container.getProvider(ANALYTICS_TYPE).getImmediate();
1265 return {
1266 logEvent: function (eventName, eventParams, options) { return logEvent(analytics_1, eventName, eventParams, options); }
1267 };
1268 }
1269 catch (e) {
1270 throw ERROR_FACTORY.create("interop-component-reg-failed" /* INTEROP_COMPONENT_REG_FAILED */, {
1271 reason: e
1272 });
1273 }
1274 }
1275}
1276registerAnalytics();
1277
1278export { getAnalytics, initializeAnalytics, isSupported, logEvent, setAnalyticsCollectionEnabled, setCurrentScreen, setUserId, setUserProperties, settings };
1279//# sourceMappingURL=index.esm.js.map