TypeScript SDK
A typed client over the query surfaces, plus a second client for the control plane. Ships ESM and CommonJS builds with declarations, and runs anywhere there is a fetch.
Install
Node 18 or newer, where fetch is built in. Works with npm, pnpm, yarn and bun.
npm install @originchain/sdkConnect
Two required options. The tenant id is parsed from the first DNS label of the endpoint, so you only pass tenantId for non-standard hostnames or local development. Every request times out after 60 seconds unless you set timeoutMs.
import { OriginChainClient } from "@originchain/sdk";
const db = new OriginChainClient({
baseUrl: process.env.OC_BASE_URL!,
bearer: process.env.OC_BEARER!,
});| Option | Meaning |
|---|---|
| baseUrl | engine endpoint - required, throws if absent |
| bearer | bearer token - required, throws if absent |
| tenantId | override the tenant derived from the hostname |
| timeoutMs | per-request timeout, 60 seconds by default |
| fetch | swap the fetch implementation, for tests or instrumentation |
Query
SQL
const resp = await db.sql(
"SELECT name, price FROM shop.products WHERE price > $1", [500]
);
const one = await db.sqlOne("SELECT count(*) AS n FROM shop.products");Full-text
await db.ftsIndex("shop.products", "name", { pk: "sku-1", text: "Aeron chair" });
const hits = await db.ftsSearch("shop.products", "name", { q: "chair", limit: 10 });Vector
await db.vectorPut("shop.products", { pk: "sku-1", vector: embedding });
const near = await db.vectorTopk("shop.products", { vector: q, k: 10 });
await db.vectorDelete("shop.products", { pk: "sku-1" });Graph
The traversals live on a graph property, not on the client itself:
await db.graph.neighbors("shop", { rel: "bought_with", pk: "sku-1" });
await db.graph.bfs("shop", { rel: "bought_with", pk: "sku-1", depth: 3 });
await db.graph.dijkstra("shop", { rel: "ships_to", from: "a", to: "b" });Schemas, ask and usage
await db.listSchemas();
await db.registerSchema(toml);
await db.ask("which products sold best last week?");
await db.usage();This client has no rows.put equivalent yet - write rows through SQL, or call the row endpoint directly from the HTTP API. The Python client has the helper if you need it today.
The control-plane client
Instances, access, billing and operations live behind a different service and a different client. It is exported from the same package.
import { OriginChainAdminClient } from "@originchain/sdk";
const cp = new OriginChainAdminClient({
baseUrl: "https://api.originchain.ai",
credentials: "omit",
bearer: token,
});
await cp.instances.list();
await cp.instances.setAllowlist(id, entries);
await cp.instances.enablePgwire(id);
await cp.instances.metrics(id, 60, 60);It also covers sign-in and session management, snapshots, point-in-time archives, logs and per-instance schemas. Cookies are sent by default for browser use - pass credentials: "omit" and an explicit bearer from Node.
Errors
Failures throw. The base class carries the status and the parsed body:
| Class | Raised when |
|---|---|
| ApiError | any non-2xx response - has the status and body on it |
| OCAddonRequiredError | the call needs an add-on the account does not have |
| OCPaymentRequiredError | payment is required before the call can proceed |
import { ApiError } from "@originchain/sdk";
try {
await db.sql("SELECT 1");
} catch (e) {
if (e instanceof ApiError && e.status === 429) await backOff();
else throw e;
}Retries and idempotency
Every mutating request gets a generated Idempotency-Key header, and the engine caches the result server-side. This client does not retry for you - it applies the per-request timeout and throws.
So write the loop yourself. Because the key travels with the request, a retry of the same call collapses into the original write rather than duplicating it. Set the header explicitly when a retry must survive a process restart.
Source
npm install @originchain/sdk · originchain-ai/originchain-typescript · the HTTP API underneath