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

get-db9

v0.6.1

Published

TypeScript SDK for db9-server — instant PostgreSQL databases

Downloads

881

Readme

get-db9

TypeScript SDK for db9-backend — instant PostgreSQL-compatible databases on TiKV.

Install

npm install get-db9

Quick Start

One-liner: Get a database instantly

import { instantDatabase } from 'get-db9';

const db = await instantDatabase();
console.log(db.connectionString);
// postgresql://tenant.admin:password@host:5433/postgres

With seeding

const db = await instantDatabase({
  name: 'myapp',
  seed: 'CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT)',
});

Db9 Client

Full typed client for the API — databases, SQL, file storage, tokens, migrations, and more.

import { createDb9Client } from 'get-db9';

// Uses the credential store if present, or auto-registers an anonymous session.
const client = createDb9Client();

// Create a database
const db = await client.databases.create({ name: 'myapp' });

// Execute SQL
const result = await client.databases.sql(db.id, 'SELECT * FROM users');
console.log(result.columns, result.rows);

// Schema inspection
const schema = await client.databases.schema(db.id);

// Migrations
await client.databases.applyMigration(db.id, {
  name: 'add_users',
  sql: 'CREATE TABLE users (id SERIAL PRIMARY KEY)',
  checksum: 'abc123',
});

File Storage (fs9)

Each database includes a built-in file system accessible via WebSocket. The SDK connects to the fs9 WebSocket server, authenticates, and provides a high-level API for file operations.

Note: File storage requires a WebSocket implementation. Browsers, Deno, Bun, and Node 21+ have native WebSocket. For Node 18–20, install the ws package and pass it via the WebSocket option.

import { createDb9Client } from 'get-db9';
import WebSocket from 'ws'; // Node 18–20 only

const client = createDb9Client({ WebSocket: WebSocket as any });
const dbId = 'your-database-id';

// Write a file (string, ArrayBuffer, or Uint8Array)
await client.fs.write(dbId, '/data/hello.txt', 'Hello, world!');

// Read file as text
const text = await client.fs.read(dbId, '/data/hello.txt');

// Read file as raw bytes (Uint8Array)
const bytes = await client.fs.readBinary(dbId, '/data/image.png');

// List files in a directory
const files = await client.fs.list(dbId, '/data');

// Check if file exists
const exists = await client.fs.exists(dbId, '/data/hello.txt');

// Get file metadata (type, size, mode, mtime)
const stat = await client.fs.stat(dbId, '/data/hello.txt');
console.log(stat.type, stat.size); // 'file', 1024

// Create directory (recursive)
await client.fs.mkdir(dbId, '/data/nested/dir');

// Append to a file
await client.fs.append(dbId, '/data/log.txt', 'new line\n');

// Rename (move) a file
await client.fs.rename(dbId, '/data/old.txt', '/data/new.txt');

// Delete a file
await client.fs.remove(dbId, '/data/hello.txt');

// Delete a directory recursively
await client.fs.remove(dbId, '/data/old-dir', { recursive: true });

Persistent Connection

For multiple operations on the same database, use fs.connect() to hold a single WebSocket connection and avoid reconnecting per-call:

const fs = await client.fs.connect(dbId);
try {
  await fs.mkdir('/batch');
  await fs.writeFile('/batch/a.txt', 'file A');
  await fs.writeFile('/batch/b.txt', 'file B');
  const entries = await fs.readdir('/batch');
  console.log(entries); // [{path: '/batch/a.txt', ...}, ...]
} finally {
  await fs.close();
}

Token Management

const client = createDb9Client();

// Create a named API token
const token = await client.tokens.create({
  name: 'ci-deploy',
  expires_in_days: 90,
});
console.log(token.token); // Use this for CI/CD

// List all tokens
const tokens = await client.tokens.list();

// Revoke a token
await client.tokens.revoke(token.id);

Anonymous + Claim

If no credentials are available, the SDK auto-registers an anonymous session on the first authenticated call and stores token, is_anonymous, anonymous_id, and anonymous_secret in the configured credential store (~/.db9/credentials by default).

  • Run db9 claim (or db9 claim --id-token <AUTH0_ID_TOKEN>) to upgrade that account to a verified Auth0 identity.
  • After claim, continue using the stored token or create named API tokens for CI/CD and agents.

Database Credentials

Retrieve stored admin credentials without resetting the password:

const client = createDb9Client();
const dbId = 'your-database-id';

// Get stored credentials (no password reset)
const creds = await client.databases.credentials(dbId);
console.log(creds.admin_user);         // admin username
console.log(creds.admin_password);     // current password
console.log(creds.connection_string);  // full connection string

SQL Error Handling

SQL results include structured error details when queries fail:

const result = await client.databases.sql(dbId, 'SELECT * FROM nonexistent');

if (result.error) {
  // result.error is a SqlErrorDetail object:
  // {
  //   message: "relation \"nonexistent\" does not exist",
  //   code: "42P01",         // PostgreSQL error code
  //   detail: "...",         // optional
  //   hint: "...",           // optional
  //   position: 15           // optional cursor position
  // }
  console.log(result.error.message);
  console.log(result.error.code);
}

Configuration

instantDatabase options

| Option | Type | Default | Description | |--------|------|---------|-------------| | name | string | 'default' | Database name | | baseUrl | string | Production URL | API endpoint | | fetch | FetchFn | globalThis.fetch | Custom fetch | | credentialStore | CredentialStore | FileCredentialStore | Credential storage | | seed | string | — | SQL to run after creation | | seedFile | string | — | SQL file content to run | | timeout | number | — | Request timeout in ms | | maxRetries | number | 3 (max) | Retry count for failed requests | | retryDelay | number | — | Delay between retries in ms |

Db9 client options

| Option | Type | Default | Description | |--------|------|---------|-------------| | baseUrl | string | Production URL | API endpoint | | token | string | — | Bearer token (optional) | | fetch | FetchFn | globalThis.fetch | Custom fetch | | credentialStore | CredentialStore | FileCredentialStore | Load/save token | | timeout | number | — | Request timeout in ms | | maxRetries | number | 3 (max) | Retry count for failed requests | | retryDelay | number | — | Delay between retries in ms | | WebSocket | WebSocketConstructor | globalThis.WebSocket | WebSocket impl for fs operations | | wsPort | number | 5480 | WebSocket port for fs9 server |

Zero-config client

import { createDb9Client } from 'get-db9';

// Loads existing credentials or auto-registers an anonymous session
const client = createDb9Client();
const db = await client.databases.create({ name: 'myapp' });

Error Handling

import {
  createDb9Client,
  Db9Error,
  Db9AuthError,
  Db9NotFoundError,
} from 'get-db9';

const client = createDb9Client();

try {
  await client.databases.get('nonexistent');
} catch (err) {
  if (err instanceof Db9NotFoundError) {
    console.log('Database not found');
  } else if (err instanceof Db9AuthError) {
    console.log('Authentication failed');
  } else if (err instanceof Db9Error) {
    console.log(`API error ${err.statusCode}: ${err.message}`);
  }
}

Note: If you rely on instanceof, import createDb9Client and the error classes from the same entrypoint: get-db9.

Credential Storage

Credentials are stored in ~/.db9/credentials (TOML format), shared with the db9 CLI.

import { FileCredentialStore, MemoryCredentialStore } from 'get-db9';

// File-based (default, shared with CLI)
const fileStore = new FileCredentialStore();

// Custom path
const customStore = new FileCredentialStore('/path/to/credentials');

// In-memory (for testing or serverless)
const memStore = new MemoryCredentialStore();

API Reference

client.auth

| Method | Description | |--------|-------------| | me() | Get current user profile |

client.tokens

| Method | Description | |--------|-------------| | create(req) | Create a named API token ({ name?, expires_in_days? }) | | list() | List all tokens | | revoke(tokenId) | Revoke a token by ID |

client.databases

| Method | Description | |--------|-------------| | create(req) | Create a new database | | list() | List all databases | | get(id) | Get database details | | delete(id) | Delete a database | | resetPassword(id) | Reset admin password | | credentials(id) | Get stored admin credentials without resetting | | observability(id) | Get TPS, latency, connection stats | | sql(id, query) | Execute SQL query (errors returned as SqlErrorDetail) | | sqlFile(id, content) | Execute SQL from file content | | schema(id) | Get schema metadata | | dump(id, req?) | Export schema/data as SQL | | applyMigration(id, req) | Apply a migration | | listMigrations(id) | List applied migrations | | branch(id, req) | Create a database branch | | users.list(id) | List database users | | users.create(id, req) | Create database user | | users.delete(id, username) | Delete database user |

client.fs

All methods auto-resolve database credentials and connect via WebSocket.

| Method | Description | |--------|-------------| | connect(dbId) | Open a persistent FsClient WebSocket connection | | read(dbId, path) | Read file as text (UTF-8) | | readBinary(dbId, path) | Read file as Uint8Array | | write(dbId, path, content) | Write file (string, ArrayBuffer, or Uint8Array) | | append(dbId, path, content) | Append to a file, returns bytes written | | list(dbId, path) | List directory contents (returns FileInfo[]) | | stat(dbId, path) | Get file metadata (FileInfo) | | exists(dbId, path) | Check if file exists (returns boolean) | | mkdir(dbId, path) | Create directory recursively | | remove(dbId, path, opts?) | Remove file or directory ({ recursive?: boolean }) | | rename(dbId, old, new) | Rename (move) a file or directory |

Requirements

  • Node.js >= 18 (native fetch)
  • TypeScript >= 5.0 (for type exports)

License

Apache-2.0