Skip to content

v3.0.0

Choose a tag to compare

@grischaerbe grischaerbe released this 29 Apr 22:05
· 1 commit to master since this release
23295a0

cacheables v3.0.0

v3 is a ground-up rewrite. The core idea is unchanged — wrap an async call, get caching for free — but the storage model, options shape, and method names are new.

What's new

  • Multilayer storage via buckets. Stack a fast in-memory L1 with any L2/L3 you write (filesystem, Redis, S3, IndexedDB, …). Reads cascade L1 → Ln; on any hit, missing upper layers are back-filled. Writes fan out to every bucket in parallel.
  • Bucket views (cache.resolve). Cacheable<TView> is generic; buckets can publish a domain-specific projection — a local file URL, a presigned S3 link, an ObjectURL — separately from the cached value. cache.resolve() returns the L1 view and shares the policy + dedup pipeline with remember(), so callers stay on a freshness-aware path instead of bypassing the policy with a raw bucket read.
  • Pluggable logger. ILogger interface plus a consoleLogger singleton replaces the boolean log / logTiming flags. One formatted line per call: Cacheable "<namespace>:<key>": HIT|MISS <Xms>. Omit logger for silent operation; assign cache.logger at runtime to flip on/off.
  • Concurrency-safe dedup. Concurrent same-key callers share one cascade probe, one value read, and (for SWR) one background revalidation. Concurrent remember + resolve on the same key still trigger only one producer call.

Migrating from v2

// v2
import { Cacheables } from 'cacheables'

const cache = new Cacheables({ log: true, logTiming: true })

await cache.cacheable(() => fetch(url), 'weather', {
  cachePolicy: 'max-age',
  maxAge: 5_000,
})
// v3
import { Cacheable, MemoryBucket, consoleLogger } from 'cacheables'

const cache = new Cacheable('weather', {
  buckets: [new MemoryBucket()],
  policy: 'max-age',
  maxAge: 5_000,
  logger: consoleLogger,
})

await cache.remember(() => fetch(url).then((r) => r.json()), 'weather')

Breaking changes

  • Class renamed CacheablesCacheable.
  • Method renamed cache.cacheable(...)cache.remember(...).
  • Cache policy moved to the constructor. No per-call options. Pass policy (and maxAge where required) once on new Cacheable(namespace, { ... }). Field is policy, not cachePolicy. A single instance serves a single policy — split into multiple instances to mix.
  • buckets is required. new Cacheable('app', { buckets: [new MemoryBucket()] }) reproduces the v2 default.
  • namespace is required and positional (first constructor argument). Prefixed onto every bucket key as ${namespace}:.
  • delete and clear are async — they return Promise<void>.
  • log / logTiming replaced by logger. Pass consoleLogger to restore default-on logging.
  • Removed: enabled option (call resource() directly to bypass), keys(), isCached(), Cacheables.key(...) (build keys with template literals or [...].join(':')).
  • Buckets can throw. Any throw from any bucket rejects remember(). v2's in-memory store couldn't fail; this is a new error surface once you wire up a custom bucket.

Runtime

  • Node ≥ 18 required.
  • sideEffects: false so bundlers can tree-shake unused exports.
  • Dual ESM/CJS publish, browser + Node, no dependencies.