1+ import { print , Kind , OperationDefinitionNode } from "graphql" ;
2+ import { globalSignal } from "../../utils/globals" ;
3+ import { getDefaultScalarValue } from "../ad-hoc-mutations" ;
4+ import { AuthParams , AuthParamsKind } from "../../../common/messaging/protocol" ;
5+ import { Impersonation } from "../../dataconnect/types" ;
6+ import { Disposable } from "vscode" ;
7+ import { ExtensionBrokerImpl } from "../../extension-broker" ;
8+ import { AnalyticsLogger , DATA_CONNECT_EVENT_NAME } from "../../analytics" ;
9+
10+ /**
11+ * Contains the unparsed JSON object mutation/query variables.
12+ * The JSON may be invalid.
13+ */
14+ export const executionVarsJSON = globalSignal ( "{}" ) ;
15+ export const executionAuthParams = globalSignal < AuthParams > ( { kind : AuthParamsKind . ADMIN } ) ;
16+
17+ export class ExecutionParamsService implements Disposable {
18+ constructor ( readonly broker : ExtensionBrokerImpl , readonly analyticsLogger : AnalyticsLogger ) {
19+ this . disposable . push ( {
20+ dispose : broker . on (
21+ "defineAuthParams" ,
22+ ( auth ) => ( executionAuthParams . value = auth )
23+ ) ,
24+ } ) ;
25+ this . disposable . push ( {
26+ dispose : broker . on (
27+ "defineVariables" ,
28+ ( value ) => ( executionVarsJSON . value = value ) ,
29+ )
30+ } ) ;
31+ }
32+
33+ disposable : Disposable [ ] = [ ] ;
34+
35+ dispose ( ) {
36+ for ( const disposable of this . disposable ) {
37+ disposable . dispose ( ) ;
38+ }
39+ }
40+
41+ executeGraphqlVariables ( ) : Record < string , any > {
42+ const variables = executionVarsJSON . value ;
43+ if ( ! variables ) {
44+ return { } ;
45+ }
46+ try {
47+ return JSON . parse ( variables ) ;
48+ } catch ( e : any ) {
49+ throw new Error (
50+ "Unable to parse variables as JSON. Check the variables pane.\n" + e . message ,
51+ ) ;
52+ }
53+ }
54+
55+ executeGraphqlExtensions ( ) : { impersonate ?: Impersonation } {
56+ const auth = executionAuthParams . value ;
57+ switch ( auth . kind ) {
58+ case AuthParamsKind . ADMIN :
59+ this . analyticsLogger . logger . logUsage ( DATA_CONNECT_EVENT_NAME . RUN_AUTH_ADMIN ) ;
60+ return { } ;
61+ case AuthParamsKind . UNAUTHENTICATED :
62+ this . analyticsLogger . logger . logUsage ( DATA_CONNECT_EVENT_NAME . RUN_AUTH_UNAUTHENTICATED ) ;
63+ return { impersonate : { unauthenticated : true , includeDebugDetails : true } } ;
64+ case AuthParamsKind . AUTHENTICATED :
65+ this . analyticsLogger . logger . logUsage ( DATA_CONNECT_EVENT_NAME . RUN_AUTH_AUTHENTICATED ) ;
66+ try {
67+ return {
68+ impersonate :
69+ { authClaims : JSON . parse ( auth . claims ) , includeDebugDetails : true }
70+ } ;
71+ } catch ( e : any ) {
72+ throw new Error (
73+ "Unable to parse auth claims as JSON. Check the authentication panel.\n" + e . message ,
74+ ) ;
75+ }
76+ default :
77+ throw new Error ( `Unknown auth params kind: ${ auth } ` ) ;
78+ }
79+ }
80+
81+ async applyDetectedFixes ( ast : OperationDefinitionNode ) : Promise < void > {
82+ const userVars = this . executeGraphqlVariables ( ) ;
83+ const fixes = [ ] ;
84+ {
85+ const undefinedVars = [ ] ;
86+ for ( const varName in userVars ) {
87+ if ( ! ast . variableDefinitions ?. find ( ( v ) => v . variable . name . value === varName ) ) {
88+ delete userVars [ varName ] ;
89+ undefinedVars . push ( varName ) ;
90+ }
91+ }
92+ if ( undefinedVars . length > 0 ) {
93+ this . analyticsLogger . logger . logUsage ( DATA_CONNECT_EVENT_NAME . RUN_UNDEFINED_VARIABLES ) ;
94+ fixes . push ( `Removed undefined variables: ${ undefinedVars . map ( ( v ) => "$" + v ) . join ( ", " ) } ` ) ;
95+ }
96+ }
97+ {
98+ const missingRequiredVars = [ ] ;
99+ for ( const variable of ast . variableDefinitions || [ ] ) {
100+ const varName = variable . variable . name . value ;
101+ if ( variable . type . kind === Kind . NON_NULL_TYPE && userVars [ varName ] === undefined ) {
102+ userVars [ varName ] = getDefaultScalarValue ( print ( variable . type . type ) ) ;
103+ missingRequiredVars . push ( varName ) ;
104+ }
105+ }
106+ if ( missingRequiredVars . length > 0 ) {
107+ this . analyticsLogger . logger . logUsage ( DATA_CONNECT_EVENT_NAME . RUN_MISSING_VARIABLES ) ;
108+ fixes . push ( `Included required variables: ${ missingRequiredVars . map ( ( v ) => "$" + v ) . join ( ", " ) } ` ) ;
109+ }
110+ }
111+ if ( fixes . length === 0 ) {
112+ return ;
113+ }
114+ executionVarsJSON . value = JSON . stringify ( userVars , null , 2 ) ;
115+ this . broker . send ( "notifyVariables" , { variables : executionVarsJSON . value , fixes } ) ;
116+ return ;
117+ }
118+ }
0 commit comments