@@ -16,11 +16,12 @@ import { unstable_readConfig } from "wrangler";
1616
1717import {
1818 BINDING_NAME as KV_CACHE_BINDING_NAME ,
19+ computeCacheKey as computeKVCacheKey ,
1920 NAME as KV_CACHE_NAME ,
2021} from "../../api/overrides/incremental-cache/kv-incremental-cache.js" ;
2122import {
2223 BINDING_NAME as R2_CACHE_BINDING_NAME ,
23- DEFAULT_PREFIX as R2_CACHE_DEFAULT_PREFIX ,
24+ computeCacheKey as computeR2CacheKey ,
2425 NAME as R2_CACHE_NAME ,
2526 PREFIX_ENV_NAME as R2_CACHE_PREFIX_ENV_NAME ,
2627} from "../../api/overrides/incremental-cache/r2-incremental-cache.js" ;
@@ -45,22 +46,50 @@ async function resolveCacheName(
4546 return typeof value === "function" ? ( await value ( ) ) . name : value ;
4647}
4748
48- function getCacheAssetPaths ( opts : BuildOptions ) {
49- return globSync ( path . join ( opts . outputDir , "cache/**/*" ) , {
49+ export type CacheAsset = { isFetch : boolean ; fullPath : string ; key : string ; buildId : string } ;
50+
51+ export function getCacheAssets ( opts : BuildOptions ) : CacheAsset [ ] {
52+ const allFiles = globSync ( path . join ( opts . outputDir , "cache/**/*" ) , {
5053 withFileTypes : true ,
5154 windowsPathsNoEscape : true ,
52- } )
53- . filter ( ( f ) => f . isFile ( ) )
54- . map ( ( f ) => {
55- const relativePath = path . relative ( path . join ( opts . outputDir , "cache" ) , f . fullpathPosix ( ) ) ;
56-
57- return {
58- fsPath : f . fullpathPosix ( ) ,
59- destPath : relativePath . startsWith ( "__fetch" )
60- ? `${ relativePath . replace ( "__fetch/" , "" ) } .fetch`
61- : relativePath ,
62- } ;
63- } ) ;
55+ } ) . filter ( ( f ) => f . isFile ( ) ) ;
56+
57+ const assets : CacheAsset [ ] = [ ] ;
58+
59+ for ( const file of allFiles ) {
60+ const fullPath = file . fullpathPosix ( ) ;
61+ const relativePath = path . relative ( path . join ( opts . outputDir , "cache" ) , fullPath ) ;
62+
63+ if ( relativePath . startsWith ( "__fetch" ) ) {
64+ const [ __fetch , buildId , ...keyParts ] = relativePath . split ( "/" ) ;
65+
66+ if ( __fetch !== "__fetch" || buildId === undefined || keyParts . length === 0 ) {
67+ throw new Error ( `Invalid path for a Cache Asset file: ${ relativePath } ` ) ;
68+ }
69+
70+ assets . push ( {
71+ isFetch : true ,
72+ fullPath,
73+ key : `/${ keyParts . join ( "/" ) } ` ,
74+ buildId,
75+ } ) ;
76+ } else {
77+ const [ buildId , ...keyParts ] = relativePath . slice ( 0 , - ".cache" . length ) . split ( "/" ) ;
78+
79+ if ( ! relativePath . endsWith ( ".cache" ) || buildId === undefined || keyParts . length === 0 ) {
80+ throw new Error ( `Invalid path for a Cache Asset file: ${ relativePath } ` ) ;
81+ }
82+
83+ assets . push ( {
84+ isFetch : false ,
85+ fullPath,
86+ key : `/${ keyParts . join ( "/" ) } ` ,
87+ buildId,
88+ } ) ;
89+ }
90+ }
91+
92+ return assets ;
6493}
6594
6695function populateR2IncrementalCache (
@@ -81,17 +110,18 @@ function populateR2IncrementalCache(
81110 throw new Error ( `R2 binding ${ JSON . stringify ( R2_CACHE_BINDING_NAME ) } should have a 'bucket_name'` ) ;
82111 }
83112
84- const assets = getCacheAssetPaths ( options ) ;
85- for ( const { fsPath, destPath } of tqdm ( assets ) ) {
86- const fullDestPath = path . join (
87- bucket ,
88- process . env [ R2_CACHE_PREFIX_ENV_NAME ] ?? R2_CACHE_DEFAULT_PREFIX ,
89- destPath
90- ) ;
113+ const assets = getCacheAssets ( options ) ;
114+
115+ for ( const { fullPath, key, buildId, isFetch } of tqdm ( assets ) ) {
116+ const cacheKey = computeR2CacheKey ( key , {
117+ directory : process . env [ R2_CACHE_PREFIX_ENV_NAME ] ,
118+ buildId,
119+ isFetch,
120+ } ) ;
91121
92122 runWrangler (
93123 options ,
94- [ "r2 object put" , JSON . stringify ( fullDestPath ) , `--file ${ JSON . stringify ( fsPath ) } ` ] ,
124+ [ "r2 object put" , JSON . stringify ( path . join ( bucket , cacheKey ) ) , `--file ${ JSON . stringify ( fullPath ) } ` ] ,
95125 // NOTE: R2 does not support the environment flag and results in the following error:
96126 // Incorrect type for the 'cacheExpiry' field on 'HttpMetadata': the provided value is not of type 'date'.
97127 { target : populateCacheOptions . target , excludeRemoteFlag : true , logging : "error" }
@@ -113,15 +143,21 @@ function populateKVIncrementalCache(
113143 throw new Error ( `No KV binding ${ JSON . stringify ( KV_CACHE_BINDING_NAME ) } found!` ) ;
114144 }
115145
116- const assets = getCacheAssetPaths ( options ) ;
117- for ( const { fsPath, destPath } of tqdm ( assets ) ) {
146+ const assets = getCacheAssets ( options ) ;
147+
148+ for ( const { fullPath, key, buildId, isFetch } of tqdm ( assets ) ) {
149+ const cacheKey = computeKVCacheKey ( key , {
150+ buildId,
151+ isFetch,
152+ } ) ;
153+
118154 runWrangler (
119155 options ,
120156 [
121157 "kv key put" ,
122- JSON . stringify ( destPath ) ,
158+ JSON . stringify ( cacheKey ) ,
123159 `--binding ${ JSON . stringify ( KV_CACHE_BINDING_NAME ) } ` ,
124- `--path ${ JSON . stringify ( fsPath ) } ` ,
160+ `--path ${ JSON . stringify ( fullPath ) } ` ,
125161 ] ,
126162 { ...populateCacheOptions , logging : "error" }
127163 ) ;
0 commit comments