UNPKG

idb-file-storage

Version:

Simple Promise-based IndexedDB wrapper to store files

3 lines (2 loc) 8.88 kB
(function(global,factory){if("function"==typeof define&&define.amd)define("idb-file-storage",["exports"],factory);else if("undefined"!=typeof exports)factory(exports);else{var mod={exports:{}};factory(mod.exports),global.IDBFiles=mod.exports}})(this,function(exports){"use strict";function waitForDOMRequest(req,onsuccess){return new Promise((resolve,reject)=>{req.onsuccess=onsuccess?()=>resolve(onsuccess(req.result)):()=>resolve(req.result),req.onerror=()=>reject(req.error)})}Object.defineProperty(exports,"__esModule",{value:!0}),exports.waitForDOMRequest=waitForDOMRequest,exports.getFileStorage=async function({name,persistent}={}){const filesStorage=new IDBFileStorage({name:name||"default",persistent});return await filesStorage.initializedDB(),filesStorage};class IDBPromisedFileHandle{constructor({file,lockedFile}){this.file=file,this.lockedFile=lockedFile,this.writeQueue=Promise.resolve(),this.closed=void 0,this.aborted=void 0}ensureLocked({invalidMode}={}){if(this.closed)throw new Error("FileHandle has been closed");if(this.aborted)throw new Error("FileHandle has been aborted");if(!this.lockedFile)throw new Error("Invalid FileHandled");if(invalidMode&&this.lockedFile.mode===invalidMode)throw new Error(`FileHandle should not be opened as '${this.lockedFile.mode}'`);this.lockedFile.active||this.file.reopenFileHandle(this)}get mode(){return this.lockedFile.mode}get active(){return!!this.lockedFile&&this.lockedFile.active}async close(){if(!this.lockedFile)throw new Error("FileHandle is not open");await this.writeQueue,this.lockedFile.active&&"readonly"!==this.lockedFile.mode&&(await waitForDOMRequest(this.lockedFile.flush())),this.closed=!0,this.lockedFile=null,this.writeQueue=Promise.resolve()}async abort(){this.lockedFile.active&&this.lockedFile.abort(),this.aborted=!0,this.lockedFile=null,this.writeQueue=Promise.resolve()}async getMetadata(){return this.ensureLocked(),waitForDOMRequest(this.lockedFile.getMetadata())}async readAsText(size,location){return this.ensureLocked({invalidMode:"writeonly"}),"number"==typeof location&&(this.lockedFile.location=location),waitForDOMRequest(this.lockedFile.readAsText(size))}async readAsArrayBuffer(size,location){return this.ensureLocked({invalidMode:"writeonly"}),"number"==typeof location&&(this.lockedFile.location=location),waitForDOMRequest(this.lockedFile.readAsArrayBuffer(size))}async truncate(location=0){return this.ensureLocked({invalidMode:"readonly"}),waitForDOMRequest(this.lockedFile.truncate(location))}async append(data){return this.ensureLocked({invalidMode:"readonly"}),waitForDOMRequest(this.lockedFile.append(data))}async write(data,location){return this.ensureLocked({invalidMode:"readonly"}),"number"==typeof location&&(this.lockedFile.location=location),waitForDOMRequest(this.lockedFile.write(data),()=>{return this.lockedFile.location})}queuedWrite(data,location){return this.writeQueue=this.writeQueue.then(async lastLocation=>{return this.ensureLocked({invalidMode:"readonly"}),"number"==typeof location?this.write(data,location):this.write(data,lastLocation)}),this.writeQueue}async waitForQueuedWrites(){await this.writeQueue}}exports.IDBPromisedFileHandle=IDBPromisedFileHandle;class IDBPromisedMutableFile{constructor({filesStorage,idb,fileName,fileType,mutableFile}){this.filesStorage=filesStorage,this.idb=idb,this.fileName=fileName,this.fileType=fileType,this.mutableFile=mutableFile}reopenFileHandle(fileHandle){fileHandle.lockedFile=this.mutableFile.open(fileHandle.mode)}open(mode){if(this.lockedFile)throw new Error("MutableFile cannot be opened twice");const lockedFile=this.mutableFile.open(mode);return new IDBPromisedFileHandle({file:this,lockedFile})}getFile(){return waitForDOMRequest(this.mutableFile.getFile())}async persistAsFileSnapshot(snapshotName){if(snapshotName===this.fileName)throw new Error("Snapshot name and the file name should be different");const idb=await this.filesStorage.initializedDB();return await this.runFileRequestGenerator(function*(){const file=yield this.mutableFile.getFile(),objectStore=this.filesStorage.getObjectStoreTransaction({idb,mode:"readwrite"});yield objectStore.put(file,snapshotName)}.bind(this)),this.filesStorage.get(snapshotName)}persist(){return this.filesStorage.put(this.fileName,this)}async runFileRequestGenerator(generatorFunction,mode){if("GeneratorFunction"!==generatorFunction.constructor.name)throw new Error("runGenerator parameter should be a generator function");await new Promise((resolve,reject)=>{const lockedFile=this.mutableFile.open(mode||"readwrite"),fileRequestsIter=generatorFunction(lockedFile),processFileRequestIter=prevRequestResult=>{const nextFileRequest=fileRequestsIter.next(prevRequestResult);if(nextFileRequest.done)return void resolve();if(!(nextFileRequest.value instanceof window.DOMRequest||nextFileRequest.value instanceof window.IDBRequest)){const error=new Error("FileRequestGenerator should only yield DOMRequest instances");return fileRequestsIter.throw(error),void reject(error)}const request=nextFileRequest.value;if(request.onsuccess||request.onerror){const error=new Error("DOMRequest onsuccess/onerror callbacks are already set");fileRequestsIter.throw(error),reject(error)}else request.onsuccess=()=>processFileRequestIter(request.result),request.onerror=()=>reject(request.error)};processFileRequestIter()})}}exports.IDBPromisedMutableFile=IDBPromisedMutableFile;class IDBFileStorage{constructor({name,persistent}={}){this.name=name,this.persistent=persistent,this.indexedDBName=`IDBFilesStorage-DB-${this.name}`,this.objectStorageName="IDBFilesObjectStorage",this.initializedPromise=void 0,this.version=1}initializedDB(){return this.initializedPromise?this.initializedPromise:(this.initializedPromise=(async()=>{window.IDBMutableFile&&this.persistent&&(this.version={version:this.version,storage:"persistent"});const dbReq=indexedDB.open(this.indexedDBName,this.version);return dbReq.onupgradeneeded=()=>{const db=dbReq.result;db.objectStoreNames.contains(this.objectStorageName)||db.createObjectStore(this.objectStorageName)},waitForDOMRequest(dbReq)})(),this.initializedPromise)}getObjectStoreTransaction({idb,mode}={}){const transaction=idb.transaction([this.objectStorageName],mode);return transaction.objectStore(this.objectStorageName)}async createMutableFile(fileName,fileType="text"){if(!window.IDBMutableFile)throw new Error("This environment does not support IDBMutableFile");const idb=await this.initializedDB(),mutableFile=await waitForDOMRequest(idb.createMutableFile(fileName,fileType));return new IDBPromisedMutableFile({filesStorage:this,idb,fileName,fileType,mutableFile})}async put(fileName,file){if(!fileName||"string"!=typeof fileName)throw new Error("fileName parameter is mandatory");if(!(file instanceof File)&&!(file instanceof Blob)&&!(window.IDBMutableFile&&file instanceof window.IDBMutableFile)&&!(file instanceof IDBPromisedMutableFile))throw new Error(`Unable to persist ${fileName}. Unknown file type.`);file instanceof IDBPromisedMutableFile&&(file=file.mutableFile);const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb,mode:"readwrite"});return waitForDOMRequest(objectStore.put(file,fileName))}async remove(fileName){if(!fileName)throw new Error("fileName parameter is mandatory");const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb,mode:"readwrite"});return waitForDOMRequest(objectStore.delete(fileName))}async list(options){const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb}),allKeys=await waitForDOMRequest(objectStore.getAllKeys());let filteredKeys=allKeys;return options&&(filteredKeys=filteredKeys.filter(key=>{let match=!0;return"string"==typeof options.startsWith&&(match=match&&key.startsWith(options.startsWith)),"string"==typeof options.endsWith&&(match=match&&key.endsWith(options.endsWith)),"string"==typeof options.includes&&(match=match&&key.includes(options.includes)),"function"==typeof options.filterFn&&(match=match&&options.filterFn(key)),match})),filteredKeys}async count(options){if(!options){const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb});return waitForDOMRequest(objectStore.count())}const filteredKeys=await this.list(options);return filteredKeys.length}async get(fileName){const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb});return waitForDOMRequest(objectStore.get(fileName)).then(result=>{return window.IDBMutableFile&&result instanceof window.IDBMutableFile?new IDBPromisedMutableFile({filesStorage:this,idb,fileName,fileType:result.type,mutableFile:result}):result})}async clear(){const idb=await this.initializedDB(),objectStore=this.getObjectStoreTransaction({idb,mode:"readwrite"});return waitForDOMRequest(objectStore.clear())}}exports.IDBFileStorage=IDBFileStorage}); //# sourceMappingURL=idb-file-storage.min.js.map