From c4959bbba280bd1b33f79f412536bf9411e11a26 Mon Sep 17 00:00:00 2001 From: Shinwoo PARK Date: Mon, 11 May 2026 15:02:55 +0900 Subject: [PATCH] docs: add wiki API reference --- API-Reference.md | 814 +++++++++++++++++++++++++++++++++++++++++++++ Getting-Started.md | 2 + Home.md | 1 + _Sidebar.md | 1 + 4 files changed, 818 insertions(+) create mode 100644 API-Reference.md diff --git a/API-Reference.md b/API-Reference.md new file mode 100644 index 0000000..e8fbfeb --- /dev/null +++ b/API-Reference.md @@ -0,0 +1,814 @@ +# 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](Getting-Started). + +## Package entry point + +```ts +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` +- `IdentityDB` from `./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` + +```ts +type IdentityDBConnectionConfig = + | SqliteConnectionConfig + | PostgresConnectionConfig + | MysqlConnectionConfig; +``` + +### `SqliteConnectionConfig` + +```ts +interface SqliteConnectionConfig { + client: 'sqlite'; + filename: string; + readonly?: boolean; +} +``` + +### `PostgresConnectionConfig` + +```ts +interface PostgresConnectionConfig { + client: 'postgres'; + connectionString?: string; + host?: string; + port?: number; + database?: string; + user?: string; + password?: string; + ssl?: boolean; +} +``` + +### `MysqlConnectionConfig` + +```ts +interface MysqlConnectionConfig { + client: 'mysql' | 'mariadb'; + uri?: string; + host?: string; + port?: number; + database?: string; + user?: string; + password?: string; +} +``` + +### Example + +```ts +const db = await IdentityDB.connect({ + client: 'sqlite', + filename: ':memory:', +}); +``` + +--- + +## Core class: `IdentityDB` + +### `IdentityDB.connect(config)` + +```ts +static connect(config: IdentityDBConnectionConfig): Promise +``` + +Creates a new database-backed IdentityDB instance. + +### `initialize()` + +```ts +initialize(): Promise +``` + +Creates or updates the schema required by IdentityDB. + +Current tables: + +- `spaces` +- `topics` +- `facts` +- `fact_topics` +- `topic_relations` +- `topic_aliases` +- `fact_embeddings` + +### `close()` + +```ts +close(): Promise +``` + +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)` + +```ts +upsertSpace(input: UpsertSpaceInput): Promise +``` + +Creates a new space or updates an existing one by normalized name. + +#### `UpsertSpaceInput` + +```ts +interface UpsertSpaceInput { + name: string; + description?: string | null; + metadata?: JsonValue | null; +} +``` + +### `getSpaceByName(name)` + +```ts +getSpaceByName(name: string): Promise +``` + +Returns a space by name, or `null` if it does not exist. + +### `listSpaces()` + +```ts +listSpaces(): Promise +``` + +Returns all spaces ordered by normalized name. + +### `Space` + +```ts +interface Space { + id: string; + name: string; + normalizedName: string; + description: string | null; + metadata: JsonValue | null; + createdAt: string; + updatedAt: string; +} +``` + +### Example + +```ts +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)` + +```ts +upsertTopic(input: UpsertTopicInput): Promise +``` + +Creates or updates a canonical topic within a space. + +#### `UpsertTopicInput` + +```ts +interface UpsertTopicInput { + spaceName?: string; + name: string; + category?: TopicCategory; + granularity?: TopicGranularity; + description?: string | null; + metadata?: JsonValue | null; +} +``` + +### `addFact(input)` + +```ts +addFact(input: AddFactInput): Promise +``` + +Adds a structured fact and links it to one or more topics. + +#### `AddFactInput` + +```ts +interface AddFactInput { + spaceName?: string; + statement: string; + summary?: string | null; + source?: string | null; + confidence?: number | null; + metadata?: JsonValue | null; + topics: TopicLinkInput[]; +} +``` + +#### `TopicLinkInput` + +```ts +interface TopicLinkInput { + spaceName?: string; + name: string; + category?: TopicCategory; + granularity?: TopicGranularity; + description?: string | null; + metadata?: JsonValue | null; + role?: string | null; +} +``` + +### Example + +```ts +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)` + +```ts +ingestStatement(statement: string, options: IngestStatementOptions): Promise +``` + +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` + +```ts +interface IngestStatementOptions { + extractor: FactExtractor; + embeddingProvider?: EmbeddingProvider; + duplicateThreshold?: number; + spaceName?: string; +} +``` + +### Extractor interfaces + +#### `FactExtractor` + +```ts +interface FactExtractor { + extract(input: string): Promise; +} +``` + +#### `ExtractedFact` + +```ts +interface ExtractedFact { + statement?: string; + summary?: string | null; + source?: string | null; + confidence?: number | null; + metadata?: JsonValue | null; + topics: TopicLinkInput[]; +} +``` + +### Built-in extractor: `NaiveExtractor` + +```ts +class NaiveExtractor implements FactExtractor +``` + +Deterministic rule-based extractor that looks for: + +- `I` +- 4-digit years like `2025` +- capitalized tokens like `TypeScript`, `Bun`, or `PostgreSQL` + +Good for tests, local demos, and environments where you do not want an LLM dependency. + +### Built-in extractor: `LlmFactExtractor` + +```ts +class LlmFactExtractor implements FactExtractor { + constructor(options: LlmFactExtractorOptions) +} +``` + +Wraps any model that can satisfy a very small text-generation contract. + +#### `LlmTextGenerationModel` + +```ts +interface LlmTextGenerationModel { + generateText(prompt: string): Promise; +} +``` + +#### `LlmFactExtractorOptions` + +```ts +interface LlmFactExtractorOptions { + model: LlmTextGenerationModel; + instructions?: string; + promptBuilder?: (input: string, instructions?: string) => string; +} +``` + +#### `parseLlmExtractedFactResponse(response)` + +```ts +parseLlmExtractedFactResponse(response: string): ExtractedFact +``` + +Parses a raw LLM response into an `ExtractedFact`. + +Notes: + +- expects JSON output +- tolerates fenced `json` code blocks +- throws `IdentityDBError` on invalid JSON or invalid topic payloads + +### Example + +```ts +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)` + +```ts +linkTopics(input: LinkTopicsInput): Promise +``` + +Creates a `parent_of` relation between two topics inside one space. + +#### `LinkTopicsInput` + +```ts +interface LinkTopicsInput { + spaceName?: string; + parentName: string; + childName: string; +} +``` + +### `addTopicAlias(canonicalName, alias, options?)` + +```ts +addTopicAlias(canonicalName: string, alias: string, options?: SpaceScopedInput): Promise +``` + +Registers an alias for a canonical topic within one space. + +### `resolveTopic(name, options?)` + +```ts +resolveTopic(name: string, options?: SpaceScopedInput): Promise +``` + +Resolves a canonical topic by either its canonical name or one of its aliases. + +### `getTopicAliases(name, options?)` + +```ts +getTopicAliases(name: string, options?: SpaceScopedInput): Promise +``` + +Lists aliases for the canonical topic identified by `name`. + +### `getTopicChildren(name, options?)` + +```ts +getTopicChildren(name: string, options?: SpaceScopedInput): Promise +``` + +Returns direct children of a topic. + +### `getTopicParents(name, options?)` + +```ts +getTopicParents(name: string, options?: SpaceScopedInput): Promise +``` + +Returns direct parents of a topic. + +### `getTopicLineage(name, options?)` + +```ts +getTopicLineage(name: string, options?: SpaceScopedInput): Promise +``` + +Returns ancestor topics reachable through repeated parent traversal. + +### Example + +```ts +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?)` + +```ts +getTopicFacts(name: string, options?: SpaceScopedInput): Promise +``` + +Returns facts linked to a topic. + +### `getTopicFactsLinkedTo(name, linkedTopicName, options?)` + +```ts +getTopicFactsLinkedTo( + name: string, + linkedTopicName: string, + options?: SpaceScopedInput, +): Promise +``` + +Returns facts that connect two topics. + +### `findFactsConnectingTopics(names, options?)` + +```ts +findFactsConnectingTopics(names: string[], options?: SpaceScopedInput): Promise +``` + +Generalized version of `getTopicFactsLinkedTo()` for any number of topics. + +### `getTopicByName(name, options?)` + +```ts +getTopicByName(name: string, options?: TopicLookupOptions): Promise +getTopicByName(name: string, options: { includeFacts: true; spaceName?: string }): Promise +``` + +Looks up a topic by canonical name or alias. + +#### `TopicLookupOptions` + +```ts +interface TopicLookupOptions { + spaceName?: string; + includeFacts?: boolean; +} +``` + +### `listTopics(options?)` + +```ts +listTopics(options?: ListTopicsOptions): Promise +listTopics(options: { includeFacts: true; limit?: number; spaceName?: string }): Promise +``` + +Lists topics in one space, optionally hydrating each topic with facts. + +#### `ListTopicsOptions` + +```ts +interface ListTopicsOptions { + spaceName?: string; + includeFacts?: boolean; + limit?: number; +} +``` + +### `findConnectedTopics(name, options?)` + +```ts +findConnectedTopics(name: string, options?: SpaceScopedInput): Promise +``` + +Returns topics that share facts with the requested topic. + +--- + +## Semantic search and duplicate detection + +### `EmbeddingProvider` + +```ts +interface EmbeddingProvider { + model: string; + dimensions: number; + embed(input: string): Promise; + embedMany?(inputs: string[]): Promise; +} +``` + +IdentityDB stays provider-agnostic. You can wrap hosted APIs, local models, or custom services as long as they implement this interface. + +### `indexFactEmbeddings(input)` + +```ts +indexFactEmbeddings(input: IndexFactEmbeddingsInput): Promise +``` + +Indexes all facts in a space for one embedding model. + +### `indexFactEmbedding(factId, input)` + +```ts +indexFactEmbedding(factId: string, input: IndexFactEmbeddingsInput): Promise +``` + +Indexes one fact by ID. + +#### `IndexFactEmbeddingsInput` + +```ts +interface IndexFactEmbeddingsInput { + spaceName?: string; + provider: EmbeddingProvider; +} +``` + +### `searchFacts(input)` + +```ts +searchFacts(input: SearchFactsInput): Promise +``` + +Runs semantic retrieval over facts in one space. + +#### `SearchFactsInput` + +```ts +interface SearchFactsInput { + spaceName?: string; + query: string; + provider: EmbeddingProvider; + topicNames?: string[]; + limit?: number; + minimumScore?: number; +} +``` + +### `findSimilarFacts(input)` + +```ts +findSimilarFacts(input: FindSimilarFactsInput): Promise +``` + +Finds facts similar to a provided statement. This is also used by duplicate-aware ingestion. + +#### `FindSimilarFactsInput` + +```ts +interface FindSimilarFactsInput { + spaceName?: string; + statement: string; + provider: EmbeddingProvider; + topicNames?: string[]; + limit?: number; + minimumScore?: number; +} +``` + +### Example + +```ts +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` + +```ts +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` + +```ts +interface FactTopic extends Topic { + role: string | null; + position: number; +} +``` + +### `Fact` + +```ts +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` + +```ts +interface TopicWithFacts extends Topic { + facts: Fact[]; +} +``` + +### `ConnectedTopic` + +```ts +interface ConnectedTopic extends Topic { + sharedFactCount: number; +} +``` + +### Domain enums + +```ts +type TopicCategory = 'entity' | 'concept' | 'temporal' | 'custom'; +type TopicGranularity = 'abstract' | 'concrete' | 'mixed'; +``` + +--- + +## Errors + +The package exposes custom error classes: + +- `IdentityDBError` +- `IdentityDBConfigurationError` + +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()`, and `addTopicAlias()` can create or use spaces on demand +- **Reads** scoped to a missing explicit space usually return `null` or `[]` +- when `spaceName` is omitted, the package falls back to the `default` space + +That means this is valid and isolated: + +```ts +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. + +--- + +## Recommended reading + +- [Getting Started](Getting-Started) +- [Memory Spaces](Memory-Spaces) +- [Extractors](Extractors) +- [Repository](https://git.psw.kr/p-sw/IdentityDB) diff --git a/Getting-Started.md b/Getting-Started.md index 7085084..6a94d19 100644 --- a/Getting-Started.md +++ b/Getting-Started.md @@ -2,6 +2,8 @@ This page shows the concrete workflow for using IdentityDB as a structured memory layer. +For the full exported package surface, see [API Reference](API-Reference). + ## 1. Connect to a database IdentityDB supports SQLite, PostgreSQL, MySQL, and MariaDB through Kysely-backed adapters. diff --git a/Home.md b/Home.md index 3af68aa..a64fd31 100644 --- a/Home.md +++ b/Home.md @@ -62,6 +62,7 @@ That means IdentityDB can answer more than plain keyword lookup. It can tell you ## Recommended reading order - [Getting Started](Getting-Started) — installation, initialization, and concrete examples +- [API Reference](API-Reference) — the exported package surface, method signatures, and return types - [Memory Spaces](Memory-Spaces) — how to keep separate memory graphs isolated - [Extractors](Extractors) — when to use `NaiveExtractor` vs `LlmFactExtractor` diff --git a/_Sidebar.md b/_Sidebar.md index 22392de..3d8966f 100644 --- a/_Sidebar.md +++ b/_Sidebar.md @@ -2,6 +2,7 @@ - [Home](Home) - [Getting Started](Getting-Started) +- [API Reference](API-Reference) - [Memory Spaces](Memory-Spaces) - [Extractors](Extractors) - [Repository](https://git.psw.kr/p-sw/IdentityDB)