all files / firebase/utils/ apps.js

74.6% Statements 47/63
66.67% Branches 30/45
66.67% Functions 2/3
77.05% Lines 47/61
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189                                              1745× 1745× 1745× 1745×                                       90× 1718×     1718×             1718× 30×     1718×                                                                                                                                                         30× 1715×     1715×   1715×     1715× 1715× 14×     1701× 1701×     30×          
/**
 * @flow
 */
import { NativeModules } from 'react-native';
import App from '../modules/core/app';
import INTERNALS from './internals';
import { isAndroid, isObject, isString } from './';
 
import type {
  FirebaseModule,
  FirebaseModuleAndStatics,
  FirebaseModuleName,
  FirebaseNamespace,
  FirebaseOptions,
  FirebaseStatics,
} from '../types';
 
const FirebaseCoreModule = NativeModules.RNFirebase;
 
const APPS: { [string]: App } = {};
const APP_MODULES: { [string]: { [string]: FirebaseModule } } = {};
const DEFAULT_APP_NAME = '[DEFAULT]';
 
export default {
  DEFAULT_APP_NAME,
 
  app(name?: string): App {
    const _name = name ? name.toUpperCase() : DEFAULT_APP_NAME;
    const app = APPS[_name];
    Iif (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
    return app;
  },
 
  apps(): Array<App> {
    // $FlowExpectedError: Object.values always returns mixed type: https://github.com/facebook/flow/issues/2221
    return Object.values(APPS);
  },
 
  /**
   *
   * @param app
   * @param namespace
   * @param InstanceClass
   * @return {function()}
   * @private
   */
  appModule<M: FirebaseModule>(
    app: App,
    namespace: FirebaseNamespace,
    InstanceClass: Class<M>
  ): () => FirebaseModule {
    return (): M => {
      if (!APP_MODULES[app._name]) {
        APP_MODULES[app._name] = {};
      }
 
      if (
        isAndroid &&
        namespace !== 'utils' &&
        !INTERNALS.FLAGS.checkedPlayServices
      ) {
        INTERNALS.FLAGS.checkedPlayServices = true;
        app.utils().checkPlayServicesAvailability();
      }
 
      if (!APP_MODULES[app._name][namespace]) {
        APP_MODULES[app._name][namespace] = new InstanceClass(app, app.options);
      }
 
      return APP_MODULES[app._name][namespace];
    };
  },
 
  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 {*}
   */
  initializeApp(options: FirebaseOptions, name: string): App {
    Iif (name && !isString(name)) {
      throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
    }
 
    const _name = (name || DEFAULT_APP_NAME).toUpperCase();
 
    // return an existing app if found
    // todo in v4 remove deprecation and throw an error
    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)
    Iif (!isObject(options)) {
      throw new Error(INTERNALS.STRINGS.ERROR_INIT_OBJECT);
    }
 
    Iif (!options.apiKey) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('apiKey'));
    }
 
    Iif (!options.appId) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('appId'));
    }
 
    Iif (!options.databaseURL) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('databaseURL'));
    }
 
    Iif (!options.messagingSenderId) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('messagingSenderId'));
    }
 
    Iif (!options.projectId) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('projectId'));
    }
 
    Iif (!options.storageBucket) {
      throw new Error(INTERNALS.STRINGS.ERROR_MISSING_OPT('storageBucket'));
    }
 
    APPS[_name] = new App(_name, options);
 
    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;
      APPS[app.name] = new App(app.name, options, true);
    }
  },
 
  /**
   *
   * @param namespace
   * @param statics
   * @param moduleName
   * @return {function(App=)}
   */
  moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(
    namespace: FirebaseNamespace,
    statics: S,
    moduleName: FirebaseModuleName
  ): FirebaseModuleAndStatics<M, S> {
    const getModule = (app?: App): FirebaseModule => {
      let _app = app;
 
      // throw an error if it's not a valid app instance
      Iif (_app && !(_app instanceof App))
        throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
      else Eif (!_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);
      if (namespace === 'crashlytics') {
        return _app.fabric[namespace]();
      }
      // $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
      const module = _app[namespace];
      return module();
    };
 
    return Object.assign(getModule, statics, {
      nativeModuleExists: !!NativeModules[moduleName],
    });
  },
};