4
4
DocumentNode ,
5
5
ExecutionArgs ,
6
6
getOperationAST ,
7
- GraphQLDirective ,
7
+ GraphQLSchema ,
8
8
Kind ,
9
9
print ,
10
10
TypeInfo ,
@@ -30,6 +30,7 @@ import {
30
30
mergeIncrementalResult ,
31
31
} from '@graphql-tools/utils' ;
32
32
import type { Cache , CacheEntityRecord } from './cache.js' ;
33
+ import { getScopeFromQuery } from './get-scope.js' ;
33
34
import { hashSHA256 } from './hash-sha256.js' ;
34
35
import { createInMemoryCache } from './in-memory-cache.js' ;
35
36
@@ -47,6 +48,8 @@ export type BuildResponseCacheKeyFunction = (params: {
47
48
sessionId : Maybe < string > ;
48
49
/** GraphQL Context */
49
50
context : ExecutionArgs [ 'contextValue' ] ;
51
+ /** Callback to get the scope */
52
+ getScope : ( ) => NonNullable < CacheControlDirective [ 'scope' ] > ;
50
53
} ) => Promise < string > ;
51
54
52
55
export type GetDocumentStringFunction = ( executionArgs : ExecutionArgs ) => string ;
@@ -76,8 +79,8 @@ export type UseResponseCacheParameter<PluginContext extends Record<string, any>
76
79
* In the unusual case where you actually want to cache introspection query operations,
77
80
* you need to provide the value `{ 'Query.__schema': undefined }`.
78
81
*/
79
- ttlPerSchemaCoordinate ?: Record < string , number | undefined > ;
80
- scopePerSchemaCoordinate ?: Record < string , 'PRIVATE' | 'PUBLIC' | undefined > ;
82
+ ttlPerSchemaCoordinate ?: Record < string , CacheControlDirective [ 'maxAge' ] > ;
83
+ scopePerSchemaCoordinate ?: Record < string , CacheControlDirective [ 'scope' ] > ;
81
84
/**
82
85
* Allows to cache responses based on the resolved session id.
83
86
* Return a unique value for each session.
@@ -215,11 +218,11 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
215
218
ttlPerSchemaCoordinate,
216
219
} : {
217
220
invalidateViaMutation : boolean ;
218
- ttlPerSchemaCoordinate ?: Record < string , number | undefined > ;
221
+ ttlPerSchemaCoordinate ?: Record < string , CacheControlDirective [ 'maxAge' ] > ;
219
222
} ,
220
- schema : any ,
223
+ schema : GraphQLSchema ,
221
224
idFieldByTypeName : Map < string , string > ,
222
- ) : [ DocumentNode , number | undefined ] {
225
+ ) : [ DocumentNode , CacheControlDirective [ 'maxAge' ] ] {
223
226
const typeInfo = new TypeInfo ( schema ) ;
224
227
let ttl : number | undefined ;
225
228
const visitor : ASTVisitor = {
@@ -238,7 +241,7 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
238
241
const parentType = typeInfo . getParentType ( ) ;
239
242
if ( parentType ) {
240
243
const schemaCoordinate = `${ parentType . name } .${ fieldNode . name . value } ` ;
241
- const maybeTtl = ttlPerSchemaCoordinate [ schemaCoordinate ] as unknown ;
244
+ const maybeTtl = ttlPerSchemaCoordinate [ schemaCoordinate ] ;
242
245
ttl = calculateTtl ( maybeTtl , ttl ) ;
243
246
}
244
247
} ,
@@ -279,20 +282,38 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
279
282
return [ visit ( document , visitWithTypeInfo ( typeInfo , visitor ) ) , ttl ] ;
280
283
} ) ;
281
284
282
- type CacheControlDirective = {
285
+ export type CacheControlDirective = {
283
286
maxAge ?: number ;
284
287
scope ?: 'PUBLIC' | 'PRIVATE' ;
285
288
} ;
286
289
290
+ export let schema : GraphQLSchema ;
291
+ let ttlPerSchemaCoordinate : Record < string , CacheControlDirective [ 'maxAge' ] > = { } ;
292
+ let scopePerSchemaCoordinate : Record < string , CacheControlDirective [ 'scope' ] > = { } ;
293
+
294
+ export function isPrivate (
295
+ typeName : string ,
296
+ data ?: Record < string , NonNullable < CacheControlDirective [ 'scope' ] > > ,
297
+ ) : boolean {
298
+ if ( scopePerSchemaCoordinate [ typeName ] === 'PRIVATE' ) {
299
+ return true ;
300
+ }
301
+ return data
302
+ ? Object . keys ( data ) . some (
303
+ fieldName => scopePerSchemaCoordinate [ `${ typeName } .${ fieldName } ` ] === 'PRIVATE' ,
304
+ )
305
+ : false ;
306
+ }
307
+
287
308
export function useResponseCache < PluginContext extends Record < string , any > = { } > ( {
288
309
cache = createInMemoryCache ( ) ,
289
310
ttl : globalTtl = Infinity ,
290
311
session,
291
312
enabled,
292
313
ignoredTypes = [ ] ,
293
314
ttlPerType = { } ,
294
- ttlPerSchemaCoordinate = { } ,
295
- scopePerSchemaCoordinate = { } ,
315
+ ttlPerSchemaCoordinate : localTtlPerSchemaCoordinate = { } ,
316
+ scopePerSchemaCoordinate : localScopePerSchemaCoordinate = { } ,
296
317
idFields = [ 'id' ] ,
297
318
invalidateViaMutation = true ,
298
319
buildResponseCacheKey = defaultBuildResponseCacheKey ,
@@ -308,22 +329,13 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
308
329
enabled = enabled ? memoize1 ( enabled ) : enabled ;
309
330
310
331
// never cache Introspections
311
- ttlPerSchemaCoordinate = { 'Query.__schema' : 0 , ...ttlPerSchemaCoordinate } ;
332
+ ttlPerSchemaCoordinate = { 'Query.__schema' : 0 , ...localTtlPerSchemaCoordinate } ;
312
333
const documentMetadataOptions = {
313
334
queries : { invalidateViaMutation, ttlPerSchemaCoordinate } ,
314
335
mutations : { invalidateViaMutation } , // remove ttlPerSchemaCoordinate for mutations to skip TTL calculation
315
336
} ;
337
+ scopePerSchemaCoordinate = { ...localScopePerSchemaCoordinate } ;
316
338
const idFieldByTypeName = new Map < string , string > ( ) ;
317
- let schema : any ;
318
-
319
- function isPrivate ( typeName : string , data : Record < string , unknown > ) : boolean {
320
- if ( scopePerSchemaCoordinate [ typeName ] === 'PRIVATE' ) {
321
- return true ;
322
- }
323
- return Object . keys ( data ) . some (
324
- fieldName => scopePerSchemaCoordinate [ `${ typeName } .${ fieldName } ` ] === 'PRIVATE' ,
325
- ) ;
326
- }
327
339
328
340
return {
329
341
onSchemaChange ( { schema : newSchema } ) {
@@ -332,9 +344,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
332
344
}
333
345
schema = newSchema ;
334
346
335
- const directive = schema . getDirective ( 'cacheControl' ) as unknown as
336
- | GraphQLDirective
337
- | undefined ;
347
+ const directive = schema . getDirective ( 'cacheControl' ) ;
338
348
339
349
mapSchema ( schema , {
340
350
...( directive && {
@@ -522,6 +532,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
522
532
operationName : onExecuteParams . args . operationName ,
523
533
sessionId,
524
534
context : onExecuteParams . args . contextValue ,
535
+ getScope : ( ) => getScopeFromQuery ( schema , onExecuteParams . args . document . loc . source . body ) ,
525
536
} ) ;
526
537
527
538
const cachedResponse = ( await cache . get ( cacheKey ) ) as ResponseCacheExecutionResult ;
0 commit comments