Skip to content
Docs
SDK

JavaScript SDK

The @boltstore/client SDK provides a type-safe, promise-based interface to interact with your Boltstore databases. HTTP-only — no realtime, no offline sync, no client-side cache. Works in Node.js, Bun, Deno, and browsers.

Installation

# npm
npm install @boltstore/client
# yarn
yarn add @boltstore/client
# bun
bun install @boltstore/client

Initialization

import { BoltstoreClient } from '@boltstore/client';
const client = new BoltstoreClient({
url: 'http://localhost:8080',
database: 'my-app',
key: 'boltstore_...', // per-database API key, or admin session token
});
// Update the key later
client.setKey('boltstore_...');

The key is sent as Authorization: Bearer <key> on every request. Use a per-database API key for data access, or an admin session token (from POST /api/admin/login) for admin methods.

Tables

// List all tables
const tables = await client.tables.list();
// Create a table with column definitions
await client.tables.create('posts', [
{ name: 'id', type: 'integer', primary_key: true, auto_increment: true },
{ name: 'title', type: 'text', nullable: false },
{ name: 'views', type: 'integer', default: '0' },
]);
// Get table schema
const schema = await client.tables.get('posts');
// Rename, add/drop columns
await client.tables.update('posts', {
name: 'articles',
add_columns: [{ name: 'body', type: 'text' }],
});
// Drop a table
await client.tables.delete('articles');

Typed Records

const posts = client.table<{ id: number; title: string; views: number }>('posts');
// Create
const created = await posts.create({ title: 'Hello World', views: 0 });
// Get by ID
const fetched = await posts.get(created.id);
// Update
await posts.update(created.id, { views: 1 });
// Delete
await posts.delete(created.id);
// List with filter, sort, pagination
const result = await posts.list({
filter: { title: 'Hello%' },
sort: '-id',
limit: 10,
offset: 0,
});

Query Builder

const list = await posts
.query()
.where('title', 'like', 'Hello%')
.orWhere('views', 'gt', 100)
.orderBy('id', 'desc')
.limit(10)
.get();
// Get first match
const first = await posts.query().where('title', 'eq', 'Hello').first();
// Paginate
const page = await posts.query().paginate(1, 20);

Supported operators: eq, ne, gt, gte, lt, lte, in, like, glob.

Raw SQL

// SELECT only for non-admin keys; DDL/DML requires admin
const rows = await client.sql<{ id: number; title: string }>(
'SELECT id, title FROM posts WHERE views > ? ORDER BY id',
[0],
);

Admin Operations

These methods require an admin session token or admin API key:

// Database info / delete / export
const info = await client.info();
await client.delete();
const blob = await client.export();
// Per-database config
const config = await client.config.get();
await client.config.update({ cors_origins: ['https://myapp.com'] });
// API key management
const keys = await client.keys.list();
const newKey = await client.keys.create('Production Backend');
await client.keys.rotate(newKey.id);
await client.keys.revoke(newKey.id);

Health Check

const health = await client.health();
// { status: "ok", version: "1.0.0", databases: 3 }

Authentication Model

The SDK holds a single key used for every request. Methods that hit admin routes (info, delete, export, config.*, keys.*) require an admin session token. Methods that hit data routes (tables.*, table(), records, sql) accept either a per-database API key or an admin credential.

If you only have a per-database API key, use tables, table(), list, and sql(). Calling info() or keys.list() will return 401 Unauthorized.

Known Issues

  • PaginatedResult.total is currently broken. list() and paginate() return total as the current page's row count, not the total matching rows. Do not rely on total for pagination page-count math until fixed.
  • QueryBuilder.where op is not validated client-side. An unsupported op is silently dropped by the server. Stick to the supported operators listed above.