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

@liorandb/driver

v1.1.5

Published

TypeScript and JavaScript driver for the LioranDB Host API.

Readme

@liorandb/driver

TypeScript and JavaScript driver for the LioranDB Host API.

This package gives you a small MongoDB-style interface on top of the host server running at http://<host>:4000.

Installation

npm install @liorandb/driver

Before You Connect

The host will not start until at least one admin user exists.

Create the first admin with the CLI:

ldb-cli 'admin.create("admin","password123")'

Then start the host and authenticate through /auth/login or /auth/register.

Quick Start

import { LioranClient } from "@liorandb/driver";

const client = new LioranClient("http://localhost:4000");

await client.login("admin", "password123");

const db = client.db("app");
const users = db.collection<{ name: string; age: number }>("users");

await users.insertOne({ name: "John", age: 20 });

const results = await users.find({ age: { $gt: 18 } });
console.log(results);

Connection Formats

The client accepts these URI formats:

http://<host>:<port>
https://<host>:<port>
liorandb://<dbUsername>:<dbPassword>@<host>:<port>/<dbName>
lioran://<username>:<password>@<host>:<port>

Examples:

http://localhost:4000
https://db.example.com:4000
liorandb://app_user:app_pass@localhost:4000/app
lioran://admin:password123@localhost:4000 (legacy)

Use http(s)://... when you want to call login(), superAdminLogin(), setToken(), or setConnectionString() yourself.

Use liorandb://... when you want connect() (or setConnectionString()) to authenticate using a database connection string.

Use lioran://... when you want connect() to log in from URI credentials (legacy format).

Authentication

Login with username and password

const client = new LioranClient("http://localhost:4000");
const auth = await client.login("admin", "password123");

console.log(auth.user.username);
console.log(client.getToken());

Super admin login

const client = new LioranClient("http://localhost:4000");
await client.superAdminLogin(process.env.LIORAN_SUPER_ADMIN_SECRET!);

Register a user

const client = new LioranClient("http://localhost:4000");
await client.login("admin", "password123");

await client.register("editor", "password123");

Connect from a lioran:// URI

const client = new LioranClient(
  "lioran://admin:password123@localhost:4000"
);

await client.connect();

Connect from a liorandb:// connection string

const client = new LioranClient(
  "liorandb://app_user:app_pass@localhost:4000/app"
);

await client.connect();

const db = client.db("app");

Reuse an existing JWT

const client = new LioranClient("http://localhost:4000");
client.setToken(process.env.LIORAN_TOKEN!);

Use an existing database connection string

const client = new LioranClient("http://localhost:4000");
client.setConnectionString(process.env.LIORANDB_CONNECTION_STRING!);

Protected driver methods throw until the client is authenticated (via login(), superAdminLogin(), connect(), setToken(), or setConnectionString()).

Client API

Constructor

const client = new LioranClient(uri);

connect()

Supports:

  • liorandb://...: stores the connection string and authenticates via x-liorandb-connection-string
  • lioran://...: logs in via /auth/login (legacy format)
  • http(s)://user:pass@host:port: logs in via /auth/login
await client.connect();

login(username, password)

const auth = await client.login("admin", "password123");

Returns:

{
  user: { userId: string, username: string, role: "super_admin" | "admin" | "user" },
  token: string
}

superAdminLogin(secret)

const auth = await client.superAdminLogin(process.env.LIORAN_SUPER_ADMIN_SECRET!);

Returns the same shape as login().

register(username, password)

await client.login("admin", "password123");
await client.register("editor", "password123");

Requires authentication and returns the same shape as login().

Note: if you call register(input) without a password, the server returns token: null.

register(input)

Create a user with more control (user id, role, external id).

await client.login("admin", "password123");
await client.register({
  userId: "editor_1",
  username: "editor",
  password: "password123",
  role: "user",
  externalUserId: "auth0|abc123"
});

me()

Calls GET /auth/me and updates client.getUser().

const me = await client.me();
console.log(me.user.role);

listUsers()

Calls GET /auth/users.

const users = await client.listUsers();

updateMyCors(origins)

Calls PUT /auth/me/cors.

await client.updateMyCors(["https://app.example.com"]);

updateUserCors(userId, origins)

Calls PUT /auth/users/:userId/cors (admin-only).

await client.updateUserCors("user_123", ["https://app.example.com"]);

issueUserToken(userId)

Calls POST /auth/users/:userId/token.

const { token } = await client.issueUserToken("editor_1");

health()

Calls GET /health.

const health = await client.health();

Response:

{
  ok: true,
  time: "2026-04-13T12:00:00.000Z"
}

info()

Calls GET /.

const info = await client.info();

Response:

{
  name: "LioranDB",
  role: "Database Host",
  status: "online"
}

listDocs() / getDoc(id)

Calls GET /docs and GET /docs/:id.

const { docs } = await client.listDocs();
const apiDoc = await client.getDoc("api");

maintenanceStatus() / listSnapshots() / createSnapshotNow()

Calls admin-only maintenance endpoints under /maintenance/*.

await client.maintenanceStatus();
await client.listSnapshots();
await client.createSnapshotNow();

setToken(token)

client.setToken(jwt);

setConnectionString(connectionString)

client.setConnectionString("liorandb://user:pass@localhost:4000/app");

getToken()

const token = client.getToken();

getConnectionString()

const cs = client.getConnectionString();

getUser()

Returns the last authenticated user from login(), superAdminLogin(), me(), or connect().

const user = client.getUser();

isAuthenticated()

if (client.isAuthenticated()) {
  // ...
}

logout()

Clears the in-memory JWT/connection-string auth state and current user.

client.logout();

db(name)

const db = client.db("app");

listDatabases()

Calls GET /databases.

const databases = await client.listDatabases();

countDatabases(userId?)

Calls GET /databases/count (optionally filtered by userId).

const { count } = await client.countDatabases();

listUserDatabases(userId)

Calls GET /databases/user/:userId.

const res = await client.listUserDatabases("editor_1");
console.log(res.count, res.databases);

createDatabase(name)

Calls POST /databases.

const res = await client.createDatabase("app");

Response:

{ ok: true, database: { databaseName: "app", ... } }

createDatabase({ name, ownerUserId? })

const res = await client.createDatabase({ name: "app", ownerUserId: "editor_1" });

dropDatabase(name)

Calls DELETE /databases/:db.

const res = await client.dropDatabase("app");

Response:

{ ok: true }

databaseStats(name)

Calls GET /databases/:db/stats.

const stats = await client.databaseStats("app");

Response:

{
  name: "app",
  collections: 2,
  documents: 154
}

DB API

const db = client.db("app");

collection(name)

const users = db.collection("users");

You can pass a generic type for better autocomplete:

type User = {
  name: string;
  age: number;
  active?: boolean;
};

const users = db.collection<User>("users");

listCollections()

Calls GET /db/:db/collections.

const collections = await db.listCollections();

createCollection(name)

Calls POST /db/:db/collections.

const res = await db.createCollection("users");

Response:

{ ok: true, collection: "users" }

dropCollection(name)

Calls DELETE /db/:db/collections/:col.

const res = await db.dropCollection("users");

renameCollection(oldName, newName)

Calls PATCH /db/:db/collections/:col/rename.

const res = await db.renameCollection("users", "customers");

stats()

Calls GET /databases/:db/stats.

const stats = await db.stats();

getCredentials()

Calls GET /databases/:db/credentials.

const creds = await db.getCredentials();
console.log(creds.username, creds.password);

setCredentials({ username, password })

Calls PUT /databases/:db/credentials.

await db.setCredentials({ username: "app_user", password: "app_pass" });

getConnectionString()

Calls GET /databases/:db/connection-string.

const { connectionString } = await db.getConnectionString();

Collection API

const users = db.collection<User>("users");

insertOne(doc)

Calls POST /db/:db/collections/:col.

const user = await users.insertOne({ name: "John", age: 20 });

insertMany(docs)

Calls POST /db/:db/collections/:col/bulk.

const inserted = await users.insertMany([
  { name: "A", age: 20 },
  { name: "B", age: 21 }
]);

find(filter, options?)

Calls POST /db/:db/collections/:col/find.

const adults = await users.find({ age: { $gt: 18 } });

options supports (server passes through to the underlying query engine):

  • limit?: number
  • offset?: number
  • projection?: string[]
  • sort?: Record<string, 1 | -1>

findOne(filter, options?)

const john = await users.findOne({ name: "John" });

Returns the first matching document or null.

updateMany(filter, update)

Calls PATCH /db/:db/collections/:col/updateMany.

const res = await users.updateMany(
  { age: { $lt: 18 } },
  { $set: { minor: true } }
);

Response:

{ updated: 3, docs: [] }

aggregate(pipeline)

Calls POST /db/:db/collections/:col/aggregate.

const res = await users.aggregate([
  { $match: { age: { $gte: 18 } } },
  { $limit: 10 }
]);

explain(query, options?)

Calls POST /db/:db/collections/:col/explain.

const plan = await users.explain({ age: { $gte: 18 } }, { limit: 50 });

deleteMany(filter)

Calls POST /db/:db/collections/:col/deleteMany.

const res = await users.deleteMany({ inactive: true });

Response:

{ deleted: 5 }

count(filter)

Calls POST /db/:db/collections/:col/count.

const total = await users.count({ active: true });

stats()

Calls GET /db/:db/collections/:col/stats.

const stats = await users.stats();

Response:

{
  name: "users",
  documents: 42
}

Error Handling

The driver throws regular Error values for client-side validation issues and HttpError for failed HTTP requests.

import { HttpError, LioranClient } from "@liorandb/driver";

try {
  await client.login("admin", "wrong-password");
} catch (error) {
  if (error instanceof HttpError) {
    console.error(error.status);
    console.error(error.data);
  }
}

Exports

import {
  Collection,
  DB,
  HttpClient,
  HttpError,
  LioranClient
} from "@liorandb/driver";

The package also exports the shared TypeScript types from src/types.ts (for example: Filter, UpdateQuery, and response types).

License

MIT