Reference
SDK Cheat Sheet
One-page reference for common Onyx SDK calls. Select a language to see the syntax.
Onyx Environment Variables
Set these to control how the SDK scopes requests and where it fetches credentials.
| Env Var | Description | Default |
|---|---|---|
| ONYX_DATABASE_ID | Database UUID used to scope requests; required. | none |
| ONYX_DATABASE_BASE_URL | HTTP base for DB API. | https://api.onyx.dev |
| ONYX_DATABASE_API_KEY | API key for the database; required. | none |
| ONYX_DATABASE_API_SECRET | API secret for the database; required. | none |
| ONYX_AI_BASE_URL | Base URL for AI/chat endpoints. | https://ai.onyx.dev |
| ONYX_DEFAULT_MODEL | Model used by db.chat() shorthand. | onyx |
| ONYX_CONFIG_PATH | Path to JSON credentials file (Node only; ignored on edge). Falls back to project/home files after env vars. | unset |
| ONYX_DEBUG | When "true", enables request/response logging and config debug output. | false |
| ONYX_STREAM_DEBUG | When "true"/"1", logs streaming connection details. | false |
Initialization Patterns
Initialize the SDK with typed configuration.
Auto resolution
Resolution order: env vars → ONYX_CONFIG_PATH file → ./onyx-database.json (default locations).
import { onyx } from "@onyx.dev/onyx-database";
import { Schema, tables } from "./generated/onyx/types";
const db = onyx.init<Schema>();
Initialize with config object
Pass credentials directly when you can’t rely on env/file resolution.
import { onyx } from "@onyx.dev/onyx-database";
import { Schema, tables } from "./generated/onyx/types";
const db = onyx.init<Schema>({
apiKey: process.env.ONYX_DATABASE_API_KEY,
apiSecret: process.env.ONYX_DATABASE_API_SECRET,
});
Optional config fields
| Attribute | Description | Default |
|---|---|---|
| baseUrl | REST base URL for database operations. | https://api.onyx.dev |
| databaseId | Database ID. Usually inferred from DB-scoped API keys; set for org-wide keys. | resolved from API key |
| aiBaseUrl | Base URL for AI endpoints. | https://ai.onyx.dev |
| fetch | Custom fetch implementation (useful in non-Node runtimes). | global fetch |
| defaultModel | Fallback AI model when using shorthand chat calls. | onyx |
| partition | Default partition for queries, findById, and deletes. | none (use entity partition) |
| requestLoggingEnabled | Log HTTP requests and bodies to console. | false |
| responseLoggingEnabled | Log HTTP responses and bodies to console. | false |
| ttl | Milliseconds to cache resolved credentials. | 300000 (5 minutes) |
| retry | Retry configuration for idempotent GET requests (honors Retry-After). | enabled; 3 retries; backoff 300/600/1200ms |
- Typed vs. Untyped ClientsFor full IntelliSense and type safety, run
onyx genand initialize withonyx.init<Schema>(). Only use the untypedonyx.init()for quick prototyping. - Retry LogicIdempotent GET requests automatically retry 3 times with exponential backoff (300ms → 1.2s) and honor
Retry-Afterheaders. You can override defaults via theretryconfig object. - Performance & CachingConfig resolves once (Env → File → Defaults) and caches per
databaseId-apiKeyfor 5 minutes. Always reuse the client instance to utilize the cache. Clear manually viaonyx.clearCacheConfig().
Core CRUD
Upsert, fetch, update, and delete entities by primary key.
import { onyx } from "@onyx.dev/onyx-database";
import { Schema, tables, Account } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const account: Account = {
id: "acct_1",
name: "Checking",
balance: 1250,
};
await db.save(tables.Account, account);
const fetched = await db.findById(tables.Account, "acct_1");
await db.save(tables.Account, { ...account, balance: 1400 });
await db.delete(tables.Account, "acct_1");
TypeScript return types
onyx.init<Schema>(): IOnyxDatabase<Schema> db.save(tables.Account, account): Promise<Account> db.findById(tables.Account, id): Promise<Account | null> db.save(tables.Account, partialAccount): Promise<Account> // upsert db.delete(tables.Account, id): Promise<boolean>
Atomic Saving
Persist a parent plus related records in one call—no explicit transactions needed; the graph commits all-or-none.
Cascade save
Tell Onyx which related collection to save with the parent. Format: field:RelatedTable(targetField, sourceField). Assumes db is already initialized and tables is imported.
const accountWithTransactions = {
id: "acct_1",
name: "Primary",
balance: 0,
transactions: [
{ id: "txn_1", accountId: "acct_1", amount: 250, currency: "USD" },
{ id: "txn_2", accountId: "acct_1", amount: 125, currency: "USD" },
],
};
const savedAccount = await db
.cascade("transactions:Transaction(accountId, id)")
.save(tables.Account, accountWithTransactions);Cascade builder
Fluent builder emits the same cascade string; helpful when composing or reusing mappings.
const txRel = db
.cascadeBuilder()
.graph("transactions")
.graphType("Transaction")
.targetField("accountId")
.sourceField("id");
const cascadeString = String(txRel);
console.log("cascade string:", cascadeString); // transactions:Transaction(accountId, id)Cascade string syntax
<field>:<RelatedTable>(<targetField>, <sourceField>) — field: property on the parent holding related rows; RelatedTable: table to upsert; targetField: FK on the related table; sourceField: parent field to copy.
TypeScript return types
onyx.init<Schema>(): IOnyxDatabase<Schema>
db.cascade(...): ICascadeBuilder<Schema>
db.cascade(...).save(tables.Account, entity): Promise<Account>
db.cascadeBuilder(): ICascadeRelationshipBuilder
cascadeBuilder().graph(...).graphType(...).targetField(...).sourceField(...): string
db.from(tables.Account): IQueryBuilder<Account>
resolve("transactions.lineItems"): IQueryBuilder<Account>
firstOrNull(): Promise<Account | null>Resolvers
Hydrate schema-defined relations inline to avoid extra round trips; resolvers are declared in your generated schema.
Fetch by id with resolver
Load a record and its related resolver in one call.
import { tables } from "./generated/onyx/types";
const tx = await db.findById(tables.Transaction, "txn_123", { resolvers: ["account"] });Query with resolver
Include related data while filtering the base table.
import { eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const transactionsWithAccounts = await db
.from(tables.Transaction)
.where(eq("status", "posted"))
.resolve("account")
.list();Filter by resolver field
Filter using fields exposed by the resolver.
import { eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const primaryAccountTransactions = await db
.from(tables.Transaction)
.where(eq("account.name", "Primary"))
.resolve("account")
.list();Resolver names match the resolvers entries in your schema (e.g., a Transaction → account relation). They’re generated into the typed client so you can request related data without manual joins.
TypeScript return types
findById(..., { resolvers }): Promise<Transaction | null>
resolve("account"): IQueryBuilder<Transaction>
where(eq("account.name", ...)): IQueryBuilder<Transaction>
list(): QueryResultsPromise<Transaction>Bulk Save
Insert many records efficiently by passing an array to save.
import { tables } from "./generated/onyx/types";
const transactions = [
{ id: "txn_batch_1", accountId: "acct_batch", amount: 1.99, currency: "USD" },
{ id: "txn_batch_2", accountId: "acct_batch", amount: 12.5, currency: "USD" },
{ id: "txn_batch_3", accountId: "acct_batch", amount: 45.0, currency: "USD" },
{ id: "txn_batch_4", accountId: "acct_batch", amount: 7.25, currency: "USD" },
];
await db.save(tables.Transaction, transactions);TypeScript return types
db.save(tables.Transaction, transactions): Promise<Transaction[]>
Query & Filter
Boolean filters, ranges, text contains, ordering, and limits.
import { eq, gt, gte, contains, desc } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const transactions = await db
.from(tables.Transaction)
.where(
eq("status", "posted")
.and(gt("amount", 100))
.and(gte("createdAt", "2025-01-01"))
.and(contains("merchant", "aws"))
)
.orderBy(desc("createdAt"))
.limit(25)
.list();
Defaults: if you omit limit() and pageSize, the API uses its server-side default page size (capped at 1000); responses include nextPage when more rows remain.
TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
eq()/gt()/gte()/contains(): ConditionBuilderImpl (IConditionBuilder)
where(...): IQueryBuilder<Transaction>
orderBy(desc("createdAt")): IQueryBuilder<Transaction>
limit(25): IQueryBuilder<Transaction>
list(): QueryResultsPromise<Transaction> // await -> QueryResults<Transaction> & Transaction[]Query clauses
| Clause | Signature | What it does |
|---|---|---|
| where | where(condition) | Sets the primary filter. |
| and | and(condition) | Adds an additional filter with AND. |
| or | or(condition) | Adds an additional filter with OR. |
| orderBy | orderBy(asc/desc(...)) | Sorts results by one or more fields. |
| groupBy | groupBy(...fields) | Groups records for aggregations. |
| distinct | distinct() | Returns only unique rows for selected fields. |
| limit | limit(n) | Caps number of records returned. |
| pageSize | pageSize(n) | Sets page size for list/page calls and streams. |
| inPartition | inPartition("partition") | Scopes the query to a partition. |
| nextPage | nextPage(token) | Continues a paged query using a cursor token. |
Filters
| Helper | Signature | What it does |
|---|---|---|
| eq | eq("field", value) | Equals. |
| neq | neq("field", value) | Not equals. |
| gt | gt("field", value) | Greater than. |
| gte | gte("field", value) | Greater than or equal. |
| lt | lt("field", value) | Less than. |
| lte | lte("field", value) | Less than or equal. |
| between | between("field", low, high) | Inclusive range. |
| like | like("field", pattern) | SQL-like match (%, _). |
| notLike | notLike("field", pattern) | Negated SQL-like match. |
| matches | matches("field", regex) | Regex match. |
| notMatches | notMatches("field", regex) | Regex does not match. |
| contains | contains("field", text) | Substring contains (case-sensitive). |
| containsIgnoreCase | containsIgnoreCase("field", text) | Substring contains (case-insensitive). |
| notContains | notContains("field", text) | Does not contain (case-sensitive). |
| notContainsIgnoreCase | notContainsIgnoreCase("field", text) | Does not contain (case-insensitive). |
| startsWith | startsWith("field", text) | Prefix match. |
| notStartsWith | notStartsWith("field", text) | Not prefix match. |
| inOp | inOp("field", values) | Field in list of values. |
| notIn | notIn("field", values) | Field not in list of values. |
| within | within("field", subquery) | Field in subquery results. |
| notWithin | notWithin("field", subquery) | Field not in subquery results. |
| isNull | isNull("field") | Field is null. |
| notNull | notNull("field") | Field is not null. |
Select Query
Pick specific columns to return from a table.
import { eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const rows = await db
.select("id", "accountId", "amount", "createdAt")
.from(tables.Transaction)
.list();TypeScript return types
select("id","accountId",...): IQueryBuilder<Pick<Transaction, "id" | "accountId" | "amount" | "createdAt">>
from(tables.Transaction): IQueryBuilder<...>
where(eq(...)): IQueryBuilder<...>
orderBy(desc("createdAt")): IQueryBuilder<...>
limit(20): IQueryBuilder<...>
list(): QueryResultsPromise<Pick<Transaction, "id" | "accountId" | "amount" | "createdAt">>First or Null
When you expect a single row, use firstOrNull() or its alias one().
import { eq } from "@onyx.dev/onyx-database";
import { Schema, tables } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const tx = await db
.from(tables.Transaction)
.where(eq("id", "txn_123"))
.firstOrNull();
const txAlt = await db
.from(tables.Transaction)
.where(eq("id", "txn_123"))
.one();TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
where(eq("id", ...)): IQueryBuilder<Transaction>
firstOrNull(): Promise<Transaction | null>
one(): Promise<Transaction | null>Inner Queries
Filter a table using sub-selects returned from another query.
import { onyx, within, gt } from "@onyx.dev/onyx-database";
import { Schema, tables } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const accountsWithLargeTx = await db
.from(tables.Account)
.where(
within(
"id",
db
.select("accountId")
.from(tables.Transaction)
.where(gt("amount", 1000))
)
)
.list();
TypeScript return types
onyx.init<Schema>(): IOnyxDatabase<Schema>
db.select("accountId"): IQueryBuilder<Transaction>
within("id", subquery): ConditionBuilderImpl
db.from(tables.Account): IQueryBuilder<Account>
where(...): IQueryBuilder<Account>
list(): QueryResultsPromise<Account> // await -> QueryResults<Account> & Account[]Update Query
Set partial updates for all rows matching a condition.
import { eq, gt } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const updated = await db
.from(tables.Transaction)
.where(eq("status", "pending").and(gt("amount", 100)))
.setUpdates({ status: "posted" })
.update();TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
where(...): IQueryBuilder<Transaction>
setUpdates({ status: "posted" }): IQueryBuilder<Transaction>
update(): Promise<unknown>Delete Query
Delete all rows that match a filter.
import { eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const deletedCount = await db
.from(tables.Transaction)
.where(eq("status", "archived"))
.delete();TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
where(eq("status", "archived")): IQueryBuilder<Transaction>
delete(): Promise<number>Group By
Group results by one or more fields to segment metrics.
import { eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const byMerchant = await db
.select("merchant", "currency")
.from(tables.Transaction)
.where(eq("status", "posted"))
.groupBy("merchant", "currency")
.list();
Aggregations
Server-side rollups for dashboards and billing summaries.
import { sum, eq } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const totals = await db
.select(sum("amount"), "merchant")
.from(tables.Transaction)
.where(eq("status", "posted"))
.list();
TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
sum("amount"): string // aggregation expression
select(...): IQueryBuilder<Transaction>
groupBy("merchant"): IQueryBuilder<Transaction>
list(): QueryResultsPromise<Record<string, unknown>> // await -> QueryResults<Record<string, unknown>> & Record<string, unknown>[]Server-side aggregate helpers
| Function | Signature | What it does |
|---|---|---|
| sum | sum("field") | Numeric sum of a column. |
| count | count("field" | "*") | Row count; accepts a field or "*". |
| avg | avg("field") | Arithmetic mean. |
| min | min("field") | Smallest value. |
| max | max("field") | Largest value. |
| median | median("field") | 50th percentile. |
| percentile | percentile("field", p) | p-th percentile; p is 0–100. |
| std | std("field") | Sample standard deviation. |
| variance | variance("field") | Sample variance. |
| upper | upper("field") | Uppercases text for grouping/aggregation. |
| lower | lower("field") | Lowercases text for grouping/aggregation. |
| format | format("field", "pattern") | Apply a Java-style date/number format before grouping (e.g., yyyy-MM). |
| substring | substring("field", from, length) | Substring of text (0-based offset). |
| replace | replace("field", pattern, repl) | Regex/substring replacement prior to grouping. |
| groupBy | groupBy(...fields) | Groups rows by one or more fields before aggregating. |
| select | select(...fields | aggregates) | Choose which columns or aggregate expressions to return. |
| distinct | distinct() | Deduplicate rows on the selected fields before aggregation. |
| resolve | resolve(...relations) | Resolve related values prior to grouping/aggregating. |
Streaming Queries
Consume large result sets incrementally and react to live query responses.
import { onyx, eq } from "@onyx.dev/onyx-database";
import { Schema, tables } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const handle = await db
.from(tables.Transaction)
.where(eq("status", "posted"))
.pageSize(100)
.onItem((tx, action) => {
if (!tx) return;
switch (action) {
case "QUERY_RESPONSE":
console.log("Initial result", tx.id, tx.amount);
break;
case "CREATE":
console.log("Created", tx.id);
break;
case "UPDATE":
console.log("Updated", tx.id);
break;
case "DELETE":
console.log("Deleted", tx.id);
break;
default:
break;
}
})
.stream(true, false);
setTimeout(() => handle.cancel(), 1000);TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
pageSize(100): IQueryBuilder<Transaction>
onItem((tx, action) => ...): IQueryBuilder<Transaction>
stream(includeQueryResults?: boolean, keepAlive?: boolean): Promise<{ cancel(): void }>Stream behavior
- Wire format: newline-delimited JSON over
PUT /data/{db}/query/stream/{table}; the JS client setsincludeQueryResults=trueby default,keepAlive=falseunless you opt in. includeQueryResultssends the initial snapshot asQUERY_RESPONSElines; setfalseto receive only live changes.keepAlivekeeps the connection open for future mutations and emitsKEEP_ALIVEheartbeats ~every 10s;falsecloses after the initial batch.- Actions delivered:
QUERY_RESPONSE,CREATE,UPDATE,DELETE,KEEP_ALIVE. - Server flushes frequently (every ~200ms or 32KiB) and runs with
Connection: keep-alive; callcancel()on the handle to detach listeners and close cleanly.
Full-Text Search
Lucene-style search across tables marked SEARCHABLE in your schema.
All searchable tables
Runs across every table marked SEARCHABLE in your schema (optionally set a minimum score).
const hits = await db
.search("error AND status:active", 4.0)
.limit(50)
.list();Table-scoped search with minScore
Scopes search to a single table and applies a score threshold.
const hits = await db
.from(tables.Transaction)
.search('status:posted AND merchant:"AWS"', 4.4)
.list();Using from(tables.Transaction) limits the Lucene query to that table only; without it the query runs across all SEARCHABLE tables.
TypeScript return types
db.search(text): IQueryBuilder<Record<string, unknown>> from(tables.Transaction): IQueryBuilder<Record<string, unknown>> limit(50): IQueryBuilder<Record<string, unknown>> list(): QueryResultsPromise<Record<string, unknown>> // await -> QueryResults<Record<string, unknown>> & Record<string, unknown>[]
Pagination
Page through ordered results with stable cursors (offset-free).
import { desc } from "@onyx.dev/onyx-database";
import { tables } from "./generated/onyx/types";
const page1 = await db
.from(tables.Transaction)
.orderBy(desc("createdAt"))
.list({ pageSize: 50 });
const page2 = page1.nextPage
? await db.from(tables.Transaction).nextPage(page1.nextPage).list()
: null;
if (page2) {
console.log("page2 size", page2.length, "next token", page2.nextPage);
}
TypeScript return types
from(tables.Transaction): IQueryBuilder<Transaction>
orderBy(...): IQueryBuilder<Transaction>
list({ pageSize: 50 }): QueryResultsPromise<Transaction> // await -> QueryResults<Transaction> & Transaction[]
await list result -> { nextPage?: string }
nextPage(token): IQueryBuilder<Transaction>
list(): QueryResultsPromise<Transaction>AI Chat
Use the AI endpoint to answer questions that reference your data.
Chat completions
Control model, messages, streaming/raw response options.
const response = await db.ai.chat(
{
model: "onyx",
messages: [
{ role: "system", content: "You are a finance assistant. Respond with 3 concise bullet points." },
{ role: "assistant", content: "I summarize trends and call out anomalies each Friday." },
{ role: "user", content: "Draft a status update for finance stakeholders." },
],
stream: false,
},
{ raw: true }
);Streaming chat
Stream tokens as they arrive; remember to consume the async iterator.
const stream = await db.ai.chat(
{
model: "onyx",
messages: [{ role: "user", content: "List the top 3 spend categories this week." }],
stream: true,
}
);
for await (const chunk of stream) {
console.log(chunk.choices[0]?.delta?.content ?? "");
}
Shorthand chat (string in, string out)
Quick, typed call that returns the first message content.
const answer = await db.chat("Summarize yesterday's transactions");List available models
Discover model IDs before picking one.
const models = await db.ai.getModels();Get model details
Inspect a specific model's capabilities and limits.
const model = await db.ai.getModel("onyx");Request script approval
Validate a mutation script before execution.
const approval = await db.ai.requestScriptApproval({
script: "db.save({ id: 'acct_1', name: 'Checking' })",
});TypeScript return types
db.chat(text): Promise<string>
db.ai.chat(fullRequest, { raw: true }): Promise<AiChatCompletionResponse | AiChatCompletionStream>
db.ai.chat(text, { stream: true }): Promise<AiChatCompletionStream>
db.ai.chat(fullRequest, { stream: true }): Promise<AiChatCompletionStream>
AiChatCompletionStream: AsyncIterable<AiChatCompletionChunk> & { cancel(): void }
AiChatCompletionChunk.choices[0].delta.content?: string | null
db.ai.getModels(): Promise<AiModelsResponse>
db.ai.getModel(id): Promise<AiModel>
db.ai.requestScriptApproval(input): Promise<AiScriptApprovalResponse>Documents
Upload binary files with metadata, fetch with optional resizing, or delete stored documents.
Save a document
Stores metadata in the DB and writes bytes to the database’s _documents path.
import { onyx } from "@onyx.dev/onyx-database";
import { Schema } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const documentId = await db.saveDocument({
path: "/receipts/2026-01-31.pdf",
mimeType: "application/pdf",
content: fileBase64,
});Get a document (optional resize for images)
Fetches by documentId; width/height resize images on the fly.
const doc = await db.getDocument(documentId, {
width: 800,
height: 600,
});Delete a document
Removes the file and its metadata.
await db.deleteDocument(documentId);TypeScript return types
db.saveDocument(doc): Promise<unknown> // returns generated documentId
db.getDocument(id, { width?, height? }): Promise<unknown>
db.deleteDocument(id): Promise<unknown>Storage & search
Files are written to your database’s filesystem under _documents/; only metadata (path, mimeType, timestamps) is stored in the Document record. If you provide plaintext content, it is chunked into Lucene-indexed parts so full-text search can find the document.
Secrets
Manage encrypted secrets stored per database; client calls never persist plaintext.
List secrets (metadata only)
Returns keys, purposes, and timestamps—no values.
import { onyx } from "@onyx.dev/onyx-database";
import { Schema } from "./generated/onyx/types";
const db = onyx.init<Schema>();
const { records } = await db.listSecrets();Fetch a secret value
Decrypts and returns the plaintext for a single key.
const secret = await db.getSecret("stripe_api_key");Create or rotate a secret
Stores the value encrypted at rest; re-encrypts on each update.
const saved = await db.putSecret("stripe_api_key", {
value: process.env.STRIPE_KEY ?? "",
purpose: "Stripe server key",
});Delete a secret
Removes the record from the database.
await db.deleteSecret("stripe_api_key");How Onyx secures secrets
- Each secret is encrypted with a random AES-256-GCM key; that key is wrapped using the database’s 4096-bit RSA public key. Only ciphertext and wrapped keys are stored.
- Per-database RSA private keys are themselves encrypted with a master key.
- API routes require valid database credentials; plaintext values are only returned on authenticated
GET /secret/{key}and are never persisted decrypted. - Back up the keystore directory (
secret-keystore) together with the master key to preserve decryption ability.
TypeScript return types
db.listSecrets(): Promise<SecretsListResponse>
db.getSecret(key: string): Promise<SecretRecord>
db.putSecret(key: string, input: SecretSaveRequest): Promise<SecretMetadata>
db.deleteSecret(key: string): Promise<{ key: string }>Schema
Fetch, diff, validate, and publish schema revisions.
import { onyx, type SchemaEntity } from "@onyx.dev/onyx-database";
const db = onyx.init();
const current = await db.getSchema();
const tempTable: SchemaEntity = {
name: "TempTable",
identifier: { name: "id", generator: "UUID", type: "String" },
attributes: [
{ name: "id", type: "String", isNullable: false },
{ name: "name", type: "String", isNullable: false },
],
};
const nextSchema = {
...current,
entities: [...(current.entities ?? []), tempTable],
revisionDescription: "Add TempTable via SDK",
};
const diff = await db.diffSchema(nextSchema);
const validation = await db.validateSchema(nextSchema);
if (validation.valid) {
await db.updateSchema(nextSchema, { publish: true });
}Need the JSON shape for entities, attributes, and resolvers? See Schema Example.
TypeScript return types
db.getSchema(): Promise<SchemaRevision>
db.diffSchema(schema): Promise<SchemaDiff>
db.validateSchema(schema): Promise<SchemaValidationResult>
db.updateSchema(schema, { publish?: boolean }): Promise<SchemaRevision>