From 64c73e275477f42639db8e459d079127d0c7e039 Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 10:39:59 +0530 Subject: [PATCH 01/22] Update README.md --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 75a12b1..4e78406 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,9 @@ Save and load the [Redux][] state with ease. -# Deprecated - No longer maintained +# A fork of [michaelcontento/redux-storage](https://github.com/michaelcontento/redux-storage) -My focus has left the node / react ecosystem and this module is no -longer maintained. Maybe [redux-persist](https://github.com/rt2zz/redux-persist) -is a good replacement for you? Or if you want to step in and become -the new owner - just ping me :smile: - -Thank you for your patience and using this module in the first place! +The original author of the package [redux-storage](https://github.com/michaelcontento/redux-storage) has decided to deprecate the project and no longer maintained. The package will now be maintained here. ## Features From 1150ed67f2b3127a90775afebb1aa4c349e92208 Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 10:57:03 +0530 Subject: [PATCH 02/22] Update README.md --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4e78406..6472e71 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Save and load the [Redux][] state with ease. The original author of the package [redux-storage](https://github.com/michaelcontento/redux-storage) has decided to deprecate the project and no longer maintained. The package will now be maintained here. +Thank you michaelcontento for a great library! + ## Features * Flexible storage engines @@ -163,7 +165,7 @@ const middleware = createMiddleware(engine, [], [ SHOULD_SAVE ]); The MIT License (MIT) - Copyright (c) 2015 Michael Contento + Copyright (c) 2015 Gunjan Soni Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -182,22 +184,22 @@ const middleware = createMiddleware(engine, [], [ SHOULD_SAVE ]); IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - [merger-simple]: https://github.com/michaelcontento/redux-storage-merger-simple - [merger-immutablejs]: https://github.com/michaelcontento/redux-storage-merger-immutablejs + [merger-simple]: https://github.com/guns2410/redux-storage-merger-simple + [merger-immutablejs]: https://github.com/guns2410/redux-storage-merger-immutablejs [npm-engine]: https://www.npmjs.com/browse/keyword/redux-storage-engine [npm-decorator]: https://www.npmjs.com/browse/keyword/redux-storage-decorator [npm-merger]: https://www.npmjs.com/browse/keyword/redux-storage-merger [Redux]: https://github.com/gaearon/redux [Immutable]: https://github.com/facebook/immutable-js - [redux-storage]: https://github.com/michaelcontento/redux-storage + [redux-storage]: https://github.com/guns2410/redux-storage [react-native]: https://facebook.github.io/react-native/ [localStorage]: https://github.com/michaelcontento/redux-storage-engine-localStorage - [localStorageFakePromise]: https://github.com/michaelcontento/redux-storage-engine-localStorageFakePromise - [reactNativeAsyncStorage]: https://github.com/michaelcontento/redux-storage-engine-reactNativeAsyncStorage - [LOAD]: https://github.com/michaelcontento/redux-storage/blob/master/src/constants.js#L1 - [SAVE]: https://github.com/michaelcontento/redux-storage/blob/master/src/constants.js#L2 - [debounce]: https://github.com/michaelcontento/redux-storage-decorator-debounce + [localStorageFakePromise]: https://github.com/guns2410/redux-storage-engine-localStorageFakePromise + [reactNativeAsyncStorage]: https://github.com/guns2410/redux-storage-engine-reactNativeAsyncStorage + [LOAD]: https://github.com/guns2410/redux-storage/blob/master/src/constants.js#L1 + [SAVE]: https://github.com/guns2410/redux-storage/blob/master/src/constants.js#L2 + [debounce]: https://github.com/guns2410/redux-storage-decorator-debounce [engines]: https://github.com/allegro/redux-storage-decorator-engines - [filter]: https://github.com/michaelcontento/redux-storage-decorator-filter + [filter]: https://github.com/guns2410/redux-storage-decorator-filter [migrate]: https://github.com/mathieudutour/redux-storage-decorator-migrate - [immutablejs]: https://github.com/michaelcontento/redux-storage-decorator-immutablejs + [immutablejs]: https://github.com/guns2410/redux-storage-decorator-immutablejs From 955a27bb886ec324b890f545cea0b5a9513f01b8 Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 11:04:48 +0530 Subject: [PATCH 03/22] Update package.json --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index d8a0ef2..8106cf0 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,9 @@ }, "repository": { "type": "git", - "url": "https://github.com/michaelcontento/redux-storage.git" + "url": "https://github.com/guns2410/redux-storage.git" }, - "homepage": "https://github.com/michaelcontento/redux-storage", + "homepage": "https://github.com/guns2410/redux-storage", "keywords": [ "redux", "redux-middleware", @@ -23,7 +23,7 @@ "data", "localstorage" ], - "author": "Michael Contento ", + "author": "Guns ", "files": [ "build/", "build-es/", From 1ebded5218c2dad050b4fe0dbecec1039b1f2091 Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 11:07:01 +0530 Subject: [PATCH 04/22] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6472e71..17febdb 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,6 @@ Save and load the [Redux][] state with ease. -# A fork of [michaelcontento/redux-storage](https://github.com/michaelcontento/redux-storage) - -The original author of the package [redux-storage](https://github.com/michaelcontento/redux-storage) has decided to deprecate the project and no longer maintained. The package will now be maintained here. - -Thank you michaelcontento for a great library! - ## Features * Flexible storage engines @@ -161,6 +155,12 @@ import { SHOULD_SAVE } from './constants'; const middleware = createMiddleware(engine, [], [ SHOULD_SAVE ]); ``` +# A fork of [redux-storage](https://github.com/michaelcontento/redux-storage) + +The original author of the package [redux-storage](https://github.com/michaelcontento/redux-storage) has decided to deprecate the project and no longer maintained. The package will now be maintained here. + +Thank you [michaelcontento](https://github.com/michaelcontento) for a great library! + ## License The MIT License (MIT) From eef1ccb663e9ae4ef6cb11007533446e145b2cce Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 11:08:28 +0530 Subject: [PATCH 05/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17febdb..abb356e 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ Thank you [michaelcontento](https://github.com/michaelcontento) for a great libr [Immutable]: https://github.com/facebook/immutable-js [redux-storage]: https://github.com/guns2410/redux-storage [react-native]: https://facebook.github.io/react-native/ - [localStorage]: https://github.com/michaelcontento/redux-storage-engine-localStorage + [localStorage]: https://github.com/guns2410/redux-storage-engine-localStorage [localStorageFakePromise]: https://github.com/guns2410/redux-storage-engine-localStorageFakePromise [reactNativeAsyncStorage]: https://github.com/guns2410/redux-storage-engine-reactNativeAsyncStorage [LOAD]: https://github.com/guns2410/redux-storage/blob/master/src/constants.js#L1 From 1b12c5e99135d2d8c7870bd43f32573001f04c3d Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 11:56:37 +0530 Subject: [PATCH 06/22] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index abb356e..d5fd500 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ # [redux-storage][] [![build](https://travis-ci.org/michaelcontento/redux-storage.svg?branch=master)](https://travis-ci.org/michaelcontento/redux-storage) -[![dependencies](https://david-dm.org/michaelcontento/redux-storage.svg)](https://david-dm.org/michaelcontento/redux-storage) -[![devDependencies](https://david-dm.org/michaelcontento/redux-storage/dev-status.svg)](https://david-dm.org/michaelcontento/redux-storage#info=devDependencies) +[![dependencies](https://david-dm.org/guns2410/redux-storage.svg)](https://david-dm.org/michaelcontento/redux-storage) +[![devDependencies](https://david-dm.org/guns2410/redux-storage/dev-status.svg)](https://david-dm.org/michaelcontento/redux-storage#info=devDependencies) [![license](https://img.shields.io/npm/l/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) [![npm version](https://img.shields.io/npm/v/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) [![npm downloads](https://img.shields.io/npm/dm/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) -[![Code Climate](https://codeclimate.com/github/michaelcontento/redux-storage/badges/gpa.svg)](https://codeclimate.com/github/michaelcontento/redux-storage) +[![Code Climate](https://codeclimate.com/github/guns2410/redux-storage/badges/gpa.svg)](https://codeclimate.com/github/michaelcontento/redux-storage) Save and load the [Redux][] state with ease. From 474e91012046110d8340807d253b4e38ea1402bf Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 9 Nov 2016 11:58:43 +0530 Subject: [PATCH 07/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5fd500..b67303e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [redux-storage][] -[![build](https://travis-ci.org/michaelcontento/redux-storage.svg?branch=master)](https://travis-ci.org/michaelcontento/redux-storage) +[![build](https://travis-ci.org/guns2410/redux-storage.svg?branch=master)](https://travis-ci.org/michaelcontento/redux-storage) [![dependencies](https://david-dm.org/guns2410/redux-storage.svg)](https://david-dm.org/michaelcontento/redux-storage) [![devDependencies](https://david-dm.org/guns2410/redux-storage/dev-status.svg)](https://david-dm.org/michaelcontento/redux-storage#info=devDependencies) From b177bf225da0f9782808015c72df5d7aa29355e8 Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 16 Nov 2016 12:25:57 +0530 Subject: [PATCH 08/22] updated license --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b67303e..4898900 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,8 @@ Thank you [michaelcontento](https://github.com/michaelcontento) for a great libr The MIT License (MIT) - Copyright (c) 2015 Gunjan Soni + Copyright (c) 2016- Gunjan Soni + Copyright (c) 2015-2016 Michael Contento Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 45ff1061bf252f5012b3cc0481c827d7cad0acea Mon Sep 17 00:00:00 2001 From: Guns Date: Wed, 16 Nov 2016 12:26:24 +0530 Subject: [PATCH 09/22] Update LICENSE.txt --- LICENSE.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 8facf8a..9df9522 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2015 Michael Contento +Copyright (c) 2016- Gunjan Soni +Copyright (c) 2015-2016 Michael Contento Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 8d886239ead3dcb478d457311d039b3b1f8d341f Mon Sep 17 00:00:00 2001 From: Guns Date: Thu, 24 Nov 2016 10:26:05 +0530 Subject: [PATCH 10/22] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4898900..8b6b7e3 100644 --- a/README.md +++ b/README.md @@ -185,22 +185,22 @@ Thank you [michaelcontento](https://github.com/michaelcontento) for a great libr IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - [merger-simple]: https://github.com/guns2410/redux-storage-merger-simple - [merger-immutablejs]: https://github.com/guns2410/redux-storage-merger-immutablejs + [merger-simple]: https://github.com/react-stack/redux-storage-merger-simple + [merger-immutablejs]: https://github.com/react-stack/redux-storage-merger-immutablejs [npm-engine]: https://www.npmjs.com/browse/keyword/redux-storage-engine [npm-decorator]: https://www.npmjs.com/browse/keyword/redux-storage-decorator [npm-merger]: https://www.npmjs.com/browse/keyword/redux-storage-merger [Redux]: https://github.com/gaearon/redux [Immutable]: https://github.com/facebook/immutable-js - [redux-storage]: https://github.com/guns2410/redux-storage + [redux-storage]: https://github.com/react-stack/redux-storage [react-native]: https://facebook.github.io/react-native/ - [localStorage]: https://github.com/guns2410/redux-storage-engine-localStorage - [localStorageFakePromise]: https://github.com/guns2410/redux-storage-engine-localStorageFakePromise - [reactNativeAsyncStorage]: https://github.com/guns2410/redux-storage-engine-reactNativeAsyncStorage - [LOAD]: https://github.com/guns2410/redux-storage/blob/master/src/constants.js#L1 - [SAVE]: https://github.com/guns2410/redux-storage/blob/master/src/constants.js#L2 - [debounce]: https://github.com/guns2410/redux-storage-decorator-debounce + [localStorage]: https://github.com/react-stack/redux-storage-engine-localStorage + [localStorageFakePromise]: https://github.com/react-stack/redux-storage-engine-localStorageFakePromise + [reactNativeAsyncStorage]: https://github.com/react-stack/redux-storage-engine-reactNativeAsyncStorage + [LOAD]: https://github.com/react-stack/redux-storage/blob/master/src/constants.js#L1 + [SAVE]: https://github.com/react-stack/redux-storage/blob/master/src/constants.js#L2 + [debounce]: https://github.com/react-stack/redux-storage-decorator-debounce [engines]: https://github.com/allegro/redux-storage-decorator-engines - [filter]: https://github.com/guns2410/redux-storage-decorator-filter + [filter]: https://github.com/react-stack/redux-storage-decorator-filter [migrate]: https://github.com/mathieudutour/redux-storage-decorator-migrate - [immutablejs]: https://github.com/guns2410/redux-storage-decorator-immutablejs + [immutablejs]: https://github.com/react-stack/redux-storage-decorator-immutablejs From 9433d14743703fbdc7b61b3f06c1709e9c1f42b0 Mon Sep 17 00:00:00 2001 From: Michael Contento Date: Mon, 12 Dec 2016 18:19:29 +0100 Subject: [PATCH 11/22] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8b6b7e3..593a91c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ # [redux-storage][] -[![build](https://travis-ci.org/guns2410/redux-storage.svg?branch=master)](https://travis-ci.org/michaelcontento/redux-storage) -[![dependencies](https://david-dm.org/guns2410/redux-storage.svg)](https://david-dm.org/michaelcontento/redux-storage) -[![devDependencies](https://david-dm.org/guns2410/redux-storage/dev-status.svg)](https://david-dm.org/michaelcontento/redux-storage#info=devDependencies) +[![build](https://travis-ci.org/guns2410/redux-storage.svg?branch=master)](https://travis-ci.org/react-stack/redux-storage) +[![dependencies](https://david-dm.org/guns2410/redux-storage.svg)](https://david-dm.org/react-stack/redux-storage) +[![devDependencies](https://david-dm.org/guns2410/redux-storage/dev-status.svg)](https://david-dm.org/react-stack/redux-storage#info=devDependencies) [![license](https://img.shields.io/npm/l/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) [![npm version](https://img.shields.io/npm/v/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) [![npm downloads](https://img.shields.io/npm/dm/redux-storage.svg?style=flat-square)](https://www.npmjs.com/package/redux-storage) -[![Code Climate](https://codeclimate.com/github/guns2410/redux-storage/badges/gpa.svg)](https://codeclimate.com/github/michaelcontento/redux-storage) Save and load the [Redux][] state with ease. From d36e2a752f1d4445e72e42826e0a3411e443eb62 Mon Sep 17 00:00:00 2001 From: Michael Contento Date: Mon, 12 Dec 2016 18:20:03 +0100 Subject: [PATCH 12/22] Update package.json --- package.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8106cf0..e0996af 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,10 @@ }, "repository": { "type": "git", - "url": "https://github.com/guns2410/redux-storage.git" + "url": "https://github.com/react-stack/redux-storage.git" }, - "homepage": "https://github.com/guns2410/redux-storage", + "bugs": "https://github.com/react-stack/redux-storage/issues", + "homepage": "https://github.com/react-stack/redux-storage", "keywords": [ "redux", "redux-middleware", @@ -23,7 +24,10 @@ "data", "localstorage" ], - "author": "Guns ", + "author": [ + "Michael Contento ", + "Guns " + ], "files": [ "build/", "build-es/", From b62f000bcc05f0ab43866d49416f32381de2a5c9 Mon Sep 17 00:00:00 2001 From: Michael Contento Date: Mon, 12 Dec 2016 18:34:48 +0100 Subject: [PATCH 13/22] Release 4.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0996af..0b7ed01 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-storage", - "version": "4.1.1", + "version": "4.1.2", "description": "Persistence layer for redux with flexible backends", "main": "build/index.js", "jsnext:main": "build-es/index.js", From 4cb514d1a63fccfca5e10a521dd93c5a1212901e Mon Sep 17 00:00:00 2001 From: Michael Contento Date: Mon, 12 Dec 2016 18:53:17 +0100 Subject: [PATCH 14/22] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 593a91c..8ce56d0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Save and load the [Redux][] state with ease. * [localStorage][]: based on window.localStorage * Or for environments without `Promise` support [localStorageFakePromise][] * [reactNativeAsyncStorage][]: based on `react-native/AsyncStorage` + * [remoteEndpoint][]: save/load via XHR * Flexible state merger functions * [simple][merger-simple]: merge plain old JS structures (default) * [immutablejs][merger-immutablejs]: merge plain old JS **and** [Immutable][] @@ -203,3 +204,4 @@ Thank you [michaelcontento](https://github.com/michaelcontento) for a great libr [filter]: https://github.com/react-stack/redux-storage-decorator-filter [migrate]: https://github.com/mathieudutour/redux-storage-decorator-migrate [immutablejs]: https://github.com/react-stack/redux-storage-decorator-immutablejs + [remoteEndpoint]: https://github.com/bionexo/redux-storage-engine-remoteendpoint From e1341b6e2895dae95f4944fa20029c35d54de5c1 Mon Sep 17 00:00:00 2001 From: Prateek Bhatnagar Date: Sat, 11 Feb 2017 19:42:47 +0530 Subject: [PATCH 15/22] indexedDb --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ce56d0..4060a4a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Save and load the [Redux][] state with ease. ## Features * Flexible storage engines + * [indexedDb](https://github.com/prateekbh/redux-storage-engine-indexed-db): based on window.indexedDb * [localStorage][]: based on window.localStorage * Or for environments without `Promise` support [localStorageFakePromise][] * [reactNativeAsyncStorage][]: based on `react-native/AsyncStorage` @@ -165,8 +166,8 @@ Thank you [michaelcontento](https://github.com/michaelcontento) for a great libr The MIT License (MIT) - Copyright (c) 2016- Gunjan Soni - Copyright (c) 2015-2016 Michael Contento + Copyright (c) 2016- Gunjan Soni + Copyright (c) 2015-2016 Michael Contento Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 09698a5db840596722dcfcd425b65b48e44034b5 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 25 May 2018 10:23:05 +0200 Subject: [PATCH 16/22] Update peerDependencies to support redux@4 There are no breaking changes relative to this plugin. The middleware api hasn't changed. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b7ed01..62ee465 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "redux-storage-merger-simple": "^1.0.2" }, "peerDependencies": { - "redux": "^3.0.0 || ^2.0.0 || ^1.0.0 || 1.0.0-alpha || 1.0.0-rc" + "redux": "^4.0.0 || ^3.0.0 || ^2.0.0 || ^1.0.0 || 1.0.0-alpha || 1.0.0-rc" }, "browserify": { "transform": [ From ff1e0969c5ce029b5b20bbca75ae691f2dc6f0aa Mon Sep 17 00:00:00 2001 From: Nathaniel Hill Date: Thu, 20 Sep 2018 18:15:39 -0500 Subject: [PATCH 17/22] Update package.json Works with redux-4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b7ed01..62ee465 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "redux-storage-merger-simple": "^1.0.2" }, "peerDependencies": { - "redux": "^3.0.0 || ^2.0.0 || ^1.0.0 || 1.0.0-alpha || 1.0.0-rc" + "redux": "^4.0.0 || ^3.0.0 || ^2.0.0 || ^1.0.0 || 1.0.0-alpha || 1.0.0-rc" }, "browserify": { "transform": [ From f837e8ded10841d4cb1b44240435ebf83576953a Mon Sep 17 00:00:00 2001 From: "Zachary E. Dahan" Date: Fri, 21 Dec 2018 18:35:36 -0800 Subject: [PATCH 18/22] Skip dispatching redux action on save --- src/createMiddleware.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/createMiddleware.js b/src/createMiddleware.js index 01ed44d..b527920 100644 --- a/src/createMiddleware.js +++ b/src/createMiddleware.js @@ -62,7 +62,9 @@ function handleWhitelist(action, actionWhitelist) { return actionWhitelist(action); } -export default (engine, actionBlacklist = [], actionWhitelist = []) => { +export default (engine, actionBlacklist = [], actionWhitelist = [], options = {}) => { + const opts = Object.assign({ disableDispatchSaveAction: false }, options); + // Also don't save if we process our own actions const blacklistedActions = [...actionBlacklist, LOAD, SAVE]; @@ -94,7 +96,13 @@ export default (engine, actionBlacklist = [], actionWhitelist = []) => { } const dispatchSave = () => dispatch(saveAction); - engine.save(saveState).then(dispatchSave).catch(swallow); + engine.save(saveState) + .then(() => { + if (opts.disableDispatchSaveAction === false) { + return dispatchSave(); + } + }) + .catch(swallow); } return result; From 9913b58f36e7f532b11c9272d104dd457ffef378 Mon Sep 17 00:00:00 2001 From: "Zachary E. Dahan" Date: Sat, 22 Dec 2018 11:57:00 -0800 Subject: [PATCH 19/22] Add documentation for disabling dispatch save action --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 4060a4a..34ccdd7 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,17 @@ import { SHOULD_SAVE } from './constants'; const middleware = createMiddleware(engine, [], [ SHOULD_SAVE ]); ``` +If you want to skip dispatching a redux action everytime something gets saved, +just specify it to the option object, which is the fourth argument. + +```js +import { createMiddleware } from 'redux-storage' + +import { SHOULD_SAVE } from './constants'; + +const middleware = createMiddleware(engine, [], [], { disableDispatchSaveAction: true }); +``` + # A fork of [redux-storage](https://github.com/michaelcontento/redux-storage) The original author of the package [redux-storage](https://github.com/michaelcontento/redux-storage) has decided to deprecate the project and no longer maintained. The package will now be maintained here. From 8f0c1bd946ffd8536dde10439803caaade049553 Mon Sep 17 00:00:00 2001 From: Renan Bandeira Date: Thu, 10 Sep 2020 09:34:37 -0300 Subject: [PATCH 20/22] Adds Collaborator --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 62ee465..ce8471f 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ ], "author": [ "Michael Contento ", - "Guns " + "Guns ", + "Renan Bandeira " ], "files": [ "build/", From f1aebf7f029c53eb3c530e2f0dd577b4bda8293b Mon Sep 17 00:00:00 2001 From: Renan Bandeira Date: Thu, 10 Sep 2020 09:35:54 -0300 Subject: [PATCH 21/22] Release 4.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce8471f..f3f9602 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-storage", - "version": "4.1.2", + "version": "4.1.3", "description": "Persistence layer for redux with flexible backends", "main": "build/index.js", "jsnext:main": "build-es/index.js", From f7d1fbe711cefb805d1f17ccb5d5bc312c738e2c Mon Sep 17 00:00:00 2001 From: Renan Bandeira Date: Fri, 11 Sep 2020 07:38:30 -0300 Subject: [PATCH 22/22] Sends build folder to git --- .gitignore | 4 +- build-es/__tests__/createMiddleware-test.js | 271 +++++++++++++++++++ build-es/__tests__/index-test.js | 35 +++ build-es/__tests__/reducer-test.js | 42 +++ build-es/actions.js | 8 + build-es/constants.js | 4 + build-es/createLoader.js | 15 ++ build-es/createMiddleware.js | 112 ++++++++ build-es/index.js | 15 ++ build-es/reducer.js | 13 + build/__tests__/createMiddleware-test.js | 276 ++++++++++++++++++++ build/__tests__/index-test.js | 37 +++ build/__tests__/reducer-test.js | 47 ++++ build/actions.js | 17 ++ build/constants.js | 7 + build/createLoader.js | 19 ++ build/createMiddleware.js | 124 +++++++++ build/index.js | 58 ++++ build/reducer.js | 21 ++ package.json | 2 +- 20 files changed, 1124 insertions(+), 3 deletions(-) create mode 100644 build-es/__tests__/createMiddleware-test.js create mode 100644 build-es/__tests__/index-test.js create mode 100644 build-es/__tests__/reducer-test.js create mode 100644 build-es/actions.js create mode 100644 build-es/constants.js create mode 100644 build-es/createLoader.js create mode 100644 build-es/createMiddleware.js create mode 100644 build-es/index.js create mode 100644 build-es/reducer.js create mode 100644 build/__tests__/createMiddleware-test.js create mode 100644 build/__tests__/index-test.js create mode 100644 build/__tests__/reducer-test.js create mode 100644 build/actions.js create mode 100644 build/constants.js create mode 100644 build/createLoader.js create mode 100644 build/createMiddleware.js create mode 100644 build/index.js create mode 100644 build/reducer.js diff --git a/.gitignore b/.gitignore index ba45838..ae3bb0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # build artefacts -/build/ -/build-es/ +# /build/ +# /build-es/ # npm /node_modules/ diff --git a/build-es/__tests__/createMiddleware-test.js b/build-es/__tests__/createMiddleware-test.js new file mode 100644 index 0000000..dd0fb80 --- /dev/null +++ b/build-es/__tests__/createMiddleware-test.js @@ -0,0 +1,271 @@ +'use strict'; + +import createMiddleware from '../createMiddleware'; +import { LOAD, SAVE } from '../constants'; + +describe('createMiddleware', function () { + var oldEnv = void 0; + beforeEach(function () { + oldEnv = process.env.NODE_ENV; + process.env.NODE_ENV = 'production'; + }); + + afterEach(function () { + process.env.NODE_ENV = oldEnv; + }); + + function describeConsoleWarnInNonProduction(msg, cb, msgCheck) { + describe(msg, function () { + var warn = void 0; + + beforeEach(function () { + warn = sinon.stub(console, 'warn'); + }); + + afterEach(function () { + warn.restore(); + }); + + it('should warn if NODE_ENV != production', function () { + process.env.NODE_ENV = 'develop'; + cb(); + warn.should.have.been.called; + if (msgCheck) { + msgCheck(warn.firstCall.args[0]); + } + }); + + it('should NOT warn if NODE_ENV == production', function () { + process.env.NODE_ENV = 'production'; + cb(); + warn.should.not.have.been.called; + }); + }); + } + + it('should call next with the given action', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + createMiddleware(engine)(store)(next)(action); + + next.should.have.been.calledWith(action); + }); + + it('should return the result of next', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.stub().returns('nextResult'); + var action = { type: 'dummy' }; + + var result = createMiddleware(engine)(store)(next)(action); + + result.should.equal('nextResult'); + }); + + it('should ignore blacklisted actions', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: 'IGNORE_ME' }; + + createMiddleware(engine, ['IGNORE_ME'])(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should ignore non-whitelisted actions', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: 'IGNORE_ME' }; + + createMiddleware(engine, [], ['ALLOWED'])(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should process whitelisted actions', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + + createMiddleware(engine, [], ['ALLOWED'])(store)(next)(action); + + engine.save.should.have.been.called; + }); + + it('should allow whitelist function', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn() { + return true; + }; + + createMiddleware(engine, [], whitelistFn)(store)(next)(action); + + engine.save.should.have.been.called; + }); + + it('should ignore actions if the whitelist function returns false', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn() { + return false; + }; + + createMiddleware(engine, [], whitelistFn)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should pass the whole action to the whitelist function', function (done) { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn(checkAction) { + checkAction.should.deep.equal(action); + done(); + }; + + createMiddleware(engine, [], whitelistFn)(store)(next)(action); + }); + + describeConsoleWarnInNonProduction('should not process functions', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = function action() {}; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('but received a function'); + }); + + describeConsoleWarnInNonProduction('should not process strings', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = 'haha'; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('but received: haha'); + }); + + describeConsoleWarnInNonProduction('should not process objects without a type', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { noType: 'damn it' }; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('objects should have a type property'); + }); + + describeConsoleWarnInNonProduction('should warn about action on both black- and whitelist', function () { + var engine = {}; + createMiddleware(engine, ['A'], ['A']); + }); + + it('should pass the current state to engine.save', function () { + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { getState: sinon.stub().returns(state) }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.have.been.calledWith(state); + }); + + it('should trigger a SAVE action after engine.save', function (done) { + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { + getState: sinon.stub().returns(state), + dispatch: sinon.spy() + }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + createMiddleware(engine)(store)(next)(action); + + setTimeout(function () { + var saveAction = { payload: state, type: SAVE }; + store.dispatch.should.have.been.calledWith(saveAction); + done(); + }, 5); + }); + + it('should add the parent action as meta.origin to the saveAction', function (done) { + process.env.NODE_ENV = 'develop'; + + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { + getState: sinon.stub().returns(state), + dispatch: sinon.spy() + }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + createMiddleware(engine)(store)(next)(action); + + setTimeout(function () { + var saveAction = { payload: state, type: SAVE, meta: { origin: action } }; + store.dispatch.should.have.been.calledWith(saveAction); + done(); + }, 5); + }); + + it('should do nothing if engine.save fails', function () { + var engine = { save: sinon.stub().rejects() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + createMiddleware(engine)(store)(next)(action); + }); + + it('should always ignore SAVE action', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: SAVE }; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should always ignore LOAD action', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: LOAD }; + + createMiddleware(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); +}); \ No newline at end of file diff --git a/build-es/__tests__/index-test.js b/build-es/__tests__/index-test.js new file mode 100644 index 0000000..c11d6c4 --- /dev/null +++ b/build-es/__tests__/index-test.js @@ -0,0 +1,35 @@ +'use strict'; + +var _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; }; + +import defaultImport from '../'; +import * as fullImport from '../'; +import { LOAD, SAVE, createLoader, createMiddleware, reducer } from '../'; + +describe('index', function () { + it('should export everything by default', function () { + // NOTE: the new object is created to include the "default" key + // that exists in fullImport + fullImport.should.be.deep.equal(_extends({}, defaultImport, { 'default': defaultImport })); + }); + + it('should export LOAD', function () { + LOAD.should.be.a.string; + }); + + it('should export SAVE', function () { + SAVE.should.be.a.string; + }); + + it('should export createLoader', function () { + createLoader.should.be.a.func; + }); + + it('should export createMiddleware', function () { + createMiddleware.should.be.a.func; + }); + + it('should export reducer', function () { + reducer.should.be.a.func; + }); +}); \ No newline at end of file diff --git a/build-es/__tests__/reducer-test.js b/build-es/__tests__/reducer-test.js new file mode 100644 index 0000000..86d1959 --- /dev/null +++ b/build-es/__tests__/reducer-test.js @@ -0,0 +1,42 @@ +'use strict'; + +import reducer from '../reducer'; +import { LOAD } from '../constants'; + +describe('reducer', function () { + it('should do nothing for non LOAD actions', function () { + var spy = sinon.spy(); + var oldState = {}; + var action = { type: 'SOMETHING', payload: {} }; + + reducer(spy)(oldState, action); + + spy.should.have.been.calledWith(oldState, action); + }); + + it('should have a default merger in place', function () { + var spy = sinon.spy(); + var oldState = { x: 0, y: 0 }; + var action = { type: LOAD, payload: { y: 42 } }; + + reducer(spy)(oldState, action); + + spy.should.have.been.calledWith({ x: 0, y: 42 }, action); + }); + + it('should allow me to change the merger', function () { + var spy = sinon.spy(); + var oldState = { x: 0, y: 0 }; + var action = { type: LOAD, payload: { y: 42 } }; + + var merger = function merger(a, b) { + a.should.equal(oldState); + b.should.deep.equal({ y: 42 }); + return { c: 1 }; + }; + + reducer(spy, merger)(oldState, action); + + spy.should.have.been.calledWith({ c: 1 }, action); + }); +}); \ No newline at end of file diff --git a/build-es/actions.js b/build-es/actions.js new file mode 100644 index 0000000..81bbf7f --- /dev/null +++ b/build-es/actions.js @@ -0,0 +1,8 @@ +'use strict'; + +import { createAction } from 'redux-actions'; + +import * as constants from './constants'; + +export var load = createAction(constants.LOAD); +export var save = createAction(constants.SAVE); \ No newline at end of file diff --git a/build-es/constants.js b/build-es/constants.js new file mode 100644 index 0000000..efc4a2b --- /dev/null +++ b/build-es/constants.js @@ -0,0 +1,4 @@ +'use strict'; + +export var LOAD = 'REDUX_STORAGE_LOAD'; +export var SAVE = 'REDUX_STORAGE_SAVE'; \ No newline at end of file diff --git a/build-es/createLoader.js b/build-es/createLoader.js new file mode 100644 index 0000000..1a99eaf --- /dev/null +++ b/build-es/createLoader.js @@ -0,0 +1,15 @@ +'use strict'; + +import { load as actionLoad } from './actions'; + +export default (function (engine) { + return function (store) { + var dispatchLoad = function dispatchLoad(state) { + return store.dispatch(actionLoad(state)); + }; + return engine.load().then(function (newState) { + dispatchLoad(newState); + return newState; + }); + }; +}); \ No newline at end of file diff --git a/build-es/createMiddleware.js b/build-es/createMiddleware.js new file mode 100644 index 0000000..22f3f04 --- /dev/null +++ b/build-es/createMiddleware.js @@ -0,0 +1,112 @@ +'use strict'; + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +import isFunction from 'lodash.isfunction'; +import isObject from 'lodash.isobject'; + +import { save as actionSave } from './actions'; +import { LOAD, SAVE } from './constants'; + +function swallow() {} + +function warnAboutConfusingFiltering(blacklist, whitelist) { + blacklist.filter(function (item) { + return whitelist.indexOf(item) !== -1; + }).forEach(function (item) { + console.warn( // eslint-disable-line no-console + '[redux-storage] Action ' + item + ' is on BOTH black- and whitelist.' + ' This is most likely a mistake!'); + }); +} + +function isValidAction(action) { + var isFunc = isFunction(action); + var isObj = isObject(action); + var hasType = isObj && action.hasOwnProperty('type'); + + if (!isFunc && isObj && hasType) { + return true; + } + + if (process.env.NODE_ENV !== 'production') { + if (isFunc) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Actions should be objects' + ' with a type property but received a function! Your' + ' function resolving middleware (e.g. redux-thunk) must be' + ' placed BEFORE redux-storage!'); + } else if (!isObj) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Actions should be objects' + (' with a type property but received: ' + action)); + } else if (!hasType) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Action objects should have' + ' a type property.'); + } + } + + return false; +} + +function handleWhitelist(action, actionWhitelist) { + if (Array.isArray(actionWhitelist)) { + return actionWhitelist.length === 0 ? true // Don't filter if the whitelist is empty + : actionWhitelist.indexOf(action.type) !== -1; + } + + // actionWhitelist is a function that returns true or false + return actionWhitelist(action); +} + +export default (function (engine) { + var actionBlacklist = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var actionWhitelist = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + var opts = Object.assign({ disableDispatchSaveAction: false }, options); + + // Also don't save if we process our own actions + var blacklistedActions = [].concat(_toConsumableArray(actionBlacklist), [LOAD, SAVE]); + + if (process.env.NODE_ENV !== 'production' && Array.isArray(actionWhitelist)) { + warnAboutConfusingFiltering(actionBlacklist, actionWhitelist); + } + + return function (_ref) { + var dispatch = _ref.dispatch, + getState = _ref.getState; + + return function (next) { + return function (action) { + var result = next(action); + + if (!isValidAction(action)) { + return result; + } + + var isOnBlacklist = blacklistedActions.indexOf(action.type) !== -1; + var isOnWhitelist = handleWhitelist(action, actionWhitelist); + + // Skip blacklisted actions + if (!isOnBlacklist && isOnWhitelist) { + var saveState = getState(); + var saveAction = actionSave(saveState); + + if (process.env.NODE_ENV !== 'production') { + if (!saveAction.meta) { + saveAction.meta = {}; + } + saveAction.meta.origin = action; + } + + var dispatchSave = function dispatchSave() { + return dispatch(saveAction); + }; + engine.save(saveState).then(function () { + if (opts.disableDispatchSaveAction === false) { + return dispatchSave(); + } + })['catch'](swallow); + } + + return result; + }; + }; + }; +}); \ No newline at end of file diff --git a/build-es/index.js b/build-es/index.js new file mode 100644 index 0000000..52d7ab7 --- /dev/null +++ b/build-es/index.js @@ -0,0 +1,15 @@ +'use strict'; + +var _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; }; + +export { default as createLoader } from './createLoader'; +export { default as createMiddleware } from './createMiddleware'; +export { default as reducer } from './reducer'; +export { LOAD, SAVE } from './constants'; + +// The full default export is required to be BC with redux-storage <= v1.3.2 +export default _extends({}, require('./constants'), { + createLoader: require('./createLoader')['default'], + createMiddleware: require('./createMiddleware')['default'], + reducer: require('./reducer')['default'] +}); \ No newline at end of file diff --git a/build-es/reducer.js b/build-es/reducer.js new file mode 100644 index 0000000..b2c07d5 --- /dev/null +++ b/build-es/reducer.js @@ -0,0 +1,13 @@ +'use strict'; + +import simpleMerger from 'redux-storage-merger-simple'; + +import { LOAD } from './constants'; + +export default (function (reducer) { + var merger = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : simpleMerger; + + return function (state, action) { + return reducer(action.type === LOAD ? merger(state, action.payload) : state, action); + }; +}); \ No newline at end of file diff --git a/build/__tests__/createMiddleware-test.js b/build/__tests__/createMiddleware-test.js new file mode 100644 index 0000000..86c3007 --- /dev/null +++ b/build/__tests__/createMiddleware-test.js @@ -0,0 +1,276 @@ +'use strict'; + +var _createMiddleware = require('../createMiddleware'); + +var _createMiddleware2 = _interopRequireDefault(_createMiddleware); + +var _constants = require('../constants'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +describe('createMiddleware', function () { + var oldEnv = void 0; + beforeEach(function () { + oldEnv = process.env.NODE_ENV; + process.env.NODE_ENV = 'production'; + }); + + afterEach(function () { + process.env.NODE_ENV = oldEnv; + }); + + function describeConsoleWarnInNonProduction(msg, cb, msgCheck) { + describe(msg, function () { + var warn = void 0; + + beforeEach(function () { + warn = sinon.stub(console, 'warn'); + }); + + afterEach(function () { + warn.restore(); + }); + + it('should warn if NODE_ENV != production', function () { + process.env.NODE_ENV = 'develop'; + cb(); + warn.should.have.been.called; + if (msgCheck) { + msgCheck(warn.firstCall.args[0]); + } + }); + + it('should NOT warn if NODE_ENV == production', function () { + process.env.NODE_ENV = 'production'; + cb(); + warn.should.not.have.been.called; + }); + }); + } + + it('should call next with the given action', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + next.should.have.been.calledWith(action); + }); + + it('should return the result of next', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.stub().returns('nextResult'); + var action = { type: 'dummy' }; + + var result = (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + result.should.equal('nextResult'); + }); + + it('should ignore blacklisted actions', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: 'IGNORE_ME' }; + + (0, _createMiddleware2['default'])(engine, ['IGNORE_ME'])(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should ignore non-whitelisted actions', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: 'IGNORE_ME' }; + + (0, _createMiddleware2['default'])(engine, [], ['ALLOWED'])(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should process whitelisted actions', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + + (0, _createMiddleware2['default'])(engine, [], ['ALLOWED'])(store)(next)(action); + + engine.save.should.have.been.called; + }); + + it('should allow whitelist function', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn() { + return true; + }; + + (0, _createMiddleware2['default'])(engine, [], whitelistFn)(store)(next)(action); + + engine.save.should.have.been.called; + }); + + it('should ignore actions if the whitelist function returns false', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn() { + return false; + }; + + (0, _createMiddleware2['default'])(engine, [], whitelistFn)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should pass the whole action to the whitelist function', function (done) { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'ALLOWED' }; + var whitelistFn = function whitelistFn(checkAction) { + checkAction.should.deep.equal(action); + done(); + }; + + (0, _createMiddleware2['default'])(engine, [], whitelistFn)(store)(next)(action); + }); + + describeConsoleWarnInNonProduction('should not process functions', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = function action() {}; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('but received a function'); + }); + + describeConsoleWarnInNonProduction('should not process strings', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = 'haha'; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('but received: haha'); + }); + + describeConsoleWarnInNonProduction('should not process objects without a type', function () { + var engine = { save: sinon.stub().resolves() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { noType: 'damn it' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }, function (msg) { + msg.should.contain('ACTION IGNORED!'); + msg.should.contain('objects should have a type property'); + }); + + describeConsoleWarnInNonProduction('should warn about action on both black- and whitelist', function () { + var engine = {}; + (0, _createMiddleware2['default'])(engine, ['A'], ['A']); + }); + + it('should pass the current state to engine.save', function () { + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { getState: sinon.stub().returns(state) }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.have.been.calledWith(state); + }); + + it('should trigger a SAVE action after engine.save', function (done) { + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { + getState: sinon.stub().returns(state), + dispatch: sinon.spy() + }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + setTimeout(function () { + var saveAction = { payload: state, type: _constants.SAVE }; + store.dispatch.should.have.been.calledWith(saveAction); + done(); + }, 5); + }); + + it('should add the parent action as meta.origin to the saveAction', function (done) { + process.env.NODE_ENV = 'develop'; + + var engine = { save: sinon.stub().resolves() }; + var state = { x: 42 }; + var store = { + getState: sinon.stub().returns(state), + dispatch: sinon.spy() + }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + setTimeout(function () { + var saveAction = { payload: state, type: _constants.SAVE, meta: { origin: action } }; + store.dispatch.should.have.been.calledWith(saveAction); + done(); + }, 5); + }); + + it('should do nothing if engine.save fails', function () { + var engine = { save: sinon.stub().rejects() }; + var store = { getState: sinon.spy() }; + var next = sinon.spy(); + var action = { type: 'dummy' }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + }); + + it('should always ignore SAVE action', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: _constants.SAVE }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); + + it('should always ignore LOAD action', function () { + var engine = { save: sinon.spy() }; + var store = {}; + var next = sinon.spy(); + var action = { type: _constants.LOAD }; + + (0, _createMiddleware2['default'])(engine)(store)(next)(action); + + engine.save.should.not.have.been.called; + }); +}); \ No newline at end of file diff --git a/build/__tests__/index-test.js b/build/__tests__/index-test.js new file mode 100644 index 0000000..4f69789 --- /dev/null +++ b/build/__tests__/index-test.js @@ -0,0 +1,37 @@ +'use strict'; + +var _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; }; + +var _ = require('../'); + +var fullImport = _interopRequireWildcard(_); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +describe('index', function () { + it('should export everything by default', function () { + // NOTE: the new object is created to include the "default" key + // that exists in fullImport + fullImport.should.be.deep.equal(_extends({}, fullImport['default'], { 'default': fullImport['default'] })); + }); + + it('should export LOAD', function () { + _.LOAD.should.be.a.string; + }); + + it('should export SAVE', function () { + _.SAVE.should.be.a.string; + }); + + it('should export createLoader', function () { + _.createLoader.should.be.a.func; + }); + + it('should export createMiddleware', function () { + _.createMiddleware.should.be.a.func; + }); + + it('should export reducer', function () { + _.reducer.should.be.a.func; + }); +}); \ No newline at end of file diff --git a/build/__tests__/reducer-test.js b/build/__tests__/reducer-test.js new file mode 100644 index 0000000..6e00a84 --- /dev/null +++ b/build/__tests__/reducer-test.js @@ -0,0 +1,47 @@ +'use strict'; + +var _reducer = require('../reducer'); + +var _reducer2 = _interopRequireDefault(_reducer); + +var _constants = require('../constants'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +describe('reducer', function () { + it('should do nothing for non LOAD actions', function () { + var spy = sinon.spy(); + var oldState = {}; + var action = { type: 'SOMETHING', payload: {} }; + + (0, _reducer2['default'])(spy)(oldState, action); + + spy.should.have.been.calledWith(oldState, action); + }); + + it('should have a default merger in place', function () { + var spy = sinon.spy(); + var oldState = { x: 0, y: 0 }; + var action = { type: _constants.LOAD, payload: { y: 42 } }; + + (0, _reducer2['default'])(spy)(oldState, action); + + spy.should.have.been.calledWith({ x: 0, y: 42 }, action); + }); + + it('should allow me to change the merger', function () { + var spy = sinon.spy(); + var oldState = { x: 0, y: 0 }; + var action = { type: _constants.LOAD, payload: { y: 42 } }; + + var merger = function merger(a, b) { + a.should.equal(oldState); + b.should.deep.equal({ y: 42 }); + return { c: 1 }; + }; + + (0, _reducer2['default'])(spy, merger)(oldState, action); + + spy.should.have.been.calledWith({ c: 1 }, action); + }); +}); \ No newline at end of file diff --git a/build/actions.js b/build/actions.js new file mode 100644 index 0000000..03e0ff8 --- /dev/null +++ b/build/actions.js @@ -0,0 +1,17 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.save = exports.load = undefined; + +var _reduxActions = require('redux-actions'); + +var _constants = require('./constants'); + +var constants = _interopRequireWildcard(_constants); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +var load = exports.load = (0, _reduxActions.createAction)(constants.LOAD); +var save = exports.save = (0, _reduxActions.createAction)(constants.SAVE); \ No newline at end of file diff --git a/build/constants.js b/build/constants.js new file mode 100644 index 0000000..05d1db5 --- /dev/null +++ b/build/constants.js @@ -0,0 +1,7 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var LOAD = exports.LOAD = 'REDUX_STORAGE_LOAD'; +var SAVE = exports.SAVE = 'REDUX_STORAGE_SAVE'; \ No newline at end of file diff --git a/build/createLoader.js b/build/createLoader.js new file mode 100644 index 0000000..cd759a1 --- /dev/null +++ b/build/createLoader.js @@ -0,0 +1,19 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _actions = require('./actions'); + +exports['default'] = function (engine) { + return function (store) { + var dispatchLoad = function dispatchLoad(state) { + return store.dispatch((0, _actions.load)(state)); + }; + return engine.load().then(function (newState) { + dispatchLoad(newState); + return newState; + }); + }; +}; \ No newline at end of file diff --git a/build/createMiddleware.js b/build/createMiddleware.js new file mode 100644 index 0000000..8787f62 --- /dev/null +++ b/build/createMiddleware.js @@ -0,0 +1,124 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _lodash = require('lodash.isfunction'); + +var _lodash2 = _interopRequireDefault(_lodash); + +var _lodash3 = require('lodash.isobject'); + +var _lodash4 = _interopRequireDefault(_lodash3); + +var _actions = require('./actions'); + +var _constants = require('./constants'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + +function swallow() {} + +function warnAboutConfusingFiltering(blacklist, whitelist) { + blacklist.filter(function (item) { + return whitelist.indexOf(item) !== -1; + }).forEach(function (item) { + console.warn( // eslint-disable-line no-console + '[redux-storage] Action ' + item + ' is on BOTH black- and whitelist.' + ' This is most likely a mistake!'); + }); +} + +function isValidAction(action) { + var isFunc = (0, _lodash2['default'])(action); + var isObj = (0, _lodash4['default'])(action); + var hasType = isObj && action.hasOwnProperty('type'); + + if (!isFunc && isObj && hasType) { + return true; + } + + if (process.env.NODE_ENV !== 'production') { + if (isFunc) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Actions should be objects' + ' with a type property but received a function! Your' + ' function resolving middleware (e.g. redux-thunk) must be' + ' placed BEFORE redux-storage!'); + } else if (!isObj) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Actions should be objects' + (' with a type property but received: ' + action)); + } else if (!hasType) { + console.warn( // eslint-disable-line no-console + '[redux-storage] ACTION IGNORED! Action objects should have' + ' a type property.'); + } + } + + return false; +} + +function handleWhitelist(action, actionWhitelist) { + if (Array.isArray(actionWhitelist)) { + return actionWhitelist.length === 0 ? true // Don't filter if the whitelist is empty + : actionWhitelist.indexOf(action.type) !== -1; + } + + // actionWhitelist is a function that returns true or false + return actionWhitelist(action); +} + +exports['default'] = function (engine) { + var actionBlacklist = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var actionWhitelist = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + var opts = Object.assign({ disableDispatchSaveAction: false }, options); + + // Also don't save if we process our own actions + var blacklistedActions = [].concat(_toConsumableArray(actionBlacklist), [_constants.LOAD, _constants.SAVE]); + + if (process.env.NODE_ENV !== 'production' && Array.isArray(actionWhitelist)) { + warnAboutConfusingFiltering(actionBlacklist, actionWhitelist); + } + + return function (_ref) { + var dispatch = _ref.dispatch, + getState = _ref.getState; + + return function (next) { + return function (action) { + var result = next(action); + + if (!isValidAction(action)) { + return result; + } + + var isOnBlacklist = blacklistedActions.indexOf(action.type) !== -1; + var isOnWhitelist = handleWhitelist(action, actionWhitelist); + + // Skip blacklisted actions + if (!isOnBlacklist && isOnWhitelist) { + var saveState = getState(); + var saveAction = (0, _actions.save)(saveState); + + if (process.env.NODE_ENV !== 'production') { + if (!saveAction.meta) { + saveAction.meta = {}; + } + saveAction.meta.origin = action; + } + + var dispatchSave = function dispatchSave() { + return dispatch(saveAction); + }; + engine.save(saveState).then(function () { + if (opts.disableDispatchSaveAction === false) { + return dispatchSave(); + } + })['catch'](swallow); + } + + return result; + }; + }; + }; +}; \ No newline at end of file diff --git a/build/index.js b/build/index.js new file mode 100644 index 0000000..c96116f --- /dev/null +++ b/build/index.js @@ -0,0 +1,58 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _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; }; + +var _createLoader = require('./createLoader'); + +Object.defineProperty(exports, 'createLoader', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_createLoader)['default']; + } +}); + +var _createMiddleware = require('./createMiddleware'); + +Object.defineProperty(exports, 'createMiddleware', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_createMiddleware)['default']; + } +}); + +var _reducer = require('./reducer'); + +Object.defineProperty(exports, 'reducer', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_reducer)['default']; + } +}); + +var _constants = require('./constants'); + +Object.defineProperty(exports, 'LOAD', { + enumerable: true, + get: function get() { + return _constants.LOAD; + } +}); +Object.defineProperty(exports, 'SAVE', { + enumerable: true, + get: function get() { + return _constants.SAVE; + } +}); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +// The full default export is required to be BC with redux-storage <= v1.3.2 +exports['default'] = _extends({}, require('./constants'), { + createLoader: require('./createLoader')['default'], + createMiddleware: require('./createMiddleware')['default'], + reducer: require('./reducer')['default'] +}); \ No newline at end of file diff --git a/build/reducer.js b/build/reducer.js new file mode 100644 index 0000000..647028d --- /dev/null +++ b/build/reducer.js @@ -0,0 +1,21 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _reduxStorageMergerSimple = require('redux-storage-merger-simple'); + +var _reduxStorageMergerSimple2 = _interopRequireDefault(_reduxStorageMergerSimple); + +var _constants = require('./constants'); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +exports['default'] = function (reducer) { + var merger = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _reduxStorageMergerSimple2['default']; + + return function (state, action) { + return reducer(action.type === _constants.LOAD ? merger(state, action.payload) : state, action); + }; +}; \ No newline at end of file diff --git a/package.json b/package.json index f3f9602..70d8b33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "redux-storage", - "version": "4.1.3", + "version": "4.1.4", "description": "Persistence layer for redux with flexible backends", "main": "build/index.js", "jsnext:main": "build-es/index.js",