firebase
Version:
Firebase JavaScript library for web and Node.js
1,345 lines (1,322 loc) • 79.4 kB
JavaScript
import { _getProvider, getApp, _registerComponent, registerVersion } from 'https://www.gstatic.com/firebasejs/9.0.0/firebase-app.js';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __spreadArray(to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
}
/**
* @license
* Copyright 2017 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 stringToByteArray$1 = function (str) {
// TODO(user): Use native implementations if/when available
var out = [];
var p = 0;
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
if (c < 128) {
out[p++] = c;
}
else if (c < 2048) {
out[p++] = (c >> 6) | 192;
out[p++] = (c & 63) | 128;
}
else if ((c & 0xfc00) === 0xd800 &&
i + 1 < str.length &&
(str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) {
// Surrogate Pair
c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff);
out[p++] = (c >> 18) | 240;
out[p++] = ((c >> 12) & 63) | 128;
out[p++] = ((c >> 6) & 63) | 128;
out[p++] = (c & 63) | 128;
}
else {
out[p++] = (c >> 12) | 224;
out[p++] = ((c >> 6) & 63) | 128;
out[p++] = (c & 63) | 128;
}
}
return out;
};
/**
* Turns an array of numbers into the string given by the concatenation of the
* characters to which the numbers correspond.
* @param bytes Array of numbers representing characters.
* @return Stringification of the array.
*/
var byteArrayToString = function (bytes) {
// TODO(user): Use native implementations if/when available
var out = [];
var pos = 0, c = 0;
while (pos < bytes.length) {
var c1 = bytes[pos++];
if (c1 < 128) {
out[c++] = String.fromCharCode(c1);
}
else if (c1 > 191 && c1 < 224) {
var c2 = bytes[pos++];
out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
}
else if (c1 > 239 && c1 < 365) {
// Surrogate Pair
var c2 = bytes[pos++];
var c3 = bytes[pos++];
var c4 = bytes[pos++];
var u = (((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63)) -
0x10000;
out[c++] = String.fromCharCode(0xd800 + (u >> 10));
out[c++] = String.fromCharCode(0xdc00 + (u & 1023));
}
else {
var c2 = bytes[pos++];
var c3 = bytes[pos++];
out[c++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
}
}
return out.join('');
};
// We define it as an object literal instead of a class because a class compiled down to es5 can't
// be treeshaked. https://github.com/rollup/rollup/issues/1691
// Static lookup maps, lazily populated by init_()
var base64 = {
/**
* Maps bytes to characters.
*/
byteToCharMap_: null,
/**
* Maps characters to bytes.
*/
charToByteMap_: null,
/**
* Maps bytes to websafe characters.
* @private
*/
byteToCharMapWebSafe_: null,
/**
* Maps websafe characters to bytes.
* @private
*/
charToByteMapWebSafe_: null,
/**
* Our default alphabet, shared between
* ENCODED_VALS and ENCODED_VALS_WEBSAFE
*/
ENCODED_VALS_BASE: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789',
/**
* Our default alphabet. Value 64 (=) is special; it means "nothing."
*/
get ENCODED_VALS() {
return this.ENCODED_VALS_BASE + '+/=';
},
/**
* Our websafe alphabet.
*/
get ENCODED_VALS_WEBSAFE() {
return this.ENCODED_VALS_BASE + '-_.';
},
/**
* Whether this browser supports the atob and btoa functions. This extension
* started at Mozilla but is now implemented by many browsers. We use the
* ASSUME_* variables to avoid pulling in the full useragent detection library
* but still allowing the standard per-browser compilations.
*
*/
HAS_NATIVE_SUPPORT: typeof atob === 'function',
/**
* Base64-encode an array of bytes.
*
* @param input An array of bytes (numbers with
* value in [0, 255]) to encode.
* @param webSafe Boolean indicating we should use the
* alternative alphabet.
* @return The base64 encoded string.
*/
encodeByteArray: function (input, webSafe) {
if (!Array.isArray(input)) {
throw Error('encodeByteArray takes an array as a parameter');
}
this.init_();
var byteToCharMap = webSafe
? this.byteToCharMapWebSafe_
: this.byteToCharMap_;
var output = [];
for (var i = 0; i < input.length; i += 3) {
var byte1 = input[i];
var haveByte2 = i + 1 < input.length;
var byte2 = haveByte2 ? input[i + 1] : 0;
var haveByte3 = i + 2 < input.length;
var byte3 = haveByte3 ? input[i + 2] : 0;
var outByte1 = byte1 >> 2;
var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
var outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6);
var outByte4 = byte3 & 0x3f;
if (!haveByte3) {
outByte4 = 64;
if (!haveByte2) {
outByte3 = 64;
}
}
output.push(byteToCharMap[outByte1], byteToCharMap[outByte2], byteToCharMap[outByte3], byteToCharMap[outByte4]);
}
return output.join('');
},
/**
* Base64-encode a string.
*
* @param input A string to encode.
* @param webSafe If true, we should use the
* alternative alphabet.
* @return The base64 encoded string.
*/
encodeString: function (input, webSafe) {
// Shortcut for Mozilla browsers that implement
// a native base64 encoder in the form of "btoa/atob"
if (this.HAS_NATIVE_SUPPORT && !webSafe) {
return btoa(input);
}
return this.encodeByteArray(stringToByteArray$1(input), webSafe);
},
/**
* Base64-decode a string.
*
* @param input to decode.
* @param webSafe True if we should use the
* alternative alphabet.
* @return string representing the decoded value.
*/
decodeString: function (input, webSafe) {
// Shortcut for Mozilla browsers that implement
// a native base64 encoder in the form of "btoa/atob"
if (this.HAS_NATIVE_SUPPORT && !webSafe) {
return atob(input);
}
return byteArrayToString(this.decodeStringToByteArray(input, webSafe));
},
/**
* Base64-decode a string.
*
* In base-64 decoding, groups of four characters are converted into three
* bytes. If the encoder did not apply padding, the input length may not
* be a multiple of 4.
*
* In this case, the last group will have fewer than 4 characters, and
* padding will be inferred. If the group has one or two characters, it decodes
* to one byte. If the group has three characters, it decodes to two bytes.
*
* @param input Input to decode.
* @param webSafe True if we should use the web-safe alphabet.
* @return bytes representing the decoded value.
*/
decodeStringToByteArray: function (input, webSafe) {
this.init_();
var charToByteMap = webSafe
? this.charToByteMapWebSafe_
: this.charToByteMap_;
var output = [];
for (var i = 0; i < input.length;) {
var byte1 = charToByteMap[input.charAt(i++)];
var haveByte2 = i < input.length;
var byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0;
++i;
var haveByte3 = i < input.length;
var byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64;
++i;
var haveByte4 = i < input.length;
var byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64;
++i;
if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) {
throw Error();
}
var outByte1 = (byte1 << 2) | (byte2 >> 4);
output.push(outByte1);
if (byte3 !== 64) {
var outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2);
output.push(outByte2);
if (byte4 !== 64) {
var outByte3 = ((byte3 << 6) & 0xc0) | byte4;
output.push(outByte3);
}
}
}
return output;
},
/**
* Lazy static initialization function. Called before
* accessing any of the static map variables.
* @private
*/
init_: function () {
if (!this.byteToCharMap_) {
this.byteToCharMap_ = {};
this.charToByteMap_ = {};
this.byteToCharMapWebSafe_ = {};
this.charToByteMapWebSafe_ = {};
// We want quick mappings back and forth, so we precompute two maps.
for (var i = 0; i < this.ENCODED_VALS.length; i++) {
this.byteToCharMap_[i] = this.ENCODED_VALS.charAt(i);
this.charToByteMap_[this.byteToCharMap_[i]] = i;
this.byteToCharMapWebSafe_[i] = this.ENCODED_VALS_WEBSAFE.charAt(i);
this.charToByteMapWebSafe_[this.byteToCharMapWebSafe_[i]] = i;
// Be forgiving when decoding and correctly decode both encodings.
if (i >= this.ENCODED_VALS_BASE.length) {
this.charToByteMap_[this.ENCODED_VALS_WEBSAFE.charAt(i)] = i;
this.charToByteMapWebSafe_[this.ENCODED_VALS.charAt(i)] = i;
}
}
}
}
};
/**
* URL-safe base64 decoding
*
* NOTE: DO NOT use the global atob() function - it does NOT support the
* base64Url variant encoding.
*
* @param str To be decoded
* @return Decoded result, if possible
*/
var base64Decode = function (str) {
try {
return base64.decodeString(str, true);
}
catch (e) {
console.error('base64Decode failed: ', e);
}
return null;
};
/**
* @license
* Copyright 2017 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 Deferred = /** @class */ (function () {
function Deferred() {
var _this = this;
this.reject = function () { };
this.resolve = function () { };
this.promise = new Promise(function (resolve, reject) {
_this.resolve = resolve;
_this.reject = reject;
});
}
/**
* Our API internals are not promiseified and cannot because our callback APIs have subtle expectations around
* invoking promises inline, which Promises are forbidden to do. This method accepts an optional node-style callback
* and returns a node-style callback which will resolve or reject the Deferred's promise.
*/
Deferred.prototype.wrapCallback = function (callback) {
var _this = this;
return function (error, value) {
if (error) {
_this.reject(error);
}
else {
_this.resolve(value);
}
if (typeof callback === 'function') {
// Attaching noop handler just in case developer wasn't expecting
// promises
_this.promise.catch(function () { });
// Some of our callbacks don't expect a value and our own tests
// assert that the parameter length is 1
if (callback.length === 1) {
callback(error);
}
else {
callback(error, value);
}
}
};
};
return Deferred;
}());
/**
* This method checks if indexedDB is supported by current browser/service worker context
* @return true if indexedDB is supported by current browser/service worker context
*/
function isIndexedDBAvailable() {
return 'indexedDB' in self && indexedDB != null;
}
/**
* Polyfill for `globalThis` object.
* @returns the `globalThis` object for the given environment.
*/
function getGlobal() {
if (typeof self !== 'undefined') {
return self;
}
if (typeof window !== 'undefined') {
return window;
}
if (typeof global !== 'undefined') {
return global;
}
throw new Error('Unable to locate global object.');
}
/**
* @license
* Copyright 2017 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 ERROR_NAME = 'FirebaseError';
// Based on code from:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types
var FirebaseError = /** @class */ (function (_super) {
__extends(FirebaseError, _super);
function FirebaseError(code, message, customData) {
var _this = _super.call(this, message) || this;
_this.code = code;
_this.customData = customData;
_this.name = ERROR_NAME;
// Fix For ES5
// https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
Object.setPrototypeOf(_this, FirebaseError.prototype);
// Maintains proper stack trace for where our error was thrown.
// Only available on V8.
if (Error.captureStackTrace) {
Error.captureStackTrace(_this, ErrorFactory.prototype.create);
}
return _this;
}
return FirebaseError;
}(Error));
var ErrorFactory = /** @class */ (function () {
function ErrorFactory(service, serviceName, errors) {
this.service = service;
this.serviceName = serviceName;
this.errors = errors;
}
ErrorFactory.prototype.create = function (code) {
var data = [];
for (var _i = 1; _i < arguments.length; _i++) {
data[_i - 1] = arguments[_i];
}
var customData = data[0] || {};
var fullCode = this.service + "/" + code;
var template = this.errors[code];
var message = template ? replaceTemplate(template, customData) : 'Error';
// Service Name: Error message (service/code).
var fullMessage = this.serviceName + ": " + message + " (" + fullCode + ").";
var error = new FirebaseError(fullCode, fullMessage, customData);
return error;
};
return ErrorFactory;
}());
function replaceTemplate(template, data) {
return template.replace(PATTERN, function (_, key) {
var value = data[key];
return value != null ? String(value) : "<" + key + "?>";
});
}
var PATTERN = /\{\$([^}]+)}/g;
/**
* @license
* Copyright 2017 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.
*/
/**
* Evaluates a JSON string into a javascript object.
*
* @param {string} str A string containing JSON.
* @return {*} The javascript object representing the specified JSON.
*/
function jsonEval(str) {
return JSON.parse(str);
}
/**
* @license
* Copyright 2017 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.
*/
/**
* Decodes a Firebase auth. token into constituent parts.
*
* Notes:
* - May return with invalid / incomplete claims if there's no native base64 decoding support.
* - Doesn't check if the token is actually valid.
*/
var decode = function (token) {
var header = {}, claims = {}, data = {}, signature = '';
try {
var parts = token.split('.');
header = jsonEval(base64Decode(parts[0]) || '');
claims = jsonEval(base64Decode(parts[1]) || '');
signature = parts[2];
data = claims['d'] || {};
delete claims['d'];
}
catch (e) { }
return {
header: header,
claims: claims,
data: data,
signature: signature
};
};
/**
* Decodes a Firebase auth. token and returns its issued at time if valid, null otherwise.
*
* Notes:
* - May return null if there's no native base64 decoding support.
* - Doesn't check if the token is actually valid.
*/
var issuedAtTime = function (token) {
var claims = decode(token).claims;
if (typeof claims === 'object' && claims.hasOwnProperty('iat')) {
return claims['iat'];
}
return null;
};
/**
* @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.
*/
function getModularInstance(service) {
if (service && service._delegate) {
return service._delegate;
}
else {
return service;
}
}
/**
* Component for service name T, e.g. `auth`, `auth-internal`
*/
var Component = /** @class */ (function () {
/**
*
* @param name The public service name, e.g. app, auth, firestore, database
* @param instanceFactory Service factory responsible for creating the public interface
* @param type whether the service provided by the component is public or private
*/
function Component(name, instanceFactory, type) {
this.name = name;
this.instanceFactory = instanceFactory;
this.type = type;
this.multipleInstances = false;
/**
* Properties to be added to the service namespace
*/
this.serviceProps = {};
this.instantiationMode = "LAZY" /* LAZY */;
this.onInstanceCreated = null;
}
Component.prototype.setInstantiationMode = function (mode) {
this.instantiationMode = mode;
return this;
};
Component.prototype.setMultipleInstances = function (multipleInstances) {
this.multipleInstances = multipleInstances;
return this;
};
Component.prototype.setServiceProps = function (props) {
this.serviceProps = props;
return this;
};
Component.prototype.setInstanceCreatedCallback = function (callback) {
this.onInstanceCreated = callback;
return this;
};
return Component;
}());
/**
* @license
* Copyright 2017 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;
/**
* The JS SDK supports 5 log levels and also allows a user the ability to
* silence the logs altogether.
*
* The order is a follows:
* DEBUG < VERBOSE < INFO < WARN < ERROR
*
* All of the log types above the current log level will be captured (i.e. if
* you set the log level to `INFO`, errors will still be logged, but `DEBUG` and
* `VERBOSE` logs will not)
*/
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
LogLevel[LogLevel["VERBOSE"] = 1] = "VERBOSE";
LogLevel[LogLevel["INFO"] = 2] = "INFO";
LogLevel[LogLevel["WARN"] = 3] = "WARN";
LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
LogLevel[LogLevel["SILENT"] = 5] = "SILENT";
})(LogLevel || (LogLevel = {}));
var levelStringToEnum = {
'debug': LogLevel.DEBUG,
'verbose': LogLevel.VERBOSE,
'info': LogLevel.INFO,
'warn': LogLevel.WARN,
'error': LogLevel.ERROR,
'silent': LogLevel.SILENT
};
/**
* The default log level
*/
var defaultLogLevel = LogLevel.INFO;
/**
* By default, `console.debug` is not displayed in the developer console (in
* chrome). To avoid forcing users to have to opt-in to these logs twice
* (i.e. once for firebase, and once in the console), we are sending `DEBUG`
* logs to the `console.log` function.
*/
var ConsoleMethod = (_a = {},
_a[LogLevel.DEBUG] = 'log',
_a[LogLevel.VERBOSE] = 'log',
_a[LogLevel.INFO] = 'info',
_a[LogLevel.WARN] = 'warn',
_a[LogLevel.ERROR] = 'error',
_a);
/**
* The default log handler will forward DEBUG, VERBOSE, INFO, WARN, and ERROR
* messages on to their corresponding console counterparts (if the log method
* is supported by the current log level)
*/
var defaultLogHandler = function (instance, logType) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
if (logType < instance.logLevel) {
return;
}
var now = new Date().toISOString();
var method = ConsoleMethod[logType];
if (method) {
console[method].apply(console, __spreadArray(["[" + now + "] " + instance.name + ":"], args));
}
else {
throw new Error("Attempted to log a message with an invalid logType (value: " + logType + ")");
}
};
var Logger = /** @class */ (function () {
/**
* Gives you an instance of a Logger to capture messages according to
* Firebase's logging scheme.
*
* @param name The name that the logs will be associated with
*/
function Logger(name) {
this.name = name;
/**
* The log level of the given Logger instance.
*/
this._logLevel = defaultLogLevel;
/**
* The main (internal) log handler for the Logger instance.
* Can be set to a new function in internal package code but not by user.
*/
this._logHandler = defaultLogHandler;
/**
* The optional, additional, user-defined log handler for the Logger instance.
*/
this._userLogHandler = null;
}
Object.defineProperty(Logger.prototype, "logLevel", {
get: function () {
return this._logLevel;
},
set: function (val) {
if (!(val in LogLevel)) {
throw new TypeError("Invalid value \"" + val + "\" assigned to `logLevel`");
}
this._logLevel = val;
},
enumerable: false,
configurable: true
});
// Workaround for setter/getter having to be the same type.
Logger.prototype.setLogLevel = function (val) {
this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val;
};
Object.defineProperty(Logger.prototype, "logHandler", {
get: function () {
return this._logHandler;
},
set: function (val) {
if (typeof val !== 'function') {
throw new TypeError('Value assigned to `logHandler` must be a function');
}
this._logHandler = val;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Logger.prototype, "userLogHandler", {
get: function () {
return this._userLogHandler;
},
set: function (val) {
this._userLogHandler = val;
},
enumerable: false,
configurable: true
});
/**
* The functions below are all based on the `console` interface
*/
Logger.prototype.debug = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._userLogHandler && this._userLogHandler.apply(this, __spreadArray([this, LogLevel.DEBUG], args));
this._logHandler.apply(this, __spreadArray([this, LogLevel.DEBUG], args));
};
Logger.prototype.log = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._userLogHandler && this._userLogHandler.apply(this, __spreadArray([this, LogLevel.VERBOSE], args));
this._logHandler.apply(this, __spreadArray([this, LogLevel.VERBOSE], args));
};
Logger.prototype.info = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._userLogHandler && this._userLogHandler.apply(this, __spreadArray([this, LogLevel.INFO], args));
this._logHandler.apply(this, __spreadArray([this, LogLevel.INFO], args));
};
Logger.prototype.warn = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._userLogHandler && this._userLogHandler.apply(this, __spreadArray([this, LogLevel.WARN], args));
this._logHandler.apply(this, __spreadArray([this, LogLevel.WARN], args));
};
Logger.prototype.error = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._userLogHandler && this._userLogHandler.apply(this, __spreadArray([this, LogLevel.ERROR], args));
this._logHandler.apply(this, __spreadArray([this, LogLevel.ERROR], args));
};
return Logger;
}());
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const APP_CHECK_STATES = new Map();
const DEFAULT_STATE = {
activated: false,
tokenObservers: []
};
const DEBUG_STATE = {
enabled: false
};
function getState(app) {
return APP_CHECK_STATES.get(app) || DEFAULT_STATE;
}
function setState(app, state) {
APP_CHECK_STATES.set(app, state);
}
function getDebugState() {
return DEBUG_STATE;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const BASE_ENDPOINT = 'https://content-firebaseappcheck.googleapis.com/v1beta';
const EXCHANGE_RECAPTCHA_TOKEN_METHOD = 'exchangeRecaptchaToken';
const EXCHANGE_DEBUG_TOKEN_METHOD = 'exchangeDebugToken';
const TOKEN_REFRESH_TIME = {
/**
* The offset time before token natural expiration to run the refresh.
* This is currently 5 minutes.
*/
OFFSET_DURATION: 5 * 60 * 1000,
/**
* This is the first retrial wait after an error. This is currently
* 30 seconds.
*/
RETRIAL_MIN_WAIT: 30 * 1000,
/**
* This is the maximum retrial wait, currently 16 minutes.
*/
RETRIAL_MAX_WAIT: 16 * 60 * 1000
};
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Port from auth proactiverefresh.js
*
*/
// TODO: move it to @firebase/util?
// TODO: allow to config whether refresh should happen in the background
class Refresher {
constructor(operation, retryPolicy, getWaitDuration, lowerBound, upperBound) {
this.operation = operation;
this.retryPolicy = retryPolicy;
this.getWaitDuration = getWaitDuration;
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.pending = null;
this.nextErrorWaitInterval = lowerBound;
if (lowerBound > upperBound) {
throw new Error('Proactive refresh lower bound greater than upper bound!');
}
}
start() {
this.nextErrorWaitInterval = this.lowerBound;
this.process(true).catch(() => {
/* we don't care about the result */
});
}
stop() {
if (this.pending) {
this.pending.reject('cancelled');
this.pending = null;
}
}
isRunning() {
return !!this.pending;
}
async process(hasSucceeded) {
this.stop();
try {
this.pending = new Deferred();
await sleep(this.getNextRun(hasSucceeded));
// Why do we resolve a promise, then immediate wait for it?
// We do it to make the promise chain cancellable.
// We can call stop() which rejects the promise before the following line execute, which makes
// the code jump to the catch block.
// TODO: unit test this
this.pending.resolve();
await this.pending.promise;
this.pending = new Deferred();
await this.operation();
this.pending.resolve();
await this.pending.promise;
this.process(true).catch(() => {
/* we don't care about the result */
});
}
catch (error) {
if (this.retryPolicy(error)) {
this.process(false).catch(() => {
/* we don't care about the result */
});
}
else {
this.stop();
}
}
}
getNextRun(hasSucceeded) {
if (hasSucceeded) {
// If last operation succeeded, reset next error wait interval and return
// the default wait duration.
this.nextErrorWaitInterval = this.lowerBound;
// Return typical wait duration interval after a successful operation.
return this.getWaitDuration();
}
else {
// Get next error wait interval.
const currentErrorWaitInterval = this.nextErrorWaitInterval;
// Double interval for next consecutive error.
this.nextErrorWaitInterval *= 2;
// Make sure next wait interval does not exceed the maximum upper bound.
if (this.nextErrorWaitInterval > this.upperBound) {
this.nextErrorWaitInterval = this.upperBound;
}
return currentErrorWaitInterval;
}
}
}
function sleep(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const ERRORS = {
["already-initialized" /* ALREADY_INITIALIZED */]: 'You have already called initializeAppCheck() for FirebaseApp {$appName} with ' +
'different options. To avoid this error, call initializeAppCheck() with the ' +
'same options as when it was originally called. This will return the ' +
'already initialized instance.',
["use-before-activation" /* USE_BEFORE_ACTIVATION */]: 'App Check is being used before initializeAppCheck() is called for FirebaseApp {$appName}. ' +
'Call initializeAppCheck() before instantiating other Firebase services.',
["fetch-network-error" /* FETCH_NETWORK_ERROR */]: 'Fetch failed to connect to a network. Check Internet connection. ' +
'Original error: {$originalErrorMessage}.',
["fetch-parse-error" /* FETCH_PARSE_ERROR */]: 'Fetch client could not parse response.' +
' Original error: {$originalErrorMessage}.',
["fetch-status-error" /* FETCH_STATUS_ERROR */]: 'Fetch server returned an HTTP error status. HTTP status: {$httpStatus}.',
["storage-open" /* STORAGE_OPEN */]: 'Error thrown when opening storage. Original error: {$originalErrorMessage}.',
["storage-get" /* STORAGE_GET */]: 'Error thrown when reading from storage. Original error: {$originalErrorMessage}.',
["storage-set" /* STORAGE_WRITE */]: 'Error thrown when writing to storage. Original error: {$originalErrorMessage}.',
["recaptcha-error" /* RECAPTCHA_ERROR */]: 'ReCAPTCHA error.'
};
const ERROR_FACTORY = new ErrorFactory('appCheck', 'AppCheck', ERRORS);
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function getRecaptcha() {
return self.grecaptcha;
}
function ensureActivated(app) {
if (!getState(app).activated) {
throw ERROR_FACTORY.create("use-before-activation" /* USE_BEFORE_ACTIVATION */, {
appName: app.name
});
}
}
/**
* Copied from https://stackoverflow.com/a/2117523
*/
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (Math.random() * 16) | 0, v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
async function exchangeToken({ url, body }, platformLoggerProvider) {
const headers = {
'Content-Type': 'application/json'
};
// If platform logger exists, add the platform info string to the header.
const platformLogger = platformLoggerProvider.getImmediate({
optional: true
});
if (platformLogger) {
headers['X-Firebase-Client'] = platformLogger.getPlatformInfoString();
}
const options = {
method: 'POST',
body: JSON.stringify(body),
headers
};
let response;
try {
response = await fetch(url, options);
}
catch (originalError) {
throw ERROR_FACTORY.create("fetch-network-error" /* FETCH_NETWORK_ERROR */, {
originalErrorMessage: originalError.message
});
}
if (response.status !== 200) {
throw ERROR_FACTORY.create("fetch-status-error" /* FETCH_STATUS_ERROR */, {
httpStatus: response.status
});
}
let responseBody;
try {
// JSON parsing throws SyntaxError if the response body isn't a JSON string.
responseBody = await response.json();
}
catch (originalError) {
throw ERROR_FACTORY.create("fetch-parse-error" /* FETCH_PARSE_ERROR */, {
originalErrorMessage: originalError.message
});
}
// Protobuf duration format.
// https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Duration
const match = responseBody.ttl.match(/^([\d.]+)(s)$/);
if (!match || !match[2] || isNaN(Number(match[1]))) {
throw ERROR_FACTORY.create("fetch-parse-error" /* FETCH_PARSE_ERROR */, {
originalErrorMessage: `ttl field (timeToLive) is not in standard Protobuf Duration ` +
`format: ${responseBody.ttl}`
});
}
const timeToLiveAsNumber = Number(match[1]) * 1000;
const now = Date.now();
return {
token: responseBody.attestationToken,
expireTimeMillis: now + timeToLiveAsNumber,
issuedAtTimeMillis: now
};
}
function getExchangeRecaptchaTokenRequest(app, reCAPTCHAToken) {
const { projectId, appId, apiKey } = app.options;
return {
url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_RECAPTCHA_TOKEN_METHOD}?key=${apiKey}`,
body: {
// eslint-disable-next-line
recaptcha_token: reCAPTCHAToken
}
};
}
function getExchangeDebugTokenRequest(app, debugToken) {
const { projectId, appId, apiKey } = app.options;
return {
url: `${BASE_ENDPOINT}/projects/${projectId}/apps/${appId}:${EXCHANGE_DEBUG_TOKEN_METHOD}?key=${apiKey}`,
body: {
// eslint-disable-next-line
debug_token: debugToken
}
};
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const DB_NAME = 'firebase-app-check-database';
const DB_VERSION = 1;
const STORE_NAME = 'firebase-app-check-store';
const DEBUG_TOKEN_KEY = 'debug-token';
let dbPromise = null;
function getDBPromise() {
if (dbPromise) {
return dbPromise;
}
dbPromise = new Promise((resolve, reject) => {
try {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onsuccess = event => {
resolve(event.target.result);
};
request.onerror = event => {
var _a;
reject(ERROR_FACTORY.create("storage-open" /* STORAGE_OPEN */, {
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
}));
};
request.onupgradeneeded = event => {
const db = event.target.result;
// We don't use 'break' in this switch statement, the fall-through
// behavior is what we want, because if there are multiple versions between
// the old version and the current version, we want ALL the migrations
// that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (event.oldVersion) {
case 0:
db.createObjectStore(STORE_NAME, {
keyPath: 'compositeKey'
});
}
};
}
catch (e) {
reject(ERROR_FACTORY.create("storage-open" /* STORAGE_OPEN */, {
originalErrorMessage: e.message
}));
}
});
return dbPromise;
}
function readTokenFromIndexedDB(app) {
return read(computeKey(app));
}
function writeTokenToIndexedDB(app, token) {
return write(computeKey(app), token);
}
function writeDebugTokenToIndexedDB(token) {
return write(DEBUG_TOKEN_KEY, token);
}
function readDebugTokenFromIndexedDB() {
return read(DEBUG_TOKEN_KEY);
}
async function write(key, value) {
const db = await getDBPromise();
const transaction = db.transaction(STORE_NAME, 'readwrite');
const store = transaction.objectStore(STORE_NAME);
const request = store.put({
compositeKey: key,
value
});
return new Promise((resolve, reject) => {
request.onsuccess = _event => {
resolve();
};
transaction.onerror = event => {
var _a;
reject(ERROR_FACTORY.create("storage-set" /* STORAGE_WRITE */, {
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
}));
};
});
}
async function read(key) {
const db = await getDBPromise();
const transaction = db.transaction(STORE_NAME, 'readonly');
const store = transaction.objectStore(STORE_NAME);
const request = store.get(key);
return new Promise((resolve, reject) => {
request.onsuccess = event => {
const result = event.target.result;
if (result) {
resolve(result.value);
}
else {
resolve(undefined);
}
};
transaction.onerror = event => {
var _a;
reject(ERROR_FACTORY.create("storage-get" /* STORAGE_GET */, {
originalErrorMessage: (_a = event.target.error) === null || _a === void 0 ? void 0 : _a.message
}));
};
});
}
function computeKey(app) {
return `${app.options.appId}-${app.name}`;
}
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const logger = new Logger('https://www.gstatic.com/firebasejs/9.0.0/firebase-app.js-check');
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Always resolves. In case of an error reading from indexeddb, resolve with undefined
*/
async function readTokenFromStorage(app) {
if (isIndexedDBAvailable()) {
let token = undefined;
try {
token = await readTokenFromIndexedDB(app);
}
catch (e) {
// swallow the error and return undefined
logger.warn(`Failed to read token from IndexedDB. Error: ${e}`);
}
return token;
}
return undefined;
}
/**
* Always resolves. In case of an error writing to indexeddb, print a warning and resolve the promise
*/
function writeTokenToStorage(app, token) {
if (isIndexedDBAvailable()) {
return writeTokenToIndexedDB(app, token).catch(e => {
// swallow the error and resolve the promise
logger.warn(`Failed to write token to IndexedDB. Error: ${e}`);
}