API

Complete API reference for Cache module

This page provides a complete API reference for all decorators, classes, and types in the @vercube/cache package.

@Cache() (Decorator)

Replaces the decorated method with a cached version of itself. The cache key is derived from the method's arguments, concurrent calls for the same key are coalesced into a single execution, and entries are dropped automatically when the method body or its options change.

Signature

function Cache(options?: CacheTypes.DecoratorOptions): Function

Parameters:

ParameterTypeRequiredDescription
optionsCacheTypes.DecoratorOptionsNoCache options for this method. See Options.

When name is not given it defaults to ClassName.methodName, so two classes declaring the same method name never share entries.

Example:

import { Cache } from '@vercube/cache';

export class UsersService {
  @Cache({ maxAge: 300, swr: true, staleMaxAge: 900, storage: 'cache' })
  public async getUser(id: string): Promise<User> {
    return this.database.findUser(id);
  }
}

Helpers on the decorated method

The decorated method exposes three helpers that resolve exactly the keys the cached calls use.

type CachedMethod<ArgsT extends unknown[], T> = {
  (...args: ArgsT): Promise<T>;
  resolveKeys(...args: ArgsT): Promise<string[]>;
  invalidate(...args: ArgsT): Promise<void>;
  expire(...args: ArgsT): Promise<void>;
};
HelperDescription
resolveKeys()Returns every storage key (one per storage tier) the given arguments cache under.
invalidate()Removes the cached entries for the given arguments. The next call resolves again.
expire()Marks the entries stale without removing them. With swr the stale value is still served while the next access refreshes it.

Example:

import type { CacheTypes } from '@vercube/cache';

const getUser = usersService.getUser as CacheTypes.CachedMethod<[string], User>;

await getUser.resolveKeys('123'); // ['/cache:functions:UsersServicegetUser.GuK_juM6...:NYOXd4T2....json']
await getUser.invalidate('123');
await getUser.expire('123');
The cast is only needed to make the helpers visible to TypeScript - decorators cannot widen a method's declared type. At runtime the helpers are always there.

CacheManager (Class)

The central service of the module. It wires the caching engine to the storages mounted in @vercube/storage, holds the application wide defaults, and exposes the imperative API used both directly and by the @Cache() decorator.

Signature

class CacheManager {
  public get adapter(): CacheStorageAdapter | null;
  public get defaults(): CacheTypes.Defaults;
  public configure(defaults: CacheTypes.Defaults): void;
  public cached<T, ArgsT>(fn: (...args: ArgsT) => T | Promise<T>, options?: CacheTypes.Options<T, ArgsT>): CacheTypes.CachedFunction<T, ArgsT>;
  public invalidate<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<void>;
  public expire<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<void>;
  public resolveKeys<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<string[]>;
}

Methods

configure()

Sets the application wide cache defaults. Options passed per cached function always win. Repeated calls merge into the existing defaults.

public configure(defaults: CacheTypes.Defaults): void

Example:

container.get(CacheManager).configure({
  storage: 'cache',
  maxAge: 60,
  swr: true,
  staleMaxAge: 600,
  onError: (error) => logger.error('Cache failure', error),
});

cached()

Wraps a function with caching. Use it for functions that are not class methods, or when the options are only known at runtime.

public cached<T, ArgsT extends unknown[]>(
  fn: (...args: ArgsT) => T | Promise<T>,
  options?: CacheTypes.Options<T, ArgsT>,
): CacheTypes.CachedFunction<T, ArgsT>

Returns: the cached function, carrying the same resolveKeys(), invalidate() and expire() helpers as a decorated method.

Throws: CacheError when fn is not a function.

Example:

const getRates = cacheManager.cached(
  (currency: string) => http.get(`/rates/${currency}`),
  { name: 'getRates', maxAge: 60, swr: true, staleMaxAge: 300 },
);

await getRates('EUR');
await getRates.invalidate('EUR');

invalidate() / expire() / resolveKeys()

Act on entries without holding a reference to the cached function. Pass the same options (name, group, storage, getKey) the entry was cached with, so the very same keys are resolved.

public invalidate<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<void>
public expire<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<void>
public resolveKeys<ArgsT>(options: CacheTypes.Options<any, ArgsT>, ...args: ArgsT): Promise<string[]>

Example:

// drop what UsersService.getUser cached for user 123, from anywhere in the app
await cacheManager.invalidate({ name: 'UsersService.getUser', storage: 'cache' }, '123');

CacheTypes.Options (Interface)

Options accepted by @Cache() and CacheManager.cached().

OptionTypeDefaultDescription
namestringClassName.methodNameName used as part of the cache key.
groupstring'functions'Key group prefix, useful for grouping related entries.
storagestring | string[]'default'Mounted storage(s) backing the entries. An array reads in order and writes to all; it must not be empty, and a name must not contain a colon.
maxAgenumber1Seconds an entry stays fresh.
swrbooleanfalseServe a stale entry while refreshing it in the background.
staleMaxAgenumber-Seconds a stale entry may still be served while revalidating. 0 never serves stale.
getKey(...args) => string | Promise<string>hash of the argumentsDerives the key segment from the arguments.
getMaxAge(entry) => number | { maxAge?, staleMaxAge? }-Derives the lifetime from the resolved value.
validate(entry, ctx) => boolean | Promise<boolean>value is definedReturn false to treat an entry as invalid and re-resolve.
shouldBypassCache(...args) => boolean | Promise<boolean>-Return true to skip the cache entirely for this call.
shouldInvalidateCache(...args) => boolean | Promise<boolean>-Return true to drop the entry and re-resolve.
serialize(entry, ctx) => any-Convert the resolved value into a storable shape. Runs once per resolution.
transform(entry, ...args) => any-Rebuild the usable value when an entry is read back. Also receives entry.status.
integrityunknownhash of the method and its optionsOverrides the value that invalidates entries when the code changes.
onError(error: unknown) => voidlogs to consoleCalled for every cache related error (read, write, background refresh).

entry.status

Inside transform the entry carries how the value was served on that call:

StatusMeaning
hitA fresh cached value was returned without re-resolving.
staleA stale value was served while a background refresh runs.
revalidatedA prior value existed but was expired, so it was re-resolved before returning.
missThe value was resolved fresh on this call.
@Cache({
  maxAge: 60,
  swr: true,
  staleMaxAge: 300,
  transform: (entry) => {
    metrics.increment(`cache.${entry.status}`);
    return entry.value;
  },
})
public async getRates(currency: string): Promise<Rates> { /* ... */ }

CacheTypes.Defaults (Interface)

Application wide defaults passed to CacheManager.configure(). Every field is optional and is overridden by per-function options.

OptionTypeDescription
maxAgenumberDefault freshness window in seconds.
swrbooleanDefault stale-while-revalidate behaviour.
staleMaxAgenumberDefault stale window in seconds.
groupstringDefault key group prefix.
storagestring | string[]Default storage(s) to keep entries in.
onError(error: unknown) => voidDefault cache error handler.

CacheStorageAdapter (Class)

Bridges the caching engine onto the Vercube StorageManager. You rarely touch it directly - CacheManager creates one during initialization and binds every cached function to it - but it defines how cache keys map onto storages.

Signature

class CacheStorageAdapter {
  public get<T>(key: string): Promise<T | null>;
  public set<T>(key: string, value: T, opts?: { ttl?: number }): Promise<void>;
}

Writing null deletes the entry, mirroring how the caching engine signals invalidation.

Key helpers

const CACHE_BASE_PREFIX = '/cache';

function cacheBaseForStorage(storage?: string): string;
function storageNameFromCacheKey(key: string): string;
FunctionDescription
cacheBaseForStorage()Builds the key base for a mounted storage: 'redis' becomes /cache/redis, the default storage stays /cache.
storageNameFromCacheKey()Reads the storage name back out of a full cache key.

A complete key looks like:

/cache/redis:functions:UsersServicegetUser.GuK_juM6...:NYOXd4T2....json
└─ base ──┘ └─ group ┘ └────── name ───────────────┘ └─ arg hash ─┘

The group and name segments are sanitized before they reach the key: every character outside [A-Za-z0-9_] is dropped and a hash of the original is appended when that changes the value, which is why UsersService.getUser reads as UsersServicegetUser.GuK_juM6.... Call resolveKeys() rather than assembling a key by hand.

When a cached function points at a storage that has not been mounted, the adapter mounts a MemoryStorage under that name on first use and logs a warning. Mounting the name yourself - before or after - is what swaps the backend for a real one.

CacheError (Class)

Thrown for cache configuration and wiring failures: decorating a non-method, using the cache without a StorageManager bound, passing an empty storage list, or a storage name containing a colon (which would break key routing).

Signature

class CacheError extends Error {
  public readonly operation: string;
  public readonly cause?: Error;
  public readonly metadata?: Record<string, unknown>;
}
PropertyTypeDescription
operationstringThe cache operation that failed.
causeErrorThe underlying error, when there is one.
metadataRecord<string, unknown>Non-sensitive context about the failure.

Storage failures that happen while serving a cached call are not thrown - they are routed to the onError option so a failing cache never takes the request down. Failures during an explicit invalidate() or expire() do propagate, since you asked for that write to happen.

Previous

Overview

How Vercube’s default build relates to production and development, and where to deploy.

Next