diff options
Diffstat (limited to 'frontend-old/node_modules/firebase/firebase-app.js')
| -rw-r--r-- | frontend-old/node_modules/firebase/firebase-app.js | 2799 |
1 files changed, 0 insertions, 2799 deletions
diff --git a/frontend-old/node_modules/firebase/firebase-app.js b/frontend-old/node_modules/firebase/firebase-app.js deleted file mode 100644 index 5693cc3..0000000 --- a/frontend-old/node_modules/firebase/firebase-app.js +++ /dev/null @@ -1,2799 +0,0 @@ -/** - * @license - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// This value is retrieved and hardcoded by the NPM postinstall script -const getDefaultsFromPostinstall = () => undefined; - -/** - * @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. - */ -const stringToByteArray$1 = function (str) { - // TODO(user): Use native implementations if/when available - const out = []; - let p = 0; - for (let i = 0; i < str.length; i++) { - let 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. - */ -const byteArrayToString = function (bytes) { - // TODO(user): Use native implementations if/when available - const out = []; - let pos = 0, c = 0; - while (pos < bytes.length) { - const c1 = bytes[pos++]; - if (c1 < 128) { - out[c++] = String.fromCharCode(c1); - } - else if (c1 > 191 && c1 < 224) { - const c2 = bytes[pos++]; - out[c++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); - } - else if (c1 > 239 && c1 < 365) { - // Surrogate Pair - const c2 = bytes[pos++]; - const c3 = bytes[pos++]; - const c4 = bytes[pos++]; - const 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 { - const c2 = bytes[pos++]; - const 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_() -// TODO(dlarocque): Define this as a class, since we no longer target ES5. -const 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(input, webSafe) { - if (!Array.isArray(input)) { - throw Error('encodeByteArray takes an array as a parameter'); - } - this.init_(); - const byteToCharMap = webSafe - ? this.byteToCharMapWebSafe_ - : this.byteToCharMap_; - const output = []; - for (let i = 0; i < input.length; i += 3) { - const byte1 = input[i]; - const haveByte2 = i + 1 < input.length; - const byte2 = haveByte2 ? input[i + 1] : 0; - const haveByte3 = i + 2 < input.length; - const byte3 = haveByte3 ? input[i + 2] : 0; - const outByte1 = byte1 >> 2; - const outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); - let outByte3 = ((byte2 & 0x0f) << 2) | (byte3 >> 6); - let 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(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(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(input, webSafe) { - this.init_(); - const charToByteMap = webSafe - ? this.charToByteMapWebSafe_ - : this.charToByteMap_; - const output = []; - for (let i = 0; i < input.length;) { - const byte1 = charToByteMap[input.charAt(i++)]; - const haveByte2 = i < input.length; - const byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0; - ++i; - const haveByte3 = i < input.length; - const byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64; - ++i; - const haveByte4 = i < input.length; - const byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64; - ++i; - if (byte1 == null || byte2 == null || byte3 == null || byte4 == null) { - throw new DecodeBase64StringError(); - } - const outByte1 = (byte1 << 2) | (byte2 >> 4); - output.push(outByte1); - if (byte3 !== 64) { - const outByte2 = ((byte2 << 4) & 0xf0) | (byte3 >> 2); - output.push(outByte2); - if (byte4 !== 64) { - const 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_() { - if (!this.byteToCharMap_) { - this.byteToCharMap_ = {}; - this.charToByteMap_ = {}; - this.byteToCharMapWebSafe_ = {}; - this.charToByteMapWebSafe_ = {}; - // We want quick mappings back and forth, so we precompute two maps. - for (let 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; - } - } - } - } -}; -/** - * An error encountered while decoding base64 string. - */ -class DecodeBase64StringError extends Error { - constructor() { - super(...arguments); - this.name = 'DecodeBase64StringError'; - } -} -/** - * URL-safe base64 encoding - */ -const base64Encode = function (str) { - const utf8Bytes = stringToByteArray$1(str); - return base64.encodeByteArray(utf8Bytes, true); -}; -/** - * URL-safe base64 encoding (without "." padding in the end). - * e.g. Used in JSON Web Token (JWT) parts. - */ -const base64urlEncodeWithoutPadding = function (str) { - // Use base64url encoding and remove padding in the end (dot characters). - return base64Encode(str).replace(/\./g, ''); -}; -/** - * 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 - */ -const base64Decode = function (str) { - try { - return base64.decodeString(str, true); - } - catch (e) { - console.error('base64Decode failed: ', e); - } - return null; -}; -/** - * @license - * Copyright 2022 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. - */ -/** - * Polyfill for `globalThis` object. - * @returns the `globalThis` object for the given environment. - * @public - */ -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 2022 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 getDefaultsFromGlobal = () => getGlobal().__FIREBASE_DEFAULTS__; -/** - * Attempt to read defaults from a JSON string provided to - * process(.)env(.)__FIREBASE_DEFAULTS__ or a JSON file whose path is in - * process(.)env(.)__FIREBASE_DEFAULTS_PATH__ - * The dots are in parens because certain compilers (Vite?) cannot - * handle seeing that variable in comments. - * See https://github.com/firebase/firebase-js-sdk/issues/6838 - */ -const getDefaultsFromEnvVariable = () => { - if (typeof process === 'undefined' || typeof process.env === 'undefined') { - return; - } - const defaultsJsonString = process.env.__FIREBASE_DEFAULTS__; - if (defaultsJsonString) { - return JSON.parse(defaultsJsonString); - } -}; -const getDefaultsFromCookie = () => { - if (typeof document === 'undefined') { - return; - } - let match; - try { - match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/); - } - catch (e) { - // Some environments such as Angular Universal SSR have a - // `document` object but error on accessing `document.cookie`. - return; - } - const decoded = match && base64Decode(match[1]); - return decoded && JSON.parse(decoded); -}; -/** - * Get the __FIREBASE_DEFAULTS__ object. It checks in order: - * (1) if such an object exists as a property of `globalThis` - * (2) if such an object was provided on a shell environment variable - * (3) if such an object exists in a cookie - * @public - */ -const getDefaults = () => { - try { - return (getDefaultsFromPostinstall() || - getDefaultsFromGlobal() || - getDefaultsFromEnvVariable() || - getDefaultsFromCookie()); - } - catch (e) { - /** - * Catch-all for being unable to get __FIREBASE_DEFAULTS__ due - * to any environment case we have not accounted for. Log to - * info instead of swallowing so we can find these unknown cases - * and add paths for them if needed. - */ - console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`); - return; - } -}; -/** - * Returns Firebase app config stored in the __FIREBASE_DEFAULTS__ object. - * @public - */ -const getDefaultAppConfig = () => getDefaults()?.config; -/** - * @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. - */ -class Deferred { - constructor() { - this.reject = () => { }; - this.resolve = () => { }; - this.promise = new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - }); - } - /** - * Our API internals are not promisified 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. - */ - wrapCallback(callback) { - return (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(() => { }); - // 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); - } - } - }; - } -} -/** - * Detect Browser Environment. - * Note: This will return true for certain test frameworks that are incompletely - * mimicking a browser, and should not lead to assuming all browser APIs are - * available. - */ -function isBrowser() { - return typeof window !== 'undefined' || isWebWorker(); -} -/** - * Detect Web Worker context. - */ -function isWebWorker() { - return (typeof WorkerGlobalScope !== 'undefined' && - typeof self !== 'undefined' && - self instanceof WorkerGlobalScope); -} -/** - * 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() { - try { - return typeof indexedDB === 'object'; - } - catch (e) { - return false; - } -} -/** - * This method validates browser/sw context for indexedDB by opening a dummy indexedDB database and reject - * if errors occur during the database open operation. - * - * @throws exception if current browser/sw context can't run idb.open (ex: Safari iframe, Firefox - * private browsing) - */ -function validateIndexedDBOpenable() { - return new Promise((resolve, reject) => { - try { - let preExist = true; - const DB_CHECK_NAME = 'validate-browser-context-for-indexeddb-analytics-module'; - const request = self.indexedDB.open(DB_CHECK_NAME); - request.onsuccess = () => { - request.result.close(); - // delete database only when it doesn't pre-exist - if (!preExist) { - self.indexedDB.deleteDatabase(DB_CHECK_NAME); - } - resolve(true); - }; - request.onupgradeneeded = () => { - preExist = false; - }; - request.onerror = () => { - reject(request.error?.message || ''); - }; - } - catch (error) { - reject(error); - } - }); -} -/** - * @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. - */ -/** - * @fileoverview Standardized Firebase Error. - * - * Usage: - * - * // TypeScript string literals for type-safe codes - * type Err = - * 'unknown' | - * 'object-not-found' - * ; - * - * // Closure enum for type-safe error codes - * // at-enum {string} - * var Err = { - * UNKNOWN: 'unknown', - * OBJECT_NOT_FOUND: 'object-not-found', - * } - * - * let errors: Map<Err, string> = { - * 'generic-error': "Unknown error", - * 'file-not-found': "Could not find file: {$file}", - * }; - * - * // Type-safe function - must pass a valid error code as param. - * let error = new ErrorFactory<Err>('service', 'Service', errors); - * - * ... - * throw error.create(Err.GENERIC); - * ... - * throw error.create(Err.FILE_NOT_FOUND, {'file': fileName}); - * ... - * // Service: Could not file file: foo.txt (service/file-not-found). - * - * catch (e) { - * assert(e.message === "Could not find file: foo.txt."); - * if ((e as FirebaseError)?.code === 'service/file-not-found') { - * console.log("Could not read file: " + e['file']); - * } - * } - */ -const ERROR_NAME = 'FirebaseError'; -// Based on code from: -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error#Custom_Error_Types -class FirebaseError extends Error { - constructor( - /** The error code for this error. */ - code, message, - /** Custom data for this error. */ - customData) { - super(message); - this.code = code; - this.customData = customData; - /** The custom name for all FirebaseErrors. */ - 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 - // TODO(dlarocque): Replace this with `new.target`: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget - // which we can now use since we no longer target ES5. - 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); - } - } -} -class ErrorFactory { - constructor(service, serviceName, errors) { - this.service = service; - this.serviceName = serviceName; - this.errors = errors; - } - create(code, ...data) { - const customData = data[0] || {}; - const fullCode = `${this.service}/${code}`; - const template = this.errors[code]; - const message = template ? replaceTemplate(template, customData) : 'Error'; - // Service Name: Error message (service/code). - const fullMessage = `${this.serviceName}: ${message} (${fullCode}).`; - const error = new FirebaseError(fullCode, fullMessage, customData); - return error; - } -} -function replaceTemplate(template, data) { - return template.replace(PATTERN, (_, key) => { - const value = data[key]; - return value != null ? String(value) : `<${key}?>`; - }); -} -const PATTERN = /\{\$([^}]+)}/g; -/** - * Deep equal two objects. Support Arrays and Objects. - */ -function deepEqual(a, b) { - if (a === b) { - return true; - } - const aKeys = Object.keys(a); - const bKeys = Object.keys(b); - for (const k of aKeys) { - if (!bKeys.includes(k)) { - return false; - } - const aProp = a[k]; - const bProp = b[k]; - if (isObject(aProp) && isObject(bProp)) { - if (!deepEqual(aProp, bProp)) { - return false; - } - } - else if (aProp !== bProp) { - return false; - } - } - for (const k of bKeys) { - if (!aKeys.includes(k)) { - return false; - } - } - return true; -} -function isObject(thing) { - return thing !== null && typeof thing === 'object'; -} - -/** - * Component for service name T, e.g. `auth`, `auth-internal` - */ -class Component { - /** - * - * @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 - */ - constructor(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" /* InstantiationMode.LAZY */; - this.onInstanceCreated = null; - } - setInstantiationMode(mode) { - this.instantiationMode = mode; - return this; - } - setMultipleInstances(multipleInstances) { - this.multipleInstances = multipleInstances; - return this; - } - setServiceProps(props) { - this.serviceProps = props; - return this; - } - setInstanceCreatedCallback(callback) { - this.onInstanceCreated = callback; - return this; - } -} -/** - * @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. - */ -const DEFAULT_ENTRY_NAME$1 = '[DEFAULT]'; -/** - * @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. - */ -/** - * Provider for instance for service name T, e.g. 'auth', 'auth-internal' - * NameServiceMapping[T] is an alias for the type of the instance - */ -class Provider { - constructor(name, container) { - this.name = name; - this.container = container; - this.component = null; - this.instances = new Map(); - this.instancesDeferred = new Map(); - this.instancesOptions = new Map(); - this.onInitCallbacks = new Map(); - } - /** - * @param identifier A provider can provide multiple instances of a service - * if this.component.multipleInstances is true. - */ - get(identifier) { - // if multipleInstances is not supported, use the default name - const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); - if (!this.instancesDeferred.has(normalizedIdentifier)) { - const deferred = new Deferred(); - this.instancesDeferred.set(normalizedIdentifier, deferred); - if (this.isInitialized(normalizedIdentifier) || - this.shouldAutoInitialize()) { - // initialize the service if it can be auto-initialized - try { - const instance = this.getOrInitializeService({ - instanceIdentifier: normalizedIdentifier - }); - if (instance) { - deferred.resolve(instance); - } - } - catch (e) { - // when the instance factory throws an exception during get(), it should not cause - // a fatal error. We just return the unresolved promise in this case. - } - } - } - return this.instancesDeferred.get(normalizedIdentifier).promise; - } - getImmediate(options) { - // if multipleInstances is not supported, use the default name - const normalizedIdentifier = this.normalizeInstanceIdentifier(options?.identifier); - const optional = options?.optional ?? false; - if (this.isInitialized(normalizedIdentifier) || - this.shouldAutoInitialize()) { - try { - return this.getOrInitializeService({ - instanceIdentifier: normalizedIdentifier - }); - } - catch (e) { - if (optional) { - return null; - } - else { - throw e; - } - } - } - else { - // In case a component is not initialized and should/cannot be auto-initialized at the moment, return null if the optional flag is set, or throw - if (optional) { - return null; - } - else { - throw Error(`Service ${this.name} is not available`); - } - } - } - getComponent() { - return this.component; - } - setComponent(component) { - if (component.name !== this.name) { - throw Error(`Mismatching Component ${component.name} for Provider ${this.name}.`); - } - if (this.component) { - throw Error(`Component for ${this.name} has already been provided`); - } - this.component = component; - // return early without attempting to initialize the component if the component requires explicit initialization (calling `Provider.initialize()`) - if (!this.shouldAutoInitialize()) { - return; - } - // if the service is eager, initialize the default instance - if (isComponentEager(component)) { - try { - this.getOrInitializeService({ instanceIdentifier: DEFAULT_ENTRY_NAME$1 }); - } - catch (e) { - // when the instance factory for an eager Component throws an exception during the eager - // initialization, it should not cause a fatal error. - // TODO: Investigate if we need to make it configurable, because some component may want to cause - // a fatal error in this case? - } - } - // Create service instances for the pending promises and resolve them - // NOTE: if this.multipleInstances is false, only the default instance will be created - // and all promises with resolve with it regardless of the identifier. - for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { - const normalizedIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); - try { - // `getOrInitializeService()` should always return a valid instance since a component is guaranteed. use ! to make typescript happy. - const instance = this.getOrInitializeService({ - instanceIdentifier: normalizedIdentifier - }); - instanceDeferred.resolve(instance); - } - catch (e) { - // when the instance factory throws an exception, it should not cause - // a fatal error. We just leave the promise unresolved. - } - } - } - clearInstance(identifier = DEFAULT_ENTRY_NAME$1) { - this.instancesDeferred.delete(identifier); - this.instancesOptions.delete(identifier); - this.instances.delete(identifier); - } - // app.delete() will call this method on every provider to delete the services - // TODO: should we mark the provider as deleted? - async delete() { - const services = Array.from(this.instances.values()); - await Promise.all([ - ...services - .filter(service => 'INTERNAL' in service) // legacy services - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .map(service => service.INTERNAL.delete()), - ...services - .filter(service => '_delete' in service) // modularized services - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .map(service => service._delete()) - ]); - } - isComponentSet() { - return this.component != null; - } - isInitialized(identifier = DEFAULT_ENTRY_NAME$1) { - return this.instances.has(identifier); - } - getOptions(identifier = DEFAULT_ENTRY_NAME$1) { - return this.instancesOptions.get(identifier) || {}; - } - initialize(opts = {}) { - const { options = {} } = opts; - const normalizedIdentifier = this.normalizeInstanceIdentifier(opts.instanceIdentifier); - if (this.isInitialized(normalizedIdentifier)) { - throw Error(`${this.name}(${normalizedIdentifier}) has already been initialized`); - } - if (!this.isComponentSet()) { - throw Error(`Component ${this.name} has not been registered yet`); - } - const instance = this.getOrInitializeService({ - instanceIdentifier: normalizedIdentifier, - options - }); - // resolve any pending promise waiting for the service instance - for (const [instanceIdentifier, instanceDeferred] of this.instancesDeferred.entries()) { - const normalizedDeferredIdentifier = this.normalizeInstanceIdentifier(instanceIdentifier); - if (normalizedIdentifier === normalizedDeferredIdentifier) { - instanceDeferred.resolve(instance); - } - } - return instance; - } - /** - * - * @param callback - a function that will be invoked after the provider has been initialized by calling provider.initialize(). - * The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program. - * - * @param identifier An optional instance identifier - * @returns a function to unregister the callback - */ - onInit(callback, identifier) { - const normalizedIdentifier = this.normalizeInstanceIdentifier(identifier); - const existingCallbacks = this.onInitCallbacks.get(normalizedIdentifier) ?? - new Set(); - existingCallbacks.add(callback); - this.onInitCallbacks.set(normalizedIdentifier, existingCallbacks); - const existingInstance = this.instances.get(normalizedIdentifier); - if (existingInstance) { - callback(existingInstance, normalizedIdentifier); - } - return () => { - existingCallbacks.delete(callback); - }; - } - /** - * Invoke onInit callbacks synchronously - * @param instance the service instance` - */ - invokeOnInitCallbacks(instance, identifier) { - const callbacks = this.onInitCallbacks.get(identifier); - if (!callbacks) { - return; - } - for (const callback of callbacks) { - try { - callback(instance, identifier); - } - catch { - // ignore errors in the onInit callback - } - } - } - getOrInitializeService({ instanceIdentifier, options = {} }) { - let instance = this.instances.get(instanceIdentifier); - if (!instance && this.component) { - instance = this.component.instanceFactory(this.container, { - instanceIdentifier: normalizeIdentifierForFactory(instanceIdentifier), - options - }); - this.instances.set(instanceIdentifier, instance); - this.instancesOptions.set(instanceIdentifier, options); - /** - * Invoke onInit listeners. - * Note this.component.onInstanceCreated is different, which is used by the component creator, - * while onInit listeners are registered by consumers of the provider. - */ - this.invokeOnInitCallbacks(instance, instanceIdentifier); - /** - * Order is important - * onInstanceCreated() should be called after this.instances.set(instanceIdentifier, instance); which - * makes `isInitialized()` return true. - */ - if (this.component.onInstanceCreated) { - try { - this.component.onInstanceCreated(this.container, instanceIdentifier, instance); - } - catch { - // ignore errors in the onInstanceCreatedCallback - } - } - } - return instance || null; - } - normalizeInstanceIdentifier(identifier = DEFAULT_ENTRY_NAME$1) { - if (this.component) { - return this.component.multipleInstances ? identifier : DEFAULT_ENTRY_NAME$1; - } - else { - return identifier; // assume multiple instances are supported before the component is provided. - } - } - shouldAutoInitialize() { - return (!!this.component && - this.component.instantiationMode !== "EXPLICIT" /* InstantiationMode.EXPLICIT */); - } -} -// undefined should be passed to the service factory for the default instance -function normalizeIdentifierForFactory(identifier) { - return identifier === DEFAULT_ENTRY_NAME$1 ? undefined : identifier; -} -function isComponentEager(component) { - return component.instantiationMode === "EAGER" /* InstantiationMode.EAGER */; -} -/** - * @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. - */ -/** - * ComponentContainer that provides Providers for service name T, e.g. `auth`, `auth-internal` - */ -class ComponentContainer { - constructor(name) { - this.name = name; - this.providers = new Map(); - } - /** - * - * @param component Component being added - * @param overwrite When a component with the same name has already been registered, - * if overwrite is true: overwrite the existing component with the new component and create a new - * provider with the new component. It can be useful in tests where you want to use different mocks - * for different tests. - * if overwrite is false: throw an exception - */ - addComponent(component) { - const provider = this.getProvider(component.name); - if (provider.isComponentSet()) { - throw new Error(`Component ${component.name} has already been registered with ${this.name}`); - } - provider.setComponent(component); - } - addOrOverwriteComponent(component) { - const provider = this.getProvider(component.name); - if (provider.isComponentSet()) { - // delete the existing provider from the container, so we can register the new component - this.providers.delete(component.name); - } - this.addComponent(component); - } - /** - * getProvider provides a type safe interface where it can only be called with a field name - * present in NameServiceMapping interface. - * - * Firebase SDKs providing services should extend NameServiceMapping interface to register - * themselves. - */ - getProvider(name) { - if (this.providers.has(name)) { - return this.providers.get(name); - } - // create a Provider for a service that hasn't registered with Firebase - const provider = new Provider(name, this); - this.providers.set(name, provider); - return provider; - } - getProviders() { - return Array.from(this.providers.values()); - } -} - -/** - * @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. - */ -/** - * A container for all of the Logger instances - */ -const instances = []; -/** - * 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 = {})); -const levelStringToEnum = { - 'debug': LogLevel.DEBUG, - 'verbose': LogLevel.VERBOSE, - 'info': LogLevel.INFO, - 'warn': LogLevel.WARN, - 'error': LogLevel.ERROR, - 'silent': LogLevel.SILENT -}; -/** - * The default log level - */ -const 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. - */ -const ConsoleMethod = { - [LogLevel.DEBUG]: 'log', - [LogLevel.VERBOSE]: 'log', - [LogLevel.INFO]: 'info', - [LogLevel.WARN]: 'warn', - [LogLevel.ERROR]: 'error' -}; -/** - * 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) - */ -const defaultLogHandler = (instance, logType, ...args) => { - if (logType < instance.logLevel) { - return; - } - const now = new Date().toISOString(); - const method = ConsoleMethod[logType]; - if (method) { - console[method](`[${now}] ${instance.name}:`, ...args); - } - else { - throw new Error(`Attempted to log a message with an invalid logType (value: ${logType})`); - } -}; -class Logger { - /** - * 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 - */ - constructor(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; - /** - * Capture the current instance for later use - */ - instances.push(this); - } - get logLevel() { - return this._logLevel; - } - set logLevel(val) { - if (!(val in LogLevel)) { - throw new TypeError(`Invalid value "${val}" assigned to \`logLevel\``); - } - this._logLevel = val; - } - // Workaround for setter/getter having to be the same type. - setLogLevel(val) { - this._logLevel = typeof val === 'string' ? levelStringToEnum[val] : val; - } - get logHandler() { - return this._logHandler; - } - set logHandler(val) { - if (typeof val !== 'function') { - throw new TypeError('Value assigned to `logHandler` must be a function'); - } - this._logHandler = val; - } - get userLogHandler() { - return this._userLogHandler; - } - set userLogHandler(val) { - this._userLogHandler = val; - } - /** - * The functions below are all based on the `console` interface - */ - debug(...args) { - this._userLogHandler && this._userLogHandler(this, LogLevel.DEBUG, ...args); - this._logHandler(this, LogLevel.DEBUG, ...args); - } - log(...args) { - this._userLogHandler && - this._userLogHandler(this, LogLevel.VERBOSE, ...args); - this._logHandler(this, LogLevel.VERBOSE, ...args); - } - info(...args) { - this._userLogHandler && this._userLogHandler(this, LogLevel.INFO, ...args); - this._logHandler(this, LogLevel.INFO, ...args); - } - warn(...args) { - this._userLogHandler && this._userLogHandler(this, LogLevel.WARN, ...args); - this._logHandler(this, LogLevel.WARN, ...args); - } - error(...args) { - this._userLogHandler && this._userLogHandler(this, LogLevel.ERROR, ...args); - this._logHandler(this, LogLevel.ERROR, ...args); - } -} -function setLogLevel$1(level) { - instances.forEach(inst => { - inst.setLogLevel(level); - }); -} -function setUserLogHandler(logCallback, options) { - for (const instance of instances) { - let customLogLevel = null; - if (options && options.level) { - customLogLevel = levelStringToEnum[options.level]; - } - if (logCallback === null) { - instance.userLogHandler = null; - } - else { - instance.userLogHandler = (instance, level, ...args) => { - const message = args - .map(arg => { - if (arg == null) { - return null; - } - else if (typeof arg === 'string') { - return arg; - } - else if (typeof arg === 'number' || typeof arg === 'boolean') { - return arg.toString(); - } - else if (arg instanceof Error) { - return arg.message; - } - else { - try { - return JSON.stringify(arg); - } - catch (ignored) { - return null; - } - } - }) - .filter(arg => arg) - .join(' '); - if (level >= (customLogLevel ?? instance.logLevel)) { - logCallback({ - level: LogLevel[level].toLowerCase(), - message, - args, - type: instance.name - }); - } - }; - } - } -} - -const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c); -let idbProxyableTypes; -let cursorAdvanceMethods; -// This is a function to prevent it throwing up in node environments. -function getIdbProxyableTypes() { - return (idbProxyableTypes || - (idbProxyableTypes = [ - IDBDatabase, - IDBObjectStore, - IDBIndex, - IDBCursor, - IDBTransaction, - ])); -} -// This is a function to prevent it throwing up in node environments. -function getCursorAdvanceMethods() { - return (cursorAdvanceMethods || - (cursorAdvanceMethods = [ - IDBCursor.prototype.advance, - IDBCursor.prototype.continue, - IDBCursor.prototype.continuePrimaryKey, - ])); -} -const cursorRequestMap = new WeakMap(); -const transactionDoneMap = new WeakMap(); -const transactionStoreNamesMap = new WeakMap(); -const transformCache = new WeakMap(); -const reverseTransformCache = new WeakMap(); -function promisifyRequest(request) { - const promise = new Promise((resolve, reject) => { - const unlisten = () => { - request.removeEventListener('success', success); - request.removeEventListener('error', error); - }; - const success = () => { - resolve(wrap(request.result)); - unlisten(); - }; - const error = () => { - reject(request.error); - unlisten(); - }; - request.addEventListener('success', success); - request.addEventListener('error', error); - }); - promise - .then((value) => { - // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval - // (see wrapFunction). - if (value instanceof IDBCursor) { - cursorRequestMap.set(value, request); - } - // Catching to avoid "Uncaught Promise exceptions" - }) - .catch(() => { }); - // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This - // is because we create many promises from a single IDBRequest. - reverseTransformCache.set(promise, request); - return promise; -} -function cacheDonePromiseForTransaction(tx) { - // Early bail if we've already created a done promise for this transaction. - if (transactionDoneMap.has(tx)) - return; - const done = new Promise((resolve, reject) => { - const unlisten = () => { - tx.removeEventListener('complete', complete); - tx.removeEventListener('error', error); - tx.removeEventListener('abort', error); - }; - const complete = () => { - resolve(); - unlisten(); - }; - const error = () => { - reject(tx.error || new DOMException('AbortError', 'AbortError')); - unlisten(); - }; - tx.addEventListener('complete', complete); - tx.addEventListener('error', error); - tx.addEventListener('abort', error); - }); - // Cache it for later retrieval. - transactionDoneMap.set(tx, done); -} -let idbProxyTraps = { - get(target, prop, receiver) { - if (target instanceof IDBTransaction) { - // Special handling for transaction.done. - if (prop === 'done') - return transactionDoneMap.get(target); - // Polyfill for objectStoreNames because of Edge. - if (prop === 'objectStoreNames') { - return target.objectStoreNames || transactionStoreNamesMap.get(target); - } - // Make tx.store return the only store in the transaction, or undefined if there are many. - if (prop === 'store') { - return receiver.objectStoreNames[1] - ? undefined - : receiver.objectStore(receiver.objectStoreNames[0]); - } - } - // Else transform whatever we get back. - return wrap(target[prop]); - }, - set(target, prop, value) { - target[prop] = value; - return true; - }, - has(target, prop) { - if (target instanceof IDBTransaction && - (prop === 'done' || prop === 'store')) { - return true; - } - return prop in target; - }, -}; -function replaceTraps(callback) { - idbProxyTraps = callback(idbProxyTraps); -} -function wrapFunction(func) { - // Due to expected object equality (which is enforced by the caching in `wrap`), we - // only create one new func per func. - // Edge doesn't support objectStoreNames (booo), so we polyfill it here. - if (func === IDBDatabase.prototype.transaction && - !('objectStoreNames' in IDBTransaction.prototype)) { - return function (storeNames, ...args) { - const tx = func.call(unwrap(this), storeNames, ...args); - transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]); - return wrap(tx); - }; - } - // Cursor methods are special, as the behaviour is a little more different to standard IDB. In - // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the - // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense - // with real promises, so each advance methods returns a new promise for the cursor object, or - // undefined if the end of the cursor has been reached. - if (getCursorAdvanceMethods().includes(func)) { - return function (...args) { - // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use - // the original object. - func.apply(unwrap(this), args); - return wrap(cursorRequestMap.get(this)); - }; - } - return function (...args) { - // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use - // the original object. - return wrap(func.apply(unwrap(this), args)); - }; -} -function transformCachableValue(value) { - if (typeof value === 'function') - return wrapFunction(value); - // This doesn't return, it just creates a 'done' promise for the transaction, - // which is later returned for transaction.done (see idbObjectHandler). - if (value instanceof IDBTransaction) - cacheDonePromiseForTransaction(value); - if (instanceOfAny(value, getIdbProxyableTypes())) - return new Proxy(value, idbProxyTraps); - // Return the same value back if we're not going to transform it. - return value; -} -function wrap(value) { - // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because - // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached. - if (value instanceof IDBRequest) - return promisifyRequest(value); - // If we've already transformed this value before, reuse the transformed value. - // This is faster, but it also provides object equality. - if (transformCache.has(value)) - return transformCache.get(value); - const newValue = transformCachableValue(value); - // Not all types are transformed. - // These may be primitive types, so they can't be WeakMap keys. - if (newValue !== value) { - transformCache.set(value, newValue); - reverseTransformCache.set(newValue, value); - } - return newValue; -} -const unwrap = (value) => reverseTransformCache.get(value); - -/** - * Open a database. - * - * @param name Name of the database. - * @param version Schema version. - * @param callbacks Additional callbacks. - */ -function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) { - const request = indexedDB.open(name, version); - const openPromise = wrap(request); - if (upgrade) { - request.addEventListener('upgradeneeded', (event) => { - upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event); - }); - } - if (blocked) { - request.addEventListener('blocked', (event) => blocked( - // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405 - event.oldVersion, event.newVersion, event)); - } - openPromise - .then((db) => { - if (terminated) - db.addEventListener('close', () => terminated()); - if (blocking) { - db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event)); - } - }) - .catch(() => { }); - return openPromise; -} -const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count']; -const writeMethods = ['put', 'add', 'delete', 'clear']; -const cachedMethods = new Map(); -function getMethod(target, prop) { - if (!(target instanceof IDBDatabase && - !(prop in target) && - typeof prop === 'string')) { - return; - } - if (cachedMethods.get(prop)) - return cachedMethods.get(prop); - const targetFuncName = prop.replace(/FromIndex$/, ''); - const useIndex = prop !== targetFuncName; - const isWrite = writeMethods.includes(targetFuncName); - if ( - // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge. - !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) || - !(isWrite || readMethods.includes(targetFuncName))) { - return; - } - const method = async function (storeName, ...args) { - // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :( - const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly'); - let target = tx.store; - if (useIndex) - target = target.index(args.shift()); - // Must reject if op rejects. - // If it's a write operation, must reject if tx.done rejects. - // Must reject with op rejection first. - // Must resolve with op value. - // Must handle both promises (no unhandled rejections) - return (await Promise.all([ - target[targetFuncName](...args), - isWrite && tx.done, - ]))[0]; - }; - cachedMethods.set(prop, method); - return method; -} -replaceTraps((oldTraps) => ({ - ...oldTraps, - get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver), - has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop), -})); - -/** - * @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. - */ -class PlatformLoggerServiceImpl { - constructor(container) { - this.container = container; - } - // In initial implementation, this will be called by installations on - // auth token refresh, and installations will send this string. - getPlatformInfoString() { - const providers = this.container.getProviders(); - // Loop through providers and get library/version pairs from any that are - // version components. - return providers - .map(provider => { - if (isVersionServiceProvider(provider)) { - const service = provider.getImmediate(); - return `${service.library}/${service.version}`; - } - else { - return null; - } - }) - .filter(logString => logString) - .join(' '); - } -} -/** - * - * @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) { - const component = provider.getComponent(); - return component?.type === "VERSION" /* ComponentType.VERSION */; -} -const name$q = "https://www.gstatic.com/firebasejs/12.5.0/firebase-app.js"; -const version$1 = "0.14.5"; -/** - * @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. - */ -const logger = new Logger('https://www.gstatic.com/firebasejs/12.5.0/firebase-app.js'); -const name$p = "@firebase/app-compat"; -const name$o = "@firebase/analytics-compat"; -const name$n = "@firebase/analytics"; -const name$m = "@firebase/app-check-compat"; -const name$l = "@firebase/app-check"; -const name$k = "@firebase/auth"; -const name$j = "@firebase/auth-compat"; -const name$i = "@firebase/database"; -const name$h = "@firebase/data-connect"; -const name$g = "@firebase/database-compat"; -const name$f = "@firebase/functions"; -const name$e = "@firebase/functions-compat"; -const name$d = "@firebase/installations"; -const name$c = "@firebase/installations-compat"; -const name$b = "@firebase/messaging"; -const name$a = "@firebase/messaging-compat"; -const name$9 = "@firebase/performance"; -const name$8 = "@firebase/performance-compat"; -const name$7 = "@firebase/remote-config"; -const name$6 = "@firebase/remote-config-compat"; -const name$5 = "@firebase/storage"; -const name$4 = "@firebase/storage-compat"; -const name$3 = "@firebase/firestore"; -const name$2 = "@firebase/ai"; -const name$1 = "@firebase/firestore-compat"; -const name$r = "firebase"; -const version$2 = "12.5.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. - */ -/** - * The default app name - * - * @internal - */ -const DEFAULT_ENTRY_NAME = '[DEFAULT]'; -const PLATFORM_LOG_STRING = { - [name$q]: 'fire-core', - [name$p]: 'fire-core-compat', - [name$n]: 'fire-analytics', - [name$o]: 'fire-analytics-compat', - [name$l]: 'fire-app-check', - [name$m]: 'fire-app-check-compat', - [name$k]: 'fire-auth', - [name$j]: 'fire-auth-compat', - [name$i]: 'fire-rtdb', - [name$h]: 'fire-data-connect', - [name$g]: 'fire-rtdb-compat', - [name$f]: 'fire-fn', - [name$e]: 'fire-fn-compat', - [name$d]: 'fire-iid', - [name$c]: 'fire-iid-compat', - [name$b]: 'fire-fcm', - [name$a]: 'fire-fcm-compat', - [name$9]: 'fire-perf', - [name$8]: 'fire-perf-compat', - [name$7]: 'fire-rc', - [name$6]: 'fire-rc-compat', - [name$5]: 'fire-gcs', - [name$4]: 'fire-gcs-compat', - [name$3]: 'fire-fst', - [name$1]: 'fire-fst-compat', - [name$2]: 'fire-vertex', - 'fire-js': 'fire-js', // Platform identifier for JS SDK. - [name$r]: 'fire-js-all' -}; -/** - * @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 - */ -const _apps = new Map(); -/** - * @internal - */ -const _serverApps = new Map(); -/** - * Registered components. - * - * @internal - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const _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 ${component.name} failed to register with FirebaseApp ${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) { - const componentName = component.name; - if (_components.has(componentName)) { - logger.debug(`There were multiple attempts to register component ${componentName}.`); - return false; - } - _components.set(componentName, component); - // add the component to existing app instances - for (const app of _apps.values()) { - _addComponent(app, component); - } - for (const serverApp of _serverApps.values()) { - _addComponent(serverApp, component); - } - 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) { - const 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 = DEFAULT_ENTRY_NAME) { - _getProvider(app, name).clearInstance(instanceIdentifier); -} -/** - * - * @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings. - * - * @returns true if the provide object is of type FirebaseApp. - * - * @internal - */ -function _isFirebaseApp(obj) { - return obj.options !== undefined; -} -/** - * - * @param obj - an object of type FirebaseApp, FirebaseOptions or FirebaseAppSettings. - * - * @returns true if the provided object is of type FirebaseServerAppImpl. - * - * @internal - */ -function _isFirebaseServerAppSettings(obj) { - if (_isFirebaseApp(obj)) { - return false; - } - return ('authIdToken' in obj || - 'appCheckToken' in obj || - 'releaseOnDeref' in obj || - 'automaticDataCollectionEnabled' in obj); -} -/** - * - * @param obj - an object of type FirebaseApp. - * - * @returns true if the provided object is of type FirebaseServerAppImpl. - * - * @internal - */ -function _isFirebaseServerApp(obj) { - if (obj === null || obj === undefined) { - return false; - } - return obj.settings !== undefined; -} -/** - * 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. - */ -const ERRORS = { - ["no-app" /* AppError.NO_APP */]: "No Firebase App '{$appName}' has been created - " + - 'call initializeApp() first', - ["bad-app-name" /* AppError.BAD_APP_NAME */]: "Illegal App name: '{$appName}'", - ["duplicate-app" /* AppError.DUPLICATE_APP */]: "Firebase App named '{$appName}' already exists with different options or config", - ["app-deleted" /* AppError.APP_DELETED */]: "Firebase App named '{$appName}' already deleted", - ["server-app-deleted" /* AppError.SERVER_APP_DELETED */]: 'Firebase Server App has been deleted', - ["no-options" /* AppError.NO_OPTIONS */]: 'Need to provide options, when not being deployed to hosting via source.', - ["invalid-app-argument" /* AppError.INVALID_APP_ARGUMENT */]: 'firebase.{$appName}() takes either no argument or a ' + - 'Firebase App instance.', - ["invalid-log-argument" /* AppError.INVALID_LOG_ARGUMENT */]: 'First argument to `onLog` must be null or a function.', - ["idb-open" /* AppError.IDB_OPEN */]: 'Error thrown when opening IndexedDB. Original error: {$originalErrorMessage}.', - ["idb-get" /* AppError.IDB_GET */]: 'Error thrown when reading from IndexedDB. Original error: {$originalErrorMessage}.', - ["idb-set" /* AppError.IDB_WRITE */]: 'Error thrown when writing to IndexedDB. Original error: {$originalErrorMessage}.', - ["idb-delete" /* AppError.IDB_DELETE */]: 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.', - ["finalization-registry-not-supported" /* AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED */]: 'FirebaseServerApp deleteOnDeref field defined but the JS runtime does not support FinalizationRegistry.', - ["invalid-server-app-environment" /* AppError.INVALID_SERVER_APP_ENVIRONMENT */]: 'FirebaseServerApp is not for use in browser environments.' -}; -const 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. - */ -class FirebaseAppImpl { - constructor(options, config, container) { - this._isDeleted = false; - this._options = { ...options }; - this._config = { ...config }; - this._name = config.name; - this._automaticDataCollectionEnabled = - config.automaticDataCollectionEnabled; - this._container = container; - this.container.addComponent(new Component('app', () => this, "PUBLIC" /* ComponentType.PUBLIC */)); - } - get automaticDataCollectionEnabled() { - this.checkDestroyed(); - return this._automaticDataCollectionEnabled; - } - set automaticDataCollectionEnabled(val) { - this.checkDestroyed(); - this._automaticDataCollectionEnabled = val; - } - get name() { - this.checkDestroyed(); - return this._name; - } - get options() { - this.checkDestroyed(); - return this._options; - } - get config() { - this.checkDestroyed(); - return this._config; - } - get container() { - return this._container; - } - get isDeleted() { - return this._isDeleted; - } - set isDeleted(val) { - this._isDeleted = val; - } - /** - * This function will throw an Error if the App has already been deleted - - * use before performing API actions on the App. - */ - checkDestroyed() { - if (this.isDeleted) { - throw ERROR_FACTORY.create("app-deleted" /* AppError.APP_DELETED */, { appName: this._name }); - } - } -} -/** - * @license - * Copyright 2023 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. - */ -// Parse the token and check to see if the `exp` claim is in the future. -// Reports an error to the console if the token or claim could not be parsed, or if `exp` is in -// the past. -function validateTokenTTL(base64Token, tokenName) { - const secondPart = base64Decode(base64Token.split('.')[1]); - if (secondPart === null) { - console.error(`FirebaseServerApp ${tokenName} is invalid: second part could not be parsed.`); - return; - } - const expClaim = JSON.parse(secondPart).exp; - if (expClaim === undefined) { - console.error(`FirebaseServerApp ${tokenName} is invalid: expiration claim could not be parsed`); - return; - } - const exp = JSON.parse(secondPart).exp * 1000; - const now = new Date().getTime(); - const diff = exp - now; - if (diff <= 0) { - console.error(`FirebaseServerApp ${tokenName} is invalid: the token has expired.`); - } -} -class FirebaseServerAppImpl extends FirebaseAppImpl { - constructor(options, serverConfig, name, container) { - // Build configuration parameters for the FirebaseAppImpl base class. - const automaticDataCollectionEnabled = serverConfig.automaticDataCollectionEnabled !== undefined - ? serverConfig.automaticDataCollectionEnabled - : true; - // Create the FirebaseAppSettings object for the FirebaseAppImp constructor. - const config = { - name, - automaticDataCollectionEnabled - }; - if (options.apiKey !== undefined) { - // Construct the parent FirebaseAppImp object. - super(options, config, container); - } - else { - const appImpl = options; - super(appImpl.options, config, container); - } - // Now construct the data for the FirebaseServerAppImpl. - this._serverConfig = { - automaticDataCollectionEnabled, - ...serverConfig - }; - // Ensure that the current time is within the `authIdtoken` window of validity. - if (this._serverConfig.authIdToken) { - validateTokenTTL(this._serverConfig.authIdToken, 'authIdToken'); - } - // Ensure that the current time is within the `appCheckToken` window of validity. - if (this._serverConfig.appCheckToken) { - validateTokenTTL(this._serverConfig.appCheckToken, 'appCheckToken'); - } - this._finalizationRegistry = null; - if (typeof FinalizationRegistry !== 'undefined') { - this._finalizationRegistry = new FinalizationRegistry(() => { - this.automaticCleanup(); - }); - } - this._refCount = 0; - this.incRefCount(this._serverConfig.releaseOnDeref); - // Do not retain a hard reference to the dref object, otherwise the FinalizationRegistry - // will never trigger. - this._serverConfig.releaseOnDeref = undefined; - serverConfig.releaseOnDeref = undefined; - registerVersion(name$q, version$1, 'serverapp'); - } - toJSON() { - return undefined; - } - get refCount() { - return this._refCount; - } - // Increment the reference count of this server app. If an object is provided, register it - // with the finalization registry. - incRefCount(obj) { - if (this.isDeleted) { - return; - } - this._refCount++; - if (obj !== undefined && this._finalizationRegistry !== null) { - this._finalizationRegistry.register(obj, this); - } - } - // Decrement the reference count. - decRefCount() { - if (this.isDeleted) { - return 0; - } - return --this._refCount; - } - // Invoked by the FinalizationRegistry callback to note that this app should go through its - // reference counts and delete itself if no reference count remain. The coordinating logic that - // handles this is in deleteApp(...). - automaticCleanup() { - void deleteApp(this); - } - get settings() { - this.checkDestroyed(); - return this._serverConfig; - } - /** - * This function will throw an Error if the App has already been deleted - - * use before performing API actions on the App. - */ - checkDestroyed() { - if (this.isDeleted) { - throw ERROR_FACTORY.create("server-app-deleted" /* AppError.SERVER_APP_DELETED */); - } - } -} -/** - * @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 - */ -const SDK_VERSION = version$2; -function initializeApp(_options, rawConfig = {}) { - let options = _options; - if (typeof rawConfig !== 'object') { - const name = rawConfig; - rawConfig = { name }; - } - const config = { - name: DEFAULT_ENTRY_NAME, - automaticDataCollectionEnabled: true, - ...rawConfig - }; - const 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 */); - } - const 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 }); - } - } - const container = new ComponentContainer(name); - for (const component of _components.values()) { - container.addComponent(component); - } - const newApp = new FirebaseAppImpl(options, config, container); - _apps.set(name, newApp); - return newApp; -} -function initializeServerApp(_options, _serverAppConfig = {}) { - if (isBrowser() && !isWebWorker()) { - // FirebaseServerApp isn't designed to be run in browsers. - throw ERROR_FACTORY.create("invalid-server-app-environment" /* AppError.INVALID_SERVER_APP_ENVIRONMENT */); - } - let firebaseOptions; - let serverAppSettings = _serverAppConfig || {}; - if (_options) { - if (_isFirebaseApp(_options)) { - firebaseOptions = _options.options; - } - else if (_isFirebaseServerAppSettings(_options)) { - serverAppSettings = _options; - } - else { - firebaseOptions = _options; - } - } - if (serverAppSettings.automaticDataCollectionEnabled === undefined) { - serverAppSettings.automaticDataCollectionEnabled = true; - } - firebaseOptions || (firebaseOptions = getDefaultAppConfig()); - if (!firebaseOptions) { - throw ERROR_FACTORY.create("no-options" /* AppError.NO_OPTIONS */); - } - // Build an app name based on a hash of the configuration options. - const nameObj = { - ...serverAppSettings, - ...firebaseOptions - }; - // However, Do not mangle the name based on releaseOnDeref, since it will vary between the - // construction of FirebaseServerApp instances. For example, if the object is the request headers. - if (nameObj.releaseOnDeref !== undefined) { - delete nameObj.releaseOnDeref; - } - const hashCode = (s) => { - return [...s].reduce((hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0, 0); - }; - if (serverAppSettings.releaseOnDeref !== undefined) { - if (typeof FinalizationRegistry === 'undefined') { - throw ERROR_FACTORY.create("finalization-registry-not-supported" /* AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED */, {}); - } - } - const nameString = '' + hashCode(JSON.stringify(nameObj)); - const existingApp = _serverApps.get(nameString); - if (existingApp) { - existingApp.incRefCount(serverAppSettings.releaseOnDeref); - return existingApp; - } - const container = new ComponentContainer(nameString); - for (const component of _components.values()) { - container.addComponent(component); - } - const newApp = new FirebaseServerAppImpl(firebaseOptions, serverAppSettings, nameString, container); - _serverApps.set(nameString, 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 = DEFAULT_ENTRY_NAME) { - const 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 - */ -async function deleteApp(app) { - let cleanupProviders = false; - const name = app.name; - if (_apps.has(name)) { - cleanupProviders = true; - _apps.delete(name); - } - else if (_serverApps.has(name)) { - const firebaseServerApp = app; - if (firebaseServerApp.decRefCount() <= 0) { - _serverApps.delete(name); - cleanupProviders = true; - } - } - if (cleanupProviders) { - await Promise.all(app.container - .getProviders() - .map(provider => provider.delete())); - app.isDeleted = true; - } -} -/** - * 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) { - // TODO: We can use this check to whitelist strings when/if we set up - // a good whitelist system. - let library = PLATFORM_LOG_STRING[libraryKeyOrName] ?? libraryKeyOrName; - if (variant) { - library += `-${variant}`; - } - const libraryMismatch = library.match(/\s|\//); - const versionMismatch = version.match(/\s|\//); - if (libraryMismatch || versionMismatch) { - const warning = [ - `Unable to register library "${library}" with version "${version}":` - ]; - if (libraryMismatch) { - warning.push(`library name "${library}" contains illegal characters (whitespace or "/")`); - } - if (libraryMismatch && versionMismatch) { - warning.push('and'); - } - if (versionMismatch) { - warning.push(`version name "${version}" contains illegal characters (whitespace or "/")`); - } - logger.warn(warning.join(' ')); - return; - } - _registerComponent(new Component(`${library}-version`, () => ({ library, 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. - */ -const DB_NAME = 'firebase-heartbeat-database'; -const DB_VERSION = 1; -const STORE_NAME = 'firebase-heartbeat-store'; -let dbPromise = null; -function getDbPromise() { - if (!dbPromise) { - dbPromise = openDB(DB_NAME, DB_VERSION, { - upgrade: (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(e => { - throw ERROR_FACTORY.create("idb-open" /* AppError.IDB_OPEN */, { - originalErrorMessage: e.message - }); - }); - } - return dbPromise; -} -async function readHeartbeatsFromIndexedDB(app) { - try { - const db = await getDbPromise(); - const tx = db.transaction(STORE_NAME); - const result = await tx.objectStore(STORE_NAME).get(computeKey(app)); - // We already have the value but tx.done can throw, - // so we need to await it here to catch errors - await tx.done; - return result; - } - catch (e) { - if (e instanceof FirebaseError) { - logger.warn(e.message); - } - else { - const idbGetError = ERROR_FACTORY.create("idb-get" /* AppError.IDB_GET */, { - originalErrorMessage: e?.message - }); - logger.warn(idbGetError.message); - } - } -} -async function writeHeartbeatsToIndexedDB(app, heartbeatObject) { - try { - const db = await getDbPromise(); - const tx = db.transaction(STORE_NAME, 'readwrite'); - const objectStore = tx.objectStore(STORE_NAME); - await objectStore.put(heartbeatObject, computeKey(app)); - await tx.done; - } - catch (e) { - if (e instanceof FirebaseError) { - logger.warn(e.message); - } - else { - const idbGetError = ERROR_FACTORY.create("idb-set" /* AppError.IDB_WRITE */, { - originalErrorMessage: e?.message - }); - logger.warn(idbGetError.message); - } - } -} -function computeKey(app) { - return `${app.name}!${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. - */ -const MAX_HEADER_BYTES = 1024; -const MAX_NUM_STORED_HEARTBEATS = 30; -class HeartbeatServiceImpl { - constructor(container) { - 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; - const app = this.container.getProvider('app').getImmediate(); - this._storage = new HeartbeatStorageImpl(app); - this._heartbeatsCachePromise = this._storage.read().then(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. - */ - async triggerHeartbeat() { - try { - const platformLogger = this.container - .getProvider('platform-logger') - .getImmediate(); - // This is the "Firebase user agent" string from the platform logger - // service, not the browser user agent. - const agent = platformLogger.getPlatformInfoString(); - const date = getUTCDateString(); - if (this._heartbeatsCache?.heartbeats == null) { - this._heartbeatsCache = await this._heartbeatsCachePromise; - // If we failed to construct a heartbeats cache, then return immediately. - if (this._heartbeatsCache?.heartbeats == null) { - return; - } - } - // 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(singleDateHeartbeat => singleDateHeartbeat.date === date)) { - return; - } - else { - // There is no entry for this date. Create one. - this._heartbeatsCache.heartbeats.push({ date, agent }); - // If the number of stored heartbeats exceeds the maximum number of stored heartbeats, remove the heartbeat with the earliest date. - // Since this is executed each time a heartbeat is pushed, the limit can only be exceeded by one, so only one needs to be removed. - if (this._heartbeatsCache.heartbeats.length > MAX_NUM_STORED_HEARTBEATS) { - const earliestHeartbeatIdx = getEarliestHeartbeatIdx(this._heartbeatsCache.heartbeats); - this._heartbeatsCache.heartbeats.splice(earliestHeartbeatIdx, 1); - } - } - return this._storage.overwrite(this._heartbeatsCache); - } - catch (e) { - logger.warn(e); - } - } - /** - * 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. - */ - async getHeartbeatsHeader() { - try { - if (this._heartbeatsCache === null) { - await this._heartbeatsCachePromise; - } - // If it's still null or the array is empty, there is no data to send. - if (this._heartbeatsCache?.heartbeats == null || - this._heartbeatsCache.heartbeats.length === 0) { - return ''; - } - const date = getUTCDateString(); - // Extract as many heartbeats from the cache as will fit under the size limit. - const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats); - const 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) { - // 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. - await this._storage.overwrite(this._heartbeatsCache); - } - else { - this._heartbeatsCache.heartbeats = []; - // Do not wait for this, to reduce latency. - void this._storage.overwrite(this._heartbeatsCache); - } - return headerString; - } - catch (e) { - logger.warn(e); - return ''; - } - } -} -function getUTCDateString() { - const today = new Date(); - // Returns date format 'YYYY-MM-DD' - return today.toISOString().substring(0, 10); -} -function extractHeartbeatsForHeader(heartbeatsCache, maxSize = MAX_HEADER_BYTES) { - // Heartbeats grouped by user agent in the standard format to be sent in - // the header. - const heartbeatsToSend = []; - // Single date format heartbeats that are not sent. - let unsentEntries = heartbeatsCache.slice(); - for (const singleDateHeartbeat of heartbeatsCache) { - // Look for an existing entry with the same user agent. - const heartbeatEntry = heartbeatsToSend.find(hb => 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(); - 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(); - break; - } - } - // Pop unsent entry from queue. (Skipped if adding the entry exceeded - // quota and the loop breaks early.) - unsentEntries = unsentEntries.slice(1); - } - return { - heartbeatsToSend, - unsentEntries - }; -} -class HeartbeatStorageImpl { - constructor(app) { - this.app = app; - this._canUseIndexedDBPromise = this.runIndexedDBEnvironmentCheck(); - } - async runIndexedDBEnvironmentCheck() { - if (!isIndexedDBAvailable()) { - return false; - } - else { - return validateIndexedDBOpenable() - .then(() => true) - .catch(() => false); - } - } - /** - * Read all heartbeats. - */ - async read() { - const canUseIndexedDB = await this._canUseIndexedDBPromise; - if (!canUseIndexedDB) { - return { heartbeats: [] }; - } - else { - const idbHeartbeatObject = await readHeartbeatsFromIndexedDB(this.app); - if (idbHeartbeatObject?.heartbeats) { - return idbHeartbeatObject; - } - else { - return { heartbeats: [] }; - } - } - } - // overwrite the storage with the provided heartbeats - async overwrite(heartbeatsObject) { - const canUseIndexedDB = await this._canUseIndexedDBPromise; - if (!canUseIndexedDB) { - return; - } - else { - const existingHeartbeatsObject = await this.read(); - return writeHeartbeatsToIndexedDB(this.app, { - lastSentHeartbeatDate: heartbeatsObject.lastSentHeartbeatDate ?? - existingHeartbeatsObject.lastSentHeartbeatDate, - heartbeats: heartbeatsObject.heartbeats - }); - } - } - // add heartbeats - async add(heartbeatsObject) { - const canUseIndexedDB = await this._canUseIndexedDBPromise; - if (!canUseIndexedDB) { - return; - } - else { - const existingHeartbeatsObject = await this.read(); - return writeHeartbeatsToIndexedDB(this.app, { - lastSentHeartbeatDate: heartbeatsObject.lastSentHeartbeatDate ?? - existingHeartbeatsObject.lastSentHeartbeatDate, - heartbeats: [ - ...existingHeartbeatsObject.heartbeats, - ...heartbeatsObject.heartbeats - ] - }); - } - } -} -/** - * 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; -} -/** - * Returns the index of the heartbeat with the earliest date. - * If the heartbeats array is empty, -1 is returned. - */ -function getEarliestHeartbeatIdx(heartbeats) { - if (heartbeats.length === 0) { - return -1; - } - let earliestHeartbeatIdx = 0; - let earliestHeartbeatDate = heartbeats[0].date; - for (let i = 1; i < heartbeats.length; i++) { - if (heartbeats[i].date < earliestHeartbeatDate) { - earliestHeartbeatDate = heartbeats[i].date; - earliestHeartbeatIdx = i; - } - } - return earliestHeartbeatIdx; -} -/** - * @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', container => new PlatformLoggerServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); - _registerComponent(new Component('heartbeat', container => new HeartbeatServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */)); - // Register `app` package. - registerVersion(name$q, version$1, variant); - // BUILD_TARGET will be replaced by values like esm, cjs, etc during the compilation - registerVersion(name$q, version$1, 'esm2020'); - // Register platform SDK identifier (no version). - registerVersion('fire-js', ''); -} -/** - * Firebase App - * - * @remarks This package coordinates the communication between the different Firebase components - * @packageDocumentation - */ -registerCoreComponents(''); - -var name = "firebase"; -var version = "12.5.0"; - -/** - * @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. - */ -registerVersion(name, version, 'cdn'); - -export { FirebaseError, SDK_VERSION, DEFAULT_ENTRY_NAME as _DEFAULT_ENTRY_NAME, _addComponent, _addOrOverwriteComponent, _apps, _clearComponents, _components, _getProvider, _isFirebaseApp, _isFirebaseServerApp, _isFirebaseServerAppSettings, _registerComponent, _removeServiceInstance, _serverApps, deleteApp, getApp, getApps, initializeApp, initializeServerApp, onLog, registerVersion, setLogLevel }; - -//# sourceMappingURL=firebase-app.js.map |
