1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 | 1x
1x
22x
1x
21x
1x
20x
1x
19x
19x
19x
1x
1x
1x
1x
1x
1x
57x
57x
57x
57x
57x
40x
39x
37x
21x
21x
21x
1x
20x
10x
56x
46x
9x
9x
3x
9x
16x
37x
46x
1x
10x
1x
1x
57x
57x
57x
33x
28x
5x
57x
1x
| const typeToInterceptor = new Map();
const addInterceptor = (interceptType, interceptor, interceptInThunks = false) => {
if (typeof interceptType !== "string" || interceptType === "") {
throw new Error("interceptType must be a non-empty string");
}
if (typeToInterceptor.has(interceptType)) {
throw new Error("A dispatch interceptor of type '" + interceptType + "' is already registered");
}
if (typeof interceptor !== "function") {
throw new Error("interceptor of type '" + interceptType + "' must be a synchronous callback, but got '" + typeof interceptor + "'");
}
typeToInterceptor.set(interceptType, {interceptor, interceptInThunks});
return {
removeInterceptor: () => {
typeToInterceptor.delete(interceptType);
},
}
};
const getInterceptEnhancer = () => next => (...args) => {
const store = next(...args); // eslint-disable-line callback-return
const getState = store.getState;
const reduxDispatch = store.dispatch;
let enhancedDispatch = null;
const handleDispatch = (action, interceptorDispatchArg, ...restArgs) => {
const {
noIntercept,
noInterceptTypes,
onDispatchHandledCallback,
isFromThunk,
} = interceptorDispatchArg;
const dispatchTimestamp = Date.now();
const skipTypes = typeof noInterceptTypes === "string" ? new Set([noInterceptTypes]) : new Set(noInterceptTypes);
let blockedBy = null;
typeToInterceptor.forEach(({interceptor, interceptInThunks}, interceptType) => {
if (blockedBy === null) {
if (!isFromThunk || interceptInThunks) {
if (!noIntercept && !skipTypes.has(interceptType)) {
let interceptResult = null;
interceptResult = interceptor({
action,
dispatch: enhancedDispatch,
getState,
dispatchTimestamp,
}, ...restArgs);
if (typeof interceptResult !== "boolean") {
// We cannot allow for async interceptors, because redux users
// expect the dispatch function to work synchronously.
throw new Error("interceptor of type'" + interceptType + "' returned no boolean");
}
if (interceptResult === false) {
blockedBy = interceptType;
}
}
}
}
});
if (blockedBy === null) {
if (typeof action === "function") {
// We must wrap the dispatch given to the thunk, to ensure that we not only pass over the
// interceptor arg the thunk was called with, but also setting isFromThunk to true
let newInterceptorDispatchArg = {...interceptorDispatchArg, isFromThunk: true};
if (interceptorDispatchArg.doNotUseInThunk) {
newInterceptorDispatchArg = {
noIntercept: false,
noInterceptTypes: null,
onDispatchHandledCallback: null,
isFromThunk: true,
doNotUseInThunk: true,
};
}
action((innerAction, ...dispatchArgs) => {
enhancedDispatch(innerAction, newInterceptorDispatchArg, ...dispatchArgs);
}, getState, ...restArgs);
}
else {
reduxDispatch(action, ...restArgs);
}
if (typeof onDispatchHandledCallback === "function") {
onDispatchHandledCallback({
blocked: false,
blockedBy,
isFromThunk,
})
}
// It's not possible to give another dispatch to promise middleware -> thus dispatch interceptor is not
// compatible with redux-promise-middleware. We could make it work, by wrapping the promises in the payload,
// but there could also be payloads with a promise without promise middleware being used.
}
else if (typeof onDispatchHandledCallback === "function") {
onDispatchHandledCallback({
blocked: true,
blockedBy,
isFromThunk,
})
}
};
enhancedDispatch = (action, ...dispatchArgs) => {
let interceptorDispatchArg = {
noIntercept: false,
noInterceptTypes: null,
onDispatchHandledCallback: null,
isFromThunk: false,
doNotUseInThunk: false,
};
const newDispatchArgs = [];
for (let i = 0; i < dispatchArgs.length; ++i) {
if (typeof dispatchArgs[i] === "object" && (
typeof dispatchArgs[i].noIntercept === "boolean" ||
typeof dispatchArgs[i].noInterceptTypes === "string" ||
Array.isArray(dispatchArgs[i].noInterceptTypes) ||
typeof dispatchArgs[i].onDispatchHandledCallback === "function" ||
typeof dispatchArgs[i].isFromThunk === "boolean" ||
typeof dispatchArgs[i].doNotUseInThunk === "boolean"
)) {
interceptorDispatchArg = {...interceptorDispatchArg, ...dispatchArgs[i]};
}
else {
newDispatchArgs.push(dispatchArgs[i]);
}
}
handleDispatch(action, interceptorDispatchArg, ...newDispatchArgs);
};
return {
...store,
dispatch: enhancedDispatch,
};
};
export {
getInterceptEnhancer,
addInterceptor,
};
|