(feat): add cache package
(feat): improve local storage security (feat): move settings to dedicated settings package
This commit is contained in:
parent
fb095db7a6
commit
790a1db788
54 changed files with 1984 additions and 947 deletions
98
packages/shared/src/indexedDb.ts
Normal file
98
packages/shared/src/indexedDb.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
export const TENSAMIN_DB_NAME = "tensamin";
|
||||
export const TENSAMIN_DB_VERSION = 1;
|
||||
export type TensaminStore = "storage" | "cache" | "keys";
|
||||
|
||||
const stores: TensaminStore[] = ["storage", "cache", "keys"];
|
||||
let databasePromise: Promise<IDBDatabase> | undefined;
|
||||
|
||||
export function openTensaminDatabase(
|
||||
indexedDb: IDBFactory = globalThis.indexedDB,
|
||||
) {
|
||||
databasePromise ??= new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const request = indexedDb.open(TENSAMIN_DB_NAME, TENSAMIN_DB_VERSION);
|
||||
request.onupgradeneeded = () => {
|
||||
for (const store of stores) {
|
||||
if (!request.result.objectStoreNames.contains(store)) {
|
||||
request.result.createObjectStore(store);
|
||||
}
|
||||
}
|
||||
};
|
||||
request.onsuccess = () => {
|
||||
request.result.onversionchange = () => request.result.close();
|
||||
resolve(request.result);
|
||||
};
|
||||
request.onerror = () => {
|
||||
databasePromise = undefined;
|
||||
reject(request.error);
|
||||
};
|
||||
request.onblocked = () => {
|
||||
databasePromise = undefined;
|
||||
reject(new Error("The Tensamin database upgrade is blocked."));
|
||||
};
|
||||
});
|
||||
return databasePromise;
|
||||
}
|
||||
|
||||
export async function getDatabaseEntry<T>(store: TensaminStore, key: string) {
|
||||
const database = await openTensaminDatabase();
|
||||
return new Promise<T | undefined>((resolve, reject) => {
|
||||
const request = database
|
||||
.transaction(store, "readonly")
|
||||
.objectStore(store)
|
||||
.get(key);
|
||||
request.onsuccess = () => resolve(request.result as T | undefined);
|
||||
request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
export async function setDatabaseEntry(
|
||||
store: TensaminStore,
|
||||
key: string,
|
||||
value: unknown,
|
||||
) {
|
||||
const database = await openTensaminDatabase();
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const transaction = database.transaction(store, "readwrite");
|
||||
transaction.objectStore(store).put(value, key);
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
transaction.onabort = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteDatabaseEntry(store: TensaminStore, key: string) {
|
||||
const database = await openTensaminDatabase();
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const transaction = database.transaction(store, "readwrite");
|
||||
transaction.objectStore(store).delete(key);
|
||||
transaction.oncomplete = () => resolve();
|
||||
transaction.onerror = () => reject(transaction.error);
|
||||
transaction.onabort = () => reject(transaction.error);
|
||||
});
|
||||
}
|
||||
|
||||
export async function listDatabaseEntries(
|
||||
store: TensaminStore,
|
||||
keyPrefix: string,
|
||||
) {
|
||||
const database = await openTensaminDatabase();
|
||||
return new Promise<Array<[string, unknown]>>((resolve, reject) => {
|
||||
const entries: Array<[string, unknown]> = [];
|
||||
const cursor = database
|
||||
.transaction(store, "readonly")
|
||||
.objectStore(store)
|
||||
.openCursor();
|
||||
cursor.onsuccess = () => {
|
||||
const value = cursor.result;
|
||||
if (!value) {
|
||||
resolve(entries);
|
||||
return;
|
||||
}
|
||||
if (typeof value.key === "string" && value.key.startsWith(keyPrefix)) {
|
||||
entries.push([value.key, value.value]);
|
||||
}
|
||||
value.continue();
|
||||
};
|
||||
cursor.onerror = () => reject(cursor.error);
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue