11import { existsSync } from 'node:fs'
2- import { readFile } from 'node:fs/promises'
3- import { join } from 'node:path'
2+ import { mkdir , readFile , writeFile } from 'node:fs/promises'
3+ import { dirname , join } from 'node:path'
44
5- import glob from 'fast-glob'
5+ import { glob } from 'fast-glob'
6+ import type { CacheHandlerValue } from 'next/dist/server/lib/incremental-cache/index.js'
7+ import type { IncrementalCacheValue } from 'next/dist/server/response-cache/types.js'
68
7- import type {
8- CacheValue ,
9- FetchCacheValue ,
10- PageCacheValue ,
11- PluginContext ,
12- RouteCacheValue ,
13- } from '../plugin-context.js'
9+ import { encodeBlobKey } from '../../shared/blobkey.js'
10+ import type { PluginContext } from '../plugin-context.js'
11+
12+ type CachedPageValue = Extract < IncrementalCacheValue , { kind : 'PAGE' } >
13+ type CachedRouteValue = Extract < IncrementalCacheValue , { kind : 'ROUTE' } >
14+ type CachedFetchValue = Extract < IncrementalCacheValue , { kind : 'FETCH' } >
15+
16+ /**
17+ * Write a cache entry to the blob upload directory.
18+ */
19+ const writeCacheEntry = async (
20+ route : string ,
21+ value : IncrementalCacheValue ,
22+ lastModified : number ,
23+ ctx : PluginContext ,
24+ ) : Promise < void > => {
25+ const path = join ( ctx . blobDir , await encodeBlobKey ( route ) )
26+ const entry = JSON . stringify ( {
27+ lastModified,
28+ value,
29+ } satisfies CacheHandlerValue )
30+
31+ await mkdir ( dirname ( path ) , { recursive : true } )
32+ await writeFile ( path , entry , 'utf-8' )
33+ }
1434
1535/**
1636 * Normalize routes by stripping leading slashes and ensuring root path is index
1737 */
1838const routeToFilePath = ( path : string ) => ( path === '/' ? '/index' : path )
1939
20- const buildPagesCacheValue = async ( path : string ) : Promise < PageCacheValue > => ( {
40+ const buildPagesCacheValue = async ( path : string ) : Promise < CachedPageValue > => ( {
2141 kind : 'PAGE' ,
2242 html : await readFile ( `${ path } .html` , 'utf-8' ) ,
2343 pageData : JSON . parse ( await readFile ( `${ path } .json` , 'utf-8' ) ) ,
44+ postponed : undefined ,
45+ headers : undefined ,
46+ status : undefined ,
2447} )
2548
26- const buildAppCacheValue = async ( path : string ) : Promise < PageCacheValue > => ( {
49+ const buildAppCacheValue = async ( path : string ) : Promise < CachedPageValue > => ( {
2750 kind : 'PAGE' ,
2851 html : await readFile ( `${ path } .html` , 'utf-8' ) ,
2952 pageData : await readFile ( `${ path } .rsc` , 'utf-8' ) ,
3053 ...JSON . parse ( await readFile ( `${ path } .meta` , 'utf-8' ) ) ,
3154} )
3255
33- const buildRouteCacheValue = async ( path : string ) : Promise < RouteCacheValue > => ( {
56+ const buildRouteCacheValue = async ( path : string ) : Promise < CachedRouteValue > => ( {
3457 kind : 'ROUTE' ,
3558 body : await readFile ( `${ path } .body` , 'base64' ) ,
3659 ...JSON . parse ( await readFile ( `${ path } .meta` , 'utf-8' ) ) ,
3760} )
3861
39- const buildFetchCacheValue = async ( path : string ) : Promise < FetchCacheValue > => ( {
62+ const buildFetchCacheValue = async ( path : string ) : Promise < CachedFetchValue > => ( {
4063 kind : 'FETCH' ,
4164 ...JSON . parse ( await readFile ( path , 'utf-8' ) ) ,
4265} )
@@ -51,45 +74,38 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void>
5174
5275 await Promise . all (
5376 Object . entries ( manifest . routes ) . map ( async ( [ route , meta ] ) : Promise < void > => {
77+ const lastModified = meta . initialRevalidateSeconds ? 1 : Date . now ( )
5478 const key = routeToFilePath ( route )
55- let value : CacheValue
56- let path : string
79+ let value : IncrementalCacheValue
5780 switch ( true ) {
5881 // Parallel route default layout has no prerendered page
5982 case meta . dataRoute ?. endsWith ( '/default.rsc' ) &&
6083 ! existsSync ( join ( ctx . publishDir , 'server/app' , `${ key } .html` ) ) :
6184 return
6285 case meta . dataRoute ?. endsWith ( '.json' ) :
63- path = join ( ctx . publishDir , 'server/pages' , key )
64- value = await buildPagesCacheValue ( path )
86+ value = await buildPagesCacheValue ( join ( ctx . publishDir , 'server/pages' , key ) )
6587 break
6688 case meta . dataRoute ?. endsWith ( '.rsc' ) :
67- path = join ( ctx . publishDir , 'server/app' , key )
68- value = await buildAppCacheValue ( path )
89+ value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
6990 break
7091 case meta . dataRoute === null :
71- path = join ( ctx . publishDir , 'server/app' , key )
72- value = await buildRouteCacheValue ( path )
92+ value = await buildRouteCacheValue ( join ( ctx . publishDir , 'server/app' , key ) )
7393 break
7494 default :
7595 throw new Error ( `Unrecognized content: ${ route } ` )
7696 }
7797
78- await ctx . writeCacheEntry (
79- key ,
80- value ,
81- meta . dataRoute === null ? `${ path } .body` : `${ path } .html` ,
82- )
98+ await writeCacheEntry ( key , value , lastModified , ctx )
8399 } ) ,
84100 )
85101
86102 // app router 404 pages are not in the prerender manifest
87103 // so we need to check for them manually
88104 if ( existsSync ( join ( ctx . publishDir , `server/app/_not-found.html` ) ) ) {
105+ const lastModified = Date . now ( )
89106 const key = '/404'
90- const path = join ( ctx . publishDir , 'server/app/_not-found' )
91- const value = await buildAppCacheValue ( path )
92- await ctx . writeCacheEntry ( key , value , `${ path } .html` )
107+ const value = await buildAppCacheValue ( join ( ctx . publishDir , 'server/app/_not-found' ) )
108+ await writeCacheEntry ( key , value , lastModified , ctx )
93109 }
94110 } catch ( error ) {
95111 ctx . failBuild ( 'Failed assembling prerendered content for upload' , error )
@@ -108,9 +124,10 @@ export const copyFetchContent = async (ctx: PluginContext): Promise<void> => {
108124
109125 await Promise . all (
110126 paths . map ( async ( key ) : Promise < void > => {
127+ const lastModified = 1
111128 const path = join ( ctx . publishDir , 'cache/fetch-cache' , key )
112129 const value = await buildFetchCacheValue ( path )
113- await ctx . writeCacheEntry ( key , value , path )
130+ await writeCacheEntry ( key , value , lastModified , ctx )
114131 } ) ,
115132 )
116133 } catch ( error ) {
0 commit comments