
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
leaf-db is meant as a simple database that allows for basic querying over JSON data without needing to set up a database server / connection like with MongoDB or SQLite.
Node does support working with SQLite directly, if you prefer a more stable, feature-complete database.
leaf-db can be used in the browser if persistent read / write isn't required.
npm i leaf-db
Create a database using file storage with strong-typed documents:
import LeafDB from 'leaf-db';
type Document = {
title: string
name: string
}
const db = new LeafDB<Document>();
await db.open({ name: 'db', dir: process.cwd() });
const drafts = [
{ title: 'Lady', name: 'Mipha' },
{ title: 'Young Rito Warrior', name: 'Tulin' }
]
await Promise.all(drafts.map(async draft => db.insert(draft)));
// [{ _id: <string>, title: 'Young Rito Warrior', name: 'Tulin' }]
const characters = db.query({ name: 'Tulin' });
const tulin = characters[0];
tulin.title = 'Rito Warrior';
await db.update(tulin); // Overwrite existing document
await db.close();
Leaf-db stores data as JSON documents and saves them inside a JSONL file.
Document keys must be of type string and cannot start with $.
Every document is required to have an _id field. Leaf-db automatically creates an _id if the field does not exist on insertion. _id is required to be unique when inserting documents.
Leaf-db only supports JSON values, which is defined as:
type Json =
string |
number |
boolean |
null |
Json[] |
{ [key: string]: Json };
Leaf-db stores the database in memory by default. To make use of persistence, simply open the database.
import LeafDB from 'leaf-db';
/** Create a new database, `db.jsonl`, in process.cwd() */
const db = new LeafDB();
await db.open({ name: 'db', dir: process.cwd() });
When opening a database from storage, leaf-db will return documents that are corrupt. These documents are deleted once opened and cannot be recovered afterwards.
import LeafDB from 'leaf-db';
const db = new LeafDB({ name: 'db', dir: process.cwd() });
const corrupt = await db.open(); // Corrupt[]
type Corrupt = {
raw: string;
error: Error;
};
Leaf-db supports both literal values and operators. Example:
/**
* Literal query where value must equal the query value
* { name: 'tulin' } // No match
* { name: 'Mipha' } // No match
*/
const a = { name: 'Tulin' };
/**
* Objects and arrays match on partial matches
* { eras: [] } // Match
* { eras: ['era of the wilds'] } // No match
* { eras: [Sky Era'] } // No Match
*/
const b = { eras: ['Era of the Wilds'] }
Operators allow for more complex queries. Operators must always be used in combination with values.
$gtIs greater than
const query = { a: { $gt: 3 } };
const a = { a: 2 }; // false
const b = { a: 3 }; // false
const c = { a: 4 }; // true
$gteIs greater than or equal to
const query = { a: { $gte: 3 } };
const a = { a: 2 }; // false
const b = { a: 3 }; // true
const c = { a: 4 }; // true
$ltIs less than
const query = { a: { $lt: 3 } };
const a = { a: 2 }; // true
const b = { a: 3 }; // false
const c = { a: 4 }; // false
$lteIs less than or equal to
const query = { a: { $lte: 3 } };
const a = { a: 2 }; // true
const b = { a: 3 }; // true
const c = { a: 4 }; // false
$regexpMatches strings against RegExp
const query = { a: { $regexp: /\w+/g } }
const a = { a: '' }; // false
const b = { a: '0' }; // false
const c = { a: 'a' }; // true
$lengthEqual to length
const query = { a: { $length: 3 } }
const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true
const c = { a: [1, 2, 3, 4] }; // false
$includesHas value in array. Does not partial match on arrays or objects.
const query = { a: { $includes: 3 } };
const a = { a: [] }; // false
const b = { a: [1, 2, 3] }; // true
const query = { b: { $includes: [3] } };
const a = { b: [ [3] ] }; // true
const b = { b: [ [3, 4] ] }; // false
$notInvert query
const query = { $not: { a: { $lt: 3 } } };
const a = { a: 2 }; // false
const b = { a: 4 }; // true
$andMust match all queries
const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };
const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // false
$orMatches any query
const query = { $and: [{ a: 2 }, { b: { $lt: 3 } }] };
const a = { a: 2, b: 2 }; // true
const b = { a: 2, b: 4 }; // true
id()Generate a new, unique id with format [timestamp]-[random].
import LeafDB from 'leaf-db';
const id = LeafDB.id();
docsGet all documents
const docs = db.docs // Doc<T>[]
open()Open persistent storage.
import LeafDB from 'leaf-db';
const db = new LeafDB();
const corrupted = await db.open({ name: 'db', dir: process.cwd() }); // Corrupt[]
close()Close persistent storage.
await db.close();
get()Get document by id
db.get('a'); // { _id: 'a' }
insert()Insert document(s) into the database. Will throw an error if duplicate _id's are found.
const drafts = [{ name: 'Tulin', }, { name: 'Mipha' }];
// [{ _id: <string>, name: 'Tulin' }, { _id: <string>, name: 'Mipha' }]
const docs = await Promise.all(drafts.map(async draft => draft.insert(draft)));
query()Find document(s) based by query.
// Return docs where `name` is equal to `Mipha`
const docs = db.query({ name: 'Mipha' });
// Return docs where `name` is equal to `Mipha` or where `name` is equal to `Tulin`
const docs = db.query({ $or: [{ name: 'Mipha' }, { name: 'Tulin' }] });
update()Update existing document. Throws if document does not exist
// Update document `a` with new name `Tulin`
const docs = db.update({ _id: 'a', name: 'Tulin' });
delete()Delete document by _id
// Delete document `a`
await db.delete('a');
drop()Delete all documents in the database.
await db.drop();
FAQs
Small file-based database for node.js
We found that leaf-db demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.