@react-native-firebase/app
Version:
A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Sto
269 lines (253 loc) • 9.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createFirebaseRoot = createFirebaseRoot;
exports.createModuleNamespace = createModuleNamespace;
exports.firebaseAppModuleProxy = firebaseAppModuleProxy;
exports.getFirebaseRoot = getFirebaseRoot;
var _index = require("../../common/index.js");
var _version = require("../../version.js");
var _constants = require("../constants.js");
var _FirebaseModule = _interopRequireDefault(require("../FirebaseModule.js"));
var _app2 = require("./app.js");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library 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.
*
*/
// firebase.X
let FIREBASE_ROOT = null;
const NAMESPACE_REGISTRY = {};
const APP_MODULE_INSTANCE = {};
const MODULE_GETTER_FOR_APP = {};
const MODULE_GETTER_FOR_ROOT = {};
/**
* Attaches module namespace getters on every newly created app.
*
* Structured like this to avoid metro require cycles.
*/
(0, _app2.setOnAppCreate)(app => {
for (let i = 0; i < _constants.KNOWN_NAMESPACES.length; i++) {
const moduleNamespace = _constants.KNOWN_NAMESPACES[i];
if (moduleNamespace) {
Object.defineProperty(app, moduleNamespace, {
enumerable: false,
get: firebaseAppModuleProxy.bind(null, app, moduleNamespace)
});
}
}
});
/**
* Destroys all APP_MODULE_INSTANCE & MODULE_GETTER_FOR_APP objects relating to the
* recently destroyed app.
*
* Structured like this to avoid metro require cycles.
*/
(0, _app2.setOnAppDestroy)(app => {
delete APP_MODULE_INSTANCE[app.name];
delete MODULE_GETTER_FOR_APP[app.name];
});
/**
*
* @param app
* @param moduleNamespace
* @returns {*}
*/
function getOrCreateModuleForApp(app, moduleNamespace) {
if (MODULE_GETTER_FOR_APP[app.name] && MODULE_GETTER_FOR_APP[app.name]?.[moduleNamespace]) {
return MODULE_GETTER_FOR_APP[app.name][moduleNamespace];
}
if (!MODULE_GETTER_FOR_APP[app.name]) {
MODULE_GETTER_FOR_APP[app.name] = {};
}
const config = NAMESPACE_REGISTRY[moduleNamespace];
if (!config) {
throw new Error(`Module namespace '${moduleNamespace}' is not registered.`);
}
const {
hasCustomUrlOrRegionSupport,
hasMultiAppSupport,
ModuleClass
} = config;
// modules such as analytics only run on the default app
if (!hasMultiAppSupport && app.name !== _constants.DEFAULT_APP_NAME) {
throw new Error([`You attempted to call "firebase.app('${app.name}').${moduleNamespace}" but; ${moduleNamespace} does not support multiple Firebase Apps.`, '', `Ensure you access ${moduleNamespace} from the default application only.`].join('\r\n'));
}
// e.g. firebase.storage(customUrlOrRegion), firebase.functions(customUrlOrRegion), firebase.firestore(databaseId), firebase.database(url)
function firebaseModuleWithArgs(customUrlOrRegionOrDatabaseId) {
if (customUrlOrRegionOrDatabaseId !== undefined) {
if (!hasCustomUrlOrRegionSupport) {
// TODO throw Module does not support arguments error
}
if (!(0, _index.isString)(customUrlOrRegionOrDatabaseId)) {
// TODO throw Module first argument must be a string error
}
}
const key = customUrlOrRegionOrDatabaseId ? `${customUrlOrRegionOrDatabaseId}:${moduleNamespace}` : moduleNamespace;
if (!APP_MODULE_INSTANCE[app.name]) {
APP_MODULE_INSTANCE[app.name] = {};
}
if (!APP_MODULE_INSTANCE[app.name]?.[key]) {
const moduleConfig = NAMESPACE_REGISTRY[moduleNamespace];
if (!moduleConfig) {
throw new Error(`Module namespace '${moduleNamespace}' is not registered.`);
}
const module = (0, _index.createDeprecationProxy)(new ModuleClass(app, moduleConfig, customUrlOrRegionOrDatabaseId));
APP_MODULE_INSTANCE[app.name][key] = module;
}
return APP_MODULE_INSTANCE[app.name][key];
}
MODULE_GETTER_FOR_APP[app.name][moduleNamespace] = firebaseModuleWithArgs;
return MODULE_GETTER_FOR_APP[app.name][moduleNamespace];
}
/**
*
* @param moduleNamespace
* @returns {*}
*/
function getOrCreateModuleForRoot(moduleNamespace) {
if (MODULE_GETTER_FOR_ROOT[moduleNamespace]) {
return MODULE_GETTER_FOR_ROOT[moduleNamespace];
}
const config = NAMESPACE_REGISTRY[moduleNamespace];
if (!config) {
throw new Error(`Module namespace '${moduleNamespace}' is not registered.`);
}
const {
statics,
hasMultiAppSupport,
ModuleClass
} = config;
// e.g. firebase.storage(app)
function firebaseModuleWithApp(app) {
const _app = app || (0, _app2.getApp)();
// Duck-type check for FirebaseApp (checking for required properties)
if (!_app || typeof _app !== 'object' || !('name' in _app) || !('options' in _app) || typeof _app.name !== 'string') {
throw new Error([`"firebase.${moduleNamespace}(app)" arg expects a FirebaseApp instance or undefined.`, '', 'Ensure the arg provided is a Firebase app instance; or no args to use the default Firebase app.'].join('\r\n'));
}
// modules such as analytics only run on the default app
if (!hasMultiAppSupport && _app.name !== _constants.DEFAULT_APP_NAME) {
throw new Error([`You attempted to call "firebase.${moduleNamespace}(app)" but; ${moduleNamespace} does not support multiple Firebase Apps.`, '', `Ensure the app provided is the default Firebase app only and not the "${_app.name}" app.`].join('\r\n'));
}
if (!APP_MODULE_INSTANCE[_app.name]) {
APP_MODULE_INSTANCE[_app.name] = {};
}
if (!APP_MODULE_INSTANCE[_app.name]?.[moduleNamespace]) {
const moduleConfig = NAMESPACE_REGISTRY[moduleNamespace];
if (!moduleConfig) {
throw new Error(`Module namespace '${moduleNamespace}' is not registered.`);
}
const module = (0, _index.createDeprecationProxy)(new ModuleClass(_app, moduleConfig));
APP_MODULE_INSTANCE[_app.name][moduleNamespace] = module;
}
return APP_MODULE_INSTANCE[_app.name][moduleNamespace];
}
Object.assign(firebaseModuleWithApp, statics || {});
// Object.freeze(firebaseModuleWithApp);
// Wrap around statics, e.g. firebase.firestore.FieldValue, removed freeze as it stops proxy working. it is deprecated anyway
MODULE_GETTER_FOR_ROOT[moduleNamespace] = (0, _index.createDeprecationProxy)(firebaseModuleWithApp);
return MODULE_GETTER_FOR_ROOT[moduleNamespace];
}
/**
*
* @param firebaseNamespace
* @param moduleNamespace
* @returns {*}
*/
function firebaseRootModuleProxy(_firebaseNamespace, moduleNamespace) {
if (NAMESPACE_REGISTRY[moduleNamespace]) {
return getOrCreateModuleForRoot(moduleNamespace);
}
const moduleWithDashes = moduleNamespace.split(/(?=[A-Z])/).join('-').toLowerCase();
throw new Error([`You attempted to use 'firebase.${moduleNamespace}' but this module could not be found.`, '', `Ensure you have installed and imported the '@react-native-firebase/${moduleWithDashes}' package.`].join('\r\n'));
}
/**
*
* @param app
* @param moduleNamespace
* @returns {*}
*/
function firebaseAppModuleProxy(app, moduleNamespace) {
if (NAMESPACE_REGISTRY[moduleNamespace]) {
// Call private _checkDestroyed method
app._checkDestroyed();
return getOrCreateModuleForApp(app, moduleNamespace);
}
const moduleWithDashes = moduleNamespace.split(/(?=[A-Z])/).join('-').toLowerCase();
throw new Error([`You attempted to use "firebase.app('${app.name}').${moduleNamespace}" but this module could not be found.`, '', `Ensure you have installed and imported the '@react-native-firebase/${moduleWithDashes}' package.`].join('\r\n'));
}
/**
*
* @returns {*}
*/
function createFirebaseRoot() {
// Create partial root object - module namespaces like 'utils' are added dynamically below
const root = {
initializeApp: _app2.initializeApp,
setReactNativeAsyncStorage: _app2.setReactNativeAsyncStorage,
get app() {
return _app2.getApp;
},
get apps() {
return (0, _app2.getApps)();
},
SDK_VERSION: _version.version,
setLogLevel: _app2.setLogLevel
};
for (let i = 0; i < _constants.KNOWN_NAMESPACES.length; i++) {
const namespace = _constants.KNOWN_NAMESPACES[i];
if (namespace) {
Object.defineProperty(root, namespace, {
enumerable: false,
get: firebaseRootModuleProxy.bind(null, root, namespace)
});
}
}
FIREBASE_ROOT = root;
return root;
}
/**
*
* @returns {*}
*/
function getFirebaseRoot() {
if (FIREBASE_ROOT) {
return FIREBASE_ROOT;
}
return createFirebaseRoot();
}
/**
*
* @param options
* @returns {*}
*/
function createModuleNamespace(options) {
const {
namespace,
ModuleClass
} = options;
if (!NAMESPACE_REGISTRY[namespace]) {
// validation only for internal / module dev usage
const firebaseModuleExtended = _FirebaseModule.default.__extended__;
const moduleClassExtended = ModuleClass.__extended__;
if (firebaseModuleExtended !== moduleClassExtended) {
throw new Error('INTERNAL ERROR: ModuleClass must be an instance of FirebaseModule.');
}
NAMESPACE_REGISTRY[namespace] = Object.assign({}, options);
}
return getFirebaseRoot()[namespace];
}
//# sourceMappingURL=namespace.js.map