Skip to content

Latest commit

Β 

History

20 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@nuvix/cache

A high-performance, Bun-native caching library with namespace support, tag-based invalidation, batch operations, optional compression, and telemetry integration. Zero runtime dependencies β€” the Redis adapter runs on bun:redis, which ships with Bun itself.

✨ Features

  • πŸš€ Multiple adapters: Redis (via bun:redis), Memory, and None (no-op)
  • πŸ“¦ Zero runtime dependencies β€” everything is built into Bun
  • πŸ”§ TypeScript-first with complete type definitions
  • 🏷️ Namespaces for logical isolation of cache entries
  • 🏷️ Tag-based invalidation across namespaces
  • πŸ“Š Batch operations: mget, mset, deleteMany
  • πŸ”’ Atomic counters: increment / decrement with TTL seeding (Redis)
  • πŸ—œοΈ Optional gzip compression with a configurable size threshold
  • πŸ“ˆ Telemetry integration via @nuvix/telemetry
  • πŸ›‘οΈ Safe by default: key/namespace validation, scoped flushes that never issue FLUSHALL, non-blocking SCAN + UNLINK

πŸ“‹ Requirements

  • Bun β‰₯ 1.2.21 (the Redis adapter uses the built-in bun:redis client)

πŸš€ Installation

bun add @nuvix/cache
# or
npm install @nuvix/cache

Note: v2 is ESM-only and requires the Bun runtime. For CommonJS or non-Bun environments, stay on v1.

🏁 Quick Start

import { Cache, Memory } from "@nuvix/cache";

const cache = new Cache(new Memory());

await cache.set(
  "profile:123",
  { name: "John Doe" },
  {
    ttl: 1800, // seconds
    tags: ["user", "profile"],
  },
);

const profile = await cache.get<{ name: string }>("profile:123");

// Invalidate everything tagged "user"
await cache.flushByTags(["user"]);

Redis

The Redis adapter accepts a connection URL, an options object, or an existing RedisClient instance:

import { Cache, Redis } from "@nuvix/cache";

// 1. From a URL (also honors REDIS_URL / VALKEY_URL when constructed empty)
const redis = new Redis("redis://localhost:6379");

// 2. From options
const redis2 = new Redis({
  url: "redis://localhost:6379",
  namespace: "myapp",
  defaultTTL: 3600,
  keyPrefix: "nvx:cache:",
  enableCompression: true, // gzip values above compressionThreshold
  compressionThreshold: 1024,
});

// 3. Share an existing client β€” the adapter will NOT close it on close()
import { RedisClient } from "bun";
const shared = new RedisClient("redis://localhost:6379");
const redis3 = new Redis({ client: shared, namespace: "sessions" });

const cache = new Cache(redis);

None (disable caching)

import { Cache, None } from "@nuvix/cache";

// Writes report success but store nothing β€” useful to disable caching in
// one environment without changing call sites.
const cache = new Cache(new None());

🎯 Usage

Namespaces

cache.setDefaultNamespace("users");
await cache.set("k", "v"); // stored under "users"
await cache.set("k", "v", { namespace: "side" }); // stored under "side"

await cache.flushNamespace("side"); // clear one namespace
const keys = await cache.getKeysByNamespace("users", "k*");

Tags

await cache.set("product:1", data, { tags: ["products", "featured"] });
await cache.set("product:2", data, { tags: ["products"] });

await cache.getKeysByTags(["products"]); // ["product:1", "product:2"]
await cache.flushByTags(["featured"]); // removes product:1 only

Batch operations

await cache.mset({ "user:1": alice, "user:2": bob }, { ttl: 3600 });
const users = await cache.mget(["user:1", "user:2", "missing"]);
await cache.deleteMany(["user:1"]);

Counters (Redis)

await cache.increment("page:views", 1); // seeds TTL on first write
await cache.decrement("quota:user", 1);

Enhanced operations

await cache.exists("key");
await cache.expire("key", 300);
await cache.ttl("key"); // -2 missing, -1 no expiry
const stats = await cache.getStats(); // hits / misses / sets / deletes / errors / keyCount

Need the full adapter surface (patterns, namespace enumeration)? Keep a reference to the adapter instance you constructed β€” every first-party adapter implements EnhancedAdapter.

Telemetry

import { OpenTelemetry } from "@nuvix/telemetry";

cache.setTelemetry(new OpenTelemetry());
// Every operation records a duration sample into a histogram
// ("cache.operation.duration") tagged with operation and adapter.

πŸ”Œ CacheDriver contract

@nuvix/db consumes any driver exposing these four operations:

interface CacheDriver {
  get<T>(key: string, options?: CacheOperationOptions): Promise<T | null>;
  set<T>(
    key: string,
    value: T,
    options?: CacheOperationOptions,
  ): Promise<boolean>;
  flushByTags(tags: string[]): Promise<boolean>;
  flush(): Promise<boolean>;
}

interface CacheOperationOptions {
  ttl?: number; // seconds
  tags?: string[];
}

All first-party adapters satisfy this contract. Third-party drivers exposing only these four methods also work through the facade; enhanced operations on such drivers throw UnsupportedOperationError.

βš™οΈ Redis adapter options

Option Default Description
url env / localhost Connection URL (redis://user:pass@host:port/db)
client β€” Existing RedisClient (shared, never closed)
namespace "default" Logical namespace segment
defaultTTL 3600 Default TTL in seconds
keyPrefix "nvx:cache:" Prefix for every owned key
enableCompression false Gzip values above the threshold
compressionThreshold 1024 Minimum serialized size in bytes
maxKeyLength 512 Maximum user key length

Storage format: each value is a JSON envelope { d, c, e, m } (data, created-at, expires-at, metadata) stored under {keyPrefix}{namespace}:{key}. Tag membership lives in sets at {keyPrefix}tags:{tag}.

πŸ“¦ Module exports

import { Cache, Redis, Memory, None } from "@nuvix/cache";
import { Redis } from "@nuvix/cache/adapters/redis";
import { Memory } from "@nuvix/cache/adapters/memory";
import { None } from "@nuvix/cache/adapters/none";

Types: CacheDriver, EnhancedAdapter, CacheOperationOptions, CacheEntry, CacheStats, RedisAdapterInput, RedisAdapterOptions, plus the error classes.

πŸ› οΈ Development

bun install          # install dev dependencies
bun run lint         # oxlint
bun run typecheck    # tsc --noEmit
bun test             # bun test runner
bun run build        # bun build (ESM) + tsc declarations β†’ dist/

πŸ“„ License

BSD 3-Clause β€” see the LICENSE file.


Related Packages

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages