@amiki/cache
v1.0.1
Published
Pluggable cache strategies for amiki-framework — memory (LRU+TTL), SQLite, Redis, Hybrid (L1+L2), with transport-based invalidation and index support
Maintainers
Readme
@amiki/cache
Pluggable cache strategies for amiki-framework — memory, SQLite, Redis, Hybrid.
Unified Cache<T> interface with multiple backends, TTL support, bulk operations, scan/pagination, and transport-based invalidation.
Installation
bun add @amiki/cacheQuick Start
import { createCache } from '@amiki/cache';
// In-memory LRU with TTL
const cache = createCache({ strategy: 'memory', maxSize: 10_000, ttl: 60_000 });
await cache.set('myKey', { hello: 'world' });
const val = await cache.get('myKey'); // { hello: 'world' }
await cache.delete('myKey');Backends
| Strategy | Class | Description | Persistence |
|----------|-------|-------------|-------------|
| memory | MemoryCache | LRU + TTL, zero-dependency | ❌ Volatile |
| sqlite | SqliteCache | Bun.sqlite WAL mode, persistent | ✅ File-based |
| redis | RedisCache | Bun.RedisClient, distributed | ✅ Remote |
| hybrid | HybridCache | L1 memory + L2 Redis, read-through/write-through | ✅ Remote |
Features
- TTL: per-key or default, automatic sweep
- Bulk ops:
getMany,setMany,deleteMany - Scan: key prefix filter, cursor-based pagination
- Stats: hit/miss counters, size, evictions, memory usage
- Hybrid mode: L1 MemoryCache (fast) + L2 RedisCache (shared), read-through/write-through
- Invalidation:
CacheInvalidatorbroadcasts invalidation events over transport - 152 tests, 263
expect()across all backends
Usage
Factory
const memory = createCache({ strategy: 'memory', maxSize: 5_000, ttl: 30_000 });
const sqlite = createCache({ strategy: 'sqlite', path: './cache.db', ttl: 60_000 });
const redis = createCache({ strategy: 'redis', redisUrl: 'redis://localhost:6379' });
// Hybrid: memory (L1) + Redis (L2)
const hybrid = createCache({
strategy: 'hybrid',
redisUrl: 'redis://localhost:6379',
maxSize: 10_000,
ttl: 300_000,
});Note:
redisandhybridstrategies requireawait cache.connect()before use.
Direct Construction
import { MemoryCache, SqliteCache, RedisCache, HybridCache, CacheInvalidator } from '@amiki/cache';
const cache = new MemoryCache<string>({ maxSize: 1000, defaultTtl: 60_000 });
await cache.set('key', 'value');Cache Invalidation
import { createTransport } from '@amiki/transport';
import { CacheInvalidator } from '@amiki/cache';
const transport = createTransport({ type: 'redis', redisUrl: 'redis://localhost:6379' });
await transport.connect();
const invalidator = new CacheInvalidator({ transport, namespace: 'my-cache' });
await invalidator.connect();
// Broadcast invalidation to all processes
await invalidator.invalidate(['key1', 'key2'], 'user-update');
// Listen for invalidation events
invalidator.onInvalidation((event) => {
console.log('Invalidation received:', event.keys);
});API
Cache<T> Interface
| Method | Description |
|--------|-------------|
| get(key) | Get value by key |
| set(key, value, ttl?) | Set value with optional TTL |
| delete(key) | Delete key |
| has(key) | Check key existence |
| getMany(keys) | Bulk get |
| setMany(entries, ttl?) | Bulk set |
| deleteMany(keys) | Bulk delete |
| scan(options?) | Scan keys with prefix filter |
| clear() | Clear all entries |
| stats() | Cache statistics |
| name | Cache namespace |
CacheStats
{ size, capacity, gets, hits, misses, sets, deletes, evictions, memoryUsageBytes }Test Coverage
| Backend | Tests | Key Coverage | |---------|-------|--------------| | MemoryCache | 40 | LRU eviction, TTL sweep, scan pagination, concurrent access | | SqliteCache | 33 | WAL persistence, TTL, multi-cache isolation, scan | | RedisCache | 39 | 11 structure + 28 integration (graceful skip if no Redis) | | HybridCache | 23 | L1 hit, L1→L2 read-through, write-through, invalidateLocal | | CacheInvalidator | 17 | Mock transport, publish/subscribe roundtrip, malformed payloads |
License
GPL-2.0-only — see LICENSE for details.
