@react-native-firebase/app
Version:
A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Functions, Messaging (FCM), Remote Config, Sto
385 lines (345 loc) • 11.6 kB
JavaScript
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { Platform } from 'react-native';
import Base64 from './Base64';
import { isString } from './validate';
export * from './id';
export * from './path';
export * from './promise';
export * from './validate';
export { default as Base64 } from './Base64';
export { default as ReferenceBase } from './ReferenceBase';
export function getDataUrlParts(dataUrlString) {
const isBase64 = dataUrlString.includes(';base64');
let [mediaType, base64String] = dataUrlString.split(',');
if (!mediaType || !base64String) {
return { base64String: undefined, mediaType: undefined };
}
mediaType = mediaType.replace('data:', '').replace(';base64', '');
if (base64String && base64String.includes('%')) {
base64String = decodeURIComponent(base64String);
}
if (!isBase64) {
base64String = Base64.btoa(base64String);
}
return { base64String, mediaType };
}
export function once(fn, context) {
let onceResult;
let ranOnce = false;
return function onceInner(...args) {
if (!ranOnce) {
ranOnce = true;
onceResult = fn.apply(context || this, args);
}
return onceResult;
};
}
export function isError(value) {
if (Object.prototype.toString.call(value) === '[object Error]') {
return true;
}
return value instanceof Error;
}
export function hasOwnProperty(target, property) {
return Object.hasOwnProperty.call(target, property);
}
/**
* Remove a trailing forward slash from a string if it exists
*
* @param string
* @returns {*}
*/
export function stripTrailingSlash(string) {
if (!isString(string)) {
return string;
}
return string.endsWith('/') ? string.slice(0, -1) : string;
}
export const isIOS = Platform.OS === 'ios';
export const isAndroid = Platform.OS === 'android';
export const isOther = Platform.OS !== 'ios' && Platform.OS !== 'android';
export function tryJSONParse(string) {
try {
return string && JSON.parse(string);
} catch (_) {
return string;
}
}
export function tryJSONStringify(data) {
try {
return JSON.stringify(data);
} catch (_) {
return null;
}
}
// Used to indicate if there is no corresponding modular function
const NO_REPLACEMENT = true;
const mapOfDeprecationReplacements = {
appCheck: {
default: {
activate: 'initializeAppCheck()',
setTokenAutoRefreshEnabled: 'setTokenAutoRefreshEnabled()',
getToken: 'getToken()',
getLimitedUseToken: 'getLimitedUseToken()',
onTokenChanged: 'onTokenChanged()',
},
statics: {
CustomProvider: 'CustomProvider',
},
},
crashlytics: {
default: {
checkForUnsentReports: 'checkForUnsentReports()',
crash: 'crash()',
deleteUnsentReports: 'deleteUnsentReports()',
didCrashOnPreviousExecution: 'didCrashOnPreviousExecution()',
log: 'log()',
setAttribute: 'setAttribute()',
setAttributes: 'setAttributes()',
setUserId: 'setUserId()',
recordError: 'recordError()',
sendUnsentReports: 'sendUnsentReports()',
setCrashlyticsCollectionEnabled: 'setCrashlyticsCollectionEnabled()',
},
},
firestore: {
default: {
batch: 'writeBatch()',
loadBundle: 'loadBundle()',
namedQuery: 'namedQuery()',
clearPersistence: 'clearIndexedDbPersistence()',
waitForPendingWrites: 'waitForPendingWrites()',
terminate: 'terminate()',
useEmulator: 'connectFirestoreEmulator()',
collection: 'collection()',
collectionGroup: 'collectionGroup()',
disableNetwork: 'disableNetwork()',
doc: 'doc()',
enableNetwork: 'enableNetwork()',
runTransaction: 'runTransaction()',
settings: 'settings()',
persistentCacheIndexManager: 'getPersistentCacheIndexManager()',
},
statics: {
setLogLevel: 'setLogLevel()',
Filter: 'where()',
FieldValue: 'FieldValue',
Timestamp: 'Timestamp',
GeoPoint: 'GeoPoint',
Blob: 'Bytes',
FieldPath: 'FieldPath',
},
FirestoreCollectionReference: {
count: 'getCountFromServer()',
countFromServer: 'getCountFromServer()',
endAt: 'endAt()',
endBefore: 'endBefore()',
get: 'getDocs()',
isEqual: NO_REPLACEMENT,
limit: 'limit()',
limitToLast: 'limitToLast()',
onSnapshot: 'onSnapshot()',
orderBy: 'orderBy()',
startAfter: 'startAfter()',
startAt: 'startAt()',
where: 'where()',
add: 'addDoc()',
doc: 'doc()',
},
FirestoreDocumentReference: {
collection: 'collection()',
delete: 'deleteDoc()',
get: 'getDoc()',
isEqual: NO_REPLACEMENT,
onSnapshot: 'onSnapshot()',
set: 'setDoc()',
update: 'updateDoc()',
},
FirestoreDocumentSnapshot: {
isEqual: NO_REPLACEMENT,
},
FirestoreFieldValue: {
arrayRemove: 'arrayRemove()',
arrayUnion: 'arrayUnion()',
delete: 'deleteField()',
increment: 'increment()',
serverTimestamp: 'serverTimestamp()',
},
Filter: {
or: 'or()',
and: 'and()',
},
FirestorePersistentCacheIndexManager: {
enableIndexAutoCreation: 'enablePersistentCacheIndexAutoCreation()',
disableIndexAutoCreation: 'disablePersistentCacheIndexAutoCreation()',
deleteAllIndexes: 'deleteAllPersistentCacheIndexes()',
},
FirestoreTimestamp: {
seconds: NO_REPLACEMENT,
nanoseconds: NO_REPLACEMENT,
},
},
};
const modularDeprecationMessage =
'This method is deprecated (as well as all React Native Firebase namespaced API) and will be removed in the next major release ' +
'as part of move to match Firebase Web modular SDK API. Please see migration guide for more details: https://rnfirebase.io/migrating-to-v22';
export function deprecationConsoleWarning(nameSpace, methodName, instanceName, isModularMethod) {
if (!isModularMethod) {
const moduleMap = mapOfDeprecationReplacements[nameSpace];
if (moduleMap) {
const instanceMap = moduleMap[instanceName];
const deprecatedMethod = instanceMap[methodName];
if (instanceMap && deprecatedMethod) {
if (!globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS) {
// eslint-disable-next-line no-console
console.warn(createMessage(nameSpace, methodName, instanceName));
if (globalThis.RNFB_MODULAR_DEPRECATION_STRICT_MODE === true) {
throw new Error('Deprecated API usage detected while in strict mode.');
}
}
}
}
}
}
export function createMessage(
nameSpace,
methodName,
instanceName = 'default',
uniqueMessage = null,
) {
if (uniqueMessage) {
// Unique deprecation message used for testing
return uniqueMessage;
}
const moduleMap = mapOfDeprecationReplacements[nameSpace];
if (moduleMap) {
const instance = moduleMap[instanceName];
if (instance) {
const replacementMethodName = instance[methodName];
if (replacementMethodName !== NO_REPLACEMENT) {
return (
modularDeprecationMessage +
`. Method called was \`${methodName}\`. Please use \`${replacementMethodName}\` instead.`
);
} else {
return modularDeprecationMessage + `. Method called was \`${methodName}\``;
}
}
}
}
function getNamespace(target) {
if (target.GeoPoint || target.CustomProvider) {
// target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck
return 'firestore';
}
if (target._config && target._config.namespace) {
return target._config.namespace;
}
const className = target.name ? target.name : target.constructor.name;
return Object.keys(mapOfDeprecationReplacements).find(key => {
if (mapOfDeprecationReplacements[key][className]) {
return key;
}
});
}
function getInstanceName(target) {
if (target.GeoPoint || target.CustomProvider) {
// target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck
return 'statics';
}
if (target._config) {
// module class instance, we use default to store map of deprecated methods
return 'default';
}
if (target.name) {
// It's a function which has a name property unlike classes
return target.name;
}
// It's a class instance
return target.constructor.name;
}
export function createDeprecationProxy(instance) {
return new Proxy(instance, {
construct(target, args) {
// needed for Timestamp which we pass as static, when we construct new instance, we need to wrap it in proxy again.
return createDeprecationProxy(new target(...args));
},
get(target, prop, receiver) {
const originalMethod = target[prop];
if (prop === 'constructor') {
return Reflect.get(target, prop, receiver);
}
if (target && target.constructor && target.constructor.name === 'FirestoreTimestamp') {
deprecationConsoleWarning('firestore', prop, 'FirestoreTimestamp', false);
return Reflect.get(target, prop, receiver);
}
if (target && target.name === 'firebaseModuleWithApp') {
// statics
if (
prop === 'Filter' ||
prop === 'FieldValue' ||
prop === 'Timestamp' ||
prop === 'GeoPoint' ||
prop === 'Blob' ||
prop === 'FieldPath'
) {
deprecationConsoleWarning('firestore', prop, 'statics', false);
}
if (prop === 'CustomProvider') {
deprecationConsoleWarning('appCheck', prop, 'statics', false);
}
if (prop !== 'setLogLevel') {
// we want to capture setLogLevel function call which we do below
return Reflect.get(target, prop, receiver);
}
}
if (typeof originalMethod === 'function') {
return function (...args) {
const isModularMethod = args.includes(MODULAR_DEPRECATION_ARG);
const instanceName = getInstanceName(target);
const nameSpace = getNamespace(target);
deprecationConsoleWarning(nameSpace, prop, instanceName, isModularMethod);
return originalMethod.apply(target, filterModularArgument(args));
};
}
return Reflect.get(target, prop, receiver);
},
});
}
export const MODULAR_DEPRECATION_ARG = 'react-native-firebase-modular-method-call';
export function filterModularArgument(list) {
return list.filter(arg => arg !== MODULAR_DEPRECATION_ARG);
}
export function warnIfNotModularCall(args, replacementMethodName = '') {
for (let i = 0; i < args.length; i++) {
if (args[i] === MODULAR_DEPRECATION_ARG) {
return;
}
}
let message = modularDeprecationMessage;
if (replacementMethodName.length > 0) {
message += ` Please use \`${replacementMethodName}\` instead.`;
}
if (!globalThis.RNFB_SILENCE_MODULAR_DEPRECATION_WARNINGS) {
// eslint-disable-next-line no-console
console.warn(message);
if (globalThis.RNFB_MODULAR_DEPRECATION_STRICT_MODE === true) {
throw new Error('Deprecated API usage detected while in strict mode.');
}
}
}