diff --git a/bridge/.babelrc b/bridge/.babelrc index 160a9c97..fca4ef15 100644 --- a/bridge/.babelrc +++ b/bridge/.babelrc @@ -9,8 +9,16 @@ "useInlineSourceMaps": true, "instrument": true, "include": [ - "firebase" + "lib/*" + ], + "exclude": [ + "node_modules" ] + }], + ["module-resolver", { + "alias": { + "react-native-firebase": ".." + } }] ] } diff --git a/bridge/app.js b/bridge/app.js index f5ccf182..f88ac5e0 100755 --- a/bridge/app.js +++ b/bridge/app.js @@ -10,7 +10,7 @@ import React, { Component } from 'react'; import { AppRegistry, Text, View } from 'react-native'; import bridge from 'bridge/platform/react-native'; -import firebase from './firebase'; +import firebase from 'react-native-firebase'; require('sinon'); require('should-sinon'); diff --git a/bridge/e2e/auth/module.e2e.js b/bridge/e2e/auth/module.e2e.js index 0f0397b5..a6ac3050 100644 --- a/bridge/e2e/auth/module.e2e.js +++ b/bridge/e2e/auth/module.e2e.js @@ -1,9 +1,4 @@ describe('.auth()', () => { - beforeEach(async () => { - await device.reloadReactNative(); - // bridge.root.setState({ message: this.currentTest.title }); - }); - describe('.signInAnonymously()', () => { it('it should sign in anonymously', () => { const successCb = currentUser => { @@ -13,9 +8,7 @@ describe('.auth()', () => { should.equal(currentUser.toJSON().email, null); currentUser.isAnonymous.should.equal(true); currentUser.providerId.should.equal('firebase'); - currentUser.should.equal(firebase.auth().currentUser); - return firebase.auth().signOut(); }; diff --git a/bridge/e2e/bridge.spec.js b/bridge/e2e/bridge.spec.js index 782d6eb0..249635f5 100755 --- a/bridge/e2e/bridge.spec.js +++ b/bridge/e2e/bridge.spec.js @@ -2,7 +2,7 @@ const should = require('should'); describe('bridge', () => { beforeEach(async function beforeEach() { - await device.reloadReactNative(); + // await device.reloadReactNative(); bridge.root.setState({ message: this.currentTest.title }); }); diff --git a/bridge/e2e/mocha.opts b/bridge/e2e/mocha.opts index 41cc1066..c389abcc 100755 --- a/bridge/e2e/mocha.opts +++ b/bridge/e2e/mocha.opts @@ -1,6 +1,6 @@ --recursive --timeout 120000 ---slow 2200 +--slow 750 --bail --exit --require bridge/platform/node diff --git a/bridge/firebase/firebase-app.js b/bridge/firebase/firebase-app.js deleted file mode 100644 index ae1a254d..00000000 --- a/bridge/firebase/firebase-app.js +++ /dev/null @@ -1,175 +0,0 @@ -import { NativeModules } from 'react-native'; - -import INTERNALS from './internals'; -import { isObject, isAndroid } from './utils'; - -import AdMob, { statics as AdMobStatics } from './modules/admob'; -import Auth, { statics as AuthStatics } from './modules/auth'; -import Analytics from './modules/analytics'; -import Crash from './modules/crash'; -import Performance from './modules/perf'; -import RemoteConfig from './modules/config'; -import Storage, { statics as StorageStatics } from './modules/storage'; -import Database, { statics as DatabaseStatics } from './modules/database'; -import Messaging, { statics as MessagingStatics } from './modules/messaging'; -import Firestore, { statics as FirestoreStatics } from './modules/firestore'; -import Links, { statics as LinksStatics } from './modules/links'; -import Utils, { statics as UtilsStatics } from './modules/utils'; - -const FirebaseCoreModule = NativeModules.RNFirebase; - -export default class FirebaseApp { - constructor(name: string, options: Object = {}) { - 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.auth = this._staticsOrModuleInstance(AuthStatics, Auth); - this.analytics = this._staticsOrModuleInstance({}, Analytics); - this.config = this._staticsOrModuleInstance({}, RemoteConfig); - this.crash = this._staticsOrModuleInstance({}, Crash); - this.database = this._staticsOrModuleInstance(DatabaseStatics, Database); - this.firestore = this._staticsOrModuleInstance(FirestoreStatics, Firestore); - this.links = this._staticsOrModuleInstance(LinksStatics, Links); - this.messaging = this._staticsOrModuleInstance(MessagingStatics, Messaging); - this.perf = this._staticsOrModuleInstance({}, Performance); - this.storage = this._staticsOrModuleInstance(StorageStatics, Storage); - this.utils = this._staticsOrModuleInstance(UtilsStatics, Utils); - this._extendedProps = {}; - } - - /** - * - * @param native - * @private - */ - _initializeApp(native = false) { - if (native) { - // for apps already initialized natively that - // we have info from RN constants - this._initialized = true; - this._nativeInitialized = true; - } else { - FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => { - this._initialized = true; - INTERNALS.SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result }); - }); - } - } - - /** - * - * @return {*} - */ - get name() { - if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME) { - // ios and android firebase sdk's return different - // app names - so we just return what the web sdk - // would if it was default. - return '[DEFAULT]'; - } - - return this._name; - } - - /** - * - * @return {*} - */ - get options() { - return Object.assign({}, this._options); - } - - /** - * Undocumented firebase web sdk method that allows adding additional properties onto - * a firebase app instance. - * - * See: https://github.com/firebase/firebase-js-sdk/blob/master/tests/app/firebase_app.test.ts#L328 - * - * @param props - */ - extendApp(props: Object) { - if (!isObject(props)) throw new Error(INTERNALS.ERROR_MISSING_ARG('Object', 'extendApp')); - const keys = Object.keys(props); - - for (let i = 0, len = keys.length; i < len; i++) { - const key = keys[i]; - - if (!this._extendedProps[key] && Object.hasOwnProperty.call(this, key)) { - throw new Error(INTERNALS.ERROR_PROTECTED_PROP(key)); - } - - this[key] = props[key]; - this._extendedProps[key] = true; - } - } - - /** - * - * @return {Promise} - */ - delete() { - throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete')); - // TODO only the ios sdk currently supports delete, add back in when android also supports it - // if (this._name === INTERNALS.STRINGS.DEFAULT_APP_NAME && this._nativeInitialized) { - // return Promise.reject( - // new Error('Unable to delete the default native firebase app instance.'), - // ); - // } - // - // return FirebaseCoreModule.deleteApp(this._name); - } - - - /** - * - * @return {*} - */ - onReady(): Promise { - if (this._initialized) return Promise.resolve(this); - - return new Promise((resolve, reject) => { - INTERNALS.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 name - * @param statics - * @param InstanceClass - * @return {function()} - * @private - */ - _staticsOrModuleInstance(statics = {}, InstanceClass): Function { - const getInstance = () => { - 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]; - }; - - Object.assign(getInstance, statics, { - nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE], - }); - - return getInstance; - } -} diff --git a/bridge/firebase/firebase.js b/bridge/firebase/firebase.js deleted file mode 100644 index 1cfc1afb..00000000 --- a/bridge/firebase/firebase.js +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @providesModule Firebase - * @flow - */ -import { NativeModules, NativeEventEmitter } from 'react-native'; - -import INTERNALS from './internals'; -import FirebaseApp from './firebase-app'; -import { isObject, isString, isAndroid } from './utils'; - -// module imports -import AdMob, { statics as AdMobStatics } from './modules/admob'; -import Auth, { statics as AuthStatics } from './modules/auth'; -import Analytics from './modules/analytics'; -import Crash from './modules/crash'; -import Performance from './modules/perf'; -import Links, { statics as LinksStatics } from './modules/links'; -import RemoteConfig from './modules/config'; -import Storage, { statics as StorageStatics } from './modules/storage'; -import Database, { statics as DatabaseStatics } from './modules/database'; -import Messaging, { statics as MessagingStatics } from './modules/messaging'; -import Firestore, { statics as FirestoreStatics } from './modules/firestore'; -import Utils, { statics as UtilsStatics } from './modules/utils'; - -const FirebaseCoreModule = NativeModules.RNFirebase; - -class FirebaseCore { - constructor() { - this._nativeEmitters = {}; - this._nativeSubscriptions = {}; - - if (!FirebaseCoreModule) { - throw (new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE)); - } - - this._initializeNativeApps(); - - // modules - this.admob = this._appNamespaceOrStatics(AdMobStatics, AdMob); - this.auth = this._appNamespaceOrStatics(AuthStatics, Auth); - this.analytics = this._appNamespaceOrStatics({}, Analytics); - this.config = this._appNamespaceOrStatics({}, RemoteConfig); - this.crash = this._appNamespaceOrStatics({}, Crash); - this.database = this._appNamespaceOrStatics(DatabaseStatics, Database); - this.firestore = this._appNamespaceOrStatics(FirestoreStatics, Firestore); - this.links = this._appNamespaceOrStatics(LinksStatics, Links); - this.messaging = this._appNamespaceOrStatics(MessagingStatics, Messaging); - this.perf = this._appNamespaceOrStatics(DatabaseStatics, 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); - } - } - - /** - * Web SDK initializeApp - * - * @param options - * @param name - * @return {*} - */ - initializeApp(options: Object = {}, 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]; - } - - /** - * Retrieves a Firebase app instance. - * - * When called with no arguments, the default app is returned. - * When an app name is provided, the app corresponding to that name is returned. - * - * @param name - * @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; - } - - /** - * A (read-only) array of all initialized apps. - * @return {Array} - */ - get apps(): Array { - 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, nativeEmitter) { - 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(statics = {}, InstanceClass): Function { - 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); - return INTERNALS.APPS[_app._name][namespace](_app); - }; - - Object.assign(getNamespace, statics, { - nativeModuleExists: !!NativeModules[InstanceClass._NATIVE_MODULE], - }); - - return getNamespace; - } - - /** - * - * @param name - * @param nativeModule - * @return {*} - * @private - */ - _getOrSetNativeEmitter(name, nativeModule) { - if (this._nativeEmitters[name]) { - return this._nativeEmitters[name]; - } - - return this._nativeEmitters[name] = new NativeEventEmitter(nativeModule); - } - -} - -export default new FirebaseCore(); diff --git a/bridge/firebase/flow.js b/bridge/firebase/flow.js deleted file mode 100644 index f5295758..00000000 --- a/bridge/firebase/flow.js +++ /dev/null @@ -1,50 +0,0 @@ -/* eslint-disable */ -// declare module 'react-native' { -// // noinspection ES6ConvertVarToLetConst -// declare var exports: any; -// } - -declare type AuthResultType = { - authenticated: boolean, - user: Object|null -} | null; - -declare type CredentialType = { - providerId: string, - token: string, - secret: string -}; - -declare type DatabaseListener = { - listenerId: number; - eventName: string; - successCallback: Function; - failureCallback?: Function; -}; - -declare type DatabaseModifier = { - type: 'orderBy' | 'limit' | 'filter'; - name?: string; - key?: string; - limit?: number; - value?: any; - valueType?: string; -}; - -declare type GoogleApiAvailabilityType = { - status: number, - isAvailable: boolean, - isUserResolvableError?: boolean, - hasResolution?: boolean, - error?: string -}; - -declare class FirebaseError { - message: string, - name: string, - code: string, - stack: string, - path: string, - details: string, - modifiers: string -}; diff --git a/bridge/firebase/index.d.ts b/bridge/firebase/index.d.ts deleted file mode 100644 index 205580ac..00000000 --- a/bridge/firebase/index.d.ts +++ /dev/null @@ -1,1368 +0,0 @@ -// Type definitions for React Native Firebase v1.0.0-alpha7 -// Project: https://github.com/invertase/react-native-firebase -// Definitions by: Tal -// TypeScript Version: 2.1 - -declare module "react-native-firebase" { - - /** 3rd party provider Credentials */ - type AuthCredential = { - providerId: string, - token: string, - secret: string - } - - type FirebaseModuleAndStatics = { - (): M; - nativeModuleExists: boolean; - } & S - - // Modules commented-out do not currently have type definitions - export class Firebase { - private constructor(); - // admob: FirebaseModuleAndStatics; - analytics: FirebaseModuleAndStatics; - auth: FirebaseModuleAndStatics; - // config: FirebaseModule; - crash: FirebaseModuleAndStatics; - database: FirebaseModuleAndStatics; - fabric: { - crashlytics: FirebaseModuleAndStatics; - }; - firestore: FirebaseModuleAndStatics; - links: FirebaseModuleAndStatics; - messaging: FirebaseModuleAndStatics; - // perf: FirebaseModuleAndStatics; - storage: FirebaseModuleAndStatics; - // utils: FirebaseModuleAndStatics; - initializeApp(options: Firebase.Options, name: string): App; - app(name?: string): App; - readonly apps: App[]; - readonly SDK_VERSION: string; - } - namespace Firebase { - interface Options { - apiKey: string; - appId: string; - databaseURL: string; - messagingSenderId: string; - projectId: string; - storageBucket: string; - } - } - const firebase: Firebase; - export default firebase; - - // Modules commented-out do not currently have type definitions - export class App { - private constructor(); - // admob(): RNFirebase.admob.AdMob; - analytics(): RNFirebase.Analytics; - auth(): RNFirebase.auth.Auth; - // config(): RNFirebase.config.Config; - crash(): RNFirebase.crash.Crash; - database(): RNFirebase.database.Database; - fabric: { - crashlytics(): RNFirebase.crashlytics.Crashlytics, - }; - firestore(): RNFirebase.firestore.Firestore; - links(): RNFirebase.links.Links; - messaging(): RNFirebase.messaging.Messaging; - // perf(): RNFirebase.perf.Performance; - storage(): RNFirebase.storage.Storage; - // utils(): RNFirebase.utils.Utils; - readonly name: string; - readonly options: Firebase.Options; - } - - export namespace RNFirebase { - interface RnError extends Error { - code?: string; - } - - type GoogleApiAvailabilityType = { - status: number, - isAvailable: boolean, - isUserResolvableError?: boolean, - error?: string - }; - - /** - * pass custom options by passing an object with configuration options. - * The configuration object will be generated first by the native configuration object, if set and then will be overridden if passed in JS. - * That is, all of the following key/value pairs are optional if the native configuration is set. - */ - interface configurationOptions { - /** - * default false - * When set to true, RNFirebase will log messages to the console and fire debug events we can listen to in js - * @usage - * firebase.on('debug', msg => console.log('Received debug message', msg)) - */ - debug?: boolean; - /** - * default false - * When set to true, database persistence will be enabled. - */ - persistence?: boolean; - /** - * Default from app [NSBundle mainBundle] The bundle ID for the app to be bundled with - */ - bundleID?: string; - /** - * defualt "" - * The Google App ID that is used to uniquely identify an instance of an app. - */ - googleAppID?: string; - /** - * deufalt "" - * The database root (i.e. https://my-app.firebaseio.com) - */ - databaseURL?: string; - /** - * defualt "" - * URL scheme to set up durable deep link service - */ - deepLinkURLScheme?: string; - /** - * defualt "" - * The Google Cloud storage bucket name - */ - storageBucket?: string; - /** - * default "" - * The Android client ID used in Google AppInvite when an iOS app has it's android version - */ - androidClientID?: string; - /** - * default "" - * The Project number from the Google Developer's console used to configure Google Cloud Messaging - */ - GCMSenderID?: string; - /** - * default "" - * The tracking ID for Google Analytics - */ - trackingID?: string; - /** - * default "" - * The OAuth2 client ID for iOS application used to authenticate Google Users for signing in with Google - */ - clientID?: string; - /** - * defualt "" - * The secret iOS API key used for authenticating requests from our app - */ - APIKey?: string - } - - namespace storage { - - interface StorageTask extends Promise { - on(event: TaskEvent, - nextOrObserver: (snapshot: any) => any, - error: (error: RnError) => any, - complete: (complete: any) => any): any - - /** - * is not currently supported by react-native-firebase - */ - pause(): void - - /** - * is not currently supported by react-native-firebase - */ - resume(): void - - /** - * is not currently supported by react-native-firebase - */ - cancel(): void - - } - - interface RNStorage extends Reference { - /** - * Downloads a reference to the device - * @param {String} filePath Where to store the file - * @return {Promise} - * */ - downloadFile(filePath: string): StorageTask; - - /** - * Upload a file path - * @returns {Promise} - */ - putFile(filePath: string, metadata?: any): StorageTask; - - setMaxDownloadRetryTime(time: number): void - - [key: string]: any; - } - - interface Storage { - maxOperationRetryTime: number; - maxUploadRetryTime: number; - - ref(path?: string): storage.RNStorage; - - refFromURL(url: string): storage.RNStorage; - - setMaxOperationRetryTime(time: number): any; - - setMaxUploadRetryTime(time: number): any; - } - - interface Reference { - bucket: string; - - child(path: string): storage.Reference; - - delete(): Promise; - - fullPath: string; - - getDownloadURL(): Promise; - - getMetadata(): Promise; - - name: string; - parent: storage.Reference | null; - - put(data: any | Uint8Array | ArrayBuffer, - metadata?: storage.UploadMetadata): storage.UploadTask; - - putString(data: string, format?: storage.StringFormat, - metadata?: storage.UploadMetadata): storage.UploadTask; - - root: storage.Reference; - storage: storage.Storage; - - toString(): string; - - updateMetadata(metadata: storage.SettableMetadata): Promise; - } - - interface UploadMetadata extends storage.SettableMetadata { - md5Hash?: string | null; - } - - interface SettableMetadata { - cacheControl?: string | null; - contentDisposition?: string | null; - contentEncoding?: string | null; - contentLanguage?: string | null; - contentType?: string | null; - customMetadata?: { [/* warning: coerced from ? */ key: string]: string } | null; - } - - type StringFormat = string; - var StringFormat: { - BASE64: StringFormat, - BASE64URL: StringFormat, - DATA_URL: StringFormat, - RAW: StringFormat, - } - - interface UploadTask { - cancel(): boolean; - - catch(onRejected: (a: RnError) => any): Promise; - - on(event: storage.TaskEvent, nextOrObserver?: null | Object, - error?: ((a: RnError) => any) | null, complete?: (() => any) | null): Function; - - pause(): boolean; - - resume(): boolean; - - snapshot: storage.UploadTaskSnapshot; - - then(onFulfilled?: ((a: storage.UploadTaskSnapshot) => any) | null, - onRejected?: ((a: RnError) => any) | null): Promise; - } - - interface UploadTaskSnapshot { - bytesTransferred: number; - downloadURL: string | null; - metadata: storage.FullMetadata; - ref: storage.Reference; - state: storage.TaskState; - task: storage.UploadTask; - totalBytes: number; - } - - interface FullMetadata extends storage.UploadMetadata { - bucket: string; - downloadURLs: string[]; - fullPath: string; - generation: string; - metageneration: string; - name: string; - size: number; - timeCreated: string; - updated: string; - } - - type TaskEvent = string; - var TaskEvent: { - STATE_CHANGED: TaskEvent, - }; - - type TaskState = string; - var TaskState: { - CANCELED: TaskState, - ERROR: TaskState, - PAUSED: TaskState, - RUNNING: TaskState, - SUCCESS: TaskState, - }; - } - - - namespace database { - - - interface Database { - /** - * Returns a new firebase reference instance - * */ - ref(path?: string): RnReference - - /** - * register listener - */ - on(path: string, modifiersString: string, modifiers: Array, eventName: string, cb: () => void, errorCb: () => void): any - - /** - * unregister listener - */ - off(path: string, modifiersString: string, eventName?: string, origCB?: () => void): any - - /** - * Removes all event handlers and their native subscriptions - */ - cleanup(): Promise - - /** - * connect to firebase backend - */ - goOnline(): void - - /** - * disconnect to firebase backend - */ - goOffline(): void - - [key: string]: any; - } - - interface RnReference extends Reference { - keepSynced(bool: boolean): any - - filter(name: string, value: any, key?: string): any; - - [key: string]: any; - } - - type QueryEventType = "value" | "child_added" | "child_removed" | "child_changed" | "child_moved"; - type QuerySuccessCallback = (snapshot: DataSnapshot, previousChildId?: string | null) => void; - type QueryErrorCallback = (e: Error) => void; - - interface Query { - endAt(value: number | string | boolean | null, key?: string): database.Query; - - equalTo(value: number | string | boolean | null, key?: string): database.Query; - - isEqual(other: database.Query | null): boolean; - - limitToFirst(limit: number): database.Query; - - limitToLast(limit: number): database.Query; - - off(eventType?: QueryEventType, - callback?: QuerySuccessCallback, - context?: Object): void; - - on(eventType: QueryEventType, - callback: QuerySuccessCallback, - cancelCallbackOrContext?: QueryErrorCallback, - context?: Object): (a: database.DataSnapshot | null, b?: string) => QuerySuccessCallback; - - once(eventType: QueryEventType, - successCallback?: QuerySuccessCallback, - failureCallbackOrContext?: QueryErrorCallback, - context?: Object): Promise; - - orderByChild(path: string): database.Query; - - orderByKey(): database.Query; - - orderByPriority(): database.Query; - - orderByValue(): database.Query; - - ref: database.Reference; - - startAt(value: number | string | boolean | null, key?: string): database.Query; - - toJSON(): Object; - - toString(): string; - } - - interface DataSnapshot { - child(path: string): database.DataSnapshot; - - exists(): boolean; - - exportVal(): any; - - forEach(action: (a: database.DataSnapshot) => boolean): boolean; - - getPriority(): string | number | null; - - hasChild(path: string): boolean; - - hasChildren(): boolean; - - key: string | null; - - numChildren(): number; - - ref: database.Reference; - - toJSON(): Object | null; - - val(): any; - } - - interface ThenableReference extends Promise { - } - - interface ThenableReference extends Reference { - } - - interface Reference extends database.Query { - child(path: string): database.Reference; - - key: string | null; - - onDisconnect(): any; - - parent: database.Reference | null; - - push(value?: any, onComplete?: (a: RnError | null) => any): ThenableReference - - remove(onComplete?: (a: RnError | null) => any): Promise; - - root: database.Reference; - - set(value: any, onComplete?: (a: RnError | null) => any): Promise; - - setPriority(priority: string | number | null, - onComplete: (a: RnError | null) => any): Promise; - - setWithPriority(newVal: any, newPriority: string | number | null, - onComplete?: (a: RnError | null) => any): Promise; - - transaction(transactionUpdate: (a: any) => any, - onComplete?: (a: RnError | null, b: boolean, - c: database.DataSnapshot | null) => any, - applyLocally?: boolean): Promise; - - update(values: Object, onComplete?: (a: RnError | null) => any): Promise; - } - - interface DatabaseStatics { - /** @see https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/ServerValue.html#TIMESTAMP */ - ServerValue: { - TIMESTAMP: { - [key: string]: string - } - } - } - } - - /** - * firebase Analytics - */ - interface Analytics { - /**Log a custom event with optional params. */ - logEvent(event: string, params?: Object): void - - /** Sets whether analytics collection is enabled for this app on this device. */ - setAnalyticsCollectionEnabled(enabled: boolean): void - - /** - * Sets the current screen name, which specifies the current visual context in your app. - * Whilst screenClassOverride is optional, - * it is recommended it is always sent as your current class name, - * for example on Android it will always show as 'MainActivity' if not specified. - */ - setCurrentScreen(screenName: string | null, screenClassOverride?: string): void - - /** - * Sets the minimum engagement time required before starting a session. - * The default value is 10000 (10 seconds) - */ - setMinimumSessionDuration(miliseconds: number): void - - /** - * Sets the duration of inactivity that terminates the current session. - * The default value is 1800000 (30 minutes). - */ - setSessionTimeoutDuration(miliseconds: number): void - - /** - * Gives a user a uniqiue identificaition. - * @example - * const id = firebase.auth().currentUser.uid; - * - * firebase.analytics().setUserId(id); - */ - setUserId(id: string | null): void - - /** - * Sets a key/value pair of data on the current user. - */ - setUserProperty(name: string, value: string | null): void; - - [key: string]: any; - } - - type AdditionalUserInfo = { - isNewUser: boolean, - profile?: Object, - providerId: string, - username?: string, - } - - type UserCredential = { - additionalUserInfo?: AdditionalUserInfo, - user: User, - } - - type UserInfo = { - displayName?: string, - email?: string, - phoneNumber?: string, - photoURL?: string, - providerId: string, - uid: string, - } - - type UpdateProfile = { - displayName?: string, - photoURL?: string, - } - - type UserMetadata = { - creationTime?: string, - lastSignInTime?: string, - } - - interface User { - /** - * The user's display name (if available). - */ - displayName: string | null - /** - * - The user's email address (if available). - */ - email: string | null - /** - * - True if the user's email address has been verified. - */ - emailVerified: boolean - /** - * - */ - isAnonymous: boolean - - metadata: UserMetadata - - phoneNumber: string | null - /** - * - The URL of the user's profile picture (if available). - */ - photoURL: string | null - /** - * - Additional provider-specific information about the user. - */ - providerData: Array - /** - * - The authentication provider ID for the current user. - * For example, 'facebook.com', or 'google.com'. - */ - providerId: string - /** - * - The user's unique ID. - */ - uid: string - - /** - * Delete the current user. - */ - delete(): Promise - - /** - * Returns the users authentication token. - * - * @param forceRefresh: boolean - default to false - */ - getIdToken(forceRefresh?: boolean): Promise - - getToken(forceRefresh?: boolean): Promise - - linkAndRetrieveDataWithCredential(credential: AuthCredential): Promise - - /** - * Link the user with a 3rd party credential provider. - */ - linkWithCredential(credential: AuthCredential): Promise - - reauthenticateAndRetrieveDataWithCredential(credential: AuthCredential): Promise - - /** - * Re-authenticate a user with a third-party authentication provider - */ - reauthenticateWithCredential(credential: AuthCredential): Promise - - /** - * Refreshes the current user. - */ - reload(): Promise - - /** - * Sends a verification email to a user. - * This will Promise reject is the user is anonymous. - */ - sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise - - toJSON(): object - - unlink(providerId: string): Promise - - /** - * Updates the user's email address. - * See Firebase docs for more information on security & email validation. - * This will Promise reject is the user is anonymous. - */ - updateEmail(email: string): Promise - - /** - * Important: this is a security sensitive operation that requires the user to have recently signed in. - * If this requirement isn't met, ask the user to authenticate again and then call firebase.User#reauthenticate. - * This will Promise reject is the user is anonymous. - */ - updatePassword(password: string): Promise - - /** - * Updates a user's profile data. - * Profile data should be an object of fields to update: - */ - updateProfile(updates: UpdateProfile): Promise - } - - type ActionCodeSettings = { - android: { - installApp?: boolean, - minimumVersion?: string, - packageName: string, - }, - handleCodeInApp?: boolean, - iOS: { - bundleId?: string, - }, - url: string, - } - - interface ActionCodeInfo { - data: { - email?: string, - fromEmail?: string - }, - operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL' - } - - interface ConfirmationResult { - - confirm(verificationCode: string): Promise; - - verificationId: string | null; - } - - type PhoneAuthSnapshot = { - state: 'sent' | 'timeout' | 'verified' | 'error', - verificationId: string, - code: string | null, - error: Error | null, - }; - - type PhoneAuthError = { - code: string | null, - verificationId: string, - message: string | null, - stack: string | null, - }; - - interface PhoneAuthListener { - - on(event: string, - observer: () => PhoneAuthSnapshot, - errorCb?: () => PhoneAuthError, - successCb?: () => PhoneAuthSnapshot): PhoneAuthListener; - - then(fn: () => PhoneAuthSnapshot): Promise - - catch(fn: () => Error): Promise - } - - namespace auth { - type AuthResult = { - authenticated: boolean, - user: object | null - } | null; - - type AuthProvider = { - PROVIDER_ID: string, - credential: (token: string, secret?: string) => AuthCredential, - }; - - interface Auth { - readonly app: App; - /** - * Returns the current Firebase authentication state. - */ - authResult: AuthResult | null; - /** - * Returns the currently signed-in user (or null). See the User class documentation for further usage. - */ - currentUser: User | null - - /** - * Gets/Sets the language for the app instance - */ - languageCode: string | null; - - /** - * Listen for changes in the users auth state (logging in and out). - * This method returns a unsubscribe function to stop listening to events. - * Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use. - */ - onAuthStateChanged(listener: Function): () => void; - - /** - * Listen for changes in id token. - * This method returns a unsubscribe function to stop listening to events. - * Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use. - */ - onIdTokenChanged(listener: Function): () => void; - - /** - * Listen for changes in the user. - * This method returns a unsubscribe function to stop listening to events. - * Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use. - */ - onUserChanged(listener: Function): () => void; - - signOut(): Promise - - signInAnonymouslyAndRetrieveData(): Promise - - /** - * Sign an anonymous user. - * If the user has already signed in, that user will be returned - */ - signInAnonymously(): Promise - - createUserAndRetrieveDataWithEmailAndPassword(email: string, password: string): Promise - - /** - * We can create a user by calling the createUserWithEmailAndPassword() function. - * The method accepts two parameters, an email and a password. - */ - createUserWithEmailAndPassword(email: string, password: string): Promise - - signInAndRetrieveDataWithEmailAndPassword(email: string, password: string): Promise - - /** - * To sign a user in with their email and password, use the signInWithEmailAndPassword() function. - * It accepts two parameters, the user's email and password: - */ - signInWithEmailAndPassword(email: string, password: string): Promise - - signInAndRetrieveDataWithCustomToken(token: string): Promise - - /** - * Sign a user in with a self-signed JWT token. - * To sign a user using a self-signed custom token, - * use the signInWithCustomToken() function. - * It accepts one parameter, the custom token: - */ - signInWithCustomToken(token: string): Promise - - signInAndRetrieveDataWithCredential(credential: AuthCredential): Promise - - /** - * Sign in the user with a 3rd party credential provider. - * credential requires the following properties: - */ - signInWithCredential(credential: AuthCredential): Promise - - /** - * Asynchronously signs in using a phone number. - */ - signInWithPhoneNumber(phoneNumber: string): Promise - - /** - * Returns a PhoneAuthListener to listen to phone verification events, - * on the final completion event a PhoneAuthCredential can be generated for - * authentication purposes. - */ - verifyPhoneNumber(phoneNumber: string, autoVerifyTimeout?: number): PhoneAuthListener - - /** - * Sends a password reset email to the given email address. - * Unlike the web SDK, - * the email will contain a password reset link rather than a code. - */ - sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise - - /** - * Completes the password reset process, given a confirmation code and new password. - */ - confirmPasswordReset(code: string, newPassword: string): Promise - - /** - * Applies a verification code sent to the user by email or other out-of-band mechanism. - */ - applyActionCode(code: string): Promise - - /** - * Checks a verification code sent to the user by email or other out-of-band mechanism. - */ - checkActionCode(code: string): Promise - - /** - * Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address). - */ - fetchProvidersForEmail(email: string): Promise> - - verifyPasswordResetCode(code: string): Promise - - [key: string]: any; - } - - interface AuthStatics { - EmailAuthProvider: AuthProvider; - PhoneAuthProvider: AuthProvider; - GoogleAuthProvider: AuthProvider; - GithubAuthProvider: AuthProvider; - OAuthProvider: AuthProvider; - TwitterAuthProvider: AuthProvider; - FacebookAuthProvider: AuthProvider; - PhoneAuthState: { - CODE_SENT: string; - AUTO_VERIFY_TIMEOUT: string; - AUTO_VERIFIED: string; - ERROR: string; - }; - } - } - - namespace messaging { - - interface Messaging { - /** - * Subscribes the device to a topic. - */ - subscribeToTopic(topic: string): void - - /** - * Unsubscribes the device from a topic. - */ - unsubscribeFromTopic(topic: string): void - - /** - * When the application has been opened from a notification - * getInitialNotification is called and the notification payload is returned. - * Use onMessage for notifications when the app is running. - */ - getInitialNotification(): Promise - - /** - * Returns the devices FCM token. - * This token can be used in the Firebase console to send messages to directly. - */ - getToken(forceRefresh?: Boolean): Promise - - /** - * Reset Instance ID and revokes all tokens. - */ - deleteInstanceId(): Promise - - /** - * On the event a devices FCM token is refreshed by Google, - * the new token is returned in a callback listener. - */ - onTokenRefresh(listener: (token: string) => any): () => any - - /** - * On a new message, - * the payload object is passed to the listener callback. - * This method is only triggered when the app is running. - * Use getInitialNotification for notifications which cause the app to open. - */ - onMessage(listener: (message: any) => any): () => any - - /** - * Create a local notification from the device itself. - */ - createLocalNotification(notification: any): any - - /** - * Schedule a local notification to be shown on the device. - */ - scheduleLocalNotification(notification: any): any - - /** - * Returns an array of all currently scheduled notifications. - * ``` - * firebase.messaging().getScheduledLocalNotifications() - * .then((notifications) => { - * console.log('Current scheduled notifications: ', notifications); - * }); - * ``` - */ - getScheduledLocalNotifications(): Promise - - /** - * Cancels a location notification by ID, - * or all notifications by *. - */ - cancelLocalNotification(id: string): void - - /** - * Removes all delivered notifications from device by ID, - * or all notifications by *. - */ - removeDeliveredNotification(id: string): void - - /** - * IOS - * Requests app notification permissions in an Alert dialog. - */ - requestPermissions(): Promise<{ granted: boolean }>; - - /** - * Sets the badge number on the iOS app icon. - */ - setBadgeNumber(value: number): void - - /** - * Returns the current badge number on the app icon. - */ - getBadgeNumber(): Promise - - /** - * Send an upstream message - * @param senderId - * @param payload - */ - sendMessage(senderId: string, payload: RemoteMessage): any - - NOTIFICATION_TYPE: Object - REMOTE_NOTIFICATION_RESULT: Object - WILL_PRESENT_RESULT: Object - EVENT_TYPE: Object - } - - interface RemoteMessage { - id: string, - type: string, - ttl?: number, - sender: string, - collapseKey?: string, - data: Object, - } - } - namespace crash { - - interface Crash { - /** Logs a message that will appear in a subsequent crash report. */ - log(message: string): void - - /** - * Android: Logs a message that will appear in a subsequent crash report as well as in logcat. - * iOS: Logs the message in the subsequest crash report only (same as log). - */ - logcat(level: number, tag: string, message: string): void - - /** - * Files a crash report, along with any previous logs to Firebase. - * An Error object must be passed into the report method. - */ - report(error: RnError, maxStackSize: Number): void - - [key: string]: any; - } - } - - namespace crashlytics { - - interface Crashlytics { - /** - * Forces a crash. Useful for testing your application is set up correctly. - */ - crash(): void; - - /** - * Logs a message that will appear in any subsequent crash reports. - */ - log(message: string): void; - - /** - * Logs a non fatal exception. - */ - recordError(code: number, message: string): void; - - /** - * Set a boolean value to show alongside any subsequent crash reports. - */ - setBoolValue(key: string, value: boolean): void; - - /** - * Set a float value to show alongside any subsequent crash reports. - */ - setFloatValue(key: string, value: number): void; - - /** - * Set an integer value to show alongside any subsequent crash reports. - */ - setIntValue(key: string, value: number): void; - - /** - * Set a string value to show alongside any subsequent crash reports. - */ - setStringValue(key: string, value: string): void; - - /** - * Set the user ID to show alongside any subsequent crash reports. - */ - setUserIdentifier(userId: string): void; - } - } - - namespace links { - interface Links { - /** Creates a standard dynamic link. */ - createDynamicLink(parameters: LinkConfiguration): Promise; - /** Creates a short dynamic link. */ - createShortDynamicLink(parameters: LinkConfiguration): Promise; - /** - * Returns the URL that the app has been launched from. If the app was - * not launched from a URL the return value will be null. - */ - getInitialLink(): Promise; - /** - * Subscribe to URL open events while the app is still running. - * The listener is called from URL open events whilst the app is still - * running, use getInitialLink for URLs which cause the app to open - * from a previously closed / not running state. - * Returns an unsubscribe function, call the returned function to - * unsubscribe from all future events. - */ - onLink(listener: (url: string) => void): () => void; - } - - /** - * Configuration when creating a Dynamic Link (standard or short). For - * more information about each parameter, see the official Firebase docs: - * https://firebase.google.com/docs/reference/dynamic-links/link-shortener - */ - interface LinkConfiguration { - link: string, - dynamicLinkDomain: string, - androidInfo?: { - androidLink?: string, - androidPackageName: string, - androidFallbackLink?: string, - androidMinPackageVersionCode?: string, - }, - iosInfo?: { - iosBundleId: string, - iosAppStoreId?: string, - iosFallbackLink?: string, - iosCustomScheme?: string, - iosIpadBundleId?: string, - iosIpadFallbackLink?: string, - }, - socialMetaTagInfo?: { - socialTitle: string, - socialImageLink: string, - socialDescription: string, - }, - suffix?: { - option: 'SHORT' | 'UNGUESSABLE', - }, - } - } - - namespace firestore { - interface Firestore { - readonly app: App; - batch(): WriteBatch; - collection(collectionPath: string): CollectionReference; - doc(documentPath: string): DocumentReference; - - /** NOT SUPPORTED YET */ - // enablePersistence(): Promise; - /** NOT SUPPORTED YET */ - // runTransaction(): Promise; - /** NOT SUPPORTED YET */ - // settings(): void; - } - - interface FirestoreStatics { - FieldPath: typeof FieldPath; - FieldValue: typeof FieldValue; - GeoPoint: typeof GeoPoint; - enableLogging(enabled: boolean): void; - } - - interface CollectionReference { - readonly firestore: Firestore; - readonly id: string; - readonly parent: DocumentReference; - add(data: object): Promise; - doc(documentPath?: string): DocumentReference; - endAt(snapshot: DocumentSnapshot): Query; - endAt(...varargs: any[]): Query; - endBefore(snapshot: DocumentSnapshot): Query; - endBefore(...varargs: any[]): Query; - get(): Promise; - limit(limit: number): Query; - onSnapshot(onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void; - onSnapshot(observer: Query.Observer): () => void; - onSnapshot(queryListenOptions: Query.QueryListenOptions, onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void; - onSnapshot(queryListenOptions: Query.QueryListenOptions, observer: Query.Observer): () => void; - orderBy(fieldPath: string | FieldPath, directionStr?: Types.QueryDirection): Query; - startAfter(snapshot: DocumentSnapshot): Query; - startAfter(...varargs: any[]): Query; - startAt(snapshot: DocumentSnapshot): Query; - startAt(...varargs: any[]): Query; - where(fieldPath: string, op: Types.QueryOperator, value: any): Query; - } - - interface DocumentChange { - readonly doc: DocumentSnapshot; - readonly newIndex: number; - readonly oldIndex: number; - readonly type: string; - } - - interface DocumentReference { - readonly firestore: Firestore; - readonly id: string | null; - readonly parent: CollectionReference; - readonly path: string; - collection(collectionPath: string): CollectionReference; - delete(): Promise; - get(): Promise; - onSnapshot(onNext: DocumentReference.ObserverOnNext, onError?: DocumentReference.ObserverOnError): () => void; - onSnapshot(observer: DocumentReference.Observer): () => void; - onSnapshot(documentListenOptions: DocumentReference.DocumentListenOptions, onNext: DocumentReference.ObserverOnNext, onError?: DocumentReference.ObserverOnError): () => void; - onSnapshot(documentListenOptions: DocumentReference.DocumentListenOptions, observer: DocumentReference.Observer): () => void; - set(data: object, writeOptions?: Types.WriteOptions): Promise; - update(obj: object): Promise; - update(key1: Types.UpdateKey, val1: any): Promise; - update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any): Promise; - update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any): Promise; - update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any): Promise; - update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any, key5: Types.UpdateKey, val5: any): Promise; - } - namespace DocumentReference { - interface DocumentListenOptions { - includeMetadataChanges: boolean; - } - - type ObserverOnNext = (documentSnapshot: DocumentSnapshot) => void; - type ObserverOnError = (err: object) => void; - interface Observer { - next: ObserverOnNext; - error?: ObserverOnError; - } - } - - interface DocumentSnapshot { - readonly exists: boolean; - readonly id: string | null; - readonly metadata: Types.SnapshotMetadata; - readonly ref: DocumentReference; - data(): object | void; - get(fieldPath: string | FieldPath): any | undefined; - } - - class FieldPath { - static documentId(): FieldPath; - constructor(...segments: string[]); - } - - class FieldValue { - static delete(): FieldValue; - static serverTimestamp(): FieldValue; - } - - class GeoPoint { - constructor(latitude: number, longitude: number); - readonly latitude: number; - readonly longitude: number; - } - - class Path { - static fromName(name: string): Path; - constructor(pathComponents: string[]); - readonly id: string | null; - readonly isDocument: boolean; - readonly isCollection: boolean; - readonly relativeName: string; - child(relativePath: string): Path; - parent(): Path | null; - } - - interface Query { - readonly firestore: Firestore; - endAt(snapshot: DocumentSnapshot): Query; - endAt(...varargs: any[]): Query; - endBefore(snapshot: DocumentSnapshot): Query; - endBefore(...varargs: any[]): Query; - get(): Promise; - limit(limit: number): Query; - onSnapshot(onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void; - onSnapshot(observer: Query.Observer): () => void; - onSnapshot(queryListenOptions: Query.QueryListenOptions, onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void; - onSnapshot(queryListenOptions: Query.QueryListenOptions, observer: Query.Observer): () => void; - orderBy(fieldPath: string | FieldPath, directionStr?: Types.QueryDirection): Query; - startAfter(snapshot: DocumentSnapshot): Query; - startAfter(...varargs: any[]): Query; - startAt(snapshot: DocumentSnapshot): Query; - startAt(...varargs: any[]): Query; - where(fieldPath: string, op: Types.QueryOperator, value: any): Query; - } - namespace Query { - interface NativeFieldPath { - elements?: string[]; - string?: string; - type: 'fieldpath' | 'string'; - } - - interface FieldFilter { - fieldPath: NativeFieldPath; - operator: string; - value: any; - } - - interface FieldOrder { - direction: string; - fieldPath: NativeFieldPath; - } - - interface QueryOptions { - endAt?: any[]; - endBefore?: any[]; - limit?: number; - offset?: number; - selectFields?: string[]; - startAfter?: any[]; - startAt?: any[]; - } - - // The JS code expects at least one of 'includeDocumentMetadataChanges' - // or 'includeQueryMetadataChanges' to be defined. - interface _IncludeDocumentMetadataChanges { - includeDocumentMetadataChanges: boolean; - } - interface _IncludeQueryMetadataChanges { - includeQueryMetadataChanges: boolean; - } - type QueryListenOptions = _IncludeDocumentMetadataChanges | _IncludeQueryMetadataChanges | (_IncludeDocumentMetadataChanges & _IncludeQueryMetadataChanges); - - type ObserverOnNext = (querySnapshot: QuerySnapshot) => void; - type ObserverOnError = (err: object) => void; - interface Observer { - next: ObserverOnNext; - error?: ObserverOnError; - } - } - - interface QuerySnapshot { - readonly docChanges: DocumentChange[]; - readonly docs: DocumentSnapshot[]; - readonly empty: boolean; - readonly metadata: Types.SnapshotMetadata; - readonly query: Query; - readonly size: number; - forEach(callback: (snapshot: DocumentSnapshot) => any): void; - } - namespace QuerySnapshot { - interface NativeData { - changes: Types.NativeDocumentChange[]; - documents: Types.NativeDocumentSnapshot[]; - metadata: Types.SnapshotMetadata; - } - } - - interface WriteBatch { - commit(): Promise; - delete(docRef: DocumentReference): WriteBatch; - set(docRef: DocumentReference, data: object, options?: Types.WriteOptions): WriteBatch; - // multiple overrides for update() to allow strong-typed var_args - update(docRef: DocumentReference, obj: object): WriteBatch; - update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any): WriteBatch; - update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any): WriteBatch; - update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any): WriteBatch; - update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any): WriteBatch; - update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any, key5: Types.UpdateKey, val5: any): WriteBatch; - } - - namespace Types { - interface NativeDocumentChange { - document: NativeDocumentSnapshot; - newIndex: number; - oldIndex: number; - type: string; - } - - interface NativeDocumentSnapshot { - data: { - [key: string]: TypeMap; - }; - metadata: SnapshotMetadata; - path: string; - } - - interface SnapshotMetadata { - fromCache: boolean; - hasPendingWrites: boolean; - } - - type QueryDirection = 'asc' | 'ASC' | 'desc' | 'DESC'; - type QueryOperator = '=' | '==' | '>' | '>=' | '<' | '<='; - - interface TypeMap { - type: 'array' | 'boolean' | 'date' | 'documentid' | 'fieldvalue' | 'geopoint' | 'null' | 'number' | 'object' | 'reference' | 'string'; - value: any; - } - - /** The key in update() function for DocumentReference and WriteBatch. */ - type UpdateKey = string | FieldPath - - interface WriteOptions { - merge?: boolean; - } - } - } - } -} diff --git a/bridge/firebase/index.js b/bridge/firebase/index.js deleted file mode 100644 index 9d8a3e8a..00000000 --- a/bridge/firebase/index.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @flow - */ -import firebase from './modules/core/firebase'; - -export default firebase; - -/* - * Export App types - */ -export type { default as App } from './modules/core/app'; - -/* - * Export Auth types - */ -export type { - ActionCodeInfo, - ActionCodeSettings, - AdditionalUserInfo, - AuthCredential, - UserCredential, - UserInfo, - UserMetadata, -} from './modules/auth/types'; -export type { - default as ConfirmationResult, -} from './modules/auth/phone/ConfirmationResult'; -export type { default as User } from './modules/auth/User'; - -/* - * Export Database types - */ -export type { default as DataSnapshot } from './modules/database/DataSnapshot'; -export type { default as OnDisconnect } from './modules/database/OnDisconnect'; -export type { default as Reference } from './modules/database/Reference'; -export type { default as DataQuery } from './modules/database/Query'; - -/* - * Export Firestore types - */ -export type { - DocumentListenOptions, - QueryListenOptions, - SetOptions, - SnapshotMetadata, -} from './modules/firestore/types'; -export type { - default as CollectionReference, -} from './modules/firestore/CollectionReference'; -export type { - default as DocumentChange, -} from './modules/firestore/DocumentChange'; -export type { - default as DocumentReference, -} from './modules/firestore/DocumentReference'; -export type { - default as DocumentSnapshot, -} from './modules/firestore/DocumentSnapshot'; -export type { default as FieldPath } from './modules/firestore/FieldPath'; -export type { default as FieldValue } from './modules/firestore/FieldValue'; -export type { default as GeoPoint } from './modules/firestore/GeoPoint'; -export type { default as Query } from './modules/firestore/Query'; -export type { - default as QuerySnapshot, -} from './modules/firestore/QuerySnapshot'; -export type { default as WriteBatch } from './modules/firestore/WriteBatch'; - -/* - * Export Messaging types - */ -export type { - default as RemoteMessage, -} from './modules/messaging/RemoteMessage'; - -/* - * Export Notifications types - */ -export type { - default as Notification, -} from './modules/notifications/Notification'; diff --git a/bridge/firebase/internals.js b/bridge/firebase/internals.js deleted file mode 100644 index 159ba007..00000000 --- a/bridge/firebase/internals.js +++ /dev/null @@ -1,239 +0,0 @@ -import { Platform, NativeModules } from 'react-native'; - -import EventEmitter from './utils/emitter/EventEmitter'; -import SyncTree from './utils/SyncTree'; - -const DEFAULT_APP_NAME = Platform.OS === 'ios' ? '__FIRAPP_DEFAULT' : '[DEFAULT]'; - -const NAMESPACE_PODS = { - admob: 'Firebase/AdMob', - analytics: 'Firebase/Analytics', - auth: 'Firebase/Auth', - config: 'Firebase/RemoteConfig', - crash: 'Firebase/Crash', - database: 'Firebase/Database', - links: 'Firebase/DynamicLinks', - messaging: 'Firebase/Messaging', - perf: 'Firebase/Performance', - storage: 'Firebase/Storage', -}; - -const GRADLE_DEPS = { - admob: 'ads', -}; - -const PLAY_SERVICES_CODES = { - 1: { - code: 'SERVICE_MISSING', - message: 'Google Play services is missing on this device.', - }, - 2: { - code: 'SERVICE_VERSION_UPDATE_REQUIRED', - message: 'The installed version of Google Play services on this device is out of date.', - }, - 3: { - code: 'SERVICE_DISABLED', - message: 'The installed version of Google Play services has been disabled on this device.', - }, - 9: { - code: 'SERVICE_INVALID', - message: 'The version of the Google Play services installed on this device is not authentic.', - }, - 18: { - code: 'SERVICE_UPDATING', - message: 'Google Play services is currently being updated on this device.', - }, - 19: { - code: 'SERVICE_MISSING_PERMISSION', - message: 'Google Play service doesn\'t have one or more required permissions.', - }, -}; - -export default { - // default options - OPTIONS: { - logLevel: 'warn', - errorOnMissingPlayServices: true, - promptOnMissingPlayServices: true, - }, - - FLAGS: { - checkedPlayServices: false, - }, - - // track all initialized firebase apps - APPS: { - [DEFAULT_APP_NAME]: null, - }, - - 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.', - - /** - * @return {string} - */ - get ERROR_MISSING_CORE() { - if (Platform.OS === 'ios') { - return 'RNFirebase core module was not found natively on iOS, ensure you have ' + - 'correctly included the RNFirebase pod in your projects `Podfile` and have run `pod install`.' + - '\r\n\r\n See http://invertase.link/ios for the ios setup guide.'; - } - - return 'RNFirebase core module was not found natively on Android, ensure you have ' + - 'correctly added the RNFirebase and Firebase gradle dependencies to your `android/app/build.gradle` file.' + - '\r\n\r\n See http://invertase.link/android for the android setup guide.'; - }, - - - ERROR_INIT_OBJECT: 'Firebase.initializeApp(options <-- requires a valid configuration object.', - ERROR_INIT_STRING_NAME: 'Firebase.initializeApp(options, name <-- requires a valid string value.', - - /** - * @return {string} - */ - ERROR_MISSING_CB(method) { - return `Missing required callback for method ${method}().`; - }, - - /** - * @return {string} - */ - ERROR_MISSING_ARG(type, method) { - return `Missing required argument of type '${type}' for method '${method}()'.`; - }, - - /** - * @return {string} - */ - ERROR_MISSING_ARG_NAMED(name, type, method) { - return `Missing required argument '${name}' of type '${type}' for method '${method}()'.`; - }, - - /** - * @return {string} - */ - ERROR_ARG_INVALID_VALUE(name, expected, got) { - return `Invalid value for argument '${name}' expected value '${expected}' but got '${got}'.`; - }, - - /** - * @return {string} - */ - ERROR_PROTECTED_PROP(name) { - return `Property '${name}' is protected and can not be overridden by extendApp.`; - }, - - /** - * @return {string} - * @param namespace - * @param nativeModule - */ - ERROR_MISSING_MODULE(namespace, nativeModule) { - const snippet = `firebase.${namespace}()`; - if (Platform.OS === 'ios') { - return `You attempted to use a firebase module that's not installed natively on your iOS project by calling ${snippet}.` + - '\r\n\r\nEnsure you have the required Firebase iOS SDK pod for this module included in your Podfile, in this instance ' + - `confirm you've added "pod '${NAMESPACE_PODS[namespace]}'" to your Podfile` + - '\r\n\r\nSee http://invertase.link/ios for full setup instructions.'; - } - - const fbSDKDep = `'com.google.firebase:firebase-${GRADLE_DEPS[namespace] || namespace}'`; - const rnFirebasePackage = `'io.invertase.firebase.${namespace}.${nativeModule}Package'`; - const newInstance = `'new ${nativeModule}Package()'`; - return `You attempted to use a firebase module that's not installed on your Android project by calling ${snippet}.` + - `\r\n\r\nEnsure you have:\r\n\r\n1) Installed the required Firebase Android SDK dependency ${fbSDKDep} in your 'android/app/build.gradle' ` + - `file.\r\n\r\n2) Imported the ${rnFirebasePackage} module in your 'MainApplication.java' file.\r\n\r\n3) Added the ` + - `${newInstance} line inside of the RN 'getPackages()' method list.` + - '\r\n\r\nSee http://invertase.link/android for full setup instructions.'; - }, - - /** - * @return {string} - */ - ERROR_APP_NOT_INIT(appName) { - return `The [${appName}] firebase app has not been initialized!`; - }, - - /** - * @param optName - * @return {string} - * @constructor - */ - ERROR_MISSING_OPT(optName) { - return `Failed to initialize app. FirebaseOptions missing or invalid '${optName}' property.`; - }, - - /** - * @return {string} - */ - ERROR_NOT_APP(namespace) { - return `Invalid FirebaseApp instance passed to firebase.${namespace}(app <--).`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_CLASS_METHOD(className, method) { - return `${className}.${method}() is unsupported by the native Firebase SDKs.`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_CLASS_PROPERTY(className, property) { - return `${className}.${property} is unsupported by the native Firebase SDKs.`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_MODULE_METHOD(module, method) { - return `firebase.${module._NAMESPACE}().${method}() is unsupported by the native Firebase SDKs.`; - }, - - - /** - * @return {string} - */ - ERROR_PLAY_SERVICES(statusCode) { - const knownError = PLAY_SERVICES_CODES[statusCode]; - let start = 'Google Play Services is required to run firebase services on android but a valid installation was not found on this device.'; - - if (statusCode === 2) { - start = 'Google Play Services is out of date and may cause some firebase services like authentication to hang when used. It is recommended that you update it.'; - } - - // eslint-disable-next-line prefer-template - return `${start}\r\n\r\n` + - '-------------------------\r\n' + - (knownError ? - `${knownError.code}: ${knownError.message} (code ${statusCode})` : - `A specific play store availability reason reason was not available (unknown code: ${statusCode || null})` - ) + - '\r\n-------------------------' + - '\r\n\r\n' + - 'For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:' + - '\r\n\r\nhttp://invertase.link/play-services'; - }, - - - DEFAULT_APP_NAME, - }, - - - SharedEventEmitter: new EventEmitter(), - SyncTree: NativeModules.RNFirebaseDatabase ? new SyncTree(NativeModules.RNFirebaseDatabase) : null, - - // internal utils - deleteApp(name: String) { - const app = this.APPS[name]; - if (!app) return Promise.resolve(); - - // https://firebase.google.com/docs/reference/js/firebase.app.App#delete - return app.delete().then(() => { - delete this.APPS[name]; - return true; - }); - }, -}; diff --git a/bridge/firebase/modules/admob/AdMobComponent.js b/bridge/firebase/modules/admob/AdMobComponent.js deleted file mode 100644 index c39b4c07..00000000 --- a/bridge/firebase/modules/admob/AdMobComponent.js +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react'; -import { ViewPropTypes, requireNativeComponent } from 'react-native'; -import PropTypes from 'prop-types'; -import EventTypes, { NativeExpressEventTypes } from './EventTypes'; -import { nativeToJSError } from '../../utils'; - -import AdRequest from './AdRequest'; -import VideoOptions from './VideoOptions'; - -const adMobPropTypes = { - ...ViewPropTypes, - size: PropTypes.string.isRequired, - unitId: PropTypes.string.isRequired, - /* eslint-disable react/forbid-prop-types */ - request: PropTypes.object, - video: PropTypes.object, - /* eslint-enable react/forbid-prop-types */ -}; -Object.keys(EventTypes).forEach(eventType => { - adMobPropTypes[eventType] = PropTypes.func; -}); -Object.keys(NativeExpressEventTypes).forEach(eventType => { - adMobPropTypes[eventType] = PropTypes.func; -}); - -const nativeComponents = {}; - -function getNativeComponent(name) { - if (nativeComponents[name]) return nativeComponents[name]; - const component = requireNativeComponent(name, AdMobComponent, { - nativeOnly: { - onBannerEvent: true, - }, - }); - nativeComponents[name] = component; - return component; -} - -class AdMobComponent extends React.Component { - static propTypes = adMobPropTypes; - - static defaultProps = { - request: new AdRequest().addTestDevice().build(), - video: new VideoOptions().build(), - }; - - constructor(props) { - super(props); - this.state = { - width: 0, - height: 0, - }; - - this.nativeView = getNativeComponent(props.class); - } - - /** - * Handle a single banner event and pass to - * any props watching it - * @param nativeEvent - */ - onBannerEvent = ({ nativeEvent }) => { - if (this.props[nativeEvent.type]) { - if (nativeEvent.type === 'onAdFailedToLoad') { - const { code, message } = nativeEvent.payload; - this.props[nativeEvent.type](nativeToJSError(code, message)); - } else { - this.props[nativeEvent.type](nativeEvent.payload || {}); - } - } - - if (nativeEvent.type === 'onSizeChange') - this.updateSize(nativeEvent.payload); - }; - - /** - * Set the JS size of the loaded banner - * @param width - * @param height - */ - updateSize = ({ width, height }) => { - this.setState({ width, height }); - }; - - /** - * Render the native component - * @returns {XML} - */ - render() { - return ( - - ); - } -} - -export default AdMobComponent; diff --git a/bridge/firebase/modules/admob/AdRequest.js b/bridge/firebase/modules/admob/AdRequest.js deleted file mode 100644 index 41d2d5d6..00000000 --- a/bridge/firebase/modules/admob/AdRequest.js +++ /dev/null @@ -1,58 +0,0 @@ -export default class AdRequest { - constructor() { - this._props = { - keywords: [], - testDevices: [], - }; - } - - build() { - return this._props; - } - - addTestDevice(deviceId?: string) { - this._props.testDevices.push(deviceId || 'DEVICE_ID_EMULATOR'); - return this; - } - - addKeyword(keyword: string) { - this._props.keywords.push(keyword); - return this; - } - - setBirthday() { - // TODO - } - - setContentUrl(url: string) { - this._props.contentUrl = url; - return this; - } - - setGender(gender: 'male | female | unknown') { - const genders = ['male', 'female', 'unknown']; - if (genders.includes(gender)) { - this._props.gender = gender; - } - return this; - } - - setLocation() { - // TODO - } - - setRequestAgent(requestAgent: string) { - this._props.requestAgent = requestAgent; - return this; - } - - setIsDesignedForFamilies(isDesignedForFamilies: boolean) { - this._props.isDesignedForFamilies = isDesignedForFamilies; - return this; - } - - tagForChildDirectedTreatment(tagForChildDirectedTreatment: boolean) { - this._props.tagForChildDirectedTreatment = tagForChildDirectedTreatment; - return this; - } -} diff --git a/bridge/firebase/modules/admob/Banner.js b/bridge/firebase/modules/admob/Banner.js deleted file mode 100644 index 82eac4e8..00000000 --- a/bridge/firebase/modules/admob/Banner.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import AdMobComponent from './AdMobComponent'; - -function Banner({ ...props }) { - return ; -} - -Banner.propTypes = AdMobComponent.propTypes; - -Banner.defaultProps = { - size: 'SMART_BANNER', -}; - -export default Banner; diff --git a/bridge/firebase/modules/admob/EventTypes.js b/bridge/firebase/modules/admob/EventTypes.js deleted file mode 100644 index 510f62e3..00000000 --- a/bridge/firebase/modules/admob/EventTypes.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @flow - */ -export default { - onAdLoaded: 'onAdLoaded', - onAdOpened: 'onAdOpened', - onAdLeftApplication: 'onAdLeftApplication', - onAdClosed: 'onAdClosed', - onAdFailedToLoad: 'onAdFailedToLoad', -}; - -export const NativeExpressEventTypes = { - onVideoEnd: 'onVideoEnd', - onVideoMute: 'onVideoMute', - onVideoPause: 'onVideoPause', - onVideoPlay: 'onVideoPlay', - onVideoStart: 'onVideoStart', -}; - -export const RewardedVideoEventTypes = { - onRewarded: 'onRewarded', - onRewardedVideoStarted: 'onRewardedVideoStarted', -}; diff --git a/bridge/firebase/modules/admob/Interstitial.js b/bridge/firebase/modules/admob/Interstitial.js deleted file mode 100644 index a2f4c821..00000000 --- a/bridge/firebase/modules/admob/Interstitial.js +++ /dev/null @@ -1,119 +0,0 @@ -import { Platform } from 'react-native'; -import { statics } from './'; -import AdRequest from './AdRequest'; -import { SharedEventEmitter } from '../../utils/events'; -import { getNativeModule } from '../../utils/native'; -import { nativeToJSError } from '../../utils'; -import type AdMob from './'; - -let subscriptions = []; - -export default class Interstitial { - _admob: AdMob; - - constructor(admob: AdMob, adUnit: string) { - // Interstitials on iOS require a new instance each time - if (Platform.OS === 'ios') { - getNativeModule(admob).clearInterstitial(adUnit); - } - - for (let i = 0, len = subscriptions.length; i < len; i++) { - subscriptions[i].remove(); - } - subscriptions = []; - - this._admob = admob; - this.adUnit = adUnit; - this.loaded = false; - SharedEventEmitter.removeAllListeners(`interstitial_${adUnit}`); - SharedEventEmitter.addListener( - `interstitial_${adUnit}`, - this._onInterstitialEvent - ); - } - - /** - * Handle a JS emit event - * @param event - * @private - */ - _onInterstitialEvent = event => { - const eventType = `interstitial:${this.adUnit}:${event.type}`; - - let emitData = Object.assign({}, event); - - switch (event.type) { - case 'onAdLoaded': - this.loaded = true; - break; - case 'onAdFailedToLoad': - emitData = nativeToJSError(event.payload.code, event.payload.message); - emitData.type = event.type; - break; - default: - } - - SharedEventEmitter.emit(eventType, emitData); - SharedEventEmitter.emit(`interstitial:${this.adUnit}:*`, emitData); - }; - - /** - * Load an ad with an instance of AdRequest - * @param request - * @returns {*} - */ - loadAd(request?: AdRequest) { - let adRequest = request; - - if (!adRequest || !Object.keys(adRequest)) { - adRequest = new AdRequest().addTestDevice().build(); - } - - return getNativeModule(this._admob).interstitialLoadAd( - this.adUnit, - adRequest - ); - } - - /** - * Return a local instance of isLoaded - * @returns {boolean} - */ - isLoaded() { - return this.loaded; - } - - /** - * Show the advert - will only show if loaded - * @returns {*} - */ - show() { - if (this.loaded) { - getNativeModule(this._admob).interstitialShowAd(this.adUnit); - } - } - - /** - * Listen to an Ad event - * @param eventType - * @param listenerCb - * @returns {null} - */ - on(eventType, listenerCb) { - if (!statics.EventTypes[eventType]) { - console.warn( - `Invalid event type provided, must be one of: ${Object.keys( - statics.EventTypes - ).join(', ')}` - ); - return null; - } - - const sub = SharedEventEmitter.addListener( - `interstitial:${this.adUnit}:${eventType}`, - listenerCb - ); - subscriptions.push(sub); - return sub; - } -} diff --git a/bridge/firebase/modules/admob/NativeExpress.js b/bridge/firebase/modules/admob/NativeExpress.js deleted file mode 100644 index 1dd57232..00000000 --- a/bridge/firebase/modules/admob/NativeExpress.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import AdMobComponent from './AdMobComponent'; - -function NativeExpress({ ...props }) { - return ; -} - -NativeExpress.propTypes = AdMobComponent.propTypes; - -NativeExpress.defaultProps = { - size: 'SMART_BANNER', -}; - -export default NativeExpress; diff --git a/bridge/firebase/modules/admob/RewardedVideo.js b/bridge/firebase/modules/admob/RewardedVideo.js deleted file mode 100644 index f5f6e0db..00000000 --- a/bridge/firebase/modules/admob/RewardedVideo.js +++ /dev/null @@ -1,118 +0,0 @@ -import { statics } from './'; -import AdRequest from './AdRequest'; -import { SharedEventEmitter } from '../../utils/events'; -import { getNativeModule } from '../../utils/native'; -import { nativeToJSError } from '../../utils'; -import type AdMob from './'; - -let subscriptions = []; - -export default class RewardedVideo { - _admob: AdMob; - - constructor(admob: AdMob, adUnit: string) { - for (let i = 0, len = subscriptions.length; i < len; i++) { - subscriptions[i].remove(); - } - subscriptions = []; - - this._admob = admob; - this.adUnit = adUnit; - this.loaded = false; - SharedEventEmitter.removeAllListeners(`rewarded_video_${adUnit}`); - SharedEventEmitter.addListener( - `rewarded_video_${adUnit}`, - this._onRewardedVideoEvent - ); - } - - /** - * Handle a JS emit event - * @param event - * @private - */ - _onRewardedVideoEvent = event => { - const eventType = `rewarded_video:${this.adUnit}:${event.type}`; - - let emitData = Object.assign({}, event); - - switch (event.type) { - case 'onAdLoaded': - this.loaded = true; - break; - case 'onAdFailedToLoad': - emitData = nativeToJSError(event.payload.code, event.payload.message); - emitData.type = event.type; - break; - default: - } - - SharedEventEmitter.emit(eventType, emitData); - SharedEventEmitter.emit(`rewarded_video:${this.adUnit}:*`, emitData); - }; - - /** - * Load an ad with an instance of AdRequest - * @param request - * @returns {*} - */ - loadAd(request?: AdRequest) { - let adRequest = request; - - if (!adRequest || !Object.keys(adRequest)) { - adRequest = new AdRequest().addTestDevice().build(); - } - - return getNativeModule(this._admob).rewardedVideoLoadAd( - this.adUnit, - adRequest - ); - } - - /** - * Return a local instance of isLoaded - * @returns {boolean} - */ - isLoaded() { - return this.loaded; - } - - /** - * Show the advert - will only show if loaded - * @returns {*} - */ - show() { - if (this.loaded) { - getNativeModule(this._admob).rewardedVideoShowAd(this.adUnit); - } - } - - /** - * Listen to an Ad event - * @param eventType - * @param listenerCb - * @returns {null} - */ - on(eventType, listenerCb) { - const types = { - ...statics.EventTypes, - ...statics.RewardedVideoEventTypes, - }; - - if (!types[eventType]) { - console.warn( - `Invalid event type provided, must be one of: ${Object.keys(types).join( - ', ' - )}` - ); - return null; - } - - const sub = SharedEventEmitter.addListener( - `rewarded_video:${this.adUnit}:${eventType}`, - listenerCb - ); - subscriptions.push(sub); - return sub; - } -} diff --git a/bridge/firebase/modules/admob/VideoOptions.js b/bridge/firebase/modules/admob/VideoOptions.js deleted file mode 100644 index ab8a4777..00000000 --- a/bridge/firebase/modules/admob/VideoOptions.js +++ /dev/null @@ -1,16 +0,0 @@ -export default class VideoOptions { - constructor() { - this._props = { - startMuted: true, - }; - } - - build() { - return this._props; - } - - setStartMuted(muted: boolean = true) { - this._props.startMuted = muted; - return this; - } -} diff --git a/bridge/firebase/modules/admob/index.js b/bridge/firebase/modules/admob/index.js deleted file mode 100644 index 063e42ea..00000000 --- a/bridge/firebase/modules/admob/index.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @flow - * AdMob representation wrapper - */ -import { SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import { getNativeModule } from '../../utils/native'; -import ModuleBase from '../../utils/ModuleBase'; - -import Interstitial from './Interstitial'; -import RewardedVideo from './RewardedVideo'; -import AdRequest from './AdRequest'; -import VideoOptions from './VideoOptions'; -import Banner from './Banner'; -import NativeExpress from './NativeExpress'; - -import EventTypes, { - NativeExpressEventTypes, - RewardedVideoEventTypes, -} from './EventTypes'; - -import type App from '../core/app'; - -type NativeEvent = { - adUnit: string, - payload: Object, - type: string, -}; - -const NATIVE_EVENTS = ['interstitial_event', 'rewarded_video_event']; - -export const MODULE_NAME = 'RNFirebaseAdMob'; -export const NAMESPACE = 'admob'; - -export default class AdMob extends ModuleBase { - _appId: ?string; - _initialized: boolean; - - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - - this._initialized = false; - this._appId = null; - - 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 (SharedEventEmitter.listeners(jsEventType).length === 0) { - // TODO - } - - SharedEventEmitter.emit(jsEventType, event); - } - - _onRewardedVideoEvent(event: NativeEvent): void { - const { adUnit } = event; - const jsEventType = `rewarded_video_${adUnit}`; - - if (SharedEventEmitter.listeners(jsEventType).length === 0) { - // TODO - } - - SharedEventEmitter.emit(jsEventType, event); - } - - initialize(appId: string): void { - if (this._initialized) { - getLogger(this).warn('AdMob has already been initialized!'); - } else { - this._initialized = true; - this._appId = appId; - getNativeModule(this).initialize(appId); - } - } - - openDebugMenu(): void { - if (!this._initialized) { - getLogger(this).warn( - 'AdMob needs to be initialized before opening the dev menu!' - ); - } else { - getLogger(this).info('Opening debug menu'); - getNativeModule(this).openDebugMenu(this._appId); - } - } - - interstitial(adUnit: string): Interstitial { - return new Interstitial(this, adUnit); - } - - rewarded(adUnit: string): RewardedVideo { - return new RewardedVideo(this, adUnit); - } -} - -export const statics = { - Banner, - NativeExpress, - AdRequest, - VideoOptions, - EventTypes, - RewardedVideoEventTypes, - NativeExpressEventTypes, -}; diff --git a/bridge/firebase/modules/analytics/index.js b/bridge/firebase/modules/analytics/index.js deleted file mode 100644 index 7e1af364..00000000 --- a/bridge/firebase/modules/analytics/index.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @flow - * Analytics representation wrapper - */ -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; -import { isString, isObject } from '../../utils'; - -import type App from '../core/app'; - -const AlphaNumericUnderscore = /^[a-zA-Z0-9_]+$/; - -const ReservedEventNames = [ - 'app_clear_data', - 'app_uninstall', - 'app_update', - 'error', - 'first_open', - 'in_app_purchase', - 'notification_dismiss', - 'notification_foreground', - 'notification_open', - 'notification_receive', - 'os_update', - 'session_start', - 'user_engagement', -]; - -export const MODULE_NAME = 'RNFirebaseAnalytics'; -export const NAMESPACE = 'analytics'; - -export default class Analytics extends ModuleBase { - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - } - - /** - * Logs an app event. - * @param {string} name - * @param params - * @return {Promise} - */ - logEvent(name: string, params: Object = {}): void { - if (!isString(name)) { - throw new Error( - `analytics.logEvent(): First argument 'name' is required and must be a string value.` - ); - } - - if (typeof params !== 'undefined' && !isObject(params)) { - throw new Error( - `analytics.logEvent(): Second optional argument 'params' must be an object if provided.` - ); - } - - // check name is not a reserved event name - if (ReservedEventNames.includes(name)) { - throw new Error( - `analytics.logEvent(): event name '${name}' is a reserved event name and can not be used.` - ); - } - - // name format validation - if (!AlphaNumericUnderscore.test(name)) { - throw new Error( - `analytics.logEvent(): Event name '${name}' is invalid. Names should contain 1 to 32 alphanumeric characters or underscores.` - ); - } - - // maximum number of allowed params check - if (params && Object.keys(params).length > 25) - throw new Error( - 'analytics.logEvent(): Maximum number of parameters exceeded (25).' - ); - - // Parameter names can be up to 24 characters long and must start with an alphabetic character - // and contain only alphanumeric characters and underscores. Only String, long and double param - // types are supported. String parameter values can be up to 36 characters long. The "firebase_" - // prefix is reserved and should not be used for parameter names. - - getNativeModule(this).logEvent(name, params); - } - - /** - * Sets whether analytics collection is enabled for this app on this device. - * @param enabled - */ - setAnalyticsCollectionEnabled(enabled: boolean): void { - getNativeModule(this).setAnalyticsCollectionEnabled(enabled); - } - - /** - * Sets the current screen name, which specifies the current visual context in your app. - * @param screenName - * @param screenClassOverride - */ - setCurrentScreen(screenName: string, screenClassOverride: string): void { - getNativeModule(this).setCurrentScreen(screenName, screenClassOverride); - } - - /** - * Sets the minimum engagement time required before starting a session. The default value is 10000 (10 seconds). - * @param milliseconds - */ - setMinimumSessionDuration(milliseconds: number = 10000): void { - getNativeModule(this).setMinimumSessionDuration(milliseconds); - } - - /** - * Sets the duration of inactivity that terminates the current session. The default value is 1800000 (30 minutes). - * @param milliseconds - */ - setSessionTimeoutDuration(milliseconds: number = 1800000): void { - getNativeModule(this).setSessionTimeoutDuration(milliseconds); - } - - /** - * Sets the user ID property. - * @param id - */ - setUserId(id: string | null): void { - if (id !== null && !isString(id)) { - throw new Error( - 'analytics.setUserId(): The supplied userId must be a string value or null.' - ); - } - getNativeModule(this).setUserId(id); - } - - /** - * Sets a user property to a given value. - * @param name - * @param value - */ - setUserProperty(name: string, value: string | null): void { - if (value !== null && !isString(value)) { - throw new Error( - 'analytics.setUserProperty(): The supplied property must be a string value or null.' - ); - } - getNativeModule(this).setUserProperty(name, value); - } - - /** - * Sets multiple user properties to the supplied values. - * @RNFirebaseSpecific - * @param object - */ - setUserProperties(object: Object): void { - Object.keys(object).forEach(property => { - const value = object[property]; - if (value !== null && !isString(value)) { - throw new Error( - `analytics.setUserProperties(): The property with name '${property}' must be a string value or null.` - ); - } - getNativeModule(this).setUserProperty(property, object[property]); - }); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/auth/ConfirmationResult.js b/bridge/firebase/modules/auth/ConfirmationResult.js deleted file mode 100644 index fd76e69a..00000000 --- a/bridge/firebase/modules/auth/ConfirmationResult.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @flow - * ConfirmationResult representation wrapper - */ -import { getNativeModule } from '../../utils/native'; -import type Auth from './'; -import type User from './User'; - -export default class ConfirmationResult { - _auth: Auth; - _verificationId: string; - - /** - * - * @param auth - * @param verificationId The phone number authentication operation's verification ID. - */ - constructor(auth: Auth, verificationId: string) { - this._auth = auth; - this._verificationId = verificationId; - } - - /** - * - * @param verificationCode - * @return {*} - */ - confirm(verificationCode: string): Promise { - return getNativeModule(this._auth) - ._confirmVerificationCode(verificationCode) - .then(user => this._auth._setUser(user)); - } - - get verificationId(): string | null { - return this._verificationId; - } -} diff --git a/bridge/firebase/modules/auth/PhoneAuthListener.js b/bridge/firebase/modules/auth/PhoneAuthListener.js deleted file mode 100644 index d85bcace..00000000 --- a/bridge/firebase/modules/auth/PhoneAuthListener.js +++ /dev/null @@ -1,347 +0,0 @@ -// @flow -import INTERNALS from '../../utils/internals'; -import { SharedEventEmitter } from '../../utils/events'; -import { - generatePushID, - isFunction, - isAndroid, - isIOS, - isString, - nativeToJSError, -} from '../../utils'; -import { getNativeModule } from '../../utils/native'; - -import type Auth from './'; - -type PhoneAuthSnapshot = { - state: 'sent' | 'timeout' | 'verified' | 'error', - verificationId: string, - code: string | null, - error: Error | null, -}; - -type PhoneAuthError = { - code: string | null, - verificationId: string, - message: string | null, - stack: string | null, -}; - -export default class PhoneAuthListener { - _auth: Auth; - _timeout: number; - _publicEvents: Object; - _internalEvents: Object; - _reject: Function | null; - _resolve: Function | null; - _credential: Object | null; - _promise: Promise<*> | null; - _phoneAuthRequestKey: string; - - /** - * - * @param auth - * @param phoneNumber - * @param timeout - */ - constructor(auth: Auth, phoneNumber: string, timeout?: number) { - this._auth = auth; - this._reject = null; - this._resolve = null; - this._promise = null; - this._credential = null; - - this._timeout = timeout || 20; // 20 secs - this._phoneAuthRequestKey = generatePushID(); - - // internal events - this._internalEvents = { - codeSent: `phone:auth:${this._phoneAuthRequestKey}:onCodeSent`, - verificationFailed: `phone:auth:${ - this._phoneAuthRequestKey - }:onVerificationFailed`, - verificationComplete: `phone:auth:${ - this._phoneAuthRequestKey - }:onVerificationComplete`, - codeAutoRetrievalTimeout: `phone:auth:${ - this._phoneAuthRequestKey - }:onCodeAutoRetrievalTimeout`, - }; - - // user observer events - this._publicEvents = { - // error cb - error: `phone:auth:${this._phoneAuthRequestKey}:error`, - // observer - event: `phone:auth:${this._phoneAuthRequestKey}:event`, - // success cb - success: `phone:auth:${this._phoneAuthRequestKey}:success`, - }; - - // setup internal event listeners - this._subscribeToEvents(); - - // start verification flow natively - if (isAndroid) { - getNativeModule(this._auth).verifyPhoneNumber( - phoneNumber, - this._phoneAuthRequestKey, - this._timeout - ); - } - - if (isIOS) { - getNativeModule(this._auth).verifyPhoneNumber( - phoneNumber, - this._phoneAuthRequestKey - ); - } - } - - /** - * Subscribes to all EE events on this._internalEvents - * @private - */ - _subscribeToEvents() { - const events = Object.keys(this._internalEvents); - - for (let i = 0, len = events.length; i < len; i++) { - const type = events[i]; - SharedEventEmitter.once( - this._internalEvents[type], - // $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 - this[`_${type}Handler`].bind(this) - ); - } - } - - /** - * Subscribe a users listener cb to the snapshot events. - * @param observer - * @private - */ - _addUserObserver(observer) { - SharedEventEmitter.addListener(this._publicEvents.event, observer); - } - - /** - * Send a snapshot event to users event observer. - * @param snapshot PhoneAuthSnapshot - * @private - */ - _emitToObservers(snapshot: PhoneAuthSnapshot) { - SharedEventEmitter.emit(this._publicEvents.event, snapshot); - } - - /** - * Send a error snapshot event to any subscribed errorCb's - * @param snapshot - * @private - */ - _emitToErrorCb(snapshot) { - const { error } = snapshot; - if (this._reject) this._reject(error); - SharedEventEmitter.emit(this._publicEvents.error, error); - } - - /** - * Send a success snapshot event to any subscribed completeCb's - * @param snapshot - * @private - */ - _emitToSuccessCb(snapshot) { - if (this._resolve) this._resolve(snapshot); - SharedEventEmitter.emit(this._publicEvents.success, snapshot); - } - - /** - * Removes all listeners for this phone auth instance - * @private - */ - _removeAllListeners() { - setTimeout(() => { - // move to next event loop - not sure if needed - // internal listeners - Object.values(this._internalEvents).forEach(event => { - SharedEventEmitter.removeAllListeners(event); - }); - - // user observer listeners - Object.values(this._publicEvents).forEach(publicEvent => { - SharedEventEmitter.removeAllListeners(publicEvent); - }); - }, 0); - } - - /** - * Create a new internal deferred promise, if not already created - * @private - */ - _promiseDeferred() { - if (!this._promise) { - this._promise = new Promise((resolve, reject) => { - this._resolve = result => { - this._resolve = null; - return resolve(result); - }; - - this._reject = possibleError => { - this._reject = null; - return reject(possibleError); - }; - }); - } - } - - /* -------------------------- - --- INTERNAL EVENT HANDLERS - ---------------------------- */ - - /** - * Internal code sent event handler - * @private - * @param credential - */ - _codeSentHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: null, - error: null, - state: 'sent', - }; - - this._emitToObservers(snapshot); - - if (isIOS) { - this._emitToSuccessCb(snapshot); - } - - if (isAndroid) { - // android can auto retrieve so we don't emit to successCb immediately, - // if auto retrieve times out then that will emit to successCb - } - } - - /** - * Internal code auto retrieve timeout event handler - * @private - * @param credential - */ - _codeAutoRetrievalTimeoutHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: null, - error: null, - state: 'timeout', - }; - - this._emitToObservers(snapshot); - this._emitToSuccessCb(snapshot); - } - - /** - * Internal verification complete event handler - * @param credential - * @private - */ - _verificationCompleteHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: credential.code || null, - error: null, - state: 'verified', - }; - - this._emitToObservers(snapshot); - this._emitToSuccessCb(snapshot); - this._removeAllListeners(); - } - - /** - * Internal verification failed event handler - * @param state - * @private - */ - _verificationFailedHandler(state) { - const snapshot: PhoneAuthSnapshot = { - verificationId: state.verificationId, - code: null, - error: null, - state: 'error', - }; - - const { code, message, nativeErrorMessage } = state.error; - snapshot.error = nativeToJSError(code, message, { nativeErrorMessage }); - - this._emitToObservers(snapshot); - this._emitToErrorCb(snapshot); - this._removeAllListeners(); - } - - /* ------------- - -- PUBLIC API - --------------*/ - - on( - event: string, - observer: () => PhoneAuthSnapshot, - errorCb?: () => PhoneAuthError, - successCb?: () => PhoneAuthSnapshot - ): this { - if (!isString(event)) { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('event', 'string', 'on') - ); - } - - if (event !== 'state_changed') { - throw new Error( - INTERNALS.STRINGS.ERROR_ARG_INVALID_VALUE( - 'event', - 'state_changed', - event - ) - ); - } - - if (!isFunction(observer)) { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('observer', 'function', 'on') - ); - } - - this._addUserObserver(observer); - - if (isFunction(errorCb)) { - SharedEventEmitter.once(this._publicEvents.error, errorCb); - } - - if (isFunction(successCb)) { - SharedEventEmitter.once(this._publicEvents.success, successCb); - } - - return this; - } - - /** - * Promise .then proxy - * @param fn - */ - then(fn: () => PhoneAuthSnapshot) { - this._promiseDeferred(); - // $FlowFixMe: Unsure how to annotate `bind` here - if (this._promise) return this._promise.then.bind(this._promise)(fn); - return undefined; // will never get here - just to keep flow happy - } - - /** - * Promise .catch proxy - * @param fn - */ - catch(fn: () => Error) { - this._promiseDeferred(); - // $FlowFixMe: Unsure how to annotate `bind` here - if (this._promise) return this._promise.catch.bind(this._promise)(fn); - return undefined; // will never get here - just to keep flow happy - } -} diff --git a/bridge/firebase/modules/auth/User.js b/bridge/firebase/modules/auth/User.js deleted file mode 100644 index e509bb94..00000000 --- a/bridge/firebase/modules/auth/User.js +++ /dev/null @@ -1,334 +0,0 @@ -/** - * @flow - * User representation wrapper - */ -import INTERNALS from '../../utils/internals'; -import { getNativeModule } from '../../utils/native'; - -import type Auth from './'; -import type { - ActionCodeSettings, - AuthCredential, - NativeUser, - UserCredential, - UserInfo, - UserMetadata, -} from './types'; - -type UpdateProfile = { - displayName?: string, - photoURL?: string, -}; - -export default class User { - _auth: Auth; - _user: NativeUser; - - /** - * - * @param auth Instance of Authentication class - * @param user user result object from native - */ - constructor(auth: Auth, user: NativeUser) { - this._auth = auth; - this._user = user; - } - - /** - * PROPERTIES - */ - - get displayName(): ?string { - return this._user.displayName || null; - } - - get email(): ?string { - return this._user.email || null; - } - - get emailVerified(): boolean { - return this._user.emailVerified || false; - } - - get isAnonymous(): boolean { - return this._user.isAnonymous || false; - } - - get metadata(): UserMetadata { - return this._user.metadata; - } - - get phoneNumber(): ?string { - return this._user.phoneNumber || null; - } - - get photoURL(): ?string { - return this._user.photoURL || null; - } - - get providerData(): Array { - return this._user.providerData; - } - - get providerId(): string { - return this._user.providerId; - } - - get uid(): string { - return this._user.uid; - } - - /** - * METHODS - */ - - /** - * Delete the current user - * @return {Promise} - */ - delete(): Promise { - return getNativeModule(this._auth) - .delete() - .then(() => { - this._auth._setUser(); - }); - } - - /** - * get the token of current user - * @return {Promise} - */ - getIdToken(forceRefresh: boolean = false): Promise { - return getNativeModule(this._auth).getToken(forceRefresh); - } - - /** - * get the token of current user - * @deprecated Deprecated getToken in favor of getIdToken. - * @return {Promise} - */ - getToken(forceRefresh: boolean = false): Promise { - console.warn( - 'Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.' - ); - return getNativeModule(this._auth).getToken(forceRefresh); - } - - /** - * @deprecated Deprecated linkWithCredential in favor of linkAndRetrieveDataWithCredential. - * @param credential - */ - linkWithCredential(credential: AuthCredential): Promise { - console.warn( - 'Deprecated firebase.User.prototype.linkWithCredential in favor of firebase.User.prototype.linkAndRetrieveDataWithCredential.' - ); - return getNativeModule(this._auth) - .linkWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(user => this._auth._setUser(user)); - } - - /** - * - * @param credential - */ - linkAndRetrieveDataWithCredential( - credential: AuthCredential - ): Promise { - return getNativeModule(this._auth) - .linkAndRetrieveDataWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - /** - * Re-authenticate a user with a third-party authentication provider - * @return {Promise} A promise resolved upon completion - */ - reauthenticateWithCredential(credential: AuthCredential): Promise { - console.warn( - 'Deprecated firebase.User.prototype.reauthenticateWithCredential in favor of firebase.User.prototype.reauthenticateAndRetrieveDataWithCredential.' - ); - return getNativeModule(this._auth) - .reauthenticateWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(user => { - this._auth._setUser(user); - }); - } - - /** - * Re-authenticate a user with a third-party authentication provider - * @return {Promise} A promise resolved upon completion - */ - reauthenticateAndRetrieveDataWithCredential( - credential: AuthCredential - ): Promise { - return getNativeModule(this._auth) - .reauthenticateAndRetrieveDataWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(userCredential => this._auth._setUserCredential(userCredential)); - } - - /** - * Reload the current user - * @return {Promise} - */ - reload(): Promise { - return getNativeModule(this._auth) - .reload() - .then(user => { - this._auth._setUser(user); - }); - } - - /** - * Send verification email to current user. - */ - sendEmailVerification( - actionCodeSettings?: ActionCodeSettings - ): Promise { - return getNativeModule(this._auth) - .sendEmailVerification(actionCodeSettings) - .then(user => { - this._auth._setUser(user); - }); - } - - toJSON(): Object { - return Object.assign({}, this._user); - } - - /** - * - * @param providerId - * @return {Promise.|*} - */ - unlink(providerId: string): Promise { - return getNativeModule(this._auth) - .unlink(providerId) - .then(user => this._auth._setUser(user)); - } - - /** - * Update the current user's email - * - * @param {string} email The user's _new_ email - * @return {Promise} A promise resolved upon completion - */ - updateEmail(email: string): Promise { - return getNativeModule(this._auth) - .updateEmail(email) - .then(user => { - this._auth._setUser(user); - }); - } - - /** - * Update the current user's password - * @param {string} password the new password - * @return {Promise} - */ - updatePassword(password: string): Promise { - return getNativeModule(this._auth) - .updatePassword(password) - .then(user => { - this._auth._setUser(user); - }); - } - - /** - * Update the current user's profile - * @param {Object} updates An object containing the keys listed [here](https://firebase.google.com/docs/auth/ios/manage-users#update_a_users_profile) - * @return {Promise} - */ - updateProfile(updates: UpdateProfile = {}): Promise { - return getNativeModule(this._auth) - .updateProfile(updates) - .then(user => { - this._auth._setUser(user); - }); - } - - /** - * KNOWN UNSUPPORTED METHODS - */ - - linkWithPhoneNumber() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'linkWithPhoneNumber' - ) - ); - } - - linkWithPopup() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkWithPopup') - ); - } - - linkWithRedirect() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'linkWithRedirect' - ) - ); - } - - reauthenticateWithPhoneNumber() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'reauthenticateWithPhoneNumber' - ) - ); - } - - reauthenticateWithPopup() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'reauthenticateWithPopup' - ) - ); - } - - reauthenticateWithRedirect() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'reauthenticateWithRedirect' - ) - ); - } - - updatePhoneNumber() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD( - 'User', - 'updatePhoneNumber' - ) - ); - } - - get refreshToken(): string { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('User', 'refreshToken') - ); - } -} diff --git a/bridge/firebase/modules/auth/index.js b/bridge/firebase/modules/auth/index.js deleted file mode 100644 index b4b697af..00000000 --- a/bridge/firebase/modules/auth/index.js +++ /dev/null @@ -1,526 +0,0 @@ -/** - * @flow - * Auth representation wrapper - */ -import User from './User'; -import ModuleBase from '../../utils/ModuleBase'; -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import { getNativeModule } from '../../utils/native'; -import INTERNALS from '../../utils/internals'; -import ConfirmationResult from './phone/ConfirmationResult'; -import PhoneAuthListener from './phone/PhoneAuthListener'; - -// providers -import EmailAuthProvider from './providers/EmailAuthProvider'; -import PhoneAuthProvider from './providers/PhoneAuthProvider'; -import GoogleAuthProvider from './providers/GoogleAuthProvider'; -import GithubAuthProvider from './providers/GithubAuthProvider'; -import OAuthProvider from './providers/OAuthProvider'; -import TwitterAuthProvider from './providers/TwitterAuthProvider'; -import FacebookAuthProvider from './providers/FacebookAuthProvider'; - -import type { - ActionCodeInfo, - ActionCodeSettings, - AuthCredential, - NativeUser, - NativeUserCredential, - UserCredential, -} from './types'; -import type App from '../core/app'; - -type AuthState = { - user?: NativeUser, -}; - -const NATIVE_EVENTS = [ - 'auth_state_changed', - 'auth_id_token_changed', - 'phone_auth_state_changed', -]; - -export const MODULE_NAME = 'RNFirebaseAuth'; -export const NAMESPACE = 'auth'; - -export default class Auth extends ModuleBase { - _authResult: boolean; - _languageCode: string; - _user: User | null; - - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: true, - hasShards: false, - namespace: NAMESPACE, - }); - this._user = null; - this._authResult = false; - this._languageCode = - getNativeModule(this).APP_LANGUAGE[app._name] || - getNativeModule(this).APP_LANGUAGE['[DEFAULT]']; - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onAuthStateChanged - getAppEventName(this, 'auth_state_changed'), - (state: AuthState) => { - this._setUser(state.user); - SharedEventEmitter.emit( - getAppEventName(this, 'onAuthStateChanged'), - this._user - ); - } - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public events based on event.type - getAppEventName(this, 'phone_auth_state_changed'), - (event: Object) => { - const eventKey = `phone:auth:${event.requestKey}:${event.type}`; - SharedEventEmitter.emit(eventKey, event.state); - } - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onIdTokenChanged - getAppEventName(this, 'auth_id_token_changed'), - (auth: AuthState) => { - this._setUser(auth.user); - SharedEventEmitter.emit( - getAppEventName(this, 'onIdTokenChanged'), - this._user - ); - } - ); - - getNativeModule(this).addAuthStateListener(); - getNativeModule(this).addIdTokenListener(); - } - - _setUser(user: ?NativeUser): ?User { - this._authResult = true; - this._user = user ? new User(this, user) : null; - SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user); - return this._user; - } - - _setUserCredential(userCredential: NativeUserCredential): UserCredential { - const user = new User(this, userCredential.user); - this._authResult = true; - this._user = user; - SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user); - return { - additionalUserInfo: userCredential.additionalUserInfo, - user, - }; - } - - /* - * WEB API - */ - - /** - * Listen for auth changes. - * @param listener - */ - onAuthStateChanged(listener: Function) { - getLogger(this).info('Creating onAuthStateChanged listener'); - SharedEventEmitter.addListener( - getAppEventName(this, 'onAuthStateChanged'), - listener - ); - if (this._authResult) listener(this._user || null); - - return () => { - getLogger(this).info('Removing onAuthStateChanged listener'); - SharedEventEmitter.removeListener( - getAppEventName(this, 'onAuthStateChanged'), - listener - ); - }; - } - - /** - * Listen for id token changes. - * @param listener - */ - onIdTokenChanged(listener: Function) { - getLogger(this).info('Creating onIdTokenChanged listener'); - SharedEventEmitter.addListener( - getAppEventName(this, 'onIdTokenChanged'), - listener - ); - if (this._authResult) listener(this._user || null); - - return () => { - getLogger(this).info('Removing onIdTokenChanged listener'); - SharedEventEmitter.removeListener( - getAppEventName(this, 'onIdTokenChanged'), - listener - ); - }; - } - - /** - * Listen for user changes. - * @param listener - */ - onUserChanged(listener: Function) { - getLogger(this).info('Creating onUserChanged listener'); - SharedEventEmitter.addListener( - getAppEventName(this, 'onUserChanged'), - listener - ); - if (this._authResult) listener(this._user || null); - - return () => { - getLogger(this).info('Removing onUserChanged listener'); - SharedEventEmitter.removeListener( - getAppEventName(this, 'onUserChanged'), - listener - ); - }; - } - - /** - * Sign the current user out - * @return {Promise} - */ - signOut(): Promise { - return getNativeModule(this) - .signOut() - .then(() => { - this._setUser(); - }); - } - - /** - * Sign a user in anonymously - * @deprecated Deprecated signInAnonymously in favor of signInAnonymouslyAndRetrieveData. - * @return {Promise} A promise resolved upon completion - */ - signInAnonymously(): Promise { - console.warn( - 'Deprecated firebase.User.prototype.signInAnonymously in favor of firebase.User.prototype.signInAnonymouslyAndRetrieveData.' - ); - return getNativeModule(this) - .signInAnonymously() - .then(user => this._setUser(user)); - } - - /** - * Sign a user in anonymously - * @return {Promise} A promise resolved upon completion - */ - signInAnonymouslyAndRetrieveData(): Promise { - return getNativeModule(this) - .signInAnonymouslyAndRetrieveData() - .then(userCredential => this._setUserCredential(userCredential)); - } - - /** - * Create a user with the email/password functionality - * @deprecated Deprecated createUserWithEmailAndPassword in favor of createUserAndRetrieveDataWithEmailAndPassword. - * @param {string} email The user's email - * @param {string} password The user's password - * @return {Promise} A promise indicating the completion - */ - createUserWithEmailAndPassword( - email: string, - password: string - ): Promise { - console.warn( - 'Deprecated firebase.User.prototype.createUserWithEmailAndPassword in favor of firebase.User.prototype.createUserAndRetrieveDataWithEmailAndPassword.' - ); - return getNativeModule(this) - .createUserWithEmailAndPassword(email, password) - .then(user => this._setUser(user)); - } - - /** - * Create a user with the email/password functionality - * @param {string} email The user's email - * @param {string} password The user's password - * @return {Promise} A promise indicating the completion - */ - createUserAndRetrieveDataWithEmailAndPassword( - email: string, - password: string - ): Promise { - return getNativeModule(this) - .createUserAndRetrieveDataWithEmailAndPassword(email, password) - .then(userCredential => this._setUserCredential(userCredential)); - } - - /** - * Sign a user in with email/password - * @deprecated Deprecated signInWithEmailAndPassword in favor of signInAndRetrieveDataWithEmailAndPassword - * @param {string} email The user's email - * @param {string} password The user's password - * @return {Promise} A promise that is resolved upon completion - */ - signInWithEmailAndPassword(email: string, password: string): Promise { - console.warn( - 'Deprecated firebase.User.prototype.signInWithEmailAndPassword in favor of firebase.User.prototype.signInAndRetrieveDataWithEmailAndPassword.' - ); - return getNativeModule(this) - .signInWithEmailAndPassword(email, password) - .then(user => this._setUser(user)); - } - - /** - * Sign a user in with email/password - * @param {string} email The user's email - * @param {string} password The user's password - * @return {Promise} A promise that is resolved upon completion - */ - signInAndRetrieveDataWithEmailAndPassword( - email: string, - password: string - ): Promise { - return getNativeModule(this) - .signInAndRetrieveDataWithEmailAndPassword(email, password) - .then(userCredential => this._setUserCredential(userCredential)); - } - - /** - * Sign the user in with a custom auth token - * @deprecated Deprecated signInWithCustomToken in favor of signInAndRetrieveDataWithCustomToken - * @param {string} customToken A self-signed custom auth token. - * @return {Promise} A promise resolved upon completion - */ - signInWithCustomToken(customToken: string): Promise { - console.warn( - 'Deprecated firebase.User.prototype.signInWithCustomToken in favor of firebase.User.prototype.signInAndRetrieveDataWithCustomToken.' - ); - return getNativeModule(this) - .signInWithCustomToken(customToken) - .then(user => this._setUser(user)); - } - - /** - * Sign the user in with a custom auth token - * @param {string} customToken A self-signed custom auth token. - * @return {Promise} A promise resolved upon completion - */ - signInAndRetrieveDataWithCustomToken( - customToken: string - ): Promise { - return getNativeModule(this) - .signInAndRetrieveDataWithCustomToken(customToken) - .then(userCredential => this._setUserCredential(userCredential)); - } - - /** - * Sign the user in with a third-party authentication provider - * @deprecated Deprecated signInWithCredential in favor of signInAndRetrieveDataWithCredential. - * @return {Promise} A promise resolved upon completion - */ - signInWithCredential(credential: AuthCredential): Promise { - console.warn( - 'Deprecated firebase.User.prototype.signInWithCredential in favor of firebase.User.prototype.signInAndRetrieveDataWithCredential.' - ); - return getNativeModule(this) - .signInWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(user => this._setUser(user)); - } - - /** - * Sign the user in with a third-party authentication provider - * @return {Promise} A promise resolved upon completion - */ - signInAndRetrieveDataWithCredential( - credential: AuthCredential - ): Promise { - return getNativeModule(this) - .signInAndRetrieveDataWithCredential( - credential.providerId, - credential.token, - credential.secret - ) - .then(userCredential => this._setUserCredential(userCredential)); - } - - /** - * Asynchronously signs in using a phone number. - * - */ - signInWithPhoneNumber(phoneNumber: string): Promise { - return getNativeModule(this) - .signInWithPhoneNumber(phoneNumber) - .then(result => new ConfirmationResult(this, result.verificationId)); - } - - /** - * Returns a PhoneAuthListener to listen to phone verification events, - * on the final completion event a PhoneAuthCredential can be generated for - * authentication purposes. - * - * @param phoneNumber - * @param autoVerifyTimeout Android Only - * @returns {PhoneAuthListener} - */ - verifyPhoneNumber( - phoneNumber: string, - autoVerifyTimeout?: number - ): PhoneAuthListener { - return new PhoneAuthListener(this, phoneNumber, autoVerifyTimeout); - } - - /** - * Send reset password instructions via email - * @param {string} email The email to send password reset instructions - */ - sendPasswordResetEmail( - email: string, - actionCodeSettings?: ActionCodeSettings - ): Promise { - return getNativeModule(this).sendPasswordResetEmail( - email, - actionCodeSettings - ); - } - - /** - * Completes the password reset process, given a confirmation code and new password. - * - * @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#confirmPasswordReset - * @param code - * @param newPassword - * @return {Promise.} - */ - confirmPasswordReset(code: string, newPassword: string): Promise { - return getNativeModule(this).confirmPasswordReset(code, newPassword); - } - - /** - * Applies a verification code sent to the user by email or other out-of-band mechanism. - * - * @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#applyActionCode - * @param code - * @return {Promise.} - */ - applyActionCode(code: string): Promise { - return getNativeModule(this).applyActionCode(code); - } - - /** - * Checks a verification code sent to the user by email or other out-of-band mechanism. - * - * @link https://firebase.google.com/docs/reference/js/firebase.auth.Auth#checkActionCode - * @param code - * @return {Promise.|Promise} - */ - checkActionCode(code: string): Promise { - return getNativeModule(this).checkActionCode(code); - } - - /** - * Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address). - * @return {Promise} - */ - fetchProvidersForEmail(email: string): Promise { - return getNativeModule(this).fetchProvidersForEmail(email); - } - - verifyPasswordResetCode(code: string): Promise { - return getNativeModule(this).verifyPasswordResetCode(code); - } - - /** - * Sets the language for the auth module - * @param code - * @returns {*} - */ - set languageCode(code: string) { - this._languageCode = code; - getNativeModule(this).setLanguageCode(code); - } - - /** - * Get the currently signed in user - * @return {Promise} - */ - get currentUser(): User | null { - return this._user; - } - - get languageCode(): string { - return this._languageCode; - } - - /** - * KNOWN UNSUPPORTED METHODS - */ - - getRedirectResult() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'auth', - 'getRedirectResult' - ) - ); - } - - setPersistence() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'auth', - 'setPersistence' - ) - ); - } - - signInWithPopup() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'auth', - 'signInWithPopup' - ) - ); - } - - signInWithRedirect() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'auth', - 'signInWithRedirect' - ) - ); - } - - // firebase issue - https://github.com/invertase/react-native-firebase/pull/655#issuecomment-349904680 - useDeviceLanguage() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'auth', - 'useDeviceLanguage' - ) - ); - } -} - -export const statics = { - EmailAuthProvider, - PhoneAuthProvider, - GoogleAuthProvider, - GithubAuthProvider, - TwitterAuthProvider, - FacebookAuthProvider, - OAuthProvider, - PhoneAuthState: { - CODE_SENT: 'sent', - AUTO_VERIFY_TIMEOUT: 'timeout', - AUTO_VERIFIED: 'verified', - ERROR: 'error', - }, -}; diff --git a/bridge/firebase/modules/auth/phone/ConfirmationResult.js b/bridge/firebase/modules/auth/phone/ConfirmationResult.js deleted file mode 100644 index 25d701d1..00000000 --- a/bridge/firebase/modules/auth/phone/ConfirmationResult.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @flow - * ConfirmationResult representation wrapper - */ -import { getNativeModule } from '../../../utils/native'; -import type Auth from '../'; -import type User from '../User'; - -export default class ConfirmationResult { - _auth: Auth; - _verificationId: string; - - /** - * - * @param auth - * @param verificationId The phone number authentication operation's verification ID. - */ - constructor(auth: Auth, verificationId: string) { - this._auth = auth; - this._verificationId = verificationId; - } - - /** - * - * @param verificationCode - * @return {*} - */ - confirm(verificationCode: string): Promise { - return getNativeModule(this._auth) - ._confirmVerificationCode(verificationCode) - .then(user => this._auth._setUser(user)); - } - - get verificationId(): string | null { - return this._verificationId; - } -} diff --git a/bridge/firebase/modules/auth/phone/PhoneAuthListener.js b/bridge/firebase/modules/auth/phone/PhoneAuthListener.js deleted file mode 100644 index 68bc78fb..00000000 --- a/bridge/firebase/modules/auth/phone/PhoneAuthListener.js +++ /dev/null @@ -1,347 +0,0 @@ -// @flow -import INTERNALS from '../../../utils/internals'; -import { SharedEventEmitter } from '../../../utils/events'; -import { - generatePushID, - isFunction, - isAndroid, - isIOS, - isString, - nativeToJSError, -} from '../../../utils'; -import { getNativeModule } from '../../../utils/native'; - -import type Auth from '../'; - -type PhoneAuthSnapshot = { - state: 'sent' | 'timeout' | 'verified' | 'error', - verificationId: string, - code: string | null, - error: Error | null, -}; - -type PhoneAuthError = { - code: string | null, - verificationId: string, - message: string | null, - stack: string | null, -}; - -export default class PhoneAuthListener { - _auth: Auth; - _timeout: number; - _publicEvents: Object; - _internalEvents: Object; - _reject: Function | null; - _resolve: Function | null; - _credential: Object | null; - _promise: Promise<*> | null; - _phoneAuthRequestKey: string; - - /** - * - * @param auth - * @param phoneNumber - * @param timeout - */ - constructor(auth: Auth, phoneNumber: string, timeout?: number) { - this._auth = auth; - this._reject = null; - this._resolve = null; - this._promise = null; - this._credential = null; - - this._timeout = timeout || 20; // 20 secs - this._phoneAuthRequestKey = generatePushID(); - - // internal events - this._internalEvents = { - codeSent: `phone:auth:${this._phoneAuthRequestKey}:onCodeSent`, - verificationFailed: `phone:auth:${ - this._phoneAuthRequestKey - }:onVerificationFailed`, - verificationComplete: `phone:auth:${ - this._phoneAuthRequestKey - }:onVerificationComplete`, - codeAutoRetrievalTimeout: `phone:auth:${ - this._phoneAuthRequestKey - }:onCodeAutoRetrievalTimeout`, - }; - - // user observer events - this._publicEvents = { - // error cb - error: `phone:auth:${this._phoneAuthRequestKey}:error`, - // observer - event: `phone:auth:${this._phoneAuthRequestKey}:event`, - // success cb - success: `phone:auth:${this._phoneAuthRequestKey}:success`, - }; - - // setup internal event listeners - this._subscribeToEvents(); - - // start verification flow natively - if (isAndroid) { - getNativeModule(this._auth).verifyPhoneNumber( - phoneNumber, - this._phoneAuthRequestKey, - this._timeout - ); - } - - if (isIOS) { - getNativeModule(this._auth).verifyPhoneNumber( - phoneNumber, - this._phoneAuthRequestKey - ); - } - } - - /** - * Subscribes to all EE events on this._internalEvents - * @private - */ - _subscribeToEvents() { - const events = Object.keys(this._internalEvents); - - for (let i = 0, len = events.length; i < len; i++) { - const type = events[i]; - SharedEventEmitter.once( - this._internalEvents[type], - // $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 - this[`_${type}Handler`].bind(this) - ); - } - } - - /** - * Subscribe a users listener cb to the snapshot events. - * @param observer - * @private - */ - _addUserObserver(observer) { - SharedEventEmitter.addListener(this._publicEvents.event, observer); - } - - /** - * Send a snapshot event to users event observer. - * @param snapshot PhoneAuthSnapshot - * @private - */ - _emitToObservers(snapshot: PhoneAuthSnapshot) { - SharedEventEmitter.emit(this._publicEvents.event, snapshot); - } - - /** - * Send a error snapshot event to any subscribed errorCb's - * @param snapshot - * @private - */ - _emitToErrorCb(snapshot) { - const { error } = snapshot; - if (this._reject) this._reject(error); - SharedEventEmitter.emit(this._publicEvents.error, error); - } - - /** - * Send a success snapshot event to any subscribed completeCb's - * @param snapshot - * @private - */ - _emitToSuccessCb(snapshot) { - if (this._resolve) this._resolve(snapshot); - SharedEventEmitter.emit(this._publicEvents.success, snapshot); - } - - /** - * Removes all listeners for this phone auth instance - * @private - */ - _removeAllListeners() { - setTimeout(() => { - // move to next event loop - not sure if needed - // internal listeners - Object.values(this._internalEvents).forEach(event => { - SharedEventEmitter.removeAllListeners(event); - }); - - // user observer listeners - Object.values(this._publicEvents).forEach(publicEvent => { - SharedEventEmitter.removeAllListeners(publicEvent); - }); - }, 0); - } - - /** - * Create a new internal deferred promise, if not already created - * @private - */ - _promiseDeferred() { - if (!this._promise) { - this._promise = new Promise((resolve, reject) => { - this._resolve = result => { - this._resolve = null; - return resolve(result); - }; - - this._reject = possibleError => { - this._reject = null; - return reject(possibleError); - }; - }); - } - } - - /* -------------------------- - --- INTERNAL EVENT HANDLERS - ---------------------------- */ - - /** - * Internal code sent event handler - * @private - * @param credential - */ - _codeSentHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: null, - error: null, - state: 'sent', - }; - - this._emitToObservers(snapshot); - - if (isIOS) { - this._emitToSuccessCb(snapshot); - } - - if (isAndroid) { - // android can auto retrieve so we don't emit to successCb immediately, - // if auto retrieve times out then that will emit to successCb - } - } - - /** - * Internal code auto retrieve timeout event handler - * @private - * @param credential - */ - _codeAutoRetrievalTimeoutHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: null, - error: null, - state: 'timeout', - }; - - this._emitToObservers(snapshot); - this._emitToSuccessCb(snapshot); - } - - /** - * Internal verification complete event handler - * @param credential - * @private - */ - _verificationCompleteHandler(credential) { - const snapshot: PhoneAuthSnapshot = { - verificationId: credential.verificationId, - code: credential.code || null, - error: null, - state: 'verified', - }; - - this._emitToObservers(snapshot); - this._emitToSuccessCb(snapshot); - this._removeAllListeners(); - } - - /** - * Internal verification failed event handler - * @param state - * @private - */ - _verificationFailedHandler(state) { - const snapshot: PhoneAuthSnapshot = { - verificationId: state.verificationId, - code: null, - error: null, - state: 'error', - }; - - const { code, message, nativeErrorMessage } = state.error; - snapshot.error = nativeToJSError(code, message, { nativeErrorMessage }); - - this._emitToObservers(snapshot); - this._emitToErrorCb(snapshot); - this._removeAllListeners(); - } - - /* ------------- - -- PUBLIC API - --------------*/ - - on( - event: string, - observer: () => PhoneAuthSnapshot, - errorCb?: () => PhoneAuthError, - successCb?: () => PhoneAuthSnapshot - ): this { - if (!isString(event)) { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('event', 'string', 'on') - ); - } - - if (event !== 'state_changed') { - throw new Error( - INTERNALS.STRINGS.ERROR_ARG_INVALID_VALUE( - 'event', - 'state_changed', - event - ) - ); - } - - if (!isFunction(observer)) { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('observer', 'function', 'on') - ); - } - - this._addUserObserver(observer); - - if (isFunction(errorCb)) { - SharedEventEmitter.once(this._publicEvents.error, errorCb); - } - - if (isFunction(successCb)) { - SharedEventEmitter.once(this._publicEvents.success, successCb); - } - - return this; - } - - /** - * Promise .then proxy - * @param fn - */ - then(fn: () => PhoneAuthSnapshot) { - this._promiseDeferred(); - // $FlowFixMe: Unsure how to annotate `bind` here - if (this._promise) return this._promise.then.bind(this._promise)(fn); - return undefined; // will never get here - just to keep flow happy - } - - /** - * Promise .catch proxy - * @param fn - */ - catch(fn: () => Error) { - this._promiseDeferred(); - // $FlowFixMe: Unsure how to annotate `bind` here - if (this._promise) return this._promise.catch.bind(this._promise)(fn); - return undefined; // will never get here - just to keep flow happy - } -} diff --git a/bridge/firebase/modules/auth/providers/EmailAuthProvider.js b/bridge/firebase/modules/auth/providers/EmailAuthProvider.js deleted file mode 100644 index 0c37d661..00000000 --- a/bridge/firebase/modules/auth/providers/EmailAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * EmailAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'password'; - -export default class EmailAuthProvider { - constructor() { - throw new Error( - '`new EmailAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(email: string, password: string): AuthCredential { - return { - token: email, - secret: password, - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/FacebookAuthProvider.js b/bridge/firebase/modules/auth/providers/FacebookAuthProvider.js deleted file mode 100644 index 67fa957b..00000000 --- a/bridge/firebase/modules/auth/providers/FacebookAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * FacebookAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'facebook.com'; - -export default class FacebookAuthProvider { - constructor() { - throw new Error( - '`new FacebookAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(token: string): AuthCredential { - return { - token, - secret: '', - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/GithubAuthProvider.js b/bridge/firebase/modules/auth/providers/GithubAuthProvider.js deleted file mode 100644 index a6e8c13c..00000000 --- a/bridge/firebase/modules/auth/providers/GithubAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * GithubAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'github.com'; - -export default class GithubAuthProvider { - constructor() { - throw new Error( - '`new GithubAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(token: string): AuthCredential { - return { - token, - secret: '', - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/GoogleAuthProvider.js b/bridge/firebase/modules/auth/providers/GoogleAuthProvider.js deleted file mode 100644 index 25c81a21..00000000 --- a/bridge/firebase/modules/auth/providers/GoogleAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * EmailAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'google.com'; - -export default class GoogleAuthProvider { - constructor() { - throw new Error( - '`new GoogleAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(token: string, secret: string): AuthCredential { - return { - token, - secret, - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/OAuthProvider.js b/bridge/firebase/modules/auth/providers/OAuthProvider.js deleted file mode 100644 index 2bd28ed2..00000000 --- a/bridge/firebase/modules/auth/providers/OAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * OAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'oauth'; - -export default class OAuthProvider { - constructor() { - throw new Error( - '`new OAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(idToken: string, accessToken: string): AuthCredential { - return { - token: idToken, - secret: accessToken, - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/PhoneAuthProvider.js b/bridge/firebase/modules/auth/providers/PhoneAuthProvider.js deleted file mode 100644 index 57ce6558..00000000 --- a/bridge/firebase/modules/auth/providers/PhoneAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * PhoneAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'phone'; - -export default class PhoneAuthProvider { - constructor() { - throw new Error( - '`new PhoneAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(verificationId: string, code: string): AuthCredential { - return { - token: verificationId, - secret: code, - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/providers/TwitterAuthProvider.js b/bridge/firebase/modules/auth/providers/TwitterAuthProvider.js deleted file mode 100644 index 150926bb..00000000 --- a/bridge/firebase/modules/auth/providers/TwitterAuthProvider.js +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @flow - * TwitterAuthProvider representation wrapper - */ -import type { AuthCredential } from '../types'; - -const providerId = 'twitter.com'; - -export default class TwitterAuthProvider { - constructor() { - throw new Error( - '`new TwitterAuthProvider()` is not supported on the native Firebase SDKs.' - ); - } - - static get PROVIDER_ID(): string { - return providerId; - } - - static credential(token: string, secret: string): AuthCredential { - return { - token, - secret, - providerId, - }; - } -} diff --git a/bridge/firebase/modules/auth/types.js b/bridge/firebase/modules/auth/types.js deleted file mode 100644 index 64655509..00000000 --- a/bridge/firebase/modules/auth/types.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @flow - */ -import type User from './User'; - -export type ActionCodeInfo = { - data: { - email?: string, - fromEmail?: string, - }, - operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL', -}; - -export type ActionCodeSettings = { - android: { - installApp?: boolean, - minimumVersion?: string, - packageName: string, - }, - handleCodeInApp?: boolean, - iOS: { - bundleId?: string, - }, - url: string, -}; - -export type AdditionalUserInfo = { - isNewUser: boolean, - profile?: Object, - providerId: string, - username?: string, -}; - -export type AuthCredential = { - providerId: string, - token: string, - secret: string, -}; - -export type UserCredential = {| - additionalUserInfo?: AdditionalUserInfo, - user: User, -|}; - -export type UserInfo = { - displayName?: string, - email?: string, - phoneNumber?: string, - photoURL?: string, - providerId: string, - uid: string, -}; - -export type UserMetadata = { - creationTime?: string, - lastSignInTime?: string, -}; - -export type NativeUser = { - displayName?: string, - email?: string, - emailVerified?: boolean, - isAnonymous?: boolean, - metadata: UserMetadata, - phoneNumber?: string, - photoURL?: string, - providerData: UserInfo[], - providerId: string, - uid: string, -}; - -export type NativeUserCredential = {| - additionalUserInfo?: AdditionalUserInfo, - user: NativeUser, -|}; diff --git a/bridge/firebase/modules/base.js b/bridge/firebase/modules/base.js deleted file mode 100644 index f1ea818f..00000000 --- a/bridge/firebase/modules/base.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @flow - */ - -// todo move out -export class ReferenceBase extends Base { - constructor(path: string) { - super(); - this.path = path || '/'; - } - - /** - * The last part of a Reference's path (after the last '/') - * The key of a root Reference is null. - * @type {String} - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#key} - */ - get key(): string | null { - return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1); - } -} diff --git a/bridge/firebase/modules/config/index.js b/bridge/firebase/modules/config/index.js deleted file mode 100644 index 05511262..00000000 --- a/bridge/firebase/modules/config/index.js +++ /dev/null @@ -1,185 +0,0 @@ -/** - * @flow - * Remote Config representation wrapper - */ -import { getLogger } from '../../utils/log'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; - -type NativeValue = { - stringValue?: string, - numberValue?: number, - dataValue?: Object, - boolValue?: boolean, - source: - | 'remoteConfigSourceRemote' - | 'remoteConfigSourceDefault' - | ' remoteConfigSourceStatic', -}; - -export const MODULE_NAME = 'RNFirebaseRemoteConfig'; -export const NAMESPACE = 'config'; - -/** - * @class Config - */ -export default class RemoteConfig extends ModuleBase { - _developerModeEnabled: boolean; - - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - this._developerModeEnabled = false; - } - - /** - * Converts a native map to single JS value - * @param nativeValue - * @returns {*} - * @private - */ - _nativeValueToJS(nativeValue: NativeValue) { - return { - source: nativeValue.source, - val() { - if ( - nativeValue.boolValue !== null && - (nativeValue.stringValue === 'true' || - nativeValue.stringValue === 'false' || - nativeValue.stringValue === null) - ) - return nativeValue.boolValue; - if ( - nativeValue.numberValue !== null && - nativeValue.numberValue !== undefined && - (nativeValue.stringValue == null || - nativeValue.stringValue === '' || - nativeValue.numberValue.toString() === nativeValue.stringValue) - ) - return nativeValue.numberValue; - if ( - nativeValue.dataValue !== nativeValue.stringValue && - (nativeValue.stringValue == null || nativeValue.stringValue === '') - ) - return nativeValue.dataValue; - return nativeValue.stringValue; - }, - }; - } - - /** - * Enable Remote Config developer mode to allow for frequent refreshes of the cache - */ - enableDeveloperMode() { - if (!this._developerModeEnabled) { - getLogger(this).debug('Enabled developer mode'); - getNativeModule(this).enableDeveloperMode(); - this._developerModeEnabled = true; - } - } - - /** - * Fetches Remote Config data - * Call activateFetched to make fetched data available in app - * @returns {*|Promise.}: - */ - fetch(expiration?: number) { - if (expiration !== undefined) { - getLogger(this).debug( - `Fetching remote config data with expiration ${expiration.toString()}` - ); - return getNativeModule(this).fetchWithExpirationDuration(expiration); - } - getLogger(this).debug('Fetching remote config data'); - return getNativeModule(this).fetch(); - } - - /** - * Applies Fetched Config data to the Active Config - * @returns {*|Promise.} - * resolves if there was a Fetched Config, and it was activated, - * rejects if no Fetched Config was found, or the Fetched Config was already activated. - */ - activateFetched() { - getLogger(this).debug('Activating remote config'); - return getNativeModule(this).activateFetched(); - } - - /** - * Gets the config value of the default namespace. - * @param key: Config key - * @returns {*|Promise.}, will always resolve - * Object looks like - * { - * "stringValue" : stringValue, - * "numberValue" : numberValue, - * "dataValue" : dataValue, - * "boolValue" : boolValue, - * "source" : OneOf(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic) - * } - */ - getValue(key: string) { - return getNativeModule(this) - .getValue(key || '') - .then(this._nativeValueToJS); - } - - /** - * Gets the config value of the default namespace. - * @param keys: Config key - * @returns {*|Promise.}, will always resolve. - * Result will be a dictionary of key and config objects - * Object looks like - * { - * "stringValue" : stringValue, - * "numberValue" : numberValue, - * "dataValue" : dataValue, - * "boolValue" : boolValue, - * "source" : OneOf(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic) - * } - */ - getValues(keys: Array) { - return getNativeModule(this) - .getValues(keys || []) - .then(nativeValues => { - const values: { [string]: Object } = {}; - for (let i = 0, len = keys.length; i < len; i++) { - values[keys[i]] = this._nativeValueToJS(nativeValues[i]); - } - return values; - }); - } - - /** - * Get the set of parameter keys that start with the given prefix, from the default namespace - * @param prefix: The key prefix to look for. If prefix is nil or empty, returns all the keys. - * @returns {*|Promise.>} - */ - getKeysByPrefix(prefix?: string) { - return getNativeModule(this).getKeysByPrefix(prefix); - } - - /** - * Sets config defaults for parameter keys and values in the default namespace config. - * @param defaults: A dictionary mapping a String key to a Object values. - */ - setDefaults(defaults: Object) { - getNativeModule(this).setDefaults(defaults); - } - - /** - * Sets default configs from plist for default namespace; - * @param resource: The plist file name or resource ID - */ - setDefaultsFromResource(resource: string | number) { - getNativeModule(this).setDefaultsFromResource(resource); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/core/app.js b/bridge/firebase/modules/core/app.js deleted file mode 100644 index 352ec7d4..00000000 --- a/bridge/firebase/modules/core/app.js +++ /dev/null @@ -1,196 +0,0 @@ -/* - * @flow - */ -import { NativeModules } from 'react-native'; - -import APPS from '../../utils/apps'; -import { SharedEventEmitter } from '../../utils/events'; -import INTERNALS from '../../utils/internals'; -import { isObject } from '../../utils'; - -import AdMob, { NAMESPACE as AdmobNamespace } from '../admob'; -import Auth, { NAMESPACE as AuthNamespace } from '../auth'; -import Analytics, { NAMESPACE as AnalyticsNamespace } from '../analytics'; -import Config, { NAMESPACE as ConfigNamespace } from '../config'; -import Crash, { NAMESPACE as CrashNamespace } from '../crash'; -import Crashlytics, { - NAMESPACE as CrashlyticsNamespace, -} from '../fabric/crashlytics'; -import Database, { NAMESPACE as DatabaseNamespace } from '../database'; -import Firestore, { NAMESPACE as FirestoreNamespace } from '../firestore'; -import InstanceId, { NAMESPACE as InstanceIdNamespace } from '../instanceid'; -import Invites, { NAMESPACE as InvitesNamespace } from '../invites'; -import Links, { NAMESPACE as LinksNamespace } from '../links'; -import Messaging, { NAMESPACE as MessagingNamespace } from '../messaging'; -import Notifications, { - NAMESPACE as NotificationsNamespace, -} from '../notifications'; -import Performance, { NAMESPACE as PerfNamespace } from '../perf'; -import Storage, { NAMESPACE as StorageNamespace } from '../storage'; -import Utils, { NAMESPACE as UtilsNamespace } from '../utils'; - -import type { FirebaseOptions } from '../../types'; - -const FirebaseCoreModule = NativeModules.RNFirebase; - -export default class App { - _extendedProps: { [string]: boolean }; - _initialized: boolean = false; - _name: string; - _nativeInitialized: boolean = false; - _options: FirebaseOptions; - admob: () => AdMob; - analytics: () => Analytics; - auth: () => Auth; - config: () => Config; - crash: () => Crash; - database: () => Database; - fabric: { - crashlytics: () => Crashlytics, - }; - firestore: () => Firestore; - instanceid: () => InstanceId; - invites: () => Invites; - links: () => Links; - messaging: () => Messaging; - notifications: () => Notifications; - perf: () => Performance; - storage: () => Storage; - utils: () => Utils; - - constructor( - name: string, - options: FirebaseOptions, - fromNative: boolean = false - ) { - this._name = name; - this._options = Object.assign({}, options); - - if (fromNative) { - this._initialized = true; - this._nativeInitialized = true; - } else if (options.databaseURL && options.apiKey) { - FirebaseCoreModule.initializeApp( - this._name, - this._options, - (error, result) => { - this._initialized = true; - SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result }); - } - ); - } - - // modules - this.admob = APPS.appModule(this, AdmobNamespace, AdMob); - this.analytics = APPS.appModule(this, AnalyticsNamespace, Analytics); - this.auth = APPS.appModule(this, AuthNamespace, Auth); - this.config = APPS.appModule(this, ConfigNamespace, Config); - this.crash = APPS.appModule(this, CrashNamespace, Crash); - this.database = APPS.appModule(this, DatabaseNamespace, Database); - this.fabric = { - crashlytics: APPS.appModule(this, CrashlyticsNamespace, Crashlytics), - }; - this.firestore = APPS.appModule(this, FirestoreNamespace, Firestore); - this.instanceid = APPS.appModule(this, InstanceIdNamespace, InstanceId); - this.invites = APPS.appModule(this, InvitesNamespace, Invites); - this.links = APPS.appModule(this, LinksNamespace, Links); - this.messaging = APPS.appModule(this, MessagingNamespace, Messaging); - this.notifications = APPS.appModule( - this, - NotificationsNamespace, - Notifications - ); - this.perf = APPS.appModule(this, PerfNamespace, Performance); - this.storage = APPS.appModule(this, StorageNamespace, Storage); - this.utils = APPS.appModule(this, UtilsNamespace, Utils); - this._extendedProps = {}; - } - - /** - * - * @return {*} - */ - get name(): string { - return this._name; - } - - /** - * - * @return {*} - */ - get options(): FirebaseOptions { - return Object.assign({}, this._options); - } - - /** - * Undocumented firebase web sdk method that allows adding additional properties onto - * a firebase app instance. - * - * See: https://github.com/firebase/firebase-js-sdk/blob/master/tests/app/firebase_app.test.ts#L328 - * - * @param props - */ - extendApp(props: Object) { - if (!isObject(props)) { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_ARG('Object', 'extendApp') - ); - } - - const keys = Object.keys(props); - - for (let i = 0, len = keys.length; i < len; i++) { - const key = keys[i]; - - if (!this._extendedProps[key] && Object.hasOwnProperty.call(this, key)) { - throw new Error(INTERNALS.STRINGS.ERROR_PROTECTED_PROP(key)); - } - - // $FlowExpectedError: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323 - this[key] = props[key]; - this._extendedProps[key] = true; - } - } - - /** - * - * @return {Promise} - */ - delete() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete') - ); - // TODO only the ios sdk currently supports delete, add back in when android also supports it - // if (this._name === APPS.DEFAULT_APP_NAME && this._nativeInitialized) { - // return Promise.reject( - // new Error('Unable to delete the default native firebase app instance.'), - // ); - // } - // - // return FirebaseCoreModule.deleteApp(this._name); - } - - /** - * - * @return {*} - */ - onReady(): Promise { - if (this._initialized) return Promise.resolve(this); - - return new Promise((resolve, reject) => { - 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 - }); - }); - } - - /** - * toString returns the name of the app. - * - * @return {string} - */ - toString() { - return this._name; - } -} diff --git a/bridge/firebase/modules/core/firebase.js b/bridge/firebase/modules/core/firebase.js deleted file mode 100644 index 91f3ffcc..00000000 --- a/bridge/firebase/modules/core/firebase.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * @flow - */ -import { NativeModules } from 'react-native'; - -import APPS from '../../utils/apps'; -import INTERNALS from '../../utils/internals'; -import App from './app'; -import VERSION from '../../version'; - -// module imports -import { - statics as AdMobStatics, - MODULE_NAME as AdmobModuleName, -} from '../admob'; -import { statics as AuthStatics, MODULE_NAME as AuthModuleName } from '../auth'; -import { - statics as AnalyticsStatics, - MODULE_NAME as AnalyticsModuleName, -} from '../analytics'; -import { - statics as ConfigStatics, - MODULE_NAME as ConfigModuleName, -} from '../config'; -import { - statics as CrashStatics, - MODULE_NAME as CrashModuleName, -} from '../crash'; -import { - statics as CrashlyticsStatics, - MODULE_NAME as CrashlyticsModuleName, -} from '../fabric/crashlytics'; -import { - statics as DatabaseStatics, - MODULE_NAME as DatabaseModuleName, -} from '../database'; -import { - statics as FirestoreStatics, - MODULE_NAME as FirestoreModuleName, -} from '../firestore'; -import { - statics as InstanceIdStatics, - MODULE_NAME as InstanceIdModuleName, -} from '../instanceid'; -import { - statics as InvitesStatics, - MODULE_NAME as InvitesModuleName, -} from '../invites'; -import { - statics as LinksStatics, - MODULE_NAME as LinksModuleName, -} from '../links'; -import { - statics as MessagingStatics, - MODULE_NAME as MessagingModuleName, -} from '../messaging'; -import { - statics as NotificationsStatics, - MODULE_NAME as NotificationsModuleName, -} from '../notifications'; -import { - statics as PerformanceStatics, - MODULE_NAME as PerfModuleName, -} from '../perf'; -import { - statics as StorageStatics, - MODULE_NAME as StorageModuleName, -} from '../storage'; -import { - statics as UtilsStatics, - MODULE_NAME as UtilsModuleName, -} from '../utils'; - -import type { - AdMobModule, - AnalyticsModule, - AuthModule, - ConfigModule, - CrashModule, - DatabaseModule, - FabricModule, - FirebaseOptions, - FirestoreModule, - InstanceIdModule, - InvitesModule, - LinksModule, - MessagingModule, - NotificationsModule, - PerformanceModule, - StorageModule, - UtilsModule, -} from '../../types'; - -const FirebaseCoreModule = NativeModules.RNFirebase; - -class Firebase { - admob: AdMobModule; - analytics: AnalyticsModule; - auth: AuthModule; - config: ConfigModule; - crash: CrashModule; - database: DatabaseModule; - fabric: FabricModule; - firestore: FirestoreModule; - instanceid: InstanceIdModule; - invites: InvitesModule; - links: LinksModule; - messaging: MessagingModule; - notifications: NotificationsModule; - perf: PerformanceModule; - storage: StorageModule; - utils: UtilsModule; - - constructor() { - if (!FirebaseCoreModule) { - throw new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE); - } - APPS.initializeNativeApps(); - - // modules - this.admob = APPS.moduleAndStatics('admob', AdMobStatics, AdmobModuleName); - this.analytics = APPS.moduleAndStatics( - 'analytics', - AnalyticsStatics, - AnalyticsModuleName - ); - this.auth = APPS.moduleAndStatics('auth', AuthStatics, AuthModuleName); - this.config = APPS.moduleAndStatics( - 'config', - ConfigStatics, - ConfigModuleName - ); - this.crash = APPS.moduleAndStatics('crash', CrashStatics, CrashModuleName); - this.database = APPS.moduleAndStatics( - 'database', - DatabaseStatics, - DatabaseModuleName - ); - this.fabric = { - crashlytics: APPS.moduleAndStatics( - 'crashlytics', - CrashlyticsStatics, - CrashlyticsModuleName - ), - }; - this.firestore = APPS.moduleAndStatics( - 'firestore', - FirestoreStatics, - FirestoreModuleName - ); - this.instanceid = APPS.moduleAndStatics( - 'instanceid', - InstanceIdStatics, - InstanceIdModuleName - ); - this.invites = APPS.moduleAndStatics( - 'invites', - InvitesStatics, - InvitesModuleName - ); - this.links = APPS.moduleAndStatics('links', LinksStatics, LinksModuleName); - this.messaging = APPS.moduleAndStatics( - 'messaging', - MessagingStatics, - MessagingModuleName - ); - this.notifications = APPS.moduleAndStatics( - 'notifications', - NotificationsStatics, - NotificationsModuleName - ); - this.perf = APPS.moduleAndStatics( - 'perf', - PerformanceStatics, - PerfModuleName - ); - this.storage = APPS.moduleAndStatics( - 'storage', - StorageStatics, - StorageModuleName - ); - this.utils = APPS.moduleAndStatics('utils', UtilsStatics, UtilsModuleName); - } - - /** - * Web SDK initializeApp - * - * @param options - * @param name - * @return {*} - */ - initializeApp(options: FirebaseOptions, name: string): App { - return APPS.initializeApp(options, name); - } - - /** - * Retrieves a Firebase app instance. - * - * When called with no arguments, the default app is returned. - * When an app name is provided, the app corresponding to that name is returned. - * - * @param name - * @return {*} - */ - app(name?: string): App { - return APPS.app(name); - } - - /** - * A (read-only) array of all initialized apps. - * @return {Array} - */ - get apps(): Array { - return APPS.apps(); - } - - /** - * The current SDK version. - * @return {string} - */ - get SDK_VERSION(): string { - return VERSION; - } -} - -export default new Firebase(); diff --git a/bridge/firebase/modules/crash/index.js b/bridge/firebase/modules/crash/index.js deleted file mode 100644 index 2d9a0a8f..00000000 --- a/bridge/firebase/modules/crash/index.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @flow - * Crash Reporting representation wrapper - */ -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; -import type { FirebaseError } from '../../types'; - -export const MODULE_NAME = 'RNFirebaseCrash'; -export const NAMESPACE = 'crash'; - -export default class Crash extends ModuleBase { - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - } - - /** - * Enables/Disables crash reporting - * @param enabled - */ - setCrashCollectionEnabled(enabled: boolean): void { - getNativeModule(this).setCrashCollectionEnabled(enabled); - } - - /** - * Returns whether or not crash reporting is currently enabled - * @returns {Promise.} - */ - isCrashCollectionEnabled(): Promise { - return getNativeModule(this).isCrashCollectionEnabled(); - } - - /** - * Logs a message that will appear in a subsequent crash report. - * @param {string} message - */ - log(message: string): void { - getNativeModule(this).log(message); - } - - /** - * Logs a message that will appear in a subsequent crash report as well as in logcat. - * NOTE: Android only functionality. iOS will just log the message. - * @param {string} message - * @param {number} level - * @param {string} tag - */ - logcat(level: number, tag: string, message: string): void { - getNativeModule(this).logcat(level, tag, message); - } - - /** - * Generates a crash report for the given message. This method should be used for unexpected - * exceptions where recovery is not possible. - * NOTE: on iOS, this will cause the app to crash as it's the only way to ensure the exception - * gets sent to Firebase. Otherwise it just gets lost as a log message. - * @param {Error} error - * @param maxStackSize - */ - report(error: FirebaseError, maxStackSize: number = 10): void { - if (!error || !error.message) return; - - let errorMessage = `Message: ${error.message}\r\n`; - - if (error.code) { - errorMessage = `${errorMessage}Code: ${error.code}\r\n`; - } - - const stackRows = error.stack.split('\n'); - errorMessage = `${errorMessage}\r\nStack: \r\n`; - for (let i = 0, len = stackRows.length; i < len; i++) { - if (i === maxStackSize) break; - errorMessage = `${errorMessage} - ${stackRows[i]}\r\n`; - } - - getNativeModule(this).report(errorMessage); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/database/DataSnapshot.js b/bridge/firebase/modules/database/DataSnapshot.js deleted file mode 100644 index 31597cbf..00000000 --- a/bridge/firebase/modules/database/DataSnapshot.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @flow - * DataSnapshot representation wrapper - */ -import { isObject, deepGet, deepExists } from './../../utils'; -import type Reference from './Reference'; - -/** - * @class DataSnapshot - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot - */ -export default class DataSnapshot { - ref: Reference; - key: string; - - _value: any; - _priority: any; - _childKeys: Array; - - constructor(ref: Reference, snapshot: Object) { - this.key = snapshot.key; - - if (ref.key !== snapshot.key) { - this.ref = ref.child(snapshot.key); - } else { - this.ref = ref; - } - - // internal use only - this._value = snapshot.value; - this._priority = snapshot.priority === undefined ? null : snapshot.priority; - this._childKeys = snapshot.childKeys || []; - } - - /** - * Extracts a JavaScript value from a DataSnapshot. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#val - * @returns {any} - */ - val(): any { - // clone via JSON stringify/parse - prevent modification of this._value - if (isObject(this._value) || Array.isArray(this._value)) - return JSON.parse(JSON.stringify(this._value)); - return this._value; - } - - /** - * Gets another DataSnapshot for the location at the specified relative path. - * @param path - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach - * @returns {Snapshot} - */ - child(path: string): DataSnapshot { - const value = deepGet(this._value, path); - const childRef = this.ref.child(path); - return new DataSnapshot(childRef, { - value, - key: childRef.key, - exists: value !== null, - - // todo this is wrong - child keys needs to be the ordered keys, from FB - // todo potential solution is build up a tree/map of a snapshot and its children - // todo natively and send that back to JS to be use in this class. - childKeys: isObject(value) ? Object.keys(value) : [], - }); - } - - /** - * Returns true if this DataSnapshot contains any data. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#exists - * @returns {boolean} - */ - exists(): boolean { - return this._value !== null; - } - - /** - * Enumerates the top-level children in the DataSnapshot. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach - * @param action - */ - forEach(action: (key: any) => any): boolean { - if (!this._childKeys.length) return false; - let cancelled = false; - - for (let i = 0, len = this._childKeys.length; i < len; i++) { - const key = this._childKeys[i]; - const childSnapshot = this.child(key); - const returnValue = action(childSnapshot); - - if (returnValue === true) { - cancelled = true; - break; - } - } - - return cancelled; - } - - /** - * Gets the priority value of the data in this DataSnapshot. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#getPriority - * @returns {String|Number|null} - */ - getPriority(): string | number | null { - return this._priority; - } - - /** - * Returns true if the specified child path has (non-null) data. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#hasChild - * @param path - * @returns {Boolean} - */ - hasChild(path: string): boolean { - return deepExists(this._value, path); - } - - /** - * Returns whether or not the DataSnapshot has any non-null child properties. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#hasChildren - * @returns {boolean} - */ - hasChildren(): boolean { - return this.numChildren() > 0; - } - - /** - * Returns the number of child properties of this DataSnapshot. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#numChildren - * @returns {Number} - */ - numChildren(): number { - if (!isObject(this._value)) return 0; - return Object.keys(this._value).length; - } - - /** - * Returns a JSON-serializable representation of this object. - * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#toJSON - * @returns {any} - */ - toJSON(): Object { - return this.val(); - } -} diff --git a/bridge/firebase/modules/database/OnDisconnect.js b/bridge/firebase/modules/database/OnDisconnect.js deleted file mode 100644 index 1662b085..00000000 --- a/bridge/firebase/modules/database/OnDisconnect.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @flow - * OnDisconnect representation wrapper - */ -import { typeOf } from '../../utils'; -import { getNativeModule } from '../../utils/native'; -import type Database from './'; -import type Reference from './Reference'; - -/** - * @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect - * @class OmDisconnect - */ -export default class OnDisconnect { - _database: Database; - ref: Reference; - path: string; - - /** - * - * @param ref - */ - constructor(ref: Reference) { - this.ref = ref; - this.path = ref.path; - this._database = ref._database; - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#set - * @param value - * @returns {*} - */ - set(value: string | Object): Promise { - return getNativeModule(this._database).onDisconnectSet(this.path, { - type: typeOf(value), - value, - }); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#update - * @param values - * @returns {*} - */ - update(values: Object): Promise { - return getNativeModule(this._database).onDisconnectUpdate( - this.path, - values - ); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#remove - * @returns {*} - */ - remove(): Promise { - return getNativeModule(this._database).onDisconnectRemove(this.path); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#cancel - * @returns {*} - */ - cancel(): Promise { - return getNativeModule(this._database).onDisconnectCancel(this.path); - } -} diff --git a/bridge/firebase/modules/database/Query.js b/bridge/firebase/modules/database/Query.js deleted file mode 100644 index b58388be..00000000 --- a/bridge/firebase/modules/database/Query.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @flow - * Query representation wrapper - */ -import { objectToUniqueId } from '../../utils'; - -import type { DatabaseModifier } from '../../types'; -import type Reference from './Reference'; - -// todo doc methods - -/** - * @class Query - */ -export default class Query { - _reference: Reference; - modifiers: Array; - - constructor(ref: Reference, existingModifiers?: Array) { - this.modifiers = existingModifiers ? [...existingModifiers] : []; - this._reference = ref; - } - - /** - * - * @param name - * @param key - * @return {Reference|*} - */ - orderBy(name: string, key?: string) { - this.modifiers.push({ - id: `orderBy-${name}:${key || ''}`, - type: 'orderBy', - name, - key, - }); - - return this._reference; - } - - /** - * - * @param name - * @param limit - * @return {Reference|*} - */ - limit(name: string, limit: number) { - this.modifiers.push({ - id: `limit-${name}:${limit}`, - type: 'limit', - name, - limit, - }); - - return this._reference; - } - - /** - * - * @param name - * @param value - * @param key - * @return {Reference|*} - */ - filter(name: string, value: any, key?: string) { - this.modifiers.push({ - id: `filter-${name}:${objectToUniqueId(value)}:${key || ''}`, - type: 'filter', - name, - value, - valueType: typeof value, - key, - }); - - return this._reference; - } - - /** - * - * @return {[*]} - */ - getModifiers(): Array { - return [...this.modifiers]; - } - - /** - * - * @return {*} - */ - queryIdentifier() { - // sort modifiers to enforce ordering - const sortedModifiers = this.getModifiers().sort((a, b) => { - if (a.id < b.id) return -1; - if (a.id > b.id) return 1; - return 0; - }); - - // Convert modifiers to unique key - let key = '{'; - for (let i = 0; i < sortedModifiers.length; i++) { - if (i !== 0) key += ','; - key += sortedModifiers[i].id; - } - key += '}'; - - return key; - } -} diff --git a/bridge/firebase/modules/database/Reference.js b/bridge/firebase/modules/database/Reference.js deleted file mode 100644 index ce54e645..00000000 --- a/bridge/firebase/modules/database/Reference.js +++ /dev/null @@ -1,894 +0,0 @@ -/** - * @flow - * Database Reference representation wrapper - */ -import Query from './Query'; -import DataSnapshot from './DataSnapshot'; -import OnDisconnect from './OnDisconnect'; -import { getLogger } from '../../utils/log'; -import { getNativeModule } from '../../utils/native'; -import ReferenceBase from '../../utils/ReferenceBase'; - -import { - promiseOrCallback, - isFunction, - isObject, - isString, - tryJSONParse, - tryJSONStringify, - generatePushID, -} from '../../utils'; - -import SyncTree from '../../utils/SyncTree'; - -import type Database from './'; -import type { DatabaseModifier, FirebaseError } from '../../types'; - -// track all event registrations by path -let listeners = 0; - -/** - * Enum for event types - * @readonly - * @enum {String} - */ -const ReferenceEventTypes = { - value: 'value', - child_added: 'child_added', - child_removed: 'child_removed', - child_changed: 'child_changed', - child_moved: 'child_moved', -}; - -type DatabaseListener = { - listenerId: number, - eventName: string, - successCallback: Function, - failureCallback?: Function, -}; - -/** - * @typedef {String} ReferenceLocation - Path to location in the database, relative - * to the root reference. Consists of a path where segments are separated by a - * forward slash (/) and ends in a ReferenceKey - except the root location, which - * has no ReferenceKey. - * - * @example - * // root reference location: '/' - * // non-root reference: '/path/to/referenceKey' - */ - -/** - * @typedef {String} ReferenceKey - Identifier for each location that is unique to that - * location, within the scope of its parent. The last part of a ReferenceLocation. - */ - -/** - * Represents a specific location in your Database that can be used for - * reading or writing data. - * - * You can reference the root using firebase.database().ref() or a child location - * by calling firebase.database().ref("child/path"). - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference - * @class Reference - * @extends ReferenceBase - */ -export default class Reference extends ReferenceBase { - _database: Database; - _promise: ?Promise<*>; - _query: Query; - _refListeners: { [listenerId: number]: DatabaseListener }; - - constructor( - database: Database, - path: string, - existingModifiers?: Array - ) { - super(path); - this._promise = null; - this._refListeners = {}; - this._database = database; - this._query = new Query(this, existingModifiers); - getLogger(database).debug('Created new Reference', this._getRefKey()); - } - - /** - * By calling `keepSynced(true)` on a location, the data for that location will - * automatically be downloaded and kept in sync, even when no listeners are - * attached for that location. Additionally, while a location is kept synced, - * it will not be evicted from the persistent disk cache. - * - * @link https://firebase.google.com/docs/reference/android/com/google/firebase/database/Query.html#keepSynced(boolean) - * @param bool - * @returns {*} - */ - keepSynced(bool: boolean): Promise { - return getNativeModule(this._database).keepSynced( - this._getRefKey(), - this.path, - this._query.getModifiers(), - bool - ); - } - - /** - * Writes data to this Database location. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#set - * @param value - * @param onComplete - * @returns {Promise} - */ - set(value: any, onComplete?: Function): Promise { - return promiseOrCallback( - getNativeModule(this._database).set( - this.path, - this._serializeAnyType(value) - ), - onComplete - ); - } - - /** - * Sets a priority for the data at this Database location. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#setPriority - * @param priority - * @param onComplete - * @returns {Promise} - */ - setPriority( - priority: string | number | null, - onComplete?: Function - ): Promise { - const _priority = this._serializeAnyType(priority); - - return promiseOrCallback( - getNativeModule(this._database).setPriority(this.path, _priority), - onComplete - ); - } - - /** - * Writes data the Database location. Like set() but also specifies the priority for that data. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#setWithPriority - * @param value - * @param priority - * @param onComplete - * @returns {Promise} - */ - setWithPriority( - value: any, - priority: string | number | null, - onComplete?: Function - ): Promise { - const _value = this._serializeAnyType(value); - const _priority = this._serializeAnyType(priority); - - return promiseOrCallback( - getNativeModule(this._database).setWithPriority( - this.path, - _value, - _priority - ), - onComplete - ); - } - - /** - * Writes multiple values to the Database at once. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#update - * @param val - * @param onComplete - * @returns {Promise} - */ - update(val: Object, onComplete?: Function): Promise { - const value = this._serializeObject(val); - - return promiseOrCallback( - getNativeModule(this._database).update(this.path, value), - onComplete - ); - } - - /** - * Removes the data at this Database location. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#remove - * @param onComplete - * @return {Promise} - */ - remove(onComplete?: Function): Promise { - return promiseOrCallback( - getNativeModule(this._database).remove(this.path), - onComplete - ); - } - - /** - * Atomically modifies the data at this location. - * - * @link https://firebase.google.com/docs/reference/js/firebase.database.Reference#transaction - * @param transactionUpdate - * @param onComplete - * @param applyLocally - */ - transaction( - transactionUpdate: Function, - onComplete: ( - error: ?Error, - committed: boolean, - snapshot: ?DataSnapshot - ) => *, - applyLocally: boolean = false - ) { - if (!isFunction(transactionUpdate)) { - return Promise.reject( - new Error('Missing transactionUpdate function argument.') - ); - } - - return new Promise((resolve, reject) => { - const onCompleteWrapper = (error, committed, snapshotData) => { - if (isFunction(onComplete)) { - if (error) { - onComplete(error, committed, null); - } else { - onComplete(null, committed, new DataSnapshot(this, snapshotData)); - } - } - - if (error) return reject(error); - return resolve({ - committed, - snapshot: new DataSnapshot(this, snapshotData), - }); - }; - - // start the transaction natively - this._database._transactionHandler.add( - this, - transactionUpdate, - onCompleteWrapper, - applyLocally - ); - }); - } - - /** - * - * @param eventName - * @param successCallback - * @param cancelOrContext - * @param context - * @returns {Promise.} - */ - once( - eventName: string = 'value', - successCallback: (snapshot: DataSnapshot) => void, - cancelOrContext: (error: FirebaseError) => void, - context?: Object - ) { - return getNativeModule(this._database) - .once(this._getRefKey(), this.path, this._query.getModifiers(), eventName) - .then(({ snapshot }) => { - const _snapshot = new DataSnapshot(this, snapshot); - - if (isFunction(successCallback)) { - if (isObject(cancelOrContext)) - successCallback.bind(cancelOrContext)(_snapshot); - if (context && isObject(context)) - successCallback.bind(context)(_snapshot); - successCallback(_snapshot); - } - - return _snapshot; - }) - .catch(error => { - if (isFunction(cancelOrContext)) return cancelOrContext(error); - throw error; - }); - } - - /** - * - * @param value - * @param onComplete - * @returns {*} - */ - push(value: any, onComplete?: Function): Reference | Promise { - if (value === null || value === undefined) { - return new Reference( - this._database, - `${this.path}/${generatePushID(this._database._serverTimeOffset)}` - ); - } - - const newRef = new Reference( - this._database, - `${this.path}/${generatePushID(this._database._serverTimeOffset)}` - ); - const promise = newRef.set(value); - - // if callback provided then internally call the set promise with value - if (isFunction(onComplete)) { - return ( - promise - // $FlowExpectedError: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655 - .then(() => onComplete(null, newRef)) - // $FlowExpectedError: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655 - .catch(error => onComplete(error, null)) - ); - } - - // otherwise attach promise to 'thenable' reference and return the - // new reference - newRef._setThenable(promise); - return newRef; - } - - /** - * MODIFIERS - */ - - /** - * - * @returns {Reference} - */ - orderByKey(): Reference { - return this.orderBy('orderByKey'); - } - - /** - * - * @returns {Reference} - */ - orderByPriority(): Reference { - return this.orderBy('orderByPriority'); - } - - /** - * - * @returns {Reference} - */ - orderByValue(): Reference { - return this.orderBy('orderByValue'); - } - - /** - * - * @param key - * @returns {Reference} - */ - orderByChild(key: string): Reference { - return this.orderBy('orderByChild', key); - } - - /** - * - * @param name - * @param key - * @returns {Reference} - */ - orderBy(name: string, key?: string): Reference { - const newRef = new Reference( - this._database, - this.path, - this._query.getModifiers() - ); - newRef._query.orderBy(name, key); - return newRef; - } - - /** - * LIMITS - */ - - /** - * - * @param limit - * @returns {Reference} - */ - limitToLast(limit: number): Reference { - return this.limit('limitToLast', limit); - } - - /** - * - * @param limit - * @returns {Reference} - */ - limitToFirst(limit: number): Reference { - return this.limit('limitToFirst', limit); - } - - /** - * - * @param name - * @param limit - * @returns {Reference} - */ - limit(name: string, limit: number): Reference { - const newRef = new Reference( - this._database, - this.path, - this._query.getModifiers() - ); - newRef._query.limit(name, limit); - return newRef; - } - - /** - * FILTERS - */ - - /** - * - * @param value - * @param key - * @returns {Reference} - */ - equalTo(value: any, key?: string): Reference { - return this.filter('equalTo', value, key); - } - - /** - * - * @param value - * @param key - * @returns {Reference} - */ - endAt(value: any, key?: string): Reference { - return this.filter('endAt', value, key); - } - - /** - * - * @param value - * @param key - * @returns {Reference} - */ - startAt(value: any, key?: string): Reference { - return this.filter('startAt', value, key); - } - - /** - * - * @param name - * @param value - * @param key - * @returns {Reference} - */ - filter(name: string, value: any, key?: string): Reference { - const newRef = new Reference( - this._database, - this.path, - this._query.getModifiers() - ); - newRef._query.filter(name, value, key); - return newRef; - } - - /** - * - * @returns {OnDisconnect} - */ - onDisconnect(): OnDisconnect { - return new OnDisconnect(this); - } - - /** - * Creates a Reference to a child of the current Reference, using a relative path. - * No validation is performed on the path to ensure it has a valid format. - * @param {String} path relative to current ref's location - * @returns {!Reference} A new Reference to the path provided, relative to the current - * Reference - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#child} - */ - child(path: string): Reference { - return new Reference(this._database, `${this.path}/${path}`); - } - - /** - * Return the ref as a path string - * @returns {string} - */ - toString(): string { - return `${this._database.databaseUrl}/${this.path}`; - } - - /** - * Returns whether another Reference represent the same location and are from the - * same instance of firebase.app.App - multiple firebase apps not currently supported. - * @param {Reference} otherRef - Other reference to compare to this one - * @return {Boolean} Whether otherReference is equal to this one - * - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#isEqual} - */ - isEqual(otherRef: Reference): boolean { - return ( - !!otherRef && - otherRef.constructor === Reference && - otherRef.key === this.key && - this._query.queryIdentifier() === otherRef._query.queryIdentifier() - ); - } - - /** - * GETTERS - */ - - /** - * The parent location of a Reference, or null for the root Reference. - * @type {Reference} - * - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#parent} - */ - get parent(): Reference | null { - if (this.path === '/') return null; - return new Reference( - this._database, - this.path.substring(0, this.path.lastIndexOf('/')) - ); - } - - /** - * A reference to itself - * @type {!Reference} - * - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#ref} - */ - get ref(): Reference { - return this; - } - - /** - * Reference to the root of the database: '/' - * @type {!Reference} - * - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#root} - */ - get root(): Reference { - return new Reference(this._database, '/'); - } - - /** - * Access then method of promise if set - * @return {*} - */ - then(fnResolve: any => any, fnReject: any => any) { - if (isFunction(fnResolve) && this._promise && this._promise.then) { - return this._promise.then.bind(this._promise)( - result => { - this._promise = null; - return fnResolve(result); - }, - possibleErr => { - this._promise = null; - - if (isFunction(fnReject)) { - return fnReject(possibleErr); - } - - throw possibleErr; - } - ); - } - - throw new Error("Cannot read property 'then' of undefined."); - } - - /** - * Access catch method of promise if set - * @return {*} - */ - catch(fnReject: any => any) { - if (isFunction(fnReject) && this._promise && this._promise.catch) { - return this._promise.catch.bind(this._promise)(possibleErr => { - this._promise = null; - return fnReject(possibleErr); - }); - } - - throw new Error("Cannot read property 'catch' of undefined."); - } - - /** - * INTERNALS - */ - - /** - * Generate a unique registration key. - * - * @return {string} - */ - _getRegistrationKey(eventType: string): string { - return `$${this._database.databaseUrl}$/${ - this.path - }$${this._query.queryIdentifier()}$${listeners}$${eventType}`; - } - - /** - * Generate a string that uniquely identifies this - * combination of path and query modifiers - * - * @return {string} - * @private - */ - _getRefKey() { - return `$${this._database.databaseUrl}$/${ - this.path - }$${this._query.queryIdentifier()}`; - } - - /** - * Set the promise this 'thenable' reference relates to - * @param promise - * @private - */ - _setThenable(promise: Promise<*>) { - this._promise = promise; - } - - /** - * - * @param obj - * @returns {Object} - * @private - */ - _serializeObject(obj: Object) { - if (!isObject(obj)) return obj; - - // json stringify then parse it calls toString on Objects / Classes - // that support it i.e new Date() becomes a ISO string. - return tryJSONParse(tryJSONStringify(obj)); - } - - /** - * - * @param value - * @returns {*} - * @private - */ - _serializeAnyType(value: any) { - if (isObject(value)) { - return { - type: 'object', - value: this._serializeObject(value), - }; - } - - return { - type: typeof value, - value, - }; - } - - /** - * Register a listener for data changes at the current ref's location. - * The primary method of reading data from a Database. - * - * Listeners can be unbound using {@link off}. - * - * Event Types: - * - * - value: {@link callback}. - * - child_added: {@link callback} - * - child_removed: {@link callback} - * - child_changed: {@link callback} - * - child_moved: {@link callback} - * - * @param {ReferenceEventType} eventType - Type of event to attach a callback for. - * @param {ReferenceEventCallback} callback - Function that will be called - * when the event occurs with the new data. - * @param {cancelCallbackOrContext=} cancelCallbackOrContext - Optional callback that is called - * if the event subscription fails. {@link cancelCallbackOrContext} - * @param {*=} context - Optional object to bind the callbacks to when calling them. - * @returns {ReferenceEventCallback} callback function, unmodified (unbound), for - * convenience if you want to pass an inline function to on() and store it later for - * removing using off(). - * - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on} - */ - on( - eventType: string, - callback: DataSnapshot => any, - cancelCallbackOrContext?: Object => any | Object, - context?: Object - ): Function { - if (!eventType) { - throw new Error( - 'Query.on failed: Function called with 0 arguments. Expects at least 2.' - ); - } - - if (!isString(eventType) || !ReferenceEventTypes[eventType]) { - throw new Error( - `Query.on failed: First argument must be a valid string event type: "${Object.keys( - ReferenceEventTypes - ).join(', ')}"` - ); - } - - if (!callback) { - throw new Error( - 'Query.on failed: Function called with 1 argument. Expects at least 2.' - ); - } - - if (!isFunction(callback)) { - throw new Error( - 'Query.on failed: Second argument must be a valid function.' - ); - } - - if ( - cancelCallbackOrContext && - !isFunction(cancelCallbackOrContext) && - !isObject(context) && - !isObject(cancelCallbackOrContext) - ) { - throw new Error( - 'Query.on failed: Function called with 3 arguments, but third optional argument `cancelCallbackOrContext` was not a function.' - ); - } - - if ( - cancelCallbackOrContext && - !isFunction(cancelCallbackOrContext) && - context - ) { - throw new Error( - 'Query.on failed: Function called with 4 arguments, but third optional argument `cancelCallbackOrContext` was not a function.' - ); - } - - const eventRegistrationKey = this._getRegistrationKey(eventType); - const registrationCancellationKey = `${eventRegistrationKey}$cancelled`; - const _context = - cancelCallbackOrContext && !isFunction(cancelCallbackOrContext) - ? cancelCallbackOrContext - : context; - const registrationObj = { - eventType, - ref: this, - path: this.path, - key: this._getRefKey(), - appName: this._database.app.name, - dbURL: this._database.databaseUrl, - eventRegistrationKey, - }; - - SyncTree.addRegistration({ - ...registrationObj, - listener: _context ? callback.bind(_context) : callback, - }); - - if (cancelCallbackOrContext && isFunction(cancelCallbackOrContext)) { - // cancellations have their own separate registration - // as these are one off events, and they're not guaranteed - // to occur either, only happens on failure to register on native - SyncTree.addRegistration({ - ref: this, - once: true, - path: this.path, - key: this._getRefKey(), - appName: this._database.app.name, - dbURL: this._database.databaseUrl, - eventType: `${eventType}$cancelled`, - eventRegistrationKey: registrationCancellationKey, - listener: _context - ? cancelCallbackOrContext.bind(_context) - : cancelCallbackOrContext, - }); - } - - // initialise the native listener if not already listening - getNativeModule(this._database).on({ - eventType, - path: this.path, - key: this._getRefKey(), - appName: this._database.app.name, - modifiers: this._query.getModifiers(), - hasCancellationCallback: isFunction(cancelCallbackOrContext), - registration: { - eventRegistrationKey, - key: registrationObj.key, - registrationCancellationKey, - }, - }); - - // increment number of listeners - just s short way of making - // every registration unique per .on() call - listeners += 1; - - // return original unbound successCallback for - // the purposes of calling .off(eventType, callback) at a later date - return callback; - } - - /** - * Detaches a callback previously attached with on(). - * - * Detach a callback previously attached with on(). Note that if on() was called - * multiple times with the same eventType and callback, the callback will be called - * multiple times for each event, and off() must be called multiple times to - * remove the callback. Calling off() on a parent listener will not automatically - * remove listeners registered on child nodes, off() must also be called on any - * child listeners to remove the callback. - * - * If a callback is not specified, all callbacks for the specified eventType will be removed. - * Similarly, if no eventType or callback is specified, all callbacks for the Reference will be removed. - * @param eventType - * @param originalCallback - */ - off(eventType?: string = '', originalCallback?: () => any) { - if (!arguments.length) { - // Firebase Docs: - // if no eventType or callback is specified, all callbacks for the Reference will be removed. - return SyncTree.removeListenersForRegistrations( - SyncTree.getRegistrationsByPath(this.path) - ); - } - - /* - * VALIDATE ARGS - */ - if ( - eventType && - (!isString(eventType) || !ReferenceEventTypes[eventType]) - ) { - throw new Error( - `Query.off failed: First argument must be a valid string event type: "${Object.keys( - ReferenceEventTypes - ).join(', ')}"` - ); - } - - if (originalCallback && !isFunction(originalCallback)) { - throw new Error( - 'Query.off failed: Function called with 2 arguments, but second optional argument was not a function.' - ); - } - - // Firebase Docs: - // Note that if on() was called - // multiple times with the same eventType and callback, the callback will be called - // multiple times for each event, and off() must be called multiple times to - // remove the callback. - // Remove only a single registration - if (eventType && originalCallback) { - const registration = SyncTree.getOneByPathEventListener( - this.path, - eventType, - originalCallback - ); - if (!registration) return []; - - // remove the paired cancellation registration if any exist - SyncTree.removeListenersForRegistrations([`${registration}$cancelled`]); - - // remove only the first registration to match firebase web sdk - // call multiple times to remove multiple registrations - return SyncTree.removeListenerRegistrations(originalCallback, [ - registration, - ]); - } - - // Firebase Docs: - // If a callback is not specified, all callbacks for the specified eventType will be removed. - const registrations = SyncTree.getRegistrationsByPathEvent( - this.path, - eventType - ); - - SyncTree.removeListenersForRegistrations( - SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`) - ); - - return SyncTree.removeListenersForRegistrations(registrations); - } -} diff --git a/bridge/firebase/modules/database/index.js b/bridge/firebase/modules/database/index.js deleted file mode 100644 index fb198588..00000000 --- a/bridge/firebase/modules/database/index.js +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @flow - * Database representation wrapper - */ -import { NativeModules } from 'react-native'; - -import Reference from './Reference'; -import TransactionHandler from './transaction'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; -import firebase from '../core/firebase'; - -const NATIVE_EVENTS = [ - 'database_transaction_event', - // 'database_server_offset', // TODO -]; - -export const MODULE_NAME = 'RNFirebaseDatabase'; -export const NAMESPACE = 'database'; - -/** - * @class Database - */ -export default class Database extends ModuleBase { - _offsetRef: Reference; - _serverTimeOffset: number; - _transactionHandler: TransactionHandler; - _serviceUrl: string; - - constructor(appOrUrl: App | string, options: Object = {}) { - let app; - let serviceUrl; - if (typeof appOrUrl === 'string') { - app = firebase.app(); - serviceUrl = appOrUrl.endsWith('/') ? appOrUrl : `${appOrUrl}/`; - } else { - app = appOrUrl; - serviceUrl = app.options.databaseURL; - } - - super( - app, - { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: true, - hasShards: true, - namespace: NAMESPACE, - }, - serviceUrl - ); - - this._serviceUrl = serviceUrl; - this._transactionHandler = new TransactionHandler(this); - - if (options.persistence) { - getNativeModule(this).setPersistence(options.persistence); - } - - // server time listener - // setTimeout used to avoid setPersistence race conditions - // todo move this and persistence to native side, create a db configure() method natively perhaps? - // todo and then native can call setPersistence and then emit offset events - setTimeout(() => { - this._serverTimeOffset = 0; - this._offsetRef = this.ref('.info/serverTimeOffset'); - this._offsetRef.on('value', snapshot => { - this._serverTimeOffset = snapshot.val() || this._serverTimeOffset; - }); - }, 1); - } - - /** - * - * @return {number} - */ - getServerTime(): number { - return new Date(Date.now() + this._serverTimeOffset); - } - - /** - * - */ - goOnline(): void { - getNativeModule(this).goOnline(); - } - - /** - * - */ - goOffline(): void { - getNativeModule(this).goOffline(); - } - - /** - * Returns a new firebase reference instance - * @param path - * @returns {Reference} - */ - ref(path: string): Reference { - return new Reference(this, path); - } - - /** - * Returns the database url - * @returns {string} - */ - get databaseUrl(): string { - return this._serviceUrl; - } -} - -export const statics = { - ServerValue: NativeModules.RNFirebaseDatabase - ? { - TIMESTAMP: NativeModules.RNFirebaseDatabase.serverValueTimestamp || { - '.sv': 'timestamp', - }, - } - : {}, - enableLogging(enabled: boolean) { - if (NativeModules[MODULE_NAME]) { - NativeModules[MODULE_NAME].enableLogging(enabled); - } - }, -}; diff --git a/bridge/firebase/modules/database/transaction.js b/bridge/firebase/modules/database/transaction.js deleted file mode 100644 index 5ac6dd4e..00000000 --- a/bridge/firebase/modules/database/transaction.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @flow - * Database Transaction representation wrapper - */ -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import { getNativeModule } from '../../utils/native'; -import type Database from './'; - -let transactionId = 0; - -/** - * Uses the push id generator to create a transaction id - * @returns {number} - * @private - */ -const generateTransactionId = (): number => transactionId++; - -/** - * @class TransactionHandler - */ -export default class TransactionHandler { - _database: Database; - _transactions: { [number]: Object }; - - constructor(database: Database) { - this._transactions = {}; - this._database = database; - - SharedEventEmitter.addListener( - getAppEventName(this._database, 'database_transaction_event'), - this._handleTransactionEvent.bind(this) - ); - } - - /** - * Add a new transaction and start it natively. - * @param reference - * @param transactionUpdater - * @param onComplete - * @param applyLocally - */ - add( - reference: Object, - transactionUpdater: Function, - onComplete?: Function, - applyLocally?: boolean = false - ) { - const id = generateTransactionId(); - - this._transactions[id] = { - id, - reference, - transactionUpdater, - onComplete, - applyLocally, - completed: false, - started: true, - }; - - getNativeModule(this._database).transactionStart( - reference.path, - id, - applyLocally - ); - } - - /** - * INTERNALS - */ - - /** - * - * @param event - * @returns {*} - * @private - */ - _handleTransactionEvent(event: Object = {}) { - switch (event.type) { - case 'update': - return this._handleUpdate(event); - case 'error': - return this._handleError(event); - case 'complete': - return this._handleComplete(event); - default: - getLogger(this._database).warn( - `Unknown transaction event type: '${event.type}'`, - event - ); - return undefined; - } - } - - /** - * - * @param event - * @private - */ - _handleUpdate(event: Object = {}) { - let newValue; - const { id, value } = event; - - try { - const transaction = this._transactions[id]; - if (!transaction) return; - - newValue = transaction.transactionUpdater(value); - } finally { - let abort = false; - - if (newValue === undefined) { - abort = true; - } - - getNativeModule(this._database).transactionTryCommit(id, { - value: newValue, - abort, - }); - } - } - - /** - * - * @param event - * @private - */ - _handleError(event: Object = {}) { - const transaction = this._transactions[event.id]; - if (transaction && !transaction.completed) { - transaction.completed = true; - try { - transaction.onComplete(event.error, false, null); - } finally { - setImmediate(() => { - delete this._transactions[event.id]; - }); - } - } - } - - /** - * - * @param event - * @private - */ - _handleComplete(event: Object = {}) { - const transaction = this._transactions[event.id]; - if (transaction && !transaction.completed) { - transaction.completed = true; - try { - transaction.onComplete( - null, - event.committed, - Object.assign({}, event.snapshot) - ); - } finally { - setImmediate(() => { - delete this._transactions[event.id]; - }); - } - } - } -} diff --git a/bridge/firebase/modules/fabric/crashlytics/index.js b/bridge/firebase/modules/fabric/crashlytics/index.js deleted file mode 100644 index 7e797774..00000000 --- a/bridge/firebase/modules/fabric/crashlytics/index.js +++ /dev/null @@ -1,83 +0,0 @@ -/** - * @flow - * Crash Reporting representation wrapper - */ -import ModuleBase from '../../../utils/ModuleBase'; -import { getNativeModule } from '../../../utils/native'; - -import type App from '../../core/app'; - -export const MODULE_NAME = 'RNFirebaseCrashlytics'; -export const NAMESPACE = 'crashlytics'; - -export default class Crashlytics extends ModuleBase { - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - } - - /** - * Forces a crash. Useful for testing your application is set up correctly. - */ - crash(): void { - getNativeModule(this).crash(); - } - - /** - * Logs a message that will appear in any subsequent crash reports. - * @param {string} message - */ - log(message: string): void { - getNativeModule(this).log(message); - } - - /** - * Logs a non fatal exception. - * @param {string} code - * @param {string} message - */ - recordError(code: number, message: string): void { - getNativeModule(this).recordError(code, message); - } - - /** - * Set a boolean value to show alongside any subsequent crash reports. - */ - setBoolValue(key: string, value: boolean): void { - getNativeModule(this).setBoolValue(key, value); - } - - /** - * Set a float value to show alongside any subsequent crash reports. - */ - setFloatValue(key: string, value: number): void { - getNativeModule(this).setFloatValue(key, value); - } - - /** - * Set an integer value to show alongside any subsequent crash reports. - */ - setIntValue(key: string, value: number): void { - getNativeModule(this).setIntValue(key, value); - } - - /** - * Set a string value to show alongside any subsequent crash reports. - */ - setStringValue(key: string, value: string): void { - getNativeModule(this).setStringValue(key, value); - } - - /** - * Set the user ID to show alongside any subsequent crash reports. - */ - setUserIdentifier(userId: string): void { - getNativeModule(this).setUserIdentifier(userId); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/firestore/CollectionReference.js b/bridge/firebase/modules/firestore/CollectionReference.js deleted file mode 100644 index 57e6d2a3..00000000 --- a/bridge/firebase/modules/firestore/CollectionReference.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @flow - * CollectionReference representation wrapper - */ -import DocumentReference from './DocumentReference'; -import Query from './Query'; -import { firestoreAutoId } from '../../utils'; - -import type Firestore from './'; -import type { - QueryDirection, - QueryListenOptions, - QueryOperator, -} from './types'; -import type FieldPath from './FieldPath'; -import type Path from './Path'; -import type { Observer, ObserverOnError, ObserverOnNext } from './Query'; -import type QuerySnapshot from './QuerySnapshot'; - -/** - * @class CollectionReference - */ -export default class CollectionReference { - _collectionPath: Path; - _firestore: Firestore; - _query: Query; - - constructor(firestore: Firestore, collectionPath: Path) { - this._collectionPath = collectionPath; - this._firestore = firestore; - this._query = new Query(firestore, collectionPath); - } - - get firestore(): Firestore { - return this._firestore; - } - - get id(): string | null { - return this._collectionPath.id; - } - - get parent(): DocumentReference | null { - const parentPath = this._collectionPath.parent(); - return parentPath - ? new DocumentReference(this._firestore, parentPath) - : null; - } - - add(data: Object): Promise { - const documentRef = this.doc(); - return documentRef.set(data).then(() => Promise.resolve(documentRef)); - } - - doc(documentPath?: string): DocumentReference { - const newPath = documentPath || firestoreAutoId(); - - const path = this._collectionPath.child(newPath); - if (!path.isDocument) { - throw new Error('Argument "documentPath" must point to a document.'); - } - - return new DocumentReference(this._firestore, path); - } - - // From Query - endAt(...snapshotOrVarArgs: any[]): Query { - return this._query.endAt(snapshotOrVarArgs); - } - - endBefore(...snapshotOrVarArgs: any[]): Query { - return this._query.endBefore(snapshotOrVarArgs); - } - - get(): Promise { - return this._query.get(); - } - - limit(limit: number): Query { - return this._query.limit(limit); - } - - onSnapshot( - optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext, - observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, - onError?: ObserverOnError - ): () => void { - return this._query.onSnapshot( - optionsOrObserverOrOnNext, - observerOrOnNextOrOnError, - onError - ); - } - - orderBy(fieldPath: string | FieldPath, directionStr?: QueryDirection): Query { - return this._query.orderBy(fieldPath, directionStr); - } - - startAfter(...snapshotOrVarArgs: any[]): Query { - return this._query.startAfter(snapshotOrVarArgs); - } - - startAt(...snapshotOrVarArgs: any[]): Query { - return this._query.startAt(snapshotOrVarArgs); - } - - where(fieldPath: string, opStr: QueryOperator, value: any): Query { - return this._query.where(fieldPath, opStr, value); - } -} diff --git a/bridge/firebase/modules/firestore/DocumentChange.js b/bridge/firebase/modules/firestore/DocumentChange.js deleted file mode 100644 index 6adf9577..00000000 --- a/bridge/firebase/modules/firestore/DocumentChange.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @flow - * DocumentChange representation wrapper - */ -import DocumentSnapshot from './DocumentSnapshot'; - -import type Firestore from './'; -import type { NativeDocumentChange } from './types'; - -/** - * @class DocumentChange - */ -export default class DocumentChange { - _document: DocumentSnapshot; - _newIndex: number; - _oldIndex: number; - _type: string; - - constructor(firestore: Firestore, nativeData: NativeDocumentChange) { - this._document = new DocumentSnapshot(firestore, nativeData.document); - this._newIndex = nativeData.newIndex; - this._oldIndex = nativeData.oldIndex; - this._type = nativeData.type; - } - - get doc(): DocumentSnapshot { - return this._document; - } - - get newIndex(): number { - return this._newIndex; - } - - get oldIndex(): number { - return this._oldIndex; - } - - get type(): string { - return this._type; - } -} diff --git a/bridge/firebase/modules/firestore/DocumentReference.js b/bridge/firebase/modules/firestore/DocumentReference.js deleted file mode 100644 index ebce412b..00000000 --- a/bridge/firebase/modules/firestore/DocumentReference.js +++ /dev/null @@ -1,260 +0,0 @@ -/** - * @flow - * DocumentReference representation wrapper - */ -import CollectionReference from './CollectionReference'; -import DocumentSnapshot from './DocumentSnapshot'; -import { parseUpdateArgs } from './utils'; -import { buildNativeMap } from './utils/serialize'; -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import { firestoreAutoId, isFunction, isObject } from '../../utils'; -import { getNativeModule } from '../../utils/native'; - -import type Firestore from './'; -import type { - DocumentListenOptions, - NativeDocumentSnapshot, - SetOptions, -} from './types'; -import type Path from './Path'; - -type ObserverOnError = Object => void; -type ObserverOnNext = DocumentSnapshot => void; - -type Observer = { - error?: ObserverOnError, - next: ObserverOnNext, -}; - -/** - * @class DocumentReference - */ -export default class DocumentReference { - _documentPath: Path; - _firestore: Firestore; - - constructor(firestore: Firestore, documentPath: Path) { - this._documentPath = documentPath; - this._firestore = firestore; - } - - get firestore(): Firestore { - return this._firestore; - } - - get id(): string | null { - return this._documentPath.id; - } - - get parent(): CollectionReference { - const parentPath = this._documentPath.parent(); - // $FlowExpectedError: parentPath can never be null - return new CollectionReference(this._firestore, parentPath); - } - - get path(): string { - return this._documentPath.relativeName; - } - - collection(collectionPath: string): CollectionReference { - const path = this._documentPath.child(collectionPath); - if (!path.isCollection) { - throw new Error('Argument "collectionPath" must point to a collection.'); - } - - return new CollectionReference(this._firestore, path); - } - - delete(): Promise { - return getNativeModule(this._firestore).documentDelete(this.path); - } - - get(): Promise { - return getNativeModule(this._firestore) - .documentGet(this.path) - .then(result => new DocumentSnapshot(this._firestore, result)); - } - - onSnapshot( - optionsOrObserverOrOnNext: - | DocumentListenOptions - | Observer - | ObserverOnNext, - observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, - onError?: ObserverOnError - ) { - let observer: Observer; - let docListenOptions = {}; - // Called with: onNext, ?onError - if (isFunction(optionsOrObserverOrOnNext)) { - if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { - throw new Error( - 'DocumentReference.onSnapshot failed: Second argument must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: optionsOrObserverOrOnNext, - error: observerOrOnNextOrOnError, - }; - } else if ( - optionsOrObserverOrOnNext && - isObject(optionsOrObserverOrOnNext) - ) { - // Called with: Observer - if (optionsOrObserverOrOnNext.next) { - if (isFunction(optionsOrObserverOrOnNext.next)) { - if ( - optionsOrObserverOrOnNext.error && - !isFunction(optionsOrObserverOrOnNext.error) - ) { - throw new Error( - 'DocumentReference.onSnapshot failed: Observer.error must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: optionsOrObserverOrOnNext.next, - error: optionsOrObserverOrOnNext.error, - }; - } else { - throw new Error( - 'DocumentReference.onSnapshot failed: Observer.next must be a valid function.' - ); - } - } else if ( - Object.prototype.hasOwnProperty.call( - optionsOrObserverOrOnNext, - 'includeMetadataChanges' - ) - ) { - docListenOptions = optionsOrObserverOrOnNext; - // Called with: Options, onNext, ?onError - if (isFunction(observerOrOnNextOrOnError)) { - if (onError && !isFunction(onError)) { - throw new Error( - 'DocumentReference.onSnapshot failed: Third argument must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: observerOrOnNextOrOnError, - error: onError, - }; - // Called with Options, Observer - } else if ( - observerOrOnNextOrOnError && - isObject(observerOrOnNextOrOnError) && - observerOrOnNextOrOnError.next - ) { - if (isFunction(observerOrOnNextOrOnError.next)) { - if ( - observerOrOnNextOrOnError.error && - !isFunction(observerOrOnNextOrOnError.error) - ) { - throw new Error( - 'DocumentReference.onSnapshot failed: Observer.error must be a valid function.' - ); - } - observer = { - next: observerOrOnNextOrOnError.next, - error: observerOrOnNextOrOnError.error, - }; - } else { - throw new Error( - 'DocumentReference.onSnapshot failed: Observer.next must be a valid function.' - ); - } - } else { - throw new Error( - 'DocumentReference.onSnapshot failed: Second argument must be a function or observer.' - ); - } - } else { - throw new Error( - 'DocumentReference.onSnapshot failed: First argument must be a function, observer or options.' - ); - } - } else { - throw new Error( - 'DocumentReference.onSnapshot failed: Called with invalid arguments.' - ); - } - const listenerId = firestoreAutoId(); - - const listener = (nativeDocumentSnapshot: NativeDocumentSnapshot) => { - const documentSnapshot = new DocumentSnapshot( - this.firestore, - nativeDocumentSnapshot - ); - observer.next(documentSnapshot); - }; - - // Listen to snapshot events - SharedEventEmitter.addListener( - getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), - listener - ); - - // Listen for snapshot error events - if (observer.error) { - SharedEventEmitter.addListener( - getAppEventName( - this._firestore, - `onDocumentSnapshotError:${listenerId}` - ), - observer.error - ); - } - - // Add the native listener - getNativeModule(this._firestore).documentOnSnapshot( - this.path, - listenerId, - docListenOptions - ); - - // Return an unsubscribe method - return this._offDocumentSnapshot.bind(this, listenerId, listener); - } - - set(data: Object, options?: SetOptions): Promise { - const nativeData = buildNativeMap(data); - return getNativeModule(this._firestore).documentSet( - this.path, - nativeData, - options - ); - } - - update(...args: any[]): Promise { - const data = parseUpdateArgs(args, 'DocumentReference.update'); - const nativeData = buildNativeMap(data); - return getNativeModule(this._firestore).documentUpdate( - this.path, - nativeData - ); - } - - /** - * INTERNALS - */ - - /** - * Remove document snapshot listener - * @param listener - */ - _offDocumentSnapshot(listenerId: string, listener: Function) { - getLogger(this._firestore).info('Removing onDocumentSnapshot listener'); - SharedEventEmitter.removeListener( - getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), - listener - ); - SharedEventEmitter.removeListener( - getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), - listener - ); - getNativeModule(this._firestore).documentOffSnapshot(this.path, listenerId); - } -} diff --git a/bridge/firebase/modules/firestore/DocumentSnapshot.js b/bridge/firebase/modules/firestore/DocumentSnapshot.js deleted file mode 100644 index 23e8ef10..00000000 --- a/bridge/firebase/modules/firestore/DocumentSnapshot.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @flow - * DocumentSnapshot representation wrapper - */ -import DocumentReference from './DocumentReference'; -import FieldPath from './FieldPath'; -import Path from './Path'; -import { isObject } from '../../utils'; -import { parseNativeMap } from './utils/serialize'; - -import type Firestore from './'; -import type { NativeDocumentSnapshot, SnapshotMetadata } from './types'; - -const extractFieldPathData = (data: Object | void, segments: string[]): any => { - if (!data || !isObject(data)) { - return undefined; - } - const pathValue = data[segments[0]]; - if (segments.length === 1) { - return pathValue; - } - return extractFieldPathData(pathValue, segments.slice(1)); -}; - -/** - * @class DocumentSnapshot - */ -export default class DocumentSnapshot { - _data: Object | void; - _metadata: SnapshotMetadata; - _ref: DocumentReference; - - constructor(firestore: Firestore, nativeData: NativeDocumentSnapshot) { - this._data = parseNativeMap(firestore, nativeData.data); - this._metadata = nativeData.metadata; - this._ref = new DocumentReference( - firestore, - Path.fromName(nativeData.path) - ); - } - - get exists(): boolean { - return this._data !== undefined; - } - - get id(): string | null { - return this._ref.id; - } - - get metadata(): SnapshotMetadata { - return this._metadata; - } - - get ref(): DocumentReference { - return this._ref; - } - - data(): Object | void { - return this._data; - } - - get(fieldPath: string | FieldPath): any { - if (fieldPath instanceof FieldPath) { - return extractFieldPathData(this._data, fieldPath._segments); - } - return this._data ? this._data[fieldPath] : undefined; - } -} diff --git a/bridge/firebase/modules/firestore/FieldPath.js b/bridge/firebase/modules/firestore/FieldPath.js deleted file mode 100644 index 202f3309..00000000 --- a/bridge/firebase/modules/firestore/FieldPath.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @flow - * FieldPath representation wrapper - */ - -/** - * @class FieldPath - */ -export default class FieldPath { - _segments: string[]; - - constructor(...segments: string[]) { - // TODO: Validation - this._segments = segments; - } - - static documentId(): FieldPath { - return DOCUMENT_ID; - } -} - -export const DOCUMENT_ID = new FieldPath('__name__'); diff --git a/bridge/firebase/modules/firestore/FieldValue.js b/bridge/firebase/modules/firestore/FieldValue.js deleted file mode 100644 index 14067038..00000000 --- a/bridge/firebase/modules/firestore/FieldValue.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @flow - * FieldValue representation wrapper - */ - -export default class FieldValue { - static delete(): FieldValue { - return DELETE_FIELD_VALUE; - } - - static serverTimestamp(): FieldValue { - return SERVER_TIMESTAMP_FIELD_VALUE; - } -} - -export const DELETE_FIELD_VALUE = new FieldValue(); -export const SERVER_TIMESTAMP_FIELD_VALUE = new FieldValue(); diff --git a/bridge/firebase/modules/firestore/GeoPoint.js b/bridge/firebase/modules/firestore/GeoPoint.js deleted file mode 100644 index 2e913c4d..00000000 --- a/bridge/firebase/modules/firestore/GeoPoint.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @flow - * GeoPoint representation wrapper - */ - -/** - * @class GeoPoint - */ -export default class GeoPoint { - _latitude: number; - _longitude: number; - - constructor(latitude: number, longitude: number) { - // TODO: Validation - // validate.isNumber('latitude', latitude); - // validate.isNumber('longitude', longitude); - - this._latitude = latitude; - this._longitude = longitude; - } - - get latitude(): number { - return this._latitude; - } - - get longitude(): number { - return this._longitude; - } -} diff --git a/bridge/firebase/modules/firestore/Path.js b/bridge/firebase/modules/firestore/Path.js deleted file mode 100644 index dd215cb1..00000000 --- a/bridge/firebase/modules/firestore/Path.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @flow - * Path representation wrapper - */ - -/** - * @class Path - */ -export default class Path { - _parts: string[]; - - constructor(pathComponents: string[]) { - this._parts = pathComponents; - } - - get id(): string | null { - return this._parts.length > 0 ? this._parts[this._parts.length - 1] : null; - } - - get isDocument(): boolean { - return this._parts.length > 0 && this._parts.length % 2 === 0; - } - - get isCollection(): boolean { - return this._parts.length % 2 === 1; - } - - get relativeName(): string { - return this._parts.join('/'); - } - - child(relativePath: string): Path { - return new Path(this._parts.concat(relativePath.split('/'))); - } - - parent(): Path | null { - return this._parts.length > 0 - ? new Path(this._parts.slice(0, this._parts.length - 1)) - : null; - } - - /** - * - * @package - */ - static fromName(name: string): Path { - const parts = name.split('/'); - return parts.length === 0 ? new Path([]) : new Path(parts); - } -} diff --git a/bridge/firebase/modules/firestore/Query.js b/bridge/firebase/modules/firestore/Query.js deleted file mode 100644 index 90ad3667..00000000 --- a/bridge/firebase/modules/firestore/Query.js +++ /dev/null @@ -1,459 +0,0 @@ -/** - * @flow - * Query representation wrapper - */ -import DocumentSnapshot from './DocumentSnapshot'; -import FieldPath from './FieldPath'; -import QuerySnapshot from './QuerySnapshot'; -import { buildNativeArray, buildTypeMap } from './utils/serialize'; -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import { firestoreAutoId, isFunction, isObject } from '../../utils'; -import { getNativeModule } from '../../utils/native'; - -import type Firestore from './'; -import type Path from './Path'; -import type { - QueryDirection, - QueryOperator, - QueryListenOptions, -} from './types'; - -const DIRECTIONS: { [QueryDirection]: string } = { - ASC: 'ASCENDING', - asc: 'ASCENDING', - DESC: 'DESCENDING', - desc: 'DESCENDING', -}; - -const OPERATORS: { [QueryOperator]: string } = { - '=': 'EQUAL', - '==': 'EQUAL', - '>': 'GREATER_THAN', - '>=': 'GREATER_THAN_OR_EQUAL', - '<': 'LESS_THAN', - '<=': 'LESS_THAN_OR_EQUAL', -}; - -type NativeFieldPath = {| - elements?: string[], - string?: string, - type: 'fieldpath' | 'string', -|}; -type FieldFilter = {| - fieldPath: NativeFieldPath, - operator: string, - value: any, -|}; -type FieldOrder = {| - direction: string, - fieldPath: NativeFieldPath, -|}; -type QueryOptions = { - endAt?: any[], - endBefore?: any[], - limit?: number, - offset?: number, - selectFields?: string[], - startAfter?: any[], - startAt?: any[], -}; - -export type ObserverOnError = Object => void; -export type ObserverOnNext = QuerySnapshot => void; - -export type Observer = { - error?: ObserverOnError, - next: ObserverOnNext, -}; - -const buildNativeFieldPath = ( - fieldPath: string | FieldPath -): NativeFieldPath => { - if (fieldPath instanceof FieldPath) { - return { - elements: fieldPath._segments, - type: 'fieldpath', - }; - } - return { - string: fieldPath, - type: 'string', - }; -}; - -/** - * @class Query - */ -export default class Query { - _fieldFilters: FieldFilter[]; - _fieldOrders: FieldOrder[]; - _firestore: Firestore; - _iid: number; - _queryOptions: QueryOptions; - _referencePath: Path; - - constructor( - firestore: Firestore, - path: Path, - fieldFilters?: FieldFilter[], - fieldOrders?: FieldOrder[], - queryOptions?: QueryOptions - ) { - this._fieldFilters = fieldFilters || []; - this._fieldOrders = fieldOrders || []; - this._firestore = firestore; - this._queryOptions = queryOptions || {}; - this._referencePath = path; - } - - get firestore(): Firestore { - return this._firestore; - } - - endAt(...snapshotOrVarArgs: any[]): Query { - const options = { - ...this._queryOptions, - endAt: this._buildOrderByOption(snapshotOrVarArgs), - }; - - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - this._fieldOrders, - options - ); - } - - endBefore(...snapshotOrVarArgs: any[]): Query { - const options = { - ...this._queryOptions, - endBefore: this._buildOrderByOption(snapshotOrVarArgs), - }; - - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - this._fieldOrders, - options - ); - } - - get(): Promise { - return getNativeModule(this._firestore) - .collectionGet( - this._referencePath.relativeName, - this._fieldFilters, - this._fieldOrders, - this._queryOptions - ) - .then(nativeData => new QuerySnapshot(this._firestore, this, nativeData)); - } - - limit(limit: number): Query { - // TODO: Validation - // validate.isInteger('n', n); - - const options = { - ...this._queryOptions, - limit, - }; - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - this._fieldOrders, - options - ); - } - - onSnapshot( - optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext, - observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError, - onError?: ObserverOnError - ) { - let observer: Observer; - let queryListenOptions = {}; - // Called with: onNext, ?onError - if (isFunction(optionsOrObserverOrOnNext)) { - if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) { - throw new Error( - 'Query.onSnapshot failed: Second argument must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: optionsOrObserverOrOnNext, - error: observerOrOnNextOrOnError, - }; - } else if ( - optionsOrObserverOrOnNext && - isObject(optionsOrObserverOrOnNext) - ) { - // Called with: Observer - if (optionsOrObserverOrOnNext.next) { - if (isFunction(optionsOrObserverOrOnNext.next)) { - if ( - optionsOrObserverOrOnNext.error && - !isFunction(optionsOrObserverOrOnNext.error) - ) { - throw new Error( - 'Query.onSnapshot failed: Observer.error must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: optionsOrObserverOrOnNext.next, - error: optionsOrObserverOrOnNext.error, - }; - } else { - throw new Error( - 'Query.onSnapshot failed: Observer.next must be a valid function.' - ); - } - } else if ( - Object.prototype.hasOwnProperty.call( - optionsOrObserverOrOnNext, - 'includeDocumentMetadataChanges' - ) || - Object.prototype.hasOwnProperty.call( - optionsOrObserverOrOnNext, - 'includeQueryMetadataChanges' - ) - ) { - queryListenOptions = optionsOrObserverOrOnNext; - // Called with: Options, onNext, ?onError - if (isFunction(observerOrOnNextOrOnError)) { - if (onError && !isFunction(onError)) { - throw new Error( - 'Query.onSnapshot failed: Third argument must be a valid function.' - ); - } - // $FlowExpectedError: Not coping with the overloaded method signature - observer = { - next: observerOrOnNextOrOnError, - error: onError, - }; - // Called with Options, Observer - } else if ( - observerOrOnNextOrOnError && - isObject(observerOrOnNextOrOnError) && - observerOrOnNextOrOnError.next - ) { - if (isFunction(observerOrOnNextOrOnError.next)) { - if ( - observerOrOnNextOrOnError.error && - !isFunction(observerOrOnNextOrOnError.error) - ) { - throw new Error( - 'Query.onSnapshot failed: Observer.error must be a valid function.' - ); - } - observer = { - next: observerOrOnNextOrOnError.next, - error: observerOrOnNextOrOnError.error, - }; - } else { - throw new Error( - 'Query.onSnapshot failed: Observer.next must be a valid function.' - ); - } - } else { - throw new Error( - 'Query.onSnapshot failed: Second argument must be a function or observer.' - ); - } - } else { - throw new Error( - 'Query.onSnapshot failed: First argument must be a function, observer or options.' - ); - } - } else { - throw new Error( - 'Query.onSnapshot failed: Called with invalid arguments.' - ); - } - const listenerId = firestoreAutoId(); - - const listener = nativeQuerySnapshot => { - const querySnapshot = new QuerySnapshot( - this._firestore, - this, - nativeQuerySnapshot - ); - observer.next(querySnapshot); - }; - - // Listen to snapshot events - SharedEventEmitter.addListener( - getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), - listener - ); - - // Listen for snapshot error events - if (observer.error) { - SharedEventEmitter.addListener( - getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), - observer.error - ); - } - - // Add the native listener - getNativeModule(this._firestore).collectionOnSnapshot( - this._referencePath.relativeName, - this._fieldFilters, - this._fieldOrders, - this._queryOptions, - listenerId, - queryListenOptions - ); - - // Return an unsubscribe method - return this._offCollectionSnapshot.bind(this, listenerId, listener); - } - - orderBy( - fieldPath: string | FieldPath, - directionStr?: QueryDirection = 'asc' - ): Query { - // TODO: Validation - // validate.isFieldPath('fieldPath', fieldPath); - // validate.isOptionalFieldOrder('directionStr', directionStr); - - if ( - this._queryOptions.startAt || - this._queryOptions.startAfter || - this._queryOptions.endAt || - this._queryOptions.endBefore - ) { - throw new Error( - 'Cannot specify an orderBy() constraint after calling ' + - 'startAt(), startAfter(), endBefore() or endAt().' - ); - } - - const newOrder: FieldOrder = { - direction: DIRECTIONS[directionStr], - fieldPath: buildNativeFieldPath(fieldPath), - }; - const combinedOrders = this._fieldOrders.concat(newOrder); - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - combinedOrders, - this._queryOptions - ); - } - - startAfter(...snapshotOrVarArgs: any[]): Query { - const options = { - ...this._queryOptions, - startAfter: this._buildOrderByOption(snapshotOrVarArgs), - }; - - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - this._fieldOrders, - options - ); - } - - startAt(...snapshotOrVarArgs: any[]): Query { - const options = { - ...this._queryOptions, - startAt: this._buildOrderByOption(snapshotOrVarArgs), - }; - - return new Query( - this.firestore, - this._referencePath, - this._fieldFilters, - this._fieldOrders, - options - ); - } - - where( - fieldPath: string | FieldPath, - opStr: QueryOperator, - value: any - ): Query { - // TODO: Validation - // validate.isFieldPath('fieldPath', fieldPath); - // validate.isFieldFilter('fieldFilter', opStr, value); - const nativeValue = buildTypeMap(value); - const newFilter: FieldFilter = { - fieldPath: buildNativeFieldPath(fieldPath), - operator: OPERATORS[opStr], - value: nativeValue, - }; - const combinedFilters = this._fieldFilters.concat(newFilter); - return new Query( - this.firestore, - this._referencePath, - combinedFilters, - this._fieldOrders, - this._queryOptions - ); - } - - /** - * INTERNALS - */ - - _buildOrderByOption(snapshotOrVarArgs: any[]) { - // TODO: Validation - let values; - if ( - snapshotOrVarArgs.length === 1 && - snapshotOrVarArgs[0] instanceof DocumentSnapshot - ) { - const docSnapshot: DocumentSnapshot = snapshotOrVarArgs[0]; - values = []; - for (let i = 0; i < this._fieldOrders.length; i++) { - const fieldOrder = this._fieldOrders[i]; - if ( - fieldOrder.fieldPath.type === 'string' && - fieldOrder.fieldPath.string - ) { - values.push(docSnapshot.get(fieldOrder.fieldPath.string)); - } else if (fieldOrder.fieldPath.fieldpath) { - const fieldPath = new FieldPath(...fieldOrder.fieldPath.fieldpath); - values.push(docSnapshot.get(fieldPath)); - } - } - } else { - values = snapshotOrVarArgs; - } - - return buildNativeArray(values); - } - - /** - * Remove query snapshot listener - * @param listener - */ - _offCollectionSnapshot(listenerId: string, listener: Function) { - getLogger(this._firestore).info('Removing onQuerySnapshot listener'); - SharedEventEmitter.removeListener( - getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), - listener - ); - SharedEventEmitter.removeListener( - getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), - listener - ); - getNativeModule(this._firestore).collectionOffSnapshot( - this._referencePath.relativeName, - this._fieldFilters, - this._fieldOrders, - this._queryOptions, - listenerId - ); - } -} diff --git a/bridge/firebase/modules/firestore/QuerySnapshot.js b/bridge/firebase/modules/firestore/QuerySnapshot.js deleted file mode 100644 index d7748cf8..00000000 --- a/bridge/firebase/modules/firestore/QuerySnapshot.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @flow - * QuerySnapshot representation wrapper - */ -import DocumentChange from './DocumentChange'; -import DocumentSnapshot from './DocumentSnapshot'; - -import type Firestore from './'; -import type { - NativeDocumentChange, - NativeDocumentSnapshot, - SnapshotMetadata, -} from './types'; -import type Query from './Query'; - -type NativeQuerySnapshot = { - changes: NativeDocumentChange[], - documents: NativeDocumentSnapshot[], - metadata: SnapshotMetadata, -}; - -/** - * @class QuerySnapshot - */ -export default class QuerySnapshot { - _changes: DocumentChange[]; - _docs: DocumentSnapshot[]; - _metadata: SnapshotMetadata; - _query: Query; - - constructor( - firestore: Firestore, - query: Query, - nativeData: NativeQuerySnapshot - ) { - this._changes = nativeData.changes.map( - change => new DocumentChange(firestore, change) - ); - this._docs = nativeData.documents.map( - doc => new DocumentSnapshot(firestore, doc) - ); - this._metadata = nativeData.metadata; - this._query = query; - } - - get docChanges(): DocumentChange[] { - return this._changes; - } - - get docs(): DocumentSnapshot[] { - return this._docs; - } - - get empty(): boolean { - return this._docs.length === 0; - } - - get metadata(): SnapshotMetadata { - return this._metadata; - } - - get query(): Query { - return this._query; - } - - get size(): number { - return this._docs.length; - } - - forEach(callback: DocumentSnapshot => any) { - // TODO: Validation - // validate.isFunction('callback', callback); - - this._docs.forEach(doc => { - callback(doc); - }); - } -} diff --git a/bridge/firebase/modules/firestore/Transaction.js b/bridge/firebase/modules/firestore/Transaction.js deleted file mode 100644 index 1fa0ce13..00000000 --- a/bridge/firebase/modules/firestore/Transaction.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @flow - * Firestore Transaction representation wrapper - */ -import { parseUpdateArgs } from './utils'; -import { buildNativeMap } from './utils/serialize'; - -import type Firestore from './'; -import type { TransactionMeta } from './TransactionHandler'; -import type DocumentReference from './DocumentReference'; -import DocumentSnapshot from './DocumentSnapshot'; -import { getNativeModule } from '../../utils/native'; - -type Command = { - type: 'set' | 'update' | 'delete', - path: string, - data?: { [string]: any }, - options?: SetOptions | {}, -}; - -type SetOptions = { - merge: boolean, -}; - -// TODO docs state all get requests must be made FIRST before any modifications -// TODO so need to validate that - -/** - * @class Transaction - */ -export default class Transaction { - _pendingResult: ?any; - _firestore: Firestore; - _meta: TransactionMeta; - _commandBuffer: Array; - - constructor(firestore: Firestore, meta: TransactionMeta) { - this._meta = meta; - this._commandBuffer = []; - this._firestore = firestore; - this._pendingResult = undefined; - } - - /** - * ------------- - * INTERNAL API - * ------------- - */ - - /** - * Clears the command buffer and any pending result in prep for - * the next transaction iteration attempt. - * - * @private - */ - _prepare() { - this._commandBuffer = []; - this._pendingResult = undefined; - } - - /** - * ------------- - * PUBLIC API - * ------------- - */ - - /** - * Reads the document referenced by the provided DocumentReference. - * - * @param documentRef DocumentReference A reference to the document to be retrieved. Value must not be null. - * - * @returns Promise - */ - get(documentRef: DocumentReference): Promise { - // todo validate doc ref - return getNativeModule(this._firestore) - .transactionGetDocument(this._meta.id, documentRef.path) - .then(result => new DocumentSnapshot(this._firestore, result)); - } - - /** - * Writes to the document referred to by the provided DocumentReference. - * If the document does not exist yet, it will be created. If you pass options, - * the provided data can be merged into the existing document. - * - * @param documentRef DocumentReference A reference to the document to be created. Value must not be null. - * @param data Object An object of the fields and values for the document. - * @param options SetOptions An object to configure the set behavior. - * Pass {merge: true} to only replace the values specified in the data argument. - * Fields omitted will remain untouched. - * - * @returns {Transaction} - */ - set( - documentRef: DocumentReference, - data: Object, - options?: SetOptions - ): Transaction { - // todo validate doc ref - // todo validate data is object - this._commandBuffer.push({ - type: 'set', - path: documentRef.path, - data: buildNativeMap(data), - options: options || {}, - }); - - return this; - } - - /** - * Updates fields in the document referred to by this DocumentReference. - * The update will fail if applied to a document that does not exist. Nested - * fields can be updated by providing dot-separated field path strings or by providing FieldPath objects. - * - * @param documentRef DocumentReference A reference to the document to be updated. Value must not be null. - * @param args any Either an object containing all of the fields and values to update, - * or a series of arguments alternating between fields (as string or FieldPath - * objects) and values. - * - * @returns {Transaction} - */ - update(documentRef: DocumentReference, ...args: Array): Transaction { - // todo validate doc ref - const data = parseUpdateArgs(args, 'Transaction.update'); - this._commandBuffer.push({ - type: 'update', - path: documentRef.path, - data: buildNativeMap(data), - }); - - return this; - } - - /** - * Deletes the document referred to by the provided DocumentReference. - * - * @param documentRef DocumentReference A reference to the document to be deleted. Value must not be null. - * - * @returns {Transaction} - */ - delete(documentRef: DocumentReference): Transaction { - // todo validate doc ref - this._commandBuffer.push({ - type: 'delete', - path: documentRef.path, - }); - - return this; - } -} diff --git a/bridge/firebase/modules/firestore/TransactionHandler.js b/bridge/firebase/modules/firestore/TransactionHandler.js deleted file mode 100644 index 1f424a80..00000000 --- a/bridge/firebase/modules/firestore/TransactionHandler.js +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @flow - * Firestore Transaction representation wrapper - */ -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import { getNativeModule } from '../../utils/native'; -import Transaction from './Transaction'; -import type Firestore from './'; - -let transactionId = 0; - -/** - * Uses the push id generator to create a transaction id - * @returns {number} - * @private - */ -const generateTransactionId = (): number => transactionId++; - -export type TransactionMeta = { - id: number, - stack: string[], - reject?: Function, - resolve?: Function, - transaction: Transaction, - updateFunction: (transaction: Transaction) => Promise, -}; - -type TransactionEvent = { - id: number, - type: 'update' | 'error' | 'complete', - error: ?{ code: string, message: string }, -}; - -/** - * @class TransactionHandler - */ -export default class TransactionHandler { - _firestore: Firestore; - _pending: { - [number]: { - meta: TransactionMeta, - transaction: Transaction, - }, - }; - - constructor(firestore: Firestore) { - this._pending = {}; - this._firestore = firestore; - SharedEventEmitter.addListener( - getAppEventName(this._firestore, 'firestore_transaction_event'), - this._handleTransactionEvent.bind(this) - ); - } - - /** - * ------------- - * INTERNAL API - * ------------- - */ - - /** - * Add a new transaction and start it natively. - * @param updateFunction - */ - _add( - updateFunction: (transaction: Transaction) => Promise - ): Promise { - const id = generateTransactionId(); - // $FlowExpectedError: Transaction has to be populated - const meta: TransactionMeta = { - id, - updateFunction, - stack: new Error().stack - .split('\n') - .slice(4) - .join('\n'), - }; - - this._pending[id] = { - meta, - transaction: new Transaction(this._firestore, meta), - }; - - // deferred promise - return new Promise((resolve, reject) => { - getNativeModule(this._firestore).transactionBegin(id); - meta.resolve = r => { - resolve(r); - this._remove(id); - }; - meta.reject = e => { - reject(e); - this._remove(id); - }; - }); - } - - /** - * Destroys a local instance of a transaction meta - * - * @param id - * @private - */ - _remove(id) { - getNativeModule(this._firestore).transactionDispose(id); - delete this._pending[id]; - } - - /** - * ------------- - * EVENTS - * ------------- - */ - - /** - * Handles incoming native transaction events and distributes to correct - * internal handler by event.type - * - * @param event - * @returns {*} - * @private - */ - _handleTransactionEvent(event: TransactionEvent) { - // eslint-disable-next-line default-case - switch (event.type) { - case 'update': - this._handleUpdate(event); - break; - case 'error': - this._handleError(event); - break; - case 'complete': - this._handleComplete(event); - break; - } - } - - /** - * Handles incoming native transaction update events - * - * @param event - * @private - */ - async _handleUpdate(event: TransactionEvent) { - const { id } = event; - // abort if no longer exists js side - if (!this._pending[id]) return this._remove(id); - - const { meta, transaction } = this._pending[id]; - const { updateFunction, reject } = meta; - - // clear any saved state from previous transaction runs - transaction._prepare(); - - let finalError; - let updateFailed; - let pendingResult; - - // run the users custom update functionality - try { - const possiblePromise = updateFunction(transaction); - - // validate user has returned a promise in their update function - // TODO must it actually return a promise? Can't find any usages of it without one... - if (!possiblePromise || !possiblePromise.then) { - finalError = new Error( - 'Update function for `firestore.runTransaction(updateFunction)` must return a Promise.' - ); - } else { - pendingResult = await possiblePromise; - } - } catch (exception) { - // exception can still be falsey if user `Promise.reject();` 's with no args - // so we track the exception with a updateFailed boolean to ensure no fall-through - updateFailed = true; - finalError = exception; - } - - // reject the final promise and remove from native - // update is failed when either the users updateFunction - // throws an error or rejects a promise - if (updateFailed) { - // $FlowExpectedError: Reject will always be present - return reject(finalError); - } - - // capture the resolved result as we'll need this - // to resolve the runTransaction() promise when - // native emits that the transaction is final - transaction._pendingResult = pendingResult; - - // send the buffered update/set/delete commands for native to process - return getNativeModule(this._firestore).transactionApplyBuffer( - id, - transaction._commandBuffer - ); - } - - /** - * Handles incoming native transaction error events - * - * @param event - * @private - */ - _handleError(event: TransactionEvent) { - const { id, error } = event; - const { meta } = this._pending[id]; - - if (meta && error) { - const { code, message } = error; - // build a JS error and replace its stack - // with the captured one at start of transaction - // so it's actually relevant to the user - const errorWithStack = new Error(message); - // $FlowExpectedError: code is needed for Firebase errors - errorWithStack.code = code; - // $FlowExpectedError: stack should be a stack trace - errorWithStack.stack = meta.stack; - - // $FlowExpectedError: Reject will always be present - meta.reject(errorWithStack); - } - } - - /** - * Handles incoming native transaction complete events - * - * @param event - * @private - */ - _handleComplete(event: TransactionEvent) { - const { id } = event; - const { meta, transaction } = this._pending[id]; - - if (meta) { - const pendingResult = transaction._pendingResult; - // $FlowExpectedError: Resolve will always be present - meta.resolve(pendingResult); - } - } -} diff --git a/bridge/firebase/modules/firestore/WriteBatch.js b/bridge/firebase/modules/firestore/WriteBatch.js deleted file mode 100644 index 5f4fd163..00000000 --- a/bridge/firebase/modules/firestore/WriteBatch.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @flow - * WriteBatch representation wrapper - */ -import { parseUpdateArgs } from './utils'; -import { buildNativeMap } from './utils/serialize'; -import { getNativeModule } from '../../utils/native'; - -import type DocumentReference from './DocumentReference'; -import type Firestore from './'; -import type { SetOptions } from './types'; - -type DocumentWrite = { - data?: Object, - options?: Object, - path: string, - type: 'DELETE' | 'SET' | 'UPDATE', -}; - -/** - * @class WriteBatch - */ -export default class WriteBatch { - _firestore: Firestore; - _writes: DocumentWrite[]; - - constructor(firestore: Firestore) { - this._firestore = firestore; - this._writes = []; - } - - commit(): Promise { - return getNativeModule(this._firestore).documentBatch(this._writes); - } - - delete(docRef: DocumentReference): WriteBatch { - // TODO: Validation - // validate.isDocumentReference('docRef', docRef); - // validate.isOptionalPrecondition('deleteOptions', deleteOptions); - this._writes.push({ - path: docRef.path, - type: 'DELETE', - }); - - return this; - } - - set(docRef: DocumentReference, data: Object, options?: SetOptions) { - // TODO: Validation - // validate.isDocumentReference('docRef', docRef); - // validate.isDocument('data', data); - // validate.isOptionalPrecondition('options', writeOptions); - const nativeData = buildNativeMap(data); - this._writes.push({ - data: nativeData, - options, - path: docRef.path, - type: 'SET', - }); - - return this; - } - - update(docRef: DocumentReference, ...args: any[]): WriteBatch { - // TODO: Validation - // validate.isDocumentReference('docRef', docRef); - const data = parseUpdateArgs(args, 'WriteBatch.update'); - this._writes.push({ - data: buildNativeMap(data), - path: docRef.path, - type: 'UPDATE', - }); - - return this; - } -} diff --git a/bridge/firebase/modules/firestore/index.js b/bridge/firebase/modules/firestore/index.js deleted file mode 100644 index e8047894..00000000 --- a/bridge/firebase/modules/firestore/index.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * @flow - * Firestore representation wrapper - */ -import { NativeModules } from 'react-native'; - -import { getAppEventName, SharedEventEmitter } from '../../utils/events'; -import ModuleBase from '../../utils/ModuleBase'; -import CollectionReference from './CollectionReference'; -import DocumentReference from './DocumentReference'; -import FieldPath from './FieldPath'; -import FieldValue from './FieldValue'; -import GeoPoint from './GeoPoint'; -import Path from './Path'; -import WriteBatch from './WriteBatch'; -import TransactionHandler from './TransactionHandler'; -import Transaction from './Transaction'; -import INTERNALS from '../../utils/internals'; - -import type DocumentSnapshot from './DocumentSnapshot'; -import type App from '../core/app'; -import type QuerySnapshot from './QuerySnapshot'; - -type CollectionSyncEvent = { - appName: string, - querySnapshot?: QuerySnapshot, - error?: Object, - listenerId: string, - path: string, -}; - -type DocumentSyncEvent = { - appName: string, - documentSnapshot?: DocumentSnapshot, - error?: Object, - listenerId: string, - path: string, -}; - -const NATIVE_EVENTS = [ - 'firestore_transaction_event', - 'firestore_document_sync_event', - 'firestore_collection_sync_event', -]; - -export const MODULE_NAME = 'RNFirebaseFirestore'; -export const NAMESPACE = 'firestore'; - -/** - * @class Firestore - */ -export default class Firestore extends ModuleBase { - _referencePath: Path; - _transactionHandler: TransactionHandler; - - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: true, - hasShards: false, - namespace: NAMESPACE, - }); - - this._referencePath = new Path([]); - this._transactionHandler = new TransactionHandler(this); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onCollectionSnapshot - getAppEventName(this, 'firestore_collection_sync_event'), - this._onCollectionSyncEvent.bind(this) - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onDocumentSnapshot - getAppEventName(this, 'firestore_document_sync_event'), - this._onDocumentSyncEvent.bind(this) - ); - } - - /** - * ------------- - * PUBLIC API - * ------------- - */ - - /** - * Creates a write batch, used for performing multiple writes as a single atomic operation. - * - * @returns {WriteBatch} - */ - batch(): WriteBatch { - return new WriteBatch(this); - } - - /** - * Gets a CollectionReference instance that refers to the collection at the specified path. - * - * @param collectionPath - * @returns {CollectionReference} - */ - collection(collectionPath: string): CollectionReference { - const path = this._referencePath.child(collectionPath); - if (!path.isCollection) { - throw new Error('Argument "collectionPath" must point to a collection.'); - } - - return new CollectionReference(this, path); - } - - /** - * Gets a DocumentReference instance that refers to the document at the specified path. - * - * @param documentPath - * @returns {DocumentReference} - */ - doc(documentPath: string): DocumentReference { - const path = this._referencePath.child(documentPath); - if (!path.isDocument) { - throw new Error('Argument "documentPath" must point to a document.'); - } - - return new DocumentReference(this, path); - } - - /** - * Executes the given updateFunction and then attempts to commit the - * changes applied within the transaction. If any document read within - * the transaction has changed, Cloud Firestore retries the updateFunction. - * - * If it fails to commit after 5 attempts, the transaction fails. - * - * @param updateFunction - * @returns {void|Promise} - */ - runTransaction( - updateFunction: (transaction: Transaction) => Promise - ): Promise { - return this._transactionHandler._add(updateFunction); - } - - /** - * ------------- - * UNSUPPORTED - * ------------- - */ - - setLogLevel(): void { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'firestore', - 'setLogLevel' - ) - ); - } - - enableNetwork(): void { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'firestore', - 'enableNetwork' - ) - ); - } - - disableNetwork(): void { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'firestore', - 'disableNetwork' - ) - ); - } - - /** - * ------------- - * MISC - * ------------- - */ - - enablePersistence(): Promise { - throw new Error('Persistence is enabled by default on the Firestore SDKs'); - } - - settings(): void { - throw new Error('firebase.firestore().settings() coming soon'); - } - - /** - * ------------- - * INTERNALS - * ------------- - */ - - /** - * 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 = { - FieldPath, - FieldValue, - GeoPoint, - enableLogging(enabled: boolean) { - if (NativeModules[MODULE_NAME]) { - NativeModules[MODULE_NAME].enableLogging(enabled); - } - }, -}; diff --git a/bridge/firebase/modules/firestore/types.js b/bridge/firebase/modules/firestore/types.js deleted file mode 100644 index 6ed935dc..00000000 --- a/bridge/firebase/modules/firestore/types.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * @flow - */ - -export type DocumentListenOptions = { - includeMetadataChanges: boolean, -}; - -export type QueryDirection = 'DESC' | 'desc' | 'ASC' | 'asc'; - -export type QueryListenOptions = {| - includeDocumentMetadataChanges: boolean, - includeQueryMetadataChanges: boolean, -|}; - -export type QueryOperator = '<' | '<=' | '=' | '==' | '>' | '>='; - -export type SetOptions = { - merge?: boolean, -}; - -export type SnapshotMetadata = { - fromCache: boolean, - hasPendingWrites: boolean, -}; - -export type NativeDocumentChange = { - document: NativeDocumentSnapshot, - newIndex: number, - oldIndex: number, - type: string, -}; - -export type NativeDocumentSnapshot = { - data: { [string]: NativeTypeMap }, - metadata: SnapshotMetadata, - path: string, -}; - -export type NativeTypeMap = { - type: - | 'array' - | 'boolean' - | 'date' - | 'documentid' - | 'fieldvalue' - | 'geopoint' - | 'null' - | 'number' - | 'object' - | 'reference' - | 'string', - value: any, -}; diff --git a/bridge/firebase/modules/firestore/utils/index.js b/bridge/firebase/modules/firestore/utils/index.js deleted file mode 100644 index 6aabeeaf..00000000 --- a/bridge/firebase/modules/firestore/utils/index.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @flow - */ -import FieldPath from '../FieldPath'; -import { isObject, isString } from '../../../utils'; - -const buildFieldPathData = (segments: string[], value: any): Object => { - if (segments.length === 1) { - return { - [segments[0]]: value, - }; - } - return { - [segments[0]]: buildFieldPathData(segments.slice(1), value), - }; -}; - -// eslint-disable-next-line import/prefer-default-export -export const mergeFieldPathData = ( - data: Object, - segments: string[], - value: any -): Object => { - if (segments.length === 1) { - return { - ...data, - [segments[0]]: value, - }; - } else if (data[segments[0]]) { - return { - ...data, - [segments[0]]: mergeFieldPathData( - data[segments[0]], - segments.slice(1), - value - ), - }; - } - return { - ...data, - [segments[0]]: buildFieldPathData(segments.slice(1), value), - }; -}; - -export const parseUpdateArgs = (args: any[], methodName: string) => { - let data = {}; - if (args.length === 1) { - if (!isObject(args[0])) { - throw new Error( - `${methodName} failed: If using a single update argument, it must be an object.` - ); - } - [data] = args; - } else if (args.length % 2 === 1) { - throw new Error( - `${methodName} failed: The update arguments must be either a single object argument, or equal numbers of key/value pairs.` - ); - } else { - for (let i = 0; i < args.length; i += 2) { - const key = args[i]; - const value = args[i + 1]; - if (isString(key)) { - data[key] = value; - } else if (key instanceof FieldPath) { - data = mergeFieldPathData(data, key._segments, value); - } else { - throw new Error( - `${methodName} failed: Argument at index ${i} must be a string or FieldPath` - ); - } - } - } - return data; -}; diff --git a/bridge/firebase/modules/firestore/utils/serialize.js b/bridge/firebase/modules/firestore/utils/serialize.js deleted file mode 100644 index 8ea8a5d7..00000000 --- a/bridge/firebase/modules/firestore/utils/serialize.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @flow - */ - -import DocumentReference from '../DocumentReference'; -import { DOCUMENT_ID } from '../FieldPath'; -import { - DELETE_FIELD_VALUE, - SERVER_TIMESTAMP_FIELD_VALUE, -} from '../FieldValue'; -import GeoPoint from '../GeoPoint'; -import Path from '../Path'; -import { typeOf } from '../../../utils'; - -import type Firestore from '../'; -import type { NativeTypeMap } from '../types'; - -/* - * Functions that build up the data needed to represent - * the different types available within Firestore - * for transmission to the native side - */ - -export const buildNativeMap = (data: Object): { [string]: NativeTypeMap } => { - const nativeData = {}; - if (data) { - Object.keys(data).forEach(key => { - const typeMap = buildTypeMap(data[key]); - if (typeMap) { - nativeData[key] = typeMap; - } - }); - } - return nativeData; -}; - -export const buildNativeArray = (array: Object[]): NativeTypeMap[] => { - const nativeArray = []; - if (array) { - array.forEach(value => { - const typeMap = buildTypeMap(value); - if (typeMap) { - nativeArray.push(typeMap); - } - }); - } - return nativeArray; -}; - -export const buildTypeMap = (value: any): NativeTypeMap | null => { - const type = typeOf(value); - if (value === null || value === undefined || Number.isNaN(value)) { - return { - type: 'null', - value: null, - }; - } else if (value === DELETE_FIELD_VALUE) { - return { - type: 'fieldvalue', - value: 'delete', - }; - } else if (value === SERVER_TIMESTAMP_FIELD_VALUE) { - return { - type: 'fieldvalue', - value: 'timestamp', - }; - } else if (value === DOCUMENT_ID) { - return { - type: 'documentid', - value: null, - }; - } else if (type === 'boolean' || type === 'number' || type === 'string') { - return { - type, - value, - }; - } else if (type === 'array') { - return { - type, - value: buildNativeArray(value), - }; - } else if (type === 'object') { - if (value instanceof DocumentReference) { - return { - type: 'reference', - value: value.path, - }; - } else if (value instanceof GeoPoint) { - return { - type: 'geopoint', - value: { - latitude: value.latitude, - longitude: value.longitude, - }, - }; - } else if (value instanceof Date) { - return { - type: 'date', - value: value.getTime(), - }; - } - return { - type: 'object', - value: buildNativeMap(value), - }; - } - console.warn(`Unknown data type received ${type}`); - return null; -}; - -/* - * Functions that parse the received from the native - * side and converts to the correct Firestore JS types - */ - -export const parseNativeMap = ( - firestore: Firestore, - nativeData: { [string]: NativeTypeMap } -): Object | void => { - let data; - if (nativeData) { - data = {}; - Object.keys(nativeData).forEach(key => { - data[key] = parseTypeMap(firestore, nativeData[key]); - }); - } - return data; -}; - -const parseNativeArray = ( - firestore: Firestore, - nativeArray: NativeTypeMap[] -): any[] => { - const array = []; - if (nativeArray) { - nativeArray.forEach(typeMap => { - array.push(parseTypeMap(firestore, typeMap)); - }); - } - return array; -}; - -const parseTypeMap = (firestore: Firestore, typeMap: NativeTypeMap): any => { - const { type, value } = typeMap; - if (type === 'null') { - return null; - } else if (type === 'boolean' || type === 'number' || type === 'string') { - return value; - } else if (type === 'array') { - return parseNativeArray(firestore, value); - } else if (type === 'object') { - return parseNativeMap(firestore, value); - } else if (type === 'reference') { - return new DocumentReference(firestore, Path.fromName(value)); - } else if (type === 'geopoint') { - return new GeoPoint(value.latitude, value.longitude); - } else if (type === 'date') { - return new Date(value); - } - console.warn(`Unknown data type received ${type}`); - return value; -}; diff --git a/bridge/firebase/modules/instanceid/index.js b/bridge/firebase/modules/instanceid/index.js deleted file mode 100644 index 0cd6528d..00000000 --- a/bridge/firebase/modules/instanceid/index.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @flow - * Instance ID representation wrapper - */ -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; - -export const MODULE_NAME = 'RNFirebaseInstanceId'; -export const NAMESPACE = 'instanceid'; - -export default class InstanceId extends ModuleBase { - constructor(app: App) { - super(app, { - hasShards: false, - moduleName: MODULE_NAME, - multiApp: false, - namespace: NAMESPACE, - }); - } - - delete(): Promise { - return getNativeModule(this).delete(); - } - - get(): Promise { - return getNativeModule(this).get(); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/invites/AndroidInvitation.js b/bridge/firebase/modules/invites/AndroidInvitation.js deleted file mode 100644 index 31a87d51..00000000 --- a/bridge/firebase/modules/invites/AndroidInvitation.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @flow - * AndroidInvitation representation wrapper - */ -import type Invitation from './Invitation'; -import type { NativeAndroidInvitation } from './types'; - -export default class AndroidInvitation { - _additionalReferralParameters: { [string]: string } | void; - _emailHtmlContent: string | void; - _emailSubject: string | void; - _googleAnalyticsTrackingId: string | void; - _invitation: Invitation; - - constructor(invitation: Invitation) { - this._invitation = invitation; - } - - /** - * - * @param additionalReferralParameters - * @returns {Invitation} - */ - setAdditionalReferralParameters(additionalReferralParameters: { - [string]: string, - }): Invitation { - this._additionalReferralParameters = additionalReferralParameters; - return this._invitation; - } - - /** - * - * @param emailHtmlContent - * @returns {Invitation} - */ - setEmailHtmlContent(emailHtmlContent: string): Invitation { - this._emailHtmlContent = emailHtmlContent; - return this._invitation; - } - - /** - * - * @param emailSubject - * @returns {Invitation} - */ - setEmailSubject(emailSubject: string): Invitation { - this._emailSubject = emailSubject; - return this._invitation; - } - - /** - * - * @param googleAnalyticsTrackingId - * @returns {Invitation} - */ - setGoogleAnalyticsTrackingId(googleAnalyticsTrackingId: string): Invitation { - this._googleAnalyticsTrackingId = googleAnalyticsTrackingId; - return this._invitation; - } - - build(): NativeAndroidInvitation { - return { - additionalReferralParameters: this._additionalReferralParameters, - emailHtmlContent: this._emailHtmlContent, - emailSubject: this._emailSubject, - googleAnalyticsTrackingId: this._googleAnalyticsTrackingId, - }; - } -} diff --git a/bridge/firebase/modules/invites/Invitation.js b/bridge/firebase/modules/invites/Invitation.js deleted file mode 100644 index 04c0b0aa..00000000 --- a/bridge/firebase/modules/invites/Invitation.js +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @flow - * Invitation representation wrapper - */ -import { Platform } from 'react-native'; -import AndroidInvitation from './AndroidInvitation'; - -import type { NativeInvitation } from './types'; - -export default class Invitation { - _android: AndroidInvitation; - _androidClientId: string | void; - _androidMinimumVersionCode: number | void; - _callToActionText: string | void; - _customImage: string | void; - _deepLink: string | void; - _iosClientId: string | void; - _message: string; - _title: string; - - constructor(title: string, message: string) { - this._android = new AndroidInvitation(this); - this._message = message; - this._title = title; - } - - get android(): AndroidInvitation { - return this._android; - } - - /** - * - * @param androidClientId - * @returns {Invitation} - */ - setAndroidClientId(androidClientId: string): Invitation { - this._androidClientId = androidClientId; - return this; - } - - /** - * - * @param androidMinimumVersionCode - * @returns {Invitation} - */ - setAndroidMinimumVersionCode(androidMinimumVersionCode: number): Invitation { - this._androidMinimumVersionCode = androidMinimumVersionCode; - return this; - } - - /** - * - * @param callToActionText - * @returns {Invitation} - */ - setCallToActionText(callToActionText: string): Invitation { - this._callToActionText = callToActionText; - return this; - } - - /** - * - * @param customImage - * @returns {Invitation} - */ - setCustomImage(customImage: string): Invitation { - this._customImage = customImage; - return this; - } - - /** - * - * @param deepLink - * @returns {Invitation} - */ - setDeepLink(deepLink: string): Invitation { - this._deepLink = deepLink; - return this; - } - - /** - * - * @param iosClientId - * @returns {Invitation} - */ - setIOSClientId(iosClientId: string): Invitation { - this._iosClientId = iosClientId; - return this; - } - - build(): NativeInvitation { - if (!this._message) { - throw new Error('Invitation: Missing required `message` property'); - } else if (!this._title) { - throw new Error('Invitation: Missing required `title` property'); - } - - return { - android: Platform.OS === 'android' ? this._android.build() : undefined, - androidClientId: this._androidClientId, - androidMinimumVersionCode: this._androidMinimumVersionCode, - callToActionText: this._callToActionText, - customImage: this._customImage, - deepLink: this._deepLink, - iosClientId: this._iosClientId, - message: this._message, - title: this._title, - }; - } -} diff --git a/bridge/firebase/modules/invites/index.js b/bridge/firebase/modules/invites/index.js deleted file mode 100644 index 3ba53fae..00000000 --- a/bridge/firebase/modules/invites/index.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @flow - * Invites representation wrapper - */ -import { SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; -import Invitation from './Invitation'; - -import type App from '../core/app'; - -export const MODULE_NAME = 'RNFirebaseInvites'; -export const NAMESPACE = 'invites'; -const NATIVE_EVENTS = ['invites_invitation_received']; - -type InvitationOpen = { - deepLink: string, - invitationId: string, -}; - -export default class Invites extends ModuleBase { - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - hasShards: false, - moduleName: MODULE_NAME, - multiApp: false, - namespace: NAMESPACE, - }); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onMessage - 'invites_invitation_received', - (invitation: InvitationOpen) => { - SharedEventEmitter.emit('onInvitation', invitation); - } - ); - } - - /** - * Returns the invitation that triggered application open - * @returns {Promise.} - */ - getInitialInvitation(): Promise { - return getNativeModule(this).getInitialInvitation(); - } - - /** - * Subscribe to invites - * @param listener - * @returns {Function} - */ - onInvitation(listener: InvitationOpen => any) { - getLogger(this).info('Creating onInvitation listener'); - - SharedEventEmitter.addListener('onInvitation', listener); - - return () => { - getLogger(this).info('Removing onInvitation listener'); - SharedEventEmitter.removeListener('onInvitation', listener); - }; - } - - sendInvitation(invitation: Invitation): Promise { - if (!(invitation instanceof Invitation)) { - throw new Error( - `Invites:sendInvitation expects an 'Invitation' but got type ${typeof invitation}` - ); - } - return getNativeModule(this).sendInvitation(invitation.build()); - } -} - -export const statics = { - Invitation, -}; diff --git a/bridge/firebase/modules/invites/types.js b/bridge/firebase/modules/invites/types.js deleted file mode 100644 index 45e24727..00000000 --- a/bridge/firebase/modules/invites/types.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @flow - */ -export type NativeAndroidInvitation = {| - additionalReferralParameters?: { [string]: string }, - emailHtmlContent?: string, - emailSubject?: string, - googleAnalyticsTrackingId?: string, -|}; - -export type NativeInvitation = {| - android?: NativeAndroidInvitation, - androidClientId?: string, - androidMinimumVersionCode?: number, - callToActionText?: string, - customImage?: string, - deepLink?: string, - iosClientId?: string, - message: string, - title: string, -|}; diff --git a/bridge/firebase/modules/links/AnalyticsParameters.js b/bridge/firebase/modules/links/AnalyticsParameters.js deleted file mode 100644 index 36e77209..00000000 --- a/bridge/firebase/modules/links/AnalyticsParameters.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @flow - * AnalyticsParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeAnalyticsParameters } from './types'; - -export default class AnalyticsParameters { - _campaign: string | void; - _content: string | void; - _link: DynamicLink; - _medium: string | void; - _source: string | void; - _term: string | void; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param campaign - * @returns {DynamicLink} - */ - setCampaign(campaign: string): DynamicLink { - this._campaign = campaign; - return this._link; - } - - /** - * - * @param content - * @returns {DynamicLink} - */ - setContent(content: string): DynamicLink { - this._content = content; - return this._link; - } - - /** - * - * @param medium - * @returns {DynamicLink} - */ - setMedium(medium: string): DynamicLink { - this._medium = medium; - return this._link; - } - - /** - * - * @param source - * @returns {DynamicLink} - */ - setSource(source: string): DynamicLink { - this._source = source; - return this._link; - } - - /** - * - * @param term - * @returns {DynamicLink} - */ - setTerm(term: string): DynamicLink { - this._term = term; - return this._link; - } - - build(): NativeAnalyticsParameters { - return { - campaign: this._campaign, - content: this._content, - medium: this._medium, - source: this._source, - term: this._term, - }; - } -} diff --git a/bridge/firebase/modules/links/AndroidParameters.js b/bridge/firebase/modules/links/AndroidParameters.js deleted file mode 100644 index 985bfd4b..00000000 --- a/bridge/firebase/modules/links/AndroidParameters.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @flow - * AndroidParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeAndroidParameters } from './types'; - -export default class AndroidParameters { - _fallbackUrl: string | void; - _link: DynamicLink; - _minimumVersion: number | void; - _packageName: string | void; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param fallbackUrl - * @returns {DynamicLink} - */ - setFallbackUrl(fallbackUrl: string): DynamicLink { - this._fallbackUrl = fallbackUrl; - return this._link; - } - - /** - * - * @param minimumVersion - * @returns {DynamicLink} - */ - setMinimumVersion(minimumVersion: number): DynamicLink { - this._minimumVersion = minimumVersion; - return this._link; - } - - /** - * - * @param packageName - * @returns {DynamicLink} - */ - setPackageName(packageName: string): DynamicLink { - this._packageName = packageName; - return this._link; - } - - build(): NativeAndroidParameters { - if ((this._fallbackUrl || this._minimumVersion) && !this._packageName) { - throw new Error( - 'AndroidParameters: Missing required `packageName` property' - ); - } - return { - fallbackUrl: this._fallbackUrl, - minimumVersion: this._minimumVersion, - packageName: this._packageName, - }; - } -} diff --git a/bridge/firebase/modules/links/DynamicLink.js b/bridge/firebase/modules/links/DynamicLink.js deleted file mode 100644 index 2930a3d0..00000000 --- a/bridge/firebase/modules/links/DynamicLink.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @flow - * DynamicLink representation wrapper - */ -import AnalyticsParameters from './AnalyticsParameters'; -import AndroidParameters from './AndroidParameters'; -import IOSParameters from './IOSParameters'; -import ITunesParameters from './ITunesParameters'; -import NavigationParameters from './NavigationParameters'; -import SocialParameters from './SocialParameters'; - -import type { NativeDynamicLink } from './types'; - -export default class DynamicLink { - _analytics: AnalyticsParameters; - _android: AndroidParameters; - _dynamicLinkDomain: string; - _ios: IOSParameters; - _itunes: ITunesParameters; - _link: string; - _navigation: NavigationParameters; - _social: SocialParameters; - - constructor(link: string, dynamicLinkDomain: string) { - this._analytics = new AnalyticsParameters(this); - this._android = new AndroidParameters(this); - this._dynamicLinkDomain = dynamicLinkDomain; - this._ios = new IOSParameters(this); - this._itunes = new ITunesParameters(this); - this._link = link; - this._navigation = new NavigationParameters(this); - this._social = new SocialParameters(this); - } - - get analytics(): AnalyticsParameters { - return this._analytics; - } - - get android(): AndroidParameters { - return this._android; - } - - get ios(): IOSParameters { - return this._ios; - } - - get itunes(): ITunesParameters { - return this._itunes; - } - - get navigation(): NavigationParameters { - return this._navigation; - } - - get social(): SocialParameters { - return this._social; - } - - build(): NativeDynamicLink { - if (!this._link) { - throw new Error('DynamicLink: Missing required `link` property'); - } else if (!this._dynamicLinkDomain) { - throw new Error( - 'DynamicLink: Missing required `dynamicLinkDomain` property' - ); - } - - return { - analytics: this._analytics.build(), - android: this._android.build(), - dynamicLinkDomain: this._dynamicLinkDomain, - ios: this._ios.build(), - itunes: this._itunes.build(), - link: this._link, - navigation: this._navigation.build(), - social: this._social.build(), - }; - } -} diff --git a/bridge/firebase/modules/links/IOSParameters.js b/bridge/firebase/modules/links/IOSParameters.js deleted file mode 100644 index 1ac46631..00000000 --- a/bridge/firebase/modules/links/IOSParameters.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * @flow - * IOSParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeIOSParameters } from './types'; - -export default class IOSParameters { - _appStoreId: string | void; - _bundleId: string | void; - _customScheme: string | void; - _fallbackUrl: string | void; - _iPadBundleId: string | void; - _iPadFallbackUrl: string | void; - _link: DynamicLink; - _minimumVersion: string | void; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param appStoreId - * @returns {DynamicLink} - */ - setAppStoreId(appStoreId: string): DynamicLink { - this._appStoreId = appStoreId; - return this._link; - } - - /** - * - * @param bundleId - * @returns {DynamicLink} - */ - setBundleId(bundleId: string): DynamicLink { - this._bundleId = bundleId; - return this._link; - } - - /** - * - * @param customScheme - * @returns {DynamicLink} - */ - setCustomScheme(customScheme: string): DynamicLink { - this._customScheme = customScheme; - return this._link; - } - - /** - * - * @param fallbackUrl - * @returns {DynamicLink} - */ - setFallbackUrl(fallbackUrl: string): DynamicLink { - this._fallbackUrl = fallbackUrl; - return this._link; - } - - /** - * - * @param iPadBundleId - * @returns {DynamicLink} - */ - setIPadBundleId(iPadBundleId: string): DynamicLink { - this._iPadBundleId = iPadBundleId; - return this._link; - } - - /** - * - * @param iPadFallbackUrl - * @returns {DynamicLink} - */ - setIPadFallbackUrl(iPadFallbackUrl: string): DynamicLink { - this._iPadFallbackUrl = iPadFallbackUrl; - return this._link; - } - - /** - * - * @param minimumVersion - * @returns {DynamicLink} - */ - setMinimumVersion(minimumVersion: string): DynamicLink { - this._minimumVersion = minimumVersion; - return this._link; - } - - build(): NativeIOSParameters { - if ( - (this._appStoreId || - this._customScheme || - this._fallbackUrl || - this._iPadBundleId || - this._iPadFallbackUrl || - this._minimumVersion) && - !this._bundleId - ) { - throw new Error('IOSParameters: Missing required `bundleId` property'); - } - return { - appStoreId: this._appStoreId, - bundleId: this._bundleId, - customScheme: this._customScheme, - fallbackUrl: this._fallbackUrl, - iPadBundleId: this._iPadBundleId, - iPadFallbackUrl: this._iPadFallbackUrl, - minimumVersion: this._minimumVersion, - }; - } -} diff --git a/bridge/firebase/modules/links/ITunesParameters.js b/bridge/firebase/modules/links/ITunesParameters.js deleted file mode 100644 index 784a99ff..00000000 --- a/bridge/firebase/modules/links/ITunesParameters.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @flow - * ITunesParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeITunesParameters } from './types'; - -export default class ITunesParameters { - _affiliateToken: string | void; - _campaignToken: string | void; - _link: DynamicLink; - _providerToken: string | void; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param affiliateToken - * @returns {DynamicLink} - */ - setAffiliateToken(affiliateToken: string): DynamicLink { - this._affiliateToken = affiliateToken; - return this._link; - } - - /** - * - * @param campaignToken - * @returns {DynamicLink} - */ - setCampaignToken(campaignToken: string): DynamicLink { - this._campaignToken = campaignToken; - return this._link; - } - - /** - * - * @param providerToken - * @returns {DynamicLink} - */ - setProviderToken(providerToken: string): DynamicLink { - this._providerToken = providerToken; - return this._link; - } - - build(): NativeITunesParameters { - return { - affiliateToken: this._affiliateToken, - campaignToken: this._campaignToken, - providerToken: this._providerToken, - }; - } -} diff --git a/bridge/firebase/modules/links/NavigationParameters.js b/bridge/firebase/modules/links/NavigationParameters.js deleted file mode 100644 index dbb408fb..00000000 --- a/bridge/firebase/modules/links/NavigationParameters.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @flow - * NavigationParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeNavigationParameters } from './types'; - -export default class NavigationParameters { - _forcedRedirectEnabled: string | void; - _link: DynamicLink; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param forcedRedirectEnabled - * @returns {DynamicLink} - */ - setForcedRedirectEnabled(forcedRedirectEnabled: string): DynamicLink { - this._forcedRedirectEnabled = forcedRedirectEnabled; - return this._link; - } - - build(): NativeNavigationParameters { - return { - forcedRedirectEnabled: this._forcedRedirectEnabled, - }; - } -} diff --git a/bridge/firebase/modules/links/SocialParameters.js b/bridge/firebase/modules/links/SocialParameters.js deleted file mode 100644 index be81386b..00000000 --- a/bridge/firebase/modules/links/SocialParameters.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @flow - * SocialParameters representation wrapper - */ -import type DynamicLink from './DynamicLink'; -import type { NativeSocialParameters } from './types'; - -export default class SocialParameters { - _descriptionText: string | void; - _imageUrl: string | void; - _link: DynamicLink; - _title: string | void; - - constructor(link: DynamicLink) { - this._link = link; - } - - /** - * - * @param descriptionText - * @returns {DynamicLink} - */ - setDescriptionText(descriptionText: string): DynamicLink { - this._descriptionText = descriptionText; - return this._link; - } - - /** - * - * @param imageUrl - * @returns {DynamicLink} - */ - setImageUrl(imageUrl: string): DynamicLink { - this._imageUrl = imageUrl; - return this._link; - } - - /** - * - * @param title - * @returns {DynamicLink} - */ - setTitle(title: string): DynamicLink { - this._title = title; - return this._link; - } - - build(): NativeSocialParameters { - return { - descriptionText: this._descriptionText, - imageUrl: this._imageUrl, - title: this._title, - }; - } -} diff --git a/bridge/firebase/modules/links/index.js b/bridge/firebase/modules/links/index.js deleted file mode 100644 index a926b182..00000000 --- a/bridge/firebase/modules/links/index.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @flow - * Dynamic Links representation wrapper - */ -import DynamicLink from './DynamicLink'; -import { SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; - -const NATIVE_EVENTS = ['links_link_received']; - -export const MODULE_NAME = 'RNFirebaseLinks'; -export const NAMESPACE = 'links'; - -/** - * @class Links - */ -export default class Links extends ModuleBase { - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onMessage - 'links_link_received', - (link: string) => { - SharedEventEmitter.emit('onLink', link); - } - ); - } - - /** - * Create long Dynamic Link from parameters - * @param parameters - * @returns {Promise.} - */ - createDynamicLink(link: DynamicLink): Promise { - if (!(link instanceof DynamicLink)) { - throw new Error( - `Links:createDynamicLink expects a 'DynamicLink' but got type ${typeof link}` - ); - } - return getNativeModule(this).createDynamicLink(link.build()); - } - - /** - * Create short Dynamic Link from parameters - * @param parameters - * @returns {Promise.} - */ - createShortDynamicLink( - link: DynamicLink, - type?: 'SHORT' | 'UNGUESSABLE' - ): Promise { - if (!(link instanceof DynamicLink)) { - throw new Error( - `Links:createShortDynamicLink expects a 'DynamicLink' but got type ${typeof link}` - ); - } - return getNativeModule(this).createShortDynamicLink(link.build(), type); - } - - /** - * Returns the link that triggered application open - * @returns {Promise.} - */ - getInitialLink(): Promise { - return getNativeModule(this).getInitialLink(); - } - - /** - * Subscribe to dynamic links - * @param listener - * @returns {Function} - */ - onLink(listener: string => any): () => any { - getLogger(this).info('Creating onLink listener'); - - SharedEventEmitter.addListener('onLink', listener); - - return () => { - getLogger(this).info('Removing onLink listener'); - SharedEventEmitter.removeListener('onLink', listener); - }; - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/links/types.js b/bridge/firebase/modules/links/types.js deleted file mode 100644 index 27c947a4..00000000 --- a/bridge/firebase/modules/links/types.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @flow - */ -export type NativeAnalyticsParameters = {| - campaign?: string, - content?: string, - medium?: string, - source?: string, - term?: string, -|}; - -export type NativeAndroidParameters = {| - fallbackUrl?: string, - minimumVersion?: number, - packageName?: string, -|}; - -export type NativeIOSParameters = {| - appStoreId?: string, - bundleId?: string, - customScheme?: string, - fallbackUrl?: string, - iPadBundleId?: string, - iPadFallbackUrl?: string, - minimumVersion?: string, -|}; - -export type NativeITunesParameters = {| - affiliateToken?: string, - campaignToken?: string, - providerToken?: string, -|}; - -export type NativeNavigationParameters = {| - forcedRedirectEnabled?: string, -|}; - -export type NativeSocialParameters = {| - descriptionText?: string, - imageUrl?: string, - title?: string, -|}; - -export type NativeDynamicLink = {| - analytics: NativeAnalyticsParameters, - android: NativeAndroidParameters, - dynamicLinkDomain: string, - ios: NativeIOSParameters, - itunes: NativeITunesParameters, - link: string, - navigation: NativeNavigationParameters, - social: NativeSocialParameters, -|}; diff --git a/bridge/firebase/modules/messaging/RemoteMessage.js b/bridge/firebase/modules/messaging/RemoteMessage.js deleted file mode 100644 index c40b06ff..00000000 --- a/bridge/firebase/modules/messaging/RemoteMessage.js +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @flow - * RemoteMessage representation wrapper - */ -import { isObject, generatePushID } from './../../utils'; - -import type { - NativeInboundRemoteMessage, - NativeOutboundRemoteMessage, -} from './types'; - -export default class RemoteMessage { - _collapseKey: string | void; - _data: { [string]: string }; - _from: string | void; - _messageId: string; - _messageType: string | void; - _sentTime: number | void; - _to: string; - _ttl: number; - - constructor(inboundMessage?: NativeInboundRemoteMessage) { - if (inboundMessage) { - this._collapseKey = inboundMessage.collapseKey; - this._data = inboundMessage.data; - this._from = inboundMessage.from; - this._messageId = inboundMessage.messageId; - this._messageType = inboundMessage.messageType; - this._sentTime = inboundMessage.sentTime; - } - // defaults - this._data = this._data || {}; - // TODO: Is this the best way to generate an ID? - this._messageId = this._messageId || generatePushID(); - this._ttl = 3600; - } - - get collapseKey(): ?string { - return this._collapseKey; - } - - get data(): { [string]: string } { - return this._data; - } - - get from(): ?string { - return this._from; - } - - get messageId(): ?string { - return this._messageId; - } - - get messageType(): ?string { - return this._messageType; - } - - get sentTime(): ?number { - return this._sentTime; - } - - get to(): ?string { - return this._to; - } - - get ttl(): ?number { - return this._ttl; - } - - /** - * - * @param collapseKey - * @returns {RemoteMessage} - */ - setCollapseKey(collapseKey: string): RemoteMessage { - this._collapseKey = collapseKey; - return this; - } - - /** - * - * @param data - * @returns {RemoteMessage} - */ - setData(data: { [string]: string } = {}) { - if (!isObject(data)) { - throw new Error( - `RemoteMessage:setData expects an object but got type '${typeof data}'.` - ); - } - this._data = data; - return this; - } - - /** - * - * @param messageId - * @returns {RemoteMessage} - */ - setMessageId(messageId: string): RemoteMessage { - this._messageId = messageId; - return this; - } - - /** - * - * @param messageType - * @returns {RemoteMessage} - */ - setMessageType(messageType: string): RemoteMessage { - this._messageType = messageType; - return this; - } - - /** - * - * @param to - * @returns {RemoteMessage} - */ - setTo(to: string): RemoteMessage { - this._to = to; - return this; - } - - /** - * - * @param ttl - * @returns {RemoteMessage} - */ - setTtl(ttl: number): RemoteMessage { - this._ttl = ttl; - return this; - } - - build(): NativeOutboundRemoteMessage { - if (!this._data) { - throw new Error('RemoteMessage: Missing required `data` property'); - } else if (!this._messageId) { - throw new Error('RemoteMessage: Missing required `messageId` property'); - } else if (!this._to) { - throw new Error('RemoteMessage: Missing required `to` property'); - } else if (!this._ttl) { - throw new Error('RemoteMessage: Missing required `ttl` property'); - } - - return { - collapseKey: this._collapseKey, - data: this._data, - messageId: this._messageId, - messageType: this._messageType, - to: this._to, - ttl: this._ttl, - }; - } -} diff --git a/bridge/firebase/modules/messaging/index.js b/bridge/firebase/modules/messaging/index.js deleted file mode 100644 index b56e4978..00000000 --- a/bridge/firebase/modules/messaging/index.js +++ /dev/null @@ -1,181 +0,0 @@ -/** - * @flow - * Messaging (FCM) representation wrapper - */ -import { SharedEventEmitter } from '../../utils/events'; -import INTERNALS from '../../utils/internals'; -import { getLogger } from '../../utils/log'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; -import { isFunction, isObject } from '../../utils'; -import RemoteMessage from './RemoteMessage'; - -import type App from '../core/app'; -import type { NativeInboundRemoteMessage } from './types'; - -type OnMessage = RemoteMessage => any; - -type OnMessageObserver = { - next: OnMessage, -}; - -type OnTokenRefresh = String => any; - -type OnTokenRefreshObserver = { - next: OnTokenRefresh, -}; - -const NATIVE_EVENTS = [ - 'messaging_message_received', - 'messaging_token_refreshed', -]; - -export const MODULE_NAME = 'RNFirebaseMessaging'; -export const NAMESPACE = 'messaging'; - -/** - * @class Messaging - */ -export default class Messaging extends ModuleBase { - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onMessage - 'messaging_message_received', - (message: NativeInboundRemoteMessage) => { - SharedEventEmitter.emit('onMessage', new RemoteMessage(message)); - } - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onMessage - 'messaging_token_refreshed', - (token: string) => { - SharedEventEmitter.emit('onTokenRefresh', token); - } - ); - } - - getToken(): Promise { - return getNativeModule(this).getToken(); - } - - onMessage(nextOrObserver: OnMessage | OnMessageObserver): () => any { - let listener: RemoteMessage => any; - if (isFunction(nextOrObserver)) { - // $FlowExpectedError: Not coping with the overloaded method signature - listener = nextOrObserver; - } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { - listener = nextOrObserver.next; - } else { - throw new Error( - 'Messaging.onMessage failed: First argument must be a function or observer object with a `next` function.' - ); - } - - getLogger(this).info('Creating onMessage listener'); - - SharedEventEmitter.addListener('onMessage', listener); - - return () => { - getLogger(this).info('Removing onMessage listener'); - SharedEventEmitter.removeListener('onMessage', listener); - }; - } - - onTokenRefresh( - nextOrObserver: OnTokenRefresh | OnTokenRefreshObserver - ): () => any { - let listener: String => any; - if (isFunction(nextOrObserver)) { - // $FlowExpectedError: Not coping with the overloaded method signature - listener = nextOrObserver; - } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { - listener = nextOrObserver.next; - } else { - throw new Error( - 'Messaging.OnTokenRefresh failed: First argument must be a function or observer object with a `next` function.' - ); - } - - getLogger(this).info('Creating onTokenRefresh listener'); - SharedEventEmitter.addListener('onTokenRefresh', listener); - - return () => { - getLogger(this).info('Removing onTokenRefresh listener'); - SharedEventEmitter.removeListener('onTokenRefresh', listener); - }; - } - - requestPermission(): Promise { - return getNativeModule(this).requestPermission(); - } - - /** - * NON WEB-SDK METHODS - */ - hasPermission(): Promise { - return getNativeModule(this).hasPermission(); - } - - sendMessage(remoteMessage: RemoteMessage): Promise { - if (!(remoteMessage instanceof RemoteMessage)) { - throw new Error( - `Messaging:sendMessage expects a 'RemoteMessage' but got type ${typeof remoteMessage}` - ); - } - return getNativeModule(this).sendMessage(remoteMessage.build()); - } - - subscribeToTopic(topic: string): void { - getNativeModule(this).subscribeToTopic(topic); - } - - unsubscribeFromTopic(topic: string): void { - getNativeModule(this).unsubscribeFromTopic(topic); - } - - /** - * KNOWN UNSUPPORTED METHODS - */ - - deleteToken() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'messaging', - 'deleteToken' - ) - ); - } - - setBackgroundMessageHandler() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'messaging', - 'setBackgroundMessageHandler' - ) - ); - } - - useServiceWorker() { - throw new Error( - INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD( - 'messaging', - 'useServiceWorker' - ) - ); - } -} - -export const statics = { - RemoteMessage, -}; diff --git a/bridge/firebase/modules/messaging/types.js b/bridge/firebase/modules/messaging/types.js deleted file mode 100644 index e2cbe647..00000000 --- a/bridge/firebase/modules/messaging/types.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @flow - */ -export type Notification = { - body: string, - bodyLocalizationArgs?: string[], - bodyLocalizationKey?: string, - clickAction?: string, - color?: string, - icon?: string, - link?: string, - sound: string, - subtitle?: string, - tag?: string, - title: string, - titleLocalizationArgs?: string[], - titleLocalizationKey?: string, -}; - -export type NativeInboundRemoteMessage = { - collapseKey?: string, - data: { [string]: string }, - from?: string, - messageId: string, - messageType?: string, - sentTime?: number, - to?: string, - ttl?: number, -}; - -export type NativeOutboundRemoteMessage = { - collapseKey?: string, - data: { [string]: string }, - messageId: string, - messageType?: string, - to: string, - ttl: number, -}; diff --git a/bridge/firebase/modules/notifications/AndroidAction.js b/bridge/firebase/modules/notifications/AndroidAction.js deleted file mode 100644 index ed2a940c..00000000 --- a/bridge/firebase/modules/notifications/AndroidAction.js +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @flow - * AndroidAction representation wrapper - */ -import RemoteInput, { - fromNativeAndroidRemoteInput, -} from './AndroidRemoteInput'; -import { SemanticAction } from './types'; -import type { NativeAndroidAction, SemanticActionType } from './types'; - -export default class AndroidAction { - _action: string; - _allowGeneratedReplies: boolean | void; - _icon: string; - _remoteInputs: RemoteInput[]; - _semanticAction: SemanticActionType | void; - _showUserInterface: boolean | void; - _title: string; - - constructor(action: string, icon: string, title: string) { - this._action = action; - this._icon = icon; - this._remoteInputs = []; - this._title = title; - } - - get action(): string { - return this._action; - } - - get allowGeneratedReplies(): ?boolean { - return this._allowGeneratedReplies; - } - - get icon(): string { - return this._icon; - } - - get remoteInputs(): RemoteInput[] { - return this._remoteInputs; - } - - get semanticAction(): ?SemanticActionType { - return this._semanticAction; - } - - get showUserInterface(): ?boolean { - return this._showUserInterface; - } - - get title(): string { - return this._title; - } - - /** - * - * @param remoteInput - * @returns {AndroidAction} - */ - addRemoteInput(remoteInput: RemoteInput): AndroidAction { - if (!(remoteInput instanceof RemoteInput)) { - throw new Error( - `AndroidAction:addRemoteInput expects an 'RemoteInput' but got type ${typeof remoteInput}` - ); - } - this._remoteInputs.push(remoteInput); - return this; - } - - /** - * - * @param allowGeneratedReplies - * @returns {AndroidAction} - */ - setAllowGenerateReplies(allowGeneratedReplies: boolean): AndroidAction { - this._allowGeneratedReplies = allowGeneratedReplies; - return this; - } - - /** - * - * @param semanticAction - * @returns {AndroidAction} - */ - setSemanticAction(semanticAction: SemanticActionType): AndroidAction { - if (!Object.values(SemanticAction).includes(semanticAction)) { - throw new Error( - `AndroidAction:setSemanticAction Invalid Semantic Action: ${semanticAction}` - ); - } - this._semanticAction = semanticAction; - return this; - } - - /** - * - * @param showUserInterface - * @returns {AndroidAction} - */ - setShowUserInterface(showUserInterface: boolean): AndroidAction { - this._showUserInterface = showUserInterface; - return this; - } - - build(): NativeAndroidAction { - if (!this._action) { - throw new Error('AndroidAction: Missing required `action` property'); - } else if (!this._icon) { - throw new Error('AndroidAction: Missing required `icon` property'); - } else if (!this._title) { - throw new Error('AndroidAction: Missing required `title` property'); - } - - return { - action: this._action, - allowGeneratedReplies: this._allowGeneratedReplies, - icon: this._icon, - remoteInputs: this._remoteInputs.map(remoteInput => remoteInput.build()), - semanticAction: this._semanticAction, - showUserInterface: this._showUserInterface, - title: this._title, - }; - } -} - -export const fromNativeAndroidAction = ( - nativeAction: NativeAndroidAction -): AndroidAction => { - const action = new AndroidAction( - nativeAction.action, - nativeAction.icon, - nativeAction.title - ); - if (nativeAction.allowGeneratedReplies) { - action.setAllowGenerateReplies(nativeAction.allowGeneratedReplies); - } - if (nativeAction.remoteInputs) { - nativeAction.remoteInputs.forEach(remoteInput => { - action.addRemoteInput(fromNativeAndroidRemoteInput(remoteInput)); - }); - } - if (nativeAction.semanticAction) { - action.setSemanticAction(nativeAction.semanticAction); - } - if (nativeAction.showUserInterface) { - action.setShowUserInterface(nativeAction.showUserInterface); - } - - return action; -}; diff --git a/bridge/firebase/modules/notifications/AndroidChannel.js b/bridge/firebase/modules/notifications/AndroidChannel.js deleted file mode 100644 index f64cbf9e..00000000 --- a/bridge/firebase/modules/notifications/AndroidChannel.js +++ /dev/null @@ -1,198 +0,0 @@ -/** - * @flow - * AndroidChannel representation wrapper - */ -import { Importance, Visibility } from './types'; -import type { ImportanceType, VisibilityType } from './types'; - -type NativeAndroidChannel = {| - bypassDnd?: boolean, - channelId: string, - description?: string, - group?: string, - importance: ImportanceType, - lightColor?: string, - lockScreenVisibility?: VisibilityType, - name: string, - showBadge?: boolean, - sound?: string, - vibrationPattern?: number[], -|}; - -export default class AndroidChannel { - _bypassDnd: boolean | void; - _channelId: string; - _description: string | void; - _group: string | void; - _importance: ImportanceType; - _lightColor: string | void; - _lockScreenVisibility: VisibilityType; - _name: string; - _showBadge: boolean | void; - _sound: string | void; - _vibrationPattern: number[] | void; - - constructor(channelId: string, name: string, importance: ImportanceType) { - if (!Object.values(Importance).includes(importance)) { - throw new Error(`AndroidChannel() Invalid Importance: ${importance}`); - } - this._channelId = channelId; - this._name = name; - this._importance = importance; - } - - get bypassDnd(): ?boolean { - return this._bypassDnd; - } - - get channelId(): string { - return this._channelId; - } - - get description(): ?string { - return this._description; - } - - get group(): ?string { - return this._group; - } - - get importance(): ImportanceType { - return this._importance; - } - - get lightColor(): ?string { - return this._lightColor; - } - - get lockScreenVisibility(): ?VisibilityType { - return this._lockScreenVisibility; - } - - get name(): string { - return this._name; - } - - get showBadge(): ?boolean { - return this._showBadge; - } - - get sound(): ?string { - return this._sound; - } - - get vibrationPattern(): ?(number[]) { - return this._vibrationPattern; - } - - /** - * - * @param bypassDnd - * @returns {AndroidChannel} - */ - setBypassDnd(bypassDnd: boolean): AndroidChannel { - this._bypassDnd = bypassDnd; - return this; - } - - /** - * - * @param description - * @returns {AndroidChannel} - */ - setDescription(description: string): AndroidChannel { - this._description = description; - return this; - } - - /** - * - * @param group - * @returns {AndroidChannel} - */ - setGroup(groupId: string): AndroidChannel { - this._group = groupId; - return this; - } - - /** - * - * @param lightColor - * @returns {AndroidChannel} - */ - setLightColor(lightColor: string): AndroidChannel { - this._lightColor = lightColor; - return this; - } - - /** - * - * @param lockScreenVisibility - * @returns {AndroidChannel} - */ - setLockScreenVisibility( - lockScreenVisibility: VisibilityType - ): AndroidChannel { - if (!Object.values(Visibility).includes(lockScreenVisibility)) { - throw new Error( - `AndroidChannel:setLockScreenVisibility Invalid Visibility: ${lockScreenVisibility}` - ); - } - this._lockScreenVisibility = lockScreenVisibility; - return this; - } - - /** - * - * @param showBadge - * @returns {AndroidChannel} - */ - setShowBadge(showBadge: boolean): AndroidChannel { - this._showBadge = showBadge; - return this; - } - - /** - * - * @param sound - * @returns {AndroidChannel} - */ - setSound(sound: string): AndroidChannel { - this._sound = sound; - return this; - } - - /** - * - * @param vibrationPattern - * @returns {AndroidChannel} - */ - setVibrationPattern(vibrationPattern: number[]): AndroidChannel { - this._vibrationPattern = vibrationPattern; - return this; - } - - build(): NativeAndroidChannel { - if (!this._channelId) { - throw new Error('AndroidChannel: Missing required `channelId` property'); - } else if (!this._importance) { - throw new Error('AndroidChannel: Missing required `importance` property'); - } else if (!this._name) { - throw new Error('AndroidChannel: Missing required `name` property'); - } - - return { - bypassDnd: this._bypassDnd, - channelId: this._channelId, - description: this._description, - group: this._group, - importance: this._importance, - lightColor: this._lightColor, - lockScreenVisibility: this._lockScreenVisibility, - name: this._name, - showBadge: this._showBadge, - sound: this._sound, - vibrationPattern: this._vibrationPattern, - }; - } -} diff --git a/bridge/firebase/modules/notifications/AndroidChannelGroup.js b/bridge/firebase/modules/notifications/AndroidChannelGroup.js deleted file mode 100644 index 3485c276..00000000 --- a/bridge/firebase/modules/notifications/AndroidChannelGroup.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @flow - * AndroidChannelGroup representation wrapper - */ - -type NativeAndroidChannelGroup = {| - groupId: string, - name: string, -|}; - -export default class AndroidChannelGroup { - _groupId: string; - _name: string; - - constructor(groupId: string, name: string) { - this._groupId = groupId; - this._name = name; - } - - get groupId(): string { - return this._groupId; - } - - get name(): string { - return this._name; - } - - build(): NativeAndroidChannelGroup { - if (!this._groupId) { - throw new Error( - 'AndroidChannelGroup: Missing required `groupId` property' - ); - } else if (!this._name) { - throw new Error('AndroidChannelGroup: Missing required `name` property'); - } - - return { - groupId: this._groupId, - name: this._name, - }; - } -} diff --git a/bridge/firebase/modules/notifications/AndroidNotification.js b/bridge/firebase/modules/notifications/AndroidNotification.js deleted file mode 100644 index f67b3d3f..00000000 --- a/bridge/firebase/modules/notifications/AndroidNotification.js +++ /dev/null @@ -1,676 +0,0 @@ -/** - * @flow - * AndroidNotification representation wrapper - */ -import AndroidAction, { fromNativeAndroidAction } from './AndroidAction'; -import { BadgeIconType, Category, GroupAlert, Priority } from './types'; -import type Notification from './Notification'; -import type { - BadgeIconTypeType, - CategoryType, - DefaultsType, - GroupAlertType, - Lights, - NativeAndroidNotification, - PriorityType, - Progress, - SmallIcon, - VisibilityType, -} from './types'; - -export default class AndroidNotification { - _actions: AndroidAction[]; - _autoCancel: boolean | void; - _badgeIconType: BadgeIconTypeType | void; - _category: CategoryType | void; - _channelId: string; - _clickAction: string | void; - _color: string | void; - _colorized: boolean | void; - _contentInfo: string | void; - _defaults: DefaultsType[] | void; - _group: string | void; - _groupAlertBehaviour: GroupAlertType | void; - _groupSummary: boolean | void; - _largeIcon: string | void; - _lights: Lights | void; - _localOnly: boolean | void; - _notification: Notification; - _number: number | void; - _ongoing: boolean | void; - _onlyAlertOnce: boolean | void; - _people: string[]; - _priority: PriorityType | void; - _progress: Progress | void; - // _publicVersion: Notification; - _remoteInputHistory: string[] | void; - _shortcutId: string | void; - _showWhen: boolean | void; - _smallIcon: SmallIcon; - _sortKey: string | void; - // TODO: style: Style; // Need to figure out if this can work - _ticker: string | void; - _timeoutAfter: number | void; - _usesChronometer: boolean | void; - _vibrate: number[] | void; - _visibility: VisibilityType | void; - _when: number | void; - - // android unsupported - // content: RemoteViews - // contentIntent: PendingIntent - need to look at what this is - // customBigContentView: RemoteViews - // customContentView: RemoteViews - // customHeadsUpContentView: RemoteViews - // deleteIntent: PendingIntent - // fullScreenIntent: PendingIntent - // sound.streamType - - constructor(notification: Notification, data?: NativeAndroidNotification) { - this._notification = notification; - - if (data) { - this._actions = data.actions - ? data.actions.map(action => fromNativeAndroidAction(action)) - : []; - this._autoCancel = data.autoCancel; - this._badgeIconType = data.badgeIconType; - this._category = data.category; - this._channelId = data.channelId; - this._clickAction = data.clickAction; - this._color = data.color; - this._colorized = data.colorized; - this._contentInfo = data.contentInfo; - this._defaults = data.defaults; - this._group = data.group; - this._groupAlertBehaviour = data.groupAlertBehaviour; - this._groupSummary = data.groupSummary; - this._largeIcon = data.largeIcon; - this._lights = data.lights; - this._localOnly = data.localOnly; - this._number = data.number; - this._ongoing = data.ongoing; - this._onlyAlertOnce = data.onlyAlertOnce; - this._people = data.people; - this._priority = data.priority; - this._progress = data.progress; - // _publicVersion: Notification; - this._remoteInputHistory = data.remoteInputHistory; - this._shortcutId = data.shortcutId; - this._showWhen = data.showWhen; - this._smallIcon = data.smallIcon; - this._sortKey = data.sortKey; - this._ticker = data.ticker; - this._timeoutAfter = data.timeoutAfter; - this._usesChronometer = data.usesChronometer; - this._vibrate = data.vibrate; - this._visibility = data.visibility; - this._when = data.when; - } - - // Defaults - this._actions = this._actions || []; - this._people = this._people || []; - this._smallIcon = this._smallIcon || { - icon: 'ic_launcher', - }; - } - - get actions(): AndroidAction[] { - return this._actions; - } - - get autoCancel(): ?boolean { - return this._autoCancel; - } - - get badgeIconType(): ?BadgeIconTypeType { - return this._badgeIconType; - } - - get category(): ?CategoryType { - return this._category; - } - - get channelId(): string { - return this._channelId; - } - - get clickAction(): ?string { - return this._clickAction; - } - - get color(): ?string { - return this._color; - } - - get colorized(): ?boolean { - return this._colorized; - } - - get contentInfo(): ?string { - return this._contentInfo; - } - - get defaults(): ?(DefaultsType[]) { - return this._defaults; - } - - get group(): ?string { - return this._group; - } - - get groupAlertBehaviour(): ?GroupAlertType { - return this._groupAlertBehaviour; - } - - get groupSummary(): ?boolean { - return this._groupSummary; - } - - get largeIcon(): ?string { - return this._largeIcon; - } - - get lights(): ?Lights { - return this._lights; - } - - get localOnly(): ?boolean { - return this._localOnly; - } - - get number(): ?number { - return this._number; - } - - get ongoing(): ?boolean { - return this._ongoing; - } - - get onlyAlertOnce(): ?boolean { - return this._onlyAlertOnce; - } - - get people(): string[] { - return this._people; - } - - get priority(): ?PriorityType { - return this._priority; - } - - get progress(): ?Progress { - return this._progress; - } - - get remoteInputHistory(): ?(string[]) { - return this._remoteInputHistory; - } - - get shortcutId(): ?string { - return this._shortcutId; - } - - get showWhen(): ?boolean { - return this._showWhen; - } - - get smallIcon(): SmallIcon { - return this._smallIcon; - } - - get sortKey(): ?string { - return this._sortKey; - } - - get ticker(): ?string { - return this._ticker; - } - - get timeoutAfter(): ?number { - return this._timeoutAfter; - } - - get usesChronometer(): ?boolean { - return this._usesChronometer; - } - - get vibrate(): ?(number[]) { - return this._vibrate; - } - - get visibility(): ?VisibilityType { - return this._visibility; - } - - get when(): ?number { - return this._when; - } - - /** - * - * @param action - * @returns {Notification} - */ - addAction(action: AndroidAction): Notification { - if (!(action instanceof AndroidAction)) { - throw new Error( - `AndroidNotification:addAction expects an 'AndroidAction' but got type ${typeof action}` - ); - } - this._actions.push(action); - return this._notification; - } - - /** - * - * @param person - * @returns {Notification} - */ - addPerson(person: string): Notification { - this._people.push(person); - return this._notification; - } - - /** - * - * @param autoCancel - * @returns {Notification} - */ - setAutoCancel(autoCancel: boolean): Notification { - this._autoCancel = autoCancel; - return this._notification; - } - - /** - * - * @param badgeIconType - * @returns {Notification} - */ - setBadgeIconType(badgeIconType: BadgeIconTypeType): Notification { - if (!Object.values(BadgeIconType).includes(badgeIconType)) { - throw new Error( - `AndroidNotification:setBadgeIconType Invalid BadgeIconType: ${badgeIconType}` - ); - } - this._badgeIconType = badgeIconType; - return this._notification; - } - - /** - * - * @param category - * @returns {Notification} - */ - setCategory(category: CategoryType): Notification { - if (!Object.values(Category).includes(category)) { - throw new Error( - `AndroidNotification:setCategory Invalid Category: ${category}` - ); - } - this._category = category; - return this._notification; - } - - /** - * - * @param channelId - * @returns {Notification} - */ - setChannelId(channelId: string): Notification { - this._channelId = channelId; - return this._notification; - } - - /** - * - * @param clickAction - * @returns {Notification} - */ - setClickAction(clickAction: string): Notification { - this._clickAction = clickAction; - return this._notification; - } - - /** - * - * @param color - * @returns {Notification} - */ - setColor(color: string): Notification { - this._color = color; - return this._notification; - } - - /** - * - * @param colorized - * @returns {Notification} - */ - setColorized(colorized: boolean): Notification { - this._colorized = colorized; - return this._notification; - } - - /** - * - * @param contentInfo - * @returns {Notification} - */ - setContentInfo(contentInfo: string): Notification { - this._contentInfo = contentInfo; - return this._notification; - } - - /** - * - * @param defaults - * @returns {Notification} - */ - setDefaults(defaults: DefaultsType[]): Notification { - this._defaults = defaults; - return this._notification; - } - - /** - * - * @param group - * @returns {Notification} - */ - setGroup(group: string): Notification { - this._group = group; - return this._notification; - } - - /** - * - * @param groupAlertBehaviour - * @returns {Notification} - */ - setGroupAlertBehaviour(groupAlertBehaviour: GroupAlertType): Notification { - if (!Object.values(GroupAlert).includes(groupAlertBehaviour)) { - throw new Error( - `AndroidNotification:setGroupAlertBehaviour Invalid GroupAlert: ${groupAlertBehaviour}` - ); - } - this._groupAlertBehaviour = groupAlertBehaviour; - return this._notification; - } - - /** - * - * @param groupSummary - * @returns {Notification} - */ - setGroupSummary(groupSummary: boolean): Notification { - this._groupSummary = groupSummary; - return this._notification; - } - - /** - * - * @param largeIcon - * @returns {Notification} - */ - setLargeIcon(largeIcon: string): Notification { - this._largeIcon = largeIcon; - return this._notification; - } - - /** - * - * @param argb - * @param onMs - * @param offMs - * @returns {Notification} - */ - setLights(argb: number, onMs: number, offMs: number): Notification { - this._lights = { - argb, - onMs, - offMs, - }; - return this._notification; - } - - /** - * - * @param localOnly - * @returns {Notification} - */ - setLocalOnly(localOnly: boolean): Notification { - this._localOnly = localOnly; - return this._notification; - } - - /** - * - * @param number - * @returns {Notification} - */ - setNumber(number: number): Notification { - this._number = number; - return this._notification; - } - - /** - * - * @param ongoing - * @returns {Notification} - */ - setOngoing(ongoing: boolean): Notification { - this._ongoing = ongoing; - return this._notification; - } - - /** - * - * @param onlyAlertOnce - * @returns {Notification} - */ - setOnlyAlertOnce(onlyAlertOnce: boolean): Notification { - this._onlyAlertOnce = onlyAlertOnce; - return this._notification; - } - - /** - * - * @param priority - * @returns {Notification} - */ - setPriority(priority: PriorityType): Notification { - if (!Object.values(Priority).includes(priority)) { - throw new Error( - `AndroidNotification:setPriority Invalid Priority: ${priority}` - ); - } - this._priority = priority; - return this._notification; - } - - /** - * - * @param max - * @param progress - * @param indeterminate - * @returns {Notification} - */ - setProgress( - max: number, - progress: number, - indeterminate: boolean - ): Notification { - this._progress = { - max, - progress, - indeterminate, - }; - return this._notification; - } - - /** - * - * @param publicVersion - * @returns {Notification} - */ - /* setPublicVersion(publicVersion: Notification): Notification { - this._publicVersion = publicVersion; - return this._notification; - } */ - - /** - * - * @param remoteInputHistory - * @returns {Notification} - */ - setRemoteInputHistory(remoteInputHistory: string[]): Notification { - this._remoteInputHistory = remoteInputHistory; - return this._notification; - } - - /** - * - * @param shortcutId - * @returns {Notification} - */ - setShortcutId(shortcutId: string): Notification { - this._shortcutId = shortcutId; - return this._notification; - } - - /** - * - * @param showWhen - * @returns {Notification} - */ - setShowWhen(showWhen: boolean): Notification { - this._showWhen = showWhen; - return this._notification; - } - - /** - * - * @param icon - * @param level - * @returns {Notification} - */ - setSmallIcon(icon: string, level?: number): Notification { - this._smallIcon = { - icon, - level, - }; - return this._notification; - } - - /** - * - * @param sortKey - * @returns {Notification} - */ - setSortKey(sortKey: string): Notification { - this._sortKey = sortKey; - return this._notification; - } - - /** - * - * @param ticker - * @returns {Notification} - */ - setTicker(ticker: string): Notification { - this._ticker = ticker; - return this._notification; - } - - /** - * - * @param timeoutAfter - * @returns {Notification} - */ - setTimeoutAfter(timeoutAfter: number): Notification { - this._timeoutAfter = timeoutAfter; - return this._notification; - } - - /** - * - * @param usesChronometer - * @returns {Notification} - */ - setUsesChronometer(usesChronometer: boolean): Notification { - this._usesChronometer = usesChronometer; - return this._notification; - } - - /** - * - * @param vibrate - * @returns {Notification} - */ - setVibrate(vibrate: number[]): Notification { - this._vibrate = vibrate; - return this._notification; - } - - /** - * - * @param when - * @returns {Notification} - */ - setWhen(when: number): Notification { - this._when = when; - return this._notification; - } - - build(): NativeAndroidNotification { - // TODO: Validation of required fields - if (!this._channelId) { - throw new Error( - 'AndroidNotification: Missing required `channelId` property' - ); - } else if (!this._smallIcon) { - throw new Error( - 'AndroidNotification: Missing required `smallIcon` property' - ); - } - - return { - actions: this._actions.map(action => action.build()), - autoCancel: this._autoCancel, - badgeIconType: this._badgeIconType, - category: this._category, - channelId: this._channelId, - clickAction: this._clickAction, - color: this._color, - colorized: this._colorized, - contentInfo: this._contentInfo, - defaults: this._defaults, - group: this._group, - groupAlertBehaviour: this._groupAlertBehaviour, - groupSummary: this._groupSummary, - largeIcon: this._largeIcon, - lights: this._lights, - localOnly: this._localOnly, - number: this._number, - ongoing: this._ongoing, - onlyAlertOnce: this._onlyAlertOnce, - people: this._people, - priority: this._priority, - progress: this._progress, - // publicVersion: this._publicVersion, - remoteInputHistory: this._remoteInputHistory, - shortcutId: this._shortcutId, - showWhen: this._showWhen, - smallIcon: this._smallIcon, - sortKey: this._sortKey, - // TODO: style: Style, - ticker: this._ticker, - timeoutAfter: this._timeoutAfter, - usesChronometer: this._usesChronometer, - vibrate: this._vibrate, - visibility: this._visibility, - when: this._when, - }; - } -} diff --git a/bridge/firebase/modules/notifications/AndroidNotifications.js b/bridge/firebase/modules/notifications/AndroidNotifications.js deleted file mode 100644 index bd644a60..00000000 --- a/bridge/firebase/modules/notifications/AndroidNotifications.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @flow - * AndroidNotifications representation wrapper - */ -import { Platform } from 'react-native'; -import AndroidChannel from './AndroidChannel'; -import AndroidChannelGroup from './AndroidChannelGroup'; -import { getNativeModule } from '../../utils/native'; - -import type Notifications from './'; - -export default class AndroidNotifications { - _notifications: Notifications; - - constructor(notifications: Notifications) { - this._notifications = notifications; - } - - createChannel(channel: AndroidChannel): Promise { - if (Platform.OS === 'android') { - if (!(channel instanceof AndroidChannel)) { - throw new Error( - `AndroidNotifications:createChannel expects an 'AndroidChannel' but got type ${typeof channel}` - ); - } - return getNativeModule(this._notifications).createChannel( - channel.build() - ); - } - return Promise.resolve(); - } - - createChannelGroup(channelGroup: AndroidChannelGroup): Promise { - if (Platform.OS === 'android') { - if (!(channelGroup instanceof AndroidChannelGroup)) { - throw new Error( - `AndroidNotifications:createChannelGroup expects an 'AndroidChannelGroup' but got type ${typeof channelGroup}` - ); - } - return getNativeModule(this._notifications).createChannelGroup( - channelGroup.build() - ); - } - return Promise.resolve(); - } - - createChannelGroups(channelGroups: AndroidChannelGroup[]): Promise { - if (Platform.OS === 'android') { - if (!Array.isArray(channelGroups)) { - throw new Error( - `AndroidNotifications:createChannelGroups expects an 'Array' but got type ${typeof channelGroups}` - ); - } - const nativeChannelGroups = []; - for (let i = 0; i < channelGroups.length; i++) { - const channelGroup = channelGroups[i]; - if (!(channelGroup instanceof AndroidChannelGroup)) { - throw new Error( - `AndroidNotifications:createChannelGroups expects array items of type 'AndroidChannelGroup' but got type ${typeof channelGroup}` - ); - } - nativeChannelGroups.push(channelGroup.build()); - } - return getNativeModule(this._notifications).createChannelGroups( - nativeChannelGroups - ); - } - return Promise.resolve(); - } - - createChannels(channels: AndroidChannel[]): Promise { - if (Platform.OS === 'android') { - if (!Array.isArray(channels)) { - throw new Error( - `AndroidNotifications:createChannels expects an 'Array' but got type ${typeof channels}` - ); - } - const nativeChannels = []; - for (let i = 0; i < channels.length; i++) { - const channel = channels[i]; - if (!(channel instanceof AndroidChannel)) { - throw new Error( - `AndroidNotifications:createChannels expects array items of type 'AndroidChannel' but got type ${typeof channel}` - ); - } - nativeChannels.push(channel.build()); - } - return getNativeModule(this._notifications).createChannels( - nativeChannels - ); - } - return Promise.resolve(); - } -} diff --git a/bridge/firebase/modules/notifications/AndroidRemoteInput.js b/bridge/firebase/modules/notifications/AndroidRemoteInput.js deleted file mode 100644 index 29b29fbb..00000000 --- a/bridge/firebase/modules/notifications/AndroidRemoteInput.js +++ /dev/null @@ -1,123 +0,0 @@ -/** - * @flow - * AndroidRemoteInput representation wrapper - */ - -import type { AndroidAllowDataType, NativeAndroidRemoteInput } from './types'; - -export default class AndroidRemoteInput { - _allowedDataTypes: AndroidAllowDataType[]; - _allowFreeFormInput: boolean | void; - _choices: string[]; - _label: string | void; - _resultKey: string; - - constructor(resultKey: string) { - this._allowedDataTypes = []; - this._choices = []; - this._resultKey = resultKey; - } - - get allowedDataTypes(): AndroidAllowDataType[] { - return this._allowedDataTypes; - } - - get allowFreeFormInput(): ?boolean { - return this._allowFreeFormInput; - } - - get choices(): string[] { - return this._choices; - } - - get label(): ?string { - return this._label; - } - - get resultKey(): string { - return this._resultKey; - } - - /** - * - * @param mimeType - * @param allow - * @returns {AndroidRemoteInput} - */ - setAllowDataType(mimeType: string, allow: boolean): AndroidRemoteInput { - this._allowedDataTypes.push({ - allow, - mimeType, - }); - return this; - } - - /** - * - * @param allowFreeFormInput - * @returns {AndroidRemoteInput} - */ - setAllowFreeFormInput(allowFreeFormInput: boolean): AndroidRemoteInput { - this._allowFreeFormInput = allowFreeFormInput; - return this; - } - - /** - * - * @param choices - * @returns {AndroidRemoteInput} - */ - setChoices(choices: string[]): AndroidRemoteInput { - this._choices = choices; - return this; - } - - /** - * - * @param label - * @returns {AndroidRemoteInput} - */ - setLabel(label: string): AndroidRemoteInput { - this._label = label; - return this; - } - - build(): NativeAndroidRemoteInput { - if (!this._resultKey) { - throw new Error( - 'AndroidRemoteInput: Missing required `resultKey` property' - ); - } - - return { - allowedDataTypes: this._allowedDataTypes, - allowFreeFormInput: this._allowFreeFormInput, - choices: this._choices, - label: this._label, - resultKey: this._resultKey, - }; - } -} - -export const fromNativeAndroidRemoteInput = ( - nativeRemoteInput: NativeAndroidRemoteInput -): AndroidRemoteInput => { - const remoteInput = new AndroidRemoteInput(nativeRemoteInput.resultKey); - if (nativeRemoteInput.allowDataType) { - for (let i = 0; i < nativeRemoteInput.allowDataType.length; i++) { - const allowDataType = nativeRemoteInput.allowDataType[i]; - remoteInput.setAllowDataType(allowDataType.mimeType, allowDataType.allow); - } - } - if (nativeRemoteInput.allowFreeFormInput) { - remoteInput.setAllowFreeFormInput(nativeRemoteInput.allowFreeFormInput); - } - if (nativeRemoteInput.choices) { - remoteInput.setChoices(nativeRemoteInput.choices); - } - if (nativeRemoteInput.label) { - remoteInput.setLabel(nativeRemoteInput.label); - } - - return remoteInput; -}; diff --git a/bridge/firebase/modules/notifications/IOSNotification.js b/bridge/firebase/modules/notifications/IOSNotification.js deleted file mode 100644 index cd1acaae..00000000 --- a/bridge/firebase/modules/notifications/IOSNotification.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @flow - * IOSNotification representation wrapper - */ -import type Notification from './Notification'; -import type { - IOSAttachment, - IOSAttachmentOptions, - NativeIOSNotification, -} from './types'; - -export default class IOSNotification { - _alertAction: string | void; // alertAction | N/A - _attachments: IOSAttachment[]; // N/A | attachments - _badge: number | void; // applicationIconBadgeNumber | badge - _category: string | void; - _hasAction: boolean | void; // hasAction | N/A - _launchImage: string | void; // alertLaunchImage | launchImageName - _notification: Notification; - _threadIdentifier: string | void; // N/A | threadIdentifier - - constructor(notification: Notification, data?: NativeIOSNotification) { - this._notification = notification; - - if (data) { - this._alertAction = data.alertAction; - this._attachments = data.attachments; - this._badge = data.badge; - this._category = data.category; - this._hasAction = data.hasAction; - this._launchImage = data.launchImage; - this._threadIdentifier = data.threadIdentifier; - } - - // Defaults - this._attachments = this._attachments || []; - } - - get alertAction(): ?string { - return this._alertAction; - } - - get attachments(): IOSAttachment[] { - return this._attachments; - } - - get badge(): ?number { - return this._badge; - } - - get category(): ?string { - return this._category; - } - - get hasAction(): ?boolean { - return this._hasAction; - } - - get launchImage(): ?string { - return this._launchImage; - } - - get threadIdentifier(): ?string { - return this._threadIdentifier; - } - - /** - * - * @param identifier - * @param url - * @param options - * @returns {Notification} - */ - addAttachment( - identifier: string, - url: string, - options?: IOSAttachmentOptions - ): Notification { - this._attachments.push({ - identifier, - options, - url, - }); - return this._notification; - } - - /** - * - * @param alertAction - * @returns {Notification} - */ - setAlertAction(alertAction: string): Notification { - this._alertAction = alertAction; - return this._notification; - } - - /** - * - * @param badge - * @returns {Notification} - */ - setBadge(badge: number): Notification { - this._badge = badge; - return this._notification; - } - - /** - * - * @param category - * @returns {Notification} - */ - setCategory(category: string): Notification { - this._category = category; - return this._notification; - } - - /** - * - * @param hasAction - * @returns {Notification} - */ - setHasAction(hasAction: boolean): Notification { - this._hasAction = hasAction; - return this._notification; - } - - /** - * - * @param launchImage - * @returns {Notification} - */ - setLaunchImage(launchImage: string): Notification { - this._launchImage = launchImage; - return this._notification; - } - - /** - * - * @param threadIdentifier - * @returns {Notification} - */ - setThreadIdentifier(threadIdentifier: string): Notification { - this._threadIdentifier = threadIdentifier; - return this._notification; - } - - build(): NativeIOSNotification { - // TODO: Validation of required fields - - return { - alertAction: this._alertAction, - attachments: this._attachments, - badge: this._badge, - category: this._category, - hasAction: this._hasAction, - launchImage: this._launchImage, - threadIdentifier: this._threadIdentifier, - }; - } -} diff --git a/bridge/firebase/modules/notifications/Notification.js b/bridge/firebase/modules/notifications/Notification.js deleted file mode 100644 index 9385c27e..00000000 --- a/bridge/firebase/modules/notifications/Notification.js +++ /dev/null @@ -1,169 +0,0 @@ -/** - * @flow - * Notification representation wrapper - */ -import { Platform } from 'react-native'; -import AndroidNotification from './AndroidNotification'; -import IOSNotification from './IOSNotification'; -import { generatePushID, isObject } from '../../utils'; - -import type { NativeNotification } from './types'; - -export type NotificationOpen = {| - action: string, - notification: Notification, - results?: { [string]: string }, -|}; - -export default class Notification { - // iOS 8/9 | 10+ | Android - _android: AndroidNotification; - _body: string; // alertBody | body | contentText - _data: { [string]: string }; // userInfo | userInfo | extras - _ios: IOSNotification; - _notificationId: string; - _sound: string | void; // soundName | sound | sound - _subtitle: string | void; // N/A | subtitle | subText - _title: string; // alertTitle | title | contentTitle - - constructor(data?: NativeNotification) { - this._android = new AndroidNotification(this, data && data.android); - this._ios = new IOSNotification(this, data && data.ios); - - if (data) { - this._body = data.body; - this._data = data.data; - this._notificationId = data.notificationId; - this._sound = data.sound; - this._subtitle = data.subtitle; - this._title = data.title; - } - - // Defaults - this._data = this._data || {}; - // TODO: Is this the best way to generate an ID? - this._notificationId = this._notificationId || generatePushID(); - } - - get android(): AndroidNotification { - return this._android; - } - - get body(): string { - return this._body; - } - - get data(): { [string]: string } { - return this._data; - } - - get ios(): IOSNotification { - return this._ios; - } - - get notificationId(): string { - return this._notificationId; - } - - get sound(): ?string { - return this._sound; - } - - get subtitle(): ?string { - return this._subtitle; - } - - get title(): string { - return this._title; - } - - /** - * - * @param body - * @returns {Notification} - */ - setBody(body: string): Notification { - this._body = body; - return this; - } - - /** - * - * @param data - * @returns {Notification} - */ - setData(data: Object = {}): Notification { - if (!isObject(data)) { - throw new Error( - `Notification:withData expects an object but got type '${typeof data}'.` - ); - } - this._data = data; - return this; - } - - /** - * - * @param notificationId - * @returns {Notification} - */ - setNotificationId(notificationId: string): Notification { - this._notificationId = notificationId; - return this; - } - - /** - * - * @param sound - * @returns {Notification} - */ - setSound(sound: string): Notification { - this._sound = sound; - return this; - } - - /** - * - * @param subtitle - * @returns {Notification} - */ - setSubtitle(subtitle: string): Notification { - this._subtitle = subtitle; - return this; - } - - /** - * - * @param title - * @returns {Notification} - */ - setTitle(title: string): Notification { - this._title = title; - return this; - } - - build(): NativeNotification { - // Android required fields: body, title, smallicon - // iOS required fields: TODO - if (!this._body) { - throw new Error('Notification: Missing required `body` property'); - } else if (!this._notificationId) { - throw new Error( - 'Notification: Missing required `notificationId` property' - ); - } else if (!this._title) { - throw new Error('Notification: Missing required `title` property'); - } - - return { - android: Platform.OS === 'android' ? this._android.build() : undefined, - body: this._body, - data: this._data, - ios: Platform.OS === 'ios' ? this._ios.build() : undefined, - notificationId: this._notificationId, - sound: this._sound, - subtitle: this._subtitle, - title: this._title, - }; - } -} diff --git a/bridge/firebase/modules/notifications/index.js b/bridge/firebase/modules/notifications/index.js deleted file mode 100644 index 504bd9e0..00000000 --- a/bridge/firebase/modules/notifications/index.js +++ /dev/null @@ -1,318 +0,0 @@ -/** - * @flow - * Notifications representation wrapper - */ -import { SharedEventEmitter } from '../../utils/events'; -import { getLogger } from '../../utils/log'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; -import { isFunction, isObject } from '../../utils'; -import AndroidAction from './AndroidAction'; -import AndroidChannel from './AndroidChannel'; -import AndroidChannelGroup from './AndroidChannelGroup'; -import AndroidNotifications from './AndroidNotifications'; -import AndroidRemoteInput from './AndroidRemoteInput'; -import Notification from './Notification'; -import { - BadgeIconType, - Category, - Defaults, - GroupAlert, - Importance, - Priority, - SemanticAction, - Visibility, -} from './types'; - -import type App from '../core/app'; -import type { NotificationOpen } from './Notification'; -import type { - NativeNotification, - NativeNotificationOpen, - Schedule, -} from './types'; - -type OnNotification = Notification => any; - -type OnNotificationObserver = { - next: OnNotification, -}; - -type OnNotificationOpened = NotificationOpen => any; - -type OnNotificationOpenedObserver = { - next: NotificationOpen, -}; - -const NATIVE_EVENTS = [ - 'notifications_notification_displayed', - 'notifications_notification_opened', - 'notifications_notification_received', -]; - -export const MODULE_NAME = 'RNFirebaseNotifications'; -export const NAMESPACE = 'notifications'; - -// iOS 8/9 scheduling -// fireDate: Date; -// timeZone: TimeZone; -// repeatInterval: NSCalendar.Unit; -// repeatCalendar: Calendar; -// region: CLRegion; -// regionTriggersOnce: boolean; - -// iOS 10 scheduling -// TODO - -// Android scheduling -// TODO - -/** - * @class Notifications - */ -export default class Notifications extends ModuleBase { - _android: AndroidNotifications; - - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - hasShards: false, - moduleName: MODULE_NAME, - multiApp: false, - namespace: NAMESPACE, - }); - this._android = new AndroidNotifications(this); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onNotificationDisplayed - 'notifications_notification_displayed', - (notification: NativeNotification) => { - SharedEventEmitter.emit( - 'onNotificationDisplayed', - new Notification(notification) - ); - } - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onNotificationOpened - 'notifications_notification_opened', - (notificationOpen: NativeNotificationOpen) => { - SharedEventEmitter.emit('onNotificationOpened', { - action: notificationOpen.action, - notification: new Notification(notificationOpen.notification), - results: notificationOpen.results, - }); - } - ); - - SharedEventEmitter.addListener( - // sub to internal native event - this fans out to - // public event name: onNotification - 'notifications_notification_received', - (notification: NativeNotification) => { - SharedEventEmitter.emit( - 'onNotification', - new Notification(notification) - ); - } - ); - } - - get android(): AndroidNotifications { - return this._android; - } - - /** - * Cancel all notifications - */ - cancelAllNotifications(): void { - getNativeModule(this).cancelAllNotifications(); - } - - /** - * Cancel a notification by id. - * @param notificationId - */ - cancelNotification(notificationId: string): void { - if (!notificationId) { - throw new Error( - 'Notifications: cancelNotification expects a `notificationId`' - ); - } - getNativeModule(this).cancelNotification(notificationId); - } - - /** - * Display a notification - * @param notification - * @returns {*} - */ - displayNotification(notification: Notification): Promise { - if (!(notification instanceof Notification)) { - throw new Error( - `Notifications:displayNotification expects a 'Notification' but got type ${typeof notification}` - ); - } - return getNativeModule(this).displayNotification(notification.build()); - } - - getBadge(): Promise { - return getNativeModule(this).getBadge(); - } - - getInitialNotification(): Promise { - return getNativeModule(this) - .getInitialNotification() - .then((notificationOpen: NativeNotificationOpen) => { - if (notificationOpen) { - return { - action: notificationOpen.action, - notification: new Notification(notificationOpen.notification), - results: notificationOpen.results, - }; - } - return null; - }); - } - - /** - * Returns an array of all scheduled notifications - * @returns {Promise.} - */ - getScheduledNotifications(): Promise { - return getNativeModule(this).getScheduledNotifications(); - } - - onNotification( - nextOrObserver: OnNotification | OnNotificationObserver - ): () => any { - let listener; - if (isFunction(nextOrObserver)) { - listener = nextOrObserver; - } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { - listener = nextOrObserver.next; - } else { - throw new Error( - 'Notifications.onNotification failed: First argument must be a function or observer object with a `next` function.' - ); - } - - getLogger(this).info('Creating onNotification listener'); - SharedEventEmitter.addListener('onNotification', listener); - - return () => { - getLogger(this).info('Removing onNotification listener'); - SharedEventEmitter.removeListener('onNotification', listener); - }; - } - - onNotificationDisplayed( - nextOrObserver: OnNotification | OnNotificationObserver - ): () => any { - let listener; - if (isFunction(nextOrObserver)) { - listener = nextOrObserver; - } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { - listener = nextOrObserver.next; - } else { - throw new Error( - 'Notifications.onNotificationDisplayed failed: First argument must be a function or observer object with a `next` function.' - ); - } - - getLogger(this).info('Creating onNotificationDisplayed listener'); - SharedEventEmitter.addListener('onNotificationDisplayed', listener); - - return () => { - getLogger(this).info('Removing onNotificationDisplayed listener'); - SharedEventEmitter.removeListener('onNotificationDisplayed', listener); - }; - } - - onNotificationOpened( - nextOrObserver: OnNotificationOpened | OnNotificationOpenedObserver - ): () => any { - let listener; - if (isFunction(nextOrObserver)) { - listener = nextOrObserver; - } else if (isObject(nextOrObserver) && isFunction(nextOrObserver.next)) { - listener = nextOrObserver.next; - } else { - throw new Error( - 'Notifications.onNotificationOpened failed: First argument must be a function or observer object with a `next` function.' - ); - } - - getLogger(this).info('Creating onNotificationOpened listener'); - SharedEventEmitter.addListener('onNotificationOpened', listener); - - return () => { - getLogger(this).info('Removing onNotificationOpened listener'); - SharedEventEmitter.removeListener('onNotificationOpened', listener); - }; - } - - /** - * Remove all delivered notifications. - */ - removeAllDeliveredNotifications(): void { - getNativeModule(this).removeAllDeliveredNotifications(); - } - - /** - * Remove a delivered notification. - * @param notificationId - */ - removeDeliveredNotification(notificationId: string): void { - if (!notificationId) { - throw new Error( - 'Notifications: removeDeliveredNotification expects a `notificationId`' - ); - } - getNativeModule(this).removeDeliveredNotification(notificationId); - } - - /** - * Schedule a notification - * @param notification - * @returns {*} - */ - scheduleNotification( - notification: Notification, - schedule: Schedule - ): Promise { - if (!(notification instanceof Notification)) { - throw new Error( - `Notifications:scheduleNotification expects a 'Notification' but got type ${typeof notification}` - ); - } - const nativeNotification = notification.build(); - nativeNotification.schedule = schedule; - return getNativeModule(this).scheduleNotification(nativeNotification); - } - - setBadge(badge: number): void { - getNativeModule(this).setBadge(badge); - } -} - -export const statics = { - Android: { - Action: AndroidAction, - BadgeIconType, - Category, - Channel: AndroidChannel, - ChannelGroup: AndroidChannelGroup, - Defaults, - GroupAlert, - Importance, - Priority, - RemoteInput: AndroidRemoteInput, - SemanticAction, - Visibility, - }, - Notification, -}; diff --git a/bridge/firebase/modules/notifications/types.js b/bridge/firebase/modules/notifications/types.js deleted file mode 100644 index 1441d8e3..00000000 --- a/bridge/firebase/modules/notifications/types.js +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @flow - */ -export const BadgeIconType = { - Large: 2, - None: 0, - Small: 1, -}; - -export const Category = { - Alarm: 'alarm', - Call: 'call', - Email: 'email', - Error: 'err', - Event: 'event', - Message: 'msg', - Progress: 'progress', - Promo: 'promo', - Recommendation: 'recommendation', - Reminder: 'reminder', - Service: 'service', - Social: 'social', - Status: 'status', - System: 'system', - Transport: 'transport', -}; - -export const Defaults = { - All: -1, - Lights: 4, - Sound: 1, - Vibrate: 2, -}; - -export const GroupAlert = { - All: 0, - Children: 2, - Summary: 1, -}; - -export const Importance = { - Default: 3, - High: 4, - Low: 2, - Max: 5, - Min: 1, - None: 3, - Unspecified: -1000, -}; - -export const Priority = { - Default: 0, - High: 1, - Low: -1, - Max: 2, - Min: -2, -}; - -export const SemanticAction = { - Archive: 5, - Call: 10, - Delete: 4, - MarkAsRead: 2, - MarkAsUnread: 3, - Mute: 6, - None: 0, - Reply: 1, - ThumbsDown: 9, - ThumbsUp: 8, - Unmute: 7, -}; - -export const Visibility = { - Private: 0, - Public: 1, - Secret: -1, -}; - -export type BadgeIconTypeType = $Values; -export type CategoryType = $Values; -export type DefaultsType = $Values; -export type GroupAlertType = $Values; -export type ImportanceType = $Values; -export type PriorityType = $Values; -export type SemanticActionType = $Values; -export type VisibilityType = $Values; - -export type Lights = {| - argb: number, - onMs: number, - offMs: number, -|}; - -export type Progress = {| - max: number, - progress: number, - indeterminate: boolean, -|}; - -export type SmallIcon = {| - icon: string, - level?: number, -|}; - -export type AndroidAllowDataType = { - allow: boolean, - mimeType: string, -}; - -export type NativeAndroidRemoteInput = {| - allowedDataTypes: AndroidAllowDataType[], - allowFreeFormInput?: boolean, - choices: string[], - label?: string, - resultKey: string, -|}; - -export type NativeAndroidAction = {| - action: string, - allowGeneratedReplies?: boolean, - icon: string, - remoteInputs: NativeAndroidRemoteInput[], - semanticAction?: SemanticActionType, - showUserInterface?: boolean, - title: string, -|}; - -export type NativeAndroidNotification = {| - actions?: NativeAndroidAction[], - autoCancel?: boolean, - badgeIconType?: BadgeIconTypeType, - category?: CategoryType, - channelId: string, - clickAction?: string, - color?: string, - colorized?: boolean, - contentInfo?: string, - defaults?: DefaultsType[], - group?: string, - groupAlertBehaviour?: GroupAlertType, - groupSummary?: boolean, - largeIcon?: string, - lights?: Lights, - localOnly?: boolean, - number?: number, - ongoing?: boolean, - onlyAlertOnce?: boolean, - people: string[], - priority?: PriorityType, - progress?: Progress, - // publicVersion: Notification, - remoteInputHistory?: string[], - shortcutId?: string, - showWhen?: boolean, - smallIcon: SmallIcon, - sortKey?: string, - // TODO: style: Style, - ticker?: string, - timeoutAfter?: number, - usesChronometer?: boolean, - vibrate?: number[], - visibility?: VisibilityType, - when?: number, -|}; - -export type IOSAttachmentOptions = {| - typeHint: string, - thumbnailHidden: boolean, - thumbnailClippingRect: { - height: number, - width: number, - x: number, - y: number, - }, - thumbnailTime: number, -|}; - -export type IOSAttachment = {| - identifier: string, - options?: IOSAttachmentOptions, - url: string, -|}; - -export type NativeIOSNotification = {| - alertAction?: string, - attachments: IOSAttachment[], - badge?: number, - category?: string, - hasAction?: boolean, - launchImage?: string, - threadIdentifier?: string, -|}; - -export type Schedule = {| - exact?: boolean, - fireDate: number, - repeatInterval?: 'minute' | 'hour' | 'day' | 'week', -|}; - -export type NativeNotification = {| - android?: NativeAndroidNotification, - body: string, - data: { [string]: string }, - ios?: NativeIOSNotification, - notificationId: string, - schedule?: Schedule, - sound?: string, - subtitle?: string, - title: string, -|}; - -export type NativeNotificationOpen = {| - action: string, - notification: NativeNotification, - results?: { [string]: string }, -|}; diff --git a/bridge/firebase/modules/perf/Trace.js b/bridge/firebase/modules/perf/Trace.js deleted file mode 100644 index 5fd54608..00000000 --- a/bridge/firebase/modules/perf/Trace.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @flow - * Trace representation wrapper - */ -import { getNativeModule } from '../../utils/native'; -import type PerformanceMonitoring from './'; - -export default class Trace { - identifier: string; - _perf: PerformanceMonitoring; - - constructor(perf: PerformanceMonitoring, identifier: string) { - this._perf = perf; - this.identifier = identifier; - } - - start(): void { - getNativeModule(this._perf).start(this.identifier); - } - - stop(): void { - getNativeModule(this._perf).stop(this.identifier); - } - - incrementCounter(event: string): void { - getNativeModule(this._perf).incrementCounter(this.identifier, event); - } -} diff --git a/bridge/firebase/modules/perf/index.js b/bridge/firebase/modules/perf/index.js deleted file mode 100644 index c22ed35e..00000000 --- a/bridge/firebase/modules/perf/index.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @flow - * Performance monitoring representation wrapper - */ -import Trace from './Trace'; -import ModuleBase from '../../utils/ModuleBase'; -import { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; - -export const MODULE_NAME = 'RNFirebasePerformance'; -export const NAMESPACE = 'perf'; - -export default class PerformanceMonitoring extends ModuleBase { - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - } - - /** - * Globally enable or disable performance monitoring - * @param enabled - * @returns {*} - */ - setPerformanceCollectionEnabled(enabled: boolean): void { - getNativeModule(this).setPerformanceCollectionEnabled(enabled); - } - - /** - * Returns a new trace instance - * @param trace - */ - newTrace(trace: string): Trace { - return new Trace(this, trace); - } -} - -export const statics = {}; diff --git a/bridge/firebase/modules/storage/index.js b/bridge/firebase/modules/storage/index.js deleted file mode 100644 index 457de361..00000000 --- a/bridge/firebase/modules/storage/index.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @flow - * Storage representation wrapper - */ -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 { getNativeModule } from '../../utils/native'; - -import type App from '../core/app'; - -const FirebaseStorage = NativeModules.RNFirebaseStorage; - -const NATIVE_EVENTS = ['storage_event', 'storage_error']; - -export const MODULE_NAME = 'RNFirebaseStorage'; -export const NAMESPACE = 'storage'; - -export default class Storage extends ModuleBase { - /** - * - * @param app - * @param options - */ - constructor(app: App) { - super(app, { - events: NATIVE_EVENTS, - moduleName: MODULE_NAME, - multiApp: true, - hasShards: false, - namespace: NAMESPACE, - }); - - SharedEventEmitter.addListener( - getAppEventName(this, 'storage_event'), - this._handleStorageEvent.bind(this) - ); - - SharedEventEmitter.addListener( - getAppEventName(this, 'storage_error'), - this._handleStorageEvent.bind(this) - ); - } - - /** - * Returns a reference for the given path in the default bucket. - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#ref - * @param path - * @returns {StorageReference} - */ - ref(path: string): StorageRef { - return new StorageRef(this, path); - } - - /** - * Returns a reference for the given absolute URL. - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#refFromURL - * @param url - * @returns {StorageReference} - */ - refFromURL(url: string): StorageRef { - // TODO don't think this is correct? - return new StorageRef(this, `url::${url}`); - } - - /** - * setMaxOperationRetryTime - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxOperationRetryTime - * @param time The new maximum operation retry time in milliseconds. - */ - setMaxOperationRetryTime(time: number): void { - getNativeModule(this).setMaxOperationRetryTime(time); - } - - /** - * setMaxUploadRetryTime - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxUploadRetryTime - * @param time The new maximum upload retry time in milliseconds. - */ - setMaxUploadRetryTime(time: number): void { - getNativeModule(this).setMaxUploadRetryTime(time); - } - - /** - * setMaxDownloadRetryTime - * @url N/A - * @param time The new maximum download retry time in milliseconds. - */ - setMaxDownloadRetryTime(time: number): void { - getNativeModule(this).setMaxDownloadRetryTime(time); - } - - /** - * INTERNALS - */ - _getSubEventName(path: string, eventName: string) { - return getAppEventName(this, `${path}-${eventName}`); - } - - _handleStorageEvent(event: Object) { - const { path, eventName } = event; - const body = event.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 || {}; - - getLogger(this).debug('_handleStorageError ->', err); - SharedEventEmitter.emit(this._getSubEventName(path, eventName), body); - } - - _addListener( - path: string, - eventName: string, - cb: (evt: Object) => Object - ): void { - SharedEventEmitter.addListener(this._getSubEventName(path, eventName), cb); - } - - _removeListener( - path: string, - eventName: string, - origCB: (evt: Object) => Object - ): void { - SharedEventEmitter.removeListener( - this._getSubEventName(path, eventName), - origCB - ); - } -} - -export const statics = { - TaskEvent: { - STATE_CHANGED: 'state_changed', - }, - TaskState: { - RUNNING: 'running', - PAUSED: 'paused', - SUCCESS: 'success', - CANCELLED: 'cancelled', - ERROR: 'error', - }, - Native: FirebaseStorage - ? { - MAIN_BUNDLE_PATH: FirebaseStorage.MAIN_BUNDLE_PATH, - CACHES_DIRECTORY_PATH: FirebaseStorage.CACHES_DIRECTORY_PATH, - DOCUMENT_DIRECTORY_PATH: FirebaseStorage.DOCUMENT_DIRECTORY_PATH, - EXTERNAL_DIRECTORY_PATH: FirebaseStorage.EXTERNAL_DIRECTORY_PATH, - EXTERNAL_STORAGE_DIRECTORY_PATH: - FirebaseStorage.EXTERNAL_STORAGE_DIRECTORY_PATH, - TEMP_DIRECTORY_PATH: FirebaseStorage.TEMP_DIRECTORY_PATH, - LIBRARY_DIRECTORY_PATH: FirebaseStorage.LIBRARY_DIRECTORY_PATH, - FILETYPE_REGULAR: FirebaseStorage.FILETYPE_REGULAR, - FILETYPE_DIRECTORY: FirebaseStorage.FILETYPE_DIRECTORY, - } - : {}, -}; diff --git a/bridge/firebase/modules/storage/reference.js b/bridge/firebase/modules/storage/reference.js deleted file mode 100644 index b58a3007..00000000 --- a/bridge/firebase/modules/storage/reference.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @flow - * StorageReference representation wrapper - */ -import ReferenceBase from '../../utils/ReferenceBase'; -import StorageTask, { UPLOAD_TASK, DOWNLOAD_TASK } from './task'; -import { getNativeModule } from '../../utils/native'; -import type Storage from './'; - -/** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference - */ -export default class StorageReference extends ReferenceBase { - _storage: Storage; - - constructor(storage: Storage, path: string) { - super(path); - this._storage = storage; - } - - get fullPath(): string { - return this.path; - } - - toString(): string { - return `gs://${this._storage.app.options.storageBucket}${this.path}`; - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#child - * @param path - * @returns {StorageReference} - */ - child(path: string): StorageReference { - return new StorageReference(this._storage, `${this.path}/${path}`); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete - * @returns {Promise.|*} - */ - delete(): Promise { - return getNativeModule(this._storage).delete(this.path); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL - * @returns {Promise.|*} - */ - getDownloadURL(): Promise { - return getNativeModule(this._storage).getDownloadURL(this.path); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata - * @returns {Promise.|*} - */ - getMetadata(): Promise { - return getNativeModule(this._storage).getMetadata(this.path); - } - - /** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata - * @param metadata - * @returns {Promise.|*} - */ - updateMetadata(metadata: Object = {}): Promise { - return getNativeModule(this._storage).updateMetadata(this.path, metadata); - } - - /** - * Downloads a reference to the device - * @param {String} filePath Where to store the file - * @return {Promise} - */ - downloadFile(filePath: string): Promise { - return new StorageTask( - DOWNLOAD_TASK, - getNativeModule(this._storage).downloadFile(this.path, filePath), - this - ); - } - - /** - * Alias to putFile - * @returns {StorageReference.putFile} - */ - get put(): (Object, Object) => Promise { - return this.putFile; - } - - /** - * Upload a file path - * @param {string} filePath The local path of the file - * @param {object} metadata An object containing metadata - * @return {Promise} - */ - putFile(filePath: Object, metadata: Object = {}): Promise { - const _filePath = filePath.replace('file://', ''); - return new StorageTask( - UPLOAD_TASK, - getNativeModule(this._storage).putFile(this.path, _filePath, metadata), - this - ); - } -} diff --git a/bridge/firebase/modules/storage/task.js b/bridge/firebase/modules/storage/task.js deleted file mode 100644 index 0fdc6329..00000000 --- a/bridge/firebase/modules/storage/task.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - * @flow - * UploadTask representation wrapper - */ -import { statics as StorageStatics } from './'; -import { isFunction } from './../../utils'; -import type Storage from './'; -import type StorageReference from './reference'; - -export const UPLOAD_TASK = 'upload'; -export const DOWNLOAD_TASK = 'download'; - -declare type UploadTaskSnapshotType = { - bytesTransferred: number, - downloadURL: string | null, - metadata: Object, // TODO flow type def for https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata.html - ref: StorageReference, - state: - | typeof StorageStatics.TaskState.RUNNING - | typeof StorageStatics.TaskState.PAUSED - | typeof StorageStatics.TaskState.SUCCESS - | typeof StorageStatics.TaskState.CANCELLED - | typeof StorageStatics.TaskState.ERROR, - task: StorageTask, - totalBytes: number, -}; - -declare type FuncSnapshotType = - | null - | ((snapshot: UploadTaskSnapshotType) => any); - -declare type FuncErrorType = null | ((error: Error) => any); - -declare type NextOrObserverType = - | null - | { - next?: FuncSnapshotType, - error?: FuncErrorType, - complete?: FuncSnapshotType, - } - | FuncSnapshotType; - -/** - * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask - */ -export default class StorageTask { - type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK; - ref: StorageReference; - storage: Storage; - path: string; - then: () => Promise<*>; - catch: () => Promise<*>; - - constructor( - type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK, - promise: Promise<*>, - storageRef: StorageReference - ) { - this.type = type; - this.ref = storageRef; - this.storage = storageRef._storage; - this.path = storageRef.path; - - // 'proxy' original promise - this.then = promise.then.bind(promise); - this.catch = promise.catch.bind(promise); - } - - /** - * Intercepts a native snapshot result object attaches ref / task instances - * and calls the original function - * @returns {Promise.} - * @private - */ - _interceptSnapshotEvent(f: ?Function): null | (() => *) { - if (!isFunction(f)) return null; - return snapshot => { - const _snapshot = Object.assign({}, snapshot); - _snapshot.task = this; - _snapshot.ref = this.ref; - return f && f(_snapshot); - }; - } - - /** - * Intercepts a error object form native and converts to a JS Error - * @param f - * @returns {*} - * @private - */ - _interceptErrorEvent(f: ?Function): null | (Error => *) { - if (!isFunction(f)) return null; - return error => { - const _error = new Error(error.message); - // $FlowExpectedError - _error.code = error.code; - return f && f(_error); - }; - } - - /** - * - * @param nextOrObserver - * @param error - * @param complete - * @returns {function()} - * @private - */ - _subscribe( - nextOrObserver: NextOrObserverType, - error: FuncErrorType, - complete: FuncSnapshotType - ): Function { - let _error; - let _next; - let _complete; - - if (typeof nextOrObserver === 'function') { - _error = this._interceptErrorEvent(error); - _next = this._interceptSnapshotEvent(nextOrObserver); - _complete = this._interceptSnapshotEvent(complete); - } else if (nextOrObserver) { - _error = this._interceptErrorEvent(nextOrObserver.error); - _next = this._interceptSnapshotEvent(nextOrObserver.next); - _complete = this._interceptSnapshotEvent(nextOrObserver.complete); - } - - if (_next) { - this.storage._addListener( - this.path, - StorageStatics.TaskEvent.STATE_CHANGED, - _next - ); - } - if (_error) { - this.storage._addListener(this.path, `${this.type}_failure`, _error); - } - if (_complete) { - this.storage._addListener(this.path, `${this.type}_success`, _complete); - } - - return () => { - if (_next) - this.storage._removeListener( - this.path, - StorageStatics.TaskEvent.STATE_CHANGED, - _next - ); - if (_error) - this.storage._removeListener(this.path, `${this.type}_failure`, _error); - if (_complete) - this.storage._removeListener( - this.path, - `${this.type}_success`, - _complete - ); - }; - } - - /** - * - * @param event - * @param nextOrObserver - * @param error - * @param complete - * @returns {function()} - */ - on( - event: string = StorageStatics.TaskEvent.STATE_CHANGED, - nextOrObserver: NextOrObserverType, - error: FuncErrorType, - complete: FuncSnapshotType - ): Function { - if (!event) { - throw new Error( - "StorageTask.on listener is missing required string argument 'event'." - ); - } - - if (event !== StorageStatics.TaskEvent.STATE_CHANGED) { - throw new Error( - `StorageTask.on event argument must be a string with a value of '${ - StorageStatics.TaskEvent.STATE_CHANGED - }'` - ); - } - - // if only event provided return the subscriber function - if (!nextOrObserver && !error && !complete) { - return this._subscribe.bind(this); - } - - return this._subscribe(nextOrObserver, error, complete); - } - - pause() { - throw new Error( - '.pause() is not currently supported by react-native-firebase' - ); - } - - resume() { - // todo - throw new Error( - '.resume() is not currently supported by react-native-firebase' - ); - } - - cancel() { - // todo - throw new Error( - '.cancel() is not currently supported by react-native-firebase' - ); - } -} diff --git a/bridge/firebase/modules/utils/index.js b/bridge/firebase/modules/utils/index.js deleted file mode 100644 index ce48a2ad..00000000 --- a/bridge/firebase/modules/utils/index.js +++ /dev/null @@ -1,115 +0,0 @@ -// @flow -import { NativeModules } from 'react-native'; -import INTERNALS from '../../utils/internals'; -import { isIOS } from '../../utils'; -import ModuleBase from '../../utils/ModuleBase'; -import type App from '../core/app'; - -const FirebaseCoreModule = NativeModules.RNFirebase; - -type GoogleApiAvailabilityType = { - status: number, - isAvailable: boolean, - isUserResolvableError?: boolean, - hasResolution?: boolean, - error?: string, -}; - -export const MODULE_NAME = 'RNFirebaseUtils'; -export const NAMESPACE = 'utils'; - -export default class RNFirebaseUtils extends ModuleBase { - constructor(app: App) { - super(app, { - moduleName: MODULE_NAME, - multiApp: false, - hasShards: false, - namespace: NAMESPACE, - }); - } - - /** - * - */ - checkPlayServicesAvailability() { - if (isIOS) return; - - const { status } = this.playServicesAvailability; - - if (!this.playServicesAvailability.isAvailable) { - if ( - INTERNALS.OPTIONS.promptOnMissingPlayServices && - this.playServicesAvailability.isUserResolvableError - ) { - this.promptForPlayServices(); - } else { - const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(status); - if (INTERNALS.OPTIONS.errorOnMissingPlayServices) { - if (status === 2) - console.warn(error); // only warn if it exists but may need an update - else throw new Error(error); - } else { - console.warn(error); - } - } - } - } - - promptForPlayServices() { - if (isIOS) return null; - return FirebaseCoreModule.promptForPlayServices(); - } - - resolutionForPlayServices() { - if (isIOS) return null; - return FirebaseCoreModule.resolutionForPlayServices(); - } - - makePlayServicesAvailable() { - if (isIOS) return null; - return FirebaseCoreModule.makePlayServicesAvailable(); - } - - /** - * Set the global logging level for all logs. - * - * @param logLevel - */ - set logLevel(logLevel: string) { - INTERNALS.OPTIONS.logLevel = logLevel; - } - - /** - * Returns props from the android GoogleApiAvailability sdk - * @android - * @return {RNFirebase.GoogleApiAvailabilityType|{isAvailable: boolean, status: number}} - */ - get playServicesAvailability(): GoogleApiAvailabilityType { - return ( - FirebaseCoreModule.playServicesAvailability || { - isAvailable: true, - status: 0, - } - ); - } - - /** - * Enable/Disable throwing an error or warning on detecting a play services problem - * @android - * @param bool - */ - set errorOnMissingPlayServices(bool: boolean) { - INTERNALS.OPTIONS.errorOnMissingPlayServices = bool; - } - - /** - * Enable/Disable automatic prompting of the play services update dialog - * @android - * @param bool - */ - set promptOnMissingPlayServices(bool: boolean) { - INTERNALS.OPTIONS.promptOnMissingPlayServices = bool; - } -} - -export const statics = {}; diff --git a/bridge/firebase/types/index.js b/bridge/firebase/types/index.js deleted file mode 100644 index c0ea162a..00000000 --- a/bridge/firebase/types/index.js +++ /dev/null @@ -1,232 +0,0 @@ -/* @flow */ -import type AdMob from '../modules/admob'; -import { typeof statics as AdMobStatics } from '../modules/admob'; -import type Analytics from '../modules/analytics'; -import { typeof statics as AnalyticsStatics } from '../modules/analytics'; -import type Auth from '../modules/auth'; -import { typeof statics as AuthStatics } from '../modules/auth'; -import type Config from '../modules/config'; -import { typeof statics as ConfigStatics } from '../modules/config'; -import type Crash from '../modules/crash'; -import { typeof statics as CrashStatics } from '../modules/crash'; -import type Crashlytics from '../modules/fabric/crashlytics'; -import { typeof statics as CrashlyticsStatics } from '../modules/fabric/crashlytics'; -import type Database from '../modules/database'; -import { typeof statics as DatabaseStatics } from '../modules/database'; -import type Firestore from '../modules/firestore'; -import { typeof statics as FirestoreStatics } from '../modules/firestore'; -import type InstanceId from '../modules/instanceid'; -import { typeof statics as InstanceIdStatics } from '../modules/instanceid'; -import type Invites from '../modules/invites'; -import { typeof statics as InvitesStatics } from '../modules/invites'; -import type Links from '../modules/links'; -import { typeof statics as LinksStatics } from '../modules/links'; -import type Messaging from '../modules/messaging'; -import { typeof statics as MessagingStatics } from '../modules/messaging'; -import type Notifications from '../modules/notifications'; -import { typeof statics as NotificationsStatics } from '../modules/notifications'; -import type ModuleBase from '../utils/ModuleBase'; -import type Performance from '../modules/perf'; -import { typeof statics as PerformanceStatics } from '../modules/perf'; -import type Storage from '../modules/storage'; -import { typeof statics as StorageStatics } from '../modules/storage'; -import type Utils from '../modules/utils'; -import { typeof statics as UtilsStatics } from '../modules/utils'; - -/* Core types */ -export type FirebaseError = { - message: string, - name: string, - code: string, - stack: string, - path: string, - details: string, - modifiers: string, -}; - -export type FirebaseModule = $Subtype; - -export type FirebaseModuleConfig = { - events?: string[], - moduleName: FirebaseModuleName, - multiApp: boolean, - hasShards: boolean, - namespace: FirebaseNamespace, -}; - -export type FirebaseModuleName = - | 'RNFirebaseAdMob' - | 'RNFirebaseAnalytics' - | 'RNFirebaseAuth' - | 'RNFirebaseRemoteConfig' - | 'RNFirebaseCrash' - | 'RNFirebaseCrashlytics' - | 'RNFirebaseDatabase' - | 'RNFirebaseFirestore' - | 'RNFirebaseInstanceId' - | 'RNFirebaseInvites' - | 'RNFirebaseLinks' - | 'RNFirebaseMessaging' - | 'RNFirebaseNotifications' - | 'RNFirebasePerformance' - | 'RNFirebaseStorage' - | 'RNFirebaseUtils'; - -export type FirebaseNamespace = - | 'admob' - | 'analytics' - | 'auth' - | 'config' - | 'crash' - | 'crashlytics' - | 'database' - | 'firestore' - | 'instanceid' - | 'invites' - | 'links' - | 'messaging' - | 'notifications' - | 'perf' - | 'storage' - | 'utils'; - -export type FirebaseOptions = { - apiKey: string, - appId: string, - databaseURL: string, - messagingSenderId: string, - projectId: string, - storageBucket: string, -}; - -export type FirebaseModuleAndStatics = { - (): M, - nativeModuleExists: boolean, -} & S; - -export type FirebaseStatics = $Subtype; - -/* Admob types */ - -export type AdMobModule = { - (): AdMob, - nativeModuleExists: boolean, -} & AdMobStatics; - -/* Analytics types */ - -export type AnalyticsModule = { - (): Analytics, - nativeModuleExists: boolean, -} & AnalyticsStatics; - -/* Remote Config types */ - -export type ConfigModule = { - (): Config, - nativeModuleExists: boolean, -} & ConfigStatics; - -/* Auth types */ - -export type AuthModule = { - (): Auth, - nativeModuleExists: boolean, -} & AuthStatics; - -/* Crash types */ - -export type CrashModule = { - (): Crash, - nativeModuleExists: boolean, -} & CrashStatics; - -/* Database types */ - -export type DatabaseModule = { - (): Database, - nativeModuleExists: boolean, -} & DatabaseStatics; - -export type DatabaseModifier = { - id: string, - type: 'orderBy' | 'limit' | 'filter', - name?: string, - key?: string, - limit?: number, - value?: any, - valueType?: string, -}; - -/* Fabric types */ -export type CrashlyticsModule = { - (): Crashlytics, - nativeModuleExists: boolean, -} & CrashlyticsStatics; - -export type FabricModule = { - crashlytics: CrashlyticsModule, -}; - -/* Firestore types */ - -export type FirestoreModule = { - (): Firestore, - nativeModuleExists: boolean, -} & FirestoreStatics; - -/* InstanceId types */ - -export type InstanceIdModule = { - (): InstanceId, - nativeModuleExists: boolean, -} & InstanceIdStatics; - -/* Invites types */ - -export type InvitesModule = { - (): Invites, - nativeModuleExists: boolean, -} & InvitesStatics; - -/* Links types */ - -export type LinksModule = { - (): Links, - nativeModuleExists: boolean, -} & LinksStatics; - -/* Messaging types */ - -export type MessagingModule = { - (): Messaging, - nativeModuleExists: boolean, -} & MessagingStatics; - -/* Notifications types */ - -export type NotificationsModule = { - (): Notifications, - nativeModuleExists: boolean, -} & NotificationsStatics; - -/* Performance types */ - -export type PerformanceModule = { - (): Performance, - nativeModuleExists: boolean, -} & PerformanceStatics; - -/* Storage types */ - -export type StorageModule = { - (): Storage, - nativeModuleExists: boolean, -} & StorageStatics; - -/* Utils types */ - -export type UtilsModule = { - (): Utils, - nativeModuleExists: boolean, -} & UtilsStatics; diff --git a/bridge/firebase/utils/ModuleBase.js b/bridge/firebase/utils/ModuleBase.js deleted file mode 100644 index ffa78088..00000000 --- a/bridge/firebase/utils/ModuleBase.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @flow - */ -import { initialiseLogger } from './log'; -import { initialiseNativeModule } from './native'; - -import type App from '../modules/core/app'; -import type { FirebaseModuleConfig, FirebaseNamespace } from '../types'; - -export default class ModuleBase { - _app: App; - _serviceUrl: ?string; - namespace: FirebaseNamespace; - - /** - * - * @param app - * @param config - */ - constructor(app: App, config: FirebaseModuleConfig, serviceUrl: ?string) { - if (!config.moduleName) { - throw new Error('Missing module name'); - } - if (!config.namespace) { - throw new Error('Missing namespace'); - } - const { moduleName } = config; - this._app = app; - this._serviceUrl = serviceUrl; - this.namespace = config.namespace; - - // check if native module exists as all native - initialiseNativeModule(this, config, serviceUrl); - initialiseLogger( - this, - `${app.name}:${moduleName.replace('RNFirebase', '')}` - ); - } - - /** - * Returns the App instance for current module - * @return {*} - */ - get app(): App { - return this._app; - } -} diff --git a/bridge/firebase/utils/ReferenceBase.js b/bridge/firebase/utils/ReferenceBase.js deleted file mode 100644 index 32056422..00000000 --- a/bridge/firebase/utils/ReferenceBase.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @flow - */ -export default class ReferenceBase { - path: string; - - constructor(path: string) { - if (path) { - this.path = - path.length > 1 && path.endsWith('/') - ? path.substring(0, path.length - 1) - : path; - } else { - this.path = '/'; - } - } - - /** - * The last part of a Reference's path (after the last '/') - * The key of a root Reference is null. - * @type {String} - * {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#key} - */ - get key(): string | null { - return this.path === '/' - ? null - : this.path.substring(this.path.lastIndexOf('/') + 1); - } -} diff --git a/bridge/firebase/utils/SyncTree.js b/bridge/firebase/utils/SyncTree.js deleted file mode 100644 index 7c72b7b6..00000000 --- a/bridge/firebase/utils/SyncTree.js +++ /dev/null @@ -1,334 +0,0 @@ -/** - * @flow - */ -import { NativeEventEmitter, NativeModules } from 'react-native'; - -import { SharedEventEmitter } from './events'; -import DataSnapshot from '../modules/database/DataSnapshot'; -import DatabaseReference from '../modules/database/Reference'; -import { isString, nativeToJSError } from '../utils'; - -type Listener = DataSnapshot => any; - -type Registration = { - key: string, - path: string, - once?: boolean, - appName: string, - eventType: string, - listener: Listener, - eventRegistrationKey: string, - ref: DatabaseReference, -}; - -/** - * Internally used to manage firebase database realtime event - * subscriptions and keep the listeners in sync in js vs native. - */ -class SyncTree { - _nativeEmitter: NativeEventEmitter; - _reverseLookup: { [string]: Registration }; - _tree: { [string]: { [string]: { [string]: Listener } } }; - - constructor() { - this._tree = {}; - this._reverseLookup = {}; - if (NativeModules.RNFirebaseDatabase) { - this._nativeEmitter = new NativeEventEmitter( - NativeModules.RNFirebaseDatabase - ); - this._nativeEmitter.addListener( - 'database_sync_event', - this._handleSyncEvent.bind(this) - ); - } - } - - /** - * - * @param event - * @private - */ - _handleSyncEvent(event) { - if (event.error) { - this._handleErrorEvent(event); - } else { - this._handleValueEvent(event); - } - } - - /** - * Routes native database 'on' events to their js equivalent counterpart. - * If there is no longer any listeners remaining for this event we internally - * call the native unsub method to prevent further events coming through. - * - * @param event - * @private - */ - _handleValueEvent(event) { - // console.log('SyncTree.VALUE >>>', event); - const { key, eventRegistrationKey } = event.registration; - const registration = this.getRegistration(eventRegistrationKey); - - if (!registration) { - // registration previously revoked - // notify native that the registration - // no longer exists so it can remove - // the native listeners - return NativeModules.RNFirebaseDatabase.off(key, eventRegistrationKey); - } - - const { snapshot, previousChildName } = event.data; - - // forward on to users .on(successCallback <-- listener - return SharedEventEmitter.emit( - eventRegistrationKey, - new DataSnapshot(registration.ref, snapshot), - previousChildName - ); - } - - /** - * Routes native database query listener cancellation events to their js counterparts. - * - * @param event - * @private - */ - _handleErrorEvent(event) { - // console.log('SyncTree.ERROR >>>', event); - const { code, message } = event.error; - const { - eventRegistrationKey, - registrationCancellationKey, - } = event.registration; - - const registration = this.getRegistration(registrationCancellationKey); - - if (registration) { - // build a new js error - we additionally attach - // the ref as a property for easier debugging - const error = nativeToJSError(code, message, { ref: registration.ref }); - - // forward on to users .on(successCallback, cancellationCallback <-- listener - 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 - this.removeRegistration(eventRegistrationKey); - } - } - - /** - * Returns registration information such as appName, ref, path and registration keys. - * - * @param registration - * @return {null} - */ - getRegistration(registration: string): Registration | null { - return this._reverseLookup[registration] - ? Object.assign({}, this._reverseLookup[registration]) - : null; - } - - /** - * Removes all listeners for the specified registration keys. - * - * @param registrations - * @return {number} - */ - removeListenersForRegistrations(registrations: string | string[]): number { - if (isString(registrations)) { - this.removeRegistration(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]); - SharedEventEmitter.removeAllListeners(registrations[i]); - } - - return registrations.length; - } - - /** - * Removes a specific listener from the specified registrations. - * - * @param listener - * @param registrations - * @return {Array} array of registrations removed - */ - removeListenerRegistrations(listener: () => any, registrations: string[]) { - if (!Array.isArray(registrations)) return []; - const removed = []; - - for (let i = 0, len = registrations.length; i < len; i++) { - const registration = registrations[i]; - const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType( - registration - ); - if (subscriptions) { - for (let j = 0, l = subscriptions.length; j < l; j++) { - const subscription = subscriptions[j]; - // The subscription may have been removed during this event loop. - // its listener matches the listener in method parameters - if (subscription && subscription.listener === listener) { - subscription.remove(); - removed.push(registration); - this.removeRegistration(registration); - } - } - } - } - - return removed; - } - - /** - * Returns an array of all registration keys for the specified path. - * - * @param path - * @return {Array} - */ - getRegistrationsByPath(path: string): string[] { - const out = []; - const eventKeys = Object.keys(this._tree[path] || {}); - - for (let i = 0, len = eventKeys.length; i < len; i++) { - Array.prototype.push.apply( - out, - Object.keys(this._tree[path][eventKeys[i]]) - ); - } - - return out; - } - - /** - * Returns an array of all registration keys for the specified path and eventType. - * - * @param path - * @param eventType - * @return {Array} - */ - getRegistrationsByPathEvent(path: string, eventType: string): string[] { - if (!this._tree[path]) return []; - if (!this._tree[path][eventType]) return []; - - return Object.keys(this._tree[path][eventType]); - } - - /** - * Returns a single registration key for the specified path, eventType, and listener - * - * @param path - * @param eventType - * @param listener - * @return {Array} - */ - getOneByPathEventListener( - path: string, - eventType: string, - listener: Function - ): ?string { - if (!this._tree[path]) return null; - if (!this._tree[path][eventType]) return null; - - const registrationsForPathEvent = Object.entries( - this._tree[path][eventType] - ); - - for (let i = 0; i < registrationsForPathEvent.length; i++) { - const registration = registrationsForPathEvent[i]; - if (registration[1] === listener) return registration[0]; - } - - return null; - } - - /** - * Register a new listener. - * - * @param parameters - * @param listener - * @return {String} - */ - addRegistration(registration: Registration): string { - const { - eventRegistrationKey, - eventType, - listener, - once, - path, - } = registration; - - if (!this._tree[path]) this._tree[path] = {}; - if (!this._tree[path][eventType]) this._tree[path][eventType] = {}; - - this._tree[path][eventType][eventRegistrationKey] = listener; - this._reverseLookup[eventRegistrationKey] = registration; - - if (once) { - SharedEventEmitter.once( - eventRegistrationKey, - this._onOnceRemoveRegistration(eventRegistrationKey, listener) - ); - } else { - SharedEventEmitter.addListener(eventRegistrationKey, listener); - } - - return eventRegistrationKey; - } - - /** - * Remove a registration, if it's not a `once` registration then instructs native - * to also remove the underlying database query listener. - * - * @param registration - * @return {boolean} - */ - removeRegistration(registration: string): boolean { - if (!this._reverseLookup[registration]) return false; - const { path, eventType, once } = this._reverseLookup[registration]; - - if (!this._tree[path]) { - delete this._reverseLookup[registration]; - return false; - } - - if (!this._tree[path][eventType]) { - delete this._reverseLookup[registration]; - return false; - } - - // we don't want `once` events to notify native as they're already - // automatically unsubscribed on native when the first event is sent - const registrationObj = this._reverseLookup[registration]; - if (registrationObj && !once) { - NativeModules.RNFirebaseDatabase.off(registrationObj.key, registration); - } - - delete this._tree[path][eventType][registration]; - delete this._reverseLookup[registration]; - - return !!registrationObj; - } - - /** - * Wraps a `once` listener with a new function that self de-registers. - * - * @param registration - * @param listener - * @return {function(...[*])} - * @private - */ - _onOnceRemoveRegistration(registration, listener) { - return (...args: any[]) => { - this.removeRegistration(registration); - listener(...args); - }; - } -} - -export default new SyncTree(); diff --git a/bridge/firebase/utils/apps.js b/bridge/firebase/utils/apps.js deleted file mode 100644 index 57ac16ea..00000000 --- a/bridge/firebase/utils/apps.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * @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]; - if (!app) throw new Error(INTERNALS.STRINGS.ERROR_APP_NOT_INIT(_name)); - return app; - }, - - apps(): Array { - // $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( - app: App, - namespace: FirebaseNamespace, - InstanceClass: Class - ): () => FirebaseModule { - 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] = {}; - } - - if ( - isAndroid && - namespace !== 'utils' && - !INTERNALS.FLAGS.checkedPlayServices - ) { - INTERNALS.FLAGS.checkedPlayServices = true; - app.utils().checkPlayServicesAvailability(); - } - - if (!APP_MODULES[appOrShardName][namespace]) { - APP_MODULES[appOrShardName][namespace] = new InstanceClass( - serviceUrl || app, - app.options - ); - } - - return APP_MODULES[appOrShardName][namespace]; - }; - }, - - deleteApp(name: string): Promise { - 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 { - if (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) - 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 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( - namespace: FirebaseNamespace, - statics: S, - moduleName: FirebaseModuleName - ): FirebaseModuleAndStatics { - const getModule = (appOrUrl?: App | string): FirebaseModule => { - let _app = appOrUrl; - let _serviceUrl: ?string = null; - if (typeof appOrUrl === 'string' && namespace === 'database') { - _app = null; - _serviceUrl = appOrUrl; - } - - // throw an error if it's not a valid app instance - 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); - 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(_serviceUrl); - }; - - return Object.assign(getModule, statics, { - nativeModuleExists: !!NativeModules[moduleName], - }); - }, -}; diff --git a/bridge/firebase/utils/emitter/EmitterSubscription.js b/bridge/firebase/utils/emitter/EmitterSubscription.js deleted file mode 100644 index 5d213b3d..00000000 --- a/bridge/firebase/utils/emitter/EmitterSubscription.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable */ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @noflow - */ -'use strict'; - -const EventSubscription = require('./EventSubscription'); - -import type EventEmitter from './EventEmitter'; -import type EventSubscriptionVendor from './EventSubscriptionVendor'; - -/** - * EmitterSubscription represents a subscription with listener and context data. - */ -class EmitterSubscription extends EventSubscription { - - emitter: EventEmitter; - listener: Function; - context: ?Object; - - /** - * @param {EventEmitter} emitter - The event emitter that registered this - * subscription - * @param {EventSubscriptionVendor} subscriber - The subscriber that controls - * this subscription - * @param {function} listener - Function to invoke when the specified event is - * emitted - * @param {*} context - Optional context object to use when invoking the - * listener - */ - constructor( - emitter: EventEmitter, - subscriber: EventSubscriptionVendor, - listener: Function, - context: ?Object - ) { - super(subscriber); - this.emitter = emitter; - this.listener = listener; - this.context = context; - } - - /** - * Removes this subscription from the emitter that registered it. - * Note: we're overriding the `remove()` method of EventSubscription here - * but deliberately not calling `super.remove()` as the responsibility - * for removing the subscription lies with the EventEmitter. - */ - remove() { - this.emitter.removeSubscription(this); - } -} - -module.exports = EmitterSubscription; diff --git a/bridge/firebase/utils/emitter/EventEmitter.js b/bridge/firebase/utils/emitter/EventEmitter.js deleted file mode 100644 index 96487b1e..00000000 --- a/bridge/firebase/utils/emitter/EventEmitter.js +++ /dev/null @@ -1,220 +0,0 @@ -/* eslint-disable */ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @noflow - * @typecheck - */ -'use strict'; - -const EmitterSubscription = require('./EmitterSubscription'); -const EventSubscriptionVendor = require('./EventSubscriptionVendor'); - -const emptyFunction = require('fbjs/lib/emptyFunction'); -const invariant = require('fbjs/lib/invariant'); - -/** - * @class EventEmitter - * @description - * An EventEmitter is responsible for managing a set of listeners and publishing - * events to them when it is told that such events happened. In addition to the - * data for the given event it also sends a event control object which allows - * the listeners/handlers to prevent the default behavior of the given event. - * - * The emitter is designed to be generic enough to support all the different - * contexts in which one might want to emit events. It is a simple multicast - * mechanism on top of which extra functionality can be composed. For example, a - * more advanced emitter may use an EventHolder and EventFactory. - */ -class EventEmitter { - - _subscriber: EventSubscriptionVendor; - _currentSubscription: ?EmitterSubscription; - - /** - * @constructor - * - * @param {EventSubscriptionVendor} subscriber - Optional subscriber instance - * to use. If omitted, a new subscriber will be created for the emitter. - */ - constructor(subscriber: ?EventSubscriptionVendor) { - this._subscriber = subscriber || new EventSubscriptionVendor(); - } - - /** - * Adds a listener to be invoked when events of the specified type are - * emitted. An optional calling context may be provided. The data arguments - * emitted will be passed to the listener function. - * - * TODO: Annotate the listener arg's type. This is tricky because listeners - * can be invoked with varargs. - * - * @param {string} eventType - Name of the event to listen to - * @param {function} listener - Function to invoke when the specified event is - * emitted - * @param {*} context - Optional context object to use when invoking the - * listener - */ - addListener( - eventType: string, listener: Function, context: ?Object): EmitterSubscription { - - return (this._subscriber.addSubscription( - eventType, - new EmitterSubscription(this, this._subscriber, listener, context) - ) : any); - } - - /** - * Similar to addListener, except that the listener is removed after it is - * invoked once. - * - * @param {string} eventType - Name of the event to listen to - * @param {function} listener - Function to invoke only once when the - * specified event is emitted - * @param {*} context - Optional context object to use when invoking the - * listener - */ - once(eventType: string, listener: Function, context: ?Object): EmitterSubscription { - return this.addListener(eventType, (...args) => { - this.removeCurrentListener(); - listener.apply(context, args); - }); - } - - /** - * Removes all of the registered listeners, including those registered as - * listener maps. - * - * @param {?string} eventType - Optional name of the event whose registered - * listeners to remove - */ - removeAllListeners(eventType: ?string) { - this._subscriber.removeAllSubscriptions(eventType); - } - - /** - * Provides an API that can be called during an eventing cycle to remove the - * last listener that was invoked. This allows a developer to provide an event - * object that can remove the listener (or listener map) during the - * invocation. - * - * If it is called when not inside of an emitting cycle it will throw. - * - * @throws {Error} When called not during an eventing cycle - * - * @example - * var subscription = emitter.addListenerMap({ - * someEvent: function(data, event) { - * console.log(data); - * emitter.removeCurrentListener(); - * } - * }); - * - * emitter.emit('someEvent', 'abc'); // logs 'abc' - * emitter.emit('someEvent', 'def'); // does not log anything - */ - removeCurrentListener() { - invariant( - !!this._currentSubscription, - 'Not in an emitting cycle; there is no current subscription' - ); - this.removeSubscription(this._currentSubscription); - } - - /** - * Removes a specific subscription. Called by the `remove()` method of the - * subscription itself to ensure any necessary cleanup is performed. - */ - removeSubscription(subscription: EmitterSubscription) { - invariant( - subscription.emitter === this, - 'Subscription does not belong to this emitter.' - ); - this._subscriber.removeSubscription(subscription); - } - - /** - * Returns an array of listeners that are currently registered for the given - * event. - * - * @param {string} eventType - Name of the event to query - * @returns {array} - */ - listeners(eventType: string): [EmitterSubscription] { - const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any); - return subscriptions - ? subscriptions.filter(emptyFunction.thatReturnsTrue).map( - function(subscription) { - return subscription.listener; - }) - : []; - } - - /** - * Emits an event of the given type with the given data. All handlers of that - * particular type will be notified. - * - * @param {string} eventType - Name of the event to emit - * @param {...*} Arbitrary arguments to be passed to each registered listener - * - * @example - * emitter.addListener('someEvent', function(message) { - * console.log(message); - * }); - * - * emitter.emit('someEvent', 'abc'); // logs 'abc' - */ - emit(eventType: string) { - const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any); - if (subscriptions) { - for (let i = 0, l = subscriptions.length; i < l; i++) { - const subscription = subscriptions[i]; - - // The subscription may have been removed during this event loop. - if (subscription) { - this._currentSubscription = subscription; - subscription.listener.apply( - subscription.context, - Array.prototype.slice.call(arguments, 1) - ); - } - } - this._currentSubscription = null; - } - } - - /** - * Removes the given listener for event of specific type. - * - * @param {string} eventType - Name of the event to emit - * @param {function} listener - Function to invoke when the specified event is - * emitted - * - * @example - * emitter.removeListener('someEvent', function(message) { - * console.log(message); - * }); // removes the listener if already registered - * - */ - removeListener(eventType: string, listener) { - const subscriptions: ?[EmitterSubscription] = (this._subscriber.getSubscriptionsForType(eventType): any); - if (subscriptions) { - for (let i = 0, l = subscriptions.length; i < l; i++) { - const subscription = subscriptions[i]; - - // The subscription may have been removed during this event loop. - // its listener matches the listener in method parameters - if (subscription && subscription.listener === listener) { - subscription.remove(); - } - } - } - } -} - -module.exports = EventEmitter; diff --git a/bridge/firebase/utils/emitter/EventSubscription.js b/bridge/firebase/utils/emitter/EventSubscription.js deleted file mode 100644 index 670d6231..00000000 --- a/bridge/firebase/utils/emitter/EventSubscription.js +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable */ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - */ -'use strict'; - -import type EventSubscriptionVendor from './EventSubscriptionVendor'; - -/** - * EventSubscription represents a subscription to a particular event. It can - * remove its own subscription. - */ -class EventSubscription { - - eventType: string; - key: number; - subscriber: EventSubscriptionVendor; - - /** - * @param {EventSubscriptionVendor} subscriber the subscriber that controls - * this subscription. - */ - constructor(subscriber: EventSubscriptionVendor) { - this.subscriber = subscriber; - } - - /** - * Removes this subscription from the subscriber that controls it. - */ - remove() { - this.subscriber.removeSubscription(this); - } -} - -module.exports = EventSubscription; diff --git a/bridge/firebase/utils/emitter/EventSubscriptionVendor.js b/bridge/firebase/utils/emitter/EventSubscriptionVendor.js deleted file mode 100644 index 9ca0ec49..00000000 --- a/bridge/firebase/utils/emitter/EventSubscriptionVendor.js +++ /dev/null @@ -1,100 +0,0 @@ -/* eslint-disable */ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @flow - */ -'use strict'; - -const invariant = require('fbjs/lib/invariant'); - -import type EventSubscription from './EventSubscription'; - -/** - * EventSubscriptionVendor stores a set of EventSubscriptions that are - * subscribed to a particular event type. - */ -class EventSubscriptionVendor { - - _subscriptionsForType: Object; - _currentSubscription: ?EventSubscription; - - constructor() { - this._subscriptionsForType = {}; - this._currentSubscription = null; - } - - /** - * Adds a subscription keyed by an event type. - * - * @param {string} eventType - * @param {EventSubscription} subscription - */ - addSubscription( - eventType: string, subscription: EventSubscription): EventSubscription { - invariant( - subscription.subscriber === this, - 'The subscriber of the subscription is incorrectly set.'); - if (!this._subscriptionsForType[eventType]) { - this._subscriptionsForType[eventType] = []; - } - const key = this._subscriptionsForType[eventType].length; - this._subscriptionsForType[eventType].push(subscription); - subscription.eventType = eventType; - subscription.key = key; - return subscription; - } - - /** - * Removes a bulk set of the subscriptions. - * - * @param {?string} eventType - Optional name of the event type whose - * registered supscriptions to remove, if null remove all subscriptions. - */ - removeAllSubscriptions(eventType: ?string) { - if (eventType === undefined) { - this._subscriptionsForType = {}; - } else { - delete this._subscriptionsForType[eventType]; - } - } - - /** - * Removes a specific subscription. Instead of calling this function, call - * `subscription.remove()` directly. - * - * @param {object} subscription - */ - removeSubscription(subscription: Object) { - const eventType = subscription.eventType; - const key = subscription.key; - - const subscriptionsForType = this._subscriptionsForType[eventType]; - if (subscriptionsForType) { - delete subscriptionsForType[key]; - } - } - - /** - * Returns the array of subscriptions that are currently registered for the - * given event type. - * - * Note: This array can be potentially sparse as subscriptions are deleted - * from it when they are removed. - * - * TODO: This returns a nullable array. wat? - * - * @param {string} eventType - * @returns {?array} - */ - getSubscriptionsForType(eventType: string): ?[EventSubscription] { - return this._subscriptionsForType[eventType]; - } -} - -module.exports = EventSubscriptionVendor; diff --git a/bridge/firebase/utils/events.js b/bridge/firebase/utils/events.js deleted file mode 100644 index 1d53798e..00000000 --- a/bridge/firebase/utils/events.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @flow - */ -import { NativeEventEmitter, NativeModules } from 'react-native'; -import EventEmitter from './emitter/EventEmitter'; - -import type ModuleBase from './ModuleBase'; -import type { FirebaseModuleConfig, FirebaseModuleName } from '../types'; - -const NATIVE_EMITTERS: { [string]: NativeEventEmitter } = {}; -const NATIVE_SUBSCRIPTIONS: { [string]: boolean } = {}; - -export const SharedEventEmitter = new EventEmitter(); - -export const getAppEventName = ( - module: ModuleBase, - eventName: string -): string => `${module.app.name}-${eventName}`; - -const getNativeEmitter = ( - moduleName: FirebaseModuleName, - module: ModuleBase -): NativeEventEmitter => { - const name = `${module.app.name}-${moduleName}`; - const nativeModule = NativeModules[moduleName]; - 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 = ( - moduleName: FirebaseModuleName, - module: ModuleBase, - eventName: string -): void => { - if (!NATIVE_SUBSCRIPTIONS[eventName]) { - const nativeEmitter = getNativeEmitter(moduleName, 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, - config: FirebaseModuleConfig -): void => { - const { events, moduleName } = config; - if (events && events.length) { - for (let i = 0, len = events.length; i < len; i++) { - subscribeToNativeModuleEvents(moduleName, module, events[i]); - } - } -}; diff --git a/bridge/firebase/utils/index.js b/bridge/firebase/utils/index.js deleted file mode 100644 index bbe1031e..00000000 --- a/bridge/firebase/utils/index.js +++ /dev/null @@ -1,426 +0,0 @@ -// @flow -import { Platform } from 'react-native'; - -// todo cleanup unused utilities from legacy code - -// modeled after base64 web-safe chars, but ordered by ASCII -const PUSH_CHARS = - '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'; -const AUTO_ID_CHARS = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; -const { hasOwnProperty } = Object; - -// const DEFAULT_CHUNK_SIZE = 50; - -/** - * Deep get a value from an object. - * @website https://github.com/Salakar/deeps - * @param object - * @param path - * @param joiner - * @returns {*} - */ -export function deepGet( - object: Object, - path: string, - joiner?: string = '/' -): any { - const keys = path.split(joiner); - - let i = 0; - let tmp = object; - const len = keys.length; - - while (i < len) { - const key = keys[i++]; - if (!tmp || !hasOwnProperty.call(tmp, key)) return null; - tmp = tmp[key]; - } - - return tmp; -} - -/** - * Deep check if a key exists. - * @website https://github.com/Salakar/deeps - * @param object - * @param path - * @param joiner - * @returns {*} - */ -export function deepExists( - object: Object, - path: string, - joiner?: string = '/' -): boolean { - const keys = path.split(joiner); - - let i = 0; - let tmp = object; - const len = keys.length; - - while (i < len) { - const key = keys[i++]; - if (!tmp || !hasOwnProperty.call(tmp, key)) return false; - tmp = tmp[key]; - } - - return tmp !== undefined; -} - -/** - * Deep Check if obj1 keys are contained in obj2 - * @param obj1 - * @param obj2 - * @returns {boolean} - */ -export function areObjectKeysContainedInOther( - obj1: Object, - obj2: Object -): boolean { - if (!isObject(obj1) || !isObject(obj2)) { - return false; - } - const keys1 = Object.keys(obj1); - const keys2 = Object.keys(obj2); - if (isArrayContainedInOther(keys1, keys2)) { - return keys1 - .filter(key => isObject(obj1[key])) - .reduce( - (acc, cur) => - acc && areObjectKeysContainedInOther(obj1[cur], obj2[cur]), - true - ); - } - return false; -} - -/** - * Check if arr1 is contained in arr2 - * @param arr1 - * @param arr2 - * @returns {boolean} - */ -export function isArrayContainedInOther( - arr1: Array<*>, - arr2: Array<*> -): boolean { - if (!Array.isArray(arr1) || !Array.isArray(arr2)) { - return false; - } - return arr1.reduce((acc, cur) => acc && arr2.includes(cur), true); -} - -/** - * Simple is object check. - * @param item - * @returns {boolean} - */ -export function isObject(item: mixed): boolean %checks { - return item - ? typeof item === 'object' && !Array.isArray(item) && item !== null - : false; -} - -/** - * Simple is function check - * @param item - * @returns {*|boolean} - */ -export function isFunction(item?: mixed): boolean %checks { - return item ? typeof item === 'function' : false; -} - -/** - * Simple is string check - * @param value - * @return {boolean} - */ -export function isString(value: mixed): boolean %checks { - return typeof value === 'string'; -} - -// platform checks -export const isIOS = Platform.OS === 'ios'; -export const isAndroid = Platform.OS === 'android'; - -/** - * - * @param string - * @returns {*} - */ -export function tryJSONParse(string: string | null): any { - try { - return string && JSON.parse(string); - } catch (jsonError) { - return string; - } -} - -/** - * - * @param data - * @returns {*} - */ -export function tryJSONStringify(data: mixed): string | null { - try { - return JSON.stringify(data); - } catch (jsonError) { - return null; - } -} - -/** - * No operation func - */ -export function noop(): void {} - -// /** -// * Delays chunks based on sizes per event loop. -// * @param collection -// * @param chunkSize -// * @param operation -// * @param callback -// * @private -// */ -// function _delayChunk(collection: Array<*>, -// chunkSize: number, -// operation: Function, -// callback: Function): void { -// const length = collection.length; -// const iterations = Math.ceil(length / chunkSize); -// -// // noinspection ES6ConvertVarToLetConst -// let thisIteration = 0; -// -// setImmediate(function next() { -// const start = thisIteration * chunkSize; -// const _end = start + chunkSize; -// const end = _end >= length ? length : _end; -// const result = operation(collection.slice(start, end), start, end); -// -// if (thisIteration++ > iterations) { -// callback(null, result); -// } else { -// setImmediate(next); -// } -// }); -// } -// -// /** -// * Async each with optional chunk size limit -// * @param array -// * @param chunkSize -// * @param iterator -// * @param cb -// */ -// export function each(array: Array<*>, -// chunkSize: number | Function, -// iterator: Function, -// cb?: Function): void { -// if (typeof chunkSize === 'function') { -// cb = iterator; -// iterator = chunkSize; -// chunkSize = DEFAULT_CHUNK_SIZE; -// } -// -// if (cb) { -// _delayChunk(array, chunkSize, (slice, start) => { -// for (let ii = 0, jj = slice.length; ii < jj; ii += 1) { -// iterator(slice[ii], start + ii); -// } -// }, cb); -// } -// } - -/** - * Returns a string typeof that's valid for Firebase usage - * @param value - * @return {*} - */ -export function typeOf(value: any): string { - if (value === null) return 'null'; - if (Array.isArray(value)) return 'array'; - return typeof value; -} - -// /** -// * Async map with optional chunk size limit -// * @param array -// * @param chunkSize -// * @param iterator -// * @param cb -// * @returns {*} -// */ -// export function map(array: Array<*>, -// chunkSize: number | Function, -// iterator: Function, -// cb?: Function): void { -// if (typeof chunkSize === 'function') { -// cb = iterator; -// iterator = chunkSize; -// chunkSize = DEFAULT_CHUNK_SIZE; -// } -// -// const result = []; -// _delayChunk(array, chunkSize, (slice, start) => { -// for (let ii = 0, jj = slice.length; ii < jj; ii += 1) { -// result.push(iterator(slice[ii], start + ii, array)); -// } -// return result; -// }, () => cb && cb(result)); -// } - -// /** -// * -// * @param string -// * @return {string} -// */ -// export function capitalizeFirstLetter(string: string) { -// return `${string.charAt(0).toUpperCase()}${string.slice(1)}`; -// } - -// timestamp of last push, used to prevent local collisions if you push twice in one ms. -let lastPushTime = 0; - -// we generate 72-bits of randomness which get turned into 12 characters and appended to the -// timestamp to prevent collisions with other clients. We store the last characters we -// generated because in the event of a collision, we'll use those same characters except -// "incremented" by one. -const lastRandChars = []; - -/** - * Generate a firebase id - for use with ref().push(val, cb) - e.g. -KXMr7k2tXUFQqiaZRY4' - * @param serverTimeOffset - pass in server time offset from native side - * @returns {string} - */ -export function generatePushID(serverTimeOffset?: number = 0): string { - const timeStampChars = new Array(8); - let now = new Date().getTime() + serverTimeOffset; - const duplicateTime = now === lastPushTime; - - lastPushTime = now; - - for (let i = 7; i >= 0; i -= 1) { - timeStampChars[i] = PUSH_CHARS.charAt(now % 64); - now = Math.floor(now / 64); - } - - if (now !== 0) - throw new Error('We should have converted the entire timestamp.'); - - let id = timeStampChars.join(''); - - if (!duplicateTime) { - for (let i = 0; i < 12; i += 1) { - lastRandChars[i] = Math.floor(Math.random() * 64); - } - } else { - // if the timestamp hasn't changed since last push, - // use the same random number, but increment it by 1. - let i; - for (i = 11; i >= 0 && lastRandChars[i] === 63; i -= 1) { - lastRandChars[i] = 0; - } - - lastRandChars[i] += 1; - } - - for (let i = 0; i < 12; i++) { - id += PUSH_CHARS.charAt(lastRandChars[i]); - } - - if (id.length !== 20) throw new Error('Length should be 20.'); - - return id; -} - -/** - * Converts a code and message from a native event to a JS Error - * @param code - * @param message - * @param additionalProps - * @returns {Error} - */ -export function nativeToJSError( - code: string, - message: string, - additionalProps?: Object = {} -) { - const error: Object = new Error(message); - error.code = code; - Object.assign(error, additionalProps); - // exclude this function from the stack - const _stackArray = error.stack.split('\n'); - error.stack = _stackArray.splice(1, _stackArray.length).join('\n'); - return error; -} - -/** - * - * @param object - * @return {string} - */ -export function objectToUniqueId(object: Object): string { - if (!isObject(object) || object === null) return JSON.stringify(object); - - const keys = Object.keys(object).sort(); - - let key = '{'; - for (let i = 0; i < keys.length; i++) { - if (i !== 0) key += ','; - key += JSON.stringify(keys[i]); - key += ':'; - key += objectToUniqueId(object[keys[i]]); - } - - key += '}'; - return key; -} - -/** - * Return the existing promise if no callback provided or - * exec the promise and callback if optionalCallback is valid. - * - * @param promise - * @param optionalCallback - * @return {Promise} - */ -export function promiseOrCallback( - promise: Promise<*>, - optionalCallback?: Function -): Promise<*> { - if (!isFunction(optionalCallback)) return promise; - - return promise - .then(result => { - // some of firebase internal tests & methods only check/return one arg - // see https://github.com/firebase/firebase-js-sdk/blob/master/src/utils/promise.ts#L62 - if (optionalCallback && optionalCallback.length === 1) { - optionalCallback(null); - } else if (optionalCallback) { - optionalCallback(null, result); - } - - return Promise.resolve(result); - }) - .catch(error => { - if (optionalCallback) optionalCallback(error); - return Promise.reject(error); - }); -} - -/** - * Generate a firestore auto id for use with collection/document .add() - * @return {string} - */ -export function firestoreAutoId(): string { - let autoId = ''; - - for (let i = 0; i < 20; i++) { - autoId += AUTO_ID_CHARS.charAt( - Math.floor(Math.random() * AUTO_ID_CHARS.length) - ); - } - return autoId; -} diff --git a/bridge/firebase/utils/internals.js b/bridge/firebase/utils/internals.js deleted file mode 100644 index fc656c04..00000000 --- a/bridge/firebase/utils/internals.js +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @flow - */ -import { Platform } from 'react-native'; - -const NAMESPACE_PODS = { - admob: 'Firebase/AdMob', - analytics: 'Firebase/Analytics', - auth: 'Firebase/Auth', - config: 'Firebase/RemoteConfig', - crash: 'Firebase/Crash', - database: 'Firebase/Database', - links: 'Firebase/DynamicLinks', - messaging: 'Firebase/Messaging', - perf: 'Firebase/Performance', - storage: 'Firebase/Storage', -}; - -const GRADLE_DEPS = { - admob: 'ads', -}; - -const PLAY_SERVICES_CODES = { - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 1: { - code: 'SERVICE_MISSING', - message: 'Google Play services is missing on this device.', - }, - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 2: { - code: 'SERVICE_VERSION_UPDATE_REQUIRED', - message: - 'The installed version of Google Play services on this device is out of date.', - }, - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 3: { - code: 'SERVICE_DISABLED', - message: - 'The installed version of Google Play services has been disabled on this device.', - }, - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 9: { - code: 'SERVICE_INVALID', - message: - 'The version of the Google Play services installed on this device is not authentic.', - }, - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 18: { - code: 'SERVICE_UPDATING', - message: 'Google Play services is currently being updated on this device.', - }, - // $FlowExpectedError: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380 - 19: { - code: 'SERVICE_MISSING_PERMISSION', - message: - "Google Play service doesn't have one or more required permissions.", - }, -}; - -export default { - // default options - OPTIONS: { - logLevel: 'warn', - errorOnMissingPlayServices: true, - promptOnMissingPlayServices: true, - }, - - FLAGS: { - checkedPlayServices: false, - }, - - 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.", - - /** - * @return {string} - */ - get ERROR_MISSING_CORE() { - if (Platform.OS === 'ios') { - return ( - 'RNFirebase core module was not found natively on iOS, ensure you have ' + - 'correctly included the RNFirebase pod in your projects `Podfile` and have run `pod install`.' + - '\r\n\r\n See http://invertase.link/ios for the ios setup guide.' - ); - } - - return ( - 'RNFirebase core module was not found natively on Android, ensure you have ' + - 'correctly added the RNFirebase and Firebase gradle dependencies to your `android/app/build.gradle` file.' + - '\r\n\r\n See http://invertase.link/android for the android setup guide.' - ); - }, - - ERROR_INIT_OBJECT: - 'Firebase.initializeApp(options <-- requires a valid configuration object.', - ERROR_INIT_STRING_NAME: - 'Firebase.initializeApp(options, name <-- requires a valid string value.', - - /** - * @return {string} - */ - ERROR_INIT_SERVICE_URL_UNSUPPORTED(namespace: string) { - return `${namespace} does not support URL as a param, please pass in an app.`; - }, - - /** - * @return {string} - */ - ERROR_MISSING_CB(method: string) { - return `Missing required callback for method ${method}().`; - }, - - /** - * @return {string} - */ - ERROR_MISSING_ARG(type: string, method: string) { - return `Missing required argument of type '${type}' for method '${method}()'.`; - }, - - /** - * @return {string} - */ - ERROR_MISSING_ARG_NAMED(name: string, type: string, method: string) { - return `Missing required argument '${name}' of type '${type}' for method '${method}()'.`; - }, - - /** - * @return {string} - */ - ERROR_ARG_INVALID_VALUE(name: string, expected: string, got: string) { - return `Invalid value for argument '${name}' expected value '${expected}' but got '${got}'.`; - }, - - /** - * @return {string} - */ - ERROR_PROTECTED_PROP(name: string) { - return `Property '${name}' is protected and can not be overridden by extendApp.`; - }, - - /** - * @return {string} - * @param namespace - * @param nativeModule - */ - ERROR_MISSING_MODULE(namespace: string, nativeModule: string) { - const snippet = `firebase.${namespace}()`; - if (Platform.OS === 'ios') { - return ( - `You attempted to use a firebase module that's not installed natively on your iOS project by calling ${snippet}.` + - '\r\n\r\nEnsure you have the required Firebase iOS SDK pod for this module included in your Podfile, in this instance ' + - `confirm you've added "pod '${ - NAMESPACE_PODS[namespace] - }'" to your Podfile` + - '\r\n\r\nSee http://invertase.link/ios for full setup instructions.' - ); - } - - const fbSDKDep = `'com.google.firebase:firebase-${GRADLE_DEPS[ - namespace - ] || namespace}'`; - const rnFirebasePackage = `'io.invertase.firebase.${namespace}.${nativeModule}Package'`; - const newInstance = `'new ${nativeModule}Package()'`; - return ( - `You attempted to use a firebase module that's not installed on your Android project by calling ${snippet}.` + - `\r\n\r\nEnsure you have:\r\n\r\n1) Installed the required Firebase Android SDK dependency ${fbSDKDep} in your 'android/app/build.gradle' ` + - `file.\r\n\r\n2) Imported the ${rnFirebasePackage} module in your 'MainApplication.java' file.\r\n\r\n3) Added the ` + - `${newInstance} line inside of the RN 'getPackages()' method list.` + - '\r\n\r\nSee http://invertase.link/android for full setup instructions.' - ); - }, - - /** - * @return {string} - */ - ERROR_APP_NOT_INIT(appName: string) { - return `The [${appName}] firebase app has not been initialized!`; - }, - - /** - * @param optName - * @return {string} - * @constructor - */ - ERROR_MISSING_OPT(optName: string) { - return `Failed to initialize app. FirebaseOptions missing or invalid '${optName}' property.`; - }, - - /** - * @return {string} - */ - ERROR_NOT_APP(namespace: string) { - return `Invalid App instance passed to firebase.${namespace}(app <--).`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_CLASS_METHOD(className: string, method: string) { - return `${className}.${method}() is unsupported by the native Firebase SDKs.`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_CLASS_PROPERTY(className: string, property: string) { - return `${className}.${property} is unsupported by the native Firebase SDKs.`; - }, - - /** - * @return {string} - */ - ERROR_UNSUPPORTED_MODULE_METHOD(namespace: string, method: string) { - return `firebase.${namespace}().${method}() is unsupported by the native Firebase SDKs.`; - }, - - /** - * @return {string} - */ - ERROR_PLAY_SERVICES(statusCode: number) { - const knownError = PLAY_SERVICES_CODES[statusCode]; - let start = - 'Google Play Services is required to run firebase services on android but a valid installation was not found on this device.'; - - if (statusCode === 2) { - start = - 'Google Play Services is out of date and may cause some firebase services like authentication to hang when used. It is recommended that you update it.'; - } - - // eslint-disable-next-line prefer-template - return ( - `${`${start}\r\n\r\n-------------------------\r\n`}${ - knownError - ? `${knownError.code}: ${knownError.message} (code ${statusCode})` - : `A specific play store availability reason reason was not available (unknown code: ${statusCode})` - }\r\n-------------------------` + - `\r\n\r\n` + - `For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:` + - `\r\n\r\nhttp://invertase.link/play-services` - ); - }, - }, -}; diff --git a/bridge/firebase/utils/log.js b/bridge/firebase/utils/log.js deleted file mode 100644 index c94da3dc..00000000 --- a/bridge/firebase/utils/log.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * @flow - */ - -import INTERNALS from './internals'; -import type ModuleBase from './ModuleBase'; - -const NATIVE_LOGGERS: { [string]: Object } = {}; - -const getModuleKey = (module: ModuleBase): string => - `${module.app.name}:${module.namespace}`; - -export const getLogger = (module: ModuleBase) => { - const key = getModuleKey(module); - return NATIVE_LOGGERS[key]; -}; - -export const LEVELS = { - debug: 0, - info: 1, - warn: 2, - error: 3, -}; - -export const initialiseLogger = (module: ModuleBase, logNamespace: string) => { - const key = getModuleKey(module); - if (!NATIVE_LOGGERS[key]) { - const prefix = `🔥 ${logNamespace.toUpperCase()}`; - NATIVE_LOGGERS[key] = { - debug(...args) { - if (__DEV__ && LEVELS.debug >= LEVELS[INTERNALS.OPTIONS.logLevel]) - console.log(...[prefix, ...args]); - }, - info(...args) { - if (__DEV__ && LEVELS.info >= LEVELS[INTERNALS.OPTIONS.logLevel]) - console.log(...[prefix, ...args]); - }, - warn(...args) { - if (__DEV__ && LEVELS.warn >= LEVELS[INTERNALS.OPTIONS.logLevel]) - console.warn(...args); - }, - error(...args) { - console.error(...args); - }, - }; - } -}; diff --git a/bridge/firebase/utils/native.js b/bridge/firebase/utils/native.js deleted file mode 100644 index 1b8ddd66..00000000 --- a/bridge/firebase/utils/native.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * @flow - */ -import { NativeModules } from 'react-native'; -import { initialiseNativeModuleEventEmitter } from './events'; -import INTERNALS from './internals'; - -import type ModuleBase from './ModuleBase'; -import type { FirebaseModuleConfig } from '../types'; - -const NATIVE_MODULES: { [string]: Object } = {}; - -/** - * Prepends all arguments in prependArgs to all native method calls - * @param NativeModule - * @param argToPrepend - */ -const nativeWithArgs = ( - NativeModule: Object, - argToPrepend: Array -): 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) => - NativeModule[method](...[...argToPrepend, ...args]); - } - - return native; -}; - -const nativeModuleKey = (module: ModuleBase): string => - `${module._serviceUrl || module.app.name}:${module.namespace}`; - -export const getNativeModule = (module: ModuleBase): Object => - NATIVE_MODULES[nativeModuleKey(module)]; - -export const initialiseNativeModule = ( - module: ModuleBase, - config: FirebaseModuleConfig, - serviceUrl: ?string -): Object => { - const { moduleName, multiApp, hasShards, namespace } = config; - const nativeModule = NativeModules[moduleName]; - const key = nativeModuleKey(module); - - if (!nativeModule && namespace !== 'utils') { - throw new Error( - INTERNALS.STRINGS.ERROR_MISSING_MODULE(namespace, moduleName) - ); - } - - // used by the modules that extend ModuleBase - // to access their native module counterpart - const argToPrepend = []; - if (multiApp) { - argToPrepend.push(module.app.name); - } - if (hasShards) { - argToPrepend.push(serviceUrl); - } - - if (argToPrepend.length) { - NATIVE_MODULES[key] = nativeWithArgs(nativeModule, argToPrepend); - } else { - NATIVE_MODULES[key] = nativeModule; - } - - initialiseNativeModuleEventEmitter(module, config); - - return NATIVE_MODULES[key]; -}; diff --git a/bridge/package-lock.json b/bridge/package-lock.json index 87de9c03..cfca510d 100644 --- a/bridge/package-lock.json +++ b/bridge/package-lock.json @@ -884,6 +884,19 @@ "integrity": "sha1-SuKgTqYSpuc2UfP95SwXiZEwS+o=", "dev": true }, + "babel-plugin-module-resolver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz", + "integrity": "sha512-1Q77Al4ydp6nYApJ7sQ2fmgz30WuQgJZegIYuyOdbdpxenB/bSezQ3hDPsumIXGlUS4vUIv+EwFjzzXZNWtARw==", + "dev": true, + "requires": { + "find-babel-config": "1.1.0", + "glob": "7.1.2", + "pkg-up": "2.0.0", + "reselect": "3.0.1", + "resolve": "1.6.0" + } + }, "babel-plugin-react-transform": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-3.0.0.tgz", @@ -3386,6 +3399,16 @@ } } }, + "find-babel-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz", + "integrity": "sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U=", + "dev": true, + "requires": { + "json5": "0.5.1", + "path-exists": "3.0.0" + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -5075,7 +5098,7 @@ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { "node-fetch": "1.6.3", - "whatwg-fetch": "2.0.3" + "whatwg-fetch": "2.0.4" } }, "isstream": { @@ -9352,6 +9375,15 @@ } } }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "2.1.0" + } + }, "plist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/plist/-/plist-1.2.0.tgz", @@ -9995,6 +10027,12 @@ "resolve-from": "1.0.1" } }, + "reselect": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", + "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=", + "dev": true + }, "resolve": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", @@ -11950,9 +11988,9 @@ } }, "whatwg-fetch": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", - "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, "which": { "version": "1.3.0", diff --git a/bridge/package.json b/bridge/package.json index ea2bb592..88529531 100755 --- a/bridge/package.json +++ b/bridge/package.json @@ -14,14 +14,17 @@ "test-android-cover": "nyc detox test --configuration android.emu.debug", "test-android-cover-reuse": "nyc detox test --configuration android.emu.debug --reuse", "test-ios": "detox test --configuration ios.sim.debug", - "test-ios-cover": "nyc detox test --configuration ios.sim.debug", - "test-ios-cover-reuse": "nyc detox test --configuration ios.sim.debug --reuse", + "test-ios-cover": "nyc detox test --configuration ios.sim.debug --loglevel warn", + "test-ios-cover-reuse": "nyc detox test --configuration ios.sim.debug --reuse --loglevel warn", "ios:pod:install": "cd ios && rm -rf ReactNativeFirebaseDemo.xcworkspace && pod install && cd .." }, "dependencies": { "bridge": "^0.2.1", "detox": "^7.2.0", + "escape-string-regexp": "^1.0.5", + "fbjs": "^0.8.16", "mocha": "^4.0.1", + "prop-types": "^15.6.1", "react": "^16.2.0", "react-native": "^0.52.3", "should": "^13.2.1", @@ -29,13 +32,14 @@ "sinon": "^4.4.8" }, "devDependencies": { - "babel-preset-es2015-mod": "^6.6.0", - "babel-preset-es3": "^1.0.1", "babel-cli": "^6.24.0", "babel-eslint": "^7.1.1", "babel-jest": "19.0.0", "babel-plugin-flow-react-proptypes": "^0.21.0", "babel-plugin-istanbul": "^4.1.5", + "babel-plugin-module-resolver": "^3.1.1", + "babel-preset-es2015-mod": "^6.6.0", + "babel-preset-es3": "^1.0.1", "babel-preset-react-native": "1.9.1", "eslint": "^3.16.1", "eslint-config-airbnb": "^14.1.0", @@ -51,7 +55,8 @@ "statements": 95, "functions": 95, "branches": 95, - "include": ["firebase"], + "include": ["lib/*"], + "exclude": ["node_modules"], "sourceMap": false, "instrument": false, "reporter": ["lcov", "text-summary"] @@ -71,7 +76,8 @@ "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/testing.app", "build": "xcodebuild -workspace ios/testing.xcworkspace -scheme testing -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build", "type": "ios.simulator", - "name": "iPhone 7 Plus" + "name": "iPhone 7 Plus", + "logLevel": "error" }, "android.emu.debug": { "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk", diff --git a/bridge/rn-cli.config.js b/bridge/rn-cli.config.js index bc94d8d4..47bd7ccb 100755 --- a/bridge/rn-cli.config.js +++ b/bridge/rn-cli.config.js @@ -1,3 +1,5 @@ +const { resolve } = require('path'); + let metroBundler; try { metroBundler = require('metro'); @@ -5,8 +7,22 @@ try { metroBundler = require('metro-bundler'); } +const blacklist = metroBundler.createBlacklist; + module.exports = { - getBlacklistRE: function() { - return metroBundler.createBlacklist([/test\/.*/]); - } -}; \ No newline at end of file + getProjectRoots() { + return [__dirname, resolve(__dirname, '..')]; + }, + getProvidesModuleNodeModules() { + return ['react-native', 'react', 'prop-types', 'fbjs']; + }, + getBlacklistRE() { + return blacklist([ + new RegExp(`^${escape(resolve(__dirname, '..', 'node_modules'))}\\/.*$`), + new RegExp(`^${escape(resolve(__dirname, '..', 'tests'))}\\/.*$`), + new RegExp( + `^${escape(resolve(__dirname, '..', 'tests', 'node_modules'))}\\/.*$` + ), + ]); + }, +};