import type { IpcMainInvokeEvent } from 'electron'; import Store from 'electron-store'; // Electron store instance for session management 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 */ function getUserIdFromSession(): string | null { return store.get('userId', null) as string | null; } /** * Get lang from electron-store * Set via 'set-lang' handler, defaults to 'fr' */ function getLangFromSession(): 'fr' | 'en' { return store.get('userLang', 'fr') as 'fr' | 'en'; } // ============================================================ // LEGACY HANDLERS - Manual userId injection, lang must be passed // Keep these for backward compatibility // Updated to support Promises // ============================================================ export function createDbHandler( handler: (userId: string) => TReturn | Promise ): (event: IpcMainInvokeEvent) => Promise { return async function(event: IpcMainInvokeEvent): Promise { 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( handler: (userId: string, arg1: T1) => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1): Promise { 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( handler: (userId: string, arg1: T1, arg2: T2) => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2): Promise { 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( handler: (userId: string, arg1: T1, arg2: T2, arg3: T3) => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3): Promise { 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 // ============================================================ /** * Auto-handler with 0 parameters * Automatically injects: userId, lang * * @example * ipcMain.handle('db:user:get', createAutoHandler( * function(userId: string, lang: 'fr' | 'en') { * return User.getUser(userId, lang); * } * )); * * // Frontend call (no params needed): * const user = await window.electron.invoke('db:user:get'); */ export function createAutoHandler( handler: (userId: string, lang: 'fr' | 'en') => TReturn | Promise ): (event: IpcMainInvokeEvent) => Promise { return async function(event: IpcMainInvokeEvent): Promise { const userId = getUserIdFromSession(); const lang = getLangFromSession(); if (!userId) { throw new Error('User not authenticated'); } try { return await handler(userId, 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 1 parameter * Automatically injects: userId, lang * * @example * ipcMain.handle('db:book:get', createAutoHandler1( * 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( handler: (userId: string, arg1: T1, lang: 'fr' | 'en') => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1): Promise { 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( * 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( handler: (userId: string, arg1: T1, arg2: T2, lang: 'fr' | 'en') => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2): Promise { 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( * 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( handler: (userId: string, arg1: T1, arg2: T2, arg3: T3, lang: 'fr' | 'en') => TReturn | Promise ): (event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3) => Promise { return async function(event: IpcMainInvokeEvent, arg1: T1, arg2: T2, arg3: T3): Promise { 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(); }