The Repository is the primary data access layer. It provides typed CRUD operations for all knowledge base entities and runs on both browser (SQLite WASM) and CLI (better-sqlite3).
import { repository } from '../db/repository';
// Create an entity
const entity = await repository.createEntity({
name: 'TRIZ',
type: 'concept',
description: 'Theory of Inventive Problem Solving',
});
// Search entities
const results = await repository.searchEntities('invention');
// Get entity by name
const found = await repository.getEntityByName('TRIZ');UI / CLI
│
▼
┌─────────────────────┐
│ Repository │ ← High-level typed API
│ (index.ts) │
└────────┬────────────┘
│
┌────┴────────────────────┐
▼ ▼
┌─────────────┐ ┌──────────────────┐
│ entities │ │ claims / notes │
│ (entities │ │ (claims.ts, │
│ .ts) │ │ notes.ts) │
└──────┬──────┘ └────────┬─────────┘
│ │
└────────┬───────────┘
▼
┌────────────────┐
│ RepositoryBase │ ← exec(), execRows(), transaction()
│ (base.ts) │
└────────┬───────┘
▼
┌────────────────┐
│ SQLiteDB │ ← Browser (WASM+OPFS) or Node (better-sqlite3)
│ (client.ts) │
└────────────────┘
Create a new entity. All fields except name and type are optional.
const entity = await repository.createEntity({
name: 'Altshuller',
type: 'person',
description: 'Creator of TRIZ',
source_url: 'https://en.wikipedia.org/wiki/Genrich_Altshuller',
metadata: { nationality: 'Russian' },
});Get all entities ordered by name.
const entities = await repository.getAllEntities();
const page = await repository.getAllEntities({ limit: 20, offset: 40 });Get entities with filtering, sorting, and pagination.
const filtered = await repository.getEntities({
type: 'concept',
search: 'invention',
sortBy: 'created_at',
sortOrder: 'DESC',
limit: 10,
});Count entities with optional filtering.
const count = await repository.getEntitiesCount({ type: 'concept' });const entity = await repository.getEntityById('uuid-here');const entity = await repository.getEntityByName('TRIZ');const updated = await repository.updateEntity(entity.id, {
description: 'Updated description',
type: 'methodology',
});Cascade deletes all claims, notes, and links.
await repository.deleteEntity(entity.id);Full-text search using FTS5 with porter stemming.
const results = await repository.searchEntities('problem solving');Multi-stage search (FTS5 → Orama → related entities). Returns scored results.
const results = await repository.searchRelated('invention', {
excludeIds: new Set(['already-shown-id']),
});const claim = await repository.createClaim({
entity_id: entity.id,
statement: 'TRIZ was developed in 1946',
confidence: 0.95,
evidence: 'Historical records',
source: 'Wikipedia',
});const unverified = await repository.getClaimsByVerificationStatus('unverified');const verified = await repository.updateClaimVerification(claim.id, 'verified');const note = await repository.createNote({
entity_id: entity.id,
content: 'Key insight about this concept',
format: 'markdown',
});Links represent directed relationships between entities.
const link = await repository.createLink({
source_id: entityA.id,
target_id: entityB.id,
relation: 'inspired_by',
});Get all entities that link TO the given entity.
const backlinks = await repository.getBacklinks(entity.id);const diff = await repository.diffSnapshots(snap1.id, snap2.id);
// diff.added_nodes, diff.removed_nodes, diff.added_edges, diff.removed_edgesawait repository.upsertWebCache(url, 'page content', 'Page Title', 'markdown');
const cached = await repository.getWebCache(url);Execute raw SQL. Returns unknown (use with care).
Execute raw SQL and return parsed rows.
Execute multiple statements in a transaction.
All data is validated at the repository boundary using Zod schemas from src/lib/validation.ts:
EntitySchema— validates entities with name, type, description, source_url, metadataClaimSchema— validates claims with confidence (0–1), verification_statusNoteSchema— validates notes with format (markdown/plain)LinkSchema— validates links with source_id, target_id, relation
The parseMetadata() method in RepositoryBase handles:
- JSON string → object parsing for metadata fields
- Null → undefined normalization for optional fields
Repository methods throw AppError (from src/lib/errors.ts) with:
message— human-readable error descriptioncode— machine-readable error code (e.g.'DB_ERROR')context— additional error contextrecoverable— whether the error is recoverable
| File | Purpose |
|---|---|
src/db/repository/index.ts |
Main Repository class + singleton export |
src/db/repository/base.ts |
Base class with exec/transaction/parseMetadata |
src/db/repository/types.ts |
IRepository interface + types |
src/db/repository/entities.ts |
Entity CRUD operations |
src/db/repository/claims.ts |
Claim CRUD operations |
src/db/repository/notes.ts |
Note CRUD operations |
src/db/repository/links.ts |
Link CRUD operations |
src/db/repository/graph-snapshots.ts |
Snapshot operations |
src/db/repository/web-cache.ts |
Web cache operations |
src/lib/validation.ts |
Zod schemas for all data types |
src/lib/errors.ts |
AppError class |