[bridge] import RNF from project directory directly via module alias + metro config
This commit is contained in:
parent
ed2efcdd48
commit
2122554549
|
@ -9,8 +9,16 @@
|
||||||
"useInlineSourceMaps": true,
|
"useInlineSourceMaps": true,
|
||||||
"instrument": true,
|
"instrument": true,
|
||||||
"include": [
|
"include": [
|
||||||
"firebase"
|
"lib/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
]
|
]
|
||||||
|
}],
|
||||||
|
["module-resolver", {
|
||||||
|
"alias": {
|
||||||
|
"react-native-firebase": ".."
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import React, { Component } from 'react';
|
||||||
import { AppRegistry, Text, View } from 'react-native';
|
import { AppRegistry, Text, View } from 'react-native';
|
||||||
|
|
||||||
import bridge from 'bridge/platform/react-native';
|
import bridge from 'bridge/platform/react-native';
|
||||||
import firebase from './firebase';
|
import firebase from 'react-native-firebase';
|
||||||
|
|
||||||
require('sinon');
|
require('sinon');
|
||||||
require('should-sinon');
|
require('should-sinon');
|
||||||
|
|
|
@ -1,9 +1,4 @@
|
||||||
describe('.auth()', () => {
|
describe('.auth()', () => {
|
||||||
beforeEach(async () => {
|
|
||||||
await device.reloadReactNative();
|
|
||||||
// bridge.root.setState({ message: this.currentTest.title });
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.signInAnonymously()', () => {
|
describe('.signInAnonymously()', () => {
|
||||||
it('it should sign in anonymously', () => {
|
it('it should sign in anonymously', () => {
|
||||||
const successCb = currentUser => {
|
const successCb = currentUser => {
|
||||||
|
@ -13,9 +8,7 @@ describe('.auth()', () => {
|
||||||
should.equal(currentUser.toJSON().email, null);
|
should.equal(currentUser.toJSON().email, null);
|
||||||
currentUser.isAnonymous.should.equal(true);
|
currentUser.isAnonymous.should.equal(true);
|
||||||
currentUser.providerId.should.equal('firebase');
|
currentUser.providerId.should.equal('firebase');
|
||||||
|
|
||||||
currentUser.should.equal(firebase.auth().currentUser);
|
currentUser.should.equal(firebase.auth().currentUser);
|
||||||
|
|
||||||
return firebase.auth().signOut();
|
return firebase.auth().signOut();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ const should = require('should');
|
||||||
|
|
||||||
describe('bridge', () => {
|
describe('bridge', () => {
|
||||||
beforeEach(async function beforeEach() {
|
beforeEach(async function beforeEach() {
|
||||||
await device.reloadReactNative();
|
// await device.reloadReactNative();
|
||||||
bridge.root.setState({ message: this.currentTest.title });
|
bridge.root.setState({ message: this.currentTest.title });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--recursive
|
--recursive
|
||||||
--timeout 120000
|
--timeout 120000
|
||||||
--slow 2200
|
--slow 750
|
||||||
--bail
|
--bail
|
||||||
--exit
|
--exit
|
||||||
--require bridge/platform/node
|
--require bridge/platform/node
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Object> {
|
|
||||||
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();
|
|
|
@ -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
|
|
||||||
};
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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';
|
|
|
@ -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;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -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 (
|
|
||||||
<this.nativeView
|
|
||||||
{...this.props}
|
|
||||||
style={[this.props.style, { ...this.state }]}
|
|
||||||
onBannerEvent={this.onBannerEvent}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AdMobComponent;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import AdMobComponent from './AdMobComponent';
|
|
||||||
|
|
||||||
function Banner({ ...props }) {
|
|
||||||
return <AdMobComponent {...props} class="RNFirebaseAdMobBanner" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
Banner.propTypes = AdMobComponent.propTypes;
|
|
||||||
|
|
||||||
Banner.defaultProps = {
|
|
||||||
size: 'SMART_BANNER',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Banner;
|
|
|
@ -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',
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import AdMobComponent from './AdMobComponent';
|
|
||||||
|
|
||||||
function NativeExpress({ ...props }) {
|
|
||||||
return <AdMobComponent {...props} class="RNFirebaseAdMobNativeExpress" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeExpress.propTypes = AdMobComponent.propTypes;
|
|
||||||
|
|
||||||
NativeExpress.defaultProps = {
|
|
||||||
size: 'SMART_BANNER',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NativeExpress;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
|
@ -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 = {};
|
|
|
@ -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<User> {
|
|
||||||
return getNativeModule(this._auth)
|
|
||||||
._confirmVerificationCode(verificationCode)
|
|
||||||
.then(user => this._auth._setUser(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
get verificationId(): string | null {
|
|
||||||
return this._verificationId;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<UserInfo> {
|
|
||||||
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<void> {
|
|
||||||
return getNativeModule(this._auth)
|
|
||||||
.delete()
|
|
||||||
.then(() => {
|
|
||||||
this._auth._setUser();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the token of current user
|
|
||||||
* @return {Promise}
|
|
||||||
*/
|
|
||||||
getIdToken(forceRefresh: boolean = false): Promise<string> {
|
|
||||||
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<Object> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<void> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<void> {
|
|
||||||
return getNativeModule(this._auth)
|
|
||||||
.reload()
|
|
||||||
.then(user => {
|
|
||||||
this._auth._setUser(user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send verification email to current user.
|
|
||||||
*/
|
|
||||||
sendEmailVerification(
|
|
||||||
actionCodeSettings?: ActionCodeSettings
|
|
||||||
): Promise<void> {
|
|
||||||
return getNativeModule(this._auth)
|
|
||||||
.sendEmailVerification(actionCodeSettings)
|
|
||||||
.then(user => {
|
|
||||||
this._auth._setUser(user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON(): Object {
|
|
||||||
return Object.assign({}, this._user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param providerId
|
|
||||||
* @return {Promise.<TResult>|*}
|
|
||||||
*/
|
|
||||||
unlink(providerId: string): Promise<User> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<User> {
|
|
||||||
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<UserCredential> {
|
|
||||||
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<ConfirmationResult> {
|
|
||||||
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<void> {
|
|
||||||
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.<Null>}
|
|
||||||
*/
|
|
||||||
confirmPasswordReset(code: string, newPassword: string): Promise<void> {
|
|
||||||
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.<Null>}
|
|
||||||
*/
|
|
||||||
applyActionCode(code: string): Promise<void> {
|
|
||||||
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.<any>|Promise<ActionCodeInfo>}
|
|
||||||
*/
|
|
||||||
checkActionCode(code: string): Promise<ActionCodeInfo> {
|
|
||||||
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<string[]> {
|
|
||||||
return getNativeModule(this).fetchProvidersForEmail(email);
|
|
||||||
}
|
|
||||||
|
|
||||||
verifyPasswordResetCode(code: string): Promise<string> {
|
|
||||||
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',
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -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<User> {
|
|
||||||
return getNativeModule(this._auth)
|
|
||||||
._confirmVerificationCode(verificationCode)
|
|
||||||
.then(user => this._auth._setUser(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
get verificationId(): string | null {
|
|
||||||
return this._verificationId;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
|};
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.<String>}:
|
|
||||||
*/
|
|
||||||
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.<Bool>}
|
|
||||||
* 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.<Object>}, will always resolve
|
|
||||||
* Object looks like
|
|
||||||
* {
|
|
||||||
* "stringValue" : stringValue,
|
|
||||||
* "numberValue" : numberValue,
|
|
||||||
* "dataValue" : dataValue,
|
|
||||||
* "boolValue" : boolValue,
|
|
||||||
* "source" : OneOf<String>(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.<Object>}, 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<String>(remoteConfigSourceRemote|remoteConfigSourceDefault|remoteConfigSourceStatic)
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
getValues(keys: Array<string>) {
|
|
||||||
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.<Array<String>>}
|
|
||||||
*/
|
|
||||||
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 = {};
|
|
|
@ -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<App> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<App> {
|
|
||||||
return APPS.apps();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current SDK version.
|
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
get SDK_VERSION(): string {
|
|
||||||
return VERSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new Firebase();
|
|
|
@ -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.<boolean>}
|
|
||||||
*/
|
|
||||||
isCrashCollectionEnabled(): Promise<boolean> {
|
|
||||||
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 = {};
|
|
|
@ -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<string>;
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
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<void> {
|
|
||||||
return getNativeModule(this._database).onDisconnectUpdate(
|
|
||||||
this.path,
|
|
||||||
values
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#remove
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
remove(): Promise<void> {
|
|
||||||
return getNativeModule(this._database).onDisconnectRemove(this.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect#cancel
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
cancel(): Promise<void> {
|
|
||||||
return getNativeModule(this._database).onDisconnectCancel(this.path);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<DatabaseModifier>;
|
|
||||||
|
|
||||||
constructor(ref: Reference, existingModifiers?: Array<DatabaseModifier>) {
|
|
||||||
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<DatabaseModifier> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<DatabaseModifier>
|
|
||||||
) {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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.<any>}
|
|
||||||
*/
|
|
||||||
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<void> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -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];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 = {};
|
|
|
@ -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<DocumentReference> {
|
|
||||||
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<QuerySnapshot> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
return getNativeModule(this._firestore).documentDelete(this.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
get(): Promise<DocumentSnapshot> {
|
|
||||||
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<void> {
|
|
||||||
const nativeData = buildNativeMap(data);
|
|
||||||
return getNativeModule(this._firestore).documentSet(
|
|
||||||
this.path,
|
|
||||||
nativeData,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(...args: any[]): Promise<void> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__');
|
|
|
@ -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();
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<QuerySnapshot> {
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Command>;
|
|
||||||
|
|
||||||
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<DocumentSnapshot>
|
|
||||||
*/
|
|
||||||
get(documentRef: DocumentReference): Promise<DocumentSnapshot> {
|
|
||||||
// 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<any>): 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<any>,
|
|
||||||
};
|
|
||||||
|
|
||||||
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<any>
|
|
||||||
): Promise<any> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<any>}
|
|
||||||
*/
|
|
||||||
runTransaction(
|
|
||||||
updateFunction: (transaction: Transaction) => Promise<any>
|
|
||||||
): Promise<any> {
|
|
||||||
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<void> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -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,
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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<void> {
|
|
||||||
return getNativeModule(this).delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
get(): Promise<string> {
|
|
||||||
return getNativeModule(this).get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const statics = {};
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.<Object>}
|
|
||||||
*/
|
|
||||||
getInitialInvitation(): Promise<string> {
|
|
||||||
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<string[]> {
|
|
||||||
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,
|
|
||||||
};
|
|
|
@ -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,
|
|
||||||
|};
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.<String>}
|
|
||||||
*/
|
|
||||||
createDynamicLink(link: DynamicLink): Promise<string> {
|
|
||||||
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.<String>}
|
|
||||||
*/
|
|
||||||
createShortDynamicLink(
|
|
||||||
link: DynamicLink,
|
|
||||||
type?: 'SHORT' | 'UNGUESSABLE'
|
|
||||||
): Promise<String> {
|
|
||||||
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.<String>}
|
|
||||||
*/
|
|
||||||
getInitialLink(): Promise<string> {
|
|
||||||
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 = {};
|
|
|
@ -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,
|
|
||||||
|};
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<string> {
|
|
||||||
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<void> {
|
|
||||||
return getNativeModule(this).requestPermission();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NON WEB-SDK METHODS
|
|
||||||
*/
|
|
||||||
hasPermission(): Promise<boolean> {
|
|
||||||
return getNativeModule(this).hasPermission();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(remoteMessage: RemoteMessage): Promise<void> {
|
|
||||||
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,
|
|
||||||
};
|
|
|
@ -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,
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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<void> {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<void> {
|
|
||||||
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<number> {
|
|
||||||
return getNativeModule(this).getBadge();
|
|
||||||
}
|
|
||||||
|
|
||||||
getInitialNotification(): Promise<NotificationOpen> {
|
|
||||||
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.<Array>}
|
|
||||||
*/
|
|
||||||
getScheduledNotifications(): Promise<Notification[]> {
|
|
||||||
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<void> {
|
|
||||||
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,
|
|
||||||
};
|
|
|
@ -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<typeof BadgeIconType>;
|
|
||||||
export type CategoryType = $Values<typeof Category>;
|
|
||||||
export type DefaultsType = $Values<typeof Defaults>;
|
|
||||||
export type GroupAlertType = $Values<typeof GroupAlert>;
|
|
||||||
export type ImportanceType = $Values<typeof Importance>;
|
|
||||||
export type PriorityType = $Values<typeof Priority>;
|
|
||||||
export type SemanticActionType = $Values<typeof SemanticAction>;
|
|
||||||
export type VisibilityType = $Values<typeof Visibility>;
|
|
||||||
|
|
||||||
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 },
|
|
||||||
|};
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 = {};
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
};
|
|
|
@ -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.<T>|*}
|
|
||||||
*/
|
|
||||||
delete(): Promise<void> {
|
|
||||||
return getNativeModule(this._storage).delete(this.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL
|
|
||||||
* @returns {Promise.<T>|*}
|
|
||||||
*/
|
|
||||||
getDownloadURL(): Promise<string> {
|
|
||||||
return getNativeModule(this._storage).getDownloadURL(this.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata
|
|
||||||
* @returns {Promise.<T>|*}
|
|
||||||
*/
|
|
||||||
getMetadata(): Promise<Object> {
|
|
||||||
return getNativeModule(this._storage).getMetadata(this.path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
|
|
||||||
* @param metadata
|
|
||||||
* @returns {Promise.<T>|*}
|
|
||||||
*/
|
|
||||||
updateMetadata(metadata: Object = {}): Promise<Object> {
|
|
||||||
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<Object> {
|
|
||||||
return new StorageTask(
|
|
||||||
DOWNLOAD_TASK,
|
|
||||||
getNativeModule(this._storage).downloadFile(this.path, filePath),
|
|
||||||
this
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Alias to putFile
|
|
||||||
* @returns {StorageReference.putFile}
|
|
||||||
*/
|
|
||||||
get put(): (Object, Object) => Promise<Object> {
|
|
||||||
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<Object> {
|
|
||||||
const _filePath = filePath.replace('file://', '');
|
|
||||||
return new StorageTask(
|
|
||||||
UPLOAD_TASK,
|
|
||||||
getNativeModule(this._storage).putFile(this.path, _filePath, metadata),
|
|
||||||
this
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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.<T>}
|
|
||||||
* @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'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 = {};
|
|
|
@ -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<ModuleBase>;
|
|
||||||
|
|
||||||
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: FirebaseModule, S: FirebaseStatics> = {
|
|
||||||
(): M,
|
|
||||||
nativeModuleExists: boolean,
|
|
||||||
} & S;
|
|
||||||
|
|
||||||
export type FirebaseStatics = $Subtype<Object>;
|
|
||||||
|
|
||||||
/* 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;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue