Files
jap_web_ng/src/opfs.ts
T

79 lines
3.0 KiB
TypeScript
Raw Normal View History

2026-09-14 14:32:38 +03:00
// OPFS-хранилище сырой .sqlite.
// Никакого sqlite-wasm здесь пока нет — просто кладём бинарный файл,
// чтобы следующие шаги (открытие БД, выгрузка) работали с одним источником правды.
/** Имя файла БД в OPFS. Совпадает с десктопом: один и тот же бинарный .sqlite. */
export const DB_FILENAME = 'japanese_app.db';
async function opfsRoot(): Promise<FileSystemDirectoryHandle> {
return navigator.storage.getDirectory();
}
/**
* Сохраняет сырые байты .sqlite в OPFS (перезаписывает файл целиком).
* Пишем через SyncAccessHandle, если он доступен, иначе — через WritableStream.
*/
export async function writeDatabaseFile(data: Uint8Array): Promise<void> {
data[18] = 1;
data[19] = 1;
const root = await opfsRoot();
const handle = await root.getFileHandle(DB_FILENAME, { create: true });
// SyncAccessHandle доступен только в воркерах — пробуем, в main-потоке упадёт.
const maybeSync = (handle as unknown as {
createSyncAccessHandle?: () => Promise<FileSystemSyncAccessHandle>;
}).createSyncAccessHandle;
if (typeof maybeSync === 'function') {
try {
const access = await maybeSync.call(handle);
try {
access.truncate(0);
access.write(data, { at: 0 });
access.flush();
} finally {
access.close();
}
return;
} catch {
// Падаем ниже на WritableStream — обычный путь для main-потока
}
}
const writable = await handle.createWritable();
try {
await writable.truncate(0);
// Копия: избегаем проблем с SharedArrayBuffer/neutered буферами
const copy = new Uint8Array(data.length);
copy.set(data);
await writable.write(copy);
} finally {
await writable.close();
}
}
/** Читает сырой .sqlite из OPFS. Бросает Error, если файла нет. */
export async function readDatabaseFile(): Promise<Uint8Array> {
const root = await opfsRoot();
let handle: FileSystemFileHandle;
try {
handle = await root.getFileHandle(DB_FILENAME);
} catch {
throw new Error('Локальная база не найдена — сначала скачай сохранение');
}
const file = await handle.getFile();
if (file.size === 0) throw new Error('Локальная база пуста');
let data = new Uint8Array(await file.arrayBuffer());
return data;
}
/** Проверяет, есть ли непустой файл БД в OPFS. */
export async function hasDatabaseFile(): Promise<boolean> {
try {
const root = await opfsRoot();
const handle = await root.getFileHandle(DB_FILENAME);
const file = await handle.getFile();
return file.size > 0;
} catch {
return false;
}
}