1
1
import { isAsyncIterable , Plugin } from '@envelop/core' ;
2
- import { GraphQLError , ResponsePath } from 'graphql' ;
2
+ import { ExecutionResult , GraphQLError , Kind , OperationTypeNode , ResponsePath } from 'graphql' ;
3
3
import { google , Trace } from 'apollo-reporting-protobuf' ;
4
4
5
5
const ctxKey = Symbol ( 'ApolloInlineTracePluginContextKey' ) ;
6
+ const errorsKey = Symbol ( 'ApolloInlineTracePluginErrorsKey' ) ;
6
7
7
8
interface ApolloInlineTracePluginContext {
8
9
startHrTime : [ number , number ] ;
@@ -48,7 +49,7 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
48
49
shouldTrace,
49
50
rewriteError,
50
51
} : ApolloInlineTracePluginOptions < PluginContext > ) : Plugin <
51
- PluginContext & { [ ctxKey ] : ApolloInlineTracePluginContext }
52
+ PluginContext & { [ ctxKey ] : ApolloInlineTracePluginContext ; [ errorsKey ] : GraphQLError [ ] }
52
53
> {
53
54
return {
54
55
onEnveloped ( { context, extendContext } ) {
@@ -72,6 +73,7 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
72
73
nodes : new Map ( [ [ responsePathToString ( ) , rootNode ] ] ) ,
73
74
stopped : false ,
74
75
} ,
76
+ [ errorsKey ] : [ ] ,
75
77
} ) ;
76
78
}
77
79
} ,
@@ -100,34 +102,67 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
100
102
} ;
101
103
} ,
102
104
onParse ( ) {
103
- return ( { context, result } ) => {
105
+ return ( { context, result, replaceParseResult } ) => {
104
106
const ctx = context [ ctxKey ] ;
105
107
if ( ! ctx ) return ;
106
108
107
- if ( result instanceof GraphQLError ) {
108
- handleErrors ( ctx , [ result ] , rewriteError ) ;
109
- } else if ( result instanceof Error ) {
110
- handleErrors (
111
- ctx ,
112
- [
109
+ const errors = context [ errorsKey ] ;
110
+ if ( errors && result instanceof Error ) {
111
+ if ( result instanceof GraphQLError ) {
112
+ errors . push ( result ) ;
113
+ } else {
114
+ errors . push (
113
115
new GraphQLError ( result . message , {
114
116
originalError : result ,
115
- } ) ,
117
+ } )
118
+ ) ;
119
+ }
120
+ replaceParseResult ( {
121
+ kind : Kind . DOCUMENT ,
122
+ definitions : [
123
+ {
124
+ kind : Kind . OPERATION_DEFINITION ,
125
+ operation : OperationTypeNode . QUERY ,
126
+ selectionSet : {
127
+ kind : Kind . SELECTION_SET ,
128
+ selections : [
129
+ {
130
+ kind : Kind . FIELD ,
131
+ name : {
132
+ kind : Kind . NAME ,
133
+ value : '__typename' ,
134
+ } ,
135
+ } ,
136
+ ] ,
137
+ } ,
138
+ } ,
116
139
] ,
117
- rewriteError
118
- ) ;
140
+ } ) ;
119
141
}
120
142
} ;
121
143
} ,
122
- onValidate ( ) {
123
- return ( { context, result : errors } ) => {
124
- if ( errors . length ) {
125
- const ctx = context [ ctxKey ] ;
126
- if ( ctx ) handleErrors ( ctx , errors , rewriteError ) ;
144
+ onValidate ( { context, setResult } ) {
145
+ const errorsInContext = context [ errorsKey ] ;
146
+ if ( errorsInContext ?. length ) {
147
+ setResult ( [ ] ) ;
148
+ }
149
+ return ( { result : errors , setResult } ) => {
150
+ if ( errorsInContext ) {
151
+ errorsInContext . push ( ...errors ) ;
152
+ setResult ( [ ] ) ;
127
153
}
128
154
} ;
129
155
} ,
130
- onExecute ( ) {
156
+ onExecute ( { args : { contextValue } , setResultAndStopExecution } ) {
157
+ const errors = contextValue [ errorsKey ] ;
158
+ if ( errors ?. length ) {
159
+ const ctx = contextValue [ ctxKey ] ;
160
+ if ( ! ctx ) return ;
161
+ const result = { errors } ;
162
+ const updatedResult = updateResult ( result , rewriteError , ctx ) ;
163
+ setResultAndStopExecution ( updatedResult ) ;
164
+ return ;
165
+ }
131
166
return {
132
167
onExecuteDone ( { args : { contextValue } , result, setResult } ) {
133
168
const ctx = contextValue [ ctxKey ] ;
@@ -136,38 +171,44 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
136
171
// TODO: should handle streaming results? how?
137
172
if ( isAsyncIterable ( result ) ) return ;
138
173
139
- if ( result . extensions ?. ftv1 !== undefined ) {
140
- throw new Error ( 'The `ftv1` extension is already present' ) ;
141
- }
174
+ const updatedResult = updateResult ( result , rewriteError , ctx ) ;
142
175
143
- if ( result . errors ?. length ) {
144
- handleErrors ( ctx , result . errors , rewriteError ) ;
145
- }
176
+ setResult ( updatedResult ) ;
177
+ } ,
178
+ } ;
179
+ } ,
180
+ } ;
181
+ }
146
182
147
- // onResultProcess will be called only once since we disallow async iterables
148
- if ( ctx . stopped ) throw new Error ( 'Trace stopped multiple times' ) ;
183
+ function updateResult (
184
+ result : ExecutionResult ,
185
+ rewriteError : ApolloInlineTracePluginOptions [ 'rewriteError' ] ,
186
+ ctx : ApolloInlineTracePluginContext
187
+ ) {
188
+ if ( result . extensions ?. ftv1 !== undefined ) {
189
+ throw new Error ( 'The `ftv1` extension is already present' ) ;
190
+ }
149
191
150
- ctx . stopped = true ;
151
- ctx . trace . durationNs = hrTimeToDurationInNanos ( process . hrtime ( ctx . startHrTime ) ) ;
152
- ctx . trace . endTime = nowTimestamp ( ) ;
192
+ if ( result . errors ?. length ) {
193
+ handleErrors ( ctx , result . errors , rewriteError ) ;
194
+ }
153
195
154
- const encodedUint8Array = Trace . encode ( ctx . trace ) . finish ( ) ;
155
- const encodedBuffer = Buffer . from (
156
- encodedUint8Array ,
157
- encodedUint8Array . byteOffset ,
158
- encodedUint8Array . byteLength
159
- ) ;
196
+ // onResultProcess will be called only once since we disallow async iterables
197
+ if ( ctx . stopped ) throw new Error ( 'Trace stopped multiple times' ) ;
160
198
161
- result . extensions = {
162
- ...result . extensions ,
163
- ftv1 : encodedBuffer . toString ( 'base64' ) ,
164
- } ;
199
+ ctx . stopped = true ;
200
+ ctx . trace . durationNs = hrTimeToDurationInNanos ( process . hrtime ( ctx . startHrTime ) ) ;
201
+ ctx . trace . endTime = nowTimestamp ( ) ;
165
202
166
- setResult ( result ) ;
167
- } ,
168
- } ;
169
- } ,
203
+ const encodedUint8Array = Trace . encode ( ctx . trace ) . finish ( ) ;
204
+ const encodedBuffer = Buffer . from ( encodedUint8Array , encodedUint8Array . byteOffset , encodedUint8Array . byteLength ) ;
205
+
206
+ result . extensions = {
207
+ ...result . extensions ,
208
+ ftv1 : encodedBuffer . toString ( 'base64' ) ,
170
209
} ;
210
+
211
+ return result ;
171
212
}
172
213
173
214
/**
0 commit comments