@@ -7,11 +7,38 @@ import glob from 'glob';
77import { mergeQueries } from './merge' ;
88
99export class GraphQLQueryPurifier {
10+ /**
11+ * The path to the directory containing GraphQL (.gql) files.
12+ * @private
13+ */
14+
1015 private gqlPath : string ;
16+ /**
17+ * A map of allowed query names to their corresponding GraphQL query strings.
18+ * @private
19+ */
20+
1121 private queryMap : { [ key : string ] : string } ;
22+ /**
23+ * Flag to allow Apollo Studio's introspection queries.
24+ * @private
25+ */
26+
1227 private allowStudio ?: boolean ;
28+ /**
29+ * Flag to indicate whether to allow all queries (bypassing purifier).
30+ * @private
31+ */
32+
1333 private allowAll : boolean ;
1434
35+ /**
36+ * Constructs a GraphQLQueryPurifier instance.
37+ * @param {Object } params - Configuration parameters.
38+ * @param {string } params.gqlPath - Path to the directory containing .gql files.
39+ * @param {boolean } [params.allowAll=false] - Whether to allow all queries.
40+ * @param {boolean } [params.allowStudio=false] - Whether to allow Apollo Studio introspection queries.
41+ */
1542 constructor ( {
1643 gqlPath,
1744 allowAll = false ,
@@ -24,10 +51,24 @@ export class GraphQLQueryPurifier {
2451 this . gqlPath = gqlPath ;
2552 this . queryMap = { } ;
2653 this . loadQueries ( ) ;
54+ this . startWatchingFiles ( ) ;
2755 this . allowAll = allowAll ;
2856 this . allowStudio = allowStudio ;
2957 }
3058
59+ public startWatchingFiles ( ) {
60+ fs . watch ( this . gqlPath , { recursive : true } , ( eventType , filename ) => {
61+ if ( filename && path . extname ( filename ) === '.gql' ) {
62+ console . log ( `Detected ${ eventType } in ${ filename } ` ) ;
63+ this . loadQueries ( ) ;
64+ }
65+ } ) ;
66+ }
67+
68+ /**
69+ * Loads queries from .gql files in the specified directory and updates the query map.
70+ * @private
71+ */
3172 private loadQueries ( ) {
3273 const files = glob . sync ( `${ this . gqlPath } /**/*.gql` . replace ( / \\ / g, '/' ) ) ;
3374
@@ -74,6 +115,13 @@ export class GraphQLQueryPurifier {
74115 } ) ;
75116 }
76117
118+ /**
119+ * Middleware function to filter incoming GraphQL queries based on the allowed list.
120+ * If a query is not allowed, it's replaced with a minimal query.
121+ * @param {Request } req - The request object.
122+ * @param {Response } res - The response object.
123+ * @param {NextFunction } next - The next middleware function in the stack.
124+ */
77125 public filter = ( req : Request , res : Response , next : NextFunction ) => {
78126 if ( this . allowAll ) return next ( ) ;
79127 if (
@@ -103,7 +151,11 @@ export class GraphQLQueryPurifier {
103151
104152 if ( req . body && req . body . query ) {
105153 // Use mergeQueries to filter the incoming request query
106- const filteredQuery = mergeQueries ( req . body . query , allowedQueries ) ;
154+ const filteredQuery = mergeQueries (
155+ req . body . query ,
156+ allowedQueries ,
157+ req . body . operationName
158+ ) ;
107159
108160 if ( ! filteredQuery . trim ( ) ) {
109161 console . warn (
0 commit comments