reactfire
Version:
Firebase library for React
1,029 lines (869 loc) • 33.6 kB
JavaScript
import { useMemo, createElement, useContext, createContext, version as version$1, Fragment, useState, useEffect, Suspense, useLayoutEffect } from 'react';
import { user } from 'rxfire/auth';
import { Observable, from, empty, Subject } from 'rxjs';
import firebase from 'firebase/app';
import { object, list, listVal } from 'rxfire/database';
import { map, tap, catchError, shareReplay, first } from 'rxjs/operators';
import { doc, docData, fromCollectionRef, collectionData } from 'rxfire/firestore';
import { getDownloadURL } from 'rxfire/storage';
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function importSDK(sdk) {
switch (sdk) {
case 'analytics':
return import(
/* webpackChunkName: "analytics" */
'firebase/analytics');
case 'auth':
return import(
/* webpackChunkName: "auth" */
'firebase/auth');
case 'database':
return import(
/* webpackChunkName: "database" */
'firebase/database');
case 'firestore':
return import(
/* webpackChunkName: "firestore" */
'firebase/firestore');
case 'functions':
return import(
/* webpackChunkName: "functions" */
'firebase/functions');
case 'messaging':
return import(
/* webpackChunkName: "messaging" */
'firebase/messaging');
case 'performance':
return import(
/* webpackChunkName: "performance" */
'firebase/performance');
case 'remoteConfig':
return import(
/* webpackChunkName: "remoteConfig" */
'firebase/remote-config');
case 'storage':
return import(
/* webpackChunkName: "storage" */
'firebase/storage');
}
}
function proxyComponent(componentName) {
var contextualApp;
var useComponent = function useComponent(app, suspense) {
contextualApp = useFirebaseApp();
var suspenseEnabled = useSuspenseEnabledFromConfigAndContext(suspense);
var sdkSubject = preload(componentName, app || contextualApp);
if (!sdkSubject.hasValue && suspenseEnabled) {
throw sdkSubject.firstEmission;
} else if (!sdkSubject.hasValue && !suspenseEnabled && !firebase[componentName]) {
throw new Error("ReactFire: \"firebase/" + componentName + "\" not found. Please import it in your component, or call preload" + (componentName.charAt(0).toUpperCase() + componentName.slice(1)) + " and wait for it to resolve. ReactFire can only auto-import Firebase libraries if Suspense mode is enabled.");
} // get value to throw if there's an error
return firebase[componentName];
};
return new Proxy(useComponent, {
// @ts-ignore: TODO: Fix the types here
get: function get(target, p) {
return target()[p];
},
apply: function apply(target, _this, args) {
var component = target(args[0]).bind(_this); // If they don't pass an app, assume the app in context rather than [DEFAULT]
if (!args[0]) {
args[0] = contextualApp;
}
return component.apply(void 0, args);
}
});
}
var useAuth = /*#__PURE__*/proxyComponent('auth');
var useAnalytics = /*#__PURE__*/proxyComponent('analytics');
var useDatabase = /*#__PURE__*/proxyComponent('database');
var useFirestore = /*#__PURE__*/proxyComponent('firestore');
var useFunctions = /*#__PURE__*/proxyComponent('functions');
var useMessaging = /*#__PURE__*/proxyComponent('messaging');
var usePerformance = /*#__PURE__*/proxyComponent('performance');
var useRemoteConfig = /*#__PURE__*/proxyComponent('remoteConfig');
var useStorage = /*#__PURE__*/proxyComponent('storage');
var auth = useAuth;
var analytics = useAnalytics;
var database = useDatabase;
var firestore = useFirestore;
var functions = useFunctions;
var messaging = useMessaging;
var performance$1 = usePerformance;
var remoteConfig = useRemoteConfig;
var storage = useStorage;
function preloadFactory(componentName) {
return function (options) {
return preload(componentName, options.firebaseApp, options.setup).toPromise();
};
}
function preload(componentName, firebaseApp, settingsCallback) {
if (settingsCallback === void 0) {
settingsCallback = function settingsCallback() {};
}
var app = firebaseApp;
return preloadObservable(new Observable(function (emitter) {
importSDK(componentName).then(function () {
var instanceFactory = app[componentName].bind(app);
Promise.resolve(settingsCallback(instanceFactory)).then(function () {
emitter.next(instanceFactory);
emitter.complete();
});
})["catch"](function (e) {
emitter.error(e);
emitter.complete();
});
}), "firebase-sdk:" + componentName + ":" + app.name);
}
var preloadAuth = /*#__PURE__*/preloadFactory('auth');
var preloadAnalytics = /*#__PURE__*/preloadFactory('analytics');
var preloadDatabase = /*#__PURE__*/preloadFactory('database');
var preloadFirestore = /*#__PURE__*/preloadFactory('firestore');
var preloadFunctions = /*#__PURE__*/preloadFactory('functions');
var preloadMessaging = /*#__PURE__*/preloadFactory('messaging');
var preloadPerformance = /*#__PURE__*/preloadFactory('performance');
var preloadRemoteConfig = /*#__PURE__*/preloadFactory('remoteConfig');
var preloadStorage = /*#__PURE__*/preloadFactory('storage');
var DEFAULT_APP_NAME = '[DEFAULT]';
var FirebaseAppContext = /*#__PURE__*/createContext(undefined);
var SuspenseEnabledContext = /*#__PURE__*/createContext(false); // @ts-ignore: "__REACTFIRE_VERSION__" is replaced with actual ReactFire version (see babel.config.js)
var version = "3.0.0-rc.0";
var shallowEq = function shallowEq(a, b) {
return a === b || [].concat(Object.keys(a), Object.keys(b)).every(function (key) {
return a[key] === b[key];
});
};
function FirebaseAppProvider(props) {
var firebaseConfig = props.firebaseConfig,
appName = props.appName,
suspense = props.suspense;
var firebaseApp = useMemo(function () {
if (props.firebaseApp) {
return props.firebaseApp;
}
var existingApp = firebase.apps.find(function (app) {
return app.name === (appName || DEFAULT_APP_NAME);
});
if (existingApp) {
if (firebaseConfig && shallowEq(existingApp.options, firebaseConfig)) {
return existingApp;
} else {
throw new Error("Does not match the options already provided to the " + (appName || 'default') + " firebase app instance, give this new instance a different appName.");
}
} else {
if (!firebaseConfig) {
throw new Error('No firebaseConfig provided');
} // TODO: DOUBLE CHECK THAT THIS GETS CALLED
var reactVersion = version$1 || 'unknown';
firebase.registerVersion('react', reactVersion);
firebase.registerVersion('reactfire', version);
return firebase.initializeApp(firebaseConfig, appName);
}
}, [props.firebaseApp, firebaseConfig, appName]);
return createElement(FirebaseAppContext.Provider, {
value: firebaseApp
}, createElement(SuspenseEnabledContext.Provider, Object.assign({
value: suspense != null ? suspense : false
}, props)));
}
function useIsSuspenseEnabled() {
var suspense = useContext(SuspenseEnabledContext); // default to false if not available in context
return suspense != null ? suspense : false;
}
function useSuspenseEnabledFromConfigAndContext(suspenseFromConfig) {
var suspenseFromContext = useContext(SuspenseEnabledContext); // prioritize config over context
if (suspenseFromConfig !== undefined) {
return suspenseFromConfig;
}
return suspenseFromContext;
}
function useFirebaseApp() {
var firebaseApp = useContext(FirebaseAppContext);
if (!firebaseApp) {
throw new Error('Cannot call useFirebaseApp unless your component is within a FirebaseAppProvider');
}
return firebaseApp;
}
function preloadUser(options) {
// TODO: Find an alternative that doesn't break the rules of hooks (conditional hook call)
var firebaseApp = (options == null ? void 0 : options.firebaseApp) || useFirebaseApp();
return preloadAuth({
firebaseApp: firebaseApp
}).then(function (auth) {
var result = preloadObservable(user(auth()), "auth:user:" + firebaseApp.name);
return result.toPromise();
});
}
/**
* Subscribe to Firebase auth state changes, including token refresh
*
* @param auth - the [firebase.auth](https://firebase.google.com/docs/reference/js/firebase.auth) object
* @param options
*/
function useUser(auth, options) {
// TODO: Find an alternative that doesn't break the rules of hooks (conditional hook call)
auth = auth || useAuth();
if (!auth) {
throw new Error('firebase.auth not found');
}
var observableId = "auth:user:" + auth.app.name;
var observable$ = user(auth);
var currentUser = auth.currentUser; // If currentUser is available, skip initialData
if ((options == null ? void 0 : options.initialData) && !currentUser) {
currentUser = options.initialData;
}
return useObservable(observableId, observable$, _extends({}, options, {
initialData: currentUser
}));
}
function useIdTokenResult(user, forceRefresh, options) {
if (forceRefresh === void 0) {
forceRefresh = false;
}
if (!user) {
throw new Error('you must provide a user');
}
var observableId = "auth:idTokenResult:" + user.uid + ":forceRefresh=" + forceRefresh;
var observable$ = from(user.getIdTokenResult(forceRefresh));
return useObservable(observableId, observable$, options);
}
function ClaimsCheck(_ref) {
var user = _ref.user,
fallback = _ref.fallback,
children = _ref.children,
requiredClaims = _ref.requiredClaims;
var _useIdTokenResult = useIdTokenResult(user, false),
data = _useIdTokenResult.data;
var claims = data.claims;
var missingClaims = {};
if (requiredClaims) {
Object.keys(requiredClaims).forEach(function (claim) {
if (requiredClaims[claim] !== claims[claim]) {
missingClaims[claim] = {
expected: requiredClaims[claim],
actual: claims[claim]
};
}
});
}
if (Object.keys(missingClaims).length === 0) {
return createElement(Fragment, null, children);
} else {
return createElement(Fragment, null, fallback);
}
}
function AuthCheck(_ref2) {
var auth = _ref2.auth,
fallback = _ref2.fallback,
children = _ref2.children,
requiredClaims = _ref2.requiredClaims;
var _useUser = useUser(auth),
user = _useUser.data;
if (user) {
return requiredClaims ? createElement(ClaimsCheck, {
user: user,
fallback: fallback,
requiredClaims: requiredClaims
}, children) : createElement(Fragment, null, children);
} else {
return createElement(Fragment, null, fallback);
}
}
var cachedQueries = globalThis._reactFireDatabaseCachedQueries || [];
if (!globalThis._reactFireDatabaseCachedQueries) {
globalThis._reactFireDatabaseCachedQueries = cachedQueries;
}
function getUniqueIdForDatabaseQuery(query) {
var index = cachedQueries.findIndex(function (cachedQuery) {
return cachedQuery.isEqual(query);
});
if (index > -1) {
return index;
}
return cachedQueries.push(query) - 1;
}
/**
* Subscribe to a Realtime Database object
*
* @param ref - Reference to the DB object you want to listen to
* @param options
*/
function useDatabaseObject(ref, options) {
var observableId = "database:object:" + ref.toString();
var observable$ = object(ref);
return useObservable(observableId, observable$, options);
} // ============================================================================
// TODO: switch to rxfire's objectVal once this PR is merged:
// https://github.com/firebase/firebase-js-sdk/pull/2352
function objectVal(query, keyField) {
return object(query).pipe(map(function (change) {
return changeToData(change, keyField);
}));
}
function changeToData(change, keyField) {
var _ref;
var val = change.snapshot.val(); // don't worry about setting IDs if the value is a primitive type
if (typeof val !== 'object') {
return val;
}
return _extends({}, change.snapshot.val(), keyField ? (_ref = {}, _ref[keyField] = change.snapshot.key, _ref) : null);
} // ============================================================================
function useDatabaseObjectData(ref, options) {
var idField = options ? checkIdField(options) : 'NO_ID_FIELD';
var observableId = "database:objectVal:" + ref.toString() + ":idField=" + idField;
var observable$ = objectVal(ref, idField);
return useObservable(observableId, observable$, options);
}
/**
* Subscribe to a Realtime Database list
*
* @param ref - Reference to the DB List you want to listen to
* @param options
*/
function useDatabaseList(ref, options) {
var hash = "database:list:" + getUniqueIdForDatabaseQuery(ref);
var observable$ = list(ref);
return useObservable(hash, observable$, options);
}
function useDatabaseListData(ref, options) {
var idField = options ? checkIdField(options) : 'NO_ID_FIELD';
var observableId = "database:listVal:" + getUniqueIdForDatabaseQuery(ref) + ":idField=" + idField;
var observable$ = listVal(ref, idField);
return useObservable(observableId, observable$, options);
}
var SuspenseSubject = /*#__PURE__*/function (_Subject) {
_inheritsLoose(SuspenseSubject, _Subject);
function SuspenseSubject(innerObservable, _timeoutWindow) {
var _this;
_this = _Subject.call(this) || this;
_this._timeoutWindow = _timeoutWindow;
_this._hasValue = false;
_this._error = undefined;
_this._firstEmission = new Promise(function (resolve) {
return _this._resolveFirstEmission = resolve;
});
_this._innerObservable = innerObservable.pipe(tap(function (v) {
_this._next(v);
}, function (e) {
// save the error, so that we can raise on subscription or .value
// resolve the promise, so suspense tries again
_this._error = e;
_this._resolveFirstEmission();
}), catchError(function () {
return empty();
}), shareReplay(1)); // warm up the observable
_this._warmupSubscription = _this._innerObservable.subscribe(); // set a timeout for reseting the cache, subscriptions will cancel the timeout
// and reschedule again on unsubscribe
_this._timeoutHandler = setTimeout(_this._reset, _this._timeoutWindow);
return _this;
}
var _proto = SuspenseSubject.prototype;
_proto._next = function _next(value) {
this._hasValue = true;
this._value = value;
this._resolveFirstEmission();
};
_proto._reset = function _reset() {
var _this2 = this;
// seems to be undefined in tests?
if (this._warmupSubscription) {
this._warmupSubscription.unsubscribe();
}
this._hasValue = false;
this._value = undefined;
this._error = undefined;
this._firstEmission = new Promise(function (resolve) {
return _this2._resolveFirstEmission = resolve;
});
};
_proto._subscribe = function _subscribe(subscriber) {
if (this._timeoutHandler) {
clearTimeout(this._timeoutHandler);
}
this._innerSubscriber = this._innerObservable.subscribe(subscriber);
return this._innerSubscriber.add(this._reset);
};
_createClass(SuspenseSubject, [{
key: "hasValue",
get: function get() {
// hasValue returns true if there's an error too
// so that after we resolve the promise & useObservable is called again
// we won't throw again
return this._hasValue || !!this._error;
}
}, {
key: "value",
get: function get() {
// TODO figure out how to reset the cache here, if I _reset() here before throwing
// it doesn't seem to work.
// As it is now, this will burn the cache entry until the timeout fires.
if (this._error) {
throw this._error;
}
return this._value;
}
}, {
key: "firstEmission",
get: function get() {
return this._firstEmission;
}
}, {
key: "ourError",
get: function get() {
return this._error;
}
}]);
return SuspenseSubject;
}(Subject);
var DEFAULT_TIMEOUT = 30000; // Since we're side-effect free, we need to ensure our observable cache is global
var preloadedObservables = globalThis._reactFirePreloadedObservables || /*#__PURE__*/new Map();
if (!globalThis._reactFirePreloadedObservables) {
globalThis._reactFirePreloadedObservables = preloadedObservables;
} // Starts listening to an Observable.
// Call this once you know you're going to render a
// child that will consume the observable
function preloadObservable(source, id) {
if (preloadedObservables.has(id)) {
return preloadedObservables.get(id);
} else {
var observable = new SuspenseSubject(source, DEFAULT_TIMEOUT);
preloadedObservables.set(id, observable);
return observable;
}
}
function useObservable(observableId, source, config) {
var _config;
if (config === void 0) {
config = {};
}
if (!observableId) {
throw new Error('cannot call useObservable without an observableId');
}
var observable = preloadObservable(source, observableId);
var hasInitialData = Object.keys(config).includes('initialData');
var suspenseEnabled = useSuspenseEnabledFromConfigAndContext(config.suspense);
if (!observable.hasValue && !((_config = config) == null ? void 0 : _config.initialData)) {
if (suspenseEnabled === true) {
throw observable.firstEmission;
}
}
var _React$useState = useState(function () {
return observable.hasValue ? observable.value : config.initialData;
}),
latest = _React$useState[0],
setValue = _React$useState[1];
useEffect(function () {
var subscription = observable.subscribe(function (v) {
setValue(function () {
return v;
});
}, function (e) {
throw e;
});
return function () {
return subscription.unsubscribe();
};
}, [observable]);
var status;
if (observable.hasError) {
status = 'error';
} else if (observable.hasValue || hasInitialData) {
status = 'success';
} else {
status = 'loading';
}
return {
status: status,
hasEmitted: observable.hasValue,
isComplete: observable.isStopped,
data: latest,
error: observable.ourError,
firstValuePromise: observable.firstEmission
};
}
var cachedQueries$1 = globalThis._reactFireFirestoreQueryCache || [];
if (!globalThis._reactFireFirestoreQueryCache) {
globalThis._reactFireFirestoreQueryCache = cachedQueries$1;
}
function getUniqueIdForFirestoreQuery(query) {
var index = cachedQueries$1.findIndex(function (cachedQuery) {
return cachedQuery.isEqual(query);
});
if (index > -1) {
return index;
}
return cachedQueries$1.push(query) - 1;
} // starts a request for a firestore doc.
// imports the firestore SDK automatically
// if it hasn't been imported yet.
//
// there's a decent chance this gets called before the Firestore SDK
// has been imported, so it takes a refProvider instead of a ref
function preloadFirestoreDoc(refProvider, options) {
// TODO: Find an alternative that doesn't break the rules of hooks (conditional hook call)
var firebaseApp = (options == null ? void 0 : options.firebaseApp) || useFirebaseApp();
return preloadFirestore({
firebaseApp: firebaseApp
}).then(function (firestore) {
var ref = refProvider(firestore());
return preloadObservable(doc(ref), "firestore:doc:" + firebaseApp.name + ":" + ref.path);
});
}
/**
* Suscribe to Firestore Document changes
*
* @param ref - Reference to the document you want to listen to
* @param options
*/
function useFirestoreDoc(ref, options) {
var observableId = "firestore:doc:" + ref.firestore.app.name + ":" + ref.path;
var observable$ = doc(ref);
return useObservable(observableId, observable$, options);
}
/**
* Get a firestore document and don't subscribe to changes
*
* @param ref - Reference to the document you want to get
* @param options
*/
function useFirestoreDocOnce(ref, options) {
var observableId = "firestore:docOnce:" + ref.firestore.app.name + ":" + ref.path;
var observable$ = doc(ref).pipe(first());
return useObservable(observableId, observable$, options);
}
/**
* Suscribe to Firestore Document changes
*
* @param ref - Reference to the document you want to listen to
* @param options
*/
function useFirestoreDocData(ref, options) {
var idField = options ? checkIdField(options) : 'NO_ID_FIELD';
var observableId = "firestore:docData:" + ref.firestore.app.name + ":" + ref.path + ":idField=" + idField;
var observable = docData(ref, idField);
return useObservable(observableId, observable, options);
}
/**
* Get a firestore document and don't subscribe to changes
*
* @param ref - Reference to the document you want to get
* @param options
*/
function useFirestoreDocDataOnce(ref, options) {
var idField = options ? checkIdField(options) : 'NO_ID_FIELD';
var observableId = "firestore:docDataOnce:" + ref.firestore.app.name + ":" + ref.path + ":idField=" + idField;
var observable$ = docData(ref, idField).pipe(first());
return useObservable(observableId, observable$, options);
}
/**
* Subscribe to a Firestore collection
*
* @param ref - Reference to the collection you want to listen to
* @param options
*/
function useFirestoreCollection(query, options) {
var observableId = "firestore:collection:" + getUniqueIdForFirestoreQuery(query);
var observable$ = fromCollectionRef(query);
return useObservable(observableId, observable$, options);
}
/**
* Subscribe to a Firestore collection and unwrap the snapshot.
*
* @param ref - Reference to the collection you want to listen to
* @param options
*/
function useFirestoreCollectionData(query, options) {
var idField = options ? checkIdField(options) : 'NO_ID_FIELD';
var observableId = "firestore:collectionData:" + getUniqueIdForFirestoreQuery(query) + ":idField=" + idField;
var observable$ = collectionData(query, idField);
return useObservable(observableId, observable$, options);
}
function SuspenseWithPerf(_ref) {
var _performance;
var children = _ref.children,
traceId = _ref.traceId,
fallback = _ref.fallback,
firePerf = _ref.firePerf;
if (!firePerf) {
var firebaseApp = useFirebaseApp();
preloadPerformance({
firebaseApp: firebaseApp
}).then(function (perf) {
return perf();
});
}
var entries = ((_performance = performance) == null ? void 0 : _performance.getEntriesByName(traceId, 'measure')) || [];
var startMarkName = "_" + traceId + "Start[" + entries.length + "]";
var endMarkName = "_" + traceId + "End[" + entries.length + "]";
var Fallback = function Fallback() {
useLayoutEffect(function () {
var _performance2;
(_performance2 = performance) == null ? void 0 : _performance2.mark(startMarkName);
return function () {
var _performance3, _performance4;
(_performance3 = performance) == null ? void 0 : _performance3.mark(endMarkName);
(_performance4 = performance) == null ? void 0 : _performance4.measure(traceId, startMarkName, endMarkName);
};
}, []);
return createElement(Fragment, null, fallback);
};
return createElement(Suspense, {
fallback: createElement(Fallback, null)
}, children);
}
function parameter$(_ref) {
var remoteConfig = _ref.remoteConfig,
key = _ref.key,
getter = _ref.getter;
return new Observable(function (subscriber) {
remoteConfig.ensureInitialized().then(function () {
// 'this' for the getter loses context in the next()
// call, so it needs to be bound.
subscriber.next(getter.bind(remoteConfig)(key));
});
});
}
function getValue(remoteConfig, key) {
var getter = remoteConfig.getValue;
return parameter$({
remoteConfig: remoteConfig,
key: key,
getter: getter
});
}
function getString(remoteConfig, key) {
var getter = remoteConfig.getString;
return parameter$({
remoteConfig: remoteConfig,
key: key,
getter: getter
});
}
function getNumber(remoteConfig, key) {
var getter = remoteConfig.getNumber;
return parameter$({
remoteConfig: remoteConfig,
key: key,
getter: getter
});
}
function getBoolean(remoteConfig, key) {
var getter = remoteConfig.getBoolean;
return parameter$({
remoteConfig: remoteConfig,
key: key,
getter: getter
});
}
function getAll(remoteConfig) {
var getter = remoteConfig.getAll; // No key is needed for getAll()
return parameter$({
remoteConfig: remoteConfig,
key: '',
getter: getter
});
}
/**
* Helper function to construct type safe functions. Since Remote Config has
* methods that return different types for values, we need to be extra safe
* to make sure we are not returning improper types by accident.
* @param key
* @param getter
* @param remoteConfig
*/
function useRemoteConfigValue_INTERNAL(key, getter, remoteConfig) {
var _remoteConfig$_storag;
// TODO: Find an alternative that doesn't break the rules of hooks (conditional hook call)
remoteConfig = remoteConfig || useRemoteConfig(); // INVESTIGATE need to use a public API to get at the app name, one doesn't appear to exist...
// we might need to iterate over the Firebase apps and check for remoteConfig equality? this works for now
var appName = (_remoteConfig$_storag = remoteConfig._storage) == null ? void 0 : _remoteConfig$_storag.appName;
var $value = getter(remoteConfig, key);
var observableId = "remoteConfig:" + key + ":" + getter.name + ":" + appName;
return useObservable(observableId, $value);
}
/**
* Accepts a key and optionally a Remote Config instance. Returns a
* Remote Config Value.
*
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
function useRemoteConfigValue(key, remoteConfig) {
return useRemoteConfigValue_INTERNAL(key, getValue, remoteConfig);
}
/**
* Convience method similar to useRemoteConfigValue. Returns a `string` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
function useRemoteConfigString(key, remoteConfig) {
return useRemoteConfigValue_INTERNAL(key, getString, remoteConfig);
}
/**
* Convience method similar to useRemoteConfigValue. Returns a `number` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
function useRemoteConfigNumber(key, remoteConfig) {
return useRemoteConfigValue_INTERNAL(key, getNumber, remoteConfig);
}
/**
* Convience method similar to useRemoteConfigValue. Returns a `boolean` from a Remote Config parameter.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
function useRemoteConfigBoolean(key, remoteConfig) {
return useRemoteConfigValue_INTERNAL(key, getBoolean, remoteConfig);
}
/**
* Convience method similar to useRemoteConfigValue. Returns allRemote Config parameters.
* @param key The parameter key in Remote Config
* @param remoteConfig Optional instance. If not provided ReactFire will either grab the default instance or lazy load.
*/
function useRemoteConfigAll(key, remoteConfig) {
return useRemoteConfigValue_INTERNAL(key, getAll, remoteConfig);
}
/**
* modified version of rxFire's _fromTask
*
* @param task
*/
function _fromTask(task) {
return new Observable(function (subscriber) {
var progress = function progress(snap) {
return subscriber.next(snap);
};
var error = function error(e) {
return subscriber.error(e);
};
var complete = function complete() {
return subscriber.complete();
};
task.on('state_changed', progress, error, complete); // I REMOVED THE UNSUBSCRIBE RETURN BECAUSE IT CANCELS THE UPLOAD
// https://github.com/firebase/firebase-js-sdk/issues/1659
});
}
/**
* Subscribe to the progress of a storage task
*
* @param task - the task you want to listen to
* @param ref - reference to the blob the task is acting on
* @param options
*/
function useStorageTask(task, ref, options) {
var observableId = "storage:task:" + ref.toString();
var observable$ = _fromTask(task);
return useObservable(observableId, observable$, options ? options.initialData : undefined);
}
/**
* Subscribe to a storage ref's download URL
*
* @param ref - reference to the blob you want to download
* @param options
*/
function useStorageDownloadURL(ref, options) {
var observableId = "storage:downloadUrl:" + ref.toString();
var observable$ = getDownloadURL(ref);
return useObservable(observableId, observable$, options);
}
function StorageFromContext(props) {
var storage = useStorage();
props = _extends({}, props, {
storage: storage
});
return createElement(INTERNALStorageImage, Object.assign({}, props));
}
function INTERNALStorageImage(props) {
var storage = props.storage,
storagePath = props.storagePath,
suspense = props.suspense,
placeHolder = props.placeHolder,
imgProps = _objectWithoutPropertiesLoose(props, ["storage", "storagePath", "suspense", "placeHolder"]);
var reactfireOptions = {
suspense: useSuspenseEnabledFromConfigAndContext(suspense)
};
if (!storage) {
throw new Error('Storage was not passed to component INTERNALStorageImage. This should not be possible');
}
var _useStorageDownloadUR = useStorageDownloadURL(storage.ref(storagePath), reactfireOptions),
status = _useStorageDownloadUR.status,
imgSrc = _useStorageDownloadUR.data;
if (status === 'success') {
if (!(imgProps.alt || imgProps.alt === '')) {
console.warn("No alt prop provided for StorageImage with storagePath \"" + storagePath + "\"", 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images');
}
return createElement("img", Object.assign({
src: imgSrc,
alt: imgProps.alt
}, imgProps));
} else {
return placeHolder != null ? placeHolder : createElement(Fragment, null, "''");
}
}
function StorageImage(props) {
var storage = props.storage;
if (storage) {
return createElement(INTERNALStorageImage, Object.assign({}, props));
} else {
return createElement(StorageFromContext, Object.assign({}, props));
}
}
function checkOptions(options, field) {
// make sure the field passed in is a valid key of ReactFire Options
if (field === 'idField' || field === 'initialData' || field === 'suspense') {
return options ? options[field] : undefined;
}
throw new Error("Field \"" + field + "\" is not a valid key in ReactFireOptions");
}
function checkinitialData(options) {
return checkOptions(options, 'initialData');
}
function checkIdField(options) {
return checkOptions(options, 'idField');
}
export { AuthCheck, ClaimsCheck, FirebaseAppProvider, StorageImage, SuspenseWithPerf, analytics, auth, checkIdField, checkOptions, checkinitialData, database, firestore, functions, messaging, performance$1 as performance, preloadAnalytics, preloadAuth, preloadDatabase, preloadFirestore, preloadFirestoreDoc, preloadFunctions, preloadMessaging, preloadObservable, preloadPerformance, preloadRemoteConfig, preloadStorage, preloadUser, remoteConfig, storage, useAnalytics, useAuth, useDatabase, useDatabaseList, useDatabaseListData, useDatabaseObject, useDatabaseObjectData, useFirebaseApp, useFirestore, useFirestoreCollection, useFirestoreCollectionData, useFirestoreDoc, useFirestoreDocData, useFirestoreDocDataOnce, useFirestoreDocOnce, useFunctions, useIdTokenResult, useIsSuspenseEnabled, useMessaging, useObservable, usePerformance, useRemoteConfig, useRemoteConfigAll, useRemoteConfigBoolean, useRemoteConfigNumber, useRemoteConfigString, useRemoteConfigValue, useStorage, useStorageDownloadURL, useStorageTask, useSuspenseEnabledFromConfigAndContext, useUser, version };
//# sourceMappingURL=reactfire.esm.js.map