@firebase/remote-config 0.4.9 → 0.4.10

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