openpencil/src/app/document/io/write.ts
Danila Poyarkov 37912d92a7 feat(app): recover unsaved documents
- Persist debounced FIG snapshots for source-less documents in IndexedDB

- Restore or discard orphaned snapshots from the editor startup dialog

- Clear recovery data after successful saves and explicit tab closure
2026-08-13 17:22:59 +03:00

66 lines
1.9 KiB
TypeScript

import type { EditorState } from '@open-pencil/core/editor'
import type { StorageDocumentBinding } from '@/app/integrations/storage/types'
import { persistStorageCanvasLocally } from '@/app/storage/sync/persist'
import { isTauri } from '@/app/tauri/env'
type WriteDocumentState = EditorState & { documentName: string }
type DocumentWriterOptions = {
state: WriteDocumentState
getFilePath: () => string | null
getFileHandle: () => FileSystemFileHandle | null
getStorageBinding: () => StorageDocumentBinding | null
setSavedVersion: (version: number) => void
setLastWriteTime: (time: number) => void
onWriteSuccess?: (version: number) => void | Promise<void>
}
export function createDocumentWriter({
state,
getFilePath,
getFileHandle,
getStorageBinding,
setSavedVersion,
setLastWriteTime,
onWriteSuccess
}: DocumentWriterOptions) {
async function finishWrite(version: number): Promise<true> {
setSavedVersion(version)
await onWriteSuccess?.(version)
return true
}
return async function writeFile(
data: Uint8Array,
version = state.sceneVersion
): Promise<boolean> {
setLastWriteTime(Date.now())
const storage = getStorageBinding()
if (storage) {
await persistStorageCanvasLocally({
providerId: storage.providerId,
canvasId: storage.documentId,
name: state.documentName || 'Untitled',
figBytes: data
})
return finishWrite(version)
}
const filePath = getFilePath()
const fileHandle = getFileHandle()
if (filePath && isTauri()) {
const { writeFile: tauriWrite } = await import('@tauri-apps/plugin-fs')
await tauriWrite(filePath, data)
return finishWrite(version)
}
if (fileHandle) {
const writable = await fileHandle.createWritable()
await writable.write(new Uint8Array(data))
await writable.close()
return finishWrite(version)
}
return false
}
}