File tree 8 files changed +94
-7
lines changed
runtime/src/templates/edge-shared
8 files changed +94
-7
lines changed Original file line number Diff line number Diff line change @@ -29,7 +29,7 @@ describe('appDir', () => {
29
29
} )
30
30
} )
31
31
32
- it ( 'returns a vary header for RSC data requests to ISR pages' , ( ) => {
32
+ it . skip ( 'returns a vary header for RSC data requests to ISR pages' , ( ) => {
33
33
cy . request ( {
34
34
url : '/blog/erica/' ,
35
35
followRedirect : false ,
@@ -41,7 +41,7 @@ describe('appDir', () => {
41
41
} )
42
42
} )
43
43
44
- it ( 'returns a vary header for non-RSC data requests to ISR pages' , ( ) => {
44
+ it . skip ( 'returns a vary header for non-RSC data requests to ISR pages' , ( ) => {
45
45
cy . request ( {
46
46
url : '/blog/erica/' ,
47
47
followRedirect : false ,
Original file line number Diff line number Diff line change @@ -37,6 +37,14 @@ describe('Standard middleware', () => {
37
37
cy . getCookie ( 'netlifyCookie' ) . should ( 'have.property' , 'value' , 'true' )
38
38
} )
39
39
} )
40
+
41
+ // https://github.com/netlify/pillar-support/issues/350
42
+ it ( 'MiddlewareResponse adds cookies' , ( ) => {
43
+ cy . request ( '/cookies/middleware' ) . then ( ( response ) => {
44
+ cy . getCookie ( 'middlewareCookie' ) . should ( 'have.property' , 'value' , 'true' )
45
+ expect ( response . headers ) . to . have . property ( 'x-foo' , 'bar' )
46
+ } )
47
+ } )
40
48
} )
41
49
42
50
describe ( 'Middleware matchers' , ( ) => {
Original file line number Diff line number Diff line change @@ -53,6 +53,13 @@ export async function middleware(req: NextRequest) {
53
53
return request . rewrite ( '/api/hello' )
54
54
}
55
55
56
+ if ( pathname . startsWith ( '/cookies/middleware' ) ) {
57
+ const response = await new MiddlewareRequest ( req ) . next ( )
58
+ response . cookies . set ( 'middlewareCookie' , 'true' )
59
+ response . headers . set ( 'x-foo' , 'bar' )
60
+ return response
61
+ }
62
+
56
63
if ( pathname . startsWith ( '/cookies' ) ) {
57
64
response = NextResponse . next ( )
58
65
response . cookies . set ( 'netlifyCookie' , 'true' )
@@ -129,8 +136,8 @@ export const config = {
129
136
matcher : [
130
137
'/api/:all*' ,
131
138
'/headers' ,
139
+ '/cookies/:path*' ,
132
140
{ source : '/static' } ,
133
- { source : '/cookies' } ,
134
141
{ source : '/matcher-cookie' } ,
135
142
{ source : '/shows/((?!99|88).*)' } ,
136
143
{
Original file line number Diff line number Diff line change
1
+ const Cookies = ( ) => {
2
+ return (
3
+ < div >
4
+ < p > The cookie "middlewareCookie" should be set to true</ p >
5
+ </ div >
6
+ )
7
+ }
8
+
9
+ export default Cookies
Original file line number Diff line number Diff line change @@ -11,7 +11,15 @@ export class MiddlewareResponse extends NextResponse {
11
11
private readonly dataTransforms : NextDataTransform [ ]
12
12
private readonly elementHandlers : Array < [ selector : string , handlers : ElementHandlers ] >
13
13
constructor ( public originResponse : Response ) {
14
- super ( )
14
+ // we need to propagate the set-cookie header, so response.cookies.get works correctly
15
+ const initHeaders = new Headers ( )
16
+ if ( originResponse . headers . has ( 'set-cookie' ) ) {
17
+ initHeaders . set ( 'set-cookie' , originResponse . headers . get ( 'set-cookie' ) )
18
+ }
19
+
20
+ super ( undefined , {
21
+ headers : initHeaders ,
22
+ } )
15
23
16
24
// These are private in Node when compiling, but we access them in Deno at runtime
17
25
Object . defineProperty ( this , 'dataTransforms' , {
Original file line number Diff line number Diff line change 1
1
import type { EdgeFunction } from 'https://edge.netlify.com'
2
2
3
+ // These are copied from next/dist/build. This file gets copied as part of the next
4
+ // runtime build and can't reference the next package directly.
5
+ //
6
+ // Latest types at https://github.com/vercel/next.js/blob/4a2df3c3752aeddc50fd5ab053440eccf71ae50b/packages/next/src/build/index.ts#L140
3
7
export declare type SsgRoute = {
4
8
initialRevalidateSeconds : number | false
5
9
srcRoute : string | null
6
- dataRoute : string
10
+ dataRoute : string | null
7
11
}
8
12
export declare type DynamicSsgRoute = {
9
13
routeRegex : string
10
14
fallback : string | null | false
11
- dataRoute : string
15
+ dataRoute : string | null
12
16
dataRouteRegex : string
13
17
}
14
18
export declare type PrerenderManifest = {
@@ -35,7 +39,7 @@ const rscifyPath = (route: string) => {
35
39
export const getRscDataRouter = ( { routes : staticRoutes , dynamicRoutes } : PrerenderManifest ) : EdgeFunction => {
36
40
const staticRouteSet = new Set (
37
41
Object . entries ( staticRoutes )
38
- . filter ( ( [ , { dataRoute } ] ) => dataRoute . endsWith ( '.rsc' ) )
42
+ . filter ( ( [ , { dataRoute } ] ) => dataRoute ? .endsWith ( '.rsc' ) )
39
43
. map ( ( [ route ] ) => route ) ,
40
44
)
41
45
Original file line number Diff line number Diff line change @@ -57,10 +57,15 @@ export const addMiddlewareHeaders = async (
57
57
return response
58
58
}
59
59
60
+ interface ResponseCookies {
61
+ readonly _headers : Headers
62
+ }
63
+
60
64
interface MiddlewareResponse extends Response {
61
65
originResponse : Response
62
66
dataTransforms : NextDataTransform [ ]
63
67
elementHandlers : Array < [ selector : string , handlers : ElementHandlers ] >
68
+ get cookies ( ) : ResponseCookies
64
69
}
65
70
66
71
interface MiddlewareRequest {
@@ -184,6 +189,12 @@ export const buildResponse = async ({
184
189
if ( request . method === 'HEAD' || request . method === 'OPTIONS' ) {
185
190
return response . originResponse
186
191
}
192
+
193
+ // NextResponse doesn't set cookies onto the originResponse, so we need to copy them over
194
+ if ( response . cookies . _headers . has ( 'set-cookie' ) ) {
195
+ response . originResponse . headers . set ( 'set-cookie' , response . cookies . _headers . get ( 'set-cookie' ) ! )
196
+ }
197
+
187
198
// If it's JSON we don't need to use the rewriter, we can just parse it
188
199
if ( response . originResponse . headers . get ( 'content-type' ) ?. includes ( 'application/json' ) ) {
189
200
const props = await response . originResponse . json ( )
Original file line number Diff line number Diff line change
1
+ import { getRscDataRouter , PrerenderManifest } from '../packages/runtime/src/templates/edge-shared/rsc-data'
2
+
3
+ const basePrerenderManifest : PrerenderManifest = {
4
+ version : 3 ,
5
+ routes : { } ,
6
+ dynamicRoutes : { } ,
7
+ notFoundRoutes : [ ] ,
8
+ }
9
+
10
+ describe ( 'getRscDataRouter' , ( ) => {
11
+ it ( 'should create a RSC data router when data routes are not present for routes' , ( ) => {
12
+ const manifest : PrerenderManifest = {
13
+ ...basePrerenderManifest ,
14
+ routes : {
15
+ '/' : {
16
+ initialRevalidateSeconds : 1 ,
17
+ srcRoute : null ,
18
+ dataRoute : '/index.json.rsc' ,
19
+ } ,
20
+ '/api/hello' : {
21
+ initialRevalidateSeconds : false ,
22
+ srcRoute : '/api/hello' ,
23
+ dataRoute : null ,
24
+ } ,
25
+ } ,
26
+ }
27
+
28
+ let rscDataRouter
29
+
30
+ // Normally type checking would pick this up, but because this file is copied when generating
31
+ // edge functions for the build, we need to make sure it's valid for builds.
32
+ //
33
+ // See https://github.com/netlify/next-runtime/issues/1940
34
+ expect ( ( ) => {
35
+ rscDataRouter = getRscDataRouter ( manifest )
36
+ } ) . not . toThrow ( )
37
+
38
+ expect ( typeof rscDataRouter ) . toBe ( 'function' )
39
+ } )
40
+ } )
You can’t perform that action at this time.
0 commit comments