starddb
v1.0.2
Published
A lightweight JSON document database with field-level operation queuing and concurrency support
Maintainers
Readme
StarDDB — Node.js
"Shoot for the moon. Even if you miss, you'll land among the stars." - Norman Vincent Peale
StarDDB is a lightweight, single-file JSON database for Node.js with field-level operation queuing, lazy loading, and automatic background persistence.
Features
- Lazy loading — field values are read from disk on first access via
fs.readSync; untouched fields never enter memory - Cache eviction — fields not accessed within a configurable threshold are dropped from memory and reloaded on demand
- Field-level queue — arithmetic operations are serialized per-field via an async event-loop queue, preventing interleaving on shared values
- Event-loop safe — no threads; queues drain cooperatively via
setImmediate - Auto-persistence —
setIntervalsaves every N seconds; clean fields are copied byte-for-byte from the open file descriptor (no parse/re-encode) - Atomic writes — saves go to a
.tmpfile thenfs.renameSyncinto place - Nested documents — arbitrary depth with a configurable recursion limit
Installation
npm install starddbQuick Start
Field-only usage
const { StarDDBField } = require('starddb');
const field = new StarDDBField(0);
field.update("set", 1);
field.update("mult", 5);
field.update("div", 0.5);
await field.flush();
console.log(field.value); // 10Load an existing file (lazy mode)
const { StarDDB } = require('starddb');
// Values are loaded from disk only when accessed
const db = new StarDDB('./data.json', 5);
const hook = db.db();
hook.player.health.update("sub", 30);
hook.player.mana.update("mult", 2);
await db.close(); // flushes, saves, clears intervalCreate a new database from an object
const db = new StarDDB('./data.json', 5, {
player: { health: 100, mana: 50 },
world: { level: 1 }
});
const hook = db.db();
hook.player.health.update("sub", 10);
await db.close();Cache eviction
// Fields unused for 2 minutes are evicted from memory
const db = new StarDDB('./data.json', 5, null, { cacheThreshold: 120 });API
new StarDDBField(value = null, maxQueueSize = 10000)
| Parameter | Description |
|-----------|-------------|
| value | Initial value (any JSON-serializable type) |
| maxQueueSize | Maximum queued operations before throwing (default: 10000) |
Properties:
value— get or set the field's current value (triggers lazy load on first get)
Methods:
update(method, value)— queue an operation (see Operations table below)flush()— returns a Promise that resolves when all queued operations are processeddropIfUnused(thresholdMs)— evict value from memory if clean and not recently accessed
new StarDDB(database, saveTime, databaseHook = null, options = {})
| Parameter | Description |
|-----------|-------------|
| database | Path to the JSON database file |
| saveTime | Seconds between automatic background saves |
| databaseHook | Initial data object; if null, file must exist and is loaded lazily |
| options.safeRoot | If set, restricts the database path to this directory (prevents path traversal) |
| options.cacheThreshold | Seconds since last access before a clean field is evicted from memory (default: 60) |
Methods:
| Method | Description |
|--------|-------------|
| db() | Return the database hook (nested object of StarDDBField instances) |
| flush() | Returns a Promise that resolves when all pending field operations are complete |
| save() | Write the database to disk immediately (returns a Promise) |
| close() | Flush, save, and clear the background interval (returns a Promise) |
| addField(keyPath, value) | Add a new field at runtime (see below) |
Operations
| Op | Description |
|----|-------------|
| set | Set value directly |
| add | Add to current value |
| sub | Subtract from current value |
| mult | Multiply current value |
| div | Divide current value (zero is rejected) |
| push | Append to an array field |
addField examples
keyPath is a dot-separated string or an array of keys. Object values are automatically crawled into StarDDBField instances.
// Add a primitive
db.addField("players.newGuy", 0);
// Add an array field
db.addField("players.newGuy.inventory", []);
// Append to it
hook.players.newGuy.inventory.update("push", "sword");
// Add a nested object (auto-crawled)
db.addField("players.newGuy", { coins: 0, level: 1 });
hook.players.newGuy.coins.update("add", 5);
// Use an array to avoid dot ambiguity in key names
db.addField(["some.weird.key", "nested"], 42);Testing
npm test
# or individually:
node tests/single_field.js
node tests/multi_field.js
node tests/test_crawl.js
node tests/test_errors.js