Files
jap_web_ng/src/opfs.ts
T
2026-09-14 16:12:18 +03:00

80 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
}
}