@stone-js/cache
v0.8.15
Published
Agnostic cache for Stone.js: get/set/ttl/tags/remember on a store contract, with memory and Redis drivers, decorators (@Cache, @Cacheable, @CacheEvict, @CachePut), and a cacheManager injected in the container.
Downloads
1,818
Maintainers
Readme
Stone.js - Cache
Agnostic cache for Stone.js. One store contract (get/set/ttl/tags/remember), pluggable drivers (memory now, Redis via ioredis, provider KV next), decorators (@Cache, @Cacheable, @CacheEvict, @CachePut), and a cacheManager injected in the container. Zero-config by default, with stampede protection and tag-grouped invalidation.
Installation
npm install @stone-js/cache
# for the Redis store (optional):
npm install ioredisPeer dependency:
@stone-js/core.ioredisis an optional peer, imported lazily only when a Redis store is used.
Enable it
Declarative (single store):
import { StoneApp } from '@stone-js/core'
import { Cache } from '@stone-js/cache'
@Cache({ driver: 'memory' })
@StoneApp({ name: 'app' })
export class Application {}Imperative / multi-store via stone.cache:
import { defineConfig } from '@stone-js/core'
export const AppConfig = defineConfig((blueprint) => blueprint.set('stone.cache', {
default: 'redis',
stores: [
{ name: 'redis', driver: 'redis', url: 'redis://localhost:6379', prefix: 'app' },
{ name: 'ram', driver: 'memory', ttl: 60 }
]
}))Use the cache
Inject the default store (cache) or the manager (cacheManager):
export class ReportService {
constructor (private readonly cache) {}
async monthly (year: number) {
return await this.cache.remember(`report:${year}`, async () => await this.compute(year), { ttl: 300, tags: ['reports'] })
}
}get · set(key, value, { ttl, tags }) · has · delete · clear · pull · add · increment/decrement · remember(key, factory, { ttl, tags }) · invalidateTags([...]).
Decorators
class UserService {
@Cacheable({ ttl: 300, tags: ['users'] })
async find (id: string) { return await this.repo.get(id) }
@CachePut({ key: (id) => `User.find:${id}` })
async update (id: string, data: object) { return await this.repo.save(id, data) }
@CacheEvict({ tags: ['users'] })
async purge () { await this.repo.clear() }
}@Cacheablecaches the result (cache-aside); concurrent cold calls share one execution.@CachePutalways runs and refreshes the cache.@CacheEvictinvalidates a key, tags, or the whole store after the method runs.
If the cache module is not enabled, the decorators call through with no caching (graceful no-op).
Documentation
See the official documentation for the full guide.
