UNPKG

opfs-tools

Version:

EN: A simple, high-performance, and comprehensive file system API running in the browser, built on [OPFS](https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system).

3 lines (2 loc) 12 kB
(function(c,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(c=typeof globalThis<"u"?globalThis:c||self,o(c.OPFSTools={}))})(this,function(c){"use strict";var Q=c=>{throw TypeError(c)};var D=(c,o,f)=>o.has(c)||Q("Cannot "+f);var s=(c,o,f)=>(D(c,o,"read from private field"),f?f.call(c):o.get(c)),h=(c,o,f)=>o.has(c)?Q("Cannot add the same private member more than once"):o instanceof WeakSet?o.add(c):o.set(c,f),u=(c,o,f,R)=>(D(c,o,"write to private field"),R?R.call(c,f):o.set(c,f),f);var w,I,F,d,W,T,S,v,Z,V,G;const o="KGZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIHUobil7aWYobj09PSIvIilyZXR1cm57cGFyZW50Om51bGwsbmFtZToiIn07Y29uc3QgZT1uLnNwbGl0KCIvIikuZmlsdGVyKGk9PmkubGVuZ3RoPjApO2lmKGUubGVuZ3RoPT09MCl0aHJvdyBFcnJvcigiSW52YWxpZCBwYXRoIik7Y29uc3QgYT1lW2UubGVuZ3RoLTFdLHI9Ii8iK2Uuc2xpY2UoMCwtMSkuam9pbigiLyIpO3JldHVybntuYW1lOmEscGFyZW50OnJ9fWFzeW5jIGZ1bmN0aW9uIHcobixlKXtjb25zdHtwYXJlbnQ6YSxuYW1lOnJ9PXUobik7aWYoYT09bnVsbClyZXR1cm4gYXdhaXQgbmF2aWdhdG9yLnN0b3JhZ2UuZ2V0RGlyZWN0b3J5KCk7Y29uc3QgaT1hLnNwbGl0KCIvIikuZmlsdGVyKHQ9PnQubGVuZ3RoPjApO3RyeXtsZXQgdD1hd2FpdCBuYXZpZ2F0b3Iuc3RvcmFnZS5nZXREaXJlY3RvcnkoKTtmb3IoY29uc3QgcyBvZiBpKXQ9YXdhaXQgdC5nZXREaXJlY3RvcnlIYW5kbGUocyx7Y3JlYXRlOmUuY3JlYXRlfSk7aWYoZS5pc0ZpbGUpcmV0dXJuIGF3YWl0IHQuZ2V0RmlsZUhhbmRsZShyLHtjcmVhdGU6ZS5jcmVhdGV9KX1jYXRjaCh0KXtpZih0Lm5hbWU9PT0iTm90Rm91bmRFcnJvciIpcmV0dXJuIG51bGw7dGhyb3cgdH19Y29uc3QgZj17fTtzZWxmLm9ubWVzc2FnZT1hc3luYyBuPT57dmFyIGk7Y29uc3R7ZXZ0VHlwZTplLGFyZ3M6YX09bi5kYXRhO2xldCByPWZbYS5maWxlSWRdO3RyeXtsZXQgdDtjb25zdCBzPVtdO2lmKGU9PT0icmVnaXN0ZXIiKXtjb25zdCBsPWF3YWl0IHcoYS5maWxlUGF0aCx7Y3JlYXRlOiEwLGlzRmlsZTohMH0pO2lmKGw9PW51bGwpdGhyb3cgRXJyb3IoYG5vdCBmb3VuZCBmaWxlOiAke2EuZmlsZUlkfWApO3I9YXdhaXQgbC5jcmVhdGVTeW5jQWNjZXNzSGFuZGxlKHttb2RlOmEubW9kZX0pLGZbYS5maWxlSWRdPXJ9ZWxzZSBpZihlPT09ImNsb3NlIilhd2FpdCByLmNsb3NlKCksZGVsZXRlIGZbYS5maWxlSWRdO2Vsc2UgaWYoZT09PSJ0cnVuY2F0ZSIpYXdhaXQgci50cnVuY2F0ZShhLm5ld1NpemUpO2Vsc2UgaWYoZT09PSJ3cml0ZSIpe2NvbnN0e2RhdGE6bCxvcHRzOm99PW4uZGF0YS5hcmdzO3Q9YXdhaXQgci53cml0ZShsLG8pfWVsc2UgaWYoZT09PSJyZWFkIil7Y29uc3R7b2Zmc2V0Omwsc2l6ZTpvfT1uLmRhdGEuYXJncyxnPW5ldyBVaW50OEFycmF5KG8pLGQ9YXdhaXQgci5yZWFkKGcse2F0Omx9KSxjPWcuYnVmZmVyO3Q9ZD09PW8/YzooKGk9Yy50cmFuc2Zlcik9PW51bGw/dm9pZCAwOmkuY2FsbChjLGQpKT8/Yy5zbGljZSgwLGQpLHMucHVzaCh0KX1lbHNlIGU9PT0iZ2V0U2l6ZSI/dD1hd2FpdCByLmdldFNpemUoKTplPT09ImZsdXNoIiYmYXdhaXQgci5mbHVzaCgpO3NlbGYucG9zdE1lc3NhZ2Uoe2V2dFR5cGU6ImNhbGxiYWNrIixjYklkOm4uZGF0YS5jYklkLHJldHVyblZhbDp0fSxzKX1jYXRjaCh0KXtjb25zdCBzPXQ7c2VsZi5wb3N0TWVzc2FnZSh7ZXZ0VHlwZToidGhyb3dFcnJvciIsY2JJZDpuLmRhdGEuY2JJZCxlcnJNc2c6cy5uYW1lKyI6ICIrcy5tZXNzYWdlK2AKYCtKU09OLnN0cmluZ2lmeShuLmRhdGEpfSl9fX0pKCk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPW9wZnMtd29ya2VyLUY0UldscWNfLmpzLm1hcAo=",f=r=>Uint8Array.from(atob(r),e=>e.charCodeAt(0)),R=typeof self<"u"&&self.Blob&&new Blob([f(o)],{type:"text/javascript;charset=utf-8"});function M(r){let e;try{if(e=R&&(self.URL||self.webkitURL).createObjectURL(R),!e)throw"";const t=new Worker(e,{name:r==null?void 0:r.name});return t.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),t}catch{return new Worker("data:text/javascript;base64,"+o,{name:r==null?void 0:r.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}async function _(r,e,t){const a=A();return await a("register",{fileId:r,filePath:e,mode:t}),{read:async(i,n)=>await a("read",{fileId:r,offset:i,size:n}),write:async(i,n)=>await a("write",{fileId:r,data:i,opts:n},[ArrayBuffer.isView(i)?i.buffer:i]),close:async()=>await a("close",{fileId:r}),truncate:async i=>await a("truncate",{fileId:r,newSize:i}),getSize:async()=>await a("getSize",{fileId:r}),flush:async()=>await a("flush",{fileId:r})}}const k=[];let E=0;function A(){if(k.length<3){const e=r();return k.push(e),e}else{const e=k[E];return E=(E+1)%k.length,e}function r(){const e=new M;let t=0,a={};return e.onmessage=({data:i})=>{var n,l;i.evtType==="callback"?(n=a[i.cbId])==null||n.resolve(i.returnVal):i.evtType==="throwError"&&((l=a[i.cbId])==null||l.reject(Error(i.errMsg))),delete a[i.cbId]},async function(n,l,m=[]){t+=1;const y=new Promise((X,z)=>{a[t]={resolve:X,reject:z}});return e.postMessage({cbId:t,evtType:n,args:l},m),y}}}function L(r){if(r==="/")return{parent:null,name:""};const e=r.split("/").filter(i=>i.length>0);if(e.length===0)throw Error("Invalid path");const t=e[e.length-1],a="/"+e.slice(0,-1).join("/");return{name:t,parent:a}}async function p(r,e){const{parent:t,name:a}=L(r);if(t==null)return await navigator.storage.getDirectory();const i=t.split("/").filter(n=>n.length>0);try{let n=await navigator.storage.getDirectory();for(const l of i)n=await n.getDirectoryHandle(l,{create:e.create});return e.isFile?await n.getFileHandle(a,{create:e.create}):await n.getDirectoryHandle(a,{create:e.create})}catch(n){if(n.name==="NotFoundError")return null;throw n}}async function K(r){const{parent:e,name:t}=L(r);if(e==null){const i=await navigator.storage.getDirectory();for await(const n of i.keys())await i.removeEntry(n,{recursive:!0});return}const a=await p(e,{create:!1,isFile:!1});if(a!=null)try{await a.removeEntry(t,{recursive:!0})}catch(i){if(i.name==="NotFoundError")return;throw i}}function x(r,e){return`${r}/${e}`.replace("//","/")}function g(r){return new P(r)}const C=class C{constructor(e){h(this,w);h(this,I);h(this,F);u(this,w,e);const{parent:t,name:a}=L(e);u(this,I,a),u(this,F,t)}get kind(){return"dir"}get name(){return s(this,I)}get path(){return s(this,w)}get parent(){return s(this,F)==null?null:g(s(this,F))}async create(){return await p(s(this,w),{create:!0,isFile:!1}),g(s(this,w))}async exists(){return await p(s(this,w),{create:!1,isFile:!1})instanceof FileSystemDirectoryHandle}async remove(){for(const e of await this.children())try{await e.remove()}catch(t){console.warn(t)}try{await K(s(this,w))}catch(e){console.warn(e)}}async children(){const e=await p(s(this,w),{create:!1,isFile:!1});if(e==null)return[];const t=[];for await(const a of e.values())t.push((a.kind==="file"?b:g)(x(s(this,w),a.name)));return t}async copyTo(e){if(!await this.exists())throw Error(`dir ${this.path} not exists`);if(e instanceof C){const t=await e.exists()?g(x(e.path,this.name)):e;return await t.create(),await Promise.all((await this.children()).map(a=>a.copyTo(t))),t}else if(e instanceof FileSystemDirectoryHandle)return await Promise.all((await this.children()).map(async t=>{t.kind==="file"?await t.copyTo(await e.getFileHandle(t.name,{create:!0})):await t.copyTo(await e.getDirectoryHandle(t.name,{create:!0}))})),null;throw Error("Illegal target type")}async moveTo(e){const t=await this.copyTo(e);return await this.remove(),t}};w=new WeakMap,I=new WeakMap,F=new WeakMap;let P=C;const N=new Map;function b(r,e="rw"){if(e==="rw"){const t=N.get(r)??new Y(r,e);return N.set(r,t),t}return new Y(r,e)}async function H(r,e,t={overwrite:!0}){if(e instanceof Y){await H(r,await e.stream(),t);return}const a=await(r instanceof Y?r:b(r,"rw")).createWriter();try{if(t.overwrite&&await a.truncate(0),e instanceof ReadableStream){const i=e.getReader();for(;;){const{done:n,value:l}=await i.read();if(n)break;await a.write(l)}}else await a.write(e)}catch(i){throw i}finally{await a.close()}}let $=0;const q=()=>++$,j=class j{constructor(e,t){h(this,d);h(this,W);h(this,T);h(this,S);h(this,v);h(this,Z,0);h(this,V,(()=>{let e=null;return()=>(u(this,Z,s(this,Z)+1),e??(e=new Promise(async(t,a)=>{try{const i=await _(s(this,v),s(this,d),s(this,S));t([i,async()=>{u(this,Z,s(this,Z)-1),!(s(this,Z)>0)&&(e=null,await i.close())}])}catch(i){a(i)}})))})());h(this,G,!1);u(this,v,q()),u(this,d,e),u(this,S,{r:"read-only",rw:"readwrite","rw-unsafe":"readwrite-unsafe"}[t]);const{parent:a,name:i}=L(e);if(a==null)throw Error("Invalid path");u(this,T,i),u(this,W,a)}get kind(){return"file"}get path(){return s(this,d)}get name(){return s(this,T)}get parent(){return s(this,W)==null?null:g(s(this,W))}async createWriter(){if(s(this,S)==="read-only")throw Error("file is read-only");if(s(this,G))throw Error("Other writer have not been closed");u(this,G,!0);const e=new TextEncoder,[t,a]=await s(this,V).call(this);let i=await t.getSize(),n=!1;return{write:async(l,m={})=>{if(n)throw Error("Writer is closed");const y=typeof l=="string"?e.encode(l):l,X=m.at??i,z=y.byteLength;return i=X+z,await t.write(y,{at:X})},truncate:async l=>{if(n)throw Error("Writer is closed");await t.truncate(l),i>l&&(i=l)},flush:async()=>{if(n)throw Error("Writer is closed");await t.flush()},close:async()=>{if(n)throw Error("Writer is closed");n=!0,u(this,G,!1),await a()}}}async createReader(){const[e,t]=await s(this,V).call(this);let a=!1,i=0;return{read:async(n,l={})=>{if(a)throw Error("Reader is closed");const m=l.at??i,y=await e.read(m,n);return i=m+y.byteLength,y},getSize:async()=>{if(a)throw Error("Reader is closed");return await e.getSize()},close:async()=>{a||(a=!0,await t())}}}async text(){return new TextDecoder().decode(await this.arrayBuffer())}async arrayBuffer(){const e=await p(s(this,d),{create:!1,isFile:!0});return e==null?new ArrayBuffer(0):(await e.getFile()).arrayBuffer()}async stream(){const e=await this.getOriginFile();return e==null?new ReadableStream({pull:t=>{t.close()}}):e.stream()}async getOriginFile(){var e;return(e=await p(s(this,d),{create:!1,isFile:!0}))==null?void 0:e.getFile()}async getSize(){const e=await p(s(this,d),{create:!1,isFile:!0});return e==null?0:(await e.getFile()).size}async exists(){return await p(s(this,d),{create:!1,isFile:!0})instanceof FileSystemFileHandle}async remove(){if(s(this,Z))throw Error("exists unclosed reader/writer");await K(s(this,d))}async copyTo(e){if(e instanceof j)return e.path===this.path?this:(await H(e.path,this),b(e.path));if(e instanceof P){if(!await this.exists())throw Error(`file ${this.path} not exists`);return await this.copyTo(b(x(e.path,this.name)))}else if(e instanceof FileSystemFileHandle)return await(await this.stream()).pipeTo(await e.createWritable()),null;throw Error("Illegal target type")}async moveTo(e){const t=await this.copyTo(e);return await this.remove(),t}};d=new WeakMap,W=new WeakMap,T=new WeakMap,S=new WeakMap,v=new WeakMap,Z=new WeakMap,V=new WeakMap,G=new WeakMap;let Y=j;const O="/.opfs-tools-temp-dir";async function J(r){try{if(r.kind==="file"){if(!await r.exists())return!0;const e=await r.createWriter();await e.truncate(0),await e.close(),await r.remove()}else await r.remove();return!0}catch(e){return console.warn(e),!1}}function ee(){setInterval(async()=>{for(const e of await g(O).children()){const t=/^\d+-(\d+)$/.exec(e.name);(t==null||Date.now()-Number(t[1])>2592e5)&&await J(e)}},60*1e3)}const U=[];let B=!1;async function te(){if(globalThis.localStorage==null)return;const r="OPFS_TOOLS_EXPIRES_TMP_FILES";B||(B=!0,globalThis.addEventListener("unload",()=>{U.length!==0&&localStorage.setItem(r,`${localStorage.getItem(r)??""},${U.join(",")}`)}));let e=localStorage.getItem(r)??"";for(const t of e.split(","))t.length!==0&&await J(b(`${O}/${t}`))&&(e=e.replace(t,""));localStorage.setItem(r,e.replace(/,{2,}/g,","))}(async function(){var e;globalThis.__opfs_tools_tmpfile_init__!==!0&&(globalThis.__opfs_tools_tmpfile_init__=!0,!(globalThis.FileSystemDirectoryHandle==null||globalThis.FileSystemFileHandle==null||((e=globalThis.navigator)==null?void 0:e.storage.getDirectory)==null)&&(ee(),await te()))})();function re(){const r=`${Math.random().toString().slice(2)}-${Date.now()}`;return U.push(r),b(`${O}/${r}`)}function ae(r,e){let t=b(r),a=0,i=t.createWriter(),n=t.createReader();const l=async m=>{const X=await(await n).read(a,{at:Math.round(a*.3)});a=await m.write(X,{at:0}),await m.truncate(a)};return{append:async m=>{const y=await i;a+=await y.write(m),a>=e&&await l(y)},text:t.text.bind(t),remove:async()=>{await(await n).close(),await(await i).close(),await t.remove()},getSize:async()=>a}}c.dir=g,c.file=b,c.rollfile=ae,c.tmpfile=re,c.write=H,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}); //# sourceMappingURL=opfs-tools.umd.cjs.map