import { createStore, set, get, del, entries } from "idb-keyval"; import { CanvasData, CanvasMetadata, IStorageAdapter } from "../storage"; import { generateThumbnail } from "../thumbnail"; const metadataStore = createStore("excalidraw-canvases-metadata", "metadata"); const dataStore = createStore("excalidraw-canvases-data", "data"); export class IndexedDBStorageAdapter implements IStorageAdapter { async listCanvases(): Promise { const allEntries = await entries(metadataStore); return allEntries.map(([, metadata]) => metadata); } async loadCanvas(id: string): Promise { const data = await get(id, dataStore); return data === undefined ? null : data; } async saveCanvas(id: string, data: CanvasData): Promise { const existingMetadata = await get(id, metadataStore); if (!existingMetadata) { throw new Error("Canvas metadata not found. Cannot save."); } const thumbnail = await generateThumbnail( data.elements, data.appState, data.files, ); const updatedMetadata: CanvasMetadata = { ...existingMetadata, name: data.appState.name || existingMetadata.name, updatedAt: new Date().toISOString(), thumbnail: data.elements.length > 0 ? thumbnail : undefined, }; await set(id, updatedMetadata, metadataStore); await set(id, data, dataStore); } async createCanvas(data: CanvasData): Promise { const newId = window.crypto.randomUUID(); const now = new Date().toISOString(); const thumbnail = await generateThumbnail( data.elements, data.appState, data.files, ); const newMetadata: CanvasMetadata = { id: newId, name: data.appState.name || "Untitled Canvas", createdAt: now, updatedAt: now, // UserID is 0 for local, non-synced canvases userId: 0, thumbnail: data.elements.length > 0 ? thumbnail : undefined, }; await set(newId, newMetadata, metadataStore); await set(newId, data, dataStore); return newMetadata; } async deleteCanvas(id: string): Promise { await del(id, metadataStore); await del(id, dataStore); } async renameCanvas(id: string, newName: string): Promise { // Update metadata const existingMetadata = await get(id, metadataStore); if (!existingMetadata) { throw new Error("Canvas metadata not found. Cannot rename."); } await set(id, { ...existingMetadata, name: newName }, metadataStore); // Update canvas data const existingData = await get(id, dataStore); if (!existingData) { // This should not happen if metadata exists, but as a safeguard: throw new Error("Canvas data not found. Cannot rename."); } await set( id, { ...existingData, appState: { ...existingData.appState, name: newName }, }, dataStore, ); } }