No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.cjs.js 60KB

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