Browse packages

Package · v0.14.0

kv

Standard library key-value stores

Key-value storage utilities for JavaScript runtimes.

What is @rcompat/kv?#

A cross-runtime module providing key-value storage abstractions. Currently includes a singleton cache with symbol-based keys and lazy initialization. Works consistently across Node, Deno, and Bun.

Installation#

bash
npm install @rcompat/kv
bash
pnpm add @rcompat/kv
bash
yarn add @rcompat/kv
bash
bun add @rcompat/kv

Usage#

cache#

A singleton key-value cache using symbols as keys. Supports lazy initialization.

js
import kv from "@rcompat/kv";

// Define a symbol key
const CONFIG = Symbol("config");

// Get with initializer (runs only on first access)
const config = kv.cache.get(CONFIG, () => ({
  apiUrl: "https://api.example.com",
  timeout: 5000,
}));

// Subsequent gets return the cached value
kv.cache.get(CONFIG);  // Same object, initializer not called again

Lazy initialization#

The initializer function is only called if the key doesn't exist yet.

js
import kv from "@rcompat/kv";

const DB_CONNECTION = Symbol("db");

// Connection is established only on first access
function getDb() {
  return kv.cache.get(DB_CONNECTION, () => {
    console.log("Connecting to database...");
    return createConnection();
  });
}

getDb();  // "Connecting to database..." - initializer runs
getDb();  // Returns cached connection, no log
getDb();  // Returns cached connection, no log

Symbol uniqueness#

Each symbol is unique, even with the same description.

js
import kv from "@rcompat/kv";

const KEY_A = Symbol("data");
const KEY_B = Symbol("data");

kv.cache.get(KEY_A, () => "value A");
kv.cache.get(KEY_B, () => "value B");

kv.cache.get(KEY_A);  // "value A"
kv.cache.get(KEY_B);  // "value B"
kv.cache.get(Symbol("data"));  // undefined (different symbol)

API Reference#

kv.cache.get(key, init?)#

ts
declare function get<T>(key: symbol): T | undefined;
declare function get<T>(key: symbol, init: () => T): T;

Gets a value from the cache by symbol key, optionally initializing it.

Parameter Type Description
key symbol The symbol key to look up
init () => T Optional initializer called if key missing

Returns: The cached value, or undefined if not found and no initializer provided.

Behavior:

  • If the key exists, returns the cached value
  • If the key doesn't exist and init is provided, calls init(), caches and returns the result
  • If the key doesn't exist and no init, returns undefined

Examples#

Application-wide singletons#

js
import kv from "@rcompat/kv";

// Define keys for your singletons
const LOGGER = Symbol("logger");
const CONFIG = Symbol("config");
const HTTP_CLIENT = Symbol("http");

// Logger singleton
export function getLogger() {
  return kv.cache.get(LOGGER, () => createLogger({
    level: "info",
    format: "json",
  }));
}

// Config singleton (loaded once)
export function getConfig() {
  return kv.cache.get(CONFIG, () => loadConfigFromEnv());
}

// HTTP client singleton
export function getHttpClient() {
  return kv.cache.get(HTTP_CLIENT, () => createHttpClient({
    timeout: 30000,
    retries: 3,
  }));
}

Module-level caching#

js
// user-service.js
import kv from "@rcompat/kv";

const USERS_CACHE = Symbol("users");

export function getUsers() {
  return kv.cache.get(USERS_CACHE, async () => {
    const response = await fetch("/api/users");
    return response.json();
  });
}

Expensive computation caching#

js
import kv from "@rcompat/kv";

const COMPUTED_DATA = Symbol("computed");

function getComputedData() {
  return kv.cache.get(COMPUTED_DATA, () => {
    console.log("Computing expensive data...");
    // This only runs once
    return heavyComputation();
  });
}

Cross-Runtime Compatibility#

Runtime Supported
Node.js ✓
Deno ✓
Bun ✓

No configuration required — just import and use.

License#

MIT

Contributing#

See CONTRIBUTING.md in the repository root.