import {invoke as tauriInvoke} from '@tauri-apps/api/core'; async function invoke(command: string, args?: Record): Promise { try { return await tauriInvoke(command, args); } catch (e: unknown) { if (e instanceof Error) throw e; if (typeof e === 'string') throw new Error(e); if (typeof e === 'object' && e !== null && 'message' in e) throw new Error(String((e as {message: string}).message)); throw new Error(String(e)); } } export {invoke}; // ─── Types ───────────────────────────────────────────────── import {BookProps, GuideLine, GuideLineAI} from '@/lib/types/book'; import {ChapterProps} from '@/lib/types/chapter'; import {UserProps} from '@/lib/types/user'; export interface InitUserResult { success: boolean; error: string | null; } export interface OfflineResult { success: boolean; error: string | null; userId: string | null; } export interface OfflineModeStatus { enabled: boolean; syncInterval: number; hasPin: boolean; lastUserId: string | null; } export interface SyncCheckResult { shouldSync: boolean; daysSinceSync: number | null; syncInterval: number | null; } export interface TombstoneRecord { table_name: string; entity_id: string; book_id: string | null; deleted_at: number; } // ─── User & Auth ─────────────────────────────────────────── export async function initUser(userId: string): Promise { return invoke('init_user', {data: {userId}}); } export async function dbInitialize(userId: string, encryptionKey: string): Promise { return invoke('db_initialize', {userId, encryptionKey}); } export async function getToken(): Promise { return invoke('get_token'); } export async function setToken(token: string): Promise { return invoke('set_token', {token}); } export async function removeToken(): Promise { return invoke('remove_token'); } export async function getUserEncryptionKey(userId: string): Promise { return invoke('get_user_encryption_key', {userId}); } export async function getPlatform(): Promise { return invoke('get_platform'); } export async function getUserInfo(): Promise { return invoke('get_user_info'); } export async function syncUser(data: { userId: string; username: string; email: string; }): Promise { return invoke('sync_user', {data}); } // ─── Dev ────────────────────────────────────────────────── export async function devResetAll(): Promise { return invoke('dev_reset_all'); } // ─── Offline ─────────────────────────────────────────────── export async function offlinePinSet(pin: string): Promise { return invoke('offline_pin_set', {data: {pin}}); } export async function offlinePinVerify(pin: string): Promise { return invoke('offline_pin_verify', {data: {pin}}); } export async function offlineModeGet(): Promise { return invoke('offline_mode_get'); } export async function offlineModeSet(enabled: boolean, syncIntervalDays: number): Promise { return invoke('offline_mode_set', {data: {enabled, syncIntervalDays}}); } export async function offlineSyncCheck(): Promise { return invoke('offline_sync_check'); } // ─── Book ────────────────────────────────────────────────── export async function getBooks(): Promise { return invoke('get_books'); } export async function getBook(bookId: string): Promise { return invoke('get_book', {bookId}); } export async function createBook(data: { title: string; subTitle?: string; summary?: string; type: string; serieId?: number; desiredReleaseDate?: string; desiredWordCount?: number; }): Promise { return invoke('create_book', {data}); } export async function updateBookBasicInfo(data: { bookId: string; title: string; subTitle: string; summary: string; publicationDate: string; wordCount: number; }): Promise { return invoke('update_book_basic_info', {data}); } export async function deleteBook(id: string, deletedAt: number): Promise { return invoke('delete_book', {data: {id, deletedAt}}); } export async function updateBookToolSetting(bookId: string, toolName: string, enabled: boolean): Promise { return invoke('update_book_tool_setting', {data: {bookId, toolName, enabled}}); } export async function getBookStory(bookId: string): Promise { return invoke('get_book_story', {data: {bookId}}); } export async function updateBookStory(data: { bookId: string; acts: unknown[]; mainChapters: unknown[]; issues: unknown[]; }): Promise { return invoke('update_book_story', {data}); } export async function addIncident(bookId: string, name: string, incidentId?: string): Promise { return invoke('add_incident', {data: {bookId, name, incidentId}}); } export async function removeIncident(bookId: string, incidentId: string, deletedAt: number): Promise { return invoke('remove_incident', {data: {bookId, incidentId, deletedAt}}); } export async function addPlotPoint(bookId: string, name: string, incidentId: string, plotId?: string): Promise { return invoke('add_plot_point', {data: {bookId, name, incidentId, plotId}}); } export async function removePlotPoint(plotId: string, bookId: string, deletedAt: number): Promise { return invoke('remove_plot_point', {data: {plotId, bookId, deletedAt}}); } export async function addIssue(bookId: string, name: string, issueId?: string): Promise { return invoke('add_issue', {data: {bookId, name, issueId}}); } export async function removeIssue(bookId: string, issueId: string, deletedAt: number): Promise { return invoke('remove_issue', {data: {bookId, issueId, deletedAt}}); } export async function getBookBasicInformation(bookId: string): Promise { return invoke('get_book_basic_information', {bookId}); } export async function getBookExportInfo(bookId: string): Promise { return invoke('get_book_export_info', {data: {bookId}}); } export async function exportBook(data: { bookId: string; format: string; selections: unknown[] | null; }): Promise { return invoke('export_book', {data}); } // ─── Book Guidelines ──────────────────────────────────────── export async function getGuideLine(bookId: string): Promise { return invoke('get_guideline', {data: {id: bookId}}); } export async function getAIGuideLine(bookId: string): Promise { return invoke('get_ai_guideline', {data: {id: bookId}}); } export async function updateGuideLine(data: { bookId: string; tone: string; atmosphere: string; writingStyle: string; themes: string; symbolism: string; motifs: string; narrativeVoice: string; pacing: string; intendedAudience: string; keyMessages: string; }): Promise { return invoke('update_guideline', {data}); } export async function updateAIGuideLine(data: { bookId: string; plotSummary: string; verbTense: string; narrativeType: string; dialogueType: string; toneAtmosphere: string; language: string; themes: string; }): Promise { return invoke('update_ai_guideline', {data}); } // ─── Chapter ─────────────────────────────────────────────── export async function getChapters(bookId: string): Promise { return invoke('get_chapters', {bookId}); } export async function getWholeChapter(id: string, version: number, bookId: string): Promise { return invoke('get_whole_chapter', {data: {id, version, bookId}}); } export async function getChapterStory(chapterId: string): Promise { return invoke('get_chapter_story', {chapterId}); } export async function getCompanionContent(chapterId: string, version: number): Promise { return invoke('get_companion_content', {data: {chapterId, version}}); } export async function getChapterContent(chapterId: string, version: number): Promise { return invoke('get_chapter_content', {data: {chapterId, version}}); } export async function saveChapterContent(data: { chapterId: string; version: number; content: unknown; totalWordCount: number; contentId: string; }): Promise { return invoke('save_chapter_content', {data}); } export async function getLastChapter(bookId: string): Promise { return invoke('get_last_chapter', {bookId}); } export async function addChapter(data: { bookId: string; title: string; chapterOrder: number; chapterId?: string; }): Promise { return invoke('add_chapter', {data}); } export async function removeChapter(chapterId: string, bookId: string, deletedAt: number): Promise { return invoke('remove_chapter', {data: {chapterId, bookId, deletedAt}}); } export async function updateChapter(chapterId: string, title: string, chapterOrder: number): Promise { return invoke('update_chapter', {data: {chapterId, title, chapterOrder}}); } export async function addChapterInformation(data: { chapterId: string; actId: number; bookId: string; plotId?: string; incidentId?: string; chapterInfoId?: string; }): Promise { return invoke('add_chapter_information', {data}); } export async function removeChapterInformation(chapterInfoId: string, bookId: string, deletedAt: number): Promise { return invoke('remove_chapter_information', {data: {chapterInfoId, bookId, deletedAt}}); } export async function getBookTags(bookId: string): Promise { return invoke('get_book_tags', {bookId}); } // ─── Character ───────────────────────────────────────────── export async function getCharacterList(bookId: string, enabled: boolean): Promise { return invoke('get_character_list', {data: {bookId, enabled}}); } export async function getCharacterAttributes(characterId: string): Promise { return invoke('get_character_attributes', {data: {characterId}}); } export async function createCharacter(character: unknown, bookId: string, id?: string): Promise { return invoke('create_character', {data: {character, bookId, id}}); } export async function addCharacterAttribute(characterId: string, type: string, name: string, id?: string): Promise { return invoke('add_character_attribute', {data: {characterId, type, name, id}}); } export async function deleteCharacterAttribute(attributeId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_character_attribute', {data: {attributeId, bookId, deletedAt}}); } export async function updateCharacter(character: unknown): Promise { return invoke('update_character', {data: {character}}); } export async function deleteCharacter(characterId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_character', {data: {characterId, bookId, deletedAt}}); } // ─── Location ────────────────────────────────────────────── export async function getAllLocations(bookId: string, enabled: boolean): Promise { return invoke('get_all_locations', {data: {bookId, enabled}}); } export async function addLocationSection(locationName: string, bookId: string, id?: string, seriesLocationId?: string): Promise { return invoke('add_location_section', {data: {locationName, bookId, id, seriesLocationId}}); } export async function addLocationElement(locationId: string, elementName: string, id?: string): Promise { return invoke('add_location_element', {data: {locationId, elementName, id}}); } export async function addLocationSubElement(elementId: string, subElementName: string, id?: string): Promise { return invoke('add_location_sub_element', {data: {elementId, subElementName, id}}); } export async function updateLocations(locations: unknown[]): Promise { return invoke('update_locations', {data: {locations}}); } export async function updateLocationSectionWithSeriesLink(sectionId: string, sectionName?: string, seriesLocationId?: string): Promise { return invoke('update_location_section_with_series_link', {data: {sectionId, sectionName, seriesLocationId}}); } export async function deleteLocationSection(locationId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_location_section', {data: {locationId, bookId, deletedAt}}); } export async function deleteLocationElement(elementId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_location_element', {data: {elementId, bookId, deletedAt}}); } export async function deleteLocationSubElement(subElementId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_location_sub_element', {data: {subElementId, bookId, deletedAt}}); } // ─── Spell ───────────────────────────────────────────────── export async function getSpellList(bookId: string, enabled: boolean): Promise { return invoke('get_spell_list', {data: {bookId, enabled}}); } export async function getSpellTags(bookId: string): Promise { return invoke('get_spell_tags', {data: {bookId}}); } export async function getSpellDetail(spellId: string): Promise { return invoke('get_spell_detail', {data: {spellId}}); } export async function createSpell(bookId: string, spell: unknown): Promise { return invoke('create_spell', {data: {bookId, spell}}); } export async function updateSpell(spellId: string, spell: unknown): Promise { return invoke('update_spell', {data: {spellId, spell}}); } export async function deleteSpell(spellId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_spell', {data: {spellId, bookId, deletedAt}}); } export async function createSpellTag(bookId: string, name: string, color?: string, id?: string): Promise { return invoke('create_spell_tag', {data: {bookId, name, color, id}}); } export async function updateSpellTag(tagId: string, name: string, color?: string): Promise { return invoke('update_spell_tag', {data: {tagId, name, color}}); } export async function deleteSpellTag(tagId: string, bookId: string, deletedAt: number): Promise { return invoke('delete_spell_tag', {data: {tagId, bookId, deletedAt}}); } // ─── World ───────────────────────────────────────────────── export async function getWorlds(bookId: string, enabled: boolean): Promise { return invoke('get_worlds', {data: {bookId, enabled}}); } export async function addWorld(bookId: string, worldName: string, id?: string, seriesWorldId?: string): Promise { return invoke('add_world', {data: {bookId, worldName, id, seriesWorldId}}); } export async function addWorldElement(worldId: string, elementName: string, elementType: string, id?: string): Promise { return invoke('add_world_element', {data: {worldId, elementName, elementType, id}}); } export async function removeWorldElement(elementId: string, bookId: string, deletedAt: number): Promise { return invoke('remove_world_element', {data: {elementId, bookId, deletedAt}}); } export async function updateWorld(world: unknown): Promise { return invoke('update_world', {data: {world}}); } // ─── Series ──────────────────────────────────────────────── export async function getSeriesList(): Promise { return invoke('get_series_list'); } export async function getSeriesDetail(seriesId: string): Promise { return invoke('get_series_detail', {data: {seriesId}}); } export async function createSeries(data: unknown): Promise { return invoke('create_series', {data}); } export async function updateSeries(data: unknown): Promise { return invoke('update_series', {data}); } export async function deleteSeries(seriesId: string, deletedAt: number): Promise { return invoke('delete_series', {data: {seriesId, deletedAt}}); } export async function getSeriesBooks(seriesId: string): Promise { return invoke('get_series_books', {data: {seriesId}}); } export async function addBookToSeries(seriesId: string, bookId: string): Promise { return invoke('add_book_to_series', {data: {seriesId, bookId}}); } export async function removeBookFromSeries(seriesId: string, bookId: string, deletedAt: number): Promise { return invoke('remove_book_from_series', {data: {seriesId, bookId, deletedAt}}); } export async function reorderSeriesBooks(seriesId: string, bookIds: string[]): Promise { return invoke('reorder_series_books', {data: {seriesId, bookIds}}); } export async function getSeriesForBook(bookId: string): Promise { return invoke('get_series_for_book', {data: {bookId}}); } // ─── Series Characters ───────────────────────────────────── export async function getSeriesCharacterList(seriesId: string): Promise { return invoke('get_series_character_list', {data: {seriesId}}); } export async function getSeriesCharacterAttributes(characterId: string): Promise { return invoke('get_series_character_attributes', {data: {characterId}}); } export async function addSeriesCharacter(data: unknown): Promise { return invoke('add_series_character', {data}); } export async function updateSeriesCharacter(data: unknown): Promise { return invoke('update_series_character', {data}); } export async function deleteSeriesCharacter(characterId: string, deletedAt: number): Promise { return invoke('delete_series_character', {data: {characterId, deletedAt}}); } export async function addSeriesCharacterAttribute(data: unknown): Promise { return invoke('add_series_character_attribute', {data}); } export async function deleteSeriesCharacterAttribute(attributeId: string, deletedAt: number): Promise { return invoke('delete_series_character_attribute', {data: {attributeId, deletedAt}}); } // ─── Series Locations ────────────────────────────────────── export async function getSeriesLocationList(seriesId: string): Promise { return invoke('get_series_location_list', {data: {seriesId}}); } export async function addSeriesLocationSection(data: unknown): Promise { return invoke('add_series_location_section', {data}); } export async function addSeriesLocationElement(data: unknown): Promise { return invoke('add_series_location_element', {data}); } export async function addSeriesLocationSubElement(data: unknown): Promise { return invoke('add_series_location_sub_element', {data}); } export async function deleteSeriesLocation(locationId: string, deletedAt: number): Promise { return invoke('delete_series_location', {data: {locationId, deletedAt}}); } export async function deleteSeriesLocationElement(elementId: string, deletedAt: number): Promise { return invoke('delete_series_location_element', {data: {elementId, deletedAt}}); } export async function deleteSeriesLocationSubElement(subElementId: string, deletedAt: number): Promise { return invoke('delete_series_location_sub_element', {data: {subElementId, deletedAt}}); } // ─── Series Worlds ───────────────────────────────────────── export async function getSeriesWorldList(seriesId: string): Promise { return invoke('get_series_world_list', {data: {seriesId}}); } export async function addSeriesWorld(data: unknown): Promise { return invoke('add_series_world', {data}); } export async function updateSeriesWorld(data: unknown): Promise { return invoke('update_series_world', {data}); } export async function addSeriesWorldElement(data: unknown): Promise { return invoke('add_series_world_element', {data}); } export async function deleteSeriesWorldElement(elementId: string, deletedAt: number): Promise { return invoke('delete_series_world_element', {data: {elementId, deletedAt}}); } // ─── Series Spells ───────────────────────────────────────── export async function getSeriesSpellList(seriesId: string): Promise { return invoke('get_series_spell_list', {data: {seriesId}}); } export async function getSeriesSpellDetail(spellId: string): Promise { return invoke('get_series_spell_detail', {data: {spellId}}); } export async function addSeriesSpell(data: unknown): Promise { return invoke('add_series_spell', {data}); } export async function updateSeriesSpell(data: unknown): Promise { return invoke('update_series_spell', {data}); } export async function deleteSeriesSpell(spellId: string, deletedAt: number): Promise { return invoke('delete_series_spell', {data: {spellId, deletedAt}}); } export async function addSeriesSpellTag(data: unknown): Promise { return invoke('add_series_spell_tag', {data}); } export async function updateSeriesSpellTag(data: unknown): Promise { return invoke('update_series_spell_tag', {data}); } export async function deleteSeriesSpellTag(tagId: string, deletedAt: number): Promise { return invoke('delete_series_spell_tag', {data: {tagId, deletedAt}}); } // ─── Sync (books/series) ─────────────────────────────────── export async function getSyncedBooks(): Promise { return invoke('get_synced_books'); } export async function getSyncedSeries(): Promise { return invoke('get_synced_series'); } export async function uploadBookToServer(bookId: string): Promise { return invoke('upload_book_to_server', {bookId}); } export async function syncSaveBook(book: unknown): Promise { return invoke('sync_save_book', {data: book}); } export async function syncBookToClient(book: unknown): Promise { return invoke('sync_book_to_client', {data: book}); } export async function syncBookToServer(bookToSync: unknown): Promise { return invoke('sync_book_to_server', {data: bookToSync}); } export async function uploadSeriesToServer(seriesId: string): Promise { return invoke('upload_series_to_server', {seriesId}); } export async function syncSaveSeries(series: unknown): Promise { return invoke('sync_save_series', {data: series}); } export async function syncSeriesToClient(series: unknown): Promise { return invoke('sync_series_to_client', {data: series}); } export async function syncSeriesToServer(seriesToSync: unknown): Promise { return invoke('sync_series_to_server', {data: seriesToSync}); } export async function seriesSyncUpload(data: { type: string; bookElementId: string; field: string; value: string; }): Promise { return invoke('series_sync_upload', {data}); } // ─── Tombstones ──────────────────────────────────────────── export async function getTombstonesSince(since: number): Promise { return invoke('get_tombstones_since', {since}); } export async function applyBookTombstones(tombstones: TombstoneRecord[]): Promise { return invoke('apply_book_tombstones', {tombstones}); } export async function applySeriesTombstones(tombstones: TombstoneRecord[]): Promise { return invoke('apply_series_tombstones', {tombstones}); } // ─── Migration ──────────────────────────────────────────────── export interface MigrationCheckResult { found: boolean; userId: string | null; hasDb: boolean; migrationPath: string | null; } export interface MigrationResult { success: boolean; userId: string | null; error: string | null; } export async function checkElectronMigration(migrationFilePath: string): Promise { return invoke('check_electron_migration', {migrationFilePath}); } export async function importFromElectron(migrationFilePath: string): Promise { return invoke('import_from_electron', {data: {migrationFilePath}}); } // ─── Window Management ────────────────────────────────────── let loginWindowOpening = false; export async function openLoginWindow(): Promise { if (loginWindowOpening) return; loginWindowOpening = true; const {WebviewWindow} = await import('@tauri-apps/api/webviewWindow'); const {getCurrentWindow} = await import('@tauri-apps/api/window'); const existing = await WebviewWindow.getByLabel('login'); if (existing) { await existing.setFocus(); await getCurrentWindow().hide(); loginWindowOpening = false; return; } const loginWindow = new WebviewWindow('login', { url: '/login/login/', title: 'ERitors - Connexion', width: 500, height: 900, resizable: false, center: true, decorations: true, }); loginWindow.once('tauri://created', async function () { loginWindowOpening = false; await getCurrentWindow().hide(); }); } export async function loginSuccess(): Promise { const {WebviewWindow} = await import('@tauri-apps/api/webviewWindow'); const {getCurrentWindow} = await import('@tauri-apps/api/window'); const currentLabel = getCurrentWindow().label; if (currentLabel === 'login') { const mainWindow = await WebviewWindow.getByLabel('main'); if (mainWindow) { await mainWindow.show(); await mainWindow.setFocus(); await mainWindow.emit('auth-success'); } getCurrentWindow().close(); } else { window.location.reload(); } } export async function logout(): Promise { await removeToken(); await openLoginWindow(); } export async function openExternal(url: string): Promise { const {open} = await import('@tauri-apps/plugin-shell'); return open(url); }