54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
/**
|
|
* Browser auto-backup in IndexedDB (spec §8, plan B4). Only the latest project text is kept.
|
|
* Every call can fail (private window, blocked storage); callers catch and show the failure.
|
|
*/
|
|
const DB_NAME = 'pierzainer';
|
|
const STORE = 'backup';
|
|
const KEY = 'current';
|
|
|
|
export interface Backup {
|
|
text: string;
|
|
at: string;
|
|
}
|
|
|
|
function openDb(): Promise<IDBDatabase> {
|
|
return new Promise((resolve, reject) => {
|
|
const req = indexedDB.open(DB_NAME, 1);
|
|
req.onupgradeneeded = () => req.result.createObjectStore(STORE);
|
|
req.onsuccess = () => resolve(req.result);
|
|
req.onerror = () => reject(req.error);
|
|
});
|
|
}
|
|
|
|
function run<T>(mode: IDBTransactionMode, action: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> {
|
|
return openDb().then(
|
|
(db) =>
|
|
new Promise<T>((resolve, reject) => {
|
|
const tx = db.transaction(STORE, mode);
|
|
const req = action(tx.objectStore(STORE));
|
|
tx.oncomplete = () => {
|
|
db.close();
|
|
resolve(req.result);
|
|
};
|
|
tx.onerror = () => {
|
|
db.close();
|
|
reject(tx.error);
|
|
};
|
|
}),
|
|
);
|
|
}
|
|
|
|
export function writeBackup(text: string): Promise<unknown> {
|
|
const value: Backup = { text, at: new Date().toISOString() };
|
|
return run('readwrite', (store) => store.put(value, KEY));
|
|
}
|
|
|
|
export async function readBackup(): Promise<Backup | null> {
|
|
const value = await run<Backup | undefined>('readonly', (store) => store.get(KEY));
|
|
return value ?? null;
|
|
}
|
|
|
|
export function clearBackup(): Promise<unknown> {
|
|
return run('readwrite', (store) => store.delete(KEY));
|
|
}
|