A lightweight, zero-dependency in-memory cache for TypeScript and JavaScript with TTL expiration, LRU eviction, wildcard pattern deletion, and a powerful @cached decorator for method-level memoization. Perfect for API response caching, session storage, an
npm install @humanspeak/memory-cacheA lightweight, zero-dependency in-memory cache for TypeScript and JavaScript








A powerful, feature-rich in-memory caching solution with TTL expiration, true LRU (Least Recently Used) eviction, wildcard pattern deletion, and a @cached decorator for effortless method-level memoization. Perfect for API response caching, session storage, expensive computation caching, and performance optimization.
Visit the documentation for detailed API reference and examples.
- Zero Dependencies - Lightweight and fast
- TTL Expiration - Automatic cache entry expiration
- LRU Eviction - Least recently used entries are evicted when cache is full
- Wildcard Deletion - Delete entries by prefix or wildcard patterns
- Full TypeScript Support - Complete type definitions included
- Method Decorator - @cached decorator for automatic memoization
- Null/Undefined Support - Properly caches falsy values
- Cache Statistics - Track hits, misses, evictions, and expirations
- Introspection - Query cache size, keys, values, and entries
- Lifecycle Hooks - Observe cache events for monitoring and debugging
``bash`
npm install @humanspeak/memory-cache
`bash`
pnpm add @humanspeak/memory-cache
`bash`
yarn add @humanspeak/memory-cache
`typescript
import { MemoryCache } from '@humanspeak/memory-cache'
// Create a cache with default options (100 entries, 5 minute TTL)
const cache = new MemoryCache
// Or customize the options
const customCache = new MemoryCache
maxSize: 1000, // Maximum entries before eviction
ttl: 10 60 1000 // 10 minutes TTL
})
// Store and retrieve values
cache.set('user:123', 'John Doe')
const name = cache.get('user:123') // 'John Doe'
// Check if key exists
if (cache.has('user:123')) {
// Key exists and hasn't expired
}
// Delete entries
cache.delete('user:123')
cache.clear() // Remove all entries
`
`typescript
const cache = new MemoryCache
cache.set('user:123:name', 'John')
cache.set('user:123:email', 'john@example.com')
cache.set('user:456:name', 'Jane')
cache.set('post:789', 'Hello World')
// Delete by prefix
cache.deleteByPrefix('user:123:') // Removes user:123:name and user:123:email
// Delete by wildcard pattern
cache.deleteByMagicString('user:*:name') // Removes all user names
cache.deleteByMagicString(':123:') // Removes all entries with :123:
`
`typescript
import { cached } from '@humanspeak/memory-cache'
class UserService {
@cached
async getUser(id: string): Promise
// This expensive operation will be cached
return await database.findUser(id)
}
@cached
getUserPermissions(userId: string, role: string): string[] {
// Results are cached per unique argument combination
return computePermissions(userId, role)
}
}
const service = new UserService()
// First call - executes the method
await service.getUser('123')
// Second call - returns cached result
await service.getUser('123')
`
`typescript
import { MemoryCache } from '@humanspeak/memory-cache'
const cache = new MemoryCache
// Automatically fetch and cache on miss
const user = await cache.getOrSet('user:123', async () => {
return await fetchUserFromDB(123)
})
// Concurrent requests share the same fetch (thundering herd prevention)
const promises = Array.from({ length: 100 }, () =>
cache.getOrSet('popular-key', fetchExpensiveData)
)
await Promise.all(promises) // fetchExpensiveData called only once
`
#### Constructor Options
| Option | Type | Default | Description |
| --------- | ------------ | -------- | ------------------------------------------------ |
| maxSize | number | 100 | Maximum entries before eviction (0 = unlimited) |ttl
| | number | 300000 | Time-to-live in milliseconds (0 = no expiration) |hooks
| | CacheHooks | {} | Lifecycle hooks for observing cache events |
#### Methods
| Method | Description |
| ------------------------------ | ---------------------------------------------------- |
| get(key) | Retrieves a value from the cache |set(key, value)
| | Stores a value in the cache |getOrSet(key, fetcher)
| | Gets cached value or fetches and caches on miss |has(key)
| | Checks if a key exists (useful for cached undefined) |delete(key)
| | Removes a specific entry |deleteAsync(key)
| | Async version of delete |clear()
| | Removes all entries |deleteByPrefix(prefix)
| | Removes entries starting with prefix |deleteByMagicString(pattern)
| | Removes entries matching wildcard pattern |size()
| | Returns the number of entries in cache |keys()
| | Returns array of all cache keys |values()
| | Returns array of all cached values |entries()
| | Returns array of [key, value] pairs |getStats()
| | Returns cache statistics (hits, misses, etc.) |resetStats()
| | Resets statistics counters to zero |prune()
| | Removes all expired entries, returns count |
A method decorator for automatic result caching.
`typescript`
@cached
methodName(args): ReturnType { ... }
`typescript
// High-traffic API cache
const apiCache = new MemoryCache
maxSize: 10000,
ttl: 5 60 1000 // 5 minutes
})
// Session storage (longer TTL, smaller size)
const sessionCache = new MemoryCache
maxSize: 1000,
ttl: 30 60 1000 // 30 minutes
})
// Computation cache (no TTL, size-limited)
const computeCache = new MemoryCache
maxSize: 500,
ttl: 0 // No expiration
})
// Unlimited cache (use with caution)
const unlimitedCache = new MemoryCache({
maxSize: 0, // No size limit
ttl: 0 // No expiration
})
`
Track cache performance with built-in statistics:
`typescript
const cache = new MemoryCache
cache.set('key', 'value')
cache.get('key') // hit
cache.get('missing') // miss
const stats = cache.getStats()
// { hits: 1, misses: 1, evictions: 0, expirations: 0, size: 1 }
// Reset statistics
cache.resetStats()
// Proactively remove expired entries
const prunedCount = cache.prune()
`
Monitor cache lifecycle events with optional hooks:
`typescriptCache hit: ${key}
const cache = new MemoryCache
maxSize: 100,
ttl: 60000,
hooks: {
onHit: ({ key, value }) => console.log(),Cache miss: ${key} (${reason})
onMiss: ({ key, reason }) => console.log(),Set: ${key} ${isUpdate ? '(update)' : '(new)'}
onSet: ({ key, isUpdate }) => console.log(),Evicted: ${key}
onEvict: ({ key }) => console.log(),Expired: ${key} via ${source}
onExpire: ({ key, source }) => console.log(),Deleted: ${key} via ${source}
onDelete: ({ key, source }) => console.log()`
}
})
| Hook | When Called | Context |
| ---------- | ----------------------------------- | ------------------------------------------- |
| onHit | Successful cache retrieval | { key, value } |onMiss
| | Cache miss (not found or expired) | { key, reason: 'not_found' \| 'expired' } |onSet
| | Value stored in cache | { key, value, isUpdate } |onEvict
| | Entry evicted due to size limit | { key, value } |onExpire
| | Entry removed due to TTL expiration | { key, value, source } |onDelete
| | Entry explicitly deleted | { key, value, source }` |
Hooks are synchronous and errors are silently caught to prevent cache corruption.
For complete documentation, examples, and API reference, visit memory.svelte.page.
MIT License - see LICENSE for details.
Contributions are welcome! Please feel free to submit a Pull Request.