@t8n/cachex
v1.2.0
Published
A High-Performance, Redis-like In-Memory Data Engine for TitanPL.
Readme
@t8n/cachex
Redis-inspired in-memory caching for TitanPL with:
shareContext-backed storage- optional disk persistence in
.titan/.cache - SWR-style background refresh through Titan tasks
- LRU/LFU eviction
- atomic increment/decrement helpers
Installation
npm i @t8n/cachexQuick Start
import cachex from "@t8n/cachex";
cachex.set("hello", { ok: true });
const value = cachex.get("hello");
// { ok: true }Persistence
Persistence is enabled by default.
When persist: true:
- writes are mirrored to
.titan/.cache - deletes remove the matching persisted file
- evicted keys remove their old persisted file too
- missing in-memory keys can be lazy-loaded back from disk on
get()
import { CacheX } from "@t8n/cachex";
const cache = new CacheX({ persist: true });
cache.set("user:1", { name: "Asha" });
const user = cache.get("user:1");Disable persistence like this:
import { CacheX } from "@t8n/cachex";
const cache = new CacheX({ persist: false });Rebase
rebase() rewrites the current namespace’s in-memory entries to disk and removes stale persisted files that no longer belong to live keys in that namespace.
import cachex from "@t8n/cachex";
const written = cachex.rebase();You can also configure background rebasing:
import { CacheX } from "@t8n/cachex";
const cache = new CacheX({
rebaseTask: "task/cache-rebase",
rebaseDelay: 10000,
rebaseTimeout: 30000
});SWR and Background Tasks
CacheX supports a simple SWR-style pattern through wrap() and task.
On cache miss:
wrap()runs your fetcher- stores the result
- returns it immediately
On cache hit with a configured task:
- CacheX returns the cached value immediately
- CacheX calls
task.spawn(...) - the configured
delayis forwarded to Titan’s task API
That means Titan handles cooldown / pending-task behavior for the spawned task.
import cachex from "@t8n/cachex";
export default function getUser(req) {
const id = req.body.id;
return cachex.wrap(
`user:${id}`,
() => ({ id, name: "Asha" }),
{
task: "task/refresh-user",
delay: 10000,
payload: { id }
}
);
}Example refresh task:
import cachex from "@t8n/cachex";
export default function refreshUser(req) {
const key = req?.body?.key || req?.payload?.key;
const id = req?.body?.id || req?.payload?.id;
const freshData = { id, name: "Asha Updated" };
cachex.set(key, freshData, {
task: "task/refresh-user",
delay: 10000,
payload: { id }
});
return { status: "ok" };
}Namespaces
import cachex from "@t8n/cachex";
const users = cachex.namespace("users");
users.set("1", { name: "Asha" });
users.get("1");API
Constructor
new CacheX({
maxKeys: 10000,
policy: "lru",
namespace: "",
maxObjectSize: 1024 * 1024,
persist: true,
ttl: null,
rebaseTask: null,
rebaseDelay: 10000,
rebaseTimeout: 30000,
rebaseThrottle: 5000
})Methods
set(key, value, options)stores a value and returnstrueorfalseget(key)returns the stored value ornulldelete(key)removes a key from memory and diskexists(key)checks whether a key exists and is not expiredkeys(pattern?)lists keys in the current namespaceclear()removes all keys in the current namespaceincr(key, by?)atomically increments a numberdecr(key, by?)atomically decrements a numberstats()returns{ totalKeys, hits, policy }namespace(name)creates a nested namespaceenqueue(queue, payload, options?)enqueues a Titan taskwrap(key, fetcher, options?)provides cache-miss hydration plus SWR task wiringloadStorage()loads matching persisted entries into memoryrebase(force?)rewrites current entries to disk for the namespaceflushStorage()removes persisted cache filesflushExpired()removes expired keys from memory and disk
set() / wrap() options
{
ttl?: number,
nx?: boolean,
xx?: boolean,
task?: string,
refreshAction?: string,
delay?: number,
refreshDelay?: number,
payload?: any,
refreshPayload?: any,
timeout?: number
}Notes:
refreshActionis an alias fortaskrefreshDelayis an alias fordelayrefreshPayloadis an alias forpayloaddelayis forwarded to Titan task spawn options
Exported Helpers
defaultexport: sharedCacheXinstancecleanupAction(req): runsflushExpired()rebaseAction(req): runsrebase(true)for a namespace
