44 DocumentNode ,
55 ExecutionArgs ,
66 getOperationAST ,
7- GraphQLDirective ,
7+ GraphQLSchema ,
88 Kind ,
99 print ,
1010 TypeInfo ,
@@ -30,6 +30,7 @@ import {
3030 mergeIncrementalResult ,
3131} from '@graphql-tools/utils' ;
3232import type { Cache , CacheEntityRecord } from './cache.js' ;
33+ import { getScopeFromQuery } from './get-scope.js' ;
3334import { hashSHA256 } from './hash-sha256.js' ;
3435import { createInMemoryCache } from './in-memory-cache.js' ;
3536
@@ -47,6 +48,8 @@ export type BuildResponseCacheKeyFunction = (params: {
4748 sessionId : Maybe < string > ;
4849 /** GraphQL Context */
4950 context : ExecutionArgs [ 'contextValue' ] ;
51+ /** Callback to get the scope */
52+ getScope : ( ) => NonNullable < CacheControlDirective [ 'scope' ] > ;
5053} ) => Promise < string > ;
5154
5255export type GetDocumentStringFunction = ( executionArgs : ExecutionArgs ) => string ;
@@ -76,8 +79,8 @@ export type UseResponseCacheParameter<PluginContext extends Record<string, any>
7679 * In the unusual case where you actually want to cache introspection query operations,
7780 * you need to provide the value `{ 'Query.__schema': undefined }`.
7881 */
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' ] > ;
8184 /**
8285 * Allows to cache responses based on the resolved session id.
8386 * Return a unique value for each session.
@@ -215,11 +218,11 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
215218 ttlPerSchemaCoordinate,
216219 } : {
217220 invalidateViaMutation : boolean ;
218- ttlPerSchemaCoordinate ?: Record < string , number | undefined > ;
221+ ttlPerSchemaCoordinate ?: Record < string , CacheControlDirective [ 'maxAge' ] > ;
219222 } ,
220- schema : any ,
223+ schema : GraphQLSchema ,
221224 idFieldByTypeName : Map < string , string > ,
222- ) : [ DocumentNode , number | undefined ] {
225+ ) : [ DocumentNode , CacheControlDirective [ 'maxAge' ] ] {
223226 const typeInfo = new TypeInfo ( schema ) ;
224227 let ttl : number | undefined ;
225228 const visitor : ASTVisitor = {
@@ -238,7 +241,7 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
238241 const parentType = typeInfo . getParentType ( ) ;
239242 if ( parentType ) {
240243 const schemaCoordinate = `${ parentType . name } .${ fieldNode . name . value } ` ;
241- const maybeTtl = ttlPerSchemaCoordinate [ schemaCoordinate ] as unknown ;
244+ const maybeTtl = ttlPerSchemaCoordinate [ schemaCoordinate ] ;
242245 ttl = calculateTtl ( maybeTtl , ttl ) ;
243246 }
244247 } ,
@@ -279,20 +282,38 @@ const getDocumentWithMetadataAndTTL = memoize4(function addTypeNameToDocument(
279282 return [ visit ( document , visitWithTypeInfo ( typeInfo , visitor ) ) , ttl ] ;
280283} ) ;
281284
282- type CacheControlDirective = {
285+ export type CacheControlDirective = {
283286 maxAge ?: number ;
284287 scope ?: 'PUBLIC' | 'PRIVATE' ;
285288} ;
286289
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+
287308export function useResponseCache < PluginContext extends Record < string , any > = { } > ( {
288309 cache = createInMemoryCache ( ) ,
289310 ttl : globalTtl = Infinity ,
290311 session,
291312 enabled,
292313 ignoredTypes = [ ] ,
293314 ttlPerType = { } ,
294- ttlPerSchemaCoordinate = { } ,
295- scopePerSchemaCoordinate = { } ,
315+ ttlPerSchemaCoordinate : localTtlPerSchemaCoordinate = { } ,
316+ scopePerSchemaCoordinate : localScopePerSchemaCoordinate = { } ,
296317 idFields = [ 'id' ] ,
297318 invalidateViaMutation = true ,
298319 buildResponseCacheKey = defaultBuildResponseCacheKey ,
@@ -308,22 +329,13 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
308329 enabled = enabled ? memoize1 ( enabled ) : enabled ;
309330
310331 // never cache Introspections
311- ttlPerSchemaCoordinate = { 'Query.__schema' : 0 , ...ttlPerSchemaCoordinate } ;
332+ ttlPerSchemaCoordinate = { 'Query.__schema' : 0 , ...localTtlPerSchemaCoordinate } ;
312333 const documentMetadataOptions = {
313334 queries : { invalidateViaMutation, ttlPerSchemaCoordinate } ,
314335 mutations : { invalidateViaMutation } , // remove ttlPerSchemaCoordinate for mutations to skip TTL calculation
315336 } ;
337+ scopePerSchemaCoordinate = { ...localScopePerSchemaCoordinate } ;
316338 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- }
327339
328340 return {
329341 onSchemaChange ( { schema : newSchema } ) {
@@ -332,9 +344,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
332344 }
333345 schema = newSchema ;
334346
335- const directive = schema . getDirective ( 'cacheControl' ) as unknown as
336- | GraphQLDirective
337- | undefined ;
347+ const directive = schema . getDirective ( 'cacheControl' ) ;
338348
339349 mapSchema ( schema , {
340350 ...( directive && {
@@ -522,6 +532,7 @@ export function useResponseCache<PluginContext extends Record<string, any> = {}>
522532 operationName : onExecuteParams . args . operationName ,
523533 sessionId,
524534 context : onExecuteParams . args . contextValue ,
535+ getScope : ( ) => getScopeFromQuery ( schema , onExecuteParams . args . document . loc . source . body ) ,
525536 } ) ;
526537
527538 const cachedResponse = ( await cache . get ( cacheKey ) ) as ResponseCacheExecutionResult ;
0 commit comments