@coderbuzz/kvs
v0.1.5
Published
Lightweight SQLite-backed key-value server with HTTP API, atomic transactions, TTL, queue, and TypeScript client SDK.
Maintainers
Readme
KVS — @coderbuzz/kvs
Lightweight SQLite-backed key-value server with a built-in TypeScript client SDK. KVS is designed for serverless and edge workloads that need a simple, self-hosted KV service with atomic transactions, hierarchical keys, TTL expiry, and a persistent queue — all over a secure HTTP API.
Features
- Hierarchical keys — e.g.
["users", "alice"]with prefix and range queries - Atomic transactions — conditional multi-key writes with version checks
- TTL expiry — automatic record expiry with millisecond precision
- Built-in queue — background work queue with delayed delivery, retries, and acknowledgements
- Bearer-token auth — all endpoints protected by a configurable access token
- TypeScript client SDK — type-safe fetch-based client for any runtime that supports the Fetch API
Installation
# npm
npm install @coderbuzz/kvs
# Bun
bun add @coderbuzz/kvs
# Deno
import { KvsClient } from "npm:@coderbuzz/kvs";Self-Hosting the KVS Server
KVS is a standalone HTTP server that you run alongside your application. It stores all data in a local SQLite file and exposes a REST API.
Requirements
- Bun (recommended) or Node.js 18+
- An
ACCESS_TOKENenvironment variable to protect the API
Running with Bun
ACCESS_TOKEN=your-secret bun run node_modules/@coderbuzz/kvs/dist/index.jsOr add it as a script in your package.json:
{
"scripts": {
"kvs": "ACCESS_TOKEN=your-secret bun run node_modules/@coderbuzz/kvs/dist/index.js"
}
}Environment Variables
| Variable | Default | Description |
| -------------- | -------- | ------------------------------------------------ |
| ACCESS_TOKEN | required | Bearer token required for all KV/queue endpoints |
| PORT | 3000 | Port the server listens on |
| KV_DB_PATH | kv.db | Path to the SQLite database file |
Client SDK
The package includes a TypeScript client SDK that wraps all KVS HTTP endpoints
using fetch. It works in any runtime that supports the Fetch API — Bun, Deno,
Node.js 18+, browsers, and Cloudflare Workers.
Setup
import { KvsClient } from "@coderbuzz/kvs";
const kv = new KvsClient({
url: "http://localhost:3000",
token: "your-access-token",
});Get / Set / Delete
// Set a value (with optional TTL in ms)
await kv.set(["users", "alice"], { name: "Alice", plan: "pro" }, {
ttl: 60_000,
});
// Get a value
const entry = await kv.get(["users", "alice"]);
console.log(entry?.value); // { name: "Alice", plan: "pro" }
console.log(entry?.version); // 1
// Delete a key
await kv.delete(["users", "alice"]);List by Prefix
// List with pagination
const page1 = await kv.list({ prefix: ["users"] }, { limit: 10 });
for (const entry of page1.entries) {
console.log(entry.key, entry.value);
}
// Continue with cursor
if (page1.cursor) {
const page2 = await kv.list(
{ prefix: ["users"] },
{ limit: 10, cursor: page1.cursor },
);
}
// Reverse order (e.g. latest logs first)
const latest = await kv.list({ prefix: ["logs"] }, { limit: 5, reverse: true });Atomic Operations
Conditionally update keys only when versions match — safe for concurrent writes:
const entry = await kv.get(["counters", "visits"]);
const result = await kv
.atomic()
.check({ key: ["counters", "visits"], version: entry?.version ?? null })
.set(["counters", "visits"], (entry?.value as number ?? 0) + 1)
.commit();
if (result.ok) {
console.log("Updated to version", result.version);
} else {
console.log("Conflict — retry");
}Queue
// Enqueue a job (with optional delay and max retry attempts)
await kv.enqueue(
{ to: "[email protected]", subject: "Welcome" },
{ topic: "emails", delay: 5000, maxAttempts: 3 },
);
// Dequeue and process
const messages = await kv.dequeue("emails", 10);
for (const msg of messages) {
console.log(msg.payload);
await kv.acknowledge(msg.id);
}Health Check
const health = await kv.health();
console.log(health.ok, health.uptime);HTTP API Reference
All endpoints except /health require:
Authorization: Bearer <ACCESS_TOKEN>Health
curl http://localhost:3000/healthSet a Value
curl -X POST http://localhost:3000/kv/set \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"key":["users","alice"],"value":{"name":"Alice"},"ttl":60000}'Get a Value
curl -X POST http://localhost:3000/kv/get \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"key":["users","alice"]}'List by Prefix
curl -X POST http://localhost:3000/kv/list \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"prefix":["users"],"limit":100}'Atomic Write
curl -X POST http://localhost:3000/kv/atomic \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{
"checks":[{"key":["users","alice"],"version":1}],
"mutations":[
{"type":"set","key":["users","alice"],"value":{"name":"Alice Updated"}},
{"type":"set","key":["users","alice","profile"],"value":{"active":true}}
]
}'Enqueue a Job
curl -X POST http://localhost:3000/queue/enqueue \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"topic":"emails","payload":{"to":"[email protected]"},"delay":5000}'Dequeue Jobs
curl -X POST http://localhost:3000/queue/dequeue \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"topic":"emails","limit":10}'Acknowledge a Job
curl -X POST http://localhost:3000/queue/ack \
-H 'content-type: application/json' \
-H 'authorization: Bearer your-secret' \
-d '{"id":1}'License
MIT © 2026 Indra Gunawan
