Remove DataService and OfflineDataService, refactor book and character operations to use streamlined handlers in LocalSystem
- Delete `data.service.ts` and `offline-data.service.ts`, consolidating functionality into `LocalSystem`. - Refactor book, character, and conversation operations to adopt unified, multilingual, and session-enabled IPC handlers in `LocalSystem`. - Simplify redundant legacy methods, enhancing maintainability and consistency.
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
import type { IpcMainInvokeEvent } from 'electron';
|
||||
import Store from 'electron-store';
|
||||
|
||||
// Electron store instance for session management
|
||||
// ============================================================
|
||||
// SESSION MANAGEMENT - Auto-inject userId and lang
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Electron store instance for session management
|
||||
* - userId: Set during login via 'login-success' event
|
||||
* - userLang: Set via 'set-lang' handler
|
||||
*/
|
||||
const store = new Store({
|
||||
encryptionKey: 'eritors-scribe-secure-key'
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// SESSION MANAGEMENT - Retrieve userId and lang from store
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Get userId from electron-store
|
||||
* Set during login via 'login-success' event
|
||||
@@ -27,122 +31,67 @@ function getLangFromSession(): 'fr' | 'en' {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// LEGACY HANDLERS - Manual userId injection, lang must be passed
|
||||
// Keep these for backward compatibility
|
||||
// Updated to support Promises
|
||||
// ============================================================
|
||||
|
||||
export function createDbHandler<TReturn>(
|
||||
handler: (userId: string) => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createDbHandler1<T1, TReturn>(
|
||||
handler: (userId: string, arg1: T1) => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createDbHandler2<T1, T2, TReturn>(
|
||||
handler: (userId: string, arg1: T1, arg2: T2) => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1, arg2);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createDbHandler3<T1, T2, T3, TReturn>(
|
||||
handler: (userId: string, arg1: T1, arg2: T2, arg3: T3) => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1, arg2, arg3);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AUTO HANDLERS - Automatically inject userId AND lang
|
||||
// Use these for new handlers - no need to pass lang from frontend
|
||||
// UNIVERSAL HANDLER - Like a Fastify route
|
||||
// Automatically injects: userId, lang
|
||||
// Optional body parameter (for GET, POST, PUT, DELETE)
|
||||
// Generic return type (void, object, etc.)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Auto-handler with 0 parameters
|
||||
* Automatically injects: userId, lang
|
||||
* Universal IPC handler - works like a Fastify route
|
||||
* Automatically injects: userId, lang from session
|
||||
*
|
||||
* @template TBody - Request body type (use void for no params)
|
||||
* @template TReturn - Response type (use void for no return)
|
||||
*
|
||||
* @example
|
||||
* ipcMain.handle('db:user:get', createAutoHandler<UserProps>(
|
||||
* function(userId: string, lang: 'fr' | 'en') {
|
||||
* return User.getUser(userId, lang);
|
||||
* }
|
||||
* ));
|
||||
* // GET with no params
|
||||
* ipcMain.handle('db:books:getAll',
|
||||
* createHandler<void, BookProps[]>(
|
||||
* async (userId, body, lang) => {
|
||||
* return await Book.getBooks(userId, lang);
|
||||
* }
|
||||
* )
|
||||
* );
|
||||
* // Frontend: invoke('db:books:getAll')
|
||||
*
|
||||
* // Frontend call (no params needed):
|
||||
* const user = await window.electron.invoke('db:user:get');
|
||||
* @example
|
||||
* // GET with 1 param
|
||||
* ipcMain.handle('db:book:get',
|
||||
* createHandler<string, BookProps>(
|
||||
* async (userId, bookId, lang) => {
|
||||
* return await Book.getBook(bookId, userId, lang);
|
||||
* }
|
||||
* )
|
||||
* );
|
||||
* // Frontend: invoke('db:book:get', bookId)
|
||||
*
|
||||
* @example
|
||||
* // POST with object body
|
||||
* ipcMain.handle('db:book:create',
|
||||
* createHandler<CreateBookData, string>(
|
||||
* async (userId, data, lang) => {
|
||||
* return await Book.addBook(userId, data, lang);
|
||||
* }
|
||||
* )
|
||||
* );
|
||||
* // Frontend: invoke('db:book:create', { title: '...', ... })
|
||||
*
|
||||
* @example
|
||||
* // DELETE with void return
|
||||
* ipcMain.handle('db:book:delete',
|
||||
* createHandler<string, void>(
|
||||
* async (userId, bookId, lang) => {
|
||||
* await Book.deleteBook(bookId, userId, lang);
|
||||
* }
|
||||
* )
|
||||
* );
|
||||
* // Frontend: invoke('db:book:delete', bookId)
|
||||
*/
|
||||
export function createAutoHandler<TReturn>(
|
||||
handler: (userId: string, lang: 'fr' | 'en') => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent): Promise<TReturn> {
|
||||
export function createHandler<TBody = void, TReturn = void>(
|
||||
handler: (userId: string, body: TBody, lang: 'fr' | 'en') => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, body?: TBody) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, body?: TBody): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
const lang = getLangFromSession();
|
||||
|
||||
@@ -151,7 +100,7 @@ export function createAutoHandler<TReturn>(
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, lang);
|
||||
return await handler(userId, body as TBody, lang);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
@@ -161,122 +110,3 @@ export function createAutoHandler<TReturn>(
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-handler with 1 parameter
|
||||
* Automatically injects: userId, lang
|
||||
*
|
||||
* @example
|
||||
* ipcMain.handle('db:book:get', createAutoHandler1<string, BookProps>(
|
||||
* function(userId: string, bookId: string, lang: 'fr' | 'en') {
|
||||
* return Book.getBook(bookId, userId, lang);
|
||||
* }
|
||||
* ));
|
||||
*
|
||||
* // Frontend call (only bookId needed):
|
||||
* const book = await window.electron.invoke('db:book:get', bookId);
|
||||
*/
|
||||
export function createAutoHandler1<T1, TReturn>(
|
||||
handler: (userId: string, arg1: T1, lang: 'fr' | 'en') => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
const lang = getLangFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1, lang);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-handler with 2 parameters
|
||||
* Automatically injects: userId, lang
|
||||
*
|
||||
* @example
|
||||
* ipcMain.handle('db:book:create', createAutoHandler1<CreateBookData, string>(
|
||||
* function(userId: string, data: CreateBookData, lang: 'fr' | 'en') {
|
||||
* return Book.addBook(null, userId, data.title, ..., lang);
|
||||
* }
|
||||
* ));
|
||||
*
|
||||
* // Frontend call (only data needed):
|
||||
* const bookId = await window.electron.invoke('db:book:create', bookData);
|
||||
*/
|
||||
export function createAutoHandler2<T1, T2, TReturn>(
|
||||
handler: (userId: string, arg1: T1, arg2: T2, lang: 'fr' | 'en') => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
const lang = getLangFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1, arg2, lang);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-handler with 3 parameters
|
||||
* Automatically injects: userId, lang
|
||||
*
|
||||
* @example
|
||||
* ipcMain.handle('db:book:cover:update', createAutoHandler2<string, string, boolean>(
|
||||
* function(userId: string, bookId: string, coverImageName: string, lang: 'fr' | 'en') {
|
||||
* return Book.updateBookCover(userId, bookId, coverImageName, lang);
|
||||
* }
|
||||
* ));
|
||||
*
|
||||
* // Frontend call (bookId and coverImageName needed):
|
||||
* const success = await window.electron.invoke('db:book:cover:update', bookId, coverImageName);
|
||||
*/
|
||||
export function createAutoHandler3<T1, T2, T3, TReturn>(
|
||||
handler: (userId: string, arg1: T1, arg2: T2, arg3: T3, lang: 'fr' | 'en') => TReturn | Promise<TReturn>
|
||||
): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3) => Promise<TReturn> {
|
||||
return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3): Promise<TReturn> {
|
||||
const userId = getUserIdFromSession();
|
||||
const lang = getLangFromSession();
|
||||
|
||||
if (!userId) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(userId, arg1, arg2, arg3, lang);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
console.error(`[DB] ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
throw new Error('An unknown error occurred.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createUniqueId(): string {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
export function getCurrentDate(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user