Table of Contents
- API Reference
- Package entry point
- Connection types
- IdentityDBConnectionConfig
- SqliteConnectionConfig
- PostgresConnectionConfig
- MysqlConnectionConfig
- Example
- Core class: IdentityDB
- Space management
- Topics and facts
- Free-form ingestion
- ingestStatement(statement, options)
- Extractor interfaces
- Built-in extractor: NaiveExtractor
- Built-in extractor: LlmFactExtractor
- Example
- Topic hierarchy and aliases
- linkTopics(input)
- addTopicAlias(canonicalName, alias, options?)
- resolveTopic(name, options?)
- getTopicAliases(name, options?)
- getTopicChildren(name, options?)
- getTopicParents(name, options?)
- getTopicLineage(name, options?)
- Example
- Topic and fact queries
- getTopicFacts(name, options?)
- getTopicFactsLinkedTo(name, linkedTopicName, options?)
- findFactsConnectingTopics(names, options?)
- getTopicByName(name, options?)
- listTopics(options?)
- findConnectedTopics(name, options?)
- Semantic search and duplicate detection
- EmbeddingProvider
- indexFactEmbeddings(input)
- indexFactEmbedding(factId, input)
- searchFacts(input)
- findSimilarFacts(input)
- Example
- Main return types
- Errors
- Space behavior summary
- Recommended reading
API Reference
This page documents the public package API exported by identitydb.
It focuses on the surface most application developers actually use:
IdentityDB- connection config types
- space, topic, fact, and query methods
- extractor interfaces and built-in extractors
- embedding provider interfaces
- main return types
For a guided walkthrough, start with Getting Started.
Package entry point
import {
IdentityDB,
NaiveExtractor,
LlmFactExtractor,
type IdentityDBConnectionConfig,
type EmbeddingProvider,
type AddFactInput,
type Topic,
type Fact,
type Space,
} from 'identitydb';
The package currently re-exports:
- database adapter config types from
./adapters IdentityDBfrom./core/identity-db- schema initialization from
./core/migrations - extractor helpers and built-in extractors
- API, database, and domain types
Connection types
IdentityDB connects through a discriminated client config.
IdentityDBConnectionConfig
type IdentityDBConnectionConfig =
| SqliteConnectionConfig
| PostgresConnectionConfig
| MysqlConnectionConfig;
SqliteConnectionConfig
interface SqliteConnectionConfig {
client: 'sqlite';
filename: string;
readonly?: boolean;
}
PostgresConnectionConfig
interface PostgresConnectionConfig {
client: 'postgres';
connectionString?: string;
host?: string;
port?: number;
database?: string;
user?: string;
password?: string;
ssl?: boolean;
}
MysqlConnectionConfig
interface MysqlConnectionConfig {
client: 'mysql' | 'mariadb';
uri?: string;
host?: string;
port?: number;
database?: string;
user?: string;
password?: string;
}
Example
const db = await IdentityDB.connect({
client: 'sqlite',
filename: ':memory:',
});
Core class: IdentityDB
IdentityDB.connect(config)
static connect(config: IdentityDBConnectionConfig): Promise<IdentityDB>
Creates a new database-backed IdentityDB instance.
initialize()
initialize(): Promise<void>
Creates or updates the schema required by IdentityDB.
Current tables:
spacestopicsfactsfact_topicstopic_relationstopic_aliasesfact_embeddings
close()
close(): Promise<void>
Closes the underlying DB connection or pool.
Space management
Spaces are hard-isolated memory graphs. The same topic name can exist independently in multiple spaces.
When spaceName is omitted, IdentityDB uses the default space for backward compatibility.
upsertSpace(input)
upsertSpace(input: UpsertSpaceInput): Promise<Space>
Creates a new space or updates an existing one by normalized name.
UpsertSpaceInput
interface UpsertSpaceInput {
name: string;
description?: string | null;
metadata?: JsonValue | null;
}
getSpaceByName(name)
getSpaceByName(name: string): Promise<Space | null>
Returns a space by name, or null if it does not exist.
listSpaces()
listSpaces(): Promise<Space[]>
Returns all spaces ordered by normalized name.
Space
interface Space {
id: string;
name: string;
normalizedName: string;
description: string | null;
metadata: JsonValue | null;
createdAt: string;
updatedAt: string;
}
Example
await db.upsertSpace({ name: 'customer-a' });
await db.upsertSpace({ name: 'customer-b' });
const spaces = await db.listSpaces();
const customerA = await db.getSpaceByName('customer-a');
Topics and facts
upsertTopic(input)
upsertTopic(input: UpsertTopicInput): Promise<Topic>
Creates or updates a canonical topic within a space.
UpsertTopicInput
interface UpsertTopicInput {
spaceName?: string;
name: string;
category?: TopicCategory;
granularity?: TopicGranularity;
description?: string | null;
metadata?: JsonValue | null;
}
addFact(input)
addFact(input: AddFactInput): Promise<Fact>
Adds a structured fact and links it to one or more topics.
AddFactInput
interface AddFactInput {
spaceName?: string;
statement: string;
summary?: string | null;
source?: string | null;
confidence?: number | null;
metadata?: JsonValue | null;
topics: TopicLinkInput[];
}
TopicLinkInput
interface TopicLinkInput {
spaceName?: string;
name: string;
category?: TopicCategory;
granularity?: TopicGranularity;
description?: string | null;
metadata?: JsonValue | null;
role?: string | null;
}
Example
const fact = await db.addFact({
spaceName: 'customer-a',
statement: 'TypeScript is used in the API layer.',
topics: [
{
name: 'TypeScript',
category: 'entity',
granularity: 'concrete',
role: 'object',
},
{
name: 'API layer',
category: 'concept',
granularity: 'mixed',
role: 'context',
},
],
});
Free-form ingestion
Use ingestion when your application starts from plain text instead of pre-structured topic objects.
ingestStatement(statement, options)
ingestStatement(statement: string, options: IngestStatementOptions): Promise<Fact>
Behavior:
- runs the configured extractor
- normalizes and deduplicates extracted topics
- writes the fact into the requested space
- optionally performs duplicate-aware semantic reuse before inserting
- optionally indexes the created fact with embeddings after insert
IngestStatementOptions
interface IngestStatementOptions {
extractor: FactExtractor;
embeddingProvider?: EmbeddingProvider;
duplicateThreshold?: number;
spaceName?: string;
}
Extractor interfaces
FactExtractor
interface FactExtractor {
extract(input: string): Promise<ExtractedFact>;
}
ExtractedFact
interface ExtractedFact {
statement?: string;
summary?: string | null;
source?: string | null;
confidence?: number | null;
metadata?: JsonValue | null;
topics: TopicLinkInput[];
}
Built-in extractor: NaiveExtractor
class NaiveExtractor implements FactExtractor
Deterministic rule-based extractor that looks for:
I- 4-digit years like
2025 - capitalized tokens like
TypeScript,Bun, orPostgreSQL
Good for tests, local demos, and environments where you do not want an LLM dependency.
Built-in extractor: LlmFactExtractor
class LlmFactExtractor implements FactExtractor {
constructor(options: LlmFactExtractorOptions)
}
Wraps any model that can satisfy a very small text-generation contract.
LlmTextGenerationModel
interface LlmTextGenerationModel {
generateText(prompt: string): Promise<string>;
}
LlmFactExtractorOptions
interface LlmFactExtractorOptions {
model: LlmTextGenerationModel;
instructions?: string;
promptBuilder?: (input: string, instructions?: string) => string;
}
parseLlmExtractedFactResponse(response)
parseLlmExtractedFactResponse(response: string): ExtractedFact
Parses a raw LLM response into an ExtractedFact.
Notes:
- expects JSON output
- tolerates fenced
jsoncode blocks - throws
IdentityDBErroron invalid JSON or invalid topic payloads
Example
const extractor = new LlmFactExtractor({
model: {
async generateText(prompt) {
return callYourModel(prompt);
},
},
instructions: 'Prefer product, technology, and time topics.',
});
await db.ingestStatement('I have worked with Bun and TypeScript since 2025.', {
extractor,
spaceName: 'customer-a',
});
Topic hierarchy and aliases
linkTopics(input)
linkTopics(input: LinkTopicsInput): Promise<void>
Creates a parent_of relation between two topics inside one space.
LinkTopicsInput
interface LinkTopicsInput {
spaceName?: string;
parentName: string;
childName: string;
}
addTopicAlias(canonicalName, alias, options?)
addTopicAlias(canonicalName: string, alias: string, options?: SpaceScopedInput): Promise<void>
Registers an alias for a canonical topic within one space.
resolveTopic(name, options?)
resolveTopic(name: string, options?: SpaceScopedInput): Promise<Topic | null>
Resolves a canonical topic by either its canonical name or one of its aliases.
getTopicAliases(name, options?)
getTopicAliases(name: string, options?: SpaceScopedInput): Promise<string[]>
Lists aliases for the canonical topic identified by name.
getTopicChildren(name, options?)
getTopicChildren(name: string, options?: SpaceScopedInput): Promise<Topic[]>
Returns direct children of a topic.
getTopicParents(name, options?)
getTopicParents(name: string, options?: SpaceScopedInput): Promise<Topic[]>
Returns direct parents of a topic.
getTopicLineage(name, options?)
getTopicLineage(name: string, options?: SpaceScopedInput): Promise<Topic[]>
Returns ancestor topics reachable through repeated parent traversal.
Example
await db.linkTopics({
spaceName: 'customer-a',
parentName: 'programming language',
childName: 'TypeScript',
});
await db.addTopicAlias('TypeScript', 'TS', { spaceName: 'customer-a' });
const topic = await db.resolveTopic('TS', { spaceName: 'customer-a' });
const children = await db.getTopicChildren('programming language', { spaceName: 'customer-a' });
const lineage = await db.getTopicLineage('TypeScript', { spaceName: 'customer-a' });
Topic and fact queries
getTopicFacts(name, options?)
getTopicFacts(name: string, options?: SpaceScopedInput): Promise<Fact[]>
Returns facts linked to a topic.
getTopicFactsLinkedTo(name, linkedTopicName, options?)
getTopicFactsLinkedTo(
name: string,
linkedTopicName: string,
options?: SpaceScopedInput,
): Promise<Fact[]>
Returns facts that connect two topics.
findFactsConnectingTopics(names, options?)
findFactsConnectingTopics(names: string[], options?: SpaceScopedInput): Promise<Fact[]>
Generalized version of getTopicFactsLinkedTo() for any number of topics.
getTopicByName(name, options?)
getTopicByName(name: string, options?: TopicLookupOptions): Promise<Topic | null>
getTopicByName(name: string, options: { includeFacts: true; spaceName?: string }): Promise<TopicWithFacts | null>
Looks up a topic by canonical name or alias.
TopicLookupOptions
interface TopicLookupOptions {
spaceName?: string;
includeFacts?: boolean;
}
listTopics(options?)
listTopics(options?: ListTopicsOptions): Promise<Topic[]>
listTopics(options: { includeFacts: true; limit?: number; spaceName?: string }): Promise<TopicWithFacts[]>
Lists topics in one space, optionally hydrating each topic with facts.
ListTopicsOptions
interface ListTopicsOptions {
spaceName?: string;
includeFacts?: boolean;
limit?: number;
}
findConnectedTopics(name, options?)
findConnectedTopics(name: string, options?: SpaceScopedInput): Promise<ConnectedTopic[]>
Returns topics that share facts with the requested topic.
Semantic search and duplicate detection
EmbeddingProvider
interface EmbeddingProvider {
model: string;
dimensions: number;
embed(input: string): Promise<number[]>;
embedMany?(inputs: string[]): Promise<number[][]>;
}
IdentityDB stays provider-agnostic. You can wrap hosted APIs, local models, or custom services as long as they implement this interface.
indexFactEmbeddings(input)
indexFactEmbeddings(input: IndexFactEmbeddingsInput): Promise<void>
Indexes all facts in a space for one embedding model.
indexFactEmbedding(factId, input)
indexFactEmbedding(factId: string, input: IndexFactEmbeddingsInput): Promise<void>
Indexes one fact by ID.
IndexFactEmbeddingsInput
interface IndexFactEmbeddingsInput {
spaceName?: string;
provider: EmbeddingProvider;
}
searchFacts(input)
searchFacts(input: SearchFactsInput): Promise<ScoredFact[]>
Runs semantic retrieval over facts in one space.
SearchFactsInput
interface SearchFactsInput {
spaceName?: string;
query: string;
provider: EmbeddingProvider;
topicNames?: string[];
limit?: number;
minimumScore?: number;
}
findSimilarFacts(input)
findSimilarFacts(input: FindSimilarFactsInput): Promise<ScoredFact[]>
Finds facts similar to a provided statement. This is also used by duplicate-aware ingestion.
FindSimilarFactsInput
interface FindSimilarFactsInput {
spaceName?: string;
statement: string;
provider: EmbeddingProvider;
topicNames?: string[];
limit?: number;
minimumScore?: number;
}
Example
const provider: EmbeddingProvider = {
model: 'example-embedding-v1',
dimensions: 3,
async embed(input) {
return input.toLowerCase().includes('typescript') ? [1, 0, 0] : [0, 1, 0];
},
};
await db.indexFactEmbeddings({
provider,
spaceName: 'customer-a',
});
const results = await db.searchFacts({
query: 'TypeScript experience',
provider,
limit: 5,
spaceName: 'customer-a',
});
Main return types
Topic
interface Topic {
id: string;
spaceId: string;
name: string;
normalizedName: string;
category: TopicCategory;
granularity: TopicGranularity;
description: string | null;
metadata: JsonValue | null;
createdAt: string;
updatedAt: string;
}
FactTopic
interface FactTopic extends Topic {
role: string | null;
position: number;
}
Fact
interface Fact {
id: string;
spaceId: string;
statement: string;
summary: string | null;
source: string | null;
confidence: number | null;
metadata: JsonValue | null;
createdAt: string;
updatedAt: string;
topics: FactTopic[];
}
TopicWithFacts
interface TopicWithFacts extends Topic {
facts: Fact[];
}
ConnectedTopic
interface ConnectedTopic extends Topic {
sharedFactCount: number;
}
Domain enums
type TopicCategory = 'entity' | 'concept' | 'temporal' | 'custom';
type TopicGranularity = 'abstract' | 'concrete' | 'mixed';
Errors
The package exposes custom error classes:
IdentityDBErrorIdentityDBConfigurationError
Common cases:
- empty fact statement
- no topics on a fact
- invalid alias collisions
- invalid extractor output
- invalid LLM JSON payloads
- embedding dimension mismatches
- unsupported connection configuration
Space behavior summary
A practical rule of thumb:
- Writes like
addFact(),upsertTopic(),linkTopics(), andaddTopicAlias()can create or use spaces on demand - Reads scoped to a missing explicit space usually return
nullor[] - when
spaceNameis omitted, the package falls back to thedefaultspace
That means this is valid and isolated:
await db.addFact({
spaceName: 'A',
statement: 'TypeScript is preferred by team A.',
topics: [{ name: 'TypeScript' }],
});
await db.addFact({
spaceName: 'B',
statement: 'TypeScript is not used by team B.',
topics: [{ name: 'TypeScript' }],
});
The two TypeScript topics live in different memory graphs and do not merge automatically.