114 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| interface CreateCacheOptions {
 | |
|   expires?: number; // Default expiration time for all cache entries
 | |
| }
 | |
| 
 | |
| interface SetCacheOptions {
 | |
|   expires?: number; // Override expiration for individual cache entries
 | |
| }
 | |
| 
 | |
| export const caches = new Map<
 | |
|   string,
 | |
|   {
 | |
|     info: () => { name: string; count: number; sizeInKB: number };
 | |
|     clear: () => void;
 | |
|   }
 | |
| >();
 | |
| 
 | |
| export function createCache<T>(
 | |
|   cacheName: string,
 | |
|   createOpts: CreateCacheOptions = {},
 | |
| ) {
 | |
|   const cache = new Map<string, { value: T; expiresAt?: number }>();
 | |
| 
 | |
|   const api = {
 | |
|     get(key: string): T | undefined {
 | |
|       const entry = cache.get(key);
 | |
|       if (!entry) return undefined;
 | |
| 
 | |
|       const now = Date.now();
 | |
|       if (entry.expiresAt && entry.expiresAt <= now) {
 | |
|         cache.delete(key); // Remove expired entry
 | |
|         return undefined;
 | |
|       }
 | |
| 
 | |
|       return entry.value; // Return value if not expired
 | |
|     },
 | |
| 
 | |
|     clear() {
 | |
|       cache.clear();
 | |
|     },
 | |
| 
 | |
|     set(key: string, value: T | unknown, opts: SetCacheOptions = {}) {
 | |
|       const now = Date.now();
 | |
|       const expiresIn = opts.expires ?? createOpts.expires;
 | |
|       const expiresAt = expiresIn ? now + expiresIn : undefined;
 | |
| 
 | |
|       cache.set(key, { value: value as T, expiresAt });
 | |
|     },
 | |
| 
 | |
|     cleanup() {
 | |
|       const now = Date.now();
 | |
|       for (const [key, entry] of cache.entries()) {
 | |
|         if (entry.expiresAt && entry.expiresAt <= now) {
 | |
|           cache.delete(key);
 | |
|         }
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     info() {
 | |
|       // Cleanup expired entries before calculating info
 | |
|       this.cleanup();
 | |
| 
 | |
|       // Count the number of objects in the cache
 | |
|       const count = cache.size;
 | |
| 
 | |
|       // Approximate the size in KB by serializing each key and value
 | |
|       let totalBytes = 0;
 | |
|       for (const [key, entry] of cache.entries()) {
 | |
|         const keySize = new TextEncoder().encode(key).length;
 | |
|         const valueSize = new TextEncoder().encode(
 | |
|           JSON.stringify(entry.value),
 | |
|         ).length;
 | |
|         totalBytes += keySize + valueSize;
 | |
|       }
 | |
| 
 | |
|       const sizeInKB = Math.floor(totalBytes / 1024); // Convert bytes to kilobytes
 | |
|       return { name: cacheName, count, sizeInKB };
 | |
|     },
 | |
| 
 | |
|     has(key: string): boolean {
 | |
|       const entry = cache.get(key);
 | |
|       if (!entry) return false;
 | |
| 
 | |
|       const now = Date.now();
 | |
|       if (entry.expiresAt && entry.expiresAt <= now) {
 | |
|         cache.delete(key); // Remove expired entry
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       return true;
 | |
|     },
 | |
| 
 | |
|     keys(): string[] {
 | |
|       this.cleanup(); // Cleanup before returning keys
 | |
|       return Array.from(cache.keys());
 | |
|     },
 | |
| 
 | |
|     size(): number {
 | |
|       this.cleanup(); // Cleanup before returning size
 | |
|       return cache.size;
 | |
|     },
 | |
|   };
 | |
| 
 | |
|   caches.set(cacheName, {
 | |
|     clear: api.clear.bind(api),
 | |
|     info: api.info.bind(api),
 | |
|   });
 | |
| 
 | |
|   return api;
 | |
| }
 | |
| 
 | |
| export function getCacheInfo() {
 | |
|   return [...caches.values().map((c) => c.info())];
 | |
| }
 |