Brainby arc-labs/docs
TypeScript SDK

Typed graph

Wire-only entity, statement, and relation management — create, resolve, upload schema, traverse, list, transact, and subscribe with BrainClient.

Everything on this page is wire-only. BrainHttpClient has no route for the typed graph, transactions, or subscriptions — use BrainClient. See Wire client.

Create

ParameterTypeRequired
createEntity(req)Promise<EntityCreateResponse>optional

Create a typed entity. The request carries entityTypeId, canonicalName, aliases, attributesBlob, and a requestId. The response returns the minted entityId.

createStatement(req)Promise<StatementCreateResponse>optional

Assert a typed claim (kind, subject, predicate, object, confidence, evidence, plus a bi-temporal validity window). The response reports any auto-superseded prior statement and the chain root.

createRelation(req)Promise<RelationCreateResponse>optional

Create a typed edge between two entities (relationType, fromEntity, toEntity, propertiesBlob, evidence, validity window). Returns the minted relationId.

const { entityId } = await client.createEntity({
  entityTypeId: 1,
  canonicalName: "Ada Lovelace",
  aliases: ["Ada"],
  attributesBlob: new Uint8Array(),
  requestId: newId(),
  actAs: null,
});

Typed-graph writes check per-type against the active schema: a create that references a declared type is accepted; an undeclared type is rejected. Upload your schema first (see below). newId() mints the 16-byte requestId / WireUuid values these verbs expect and is exported from the package.

Resolve

resolveEntity maps a candidate name to an entity id.

const res = await client.resolveEntity({
  candidateName: "Ada",
  context: "",
  entityTypeHint: 1, // required to be non-zero server-side
  allowCreate: true, // mint a new entity on a miss
  requestId: newId(),
  actAs: null,
});
// res: { outcome, tier, confidence, resolvedEntity, candidateIds, auditId }

Schema

uploadSchema submits a schema document. With dryRun: true the server validates without applying and returns any validationErrors plus a backward-compatibility verdict.

const up = await client.uploadSchema({
  schemaDocument: schemaText,
  dryRun: false,
  allowBreaking: false,
  requestId: newId(),
});
// up: { namespace, schemaVersion, validationErrors, backwardCompatible, ... }

Read schema back with getSchema, listSchemas / listSchemasFrames, and validateSchema.

Traverse

traverseRelations does a multi-hop walk of the relation graph from an entity, flattening every streamed frame's paths. For the raw frames (truncated, totalPaths) use traverseRelationsFrames.

const paths = await client.traverseRelations({ /* RelationTraverseRequest */ });

List

The read side is a set of paginated enumerations. Each has a flattening variant (returns a flat array) and a *Frames variant (returns the raw streamed frames with cursors). See Pagination.

VerbReturns
listEntities(req)EntityListItem[]
listStatements(req)StatementView[]
listRelationsFrom(req) / listRelationsTo(req)RelationView[]
listSchemas(req)SchemaListItemWire[]
getEntity / getStatement / getRelationone item
graphFetch(req){ nodes, edges } — the whole typed graph

Transactions

Group several writes under one transaction. The client mints the txnId; pass it on each enclosed write's request.

const txnId = newId();
await client.txnBegin({ txnId, timeoutSeconds: 30 });
try {
  await client.encode({ /* …, txnId */ });
  await client.createStatement({ /* …, */ });
  await client.txnCommit({ txnId, requestId: newId() });
} catch (e) {
  await client.txnAbort({ txnId, requestId: newId() });
  throw e;
}

Subscriptions

subscribe opens a long-lived change-feed. It resolves to a Subscription you drain with nextEvent() or for await, and tear down with unsubscribe().

const sub = await client.subscribe({
  filter: myFilter,
  includeHistory: false,
  fromLsn: null,
  maxInflight: 64,
});

for await (const event of sub) {
  console.log(event);
  break;
}
await sub.unsubscribe();

Was this page helpful?

On this page