UNPKG

@workspace-fs/core

Version:

Multi-project workspace manager for Firesystem with support for multiple sources

178 lines (156 loc) 4.77 kB
import type { Project, ProjectConfig, WorkspaceSettings } from "../types"; import { WorkspaceDatabase, StoredProject, WorkspaceState } from "../WorkspaceDatabase"; export class PersistenceManager { constructor( private database: WorkspaceDatabase, private checkProjectAccessible: (projectId: string) => Promise<boolean>, ) {} /** * Restore workspace state from database */ async restoreWorkspaceState(): Promise<{ state: WorkspaceState | null; activeProjectToLoad: StoredProject | null; }> { try { // Get stored state const state = await this.database.getWorkspaceState(); if (!state) return { state: null, activeProjectToLoad: null }; // Validate and clean orphaned references let stateChanged = false; // Validate activeProjectId if (state.activeProjectId) { const activeProjectAccessible = await this.checkProjectAccessible( state.activeProjectId, ); if (!activeProjectAccessible) { console.warn( `Removing orphaned activeProjectId: ${state.activeProjectId}`, ); state.activeProjectId = null; stateChanged = true; } } // Validate recentProjectIds if (state.recentProjectIds && state.recentProjectIds.length > 0) { const validRecentIds: string[] = []; for (const projectId of state.recentProjectIds) { const projectAccessible = await this.checkProjectAccessible(projectId); if (projectAccessible) { validRecentIds.push(projectId); } else { console.warn(`Removing orphaned recentProjectId: ${projectId}`); stateChanged = true; } } state.recentProjectIds = validRecentIds; } // Save cleaned state if any orphaned references were found if (stateChanged) { await this.database.saveWorkspaceState(state); console.info( "Workspace state cleaned: removed orphaned project references", ); } // Get active project to load let activeProjectToLoad: StoredProject | null = null; if (state.activeProjectId) { const storedProjects = await this.database.listProjects(); activeProjectToLoad = storedProjects.find( (p) => p.id === state.activeProjectId, ) || null; } return { state, activeProjectToLoad }; } catch (error) { console.error("Failed to restore workspace state:", error); return { state: null, activeProjectToLoad: null }; } } /** * Save current workspace state to database */ async saveWorkspaceState( activeProjectId: string | null, recentProjectIds: string[], settings: WorkspaceSettings, ): Promise<void> { const state: WorkspaceState = { id: "current", activeProjectId, recentProjectIds, settings, }; await this.database.saveWorkspaceState(state); } /** * Save project to database */ async saveProject(project: StoredProject): Promise<void> { await this.database.saveProject(project); } /** * Touch project in database */ async touchProject(projectId: string): Promise<void> { await this.database.touchProject(projectId); } /** * Get project from database */ async getProject(projectId: string): Promise<StoredProject | null> { return this.database.getProject(projectId); } /** * Delete project from database */ async deleteProject(projectId: string): Promise<void> { await this.database.deleteProject(projectId); } /** * Update project state in database */ async updateProjectState( projectId: string, state: { enabled?: boolean; disabledAt?: Date; enabledAt?: Date }, ): Promise<void> { await this.database.updateProjectState(projectId, state); } /** * List all projects from database */ async listProjects(): Promise<StoredProject[]> { return this.database.listProjects(); } /** * List recent projects */ async listRecentProjects(limit = 10): Promise<StoredProject[]> { return this.database.listRecentProjects(limit); } /** * Discover existing IndexedDB projects */ async discoverIndexedDBProjects(): Promise<ProjectConfig[]> { const dbNames = await this.database.discoverIndexedDBProjects(); return dbNames.map((dbName) => ({ id: `discovered-${dbName}`, name: dbName.replace(/^(firesystem-|@firesystem\/)/i, ""), source: { type: "indexeddb", config: { dbName }, }, })); } /** * Open database */ async open(): Promise<void> { await this.database.open(); } /** * Close database */ close(): void { this.database.close(); } }