Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

redux-promise-middleware

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redux-promise-middleware - npm Package Compare versions

Comparing version
2.3.3
to
2.4.0
+4
.babelrc
{
"stage": 0,
"loose": "all"
}
language: node_js
node_js:
- "4.1"
{
"stage": 0,
"loose": [
"es6.modules"
],
"env": {
"development": {
"plugins": [
"react-transform"
],
"extra": {
"react-transform": [
{
"target": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
},
{
"target": "react-transform-catch-errors",
"imports": ["react", "redbox-react"]
}
]
}
},
"production": {
"plugins": [
"react-display-name"
]
}
}
}
import * as types from '../constants/post';
import * as utils from '../utils/server/resources/post';
export function getAllPosts() {
return {
type: types.GET_POSTS,
payload: {
promise: utils.getAllPosts(),
onSuccess: () => null,
onError: () => null
}
};
}
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
class App extends Component {
render() {
return (
<div className="app-container">
<Provider store={store()}>
<h1>Hi</h1>
</Provider>
</div>
);
}
}
render(<App />, document.querySelector('#mount'));
export const GET_POSTS = 'GET_POSTS';
<!doctype html><body><div id="mount"></div><script src="/app.js"></script></body>
{
"private": true,
"author": "Patrick Burtchaell <patrick@pburtchaell.com>",
"license": "MIT",
"scripts": {
"start": "NODE_ENV=development node server.js"
},
"devDependencies": {
"babel-core": "^5.8.25",
"babel-loader": "^5.3.2",
"babel-plugin-react-display-name": "^2.0.0",
"babel-plugin-react-transform": "^1.1.1",
"eventsource-polyfill": "^0.9.6",
"express": "^4.13.3",
"morgan": "^1.6.1",
"react-transform-catch-errors": "^1.0.0",
"react-transform-hmr": "^1.0.1",
"redbox-react": "^1.1.1",
"webpack": "^1.12.2",
"webpack-dev-middleware": "^1.2.0",
"webpack-hot-middleware": "^2.2.1"
},
"dependencies": {
"core-js": "^1.2.0",
"isomorphic-fetch": "^2.1.1",
"js-schema": "^1.0.1",
"react": "^0.14.0",
"react-dom": "^0.14.0",
"react-redux": "^4.0.0",
"redux": "^3.0.4",
"regenerator": "^0.8.40"
}
}
# Promise Middleware Example
This example demonstrates using the promise middleware to make async requests to a REST API that follows [the JSON API standard v1.0](http://jsonapi.org).
Uses:
- Redux 3.x
- React 14.x + React DOM
- Fetch API
- Babel + WebPack
## Getting Started
1. Install dependencies `npm install`
2. Start the app: `npm start`
export default {
isPending: null,
isFulfilled: null,
isRejected: null,
error: null,
data: null
};
import { combineReducers } from 'redux';
export default combineReducers({
posts: require('./posts')
});
import * as types from '../constants/post';
import defaultState from './defaultState';
/*
* @function post
* @description This reducer holds the state of a post after it is fetched
* from the server.
* @param {object} state The previous state
* @param {object} action The dispatched action
* @returns {object} state The updated state
*/
export default function posts(state = defaultState, action) {
switch (action.type) {
case `${types.GET_POSTS}_PENDING`:
return {
...defaultState,
isPending: true
};
case `${types.GET_POSTS}_FULFILLED`:
return {
...defaultState,
isFulfilled: true,
error: false,
data: action.payload
};
case `${types.GET_POSTS}_REJECTED`:
return {
...defaultState,
isRejected: true,
error: action.payload
};
default: return state;
}
}
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.local.config');
var port = process.env.PORT || config.devPort;
var address = config.devAddress;
var app = express();
var compiler = webpack(config);
// Logging
app.use(require('morgan')('short'));
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000
}));
app.get('*', function (req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
/**
* Mock a fake REST API for creating posts.
*
app.get('/api/v1/posts', function (req, res) {
res.json({
data: [
{
type: 'posts',
id: '1LOL234',
attributes: {
title: res.param.title,
author: res.param.author,
body: res.param.body
}
}
]
});
});*/
/**
* Mock a fake REST API for getting posts.
*
app.post('/api/v1/posts/:id', function (req, res) {
var id = req.param.id;
res.json({
data: [
{
type: 'posts',
id: 'post-' + id,
attributes: {
title: 'This is teh post title for ' + id,
author: 'Yo',
body: 'This is the post text for ' + id
}
}
]
});
});*/
app.listen(port, address, function (error) {
if (error) throw error;
console.log('server running at http://%s:%d', address, port);
});
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware(
require('./utils/middleware/promise')()
)(createStore);
export default function store(initialState) {
const store = createStoreWithMiddleware(reducers, initialState);
if (module.hot) {
require('eventsource-polyfill');
// Enable Webpack hot module replacement for reducers
module.hot.accept('./reducers', () => {
const nextRootReducer = require('./reducers');
store.replaceReducer(reducers);
});
}
if (NODE_ENV === 'development') {
window.store = store.getState();
}
return store;
}
export default function buildURL(resource, id) {
const base = '/api/v1';
return id ? `${base}/${resource}/${id}` : `${base}/${resource}`;
};
export default function isPromise(value) {
if (value !== null && typeof value === 'object') {
return value.promise && typeof value.promise.then === 'function';
}
}
import isPromise from './isPromise';
const defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED'];
export default function promiseMiddleware(config={}) {
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypes;
return () => {
return next => action => {
if (!isPromise(action.payload)) {
return next(action);
}
const { type, payload, meta } = action;
const { promise, data } = payload;
const [ PENDING, FULFILLED, REJECTED ] = (meta || {}).promiseTypeSuffixes || promiseTypeSuffixes;
/**
* Dispatch the first async handler. This tells the
* reducer that an async action has been dispatched.
*/
next({
type: `${type}_${PENDING}`,
payload: data,
...meta ? { meta } : {}
});
/**
* Return either the fulfilled action object or the rejected
* action object.
*/
return promise.then(
payload => next({ // eslint-disable-line no-shadow
payload,
type: `${type}_${FULFILLED}`,
...meta ? { meta } : {}
}),
error => next({
payload: error,
error: true,
type: `${type}_${REJECTED}`,
...meta ? { meta } : {}
})
);
};
};
}
import 'core-js/shim';
import 'regenerator/runtime';
import 'isomorphic-fetch';
/**
* @private
* @function request
* @description Make a request to the server and return a promise.
* @param {string} url
* @param {object} options
* @returns {promise}
*/
export default function request(url, options) {
return new Promise((resolve, reject) => {
if (!url) {
reject(new Error('There is no URL provided for the request.'));
}
if (!options) {
reject(new Error('There are no options provided for the request.'));
}
fetch(url, options).then(response => {
return response.json();
}).then(response => {
if (response.status >= 200 && response.status < 300) {
return response.errors ? reject(response.errors) : reject(response);
} else {
return resolve(response)
}
}).catch(error => {
reject(error);
});
});
}
const Post = require('../server')('post');
export function getAllPosts() {
return Post.get();
}
import request from './request';
import buildURL from './buildURL';
/**
* @function Server
* @description Factory function to create a object that can send
* requests to a specific resource on the server.
* @param {string} resource The resource used for config
*/
export const Server = (resource) => {
// Default options used for every request
const defaultOptions = {
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Parse-Application-Id': PARSE_APPLICATION_ID,
'X-Parse-REST-API-Key': PARSE_REST_API_KEY
}
};
return {
/**
* @function post
* @description Make a POST request.
* @param {string} path
* @param {object} body
* @param {object} options
* @returns {promise}
*/
post: (path, body, options = {}) => {
return request(buildURL(path), Object.assign(
options,
defaultOptions,
{
method: 'POST',
body: JSON.stringify(body)
}
));
},
/**
* @function post
* @description Make a GET request.
* @param {string} path
* @param {object} options
* @returns {promise}
*/
get: (path, options = {}) => {
return request(buildURL(path), Object.assign(
options,
defaultOptions,
{ method: 'GET' }
));
},
/**
* @function edit
* @description Make a PUT request.
* @param {string} path
* @param {object} body
* @param {object} options
* @returns {promise}
*/
edit: (path, body, options = {}) => {
return request(buildURL(path), Object.assign(
options,
defaultOptions,
{ method: 'PUT' }
));
},
/**
* @function delete
* @description Make a DELETE request.
* @param {string} path
* @param {object} options
* @returns {promise}
*/
delete: (path, options = {}) => {
return request(buildURL(path), Object.assign(
options,
defaultOptions,
{ method: 'DELETE' }
));
}
};
};
var path = require('path');
var webpack = require('webpack');
var pathToReact = '/node_modules/react/react.js';
var pathToRedux = '/node_modules/redux/lib/index.js';
var pathToReduxReact = '/node_modules/redux/react.js';
// Local development server port and address
var port = 8000;
var address = '0.0.0.0';
/**
* This is the Webpack configuration file for local development. It contains
* local-specific configuration such as the React Hot Loader, as well as:
* - The entry point of the application
* - Where the output file should be
* - Which loaders to use on what files to properly transpile the source
* For more information, see: http://webpack.github.io/docs/configuration.html
*/
module.exports = {
// Efficiently evaluate modules with source maps
devtool: 'eval',
// Configure local server
devPort: port,
devAddress: address,
// Cache the build
cache: true,
entry: {
app: [
'webpack-hot-middleware/client',
path.resolve(__dirname, './client')
]
},
/**
* Instead of making Webpack go through React and all its dependencies,
* you can override the behavior in development.
*/
resolve: {
extensions: ['', '.js', '.less', '.woff', '.woff2', '.png', '.jpg'],
modulesDirectories: ['node_modules', 'app']
},
/**
* This will not actually create a bundle.js file in ./dist.
* It is used by the dev server for dynamic hot loading.
*/
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js',
publicPath: '/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
})
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
}
],
noParse: [
pathToReact,
pathToRedux,
pathToReduxReact
]
}
};
BIN = `npm bin`
SRC_JS = $(shell find src -name "*.js")
DIST_JS = $(patsubst src/%.js, dist/%.js, $(SRC_JS))
$(DIST_JS): dist/%.js: src/%.js
@mkdir -p $(dir $@)
@$(BIN)/babel $< -o $@
# Task: js
# Builds distribution JS files for publishing to npm.
js: $(DIST_JS)
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { createStore, applyMiddleware } from 'redux';
import configureStore from 'redux-mock-store';
import promiseMiddleware from '../src';
chai.use(sinonChai);
describe('Promise Middleware:', () => {
const nextHandler = promiseMiddleware();
it('must return a function to handle next', () => {
expect(nextHandler).to.be.a('function');
expect(nextHandler.length).to.eql(1);
});
/*
Make two fake middleware to surround promiseMiddleware in chain,
Give both of them a spy property to assert on their usage
*/
// first middleware mimics redux-thunk
function firstMiddlewareThunk(ref, next) {
this.spy = sinon.spy((action) =>
typeof action === 'function'
? action(ref.dispatch, ref.getState)
: next(action)
);
return this.spy;
}
// final middleware returns the action merged with dummy data
const lastMiddlewareModfiesObject = { val: 'added-by-last-middleware' };
function lastMiddlewareModfies(next) {
this.spy = sinon.spy((action) => {
next(action);
return {
...action,
...lastMiddlewareModfiesObject
};
});
return this.spy;
}
/*
Function for creating a dumb store using fake middleware stack
*/
const makeStore = (config) => applyMiddleware(
(ref) => (next) => firstMiddlewareThunk.call(firstMiddlewareThunk, ref, next),
promiseMiddleware(config),
() => (next) => lastMiddlewareModfies.call(lastMiddlewareModfies, next)
)(createStore)(()=>null);
let store;
beforeEach(()=> {
store = makeStore();
});
afterEach(()=> {
firstMiddlewareThunk.spy.reset();
lastMiddlewareModfies.spy.reset();
});
context('When Action is Not a Promise:', () => {
const mockAction = { type: 'NOT_PROMISE' };
it('invokes next with the action', () => {
store.dispatch(mockAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(mockAction);
});
it('returns the return from next middleware', () => {
expect(store.dispatch(mockAction)).to.eql({
...mockAction,
...lastMiddlewareModfiesObject
});
});
it('does not dispatch any other actions', () => {
const mockStore = configureStore([promiseMiddleware()]);
store = mockStore({});
store.dispatch(mockAction);
expect(store.getActions()).to.eql([mockAction]);
});
});
context('When Action Has Promise Payload:', () => {
let promiseAction;
let pendingAction;
beforeEach(()=> {
promiseAction = {
type: 'HAS_PROMISE',
payload: {
promise: Promise.resolve()
}
};
pendingAction = {
type: `${promiseAction.type}_PENDING`
};
});
it('dispatches a pending action', () => {
store.dispatch(promiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(pendingAction);
});
it('optionally contains optimistic update payload from data property', () => {
const optimisticUpdate = { fake: 'data' };
// data from promise becomes payload of pending
promiseAction.payload.data = optimisticUpdate;
pendingAction.payload = optimisticUpdate;
store.dispatch(promiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(pendingAction);
});
it('optionally contains meta property', () => {
const meta = { fake: 'data' };
promiseAction.meta = meta;
pendingAction.meta = meta;
store.dispatch(promiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(pendingAction);
});
it('allows customisation of global pending action.type', () => {
const customPrefix = 'PENDIDDLE';
store = makeStore({
promiseTypeSuffixes: [customPrefix, '', '']
});
pendingAction.type = `${promiseAction.type}_${customPrefix}`;
store.dispatch(promiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(pendingAction);
});
it('allows customisation of pending action.type per dispatch', () => {
const customPrefix = 'PENDOODDLE';
const actionMeta = { promiseTypeSuffixes: [customPrefix, '', ''] };
promiseAction.meta = actionMeta;
pendingAction.type = `${promiseAction.type}_${customPrefix}`;
// FIXME: Test leak, should the promiseTypeSuffixes be in other actions?
pendingAction.meta = actionMeta;
store.dispatch(promiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(pendingAction);
});
it('returns the new promise object', () => {
expect(store.dispatch(promiseAction)).to.eql(promiseAction.payload.promise);
});
context('When Promise Rejects:', ()=> {
let rejectingPromiseAction;
let rejectedAction;
let rejectValue;
beforeEach(()=> {
rejectValue = { test: 'rejected value' };
rejectingPromiseAction = {
type: 'HAS_REJECTING_PROMISE',
payload: {
promise: Promise.reject(rejectValue)
}
};
rejectedAction = {
type: `${rejectingPromiseAction.type}_REJECTED`,
error: true,
payload: rejectValue
};
pendingAction = {
type: `${rejectingPromiseAction.type}_PENDING`
};
});
it('dispatches both pending and rejected', () => {
const mockStore = configureStore([promiseMiddleware()]);
store = mockStore({});
return store.dispatch(rejectingPromiseAction).catch(() => {
expect(store.getActions()).to.eql([pendingAction, rejectedAction]);
});
});
it('re-dispatches rejected action with error and payload from error', () => {
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(rejectedAction)
);
});
it('works when resolve is null', () => {
rejectingPromiseAction.payload.promise = Promise.reject(null);
rejectedAction = {
type: `${rejectingPromiseAction.type}_REJECTED`,
error: true
};
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(rejectedAction)
);
});
it('persists meta from original action', () => {
const metaData = { fake: 'data' };
rejectingPromiseAction.meta = metaData;
rejectedAction.meta = metaData;
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(rejectedAction)
);
});
it('allows promise to resolve thunk, pre-bound to rejected action', () => {
const thunkResolve = (action, dispatch, getState) => {
expect(action).to.eql({
type: `${rejectingPromiseAction.type}_REJECTED`,
error: true
});
expect(getState()).to.equal(store.getState());
dispatch({ ...action, foo: 'bar' });
};
rejectingPromiseAction.payload.promise = Promise.reject(thunkResolve);
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith({
type: `${rejectingPromiseAction.type}_REJECTED`,
error: true,
foo: 'bar'
})
);
});
it('allows customisation of global rejected action.type', () => {
const customPrefix = 'REJIGGLED';
store = makeStore({
promiseTypeSuffixes: ['', '', customPrefix]
});
rejectedAction.type = `${rejectingPromiseAction.type}_${customPrefix}`;
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(rejectedAction)
);
});
it('allows customisation of rejected action.type per dispatch', () => {
const customPrefix = 'REJOOGGLED';
const actionMeta = { promiseTypeSuffixes: ['', '', customPrefix] };
rejectingPromiseAction.meta = actionMeta;
rejectedAction.type = `${rejectingPromiseAction.type}_${customPrefix}`;
// FIXME: Test leak, should the promiseTypeSuffixes be in other actions?
rejectedAction.meta = actionMeta;
return store.dispatch(rejectingPromiseAction).catch(() =>
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(rejectedAction)
);
});
});
context('When Promise Fulfills', ()=> {
let fulfillingPromiseAction;
let fulfillingAction;
let fulfilledValue;
beforeEach(()=> {
fulfilledValue = { test: 'fulfilled value' };
fulfillingPromiseAction = {
type: 'HAS_FULFILLING_PROMISE',
payload: {
promise: Promise.resolve(fulfilledValue)
}
};
fulfillingAction = {
type: `${fulfillingPromiseAction.type}_FULFILLED`,
payload: fulfilledValue
};
pendingAction = {
type: `${fulfillingPromiseAction.type}_PENDING`
};
});
it('dispatches both pending and fulfilled', () => {
const mockStore = configureStore([promiseMiddleware()]);
store = mockStore({});
store.dispatch(fulfillingPromiseAction).then(() => {
expect(store.getActions()).to.eql([pendingAction, fulfillingAction]);
});
});
it('re-dispatches fulfilled action with payload from promise', async () => {
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(fulfillingAction);
});
it('works when resolve is null', async () => {
fulfillingPromiseAction.payload.promise = Promise.resolve(null);
fulfillingAction = {
type: `${fulfillingPromiseAction.type}_FULFILLED`
};
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(fulfillingAction);
});
it('persists meta from original action', async () => {
const metaData = { fake: 'data' };
fulfillingPromiseAction.meta = metaData;
fulfillingAction.meta = metaData;
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(fulfillingAction);
});
it('allows promise to resolve thunk, pre-bound to fulfilled action', async () => {
const thunkResolve = (action, dispatch, getState) => {
expect(action).to.eql({
type: `${fulfillingPromiseAction.type}_FULFILLED`
});
expect(getState()).to.equal(store.getState());
dispatch({ ...action, foo: 'bar' });
};
fulfillingPromiseAction.payload.promise = Promise.resolve(thunkResolve);
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith({
type: `${fulfillingPromiseAction.type}_FULFILLED`,
foo: 'bar'
});
});
it('allows customisation of global fulfilled action.type', async () => {
const customPrefix = 'FULFIDDLED';
store = makeStore({
promiseTypeSuffixes: ['', customPrefix, '']
});
fulfillingAction.type = `${fulfillingPromiseAction.type}_${customPrefix}`;
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(fulfillingAction);
});
it('allows customisation of fulfilled action.type per dispatch', async () => {
const customPrefix = 'FULFOODDLED';
const actionMeta = { promiseTypeSuffixes: ['', customPrefix, ''] };
fulfillingPromiseAction.meta = actionMeta;
fulfillingAction.type = `${fulfillingPromiseAction.type}_${customPrefix}`;
// FIXME: Test leak, should the promiseTypeSuffixes be in other actions?
fulfillingAction.meta = actionMeta;
await store.dispatch(fulfillingPromiseAction);
expect(lastMiddlewareModfies.spy).to.have.been.calledWith(fulfillingAction);
});
it('should log errors made during dispatch within promise', async (done)=> {
const testError = new Error('test error');
sinon.stub(console, 'error');
store = applyMiddleware(
promiseMiddleware(),
)(createStore)((state, action)=> {
if (action.type === fulfillingAction.type) {
throw testError;
}
});
await store.dispatch(fulfillingPromiseAction);
setTimeout(() => {
expect(
console.error // eslint-disable-line
).to.have.been.calledWith(testError);
console.error.restore(); // eslint-disable-line
done();
}, 0);
});
});
});
});
+18
-15

@@ -16,2 +16,3 @@ 'use strict';

var defaultTypes = ['PENDING', 'FULFILLED', 'REJECTED'];
var IS_ERROR = true;

@@ -50,14 +51,11 @@ function promiseMiddleware() {

type: type + '_' + PENDING
}, !!data ? { payload: data } : {}, !!meta ? { meta: meta } : {}));
}, !data ? {} : { payload: data }, !meta ? {} : { meta: meta }));
var isAction = function isAction(resolved) {
return resolved && (resolved.meta || resolved.payload);
};
var isThunk = function isThunk(resolved) {
return typeof resolved === 'function';
};
var getResolveAction = function getResolveAction(isError) {
var getPartialAction = function getPartialAction(isError) {
return _extends({
type: type + '_' + (isError ? REJECTED : FULFILLED)
}, !!meta ? { meta: meta } : {}, !!isError ? { error: true } : {});
}, !meta ? {} : { meta: meta }, !isError ? {} : { error: true });
};

@@ -68,18 +66,23 @@

* 1. a thunk, bound to a resolved/rejected object containing ?meta and type
* 2. the resolved/rejected object, if it looks like an action, merged into action
* 3. a resolve/rejected action with the resolve/rejected object as a payload
* 2. a resolve/rejected action with the resolve/rejected object as a payload
*/
action.payload.promise = promise.then(function () {
promise.then(function () {
var resolved = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var resolveAction = getResolveAction();
return dispatch(isThunk(resolved) ? resolved.bind(null, resolveAction) : _extends({}, resolveAction, isAction(resolved) ? resolved : _extends({}, !!resolved && { payload: resolved })));
var resolveAction = getPartialAction();
dispatch(isThunk(resolved) ? resolved.bind(null, resolveAction) : _extends({}, resolveAction, !resolved ? {} : { payload: resolved }));
}, function () {
var rejected = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var resolveAction = getResolveAction(true);
return dispatch(isThunk(rejected) ? rejected.bind(null, resolveAction) : _extends({}, resolveAction, isAction(rejected) ? rejected : _extends({}, !!rejected && { payload: rejected })));
});
var rejectedAction = getPartialAction(IS_ERROR);
dispatch(isThunk(rejected) ? rejected.bind(null, rejectedAction) : _extends({}, rejectedAction, !rejected ? {} : { payload: rejected }));
})['catch'](function (error) {
return(
// log out any errors thrown as a result of the dispatch in this promise
console.error(error)
);
} // eslint-disable-line
);
return action;
return promise;
};

@@ -86,0 +89,0 @@ };

{
"name": "redux-promise-middleware",
"version": "2.3.3",
"version": "2.4.0",
"description": "Redux middleware for handling promises",
"main": "dist/index.js",
"scripts": {
"pretest": "`npm bin`/eslint ./src/*.js",
"pretest": "eslint ./src/*.js",
"test": "mocha --compilers js:babel/register --reporter spec test/*.js",

@@ -34,2 +34,3 @@ "prepublish": "npm test && make js"

"chai": "^3.4.0",
"escope": "^3.3.0",
"eslint": "^0.24.1",

@@ -40,4 +41,4 @@ "eslint-config-airbnb": "0.0.6",

"redux": "^3.0.4",
"redux-mock-store": "0.0.2",
"sinon": "^1.17.2",
"redux-mock-store": "^1.0.2",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0"

@@ -47,4 +48,3 @@ },

"redux": "^2.0.0 || ^3.0.0"
},
"dependencies": {}
}
}
# Redux Promise Middleware
[![npm version](https://img.shields.io/npm/v/redux-promise-middleware.svg?style=flat)](https://www.npmjs.com/package/redux-promise-middleware) [![Build Status](https://travis-ci.org/pburtchaell/redux-promise-middleware.svg)](https://travis-ci.org/pburtchaell/redux-promise-middleware) [![Coverage Status](https://coveralls.io/repos/pburtchaell/redux-promise-middleware/badge.svg?branch=master&service=github)](https://coveralls.io/github/pburtchaell/redux-promise-middleware?branch=master) [![npm downloads](https://img.shields.io/npm/dm/redux-promise-middleware.svg?style=flat)](https://www.npmjs.com/package/redux-promise-middleware)
[![npm version](https://img.shields.io/npm/v/redux-promise-middleware.svg?style=flat)](https://www.npmjs.com/package/redux-promise-middleware) [![Build Status](https://travis-ci.org/pburtchaell/redux-promise-middleware.svg)](https://travis-ci.org/pburtchaell/redux-promise-middleware) [![npm downloads](https://img.shields.io/npm/dm/redux-promise-middleware.svg?style=flat)](https://www.npmjs.com/package/redux-promise-middleware)

@@ -38,3 +38,3 @@ # Getting Started

The middleware returns a [FSA compliant](https://github.com/acdlite/flux-standard-action) action for both rejected and resolved/fulfilled promises. In the case of a rejected promise, an `error` is returned. You can access the promise of the action with `payload.promise`. This is useful for chaining actions together or using `async...await` within an action creator.
The middleware returns a [FSA compliant](https://github.com/acdlite/flux-standard-action) action for both rejected and resolved/fulfilled promises. In the case of a rejected promise, an `error` is returned.

@@ -60,3 +60,3 @@ ## What is the difference between this and other promise middleware?

promise: Promise.resolve({
type: 'SECOND_ACTION_TYPE'
type: 'SECEOND_ACTION_TYPE'
payload: ...

@@ -74,3 +74,3 @@ })

payload: {
promise: Promise.resolve((action, dispatch, getState) => {
promise: Promise.resolve((dispatch, getState) => {
dispatch({ type: 'SECEOND_ACTION_TYPE', payload: ... })

@@ -83,4 +83,2 @@ dispatch(someActionCreator())

Note that this behavior uses thunks, so you will need to include [thunk middleware](https://github.com/gaearon/redux-thunk) in your middleware stack.
## Type suffix configuration

@@ -87,0 +85,0 @@

Sorry, the diff of this file is not supported yet