Stone.jsDocs
Paradigm

Extensions

Cache

One cache contract, pluggable backends. @stone-js/cache gives you get/set/remember with TTL and tags, over a memory store (zero-config) or Redis, injected as cache, with decorators to cache method results declaratively. Provider KV follows.

#Install

terminalbash
npm i @stone-js/cache
npm i ioredis   # only for the Redis store

#Enable it

The principle

Caching should be a property of the call, not plumbing woven through it. Declare what to cache and for how long; let the store handle the rest.

In Stone.js

A single { get, set, remember, invalidateTags }contract backs every driver. The provider binds the manager as cacheManagerand the default store as cache.

app/Application.tsdeclarativeimperative
import { StoneApp } from '@stone-js/core'
import { Cache } from '@stone-js/cache'

@Cache({ driver: 'memory' })
@StoneApp({ name: 'app' })
export class Application {}
import { defineConfig } from '@stone-js/core'
import { defineCache } from '@stone-js/cache'

export const AppConfig = defineConfig(defineCache({
  default: 'redis',
  stores: [
    { name: 'redis', driver: 'redis', url: 'redis://localhost:6379', prefix: 'app' },
    { name: 'ram', driver: 'memory', ttl: 60 }
  ]
}))

#Use it

Inject the default store as cache (or the manager as cacheManager). remember returns the cached value or computes, stores and returns it, and concurrent cold calls share one computation (stampede protection).

app/ReportService.tsts
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'] }
    )
  }
}

#Decorators

Cache method results without touching their bodies.

app/UserService.tsts
import { Cacheable, CacheEvict, CachePut } from '@stone-js/cache'

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() }
}
decoratorTypeDescription
@CacheablemethodCache the result (cache-aside). Serves the cache on a hit; distinct arguments key distinct entries.
@CachePutmethodAlways run, then refresh the cached value. Keeps the cache warm after writes.
@CacheEvictmethodInvalidate a key, tags, or the whole store after the method runs.

#Drivers

driverTypeDescription
memorybuilt-inIn-process Map with TTL, tags and counters. The zero-config default; single process.
redisioredisShared across instances. JSON values, native TTL, tags via Redis sets. Set url / options / client.
provider KVcoming nextCloudflare / Vercel KV, same contract.

Stone.js

Your app exists in every runtime. Until you run it.

An open-source project by Stone Foundation
Created by Mr. Stone (Evens Pierre)