SochDB Node.js API Reference
Complete reference for the SochDB Node.js / TypeScript SDK.
- Package:
@sochdb/sochdb - Version:
0.5.3 - License: Apache-2.0 (the language SDKs are Apache-2.0; the core Rust engine is AGPL-3.0-or-later with commercial licensing available)
- Node engine:
>=18.0.0 - Dependencies:
@grpc/grpc-js,@grpc/proto-loader,koffi(FFI),uuid; optionalposthog-node(analytics)
Installation
npm install @sochdb/sochdb
The package ships three bin scripts: sochdb-server, sochdb-bulk, and sochdb-grpc-server.
The public surface is centered on an embedded, in-process database backed by a native library
loaded through koffi. Remote access is available through the gRPC client (SochDBClient) and the
IPC client (IpcClient). There is no routing module in this SDK.
Quick start
import { EmbeddedDatabase } from '@sochdb/sochdb';
// open() is SYNCHRONOUS — it returns an EmbeddedDatabase, not a Promise.
const db = EmbeddedDatabase.open('./my.sochdb');
await db.put(Buffer.from('greeting'), Buffer.from('hello'));
const value = await db.get(Buffer.from('greeting'));
console.log(value?.toString()); // "hello"
db.close();
open() is synchronousEmbeddedDatabase.open() returns an EmbeddedDatabase directly — it is not a Promise.
You may see await EmbeddedDatabase.open(...) in older README snippets; awaiting a non-Promise is
harmless but misleading. Do not rely on open() being async.
Exports
The top-level module (@sochdb/sochdb) re-exports the following public surface:
- Database:
EmbeddedDatabase(also exported asDatabase),EmbeddedDatabaseConfig,open,openConcurrent - Transactions:
EmbeddedTransaction - Clients:
SochDBClient(also exported asGrpcClient),IpcClient - Vector search:
HnswIndex,HnswConfig,HnswBindings,SearchResult(re-exported asHnswSearchResult) - Namespaces / collections:
Namespace,Collection,DistanceMetric, and their config/result types - Query builder:
Query - Memory:
ExtractionPipeline,Consolidator,HybridRetriever,AllowedSet - Queue:
PriorityQueue,createQueue,TaskState - Semantic cache:
SemanticCache - Context builder:
ContextQueryBuilder,createContextBuilder,ContextOutputFormat,TruncationStrategy - Studio:
StudioClient,StudioAPIError - MCP:
McpServer,McpClient,McpError,MCP_ERROR_CODES - Format:
WireFormat,ContextFormat,CanonicalFormat,FormatCapabilities,FormatConversionError - Errors:
ErrorCode,SochDBError, and the typed error subclasses - Version:
VERSION('0.5.3')
Database classes — only one is publicA separate IPC-based Database class exists internally (src/database.ts, with its own async
open(), Transaction, and SQL query()/execute()), but it is not re-exported from the
package entry point. Every public Database.* usage resolves to EmbeddedDatabase. Likewise the
SQL engine classes SQLParser/SQLExecutor are internal and not re-exported.
EmbeddedDatabase
The primary class. import { EmbeddedDatabase } from '@sochdb/sochdb' (or use the Database alias).
Opening a database
import { EmbeddedDatabase, open, openConcurrent } from '@sochdb/sochdb';
// Static factory (sync)
const db = EmbeddedDatabase.open('./data.sochdb');
// Top-level convenience functions
const db2 = open('./data.sochdb'); // alias for EmbeddedDatabase.open
const db3 = openConcurrent('./data.sochdb', { fallbackToStandard: true });
| Method | Signature | Notes |
|---|---|---|
EmbeddedDatabase.open | (path: string, config?: EmbeddedDatabaseConfig) => EmbeddedDatabase | Synchronous |
EmbeddedDatabase.openConcurrent | (path: string, options?: { fallbackToStandard?: boolean }) => EmbeddedDatabase | Multi-process; throws if the native library is older than v0.4.8 unless fallbackToStandard is set |
EmbeddedDatabase.isConcurrentModeAvailable | () => boolean | |
open (top-level) | (path: string, config?: EmbeddedDatabaseConfig) => EmbeddedDatabase | Alias for EmbeddedDatabase.open |
openConcurrent (top-level) | (path: string, options?: { fallbackToStandard?: boolean }) => EmbeddedDatabase |
Getters: isConcurrent: boolean, isConcurrentFallback: boolean.
EmbeddedDatabaseConfig
interface EmbeddedDatabaseConfig {
walEnabled?: boolean;
syncMode?: 'full' | 'normal' | 'off';
memtableSizeBytes?: number;
groupCommit?: boolean;
indexPolicy?: 'write_optimized' | 'balanced' | 'scan_optimized' | 'append_only';
}
Key-value operations
EmbeddedDatabase requires Buffer keys and values.
await db.put(Buffer.from('user:1'), Buffer.from(JSON.stringify({ name: 'Ada' })));
const raw = await db.get(Buffer.from('user:1')); // Buffer | null
await db.delete(Buffer.from('user:1'));
// Path-addressed helpers (string paths, Buffer values)
await db.putPath('users/1/name', Buffer.from('Ada'));
const name = await db.getPath('users/1/name'); // Buffer | null
| Method | Signature |
|---|---|
put | (key: Buffer, value: Buffer) => Promise<void> |
get | (key: Buffer) => Promise<Buffer | null> |
delete | (key: Buffer) => Promise<void> |
putPath | (path: string, value: Buffer) => Promise<void> |
getPath | (path: string) => Promise<Buffer | null> |
These top-level KV calls are wrapped in an auto-transaction.
scanPrefix
scanPrefix returns an AsyncGenerator<[Buffer, Buffer]>. The underlying transaction commits
when the generator completes and aborts on error. The native iterator frees memory via
sochdb_free_bytes and is closed via sochdb_iterator_close in a finally block.
for await (const [key, value] of db.scanPrefix(Buffer.from('user:'))) {
console.log(key.toString(), '=>', value.toString());
}
Checkpoint, stats, close
const lsn = await db.checkpoint(); // Promise<bigint> (returns LSN)
const s = await db.stats();
// {
// memtableSizeBytes: bigint,
// walSizeBytes: bigint,
// activeTransactions: number,
// minActiveSnapshot: bigint,
// lastCheckpointLsn: bigint
// }
db.close(); // void
checkpoint() returns a bigintEmbeddedDatabase.checkpoint() returns Promise<bigint> (the LSN), and IpcClient.beginTransaction()
returns Promise<bigint> (the transaction id). These are the only bigint-returning members —
notably, commit() does not return a bigint (see below).
Transactions
Manual transactions
EmbeddedDatabase.transaction() returns an EmbeddedTransaction synchronously.
const txn = db.transaction();
try {
txn.put(Buffer.from('a'), Buffer.from('1'));
txn.put(Buffer.from('b'), Buffer.from('2'));
await txn.commit(); // Promise<void>
} catch (err) {
await txn.abort(); // Promise<void>
throw err;
}
commit() returns Promise<void>EmbeddedTransaction.commit() returns Promise<void>, not Promise<bigint>. On failure it
throws a TransactionError when the native error_code !== 0 (-2 indicates a serializable-snapshot
isolation conflict).
EmbeddedTransaction methods:
| Method | Signature |
|---|---|
put | (key: Buffer, value: Buffer) => void |
get | (key: Buffer) => Buffer | null |
delete | (key: Buffer) => void |
putPath | (path: string, value: Buffer) => void |
getPath | (path: string) => Buffer | null |
scanPrefix | (prefix: Buffer) => AsyncGenerator<[Buffer, Buffer]> |
commit | () => Promise<void> |
abort | () => Promise<void> |
withTransaction
withTransaction runs a callback inside a transaction, committing on success and aborting on error.
const total = await db.withTransaction(async (txn) => {
txn.put(Buffer.from('counter'), Buffer.from('1'));
const v = txn.get(Buffer.from('counter'));
return Number(v?.toString() ?? '0');
});
withTransaction<T>(fn: (txn: EmbeddedTransaction) => Promise<T>): Promise<T>
Vector search (HNSW)
import { HnswIndex, HnswConfig } from '@sochdb/sochdb'.
import { HnswIndex } from '@sochdb/sochdb';
const index = new HnswIndex({ dimension: 768 });
index.insert('doc-1', vector768);
index.insertBatch(['doc-2', 'doc-3'], [vecA, vecB]);
const results = index.search(queryVector, 10); // SearchResult[]
const fast = index.search(queryVector, 10, true); // fast mode
const ultra = index.searchUltra(queryVector, 10);
index.close();
HnswConfig
interface HnswConfig {
dimension: number;
maxConnections?: number; // default 32 (engine HnswConfig::default() M=32)
efConstruction?: number; // default 256
efSearch?: number; // default 100 in the HnswIndex constructor
}
These defaults mirror the engine's HnswConfig::default() (M=32, ef_construction=256), with m0=64
and F32 precision inherited from the core. On Cohere-1M (768-dimension, cosine) this configuration
reaches roughly 0.972 recall@10.
SearchResult
interface SearchResult {
id: string;
distance: number;
}
| Method | Signature |
|---|---|
insert | (id: string, vector: number[]) => void |
insertBatch | (ids: string[], vectors: number[][]) => void |
search | (query: number[], k: number, fast?: boolean) => SearchResult[] |
searchUltra | (query: number[], k: number) => SearchResult[] |
buildFlatCache | () => void |
close | () => void |
Getters: length, dimension. Get/set: efSearch.
HNSW string IDs are hashed to a numeric representation internally. idToString only recovers the
low 64 bits, so the string round-trip can be lossy for IDs that collide on those bits.
Namespaces and collections
import { Namespace, Collection, DistanceMetric } from '@sochdb/sochdb'.
On EmbeddedDatabase: createNamespace(name, config?), namespace(name),
getOrCreateNamespace(name, config?), deleteNamespace(name) => boolean,
listNamespaces() => string[].
import { EmbeddedDatabase, DistanceMetric } from '@sochdb/sochdb';
const db = EmbeddedDatabase.open('./vectors.sochdb');
const ns = db.getOrCreateNamespace('app');
const docs = ns.getOrCreateCollection({
name: 'documents',
dimension: 768,
metric: DistanceMetric.Cosine,
indexed: true,
});
const id = docs.insert(vector768, { title: 'Intro' });
docs.insertMany([vecA, vecB], [{ t: 'a' }, { t: 'b' }]);
const hits = docs.search({ queryVector: vector768, k: 5, includeMetadata: true });
Namespace
| Method | Signature |
|---|---|
createCollection | (config: CollectionConfig) => Collection |
collection | (name: string) => Collection |
getOrCreateCollection | (config: CollectionConfig) => Collection |
deleteCollection | (name: string) => boolean |
listCollections | () => string[] |
getName | () => string |
getConfig | () => NamespaceConfig |
Collection
| Method | Signature |
|---|---|
insert | (vector: number[], metadata?, id?) => string |
insertMany | (vectors, metadatas?, ids?) => string[] (native HNSW batch fast path) |
search | (request: SearchRequest) => SearchResult[] |
get | (id: string) => ... |
delete | (id: string) => boolean |
count | () => number |
rebuildIndex | () => number |
setEfSearch | (n: number) => void (default efSearch=500) |
Getter: isIndexReady: boolean.
Config and result types
enum DistanceMetric {
Cosine = 'cosine',
Euclidean = 'euclidean',
DotProduct = 'dot',
}
interface CollectionConfig {
name: string;
dimension?: number; // default 384
metric?: DistanceMetric;
indexed?: boolean;
hnswM?: number; // default 32
hnswEfConstruction?: number; // default 256
metadata?: Record<string, unknown>;
}
interface NamespaceConfig {
name: string;
displayName?: string;
labels?: Record<string, string>;
readOnly?: boolean;
}
interface SearchRequest {
queryVector: number[];
k: number;
filter?: unknown;
includeMetadata?: boolean;
}
interface SearchResult { // re-exported as NamespaceSearchResult
id: string;
score: number;
vector?: number[];
metadata?: Record<string, unknown>;
}
Remote clients
SochDBClient (gRPC)
import { SochDBClient } from '@sochdb/sochdb' (also exported as GrpcClient). All methods are async.
import { SochDBClient } from '@sochdb/sochdb';
const client = new SochDBClient({ address: 'localhost:50051' });
await client.createIndex('docs', 768, { metric: 'cosine', m: 32, efConstruction: 256 });
await client.insertVectors('docs', [1, 2], [vecA, vecB]);
const results = await client.search('docs', queryVector, 10, 50); // SearchResult[]
await client.put('key', 'value', 'default');
const v = await client.get('key', 'default');
await client.delete('key', 'default');
await client.close();
interface SochDBClientOptions {
address?: string; // default 'localhost:50051'
secure?: boolean;
protoPath?: string;
}
Selected methods (all async):
| Method | Notes |
|---|---|
createIndex(name, dimension, { metric?, m?, efConstruction? }) | defaults m=32, efConstruction=256; returns boolean |
insertVectors(indexName, ids: number[], vectors: number[][]) | returns number |
search(indexName, query, k=10, ef=50) | returns SearchResult[] ({ id: number, distance: number }) |
createCollection(name, { dimension, namespace?, metric? }) | |
addDocuments(...), searchCollection(...) | document collections |
addNode, addEdge, traverse | graph |
cacheGet, cachePut | cache |
startTrace, startSpan, endSpan | tracing |
get(key, namespace='default'), put(...), delete(key, namespace='default') | KV; delete returns boolean |
close() |
IpcClient (Unix domain sockets)
import { IpcClient } from '@sochdb/sochdb'.
IpcClient communicates over Unix domain sockets and is not available on Windows.
import { IpcClient } from '@sochdb/sochdb';
const client = await IpcClient.connect('/tmp/sochdb.sock');
await client.put('key', 'value');
const value = await client.get('key');
const txnId = await client.beginTransaction(); // Promise<bigint>
await client.commitTransaction(txnId);
const ok = await client.ping(); // Promise<boolean>
await client.close();
Methods: get/put/delete, getPath/putPath, query(prefix, { limit, offset, columns }),
scan(prefix) => Array<{ key, value }>, beginTransaction() => Promise<bigint>,
commitTransaction(txnId), abortTransaction(txnId), checkpoint(), stats(),
ping() => Promise<boolean>, close().
Query builder
The exported Query builder (import { Query } from '@sochdb/sochdb') runs a path-prefix query
over an IpcClient (this is distinct from the internal SQL engine, which is not exported).
const result = await new Query(client, 'users/')
.select(['name', 'email'])
.limit(20)
.offset(0)
.toList(); // QueryResult[] ({ [key: string]: unknown })
Methods: limit(n), offset(n), select(cols[]), execute() => Promise<string> (TOON),
toList() => Promise<QueryResult[]>, first(), count().
Memory system
import { ExtractionPipeline, Consolidator, HybridRetriever, AllowedSet } from '@sochdb/sochdb'.
(Added in v0.4.2.) These provide an LLM-driven entity/relation/assertion pipeline, fact
consolidation, and hybrid BM25-plus-vector retrieval.
import { ExtractionPipeline, Consolidator, HybridRetriever, AllowedSet } from '@sochdb/sochdb';
const pipeline = new ExtractionPipeline(db, 'memory');
const extraction = await pipeline.extractAndCommit(text, myExtractor);
const consolidator = new Consolidator(db, 'memory');
await consolidator.add(rawAssertion);
const merged = await consolidator.consolidate(); // number of facts
const retriever = HybridRetriever.fromDatabase(db, 'memory', 'documents', {
k: 10,
alpha: 0.5,
enableRerank: false,
rerankK: 100,
});
const response = await retriever.retrieve(queryText, queryVector, AllowedSet.allowAll(), 10);
ExtractionPipeline—new ExtractionPipeline(db, namespace, schema?);extract(text, extractor),extractAndCommit(...),commit(result),getEntities(),getRelations(),getAssertions().ExtractorFunction = (text) => Promise<{ ... }>.Consolidator—new Consolidator(db, namespace, config?);add(assertion),addWithContradiction(newAssertion, contradicts),consolidate() => number,getCanonicalFacts(),explain(factId).HybridRetriever—new HybridRetriever(db, namespace, collection, config?)orHybridRetriever.fromDatabase(...);indexDocuments(docs),retrieve(queryText, queryVector, allowed, k?),explain(...).RetrievalConfigdefaults:k=10,alpha=0.5,enableRerank=false,rerankK=100.AllowedSet— abstract pre-filter with factoriesAllowedSet.fromIds(ids),.fromNamespace(ns),.fromFilter(fn),.allowAll(); instance methodcontains(id, metadata?).
Exported types: Entity, Relation, Assertion, RawAssertion, CanonicalFact,
ExtractionResult, ExtractionSchema, ConsolidationConfig, RetrievalConfig, RetrievalResult,
RetrievalResponse.
Priority queue
import { PriorityQueue, createQueue, TaskState } from '@sochdb/sochdb'. (Added in v0.4.1.)
An O(log N) priority queue with ordered keys, visibility timeout, and dead-letter support.
import { createQueue } from '@sochdb/sochdb';
const queue = createQueue(db, 'jobs', { visibilityTimeout: 30000, maxRetries: 3 });
const taskId = queue.enqueue(5, Buffer.from(JSON.stringify({ job: 'resize' })));
const task = queue.dequeue('worker-1'); // Task | null
if (task) {
queue.ack(task.id); // or queue.nack(task.id)
}
const stats = queue.stats();
PriorityQueue—PriorityQueue.fromDatabase(db, name, config?),PriorityQueue.fromClient(client, name, config?);enqueue(priority, payload, metadata?) => string,dequeue(workerId) => Task | null,ack(taskId),nack(taskId),stats() => QueueStats,purge() => number.createQueue(db, name, config?)— top-level helper returning aPriorityQueue.
enum TaskState { PENDING, CLAIMED, COMPLETED, DEAD_LETTERED }
interface QueueConfig {
name: string;
visibilityTimeout?: number; // default 30000 ms
maxRetries?: number; // default 3
deadLetterQueue?: string;
}
Types: QueueKey, Task, QueueStats.
The queue decodes its keys with positional binary parsing because keys may legitimately contain the
0x2F byte (/); it avoids an unsafe split('/').
Semantic cache
import { SemanticCache } from '@sochdb/sochdb'. (Added in v0.4.1.) Caches LLM responses keyed by
embedding similarity (cosine).
import { SemanticCache } from '@sochdb/sochdb';
const cache = new SemanticCache(db, 'llm-responses');
cache.put('prompt-1', 'cached answer', embedding, 3600, { model: 'opus' });
const hit = cache.get(queryEmbedding, 0.85); // CacheHit | null
if (hit) {
console.log(hit.value, 'score:', hit.score);
}
const removed = cache.purgeExpired(); // number
Methods: new SemanticCache(db, cacheName); put(key, value, embedding, ttlSeconds=0, metadata?),
get(queryEmbedding, threshold=0.85) => CacheHit | null, delete(key), clear() => number,
stats() => CacheStats, purgeExpired() => number.
Types: CacheEntry, CacheHit (extends CacheEntry with score),
CacheStats { count, hits, misses, hitRate, memoryUsage }.
Context builder
import { ContextQueryBuilder, createContextBuilder } from '@sochdb/sochdb'. (Added in v0.4.1.)
A fluent, token-aware, priority-based assembler for LLM context windows.
import { createContextBuilder, ContextOutputFormat, TruncationStrategy } from '@sochdb/sochdb';
const result = createContextBuilder()
.forSession('session-123')
.withBudget(4096)
.setFormat(ContextOutputFormat.MARKDOWN)
.setTruncation(TruncationStrategy.TAIL_DROP)
.literal('system', 100, 'You are a helpful assistant.')
.last(5, 'messages')
.search('documents', queryEmbedding, 3)
.done()
.execute(); // ContextResult { text, tokenCount, sections[] }
Builder methods: forSession(id), withBudget(tokens) (default 4096),
setFormat(ContextOutputFormat), setTruncation(TruncationStrategy), literal(name, priority, text),
section(name, priority), get(path), last(n, table), whereEq(field, value),
search(collection, embedding, k), sql(query), done(), execute().
enum ContextOutputFormat { TOON, JSON, MARKDOWN }
enum TruncationStrategy { TAIL_DROP, HEAD_DROP, PROPORTIONAL }
Graph overlay
The graph overlay is a thin KV wrapper exposed directly on EmbeddedDatabase. Keys are stored under
_graph/{ns}/nodes/... and _graph/{ns}/edges/....
await db.addNode('social', 'user:1', 'User', { name: 'Ada' });
await db.addEdge('social', 'user:1', 'FOLLOWS', 'user:2');
const sub = await db.traverse('social', 'user:1', 10, 'bfs'); // { nodes, edges }
| Method | Signature |
|---|---|
addNode | (namespace, nodeId, nodeType, properties?) |
addEdge | (namespace, fromId, edgeType, toId, properties?) |
traverse | (namespace, startNode, maxDepth=10, order: 'bfs' | 'dfs' = 'bfs') => { nodes, edges } |
Policy
import { PolicyService } from '@sochdb/sochdb'. (Added in v0.4.3.) Namespace-level ACL and
governance over an EmbeddedDatabase.
import { PolicyService } from '@sochdb/sochdb';
const policy = new PolicyService(db, { enableAudit: true });
policy.createNamespacePolicy(/* ... */);
policy.addRule('app', rule);
policy.grantAccess(grant);
const decision = policy.evaluate(request); // PolicyEvaluation
const log = policy.getAuditLog();
Methods: new PolicyService(db, { enableAudit? }); createNamespacePolicy,
getNamespacePolicy => NamespacePolicy | null, updateNamespacePolicy,
deleteNamespacePolicy => boolean, addRule(ns, rule), removeRule(ns, ruleId) => boolean,
evaluate(req) => PolicyEvaluation, grantAccess(grant),
revokeAccess(ns, principal) => boolean, hasPermission(...),
listGrants(ns) => NamespaceGrant[], getAuditLog(options?), clearCache().
Types: PolicyRule, PolicyCondition, PolicyEvaluation, NamespacePolicy, NamespaceGrant,
NamespacePermission, PolicyAction, PolicyRequest, PolicySet, PolicyAuditEntry.
MCP
import { McpServer, McpClient } from '@sochdb/sochdb'. (Added in v0.4.3.) Exposes the database as
MCP tools, resources, and prompts to LLM agents.
import { McpServer } from '@sochdb/sochdb';
const server = new McpServer(db, mcpServerConfig);
server.registerTool(/* ... */);
const tools = server.listTools();
const result = await server.callTool(toolCall); // McpToolResult
McpServer—new McpServer(db, config);registerTool(...),unregisterTool(name) => boolean,listTools(),callTool(call) => McpToolResult,registerPrompt(prompt),listPrompts(),getPrompt(name, args?),listResources(),readResource(uri),getServerInfo().McpClient—new McpClient(config);connect(),disconnect(),isConnected(),listTools(),callTool(name, args),listResources(),readResource(uri),listPrompts(),getPrompt(name, args?).McpError(message, code, data?)and theMCP_ERROR_CODESconstant.
Types: McpTool, McpToolCall, McpToolResult, McpResource, McpResourceContent, McpPrompt,
McpPromptArgument, McpPromptMessage, McpServerCapabilities, McpServerConfig,
McpClientConfig, McpTransport.
When the engine exposes its built-in MCP tools, the names use underscores — for example
sochdb_query, sochdb_get, sochdb_put, sochdb_context_query, memory_search_episodes,
sochdb_grep. Any dot-separated tool catalog you may find in older mcp.json/README material is
stale.
Studio
import { StudioClient } from '@sochdb/sochdb'. An HTTP client (Bearer auth) for the hosted Studio
backend.
import { StudioClient } from '@sochdb/sochdb';
const studio = new StudioClient({ baseUrl: 'https://studio.example.com', apiKey: 'sk_...' });
await studio.health();
const ingest = await studio.ingestEvents(events, { source: 'app' }); // { ok, ingested, eventIds }
Methods: new StudioClient({ baseUrl, apiKey? }); health() => StudioHealthResponse,
ingestEvents(events, { source?, apiKey? }) => StudioIngestResult.
Error: StudioAPIError(message, statusCode?). Types: StudioClientOptions, StudioEvent,
StudioHealthResponse, StudioIngestResult { ok, ingested, eventIds }.
Format utilities
import { WireFormat, ContextFormat, CanonicalFormat, FormatCapabilities } from '@sochdb/sochdb'.
enum WireFormat { TOON = 'toon', JSON = 'json', COLUMNAR = 'columnar' }
enum ContextFormat { TOON, JSON, MARKDOWN }
// CanonicalFormat also includes TOON
WireFormat.fromString(...),ContextFormat.fromString(...).FormatCapabilitiesclass — e.g.FormatCapabilities.wireToContext(wire).FormatConversionError extends Error.
Static serialization helpers exist on EmbeddedDatabase: toToon(table, records, fields?),
toJson(table, records, fields?, compact=true), fromJson(jsonStr).
Error handling
import { SochDBError, ErrorCode } from '@sochdb/sochdb'.
import { SochDBError, ErrorCode, TransactionError } from '@sochdb/sochdb';
try {
await db.withTransaction(async (txn) => {
txn.put(Buffer.from('k'), Buffer.from('v'));
// ...
});
} catch (err) {
if (err instanceof TransactionError) {
console.error('txn failed:', err.code, err.remediation);
} else if (err instanceof SochDBError) {
console.error(err.code, err.message);
}
}
ErrorCode
| Code | Value | Code | Value |
|---|---|---|---|
CONNECTION_FAILED | 1001 | INTERNAL_ERROR | 9001 |
CONNECTION_TIMEOUT | 1002 | STORAGE_ERROR | 9003 |
CONNECTION_CLOSED | 1003 | DATABASE_LOCKED | 10001 |
PROTOCOL_ERROR | 1004 | LOCK_TIMEOUT | 10002 |
TRANSACTION_ABORTED | 2001 | EPOCH_MISMATCH | 10003 |
TRANSACTION_CONFLICT | 2002 | SPLIT_BRAIN | 10004 |
STALE_LOCK | 10005 |
Error classes
SochDBError(message, code = INTERNAL_ERROR, remediation?)— base class with.codeand.remediation.ConnectionError,TransactionError,ProtocolError,DatabaseError.- Lock errors (v0.4.1):
LockError,DatabaseLockedError(path, holderPid?)(.path,.holderPid),LockTimeoutError(path, timeoutSecs),EpochMismatchError(expected, actual),SplitBrainError(message?). - Namespace / collection errors:
NamespaceNotFoundError,NamespaceExistsError,CollectionNotFoundError,CollectionExistsError(all extendSochDBError). - Service errors:
StudioAPIError,McpError.
Platform notes
The IPC client and the internal embedded-server manager use Unix domain sockets. IpcClient is not
available on Windows, and the internal server manager throws on Windows. The embedded
EmbeddedDatabase (FFI via koffi) and the gRPC SochDBClient are cross-platform.
See also
For the latest documentation, see sochdb.dev