fragmented-keys
v0.2.1
Published
Tag-versioned cache invalidation library for TypeScript
Downloads
549
Maintainers
Readme
fragmented-keys
Tag-versioned cache invalidation for TypeScript. Instead of deleting stale cache entries, increment a tag's version — all composite keys depending on that tag resolve to a new hash, producing automatic cache misses. Old entries expire naturally via TTL.
Install
npm install fragmented-keysOptional peer dependencies
npm install ioredis # for Redis support
npm install rxjs # for Observable adapter (planned)Quick Start
import { Configuration } from "fragmented-keys/configuration";
import { MemoryHandler } from "fragmented-keys/cache-handler/memory-handler";
import { FragmentedKeyRing } from "fragmented-keys/key-ring/fragmented-key-ring";
// 1. Configure a cache handler
const handler = new MemoryHandler();
Configuration.setDefaultCacheHandler(handler);
// 2. Create a key ring and define keys
const ring = new FragmentedKeyRing("my-app");
ring.defineKey("user-profile", ["user", "settings"]);
// 3. Get a key object — tags are resolved, hash is computed
const key = await ring.getKeyObj("user-profile", { user: "42" });
const cacheKey = await key.cacheKey();
// 4. Invalidate by incrementing a tag
const userTag = ring.getTag("user", "42");
await userTag.increment();
// All keys depending on user:42 now resolve to a different hashConfiguration
The library uses a static Configuration singleton:
import { Configuration } from "fragmented-keys/configuration";
// Required: set the default cache handler
Configuration.setDefaultCacheHandler(handler);
// Optional: global prefix for all tag keys (default: "DefaultPrefix")
Configuration.setGlobalPrefix("MyApp");
// Optional: cache prefix prepended to all handler reads/writes
// Useful for multi-tenant or multi-environment Redis sharing
Configuration.setCachePrefix("staging:");Redis Setup
Single Instance
import Redis from "ioredis";
import { Configuration } from "fragmented-keys/configuration";
import { RedisHandler } from "fragmented-keys/cache-handler/redis-handler";
const redis = new Redis({ host: "localhost", port: 6379 });
const handler = new RedisHandler(redis);
Configuration.setDefaultCacheHandler(handler);Custom Group Name
Pass a second argument to identify the handler in multi-handler setups:
const handler = new RedisHandler(redis, "primary-redis");
handler.groupName(); // "primary-redis"With TTL
// Tag versions stored with 1-hour TTL
await handler.set("tag:user:42", "1.1", 3600);Docker (Development)
The included docker-compose.yml provides Redis standalone and a 3-node Sentinel cluster:
# Start all Redis services
docker compose up -d
# Standalone Redis on localhost:6379
# Sentinel master on localhost:6380
# Sentinels on localhost:26379, 26380, 26381// Connect to standalone
const redis = new Redis({ host: "localhost", port: 6379 });
// Connect via Sentinel (when RedisSentinelHandler is available)
const redis = new Redis({
sentinels: [
{ host: "localhost", port: 26379 },
{ host: "localhost", port: 26380 },
{ host: "localhost", port: 26381 },
],
name: "mymaster",
});Cache Handlers
| Handler | Backend | Status |
|---------|---------|--------|
| MemoryHandler | In-memory Map | Available |
| RedisHandler | ioredis single instance | Available |
| RedisSentinelHandler | ioredis + Sentinel HA | Planned |
| RedisShardRouter | Multi-shard routing | Planned |
| EncryptedHandler | Encrypt/decrypt decorator | Planned |
All handlers implement the CacheHandler interface:
interface CacheHandler {
groupName(): string;
get(key: string): Promise<string | null>;
set(key: string, value: string, ttl?: number): Promise<void>;
getMulti(keys: string[]): Promise<Record<string, string>>;
}Development
npm install
npm run build # Build with tsup (ESM + CJS)
npm test # Run unit tests
npm run test:integration # Run integration tests (requires Docker Redis)
npm run lint # Check with Biome
npm run typecheck # TypeScript type checkingCross-Language Parity
This is the TypeScript implementation of the fragmented-keys pattern. Implementations also exist for PHP, Python, Java, Swift, and Elixir. Core tag/key/ring semantics are identical across all versions.
License
MIT — Noizu Labs, Inc.
