GSI - Employe Self Service Mobile
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.

1412 lines
60 KiB

2 months ago
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var app = require('@firebase/app');
  4. var util = require('@firebase/util');
  5. var component = require('@firebase/component');
  6. var logger = require('@firebase/logger');
  7. var tslib = require('tslib');
  8. require('@firebase/installations');
  9. var name = "@firebase/remote-config";
  10. var version = "0.4.1";
  11. /**
  12. * @license
  13. * Copyright 2019 Google LLC
  14. *
  15. * Licensed under the Apache License, Version 2.0 (the "License");
  16. * you may not use this file except in compliance with the License.
  17. * You may obtain a copy of the License at
  18. *
  19. * http://www.apache.org/licenses/LICENSE-2.0
  20. *
  21. * Unless required by applicable law or agreed to in writing, software
  22. * distributed under the License is distributed on an "AS IS" BASIS,
  23. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  24. * See the License for the specific language governing permissions and
  25. * limitations under the License.
  26. */
  27. /**
  28. * Shims a minimal AbortSignal.
  29. *
  30. * <p>AbortController's AbortSignal conveniently decouples fetch timeout logic from other aspects
  31. * of networking, such as retries. Firebase doesn't use AbortController enough to justify a
  32. * polyfill recommendation, like we do with the Fetch API, but this minimal shim can easily be
  33. * swapped out if/when we do.
  34. */
  35. var RemoteConfigAbortSignal = /** @class */ (function () {
  36. function RemoteConfigAbortSignal() {
  37. this.listeners = [];
  38. }
  39. RemoteConfigAbortSignal.prototype.addEventListener = function (listener) {
  40. this.listeners.push(listener);
  41. };
  42. RemoteConfigAbortSignal.prototype.abort = function () {
  43. this.listeners.forEach(function (listener) { return listener(); });
  44. };
  45. return RemoteConfigAbortSignal;
  46. }());
  47. /**
  48. * @license
  49. * Copyright 2020 Google LLC
  50. *
  51. * Licensed under the Apache License, Version 2.0 (the "License");
  52. * you may not use this file except in compliance with the License.
  53. * You may obtain a copy of the License at
  54. *
  55. * http://www.apache.org/licenses/LICENSE-2.0
  56. *
  57. * Unless required by applicable law or agreed to in writing, software
  58. * distributed under the License is distributed on an "AS IS" BASIS,
  59. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  60. * See the License for the specific language governing permissions and
  61. * limitations under the License.
  62. */
  63. var RC_COMPONENT_NAME = 'remote-config';
  64. /**
  65. * @license
  66. * Copyright 2019 Google LLC
  67. *
  68. * Licensed under the Apache License, Version 2.0 (the "License");
  69. * you may not use this file except in compliance with the License.
  70. * You may obtain a copy of the License at
  71. *
  72. * http://www.apache.org/licenses/LICENSE-2.0
  73. *
  74. * Unless required by applicable law or agreed to in writing, software
  75. * distributed under the License is distributed on an "AS IS" BASIS,
  76. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  77. * See the License for the specific language governing permissions and
  78. * limitations under the License.
  79. */
  80. var _a;
  81. var ERROR_DESCRIPTION_MAP = (_a = {},
  82. _a["registration-window" /* ErrorCode.REGISTRATION_WINDOW */] = 'Undefined window object. This SDK only supports usage in a browser environment.',
  83. _a["registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */] = 'Undefined project identifier. Check Firebase app initialization.',
  84. _a["registration-api-key" /* ErrorCode.REGISTRATION_API_KEY */] = 'Undefined API key. Check Firebase app initialization.',
  85. _a["registration-app-id" /* ErrorCode.REGISTRATION_APP_ID */] = 'Undefined app identifier. Check Firebase app initialization.',
  86. _a["storage-open" /* ErrorCode.STORAGE_OPEN */] = 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
  87. _a["storage-get" /* ErrorCode.STORAGE_GET */] = 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
  88. _a["storage-set" /* ErrorCode.STORAGE_SET */] = 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
  89. _a["storage-delete" /* ErrorCode.STORAGE_DELETE */] = 'Error thrown when deleting from storage. Original error: {$originalErrorMessage}.',
  90. _a["fetch-client-network" /* ErrorCode.FETCH_NETWORK */] = 'Fetch client failed to connect to a network. Check Internet connection.' +
  91. ' Original error: {$originalErrorMessage}.',
  92. _a["fetch-timeout" /* ErrorCode.FETCH_TIMEOUT */] = 'The config fetch request timed out. ' +
  93. ' Configure timeout using "fetchTimeoutMillis" SDK setting.',
  94. _a["fetch-throttle" /* ErrorCode.FETCH_THROTTLE */] = 'The config fetch request timed out while in an exponential backoff state.' +
  95. ' Configure timeout using "fetchTimeoutMillis" SDK setting.' +
  96. ' Unix timestamp in milliseconds when fetch request throttling ends: {$throttleEndTimeMillis}.',
  97. _a["fetch-client-parse" /* ErrorCode.FETCH_PARSE */] = 'Fetch client could not parse response.' +
  98. ' Original error: {$originalErrorMessage}.',
  99. _a["fetch-status" /* ErrorCode.FETCH_STATUS */] = 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.',
  100. _a["indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */] = 'Indexed DB is not supported by current browser',
  101. _a);
  102. var ERROR_FACTORY = new util.ErrorFactory('remoteconfig' /* service */, 'Remote Config' /* service name */, ERROR_DESCRIPTION_MAP);
  103. // Note how this is like typeof/instanceof, but for ErrorCode.
  104. function hasErrorCode(e, errorCode) {
  105. return e instanceof util.FirebaseError && e.code.indexOf(errorCode) !== -1;
  106. }
  107. /**
  108. * @license
  109. * Copyright 2019 Google LLC
  110. *
  111. * Licensed under the Apache License, Version 2.0 (the "License");
  112. * you may not use this file except in compliance with the License.
  113. * You may obtain a copy of the License at
  114. *
  115. * http://www.apache.org/licenses/LICENSE-2.0
  116. *
  117. * Unless required by applicable law or agreed to in writing, software
  118. * distributed under the License is distributed on an "AS IS" BASIS,
  119. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  120. * See the License for the specific language governing permissions and
  121. * limitations under the License.
  122. */
  123. var DEFAULT_VALUE_FOR_BOOLEAN = false;
  124. var DEFAULT_VALUE_FOR_STRING = '';
  125. var DEFAULT_VALUE_FOR_NUMBER = 0;
  126. var BOOLEAN_TRUTHY_VALUES = ['1', 'true', 't', 'yes', 'y', 'on'];
  127. var Value = /** @class */ (function () {
  128. function Value(_source, _value) {
  129. if (_value === void 0) { _value = DEFAULT_VALUE_FOR_STRING; }
  130. this._source = _source;
  131. this._value = _value;
  132. }
  133. Value.prototype.asString = function () {
  134. return this._value;
  135. };
  136. Value.prototype.asBoolean = function () {
  137. if (this._source === 'static') {
  138. return DEFAULT_VALUE_FOR_BOOLEAN;
  139. }
  140. return BOOLEAN_TRUTHY_VALUES.indexOf(this._value.toLowerCase()) >= 0;
  141. };
  142. Value.prototype.asNumber = function () {
  143. if (this._source === 'static') {
  144. return DEFAULT_VALUE_FOR_NUMBER;
  145. }
  146. var num = Number(this._value);
  147. if (isNaN(num)) {
  148. num = DEFAULT_VALUE_FOR_NUMBER;
  149. }
  150. return num;
  151. };
  152. Value.prototype.getSource = function () {
  153. return this._source;
  154. };
  155. return Value;
  156. }());
  157. /**
  158. * @license
  159. * Copyright 2020 Google LLC
  160. *
  161. * Licensed under the Apache License, Version 2.0 (the "License");
  162. * you may not use this file except in compliance with the License.
  163. * You may obtain a copy of the License at
  164. *
  165. * http://www.apache.org/licenses/LICENSE-2.0
  166. *
  167. * Unless required by applicable law or agreed to in writing, software
  168. * distributed under the License is distributed on an "AS IS" BASIS,
  169. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  170. * See the License for the specific language governing permissions and
  171. * limitations under the License.
  172. */
  173. /**
  174. *
  175. * @param app - The {@link @firebase/app#FirebaseApp} instance.
  176. * @returns A {@link RemoteConfig} instance.
  177. *
  178. * @public
  179. */
  180. function getRemoteConfig(app$1) {
  181. if (app$1 === void 0) { app$1 = app.getApp(); }
  182. app$1 = util.getModularInstance(app$1);
  183. var rcProvider = app._getProvider(app$1, RC_COMPONENT_NAME);
  184. return rcProvider.getImmediate();
  185. }
  186. /**
  187. * Makes the last fetched config available to the getters.
  188. * @param remoteConfig - The {@link RemoteConfig} instance.
  189. * @returns A `Promise` which resolves to true if the current call activated the fetched configs.
  190. * If the fetched configs were already activated, the `Promise` will resolve to false.
  191. *
  192. * @public
  193. */
  194. function activate(remoteConfig) {
  195. return tslib.__awaiter(this, void 0, void 0, function () {
  196. var rc, _a, lastSuccessfulFetchResponse, activeConfigEtag;
  197. return tslib.__generator(this, function (_b) {
  198. switch (_b.label) {
  199. case 0:
  200. rc = util.getModularInstance(remoteConfig);
  201. return [4 /*yield*/, Promise.all([
  202. rc._storage.getLastSuccessfulFetchResponse(),
  203. rc._storage.getActiveConfigEtag()
  204. ])];
  205. case 1:
  206. _a = _b.sent(), lastSuccessfulFetchResponse = _a[0], activeConfigEtag = _a[1];
  207. if (!lastSuccessfulFetchResponse ||
  208. !lastSuccessfulFetchResponse.config ||
  209. !lastSuccessfulFetchResponse.eTag ||
  210. lastSuccessfulFetchResponse.eTag === activeConfigEtag) {
  211. // Either there is no successful fetched config, or is the same as current active
  212. // config.
  213. return [2 /*return*/, false];
  214. }
  215. return [4 /*yield*/, Promise.all([
  216. rc._storageCache.setActiveConfig(lastSuccessfulFetchResponse.config),
  217. rc._storage.setActiveConfigEtag(lastSuccessfulFetchResponse.eTag)
  218. ])];
  219. case 2:
  220. _b.sent();
  221. return [2 /*return*/, true];
  222. }
  223. });
  224. });
  225. }
  226. /**
  227. * Ensures the last activated config are available to the getters.
  228. * @param remoteConfig - The {@link RemoteConfig} instance.
  229. *
  230. * @returns A `Promise` that resolves when the last activated config is available to the getters.
  231. * @public
  232. */
  233. function ensureInitialized(remoteConfig) {
  234. var rc = util.getModularInstance(remoteConfig);
  235. if (!rc._initializePromise) {
  236. rc._initializePromise = rc._storageCache.loadFromStorage().then(function () {
  237. rc._isInitializationComplete = true;
  238. });
  239. }
  240. return rc._initializePromise;
  241. }
  242. /**
  243. * Fetches and caches configuration from the Remote Config service.
  244. * @param remoteConfig - The {@link RemoteConfig} instance.
  245. * @public
  246. */
  247. function fetchConfig(remoteConfig) {
  248. return tslib.__awaiter(this, void 0, void 0, function () {
  249. var rc, abortSignal, e_1, lastFetchStatus;
  250. var _this = this;
  251. return tslib.__generator(this, function (_a) {
  252. switch (_a.label) {
  253. case 0:
  254. rc = util.getModularInstance(remoteConfig);
  255. abortSignal = new RemoteConfigAbortSignal();
  256. setTimeout(function () { return tslib.__awaiter(_this, void 0, void 0, function () {
  257. return tslib.__generator(this, function (_a) {
  258. // Note a very low delay, eg < 10ms, can elapse before listeners are initialized.
  259. abortSignal.abort();
  260. return [2 /*return*/];
  261. });
  262. }); }, rc.settings.fetchTimeoutMillis);
  263. _a.label = 1;
  264. case 1:
  265. _a.trys.push([1, 4, , 6]);
  266. return [4 /*yield*/, rc._client.fetch({
  267. cacheMaxAgeMillis: rc.settings.minimumFetchIntervalMillis,
  268. signal: abortSignal
  269. })];
  270. case 2:
  271. _a.sent();
  272. return [4 /*yield*/, rc._storageCache.setLastFetchStatus('success')];
  273. case 3:
  274. _a.sent();
  275. return [3 /*break*/, 6];
  276. case 4:
  277. e_1 = _a.sent();
  278. lastFetchStatus = hasErrorCode(e_1, "fetch-throttle" /* ErrorCode.FETCH_THROTTLE */)
  279. ? 'throttle'
  280. : 'failure';
  281. return [4 /*yield*/, rc._storageCache.setLastFetchStatus(lastFetchStatus)];
  282. case 5:
  283. _a.sent();
  284. throw e_1;
  285. case 6: return [2 /*return*/];
  286. }
  287. });
  288. });
  289. }
  290. /**
  291. * Gets all config.
  292. *
  293. * @param remoteConfig - The {@link RemoteConfig} instance.
  294. * @returns All config.
  295. *
  296. * @public
  297. */
  298. function getAll(remoteConfig) {
  299. var rc = util.getModularInstance(remoteConfig);
  300. return getAllKeys(rc._storageCache.getActiveConfig(), rc.defaultConfig).reduce(function (allConfigs, key) {
  301. allConfigs[key] = getValue(remoteConfig, key);
  302. return allConfigs;
  303. }, {});
  304. }
  305. /**
  306. * Gets the value for the given key as a boolean.
  307. *
  308. * Convenience method for calling <code>remoteConfig.getValue(key).asBoolean()</code>.
  309. *
  310. * @param remoteConfig - The {@link RemoteConfig} instance.
  311. * @param key - The name of the parameter.
  312. *
  313. * @returns The value for the given key as a boolean.
  314. * @public
  315. */
  316. function getBoolean(remoteConfig, key) {
  317. return getValue(util.getModularInstance(remoteConfig), key).asBoolean();
  318. }
  319. /**
  320. * Gets the value for the given key as a number.
  321. *
  322. * Convenience method for calling <code>remoteConfig.getValue(key).asNumber()</code>.
  323. *
  324. * @param remoteConfig - The {@link RemoteConfig} instance.
  325. * @param key - The name of the parameter.
  326. *
  327. * @returns The value for the given key as a number.
  328. *
  329. * @public
  330. */
  331. function getNumber(remoteConfig, key) {
  332. return getValue(util.getModularInstance(remoteConfig), key).asNumber();
  333. }
  334. /**
  335. * Gets the value for the given key as a string.
  336. * Convenience method for calling <code>remoteConfig.getValue(key).asString()</code>.
  337. *
  338. * @param remoteConfig - The {@link RemoteConfig} instance.
  339. * @param key - The name of the parameter.
  340. *
  341. * @returns The value for the given key as a string.
  342. *
  343. * @public
  344. */
  345. function getString(remoteConfig, key) {
  346. return getValue(util.getModularInstance(remoteConfig), key).asString();
  347. }
  348. /**
  349. * Gets the {@link Value} for the given key.
  350. *
  351. * @param remoteConfig - The {@link RemoteConfig} instance.
  352. * @param key - The name of the parameter.
  353. *
  354. * @returns The value for the given key.
  355. *
  356. * @public
  357. */
  358. function getValue(remoteConfig, key) {
  359. var rc = util.getModularInstance(remoteConfig);
  360. if (!rc._isInitializationComplete) {
  361. rc._logger.debug("A value was requested for key \"".concat(key, "\" before SDK initialization completed.") +
  362. ' Await on ensureInitialized if the intent was to get a previously activated value.');
  363. }
  364. var activeConfig = rc._storageCache.getActiveConfig();
  365. if (activeConfig && activeConfig[key] !== undefined) {
  366. return new Value('remote', activeConfig[key]);
  367. }
  368. else if (rc.defaultConfig && rc.defaultConfig[key] !== undefined) {
  369. return new Value('default', String(rc.defaultConfig[key]));
  370. }
  371. rc._logger.debug("Returning static value for key \"".concat(key, "\".") +
  372. ' Define a default or remote value if this is unintentional.');
  373. return new Value('static');
  374. }
  375. /**
  376. * Defines the log level to use.
  377. *
  378. * @param remoteConfig - The {@link RemoteConfig} instance.
  379. * @param logLevel - The log level to set.
  380. *
  381. * @public
  382. */
  383. function setLogLevel(remoteConfig, logLevel) {
  384. var rc = util.getModularInstance(remoteConfig);
  385. switch (logLevel) {
  386. case 'debug':
  387. rc._logger.logLevel = logger.LogLevel.DEBUG;
  388. break;
  389. case 'silent':
  390. rc._logger.logLevel = logger.LogLevel.SILENT;
  391. break;
  392. default:
  393. rc._logger.logLevel = logger.LogLevel.ERROR;
  394. }
  395. }
  396. /**
  397. * Dedupes and returns an array of all the keys of the received objects.
  398. */
  399. function getAllKeys(obj1, obj2) {
  400. if (obj1 === void 0) { obj1 = {}; }
  401. if (obj2 === void 0) { obj2 = {}; }
  402. return Object.keys(tslib.__assign(tslib.__assign({}, obj1), obj2));
  403. }
  404. /**
  405. * @license
  406. * Copyright 2019 Google LLC
  407. *
  408. * Licensed under the Apache License, Version 2.0 (the "License");
  409. * you may not use this file except in compliance with the License.
  410. * You may obtain a copy of the License at
  411. *
  412. * http://www.apache.org/licenses/LICENSE-2.0
  413. *
  414. * Unless required by applicable law or agreed to in writing, software
  415. * distributed under the License is distributed on an "AS IS" BASIS,
  416. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  417. * See the License for the specific language governing permissions and
  418. * limitations under the License.
  419. */
  420. /**
  421. * Implements the {@link RemoteConfigClient} abstraction with success response caching.
  422. *
  423. * <p>Comparable to the browser's Cache API for responses, but the Cache API requires a Service
  424. * Worker, which requires HTTPS, which would significantly complicate SDK installation. Also, the
  425. * Cache API doesn't support matching entries by time.
  426. */
  427. var CachingClient = /** @class */ (function () {
  428. function CachingClient(client, storage, storageCache, logger) {
  429. this.client = client;
  430. this.storage = storage;
  431. this.storageCache = storageCache;
  432. this.logger = logger;
  433. }
  434. /**
  435. * Returns true if the age of the cached fetched configs is less than or equal to
  436. * {@link Settings#minimumFetchIntervalInSeconds}.
  437. *
  438. * <p>This is comparable to passing `headers = { 'Cache-Control': max-age <maxAge> }` to the
  439. * native Fetch API.
  440. *
  441. * <p>Visible for testing.
  442. */
  443. CachingClient.prototype.isCachedDataFresh = function (cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis) {
  444. // Cache can only be fresh if it's populated.
  445. if (!lastSuccessfulFetchTimestampMillis) {
  446. this.logger.debug('Config fetch cache check. Cache unpopulated.');
  447. return false;
  448. }
  449. // Calculates age of cache entry.
  450. var cacheAgeMillis = Date.now() - lastSuccessfulFetchTimestampMillis;
  451. var isCachedDataFresh = cacheAgeMillis <= cacheMaxAgeMillis;
  452. this.logger.debug('Config fetch cache check.' +
  453. " Cache age millis: ".concat(cacheAgeMillis, ".") +
  454. " Cache max age millis (minimumFetchIntervalMillis setting): ".concat(cacheMaxAgeMillis, ".") +
  455. " Is cache hit: ".concat(isCachedDataFresh, "."));
  456. return isCachedDataFresh;
  457. };
  458. CachingClient.prototype.fetch = function (request) {
  459. return tslib.__awaiter(this, void 0, void 0, function () {
  460. var _a, lastSuccessfulFetchTimestampMillis, lastSuccessfulFetchResponse, response, storageOperations;
  461. return tslib.__generator(this, function (_b) {
  462. switch (_b.label) {
  463. case 0: return [4 /*yield*/, Promise.all([
  464. this.storage.getLastSuccessfulFetchTimestampMillis(),
  465. this.storage.getLastSuccessfulFetchResponse()
  466. ])];
  467. case 1:
  468. _a = _b.sent(), lastSuccessfulFetchTimestampMillis = _a[0], lastSuccessfulFetchResponse = _a[1];
  469. // Exits early on cache hit.
  470. if (lastSuccessfulFetchResponse &&
  471. this.isCachedDataFresh(request.cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis)) {
  472. return [2 /*return*/, lastSuccessfulFetchResponse];
  473. }
  474. // Deviates from pure decorator by not honoring a passed ETag since we don't have a public API
  475. // that allows the caller to pass an ETag.
  476. request.eTag =
  477. lastSuccessfulFetchResponse && lastSuccessfulFetchResponse.eTag;
  478. return [4 /*yield*/, this.client.fetch(request)];
  479. case 2:
  480. response = _b.sent();
  481. storageOperations = [
  482. // Uses write-through cache for consistency with synchronous public API.
  483. this.storageCache.setLastSuccessfulFetchTimestampMillis(Date.now())
  484. ];
  485. if (response.status === 200) {
  486. // Caches response only if it has changed, ie non-304 responses.
  487. storageOperations.push(this.storage.setLastSuccessfulFetchResponse(response));
  488. }
  489. return [4 /*yield*/, Promise.all(storageOperations)];
  490. case 3:
  491. _b.sent();
  492. return [2 /*return*/, response];
  493. }
  494. });
  495. });
  496. };
  497. return CachingClient;
  498. }());
  499. /**
  500. * @license
  501. * Copyright 2019 Google LLC
  502. *
  503. * Licensed under the Apache License, Version 2.0 (the "License");
  504. * you may not use this file except in compliance with the License.
  505. * You may obtain a copy of the License at
  506. *
  507. * http://www.apache.org/licenses/LICENSE-2.0
  508. *
  509. * Unless required by applicable law or agreed to in writing, software
  510. * distributed under the License is distributed on an "AS IS" BASIS,
  511. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  512. * See the License for the specific language governing permissions and
  513. * limitations under the License.
  514. */
  515. /**
  516. * Attempts to get the most accurate browser language setting.
  517. *
  518. * <p>Adapted from getUserLanguage in packages/auth/src/utils.js for TypeScript.
  519. *
  520. * <p>Defers default language specification to server logic for consistency.
  521. *
  522. * @param navigatorLanguage Enables tests to override read-only {@link NavigatorLanguage}.
  523. */
  524. function getUserLanguage(navigatorLanguage) {
  525. if (navigatorLanguage === void 0) { navigatorLanguage = navigator; }
  526. return (
  527. // Most reliable, but only supported in Chrome/Firefox.
  528. (navigatorLanguage.languages && navigatorLanguage.languages[0]) ||
  529. // Supported in most browsers, but returns the language of the browser
  530. // UI, not the language set in browser settings.
  531. navigatorLanguage.language
  532. // Polyfill otherwise.
  533. );
  534. }
  535. /**
  536. * @license
  537. * Copyright 2019 Google LLC
  538. *
  539. * Licensed under the Apache License, Version 2.0 (the "License");
  540. * you may not use this file except in compliance with the License.
  541. * You may obtain a copy of the License at
  542. *
  543. * http://www.apache.org/licenses/LICENSE-2.0
  544. *
  545. * Unless required by applicable law or agreed to in writing, software
  546. * distributed under the License is distributed on an "AS IS" BASIS,
  547. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  548. * See the License for the specific language governing permissions and
  549. * limitations under the License.
  550. */
  551. /**
  552. * Implements the Client abstraction for the Remote Config REST API.
  553. */
  554. var RestClient = /** @class */ (function () {
  555. function RestClient(firebaseInstallations, sdkVersion, namespace, projectId, apiKey, appId) {
  556. this.firebaseInstallations = firebaseInstallations;
  557. this.sdkVersion = sdkVersion;
  558. this.namespace = namespace;
  559. this.projectId = projectId;
  560. this.apiKey = apiKey;
  561. this.appId = appId;
  562. }
  563. /**
  564. * Fetches from the Remote Config REST API.
  565. *
  566. * @throws a {@link ErrorCode.FETCH_NETWORK} error if {@link GlobalFetch#fetch} can't
  567. * connect to the network.
  568. * @throws a {@link ErrorCode.FETCH_PARSE} error if {@link Response#json} can't parse the
  569. * fetch response.
  570. * @throws a {@link ErrorCode.FETCH_STATUS} error if the service returns an HTTP error status.
  571. */
  572. RestClient.prototype.fetch = function (request) {
  573. return tslib.__awaiter(this, void 0, void 0, function () {
  574. var _a, installationId, installationToken, urlBase, url, headers, requestBody, options, fetchPromise, timeoutPromise, response, originalError_1, errorCode, status, responseEtag, config, state, responseBody, originalError_2;
  575. return tslib.__generator(this, function (_b) {
  576. switch (_b.label) {
  577. case 0: return [4 /*yield*/, Promise.all([
  578. this.firebaseInstallations.getId(),
  579. this.firebaseInstallations.getToken()
  580. ])];
  581. case 1:
  582. _a = _b.sent(), installationId = _a[0], installationToken = _a[1];
  583. urlBase = window.FIREBASE_REMOTE_CONFIG_URL_BASE ||
  584. 'https://firebaseremoteconfig.googleapis.com';
  585. url = "".concat(urlBase, "/v1/projects/").concat(this.projectId, "/namespaces/").concat(this.namespace, ":fetch?key=").concat(this.apiKey);
  586. headers = {
  587. 'Content-Type': 'application/json',
  588. 'Content-Encoding': 'gzip',
  589. // Deviates from pure decorator by not passing max-age header since we don't currently have
  590. // service behavior using that header.
  591. 'If-None-Match': request.eTag || '*'
  592. };
  593. requestBody = {
  594. /* eslint-disable camelcase */
  595. sdk_version: this.sdkVersion,
  596. app_instance_id: installationId,
  597. app_instance_id_token: installationToken,
  598. app_id: this.appId,
  599. language_code: getUserLanguage()
  600. /* eslint-enable camelcase */
  601. };
  602. options = {
  603. method: 'POST',
  604. headers: headers,
  605. body: JSON.stringify(requestBody)
  606. };
  607. fetchPromise = fetch(url, options);
  608. timeoutPromise = new Promise(function (_resolve, reject) {
  609. // Maps async event listener to Promise API.
  610. request.signal.addEventListener(function () {
  611. // Emulates https://heycam.github.io/webidl/#aborterror
  612. var error = new Error('The operation was aborted.');
  613. error.name = 'AbortError';
  614. reject(error);
  615. });
  616. });
  617. _b.label = 2;
  618. case 2:
  619. _b.trys.push([2, 5, , 6]);
  620. return [4 /*yield*/, Promise.race([fetchPromise, timeoutPromise])];
  621. case 3:
  622. _b.sent();
  623. return [4 /*yield*/, fetchPromise];
  624. case 4:
  625. response = _b.sent();
  626. return [3 /*break*/, 6];
  627. case 5:
  628. originalError_1 = _b.sent();
  629. errorCode = "fetch-client-network" /* ErrorCode.FETCH_NETWORK */;
  630. if ((originalError_1 === null || originalError_1 === void 0 ? void 0 : originalError_1.name) === 'AbortError') {
  631. errorCode = "fetch-timeout" /* ErrorCode.FETCH_TIMEOUT */;
  632. }
  633. throw ERROR_FACTORY.create(errorCode, {
  634. originalErrorMessage: originalError_1 === null || originalError_1 === void 0 ? void 0 : originalError_1.message
  635. });
  636. case 6:
  637. status = response.status;
  638. responseEtag = response.headers.get('ETag') || undefined;
  639. if (!(response.status === 200)) return [3 /*break*/, 11];
  640. responseBody = void 0;
  641. _b.label = 7;
  642. case 7:
  643. _b.trys.push([7, 9, , 10]);
  644. return [4 /*yield*/, response.json()];
  645. case 8:
  646. responseBody = _b.sent();
  647. return [3 /*break*/, 10];
  648. case 9:
  649. originalError_2 = _b.sent();
  650. throw ERROR_FACTORY.create("fetch-client-parse" /* ErrorCode.FETCH_PARSE */, {
  651. originalErrorMessage: originalError_2 === null || originalError_2 === void 0 ? void 0 : originalError_2.message
  652. });
  653. case 10:
  654. config = responseBody['entries'];
  655. state = responseBody['state'];
  656. _b.label = 11;
  657. case 11:
  658. // Normalizes based on legacy state.
  659. if (state === 'INSTANCE_STATE_UNSPECIFIED') {
  660. status = 500;
  661. }
  662. else if (state === 'NO_CHANGE') {
  663. status = 304;
  664. }
  665. else if (state === 'NO_TEMPLATE' || state === 'EMPTY_CONFIG') {
  666. // These cases can be fixed remotely, so normalize to safe value.
  667. config = {};
  668. }
  669. // Normalize to exception-based control flow for non-success cases.
  670. // Encapsulates HTTP specifics in this class as much as possible. Status is still the best for
  671. // differentiating success states (200 from 304; the state body param is undefined in a
  672. // standard 304).
  673. if (status !== 304 && status !== 200) {
  674. throw ERROR_FACTORY.create("fetch-status" /* ErrorCode.FETCH_STATUS */, {
  675. httpStatus: status
  676. });
  677. }
  678. return [2 /*return*/, { status: status, eTag: responseEtag, config: config }];
  679. }
  680. });
  681. });
  682. };
  683. return RestClient;
  684. }());
  685. /**
  686. * @license
  687. * Copyright 2019 Google LLC
  688. *
  689. * Licensed under the Apache License, Version 2.0 (the "License");
  690. * you may not use this file except in compliance with the License.
  691. * You may obtain a copy of the License at
  692. *
  693. * http://www.apache.org/licenses/LICENSE-2.0
  694. *
  695. * Unless required by applicable law or agreed to in writing, software
  696. * distributed under the License is distributed on an "AS IS" BASIS,
  697. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  698. * See the License for the specific language governing permissions and
  699. * limitations under the License.
  700. */
  701. /**
  702. * Supports waiting on a backoff by:
  703. *
  704. * <ul>
  705. * <li>Promisifying setTimeout, so we can set a timeout in our Promise chain</li>
  706. * <li>Listening on a signal bus for abort events, just like the Fetch API</li>
  707. * <li>Failing in the same way the Fetch API fails, so timing out a live request and a throttled
  708. * request appear the same.</li>
  709. * </ul>
  710. *
  711. * <p>Visible for testing.
  712. */
  713. function setAbortableTimeout(signal, throttleEndTimeMillis) {
  714. return new Promise(function (resolve, reject) {
  715. // Derives backoff from given end time, normalizing negative numbers to zero.
  716. var backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0);
  717. var timeout = setTimeout(resolve, backoffMillis);
  718. // Adds listener, rather than sets onabort, because signal is a shared object.
  719. signal.addEventListener(function () {
  720. clearTimeout(timeout);
  721. // If the request completes before this timeout, the rejection has no effect.
  722. reject(ERROR_FACTORY.create("fetch-throttle" /* ErrorCode.FETCH_THROTTLE */, {
  723. throttleEndTimeMillis: throttleEndTimeMillis
  724. }));
  725. });
  726. });
  727. }
  728. /**
  729. * Returns true if the {@link Error} indicates a fetch request may succeed later.
  730. */
  731. function isRetriableError(e) {
  732. if (!(e instanceof util.FirebaseError) || !e.customData) {
  733. return false;
  734. }
  735. // Uses string index defined by ErrorData, which FirebaseError implements.
  736. var httpStatus = Number(e.customData['httpStatus']);
  737. return (httpStatus === 429 ||
  738. httpStatus === 500 ||
  739. httpStatus === 503 ||
  740. httpStatus === 504);
  741. }
  742. /**
  743. * Decorates a Client with retry logic.
  744. *
  745. * <p>Comparable to CachingClient, but uses backoff logic instead of cache max age and doesn't cache
  746. * responses (because the SDK has no use for error responses).
  747. */
  748. var RetryingClient = /** @class */ (function () {
  749. function RetryingClient(client, storage) {
  750. this.client = client;
  751. this.storage = storage;
  752. }
  753. RetryingClient.prototype.fetch = function (request) {
  754. return tslib.__awaiter(this, void 0, void 0, function () {
  755. var throttleMetadata;
  756. return tslib.__generator(this, function (_a) {
  757. switch (_a.label) {
  758. case 0: return [4 /*yield*/, this.storage.getThrottleMetadata()];
  759. case 1:
  760. throttleMetadata = (_a.sent()) || {
  761. backoffCount: 0,
  762. throttleEndTimeMillis: Date.now()
  763. };
  764. return [2 /*return*/, this.attemptFetch(request, throttleMetadata)];
  765. }
  766. });
  767. });
  768. };
  769. /**
  770. * A recursive helper for attempting a fetch request repeatedly.
  771. *
  772. * @throws any non-retriable errors.
  773. */
  774. RetryingClient.prototype.attemptFetch = function (request, _a) {
  775. var throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount;
  776. return tslib.__awaiter(this, void 0, void 0, function () {
  777. var response, e_1, throttleMetadata;
  778. return tslib.__generator(this, function (_b) {
  779. switch (_b.label) {
  780. case 0:
  781. // Starts with a (potentially zero) timeout to support resumption from stored state.
  782. // Ensures the throttle end time is honored if the last attempt timed out.
  783. // Note the SDK will never make a request if the fetch timeout expires at this point.
  784. return [4 /*yield*/, setAbortableTimeout(request.signal, throttleEndTimeMillis)];
  785. case 1:
  786. // Starts with a (potentially zero) timeout to support resumption from stored state.
  787. // Ensures the throttle end time is honored if the last attempt timed out.
  788. // Note the SDK will never make a request if the fetch timeout expires at this point.
  789. _b.sent();
  790. _b.label = 2;
  791. case 2:
  792. _b.trys.push([2, 5, , 7]);
  793. return [4 /*yield*/, this.client.fetch(request)];
  794. case 3:
  795. response = _b.sent();
  796. // Note the SDK only clears throttle state if response is success or non-retriable.
  797. return [4 /*yield*/, this.storage.deleteThrottleMetadata()];
  798. case 4:
  799. // Note the SDK only clears throttle state if response is success or non-retriable.
  800. _b.sent();
  801. return [2 /*return*/, response];
  802. case 5:
  803. e_1 = _b.sent();
  804. if (!isRetriableError(e_1)) {
  805. throw e_1;
  806. }
  807. throttleMetadata = {
  808. throttleEndTimeMillis: Date.now() + util.calculateBackoffMillis(backoffCount),
  809. backoffCount: backoffCount + 1
  810. };
  811. // Persists state.
  812. return [4 /*yield*/, this.storage.setThrottleMetadata(throttleMetadata)];
  813. case 6:
  814. // Persists state.
  815. _b.sent();
  816. return [2 /*return*/, this.attemptFetch(request, throttleMetadata)];
  817. case 7: return [2 /*return*/];
  818. }
  819. });
  820. });
  821. };
  822. return RetryingClient;
  823. }());
  824. /**
  825. * @license
  826. * Copyright 2019 Google LLC
  827. *
  828. * Licensed under the Apache License, Version 2.0 (the "License");
  829. * you may not use this file except in compliance with the License.
  830. * You may obtain a copy of the License at
  831. *
  832. * http://www.apache.org/licenses/LICENSE-2.0
  833. *
  834. * Unless required by applicable law or agreed to in writing, software
  835. * distributed under the License is distributed on an "AS IS" BASIS,
  836. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  837. * See the License for the specific language governing permissions and
  838. * limitations under the License.
  839. */
  840. var DEFAULT_FETCH_TIMEOUT_MILLIS = 60 * 1000; // One minute
  841. var DEFAULT_CACHE_MAX_AGE_MILLIS = 12 * 60 * 60 * 1000; // Twelve hours.
  842. /**
  843. * Encapsulates business logic mapping network and storage dependencies to the public SDK API.
  844. *
  845. * See {@link https://github.com/FirebasePrivate/firebase-js-sdk/blob/master/packages/firebase/index.d.ts|interface documentation} for method descriptions.
  846. */
  847. var RemoteConfig = /** @class */ (function () {
  848. function RemoteConfig(
  849. // Required by FirebaseServiceFactory interface.
  850. app,
  851. // JS doesn't support private yet
  852. // (https://github.com/tc39/proposal-class-fields#private-fields), so we hint using an
  853. // underscore prefix.
  854. /**
  855. * @internal
  856. */
  857. _client,
  858. /**
  859. * @internal
  860. */
  861. _storageCache,
  862. /**
  863. * @internal
  864. */
  865. _storage,
  866. /**
  867. * @internal
  868. */
  869. _logger) {
  870. this.app = app;
  871. this._client = _client;
  872. this._storageCache = _storageCache;
  873. this._storage = _storage;
  874. this._logger = _logger;
  875. /**
  876. * Tracks completion of initialization promise.
  877. * @internal
  878. */
  879. this._isInitializationComplete = false;
  880. this.settings = {
  881. fetchTimeoutMillis: DEFAULT_FETCH_TIMEOUT_MILLIS,
  882. minimumFetchIntervalMillis: DEFAULT_CACHE_MAX_AGE_MILLIS
  883. };
  884. this.defaultConfig = {};
  885. }
  886. Object.defineProperty(RemoteConfig.prototype, "fetchTimeMillis", {
  887. get: function () {
  888. return this._storageCache.getLastSuccessfulFetchTimestampMillis() || -1;
  889. },
  890. enumerable: false,
  891. configurable: true
  892. });
  893. Object.defineProperty(RemoteConfig.prototype, "lastFetchStatus", {
  894. get: function () {
  895. return this._storageCache.getLastFetchStatus() || 'no-fetch-yet';
  896. },
  897. enumerable: false,
  898. configurable: true
  899. });
  900. return RemoteConfig;
  901. }());
  902. /**
  903. * @license
  904. * Copyright 2019 Google LLC
  905. *
  906. * Licensed under the Apache License, Version 2.0 (the "License");
  907. * you may not use this file except in compliance with the License.
  908. * You may obtain a copy of the License at
  909. *
  910. * http://www.apache.org/licenses/LICENSE-2.0
  911. *
  912. * Unless required by applicable law or agreed to in writing, software
  913. * distributed under the License is distributed on an "AS IS" BASIS,
  914. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  915. * See the License for the specific language governing permissions and
  916. * limitations under the License.
  917. */
  918. /**
  919. * Converts an error event associated with a {@link IDBRequest} to a {@link FirebaseError}.
  920. */
  921. function toFirebaseError(event, errorCode) {
  922. var originalError = event.target.error || undefined;
  923. return ERROR_FACTORY.create(errorCode, {
  924. originalErrorMessage: originalError && (originalError === null || originalError === void 0 ? void 0 : originalError.message)
  925. });
  926. }
  927. /**
  928. * A general-purpose store keyed by app + namespace + {@link
  929. * ProjectNamespaceKeyFieldValue}.
  930. *
  931. * <p>The Remote Config SDK can be used with multiple app installations, and each app can interact
  932. * with multiple namespaces, so this store uses app (ID + name) and namespace as common parent keys
  933. * for a set of key-value pairs. See {@link Storage#createCompositeKey}.
  934. *
  935. * <p>Visible for testing.
  936. */
  937. var APP_NAMESPACE_STORE = 'app_namespace_store';
  938. var DB_NAME = 'firebase_remote_config';
  939. var DB_VERSION = 1;
  940. // Visible for testing.
  941. function openDatabase() {
  942. return new Promise(function (resolve, reject) {
  943. try {
  944. var request = indexedDB.open(DB_NAME, DB_VERSION);
  945. request.onerror = function (event) {
  946. reject(toFirebaseError(event, "storage-open" /* ErrorCode.STORAGE_OPEN */));
  947. };
  948. request.onsuccess = function (event) {
  949. resolve(event.target.result);
  950. };
  951. request.onupgradeneeded = function (event) {
  952. var db = event.target.result;
  953. // We don't use 'break' in this switch statement, the fall-through
  954. // behavior is what we want, because if there are multiple versions between
  955. // the old version and the current version, we want ALL the migrations
  956. // that correspond to those versions to run, not only the last one.
  957. // eslint-disable-next-line default-case
  958. switch (event.oldVersion) {
  959. case 0:
  960. db.createObjectStore(APP_NAMESPACE_STORE, {
  961. keyPath: 'compositeKey'
  962. });
  963. }
  964. };
  965. }
  966. catch (error) {
  967. reject(ERROR_FACTORY.create("storage-open" /* ErrorCode.STORAGE_OPEN */, {
  968. originalErrorMessage: error === null || error === void 0 ? void 0 : error.message
  969. }));
  970. }
  971. });
  972. }
  973. /**
  974. * Abstracts data persistence.
  975. */
  976. var Storage = /** @class */ (function () {
  977. /**
  978. * @param appId enables storage segmentation by app (ID + name).
  979. * @param appName enables storage segmentation by app (ID + name).
  980. * @param namespace enables storage segmentation by namespace.
  981. */
  982. function Storage(appId, appName, namespace, openDbPromise) {
  983. if (openDbPromise === void 0) { openDbPromise = openDatabase(); }
  984. this.appId = appId;
  985. this.appName = appName;
  986. this.namespace = namespace;
  987. this.openDbPromise = openDbPromise;
  988. }
  989. Storage.prototype.getLastFetchStatus = function () {
  990. return this.get('last_fetch_status');
  991. };
  992. Storage.prototype.setLastFetchStatus = function (status) {
  993. return this.set('last_fetch_status', status);
  994. };
  995. // This is comparable to a cache entry timestamp. If we need to expire other data, we could
  996. // consider adding timestamp to all storage records and an optional max age arg to getters.
  997. Storage.prototype.getLastSuccessfulFetchTimestampMillis = function () {
  998. return this.get('last_successful_fetch_timestamp_millis');
  999. };
  1000. Storage.prototype.setLastSuccessfulFetchTimestampMillis = function (timestamp) {
  1001. return this.set('last_successful_fetch_timestamp_millis', timestamp);
  1002. };
  1003. Storage.prototype.getLastSuccessfulFetchResponse = function () {
  1004. return this.get('last_successful_fetch_response');
  1005. };
  1006. Storage.prototype.setLastSuccessfulFetchResponse = function (response) {
  1007. return this.set('last_successful_fetch_response', response);
  1008. };
  1009. Storage.prototype.getActiveConfig = function () {
  1010. return this.get('active_config');
  1011. };
  1012. Storage.prototype.setActiveConfig = function (config) {
  1013. return this.set('active_config', config);
  1014. };
  1015. Storage.prototype.getActiveConfigEtag = function () {
  1016. return this.get('active_config_etag');
  1017. };
  1018. Storage.prototype.setActiveConfigEtag = function (etag) {
  1019. return this.set('active_config_etag', etag);
  1020. };
  1021. Storage.prototype.getThrottleMetadata = function () {
  1022. return this.get('throttle_metadata');
  1023. };
  1024. Storage.prototype.setThrottleMetadata = function (metadata) {
  1025. return this.set('throttle_metadata', metadata);
  1026. };
  1027. Storage.prototype.deleteThrottleMetadata = function () {
  1028. return this.delete('throttle_metadata');
  1029. };
  1030. Storage.prototype.get = function (key) {
  1031. return tslib.__awaiter(this, void 0, void 0, function () {
  1032. var db;
  1033. var _this = this;
  1034. return tslib.__generator(this, function (_a) {
  1035. switch (_a.label) {
  1036. case 0: return [4 /*yield*/, this.openDbPromise];
  1037. case 1:
  1038. db = _a.sent();
  1039. return [2 /*return*/, new Promise(function (resolve, reject) {
  1040. var transaction = db.transaction([APP_NAMESPACE_STORE], 'readonly');
  1041. var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
  1042. var compositeKey = _this.createCompositeKey(key);
  1043. try {
  1044. var request = objectStore.get(compositeKey);
  1045. request.onerror = function (event) {
  1046. reject(toFirebaseError(event, "storage-get" /* ErrorCode.STORAGE_GET */));
  1047. };
  1048. request.onsuccess = function (event) {
  1049. var result = event.target.result;
  1050. if (result) {
  1051. resolve(result.value);
  1052. }
  1053. else {
  1054. resolve(undefined);
  1055. }
  1056. };
  1057. }
  1058. catch (e) {
  1059. reject(ERROR_FACTORY.create("storage-get" /* ErrorCode.STORAGE_GET */, {
  1060. originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
  1061. }));
  1062. }
  1063. })];
  1064. }
  1065. });
  1066. });
  1067. };
  1068. Storage.prototype.set = function (key, value) {
  1069. return tslib.__awaiter(this, void 0, void 0, function () {
  1070. var db;
  1071. var _this = this;
  1072. return tslib.__generator(this, function (_a) {
  1073. switch (_a.label) {
  1074. case 0: return [4 /*yield*/, this.openDbPromise];
  1075. case 1:
  1076. db = _a.sent();
  1077. return [2 /*return*/, new Promise(function (resolve, reject) {
  1078. var transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite');
  1079. var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
  1080. var compositeKey = _this.createCompositeKey(key);
  1081. try {
  1082. var request = objectStore.put({
  1083. compositeKey: compositeKey,
  1084. value: value
  1085. });
  1086. request.onerror = function (event) {
  1087. reject(toFirebaseError(event, "storage-set" /* ErrorCode.STORAGE_SET */));
  1088. };
  1089. request.onsuccess = function () {
  1090. resolve();
  1091. };
  1092. }
  1093. catch (e) {
  1094. reject(ERROR_FACTORY.create("storage-set" /* ErrorCode.STORAGE_SET */, {
  1095. originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
  1096. }));
  1097. }
  1098. })];
  1099. }
  1100. });
  1101. });
  1102. };
  1103. Storage.prototype.delete = function (key) {
  1104. return tslib.__awaiter(this, void 0, void 0, function () {
  1105. var db;
  1106. var _this = this;
  1107. return tslib.__generator(this, function (_a) {
  1108. switch (_a.label) {
  1109. case 0: return [4 /*yield*/, this.openDbPromise];
  1110. case 1:
  1111. db = _a.sent();
  1112. return [2 /*return*/, new Promise(function (resolve, reject) {
  1113. var transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite');
  1114. var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
  1115. var compositeKey = _this.createCompositeKey(key);
  1116. try {
  1117. var request = objectStore.delete(compositeKey);
  1118. request.onerror = function (event) {
  1119. reject(toFirebaseError(event, "storage-delete" /* ErrorCode.STORAGE_DELETE */));
  1120. };
  1121. request.onsuccess = function () {
  1122. resolve();
  1123. };
  1124. }
  1125. catch (e) {
  1126. reject(ERROR_FACTORY.create("storage-delete" /* ErrorCode.STORAGE_DELETE */, {
  1127. originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
  1128. }));
  1129. }
  1130. })];
  1131. }
  1132. });
  1133. });
  1134. };
  1135. // Facilitates composite key functionality (which is unsupported in IE).
  1136. Storage.prototype.createCompositeKey = function (key) {
  1137. return [this.appId, this.appName, this.namespace, key].join();
  1138. };
  1139. return Storage;
  1140. }());
  1141. /**
  1142. * @license
  1143. * Copyright 2019 Google LLC
  1144. *
  1145. * Licensed under the Apache License, Version 2.0 (the "License");
  1146. * you may not use this file except in compliance with the License.
  1147. * You may obtain a copy of the License at
  1148. *
  1149. * http://www.apache.org/licenses/LICENSE-2.0
  1150. *
  1151. * Unless required by applicable law or agreed to in writing, software
  1152. * distributed under the License is distributed on an "AS IS" BASIS,
  1153. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1154. * See the License for the specific language governing permissions and
  1155. * limitations under the License.
  1156. */
  1157. /**
  1158. * A memory cache layer over storage to support the SDK's synchronous read requirements.
  1159. */
  1160. var StorageCache = /** @class */ (function () {
  1161. function StorageCache(storage) {
  1162. this.storage = storage;
  1163. }
  1164. /**
  1165. * Memory-only getters
  1166. */
  1167. StorageCache.prototype.getLastFetchStatus = function () {
  1168. return this.lastFetchStatus;
  1169. };
  1170. StorageCache.prototype.getLastSuccessfulFetchTimestampMillis = function () {
  1171. return this.lastSuccessfulFetchTimestampMillis;
  1172. };
  1173. StorageCache.prototype.getActiveConfig = function () {
  1174. return this.activeConfig;
  1175. };
  1176. /**
  1177. * Read-ahead getter
  1178. */
  1179. StorageCache.prototype.loadFromStorage = function () {
  1180. return tslib.__awaiter(this, void 0, void 0, function () {
  1181. var lastFetchStatusPromise, lastSuccessfulFetchTimestampMillisPromise, activeConfigPromise, lastFetchStatus, lastSuccessfulFetchTimestampMillis, activeConfig;
  1182. return tslib.__generator(this, function (_a) {
  1183. switch (_a.label) {
  1184. case 0:
  1185. lastFetchStatusPromise = this.storage.getLastFetchStatus();
  1186. lastSuccessfulFetchTimestampMillisPromise = this.storage.getLastSuccessfulFetchTimestampMillis();
  1187. activeConfigPromise = this.storage.getActiveConfig();
  1188. return [4 /*yield*/, lastFetchStatusPromise];
  1189. case 1:
  1190. lastFetchStatus = _a.sent();
  1191. if (lastFetchStatus) {
  1192. this.lastFetchStatus = lastFetchStatus;
  1193. }
  1194. return [4 /*yield*/, lastSuccessfulFetchTimestampMillisPromise];
  1195. case 2:
  1196. lastSuccessfulFetchTimestampMillis = _a.sent();
  1197. if (lastSuccessfulFetchTimestampMillis) {
  1198. this.lastSuccessfulFetchTimestampMillis =
  1199. lastSuccessfulFetchTimestampMillis;
  1200. }
  1201. return [4 /*yield*/, activeConfigPromise];
  1202. case 3:
  1203. activeConfig = _a.sent();
  1204. if (activeConfig) {
  1205. this.activeConfig = activeConfig;
  1206. }
  1207. return [2 /*return*/];
  1208. }
  1209. });
  1210. });
  1211. };
  1212. /**
  1213. * Write-through setters
  1214. */
  1215. StorageCache.prototype.setLastFetchStatus = function (status) {
  1216. this.lastFetchStatus = status;
  1217. return this.storage.setLastFetchStatus(status);
  1218. };
  1219. StorageCache.prototype.setLastSuccessfulFetchTimestampMillis = function (timestampMillis) {
  1220. this.lastSuccessfulFetchTimestampMillis = timestampMillis;
  1221. return this.storage.setLastSuccessfulFetchTimestampMillis(timestampMillis);
  1222. };
  1223. StorageCache.prototype.setActiveConfig = function (activeConfig) {
  1224. this.activeConfig = activeConfig;
  1225. return this.storage.setActiveConfig(activeConfig);
  1226. };
  1227. return StorageCache;
  1228. }());
  1229. /**
  1230. * @license
  1231. * Copyright 2020 Google LLC
  1232. *
  1233. * Licensed under the Apache License, Version 2.0 (the "License");
  1234. * you may not use this file except in compliance with the License.
  1235. * You may obtain a copy of the License at
  1236. *
  1237. * http://www.apache.org/licenses/LICENSE-2.0
  1238. *
  1239. * Unless required by applicable law or agreed to in writing, software
  1240. * distributed under the License is distributed on an "AS IS" BASIS,
  1241. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1242. * See the License for the specific language governing permissions and
  1243. * limitations under the License.
  1244. */
  1245. function registerRemoteConfig() {
  1246. app._registerComponent(new component.Component(RC_COMPONENT_NAME, remoteConfigFactory, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
  1247. app.registerVersion(name, version);
  1248. // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
  1249. app.registerVersion(name, version, 'cjs5');
  1250. function remoteConfigFactory(container, _a) {
  1251. var namespace = _a.instanceIdentifier;
  1252. /* Dependencies */
  1253. // getImmediate for FirebaseApp will always succeed
  1254. var app$1 = container.getProvider('app').getImmediate();
  1255. // The following call will always succeed because rc has `import '@firebase/installations'`
  1256. var installations = container
  1257. .getProvider('installations-internal')
  1258. .getImmediate();
  1259. // Guards against the SDK being used in non-browser environments.
  1260. if (typeof window === 'undefined') {
  1261. throw ERROR_FACTORY.create("registration-window" /* ErrorCode.REGISTRATION_WINDOW */);
  1262. }
  1263. // Guards against the SDK being used when indexedDB is not available.
  1264. if (!util.isIndexedDBAvailable()) {
  1265. throw ERROR_FACTORY.create("indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */);
  1266. }
  1267. // Normalizes optional inputs.
  1268. var _b = app$1.options, projectId = _b.projectId, apiKey = _b.apiKey, appId = _b.appId;
  1269. if (!projectId) {
  1270. throw ERROR_FACTORY.create("registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */);
  1271. }
  1272. if (!apiKey) {
  1273. throw ERROR_FACTORY.create("registration-api-key" /* ErrorCode.REGISTRATION_API_KEY */);
  1274. }
  1275. if (!appId) {
  1276. throw ERROR_FACTORY.create("registration-app-id" /* ErrorCode.REGISTRATION_APP_ID */);
  1277. }
  1278. namespace = namespace || 'firebase';
  1279. var storage = new Storage(appId, app$1.name, namespace);
  1280. var storageCache = new StorageCache(storage);
  1281. var logger$1 = new logger.Logger(name);
  1282. // Sets ERROR as the default log level.
  1283. // See RemoteConfig#setLogLevel for corresponding normalization to ERROR log level.
  1284. logger$1.logLevel = logger.LogLevel.ERROR;
  1285. var restClient = new RestClient(installations,
  1286. // Uses the JS SDK version, by which the RC package version can be deduced, if necessary.
  1287. app.SDK_VERSION, namespace, projectId, apiKey, appId);
  1288. var retryingClient = new RetryingClient(restClient, storage);
  1289. var cachingClient = new CachingClient(retryingClient, storage, storageCache, logger$1);
  1290. var remoteConfigInstance = new RemoteConfig(app$1, cachingClient, storageCache, storage, logger$1);
  1291. // Starts warming cache.
  1292. // eslint-disable-next-line @typescript-eslint/no-floating-promises
  1293. ensureInitialized(remoteConfigInstance);
  1294. return remoteConfigInstance;
  1295. }
  1296. }
  1297. /**
  1298. * @license
  1299. * Copyright 2020 Google LLC
  1300. *
  1301. * Licensed under the Apache License, Version 2.0 (the "License");
  1302. * you may not use this file except in compliance with the License.
  1303. * You may obtain a copy of the License at
  1304. *
  1305. * http://www.apache.org/licenses/LICENSE-2.0
  1306. *
  1307. * Unless required by applicable law or agreed to in writing, software
  1308. * distributed under the License is distributed on an "AS IS" BASIS,
  1309. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1310. * See the License for the specific language governing permissions and
  1311. * limitations under the License.
  1312. */
  1313. // This API is put in a separate file, so we can stub fetchConfig and activate in tests.
  1314. // It's not possible to stub standalone functions from the same module.
  1315. /**
  1316. *
  1317. * Performs fetch and activate operations, as a convenience.
  1318. *
  1319. * @param remoteConfig - The {@link RemoteConfig} instance.
  1320. *
  1321. * @returns A `Promise` which resolves to true if the current call activated the fetched configs.
  1322. * If the fetched configs were already activated, the `Promise` will resolve to false.
  1323. *
  1324. * @public
  1325. */
  1326. function fetchAndActivate(remoteConfig) {
  1327. return tslib.__awaiter(this, void 0, void 0, function () {
  1328. return tslib.__generator(this, function (_a) {
  1329. switch (_a.label) {
  1330. case 0:
  1331. remoteConfig = util.getModularInstance(remoteConfig);
  1332. return [4 /*yield*/, fetchConfig(remoteConfig)];
  1333. case 1:
  1334. _a.sent();
  1335. return [2 /*return*/, activate(remoteConfig)];
  1336. }
  1337. });
  1338. });
  1339. }
  1340. /**
  1341. * This method provides two different checks:
  1342. *
  1343. * 1. Check if IndexedDB exists in the browser environment.
  1344. * 2. Check if the current browser context allows IndexedDB `open()` calls.
  1345. *
  1346. * @returns A `Promise` which resolves to true if a {@link RemoteConfig} instance
  1347. * can be initialized in this environment, or false if it cannot.
  1348. * @public
  1349. */
  1350. function isSupported() {
  1351. return tslib.__awaiter(this, void 0, void 0, function () {
  1352. var isDBOpenable;
  1353. return tslib.__generator(this, function (_a) {
  1354. switch (_a.label) {
  1355. case 0:
  1356. if (!util.isIndexedDBAvailable()) {
  1357. return [2 /*return*/, false];
  1358. }
  1359. _a.label = 1;
  1360. case 1:
  1361. _a.trys.push([1, 3, , 4]);
  1362. return [4 /*yield*/, util.validateIndexedDBOpenable()];
  1363. case 2:
  1364. isDBOpenable = _a.sent();
  1365. return [2 /*return*/, isDBOpenable];
  1366. case 3:
  1367. _a.sent();
  1368. return [2 /*return*/, false];
  1369. case 4: return [2 /*return*/];
  1370. }
  1371. });
  1372. });
  1373. }
  1374. /**
  1375. * Firebase Remote Config
  1376. *
  1377. * @packageDocumentation
  1378. */
  1379. /** register component and version */
  1380. registerRemoteConfig();
  1381. exports.activate = activate;
  1382. exports.ensureInitialized = ensureInitialized;
  1383. exports.fetchAndActivate = fetchAndActivate;
  1384. exports.fetchConfig = fetchConfig;
  1385. exports.getAll = getAll;
  1386. exports.getBoolean = getBoolean;
  1387. exports.getNumber = getNumber;
  1388. exports.getRemoteConfig = getRemoteConfig;
  1389. exports.getString = getString;
  1390. exports.getValue = getValue;
  1391. exports.isSupported = isSupported;
  1392. exports.setLogLevel = setLogLevel;
  1393. //# sourceMappingURL=index.cjs.js.map