move stuff

This commit is contained in:
“chrisshank” 2025-01-02 12:49:04 -08:00
parent ae2624b7c5
commit 2f87231b45
6 changed files with 87 additions and 94 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,4 +1,6 @@
export class FileSaver { import { KeyValueStore } from '@lib/indexeddb';
export class FilePicker {
#id; #id;
#fileType; #fileType;
#fileExtension; #fileExtension;
@ -85,7 +87,7 @@ export class FileSaver {
types: [ types: [
{ {
description: `${this.#fileType.toUpperCase()} document`, description: `${this.#fileType.toUpperCase()} document`,
accept: { [this.#mimeType]: [this.#fileExtension] }, accept: { [this.#mimeType]: [this.#fileExtension] } as FilePickerAcceptType['accept'],
}, },
], ],
}); });
@ -99,11 +101,10 @@ export class FileSaver {
this.#fileHandlerPromise = window this.#fileHandlerPromise = window
.showOpenFilePicker({ .showOpenFilePicker({
id: this.#id, id: this.#id,
suggestedName: `${this.#id}.${this.#fileType}`,
types: [ types: [
{ {
description: `${this.#fileType.toUpperCase()} document`, description: `${this.#fileType.toUpperCase()} document`,
accept: { [this.#mimeType]: [this.#fileExtension] }, accept: { [this.#mimeType]: [this.#fileExtension] } as FilePickerAcceptType['accept'],
}, },
], ],
}) })
@ -114,92 +115,3 @@ export class FileSaver {
return fileHandler; return fileHandler;
} }
} }
declare global {
var showSaveFilePicker: (args: any) => Promise<FileSystemFileHandle>;
var showOpenFilePicker: (args: any) => Promise<FileSystemFileHandle[]>;
interface FileSystemHandle {
queryPermission: (args: any) => Promise<string>;
requestPermission: (args: any) => Promise<string>;
}
}
class KeyValueStore<Data> {
#db: Promise<IDBDatabase>;
#storeName;
constructor(name = 'keyval-store') {
this.#storeName = name;
const request = indexedDB.open(name);
request.onupgradeneeded = () => request.result.createObjectStore(name);
this.#db = this.#promisifyRequest(request);
}
#promisifyRequest<T>(transaction: IDBRequest<T>) {
return new Promise<T>((resolve, reject) => {
transaction.onsuccess = () => resolve(transaction.result);
transaction.onerror = () => reject(transaction.error);
});
}
#promisifyTransaction(transaction: IDBTransaction) {
return new Promise<void>((resolve, reject) => {
transaction.oncomplete = () => resolve();
transaction.onabort = transaction.onerror = () => reject(transaction.error);
});
}
#getStore(mode: 'readonly' | 'readwrite') {
return this.#db.then((db) => db.transaction(this.#storeName, mode).objectStore(this.#storeName));
}
get(key: IDBValidKey): Promise<Data | undefined> {
return this.#getStore('readonly').then((store) => this.#promisifyRequest(store.get(key)));
}
set(key: IDBValidKey, value: Data) {
return this.#getStore('readwrite').then((store) => {
store.put(value, key);
return this.#promisifyTransaction(store.transaction);
});
}
setMany(entries: [IDBValidKey, Data][]) {
return this.#getStore('readwrite').then((store) => {
entries.forEach((entry) => store.put(entry[1], entry[0]));
return this.#promisifyTransaction(store.transaction);
});
}
delete(key: IDBValidKey) {
return this.#getStore('readwrite').then((store) => {
store.delete(key);
return this.#promisifyTransaction(store.transaction);
});
}
clear() {
return this.#getStore('readwrite').then((store) => {
store.clear();
return this.#promisifyTransaction(store.transaction);
});
}
keys() {
return this.#getStore('readwrite').then((store) => this.#promisifyRequest(store.getAllKeys()));
}
values(): Promise<Data[]> {
return this.#getStore('readwrite').then((store) => this.#promisifyRequest(store.getAll()));
}
entries(): Promise<[IDBValidKey, Data][]> {
return this.#getStore('readwrite').then((store) =>
Promise.all([this.#promisifyRequest(store.getAllKeys()), this.#promisifyRequest(store.getAll())]).then(
([keys, values]) => keys.map((key, i) => [key, values[i]])
)
);
}
}

View File

@ -29,5 +29,7 @@ export * from './EffectIntegrator';
// WebGL utilities // WebGL utilities
export * from './webgl'; export * from './webgl';
export * from './indexeddb';
// Experimental features // Experimental features
export * from './Experimental'; export * from './Experimental';

78
lib/indexeddb.ts Normal file
View File

@ -0,0 +1,78 @@
export class KeyValueStore<Data> {
#db: Promise<IDBDatabase>;
#storeName;
constructor(name = 'keyval-store') {
this.#storeName = name;
const request = indexedDB.open(name);
request.onupgradeneeded = () => request.result.createObjectStore(name);
this.#db = this.#promisifyRequest(request);
}
#promisifyRequest<T>(transaction: IDBRequest<T>) {
return new Promise<T>((resolve, reject) => {
transaction.onsuccess = () => resolve(transaction.result);
transaction.onerror = () => reject(transaction.error);
});
}
#promisifyTransaction(transaction: IDBTransaction) {
return new Promise<void>((resolve, reject) => {
transaction.oncomplete = () => resolve();
transaction.onabort = transaction.onerror = () => reject(transaction.error);
});
}
#getStore(mode: 'readonly' | 'readwrite') {
return this.#db.then((db) => db.transaction(this.#storeName, mode).objectStore(this.#storeName));
}
get(key: IDBValidKey): Promise<Data | undefined> {
return this.#getStore('readonly').then((store) => this.#promisifyRequest(store.get(key)));
}
set(key: IDBValidKey, value: Data) {
return this.#getStore('readwrite').then((store) => {
store.put(value, key);
return this.#promisifyTransaction(store.transaction);
});
}
setMany(entries: [IDBValidKey, Data][]) {
return this.#getStore('readwrite').then((store) => {
entries.forEach((entry) => store.put(entry[1], entry[0]));
return this.#promisifyTransaction(store.transaction);
});
}
delete(key: IDBValidKey) {
return this.#getStore('readwrite').then((store) => {
store.delete(key);
return this.#promisifyTransaction(store.transaction);
});
}
clear() {
return this.#getStore('readwrite').then((store) => {
store.clear();
return this.#promisifyTransaction(store.transaction);
});
}
keys() {
return this.#getStore('readwrite').then((store) => this.#promisifyRequest(store.getAllKeys()));
}
values(): Promise<Data[]> {
return this.#getStore('readwrite').then((store) => this.#promisifyRequest(store.getAll()));
}
entries(): Promise<[IDBValidKey, Data][]> {
return this.#getStore('readwrite').then((store) =>
Promise.all([this.#promisifyRequest(store.getAllKeys()), this.#promisifyRequest(store.getAll())]).then(
([keys, values]) => keys.map((key, i) => [key, values[i]]),
),
);
}
}

View File

@ -23,6 +23,7 @@
"devDependencies": { "devDependencies": {
"@types/leaflet": "^1.9.14", "@types/leaflet": "^1.9.14",
"@types/node": "^22.10.1", "@types/node": "^22.10.1",
"@types/wicg-file-system-access": "^2023.10.5",
"@webgpu/types": "^0.1.51", "@webgpu/types": "^0.1.51",
"bun-types": "^1.1.38", "bun-types": "^1.1.38",
"mitata": "^1.0.20", "mitata": "^1.0.20",

View File

@ -13,7 +13,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"noUnusedLocals": false, "noUnusedLocals": false,
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"], "lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
"types": ["@webgpu/types", "@types/node", "bun-types"], "types": ["@webgpu/types", "@types/node", "@types/wicg-file-system-access", "bun-types"],
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@lib": ["lib"], "@lib": ["lib"],