@@ -35,34 +35,72 @@ export interface CacheStatsInfo {
35
35
}
36
36
37
37
export interface Container {
38
- get : ( key : string ) => Promise < string | undefined | null > ;
39
- set : ( key : string , value : string , options ?: { ttl ?: number } ) => Promise < any > ;
38
+ get : ( key : string ) => Promise < any | undefined | null > ;
39
+ set : ( key : string , value : any , options ?: { ttl ?: number } ) => Promise < any > ;
40
40
has : ( key : string ) => Promise < boolean > ;
41
41
delete : ( key : string ) => Promise < boolean > ;
42
42
clear : ( ) => Promise < void > ;
43
43
}
44
44
45
+ function estimateObjectSize ( data : unknown ) : number {
46
+ const type = typeof data ;
47
+
48
+ if ( type === 'number' ) return 8 ;
49
+ if ( type === 'boolean' ) return 4 ;
50
+ if ( type === 'string' ) return Math . max ( ( data as string ) . length * 2 , 1 ) ;
51
+ if ( data === null || data === undefined ) return 1 ;
52
+
53
+ if ( ArrayBuffer . isView ( data ) ) {
54
+ return Math . max ( data . byteLength , 1 ) ;
55
+ }
56
+
57
+ if ( Array . isArray ( data ) ) {
58
+ return Math . max (
59
+ data . reduce ( ( acc , item ) => acc + estimateObjectSize ( item ) , 0 ) ,
60
+ 1 ,
61
+ ) ;
62
+ }
63
+
64
+ if ( data instanceof Map || data instanceof Set ) {
65
+ return 1024 ;
66
+ }
67
+
68
+ if ( data instanceof Date ) {
69
+ return 8 ;
70
+ }
71
+
72
+ if ( type === 'object' ) {
73
+ return Math . max (
74
+ Object . entries ( data ) . reduce (
75
+ ( acc , [ key , value ] ) => acc + key . length * 2 + estimateObjectSize ( value ) ,
76
+ 0 ,
77
+ ) ,
78
+ 1 ,
79
+ ) ;
80
+ }
81
+
82
+ return 1 ;
83
+ }
84
+
45
85
class MemoryContainer implements Container {
46
- private lru : LRUCache < string , string > ;
86
+ private lru : LRUCache < string , any > ;
47
87
48
88
constructor ( options ?: { maxSize ?: number } ) {
49
- this . lru = new LRUCache < string , string > ( {
89
+ this . lru = new LRUCache < string , any > ( {
50
90
maxSize : options ?. maxSize ?? CacheSize . GB ,
51
- sizeCalculation : ( value : string ) : number => {
52
- return value . length * 2 ;
53
- } ,
91
+ sizeCalculation : estimateObjectSize ,
54
92
updateAgeOnGet : true ,
55
93
updateAgeOnHas : true ,
56
94
} ) ;
57
95
}
58
96
59
- async get ( key : string ) : Promise < string | undefined > {
97
+ async get ( key : string ) : Promise < any | undefined > {
60
98
return this . lru . get ( key ) ;
61
99
}
62
100
63
101
async set (
64
102
key : string ,
65
- value : string ,
103
+ value : any ,
66
104
options ?: { ttl ?: number } ,
67
105
) : Promise < void > {
68
106
if ( options ?. ttl ) {
@@ -274,28 +312,28 @@ export function cache<T extends (...args: any[]) => Promise<any>>(
274
312
}
275
313
276
314
if ( ! shouldDisableCaching ) {
277
- const cachedRaw = await currentStorage . get ( storageKey ) ;
278
- if ( cachedRaw ) {
315
+ const cached = await currentStorage . get ( storageKey ) ;
316
+ if ( cached ) {
279
317
try {
280
- const cached = JSON . parse ( cachedRaw ) as CacheItem < any > ;
281
- const age = now - cached . timestamp ;
318
+ const cacheItem = cached as CacheItem < any > ;
319
+ const age = now - cacheItem . timestamp ;
282
320
283
321
if ( age < maxAge ) {
284
322
onCache ?.( {
285
323
status : 'hit' ,
286
324
key : finalKey ,
287
325
params : args ,
288
- result : cached . data ,
326
+ result : cacheItem . data ,
289
327
} ) ;
290
- return cached . data ;
328
+ return cacheItem . data ;
291
329
}
292
330
293
331
if ( revalidate > 0 && age < maxAge + revalidate ) {
294
332
onCache ?.( {
295
333
status : 'stale' ,
296
334
key : finalKey ,
297
335
params : args ,
298
- result : cached . data ,
336
+ result : cacheItem . data ,
299
337
} ) ;
300
338
301
339
if ( ! ongoingRevalidations . has ( storageKey ) ) {
@@ -338,7 +376,7 @@ export function cache<T extends (...args: any[]) => Promise<any>>(
338
376
ongoingRevalidations . set ( storageKey , revalidationPromise ) ;
339
377
}
340
378
341
- return cached . data ;
379
+ return cacheItem . data ;
342
380
}
343
381
missReason = 3 ; // cache-expired
344
382
} catch ( error ) {
@@ -431,7 +469,7 @@ async function setCacheItem(
431
469
} ;
432
470
433
471
const ttl = ( maxAge + revalidate ) / 1000 ;
434
- await storage . set ( storageKey , JSON . stringify ( newItem ) , {
472
+ await storage . set ( storageKey , newItem , {
435
473
ttl : ttl > 0 ? ttl : undefined ,
436
474
} ) ;
437
475
@@ -445,12 +483,12 @@ async function updateTagRelationships(
445
483
) : Promise < void > {
446
484
for ( const tag of tags ) {
447
485
const tagStoreKey = `${ TAG_PREFIX } ${ tag } ` ;
448
- const keyListJson = await storage . get ( tagStoreKey ) ;
449
- const keyList : string [ ] = keyListJson ? JSON . parse ( keyListJson ) : [ ] ;
450
- if ( ! keyList . includes ( storageKey ) ) {
451
- keyList . push ( storageKey ) ;
486
+ const keyList = await storage . get ( tagStoreKey ) ;
487
+ const keyArray : string [ ] = keyList || [ ] ;
488
+ if ( ! keyArray . includes ( storageKey ) ) {
489
+ keyArray . push ( storageKey ) ;
452
490
}
453
- await storage . set ( tagStoreKey , JSON . stringify ( keyList ) ) ;
491
+ await storage . set ( tagStoreKey , keyArray ) ;
454
492
}
455
493
}
456
494
@@ -461,18 +499,18 @@ async function removeKeyFromTags(
461
499
) : Promise < void > {
462
500
for ( const tag of tags ) {
463
501
const tagStoreKey = `${ TAG_PREFIX } ${ tag } ` ;
464
- const keyListJson = await storage . get ( tagStoreKey ) ;
465
- if ( keyListJson ) {
502
+ const keyList = await storage . get ( tagStoreKey ) ;
503
+ if ( keyList ) {
466
504
try {
467
- const keyList : string [ ] = JSON . parse ( keyListJson ) ;
468
- const updatedKeyList = keyList . filter ( key => key !== storageKey ) ;
505
+ const keyArray : string [ ] = Array . isArray ( keyList ) ? keyList : [ ] ;
506
+ const updatedKeyList = keyArray . filter ( key => key !== storageKey ) ;
469
507
if ( updatedKeyList . length > 0 ) {
470
- await storage . set ( tagStoreKey , JSON . stringify ( updatedKeyList ) ) ;
508
+ await storage . set ( tagStoreKey , updatedKeyList ) ;
471
509
} else {
472
510
await storage . delete ( tagStoreKey ) ;
473
511
}
474
512
} catch ( error ) {
475
- console . warn ( `Failed to parse tag key list for tag ${ tag } :` , error ) ;
513
+ console . warn ( `Failed to process tag key list for tag ${ tag } :` , error ) ;
476
514
}
477
515
}
478
516
}
@@ -495,23 +533,21 @@ export async function revalidateTag(tag: string): Promise<void> {
495
533
const currentStorage = getStorage ( ) ;
496
534
const tagStoreKey = `${ TAG_PREFIX } ${ tag } ` ;
497
535
498
- const keyListJson = await currentStorage . get ( tagStoreKey ) ;
499
- if ( keyListJson ) {
536
+ const keyList = await currentStorage . get ( tagStoreKey ) ;
537
+ if ( keyList ) {
500
538
try {
501
- const keyList : string [ ] = JSON . parse ( keyListJson ) ;
502
-
539
+ const keyArray : string [ ] = Array . isArray ( keyList ) ? keyList : [ ] ;
503
540
// For each cache key, we need to:
504
541
// 1. Get the cache item to find its associated tags
505
542
// 2. Remove this key from all other tag relationships
506
543
// 3. Delete the cache item itself
507
- for ( const cacheKey of keyList ) {
508
- const cachedRaw = await currentStorage . get ( cacheKey ) ;
509
- if ( cachedRaw ) {
544
+ for ( const cacheKey of keyArray ) {
545
+ const cached = await currentStorage . get ( cacheKey ) ;
546
+ if ( cached ) {
510
547
try {
511
- const cached = JSON . parse ( cachedRaw ) as CacheItem < any > ;
512
- if ( cached . tags ) {
513
- // Remove this cache key from all its associated tags (except the current one being revalidated)
514
- const otherTags = cached . tags . filter ( t => t !== tag ) ;
548
+ const cacheItem = cached as CacheItem < any > ;
549
+ if ( cacheItem . tags ) {
550
+ const otherTags = cacheItem . tags . filter ( t => t !== tag ) ;
515
551
await removeKeyFromTags ( currentStorage , cacheKey , otherTags ) ;
516
552
}
517
553
} catch ( error ) {
@@ -522,14 +558,12 @@ export async function revalidateTag(tag: string): Promise<void> {
522
558
}
523
559
}
524
560
525
- // Delete the cache item itself
526
561
await currentStorage . delete ( cacheKey ) ;
527
562
}
528
563
529
- // Delete the tag relationship record
530
564
await currentStorage . delete ( tagStoreKey ) ;
531
565
} catch ( error ) {
532
- console . warn ( 'Failed to parse tag key list:' , error ) ;
566
+ console . warn ( 'Failed to process tag key list:' , error ) ;
533
567
}
534
568
}
535
569
}
0 commit comments