blindrange

Build on blindrange — Node.js

One npm install. No Python to set up, no daemon to run, no port to secure. The statements are the SQL dialectshaped like SQL, deliberately not SQL — and every sample below is quoted from examples/node/quickstart.mjs, which the test suite runs.

1Install and connect

npm install blindrange
import { connect, UnsupportedError } from "blindrange";
const db = await connect({
  path: process.env.BR_STATE || "/tmp/blindrange-node-quickstart",
  passphrase: "quickstart passphrase",
  bootstrap: [process.env.BR_BOOTSTRAP || "seed.blindrange.dev:7501"],
  networkSecret: process.env.BR_SECRET || "blindrange-public",
});
optionwhat it isexample
path directory holding your tables' master keys, encrypted at rest. Back it up — the network only has ciphertext. "./shop"
passphrase unlocks that directory. Sent to the child over stdin, never on argv, never on any socket. "correct horse battery staple"
bootstrap any one live peer; gossip finds the rest. ["seed.blindrange.dev:7501"]
networkSecret which network — anti-vandal, not access control. "blindrange-public"

2Everything is a statement

await db.execute(`CREATE TABLE orders (
  amount   INT BITS 20 BLUR 64,
  day      INT BITS 16 BLUR 16,
  status   TEXT(6) BLUR 16,
  customer STORED
)`);
await db.execute(`INSERT INTO orders (amount, day, status, customer) VALUES
  (450, 201, 'paid', 'cust-001'),
  (120, 205, 'refunded', 'cust-002'),
  (720, 210, 'paid', 'cust-003')`);
console.log(await db.execute(
  `SELECT customer, amount FROM orders WHERE amount BETWEEN 300 AND 800
   ORDER BY amount DESC`));
[ { customer: 'cust-003', amount: 720 },
  { customer: 'cust-001', amount: 450 } ]

Counts and sums come from index metadata — nothing fetched, nothing decrypted, and the sum arrives with its error bar, which is exactly the resolution you traded for privacy:

console.log(await db.execute(`SELECT COUNT(*) FROM orders`));
console.log(await db.execute(`SELECT APPROX SUM(amount) FROM orders`));
[ { count: 3, basis: 'exact-to-leaf' } ]
[ { sum: 1310.5, plus_minus: 96, rows: 3 } ]
await db.execute(`UPDATE orders SET status = 'shipped' WHERE amount = 450`);
await db.execute(`DELETE FROM orders WHERE day > 208`);

3Refusals arrive typed

Everything the engine genuinely cannot do — JOIN, OR, exact SUM(), leading-wildcard LIKE — rejects with UnsupportedError, whose message names why and what to use instead. A boundary is never dressed up as a bug:

try {
  await db.execute(`SELECT SUM(amount) FROM orders`);
} catch (e) {
  if (e instanceof UnsupportedError) console.log("refused:", e.message);
}

The full refusal table, with reasons, is in the SQL guide.

4How this package works, honestly

It is not a JavaScript reimplementation. The package spawns the reference Python client as a child it owns — a self-contained CPython ships as a platform-specific optional dependency, the same prebuilt interpreters uv installs. Stdio only: no port exists, so nothing else on the machine can reach your database, and the child dies with your process. Why: the client is where all cryptography lives, and a parallel implementation would have to match it byte-for-byte forever — every divergence would be silent corruption. Running the reference means every feature, fix and measurement lands here the day it ships, including QUIC direct paths.
Reads are local. The bridge keeps a complete encrypted mirror of each table beside the state directory — lookups, ranges, counts and "not found" answer from local disk. Writes go to the network for durability. Nothing to configure.
Costs, stated plainly: roughly 40 MB download for the bundled runtime (npm selects only your platform's), and about 100 ms of child start per connect(). If no bundled runtime exists for your platform, the package falls back to python3 on PATH with blindrange installed, or an explicit path in BLINDRANGE_PYTHON.
blindrange.dev · the SQL guide · the Python guide · demos · the web guide · built on it · live network · source