trellis
Version:
Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications
200 lines • 6.56 kB
TypeScript
/**
* Trellis Client — TypeScript SDK
*
* Isomorphic client that works in two modes:
*
* Local — embeds TrellisKernel directly (Node/Bun only, zero network)
* Remote — calls the Trellis Server HTTP API (works anywhere, including browsers)
*
* Usage:
* // Local (embeds SQLite kernel)
* const db = new TrellisClient({ path: './.trellis-db' });
*
* // Remote (hits HTTP server or Sprites deployment)
* const db = new TrellisClient({ url: 'https://myapp.sprites.app', apiKey: '...' });
*
* // Auto (reads .trellis-db.json from cwd)
* const db = await TrellisClient.fromConfig();
*
* @module trellis/client
*/
import type { SchemaDefinition } from '../core/ontology/types.js';
import { EntityConflictError } from '../core/ontology/sync-policy.js';
import type { ResolveSpec } from '../schema/resolve.js';
import type { FormDescriptor, FormMode } from '../forms/index.js';
export interface EntityData {
id: string;
type: string;
[key: string]: unknown;
}
/** Options for {@link TrellisDb.create} (ADR 0018). */
export interface CreateEntityOptions {
/** Stable id (e.g. entity:player-1). Omit → `${type.toLowerCase()}:${uuid}`. */
id?: string;
}
export { EntityConflictError };
export interface ListResult<T = EntityData> {
data: T[];
total: number;
limit: number;
offset: number;
}
export interface QueryResult {
bindings: Record<string, unknown>[];
executionTime: number;
}
export interface UploadResult {
hash: string;
size: number;
contentType: string;
}
export interface AuthResult {
token: string;
userId: string;
}
export interface Subscription<T = EntityData> {
unsubscribe(): void;
}
export type SubscriptionCallback<T = EntityData> = (result: T[], diff: {
added: T[];
updated: T[];
removed: T[];
}, meta?: {
resolved?: boolean;
}) => void;
/** Options for {@link TrellisDb.subscribe} — server-side relation expansion (TRL-6). */
export interface SubscribeOptions {
/** Entity type name (e.g. `NavSection`) for server `resolve`. */
entityType?: string;
resolve?: ResolveSpec;
}
export interface TrellisDbLocalOptions {
/** Path to the SQLite database directory. */
path: string;
/** Agent ID for attributing ops. Default: 'sdk'. */
agentId?: string;
/** Tenant ID (multi-tenant mode). */
tenantId?: string;
}
export interface TrellisDbRemoteOptions {
/** Base URL of the Trellis DB server. */
url: string;
/** API key or JWT for authentication. */
apiKey?: string;
/** Tenant ID (passed as query param if not in JWT). */
tenantId?: string;
}
export type TrellisDbOptions = TrellisDbLocalOptions | TrellisDbRemoteOptions;
export declare class TrellisDb {
private opts;
private _pool;
private _poolPromise;
private _ws;
/** In-flight connect — concurrent subscribe() shares one socket open. */
private _wsPromise;
private _subCallbacks;
private _subOpts;
constructor(opts: TrellisDbOptions);
/**
* Create a TrellisDb instance from `.trellis-db.json` in the given directory.
*/
static fromConfig(dir?: string): Promise<TrellisDb>;
/**
* Create a new entity.
* Returns the entity ID (generated or caller-supplied via options.id).
*/
create(type: string, attributes?: Record<string, unknown>, links?: Array<{
attribute: string;
targetEntityId: string;
}>, options?: CreateEntityOptions): Promise<string>;
/**
* Read an entity by ID.
* Returns null if not found.
*/
read<T extends EntityData = EntityData>(id: string): Promise<T | null>;
/**
* Update an entity's attributes (partial update).
*/
update(id: string, attributes: Record<string, unknown>): Promise<void>;
/**
* Delete an entity by ID.
*/
delete(id: string): Promise<void>;
/**
* List entities of a given type.
*/
list<T extends EntityData = EntityData>(type?: string, opts?: {
limit?: number;
offset?: number;
filters?: Record<string, unknown>;
}): Promise<ListResult<T>>;
/**
* Run an EQL-S query string.
*/
query(eql: string): Promise<QueryResult>;
/**
* Register a user/system-tier ontology schema with the kernel.
*
* Accepts a {@link SchemaDefinition} or anything carrying one (e.g. a
* `defineType` handle: `client.registerType(NavItem)`). Local mode calls
* `kernel.createOntology` directly; remote mode POSTs to `/ontologies`.
*/
registerType(schema: SchemaDefinition | {
definition: SchemaDefinition;
}): Promise<void>;
/**
* Resolve the headless form descriptor for an entity type, layered with
* any `trellis:Form` override entities in the graph.
*
* Local mode derives in-process; remote mode hits `GET /forms/:type`.
* Returns `null` when the type has no registered schema.
*/
formDescriptor(type: string, opts?: {
mode?: FormMode;
}): Promise<FormDescriptor | null>;
/** List entity types with registered schemas (form derivable). */
listForms(): Promise<Array<{
entityType: string;
schemaId: string;
label: string;
}>>;
/**
* Upload a file to the blob store.
* Returns a content-addressed hash.
*/
upload(data: Uint8Array | ArrayBuffer, contentType?: string): Promise<UploadResult>;
/**
* Download a file by its blob hash.
*/
getFile(hash: string): Promise<Uint8Array | null>;
register(email: string, password: string, name?: string): Promise<AuthResult>;
login(email: string, password: string): Promise<AuthResult>;
/**
* Set the active API key / JWT token for subsequent requests.
*/
setToken(token: string): void;
/**
* Subscribe to a live EQL-S query.
* Callback is fired immediately with the initial result, then on every update.
*
* Requires remote mode (WebSocket to server).
*/
subscribe<T = EntityData>(eql: string, callback: SubscriptionCallback<T>, opts?: SubscribeOptions): Subscription<T>;
/**
* Close the WebSocket connection.
*/
disconnect(): void;
/**
* Close local kernel pool connections.
*/
close(): void;
private _getPool;
private _fetch;
private _ensureWs;
}
export declare class FetchError extends Error {
status: number;
body?: unknown | undefined;
constructor(status: number, message: string, body?: unknown | undefined);
}
//# sourceMappingURL=sdk.d.ts.map