@@ -8,22 +8,48 @@ import type { TagsManifest } from './config.js'
88import type { RequestContext } from './handlers/request-context.cjs'
99import type { RuntimeTracer } from './handlers/tracer.cjs'
1010
11+ const ALL_VARIATIONS = Symbol . for ( 'ALL_VARIATIONS' )
1112interface NetlifyVaryValues {
12- headers : string [ ]
13- languages : string [ ]
14- cookies : string [ ]
13+ header : string [ ]
14+ language : string [ ]
15+ cookie : string [ ]
16+ /**
17+ * Query variation can be without argument in which case all query combinations would create a new cache key
18+ * This is represented by a ALL_VARIATIONS in the array.
19+ */
20+ query : ( string | typeof ALL_VARIATIONS ) [ ]
21+ country : string [ ]
1522}
1623
17- const generateNetlifyVaryValues = ( { headers, languages, cookies } : NetlifyVaryValues ) : string => {
24+ const NetlifyVaryKeys = new Set ( [ 'header' , 'language' , 'cookie' , 'query' , 'country' ] )
25+ const isNetlifyVaryKey = ( key : string ) : key is keyof NetlifyVaryValues => NetlifyVaryKeys . has ( key )
26+
27+ const generateNetlifyVaryValues = ( {
28+ header,
29+ language,
30+ cookie,
31+ query,
32+ country,
33+ } : NetlifyVaryValues ) : string => {
1834 const values : string [ ] = [ ]
19- if ( headers . length !== 0 ) {
20- values . push ( `header=${ headers . join ( `|` ) } ` )
35+ if ( query . length !== 0 ) {
36+ if ( query . includes ( ALL_VARIATIONS ) ) {
37+ values . push ( `query` )
38+ } else {
39+ values . push ( `query=${ query . join ( `|` ) } ` )
40+ }
41+ }
42+ if ( header . length !== 0 ) {
43+ values . push ( `header=${ header . join ( `|` ) } ` )
44+ }
45+ if ( language . length !== 0 ) {
46+ values . push ( `language=${ language . join ( `|` ) } ` )
2147 }
22- if ( languages . length !== 0 ) {
23- values . push ( `language =${ languages . join ( `|` ) } ` )
48+ if ( cookie . length !== 0 ) {
49+ values . push ( `cookie =${ cookie . join ( `|` ) } ` )
2450 }
25- if ( cookies . length !== 0 ) {
26- values . push ( `cookie =${ cookies . join ( `|` ) } ` )
51+ if ( country . length !== 0 ) {
52+ values . push ( `country =${ country . join ( `|` ) } ` )
2753 }
2854 return values . join ( ',' )
2955}
@@ -56,22 +82,40 @@ export const setVaryHeaders = (
5682 { basePath, i18n } : Pick < NextConfigComplete , 'basePath' | 'i18n' > ,
5783) => {
5884 const netlifyVaryValues : NetlifyVaryValues = {
59- headers : [ 'x-nextjs-data' ] ,
60- languages : [ ] ,
61- cookies : [ '__prerender_bypass' , '__next_preview_data' ] ,
85+ header : [ 'x-nextjs-data' ] ,
86+ language : [ ] ,
87+ cookie : [ '__prerender_bypass' , '__next_preview_data' ] ,
88+ query : [ ] ,
89+ country : [ ] ,
6290 }
6391
6492 const vary = headers . get ( 'vary' )
6593 if ( vary !== null ) {
66- netlifyVaryValues . headers . push ( ...getHeaderValueArray ( vary ) )
94+ netlifyVaryValues . header . push ( ...getHeaderValueArray ( vary ) )
6795 }
6896
6997 const path = new URL ( request . url ) . pathname
7098 const locales = i18n && i18n . localeDetection !== false ? i18n . locales : [ ]
7199
72100 if ( locales . length > 1 && ( path === '/' || path === basePath ) ) {
73- netlifyVaryValues . languages . push ( ...locales )
74- netlifyVaryValues . cookies . push ( `NEXT_LOCALE` )
101+ netlifyVaryValues . language . push ( ...locales )
102+ netlifyVaryValues . cookie . push ( `NEXT_LOCALE` )
103+ }
104+
105+ const userNetlifyVary = headers . get ( 'netlify-vary' )
106+ if ( userNetlifyVary ) {
107+ // respect user's header and append them
108+ const directives = getHeaderValueArray ( userNetlifyVary )
109+ for ( const directive of directives ) {
110+ const [ key , value ] = directive . split ( '=' )
111+
112+ if ( key === 'query' && ! value ) {
113+ // query can have no "assignment" and then it should vary on all possible query combinations
114+ netlifyVaryValues . query . push ( ALL_VARIATIONS )
115+ } else if ( value && isNetlifyVaryKey ( key ) ) {
116+ netlifyVaryValues [ key ] . push ( ...value . split ( '|' ) )
117+ }
118+ }
75119 }
76120
77121 headers . set ( `netlify-vary` , generateNetlifyVaryValues ( netlifyVaryValues ) )
@@ -182,6 +226,7 @@ export const setCacheControlHeaders = (
182226 if (
183227 typeof requestContext . routeHandlerRevalidate !== 'undefined' &&
184228 [ 'GET' , 'HEAD' ] . includes ( request . method ) &&
229+ ! headers . has ( 'cdn-cache-control' ) &&
185230 ! headers . has ( 'netlify-cdn-cache-control' )
186231 ) {
187232 // handle CDN Cache Control on Route Handler responses
0 commit comments