11import fs from "node:fs/promises" ;
22import path from "node:path" ;
33import { fileURLToPath } from "node:url" ;
4- import type { Schema } from "astro/zod" ;
4+ import { type Schema , z } from "zod" ;
5+
6+ // 1 week
7+ const DEFAULT_TTL = 7 * 24 * 60 * 60 ;
8+ const Meta = z . object ( {
9+ writtenAt : z . number ( ) ,
10+ } ) ;
11+ type Meta = z . infer < typeof Meta > ;
512/**
613 - this uses FS to cache. only use this for expensive things that need FS caching (such as fetching from the Internet)
714 - this does not cache `null` or `undefined`.
815 */
916export async function cache < T > (
1017 key : string ,
11- schema : Schema < T > ,
18+ Schema : Schema < T > ,
1219 load : ( ) => Promise < T > ,
20+ /** ttl: time-to-live in seconds */
21+ options : {
22+ ttl ?: number ;
23+ } = { } ,
1324) : Promise < T > {
25+ const ttl = options . ttl ?? DEFAULT_TTL ;
26+ const now = new Date ( ) . getTime ( ) / 1000 ;
1427 const path = await toPath ( sanitizeKey ( key ) ) ;
1528
1629 // cache load
1730 if ( await exists ( path ) ) {
1831 try {
19- const file = await fs . readFile ( path , {
20- encoding : "utf8" ,
21- } ) ;
22- const val = schema . parse ( JSON . parse ( file ) ) ;
32+ const file = JSON . parse (
33+ await fs . readFile ( path , {
34+ encoding : "utf8" ,
35+ } ) ,
36+ ) ;
37+ const data = Schema . parse ( file . data ) ;
38+ const meta = Meta . parse ( file . meta ) ;
2339 // cache hit
24- return val ;
40+ if ( now - meta . writtenAt <= ttl ) return data ;
2541 } catch ( err ) {
2642 console . warn ( "failed to parse retrieved cache:" , err ) ;
2743 }
@@ -30,11 +46,17 @@ export async function cache<T>(
3046 // cache miss
3147 const val = await load ( ) ;
3248
33- const parse = schema . safeParse ( val ) ;
49+ const parse = Schema . safeParse ( val ) ;
3450 if ( parse . success ) {
3551 if ( val != null ) {
3652 // write cache
37- await fs . writeFile ( path , JSON . stringify ( val ) ) ;
53+ const content = {
54+ data : val ,
55+ meta : {
56+ writtenAt : now ,
57+ } satisfies Meta ,
58+ } ;
59+ await fs . writeFile ( path , JSON . stringify ( content ) ) ;
3860 }
3961 } else {
4062 // skip lcache
0 commit comments