@firebase/remote-config
Advanced tools
Comparing version 0.4.9-canary.beaa4dffb to 0.4.9-vertexai-preview.36cb0178c
@@ -8,3 +8,3 @@ import { _getProvider, getApp, _registerComponent, registerVersion, SDK_VERSION } from '@firebase/app'; | ||
const name = "@firebase/remote-config"; | ||
const version = "0.4.9-canary.beaa4dffb"; | ||
const version = "0.4.9-vertexai-preview.36cb0178c"; | ||
@@ -1118,3 +1118,3 @@ /** | ||
registerVersion(name, version); | ||
// BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation | ||
// BUILD_TARGET will be replaced by values like esm2017, cjs2017, etc during the compilation | ||
registerVersion(name, version, 'esm2017'); | ||
@@ -1121,0 +1121,0 @@ function remoteConfigFactory(container, { instanceIdentifier: namespace }) { |
@@ -9,7 +9,6 @@ 'use strict'; | ||
var logger = require('@firebase/logger'); | ||
var tslib = require('tslib'); | ||
require('@firebase/installations'); | ||
var name = "@firebase/remote-config"; | ||
var version = "0.4.9-canary.beaa4dffb"; | ||
const name = "@firebase/remote-config"; | ||
const version = "0.4.9-vertexai-preview.36cb0178c"; | ||
@@ -40,14 +39,13 @@ /** | ||
*/ | ||
var RemoteConfigAbortSignal = /** @class */ (function () { | ||
function RemoteConfigAbortSignal() { | ||
class RemoteConfigAbortSignal { | ||
constructor() { | ||
this.listeners = []; | ||
} | ||
RemoteConfigAbortSignal.prototype.addEventListener = function (listener) { | ||
addEventListener(listener) { | ||
this.listeners.push(listener); | ||
}; | ||
RemoteConfigAbortSignal.prototype.abort = function () { | ||
this.listeners.forEach(function (listener) { return listener(); }); | ||
}; | ||
return RemoteConfigAbortSignal; | ||
}()); | ||
} | ||
abort() { | ||
this.listeners.forEach(listener => listener()); | ||
} | ||
} | ||
@@ -70,3 +68,3 @@ /** | ||
*/ | ||
var RC_COMPONENT_NAME = 'remote-config'; | ||
const RC_COMPONENT_NAME = 'remote-config'; | ||
@@ -89,25 +87,24 @@ /** | ||
*/ | ||
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.' + | ||
const ERROR_DESCRIPTION_MAP = { | ||
["registration-window" /* ErrorCode.REGISTRATION_WINDOW */]: 'Undefined window object. This SDK only supports usage in a browser environment.', | ||
["registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */]: 'Undefined project identifier. Check Firebase app initialization.', | ||
["registration-api-key" /* ErrorCode.REGISTRATION_API_KEY */]: 'Undefined API key. Check Firebase app initialization.', | ||
["registration-app-id" /* ErrorCode.REGISTRATION_APP_ID */]: 'Undefined app identifier. Check Firebase app initialization.', | ||
["storage-open" /* ErrorCode.STORAGE_OPEN */]: 'Error thrown when opening storage. Original error: {$originalErrorMessage}.', | ||
["storage-get" /* ErrorCode.STORAGE_GET */]: 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.', | ||
["storage-set" /* ErrorCode.STORAGE_SET */]: 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.', | ||
["storage-delete" /* ErrorCode.STORAGE_DELETE */]: 'Error thrown when deleting from storage. Original error: {$originalErrorMessage}.', | ||
["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. ' + | ||
["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.' + | ||
["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.' + | ||
["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 util.ErrorFactory('remoteconfig' /* service */, 'Remote Config' /* service name */, ERROR_DESCRIPTION_MAP); | ||
["fetch-status" /* ErrorCode.FETCH_STATUS */]: 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.', | ||
["indexed-db-unavailable" /* ErrorCode.INDEXED_DB_UNAVAILABLE */]: 'Indexed DB is not supported by current browser' | ||
}; | ||
const ERROR_FACTORY = new util.ErrorFactory('remoteconfig' /* service */, 'Remote Config' /* service name */, ERROR_DESCRIPTION_MAP); | ||
// Note how this is like typeof/instanceof, but for ErrorCode. | ||
@@ -134,16 +131,15 @@ function hasErrorCode(e, errorCode) { | ||
*/ | ||
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; } | ||
const DEFAULT_VALUE_FOR_BOOLEAN = false; | ||
const DEFAULT_VALUE_FOR_STRING = ''; | ||
const DEFAULT_VALUE_FOR_NUMBER = 0; | ||
const BOOLEAN_TRUTHY_VALUES = ['1', 'true', 't', 'yes', 'y', 'on']; | ||
class Value { | ||
constructor(_source, _value = DEFAULT_VALUE_FOR_STRING) { | ||
this._source = _source; | ||
this._value = _value; | ||
} | ||
Value.prototype.asString = function () { | ||
asString() { | ||
return this._value; | ||
}; | ||
Value.prototype.asBoolean = function () { | ||
} | ||
asBoolean() { | ||
if (this._source === 'static') { | ||
@@ -153,8 +149,8 @@ return DEFAULT_VALUE_FOR_BOOLEAN; | ||
return BOOLEAN_TRUTHY_VALUES.indexOf(this._value.toLowerCase()) >= 0; | ||
}; | ||
Value.prototype.asNumber = function () { | ||
} | ||
asNumber() { | ||
if (this._source === 'static') { | ||
return DEFAULT_VALUE_FOR_NUMBER; | ||
} | ||
var num = Number(this._value); | ||
let num = Number(this._value); | ||
if (isNaN(num)) { | ||
@@ -164,8 +160,7 @@ num = DEFAULT_VALUE_FOR_NUMBER; | ||
return num; | ||
}; | ||
Value.prototype.getSource = function () { | ||
} | ||
getSource() { | ||
return this._source; | ||
}; | ||
return Value; | ||
}()); | ||
} | ||
} | ||
@@ -195,6 +190,5 @@ /** | ||
*/ | ||
function getRemoteConfig(app$1) { | ||
if (app$1 === void 0) { app$1 = app.getApp(); } | ||
function getRemoteConfig(app$1 = app.getApp()) { | ||
app$1 = util.getModularInstance(app$1); | ||
var rcProvider = app._getProvider(app$1, RC_COMPONENT_NAME); | ||
const rcProvider = app._getProvider(app$1, RC_COMPONENT_NAME); | ||
return rcProvider.getImmediate(); | ||
@@ -210,33 +204,21 @@ } | ||
*/ | ||
function activate(remoteConfig) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var rc, _a, lastSuccessfulFetchResponse, activeConfigEtag; | ||
return tslib.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
rc = util.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]; | ||
} | ||
}); | ||
}); | ||
async function activate(remoteConfig) { | ||
const rc = util.getModularInstance(remoteConfig); | ||
const [lastSuccessfulFetchResponse, activeConfigEtag] = await Promise.all([ | ||
rc._storage.getLastSuccessfulFetchResponse(), | ||
rc._storage.getActiveConfigEtag() | ||
]); | ||
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 false; | ||
} | ||
await Promise.all([ | ||
rc._storageCache.setActiveConfig(lastSuccessfulFetchResponse.config), | ||
rc._storage.setActiveConfigEtag(lastSuccessfulFetchResponse.eTag) | ||
]); | ||
return true; | ||
} | ||
@@ -251,5 +233,5 @@ /** | ||
function ensureInitialized(remoteConfig) { | ||
var rc = util.getModularInstance(remoteConfig); | ||
const rc = util.getModularInstance(remoteConfig); | ||
if (!rc._initializePromise) { | ||
rc._initializePromise = rc._storageCache.loadFromStorage().then(function () { | ||
rc._initializePromise = rc._storageCache.loadFromStorage().then(() => { | ||
rc._isInitializationComplete = true; | ||
@@ -265,44 +247,34 @@ }); | ||
*/ | ||
function fetchConfig(remoteConfig) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var rc, abortSignal, e_1, lastFetchStatus; | ||
var _this = this; | ||
return tslib.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
rc = util.getModularInstance(remoteConfig); | ||
abortSignal = new RemoteConfigAbortSignal(); | ||
setTimeout(function () { return tslib.__awaiter(_this, void 0, void 0, function () { | ||
return tslib.__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*/]; | ||
} | ||
async function fetchConfig(remoteConfig) { | ||
const rc = util.getModularInstance(remoteConfig); | ||
// Aborts the request after the given timeout, causing the fetch call to | ||
// reject with an `AbortError`. | ||
// | ||
// <p>Aborting after the request completes is a no-op, so we don't need a | ||
// corresponding `clearTimeout`. | ||
// | ||
// Locating abort logic here because: | ||
// * it uses a developer setting (timeout) | ||
// * it applies to all retries (like curl's max-time arg) | ||
// * it is consistent with the Fetch API's signal input | ||
const abortSignal = new RemoteConfigAbortSignal(); | ||
setTimeout(async () => { | ||
// Note a very low delay, eg < 10ms, can elapse before listeners are initialized. | ||
abortSignal.abort(); | ||
}, rc.settings.fetchTimeoutMillis); | ||
// Catches *all* errors thrown by client so status can be set consistently. | ||
try { | ||
await rc._client.fetch({ | ||
cacheMaxAgeMillis: rc.settings.minimumFetchIntervalMillis, | ||
signal: abortSignal | ||
}); | ||
}); | ||
await rc._storageCache.setLastFetchStatus('success'); | ||
} | ||
catch (e) { | ||
const lastFetchStatus = hasErrorCode(e, "fetch-throttle" /* ErrorCode.FETCH_THROTTLE */) | ||
? 'throttle' | ||
: 'failure'; | ||
await rc._storageCache.setLastFetchStatus(lastFetchStatus); | ||
throw e; | ||
} | ||
} | ||
@@ -318,4 +290,4 @@ /** | ||
function getAll(remoteConfig) { | ||
var rc = util.getModularInstance(remoteConfig); | ||
return getAllKeys(rc._storageCache.getActiveConfig(), rc.defaultConfig).reduce(function (allConfigs, key) { | ||
const rc = util.getModularInstance(remoteConfig); | ||
return getAllKeys(rc._storageCache.getActiveConfig(), rc.defaultConfig).reduce((allConfigs, key) => { | ||
allConfigs[key] = getValue(remoteConfig, key); | ||
@@ -379,8 +351,8 @@ return allConfigs; | ||
function getValue(remoteConfig, key) { | ||
var rc = util.getModularInstance(remoteConfig); | ||
const rc = util.getModularInstance(remoteConfig); | ||
if (!rc._isInitializationComplete) { | ||
rc._logger.debug("A value was requested for key \"".concat(key, "\" before SDK initialization completed.") + | ||
rc._logger.debug(`A value was requested for key "${key}" before SDK initialization completed.` + | ||
' Await on ensureInitialized if the intent was to get a previously activated value.'); | ||
} | ||
var activeConfig = rc._storageCache.getActiveConfig(); | ||
const activeConfig = rc._storageCache.getActiveConfig(); | ||
if (activeConfig && activeConfig[key] !== undefined) { | ||
@@ -392,3 +364,3 @@ return new Value('remote', activeConfig[key]); | ||
} | ||
rc._logger.debug("Returning static value for key \"".concat(key, "\".") + | ||
rc._logger.debug(`Returning static value for key "${key}".` + | ||
' Define a default or remote value if this is unintentional.'); | ||
@@ -406,3 +378,3 @@ return new Value('static'); | ||
function setLogLevel(remoteConfig, logLevel) { | ||
var rc = util.getModularInstance(remoteConfig); | ||
const rc = util.getModularInstance(remoteConfig); | ||
switch (logLevel) { | ||
@@ -422,6 +394,4 @@ case 'debug': | ||
*/ | ||
function getAllKeys(obj1, obj2) { | ||
if (obj1 === void 0) { obj1 = {}; } | ||
if (obj2 === void 0) { obj2 = {}; } | ||
return Object.keys(tslib.__assign(tslib.__assign({}, obj1), obj2)); | ||
function getAllKeys(obj1 = {}, obj2 = {}) { | ||
return Object.keys(Object.assign(Object.assign({}, obj1), obj2)); | ||
} | ||
@@ -452,4 +422,4 @@ | ||
*/ | ||
var CachingClient = /** @class */ (function () { | ||
function CachingClient(client, storage, storageCache, logger) { | ||
class CachingClient { | ||
constructor(client, storage, storageCache, logger) { | ||
this.client = client; | ||
@@ -469,3 +439,3 @@ this.storage = storage; | ||
*/ | ||
CachingClient.prototype.isCachedDataFresh = function (cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis) { | ||
isCachedDataFresh(cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis) { | ||
// Cache can only be fresh if it's populated. | ||
@@ -477,51 +447,40 @@ if (!lastSuccessfulFetchTimestampMillis) { | ||
// Calculates age of cache entry. | ||
var cacheAgeMillis = Date.now() - lastSuccessfulFetchTimestampMillis; | ||
var isCachedDataFresh = cacheAgeMillis <= cacheMaxAgeMillis; | ||
const cacheAgeMillis = Date.now() - lastSuccessfulFetchTimestampMillis; | ||
const 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, ".")); | ||
` Cache age millis: ${cacheAgeMillis}.` + | ||
` Cache max age millis (minimumFetchIntervalMillis setting): ${cacheMaxAgeMillis}.` + | ||
` Is cache hit: ${isCachedDataFresh}.`); | ||
return isCachedDataFresh; | ||
}; | ||
CachingClient.prototype.fetch = function (request) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var _a, lastSuccessfulFetchTimestampMillis, lastSuccessfulFetchResponse, response, storageOperations; | ||
return tslib.__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; | ||
}()); | ||
} | ||
async fetch(request) { | ||
// Reads from persisted storage to avoid cache miss if callers don't wait on initialization. | ||
const [lastSuccessfulFetchTimestampMillis, lastSuccessfulFetchResponse] = await Promise.all([ | ||
this.storage.getLastSuccessfulFetchTimestampMillis(), | ||
this.storage.getLastSuccessfulFetchResponse() | ||
]); | ||
// Exits early on cache hit. | ||
if (lastSuccessfulFetchResponse && | ||
this.isCachedDataFresh(request.cacheMaxAgeMillis, lastSuccessfulFetchTimestampMillis)) { | ||
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; | ||
// Falls back to service on cache miss. | ||
const response = await this.client.fetch(request); | ||
// Fetch throws for non-success responses, so success is guaranteed here. | ||
const 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)); | ||
} | ||
await Promise.all(storageOperations); | ||
return response; | ||
} | ||
} | ||
@@ -553,4 +512,3 @@ /** | ||
*/ | ||
function getUserLanguage(navigatorLanguage) { | ||
if (navigatorLanguage === void 0) { navigatorLanguage = navigator; } | ||
function getUserLanguage(navigatorLanguage = navigator) { | ||
return ( | ||
@@ -585,4 +543,4 @@ // Most reliable, but only supported in Chrome/Firefox. | ||
*/ | ||
var RestClient = /** @class */ (function () { | ||
function RestClient(firebaseInstallations, sdkVersion, namespace, projectId, apiKey, appId) { | ||
class RestClient { | ||
constructor(firebaseInstallations, sdkVersion, namespace, projectId, apiKey, appId) { | ||
this.firebaseInstallations = firebaseInstallations; | ||
@@ -604,115 +562,99 @@ this.sdkVersion = sdkVersion; | ||
*/ | ||
RestClient.prototype.fetch = function (request) { | ||
return tslib.__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 tslib.__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 }]; | ||
} | ||
async fetch(request) { | ||
const [installationId, installationToken] = await Promise.all([ | ||
this.firebaseInstallations.getId(), | ||
this.firebaseInstallations.getToken() | ||
]); | ||
const urlBase = window.FIREBASE_REMOTE_CONFIG_URL_BASE || | ||
'https://firebaseremoteconfig.googleapis.com'; | ||
const url = `${urlBase}/v1/projects/${this.projectId}/namespaces/${this.namespace}:fetch?key=${this.apiKey}`; | ||
const 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 || '*' | ||
}; | ||
const 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 */ | ||
}; | ||
const options = { | ||
method: 'POST', | ||
headers, | ||
body: JSON.stringify(requestBody) | ||
}; | ||
// This logic isn't REST-specific, but shimming abort logic isn't worth another decorator. | ||
const fetchPromise = fetch(url, options); | ||
const timeoutPromise = new Promise((_resolve, reject) => { | ||
// Maps async event listener to Promise API. | ||
request.signal.addEventListener(() => { | ||
// Emulates https://heycam.github.io/webidl/#aborterror | ||
const error = new Error('The operation was aborted.'); | ||
error.name = 'AbortError'; | ||
reject(error); | ||
}); | ||
}); | ||
}; | ||
return RestClient; | ||
}()); | ||
let response; | ||
try { | ||
await Promise.race([fetchPromise, timeoutPromise]); | ||
response = await fetchPromise; | ||
} | ||
catch (originalError) { | ||
let errorCode = "fetch-client-network" /* ErrorCode.FETCH_NETWORK */; | ||
if ((originalError === null || originalError === void 0 ? void 0 : originalError.name) === 'AbortError') { | ||
errorCode = "fetch-timeout" /* ErrorCode.FETCH_TIMEOUT */; | ||
} | ||
throw ERROR_FACTORY.create(errorCode, { | ||
originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message | ||
}); | ||
} | ||
let status = response.status; | ||
// Normalizes nullable header to optional. | ||
const responseEtag = response.headers.get('ETag') || undefined; | ||
let config; | ||
let state; | ||
// JSON parsing throws SyntaxError if the response body isn't a JSON string. | ||
// Requesting application/json and checking for a 200 ensures there's JSON data. | ||
if (response.status === 200) { | ||
let responseBody; | ||
try { | ||
responseBody = await response.json(); | ||
} | ||
catch (originalError) { | ||
throw ERROR_FACTORY.create("fetch-client-parse" /* ErrorCode.FETCH_PARSE */, { | ||
originalErrorMessage: originalError === null || originalError === void 0 ? void 0 : originalError.message | ||
}); | ||
} | ||
config = responseBody['entries']; | ||
state = responseBody['state']; | ||
} | ||
// 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 { status, eTag: responseEtag, config }; | ||
} | ||
} | ||
@@ -748,12 +690,12 @@ /** | ||
function setAbortableTimeout(signal, throttleEndTimeMillis) { | ||
return new Promise(function (resolve, reject) { | ||
return new Promise((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); | ||
const backoffMillis = Math.max(throttleEndTimeMillis - Date.now(), 0); | ||
const timeout = setTimeout(resolve, backoffMillis); | ||
// Adds listener, rather than sets onabort, because signal is a shared object. | ||
signal.addEventListener(function () { | ||
signal.addEventListener(() => { | ||
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 | ||
throttleEndTimeMillis | ||
})); | ||
@@ -771,3 +713,3 @@ }); | ||
// Uses string index defined by ErrorData, which FirebaseError implements. | ||
var httpStatus = Number(e.customData['httpStatus']); | ||
const httpStatus = Number(e.customData['httpStatus']); | ||
return (httpStatus === 429 || | ||
@@ -784,23 +726,14 @@ httpStatus === 500 || | ||
*/ | ||
var RetryingClient = /** @class */ (function () { | ||
function RetryingClient(client, storage) { | ||
class RetryingClient { | ||
constructor(client, storage) { | ||
this.client = client; | ||
this.storage = storage; | ||
} | ||
RetryingClient.prototype.fetch = function (request) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var throttleMetadata; | ||
return tslib.__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)]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async fetch(request) { | ||
const throttleMetadata = (await this.storage.getThrottleMetadata()) || { | ||
backoffCount: 0, | ||
throttleEndTimeMillis: Date.now() | ||
}; | ||
return this.attemptFetch(request, throttleMetadata); | ||
} | ||
/** | ||
@@ -811,52 +744,28 @@ * A recursive helper for attempting a fetch request repeatedly. | ||
*/ | ||
RetryingClient.prototype.attemptFetch = function (request, _a) { | ||
var throttleEndTimeMillis = _a.throttleEndTimeMillis, backoffCount = _a.backoffCount; | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var response, e_1, throttleMetadata; | ||
return tslib.__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() + util.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; | ||
}()); | ||
async attemptFetch(request, { throttleEndTimeMillis, backoffCount }) { | ||
// 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. | ||
await setAbortableTimeout(request.signal, throttleEndTimeMillis); | ||
try { | ||
const response = await this.client.fetch(request); | ||
// Note the SDK only clears throttle state if response is success or non-retriable. | ||
await this.storage.deleteThrottleMetadata(); | ||
return response; | ||
} | ||
catch (e) { | ||
if (!isRetriableError(e)) { | ||
throw e; | ||
} | ||
// Increments backoff state. | ||
const throttleMetadata = { | ||
throttleEndTimeMillis: Date.now() + util.calculateBackoffMillis(backoffCount), | ||
backoffCount: backoffCount + 1 | ||
}; | ||
// Persists state. | ||
await this.storage.setThrottleMetadata(throttleMetadata); | ||
return this.attemptFetch(request, throttleMetadata); | ||
} | ||
} | ||
} | ||
@@ -879,4 +788,4 @@ /** | ||
*/ | ||
var DEFAULT_FETCH_TIMEOUT_MILLIS = 60 * 1000; // One minute | ||
var DEFAULT_CACHE_MAX_AGE_MILLIS = 12 * 60 * 60 * 1000; // Twelve hours. | ||
const DEFAULT_FETCH_TIMEOUT_MILLIS = 60 * 1000; // One minute | ||
const DEFAULT_CACHE_MAX_AGE_MILLIS = 12 * 60 * 60 * 1000; // Twelve hours. | ||
/** | ||
@@ -887,4 +796,4 @@ * Encapsulates business logic mapping network and storage dependencies to the public SDK API. | ||
*/ | ||
var RemoteConfig = /** @class */ (function () { | ||
function RemoteConfig( | ||
class RemoteConfig { | ||
constructor( | ||
// Required by FirebaseServiceFactory interface. | ||
@@ -927,18 +836,9 @@ app, | ||
} | ||
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; | ||
}()); | ||
get fetchTimeMillis() { | ||
return this._storageCache.getLastSuccessfulFetchTimestampMillis() || -1; | ||
} | ||
get lastFetchStatus() { | ||
return this._storageCache.getLastFetchStatus() || 'no-fetch-yet'; | ||
} | ||
} | ||
@@ -965,3 +865,3 @@ /** | ||
function toFirebaseError(event, errorCode) { | ||
var originalError = event.target.error || undefined; | ||
const originalError = event.target.error || undefined; | ||
return ERROR_FACTORY.create(errorCode, { | ||
@@ -981,18 +881,18 @@ originalErrorMessage: originalError && (originalError === null || originalError === void 0 ? void 0 : originalError.message) | ||
*/ | ||
var APP_NAMESPACE_STORE = 'app_namespace_store'; | ||
var DB_NAME = 'firebase_remote_config'; | ||
var DB_VERSION = 1; | ||
const APP_NAMESPACE_STORE = 'app_namespace_store'; | ||
const DB_NAME = 'firebase_remote_config'; | ||
const DB_VERSION = 1; | ||
// Visible for testing. | ||
function openDatabase() { | ||
return new Promise(function (resolve, reject) { | ||
return new Promise((resolve, reject) => { | ||
try { | ||
var request = indexedDB.open(DB_NAME, DB_VERSION); | ||
request.onerror = function (event) { | ||
const request = indexedDB.open(DB_NAME, DB_VERSION); | ||
request.onerror = event => { | ||
reject(toFirebaseError(event, "storage-open" /* ErrorCode.STORAGE_OPEN */)); | ||
}; | ||
request.onsuccess = function (event) { | ||
request.onsuccess = event => { | ||
resolve(event.target.result); | ||
}; | ||
request.onupgradeneeded = function (event) { | ||
var db = event.target.result; | ||
request.onupgradeneeded = event => { | ||
const db = event.target.result; | ||
// We don't use 'break' in this switch statement, the fall-through | ||
@@ -1021,3 +921,3 @@ // behavior is what we want, because if there are multiple versions between | ||
*/ | ||
var Storage = /** @class */ (function () { | ||
class Storage { | ||
/** | ||
@@ -1028,4 +928,3 @@ * @param appId enables storage segmentation by app (ID + name). | ||
*/ | ||
function Storage(appId, appName, namespace, openDbPromise) { | ||
if (openDbPromise === void 0) { openDbPromise = openDatabase(); } | ||
constructor(appId, appName, namespace, openDbPromise = openDatabase()) { | ||
this.appId = appId; | ||
@@ -1036,154 +935,123 @@ this.appName = appName; | ||
} | ||
Storage.prototype.getLastFetchStatus = function () { | ||
getLastFetchStatus() { | ||
return this.get('last_fetch_status'); | ||
}; | ||
Storage.prototype.setLastFetchStatus = function (status) { | ||
} | ||
setLastFetchStatus(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 () { | ||
getLastSuccessfulFetchTimestampMillis() { | ||
return this.get('last_successful_fetch_timestamp_millis'); | ||
}; | ||
Storage.prototype.setLastSuccessfulFetchTimestampMillis = function (timestamp) { | ||
} | ||
setLastSuccessfulFetchTimestampMillis(timestamp) { | ||
return this.set('last_successful_fetch_timestamp_millis', timestamp); | ||
}; | ||
Storage.prototype.getLastSuccessfulFetchResponse = function () { | ||
} | ||
getLastSuccessfulFetchResponse() { | ||
return this.get('last_successful_fetch_response'); | ||
}; | ||
Storage.prototype.setLastSuccessfulFetchResponse = function (response) { | ||
} | ||
setLastSuccessfulFetchResponse(response) { | ||
return this.set('last_successful_fetch_response', response); | ||
}; | ||
Storage.prototype.getActiveConfig = function () { | ||
} | ||
getActiveConfig() { | ||
return this.get('active_config'); | ||
}; | ||
Storage.prototype.setActiveConfig = function (config) { | ||
} | ||
setActiveConfig(config) { | ||
return this.set('active_config', config); | ||
}; | ||
Storage.prototype.getActiveConfigEtag = function () { | ||
} | ||
getActiveConfigEtag() { | ||
return this.get('active_config_etag'); | ||
}; | ||
Storage.prototype.setActiveConfigEtag = function (etag) { | ||
} | ||
setActiveConfigEtag(etag) { | ||
return this.set('active_config_etag', etag); | ||
}; | ||
Storage.prototype.getThrottleMetadata = function () { | ||
} | ||
getThrottleMetadata() { | ||
return this.get('throttle_metadata'); | ||
}; | ||
Storage.prototype.setThrottleMetadata = function (metadata) { | ||
} | ||
setThrottleMetadata(metadata) { | ||
return this.set('throttle_metadata', metadata); | ||
}; | ||
Storage.prototype.deleteThrottleMetadata = function () { | ||
} | ||
deleteThrottleMetadata() { | ||
return this.delete('throttle_metadata'); | ||
}; | ||
Storage.prototype.get = function (key) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var db; | ||
var _this = this; | ||
return tslib.__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 | ||
})); | ||
} | ||
})]; | ||
} | ||
}); | ||
} | ||
async get(key) { | ||
const db = await this.openDbPromise; | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([APP_NAMESPACE_STORE], 'readonly'); | ||
const objectStore = transaction.objectStore(APP_NAMESPACE_STORE); | ||
const compositeKey = this.createCompositeKey(key); | ||
try { | ||
const request = objectStore.get(compositeKey); | ||
request.onerror = event => { | ||
reject(toFirebaseError(event, "storage-get" /* ErrorCode.STORAGE_GET */)); | ||
}; | ||
request.onsuccess = event => { | ||
const 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 tslib.__awaiter(this, void 0, void 0, function () { | ||
var db; | ||
var _this = this; | ||
return tslib.__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 | ||
})); | ||
} | ||
})]; | ||
} | ||
}); | ||
} | ||
async set(key, value) { | ||
const db = await this.openDbPromise; | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite'); | ||
const objectStore = transaction.objectStore(APP_NAMESPACE_STORE); | ||
const compositeKey = this.createCompositeKey(key); | ||
try { | ||
const request = objectStore.put({ | ||
compositeKey, | ||
value | ||
}); | ||
request.onerror = (event) => { | ||
reject(toFirebaseError(event, "storage-set" /* ErrorCode.STORAGE_SET */)); | ||
}; | ||
request.onsuccess = () => { | ||
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 tslib.__awaiter(this, void 0, void 0, function () { | ||
var db; | ||
var _this = this; | ||
return tslib.__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 | ||
})); | ||
} | ||
})]; | ||
} | ||
}); | ||
} | ||
async delete(key) { | ||
const db = await this.openDbPromise; | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([APP_NAMESPACE_STORE], 'readwrite'); | ||
const objectStore = transaction.objectStore(APP_NAMESPACE_STORE); | ||
const compositeKey = this.createCompositeKey(key); | ||
try { | ||
const request = objectStore.delete(compositeKey); | ||
request.onerror = (event) => { | ||
reject(toFirebaseError(event, "storage-delete" /* ErrorCode.STORAGE_DELETE */)); | ||
}; | ||
request.onsuccess = () => { | ||
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) { | ||
createCompositeKey(key) { | ||
return [this.appId, this.appName, this.namespace, key].join(); | ||
}; | ||
return Storage; | ||
}()); | ||
} | ||
} | ||
@@ -1209,4 +1077,4 @@ /** | ||
*/ | ||
var StorageCache = /** @class */ (function () { | ||
function StorageCache(storage) { | ||
class StorageCache { | ||
constructor(storage) { | ||
this.storage = storage; | ||
@@ -1217,64 +1085,53 @@ } | ||
*/ | ||
StorageCache.prototype.getLastFetchStatus = function () { | ||
getLastFetchStatus() { | ||
return this.lastFetchStatus; | ||
}; | ||
StorageCache.prototype.getLastSuccessfulFetchTimestampMillis = function () { | ||
} | ||
getLastSuccessfulFetchTimestampMillis() { | ||
return this.lastSuccessfulFetchTimestampMillis; | ||
}; | ||
StorageCache.prototype.getActiveConfig = function () { | ||
} | ||
getActiveConfig() { | ||
return this.activeConfig; | ||
}; | ||
} | ||
/** | ||
* Read-ahead getter | ||
*/ | ||
StorageCache.prototype.loadFromStorage = function () { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var lastFetchStatusPromise, lastSuccessfulFetchTimestampMillisPromise, activeConfigPromise, lastFetchStatus, lastSuccessfulFetchTimestampMillis, activeConfig; | ||
return tslib.__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*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
async loadFromStorage() { | ||
const lastFetchStatusPromise = this.storage.getLastFetchStatus(); | ||
const lastSuccessfulFetchTimestampMillisPromise = this.storage.getLastSuccessfulFetchTimestampMillis(); | ||
const activeConfigPromise = this.storage.getActiveConfig(); | ||
// Note: | ||
// 1. we consistently check for undefined to avoid clobbering defined values | ||
// in memory | ||
// 2. we defer awaiting to improve readability, as opposed to destructuring | ||
// a Promise.all result, for example | ||
const lastFetchStatus = await lastFetchStatusPromise; | ||
if (lastFetchStatus) { | ||
this.lastFetchStatus = lastFetchStatus; | ||
} | ||
const lastSuccessfulFetchTimestampMillis = await lastSuccessfulFetchTimestampMillisPromise; | ||
if (lastSuccessfulFetchTimestampMillis) { | ||
this.lastSuccessfulFetchTimestampMillis = | ||
lastSuccessfulFetchTimestampMillis; | ||
} | ||
const activeConfig = await activeConfigPromise; | ||
if (activeConfig) { | ||
this.activeConfig = activeConfig; | ||
} | ||
} | ||
/** | ||
* Write-through setters | ||
*/ | ||
StorageCache.prototype.setLastFetchStatus = function (status) { | ||
setLastFetchStatus(status) { | ||
this.lastFetchStatus = status; | ||
return this.storage.setLastFetchStatus(status); | ||
}; | ||
StorageCache.prototype.setLastSuccessfulFetchTimestampMillis = function (timestampMillis) { | ||
} | ||
setLastSuccessfulFetchTimestampMillis(timestampMillis) { | ||
this.lastSuccessfulFetchTimestampMillis = timestampMillis; | ||
return this.storage.setLastSuccessfulFetchTimestampMillis(timestampMillis); | ||
}; | ||
StorageCache.prototype.setActiveConfig = function (activeConfig) { | ||
} | ||
setActiveConfig(activeConfig) { | ||
this.activeConfig = activeConfig; | ||
return this.storage.setActiveConfig(activeConfig); | ||
}; | ||
return StorageCache; | ||
}()); | ||
} | ||
} | ||
@@ -1300,11 +1157,10 @@ /** | ||
app.registerVersion(name, version); | ||
// BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation | ||
app.registerVersion(name, version, 'cjs5'); | ||
function remoteConfigFactory(container, _a) { | ||
var namespace = _a.instanceIdentifier; | ||
// BUILD_TARGET will be replaced by values like esm2017, cjs2017, etc during the compilation | ||
app.registerVersion(name, version, 'cjs2017'); | ||
function remoteConfigFactory(container, { instanceIdentifier: namespace }) { | ||
/* Dependencies */ | ||
// getImmediate for FirebaseApp will always succeed | ||
var app$1 = container.getProvider('app').getImmediate(); | ||
const app$1 = container.getProvider('app').getImmediate(); | ||
// The following call will always succeed because rc has `import '@firebase/installations'` | ||
var installations = container | ||
const installations = container | ||
.getProvider('installations-internal') | ||
@@ -1321,3 +1177,3 @@ .getImmediate(); | ||
// Normalizes optional inputs. | ||
var _b = app$1.options, projectId = _b.projectId, apiKey = _b.apiKey, appId = _b.appId; | ||
const { projectId, apiKey, appId } = app$1.options; | ||
if (!projectId) { | ||
@@ -1333,14 +1189,14 @@ throw ERROR_FACTORY.create("registration-project-id" /* ErrorCode.REGISTRATION_PROJECT_ID */); | ||
namespace = namespace || 'firebase'; | ||
var storage = new Storage(appId, app$1.name, namespace); | ||
var storageCache = new StorageCache(storage); | ||
var logger$1 = new logger.Logger(name); | ||
const storage = new Storage(appId, app$1.name, namespace); | ||
const storageCache = new StorageCache(storage); | ||
const logger$1 = new logger.Logger(name); | ||
// Sets ERROR as the default log level. | ||
// See RemoteConfig#setLogLevel for corresponding normalization to ERROR log level. | ||
logger$1.logLevel = logger.LogLevel.ERROR; | ||
var restClient = new RestClient(installations, | ||
const restClient = new RestClient(installations, | ||
// Uses the JS SDK version, by which the RC package version can be deduced, if necessary. | ||
app.SDK_VERSION, namespace, projectId, apiKey, appId); | ||
var retryingClient = new RetryingClient(restClient, storage); | ||
var cachingClient = new CachingClient(retryingClient, storage, storageCache, logger$1); | ||
var remoteConfigInstance = new RemoteConfig(app$1, cachingClient, storageCache, storage, logger$1); | ||
const retryingClient = new RetryingClient(restClient, storage); | ||
const cachingClient = new CachingClient(retryingClient, storage, storageCache, logger$1); | ||
const remoteConfigInstance = new RemoteConfig(app$1, cachingClient, storageCache, storage, logger$1); | ||
// Starts warming cache. | ||
@@ -1382,15 +1238,6 @@ // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
*/ | ||
function fetchAndActivate(remoteConfig) { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
return tslib.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
remoteConfig = util.getModularInstance(remoteConfig); | ||
return [4 /*yield*/, fetchConfig(remoteConfig)]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/, activate(remoteConfig)]; | ||
} | ||
}); | ||
}); | ||
async function fetchAndActivate(remoteConfig) { | ||
remoteConfig = util.getModularInstance(remoteConfig); | ||
await fetchConfig(remoteConfig); | ||
return activate(remoteConfig); | ||
} | ||
@@ -1407,25 +1254,13 @@ /** | ||
*/ | ||
function isSupported() { | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var isDBOpenable; | ||
return tslib.__generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!util.isIndexedDBAvailable()) { | ||
return [2 /*return*/, false]; | ||
} | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, util.validateIndexedDBOpenable()]; | ||
case 2: | ||
isDBOpenable = _a.sent(); | ||
return [2 /*return*/, isDBOpenable]; | ||
case 3: | ||
_a.sent(); | ||
return [2 /*return*/, false]; | ||
case 4: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
async function isSupported() { | ||
if (!util.isIndexedDBAvailable()) { | ||
return false; | ||
} | ||
try { | ||
const isDBOpenable = await util.validateIndexedDBOpenable(); | ||
return isDBOpenable; | ||
} | ||
catch (error) { | ||
return false; | ||
} | ||
} | ||
@@ -1432,0 +1267,0 @@ |
{ | ||
"name": "@firebase/remote-config", | ||
"version": "0.4.9-canary.beaa4dffb", | ||
"version": "0.4.9-vertexai-preview.36cb0178c", | ||
"description": "The Remote Config package of the Firebase JS SDK", | ||
@@ -9,3 +9,2 @@ "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)", | ||
"module": "dist/esm/index.esm2017.js", | ||
"esm5": "dist/esm/index.esm.js", | ||
"exports": { | ||
@@ -15,3 +14,2 @@ ".": { | ||
"require": "./dist/index.cjs.js", | ||
"esm5": "./dist/esm/index.esm.js", | ||
"default": "./dist/esm/index.esm2017.js" | ||
@@ -44,9 +42,9 @@ }, | ||
"peerDependencies": { | ||
"@firebase/app": "0.10.11-canary.beaa4dffb" | ||
"@firebase/app": "0.10.11-vertexai-preview.36cb0178c" | ||
}, | ||
"dependencies": { | ||
"@firebase/installations": "0.6.9-canary.beaa4dffb", | ||
"@firebase/logger": "0.4.2-canary.beaa4dffb", | ||
"@firebase/util": "1.10.0-canary.beaa4dffb", | ||
"@firebase/component": "0.6.9-canary.beaa4dffb", | ||
"@firebase/installations": "0.6.9-vertexai-preview.36cb0178c", | ||
"@firebase/logger": "0.4.2-vertexai-preview.36cb0178c", | ||
"@firebase/util": "1.10.0-vertexai-preview.36cb0178c", | ||
"@firebase/component": "0.6.9-vertexai-preview.36cb0178c", | ||
"tslib": "^2.1.0" | ||
@@ -56,3 +54,3 @@ }, | ||
"devDependencies": { | ||
"@firebase/app": "0.10.11-canary.beaa4dffb", | ||
"@firebase/app": "0.10.11-vertexai-preview.36cb0178c", | ||
"rollup": "2.79.1", | ||
@@ -59,0 +57,0 @@ "rollup-plugin-typescript2": "0.31.2", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
2
2
366905
62
5044
+ Added@firebase/app@0.10.11-vertexai-preview.36cb0178c(transitive)
+ Added@firebase/component@0.6.9-vertexai-preview.36cb0178c(transitive)
+ Added@firebase/installations@0.6.9-vertexai-preview.36cb0178c(transitive)
+ Added@firebase/logger@0.4.2-vertexai-preview.36cb0178c(transitive)
+ Added@firebase/util@1.10.0-vertexai-preview.36cb0178c(transitive)
- Removed@firebase/app@0.10.11-canary.beaa4dffb(transitive)
- Removed@firebase/component@0.6.9-canary.beaa4dffb(transitive)
- Removed@firebase/installations@0.6.9-canary.beaa4dffb(transitive)
- Removed@firebase/logger@0.4.2-canary.beaa4dffb(transitive)
- Removed@firebase/util@1.10.0-canary.beaa4dffb(transitive)
Updated@firebase/installations@0.6.9-vertexai-preview.36cb0178c