sokko-g/website/src/utils/indexedDbStorage.js
Shinuwa 09a2d4b71a
All checks were successful
Deploy Sokko G / deploy (push) Successful in 18s
Protect toolbox data after IndexedDB startup failures
2026-09-12 23:05:16 +02:00

132 lines
4.1 KiB
JavaScript

// Rôle : encapsule les opérations IndexedDB génériques utilisées par les toolboxes.
const DB_NAME = "sokkog";
const DB_VERSION = 1;
const KV_STORE = "kv";
const MODULE_STORE = "modules";
let dbPromise;
function openDatabase() {
if (dbPromise) return dbPromise;
dbPromise = new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains(KV_STORE)) db.createObjectStore(KV_STORE);
if (!db.objectStoreNames.contains(MODULE_STORE)) db.createObjectStore(MODULE_STORE, { keyPath: "key" });
};
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
}).catch((error) => {
dbPromise = undefined;
throw error;
});
return dbPromise;
}
async function storeRequest(storeName, mode, callback) {
const db = await openDatabase();
const transaction = db.transaction(storeName, mode);
const store = transaction.objectStore(storeName);
let result;
await new Promise((resolve, reject) => {
transaction.oncomplete = () => resolve();
transaction.onerror = () => reject(transaction.error);
transaction.onabort = () => reject(transaction.error);
try {
const request = callback(store);
request.onsuccess = () => { result = request.result; };
request.onerror = () => reject(request.error);
} catch (error) {
transaction.abort();
reject(error);
}
});
return result;
}
export async function getValue(key, fallback) {
const value = await storeRequest(KV_STORE, "readonly", (store) => store.get(key));
return value == null ? fallback : value;
}
export async function setValue(key, value) {
await storeRequest(KV_STORE, "readwrite", (store) => store.put(value, key));
}
export async function getToolboxes() {
return getValue("toolboxes", []);
}
export async function setToolboxes(toolboxes) {
await setValue("toolboxes", toolboxes);
}
export async function getLinks() {
return getValue("links", {});
}
export async function setLinks(links) {
await setValue("links", links);
}
export async function getSetting(key, fallback) {
return getValue(`setting:${key}`, fallback);
}
export async function setSetting(key, value) {
await setValue(`setting:${key}`, value);
}
export async function getAllModuleData() {
return storeRequest(MODULE_STORE, "readonly", (store) => store.getAll());
}
export async function setModuleData(key, data) {
await storeRequest(MODULE_STORE, "readwrite", (store) => store.put({ key, data }));
}
export async function removeModuleData(key) {
await storeRequest(MODULE_STORE, "readwrite", (store) => store.delete(key));
}
export async function removeModuleDataKeys(keys) {
if (!keys.length) return;
const db = await openDatabase();
await new Promise((resolve, reject) => {
const transaction = db.transaction(MODULE_STORE, "readwrite");
const store = transaction.objectStore(MODULE_STORE);
keys.forEach((key) => store.delete(key));
transaction.oncomplete = () => resolve();
transaction.onerror = () => reject(transaction.error);
transaction.onabort = () => reject(transaction.error);
});
}
export async function setToolboxSnapshot(toolboxes, links, moduleData) {
const db = await openDatabase();
await new Promise((resolve, reject) => {
const transaction = db.transaction([KV_STORE, MODULE_STORE], "readwrite");
const kv = transaction.objectStore(KV_STORE);
const modules = transaction.objectStore(MODULE_STORE);
transaction.oncomplete = () => resolve();
transaction.onerror = () => reject(transaction.error);
transaction.onabort = () => reject(transaction.error);
try {
kv.put(toolboxes, "toolboxes");
kv.put(links, "links");
modules.clear();
Object.entries(moduleData || {}).forEach(([key, data]) => modules.put({ key, data }));
} catch (error) {
transaction.abort();
reject(error);
}
});
}
export async function getStorageEstimate() {
if (!navigator.storage?.estimate) return { usage: 0, quota: 0 };
return navigator.storage.estimate();
}