mobileapplicationPassvault/node_modules/@firebase/app/dist/esm/index.esm5.js

1125 lines
44 KiB
JavaScript
Raw Permalink Normal View History

2024-04-12 05:23:32 +00:00
import { Component, ComponentContainer } from '@firebase/component';
import { __values, __assign, __awaiter, __generator, __spreadArray, __read } from 'tslib';
import { Logger, setUserLogHandler, setLogLevel as setLogLevel$1 } from '@firebase/logger';
import { ErrorFactory, getDefaultAppConfig, deepEqual, FirebaseError, base64urlEncodeWithoutPadding, isIndexedDBAvailable, validateIndexedDBOpenable } from '@firebase/util';
export { FirebaseError } from '@firebase/util';
import { openDB } from 'idb';
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var PlatformLoggerServiceImpl = /** @class */ (function () {
function PlatformLoggerServiceImpl(container) {
this.container = container;
}
// In initial implementation, this will be called by installations on
// auth token refresh, and installations will send this string.
PlatformLoggerServiceImpl.prototype.getPlatformInfoString = function () {
var providers = this.container.getProviders();
// Loop through providers and get library/version pairs from any that are
// version components.
return providers
.map(function (provider) {
if (isVersionServiceProvider(provider)) {
var service = provider.getImmediate();
return "".concat(service.library, "/").concat(service.version);
}
else {
return null;
}
})
.filter(function (logString) { return logString; })
.join(' ');
};
return PlatformLoggerServiceImpl;
}());
/**
*
* @param provider check if this provider provides a VersionService
*
* NOTE: Using Provider<'app-version'> is a hack to indicate that the provider
* provides VersionService. The provider is not necessarily a 'app-version'
* provider.
*/
function isVersionServiceProvider(provider) {
var component = provider.getComponent();
return (component === null || component === void 0 ? void 0 : component.type) === "VERSION" /* ComponentType.VERSION */;
}
var name$o = "@firebase/app";
var version$1 = "0.9.27";
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var logger = new Logger('@firebase/app');
var name$n = "@firebase/app-compat";
var name$m = "@firebase/analytics-compat";
var name$l = "@firebase/analytics";
var name$k = "@firebase/app-check-compat";
var name$j = "@firebase/app-check";
var name$i = "@firebase/auth";
var name$h = "@firebase/auth-compat";
var name$g = "@firebase/database";
var name$f = "@firebase/database-compat";
var name$e = "@firebase/functions";
var name$d = "@firebase/functions-compat";
var name$c = "@firebase/installations";
var name$b = "@firebase/installations-compat";
var name$a = "@firebase/messaging";
var name$9 = "@firebase/messaging-compat";
var name$8 = "@firebase/performance";
var name$7 = "@firebase/performance-compat";
var name$6 = "@firebase/remote-config";
var name$5 = "@firebase/remote-config-compat";
var name$4 = "@firebase/storage";
var name$3 = "@firebase/storage-compat";
var name$2 = "@firebase/firestore";
var name$1 = "@firebase/firestore-compat";
var name = "firebase";
var version = "10.8.0";
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var _a$1;
/**
* The default app name
*
* @internal
*/
var DEFAULT_ENTRY_NAME = '[DEFAULT]';
var PLATFORM_LOG_STRING = (_a$1 = {},
_a$1[name$o] = 'fire-core',
_a$1[name$n] = 'fire-core-compat',
_a$1[name$l] = 'fire-analytics',
_a$1[name$m] = 'fire-analytics-compat',
_a$1[name$j] = 'fire-app-check',
_a$1[name$k] = 'fire-app-check-compat',
_a$1[name$i] = 'fire-auth',
_a$1[name$h] = 'fire-auth-compat',
_a$1[name$g] = 'fire-rtdb',
_a$1[name$f] = 'fire-rtdb-compat',
_a$1[name$e] = 'fire-fn',
_a$1[name$d] = 'fire-fn-compat',
_a$1[name$c] = 'fire-iid',
_a$1[name$b] = 'fire-iid-compat',
_a$1[name$a] = 'fire-fcm',
_a$1[name$9] = 'fire-fcm-compat',
_a$1[name$8] = 'fire-perf',
_a$1[name$7] = 'fire-perf-compat',
_a$1[name$6] = 'fire-rc',
_a$1[name$5] = 'fire-rc-compat',
_a$1[name$4] = 'fire-gcs',
_a$1[name$3] = 'fire-gcs-compat',
_a$1[name$2] = 'fire-fst',
_a$1[name$1] = 'fire-fst-compat',
_a$1['fire-js'] = 'fire-js',
_a$1[name] = 'fire-js-all',
_a$1);
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @internal
*/
var _apps = new Map();
/**
* Registered components.
*
* @internal
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var _components = new Map();
/**
* @param component - the component being added to this app's container
*
* @internal
*/
function _addComponent(app, component) {
try {
app.container.addComponent(component);
}
catch (e) {
logger.debug("Component ".concat(component.name, " failed to register with FirebaseApp ").concat(app.name), e);
}
}
/**
*
* @internal
*/
function _addOrOverwriteComponent(app, component) {
app.container.addOrOverwriteComponent(component);
}
/**
*
* @param component - the component to register
* @returns whether or not the component is registered successfully
*
* @internal
*/
function _registerComponent(component) {
var e_1, _a;
var componentName = component.name;
if (_components.has(componentName)) {
logger.debug("There were multiple attempts to register component ".concat(componentName, "."));
return false;
}
_components.set(componentName, component);
try {
// add the component to existing app instances
for (var _b = __values(_apps.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var app = _c.value;
_addComponent(app, component);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return true;
}
/**
*
* @param app - FirebaseApp instance
* @param name - service name
*
* @returns the provider for the service with the matching name
*
* @internal
*/
function _getProvider(app, name) {
var heartbeatController = app.container
.getProvider('heartbeat')
.getImmediate({ optional: true });
if (heartbeatController) {
void heartbeatController.triggerHeartbeat();
}
return app.container.getProvider(name);
}
/**
*
* @param app - FirebaseApp instance
* @param name - service name
* @param instanceIdentifier - service instance identifier in case the service supports multiple instances
*
* @internal
*/
function _removeServiceInstance(app, name, instanceIdentifier) {
if (instanceIdentifier === void 0) { instanceIdentifier = DEFAULT_ENTRY_NAME; }
_getProvider(app, name).clearInstance(instanceIdentifier);
}
/**
* Test only
*
* @internal
*/
function _clearComponents() {
_components.clear();
}
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var _a;
var ERRORS = (_a = {},
_a["no-app" /* AppError.NO_APP */] = "No Firebase App '{$appName}' has been created - " +
'call initializeApp() first',
_a["bad-app-name" /* AppError.BAD_APP_NAME */] = "Illegal App name: '{$appName}",
_a["duplicate-app" /* AppError.DUPLICATE_APP */] = "Firebase App named '{$appName}' already exists with different options or config",
_a["app-deleted" /* AppError.APP_DELETED */] = "Firebase App named '{$appName}' already deleted",
_a["no-options" /* AppError.NO_OPTIONS */] = 'Need to provide options, when not being deployed to hosting via source.',
_a["invalid-app-argument" /* AppError.INVALID_APP_ARGUMENT */] = 'firebase.{$appName}() takes either no argument or a ' +
'Firebase App instance.',
_a["invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */] = 'First argument to `onLog` must be null or a function.',
_a["idb-open" /* AppError.IDB_OPEN */] = 'Error thrown when opening IndexedDB. Original error: {$originalErrorMessage}.',
_a["idb-get" /* AppError.IDB_GET */] = 'Error thrown when reading from IndexedDB. Original error: {$originalErrorMessage}.',
_a["idb-set" /* AppError.IDB_WRITE */] = 'Error thrown when writing to IndexedDB. Original error: {$originalErrorMessage}.',
_a["idb-delete" /* AppError.IDB_DELETE */] = 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.',
_a);
var ERROR_FACTORY = new ErrorFactory('app', 'Firebase', ERRORS);
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var FirebaseAppImpl = /** @class */ (function () {
function FirebaseAppImpl(options, config, container) {
var _this = this;
this._isDeleted = false;
this._options = __assign({}, options);
this._config = __assign({}, config);
this._name = config.name;
this._automaticDataCollectionEnabled =
config.automaticDataCollectionEnabled;
this._container = container;
this.container.addComponent(new Component('app', function () { return _this; }, "PUBLIC" /* ComponentType.PUBLIC */));
}
Object.defineProperty(FirebaseAppImpl.prototype, "automaticDataCollectionEnabled", {
get: function () {
this.checkDestroyed();
return this._automaticDataCollectionEnabled;
},
set: function (val) {
this.checkDestroyed();
this._automaticDataCollectionEnabled = val;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FirebaseAppImpl.prototype, "name", {
get: function () {
this.checkDestroyed();
return this._name;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FirebaseAppImpl.prototype, "options", {
get: function () {
this.checkDestroyed();
return this._options;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FirebaseAppImpl.prototype, "config", {
get: function () {
this.checkDestroyed();
return this._config;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FirebaseAppImpl.prototype, "container", {
get: function () {
return this._container;
},
enumerable: false,
configurable: true
});
Object.defineProperty(FirebaseAppImpl.prototype, "isDeleted", {
get: function () {
return this._isDeleted;
},
set: function (val) {
this._isDeleted = val;
},
enumerable: false,
configurable: true
});
/**
* This function will throw an Error if the App has already been deleted -
* use before performing API actions on the App.
*/
FirebaseAppImpl.prototype.checkDestroyed = function () {
if (this.isDeleted) {
throw ERROR_FACTORY.create("app-deleted" /* AppError.APP_DELETED */, { appName: this._name });
}
};
return FirebaseAppImpl;
}());
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The current SDK version.
*
* @public
*/
var SDK_VERSION = version;
function initializeApp(_options, rawConfig) {
var e_1, _a;
if (rawConfig === void 0) { rawConfig = {}; }
var options = _options;
if (typeof rawConfig !== 'object') {
var name_1 = rawConfig;
rawConfig = { name: name_1 };
}
var config = __assign({ name: DEFAULT_ENTRY_NAME, automaticDataCollectionEnabled: false }, rawConfig);
var name = config.name;
if (typeof name !== 'string' || !name) {
throw ERROR_FACTORY.create("bad-app-name" /* AppError.BAD_APP_NAME */, {
appName: String(name)
});
}
options || (options = getDefaultAppConfig());
if (!options) {
throw ERROR_FACTORY.create("no-options" /* AppError.NO_OPTIONS */);
}
var existingApp = _apps.get(name);
if (existingApp) {
// return the existing app if options and config deep equal the ones in the existing app.
if (deepEqual(options, existingApp.options) &&
deepEqual(config, existingApp.config)) {
return existingApp;
}
else {
throw ERROR_FACTORY.create("duplicate-app" /* AppError.DUPLICATE_APP */, { appName: name });
}
}
var container = new ComponentContainer(name);
try {
for (var _b = __values(_components.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var component = _c.value;
container.addComponent(component);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
var newApp = new FirebaseAppImpl(options, config, container);
_apps.set(name, newApp);
return newApp;
}
/**
* Retrieves a {@link @firebase/app#FirebaseApp} instance.
*
* When called with no arguments, the default app is returned. When an app name
* is provided, the app corresponding to that name is returned.
*
* An exception is thrown if the app being retrieved has not yet been
* initialized.
*
* @example
* ```javascript
* // Return the default app
* const app = getApp();
* ```
*
* @example
* ```javascript
* // Return a named app
* const otherApp = getApp("otherApp");
* ```
*
* @param name - Optional name of the app to return. If no name is
* provided, the default is `"[DEFAULT]"`.
*
* @returns The app corresponding to the provided app name.
* If no app name is provided, the default app is returned.
*
* @public
*/
function getApp(name) {
if (name === void 0) { name = DEFAULT_ENTRY_NAME; }
var app = _apps.get(name);
if (!app && name === DEFAULT_ENTRY_NAME && getDefaultAppConfig()) {
return initializeApp();
}
if (!app) {
throw ERROR_FACTORY.create("no-app" /* AppError.NO_APP */, { appName: name });
}
return app;
}
/**
* A (read-only) array of all initialized apps.
* @public
*/
function getApps() {
return Array.from(_apps.values());
}
/**
* Renders this app unusable and frees the resources of all associated
* services.
*
* @example
* ```javascript
* deleteApp(app)
* .then(function() {
* console.log("App deleted successfully");
* })
* .catch(function(error) {
* console.log("Error deleting app:", error);
* });
* ```
*
* @public
*/
function deleteApp(app) {
return __awaiter(this, void 0, void 0, function () {
var name;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
name = app.name;
if (!_apps.has(name)) return [3 /*break*/, 2];
_apps.delete(name);
return [4 /*yield*/, Promise.all(app.container
.getProviders()
.map(function (provider) { return provider.delete(); }))];
case 1:
_a.sent();
app.isDeleted = true;
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
}
/**
* Registers a library's name and version for platform logging purposes.
* @param library - Name of 1p or 3p library (e.g. firestore, angularfire)
* @param version - Current version of that library.
* @param variant - Bundle variant, e.g., node, rn, etc.
*
* @public
*/
function registerVersion(libraryKeyOrName, version, variant) {
var _a;
// TODO: We can use this check to whitelist strings when/if we set up
// a good whitelist system.
var library = (_a = PLATFORM_LOG_STRING[libraryKeyOrName]) !== null && _a !== void 0 ? _a : libraryKeyOrName;
if (variant) {
library += "-".concat(variant);
}
var libraryMismatch = library.match(/\s|\//);
var versionMismatch = version.match(/\s|\//);
if (libraryMismatch || versionMismatch) {
var warning = [
"Unable to register library \"".concat(library, "\" with version \"").concat(version, "\":")
];
if (libraryMismatch) {
warning.push("library name \"".concat(library, "\" contains illegal characters (whitespace or \"/\")"));
}
if (libraryMismatch && versionMismatch) {
warning.push('and');
}
if (versionMismatch) {
warning.push("version name \"".concat(version, "\" contains illegal characters (whitespace or \"/\")"));
}
logger.warn(warning.join(' '));
return;
}
_registerComponent(new Component("".concat(library, "-version"), function () { return ({ library: library, version: version }); }, "VERSION" /* ComponentType.VERSION */));
}
/**
* Sets log handler for all Firebase SDKs.
* @param logCallback - An optional custom log handler that executes user code whenever
* the Firebase SDK makes a logging call.
*
* @public
*/
function onLog(logCallback, options) {
if (logCallback !== null && typeof logCallback !== 'function') {
throw ERROR_FACTORY.create("invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */);
}
setUserLogHandler(logCallback, options);
}
/**
* Sets log level for all Firebase SDKs.
*
* All of the log types above the current log level are captured (i.e. if
* you set the log level to `info`, errors are logged, but `debug` and
* `verbose` logs are not).
*
* @public
*/
function setLogLevel(logLevel) {
setLogLevel$1(logLevel);
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var DB_NAME = 'firebase-heartbeat-database';
var DB_VERSION = 1;
var STORE_NAME = 'firebase-heartbeat-store';
var dbPromise = null;
function getDbPromise() {
if (!dbPromise) {
dbPromise = openDB(DB_NAME, DB_VERSION, {
upgrade: function (db, oldVersion) {
// We don't use 'break' in this switch statement, the fall-through
// behavior is what we want, because if there are multiple versions between
// the old version and the current version, we want ALL the migrations
// that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (oldVersion) {
case 0:
try {
db.createObjectStore(STORE_NAME);
}
catch (e) {
// Safari/iOS browsers throw occasional exceptions on
// db.createObjectStore() that may be a bug. Avoid blocking
// the rest of the app functionality.
console.warn(e);
}
}
}
}).catch(function (e) {
throw ERROR_FACTORY.create("idb-open" /* AppError.IDB_OPEN */, {
originalErrorMessage: e.message
});
});
}
return dbPromise;
}
function readHeartbeatsFromIndexedDB(app) {
return __awaiter(this, void 0, void 0, function () {
var db, tx, result, e_1, idbGetError;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 4, , 5]);
return [4 /*yield*/, getDbPromise()];
case 1:
db = _a.sent();
tx = db.transaction(STORE_NAME);
return [4 /*yield*/, tx.objectStore(STORE_NAME).get(computeKey(app))];
case 2:
result = _a.sent();
// We already have the value but tx.done can throw,
// so we need to await it here to catch errors
return [4 /*yield*/, tx.done];
case 3:
// We already have the value but tx.done can throw,
// so we need to await it here to catch errors
_a.sent();
return [2 /*return*/, result];
case 4:
e_1 = _a.sent();
if (e_1 instanceof FirebaseError) {
logger.warn(e_1.message);
}
else {
idbGetError = ERROR_FACTORY.create("idb-get" /* AppError.IDB_GET */, {
originalErrorMessage: e_1 === null || e_1 === void 0 ? void 0 : e_1.message
});
logger.warn(idbGetError.message);
}
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
});
}
function writeHeartbeatsToIndexedDB(app, heartbeatObject) {
return __awaiter(this, void 0, void 0, function () {
var db, tx, objectStore, e_2, idbGetError;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 4, , 5]);
return [4 /*yield*/, getDbPromise()];
case 1:
db = _a.sent();
tx = db.transaction(STORE_NAME, 'readwrite');
objectStore = tx.objectStore(STORE_NAME);
return [4 /*yield*/, objectStore.put(heartbeatObject, computeKey(app))];
case 2:
_a.sent();
return [4 /*yield*/, tx.done];
case 3:
_a.sent();
return [3 /*break*/, 5];
case 4:
e_2 = _a.sent();
if (e_2 instanceof FirebaseError) {
logger.warn(e_2.message);
}
else {
idbGetError = ERROR_FACTORY.create("idb-set" /* AppError.IDB_WRITE */, {
originalErrorMessage: e_2 === null || e_2 === void 0 ? void 0 : e_2.message
});
logger.warn(idbGetError.message);
}
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
});
}
function computeKey(app) {
return "".concat(app.name, "!").concat(app.options.appId);
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var MAX_HEADER_BYTES = 1024;
// 30 days
var STORED_HEARTBEAT_RETENTION_MAX_MILLIS = 30 * 24 * 60 * 60 * 1000;
var HeartbeatServiceImpl = /** @class */ (function () {
function HeartbeatServiceImpl(container) {
var _this = this;
this.container = container;
/**
* In-memory cache for heartbeats, used by getHeartbeatsHeader() to generate
* the header string.
* Stores one record per date. This will be consolidated into the standard
* format of one record per user agent string before being sent as a header.
* Populated from indexedDB when the controller is instantiated and should
* be kept in sync with indexedDB.
* Leave public for easier testing.
*/
this._heartbeatsCache = null;
var app = this.container.getProvider('app').getImmediate();
this._storage = new HeartbeatStorageImpl(app);
this._heartbeatsCachePromise = this._storage.read().then(function (result) {
_this._heartbeatsCache = result;
return result;
});
}
/**
* Called to report a heartbeat. The function will generate
* a HeartbeatsByUserAgent object, update heartbeatsCache, and persist it
* to IndexedDB.
* Note that we only store one heartbeat per day. So if a heartbeat for today is
* already logged, subsequent calls to this function in the same day will be ignored.
*/
HeartbeatServiceImpl.prototype.triggerHeartbeat = function () {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var platformLogger, agent, date, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
platformLogger = this.container
.getProvider('platform-logger')
.getImmediate();
agent = platformLogger.getPlatformInfoString();
date = getUTCDateString();
if (!(((_a = this._heartbeatsCache) === null || _a === void 0 ? void 0 : _a.heartbeats) == null)) return [3 /*break*/, 2];
_c = this;
return [4 /*yield*/, this._heartbeatsCachePromise];
case 1:
_c._heartbeatsCache = _d.sent();
// If we failed to construct a heartbeats cache, then return immediately.
if (((_b = this._heartbeatsCache) === null || _b === void 0 ? void 0 : _b.heartbeats) == null) {
return [2 /*return*/];
}
_d.label = 2;
case 2:
// Do not store a heartbeat if one is already stored for this day
// or if a header has already been sent today.
if (this._heartbeatsCache.lastSentHeartbeatDate === date ||
this._heartbeatsCache.heartbeats.some(function (singleDateHeartbeat) { return singleDateHeartbeat.date === date; })) {
return [2 /*return*/];
}
else {
// There is no entry for this date. Create one.
this._heartbeatsCache.heartbeats.push({ date: date, agent: agent });
}
// Remove entries older than 30 days.
this._heartbeatsCache.heartbeats = this._heartbeatsCache.heartbeats.filter(function (singleDateHeartbeat) {
var hbTimestamp = new Date(singleDateHeartbeat.date).valueOf();
var now = Date.now();
return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS;
});
return [2 /*return*/, this._storage.overwrite(this._heartbeatsCache)];
}
});
});
};
/**
* Returns a base64 encoded string which can be attached to the heartbeat-specific header directly.
* It also clears all heartbeats from memory as well as in IndexedDB.
*
* NOTE: Consuming product SDKs should not send the header if this method
* returns an empty string.
*/
HeartbeatServiceImpl.prototype.getHeartbeatsHeader = function () {
var _a;
return __awaiter(this, void 0, void 0, function () {
var date, _b, heartbeatsToSend, unsentEntries, headerString;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!(this._heartbeatsCache === null)) return [3 /*break*/, 2];
return [4 /*yield*/, this._heartbeatsCachePromise];
case 1:
_c.sent();
_c.label = 2;
case 2:
// If it's still null or the array is empty, there is no data to send.
if (((_a = this._heartbeatsCache) === null || _a === void 0 ? void 0 : _a.heartbeats) == null ||
this._heartbeatsCache.heartbeats.length === 0) {
return [2 /*return*/, ''];
}
date = getUTCDateString();
_b = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats), heartbeatsToSend = _b.heartbeatsToSend, unsentEntries = _b.unsentEntries;
headerString = base64urlEncodeWithoutPadding(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend }));
// Store last sent date to prevent another being logged/sent for the same day.
this._heartbeatsCache.lastSentHeartbeatDate = date;
if (!(unsentEntries.length > 0)) return [3 /*break*/, 4];
// Store any unsent entries if they exist.
this._heartbeatsCache.heartbeats = unsentEntries;
// This seems more likely than emptying the array (below) to lead to some odd state
// since the cache isn't empty and this will be called again on the next request,
// and is probably safest if we await it.
return [4 /*yield*/, this._storage.overwrite(this._heartbeatsCache)];
case 3:
// This seems more likely than emptying the array (below) to lead to some odd state
// since the cache isn't empty and this will be called again on the next request,
// and is probably safest if we await it.
_c.sent();
return [3 /*break*/, 5];
case 4:
this._heartbeatsCache.heartbeats = [];
// Do not wait for this, to reduce latency.
void this._storage.overwrite(this._heartbeatsCache);
_c.label = 5;
case 5: return [2 /*return*/, headerString];
}
});
});
};
return HeartbeatServiceImpl;
}());
function getUTCDateString() {
var today = new Date();
// Returns date format 'YYYY-MM-DD'
return today.toISOString().substring(0, 10);
}
function extractHeartbeatsForHeader(heartbeatsCache, maxSize) {
var e_1, _a;
if (maxSize === void 0) { maxSize = MAX_HEADER_BYTES; }
// Heartbeats grouped by user agent in the standard format to be sent in
// the header.
var heartbeatsToSend = [];
// Single date format heartbeats that are not sent.
var unsentEntries = heartbeatsCache.slice();
var _loop_1 = function (singleDateHeartbeat) {
// Look for an existing entry with the same user agent.
var heartbeatEntry = heartbeatsToSend.find(function (hb) { return hb.agent === singleDateHeartbeat.agent; });
if (!heartbeatEntry) {
// If no entry for this user agent exists, create one.
heartbeatsToSend.push({
agent: singleDateHeartbeat.agent,
dates: [singleDateHeartbeat.date]
});
if (countBytes(heartbeatsToSend) > maxSize) {
// If the header would exceed max size, remove the added heartbeat
// entry and stop adding to the header.
heartbeatsToSend.pop();
return "break";
}
}
else {
heartbeatEntry.dates.push(singleDateHeartbeat.date);
// If the header would exceed max size, remove the added date
// and stop adding to the header.
if (countBytes(heartbeatsToSend) > maxSize) {
heartbeatEntry.dates.pop();
return "break";
}
}
// Pop unsent entry from queue. (Skipped if adding the entry exceeded
// quota and the loop breaks early.)
unsentEntries = unsentEntries.slice(1);
};
try {
for (var heartbeatsCache_1 = __values(heartbeatsCache), heartbeatsCache_1_1 = heartbeatsCache_1.next(); !heartbeatsCache_1_1.done; heartbeatsCache_1_1 = heartbeatsCache_1.next()) {
var singleDateHeartbeat = heartbeatsCache_1_1.value;
var state_1 = _loop_1(singleDateHeartbeat);
if (state_1 === "break")
break;
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (heartbeatsCache_1_1 && !heartbeatsCache_1_1.done && (_a = heartbeatsCache_1.return)) _a.call(heartbeatsCache_1);
}
finally { if (e_1) throw e_1.error; }
}
return {
heartbeatsToSend: heartbeatsToSend,
unsentEntries: unsentEntries
};
}
var HeartbeatStorageImpl = /** @class */ (function () {
function HeartbeatStorageImpl(app) {
this.app = app;
this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck();
}
HeartbeatStorageImpl.prototype.runIndexedDBEnvironmentCheck = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (!isIndexedDBAvailable()) {
return [2 /*return*/, false];
}
else {
return [2 /*return*/, validateIndexedDBOpenable()
.then(function () { return true; })
.catch(function () { return false; })];
}
});
});
};
/**
* Read all heartbeats.
*/
HeartbeatStorageImpl.prototype.read = function () {
return __awaiter(this, void 0, void 0, function () {
var canUseIndexedDB, idbHeartbeatObject;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
case 1:
canUseIndexedDB = _a.sent();
if (!!canUseIndexedDB) return [3 /*break*/, 2];
return [2 /*return*/, { heartbeats: [] }];
case 2: return [4 /*yield*/, readHeartbeatsFromIndexedDB(this.app)];
case 3:
idbHeartbeatObject = _a.sent();
if (idbHeartbeatObject === null || idbHeartbeatObject === void 0 ? void 0 : idbHeartbeatObject.heartbeats) {
return [2 /*return*/, idbHeartbeatObject];
}
else {
return [2 /*return*/, { heartbeats: [] }];
}
case 4: return [2 /*return*/];
}
});
});
};
// overwrite the storage with the provided heartbeats
HeartbeatStorageImpl.prototype.overwrite = function (heartbeatsObject) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var canUseIndexedDB, existingHeartbeatsObject;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
case 1:
canUseIndexedDB = _b.sent();
if (!!canUseIndexedDB) return [3 /*break*/, 2];
return [2 /*return*/];
case 2: return [4 /*yield*/, this.read()];
case 3:
existingHeartbeatsObject = _b.sent();
return [2 /*return*/, writeHeartbeatsToIndexedDB(this.app, {
lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate,
heartbeats: heartbeatsObject.heartbeats
})];
}
});
});
};
// add heartbeats
HeartbeatStorageImpl.prototype.add = function (heartbeatsObject) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var canUseIndexedDB, existingHeartbeatsObject;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this._canUseIndexedDBPromise];
case 1:
canUseIndexedDB = _b.sent();
if (!!canUseIndexedDB) return [3 /*break*/, 2];
return [2 /*return*/];
case 2: return [4 /*yield*/, this.read()];
case 3:
existingHeartbeatsObject = _b.sent();
return [2 /*return*/, writeHeartbeatsToIndexedDB(this.app, {
lastSentHeartbeatDate: (_a = heartbeatsObject.lastSentHeartbeatDate) !== null && _a !== void 0 ? _a : existingHeartbeatsObject.lastSentHeartbeatDate,
heartbeats: __spreadArray(__spreadArray([], __read(existingHeartbeatsObject.heartbeats), false), __read(heartbeatsObject.heartbeats), false)
})];
}
});
});
};
return HeartbeatStorageImpl;
}());
/**
* Calculate bytes of a HeartbeatsByUserAgent array after being wrapped
* in a platform logging header JSON object, stringified, and converted
* to base 64.
*/
function countBytes(heartbeatsCache) {
// base64 has a restricted set of characters, all of which should be 1 byte.
return base64urlEncodeWithoutPadding(
// heartbeatsCache wrapper properties
JSON.stringify({ version: 2, heartbeats: heartbeatsCache })).length;
}
/**
* @license
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function registerCoreComponents(variant) {
_registerComponent(new Component('platform-logger', function (container) { return new PlatformLoggerServiceImpl(container); }, "PRIVATE" /* ComponentType.PRIVATE */));
_registerComponent(new Component('heartbeat', function (container) { return new HeartbeatServiceImpl(container); }, "PRIVATE" /* ComponentType.PRIVATE */));
// Register `app` package.
registerVersion(name$o, version$1, variant);
// BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
registerVersion(name$o, version$1, 'esm5');
// Register platform SDK identifier (no version).
registerVersion('fire-js', '');
}
/**
* Firebase App
*
* @remarks This package coordinates the communication between the different Firebase components
* @packageDocumentation
*/
registerCoreComponents('');
export { SDK_VERSION, DEFAULT_ENTRY_NAME as _DEFAULT_ENTRY_NAME, _addComponent, _addOrOverwriteComponent, _apps, _clearComponents, _components, _getProvider, _registerComponent, _removeServiceInstance, deleteApp, getApp, getApps, initializeApp, onLog, registerVersion, setLogLevel };
//# sourceMappingURL=index.esm5.js.map