@@ -28,8 +28,8 @@ export const MIME: Record<string, string> = {
2828 '.webp' : 'image/webp' ,
2929}
3030
31- export function cacheKey ( url : string , w : number , q : number , format : OutputFormat ) : string {
32- const hash = crypto . createHash ( 'sha256' ) . update ( `${ url } :${ w } :${ q } :${ format } ` ) . digest ( 'hex' ) . slice ( 0 , 16 )
31+ export function cacheKey ( url : string , w : number , q : number , format : OutputFormat , mtime ?: number ) : string {
32+ const hash = crypto . createHash ( 'sha256' ) . update ( `${ url } :${ w } :${ q } :${ format } : ${ mtime ?? 0 } ` ) . digest ( 'hex' ) . slice ( 0 , 16 )
3333 return `${ hash } .${ format } `
3434}
3535
@@ -95,7 +95,11 @@ export default defineHandler(async event => {
9595 const originalMime = MIME [ ext ] ?? 'application/octet-stream'
9696 const contentType = format === 'original' ? originalMime : `image/${ format } `
9797
98- const key = cacheKey ( url , w , q , format )
98+ const stat = await fs . stat ( filePath ) . catch ( ( ) => null )
99+ if ( ! stat ) {
100+ throw new HTTPError ( { status : StatusCodes . NOT_FOUND , message : 'Not Found' } )
101+ }
102+ const key = cacheKey ( url , w , q , format , stat . mtimeMs )
99103
100104 const cached = await storage . getItemRaw < Buffer > ( key )
101105 if ( cached ) {
@@ -154,6 +158,7 @@ export default defineHandler(async event => {
154158
155159export async function warmupImageCache ( ) {
156160 const { getPages, getPageImages } = await import ( '@/lib/source' ) ;
161+ // biome-ignore lint/correctness/useHookAtTopLevel: useStorage is a Nitro DI accessor, not a React hook
157162 const storage = useStorage ( STORAGE_KEY ) ;
158163 const contentDir = __CHRONICLE_CONTENT_DIR__ ;
159164 const format = 'webp' as const ;
@@ -169,14 +174,17 @@ export async function warmupImageCache() {
169174 if ( ! isLocalImage ( url ) || isSvg ( url ) || seen . has ( url ) ) continue ;
170175 seen . add ( url ) ;
171176
172- const key = cacheKey ( url , w , q , format ) ;
173- const cached = await storage . getItemRaw ( key ) ;
174- if ( cached ) continue ;
175-
176177 const relativePath = url . replace ( / ^ \/ _ c o n t e n t \/ / , '' ) ;
177178 const filePath = safePath ( contentDir , `/${ relativePath } ` ) ;
178179 if ( ! filePath ) continue ;
179180
181+ const stat = await fs . stat ( filePath ) . catch ( ( ) => null ) ;
182+ if ( ! stat ) continue ;
183+
184+ const key = cacheKey ( url , w , q , format , stat . mtimeMs ) ;
185+ const cached = await storage . getItemRaw ( key ) ;
186+ if ( cached ) continue ;
187+
180188 try {
181189 const optimized = await optimizeImage ( filePath , w , q , format ) ;
182190 await storage . setItemRaw ( key , optimized ) ;
0 commit comments