@@ -5,6 +5,7 @@ import { join } from 'node:path'
55import { trace } from '@opentelemetry/api'
66import { wrapTracer } from '@opentelemetry/api/experimental'
77import { glob } from 'fast-glob'
8+ import type { RouteMetadata } from 'next-with-cache-handler-v2/dist/export/routes/types.js'
89import pLimit from 'p-limit'
910import { satisfies } from 'semver'
1011
@@ -69,21 +70,44 @@ const buildPagesCacheValue = async (
6970 revalidate : initialRevalidateSeconds ,
7071} )
7172
73+ const RSC_SEGMENTS_DIR_SUFFIX = '.segments'
74+ const RSC_SEGMENT_SUFFIX = '.segment.rsc'
75+
7276const buildAppCacheValue = async (
7377 path : string ,
7478 shouldUseAppPageKind : boolean ,
7579) : Promise < NetlifyCachedAppPageValue | NetlifyCachedPageValue > => {
76- const meta = JSON . parse ( await readFile ( `${ path } .meta` , 'utf-8' ) )
80+ const meta = JSON . parse ( await readFile ( `${ path } .meta` , 'utf-8' ) ) as RouteMetadata
7781 const html = await readFile ( `${ path } .html` , 'utf-8' )
7882
7983 // supporting both old and new cache kind for App Router pages - https://github.com/vercel/next.js/pull/65988
8084 if ( shouldUseAppPageKind ) {
85+ // segments are normalized and outputted separately for each segment, we denormalize it here and stitch
86+ // fully constructed segmentData to avoid data fetch waterfalls later in cache handler at runtime
87+ // https://github.com/vercel/next.js/blob/def2c6ba75dff754767379afb44c26c30bd3d96b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts#L185
88+ let segmentData : NetlifyCachedAppPageValue [ 'segmentData' ]
89+ if ( meta . segmentPaths ) {
90+ const segmentsDir = path + RSC_SEGMENTS_DIR_SUFFIX
91+
92+ segmentData = Object . fromEntries (
93+ await Promise . all (
94+ meta . segmentPaths . map ( async ( segmentPath : string ) => {
95+ const segmentDataFilePath = segmentsDir + segmentPath + RSC_SEGMENT_SUFFIX
96+
97+ const segmentContent = await readFile ( segmentDataFilePath , 'base64' )
98+ return [ segmentPath , segmentContent ]
99+ } ) ,
100+ ) ,
101+ )
102+ }
103+
81104 return {
82105 kind : 'APP_PAGE' ,
83106 html,
84107 rscData : await readFile ( `${ path } .rsc` , 'base64' ) . catch ( ( ) =>
85108 readFile ( `${ path } .prefetch.rsc` , 'base64' ) ,
86109 ) ,
110+ segmentData,
87111 ...meta ,
88112 }
89113 }
@@ -97,7 +121,10 @@ const buildAppCacheValue = async (
97121 if (
98122 ! meta . status &&
99123 rsc . includes ( 'NEXT_NOT_FOUND' ) &&
100- ! meta . headers [ 'x-next-cache-tags' ] . includes ( '/@' )
124+ ! (
125+ typeof meta . headers ?. [ 'x-next-cache-tags' ] === 'string' &&
126+ meta . headers ?. [ 'x-next-cache-tags' ] . includes ( '/@' )
127+ )
101128 ) {
102129 meta . status = 404
103130 }
0 commit comments