1
1
// @flow
2
2
import { configureScope } from '@sentry/minimal' ;
3
3
import { Scope } from '@sentry/types' ;
4
- import { Action , AnyAction , PreloadedState , Reducer , StoreEnhancer , StoreEnhancerStoreCreator } from 'redux' ;
4
+
5
+ interface Action < T = any > {
6
+ type : T ;
7
+ }
8
+
9
+ interface AnyAction extends Action {
10
+ [ extraProps : string ] : any ;
11
+ }
12
+
13
+ type Reducer < S = any , A extends Action = AnyAction > = ( state : S | undefined , action : A ) => S ;
14
+
15
+ type Dispatch < A extends Action = AnyAction > = < T extends A > ( action : T , ...extraArgs : any [ ] ) => T ;
16
+
17
+ type ExtendState < State , Extension > = [ Extension ] extends [ never ] ? State : State & Extension ;
18
+
19
+ type Unsubscribe = ( ) => void ;
20
+
21
+ interface Store < S = any , A extends Action = AnyAction , StateExt = never , Ext = { } > {
22
+ dispatch : Dispatch < A > ;
23
+ getState ( ) : S ;
24
+ subscribe ( listener : ( ) => void ) : Unsubscribe ;
25
+ replaceReducer < NewState , NewActions extends Action > (
26
+ nextReducer : Reducer < NewState , NewActions > ,
27
+ ) : Store < ExtendState < NewState , StateExt > , NewActions , StateExt , Ext > & Ext ;
28
+ }
29
+
30
+ declare const $CombinedState : unique symbol ;
31
+
32
+ type CombinedState < S > = { readonly [ $CombinedState ] ?: undefined } & S ;
33
+
34
+ type PreloadedState < S > = Required < S > extends {
35
+ [ $CombinedState ] : undefined ;
36
+ }
37
+ ? S extends CombinedState < infer S1 >
38
+ ? { [ K in keyof S1 ] ?: S1 [ K ] extends object ? PreloadedState < S1 [ K ] > : S1 [ K ] }
39
+ : never
40
+ : { [ K in keyof S ] : S [ K ] extends string | number | boolean | symbol ? S [ K ] : PreloadedState < S [ K ] > } ;
41
+
42
+ type StoreEnhancer < Ext = { } , StateExt = never > = (
43
+ next : StoreEnhancerStoreCreator < Ext , StateExt > ,
44
+ ) => StoreEnhancerStoreCreator < Ext , StateExt > ;
45
+
46
+ type StoreEnhancerStoreCreator < Ext = { } , StateExt = never > = < S = any , A extends Action = AnyAction > (
47
+ reducer : Reducer < S , A > ,
48
+ preloadedState ?: PreloadedState < S > ,
49
+ ) => Store < ExtendState < S , StateExt > , A , StateExt , Ext > & Ext ;
5
50
6
51
export interface SentryEnhancerOptions {
7
52
/**
8
53
* Transforms the state before attaching it to an event.
9
54
* Use this to remove any private data before sending it to Sentry.
10
55
* Return null to not attach the state.
11
56
*/
12
- stateTransformer ( state : any | undefined ) : any | null ;
57
+ stateTransformer < S > ( state : S | undefined ) : ( S & any ) | null ;
13
58
/**
14
59
* Transforms the action before sending it as a breadcrumb.
15
60
* Use this to remove any private data before sending it to Sentry.
@@ -19,7 +64,7 @@ export interface SentryEnhancerOptions {
19
64
/**
20
65
* Called on every state update, configure the Sentry Scope with the redux state.
21
66
*/
22
- configureScopeWithState ?( scope : Scope , state : any ) : void ;
67
+ configureScopeWithState ?< S > ( scope : Scope , state : S ) : void ;
23
68
}
24
69
25
70
const ACTION_BREADCRUMB_CATEGORY = 'redux.action' ;
@@ -29,9 +74,14 @@ const STATE_CONTEXT_KEY = 'redux.state';
29
74
const defaultOptions : SentryEnhancerOptions = {
30
75
actionTransformer : action => action ,
31
76
// tslint:disable-next-line: no-unsafe-any
32
- stateTransformer : state => state ,
77
+ stateTransformer : state => state || null ,
33
78
} ;
34
79
80
+ /**
81
+ * Creates an enhancer that would be passed to Redux's createStore to log actions and the latest state to Sentry.
82
+ *
83
+ * @param enhancerOptions Options to pass to the enhancer
84
+ */
35
85
function createReduxEnhancer ( enhancerOptions ?: Partial < SentryEnhancerOptions > ) : StoreEnhancer {
36
86
const options = {
37
87
...defaultOptions ,
@@ -59,6 +109,7 @@ function createReduxEnhancer(enhancerOptions?: Partial<SentryEnhancerOptions>):
59
109
60
110
/* Set latest state to scope */
61
111
const transformedState = options . stateTransformer ( newState ) ;
112
+ // tslint:disable-next-line: strict-type-predicates
62
113
if ( typeof transformedState !== 'undefined' && transformedState !== null ) {
63
114
// tslint:disable-next-line: no-unsafe-any
64
115
scope . setContext ( STATE_CONTEXT_KEY , transformedState ) ;
0 commit comments