redux-persist.js 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (factory((global.ReduxPersist = {})));
  5. }(this, (function (exports) { 'use strict';
  6. function _typeof(obj) {
  7. if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
  8. _typeof = function (obj) {
  9. return typeof obj;
  10. };
  11. } else {
  12. _typeof = function (obj) {
  13. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  14. };
  15. }
  16. return _typeof(obj);
  17. }
  18. function _defineProperty(obj, key, value) {
  19. if (key in obj) {
  20. Object.defineProperty(obj, key, {
  21. value: value,
  22. enumerable: true,
  23. configurable: true,
  24. writable: true
  25. });
  26. } else {
  27. obj[key] = value;
  28. }
  29. return obj;
  30. }
  31. function ownKeys(object, enumerableOnly) {
  32. var keys = Object.keys(object);
  33. if (Object.getOwnPropertySymbols) {
  34. var symbols = Object.getOwnPropertySymbols(object);
  35. if (enumerableOnly) symbols = symbols.filter(function (sym) {
  36. return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  37. });
  38. keys.push.apply(keys, symbols);
  39. }
  40. return keys;
  41. }
  42. function _objectSpread2(target) {
  43. for (var i = 1; i < arguments.length; i++) {
  44. var source = arguments[i] != null ? arguments[i] : {};
  45. if (i % 2) {
  46. ownKeys(source, true).forEach(function (key) {
  47. _defineProperty(target, key, source[key]);
  48. });
  49. } else if (Object.getOwnPropertyDescriptors) {
  50. Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
  51. } else {
  52. ownKeys(source).forEach(function (key) {
  53. Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
  54. });
  55. }
  56. }
  57. return target;
  58. }
  59. function _objectWithoutPropertiesLoose(source, excluded) {
  60. if (source == null) return {};
  61. var target = {};
  62. var sourceKeys = Object.keys(source);
  63. var key, i;
  64. for (i = 0; i < sourceKeys.length; i++) {
  65. key = sourceKeys[i];
  66. if (excluded.indexOf(key) >= 0) continue;
  67. target[key] = source[key];
  68. }
  69. return target;
  70. }
  71. function _objectWithoutProperties(source, excluded) {
  72. if (source == null) return {};
  73. var target = _objectWithoutPropertiesLoose(source, excluded);
  74. var key, i;
  75. if (Object.getOwnPropertySymbols) {
  76. var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
  77. for (i = 0; i < sourceSymbolKeys.length; i++) {
  78. key = sourceSymbolKeys[i];
  79. if (excluded.indexOf(key) >= 0) continue;
  80. if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
  81. target[key] = source[key];
  82. }
  83. }
  84. return target;
  85. }
  86. function _toConsumableArray(arr) {
  87. return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
  88. }
  89. function _arrayWithoutHoles(arr) {
  90. if (Array.isArray(arr)) {
  91. for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
  92. return arr2;
  93. }
  94. }
  95. function _iterableToArray(iter) {
  96. if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
  97. }
  98. function _nonIterableSpread() {
  99. throw new TypeError("Invalid attempt to spread non-iterable instance");
  100. }
  101. var KEY_PREFIX = 'persist:';
  102. var FLUSH = 'persist/FLUSH';
  103. var REHYDRATE = 'persist/REHYDRATE';
  104. var PAUSE = 'persist/PAUSE';
  105. var PERSIST = 'persist/PERSIST';
  106. var PURGE = 'persist/PURGE';
  107. var REGISTER = 'persist/REGISTER';
  108. var DEFAULT_VERSION = -1;
  109. /*
  110. autoMergeLevel1:
  111. - merges 1 level of substate
  112. - skips substate if already modified
  113. */
  114. function autoMergeLevel1(inboundState, originalState, reducedState, _ref) {
  115. var debug = _ref.debug;
  116. var newState = _objectSpread2({}, reducedState); // only rehydrate if inboundState exists and is an object
  117. if (inboundState && _typeof(inboundState) === 'object') {
  118. Object.keys(inboundState).forEach(function (key) {
  119. // ignore _persist data
  120. if (key === '_persist') return; // if reducer modifies substate, skip auto rehydration
  121. if (originalState[key] !== reducedState[key]) {
  122. if ("development" !== 'production' && debug) console.log('redux-persist/stateReconciler: sub state for key `%s` modified, skipping.', key);
  123. return;
  124. } // otherwise hard set the new value
  125. newState[key] = inboundState[key];
  126. });
  127. }
  128. if ("development" !== 'production' && debug && inboundState && _typeof(inboundState) === 'object') console.log("redux-persist/stateReconciler: rehydrated keys '".concat(Object.keys(inboundState).join(', '), "'"));
  129. return newState;
  130. }
  131. // @TODO remove once flow < 0.63 support is no longer required.
  132. function createPersistoid(config) {
  133. // defaults
  134. var blacklist = config.blacklist || null;
  135. var whitelist = config.whitelist || null;
  136. var transforms = config.transforms || [];
  137. var throttle = config.throttle || 0;
  138. var storageKey = "".concat(config.keyPrefix !== undefined ? config.keyPrefix : KEY_PREFIX).concat(config.key);
  139. var storage = config.storage;
  140. var serialize;
  141. if (config.serialize === false) {
  142. serialize = function serialize(x) {
  143. return x;
  144. };
  145. } else if (typeof config.serialize === 'function') {
  146. serialize = config.serialize;
  147. } else {
  148. serialize = defaultSerialize;
  149. }
  150. var writeFailHandler = config.writeFailHandler || null; // initialize stateful values
  151. var lastState = {};
  152. var stagedState = {};
  153. var keysToProcess = [];
  154. var timeIterator = null;
  155. var writePromise = null;
  156. var update = function update(state) {
  157. // add any changed keys to the queue
  158. Object.keys(state).forEach(function (key) {
  159. if (!passWhitelistBlacklist(key)) return; // is keyspace ignored? noop
  160. if (lastState[key] === state[key]) return; // value unchanged? noop
  161. if (keysToProcess.indexOf(key) !== -1) return; // is key already queued? noop
  162. keysToProcess.push(key); // add key to queue
  163. }); //if any key is missing in the new state which was present in the lastState,
  164. //add it for processing too
  165. Object.keys(lastState).forEach(function (key) {
  166. if (state[key] === undefined && passWhitelistBlacklist(key) && keysToProcess.indexOf(key) === -1 && lastState[key] !== undefined) {
  167. keysToProcess.push(key);
  168. }
  169. }); // start the time iterator if not running (read: throttle)
  170. if (timeIterator === null) {
  171. timeIterator = setInterval(processNextKey, throttle);
  172. }
  173. lastState = state;
  174. };
  175. function processNextKey() {
  176. if (keysToProcess.length === 0) {
  177. if (timeIterator) clearInterval(timeIterator);
  178. timeIterator = null;
  179. return;
  180. }
  181. var key = keysToProcess.shift();
  182. var endState = transforms.reduce(function (subState, transformer) {
  183. return transformer.in(subState, key, lastState);
  184. }, lastState[key]);
  185. if (endState !== undefined) {
  186. try {
  187. stagedState[key] = serialize(endState);
  188. } catch (err) {
  189. console.error('redux-persist/createPersistoid: error serializing state', err);
  190. }
  191. } else {
  192. //if the endState is undefined, no need to persist the existing serialized content
  193. delete stagedState[key];
  194. }
  195. if (keysToProcess.length === 0) {
  196. writeStagedState();
  197. }
  198. }
  199. function writeStagedState() {
  200. // cleanup any removed keys just before write.
  201. Object.keys(stagedState).forEach(function (key) {
  202. if (lastState[key] === undefined) {
  203. delete stagedState[key];
  204. }
  205. });
  206. writePromise = storage.setItem(storageKey, serialize(stagedState)).catch(onWriteFail);
  207. }
  208. function passWhitelistBlacklist(key) {
  209. if (whitelist && whitelist.indexOf(key) === -1 && key !== '_persist') return false;
  210. if (blacklist && blacklist.indexOf(key) !== -1) return false;
  211. return true;
  212. }
  213. function onWriteFail(err) {
  214. // @TODO add fail handlers (typically storage full)
  215. if (writeFailHandler) writeFailHandler(err);
  216. if (err && "development" !== 'production') {
  217. console.error('Error storing data', err);
  218. }
  219. }
  220. var flush = function flush() {
  221. while (keysToProcess.length !== 0) {
  222. processNextKey();
  223. }
  224. return writePromise || Promise.resolve();
  225. }; // return `persistoid`
  226. return {
  227. update: update,
  228. flush: flush
  229. };
  230. } // @NOTE in the future this may be exposed via config
  231. function defaultSerialize(data) {
  232. return JSON.stringify(data);
  233. }
  234. function getStoredState(config) {
  235. var transforms = config.transforms || [];
  236. var storageKey = "".concat(config.keyPrefix !== undefined ? config.keyPrefix : KEY_PREFIX).concat(config.key);
  237. var storage = config.storage;
  238. var debug = config.debug;
  239. var deserialize;
  240. if (config.deserialize === false) {
  241. deserialize = function deserialize(x) {
  242. return x;
  243. };
  244. } else if (typeof config.deserialize === 'function') {
  245. deserialize = config.deserialize;
  246. } else {
  247. deserialize = defaultDeserialize;
  248. }
  249. return storage.getItem(storageKey).then(function (serialized) {
  250. if (!serialized) return undefined;else {
  251. try {
  252. var state = {};
  253. var rawState = deserialize(serialized);
  254. Object.keys(rawState).forEach(function (key) {
  255. state[key] = transforms.reduceRight(function (subState, transformer) {
  256. return transformer.out(subState, key, rawState);
  257. }, deserialize(rawState[key]));
  258. });
  259. return state;
  260. } catch (err) {
  261. if ("development" !== 'production' && debug) console.log("redux-persist/getStoredState: Error restoring data ".concat(serialized), err);
  262. throw err;
  263. }
  264. }
  265. });
  266. }
  267. function defaultDeserialize(serial) {
  268. return JSON.parse(serial);
  269. }
  270. function purgeStoredState(config) {
  271. var storage = config.storage;
  272. var storageKey = "".concat(config.keyPrefix !== undefined ? config.keyPrefix : KEY_PREFIX).concat(config.key);
  273. return storage.removeItem(storageKey, warnIfRemoveError);
  274. }
  275. function warnIfRemoveError(err) {
  276. if (err && "development" !== 'production') {
  277. console.error('redux-persist/purgeStoredState: Error purging data stored state', err);
  278. }
  279. }
  280. var DEFAULT_TIMEOUT = 5000;
  281. /*
  282. @TODO add validation / handling for:
  283. - persisting a reducer which has nested _persist
  284. - handling actions that fire before reydrate is called
  285. */
  286. function persistReducer(config, baseReducer) {
  287. {
  288. if (!config) throw new Error('config is required for persistReducer');
  289. if (!config.key) throw new Error('key is required in persistor config');
  290. if (!config.storage) throw new Error("redux-persist: config.storage is required. Try using one of the provided storage engines `import storage from 'redux-persist/lib/storage'`");
  291. }
  292. var version = config.version !== undefined ? config.version : DEFAULT_VERSION;
  293. var debug = config.debug || false;
  294. var stateReconciler = config.stateReconciler === undefined ? autoMergeLevel1 : config.stateReconciler;
  295. var getStoredState$$1 = config.getStoredState || getStoredState;
  296. var timeout = config.timeout !== undefined ? config.timeout : DEFAULT_TIMEOUT;
  297. var _persistoid = null;
  298. var _purge = false;
  299. var _paused = true;
  300. var conditionalUpdate = function conditionalUpdate(state) {
  301. // update the persistoid only if we are rehydrated and not paused
  302. state._persist.rehydrated && _persistoid && !_paused && _persistoid.update(state);
  303. return state;
  304. };
  305. return function (state, action) {
  306. var _ref = state || {},
  307. _persist = _ref._persist,
  308. rest = _objectWithoutProperties(_ref, ["_persist"]); // $FlowIgnore need to update State type
  309. var restState = rest;
  310. if (action.type === PERSIST) {
  311. var _sealed = false;
  312. var _rehydrate = function _rehydrate(payload, err) {
  313. // dev warning if we are already sealed
  314. if ("development" !== 'production' && _sealed) console.error("redux-persist: rehydrate for \"".concat(config.key, "\" called after timeout."), payload, err); // only rehydrate if we are not already sealed
  315. if (!_sealed) {
  316. action.rehydrate(config.key, payload, err);
  317. _sealed = true;
  318. }
  319. };
  320. timeout && setTimeout(function () {
  321. !_sealed && _rehydrate(undefined, new Error("redux-persist: persist timed out for persist key \"".concat(config.key, "\"")));
  322. }, timeout); // @NOTE PERSIST resumes if paused.
  323. _paused = false; // @NOTE only ever create persistoid once, ensure we call it at least once, even if _persist has already been set
  324. if (!_persistoid) _persistoid = createPersistoid(config); // @NOTE PERSIST can be called multiple times, noop after the first
  325. if (_persist) {
  326. // We still need to call the base reducer because there might be nested
  327. // uses of persistReducer which need to be aware of the PERSIST action
  328. return _objectSpread2({}, baseReducer(restState, action), {
  329. _persist: _persist
  330. });
  331. }
  332. if (typeof action.rehydrate !== 'function' || typeof action.register !== 'function') throw new Error('redux-persist: either rehydrate or register is not a function on the PERSIST action. This can happen if the action is being replayed. This is an unexplored use case, please open an issue and we will figure out a resolution.');
  333. action.register(config.key);
  334. getStoredState$$1(config).then(function (restoredState) {
  335. var migrate = config.migrate || function (s, v) {
  336. return Promise.resolve(s);
  337. };
  338. migrate(restoredState, version).then(function (migratedState) {
  339. _rehydrate(migratedState);
  340. }, function (migrateErr) {
  341. if ("development" !== 'production' && migrateErr) console.error('redux-persist: migration error', migrateErr);
  342. _rehydrate(undefined, migrateErr);
  343. });
  344. }, function (err) {
  345. _rehydrate(undefined, err);
  346. });
  347. return _objectSpread2({}, baseReducer(restState, action), {
  348. _persist: {
  349. version: version,
  350. rehydrated: false
  351. }
  352. });
  353. } else if (action.type === PURGE) {
  354. _purge = true;
  355. action.result(purgeStoredState(config));
  356. return _objectSpread2({}, baseReducer(restState, action), {
  357. _persist: _persist
  358. });
  359. } else if (action.type === FLUSH) {
  360. action.result(_persistoid && _persistoid.flush());
  361. return _objectSpread2({}, baseReducer(restState, action), {
  362. _persist: _persist
  363. });
  364. } else if (action.type === PAUSE) {
  365. _paused = true;
  366. } else if (action.type === REHYDRATE) {
  367. // noop on restState if purging
  368. if (_purge) return _objectSpread2({}, restState, {
  369. _persist: _objectSpread2({}, _persist, {
  370. rehydrated: true
  371. }) // @NOTE if key does not match, will continue to default else below
  372. });
  373. if (action.key === config.key) {
  374. var reducedState = baseReducer(restState, action);
  375. var inboundState = action.payload; // only reconcile state if stateReconciler and inboundState are both defined
  376. var reconciledRest = stateReconciler !== false && inboundState !== undefined ? stateReconciler(inboundState, state, reducedState, config) : reducedState;
  377. var _newState = _objectSpread2({}, reconciledRest, {
  378. _persist: _objectSpread2({}, _persist, {
  379. rehydrated: true
  380. })
  381. });
  382. return conditionalUpdate(_newState);
  383. }
  384. } // if we have not already handled PERSIST, straight passthrough
  385. if (!_persist) return baseReducer(state, action); // run base reducer:
  386. // is state modified ? return original : return updated
  387. var newState = baseReducer(restState, action);
  388. if (newState === restState) return state;
  389. return conditionalUpdate(_objectSpread2({}, newState, {
  390. _persist: _persist
  391. }));
  392. };
  393. }
  394. function symbolObservablePonyfill(root) {
  395. var result;
  396. var Symbol = root.Symbol;
  397. if (typeof Symbol === 'function') {
  398. if (Symbol.observable) {
  399. result = Symbol.observable;
  400. } else {
  401. result = Symbol('observable');
  402. Symbol.observable = result;
  403. }
  404. } else {
  405. result = '@@observable';
  406. }
  407. return result;
  408. }
  409. /* global window */
  410. var root;
  411. if (typeof self !== 'undefined') {
  412. root = self;
  413. } else if (typeof window !== 'undefined') {
  414. root = window;
  415. } else if (typeof global !== 'undefined') {
  416. root = global;
  417. } else if (typeof module !== 'undefined') {
  418. root = module;
  419. } else {
  420. root = Function('return this')();
  421. }
  422. var result = symbolObservablePonyfill(root);
  423. /**
  424. * These are private action types reserved by Redux.
  425. * For any unknown actions, you must return the current state.
  426. * If the current state is undefined, you must return the initial state.
  427. * Do not reference these action types directly in your code.
  428. */
  429. var randomString = function randomString() {
  430. return Math.random().toString(36).substring(7).split('').join('.');
  431. };
  432. var ActionTypes = {
  433. INIT: "@@redux/INIT" + randomString(),
  434. REPLACE: "@@redux/REPLACE" + randomString(),
  435. PROBE_UNKNOWN_ACTION: function PROBE_UNKNOWN_ACTION() {
  436. return "@@redux/PROBE_UNKNOWN_ACTION" + randomString();
  437. }
  438. };
  439. /**
  440. * @param {any} obj The object to inspect.
  441. * @returns {boolean} True if the argument appears to be a plain object.
  442. */
  443. function isPlainObject(obj) {
  444. if (typeof obj !== 'object' || obj === null) return false;
  445. var proto = obj;
  446. while (Object.getPrototypeOf(proto) !== null) {
  447. proto = Object.getPrototypeOf(proto);
  448. }
  449. return Object.getPrototypeOf(obj) === proto;
  450. }
  451. /**
  452. * Creates a Redux store that holds the state tree.
  453. * The only way to change the data in the store is to call `dispatch()` on it.
  454. *
  455. * There should only be a single store in your app. To specify how different
  456. * parts of the state tree respond to actions, you may combine several reducers
  457. * into a single reducer function by using `combineReducers`.
  458. *
  459. * @param {Function} reducer A function that returns the next state tree, given
  460. * the current state tree and the action to handle.
  461. *
  462. * @param {any} [preloadedState] The initial state. You may optionally specify it
  463. * to hydrate the state from the server in universal apps, or to restore a
  464. * previously serialized user session.
  465. * If you use `combineReducers` to produce the root reducer function, this must be
  466. * an object with the same shape as `combineReducers` keys.
  467. *
  468. * @param {Function} [enhancer] The store enhancer. You may optionally specify it
  469. * to enhance the store with third-party capabilities such as middleware,
  470. * time travel, persistence, etc. The only store enhancer that ships with Redux
  471. * is `applyMiddleware()`.
  472. *
  473. * @returns {Store} A Redux store that lets you read the state, dispatch actions
  474. * and subscribe to changes.
  475. */
  476. function createStore(reducer, preloadedState, enhancer) {
  477. var _ref2;
  478. if (typeof preloadedState === 'function' && typeof enhancer === 'function' || typeof enhancer === 'function' && typeof arguments[3] === 'function') {
  479. throw new Error('It looks like you are passing several store enhancers to ' + 'createStore(). This is not supported. Instead, compose them ' + 'together to a single function.');
  480. }
  481. if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
  482. enhancer = preloadedState;
  483. preloadedState = undefined;
  484. }
  485. if (typeof enhancer !== 'undefined') {
  486. if (typeof enhancer !== 'function') {
  487. throw new Error('Expected the enhancer to be a function.');
  488. }
  489. return enhancer(createStore)(reducer, preloadedState);
  490. }
  491. if (typeof reducer !== 'function') {
  492. throw new Error('Expected the reducer to be a function.');
  493. }
  494. var currentReducer = reducer;
  495. var currentState = preloadedState;
  496. var currentListeners = [];
  497. var nextListeners = currentListeners;
  498. var isDispatching = false;
  499. /**
  500. * This makes a shallow copy of currentListeners so we can use
  501. * nextListeners as a temporary list while dispatching.
  502. *
  503. * This prevents any bugs around consumers calling
  504. * subscribe/unsubscribe in the middle of a dispatch.
  505. */
  506. function ensureCanMutateNextListeners() {
  507. if (nextListeners === currentListeners) {
  508. nextListeners = currentListeners.slice();
  509. }
  510. }
  511. /**
  512. * Reads the state tree managed by the store.
  513. *
  514. * @returns {any} The current state tree of your application.
  515. */
  516. function getState() {
  517. if (isDispatching) {
  518. throw new Error('You may not call store.getState() while the reducer is executing. ' + 'The reducer has already received the state as an argument. ' + 'Pass it down from the top reducer instead of reading it from the store.');
  519. }
  520. return currentState;
  521. }
  522. /**
  523. * Adds a change listener. It will be called any time an action is dispatched,
  524. * and some part of the state tree may potentially have changed. You may then
  525. * call `getState()` to read the current state tree inside the callback.
  526. *
  527. * You may call `dispatch()` from a change listener, with the following
  528. * caveats:
  529. *
  530. * 1. The subscriptions are snapshotted just before every `dispatch()` call.
  531. * If you subscribe or unsubscribe while the listeners are being invoked, this
  532. * will not have any effect on the `dispatch()` that is currently in progress.
  533. * However, the next `dispatch()` call, whether nested or not, will use a more
  534. * recent snapshot of the subscription list.
  535. *
  536. * 2. The listener should not expect to see all state changes, as the state
  537. * might have been updated multiple times during a nested `dispatch()` before
  538. * the listener is called. It is, however, guaranteed that all subscribers
  539. * registered before the `dispatch()` started will be called with the latest
  540. * state by the time it exits.
  541. *
  542. * @param {Function} listener A callback to be invoked on every dispatch.
  543. * @returns {Function} A function to remove this change listener.
  544. */
  545. function subscribe(listener) {
  546. if (typeof listener !== 'function') {
  547. throw new Error('Expected the listener to be a function.');
  548. }
  549. if (isDispatching) {
  550. throw new Error('You may not call store.subscribe() while the reducer is executing. ' + 'If you would like to be notified after the store has been updated, subscribe from a ' + 'component and invoke store.getState() in the callback to access the latest state. ' + 'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.');
  551. }
  552. var isSubscribed = true;
  553. ensureCanMutateNextListeners();
  554. nextListeners.push(listener);
  555. return function unsubscribe() {
  556. if (!isSubscribed) {
  557. return;
  558. }
  559. if (isDispatching) {
  560. throw new Error('You may not unsubscribe from a store listener while the reducer is executing. ' + 'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.');
  561. }
  562. isSubscribed = false;
  563. ensureCanMutateNextListeners();
  564. var index = nextListeners.indexOf(listener);
  565. nextListeners.splice(index, 1);
  566. };
  567. }
  568. /**
  569. * Dispatches an action. It is the only way to trigger a state change.
  570. *
  571. * The `reducer` function, used to create the store, will be called with the
  572. * current state tree and the given `action`. Its return value will
  573. * be considered the **next** state of the tree, and the change listeners
  574. * will be notified.
  575. *
  576. * The base implementation only supports plain object actions. If you want to
  577. * dispatch a Promise, an Observable, a thunk, or something else, you need to
  578. * wrap your store creating function into the corresponding middleware. For
  579. * example, see the documentation for the `redux-thunk` package. Even the
  580. * middleware will eventually dispatch plain object actions using this method.
  581. *
  582. * @param {Object} action A plain object representing “what changed”. It is
  583. * a good idea to keep actions serializable so you can record and replay user
  584. * sessions, or use the time travelling `redux-devtools`. An action must have
  585. * a `type` property which may not be `undefined`. It is a good idea to use
  586. * string constants for action types.
  587. *
  588. * @returns {Object} For convenience, the same action object you dispatched.
  589. *
  590. * Note that, if you use a custom middleware, it may wrap `dispatch()` to
  591. * return something else (for example, a Promise you can await).
  592. */
  593. function dispatch(action) {
  594. if (!isPlainObject(action)) {
  595. throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
  596. }
  597. if (typeof action.type === 'undefined') {
  598. throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
  599. }
  600. if (isDispatching) {
  601. throw new Error('Reducers may not dispatch actions.');
  602. }
  603. try {
  604. isDispatching = true;
  605. currentState = currentReducer(currentState, action);
  606. } finally {
  607. isDispatching = false;
  608. }
  609. var listeners = currentListeners = nextListeners;
  610. for (var i = 0; i < listeners.length; i++) {
  611. var listener = listeners[i];
  612. listener();
  613. }
  614. return action;
  615. }
  616. /**
  617. * Replaces the reducer currently used by the store to calculate the state.
  618. *
  619. * You might need this if your app implements code splitting and you want to
  620. * load some of the reducers dynamically. You might also need this if you
  621. * implement a hot reloading mechanism for Redux.
  622. *
  623. * @param {Function} nextReducer The reducer for the store to use instead.
  624. * @returns {void}
  625. */
  626. function replaceReducer(nextReducer) {
  627. if (typeof nextReducer !== 'function') {
  628. throw new Error('Expected the nextReducer to be a function.');
  629. }
  630. currentReducer = nextReducer; // This action has a similiar effect to ActionTypes.INIT.
  631. // Any reducers that existed in both the new and old rootReducer
  632. // will receive the previous state. This effectively populates
  633. // the new state tree with any relevant data from the old one.
  634. dispatch({
  635. type: ActionTypes.REPLACE
  636. });
  637. }
  638. /**
  639. * Interoperability point for observable/reactive libraries.
  640. * @returns {observable} A minimal observable of state changes.
  641. * For more information, see the observable proposal:
  642. * https://github.com/tc39/proposal-observable
  643. */
  644. function observable() {
  645. var _ref;
  646. var outerSubscribe = subscribe;
  647. return _ref = {
  648. /**
  649. * The minimal observable subscription method.
  650. * @param {Object} observer Any object that can be used as an observer.
  651. * The observer object should have a `next` method.
  652. * @returns {subscription} An object with an `unsubscribe` method that can
  653. * be used to unsubscribe the observable from the store, and prevent further
  654. * emission of values from the observable.
  655. */
  656. subscribe: function subscribe(observer) {
  657. if (typeof observer !== 'object' || observer === null) {
  658. throw new TypeError('Expected the observer to be an object.');
  659. }
  660. function observeState() {
  661. if (observer.next) {
  662. observer.next(getState());
  663. }
  664. }
  665. observeState();
  666. var unsubscribe = outerSubscribe(observeState);
  667. return {
  668. unsubscribe: unsubscribe
  669. };
  670. }
  671. }, _ref[result] = function () {
  672. return this;
  673. }, _ref;
  674. } // When a store is created, an "INIT" action is dispatched so that every
  675. // reducer returns their initial state. This effectively populates
  676. // the initial state tree.
  677. dispatch({
  678. type: ActionTypes.INIT
  679. });
  680. return _ref2 = {
  681. dispatch: dispatch,
  682. subscribe: subscribe,
  683. getState: getState,
  684. replaceReducer: replaceReducer
  685. }, _ref2[result] = observable, _ref2;
  686. }
  687. /**
  688. * Prints a warning in the console if it exists.
  689. *
  690. * @param {String} message The warning message.
  691. * @returns {void}
  692. */
  693. function warning(message) {
  694. /* eslint-disable no-console */
  695. if (typeof console !== 'undefined' && typeof console.error === 'function') {
  696. console.error(message);
  697. }
  698. /* eslint-enable no-console */
  699. try {
  700. // This error was thrown as a convenience so that if you enable
  701. // "break on all exceptions" in your console,
  702. // it would pause the execution at this line.
  703. throw new Error(message);
  704. } catch (e) {} // eslint-disable-line no-empty
  705. }
  706. function getUndefinedStateErrorMessage(key, action) {
  707. var actionType = action && action.type;
  708. var actionDescription = actionType && "action \"" + String(actionType) + "\"" || 'an action';
  709. return "Given " + actionDescription + ", reducer \"" + key + "\" returned undefined. " + "To ignore an action, you must explicitly return the previous state. " + "If you want this reducer to hold no value, you can return null instead of undefined.";
  710. }
  711. function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
  712. var reducerKeys = Object.keys(reducers);
  713. var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';
  714. if (reducerKeys.length === 0) {
  715. return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
  716. }
  717. if (!isPlainObject(inputState)) {
  718. return "The " + argumentName + " has unexpected type of \"" + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + "\". Expected argument to be an object with the following " + ("keys: \"" + reducerKeys.join('", "') + "\"");
  719. }
  720. var unexpectedKeys = Object.keys(inputState).filter(function (key) {
  721. return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];
  722. });
  723. unexpectedKeys.forEach(function (key) {
  724. unexpectedKeyCache[key] = true;
  725. });
  726. if (action && action.type === ActionTypes.REPLACE) return;
  727. if (unexpectedKeys.length > 0) {
  728. return "Unexpected " + (unexpectedKeys.length > 1 ? 'keys' : 'key') + " " + ("\"" + unexpectedKeys.join('", "') + "\" found in " + argumentName + ". ") + "Expected to find one of the known reducer keys instead: " + ("\"" + reducerKeys.join('", "') + "\". Unexpected keys will be ignored.");
  729. }
  730. }
  731. function assertReducerShape(reducers) {
  732. Object.keys(reducers).forEach(function (key) {
  733. var reducer = reducers[key];
  734. var initialState = reducer(undefined, {
  735. type: ActionTypes.INIT
  736. });
  737. if (typeof initialState === 'undefined') {
  738. throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");
  739. }
  740. if (typeof reducer(undefined, {
  741. type: ActionTypes.PROBE_UNKNOWN_ACTION()
  742. }) === 'undefined') {
  743. throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");
  744. }
  745. });
  746. }
  747. /**
  748. * Turns an object whose values are different reducer functions, into a single
  749. * reducer function. It will call every child reducer, and gather their results
  750. * into a single state object, whose keys correspond to the keys of the passed
  751. * reducer functions.
  752. *
  753. * @param {Object} reducers An object whose values correspond to different
  754. * reducer functions that need to be combined into one. One handy way to obtain
  755. * it is to use ES6 `import * as reducers` syntax. The reducers may never return
  756. * undefined for any action. Instead, they should return their initial state
  757. * if the state passed to them was undefined, and the current state for any
  758. * unrecognized action.
  759. *
  760. * @returns {Function} A reducer function that invokes every reducer inside the
  761. * passed object, and builds a state object with the same shape.
  762. */
  763. function combineReducers(reducers) {
  764. var reducerKeys = Object.keys(reducers);
  765. var finalReducers = {};
  766. for (var i = 0; i < reducerKeys.length; i++) {
  767. var key = reducerKeys[i];
  768. {
  769. if (typeof reducers[key] === 'undefined') {
  770. warning("No reducer provided for key \"" + key + "\"");
  771. }
  772. }
  773. if (typeof reducers[key] === 'function') {
  774. finalReducers[key] = reducers[key];
  775. }
  776. }
  777. var finalReducerKeys = Object.keys(finalReducers); // This is used to make sure we don't warn about the same
  778. // keys multiple times.
  779. var unexpectedKeyCache;
  780. {
  781. unexpectedKeyCache = {};
  782. }
  783. var shapeAssertionError;
  784. try {
  785. assertReducerShape(finalReducers);
  786. } catch (e) {
  787. shapeAssertionError = e;
  788. }
  789. return function combination(state, action) {
  790. if (state === void 0) {
  791. state = {};
  792. }
  793. if (shapeAssertionError) {
  794. throw shapeAssertionError;
  795. }
  796. {
  797. var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
  798. if (warningMessage) {
  799. warning(warningMessage);
  800. }
  801. }
  802. var hasChanged = false;
  803. var nextState = {};
  804. for (var _i = 0; _i < finalReducerKeys.length; _i++) {
  805. var _key = finalReducerKeys[_i];
  806. var reducer = finalReducers[_key];
  807. var previousStateForKey = state[_key];
  808. var nextStateForKey = reducer(previousStateForKey, action);
  809. if (typeof nextStateForKey === 'undefined') {
  810. var errorMessage = getUndefinedStateErrorMessage(_key, action);
  811. throw new Error(errorMessage);
  812. }
  813. nextState[_key] = nextStateForKey;
  814. hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
  815. }
  816. return hasChanged ? nextState : state;
  817. };
  818. }
  819. /*
  820. * This is a dummy function to check if the function name has been altered by minification.
  821. * If the function has been minified and NODE_ENV !== 'production', warn the user.
  822. */
  823. function isCrushed() {}
  824. if ("development" !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {
  825. warning('You are currently using minified code outside of NODE_ENV === "production". ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or setting mode to production in webpack (https://webpack.js.org/concepts/mode/) ' + 'to ensure you have the correct code for your production build.');
  826. }
  827. /*
  828. autoMergeLevel2:
  829. - merges 2 level of substate
  830. - skips substate if already modified
  831. - this is essentially redux-perist v4 behavior
  832. */
  833. function autoMergeLevel2(inboundState, originalState, reducedState, _ref) {
  834. var debug = _ref.debug;
  835. var newState = _objectSpread2({}, reducedState); // only rehydrate if inboundState exists and is an object
  836. if (inboundState && _typeof(inboundState) === 'object') {
  837. Object.keys(inboundState).forEach(function (key) {
  838. // ignore _persist data
  839. if (key === '_persist') return; // if reducer modifies substate, skip auto rehydration
  840. if (originalState[key] !== reducedState[key]) {
  841. if ("development" !== 'production' && debug) console.log('redux-persist/stateReconciler: sub state for key `%s` modified, skipping.', key);
  842. return;
  843. }
  844. if (isPlainEnoughObject(reducedState[key])) {
  845. // if object is plain enough shallow merge the new values (hence "Level2")
  846. newState[key] = _objectSpread2({}, newState[key], {}, inboundState[key]);
  847. return;
  848. } // otherwise hard set
  849. newState[key] = inboundState[key];
  850. });
  851. }
  852. if ("development" !== 'production' && debug && inboundState && _typeof(inboundState) === 'object') console.log("redux-persist/stateReconciler: rehydrated keys '".concat(Object.keys(inboundState).join(', '), "'"));
  853. return newState;
  854. }
  855. function isPlainEnoughObject(o) {
  856. return o !== null && !Array.isArray(o) && _typeof(o) === 'object';
  857. }
  858. // combineReducers + persistReducer with stateReconciler defaulted to autoMergeLevel2
  859. function persistCombineReducers(config, reducers) {
  860. config.stateReconciler = config.stateReconciler === undefined ? autoMergeLevel2 : config.stateReconciler;
  861. return persistReducer(config, combineReducers(reducers));
  862. }
  863. var initialState = {
  864. registry: [],
  865. bootstrapped: false
  866. };
  867. var persistorReducer = function persistorReducer() {
  868. var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialState;
  869. var action = arguments.length > 1 ? arguments[1] : undefined;
  870. switch (action.type) {
  871. case REGISTER:
  872. return _objectSpread2({}, state, {
  873. registry: [].concat(_toConsumableArray(state.registry), [action.key])
  874. });
  875. case REHYDRATE:
  876. var firstIndex = state.registry.indexOf(action.key);
  877. var registry = _toConsumableArray(state.registry);
  878. registry.splice(firstIndex, 1);
  879. return _objectSpread2({}, state, {
  880. registry: registry,
  881. bootstrapped: registry.length === 0
  882. });
  883. default:
  884. return state;
  885. }
  886. };
  887. function persistStore(store, options, cb) {
  888. // help catch incorrect usage of passing PersistConfig in as PersistorOptions
  889. {
  890. var optionsToTest = options || {};
  891. var bannedKeys = ['blacklist', 'whitelist', 'transforms', 'storage', 'keyPrefix', 'migrate'];
  892. bannedKeys.forEach(function (k) {
  893. if (!!optionsToTest[k]) console.error("redux-persist: invalid option passed to persistStore: \"".concat(k, "\". You may be incorrectly passing persistConfig into persistStore, whereas it should be passed into persistReducer."));
  894. });
  895. }
  896. var boostrappedCb = cb || false;
  897. var _pStore = createStore(persistorReducer, initialState, options && options.enhancer ? options.enhancer : undefined);
  898. var register = function register(key) {
  899. _pStore.dispatch({
  900. type: REGISTER,
  901. key: key
  902. });
  903. };
  904. var rehydrate = function rehydrate(key, payload, err) {
  905. var rehydrateAction = {
  906. type: REHYDRATE,
  907. payload: payload,
  908. err: err,
  909. key: key // dispatch to `store` to rehydrate and `persistor` to track result
  910. };
  911. store.dispatch(rehydrateAction);
  912. _pStore.dispatch(rehydrateAction);
  913. if (boostrappedCb && persistor.getState().bootstrapped) {
  914. boostrappedCb();
  915. boostrappedCb = false;
  916. }
  917. };
  918. var persistor = _objectSpread2({}, _pStore, {
  919. purge: function purge() {
  920. var results = [];
  921. store.dispatch({
  922. type: PURGE,
  923. result: function result(purgeResult) {
  924. results.push(purgeResult);
  925. }
  926. });
  927. return Promise.all(results);
  928. },
  929. flush: function flush() {
  930. var results = [];
  931. store.dispatch({
  932. type: FLUSH,
  933. result: function result(flushResult) {
  934. results.push(flushResult);
  935. }
  936. });
  937. return Promise.all(results);
  938. },
  939. pause: function pause() {
  940. store.dispatch({
  941. type: PAUSE
  942. });
  943. },
  944. persist: function persist() {
  945. store.dispatch({
  946. type: PERSIST,
  947. register: register,
  948. rehydrate: rehydrate
  949. });
  950. }
  951. });
  952. if (!(options && options.manualPersist)) {
  953. persistor.persist();
  954. }
  955. return persistor;
  956. }
  957. function createMigrate(migrations, config) {
  958. var _ref = config || {},
  959. debug = _ref.debug;
  960. return function (state, currentVersion) {
  961. if (!state) {
  962. if ("development" !== 'production' && debug) console.log('redux-persist: no inbound state, skipping migration');
  963. return Promise.resolve(undefined);
  964. }
  965. var inboundVersion = state._persist && state._persist.version !== undefined ? state._persist.version : DEFAULT_VERSION;
  966. if (inboundVersion === currentVersion) {
  967. if ("development" !== 'production' && debug) console.log('redux-persist: versions match, noop migration');
  968. return Promise.resolve(state);
  969. }
  970. if (inboundVersion > currentVersion) {
  971. console.error('redux-persist: downgrading version is not supported');
  972. return Promise.resolve(state);
  973. }
  974. var migrationKeys = Object.keys(migrations).map(function (ver) {
  975. return parseInt(ver);
  976. }).filter(function (key) {
  977. return currentVersion >= key && key > inboundVersion;
  978. }).sort(function (a, b) {
  979. return a - b;
  980. });
  981. if ("development" !== 'production' && debug) console.log('redux-persist: migrationKeys', migrationKeys);
  982. try {
  983. var migratedState = migrationKeys.reduce(function (state, versionKey) {
  984. if ("development" !== 'production' && debug) console.log('redux-persist: running migration for versionKey', versionKey);
  985. return migrations[versionKey](state);
  986. }, state);
  987. return Promise.resolve(migratedState);
  988. } catch (err) {
  989. return Promise.reject(err);
  990. }
  991. };
  992. }
  993. function createTransform( // @NOTE inbound: transform state coming from redux on its way to being serialized and stored
  994. inbound, // @NOTE outbound: transform state coming from storage, on its way to be rehydrated into redux
  995. outbound) {
  996. var config = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  997. var whitelist = config.whitelist || null;
  998. var blacklist = config.blacklist || null;
  999. function whitelistBlacklistCheck(key) {
  1000. if (whitelist && whitelist.indexOf(key) === -1) return true;
  1001. if (blacklist && blacklist.indexOf(key) !== -1) return true;
  1002. return false;
  1003. }
  1004. return {
  1005. in: function _in(state, key, fullState) {
  1006. return !whitelistBlacklistCheck(key) && inbound ? inbound(state, key, fullState) : state;
  1007. },
  1008. out: function out(state, key, fullState) {
  1009. return !whitelistBlacklistCheck(key) && outbound ? outbound(state, key, fullState) : state;
  1010. }
  1011. };
  1012. }
  1013. exports.persistReducer = persistReducer;
  1014. exports.persistCombineReducers = persistCombineReducers;
  1015. exports.persistStore = persistStore;
  1016. exports.createMigrate = createMigrate;
  1017. exports.createTransform = createTransform;
  1018. exports.getStoredState = getStoredState;
  1019. exports.createPersistoid = createPersistoid;
  1020. exports.purgeStoredState = purgeStoredState;
  1021. exports.KEY_PREFIX = KEY_PREFIX;
  1022. exports.FLUSH = FLUSH;
  1023. exports.REHYDRATE = REHYDRATE;
  1024. exports.PAUSE = PAUSE;
  1025. exports.PERSIST = PERSIST;
  1026. exports.PURGE = PURGE;
  1027. exports.REGISTER = REGISTER;
  1028. exports.DEFAULT_VERSION = DEFAULT_VERSION;
  1029. Object.defineProperty(exports, '__esModule', { value: true });
  1030. })));
  1031. //# sourceMappingURL=redux-persist.js.map