
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.
tiny-graph-db
Advanced tools
A tiny, no-external-dependency, disk-based graph database for Node.js with rich set of operations.
A tiny, no-external-dependencies, disk-based graph database for Node.js with rich query, traversal, batch ops, batch cosine similarity, and semantic filtering.
npm install tiny-graph-db
const TinyGraphDB = require('tiny-graph-db');
const db = new TinyGraphDB();
// Add nodes with embeddings
const nodeA = db.addNode('Paper A', { type: 'paper', embedding: [0.2, 0.1, 0.5] });
const nodeC = db.addNode('Concept X', { type: 'concept', embedding: [0.25, 0.1, 0.55] });
const nodeP = db.addNode('Author', { type: 'person', embedding: [0.9, 0.8, 0.7] });
const rel1 = db.addRelation('mentions', nodeA.id, nodeC.id, { confidence: 0.92 });
const rel2 = db.addRelation('authored_by', nodeA.id, nodeP.id, { confidence: 1.0 });
// Node search by metadata
console.log('All concepts:', db.searchNodes({ metadata: { type: 'concept' } }));
// Cosine similarity search
const qv = [0.2, 0.1, 0.52];
const similar = db.searchNodesByCosineSimilarity(qv, { threshold: 0.99 });
console.log('Semantically closest nodes:', similar);
// Traverse outgoing links from nodeA up to depth 2
const walk = db.traverseFromNode(nodeA.id, { maxDepth: 2, directions: ['outgoing'] });
console.log('Traversal:', walk);
// Batch update: update all "concept" nodes
db.updateBySearch('node', { metadata: { type: 'concept' } }, { metadata: { reviewed: true } });
// Batch delete: remove all relations with low confidence
db.deleteBySearch('relation', { metadata: { confidence: { lt: 0.95 } } });
// Save (usually auto, but explicit call)
db.flushToDisk();
new TinyGraphDB(filePath?: string)
'./graph_data.json').| Method | Description | Returns |
|---|---|---|
addNode(name, metadata = {}, flush = true) | Create node with name/metadata | Node object |
getNode(nodeId) | Look up node by ID | Node or undefined |
getAllNodes() | Get all nodes | Node[] |
updateNode(nodeId, {name?, metadata?}) | Update name/metadata | Updated node |
deleteNode(nodeId) | Remove node and all its relations | Deleted node object |
deleteBySearch('node', conditions) | Batch delete by search | Array of removed |
| Method | Description | Returns |
|---|---|---|
addRelation(name, fromNodeId, toNodeId, metadata = {}, flush = true) | Create edge between nodes | Relation object |
getRelation(relationId) | Fetch edge by ID | Relation or undefined |
getAllRelations() | Get all edges | Relation[] |
updateRelation(relationId, {name?, metadata?}) | Update name/metadata | Updated relation |
deleteRelation(relationId) | Remove relation | Deleted relation object |
deleteBySearch('relation', conditions) | Batch delete by search | Array of removed |
searchNodes(conditions: SearchConditions): Node[]
searchRelations(conditions: SearchConditions): Relation[]
conditions:
name: string | RegExp | { contains: string }id, fromNodeId, toNodeIdmetadata: { [key]: ... } supports:
{ eq, ne, gt, gte, lt, lte, contains, startsWith, endsWith, in }{ cosineSimilarity: { queryEmbedding, threshold } }cosineSimilarity (top-level): { queryEmbedding, embeddingKey, threshold }searchNodesByCosineSimilarity(queryEmbedding: number[], options?): Array
searchRelationsByCosineSimilarity(queryEmbedding: number[], options?): Array
cosineSimilarity(vecA: number[], vecB: number[]): number
queryEmbedding: Numeric vectorembeddingKey: metadata key for vector (default: 'embedding')threshold: similarity threshold (default: 0.5)limit: max results (default: 10)db.searchNodesByCosineSimilarity([0.1, 0.2, 0.3], { threshold: 0.8, limit: 3 });
| Method | Description | Returns |
|---|---|---|
traverseFromNode(startNodeId, options) | Walks from a node, following edges (see below) | Array of [fromNode, relation, toNode] |
traverseFromRelation(startRelationId, maxDepth?) | Starts traversal from a relation | Same as above |
traverseFromMetadata(metadataConditions, maxDepth?) | Begins traverse from nodes/relations that match metadata | Same as above |
Options for traverseFromNode:
maxDepth: limit depth (Infinity by default)directions: ['outgoing','incoming']relationName: (optional) filter by relation namedb.traverseFromNode(nodeId, { maxDepth: 2, directions: ['outgoing'] });
Result: Array of [fromNode, relation, toNode] triplets in visit order.
updateBySearch('node' | 'relation', searchConditions, { name?, metadata? }): Array
// Example:
db.updateBySearch('node', { metadata: { genre: 'sci-fi' } }, { name: 'SF Novel' });
deleteBySearch('node' | 'relation', searchConditions): Array
// Example:
db.deleteBySearch('relation', { metadata: { confidence: { lt: 0.9 } } });
searchAndTraverse(queryEmbedding, options?): Array
Supports:
Options:
embeddingKey, threshold, limit - see cosine similarityhops: Number of hops to traverse (default: 3)nodeFilters, relationFilters: Additional filterssearchNodes, searchRelations: Whether to include nodes, edges, or bothdirections: e.g., ['outgoing', 'incoming']endOnNode: bool (whether to always finish traversal on nodes)Example:
const tree = db.searchAndTraverse([0.2, 0.1, 0.5], {
hops: 2,
searchNodes: true,
searchRelations: false,
nodeFilters: { metadata: { type: 'paper' } },
});
console.log(tree);
// Output: array of hierarchical trees, each rooted on an initial (semantic) hit, with outgoing/incoming relations, connected nodes/edges & so forth
exportData(): { nodes: Node[], relations: Relation[] }
importData(data: { nodes, relations }): void
Export produces the full graph dataset as JSON-serializable data. Import wipes and loads supplied graph, then persists.
getNeighbors(nodeId): All neighbor nodes, with edge and direction
{ node, relation, direction }getStats(): { nodeCount, relationCount, avgDegree }flushToDisk(): Explicit save to disk (auto after every mutation unless using flush = false param on add)rebuildNodeRelationsIndex(): Internal; rebuilds edge indices (auto-run after import)const book1 = db.addNode('Dune', { genre: 'sci-fi', pages: 412, published: 1965 });
const book2 = db.addNode('Foundation', { genre: 'sci-fi', pages: 255, published: 1951 });
const author1 = db.addNode('Frank Herbert', { nationality: 'US' });
// Find all US authors:
db.searchNodes({ metadata: { nationality: 'US' } });
// Find all books published pre-1960:
db.searchNodes({ metadata: { published: { lt: 1960 } } });
const doc = db.addNode('Graph Vector', { embedding: [0.2, 0.4, 0.6] });
// Find similar to [0.2, 0.41, 0.67]:
db.searchNodesByCosineSimilarity([0.2, 0.41, 0.67], { threshold: 0.95 });
// Walk two hops out from a node
const walk = db.traverseFromNode(doc.id, { maxDepth: 2, directions: ['outgoing'] });
// Start traversal from a relation
const traverseRels = db.traverseFromRelation(rel1.id, 3);
// Traverse from all nodes with type "paper":
db.traverseFromMetadata({ type: 'paper' }, 2);
// Tag all "concept" nodes as reviewed
db.updateBySearch('node', { metadata: { type: 'concept' } }, { metadata: { reviewed: true } });
// Delete all weak relations
db.deleteBySearch('relation', { metadata: { confidence: { lt: 0.8 } } });
// Retrieve node (by semantic match) then its 2-hop subgraph
const rag = db.searchAndTraverse([0.25, 0.1, 0.5], { hops: 2 });
console.log(JSON.stringify(rag, null, 2));
console.log('Stats:', db.getStats());
console.log('Neighbors of nodeA:', db.getNeighbors(nodeA.id));
// Export/import
const json = db.exportData();
db.importData(json);
| Function | Time (ms) | Ops/sec |
|---|---|---|
| getNode() | 0.0001 | 8,473,743 |
| traverseFromNode() | 0.0072 | 138,175 |
| searchNodes() | 0.1728 | 5,787 |
| searchNodesByCosineSimilarity() | 0.3456 | 2,893 |
Run benchmarks: node src/benchmark.js 1000 2000 5 or npm run benchmark -- 1000 2000 5
git checkout -b feat/my-featurePlease file bugs/requests using GitHub Issues.
MIT License (see LICENSE)
Built with ♥ by freakynit
FAQs
A tiny, no-external-dependency, disk-based graph database for Node.js with rich set of operations.
The npm package tiny-graph-db receives a total of 11 weekly downloads. As such, tiny-graph-db popularity was classified as not popular.
We found that tiny-graph-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.