@rcompat/kv
v0.6.0
Published
Standard library key-value abstractions
Readme
@rcompat/kv
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
npm install @rcompat/kvpnpm add @rcompat/kvyarn add @rcompat/kvbun add @rcompat/kvUsage
cache
A singleton key-value cache using symbols as keys. Supports lazy initialization.
import cache from "@rcompat/kv/cache";
// Define a symbol key
const CONFIG = Symbol("config");
// Get with initializer (runs only on first access)
const config = cache.get(CONFIG, () => ({
apiUrl: "https://api.example.com",
timeout: 5000,
}));
// Subsequent gets return the cached value
cache.get(CONFIG); // Same object, initializer not called againLazy initialization
The initializer function is only called if the key doesn't exist yet.
import cache from "@rcompat/kv/cache";
const DB_CONNECTION = Symbol("db");
// Connection is established only on first access
function getDb() {
return 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 logSymbol uniqueness
Each symbol is unique, even with the same description.
import cache from "@rcompat/kv/cache";
const KEY_A = Symbol("data");
const KEY_B = Symbol("data");
cache.get(KEY_A, () => "value A");
cache.get(KEY_B, () => "value B");
cache.get(KEY_A); // "value A"
cache.get(KEY_B); // "value B"
cache.get(Symbol("data")); // undefined (different symbol)API Reference
cache.get(key, init?)
declare function get<T>(key: symbol, init?: () => T): T | undefined;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
initis provided, callsinit(), caches and returns the result - If the key doesn't exist and no
init, returnsundefined
Examples
Application-wide singletons
import cache from "@rcompat/kv/cache";
// Define keys for your singletons
const LOGGER = Symbol("logger");
const CONFIG = Symbol("config");
const HTTP_CLIENT = Symbol("http");
// Logger singleton
export function getLogger() {
return cache.get(LOGGER, () => createLogger({
level: "info",
format: "json",
}));
}
// Config singleton (loaded once)
export function getConfig() {
return cache.get(CONFIG, () => loadConfigFromEnv());
}
// HTTP client singleton
export function getHttpClient() {
return cache.get(HTTP_CLIENT, () => createHttpClient({
timeout: 30000,
retries: 3,
}));
}Module-level caching
// user-service.js
import cache from "@rcompat/kv/cache";
const USERS_CACHE = Symbol("users");
export function getUsers() {
return cache.get(USERS_CACHE, async () => {
const response = await fetch("/api/users");
return response.json();
});
}Expensive computation caching
import cache from "@rcompat/kv/cache";
const COMPUTED_DATA = Symbol("computed");
function getComputedData() {
return 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.
