import type { EditorCore } from "@/core"; type SaveManagerOptions = { debounceMs?: number; }; export class SaveManager { private debounceMs: number; private isPaused = false; private isSaving = false; private hasPendingSave = false; private saveTimer: ReturnType | null = null; private unsubscribeHandlers: Array<() => void> = []; constructor( private editor: EditorCore, { debounceMs = 800 }: SaveManagerOptions = {}, ) { this.debounceMs = debounceMs; } start(): void { if (this.unsubscribeHandlers.length > 0) return; this.unsubscribeHandlers = [ this.editor.scenes.subscribe(() => { this.markDirty(); }), this.editor.timeline.subscribe(() => { this.markDirty(); }), ]; } stop(): void { for (const unsubscribe of this.unsubscribeHandlers) { unsubscribe(); } this.unsubscribeHandlers = []; this.clearTimer(); } pause(): void { this.isPaused = true; } resume(): void { this.isPaused = false; if (this.hasPendingSave) { this.queueSave(); } } markDirty({ force = false }: { force?: boolean } = {}): void { if (this.isPaused && !force) return; this.hasPendingSave = true; this.queueSave(); } async flush(): Promise { this.hasPendingSave = true; await this.saveNow(); } getIsDirty(): boolean { return this.hasPendingSave || this.isSaving; } private queueSave(): void { if (this.isSaving) return; if (this.saveTimer) { clearTimeout(this.saveTimer); } this.saveTimer = setTimeout(() => { void this.saveNow(); }, this.debounceMs); } private async saveNow(): Promise { if (this.isSaving) return; if (!this.hasPendingSave) return; const activeProject = this.editor.project.getActive(); if (!activeProject) return; if (this.editor.project.getIsLoading()) return; if (this.editor.project.getMigrationState().isMigrating) return; this.isSaving = true; this.hasPendingSave = false; this.clearTimer(); try { await this.editor.project.saveCurrentProject(); } finally { this.isSaving = false; if (this.hasPendingSave) { this.queueSave(); } } } private clearTimer(): void { if (!this.saveTimer) return; clearTimeout(this.saveTimer); this.saveTimer = null; } }