UNPKG

react-query

Version:

Hooks for managing, caching and syncing asynchronous and remote data in React

1,781 lines (1,448 loc) 95.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.ReactQueryCore = {})); }(this, (function (exports) { 'use strict'; function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } var Subscribable = /*#__PURE__*/function () { function Subscribable() { this.listeners = []; } var _proto = Subscribable.prototype; _proto.subscribe = function subscribe(listener) { var _this = this; var callback = listener || function () { return undefined; }; this.listeners.push(callback); this.onSubscribe(); return function () { _this.listeners = _this.listeners.filter(function (x) { return x !== callback; }); _this.onUnsubscribe(); }; }; _proto.hasListeners = function hasListeners() { return this.listeners.length > 0; }; _proto.onSubscribe = function onSubscribe() {// Do nothing }; _proto.onUnsubscribe = function onUnsubscribe() {// Do nothing }; return Subscribable; }(); 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); } // TYPES // UTILS var isServer = typeof window === 'undefined'; function noop() { return undefined; } function functionalUpdate(updater, input) { return typeof updater === 'function' ? updater(input) : updater; } function isValidTimeout(value) { return typeof value === 'number' && value >= 0 && value !== Infinity; } function ensureQueryKeyArray(value) { return Array.isArray(value) ? value : [value]; } function difference(array1, array2) { return array1.filter(function (x) { return array2.indexOf(x) === -1; }); } function replaceAt(array, index, value) { var copy = array.slice(0); copy[index] = value; return copy; } function timeUntilStale(updatedAt, staleTime) { return Math.max(updatedAt + (staleTime || 0) - Date.now(), 0); } function parseQueryArgs(arg1, arg2, arg3) { if (!isQueryKey(arg1)) { return arg1; } if (typeof arg2 === 'function') { return _extends({}, arg3, { queryKey: arg1, queryFn: arg2 }); } return _extends({}, arg2, { queryKey: arg1 }); } function parseFilterArgs(arg1, arg2, arg3) { return isQueryKey(arg1) ? [_extends({}, arg2, { queryKey: arg1 }), arg3] : [arg1 || {}, arg2]; } function mapQueryStatusFilter(active, inactive) { if (active === true && inactive === true || active == null && inactive == null) { return 'all'; } else if (active === false && inactive === false) { return 'none'; } else { // At this point, active|inactive can only be true|false or false|true // so, when only one value is provided, the missing one has to be the negated value var isActive = active != null ? active : !inactive; return isActive ? 'active' : 'inactive'; } } function matchQuery(filters, query) { var active = filters.active, exact = filters.exact, fetching = filters.fetching, inactive = filters.inactive, predicate = filters.predicate, queryKey = filters.queryKey, stale = filters.stale; if (isQueryKey(queryKey)) { if (exact) { if (query.queryHash !== hashQueryKeyByOptions(queryKey, query.options)) { return false; } } else if (!partialMatchKey(query.queryKey, queryKey)) { return false; } } var queryStatusFilter = mapQueryStatusFilter(active, inactive); if (queryStatusFilter === 'none') { return false; } else if (queryStatusFilter !== 'all') { var isActive = query.isActive(); if (queryStatusFilter === 'active' && !isActive) { return false; } if (queryStatusFilter === 'inactive' && isActive) { return false; } } if (typeof stale === 'boolean' && query.isStale() !== stale) { return false; } if (typeof fetching === 'boolean' && query.isFetching() !== fetching) { return false; } if (predicate && !predicate(query)) { return false; } return true; } function matchMutation(filters, mutation) { var exact = filters.exact, fetching = filters.fetching, predicate = filters.predicate, mutationKey = filters.mutationKey; if (isQueryKey(mutationKey)) { if (!mutation.options.mutationKey) { return false; } if (exact) { if (hashQueryKey(mutation.options.mutationKey) !== hashQueryKey(mutationKey)) { return false; } } else if (!partialMatchKey(mutation.options.mutationKey, mutationKey)) { return false; } } if (typeof fetching === 'boolean' && mutation.state.status === 'loading' !== fetching) { return false; } if (predicate && !predicate(mutation)) { return false; } return true; } function hashQueryKeyByOptions(queryKey, options) { var hashFn = (options == null ? void 0 : options.queryKeyHashFn) || hashQueryKey; return hashFn(queryKey); } /** * Default query keys hash function. */ function hashQueryKey(queryKey) { var asArray = ensureQueryKeyArray(queryKey); return stableValueHash(asArray); } /** * Hashes the value into a stable hash. */ function stableValueHash(value) { return JSON.stringify(value, function (_, val) { return isPlainObject(val) ? Object.keys(val).sort().reduce(function (result, key) { result[key] = val[key]; return result; }, {}) : val; }); } /** * Checks if key `b` partially matches with key `a`. */ function partialMatchKey(a, b) { return partialDeepEqual(ensureQueryKeyArray(a), ensureQueryKeyArray(b)); } /** * Checks if `b` partially matches with `a`. */ function partialDeepEqual(a, b) { if (a === b) { return true; } if (typeof a !== typeof b) { return false; } if (a && b && typeof a === 'object' && typeof b === 'object') { return !Object.keys(b).some(function (key) { return !partialDeepEqual(a[key], b[key]); }); } return false; } /** * This function returns `a` if `b` is deeply equal. * If not, it will replace any deeply equal children of `b` with those of `a`. * This can be used for structural sharing between JSON values for example. */ function replaceEqualDeep(a, b) { if (a === b) { return a; } var array = Array.isArray(a) && Array.isArray(b); if (array || isPlainObject(a) && isPlainObject(b)) { var aSize = array ? a.length : Object.keys(a).length; var bItems = array ? b : Object.keys(b); var bSize = bItems.length; var copy = array ? [] : {}; var equalItems = 0; for (var i = 0; i < bSize; i++) { var key = array ? i : bItems[i]; copy[key] = replaceEqualDeep(a[key], b[key]); if (copy[key] === a[key]) { equalItems++; } } return aSize === bSize && equalItems === aSize ? a : copy; } return b; } /** * Shallow compare objects. Only works with objects that always have the same properties. */ function shallowEqualObjects(a, b) { if (a && !b || b && !a) { return false; } for (var key in a) { if (a[key] !== b[key]) { return false; } } return true; } // Copied from: https://github.com/jonschlinkert/is-plain-object function isPlainObject(o) { if (!hasObjectPrototype(o)) { return false; } // If has modified constructor var ctor = o.constructor; if (typeof ctor === 'undefined') { return true; } // If has modified prototype var prot = ctor.prototype; if (!hasObjectPrototype(prot)) { return false; } // If constructor does not have an Object-specific method if (!prot.hasOwnProperty('isPrototypeOf')) { return false; } // Most likely a plain Object return true; } function hasObjectPrototype(o) { return Object.prototype.toString.call(o) === '[object Object]'; } function isQueryKey(value) { return typeof value === 'string' || Array.isArray(value); } function isError(value) { return value instanceof Error; } function sleep(timeout) { return new Promise(function (resolve) { setTimeout(resolve, timeout); }); } /** * Schedules a microtask. * This can be useful to schedule state updates after rendering. */ function scheduleMicrotask(callback) { Promise.resolve().then(callback).catch(function (error) { return setTimeout(function () { throw error; }); }); } var FocusManager = /*#__PURE__*/function (_Subscribable) { _inheritsLoose(FocusManager, _Subscribable); function FocusManager() { return _Subscribable.apply(this, arguments) || this; } var _proto = FocusManager.prototype; _proto.onSubscribe = function onSubscribe() { if (!this.removeEventListener) { this.setDefaultEventListener(); } }; _proto.setEventListener = function setEventListener(setup) { var _this = this; if (this.removeEventListener) { this.removeEventListener(); } this.removeEventListener = setup(function (focused) { if (typeof focused === 'boolean') { _this.setFocused(focused); } else { _this.onFocus(); } }); }; _proto.setFocused = function setFocused(focused) { this.focused = focused; if (focused) { this.onFocus(); } }; _proto.onFocus = function onFocus() { this.listeners.forEach(function (listener) { listener(); }); }; _proto.isFocused = function isFocused() { if (typeof this.focused === 'boolean') { return this.focused; } // document global can be unavailable in react native if (typeof document === 'undefined') { return true; } return [undefined, 'visible', 'prerender'].includes(document.visibilityState); }; _proto.setDefaultEventListener = function setDefaultEventListener() { var _window; if (!isServer && ((_window = window) == null ? void 0 : _window.addEventListener)) { this.setEventListener(function (onFocus) { var listener = function listener() { return onFocus(); }; // Listen to visibillitychange and focus window.addEventListener('visibilitychange', listener, false); window.addEventListener('focus', listener, false); return function () { // Be sure to unsubscribe if a new handler is set window.removeEventListener('visibilitychange', listener); window.removeEventListener('focus', listener); }; }); } }; return FocusManager; }(Subscribable); var focusManager = new FocusManager(); var OnlineManager = /*#__PURE__*/function (_Subscribable) { _inheritsLoose(OnlineManager, _Subscribable); function OnlineManager() { return _Subscribable.apply(this, arguments) || this; } var _proto = OnlineManager.prototype; _proto.onSubscribe = function onSubscribe() { if (!this.removeEventListener) { this.setDefaultEventListener(); } }; _proto.setEventListener = function setEventListener(setup) { var _this = this; if (this.removeEventListener) { this.removeEventListener(); } this.removeEventListener = setup(function (online) { if (typeof online === 'boolean') { _this.setOnline(online); } else { _this.onOnline(); } }); }; _proto.setOnline = function setOnline(online) { this.online = online; if (online) { this.onOnline(); } }; _proto.onOnline = function onOnline() { this.listeners.forEach(function (listener) { listener(); }); }; _proto.isOnline = function isOnline() { if (typeof this.online === 'boolean') { return this.online; } if (typeof navigator === 'undefined' || typeof navigator.onLine === 'undefined') { return true; } return navigator.onLine; }; _proto.setDefaultEventListener = function setDefaultEventListener() { var _window; if (!isServer && ((_window = window) == null ? void 0 : _window.addEventListener)) { this.setEventListener(function (onOnline) { var listener = function listener() { return onOnline(); }; // Listen to online window.addEventListener('online', listener, false); window.addEventListener('offline', listener, false); return function () { // Be sure to unsubscribe if a new handler is set window.removeEventListener('online', listener); window.removeEventListener('offline', listener); }; }); } }; return OnlineManager; }(Subscribable); var onlineManager = new OnlineManager(); function defaultRetryDelay(failureCount) { return Math.min(1000 * Math.pow(2, failureCount), 30000); } function isCancelable(value) { return typeof (value == null ? void 0 : value.cancel) === 'function'; } var CancelledError = function CancelledError(options) { this.revert = options == null ? void 0 : options.revert; this.silent = options == null ? void 0 : options.silent; }; function isCancelledError(value) { return value instanceof CancelledError; } // CLASS var Retryer = function Retryer(config) { var _this = this; var cancelRetry = false; var cancelFn; var continueFn; var promiseResolve; var promiseReject; this.cancel = function (cancelOptions) { return cancelFn == null ? void 0 : cancelFn(cancelOptions); }; this.cancelRetry = function () { cancelRetry = true; }; this.continue = function () { return continueFn == null ? void 0 : continueFn(); }; this.failureCount = 0; this.isPaused = false; this.isResolved = false; this.isTransportCancelable = false; this.promise = new Promise(function (outerResolve, outerReject) { promiseResolve = outerResolve; promiseReject = outerReject; }); var resolve = function resolve(value) { if (!_this.isResolved) { _this.isResolved = true; config.onSuccess == null ? void 0 : config.onSuccess(value); continueFn == null ? void 0 : continueFn(); promiseResolve(value); } }; var reject = function reject(value) { if (!_this.isResolved) { _this.isResolved = true; config.onError == null ? void 0 : config.onError(value); continueFn == null ? void 0 : continueFn(); promiseReject(value); } }; var pause = function pause() { return new Promise(function (continueResolve) { continueFn = continueResolve; _this.isPaused = true; config.onPause == null ? void 0 : config.onPause(); }).then(function () { continueFn = undefined; _this.isPaused = false; config.onContinue == null ? void 0 : config.onContinue(); }); }; // Create loop function var run = function run() { // Do nothing if already resolved if (_this.isResolved) { return; } var promiseOrValue; // Execute query try { promiseOrValue = config.fn(); } catch (error) { promiseOrValue = Promise.reject(error); } // Create callback to cancel this fetch cancelFn = function cancelFn(cancelOptions) { if (!_this.isResolved) { reject(new CancelledError(cancelOptions)); // Cancel transport if supported if (isCancelable(promiseOrValue)) { try { promiseOrValue.cancel(); } catch (_unused) {} } } }; // Check if the transport layer support cancellation _this.isTransportCancelable = isCancelable(promiseOrValue); Promise.resolve(promiseOrValue).then(resolve).catch(function (error) { var _config$retry, _config$retryDelay; // Stop if the fetch is already resolved if (_this.isResolved) { return; } // Do we need to retry the request? var retry = (_config$retry = config.retry) != null ? _config$retry : 3; var retryDelay = (_config$retryDelay = config.retryDelay) != null ? _config$retryDelay : defaultRetryDelay; var delay = typeof retryDelay === 'function' ? retryDelay(_this.failureCount, error) : retryDelay; var shouldRetry = retry === true || typeof retry === 'number' && _this.failureCount < retry || typeof retry === 'function' && retry(_this.failureCount, error); if (cancelRetry || !shouldRetry) { // We are done if the query does not need to be retried reject(error); return; } _this.failureCount++; // Notify on fail config.onFail == null ? void 0 : config.onFail(_this.failureCount, error); // Delay sleep(delay) // Pause if the document is not visible or when the device is offline .then(function () { if (!focusManager.isFocused() || !onlineManager.isOnline()) { return pause(); } }).then(function () { if (cancelRetry) { reject(error); } else { run(); } }); }); }; // Start loop run(); }; // CLASS var NotifyManager = /*#__PURE__*/function () { function NotifyManager() { this.queue = []; this.transactions = 0; this.notifyFn = function (callback) { callback(); }; this.batchNotifyFn = function (callback) { callback(); }; } var _proto = NotifyManager.prototype; _proto.batch = function batch(callback) { this.transactions++; var result = callback(); this.transactions--; if (!this.transactions) { this.flush(); } return result; }; _proto.schedule = function schedule(callback) { var _this = this; if (this.transactions) { this.queue.push(callback); } else { scheduleMicrotask(function () { _this.notifyFn(callback); }); } } /** * All calls to the wrapped function will be batched. */ ; _proto.batchCalls = function batchCalls(callback) { var _this2 = this; return function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this2.schedule(function () { callback.apply(void 0, args); }); }; }; _proto.flush = function flush() { var _this3 = this; var queue = this.queue; this.queue = []; if (queue.length) { scheduleMicrotask(function () { _this3.batchNotifyFn(function () { queue.forEach(function (callback) { _this3.notifyFn(callback); }); }); }); } } /** * Use this method to set a custom notify function. * This can be used to for example wrap notifications with `React.act` while running tests. */ ; _proto.setNotifyFunction = function setNotifyFunction(fn) { this.notifyFn = fn; } /** * Use this method to set a custom function to batch notifications together into a single tick. * By default React Query will use the batch function provided by ReactDOM or React Native. */ ; _proto.setBatchNotifyFunction = function setBatchNotifyFunction(fn) { this.batchNotifyFn = fn; }; return NotifyManager; }(); // SINGLETON var notifyManager = new NotifyManager(); // FUNCTIONS var logger = console || { error: noop, warn: noop, log: noop }; function getLogger() { return logger; } function setLogger(newLogger) { logger = newLogger; } // CLASS var Query = /*#__PURE__*/function () { function Query(config) { this.defaultOptions = config.defaultOptions; this.setOptions(config.options); this.observers = []; this.cache = config.cache; this.queryKey = config.queryKey; this.queryHash = config.queryHash; this.initialState = config.state || this.getDefaultState(this.options); this.state = this.initialState; this.scheduleGc(); } var _proto = Query.prototype; _proto.setOptions = function setOptions(options) { var _this$options$cacheTi; this.options = _extends({}, this.defaultOptions, options); // Default to 5 minutes if not cache time is set this.cacheTime = Math.max(this.cacheTime || 0, (_this$options$cacheTi = this.options.cacheTime) != null ? _this$options$cacheTi : 5 * 60 * 1000); }; _proto.setDefaultOptions = function setDefaultOptions(options) { this.defaultOptions = options; }; _proto.scheduleGc = function scheduleGc() { var _this = this; this.clearGcTimeout(); if (isValidTimeout(this.cacheTime)) { this.gcTimeout = setTimeout(function () { _this.optionalRemove(); }, this.cacheTime); } }; _proto.clearGcTimeout = function clearGcTimeout() { clearTimeout(this.gcTimeout); this.gcTimeout = undefined; }; _proto.optionalRemove = function optionalRemove() { if (!this.observers.length && !this.state.isFetching) { this.cache.remove(this); } }; _proto.setData = function setData(updater, options) { var _this$options$isDataE, _this$options; var prevData = this.state.data; // Get the new data var data = functionalUpdate(updater, prevData); // Use prev data if an isDataEqual function is defined and returns `true` if ((_this$options$isDataE = (_this$options = this.options).isDataEqual) == null ? void 0 : _this$options$isDataE.call(_this$options, prevData, data)) { data = prevData; } else if (this.options.structuralSharing !== false) { // Structurally share data between prev and new data if needed data = replaceEqualDeep(prevData, data); } // Set data and mark it as cached this.dispatch({ data: data, type: 'success', dataUpdatedAt: options == null ? void 0 : options.updatedAt }); return data; }; _proto.setState = function setState(state, setStateOptions) { this.dispatch({ type: 'setState', state: state, setStateOptions: setStateOptions }); }; _proto.cancel = function cancel(options) { var _this$retryer; var promise = this.promise; (_this$retryer = this.retryer) == null ? void 0 : _this$retryer.cancel(options); return promise ? promise.then(noop).catch(noop) : Promise.resolve(); }; _proto.destroy = function destroy() { this.clearGcTimeout(); this.cancel({ silent: true }); }; _proto.reset = function reset() { this.destroy(); this.setState(this.initialState); }; _proto.isActive = function isActive() { return this.observers.some(function (observer) { return observer.options.enabled !== false; }); }; _proto.isFetching = function isFetching() { return this.state.isFetching; }; _proto.isStale = function isStale() { return this.state.isInvalidated || !this.state.dataUpdatedAt || this.observers.some(function (observer) { return observer.getCurrentResult().isStale; }); }; _proto.isStaleByTime = function isStaleByTime(staleTime) { if (staleTime === void 0) { staleTime = 0; } return this.state.isInvalidated || !this.state.dataUpdatedAt || !timeUntilStale(this.state.dataUpdatedAt, staleTime); }; _proto.onFocus = function onFocus() { var _this$retryer2; var observer = this.observers.find(function (x) { return x.shouldFetchOnWindowFocus(); }); if (observer) { observer.refetch(); } // Continue fetch if currently paused (_this$retryer2 = this.retryer) == null ? void 0 : _this$retryer2.continue(); }; _proto.onOnline = function onOnline() { var _this$retryer3; var observer = this.observers.find(function (x) { return x.shouldFetchOnReconnect(); }); if (observer) { observer.refetch(); } // Continue fetch if currently paused (_this$retryer3 = this.retryer) == null ? void 0 : _this$retryer3.continue(); }; _proto.addObserver = function addObserver(observer) { if (this.observers.indexOf(observer) === -1) { this.observers.push(observer); // Stop the query from being garbage collected this.clearGcTimeout(); this.cache.notify({ type: 'observerAdded', query: this, observer: observer }); } }; _proto.removeObserver = function removeObserver(observer) { if (this.observers.indexOf(observer) !== -1) { this.observers = this.observers.filter(function (x) { return x !== observer; }); if (!this.observers.length) { // If the transport layer does not support cancellation // we'll let the query continue so the result can be cached if (this.retryer) { if (this.retryer.isTransportCancelable) { this.retryer.cancel({ revert: true }); } else { this.retryer.cancelRetry(); } } if (this.cacheTime) { this.scheduleGc(); } else { this.cache.remove(this); } } this.cache.notify({ type: 'observerRemoved', query: this, observer: observer }); } }; _proto.getObserversCount = function getObserversCount() { return this.observers.length; }; _proto.invalidate = function invalidate() { if (!this.state.isInvalidated) { this.dispatch({ type: 'invalidate' }); } }; _proto.fetch = function fetch(options, fetchOptions) { var _this2 = this, _this$options$behavio, _context$fetchOptions; if (this.state.isFetching) { if (this.state.dataUpdatedAt && (fetchOptions == null ? void 0 : fetchOptions.cancelRefetch)) { // Silently cancel current fetch if the user wants to cancel refetches this.cancel({ silent: true }); } else if (this.promise) { // Return current promise if we are already fetching return this.promise; } } // Update config if passed, otherwise the config from the last execution is used if (options) { this.setOptions(options); } // Use the options from the first observer with a query function if no function is found. // This can happen when the query is hydrated or created with setQueryData. if (!this.options.queryFn) { var observer = this.observers.find(function (x) { return x.options.queryFn; }); if (observer) { this.setOptions(observer.options); } } var queryKey = ensureQueryKeyArray(this.queryKey); // Create query function context var queryFnContext = { queryKey: queryKey, pageParam: undefined }; // Create fetch function var fetchFn = function fetchFn() { return _this2.options.queryFn ? _this2.options.queryFn(queryFnContext) : Promise.reject('Missing queryFn'); }; // Trigger behavior hook var context = { fetchOptions: fetchOptions, options: this.options, queryKey: queryKey, state: this.state, fetchFn: fetchFn }; if ((_this$options$behavio = this.options.behavior) == null ? void 0 : _this$options$behavio.onFetch) { var _this$options$behavio2; (_this$options$behavio2 = this.options.behavior) == null ? void 0 : _this$options$behavio2.onFetch(context); } // Store state in case the current fetch needs to be reverted this.revertState = this.state; // Set to fetching state if not already in it if (!this.state.isFetching || this.state.fetchMeta !== ((_context$fetchOptions = context.fetchOptions) == null ? void 0 : _context$fetchOptions.meta)) { var _context$fetchOptions2; this.dispatch({ type: 'fetch', meta: (_context$fetchOptions2 = context.fetchOptions) == null ? void 0 : _context$fetchOptions2.meta }); } // Try to fetch the data this.retryer = new Retryer({ fn: context.fetchFn, onSuccess: function onSuccess(data) { _this2.setData(data); // Notify cache callback _this2.cache.config.onSuccess == null ? void 0 : _this2.cache.config.onSuccess(data, _this2); // Remove query after fetching if cache time is 0 if (_this2.cacheTime === 0) { _this2.optionalRemove(); } }, onError: function onError(error) { // Optimistically update state if needed if (!(isCancelledError(error) && error.silent)) { _this2.dispatch({ type: 'error', error: error }); } if (!isCancelledError(error)) { // Notify cache callback _this2.cache.config.onError == null ? void 0 : _this2.cache.config.onError(error, _this2); // Log error getLogger().error(error); } // Remove query after fetching if cache time is 0 if (_this2.cacheTime === 0) { _this2.optionalRemove(); } }, onFail: function onFail() { _this2.dispatch({ type: 'failed' }); }, onPause: function onPause() { _this2.dispatch({ type: 'pause' }); }, onContinue: function onContinue() { _this2.dispatch({ type: 'continue' }); }, retry: context.options.retry, retryDelay: context.options.retryDelay }); this.promise = this.retryer.promise; return this.promise; }; _proto.dispatch = function dispatch(action) { var _this3 = this; this.state = this.reducer(this.state, action); notifyManager.batch(function () { _this3.observers.forEach(function (observer) { observer.onQueryUpdate(action); }); _this3.cache.notify({ query: _this3, type: 'queryUpdated', action: action }); }); }; _proto.getDefaultState = function getDefaultState(options) { var data = typeof options.initialData === 'function' ? options.initialData() : options.initialData; var hasInitialData = typeof options.initialData !== 'undefined'; var initialDataUpdatedAt = hasInitialData ? typeof options.initialDataUpdatedAt === 'function' ? options.initialDataUpdatedAt() : options.initialDataUpdatedAt : 0; var hasData = typeof data !== 'undefined'; return { data: data, dataUpdateCount: 0, dataUpdatedAt: hasData ? initialDataUpdatedAt != null ? initialDataUpdatedAt : Date.now() : 0, error: null, errorUpdateCount: 0, errorUpdatedAt: 0, fetchFailureCount: 0, fetchMeta: null, isFetching: false, isInvalidated: false, isPaused: false, status: hasData ? 'success' : 'idle' }; }; _proto.reducer = function reducer(state, action) { var _action$meta, _action$dataUpdatedAt; switch (action.type) { case 'failed': return _extends({}, state, { fetchFailureCount: state.fetchFailureCount + 1 }); case 'pause': return _extends({}, state, { isPaused: true }); case 'continue': return _extends({}, state, { isPaused: false }); case 'fetch': return _extends({}, state, { fetchFailureCount: 0, fetchMeta: (_action$meta = action.meta) != null ? _action$meta : null, isFetching: true, isPaused: false, status: !state.dataUpdatedAt ? 'loading' : state.status }); case 'success': return _extends({}, state, { data: action.data, dataUpdateCount: state.dataUpdateCount + 1, dataUpdatedAt: (_action$dataUpdatedAt = action.dataUpdatedAt) != null ? _action$dataUpdatedAt : Date.now(), error: null, fetchFailureCount: 0, isFetching: false, isInvalidated: false, isPaused: false, status: 'success' }); case 'error': var error = action.error; if (isCancelledError(error) && error.revert && this.revertState) { return _extends({}, this.revertState); } return _extends({}, state, { error: error, errorUpdateCount: state.errorUpdateCount + 1, errorUpdatedAt: Date.now(), fetchFailureCount: state.fetchFailureCount + 1, isFetching: false, isPaused: false, status: 'error' }); case 'invalidate': return _extends({}, state, { isInvalidated: true }); case 'setState': return _extends({}, state, action.state); default: return state; } }; return Query; }(); // CLASS var QueryCache = /*#__PURE__*/function (_Subscribable) { _inheritsLoose(QueryCache, _Subscribable); function QueryCache(config) { var _this; _this = _Subscribable.call(this) || this; _this.config = config || {}; _this.queries = []; _this.queriesMap = {}; return _this; } var _proto = QueryCache.prototype; _proto.build = function build(client, options, state) { var _options$queryHash; var queryKey = options.queryKey; var queryHash = (_options$queryHash = options.queryHash) != null ? _options$queryHash : hashQueryKeyByOptions(queryKey, options); var query = this.get(queryHash); if (!query) { query = new Query({ cache: this, queryKey: queryKey, queryHash: queryHash, options: client.defaultQueryOptions(options), state: state, defaultOptions: client.getQueryDefaults(queryKey) }); this.add(query); } return query; }; _proto.add = function add(query) { if (!this.queriesMap[query.queryHash]) { this.queriesMap[query.queryHash] = query; this.queries.push(query); this.notify({ type: 'queryAdded', query: query }); } }; _proto.remove = function remove(query) { var queryInMap = this.queriesMap[query.queryHash]; if (queryInMap) { query.destroy(); this.queries = this.queries.filter(function (x) { return x !== query; }); if (queryInMap === query) { delete this.queriesMap[query.queryHash]; } this.notify({ type: 'queryRemoved', query: query }); } }; _proto.clear = function clear() { var _this2 = this; notifyManager.batch(function () { _this2.queries.forEach(function (query) { _this2.remove(query); }); }); }; _proto.get = function get(queryHash) { return this.queriesMap[queryHash]; }; _proto.getAll = function getAll() { return this.queries; }; _proto.find = function find(arg1, arg2) { var _parseFilterArgs = parseFilterArgs(arg1, arg2), filters = _parseFilterArgs[0]; if (typeof filters.exact === 'undefined') { filters.exact = true; } return this.queries.find(function (query) { return matchQuery(filters, query); }); }; _proto.findAll = function findAll(arg1, arg2) { var _parseFilterArgs2 = parseFilterArgs(arg1, arg2), filters = _parseFilterArgs2[0]; return filters ? this.queries.filter(function (query) { return matchQuery(filters, query); }) : this.queries; }; _proto.notify = function notify(event) { var _this3 = this; notifyManager.batch(function () { _this3.listeners.forEach(function (listener) { listener(event); }); }); }; _proto.onFocus = function onFocus() { var _this4 = this; notifyManager.batch(function () { _this4.queries.forEach(function (query) { query.onFocus(); }); }); }; _proto.onOnline = function onOnline() { var _this5 = this; notifyManager.batch(function () { _this5.queries.forEach(function (query) { query.onOnline(); }); }); }; return QueryCache; }(Subscribable); // CLASS var Mutation = /*#__PURE__*/function () { function Mutation(config) { this.options = _extends({}, config.defaultOptions, config.options); this.mutationId = config.mutationId; this.mutationCache = config.mutationCache; this.observers = []; this.state = config.state || getDefaultState(); } var _proto = Mutation.prototype; _proto.setState = function setState(state) { this.dispatch({ type: 'setState', state: state }); }; _proto.addObserver = function addObserver(observer) { if (this.observers.indexOf(observer) === -1) { this.observers.push(observer); } }; _proto.removeObserver = function removeObserver(observer) { this.observers = this.observers.filter(function (x) { return x !== observer; }); }; _proto.cancel = function cancel() { if (this.retryer) { this.retryer.cancel(); return this.retryer.promise.then(noop).catch(noop); } return Promise.resolve(); }; _proto.continue = function _continue() { if (this.retryer) { this.retryer.continue(); return this.retryer.promise; } return this.execute(); }; _proto.execute = function execute() { var _this = this; var data; var restored = this.state.status === 'loading'; var promise = Promise.resolve(); if (!restored) { this.dispatch({ type: 'loading', variables: this.options.variables }); promise = promise.then(function () { return _this.options.onMutate == null ? void 0 : _this.options.onMutate(_this.state.variables); }).then(function (context) { if (context !== _this.state.context) { _this.dispatch({ type: 'loading', context: context, variables: _this.state.variables }); } }); } return promise.then(function () { return _this.executeMutation(); }).then(function (result) { data = result; // Notify cache callback _this.mutationCache.config.onSuccess == null ? void 0 : _this.mutationCache.config.onSuccess(data, _this.state.variables, _this.state.context, _this); }).then(function () { return _this.options.onSuccess == null ? void 0 : _this.options.onSuccess(data, _this.state.variables, _this.state.context); }).then(function () { return _this.options.onSettled == null ? void 0 : _this.options.onSettled(data, null, _this.state.variables, _this.state.context); }).then(function () { _this.dispatch({ type: 'success', data: data }); return data; }).catch(function (error) { // Notify cache callback _this.mutationCache.config.onError == null ? void 0 : _this.mutationCache.config.onError(error, _this.state.variables, _this.state.context, _this); // Log error getLogger().error(error); return Promise.resolve().then(function () { return _this.options.onError == null ? void 0 : _this.options.onError(error, _this.state.variables, _this.state.context); }).then(function () { return _this.options.onSettled == null ? void 0 : _this.options.onSettled(undefined, error, _this.state.variables, _this.state.context); }).then(function () { _this.dispatch({ type: 'error', error: error }); throw error; }); }); }; _proto.executeMutation = function executeMutation() { var _this2 = this, _this$options$retry; this.retryer = new Retryer({ fn: function fn() { if (!_this2.options.mutationFn) { return Promise.reject('No mutationFn found'); } return _this2.options.mutationFn(_this2.state.variables); }, onFail: function onFail() { _this2.dispatch({ type: 'failed' }); }, onPause: function onPause() { _this2.dispatch({ type: 'pause' }); }, onContinue: function onContinue() { _this2.dispatch({ type: 'continue' }); }, retry: (_this$options$retry = this.options.retry) != null ? _this$options$retry : 0, retryDelay: this.options.retryDelay }); return this.retryer.promise; }; _proto.dispatch = function dispatch(action) { var _this3 = this; this.state = reducer(this.state, action); notifyManager.batch(function () { _this3.observers.forEach(function (observer) { observer.onMutationUpdate(action); }); _this3.mutationCache.notify(_this3); }); }; return Mutation; }(); function getDefaultState() { return { context: undefined, data: undefined, error: null, failureCount: 0, isPaused: false, status: 'idle', variables: undefined }; } function reducer(state, action) { switch (action.type) { case 'failed': return _extends({}, state, { failureCount: state.failureCount + 1 }); case 'pause': return _extends({}, state, { isPaused: true }); case 'continue': return _extends({}, state, { isPaused: false }); case 'loading': return _extends({}, state, { context: action.context, data: undefined, error: null, isPaused: false, status: 'loading', variables: action.variables }); case 'success': return _extends({}, state, { data: action.data, error: null, status: 'success', isPaused: false }); case 'error': return _extends({}, state, { data: undefined, error: action.error, failureCount: state.failureCount + 1, isPaused: false, status: 'error' }); case 'setState': return _extends({}, state, action.state); default: return state; } } // CLASS var MutationCache = /*#__PURE__*/function (_Subscribable) { _inheritsLoose(MutationCache, _Subscribable); function MutationCache(config) { var _this; _this = _Subscribable.call(this) || this; _this.config = config || {}; _this.mutations = []; _this.mutationId = 0; return _this; } var _proto = MutationCache.prototype; _proto.build = function build(client, options, state) { var mutation = new Mutation({ mutationCache: this, mutationId: ++this.mutationId, options: client.defaultMutationOptions(options), state: state, defaultOptions: options.mutationKey ? client.getMutationDefaults(options.mutationKey) : undefined }); this.add(mutation); return mutation; }; _proto.add = function add(mutation) { this.mutations.push(mutation); this.notify(mutation); }; _proto.remove = function remove(mutation) { this.mutations = this.mutations.filter(function (x) { return x !== mutation; }); mutation.cancel(); this.notify(mutation); }; _proto.clear = function clear() { var _this2 = this; notifyManager.batch(function () { _this2.mutations.forEach(function (mutation) { _this2.remove(mutation); }); }); }; _proto.getAll = function getAll() { return this.mutations; }; _proto.find = function find(filters) { if (typeof filters.exact === 'undefined') { filters.exact = true; } return this.mutations.find(function (mutation) { return matchMutation(filters, mutation); }); }; _proto.findAll = function findAll(filters) { return this.mutations.filter(function (mutation) { return matchMutation(filters, mutation); }); }; _proto.notify = function notify(mutation) { var _this3 = this; notifyManager.batch(function () { _this3.listeners.forEach(function (listener) { listener(mutation); }); }); }; _proto.onFocus = function onFocus() { this.resumePausedMutations(); }; _proto.onOnline = function onOnline() { this.resumePausedMutations(); }; _proto.resumePausedMutations = function resumePausedMutations() { var pausedMutations = this.mutations.filter(function (x) { return x.state.isPaused; }); return notifyManager.batch(function () { return pausedMutations.reduce(function (promise, mutation) { return promise.then(function () { return mutation.continue().catch(noop); }); }, Promise.resolve()); }); }; return MutationCache; }(Subscribable); function infiniteQueryBehavior() { return { onFetch: function onFetch(context) { context.fetchFn = function () { var _context$fetchOptions, _context$fetchOptions2, _context$fetchOptions3, _context$fetchOptions4, _context$state$data, _context$state$data2; var refetchPage = (_context$fetchOptions = context.fetchOptions) == null ? void 0 : (_context$fetchOptions2 = _context$fetchOptions.meta) == null ? void 0 : _context$fetchOptions2.refetchPage; var fetchMore = (_context$fetchOptions3 = context.fetchOptions) == null ? void 0 : (_context$fetchOptions4 = _context$fetchOptions3.meta) == null ? void 0 : _context$fetchOptions4.fetchMore; var pageParam = fetchMore == null ? void 0 : fetchMore.pageParam; var isFetchingNextPage = (fetchMore == null ? void 0 : fetchMore.direction) === 'forward'; var isFetchingPreviousPage = (fetchMore == null ? void 0 : fetchMore.direction) === 'backward'; var oldPages = ((_context$state$data = context.state.data) == null ? void 0 : _context$state$data.pages) || []; var oldPageParams = ((_context$state$data2 = context.state.data) == null ? void 0 : _context$state$data2.pageParams) || []; var newPageParams = oldPageParams; var cancelled = false; // Get query function var queryFn = context.options.queryFn || function () { return Promise.reject('Missing queryFn'); }; var buildNewPages = function buildNewPages(pages, param, page, previous) { newPageParams = previous ? [param].concat(newPageParams) : [].concat(newPageParams, [param]); return previous ? [page].concat(pages) : [].concat(pages, [page]); }; // Create function to fetch a page var fetchPage = function fetchPage(pages, manual, param, previous) { if (cancelled) { return Promise.reject('Cancelled'); } if (typeof param === 'undefined' && !manual && pages.length) { return Promise.resolve(pages); } var queryFnContext = { queryKey: context.queryKey, pageParam: param }; var queryFnResult = queryFn(queryFnContext); var promise = Promise.resolve(queryFnResult).then(function (page) { return buildNewPages(pages, param, page, previous); }); if (isCancelable(queryFnResult)) { var promiseAsAny = promise; promiseAsAny.cancel = queryFnResult.cancel; } return promise; }; var promise; // Fetch first page? if (!oldPages.length) { promise = fetchPage([]); } // Fetch next page? else if (isFetchingNextPage) { var manual = typeof pageParam !== 'undefined'; var param = manual ? pagePara