npm.io
1.0.1 • Published 5d ago

@amiki/cache

Licence
GPL-2.0-only
Version
1.0.1
Deps
2
Size
266 kB
Vulns
0
Weekly
285

@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/cache

Quick 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: CacheInvalidator broadcasts 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: redis and hybrid strategies require await 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.

Keywords