TypeScript SDK
Idiomatic Node.js and TypeScript client for InferaDB.
Coming soon. The TypeScript SDK is under active development. The API surface shown here is based on the Rust SDK and may change before release.
Fully typed async client for InferaDB. Works with Node.js 18+, Bun, and Deno.
Installation
npm install @inferadb/sdk
Authentication
Three authentication methods:
| Method | Use Case | Security |
|---|---|---|
| Client Credentials (Ed25519 JWT) | Service-to-service | High |
| Bearer Token | User sessions, OAuth | Medium |
| API Key | Testing, simple integrations | Basic |
Client Credentials (Recommended)
import { InferaDB, Ed25519PrivateKey } from "@inferadb/sdk";
async function main() {
const client = new InferaDB({
url: "https://engine.inferadb.com",
credentials: {
clientId: "my-client",
privateKey: await Ed25519PrivateKey.fromPemFile("client.pem"),
certificateId: "cert-id",
},
});
}
Bearer Token
const client = new InferaDB({
url: "https://engine.inferadb.com",
token: process.env.INFERADB_TOKEN,
});
API Key
const client = new InferaDB({
url: "https://engine.inferadb.com",
apiKey: process.env.INFERADB_API_KEY,
});
Permission Checks
const vault = client.organization("my-org").vault("production");
const allowed = await vault.check("user:alice", "can_edit", "document:readme");
With ABAC Context
// Context keys are schema-defined
const allowed = await vault.check("user:alice", "can_view", "document:readme", {
context: { ip_address: "10.0.0.1" },
});
Require — Throws on Deny
// Throws AccessDeniedError if permission is denied
await vault.require("user:alice", "can_edit", "document:readme");
With Consistency Token
const allowed = await vault.check("user:alice", "can_view", "document:readme", {
atLeastAsFresh: revisionToken,
});
Batch Check
const results = await vault.checkBatch([
{ subject: "user:alice", permission: "can_edit", resource: "document:readme" },
{ subject: "user:bob", permission: "can_view", resource: "document:readme" },
]);
if (results.allAllowed()) {
// all checks passed
}
Relationships
Write
// Returns a revision token
const token = await vault.relationships.write({
resource: "document:readme",
relation: "editor",
subject: "user:alice",
});
Batch Write
await vault.relationships.writeBatch([
{ resource: "document:readme", relation: "editor", subject: "user:alice" },
{ resource: "document:readme", relation: "viewer", subject: "user:bob" },
]);
List
const rels = await vault.relationships
.list({ resource: "document:readme" })
.collect();
Delete
await vault.relationships.deleteWhere({
resource: "document:readme",
relation: "viewer",
subject: "user:bob",
});
Lookups
// What resources can Alice view?
const resources = await vault.resources
.accessibleBy("user:alice")
.withPermission("can_view")
.resourceType("document")
.collect();
// Who can edit this document?
const subjects = await vault.subjects
.withPermission("can_edit")
.onResource("document:readme")
.collect();
Testing
MockClient (Fastest)
Stub specific check results. Call assertExpectations() to verify all stubs were hit.
import { MockClient } from "@inferadb/sdk/testing";
const client = new MockClient()
.onCheck("user:alice", "can_edit", "document:readme").allow()
.onCheck("user:bob", "can_edit", "document:readme").deny()
.onCheckAnySubject("can_view", "document:readme").allow()
.defaultDeny();
client.assertExpectations();
InMemoryClient (Full Policy Evaluation)
import { InMemoryClient } from "@inferadb/sdk/testing";
const client = await InMemoryClient.withSchemaAndData(
`
type document {
relation viewer
relation editor
relation can_view = viewer | editor
}
`,
[
{ resource: "document:readme", relation: "editor", subject: "user:alice" },
{ resource: "document:readme", relation: "viewer", subject: "user:bob" },
],
);
TestVault (Real Instance)
Auto-cleans up on dispose. Call vault.preserve() to keep data for debugging.
import { TestVault } from "@inferadb/sdk/testing";
const vault = await TestVault.create(org, { schema: schemaIpl });
Error Handling
import { AccessDeniedError, InferaDBError } from "@inferadb/sdk";
try {
await vault.require("user:alice", "can_edit", "document:readme");
} catch (error) {
if (error instanceof AccessDeniedError) {
// permission denied
} else if (error instanceof InferaDBError) {
if (error.isRetriable) {
// retry after error.retryAfter milliseconds
}
console.error(error.kind, error.requestId);
}
}
ErrorKind values: "unauthorized", "forbidden", "not_found", "rate_limited", "schema_violation", "unavailable", "timeout", "invalid_argument".
Framework Integrations
Express Middleware
import { inferadbMiddleware } from "@inferadb/sdk/express";
app.use(
"/api/documents/:id",
inferadbMiddleware(vault, {
subject: (req) => `user:${req.user.id}`,
resource: (req) => `document:${req.params.id}`,
permission: (req) => (req.method === "GET" ? "can_view" : "can_edit"),
}),
);
Next.js
import { withAuthorization } from "@inferadb/sdk/next";
export const GET = withAuthorization(vault, {
subject: (req) => `user:${req.auth.userId}`,
resource: (req) => `document:${req.nextUrl.searchParams.get("id")}`,
permission: "can_view",
})(async (req) => {
return Response.json({ data: "authorized content" });
});