@tacticdb/client
v0.1.0
Published
TacticDB client SDK: list, read, and (where an app's access policy allows) create, update, or delete records from a browser or any fetch-capable runtime.
Maintainers
Readme
@tacticdb/client
The official client SDK for TacticDB. List, read, and — where an
app's access policy allows — create, update, and delete records from a browser, Node.js, or any
other fetch-capable JavaScript runtime.
- Tiny and dependency-free. Ships as ESM with full TypeScript types; no runtime dependencies.
- Type-safe records. Bring your own record type and every method is typed end to end.
- Predictable errors. Every failure — network, HTTP, or bad configuration — is thrown as a
single
TacticDbError. - Runs anywhere
fetchdoes. Browsers, Node 18+, Deno, Bun, Cloudflare Workers, and more.
import { createTacticDbClient } from '@tacticdb/client';
const db = createTacticDbClient({
baseUrl: 'https://api.example.com',
appId: 'product-catalog',
apiKey: 'pk_live_…', // optional; see Authentication
});
const products = db.table('products');
const { items } = await products.list({ where: { status: 'active' }, take: 20 });Installation
npm install @tacticdb/client
# or
pnpm add @tacticdb/client
# or
yarn add @tacticdb/clientRequires Node.js 18+ (for a global fetch) or any runtime with a fetch implementation you
can pass in. The package is ESM-only.
Without a build step (CDN)
<script type="module">
import { createTacticDbClient } from 'https://unpkg.com/@tacticdb/client/dist/tacticdb-client.esm.js';
const db = createTacticDbClient({ baseUrl: 'https://api.example.com', appId: 'product-catalog' });
</script>A UMD/global build is also published at dist/tacticdb-client.global.js (exposes window.TacticDB).
Quick start
import { createTacticDbClient, TacticDbError } from '@tacticdb/client';
// Describe your record's data shape (the fields you defined on the table).
interface Product {
name: string;
sku: string;
price: number;
status: 'active' | 'draft';
}
const db = createTacticDbClient({
baseUrl: 'https://api.example.com',
appId: 'product-catalog',
apiKey: import.meta.env.TACTICDB_KEY,
});
const products = db.table<Product>('products');
try {
// Create
const created = await products.create({ name: 'Drill', sku: 'DR-01', price: 79, status: 'active' });
// Read one
const one = await products.get(created.id);
// List with filters + paging
const { items } = await products.list({
where: { status: 'active' },
orderBy: 'price',
direction: 'desc',
take: 25,
});
// Update
await products.update(created.id, { price: 69 });
// Delete (archives the record)
await products.delete(created.id);
} catch (err) {
if (err instanceof TacticDbError) {
console.error(err.code, err.status, err.message);
}
}Core concepts
Client — createTacticDbClient(options) returns a client scoped to a single TacticDB app.
Construction is synchronous and makes no network request; an invalid baseUrl or appId throws
immediately.
Table client — db.table<T>(name) returns a handle scoped to one table with five methods:
list, get, create, update, delete.
Record — every read or write resolves to a TacticDbRecord<T>:
type TacticDbRecord<T> = {
id: string; // the record's unique id
name: string; // display value derived from the table's display field
isArchived: boolean; // archived records are hidden from normal listings
data: T; // your fields
};API at a glance
| Method | Description |
| --- | --- |
| db.table<T>(name) | Get a table client scoped to name. |
| table.list(options?) | List records. Returns { items, total? }. Default page size is 50. |
| table.get(id) | Fetch one record by id. |
| table.create(data) | Create a record. Generates an id if data.id is absent. |
| table.update(id, data, opts?) | Update a record's fields. |
| table.delete(id, opts?) | Archive a record. |
list options: where, parentId, orderBy, direction ('asc' | 'desc'), skip, take,
includeFields. See docs/querying-records.md.
Error handling
Nothing rejects with a raw fetch error or an unhandled non-2xx response — every failure is a
TacticDbError carrying a machine-readable code, the HTTP status (0 when no response was
received), and optional details and traceId.
import { TacticDbError } from '@tacticdb/client';
try {
await products.get('does-not-exist');
} catch (err) {
if (err instanceof TacticDbError && err.code === 'not_found') {
// handle a missing record
}
}See docs/error-handling.md for the full list of codes.
Documentation
Full guides live in docs/:
- Getting started — install, connect, and make your first call.
- Configuration — every client option, and per-runtime setup.
- Authentication & access — API keys and app access policies.
- Querying records —
listandget, filtering, ordering, paging. - Creating & updating records —
create,update,delete, ids, cancellation. - Error handling —
TacticDbError, codes, and retry patterns. - TypeScript guide — typing records and end-to-end inference.
- Recipes — pagination, relationships, React, server-side usage.
- API reference — every export, signature, and type.
Contributing
npm install
npm run typecheck # tsc --noEmit
npm test # vitest run
npm run build # tsup -> dist/