Files
IdentityDB/src/core/utils.ts

123 lines
3.2 KiB
TypeScript

import { createHash, randomUUID } from 'node:crypto';
import type { Fact, FactTopic, Space, Topic } from '../types/api';
import type { FactRecord, SpaceRecord, TopicRecord } from '../types/domain';
export function normalizeTopicName(name: string): string {
return name.trim().replace(/\s+/g, ' ').toLowerCase();
}
export function canonicalizeTopicName(name: string): string {
return name.trim().replace(/\s+/g, ' ');
}
export function normalizeSpaceName(name: string): string {
return normalizeTopicName(name);
}
export function canonicalizeSpaceName(name: string): string {
return canonicalizeTopicName(name);
}
export function nowIsoString(): string {
return new Date().toISOString();
}
export function createId(): string {
return randomUUID();
}
export function serializeMetadata(metadata: unknown): string | null {
if (metadata === undefined || metadata === null) {
return null;
}
return JSON.stringify(metadata);
}
export function deserializeMetadata(metadata: string | null): unknown | null {
if (metadata === null) {
return null;
}
return JSON.parse(metadata);
}
export function serializeEmbedding(embedding: number[]): string {
return JSON.stringify(embedding);
}
export function deserializeEmbedding(embedding: string): number[] {
return JSON.parse(embedding) as number[];
}
export function createContentHash(input: string): string {
return createHash('sha256').update(input).digest('hex');
}
export function cosineSimilarity(left: number[], right: number[]): number {
if (left.length === 0 || left.length !== right.length) {
return 0;
}
let dot = 0;
let leftMagnitude = 0;
let rightMagnitude = 0;
for (let index = 0; index < left.length; index += 1) {
const leftValue = left[index] ?? 0;
const rightValue = right[index] ?? 0;
dot += leftValue * rightValue;
leftMagnitude += leftValue * leftValue;
rightMagnitude += rightValue * rightValue;
}
if (leftMagnitude === 0 || rightMagnitude === 0) {
return 0;
}
return dot / (Math.sqrt(leftMagnitude) * Math.sqrt(rightMagnitude));
}
export function mapSpaceRow(record: SpaceRecord): Space {
return {
id: record.id,
name: record.name,
normalizedName: record.normalized_name,
description: record.description,
metadata: deserializeMetadata(record.metadata) as Space['metadata'],
createdAt: record.created_at,
updatedAt: record.updated_at,
};
}
export function mapTopicRow(record: TopicRecord): Topic {
return {
id: record.id,
spaceId: record.space_id,
name: record.name,
normalizedName: record.normalized_name,
category: record.category,
granularity: record.granularity,
description: record.description,
metadata: deserializeMetadata(record.metadata) as Topic['metadata'],
createdAt: record.created_at,
updatedAt: record.updated_at,
};
}
export function mapFactRow(record: FactRecord, topics: FactTopic[]): Fact {
return {
id: record.id,
spaceId: record.space_id,
statement: record.statement,
summary: record.summary,
source: record.source,
confidence: record.confidence,
metadata: deserializeMetadata(record.metadata) as Fact['metadata'],
createdAt: record.created_at,
updatedAt: record.updated_at,
topics,
};
}