import { getApp, _getProvider, _registerComponent, registerVersion, SDK_VERSION } from '@firebase/app';
import { ErrorFactory, FirebaseError, getModularInstance, calculateBackoffMillis, isIndexedDBAvailable, validateIndexedDBOpenable } from '@firebase/util';
import { Component } from '@firebase/component';
import { LogLevel, Logger } from '@firebase/logger';
import { __awaiter, __generator, __assign } from 'tslib';
import '@firebase/installations';

var name = "@firebase/remote-config";
var version = "0.4.1";

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Shims a minimal AbortSignal.
 *
 * <p>AbortController's AbortSignal conveniently decouples fetch timeout logic from other aspects
 * of networking, such as retries. Firebase doesn't use AbortController enough to justify a
 * polyfill recommendation, like we do with the Fetch API, but this minimal shim can easily be
 * swapped out if/when we do.
 */
var RemoteConfigAbortSignal = /** @class */ (function () {
    function RemoteConfigAbortSignal() {
        this.listeners = [];
    }
    RemoteConfigAbortSignal.prototype.addEventListener = function (listener) {
        this.listeners.push(listener);
    };
    RemoteConfigAbortSignal.prototype.abort = function () {
        this.listeners.forEach(function (listener) { return listener(); });
    };
    return RemoteConfigAbortSignal;
}());

/**
 * @license
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var RC_COMPONENT_NAME = 'remote-config';

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var _a;
var ERROR_DESCRIPTION_MAP = (_a = {},
    _a["registration-window" /* ErrorCode.REGISTRATION_WINDOW */] = 'Undefined window object. This SDK only supports usage in a browser environment.',
    _a["registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */] = 'Undefined project identifier. Check Firebase app initialization.',
    _a["registration-api-key" /* ErrorCode.REGISTRATION_API_KEY */] = 'Undefined API key. Check Firebase app initialization.',
    _a["registration-app-id" /* ErrorCode.REGISTRATION_APP_ID */] = 'Undefined app identifier. Check Firebase app initialization.',
    _a["storage-open" /* ErrorCode.STORAGE_OPEN */] = 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
    _a["storage-get" /* ErrorCode.STORAGE_GET */] = 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
    _a["storage-set" /* ErrorCode.STORAGE_SET */] = 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
    _a["storage-delete" /* ErrorCode.STORAGE_DELETE */] = 'Error thrown when deleting from storage. Original error: {$originalErrorMessage}.',
    _a["fetch-client-network" /* ErrorCode.FETCH_NETWORK */] = 'Fetch client failed to connect to a network. Check Internet connection.' +
        ' Original error: {$originalErrorMessage}.',
    _a["fetch-timeout" /* ErrorCode.FETCH_TIMEOUT */] = 'The config fetch request timed out. ' +
        ' Configure timeout using "fetchTimeoutMillis" SDK setting.',
    _a["fetch-throttle" /* ErrorCode.FETCH_THROTTLE */] = 'The config fetch request timed out while in an exponential backoff state.' +
        ' Configure timeout using "fetchTimeoutMillis" SDK setting.' +
        ' Unix timestamp in milliseconds when fetch request throttling ends: {$throttleEndTimeMillis}.',
    _a["fetch-client-parse" /* ErrorCode.FETCH_PARSE */] = 'Fetch client could not parse response.' +
        ' Original error: {$originalErrorMessage}.',
    _a["fetch-status" /* ErrorCode.FETCH_STATUS */] = 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.',
    _a["indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */] = 'Indexed DB is not supported by current browser',
    _a);
var ERROR_FACTORY = new ErrorFactory('remoteconfig' /* service */, 'Remote Config' /* service name */, ERROR_DESCRIPTION_MAP);
// Note how this is like typeof/instanceof, but for ErrorCode.
function hasErrorCode(e, errorCode) {
    return e instanceof FirebaseError && e.code.indexOf(errorCode) !== -1;
}

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var DEFAULT_VALUE_FOR_BOOLEAN = false;
var DEFAULT_VALUE_FOR_STRING = '';
var DEFAULT_VALUE_FOR_NUMBER = 0;
var BOOLEAN_TRUTHY_VALUES = ['1', 'true', 't', 'yes', 'y', 'on'];
var Value = /** @class */ (function () {
    function Value(_source, _value) {
        if (_value === void 0) { _value = DEFAULT_VALUE_FOR_STRING; }
        this._source = _source;
        this._value = _value;
    }
    Value.prototype.asString = function () {
        return this._value;
    };
    Value.prototype.asBoolean = function () {
        if (this._source === 'static') {
            return DEFAULT_VALUE_FOR_BOOLEAN;
        }
        return BOOLEAN_TRUTHY_VALUES.indexOf(this._value.toLowerCase()) >= 0;
    };
    Value.prototype.asNumber = function () {
        if (this._source === 'static') {
            return DEFAULT_VALUE_FOR_NUMBER;
        }
        var num = Number(this._value);
        if (isNaN(num)) {
            num = DEFAULT_VALUE_FOR_NUMBER;
        }
        return num;
    };
    Value.prototype.getSource = function () {
        return this._source;
    };
    return Value;
}());

/**
 * @license
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 *
 * @param app - The {@link @firebase/app#FirebaseApp} instance.
 * @returns A {@link RemoteConfig} instance.
 *
 * @public
 */
function getRemoteConfig(app) {
    if (app === void 0) { app = getApp(); }
    app = getModularInstance(app);
    var rcProvider = _getProvider(app, RC_COMPONENT_NAME);
    return rcProvider.getImmediate();
}
/**
 * Makes the last fetched config available to the getters.
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @returns A `Promise` which resolves to true if the current call activated the fetched configs.
 * If the fetched configs were already activated, the `Promise` will resolve to false.
 *
 * @public
 */
function activate(remoteConfig) {
    return __awaiter(this, void 0, void 0, function () {
        var rc, _a, lastSuccessfulFetchResponse, activeConfigEtag;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    rc = getModularInstance(remoteConfig);
                    return [4 /*yield*/, Promise.all([
                            rc._storage.getLastSuccessfulFetchResponse(),
                            rc._storage.getActiveConfigEtag()
                        ])];
                case 1:
                    _a = _b.sent(), lastSuccessfulFetchResponse = _a[0], activeConfigEtag = _a[1];
                    if (!lastSuccessfulFetchResponse ||
                        !lastSuccessfulFetchResponse.config ||
                        !lastSuccessfulFetchResponse.eTag ||
                        lastSuccessfulFetchResponse.eTag === activeConfigEtag) {
                        // Either there is no successful fetched config, or is the same as current active
                        // config.
                        return [2 /*return*/, false];
                    }
                    return [4 /*yield*/, Promise.all([
                            rc._storageCache.setActiveConfig(lastSuccessfulFetchResponse.config),
                            rc._storage.setActiveConfigEtag(lastSuccessfulFetchResponse.eTag)
                        ])];
                case 2:
                    _b.sent();
                    return [2 /*return*/, true];
            }
        });
    });
}
/**
 * Ensures the last activated config are available to the getters.
 * @param remoteConfig - The {@link RemoteConfig} instance.
 *
 * @returns A `Promise` that resolves when the last activated config is available to the getters.
 * @public
 */
function ensureInitialized(remoteConfig) {
    var rc = getModularInstance(remoteConfig);
    if (!rc._initializePromise) {
        rc._initializePromise = rc._storageCache.loadFromStorage().then(function () {
            rc._isInitializationComplete = true;
        });
    }
    return rc._initializePromise;
}
/**
 * Fetches and caches configuration from the Remote Config service.
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @public
 */
function fetchConfig(remoteConfig) {
    return __awaiter(this, void 0, void 0, function () {
        var rc, abortSignal, e_1, lastFetchStatus;
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    rc = getModularInstance(remoteConfig);
                    abortSignal = new RemoteConfigAbortSignal();
                    setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
                        return __generator(this, function (_a) {
                            // Note a very low delay, eg < 10ms, can elapse before listeners are initialized.
                            abortSignal.abort();
                            return [2 /*return*/];
                        });
                    }); }, rc.settings.fetchTimeoutMillis);
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 4, , 6]);
                    return [4 /*yield*/, rc._client.fetch({
                            cacheMaxAgeMillis: rc.settings.minimumFetchIntervalMillis,
                            signal: abortSignal
                        })];
                case 2:
                    _a.sent();
                    return [4 /*yield*/, rc._storageCache.setLastFetchStatus('success')];
                case 3:
                    _a.sent();
                    return [3 /*break*/, 6];
                case 4:
                    e_1 = _a.sent();
                    lastFetchStatus = hasErrorCode(e_1, "fetch-throttle" /* ErrorCode.FETCH_THROTTLE */)
                        ? 'throttle'
                        : 'failure';
                    return [4 /*yield*/, rc._storageCache.setLastFetchStatus(lastFetchStatus)];
                case 5:
                    _a.sent();
                    throw e_1;
                case 6: return [2 /*return*/];
            }
        });
    });
}
/**
 * Gets all config.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @returns All config.
 *
 * @public
 */
function getAll(remoteConfig) {
    var rc = getModularInstance(remoteConfig);
    return getAllKeys(rc._storageCache.getActiveConfig(), rc.defaultConfig).reduce(function (allConfigs, key) {
        allConfigs[key] = getValue(remoteConfig, key);
        return allConfigs;
    }, {});
}
/**
 * Gets the value for the given key as a boolean.
 *
 * Convenience method for calling <code>remoteConfig.getValue(key).asBoolean()</code>.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @param key - The name of the parameter.
 *
 * @returns The value for the given key as a boolean.
 * @public
 */
function getBoolean(remoteConfig, key) {
    return getValue(getModularInstance(remoteConfig), key).asBoolean();
}
/**
 * Gets the value for the given key as a number.
 *
 * Convenience method for calling <code>remoteConfig.getValue(key).asNumber()</code>.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @param key - The name of the parameter.
 *
 * @returns The value for the given key as a number.
 *
 * @public
 */
function getNumber(remoteConfig, key) {
    return getValue(getModularInstance(remoteConfig), key).asNumber();
}
/**
 * Gets the value for the given key as a string.
 * Convenience method for calling <code>remoteConfig.getValue(key).asString()</code>.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @param key - The name of the parameter.
 *
 * @returns The value for the given key as a string.
 *
 * @public
 */
function getString(remoteConfig, key) {
    return getValue(getModularInstance(remoteConfig), key).asString();
}
/**
 * Gets the {@link Value} for the given key.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @param key - The name of the parameter.
 *
 * @returns The value for the given key.
 *
 * @public
 */
function getValue(remoteConfig, key) {
    var rc = getModularInstance(remoteConfig);
    if (!rc._isInitializationComplete) {
        rc._logger.debug("A value was requested for key \"".concat(key, "\" before SDK initialization completed.") +
            ' Await on ensureInitialized if the intent was to get a previously activated value.');
    }
    var activeConfig = rc._storageCache.getActiveConfig();
    if (activeConfig && activeConfig[key] !== undefined) {
        return new Value('remote', activeConfig[key]);
    }
    else if (rc.defaultConfig && rc.defaultConfig[key] !== undefined) {
        return new Value('default', String(rc.defaultConfig[key]));
    }
    rc._logger.debug("Returning static value for key \"".concat(key, "\".") +
        ' Define a default or remote value if this is unintentional.');
    return new Value('static');
}
/**
 * Defines the log level to use.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 * @param logLevel - The log level to set.
 *
 * @public
 */
function setLogLevel(remoteConfig, logLevel) {
    var rc = getModularInstance(remoteConfig);
    switch (logLevel) {
        case 'debug':
            rc._logger.logLevel = LogLevel.DEBUG;
            break;
        case 'silent':
            rc._logger.logLevel = LogLevel.SILENT;
            break;
        default:
            rc._logger.logLevel = LogLevel.ERROR;
    }
}
/**
 * Dedupes and returns an array of all the keys of the received objects.
 */
function getAllKeys(obj1, obj2) {
    if (obj1 === void 0) { obj1 = {}; }
    if (obj2 === void 0) { obj2 = {}; }
    return Object.keys(__assign(__assign({}, obj1), obj2));
}

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Implements the {@link RemoteConfigClient} abstraction with success response caching.
 *
 * <p>Comparable to the browser's Cache API for responses, but the Cache API requires a Service
 * Worker, which requires HTTPS, which would significantly complicate SDK installation. Also, the
 * Cache API doesn't support matching entries by time.
 */
var CachingClient = /** @class */ (function () {
    function CachingClient(client, storage, storageCache, logger) {
        this.client = client;
        this.storage = storage;
        this.storageCache = storageCache;
        this.logger = logger;
    }
    /**
     * Returns true if the age of the cached fetched configs is less than or equal to
     * {@link Settings#minimumFetchIntervalInSeconds}.
     *
     * <p>This is comparable to passing `headers = { 'Cache-Control': max-age <maxAge> }` to the
     * native Fetch API.
     *
     * <p>Visible for testing.
     */
    CachingClient.prototype.isCachedDataFresh = function (cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis) {
        // Cache can only be fresh if it's populated.
        if (!lastSuccessfulFetchTimestampMillis) {
            this.logger.debug('Config fetch cache check. Cache unpopulated.');
            return false;
        }
        // Calculates age of cache entry.
        var cacheAgeMillis = Date.now() - lastSuccessfulFetchTimestampMillis;
        var isCachedDataFresh = cacheAgeMillis <= cacheMaxAgeMillis;
        this.logger.debug('Config fetch cache check.' +
            " Cache age millis: ".concat(cacheAgeMillis, ".") +
            " Cache max age millis (minimumFetchIntervalMillis setting): ".concat(cacheMaxAgeMillis, ".") +
            " Is cache hit: ".concat(isCachedDataFresh, "."));
        return isCachedDataFresh;
    };
    CachingClient.prototype.fetch = function (request) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, lastSuccessfulFetchTimestampMillis, lastSuccessfulFetchResponse, response, storageOperations;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, Promise.all([
                            this.storage.getLastSuccessfulFetchTimestampMillis(),
                            this.storage.getLastSuccessfulFetchResponse()
                        ])];
                    case 1:
                        _a = _b.sent(), lastSuccessfulFetchTimestampMillis = _a[0], lastSuccessfulFetchResponse = _a[1];
                        // Exits early on cache hit.
                        if (lastSuccessfulFetchResponse &&
                            this.isCachedDataFresh(request.cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis)) {
                            return [2 /*return*/, lastSuccessfulFetchResponse];
                        }
                        // Deviates from pure decorator by not honoring a passed ETag since we don't have a public API
                        // that allows the caller to pass an ETag.
                        request.eTag =
                            lastSuccessfulFetchResponse && lastSuccessfulFetchResponse.eTag;
                        return [4 /*yield*/, this.client.fetch(request)];
                    case 2:
                        response = _b.sent();
                        storageOperations = [
                            // Uses write-through cache for consistency with synchronous public API.
                            this.storageCache.setLastSuccessfulFetchTimestampMillis(Date.now())
                        ];
                        if (response.status === 200) {
                            // Caches response only if it has changed, ie non-304 responses.
                            storageOperations.push(this.storage.setLastSuccessfulFetchResponse(response));
                        }
                        return [4 /*yield*/, Promise.all(storageOperations)];
                    case 3:
                        _b.sent();
                        return [2 /*return*/, response];
                }
            });
        });
    };
    return CachingClient;
}());

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Attempts to get the most accurate browser language setting.
 *
 * <p>Adapted from getUserLanguage in packages/auth/src/utils.js for TypeScript.
 *
 * <p>Defers default language specification to server logic for consistency.
 *
 * @param navigatorLanguage Enables tests to override read-only {@link NavigatorLanguage}.
 */
function getUserLanguage(navigatorLanguage) {
    if (navigatorLanguage === void 0) { navigatorLanguage = navigator; }
    return (
    // Most reliable, but only supported in Chrome/Firefox.
    (navigatorLanguage.languages && navigatorLanguage.languages[0]) ||
        // Supported in most browsers, but returns the language of the browser
        // UI, not the language set in browser settings.
        navigatorLanguage.language
    // Polyfill otherwise.
    );
}

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Implements the Client abstraction for the Remote Config REST API.
 */
var RestClient = /** @class */ (function () {
    function RestClient(firebaseInstallations, sdkVersion, namespace, projectId, apiKey, appId) {
        this.firebaseInstallations = firebaseInstallations;
        this.sdkVersion = sdkVersion;
        this.namespace = namespace;
        this.projectId = projectId;
        this.apiKey = apiKey;
        this.appId = appId;
    }
    /**
     * Fetches from the Remote Config REST API.
     *
     * @throws a {@link ErrorCode.FETCH_NETWORK} error if {@link GlobalFetch#fetch} can't
     * connect to the network.
     * @throws a {@link ErrorCode.FETCH_PARSE} error if {@link Response#json} can't parse the
     * fetch response.
     * @throws a {@link ErrorCode.FETCH_STATUS} error if the service returns an HTTP error status.
     */
    RestClient.prototype.fetch = function (request) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, installationId, installationToken, urlBase, url, headers, requestBody, options, fetchPromise, timeoutPromise, response, originalError_1, errorCode, status, responseEtag, config, state, responseBody, originalError_2;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, Promise.all([
                            this.firebaseInstallations.getId(),
                            this.firebaseInstallations.getToken()
                        ])];
                    case 1:
                        _a = _b.sent(), installationId = _a[0], installationToken = _a[1];
                        urlBase = window.FIREBASE_REMOTE_CONFIG_URL_BASE ||
                            'https://firebaseremoteconfig.googleapis.com';
                        url = "".concat(urlBase, "/v1/projects/").concat(this.projectId, "/namespaces/").concat(this.namespace, ":fetch?key=").concat(this.apiKey);
                        headers = {
                            'Content-Type': 'application/json',
                            'Content-Encoding': 'gzip',
                            // Deviates from pure decorator by not passing max-age header since we don't currently have
                            // service behavior using that header.
                            'If-None-Match': request.eTag || '*'
                        };
                        requestBody = {
                            /* eslint-disable camelcase */
                            sdk_version: this.sdkVersion,
                            app_instance_id: installationId,
                            app_instance_id_token: installationToken,
                            app_id: this.appId,
                            language_code: getUserLanguage()
                            /* eslint-enable camelcase */
                        };
                        options = {
                            method: 'POST',
                            headers: headers,
                            body: JSON.stringify(requestBody)
                        };
                        fetchPromise = fetch(url, options);
                        timeoutPromise = new Promise(function (_resolve, reject) {
                            // Maps async event listener to Promise API.
                            request.signal.addEventListener(function () {
                                // Emulates https://heycam.github.io/webidl/#aborterror
                                var error = new Error('The operation was aborted.');
                                error.name = 'AbortError';
                                reject(error);
                            });
                        });
                        _b.label = 2;
                    case 2:
                        _b.trys.push([2, 5, , 6]);
                        return [4 /*yield*/, Promise.race([fetchPromise, timeoutPromise])];
                    case 3:
                        _b.sent();
                        return [4 /*yield*/, fetchPromise];
                    case 4:
                        response = _b.sent();
                        return [3 /*break*/, 6];
                    case 5:
                        originalError_1 = _b.sent();
                        errorCode = "fetch-client-network" /* ErrorCode.FETCH_NETWORK */;
                        if ((originalError_1 === null || originalError_1 === void 0 ? void 0 : originalError_1.name) === 'AbortError') {
                            errorCode = "fetch-timeout" /* ErrorCode.FETCH_TIMEOUT */;
                        }
                        throw ERROR_FACTORY.create(errorCode, {
                            originalErrorMessage: originalError_1 === null || originalError_1 === void 0 ? void 0 : originalError_1.message
                        });
                    case 6:
                        status = response.status;
                        responseEtag = response.headers.get('ETag') || undefined;
                        if (!(response.status === 200)) return [3 /*break*/, 11];
                        responseBody = void 0;
                        _b.label = 7;
                    case 7:
                        _b.trys.push([7, 9, , 10]);
                        return [4 /*yield*/, response.json()];
                    case 8:
                        responseBody = _b.sent();
                        return [3 /*break*/, 10];
                    case 9:
                        originalError_2 = _b.sent();
                        throw ERROR_FACTORY.create("fetch-client-parse" /* ErrorCode.FETCH_PARSE */, {
                            originalErrorMessage: originalError_2 === null || originalError_2 === void 0 ? void 0 : originalError_2.message
                        });
                    case 10:
                        config = responseBody['entries'];
                        state = responseBody['state'];
                        _b.label = 11;
                    case 11:
                        // Normalizes based on legacy state.
                        if (state === 'INSTANCE_STATE_UNSPECIFIED') {
                            status = 500;
                        }
                        else if (state === 'NO_CHANGE') {
                            status = 304;
                        }
                        else if (state === 'NO_TEMPLATE' || state === 'EMPTY_CONFIG') {
                            // These cases can be fixed remotely, so normalize to safe value.
                            config = {};
                        }
                        // Normalize to exception-based control flow for non-success cases.
                        // Encapsulates HTTP specifics in this class as much as possible. Status is still the best for
                        // differentiating success states (200 from 304; the state body param is undefined in a
                        // standard 304).
                        if (status !== 304 && status !== 200) {
                            throw ERROR_FACTORY.create("fetch-status" /* ErrorCode.FETCH_STATUS */, {
                                httpStatus: status
                            });
                        }
                        return [2 /*return*/, { status: status, eTag: responseEtag, config: config }];
                }
            });
        });
    };
    return RestClient;
}());

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Supports waiting on a backoff by:
 *
 * <ul>
 *   <li>Promisifying setTimeout, so we can set a timeout in our Promise chain</li>
 *   <li>Listening on a signal bus for abort events, just like the Fetch API</li>
 *   <li>Failing in the same way the Fetch API fails, so timing out a live request and a throttled
 *       request appear the same.</li>
 * </ul>
 *
 * <p>Visible for testing.
 */
function setAbortableTimeout(signal, throttleEndTimeMillis) {
    return new Promise(function (resolve, reject) {
        // Derives backoff from given end time, normalizing negative numbers to zero.
        var backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0);
        var timeout = setTimeout(resolve, backoffMillis);
        // Adds listener, rather than sets onabort, because signal is a shared object.
        signal.addEventListener(function () {
            clearTimeout(timeout);
            // If the request completes before this timeout, the rejection has no effect.
            reject(ERROR_FACTORY.create("fetch-throttle" /* ErrorCode.FETCH_THROTTLE */, {
                throttleEndTimeMillis: throttleEndTimeMillis
            }));
        });
    });
}
/**
 * Returns true if the {@link Error} indicates a fetch request may succeed later.
 */
function isRetriableError(e) {
    if (!(e instanceof FirebaseError) || !e.customData) {
        return false;
    }
    // Uses string index defined by ErrorData, which FirebaseError implements.
    var httpStatus = Number(e.customData['httpStatus']);
    return (httpStatus === 429 ||
        httpStatus === 500 ||
        httpStatus === 503 ||
        httpStatus === 504);
}
/**
 * Decorates a Client with retry logic.
 *
 * <p>Comparable to CachingClient, but uses backoff logic instead of cache max age and doesn't cache
 * responses (because the SDK has no use for error responses).
 */
var RetryingClient = /** @class */ (function () {
    function RetryingClient(client, storage) {
        this.client = client;
        this.storage = storage;
    }
    RetryingClient.prototype.fetch = function (request) {
        return __awaiter(this, void 0, void 0, function () {
            var throttleMetadata;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.storage.getThrottleMetadata()];
                    case 1:
                        throttleMetadata = (_a.sent()) || {
                            backoffCount: 0,
                            throttleEndTimeMillis: Date.now()
                        };
                        return [2 /*return*/, this.attemptFetch(request, throttleMetadata)];
                }
            });
        });
    };
    /**
     * A recursive helper for attempting a fetch request repeatedly.
     *
     * @throws any non-retriable errors.
     */
    RetryingClient.prototype.attemptFetch = function (request, _a) {
        var throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount;
        return __awaiter(this, void 0, void 0, function () {
            var response, e_1, throttleMetadata;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: 
                    // Starts with a (potentially zero) timeout to support resumption from stored state.
                    // Ensures the throttle end time is honored if the last attempt timed out.
                    // Note the SDK will never make a request if the fetch timeout expires at this point.
                    return [4 /*yield*/, setAbortableTimeout(request.signal, throttleEndTimeMillis)];
                    case 1:
                        // Starts with a (potentially zero) timeout to support resumption from stored state.
                        // Ensures the throttle end time is honored if the last attempt timed out.
                        // Note the SDK will never make a request if the fetch timeout expires at this point.
                        _b.sent();
                        _b.label = 2;
                    case 2:
                        _b.trys.push([2, 5, , 7]);
                        return [4 /*yield*/, this.client.fetch(request)];
                    case 3:
                        response = _b.sent();
                        // Note the SDK only clears throttle state if response is success or non-retriable.
                        return [4 /*yield*/, this.storage.deleteThrottleMetadata()];
                    case 4:
                        // Note the SDK only clears throttle state if response is success or non-retriable.
                        _b.sent();
                        return [2 /*return*/, response];
                    case 5:
                        e_1 = _b.sent();
                        if (!isRetriableError(e_1)) {
                            throw e_1;
                        }
                        throttleMetadata = {
                            throttleEndTimeMillis: Date.now() + calculateBackoffMillis(backoffCount),
                            backoffCount: backoffCount + 1
                        };
                        // Persists state.
                        return [4 /*yield*/, this.storage.setThrottleMetadata(throttleMetadata)];
                    case 6:
                        // Persists state.
                        _b.sent();
                        return [2 /*return*/, this.attemptFetch(request, throttleMetadata)];
                    case 7: return [2 /*return*/];
                }
            });
        });
    };
    return RetryingClient;
}());

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var DEFAULT_FETCH_TIMEOUT_MILLIS = 60 * 1000; // One minute
var DEFAULT_CACHE_MAX_AGE_MILLIS = 12 * 60 * 60 * 1000; // Twelve hours.
/**
 * Encapsulates business logic mapping network and storage dependencies to the public SDK API.
 *
 * See {@link https://github.com/FirebasePrivate/firebase-js-sdk/blob/master/packages/firebase/index.d.ts|interface documentation} for method descriptions.
 */
var RemoteConfig = /** @class */ (function () {
    function RemoteConfig(
    // Required by FirebaseServiceFactory interface.
    app, 
    // JS doesn't support private yet
    // (https://github.com/tc39/proposal-class-fields#private-fields), so we hint using an
    // underscore prefix.
    /**
     * @internal
     */
    _client, 
    /**
     * @internal
     */
    _storageCache, 
    /**
     * @internal
     */
    _storage, 
    /**
     * @internal
     */
    _logger) {
        this.app = app;
        this._client = _client;
        this._storageCache = _storageCache;
        this._storage = _storage;
        this._logger = _logger;
        /**
         * Tracks completion of initialization promise.
         * @internal
         */
        this._isInitializationComplete = false;
        this.settings = {
            fetchTimeoutMillis: DEFAULT_FETCH_TIMEOUT_MILLIS,
            minimumFetchIntervalMillis: DEFAULT_CACHE_MAX_AGE_MILLIS
        };
        this.defaultConfig = {};
    }
    Object.defineProperty(RemoteConfig.prototype, "fetchTimeMillis", {
        get: function () {
            return this._storageCache.getLastSuccessfulFetchTimestampMillis() || -1;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(RemoteConfig.prototype, "lastFetchStatus", {
        get: function () {
            return this._storageCache.getLastFetchStatus() || 'no-fetch-yet';
        },
        enumerable: false,
        configurable: true
    });
    return RemoteConfig;
}());

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Converts an error event associated with a {@link IDBRequest} to a {@link FirebaseError}.
 */
function toFirebaseError(event, errorCode) {
    var originalError = event.target.error || undefined;
    return ERROR_FACTORY.create(errorCode, {
        originalErrorMessage: originalError && (originalError === null || originalError === void 0 ? void 0 : originalError.message)
    });
}
/**
 * A general-purpose store keyed by app + namespace + {@link
 * ProjectNamespaceKeyFieldValue}.
 *
 * <p>The Remote Config SDK can be used with multiple app installations, and each app can interact
 * with multiple namespaces, so this store uses app (ID + name) and namespace as common parent keys
 * for a set of key-value pairs. See {@link Storage#createCompositeKey}.
 *
 * <p>Visible for testing.
 */
var APP_NAMESPACE_STORE = 'app_namespace_store';
var DB_NAME = 'firebase_remote_config';
var DB_VERSION = 1;
// Visible for testing.
function openDatabase() {
    return new Promise(function (resolve, reject) {
        try {
            var request = indexedDB.open(DB_NAME, DB_VERSION);
            request.onerror = function (event) {
                reject(toFirebaseError(event, "storage-open" /* ErrorCode.STORAGE_OPEN */));
            };
            request.onsuccess = function (event) {
                resolve(event.target.result);
            };
            request.onupgradeneeded = function (event) {
                var db = event.target.result;
                // We don't use 'break' in this switch statement, the fall-through
                // behavior is what we want, because if there are multiple versions between
                // the old version and the current version, we want ALL the migrations
                // that correspond to those versions to run, not only the last one.
                // eslint-disable-next-line default-case
                switch (event.oldVersion) {
                    case 0:
                        db.createObjectStore(APP_NAMESPACE_STORE, {
                            keyPath: 'compositeKey'
                        });
                }
            };
        }
        catch (error) {
            reject(ERROR_FACTORY.create("storage-open" /* ErrorCode.STORAGE_OPEN */, {
                originalErrorMessage: error === null || error === void 0 ? void 0 : error.message
            }));
        }
    });
}
/**
 * Abstracts data persistence.
 */
var Storage = /** @class */ (function () {
    /**
     * @param appId enables storage segmentation by app (ID + name).
     * @param appName enables storage segmentation by app (ID + name).
     * @param namespace enables storage segmentation by namespace.
     */
    function Storage(appId, appName, namespace, openDbPromise) {
        if (openDbPromise === void 0) { openDbPromise = openDatabase(); }
        this.appId = appId;
        this.appName = appName;
        this.namespace = namespace;
        this.openDbPromise = openDbPromise;
    }
    Storage.prototype.getLastFetchStatus = function () {
        return this.get('last_fetch_status');
    };
    Storage.prototype.setLastFetchStatus = function (status) {
        return this.set('last_fetch_status', status);
    };
    // This is comparable to a cache entry timestamp. If we need to expire other data, we could
    // consider adding timestamp to all storage records and an optional max age arg to getters.
    Storage.prototype.getLastSuccessfulFetchTimestampMillis = function () {
        return this.get('last_successful_fetch_timestamp_millis');
    };
    Storage.prototype.setLastSuccessfulFetchTimestampMillis = function (timestamp) {
        return this.set('last_successful_fetch_timestamp_millis', timestamp);
    };
    Storage.prototype.getLastSuccessfulFetchResponse = function () {
        return this.get('last_successful_fetch_response');
    };
    Storage.prototype.setLastSuccessfulFetchResponse = function (response) {
        return this.set('last_successful_fetch_response', response);
    };
    Storage.prototype.getActiveConfig = function () {
        return this.get('active_config');
    };
    Storage.prototype.setActiveConfig = function (config) {
        return this.set('active_config', config);
    };
    Storage.prototype.getActiveConfigEtag = function () {
        return this.get('active_config_etag');
    };
    Storage.prototype.setActiveConfigEtag = function (etag) {
        return this.set('active_config_etag', etag);
    };
    Storage.prototype.getThrottleMetadata = function () {
        return this.get('throttle_metadata');
    };
    Storage.prototype.setThrottleMetadata = function (metadata) {
        return this.set('throttle_metadata', metadata);
    };
    Storage.prototype.deleteThrottleMetadata = function () {
        return this.delete('throttle_metadata');
    };
    Storage.prototype.get = function (key) {
        return __awaiter(this, void 0, void 0, function () {
            var db;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.openDbPromise];
                    case 1:
                        db = _a.sent();
                        return [2 /*return*/, new Promise(function (resolve, reject) {
                                var transaction = db.transaction([APP_NAMESPACE_STORE], 'readonly');
                                var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
                                var compositeKey = _this.createCompositeKey(key);
                                try {
                                    var request = objectStore.get(compositeKey);
                                    request.onerror = function (event) {
                                        reject(toFirebaseError(event, "storage-get" /* ErrorCode.STORAGE_GET */));
                                    };
                                    request.onsuccess = function (event) {
                                        var result = event.target.result;
                                        if (result) {
                                            resolve(result.value);
                                        }
                                        else {
                                            resolve(undefined);
                                        }
                                    };
                                }
                                catch (e) {
                                    reject(ERROR_FACTORY.create("storage-get" /* ErrorCode.STORAGE_GET */, {
                                        originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
                                    }));
                                }
                            })];
                }
            });
        });
    };
    Storage.prototype.set = function (key, value) {
        return __awaiter(this, void 0, void 0, function () {
            var db;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.openDbPromise];
                    case 1:
                        db = _a.sent();
                        return [2 /*return*/, new Promise(function (resolve, reject) {
                                var transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite');
                                var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
                                var compositeKey = _this.createCompositeKey(key);
                                try {
                                    var request = objectStore.put({
                                        compositeKey: compositeKey,
                                        value: value
                                    });
                                    request.onerror = function (event) {
                                        reject(toFirebaseError(event, "storage-set" /* ErrorCode.STORAGE_SET */));
                                    };
                                    request.onsuccess = function () {
                                        resolve();
                                    };
                                }
                                catch (e) {
                                    reject(ERROR_FACTORY.create("storage-set" /* ErrorCode.STORAGE_SET */, {
                                        originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
                                    }));
                                }
                            })];
                }
            });
        });
    };
    Storage.prototype.delete = function (key) {
        return __awaiter(this, void 0, void 0, function () {
            var db;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.openDbPromise];
                    case 1:
                        db = _a.sent();
                        return [2 /*return*/, new Promise(function (resolve, reject) {
                                var transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite');
                                var objectStore = transaction.objectStore(APP_NAMESPACE_STORE);
                                var compositeKey = _this.createCompositeKey(key);
                                try {
                                    var request = objectStore.delete(compositeKey);
                                    request.onerror = function (event) {
                                        reject(toFirebaseError(event, "storage-delete" /* ErrorCode.STORAGE_DELETE */));
                                    };
                                    request.onsuccess = function () {
                                        resolve();
                                    };
                                }
                                catch (e) {
                                    reject(ERROR_FACTORY.create("storage-delete" /* ErrorCode.STORAGE_DELETE */, {
                                        originalErrorMessage: e === null || e === void 0 ? void 0 : e.message
                                    }));
                                }
                            })];
                }
            });
        });
    };
    // Facilitates composite key functionality (which is unsupported in IE).
    Storage.prototype.createCompositeKey = function (key) {
        return [this.appId, this.appName, this.namespace, key].join();
    };
    return Storage;
}());

/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * A memory cache layer over storage to support the SDK's synchronous read requirements.
 */
var StorageCache = /** @class */ (function () {
    function StorageCache(storage) {
        this.storage = storage;
    }
    /**
     * Memory-only getters
     */
    StorageCache.prototype.getLastFetchStatus = function () {
        return this.lastFetchStatus;
    };
    StorageCache.prototype.getLastSuccessfulFetchTimestampMillis = function () {
        return this.lastSuccessfulFetchTimestampMillis;
    };
    StorageCache.prototype.getActiveConfig = function () {
        return this.activeConfig;
    };
    /**
     * Read-ahead getter
     */
    StorageCache.prototype.loadFromStorage = function () {
        return __awaiter(this, void 0, void 0, function () {
            var lastFetchStatusPromise, lastSuccessfulFetchTimestampMillisPromise, activeConfigPromise, lastFetchStatus, lastSuccessfulFetchTimestampMillis, activeConfig;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        lastFetchStatusPromise = this.storage.getLastFetchStatus();
                        lastSuccessfulFetchTimestampMillisPromise = this.storage.getLastSuccessfulFetchTimestampMillis();
                        activeConfigPromise = this.storage.getActiveConfig();
                        return [4 /*yield*/, lastFetchStatusPromise];
                    case 1:
                        lastFetchStatus = _a.sent();
                        if (lastFetchStatus) {
                            this.lastFetchStatus = lastFetchStatus;
                        }
                        return [4 /*yield*/, lastSuccessfulFetchTimestampMillisPromise];
                    case 2:
                        lastSuccessfulFetchTimestampMillis = _a.sent();
                        if (lastSuccessfulFetchTimestampMillis) {
                            this.lastSuccessfulFetchTimestampMillis =
                                lastSuccessfulFetchTimestampMillis;
                        }
                        return [4 /*yield*/, activeConfigPromise];
                    case 3:
                        activeConfig = _a.sent();
                        if (activeConfig) {
                            this.activeConfig = activeConfig;
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Write-through setters
     */
    StorageCache.prototype.setLastFetchStatus = function (status) {
        this.lastFetchStatus = status;
        return this.storage.setLastFetchStatus(status);
    };
    StorageCache.prototype.setLastSuccessfulFetchTimestampMillis = function (timestampMillis) {
        this.lastSuccessfulFetchTimestampMillis = timestampMillis;
        return this.storage.setLastSuccessfulFetchTimestampMillis(timestampMillis);
    };
    StorageCache.prototype.setActiveConfig = function (activeConfig) {
        this.activeConfig = activeConfig;
        return this.storage.setActiveConfig(activeConfig);
    };
    return StorageCache;
}());

/**
 * @license
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function registerRemoteConfig() {
    _registerComponent(new Component(RC_COMPONENT_NAME, remoteConfigFactory, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
    registerVersion(name, version);
    // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
    registerVersion(name, version, 'esm5');
    function remoteConfigFactory(container, _a) {
        var namespace = _a.instanceIdentifier;
        /* Dependencies */
        // getImmediate for FirebaseApp will always succeed
        var app = container.getProvider('app').getImmediate();
        // The following call will always succeed because rc has `import '@firebase/installations'`
        var installations = container
            .getProvider('installations-internal')
            .getImmediate();
        // Guards against the SDK being used in non-browser environments.
        if (typeof window === 'undefined') {
            throw ERROR_FACTORY.create("registration-window" /* ErrorCode.REGISTRATION_WINDOW */);
        }
        // Guards against the SDK being used when indexedDB is not available.
        if (!isIndexedDBAvailable()) {
            throw ERROR_FACTORY.create("indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */);
        }
        // Normalizes optional inputs.
        var _b = app.options, projectId = _b.projectId, apiKey = _b.apiKey, appId = _b.appId;
        if (!projectId) {
            throw ERROR_FACTORY.create("registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */);
        }
        if (!apiKey) {
            throw ERROR_FACTORY.create("registration-api-key" /* ErrorCode.REGISTRATION_API_KEY */);
        }
        if (!appId) {
            throw ERROR_FACTORY.create("registration-app-id" /* ErrorCode.REGISTRATION_APP_ID */);
        }
        namespace = namespace || 'firebase';
        var storage = new Storage(appId, app.name, namespace);
        var storageCache = new StorageCache(storage);
        var logger = new Logger(name);
        // Sets ERROR as the default log level.
        // See RemoteConfig#setLogLevel for corresponding normalization to ERROR log level.
        logger.logLevel = LogLevel.ERROR;
        var restClient = new RestClient(installations, 
        // Uses the JS SDK version, by which the RC package version can be deduced, if necessary.
        SDK_VERSION, namespace, projectId, apiKey, appId);
        var retryingClient = new RetryingClient(restClient, storage);
        var cachingClient = new CachingClient(retryingClient, storage, storageCache, logger);
        var remoteConfigInstance = new RemoteConfig(app, cachingClient, storageCache, storage, logger);
        // Starts warming cache.
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        ensureInitialized(remoteConfigInstance);
        return remoteConfigInstance;
    }
}

/**
 * @license
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// This API is put in a separate file, so we can stub fetchConfig and activate in tests.
// It's not possible to stub standalone functions from the same module.
/**
 *
 * Performs fetch and activate operations, as a convenience.
 *
 * @param remoteConfig - The {@link RemoteConfig} instance.
 *
 * @returns A `Promise` which resolves to true if the current call activated the fetched configs.
 * If the fetched configs were already activated, the `Promise` will resolve to false.
 *
 * @public
 */
function fetchAndActivate(remoteConfig) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    remoteConfig = getModularInstance(remoteConfig);
                    return [4 /*yield*/, fetchConfig(remoteConfig)];
                case 1:
                    _a.sent();
                    return [2 /*return*/, activate(remoteConfig)];
            }
        });
    });
}
/**
 * This method provides two different checks:
 *
 * 1. Check if IndexedDB exists in the browser environment.
 * 2. Check if the current browser context allows IndexedDB `open()` calls.
 *
 * @returns A `Promise` which resolves to true if a {@link RemoteConfig} instance
 * can be initialized in this environment, or false if it cannot.
 * @public
 */
function isSupported() {
    return __awaiter(this, void 0, void 0, function () {
        var isDBOpenable;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (!isIndexedDBAvailable()) {
                        return [2 /*return*/, false];
                    }
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, validateIndexedDBOpenable()];
                case 2:
                    isDBOpenable = _a.sent();
                    return [2 /*return*/, isDBOpenable];
                case 3:
                    _a.sent();
                    return [2 /*return*/, false];
                case 4: return [2 /*return*/];
            }
        });
    });
}

/**
 * Firebase Remote Config
 *
 * @packageDocumentation
 */
/** register component and version */
registerRemoteConfig();

export { activate, ensureInitialized, fetchAndActivate, fetchConfig, getAll, getBoolean, getNumber, getRemoteConfig, getString, getValue, isSupported, setLogLevel };
//# sourceMappingURL=index.esm.js.map