2017-12-22 15:24:31 +00:00
|
|
|
/**
|
|
|
|
* @flow
|
|
|
|
*/
|
|
|
|
import { NativeModules } from 'react-native';
|
2018-02-14 13:00:19 +00:00
|
|
|
import App from '../modules/core/app';
|
2017-12-22 15:24:31 +00:00
|
|
|
import INTERNALS from './internals';
|
|
|
|
import { isAndroid, isObject, isString } from './';
|
|
|
|
|
|
|
|
import type {
|
|
|
|
FirebaseModule,
|
|
|
|
FirebaseModuleAndStatics,
|
|
|
|
FirebaseModuleName,
|
2018-01-03 20:00:38 +00:00
|
|
|
FirebaseNamespace,
|
2017-12-22 15:24:31 +00:00
|
|
|
FirebaseOptions,
|
|
|
|
FirebaseStatics,
|
|
|
|
} from '../types';
|
|
|
|
|
|
|
|
const FirebaseCoreModule = NativeModules.RNFirebase;
|
|
|
|
|
2018-01-05 17:20:02 +00:00
|
|
|
const APPS: { [string]: App } = {};
|
2018-03-01 08:39:24 +00:00
|
|
|
const APP_MODULES: { [string]: { [string]: FirebaseModule } } = {};
|
2018-01-03 20:00:38 +00:00
|
|
|
const DEFAULT_APP_NAME = '[DEFAULT]';
|
2017-12-22 15:24:31 +00:00
|
|
|
|
|
|
|
export default {
|
2018-01-03 20:00:38 +00:00
|
|
|
DEFAULT_APP_NAME,
|
|
|
|
|
2018-01-05 17:20:02 +00:00
|
|
|
app(name?: string): App {
|
2018-01-03 20:00:38 +00:00
|
|
|
const _name = name ? name.toUpperCase() : DEFAULT_APP_NAME;
|
2017-12-22 15:24:31 +00:00
|
|
|
const app = APPS[_name];
|
|
|
|
if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
|
|
|
|
return app;
|
|
|
|
},
|
|
|
|
|
2018-01-05 17:20:02 +00:00
|
|
|
apps(): Array<App> {
|
2018-02-17 12:55:19 +00:00
|
|
|
// $FlowExpectedError: Object.values always returns mixed type: https://github.com/facebook/flow/issues/2221
|
2017-12-22 15:24:31 +00:00
|
|
|
return Object.values(APPS);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2018-02-24 05:53:07 +00:00
|
|
|
* @param app
|
|
|
|
* @param namespace
|
2017-12-22 15:24:31 +00:00
|
|
|
* @param InstanceClass
|
|
|
|
* @return {function()}
|
|
|
|
* @private
|
|
|
|
*/
|
2018-01-25 18:25:39 +00:00
|
|
|
appModule<M: FirebaseModule>(
|
|
|
|
app: App,
|
|
|
|
namespace: FirebaseNamespace,
|
|
|
|
InstanceClass: Class<M>
|
|
|
|
): () => FirebaseModule {
|
2017-11-21 23:37:05 +00:00
|
|
|
return (serviceUrl: ?string = null): M => {
|
|
|
|
if (serviceUrl && namespace !== 'database') {
|
|
|
|
throw new Error(
|
|
|
|
INTERNALS.STRINGS.ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const appOrShardName = serviceUrl || app.name;
|
|
|
|
if (!APP_MODULES[appOrShardName]) {
|
|
|
|
APP_MODULES[appOrShardName] = {};
|
2017-12-22 15:24:31 +00:00
|
|
|
}
|
|
|
|
|
2018-01-25 18:25:39 +00:00
|
|
|
if (
|
|
|
|
isAndroid &&
|
|
|
|
namespace !== 'utils' &&
|
|
|
|
!INTERNALS.FLAGS.checkedPlayServices
|
|
|
|
) {
|
2017-12-22 15:24:31 +00:00
|
|
|
INTERNALS.FLAGS.checkedPlayServices = true;
|
2018-01-08 09:20:32 +00:00
|
|
|
app.utils().checkPlayServicesAvailability();
|
2017-12-22 15:24:31 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 23:37:05 +00:00
|
|
|
if (!APP_MODULES[appOrShardName][namespace]) {
|
|
|
|
APP_MODULES[appOrShardName][namespace] = new InstanceClass(
|
|
|
|
serviceUrl || app,
|
|
|
|
app.options
|
|
|
|
);
|
2017-12-22 15:24:31 +00:00
|
|
|
}
|
|
|
|
|
2017-11-21 23:37:05 +00:00
|
|
|
return APP_MODULES[appOrShardName][namespace];
|
2017-12-22 15:24:31 +00:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
deleteApp(name: string): Promise<boolean> {
|
|
|
|
const app = APPS[name];
|
|
|
|
if (!app) return Promise.resolve(true);
|
|
|
|
|
|
|
|
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
|
|
|
|
return app.delete().then(() => {
|
|
|
|
delete APPS[name];
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Web SDK initializeApp
|
|
|
|
*
|
|
|
|
* @param options
|
|
|
|
* @param name
|
|
|
|
* @return {*}
|
|
|
|
*/
|
2018-01-05 17:20:02 +00:00
|
|
|
initializeApp(options: FirebaseOptions, name: string): App {
|
2017-12-22 15:24:31 +00:00
|
|
|
if (name && !isString(name)) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
|
|
|
|
}
|
|
|
|
|
2018-01-03 20:00:38 +00:00
|
|
|
const _name = (name || DEFAULT_APP_NAME).toUpperCase();
|
2017-12-22 15:24:31 +00:00
|
|
|
|
|
|
|
// return an existing app if found
|
2018-05-05 18:25:52 +00:00
|
|
|
// TODO in v5 remove deprecation and throw an error
|
2017-12-22 15:24:31 +00:00
|
|
|
if (APPS[_name]) {
|
|
|
|
console.warn(INTERNALS.STRINGS.WARN_INITIALIZE_DEPRECATION);
|
|
|
|
return APPS[_name];
|
|
|
|
}
|
|
|
|
|
|
|
|
// only validate if app doesn't already exist
|
|
|
|
// to allow apps already initialized natively
|
|
|
|
// to still go through init without erroring (backwards compatibility)
|
|
|
|
if (!isObject(options)) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_INIT_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.apiKey) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('apiKey'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.appId) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('appId'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.databaseURL) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('databaseURL'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.messagingSenderId) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('messagingSenderId'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.projectId) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('projectId'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.storageBucket) {
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('storageBucket'));
|
|
|
|
}
|
|
|
|
|
2018-01-05 17:20:02 +00:00
|
|
|
APPS[_name] = new App(_name, options);
|
2017-12-22 15:24:31 +00:00
|
|
|
|
|
|
|
return APPS[_name];
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bootstraps all native app instances that were discovered on boot
|
|
|
|
*/
|
|
|
|
initializeNativeApps() {
|
|
|
|
for (let i = 0, len = FirebaseCoreModule.apps.length; i < len; i++) {
|
|
|
|
const app = FirebaseCoreModule.apps[i];
|
|
|
|
const options = Object.assign({}, app);
|
|
|
|
delete options.name;
|
2018-01-05 17:20:02 +00:00
|
|
|
APPS[app.name] = new App(app.name, options, true);
|
2017-12-22 15:24:31 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2018-02-24 05:53:07 +00:00
|
|
|
* @param namespace
|
2017-12-22 15:24:31 +00:00
|
|
|
* @param statics
|
2018-02-24 05:53:07 +00:00
|
|
|
* @param moduleName
|
2018-01-05 17:20:02 +00:00
|
|
|
* @return {function(App=)}
|
2017-12-22 15:24:31 +00:00
|
|
|
*/
|
2018-01-25 18:25:39 +00:00
|
|
|
moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(
|
|
|
|
namespace: FirebaseNamespace,
|
|
|
|
statics: S,
|
|
|
|
moduleName: FirebaseModuleName
|
|
|
|
): FirebaseModuleAndStatics<M, S> {
|
2017-11-21 23:37:05 +00:00
|
|
|
const getModule = (appOrUrl?: App | string): FirebaseModule => {
|
|
|
|
let _app = appOrUrl;
|
|
|
|
let _serviceUrl: ?string = null;
|
|
|
|
if (typeof appOrUrl === 'string' && namespace === 'database') {
|
|
|
|
_app = null;
|
|
|
|
_serviceUrl = appOrUrl;
|
|
|
|
}
|
2017-12-22 15:24:31 +00:00
|
|
|
|
|
|
|
// throw an error if it's not a valid app instance
|
2018-01-25 18:25:39 +00:00
|
|
|
if (_app && !(_app instanceof App))
|
|
|
|
throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
|
|
|
|
else if (!_app)
|
|
|
|
// default to the 'DEFAULT' app if no arg provided - will throw an error
|
|
|
|
// if default app not initialized
|
|
|
|
_app = this.app(DEFAULT_APP_NAME);
|
2018-02-17 12:55:19 +00:00
|
|
|
// $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
|
2018-01-05 17:20:02 +00:00
|
|
|
const module = _app[namespace];
|
2017-11-21 23:37:05 +00:00
|
|
|
return module(_serviceUrl);
|
2017-12-22 15:24:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
return Object.assign(getModule, statics, {
|
2018-01-03 20:00:38 +00:00
|
|
|
nativeModuleExists: !!NativeModules[moduleName],
|
2017-12-22 15:24:31 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|