Add database schema, encryption utilities, and local database service

- Implement `schema.ts` for SQLite schema creation, indexing, and sync metadata initialization.
- Develop `encryption.ts` with AES-256-GCM encryption utilities for securing database data.
- Add `database.service.ts` to manage CRUD operations with encryption support, user-specific databases, and schema initialization.
- Integrate book, chapter, and character operations with encrypted content handling and sync preparation.
This commit is contained in:
natreex
2025-11-17 09:34:54 -05:00
parent 09768aafcf
commit d5eb1691d9
12 changed files with 2763 additions and 197 deletions

View File

@@ -0,0 +1,174 @@
/**
* TypeScript interfaces (copied from lib/models for type safety)
*/
export interface ChapterContent {
version: number;
content: string;
wordsCount: number;
}
export interface ChapterProps {
chapterId: string;
chapterOrder: number;
title: string;
chapterContent: ChapterContent;
}
export interface ActChapter {
chapterInfoId: string;
chapterId: string;
title: string;
chapterOrder: number;
actId: number;
incidentId?: string;
plotPointId?: string;
summary: string;
goal: string;
}
/**
* Database row types (snake_case from SQLite)
*/
export interface DBChapter {
chapter_id: string;
book_id: string;
author_id: string;
title: string;
hashed_title?: string;
words_count?: number;
chapter_order?: number;
meta_chapter: string;
synced?: number;
}
export interface DBChapterContent {
content_id: string;
chapter_id: string;
author_id: string;
version: number;
content: string;
words_count: number;
meta_chapter_content: string;
time_on_it: number;
synced?: number;
}
export interface DBChapterInfo {
chapter_info_id: string;
chapter_id?: string;
act_id?: number;
incident_id?: string;
plot_point_id?: string;
book_id?: string;
author_id?: string;
summary: string;
goal: string;
meta_chapter_info: string;
synced?: number;
}
/**
* MAPPERS: DB → TypeScript Interfaces
*/
export function dbToChapter(dbChapter: DBChapter, dbContent?: DBChapterContent): ChapterProps {
const chapterContent: ChapterContent = dbContent ? {
version: dbContent.version,
content: dbContent.content,
wordsCount: dbContent.words_count
} : {
version: 2,
content: '',
wordsCount: 0
};
return {
chapterId: dbChapter.chapter_id,
chapterOrder: dbChapter.chapter_order || 0,
title: dbChapter.title,
chapterContent
};
}
export function dbToChapterContent(dbContent: DBChapterContent): ChapterContent {
return {
version: dbContent.version,
content: dbContent.content,
wordsCount: dbContent.words_count
};
}
export function dbToActChapter(dbChapter: DBChapter, dbInfo: DBChapterInfo): ActChapter {
return {
chapterInfoId: dbInfo.chapter_info_id,
chapterId: dbChapter.chapter_id,
title: dbChapter.title,
chapterOrder: dbChapter.chapter_order || 0,
actId: dbInfo.act_id || 0,
incidentId: dbInfo.incident_id,
plotPointId: dbInfo.plot_point_id,
summary: dbInfo.summary,
goal: dbInfo.goal
};
}
/**
* MAPPERS: TypeScript Interfaces → DB
*/
export function chapterToDb(chapter: ChapterProps, bookId: string, authorId: string, synced: number = 0): DBChapter {
return {
chapter_id: chapter.chapterId,
book_id: bookId,
author_id: authorId,
title: chapter.title,
hashed_title: '',
words_count: chapter.chapterContent.wordsCount,
chapter_order: chapter.chapterOrder,
meta_chapter: '',
synced
};
}
export function chapterContentToDb(
content: ChapterContent,
contentId: string,
chapterId: string,
authorId: string,
timeOnIt: number = 0,
synced: number = 0
): DBChapterContent {
return {
content_id: contentId,
chapter_id: chapterId,
author_id: authorId,
version: content.version,
content: content.content,
words_count: content.wordsCount,
meta_chapter_content: '',
time_on_it: timeOnIt,
synced
};
}
export function actChapterToDbInfo(
actChapter: ActChapter,
bookId: string,
authorId: string,
synced: number = 0
): DBChapterInfo {
return {
chapter_info_id: actChapter.chapterInfoId,
chapter_id: actChapter.chapterId,
act_id: actChapter.actId,
incident_id: actChapter.incidentId,
plot_point_id: actChapter.plotPointId,
book_id: bookId,
author_id: authorId,
summary: actChapter.summary,
goal: actChapter.goal,
meta_chapter_info: '',
synced
};
}