UNPKG

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