[internals] Start refactoring some of the internals to simplify, tidy up and also reduce flow type pollution
This commit is contained in:
parent
1a35d8a7b5
commit
f2c2007fdc
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import Firebase from './modules/core/firebase';
|
||||
import firebase from './modules/core/firebase';
|
||||
|
||||
export const AdMob = require('./modules/admob');
|
||||
export type { default as User } from './modules/auth/User';
|
||||
|
||||
export default Firebase;
|
||||
export default firebase;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { NativeModules, Platform } from 'react-native';
|
||||
import { statics } from './';
|
||||
import AdRequest from './AdRequest';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { nativeToJSError } from '../../utils';
|
||||
|
||||
const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
|
||||
|
@ -23,8 +24,8 @@ export default class Interstitial {
|
|||
this.admob = admob;
|
||||
this.adUnit = adUnit;
|
||||
this.loaded = false;
|
||||
this.admob.removeAllListeners(`interstitial_${adUnit}`);
|
||||
this.admob.on(`interstitial_${adUnit}`, this._onInterstitialEvent);
|
||||
SharedEventEmitter.removeAllListeners(`interstitial_${adUnit}`);
|
||||
SharedEventEmitter.addListener(`interstitial_${adUnit}`, this._onInterstitialEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,8 +49,8 @@ export default class Interstitial {
|
|||
default:
|
||||
}
|
||||
|
||||
this.admob.emit(eventType, emitData);
|
||||
this.admob.emit(`interstitial:${this.adUnit}:*`, emitData);
|
||||
SharedEventEmitter.emit(eventType, emitData);
|
||||
SharedEventEmitter.emit(`interstitial:${this.adUnit}:*`, emitData);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -97,7 +98,7 @@ export default class Interstitial {
|
|||
return null;
|
||||
}
|
||||
|
||||
const sub = this.admob.on(`interstitial:${this.adUnit}:${eventType}`, listenerCb);
|
||||
const sub = SharedEventEmitter.addListener(`interstitial:${this.adUnit}:${eventType}`, listenerCb);
|
||||
subscriptions.push(sub);
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { NativeModules } from 'react-native';
|
||||
import { statics } from './';
|
||||
import AdRequest from './AdRequest';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { nativeToJSError } from '../../utils';
|
||||
|
||||
const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
|
||||
|
@ -18,8 +19,8 @@ export default class RewardedVideo {
|
|||
this.admob = admob;
|
||||
this.adUnit = adUnit;
|
||||
this.loaded = false;
|
||||
this.admob.removeAllListeners(`rewarded_video_${adUnit}`);
|
||||
this.admob.on(`rewarded_video_${adUnit}`, this._onRewardedVideoEvent);
|
||||
SharedEventEmitter.removeAllListeners(`rewarded_video_${adUnit}`);
|
||||
SharedEventEmitter.addListener(`rewarded_video_${adUnit}`, this._onRewardedVideoEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,8 +44,8 @@ export default class RewardedVideo {
|
|||
default:
|
||||
}
|
||||
|
||||
this.admob.emit(eventType, emitData);
|
||||
this.admob.emit(`rewarded_video:${this.adUnit}:*`, emitData);
|
||||
SharedEventEmitter.emit(eventType, emitData);
|
||||
SharedEventEmitter.emit(`rewarded_video:${this.adUnit}:*`, emitData);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -97,7 +98,7 @@ export default class RewardedVideo {
|
|||
return null;
|
||||
}
|
||||
|
||||
const sub = this.admob.on(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb);
|
||||
const sub = SharedEventEmitter.addListener(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb);
|
||||
subscriptions.push(sub);
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
* @flow
|
||||
* AdMob representation wrapper
|
||||
*/
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
|
||||
import Interstitial from './Interstitial';
|
||||
import RewardedVideo from './RewardedVideo';
|
||||
|
@ -37,35 +39,35 @@ export default class AdMob extends ModuleBase {
|
|||
this._initialized = false;
|
||||
this._appId = null;
|
||||
|
||||
this._eventEmitter.addListener('interstitial_event', this._onInterstitialEvent.bind(this));
|
||||
this._eventEmitter.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this));
|
||||
SharedEventEmitter.addListener('interstitial_event', this._onInterstitialEvent.bind(this));
|
||||
SharedEventEmitter.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this));
|
||||
}
|
||||
|
||||
_onInterstitialEvent(event: NativeEvent): void {
|
||||
const { adUnit } = event;
|
||||
const jsEventType = `interstitial_${adUnit}`;
|
||||
|
||||
if (!this.hasListeners(jsEventType)) {
|
||||
if (!SharedEventEmitter.hasListeners(jsEventType)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
this.emit(jsEventType, event);
|
||||
SharedEventEmitter.emit(jsEventType, event);
|
||||
}
|
||||
|
||||
_onRewardedVideoEvent(event: NativeEvent): void {
|
||||
const { adUnit } = event;
|
||||
const jsEventType = `rewarded_video_${adUnit}`;
|
||||
|
||||
if (!this.hasListeners(jsEventType)) {
|
||||
if (!SharedEventEmitter.hasListeners(jsEventType)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
this.emit(jsEventType, event);
|
||||
SharedEventEmitter.emit(jsEventType, event);
|
||||
}
|
||||
|
||||
initialize(appId: string): void {
|
||||
if (this._initialized) {
|
||||
this.log.warn('AdMob has already been initialized!');
|
||||
getLogger(this).warn('AdMob has already been initialized!');
|
||||
} else {
|
||||
this._initialized = true;
|
||||
this._appId = appId;
|
||||
|
@ -75,9 +77,9 @@ export default class AdMob extends ModuleBase {
|
|||
|
||||
openDebugMenu(): void {
|
||||
if (!this._initialized) {
|
||||
this.log.warn('AdMob needs to be initialized before opening the dev menu!');
|
||||
getLogger(this).warn('AdMob needs to be initialized before opening the dev menu!');
|
||||
} else {
|
||||
this.log.info('Opening debug menu');
|
||||
getLogger(this).info('Opening debug menu');
|
||||
this._native.openDebugMenu(this._appId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// @flow
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from './../../utils';
|
||||
|
||||
import type Auth from './';
|
||||
|
@ -92,7 +93,7 @@ export default class PhoneAuthListener {
|
|||
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
const type = events[i];
|
||||
this._auth.once(this._internalEvents[type], this[`_${type}Handler`].bind(this));
|
||||
SharedEventEmitter.once(this._internalEvents[type], this[`_${type}Handler`].bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ export default class PhoneAuthListener {
|
|||
* @private
|
||||
*/
|
||||
_addUserObserver(observer) {
|
||||
this._auth.on(this._publicEvents.event, observer);
|
||||
SharedEventEmitter.addListener(this._publicEvents.event, observer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,7 +112,7 @@ export default class PhoneAuthListener {
|
|||
* @private
|
||||
*/
|
||||
_emitToObservers(snapshot: PhoneAuthSnapshot) {
|
||||
this._auth.emit(this._publicEvents.event, snapshot);
|
||||
SharedEventEmitter.emit(this._publicEvents.event, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,7 +123,7 @@ export default class PhoneAuthListener {
|
|||
_emitToErrorCb(snapshot) {
|
||||
const error = snapshot.error;
|
||||
if (this._reject) this._reject(error);
|
||||
this._auth.emit(this._publicEvents.error, error);
|
||||
SharedEventEmitter.emit(this._publicEvents.error, error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,7 +133,7 @@ export default class PhoneAuthListener {
|
|||
*/
|
||||
_emitToSuccessCb(snapshot) {
|
||||
if (this._resolve) this._resolve(snapshot);
|
||||
this._auth.emit(this._publicEvents.success, snapshot);
|
||||
SharedEventEmitter.emit(this._publicEvents.success, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,12 +144,12 @@ export default class PhoneAuthListener {
|
|||
setTimeout(() => { // move to next event loop - not sure if needed
|
||||
// internal listeners
|
||||
Object.values(this._internalEvents).forEach((event) => {
|
||||
this._auth.removeAllListeners(event);
|
||||
SharedEventEmitter.removeAllListeners(event);
|
||||
});
|
||||
|
||||
// user observer listeners
|
||||
Object.values(this._publicEvents).forEach((publicEvent) => {
|
||||
this._auth.removeAllListeners(publicEvent);
|
||||
SharedEventEmitter.removeAllListeners(publicEvent);
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
@ -279,11 +280,11 @@ export default class PhoneAuthListener {
|
|||
this._addUserObserver(observer);
|
||||
|
||||
if (isFunction(errorCb)) {
|
||||
this._auth.once(this._publicEvents.error, errorCb);
|
||||
SharedEventEmitter.once(this._publicEvents.error, errorCb);
|
||||
}
|
||||
|
||||
if (isFunction(successCb)) {
|
||||
this._auth.once(this._publicEvents.success, successCb);
|
||||
SharedEventEmitter.once(this._publicEvents.success, successCb);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
import User from './User';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import ConfirmationResult from './ConfirmationResult';
|
||||
|
||||
|
@ -37,24 +39,24 @@ export default class Auth extends ModuleBase {
|
|||
this._user = null;
|
||||
this._authResult = null;
|
||||
|
||||
this.addListener(
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onAuthStateChanged
|
||||
super._getAppEventName('auth_state_changed'),
|
||||
getAppEventName(this, 'auth_state_changed'),
|
||||
this._onInternalAuthStateChanged.bind(this),
|
||||
);
|
||||
|
||||
this.addListener(
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public events based on event.type
|
||||
super._getAppEventName('phone_auth_state_changed'),
|
||||
getAppEventName(this, 'phone_auth_state_changed'),
|
||||
this._onInternalPhoneAuthStateChanged.bind(this),
|
||||
);
|
||||
|
||||
this.addListener(
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onIdTokenChanged
|
||||
super._getAppEventName('auth_id_token_changed'),
|
||||
getAppEventName(this, 'auth_id_token_changed'),
|
||||
this._onInternalIdTokenChanged.bind(this),
|
||||
);
|
||||
|
||||
|
@ -69,13 +71,13 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
_onInternalPhoneAuthStateChanged(event: Object) {
|
||||
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
||||
this.emit(eventKey, event.state);
|
||||
SharedEventEmitter.emit(eventKey, event.state);
|
||||
}
|
||||
|
||||
_setAuthState(auth: AuthResult) {
|
||||
this._authResult = auth;
|
||||
this._user = auth && auth.user ? new User(this, auth.user) : null;
|
||||
this.emit(this._getAppEventName('onUserChanged'), this._user);
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +87,7 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
_onInternalAuthStateChanged(auth: AuthResult) {
|
||||
this._setAuthState(auth);
|
||||
this.emit(this._getAppEventName('onAuthStateChanged'), this._user);
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onAuthStateChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,7 +98,7 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
_onInternalIdTokenChanged(auth: AuthResult) {
|
||||
this._setAuthState(auth);
|
||||
this.emit(this._getAppEventName('onIdTokenChanged'), this._user);
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onIdTokenChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,8 +131,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
onAuthStateChanged(listener: Function) {
|
||||
this.log.info('Creating onAuthStateChanged listener');
|
||||
this.on(this._getAppEventName('onAuthStateChanged'), listener);
|
||||
getLogger(this).info('Creating onAuthStateChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onAuthStateChanged'), listener);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offAuthStateChanged.bind(this, listener);
|
||||
}
|
||||
|
@ -140,8 +142,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
_offAuthStateChanged(listener: Function) {
|
||||
this.log.info('Removing onAuthStateChanged listener');
|
||||
this.removeListener(this._getAppEventName('onAuthStateChanged'), listener);
|
||||
getLogger(this).info('Removing onAuthStateChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onAuthStateChanged'), listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,8 +151,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
onIdTokenChanged(listener: Function) {
|
||||
this.log.info('Creating onIdTokenChanged listener');
|
||||
this.on(this._getAppEventName('onIdTokenChanged'), listener);
|
||||
getLogger(this).info('Creating onIdTokenChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onIdTokenChanged'), listener);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offIdTokenChanged.bind(this, listener);
|
||||
}
|
||||
|
@ -160,8 +162,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
_offIdTokenChanged(listener: Function) {
|
||||
this.log.info('Removing onIdTokenChanged listener');
|
||||
this.removeListener(this._getAppEventName('onIdTokenChanged'), listener);
|
||||
getLogger(this).info('Removing onIdTokenChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onIdTokenChanged'), listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,8 +171,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
onUserChanged(listener: Function) {
|
||||
this.log.info('Creating onUserChanged listener');
|
||||
this.on(this._getAppEventName('onUserChanged'), listener);
|
||||
getLogger(this).info('Creating onUserChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onUserChanged'), listener);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offUserChanged.bind(this, listener);
|
||||
}
|
||||
|
@ -180,8 +182,8 @@ export default class Auth extends ModuleBase {
|
|||
* @param listener
|
||||
*/
|
||||
_offUserChanged(listener: Function) {
|
||||
this.log.info('Removing onUserChanged listener');
|
||||
this.removeListener(this._getAppEventName('onUserChanged'), listener);
|
||||
getLogger(this).info('Removing onUserChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onUserChanged'), listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* @flow
|
||||
* Remote Config representation wrapper
|
||||
*/
|
||||
import { getLogger } from '../../utils/log';
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
|
||||
import type FirebaseApp from '../core/firebase-app';
|
||||
|
@ -51,7 +52,7 @@ export default class RemoteConfig extends ModuleBase {
|
|||
*/
|
||||
enableDeveloperMode() {
|
||||
if (!this._developerModeEnabled) {
|
||||
this.log.debug('Enabled developer mode');
|
||||
getLogger(this).debug('Enabled developer mode');
|
||||
this._native.enableDeveloperMode();
|
||||
this._developerModeEnabled = true;
|
||||
}
|
||||
|
@ -64,10 +65,10 @@ export default class RemoteConfig extends ModuleBase {
|
|||
*/
|
||||
fetch(expiration?: number) {
|
||||
if (expiration !== undefined) {
|
||||
this.log.debug(`Fetching remote config data with expiration ${expiration.toString()}`);
|
||||
getLogger(this).debug(`Fetching remote config data with expiration ${expiration.toString()}`);
|
||||
return this._native.fetchWithExpirationDuration(expiration);
|
||||
}
|
||||
this.log.debug('Fetching remote config data');
|
||||
getLogger(this).debug('Fetching remote config data');
|
||||
return this._native.fetch();
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ export default class RemoteConfig extends ModuleBase {
|
|||
* rejects if no Fetched Config was found, or the Fetched Config was already activated.
|
||||
*/
|
||||
activateFetched() {
|
||||
this.log.debug('Activating remote config');
|
||||
getLogger(this).debug('Activating remote config');
|
||||
return this._native.activateFetched();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,41 +3,27 @@
|
|||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import APPS from '../../utils/apps';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import { isObject, isAndroid } from '../../utils';
|
||||
import { isObject } from '../../utils';
|
||||
|
||||
import AdMob, { statics as AdMobStatics } from '../admob';
|
||||
import Auth, { statics as AuthStatics } from '../auth';
|
||||
import Analytics, { statics as AnalyticsStatics } from '../analytics';
|
||||
import Config, { statics as ConfigStatics } from '../config';
|
||||
import Crash, { statics as CrashStatics } from '../crash';
|
||||
import Crashlytics, { statics as CrashlyticsStatics } from '../fabric/crashlytics';
|
||||
import Database, { statics as DatabaseStatics } from '../database';
|
||||
import Firestore, { statics as FirestoreStatics } from '../firestore';
|
||||
import Links, { statics as LinksStatics } from '../links';
|
||||
import Messaging, { statics as MessagingStatics } from '../messaging';
|
||||
import Performance, { statics as PerformanceStatics } from '../perf';
|
||||
import Storage, { statics as StorageStatics } from '../storage';
|
||||
import Utils, { statics as UtilsStatics } from '../utils';
|
||||
import AdMob from '../admob';
|
||||
import Auth from '../auth';
|
||||
import Analytics from '../analytics';
|
||||
import Config from '../config';
|
||||
import Crash from '../crash';
|
||||
import Crashlytics from '../fabric/crashlytics';
|
||||
import Database from '../database';
|
||||
import Firestore from '../firestore';
|
||||
import Links from '../links';
|
||||
import Messaging from '../messaging';
|
||||
import Performance from '../perf';
|
||||
import Storage from '../storage';
|
||||
import Utils from '../utils';
|
||||
|
||||
import type {
|
||||
AdMobModule,
|
||||
AnalyticsModule,
|
||||
AuthModule,
|
||||
ConfigModule,
|
||||
CrashModule,
|
||||
DatabaseModule,
|
||||
FabricModule,
|
||||
FirebaseModule,
|
||||
FirebaseModuleAndStatics,
|
||||
FirebaseOptions,
|
||||
FirebaseStatics,
|
||||
FirestoreModule,
|
||||
LinksModule,
|
||||
MessagingModule,
|
||||
PerformanceModule,
|
||||
StorageModule,
|
||||
UtilsModule,
|
||||
} from '../../types';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
@ -45,70 +31,57 @@ const FirebaseCoreModule = NativeModules.RNFirebase;
|
|||
|
||||
export default class FirebaseApp {
|
||||
_extendedProps: { [string] : boolean };
|
||||
_initialized: boolean;
|
||||
_initialized: boolean = false;
|
||||
_name: string;
|
||||
_namespaces: { [string]: FirebaseModule };
|
||||
_nativeInitialized: boolean;
|
||||
_nativeInitialized: boolean = false;
|
||||
_options: FirebaseOptions;
|
||||
admob: AdMobModule;
|
||||
analytics: AnalyticsModule;
|
||||
auth: AuthModule;
|
||||
config: ConfigModule;
|
||||
crash: CrashModule;
|
||||
database: DatabaseModule;
|
||||
fabric: FabricModule;
|
||||
firestore: FirestoreModule;
|
||||
links: LinksModule;
|
||||
messaging: MessagingModule;
|
||||
perf: PerformanceModule;
|
||||
storage: StorageModule;
|
||||
utils: UtilsModule;
|
||||
admob: () => AdMob;
|
||||
analytics: () => Analytics;
|
||||
auth: () => Auth;
|
||||
config: () => Config;
|
||||
crash: () => Crash;
|
||||
database: () => Database;
|
||||
fabric: {
|
||||
crashlytics: () => Crashlytics,
|
||||
};
|
||||
firestore: () => Firestore;
|
||||
links: () => Links;
|
||||
messaging: () => Messaging;
|
||||
perf: () => Performance;
|
||||
storage: () => Storage;
|
||||
utils: () => Utils;
|
||||
|
||||
constructor(name: string, options: FirebaseOptions) {
|
||||
constructor(name: string, options: FirebaseOptions, fromNative: boolean = false) {
|
||||
this._name = name;
|
||||
this._namespaces = {};
|
||||
this._options = Object.assign({}, options);
|
||||
|
||||
// native ios/android to confirm initialized
|
||||
this._initialized = false;
|
||||
this._nativeInitialized = false;
|
||||
|
||||
// modules
|
||||
this.admob = this._staticsOrModuleInstance(AdMobStatics, AdMob);
|
||||
this.analytics = this._staticsOrModuleInstance(AnalyticsStatics, Analytics);
|
||||
this.auth = this._staticsOrModuleInstance(AuthStatics, Auth);
|
||||
this.config = this._staticsOrModuleInstance(ConfigStatics, Config);
|
||||
this.crash = this._staticsOrModuleInstance(CrashStatics, Crash);
|
||||
this.database = this._staticsOrModuleInstance(DatabaseStatics, Database);
|
||||
this.fabric = {
|
||||
crashlytics: this._staticsOrModuleInstance(CrashlyticsStatics, Crashlytics),
|
||||
};
|
||||
this.firestore = this._staticsOrModuleInstance(FirestoreStatics, Firestore);
|
||||
this.links = this._staticsOrModuleInstance(LinksStatics, Links);
|
||||
this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging);
|
||||
this.perf = this._staticsOrModuleInstance(PerformanceStatics, Performance);
|
||||
this.storage = this._staticsOrModuleInstance(StorageStatics, Storage);
|
||||
this.utils = this._staticsOrModuleInstance(UtilsStatics, Utils);
|
||||
this._extendedProps = {};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param native
|
||||
* @private
|
||||
*/
|
||||
_initializeApp(native: boolean = false) {
|
||||
if (native) {
|
||||
// for apps already initialized natively that
|
||||
// we have info from RN constants
|
||||
if (fromNative) {
|
||||
this._initialized = true;
|
||||
this._nativeInitialized = true;
|
||||
} else {
|
||||
} else if (options.databaseURL && options.apiKey) {
|
||||
FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => {
|
||||
this._initialized = true;
|
||||
INTERNALS.SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result });
|
||||
SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result });
|
||||
});
|
||||
}
|
||||
|
||||
// modules
|
||||
this.admob = APPS.appModule(this, 'admob', AdMob);
|
||||
this.analytics = APPS.appModule(this, 'analytics', Analytics);
|
||||
this.auth = APPS.appModule(this, 'auth', Auth);
|
||||
this.config = APPS.appModule(this, 'config', Config);
|
||||
this.crash = APPS.appModule(this, 'crash', Crash);
|
||||
this.database = APPS.appModule(this, 'database', Database);
|
||||
this.fabric = {
|
||||
crashlytics: APPS.appModule(this, 'crashlytics', Crashlytics),
|
||||
};
|
||||
this.firestore = APPS.appModule(this, 'firestore', Firestore);
|
||||
this.links = APPS.appModule(this, 'links', Links);
|
||||
this.messaging = APPS.appModule(this, 'messaging', Messaging);
|
||||
this.perf = APPS.appModule(this, 'perf', Performance);
|
||||
this.storage = APPS.appModule(this, 'storage', Storage);
|
||||
this.utils = APPS.appModule(this, 'utils', Utils);
|
||||
this._extendedProps = {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,38 +156,10 @@ export default class FirebaseApp {
|
|||
if (this._initialized) return Promise.resolve(this);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
INTERNALS.SharedEventEmitter.once(`AppReady:${this._name}`, ({ error }) => {
|
||||
SharedEventEmitter.once(`AppReady:${this._name}`, ({ error }) => {
|
||||
if (error) return reject(new Error(error)); // error is a string as it's from native
|
||||
return resolve(this); // return app
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @return {function()}
|
||||
* @private
|
||||
*/
|
||||
_staticsOrModuleInstance<M: FirebaseModule, S:FirebaseStatics>(statics: S, InstanceClass: Class<M>): FirebaseModuleAndStatics<M, S> {
|
||||
const getInstance = (): M => {
|
||||
const _name = `_${InstanceClass._NAMESPACE}`;
|
||||
|
||||
if (isAndroid && InstanceClass._NAMESPACE !== Utils._NAMESPACE && !INTERNALS.FLAGS.checkedPlayServices) {
|
||||
INTERNALS.FLAGS.checkedPlayServices = true;
|
||||
this.utils().checkPlayServicesAvailability();
|
||||
}
|
||||
|
||||
if (!this._namespaces[_name]) {
|
||||
this._namespaces[_name] = new InstanceClass(this, this._options);
|
||||
}
|
||||
|
||||
return this._namespaces[_name];
|
||||
};
|
||||
|
||||
return Object.assign(getInstance, statics, {
|
||||
nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* @providesModule Firebase
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules, NativeEventEmitter } from 'react-native';
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import APPS from '../../utils/apps';
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import FirebaseApp from './firebase-app';
|
||||
import { isObject, isString } from '../../utils';
|
||||
|
||||
// module imports
|
||||
import AdMob, { statics as AdMobStatics } from '../admob';
|
||||
|
@ -31,10 +31,7 @@ import type {
|
|||
CrashModule,
|
||||
DatabaseModule,
|
||||
FabricModule,
|
||||
FirebaseModule,
|
||||
FirebaseModuleAndStatics,
|
||||
FirebaseOptions,
|
||||
FirebaseStatics,
|
||||
FirestoreModule,
|
||||
LinksModule,
|
||||
MessagingModule,
|
||||
|
@ -46,8 +43,6 @@ import type {
|
|||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
class FirebaseCore {
|
||||
_nativeEmitters: { [string]: NativeEventEmitter };
|
||||
_nativeSubscriptions: { [string]: boolean };
|
||||
admob: AdMobModule;
|
||||
analytics: AnalyticsModule;
|
||||
auth: AuthModule;
|
||||
|
@ -63,45 +58,27 @@ class FirebaseCore {
|
|||
utils: UtilsModule;
|
||||
|
||||
constructor() {
|
||||
this._nativeEmitters = {};
|
||||
this._nativeSubscriptions = {};
|
||||
|
||||
if (!FirebaseCoreModule) {
|
||||
throw (new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE));
|
||||
}
|
||||
|
||||
this._initializeNativeApps();
|
||||
APPS.initializeNativeApps();
|
||||
|
||||
// modules
|
||||
this.admob = this._appNamespaceOrStatics(AdMobStatics, AdMob);
|
||||
this.analytics = this._appNamespaceOrStatics(AnalyticsStatics, Analytics);
|
||||
this.auth = this._appNamespaceOrStatics(AuthStatics, Auth);
|
||||
this.config = this._appNamespaceOrStatics(ConfigStatics, Config);
|
||||
this.crash = this._appNamespaceOrStatics(CrashStatics, Crash);
|
||||
this.database = this._appNamespaceOrStatics(DatabaseStatics, Database);
|
||||
this.admob = APPS.moduleAndStatics('admob', AdMobStatics, AdMob);
|
||||
this.analytics = APPS.moduleAndStatics('analytics', AnalyticsStatics, Analytics);
|
||||
this.auth = APPS.moduleAndStatics('auth', AuthStatics, Auth);
|
||||
this.config = APPS.moduleAndStatics('config', ConfigStatics, Config);
|
||||
this.crash = APPS.moduleAndStatics('crash', CrashStatics, Crash);
|
||||
this.database = APPS.moduleAndStatics('database', DatabaseStatics, Database);
|
||||
this.fabric = {
|
||||
crashlytics: this._appNamespaceOrStatics(CrashlyticsStatics, Crashlytics),
|
||||
crashlytics: APPS.moduleAndStatics('crashlytics', CrashlyticsStatics, Crashlytics),
|
||||
};
|
||||
this.firestore = this._appNamespaceOrStatics(FirestoreStatics, Firestore);
|
||||
this.links = this._appNamespaceOrStatics(LinksStatics, Links);
|
||||
this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging);
|
||||
this.perf = this._appNamespaceOrStatics(PerformanceStatics, Performance);
|
||||
this.storage = this._appNamespaceOrStatics(StorageStatics, Storage);
|
||||
this.utils = this._appNamespaceOrStatics(UtilsStatics, Utils);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstraps all native app instances that were discovered on boot
|
||||
* @private
|
||||
*/
|
||||
_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;
|
||||
INTERNALS.APPS[app.name] = new FirebaseApp(app.name, options);
|
||||
INTERNALS.APPS[app.name]._initializeApp(true);
|
||||
}
|
||||
this.firestore = APPS.moduleAndStatics('firestore', FirestoreStatics, Firestore);
|
||||
this.links = APPS.moduleAndStatics('links', LinksStatics, Links);
|
||||
this.messaging = APPS.moduleAndStatics('messaging', MessagingStatics, Messaging);
|
||||
this.perf = APPS.moduleAndStatics('perf', PerformanceStatics, Performance);
|
||||
this.storage = APPS.moduleAndStatics('storage', StorageStatics, Storage);
|
||||
this.utils = APPS.moduleAndStatics('utils', UtilsStatics, Utils);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,57 +89,7 @@ class FirebaseCore {
|
|||
* @return {*}
|
||||
*/
|
||||
initializeApp(options: FirebaseOptions, name: string): FirebaseApp {
|
||||
if (name && !isString(name)) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
|
||||
}
|
||||
|
||||
const _name = (name || INTERNALS.STRINGS.DEFAULT_APP_NAME).toUpperCase();
|
||||
|
||||
// return an existing app if found
|
||||
// todo in v4 remove deprecation and throw an error
|
||||
if (INTERNALS.APPS[_name]) {
|
||||
console.warn(INTERNALS.STRINGS.WARN_INITIALIZE_DEPRECATION);
|
||||
return INTERNALS.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'));
|
||||
}
|
||||
|
||||
INTERNALS.APPS[_name] = new FirebaseApp(_name, options);
|
||||
// only initialize if certain props are available
|
||||
if (options.databaseURL && options.apiKey) {
|
||||
INTERNALS.APPS[_name]._initializeApp();
|
||||
}
|
||||
|
||||
return INTERNALS.APPS[_name];
|
||||
return APPS.initializeApp(options, name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,10 +102,7 @@ class FirebaseCore {
|
|||
* @return {*}
|
||||
*/
|
||||
app(name?: string): FirebaseApp {
|
||||
const _name = name ? name.toUpperCase() : INTERNALS.STRINGS.DEFAULT_APP_NAME;
|
||||
const app = INTERNALS.APPS[_name];
|
||||
if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
|
||||
return app;
|
||||
return APPS.app(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,83 +110,7 @@ class FirebaseCore {
|
|||
* @return {Array}
|
||||
*/
|
||||
get apps(): Array<FirebaseApp> {
|
||||
return Object.values(INTERNALS.APPS);
|
||||
}
|
||||
|
||||
/*
|
||||
* INTERNALS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Subscribe to a native event for js side distribution by appName
|
||||
* React Native events are hard set at compile - cant do dynamic event names
|
||||
* so we use a single event send it to js and js then internally can prefix it
|
||||
* and distribute dynamically.
|
||||
*
|
||||
* @param eventName
|
||||
* @param nativeEmitter
|
||||
* @private
|
||||
*/
|
||||
_subscribeForDistribution(eventName: string, nativeEmitter: NativeEventEmitter) {
|
||||
if (!this._nativeSubscriptions[eventName]) {
|
||||
nativeEmitter.addListener(eventName, (event) => {
|
||||
if (event.appName) {
|
||||
// native event has an appName property - auto prefix and internally emit
|
||||
INTERNALS.SharedEventEmitter.emit(`${event.appName}-${eventName}`, event);
|
||||
} else {
|
||||
// standard event - no need to prefix
|
||||
INTERNALS.SharedEventEmitter.emit(eventName, event);
|
||||
}
|
||||
});
|
||||
|
||||
this._nativeSubscriptions[eventName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @return {function(FirebaseApp=)}
|
||||
* @private
|
||||
*/
|
||||
_appNamespaceOrStatics<M: FirebaseModule, S: FirebaseStatics>(statics: S, InstanceClass: Class<M>): FirebaseModuleAndStatics<M, S> {
|
||||
const namespace = InstanceClass._NAMESPACE;
|
||||
|
||||
const getNamespace = (app?: FirebaseApp) => {
|
||||
let _app = app;
|
||||
|
||||
// throw an error if it's not a valid app instance
|
||||
if (_app && !(_app instanceof FirebaseApp)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
|
||||
|
||||
// default to the 'DEFAULT' app if no arg provided - will throw an error
|
||||
// if default app not initialized
|
||||
else if (!_app) _app = this.app(INTERNALS.STRINGS.DEFAULT_APP_NAME);
|
||||
const firebaseApp = INTERNALS.APPS[_app._name];
|
||||
if (namespace === 'crashlytics') {
|
||||
return firebaseApp.fabric[namespace](_app);
|
||||
}
|
||||
return firebaseApp[namespace](_app);
|
||||
};
|
||||
|
||||
return Object.assign(getNamespace, statics, {
|
||||
nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @param nativeModule
|
||||
* @return {*}
|
||||
* @private
|
||||
*/
|
||||
_getOrSetNativeEmitter(name: string, nativeModule: Object): NativeEventEmitter {
|
||||
if (this._nativeEmitters[name]) {
|
||||
return this._nativeEmitters[name];
|
||||
}
|
||||
|
||||
return this._nativeEmitters[name] = new NativeEventEmitter(nativeModule);
|
||||
return APPS.apps();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import Query from './query.js';
|
||||
import Snapshot from './snapshot';
|
||||
import Disconnect from './disconnect';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import ReferenceBase from '../../utils/ReferenceBase';
|
||||
|
||||
import {
|
||||
|
@ -19,6 +20,7 @@ import {
|
|||
|
||||
import INTERNALS from '../../utils/internals';
|
||||
|
||||
import type Database from './';
|
||||
import type { DatabaseModifier, FirebaseError } from '../../types';
|
||||
import type SyncTree from '../../utils/SyncTree';
|
||||
|
||||
|
@ -73,18 +75,18 @@ type DatabaseListener = {
|
|||
* @extends ReferenceBase
|
||||
*/
|
||||
export default class Reference extends ReferenceBase {
|
||||
_database: Object;
|
||||
_database: Database;
|
||||
_promise: ?Promise<*>;
|
||||
_query: Query;
|
||||
_refListeners: { [listenerId: number]: DatabaseListener };
|
||||
|
||||
constructor(database: Object, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
||||
constructor(database: Database, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
||||
super(path, database);
|
||||
this._promise = null;
|
||||
this._refListeners = {};
|
||||
this._database = database;
|
||||
this._query = new Query(this, path, existingModifiers);
|
||||
this.log.debug('Created new Reference', this._getRefKey());
|
||||
getLogger(database).debug('Created new Reference', this._getRefKey());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -549,13 +551,6 @@ export default class Reference extends ReferenceBase {
|
|||
return `$${this._database._appName}$/${this.path}$${this._query.queryIdentifier()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return instance of db logger
|
||||
*/
|
||||
get log() {
|
||||
return this._database.log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the promise this 'thenable' reference relates to
|
||||
* @param promise
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* @flow
|
||||
* Database Transaction representation wrapper
|
||||
*/
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import type Database from './';
|
||||
|
||||
let transactionId = 0;
|
||||
|
@ -18,8 +20,8 @@ export default class TransactionHandler {
|
|||
this._transactions = {};
|
||||
this._database = database;
|
||||
|
||||
this._transactionListener = this._database.addListener(
|
||||
this._database._getAppEventName('database_transaction_event'),
|
||||
this._transactionListener = SharedEventEmitter.addListener(
|
||||
getAppEventName(this._database, 'database_transaction_event'),
|
||||
this._handleTransactionEvent.bind(this),
|
||||
);
|
||||
}
|
||||
|
@ -75,7 +77,7 @@ export default class TransactionHandler {
|
|||
case 'complete':
|
||||
return this._handleComplete(event);
|
||||
default:
|
||||
this.log.warn(`Unknown transaction event type: '${event.type}'`, event);
|
||||
getLogger(this._database).warn(`Unknown transaction event type: '${event.type}'`, event);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import CollectionReference from './CollectionReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import { buildNativeMap } from './utils/serialize';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { firestoreAutoId, isFunction, isObject, isString } from '../../utils';
|
||||
|
||||
import type Firestore from './';
|
||||
|
@ -136,15 +137,15 @@ export default class DocumentReference {
|
|||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`),
|
||||
listener,
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (observer.error) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`),
|
||||
observer.error,
|
||||
);
|
||||
}
|
||||
|
@ -197,8 +198,8 @@ export default class DocumentReference {
|
|||
*/
|
||||
_offDocumentSnapshot(listenerId: string, listener: Function) {
|
||||
this._firestore.log.info('Removing onDocumentSnapshot listener');
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshot:${listenerId}`), listener);
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onDocumentSnapshotError:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), listener);
|
||||
this._firestore._native
|
||||
.documentOffSnapshot(this.path, listenerId);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import QuerySnapshot from './QuerySnapshot';
|
||||
import { buildNativeArray, buildTypeMap } from './utils/serialize';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { firestoreAutoId, isFunction, isObject } from '../../utils';
|
||||
|
||||
import type Firestore from './';
|
||||
|
@ -206,15 +207,15 @@ export default class Query {
|
|||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`),
|
||||
listener,
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (observer.error) {
|
||||
this._firestore.on(
|
||||
this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`),
|
||||
observer.error,
|
||||
);
|
||||
}
|
||||
|
@ -335,8 +336,8 @@ export default class Query {
|
|||
*/
|
||||
_offCollectionSnapshot(listenerId: string, listener: Function) {
|
||||
this._firestore.log.info('Removing onQuerySnapshot listener');
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshot:${listenerId}`), listener);
|
||||
this._firestore.removeListener(this._firestore._getAppEventName(`onQuerySnapshotError:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), listener);
|
||||
this._firestore._native
|
||||
.collectionOffSnapshot(
|
||||
this._referencePath.relativeName,
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentReference from './DocumentReference';
|
||||
import FieldValue from './FieldValue';
|
||||
|
@ -33,7 +34,10 @@ type DocumentSyncEvent = {
|
|||
path: string,
|
||||
}
|
||||
|
||||
class FirestoreInternalModule extends ModuleBase {
|
||||
/**
|
||||
* @class Firestore
|
||||
*/
|
||||
export default class Firestore extends ModuleBase {
|
||||
static _NAMESPACE = 'firestore';
|
||||
static _NATIVE_MODULE = 'RNFirebaseFirestore';
|
||||
|
||||
|
@ -43,56 +47,21 @@ class FirestoreInternalModule extends ModuleBase {
|
|||
super(firebaseApp, options, true);
|
||||
this._referencePath = new Path([]);
|
||||
|
||||
super.addListener(
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onCollectionSnapshot
|
||||
super._getAppEventName('firestore_collection_sync_event'),
|
||||
getAppEventName(this, 'firestore_collection_sync_event'),
|
||||
this._onCollectionSyncEvent.bind(this),
|
||||
);
|
||||
|
||||
super.addListener(
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onDocumentSnapshot
|
||||
super._getAppEventName('firestore_document_sync_event'),
|
||||
getAppEventName(this, 'firestore_document_sync_event'),
|
||||
this._onDocumentSyncEvent.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal collection sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onCollectionSyncEvent(event: CollectionSyncEvent) {
|
||||
if (event.error) {
|
||||
this.emit(super._getAppEventName(`onQuerySnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
this.emit(super._getAppEventName(`onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal document sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onDocumentSyncEvent(event: DocumentSyncEvent) {
|
||||
if (event.error) {
|
||||
this.emit(super._getAppEventName(`onDocumentSnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
this.emit(super._getAppEventName(`onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Firestore
|
||||
*/
|
||||
export default class Firestore extends FirestoreInternalModule {
|
||||
constructor(firebaseApp: FirebaseApp, options: Object = {}) {
|
||||
super(firebaseApp, options);
|
||||
}
|
||||
|
||||
batch(): WriteBatch {
|
||||
return new WriteBatch(this);
|
||||
}
|
||||
|
@ -140,6 +109,32 @@ export default class Firestore extends FirestoreInternalModule {
|
|||
settings(): void {
|
||||
throw new Error('firebase.firestore().settings() coming soon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal collection sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onCollectionSyncEvent(event: CollectionSyncEvent) {
|
||||
if (event.error) {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal document sync listener
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onDocumentSyncEvent(event: DocumentSyncEvent) {
|
||||
if (event.error) {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshotError:${event.listenerId}`), event.error);
|
||||
} else {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const statics = {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
* @flow
|
||||
* Dynamic Links representation wrapper
|
||||
*/
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import { areObjectKeysContainedInOther, isObject, isString } from './../../utils';
|
||||
|
||||
import type FirebaseApp from '../core/firebase-app';
|
||||
|
@ -87,7 +88,7 @@ export default class Links extends ModuleBase {
|
|||
* @returns {Function}
|
||||
*/
|
||||
onLink(listener: Function): () => any {
|
||||
const rnListener = this._eventEmitter.addListener(EVENT_TYPE.Link, listener);
|
||||
const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.Link, listener);
|
||||
return () => rnListener.remove();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* Messaging representation wrapper
|
||||
*/
|
||||
import { Platform, NativeModules } from 'react-native';
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import RemoteMessage from './RemoteMessage';
|
||||
|
||||
import type FirebaseApp from '../core/firebase-app';
|
||||
|
@ -213,7 +214,7 @@ export default class Messaging extends ModuleBase {
|
|||
* @returns {*}
|
||||
*/
|
||||
onMessage(listener: (Object) => any): () => any {
|
||||
const rnListener = this._eventEmitter.addListener(
|
||||
const rnListener = SharedEventEmitter.addListener(
|
||||
EVENT_TYPE.Notification,
|
||||
async (event) => {
|
||||
const data = {
|
||||
|
@ -236,7 +237,7 @@ export default class Messaging extends ModuleBase {
|
|||
* @returns {*}
|
||||
*/
|
||||
onTokenRefresh(listener: (string) => any): () => any {
|
||||
const rnListener = this._eventEmitter.addListener(EVENT_TYPE.RefreshToken, listener);
|
||||
const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.RefreshToken, listener);
|
||||
return () => rnListener.remove();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
import { NativeModules } from 'react-native';
|
||||
|
||||
import StorageRef from './reference';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
import ModuleBase from './../../utils/ModuleBase';
|
||||
|
||||
import type FirebaseApp from '../core/firebase-app';
|
||||
|
@ -23,13 +25,13 @@ export default class Storage extends ModuleBase {
|
|||
constructor(firebaseApp: FirebaseApp, options: Object = {}) {
|
||||
super(firebaseApp, options, true);
|
||||
|
||||
this.addListener(
|
||||
this._getAppEventName('storage_event'),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'storage_event'),
|
||||
this._handleStorageEvent.bind(this),
|
||||
);
|
||||
|
||||
this.addListener(
|
||||
this._getAppEventName('storage_error'),
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'storage_error'),
|
||||
this._handleStorageEvent.bind(this),
|
||||
);
|
||||
}
|
||||
|
@ -86,31 +88,31 @@ export default class Storage extends ModuleBase {
|
|||
* INTERNALS
|
||||
*/
|
||||
_getSubEventName(path: string, eventName: string) {
|
||||
return this._getAppEventName(`${path}-${eventName}`);
|
||||
return getAppEventName(this, `${path}-${eventName}`);
|
||||
}
|
||||
|
||||
_handleStorageEvent(event: Object) {
|
||||
const { path, eventName } = event;
|
||||
const body = event.body || {};
|
||||
|
||||
this.log.debug('_handleStorageEvent: ', path, eventName, body);
|
||||
this.emit(this._getSubEventName(path, eventName), body);
|
||||
getLogger(this).debug('_handleStorageEvent: ', path, eventName, body);
|
||||
SharedEventEmitter.emit(this._getSubEventName(path, eventName), body);
|
||||
}
|
||||
|
||||
_handleStorageError(err: Object) {
|
||||
const { path, eventName } = err;
|
||||
const body = err.body || {};
|
||||
|
||||
this.log.debug('_handleStorageError ->', err);
|
||||
this.emit(this._getSubEventName(path, eventName), body);
|
||||
getLogger(this).debug('_handleStorageError ->', err);
|
||||
SharedEventEmitter.emit(this._getSubEventName(path, eventName), body);
|
||||
}
|
||||
|
||||
_addListener(path: string, eventName: string, cb: (evt: Object) => Object): void {
|
||||
this.on(this._getSubEventName(path, eventName), cb);
|
||||
SharedEventEmitter.addListener(this._getSubEventName(path, eventName), cb);
|
||||
}
|
||||
|
||||
_removeListener(path: string, eventName: string, origCB: (evt: Object) => Object): void {
|
||||
this.removeListener(this._getSubEventName(path, eventName), origCB);
|
||||
SharedEventEmitter.removeListener(this._getSubEventName(path, eventName), origCB);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,10 +63,6 @@ export default class RNFirebaseUtils extends ModuleBase {
|
|||
return FirebaseCoreModule.makePlayServicesAvailable();
|
||||
}
|
||||
|
||||
get sharedEventEmitter(): Object {
|
||||
return INTERNALS.SharedEventEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the global logging level for all logs.
|
||||
*
|
||||
|
|
|
@ -1,45 +1,12 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
import Log from './log';
|
||||
import INTERNALS from './internals';
|
||||
import FirebaseCore from '../modules/core/firebase';
|
||||
import { nativeWithApp } from '../utils';
|
||||
import { initialiseNativeModuleEventEmitter } from './events';
|
||||
import { getNativeModule, initialiseNativeModule } from './native';
|
||||
|
||||
import type FirebaseApp from '../modules/core/firebase-app';
|
||||
import type { FirebaseModuleName } from '../types';
|
||||
|
||||
const logs = {};
|
||||
|
||||
// Firebase Native SDKs that support multiple app instances
|
||||
const MULTI_APP_MODULES = [
|
||||
'auth',
|
||||
'database',
|
||||
'firestore',
|
||||
'storage',
|
||||
];
|
||||
|
||||
const NATIVE_MODULE_EVENTS = {
|
||||
Storage: [
|
||||
'storage_event',
|
||||
'storage_error',
|
||||
],
|
||||
Auth: [
|
||||
'auth_state_changed',
|
||||
'phone_auth_state_changed',
|
||||
],
|
||||
Database: [
|
||||
'database_transaction_event',
|
||||
// 'database_server_offset', // TODO
|
||||
],
|
||||
Firestore: [
|
||||
'firestore_collection_sync_event',
|
||||
'firestore_document_sync_event',
|
||||
],
|
||||
};
|
||||
|
||||
const DEFAULTS = {
|
||||
Database: {
|
||||
persistence: false,
|
||||
|
@ -53,7 +20,6 @@ export default class ModuleBase {
|
|||
_appName: string;
|
||||
_namespace: string;
|
||||
_firebaseApp: FirebaseApp;
|
||||
_eventEmitter: Object;
|
||||
static _NAMESPACE: FirebaseModuleName;
|
||||
static _NATIVE_MODULE: string;
|
||||
|
||||
|
@ -71,53 +37,15 @@ export default class ModuleBase {
|
|||
this._options = Object.assign({}, DEFAULTS[this._module] || {}, options);
|
||||
|
||||
// check if native module exists as all native
|
||||
// modules are now optionally part of build
|
||||
const nativeModule = NativeModules[this.constructor._NATIVE_MODULE];
|
||||
|
||||
if (!nativeModule && !this.constructor._NATIVE_DISABLED) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(this.constructor._NAMESPACE, this.constructor._NATIVE_MODULE));
|
||||
}
|
||||
|
||||
// used by the modules that extend ModuleBase
|
||||
// to access their native module counterpart
|
||||
if (!MULTI_APP_MODULES.includes(this._module.toLowerCase())) {
|
||||
this._native = nativeModule;
|
||||
} else {
|
||||
this._native = nativeWithApp(this._appName, nativeModule);
|
||||
}
|
||||
initialiseNativeModule(this);
|
||||
// TODO: Get rid of
|
||||
this._native = getNativeModule(this);
|
||||
|
||||
if (withEventEmitter) {
|
||||
this._setupEventEmitter(nativeModule, this._module);
|
||||
initialiseNativeModuleEventEmitter(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param nativeModule
|
||||
* @param moduleName
|
||||
* @private
|
||||
*/
|
||||
_setupEventEmitter(nativeModule: Object, moduleName: string) {
|
||||
this._eventEmitter = FirebaseCore._getOrSetNativeEmitter(`${this._appName}-${this._module}`, nativeModule);
|
||||
const events = NATIVE_MODULE_EVENTS[moduleName];
|
||||
|
||||
if (events && events.length) {
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
FirebaseCore._subscribeForDistribution(events[i], this._eventEmitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param eventName
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
_getAppEventName(eventName: string) {
|
||||
return `${this._appName}-${eventName}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FirebaseApp instance for current module
|
||||
* @return {*}
|
||||
|
@ -125,50 +53,4 @@ export default class ModuleBase {
|
|||
get app(): FirebaseApp {
|
||||
return this._firebaseApp;
|
||||
}
|
||||
|
||||
get log(): Log {
|
||||
if (logs[this._namespace]) return logs[this._namespace];
|
||||
return logs[this._namespace] = Log.createLogger(`🔥 ${this._namespace.toUpperCase()}`);
|
||||
}
|
||||
|
||||
/*
|
||||
* Proxy functions to shared event emitter instance
|
||||
* https://github.com/facebook/react-native/blob/master/Libraries/EventEmitter/EventEmitter.js
|
||||
*/
|
||||
get sharedEventEmitter(): Object {
|
||||
return INTERNALS.SharedEventEmitter;
|
||||
}
|
||||
|
||||
get addListener(): Function {
|
||||
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get once(): Function {
|
||||
return INTERNALS.SharedEventEmitter.once.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get on(): Function {
|
||||
return INTERNALS.SharedEventEmitter.addListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get emit(): Function {
|
||||
return INTERNALS.SharedEventEmitter.emit.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get listeners(): Function {
|
||||
return INTERNALS.SharedEventEmitter.listeners.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
hasListeners(eventType: string): Boolean {
|
||||
const subscriptions = INTERNALS.SharedEventEmitter._subscriber.getSubscriptionsForType(eventType);
|
||||
return subscriptions && subscriptions.length;
|
||||
}
|
||||
|
||||
get removeListener(): Function {
|
||||
return INTERNALS.SharedEventEmitter.removeListener.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
|
||||
get removeAllListeners(): Function {
|
||||
return INTERNALS.SharedEventEmitter.removeAllListeners.bind(INTERNALS.SharedEventEmitter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import Log from './log';
|
||||
|
||||
import type Database from '../modules/database';
|
||||
import type Storage from '../modules/storage';
|
||||
|
||||
|
@ -24,8 +22,4 @@ export default class ReferenceBase {
|
|||
get key(): string | null {
|
||||
return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
get log(): Log {
|
||||
return this._module.log;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
import { NativeEventEmitter } from 'react-native';
|
||||
|
||||
import INTERNALS from './internals';
|
||||
import { SharedEventEmitter } from './events';
|
||||
import DatabaseSnapshot from '../modules/database/snapshot';
|
||||
import DatabaseReference from '../modules/database/reference';
|
||||
import { isString, nativeToJSError } from '../utils';
|
||||
|
@ -77,7 +77,7 @@ export default class SyncTree {
|
|||
const { snapshot, previousChildName } = event.data;
|
||||
|
||||
// forward on to users .on(successCallback <-- listener
|
||||
return INTERNALS.SharedEventEmitter.emit(
|
||||
return SharedEventEmitter.emit(
|
||||
eventRegistrationKey,
|
||||
new DatabaseSnapshot(registration.ref, snapshot),
|
||||
previousChildName,
|
||||
|
@ -104,7 +104,7 @@ export default class SyncTree {
|
|||
const error = nativeToJSError(code, message, { ref: registration.ref });
|
||||
|
||||
// forward on to users .on(successCallback, cancellationCallback <-- listener
|
||||
INTERNALS.SharedEventEmitter.emit(registrationCancellationKey, error);
|
||||
SharedEventEmitter.emit(registrationCancellationKey, error);
|
||||
|
||||
// remove the paired event registration - if we received a cancellation
|
||||
// event then it's guaranteed that they'll be no further value events
|
||||
|
@ -131,14 +131,14 @@ export default class SyncTree {
|
|||
removeListenersForRegistrations(registrations: string | string[]) {
|
||||
if (isString(registrations)) {
|
||||
this.removeRegistration(registrations);
|
||||
INTERNALS.SharedEventEmitter.removeAllListeners(registrations);
|
||||
SharedEventEmitter.removeAllListeners(registrations);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Array.isArray(registrations)) return 0;
|
||||
for (let i = 0, len = registrations.length; i < len; i++) {
|
||||
this.removeRegistration(registrations[i]);
|
||||
INTERNALS.SharedEventEmitter.removeAllListeners(registrations[i]);
|
||||
SharedEventEmitter.removeAllListeners(registrations[i]);
|
||||
}
|
||||
|
||||
return registrations.length;
|
||||
|
@ -157,7 +157,7 @@ export default class SyncTree {
|
|||
|
||||
for (let i = 0, len = registrations.length; i < len; i++) {
|
||||
const registration = registrations[i];
|
||||
const subscriptions = INTERNALS.SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
|
||||
const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
|
||||
if (subscriptions) {
|
||||
for (let j = 0, l = subscriptions.length; j < l; j++) {
|
||||
const subscription = subscriptions[j];
|
||||
|
@ -251,12 +251,12 @@ export default class SyncTree {
|
|||
this._reverseLookup[eventRegistrationKey] = Object.assign({ listener }, parameters);
|
||||
|
||||
if (once) {
|
||||
INTERNALS.SharedEventEmitter.once(
|
||||
SharedEventEmitter.once(
|
||||
eventRegistrationKey,
|
||||
this._onOnceRemoveRegistration(eventRegistrationKey, listener),
|
||||
);
|
||||
} else {
|
||||
INTERNALS.SharedEventEmitter.addListener(eventRegistrationKey, listener);
|
||||
SharedEventEmitter.addListener(eventRegistrationKey, listener);
|
||||
}
|
||||
|
||||
return eventRegistrationKey;
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
import FirebaseApp from '../modules/core/firebase-app';
|
||||
import INTERNALS from './internals';
|
||||
import { isAndroid, isObject, isString } from './';
|
||||
|
||||
import type {
|
||||
FirebaseModule,
|
||||
FirebaseModuleAndStatics,
|
||||
FirebaseModuleName,
|
||||
FirebaseOptions,
|
||||
FirebaseStatics,
|
||||
} from '../types';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
const APPS: { [string]: FirebaseApp } = {};
|
||||
const APP_MODULES: { [FirebaseApp]: { [string]: FirebaseModule }} = {};
|
||||
|
||||
export default {
|
||||
app(name?: string): FirebaseApp {
|
||||
const _name = name ? name.toUpperCase() : INTERNALS.STRINGS.DEFAULT_APP_NAME;
|
||||
const app = APPS[_name];
|
||||
if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name));
|
||||
return app;
|
||||
},
|
||||
|
||||
apps(): Array<FirebaseApp> {
|
||||
return Object.values(APPS);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @return {function()}
|
||||
* @private
|
||||
*/
|
||||
appModule<M: FirebaseModule>(firebaseApp: FirebaseApp, moduleName: FirebaseModuleName, InstanceClass: Class<M>): () => FirebaseModule {
|
||||
return (): M => {
|
||||
if (!APP_MODULES[firebaseApp]) {
|
||||
APP_MODULES[firebaseApp] = {};
|
||||
}
|
||||
|
||||
if (isAndroid && moduleName !== 'utils' && !INTERNALS.FLAGS.checkedPlayServices) {
|
||||
INTERNALS.FLAGS.checkedPlayServices = true;
|
||||
this.utils().checkPlayServicesAvailability();
|
||||
}
|
||||
|
||||
if (!APP_MODULES[firebaseApp][moduleName]) {
|
||||
APP_MODULES[firebaseApp][moduleName] = new InstanceClass(firebaseApp, this._options);
|
||||
}
|
||||
|
||||
return APP_MODULES[firebaseApp][moduleName];
|
||||
};
|
||||
},
|
||||
|
||||
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): FirebaseApp {
|
||||
if (name && !isString(name)) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_INIT_STRING_NAME);
|
||||
}
|
||||
|
||||
const _name = (name || INTERNALS.STRINGS.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)
|
||||
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'));
|
||||
}
|
||||
|
||||
APPS[_name] = new FirebaseApp(_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 FirebaseApp(app.name, options, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param statics
|
||||
* @param InstanceClass
|
||||
* @return {function(FirebaseApp=)}
|
||||
*/
|
||||
moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(moduleName: FirebaseModuleName, statics: S, InstanceClass: Class<M>): FirebaseModuleAndStatics<M, S> {
|
||||
const getModule = (app?: FirebaseApp): FirebaseModule => {
|
||||
let firebaseApp = app;
|
||||
|
||||
// throw an error if it's not a valid app instance
|
||||
if (firebaseApp && !(firebaseApp instanceof FirebaseApp)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(moduleName));
|
||||
|
||||
// default to the 'DEFAULT' app if no arg provided - will throw an error
|
||||
// if default app not initialized
|
||||
else if (!firebaseApp) firebaseApp = this.app(INTERNALS.STRINGS.DEFAULT_APP_NAME);
|
||||
if (moduleName === 'crashlytics') {
|
||||
return firebaseApp.fabric[moduleName]();
|
||||
}
|
||||
const module = firebaseApp[moduleName];
|
||||
return module();
|
||||
};
|
||||
|
||||
return Object.assign(getModule, statics, {
|
||||
nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE],
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import { NativeEventEmitter } from 'react-native';
|
||||
import EventEmitter from './emitter/EventEmitter';
|
||||
import { getRawNativeModule } from './native';
|
||||
|
||||
import type ModuleBase from './ModuleBase';
|
||||
|
||||
const NATIVE_MODULE_EVENTS = {
|
||||
Storage: [
|
||||
'storage_event',
|
||||
'storage_error',
|
||||
],
|
||||
Auth: [
|
||||
'auth_state_changed',
|
||||
'phone_auth_state_changed',
|
||||
],
|
||||
Database: [
|
||||
'database_transaction_event',
|
||||
// 'database_server_offset', // TODO
|
||||
],
|
||||
Firestore: [
|
||||
'firestore_collection_sync_event',
|
||||
'firestore_document_sync_event',
|
||||
],
|
||||
};
|
||||
const NATIVE_EMITTERS: { [string]: NativeEventEmitter } = {};
|
||||
const NATIVE_SUBSCRIPTIONS: { [string]: boolean } = {};
|
||||
|
||||
export const SharedEventEmitter = new EventEmitter();
|
||||
|
||||
export const getAppEventName = (module: ModuleBase, eventName: string): string => {
|
||||
return `${module._firebaseApp._name}-${eventName}`;
|
||||
};
|
||||
|
||||
const getNativeEmitter = (module: ModuleBase): NativeEventEmitter => {
|
||||
const name = `${module._appName}-${module._module}`;
|
||||
const nativeModule = getRawNativeModule(module);
|
||||
if (!NATIVE_EMITTERS[name]) {
|
||||
NATIVE_EMITTERS[name] = new NativeEventEmitter(nativeModule);
|
||||
}
|
||||
return NATIVE_EMITTERS[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe to a native event for js side distribution by appName
|
||||
* React Native events are hard set at compile - cant do dynamic event names
|
||||
* so we use a single event send it to js and js then internally can prefix it
|
||||
* and distribute dynamically.
|
||||
*
|
||||
* @param module
|
||||
* @param eventName
|
||||
* @private
|
||||
*/
|
||||
const subscribeToNativeModuleEvents = (module: ModuleBase, eventName: string): void => {
|
||||
if (!NATIVE_SUBSCRIPTIONS[eventName]) {
|
||||
const nativeEmitter = getNativeEmitter(module);
|
||||
nativeEmitter.addListener(eventName, (event) => {
|
||||
if (event.appName) {
|
||||
// native event has an appName property - auto prefix and internally emit
|
||||
SharedEventEmitter.emit(`${event.appName}-${eventName}`, event);
|
||||
} else {
|
||||
// standard event - no need to prefix
|
||||
SharedEventEmitter.emit(eventName, event);
|
||||
}
|
||||
});
|
||||
|
||||
NATIVE_SUBSCRIPTIONS[eventName] = true;
|
||||
}
|
||||
};
|
||||
|
||||
export const initialiseNativeModuleEventEmitter = (module: ModuleBase): void => {
|
||||
const events = NATIVE_MODULE_EVENTS[module._module];
|
||||
|
||||
if (events && events.length) {
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
subscribeToNativeModuleEvents(module, events[i]);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -340,25 +340,6 @@ export function nativeToJSError(code: string, message: string, additionalProps?:
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends appName arg to all native method calls
|
||||
* @param appName
|
||||
* @param NativeModule
|
||||
*/
|
||||
export function nativeWithApp(appName: string, NativeModule: Object) {
|
||||
const native = {};
|
||||
const methods = Object.keys(NativeModule);
|
||||
|
||||
for (let i = 0, len = methods.length; i < len; i++) {
|
||||
const method = methods[i];
|
||||
native[method] = (...args) => {
|
||||
return NativeModule[method](...[appName, ...args]);
|
||||
};
|
||||
}
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
|
|
|
@ -3,12 +3,9 @@
|
|||
*/
|
||||
import { Platform, NativeModules } from 'react-native';
|
||||
|
||||
import EventEmitter from './emitter/EventEmitter';
|
||||
import ModuleBase from './ModuleBase';
|
||||
import SyncTree from './SyncTree';
|
||||
|
||||
import type FirebaseApp from '../modules/core/firebase-app';
|
||||
|
||||
const DEFAULT_APP_NAME = Platform.OS === 'ios' ? '__FIRAPP_DEFAULT' : '[DEFAULT]';
|
||||
|
||||
const NAMESPACE_PODS = {
|
||||
|
@ -55,8 +52,6 @@ const PLAY_SERVICES_CODES = {
|
|||
},
|
||||
};
|
||||
|
||||
const APPS: { [string]: FirebaseApp } = {};
|
||||
|
||||
export default {
|
||||
// default options
|
||||
OPTIONS: {
|
||||
|
@ -69,9 +64,6 @@ export default {
|
|||
checkedPlayServices: false,
|
||||
},
|
||||
|
||||
// track all initialized firebase apps
|
||||
APPS,
|
||||
|
||||
STRINGS: {
|
||||
WARN_INITIALIZE_DEPRECATION: 'Deprecation: Calling \'initializeApp()\' for apps that are already initialised natively ' +
|
||||
'is unnecessary, use \'firebase.app()\' instead to access the already initialized default app instance.',
|
||||
|
@ -227,19 +219,5 @@ export default {
|
|||
DEFAULT_APP_NAME,
|
||||
},
|
||||
|
||||
|
||||
SharedEventEmitter: new EventEmitter(),
|
||||
SyncTree: NativeModules.RNFirebaseDatabase ? new SyncTree(NativeModules.RNFirebaseDatabase) : null,
|
||||
|
||||
// internal utils
|
||||
deleteApp(name: String): Promise<boolean> {
|
||||
const app = this.APPS[name];
|
||||
if (!app) return Promise.resolve(true);
|
||||
|
||||
// https://firebase.google.com/docs/reference/js/firebase.app.App#delete
|
||||
return app.delete().then(() => {
|
||||
delete this.APPS[name];
|
||||
return true;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
/*
|
||||
* @flow
|
||||
*/
|
||||
import { windowOrGlobal } from './';
|
||||
|
||||
import type ModuleBase from './ModuleBase';
|
||||
|
||||
((base) => {
|
||||
window = base || window;
|
||||
if (!window.localStorage) window.localStorage = {};
|
||||
|
@ -7,6 +12,15 @@ import { windowOrGlobal } from './';
|
|||
|
||||
// clean up time
|
||||
|
||||
const NATIVE_LOGGERS: { [ModuleBase]: Object } = {};
|
||||
|
||||
export const getLogger = (module: ModuleBase) => {
|
||||
if (!NATIVE_LOGGERS[module]) {
|
||||
NATIVE_LOGGERS[module] = require('bows')(`🔥 ${module._namespace.toUpperCase()}`);
|
||||
}
|
||||
return NATIVE_LOGGERS[module];
|
||||
};
|
||||
|
||||
export default class Log {
|
||||
static createLogger(namespace) {
|
||||
return require('bows')(namespace);
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* @flow
|
||||
*/
|
||||
import { NativeModules } from 'react-native';
|
||||
import INTERNALS from './internals';
|
||||
|
||||
import type ModuleBase from './ModuleBase';
|
||||
|
||||
// Firebase Native SDKs that support multiple app instances
|
||||
const MULTI_APP_MODULES = [
|
||||
'auth',
|
||||
'database',
|
||||
'firestore',
|
||||
'storage',
|
||||
];
|
||||
|
||||
const NATIVE_MODULES: { [ModuleBase]: Object } = {};
|
||||
const RAW_NATIVE_MODULES: { [ModuleBase]: Object } = {};
|
||||
|
||||
/**
|
||||
* Prepends appName arg to all native method calls
|
||||
* @param appName
|
||||
* @param NativeModule
|
||||
*/
|
||||
const nativeWithApp = (appName: string, NativeModule: Object): Object => {
|
||||
const native = {};
|
||||
const methods = Object.keys(NativeModule);
|
||||
|
||||
for (let i = 0, len = methods.length; i < len; i++) {
|
||||
const method = methods[i];
|
||||
native[method] = (...args) => {
|
||||
return NativeModule[method](...[appName, ...args]);
|
||||
};
|
||||
}
|
||||
|
||||
return native;
|
||||
};
|
||||
|
||||
export const getNativeModule = (module: ModuleBase): Object => {
|
||||
return NATIVE_MODULES[module];
|
||||
};
|
||||
|
||||
export const getRawNativeModule = (module: ModuleBase): Object => {
|
||||
return RAW_NATIVE_MODULES[module];
|
||||
};
|
||||
|
||||
export const initialiseNativeModule = (module: ModuleBase): void => {
|
||||
const nativeModule = NativeModules[module.constructor._NATIVE_MODULE];
|
||||
|
||||
if (!nativeModule && !module.constructor._NATIVE_DISABLED) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(module.constructor._NAMESPACE, module.constructor._NATIVE_MODULE));
|
||||
}
|
||||
|
||||
// used by the modules that extend ModuleBase
|
||||
// to access their native module counterpart
|
||||
RAW_NATIVE_MODULES[module] = nativeModule;
|
||||
if (!MULTI_APP_MODULES.includes(module._module.toLowerCase())) {
|
||||
NATIVE_MODULES[module] = nativeModule;
|
||||
} else {
|
||||
NATIVE_MODULES[module] = nativeWithApp(module._appName, nativeModule);
|
||||
}
|
||||
};
|
|
@ -153,7 +153,7 @@ PODS:
|
|||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
- RNFirebase (3.1.1):
|
||||
- RNFirebase (3.2.0):
|
||||
- React
|
||||
- yoga (0.49.1.React)
|
||||
|
||||
|
@ -215,7 +215,7 @@ SPEC CHECKSUMS:
|
|||
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
||||
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
||||
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
|
||||
RNFirebase: 976f3b35d112017c69da5ada20cf1f15fc2c327e
|
||||
RNFirebase: 22b1917fec663706907bc901ed665ac4f8b9bfd6
|
||||
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
|
||||
|
||||
PODFILE CHECKSUM: f17a538903249834df5049668d10174810db4c4c
|
||||
|
|
|
@ -40,7 +40,7 @@ const ios = {
|
|||
|
||||
const instances = {
|
||||
web: firebase.initializeApp(config),
|
||||
native: RNfirebase.app(),
|
||||
native: RNfirebase,
|
||||
another: RNfirebase.initializeApp(Platform.OS === 'ios' ? ios : android, 'anotherApp'),
|
||||
};
|
||||
|
||||
|
|
|
@ -53,8 +53,7 @@ function coreTests({ describe, it }) {
|
|||
|
||||
it('it should provide an array of apps', () => {
|
||||
should.equal(!!RNFirebase.apps.length, true);
|
||||
should.equal(RNFirebase.apps[0]._name, RNFirebase.utils.DEFAULT_APP_NAME);
|
||||
should.equal(RNFirebase.apps[0].name, '[DEFAULT]');
|
||||
should.equal(RNFirebase.apps.includes(RNFirebase.app(RNFirebase.utils.DEFAULT_APP_NAME)), true);
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue