npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

verdictdb

v0.1.0

Published

High-performance Node.js & TypeScript bindings for Verdict — the local-first embedded database with propose → verdict → commit safety pipeline, cryptographic hash chain audit, and instant rollback.

Readme

verdictdb

High-performance Node.js & TypeScript bindings for Verdict (VDB) — the local-first embedded database with a propose → verdict → commit safety pipeline, cryptographic hash-chain audit, and instant rollback.

GitHub License Node


🧭 Documentation Navigation

| 🏠 Root | ⚙️ Core Engine | 💻 CLI / REPL | 🔌 MCP Server | 🤖 AI Skill | |---|---|---|---|---| | Main README | verdict-core | verdict-cli | verdictdb | verdict-skill |

| 📖 In-Depth Guides | 📊 Comparisons | 🛡️ Security | 🤝 Contributing | |---|---|---|---| | Integration Guide | CLI Tutorial & Cheatsheet | Security Architecture | Contributing Guide |


What is Verdict?

Verdict is a local-first relational embedded database where no mutation can touch disk without an authorized verdict.

Every write goes through:

query (SQL or NL) → propose() → Verdict (dry-run diff) → commit(verdict.id) → disk

This gives you:

  • ✅ Atomic, ACID writes — nothing partial ever lands on disk
  • ✅ Instant point-in-time rollback — undo(commit_id) is microseconds
  • ✅ Cryptographic SHA-256 Merkle audit trail — tamper-evident commit log
  • ✅ Standard ANSI SQL + Natural Language — interchangeable query dialects
  • ✅ Sub-60µs query latency — redb B-Tree, no IPC, no network

Installation

npm install verdictdb

Note: verdictdb is a native Node.js addon compiled from Rust via napi-rs. It requires Rust to be installed to build from source, or pre-built binaries are provided for macOS, Linux, and Windows.


Quick Start

import { VerdictDb } from 'verdictdb';

// Open (or create) a local .vdb database file
const db = VerdictDb.open('./myapp.vdb');

Creating Tables (DDL)

Verdict supports Standard ANSI SQL CREATE TABLE with PRIMARY KEY and REFERENCES for foreign keys:

// Create a parent table
db.propose(`CREATE TABLE customers (
  id      VARCHAR PRIMARY KEY,
  name    VARCHAR,
  email   VARCHAR,
  plan    VARCHAR
)`);

// Create a child table with a foreign key reference
db.propose(`CREATE TABLE orders (
  id          VARCHAR PRIMARY KEY,
  customer_id VARCHAR REFERENCES customers(id),
  total_cents INT,
  status      VARCHAR
)`);

Or use the Natural Language DSL:

db.propose('create table customers with id:str, name:str, email:str, plan:str');
db.propose('create table orders with id:str, customer_id:str references customers.id, total_cents:num, status:str');

⚠️ DDL operations return a Verdict with risk: "SchemaChange" that must be committed to take effect:

const v = JSON.parse(db.propose(`CREATE TABLE users (id VARCHAR PRIMARY KEY, name VARCHAR, age INT)`));
db.commit(v.id);   // commits the schema change to disk

Inserting Data

Key Generation

Verdict has a built-in time-sorted key generator:

  • key() — generates vdb_k_<sortable> (globally unique, time-ordered)
  • key("prefix") — generates prefix_<sortable> (e.g. cust_..., ord_...)
  • Omitted PK — auto-generated with table-name prefix
// SQL INSERT with key() generator
const v = JSON.parse(db.propose(
  `INSERT INTO customers (id, name, email, plan) VALUES (key('cust'), 'Acme Corp', '[email protected]', 'Enterprise')`
));
// v.diff.rows_after[0].id => "cust_01a0f5d3bca8..."

db.commit(v.id);

// SQL INSERT — omit PK and it's auto-generated
const v2 = JSON.parse(db.propose(
  `INSERT INTO orders (customer_id, total_cents, status) VALUES ('cust_01a0f5d3bca8', 99900, 'pending')`
));
db.commit(v2.id);

Natural language alternative:

const v = JSON.parse(db.propose(
  `add customers with id=key("cust"), name=Acme Corp, [email protected], plan=Enterprise`
));
db.commit(v.id);

Reading Data (SELECT / Queries)

All reads return a Verdict with risk: "Read". No commit needed.

// Standard SQL SELECT
const result = JSON.parse(db.propose(`SELECT * FROM customers WHERE plan = 'Enterprise'`));
console.log(result.diff.rows_after);  // array of matching rows

// SQL JOIN across tables
const joined = JSON.parse(db.propose(
  `SELECT * FROM orders JOIN customers ON orders.customer_id = customers.id`
));
console.log(joined.diff.rows_after);

// SQL COUNT
const count = JSON.parse(db.propose(`SELECT COUNT(*) FROM orders`));
console.log(count.diff.affected);

// Natural Language equivalents
db.propose('show all customers');
db.propose('find orders where status = pending');
db.propose('show orders for customer cust_acme');   // FK navigation (forward)
db.propose('show customer for order ord_abc123');   // FK navigation (reverse)

Updating & Deleting

// SQL UPDATE
const updateV = JSON.parse(db.propose(
  `UPDATE orders SET status = 'fulfilled' WHERE id = 'ord_abc123'`
));
// updateV.diff.rows_before — shows what will change
// updateV.diff.rows_after  — shows what it becomes
const committed = JSON.parse(db.commit(updateV.id));

// SQL DELETE (scoped)
const deleteV = JSON.parse(db.propose(`DELETE FROM orders WHERE id = 'ord_abc123'`));
db.commit(deleteV.id);

// SQL DELETE ALL (quarantined as BroadWrite — requires explicit decision)
const broadV = JSON.parse(db.propose(`DELETE FROM orders`));
console.log(broadV.risk); // "BroadWrite" — check before committing!
if (broadV.risk !== 'BroadWrite') {
  db.commit(broadV.id);
}

Point-in-Time Rollback (undo)

Every commit() returns a commit_id. Pass it to undo() to instantly restore the prior state:

const verdict  = JSON.parse(db.propose(`UPDATE users SET age = 999 WHERE name = 'Alice'`));
const result   = JSON.parse(db.commit(verdict.id));

// Oops — roll back immediately
const undone = JSON.parse(db.undo(result.commit_id));
console.log(undone.status); // "undone"

Inspecting the Schema

const schema = JSON.parse(db.schema());
// {
//   tables: [
//     {
//       name: "customers",
//       primary_key: "id",
//       columns: [{ name: "id", value_type: "Str" }, ...],
//       foreign_keys: []
//     },
//     {
//       name: "orders",
//       primary_key: "id",
//       columns: [{ name: "customer_id", value_type: "Str" }, ...],
//       foreign_keys: [{ column: "customer_id", foreign_table: "customers", foreign_column: "id" }]
//     }
//   ]
// }

schema.tables.forEach(table => {
  console.log(`\nTable: ${table.name} (PK: ${table.primary_key})`);
  table.columns.forEach(col => console.log(`  ${col.name}: ${col.value_type}`));
  table.foreign_keys.forEach(fk =>
    console.log(`  FK: ${fk.column} → ${fk.foreign_table}.${fk.foreign_column}`)
  );
});

Full Example: Express.js REST API

import express from 'express';
import { VerdictDb, Verdict, CommitResult } from 'verdictdb';

const app = express();
app.use(express.json());

const db = VerdictDb.open('./data/app.vdb');

// Bootstrap schema on startup
function bootstrapSchema() {
  const tables = [
    `CREATE TABLE customers (id VARCHAR PRIMARY KEY, name VARCHAR, email VARCHAR, plan VARCHAR)`,
    `CREATE TABLE orders (id VARCHAR PRIMARY KEY, customer_id VARCHAR REFERENCES customers(id), total_cents INT, status VARCHAR)`,
  ];
  for (const ddl of tables) {
    try {
      const v = JSON.parse(db.propose(ddl)) as Verdict;
      if (v.risk === 'SchemaChange') db.commit(v.id);
    } catch (_) { /* table already exists */ }
  }
}
bootstrapSchema();

// POST /customers — create a customer
app.post('/customers', (req, res) => {
  const { name, email, plan } = req.body;
  try {
    const verdict = JSON.parse(
      db.propose(`INSERT INTO customers (id, name, email, plan) VALUES (key('cust'), '${name}', '${email}', '${plan}')`)
    ) as Verdict;

    if (verdict.risk === 'BroadWrite') {
      return res.status(400).json({ error: 'Unexpectedly broad mutation — rejected.' });
    }

    const result = JSON.parse(db.commit(verdict.id)) as CommitResult;
    const createdRow = verdict.diff.rows_after[0];

    res.status(201).json({ customer: createdRow, commit_id: result.commit_id });
  } catch (err: any) {
    res.status(400).json({ error: err.message });
  }
});

// GET /customers — list all customers
app.get('/customers', (_req, res) => {
  const verdict = JSON.parse(db.propose('SELECT * FROM customers')) as Verdict;
  res.json({ customers: verdict.diff.rows_after });
});

// GET /customers/:id/orders — FK navigation
app.get('/customers/:id/orders', (req, res) => {
  const verdict = JSON.parse(
    db.propose(`show orders for customer ${req.params.id}`)
  ) as Verdict;
  res.json({ orders: verdict.diff.rows_after });
});

// DELETE /orders/:id — delete with undo capability
app.delete('/orders/:id', (req, res) => {
  const verdict = JSON.parse(
    db.propose(`DELETE FROM orders WHERE id = '${req.params.id}'`)
  ) as Verdict;
  const result = JSON.parse(db.commit(verdict.id)) as CommitResult;
  res.json({ deleted: true, commit_id: result.commit_id, undo_with: `POST /undo/${result.commit_id}` });
});

// POST /undo/:commitId — point-in-time rollback
app.post('/undo/:commitId', (req, res) => {
  try {
    const result = JSON.parse(db.undo(req.params.commitId));
    res.json(result);
  } catch (err: any) {
    res.status(400).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('Verdict API running on http://localhost:3000'));

Full Example: Next.js 15 App Router (Server Actions)

// lib/db.ts
import { VerdictDb } from 'verdictdb';
import path from 'path';

// Singleton — reused across server-side renders
let _db: VerdictDb | null = null;

export function getDb(): VerdictDb {
  if (!_db) {
    _db = VerdictDb.open(path.join(process.cwd(), 'data', 'app.vdb'));
  }
  return _db;
}
// app/actions/users.ts
'use server';
import { getDb } from '@/lib/db';
import { revalidatePath } from 'next/cache';
import { Verdict, CommitResult } from 'verdictdb';

export async function createUser(formData: FormData) {
  const db = getDb();
  const name  = formData.get('name') as string;
  const email = formData.get('email') as string;
  const age   = Number(formData.get('age'));

  const verdict = JSON.parse(
    db.propose(`INSERT INTO users (name, email, age) VALUES ('${name}', '${email}', ${age})`)
  ) as Verdict;

  const commit = JSON.parse(db.commit(verdict.id)) as CommitResult;

  revalidatePath('/users');
  return { user: verdict.diff.rows_after[0], commitId: commit.commit_id };
}

export async function listUsers() {
  const db = getDb();
  const verdict = JSON.parse(db.propose('SELECT * FROM users')) as Verdict;
  return verdict.diff.rows_after;
}

export async function undoLastAction(commitId: string) {
  const db = getDb();
  return JSON.parse(db.undo(commitId));
}
// app/users/page.tsx
import { listUsers } from '../actions/users';

export default async function UsersPage() {
  const users = await listUsers();
  return (
    <ul>
      {users.map((u: any) => (
        <li key={u.id}>{u.name} — {u.email}</li>
      ))}
    </ul>
  );
}

Standalone Functional API

For functional-style usage, all methods are also available as standalone functions:

import { verdictOpen, verdictPropose, verdictCommit, verdictUndo, verdictSchema } from 'verdictdb';

const db = verdictOpen('./app.vdb');

const verdict = JSON.parse(verdictPropose(db, 'add users with name=Alice, age=30'));
const commit  = JSON.parse(verdictCommit(db, verdict.id));

// Roll back
verdictUndo(db, commit.commit_id);

// Inspect schema
const schema = JSON.parse(verdictSchema(db));

Building from Source

If pre-built binaries are not available for your platform:

# Prerequisites: Rust >= 1.75, Node.js >= 16

git clone https://github.com/senapati484/verdict.git
cd verdict/crates/verdict-node

npm install
npm run build   # compiles the native Rust addon

License

Licensed under the Apache License, Version 2.0. Copyright 2026 senapati484.