@taraai/read-write
Version:
Synchronous NoSQL/Firestore for React
332 lines (275 loc) • 8.59 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.authIsReady = authIsReady;
exports.createAuthIsReady = createAuthIsReady;
exports.getLoginMethodAndParams = getLoginMethodAndParams;
exports.getReauthenticateMethodAndParams = getReauthenticateMethodAndParams;
exports.setupPresence = setupPresence;
exports.updateProfileOnFirestore = updateProfileOnFirestore;
exports.updateProfileOnRTDB = updateProfileOnRTDB;
var _capitalize2 = _interopRequireDefault(require("lodash/capitalize"));
var _constants = require("../constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createAuthProvider(firebase, providerName, scopes) {
const lowerCaseProviderName = providerName.toLowerCase();
if (lowerCaseProviderName === 'microsoft.com' || lowerCaseProviderName === 'apple.com' || lowerCaseProviderName === 'yahoo.com') {
const provider = new firebase.auth.OAuthProvider(providerName);
return provider;
}
const capitalProviderName = `${(0, _capitalize2.default)(providerName)}AuthProvider`;
if (!firebase.auth[capitalProviderName]) {
throw new Error(`${providerName} is not a valid auth provider for your firebase instance. If using react-native, use a RN specific auth library.`);
}
const provider = new firebase.auth[capitalProviderName]();
const {
customAuthParameters
} = firebase._.config;
if (customAuthParameters && customAuthParameters[providerName]) {
provider.setCustomParameters(customAuthParameters[providerName]);
}
if (lowerCaseProviderName === 'twitter' || typeof provider.addScope !== 'function') {
return provider;
}
provider.addScope('email');
if (scopes) {
if (Array.isArray(scopes)) {
scopes.forEach(scope => {
provider.addScope(scope);
});
}
if (typeof scopes === 'string' || scopes instanceof String) {
provider.addScope(scopes);
}
}
return provider;
}
function getLoginMethodAndParams(firebase, credentials) {
const {
email,
password,
provider,
type,
token,
scopes,
phoneNumber,
applicationVerifier,
credential,
emailLink
} = credentials;
if (credential) {
const credentialAuth = firebase.auth().signInAndRetrieveDataWithCredential;
if (credentialAuth) {
return {
method: 'signInAndRetrieveDataWithCredential',
params: [credential]
};
}
return {
method: 'signInWithCredential',
params: [credential]
};
}
if (provider) {
if (_constants.supportedAuthProviders.indexOf(provider.toLowerCase()) === -1) {
throw new Error(`${provider} is not a valid Auth Provider`);
}
if (token) {
throw new Error('provider with token no longer supported, use credential parameter instead');
}
const authProvider = createAuthProvider(firebase, provider, scopes);
if (type === 'popup') {
return {
method: 'signInWithPopup',
params: [authProvider]
};
}
return {
method: 'signInWithRedirect',
params: [authProvider]
};
}
if (token) {
const tokenAuth = firebase.auth().signInAndRetrieveDataWithCustomToken;
if (tokenAuth) {
return {
method: 'signInAndRetrieveDataWithCustomToken',
params: [token]
};
}
return {
method: 'signInWithCustomToken',
params: [token]
};
}
if (phoneNumber) {
if (!applicationVerifier) {
throw new Error('Application verifier is required for phone authentication');
}
return {
method: 'signInWithPhoneNumber',
params: [phoneNumber, applicationVerifier]
};
}
if (emailLink && email) {
return {
method: 'signInWithEmailLink',
params: [email, emailLink]
};
}
if (!firebase.auth().signInWithEmailAndPassword) {
return {
method: 'signInAndRetrieveDataWithEmailAndPassword',
params: [email, password]
};
}
return {
method: 'signInWithEmailAndPassword',
params: [email, password]
};
}
function getReauthenticateMethodAndParams(firebase, credentials) {
const {
provider,
type,
scopes,
phoneNumber,
applicationVerifier,
credential
} = credentials;
if (credential) {
const credentialAuth = firebase.auth().reauthenticateAndRetrieveDataWithCredential;
if (credentialAuth) {
return {
method: 'reauthenticateAndRetrieveDataWithCredential',
params: [credential]
};
}
return {
method: 'reauthenticateWithCredential',
params: [credential]
};
}
if (provider) {
if (_constants.supportedAuthProviders.indexOf(provider.toLowerCase()) === -1) {
throw new Error(`${provider} is not a valid Auth Provider`);
}
const authProvider = createAuthProvider(firebase, provider, scopes);
if (type === 'popup') {
return {
method: 'reauthenticateWithPopup',
params: [authProvider]
};
}
return {
method: 'reauthenticateWithRedirect',
params: [authProvider]
};
}
if (!applicationVerifier) {
throw new Error('Application verifier is required for phone authentication');
}
return {
method: 'reauthenticateWithPhoneNumber',
params: [phoneNumber, applicationVerifier]
};
}
function isAuthReady(store, stateName) {
const state = store.getState();
const firebaseState = stateName ? state[stateName] : state;
const firebaseAuthState = firebaseState && firebaseState.auth;
if (!firebaseAuthState) {
throw new Error(`The Firebase auth state could not be found in the store under the attribute '${stateName ? `${stateName}.` : ''}auth'. Make sure your react-redux-firebase reducer is correctly set in the store`);
}
return firebaseState.auth.isLoaded;
}
function authIsReady(store) {
let stateName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'firebase';
return new Promise(resolve => {
if (isAuthReady(store, stateName)) {
resolve();
} else {
const unsubscribe = store.subscribe(() => {
if (isAuthReady(store, stateName)) {
unsubscribe();
resolve();
}
});
}
});
}
function createAuthIsReady(store, config) {
return typeof config.authIsReady === 'function' ? config.authIsReady(store, config) : authIsReady(store, config.firebaseStateName);
}
function updateProfileOnRTDB(firebase, profileUpdate) {
const {
_: {
config,
authUid
}
} = firebase;
const profileRef = firebase.database().ref(`${config.userProfile}/${authUid}`);
return profileRef.update(profileUpdate).then(() => profileRef.once('value'));
}
function updateProfileOnFirestore(firebase, profileUpdate) {
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
const {
useSet = true,
merge = true
} = options;
const {
firestore,
_: {
config,
authUid
}
} = firebase;
const profileRef = firestore().doc(`${config.userProfile}/${authUid}`);
const profileUpdatePromise = useSet ? profileRef.set(profileUpdate, {
merge
}) : profileRef.update(profileUpdate);
return profileUpdatePromise.then(() => profileRef.get());
}
function setupPresence(dispatch, firebase) {
if (!firebase.database || !firebase.database.ServerValue) {
return;
}
const ref = firebase.database().ref();
const {
config: {
presence,
sessions
},
authUid
} = firebase._;
const amOnline = ref.child('.info/connected');
const onlineRef = ref.child(typeof presence === 'function' ? presence(firebase.auth().currentUser, firebase) : presence).child(authUid);
let sessionsRef = typeof sessions === 'function' ? sessions(firebase.auth().currentUser, firebase) : sessions;
if (sessionsRef) {
sessionsRef = ref.child(sessions);
}
amOnline.on('value', snapShot => {
if (!snapShot.val()) return;
if (sessionsRef) {
dispatch({
type: _constants.actionTypes.SESSION_START,
payload: authUid
});
const session = sessionsRef.push({
startedAt: firebase.database.ServerValue.TIMESTAMP,
user: authUid
});
if (typeof session.setPriority === 'function') {
session.setPriority(authUid);
}
session.child('endedAt').onDisconnect().set(firebase.database.ServerValue.TIMESTAMP, () => {
dispatch({
type: _constants.actionTypes.SESSION_END
});
});
}
onlineRef.set(true);
onlineRef.onDisconnect().remove();
});
}