TraceDB TypeScript Client And SDK
TraceDB is an AI-native transactional candidate-stream database. One logical record. One commit epoch. Many native views. No external sync drift. Explain every candidate.
This repository is the standalone TraceDB TypeScript SDK package. It is pinned to `platform-contract-v0` through `tracedb-protocol.lock`; update that lock only when this SDK has been checked against a newer protocol revision.
Current checkpoint status: the package is tagged `v0.1.0` and npm publish is pending org/scope setup. It is not yet available on the public npm registry.
This directory contains the package-shaped TraceDB public TypeScript SDK plus a generated, dependency-free TypeScript `fetch` transport for the current TraceDB v1 HTTP API. It targets the current TraceDB HTTP product surface. TraceField runtime work, Agent Memory Flight Recorder, and tensor artifacts are future research/demo or governed-module directions, not current TypeScript SDK claims.
The transport is generated from `docs/api/v1-openapi.json` and is checked in so product smokes and examples can import a stable artifact. The package metadata now exposes `@tracedb/sdk` as the public SDK entrypoint and `@tracedb/sdk/transport` as the raw generated transport subpath. This is package metadata and local smoke coverage, not evidence that the package has been published to npm and not a managed-cloud SDK promise.
The public wrapper exports `VERSION` (`"0.1.0"`) from `@tracedb/sdk`, and the generated transport sends `User-Agent: tracedb-js/0.1.0` on HTTP requests unless a caller overrides that header in per-request options.
The source public entrypoint is `src/index.ts`, which re-exports the wrapper in `src/sdk.ts`; `npm run build` emits the package entrypoint at `dist/index.js` with declarations at `dist/index.d.ts`. That wrapper intentionally uses the generated `TraceDbClient` as its transport layer instead of duplicating HTTP routes. Current public DX starts with `new TraceDB({ url, token })` or `TraceDB.fromEnv()`, table handles, record writes, raw-contract batch ingest, row-oriented batch ingest, patch, scan/get/delete, admin compact/snapshot/restore, and a query builder that compiles to the canonical `HybridQuery` body. The wrapper also exposes native TraceQL execution through `TraceDB.traceql(query)` and `TraceDB.traceqlRequest({ query })` over the generated `/v1/traceql` transport method, generated GraphQL SDL export through `TraceDB.graphqlSchema()` over the generated `/v1/graphql/schema` transport method, plus bounded GraphQL query execution through `TraceDB.graphql(query)` and `TraceDB.graphqlRequest({ query })` over the generated `/v1/graphql` transport method. The raw generated transport also exposes `graphqlSchema()` for direct `GET /v1/graphql/schema` callers; that route exports SDL generated from applied TraceDB table schema and is not a GraphQL resolver runtime.
The generated artifact also emits TypeScript aliases from the OpenAPI component schemas and uses them in method signatures. These aliases intentionally preserve the API's permissive `additionalProperties` boundary: known fields are optional, unknown JSON fields remain allowed, and runtime validation stays server-side. They are compile-time ergonomics for the current HTTP API, not strict domain validators. The generated `RecordPutBody` alias mirrors current server behavior: `putRecord` accepts either `RecordInput` directly or `{ record: RecordInput }`. `GetRecordResponse.record` is typed as `RecordOutput | null`, and `RecordOutput` exposes the server's serialized `version_id` field. `HybridQuery` now explicitly includes the current JSON request fields `scalar_eq`, `graph_seed`, and `temporal_as_of`. The scan, query, and explain response aliases now expose current server fields for `RecordScanOutput.records`, `RecordScanOutput.returned_count`, `QueryResponse.results`, optional `QueryResponse.explain`, `HybridQueryRow`, `HybridScoreComponents`, access-path explain entries, planner candidates, and timing entries. Those fields are still optional compile-time helpers rather than strict runtime validators.
Regenerate or check it from the canonical OpenAPI generator until the generator is migrated into this standalone repo:
python3 ../tracedb/scripts/generate_typescript_client.py
python3 ../tracedb/scripts/generate_typescript_client.py --checkRun the local dependency-free Node smoke from the standalone repo root:
node --experimental-strip-types smoke.ts
npm run build
npm run public-smokeThe smoke imports `src/client.ts`, uses a fake `fetchImpl`, verifies generated schema aliases typecheck in representative schema, batch, query, and admin calls, verifies GET routes send no body, verifies POST routing metadata is added without mutating caller objects, verifies explicit `database_id` / `branch_id` request fields win, checks `Idempotency-Key`, and checks `TraceDbHttpError` method/path/status/body context plus parsed JSON error-envelope fields, including stable machine-readable error `code` exposed as `responseCode` when present. It also verifies the client rejects empty or CR/LF-containing idempotency keys as `TraceDbRequestError` before `fetchImpl` is called, and verifies current scan/query/explain response aliases typecheck. It also typechecks the read-only product response aliases for health, readiness, database catalog, branch catalog, public-safe metrics, and admin jobs. This is runtime smoke coverage for the checked artifact, not a package publishing pipeline.
The public SDK smoke imports `src/sdk.ts` and verifies the first table/query wrapper layer against a fake transport. It checks `TraceDB.fromEnv()` for `TRACEDB_URL`, `TRACEDB_TOKEN`, `TRACEDB_DATABASE_ID`, `TRACEDB_BRANCH_ID`, and `TRACEDB_TIMEOUT_MS`, verifies `TRACEDB_SAFE_RETRIES` retries transient 5xx responses only for read-only routes, verifies `TRACEDB_IDEMPOTENCY_RETRIES` retries transient 5xx responses only for keyed mutation/admin routes, and then checks table-scoped `insert`, raw-contract `insertBatch`, row-oriented `insertRows`, `patch`, `get`, `scan`, `delete`, admin compact/snapshot/restore, and query-builder chaining via `where({ tenant_id })`, `match`, `near`, `with`, `limit`, `all`, and `explainPlan`. It also checks `TraceDB.traceql()` request shape, read-only safe retries for native TraceQL, and no unsafe retry for mutating TraceQL without `Idempotency-Key`; `TraceDB.graphqlSchema()` response decoding plus read-only safe retries for the generated SDL route; `TraceDB.graphql()` request shape, read-only safe retries for native GraphQL, and no unsafe retry for mutating GraphQL without `Idempotency-Key`; and missing-tenant validation raises `TraceDbRequestError` before `fetchImpl` is called. This is public-DX smoke coverage over the generated transport, not publishing readiness or managed-cloud proof.
The package entry smoke imports from `@tracedb/sdk` and `@tracedb/sdk/transport` through the package `exports` map and verifies the public SDK entrypoint, generated transport subpath, representative type exports, config error shape, emitted JS files, emitted declarations, dry-run package contents, and clean temp-project tarball installation:
npm run build
npm run package-smoke
npm run pack-dry-run
npm run consumer-smokeRun the real local HTTP smoke from the standalone repo root:
npm run http-smokeThe HTTP smoke starts a local `tracedb-server` child process with an isolated temporary data directory, using `TRACEDB_CORE_REPO` when set or sibling `../tracedb` from the standalone repo root by default. It waits for readiness, then drives the generated client through health, catalog, metrics, schema apply, direct put, batch ingest, get, scan, query, explain, delete, compact, snapshot, restore, and admin jobs. It emits a JSON summary and `typescript client http smoke ok`. This is local loopback product evidence for the generated artifact, not a package publishing pipeline, managed-cloud health, or benchmark evidence.
Run the public SDK wrapper against a real local HTTP server:
npm run public-http-smoke
npm run public-http-smoke -- --summary-json /tmp/tracedb-typescript-sdk-smoke.jsonThe public HTTP smoke starts a local `tracedb-server` child process with an isolated temporary data directory, using `TRACEDB_CORE_REPO` when set or sibling `../tracedb` from the standalone repo root by default. It waits for readiness, then drives `TraceDB` and table handles through health, catalog, metrics, schema apply, insert, row batch ingest, raw-contract batch ingest, patch, get, scan, query, GraphQL schema export, native TraceQL result/explain, bounded GraphQL result/explain, explain, delete, idempotency replay/conflict, parsed error envelopes, compact, snapshot, restore, and admin jobs. It emits a JSON summary and `typescript public sdk http smoke ok`. This is local loopback product evidence for the public wrapper over the generated transport and is the input for:
python3 scripts/platform_conformance.py --surface typescript_sdk --summary-json /tmp/tracedb-typescript-sdk-conformance.jsonThis is local loopback conformance evidence for the public wrapper over the generated transport, not package publishing readiness, managed-cloud health, or benchmark evidence.
Run the endpoint quickstart against an existing HTTP endpoint:
TRACEDB_URL=http://127.0.0.1:8090 TRACEDB_TOKEN=dev-token npm run quickstartOptional routing metadata can be supplied with `TRACEDB_DATABASE_ID` and `TRACEDB_BRANCH_ID`. Optional local admin coverage can be enabled with `TRACEDB_ADMIN_DIR=/absolute/server/side/path`; that path is interpreted by the TraceDB server process and is intended for local scratch use. Without `TRACEDB_ADMIN_DIR`, the quickstart still checks readiness, health, catalog, metrics, schema apply, batch ingest, patch, patched visibility, scan, query, explain, delete, and admin jobs. With `TRACEDB_ADMIN_DIR`, it also compacts, snapshots, and restores to a separate directory. The quickstart emits a JSON summary and `typescript client endpoint quickstart ok`. It is an endpoint example for the generated artifact, not package publishing readiness, not managed-cloud support, not SQL compatibility, and not benchmark evidence.
Run the public TypeScript SDK wrapper through a local gateway that requires a bearer token and routes by database/branch metadata:
npm run gateway-smokeThe gateway smoke starts a local engine plus `tracedb-gateway` mode from `TRACEDB_CORE_REPO` when set or sibling `../tracedb` from the standalone repo root by default, with `TRACEDB_REQUIRE_API_KEY=true`, `TRACEDB_API_TOKEN=dev-token`, and `TRACEDB_ENGINE_URL` pointing at the engine. It then runs `new TraceDB({ url, token, databaseId, branchId })` through schema apply, insert, batch, patch, get, scan, query, explain, native TraceQL, GraphQL SDL export, bounded GraphQL query execution, delete, compact, snapshot, restore, jobs, missing-token rejection, and bad-branch rejection. It emits `typescript public sdk gateway smoke ok`. This proves bearer-auth forwarding and database/branch metadata on the public wrapper against the local gateway path; it is still not managed-cloud proof or benchmark evidence.
The repo-level local product regression gate also runs this generated client surface:
cargo run -p tracedb-cli -- product-regression
cargo run -p tracedb-cli -- product-quickstartThat gate runs `npm run check`, `npm run public-http-smoke`, and `npm run gateway-smoke` as local product regression evidence only. It does not claim package publishing readiness, SQL compatibility, managed-cloud proof, or benchmark results. Test-only `--inject-failure STEP` can validate failed-step JSON, top-level `human_summary`, and nonzero gate behavior without weakening this TypeScript smoke path. `--report-file PATH` writes the same product-regression JSON summary to a predictable file while preserving stdout. That option belongs to the repo-level product-regression gate, not the TypeScript package scripts themselves. `product-quickstart` is the same repo-level gate with a default report file at `target/tracedb/product-quickstart.json`. Use `product-regression --list-steps` to discover the TypeScript smoke step names plus `human_summary` and `only_supported` metadata without invoking Node tooling. The current `--only embedded_demo` mode and dependency-aware `--only embedded_verify` mode do not run the TypeScript smoke steps. `--only http_demo` also does not run the TypeScript smoke steps; it is limited to the self-contained local HTTP demo step. `--only local_doctor` also does not run the TypeScript smoke steps; it is limited to local endpoint diagnostics against a managed local server. `--only rust_sdk_quickstart` also does not run the TypeScript smoke steps; it is limited to local Rust SDK quickstart verification against a managed local server. `--skip-typescript` is for the full product gate and non-TypeScript selectors; a TypeScript `--only` selector conflicts with --skip-typescript. `--only typescript_check` runs only `npm run check`, which currently performs the package typecheck plus dependency-free generated-client, public SDK, package build, package-entry smoke, pack dry-run, and packed temp-consumer install checks. It does not run `http-smoke`, `gateway-smoke`, `http_demo`, local `doctor http`, the Rust SDK quickstart, managed-cloud checks, benchmark controls, or SQL compatibility checks. `--only typescript_http_smoke` runs only `npm run public-http-smoke`, which starts its own local `tracedb-server` child process and exercises the public TypeScript SDK wrapper over the generated transport. It does not run embedded demo/verify, `http_demo`, local `doctor http`, the Rust SDK quickstart, `typescript_check`, generated-transport `http-smoke`, TypeScript gateway smoke, managed-cloud checks, benchmark controls, or SQL compatibility checks. `--only typescript_gateway_smoke` runs only `npm run gateway-smoke`, which starts a local engine plus gateway-mode server, requires bearer auth, checks missing-token and bad-branch rejection, and runs the public TypeScript SDK wrapper through the gateway with `databaseId=db_local`, `branchId=db_local:main`, and a local admin scratch dir, including native TraceQL, GraphQL SDL export, and bounded GraphQL query execution. It does not run embedded demo/verify, `http_demo`, local `doctor http`, the Rust SDK quickstart, `typescript_check`, `http-smoke`, managed-cloud checks, benchmark controls, or SQL compatibility checks.
Install the local package tooling and run the package boundary:
npm ci
npm run typecheck
npm run smoke
npm run public-smoke
npm run build
npm run package-smoke
npm run pack-dry-run
npm run consumer-smoke
npm run http-smoke
npm run public-http-smoke
npm run quickstart
npm run gateway-smoke
npm run checkThe package is named `@tracedb/sdk`, exposes `.` as the public SDK and `./transport` as the generated transport subpath, declares `main`, `types`, `files`, and npm package metadata, and emits `dist/index.js`, `dist/index.d.ts`, `dist/sdk.js`, `dist/sdk.d.ts`, `dist/client.js`, and `dist/client.d.ts`. `npm run pack-dry-run` proves the tarball contents without publishing, and `npm run consumer-smoke` packs into a temporary directory, installs that tarball into a clean temporary project, and imports `@tracedb/sdk` plus `@tracedb/sdk/transport` from the installed package. This is package-ready metadata plus local build/pack/install smoke coverage, not a published npm artifact or a release pipeline.
Install
npm install @tracedb/sdk> **Note:** The package is tagged `v0.1.0` and npm publish is pending org/scope > setup. It is not yet available on the public npm registry.
> **ESM only** — this package is shipped as an ES module (`"type": "module"`). > It requires Node.js 18 or later and cannot be `require()`'d from CommonJS.
Local Usage
import { TraceDB, type TableSchema } from "@tracedb/sdk";
const db = new TraceDB({
url: "http://127.0.0.1:8090",
token: "dev-token",
});
const schema: TableSchema = {
name: "docs",
primary_id_column: "id",
tenant_id_column: "tenant",
scalar_columns: ["status"],
text_indexed_columns: ["body"],
vector_columns: [{ name: "embedding", dimensions: 3, source_columns: ["body"] }],
};
await db.ready();
await db.applySchema(schema);
const docs = db.table("docs").tenant("tenant-a");
await docs.insert("a", { body: "hello", embedding: [1, 0, 0] });
await docs.insertRows([
{ id: "b", body: "row batch", embedding: [0, 1, 0], status: "published" },
]);
await docs.insertBatch([
{ id: "c", fields: { body: "raw batch", embedding: [0, 0, 1] } },
]);
const result = await db
.table("docs")
.where({ tenant_id: "tenant-a", status: "published" })
.match("body", "hello")
.near("embedding", [1, 0, 0])
.with({ explain: true, freshness: "lazy" })
.limit(20)
.all();
console.log(result.results);The public query builder sends `match("body", ...)` as `HybridQuery.text_field = "body"` and `near("embedding", ...)` as `HybridQuery.vector_field = "embedding"`, so multi-text and multi-vector schemas do not lose the selected field at the SDK boundary. It also canonicalizes `strict`, `lazy`, and `allow_dirty` freshness inputs to the `Strict`, `Lazy`, and `AllowDirty` wire modes used by direct HTTP, TraceQL, and the bounded GraphQL adapter.
The generated transport remains available for raw route access:
import { TraceDbClient } from "@tracedb/sdk/transport";Database/Branch Routing Metadata
When `databaseId` or `branchId` is configured, the client copies object-shaped POST bodies and adds `database_id` and `branch_id` only when those root fields are absent. If `databaseId` is configured and `branchId` is omitted, copied POST bodies default `branch_id` to `<database_id>:main`. Explicit request fields win. GET routes send no JSON body.
const managedClient = new TraceDbClient({
baseUrl: "http://127.0.0.1:8090",
token: "dev-token",
databaseId: "local",
branchId: "main",
});
await managedClient.putBatch({
records: [
{
table: "docs",
id: "a",
tenant_id: "tenant-a",
fields: { id: "a", tenant: "tenant-a", body: "hello" },
},
],
});Idempotency Boundary
Mutation and admin methods accept `TraceDbRequestOptions.idempotencyKey`, which sends `Idempotency-Key`. Current TraceDB support is local data-dir replay from WAL/checkpoint-backed idempotency receipts for mutation/admin routes and survives a clean engine reopen from the same data directory. It is not cross-replica, not crash-atomic exactly-once, and not managed-cloud exactly-once semantics. The generated client rejects empty or CR/LF-containing idempotency keys before network I/O with `TraceDbRequestError`. The public wrapper's `safeRetries` / `TRACEDB_SAFE_RETRIES` setting is separate: it retries transient HTTP 5xx responses only for health/ready, GraphQL schema export, get, scan, query, bounded GraphQL, explain, and polymorphic native TraceQL/GraphQL payloads that the SDK can classify as read-only. It does not retry mutating TraceQL/GraphQL commands/root fields or other write/admin mutations without an idempotency key. The public wrapper's `idempotencyRetries` / `TRACEDB_IDEMPOTENCY_RETRIES` setting is also default-off. It retries transient HTTP 5xx responses for mutation/admin routes, including mutating native TraceQL/GraphQL payloads, only when the individual request carries a validated `Idempotency-Key`; it does not retry unkeyed writes or 4xx/409 responses.
await client.deleteRecord(
{ table: "docs", tenant_id: "tenant-a", id: "a", tombstone: "user_delete" },
{ idempotencyKey: "delete-a-1" },
);SQL compatibility is not implemented. Internal TraceDB-only runs are development evidence; exported performance claims require an external control and a number to beat.