UNPKG

reactfire

Version:
1,029 lines (869 loc) 33.6 kB
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