The test lab
This site doubles as a working demo and the project’s test bench. The lab runs a real Larva database — seeded customers, orders, and auto-numbered invoices, living in a private Vercel Blob store on format 3, the ordered commit log. Nothing is mocked.
The SQL console
Type any statement in the dialect and run it live. The example chips walk the breadth: joins + GROUP BY, zone-map-pruned date ranges, INSERT … RETURNING, revenue-by-day, HAVING + CASE, upserts, a sequence-numbered invoice, and one deliberately unsupported query so you can see an agent-grade error. Every result reports timing, chunks read vs. total (pruning, visibly), and the database version it saw.
Export buttons produce real files — the Postgres one loads with psql $DATABASE_URL < larva-demo.sql. Reset demo data re-seeds everything; mangle freely, that’s the point.
The data viewer
/viewer browses the same store visually: paged, sortable tables; a version scrubber that time-travels through every commit (asOf, live); and a chunk/zone-map internals panel powered by db.inspect(). Scrubbing is itself a demo of the architecture — watch a table grow from one chunk to several, and the format version flip, as history replays.
The stress lab
The bottom of the lab page hammers one database with concurrent writers, then audits the final state for lost updates, duplicates, and version drift — the commit protocol’s core promise, tested against the real store on every click.
- append — disjoint writes; exercises the cheap rebase recovery path
- counter — every write overlaps; forces full re-execute recovery
- mixed — both at once
Guardrails (a public toy, not a public liability)
Storage is bounded per reset, and — the part a reset can’t launder — operations are bounded per day, because blob bills count both. All budget checks live server-side (app/lib/guard.ts) and fail closed.
- Statements cap at 5,000 characters, and the console runs SELECT / INSERT / UPDATE / DELETE only. Schema statements (
CREATE,ALTER,DROP,CREATE INDEX) are blocked — not for safety, but because they amplify the op count of every later commit. Clone the repo for the full dialect. - Row ceilings: 50 rows per INSERT, 2,000 rows per table (
DEMO_TABLE_FULL→ reset to continue). - Writes draw from a budget of 400 commits between resets — budget × statement cap bounds total storage no matter what the console is fed. Exhausting it returns
WRITE_BUDGET_EXHAUSTED(HTTP 429); reset restarts it. - Global daily budgets, durable in the store itself and updated with the same CAS the commit protocol uses, shared across serverless instances: 600 console commits, 24 resets (with a 5-minute cooldown, so a reset loop can’t launder the write budget), and 30 stress runs — which also take a single-flight lease: one run at a time, abandoned leases expire on their own.
- Per-IP rate limits on every endpoint (reads included), and browser writes from foreign origins are refused outright.
- Stress runs always clean up after themselves, and reset also sweeps blobs left by failed harness runs.
API routes (what the buttons call)
| Route | Method | Does |
|---|---|---|
/api/sql | POST { sql, allowFullTable? } | run one statement, return rows + stats |
/api/export?format=postgres|json | GET | download the live database |
/api/export?format=csv&table=NAME | GET | download one table as CSV |
/api/demo-reset | POST | drop and re-seed; restarts the write budget |
/api/stress | POST { writers, commitsPerWriter, mode } | run the concurrent-writer audit |
Run your own
git clone https://github.com/pango07/larva-db && cd larva-db
bun install
vercel link
vercel blob store add my-larva-store --access private --yes
vercel env pull .env.local # BLOB_READ_WRITE_TOKEN
bun run dev # http://localhost:3000
vercel deploy --prod --yes # or ship itThe test suites — 318 checks across eight suites
Correctness risk concentrates in the conflict/retry path, so that’s where the tests concentrate. All of it runs in CI on every push; merges to main publish to npm.
bunx tsc --noEmit # typecheck (includes compile-only type tests)
bun run lint
# offline — no credentials needed
bun scripts/s3-adapter-test.ts # storage contract + injected 409/500 chaos
bun scripts/group-commit-test.ts # coalescing, conflict matrix, formats 3–4, upgrade flow
bun scripts/guard-test.ts # the demo-endpoint abuse guards above
# live — need BLOB_READ_WRITE_TOKEN in .env.local
bun scripts/sql-smoke.ts # the whole dialect, end to end
bun scripts/api-smoke.ts # transactions, exports, vacuum
bun scripts/cli-smoke.ts # the larva CLI as a subprocess
bun scripts/stress.ts --writers 4 --commits 6 # add --log for format 3
bun scripts/property.ts --writers 4 --ops 10 # add --log for format 3
bun scripts/bench.ts # write throughput, both formats| Suite | What it proves |
|---|---|
stress.ts | concurrent writers on a real store: zero lost updates, exact version arithmetic |
property.ts | randomized workloads verified against a per-writer sequential model |
sql-smoke.ts | the full dialect + the machine-readable error catalog + pruning + time travel |
api-smoke.ts | transaction atomicity, export round-trips, vacuum retention, format 3 live |
cli-smoke.ts | the CLI: arguments, exit codes, files on disk, upgrade/rollback |
s3-adapter-test.ts | the storage contract under injected chaos |
group-commit-test.ts | coalescing, the conflict matrix, the ordered commit log under chaos |
guard-test.ts | the public lab’s abuse guards: budgets count exactly under CAS contention, fail closed |
The stress and property harnesses ship in the package —
import { runStress, runProperty } from "@larva-db/core/testing" — so you can gauntlet your own
setup.