@gjsify/fs 0.4.36 → 0.4.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/browser/opfs.js +1 -0
- package/lib/esm/browser/volume.js +1 -1
- package/lib/esm/browser.js +1 -1
- package/lib/types/browser/opfs.d.ts +43 -0
- package/lib/types/browser/promises-entry.d.ts +3 -3
- package/lib/types/browser/promises.d.ts +3 -3
- package/lib/types/browser/volume.d.ts +10 -0
- package/lib/types/browser.d.ts +4 -3
- package/package.json +16 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{__defaultVolume as e}from"./volume.js";function hasOpfs(){return typeof navigator<`u`&&navigator.storage!==void 0&&typeof navigator.storage.getDirectory==`function`}function segments(e){return e.split(`/`).filter(Boolean)}async function dirHandle(e,t,n){let r=e;for(let e of t)try{r=await r.getDirectoryHandle(e,{create:n})}catch{return}return r}async function readOpfsTree(e,t,n){let r=!0;for await(let[i,a]of e.entries()){r=!1;let e=t===`/`?`/`+i:t+`/`+i;if(a.kind===`directory`)await readOpfsTree(a,e,n);else{let t=await a.getFile();n.set(e,new Uint8Array(await t.arrayBuffer()))}}r&&t!==`/`&&n.set(t,null)}async function flushVolumeToOpfs(e,t){let n=e.toJSON(),r=new Set,i=new Set;for(let[e,a]of Object.entries(n)){let n=segments(e);if(a===null){await dirHandle(t,n,!0);for(let e=1;e<=n.length;e++)r.add(n.slice(0,e).join(`/`))}else{let e=await dirHandle(t,n.slice(0,-1),!0);if(!e)continue;for(let e=1;e<n.length;e++)r.add(n.slice(0,e).join(`/`));let o=await(await e.getFileHandle(n[n.length-1],{create:!0})).createWritable();await o.write(new TextEncoder().encode(a)),await o.close(),i.add(n.join(`/`))}}await pruneStale(t,``,i,r)}async function pruneStale(e,t,n,r){let i=[];for await(let[a,o]of e.entries()){let e=t?t+`/`+a:a;o.kind===`directory`?(await pruneStale(o,e,n,r),!r.has(e)&&!n.has(e)&&i.push({name:a,recursive:!0})):n.has(e)||i.push({name:a,recursive:!1})}for(let{name:t,recursive:n}of i)try{await e.removeEntry(t,{recursive:n})}catch{}}async function enableOpfsPersistence(t={}){let n=t.volume??e;if(!hasOpfs())return{enabled:!1,reason:`no-opfs`,flush:async()=>{},disable:()=>{}};let r;try{r=await(await navigator.storage.getDirectory()).getDirectoryHandle(t.rootDir??`gjsify-fs`,{create:!0})}catch{return{enabled:!1,reason:`error`,flush:async()=>{},disable:()=>{}}}let i=!0;try{let e=new Map;await readOpfsTree(r,`/`,e);let t={};for(let[n,r]of e)t[n]=r;Object.keys(t).length>0&&n.fromJSON(t)}catch{}finally{i=!1}let a=t.flushDelayMs??50,o,s=Promise.resolve(),doFlush=()=>(s=s.then(()=>flushVolumeToOpfs(n,r)).catch(()=>{}),s),schedule=()=>{i||o===void 0&&(o=setTimeout(()=>{o=void 0,doFlush()},a))},c=n.subscribe(schedule);return{enabled:!0,async flush(){o!==void 0&&(clearTimeout(o),o=void 0),await doFlush()},disable(){o!==void 0&&(clearTimeout(o),o=void 0),c()}}}export{enableOpfsPersistence,hasOpfs};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../_virtual/_rolldown/runtime.js";import{EACCES as e,EBADF as t,EEXIST as n,EINVAL as r,EISDIR as i,ENOENT as a,ENOTDIR as o,ENOTEMPTY as s}from"./errors.js";import{dirname as c,normalize as l,resolve as u,split as d}from"./path-utils.js";import{modeFor as f}from"./types.js";const p=new Uint8Array,now=()=>Date.now();function toStatFields(e){return{kind:e.kind,size:e.kind===`file`?e.data.byteLength:e.kind===`symlink`?e.target.length:0,mode:e.mode,atimeMs:e.atimeMs,mtimeMs:e.mtimeMs,ctimeMs:e.ctimeMs,birthtimeMs:e.birthtimeMs,uid:e.uid,gid:e.gid,ino:e.ino,nlink:e.nlink}}var Volume=class{root;nextIno=2;fds=new Map;nextFd=3;constructor(){this.root={kind:`dir`,children:new Map,...this.mkBase(`dir`,493),nlink:2},this.root.ino=1}mkBase(e,t){let n=now();return{mode:f(e,t),uid:0,gid:0,atimeMs:n,mtimeMs:n,ctimeMs:n,birthtimeMs:n,ino:this.nextIno++,nlink:1}}mkNode(e,t){let n=this.mkBase(e,t);return e===`file`?{kind:`file`,data:p,...n}:e===`dir`?{kind:`dir`,children:new Map,...n,nlink:2}:{kind:`symlink`,target:``,...n}}lookup(e,t){let n=u(e);if(n===`/`)return this.root;let r=this.root;for(let e of d(n)){if(r.kind!==`dir`)throw o(t,n);let i=r.children.get(e);if(!i)throw a(t,n);r=i}return r}lookupParent(e,t){let n=u(e);if(n===`/`)throw r(t,n);let i=this.lookup(c(n),t);if(i.kind!==`dir`)throw o(t,c(n));let a=d(n);return{parent:i,name:a[a.length-1],abs:n}}existsSync(e){try{return this.lookup(e,`stat`),!0}catch{return!1}}statSync(e){let t=this.lookup(e,`stat`);return t.atimeMs=now(),toStatFields(t)}lstatSync(e){return this.statSync(e)}accessSync(e,t){this.lookup(e,`access`)}readFileSync(e){let t=this.lookup(e,`open`);if(t.kind===`dir`)throw i(`read`,u(e));if(t.kind===`symlink`)throw r(`read`,u(e));return t.atimeMs=now(),new Uint8Array(t.data)}writeFileSync(e,t,n=438){let a=u(e);try{let e=this.lookup(a,`open`);if(e.kind===`dir`)throw i(`open`,a);if(e.kind===`symlink`)throw r(`open`,a);e.data=new Uint8Array(t),e.mtimeMs=e.ctimeMs=now()}catch(e){if(e.code!==`ENOENT`)throw e;let{parent:r,name:i}=this.lookupParent(a,`open`),o=this.mkNode(`file`,n);o.data=new Uint8Array(t),r.children.set(i,o),r.mtimeMs=r.ctimeMs=now()}}appendFileSync(e,t,n=438){let r=u(e);try{let e=this.lookup(r,`open`);if(e.kind!==`file`)throw i(`open`,r);let n=new Uint8Array(e.data.byteLength+t.byteLength);n.set(e.data,0),n.set(t,e.data.byteLength),e.data=n,e.mtimeMs=e.ctimeMs=now()}catch(e){if(e.code!==`ENOENT`)throw e;this.writeFileSync(r,t,n)}}truncateSync(e,t=0){let n=this.lookup(e,`open`);if(n.kind!==`file`)throw i(`open`,u(e));if(t<n.data.byteLength)n.data=n.data.slice(0,t);else if(t>n.data.byteLength){let e=new Uint8Array(t);e.set(n.data,0),n.data=e}n.mtimeMs=n.ctimeMs=now()}readdirSync(e){let t=this.lookup(e,`scandir`);if(t.kind!==`dir`)throw o(`scandir`,u(e));return[...t.children.keys()]}readdirEntriesSync(e){let t=this.lookup(e,`scandir`);if(t.kind!==`dir`)throw o(`scandir`,u(e));return[...t.children.entries()].map(([e,t])=>({name:e,kind:t.kind}))}mkdirSync(e,t={}){let r=u(e);if(r===`/`){if(t.recursive)return;throw n(`mkdir`,r)}let i=d(r),s=t.mode??511,c,l=this.root,f=``;for(let e=0;e<i.length;e++){let u=i[e];f+=`/`+u;let d=l.children.get(u);if(!d){if(!t.recursive&&e!==i.length-1)throw a(`mkdir`,r);let n=this.mkNode(`dir`,s);l.children.set(u,n),l.mtimeMs=l.ctimeMs=now(),c===void 0&&(c=f),l=n}else if(d.kind!==`dir`)throw o(`mkdir`,f);else if(e===i.length-1&&!t.recursive)throw n(`mkdir`,r);else l=d}return c}rmdirSync(t,n={}){let r=u(t);if(r===`/`)throw e(`rmdir`,r);let{parent:i,name:c}=this.lookupParent(r,`rmdir`),l=i.children.get(c);if(!l)throw a(`rmdir`,r);if(l.kind!==`dir`)throw o(`rmdir`,r);if(!n.recursive&&l.children.size>0)throw s(`rmdir`,r);i.children.delete(c),i.mtimeMs=i.ctimeMs=now()}unlinkSync(e){let t=u(e),{parent:n,name:r}=this.lookupParent(t,`unlink`),o=n.children.get(r);if(!o)throw a(`unlink`,t);if(o.kind===`dir`)throw i(`unlink`,t);n.children.delete(r),n.mtimeMs=n.ctimeMs=now()}rmSync(e,t={}){let n=u(e),r;try{r=this.lookup(n,`unlink`)}catch(e){if(t.force&&e.code===`ENOENT`)return;throw e}if(r.kind===`dir`){if(!t.recursive)throw i(`unlink`,n);this.rmdirSync(n,{recursive:!0});return}this.unlinkSync(n)}renameSync(e,t){let n=u(e),r=u(t);if(n===r)return;let{parent:i,name:o}=this.lookupParent(n,`rename`),c=i.children.get(o);if(!c)throw a(`rename`,n);let{parent:l,name:d}=this.lookupParent(r,`rename`),f=l.children.get(d);if(f?.kind===`dir`&&f.children.size>0)throw s(`rename`,r);i.children.delete(o),l.children.set(d,c);let p=now();i.mtimeMs=i.ctimeMs=p,l.mtimeMs=l.ctimeMs=p,c.ctimeMs=p}copyFileSync(e,t,r=0){let a=this.lookup(e,`copyfile`);if(a.kind!==`file`)throw i(`copyfile`,u(e));if(r&1&&this.existsSync(t))throw n(`copyfile`,u(t));this.writeFileSync(t,a.data,a.mode&511)}linkSync(e,t){let r=this.lookup(e,`link`);if(r.kind!==`file`)throw i(`link`,u(e));let{parent:a,name:o}=this.lookupParent(t,`link`);if(a.children.has(o))throw n(`link`,u(t));r.nlink+=1,a.children.set(o,{...r,kind:`file`}),a.mtimeMs=a.ctimeMs=now()}symlinkSync(e,t){let r=u(t),{parent:i,name:a}=this.lookupParent(r,`symlink`);if(i.children.has(a))throw n(`symlink`,r);let o=this.mkNode(`symlink`,511);o.target=e,i.children.set(a,o),i.mtimeMs=i.ctimeMs=now()}readlinkSync(e){let t=this.lookup(e,`readlink`);if(t.kind!==`symlink`)throw r(`readlink`,u(e));return t.target}realpathSync(e){let t=u(e);return this.lookup(t,`lstat`),t}chmodSync(e,t){let n=this.lookup(e,`chmod`);n.mode=n.mode&-4096|t&4095,n.ctimeMs=now()}chownSync(e,t,n){let r=this.lookup(e,`chown`);r.uid=t,r.gid=n,r.ctimeMs=now()}utimesSync(e,t,n){let r=this.lookup(e,`utimes`);r.atimeMs=t,r.mtimeMs=n,r.ctimeMs=now()}openSync(e,t,r=438){let a=u(e),o=t.includes(`w`)||t.includes(`a`)||t.includes(`x`),s=t===`w`||t===`w+`,c=t.includes(`x`),l;try{let e=this.lookup(a,`open`);if(e.kind!==`file`)throw i(`open`,a);if(c)throw n(`open`,a);l=e,s&&(l.data=p,l.mtimeMs=l.ctimeMs=now())}catch(e){if(e.code!==`ENOENT`||!o)throw e;let{parent:t,name:n}=this.lookupParent(a,`open`);l=this.mkNode(`file`,r),t.children.set(n,l),t.mtimeMs=t.ctimeMs=now()}let d=this.nextFd++;return this.fds.set(d,{node:l,path:a,position:t.includes(`a`)?l.data.byteLength:0,flags:t}),d}closeSync(e){if(!this.fds.delete(e))throw t(`close`)}readSync(e,n,r,i,a){let o=this.fds.get(e);if(!o)throw t(`read`);let s=a??o.position,c=o.node.data,l=Math.max(0,Math.min(s+i,c.byteLength)-s);return l>0&&n.set(c.subarray(s,s+l),r),a===null&&(o.position+=l),o.node.atimeMs=now(),l}writeSync(e,n,r,i,a){let o=this.fds.get(e);if(!o)throw t(`write`);let s=a??o.position,c=n.subarray(r,r+i),l=s+c.byteLength;if(l>o.node.data.byteLength){let e=new Uint8Array(l);e.set(o.node.data,0),o.node.data=e}return o.node.data.set(c,s),a===null&&(o.position=l),o.node.mtimeMs=o.node.ctimeMs=now(),c.byteLength}toJSON(){let e={},walk=(t,n)=>{t.children.size===0&&n!==`/`&&(e[n]=null);for(let[r,i]of t.children){let t=n===`/`?`/`+r:n+`/`+r;i.kind===`dir`?walk(i,t):i.kind===`file`?e[t]=new TextDecoder().decode(i.data):e[t]=`[symlink → ${i.target}]`}};return walk(this.root,`/`),e}fromJSON(e,t=`/`){for(let[n,r]of Object.entries(e)){let e=u(t,n);if(this.mkdirSync(c(e),{recursive:!0}),r===null)try{this.mkdirSync(e,{recursive:!0})}catch{}else{let t=typeof r==`string`?new TextEncoder().encode(r):r;this.writeFileSync(e,t)}}}reset(){this.root.children.clear(),this.fds.clear(),this.nextIno=2,this.nextFd=3}};const m=new Volume;function absolutise(e){if(typeof e==`string`)return u(l(e));if(e instanceof URL){if(e.protocol!==`file:`)throw TypeError(`unsupported URL scheme: ${e.protocol}`);return u(decodeURIComponent(e.pathname))}if(e&&typeof e.toString==`function`)return u(e.toString());throw TypeError(`path must be a string, Buffer, or URL`)}export{Volume,m as __defaultVolume,absolutise};
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{EACCES as e,EBADF as t,EEXIST as n,EINVAL as r,EISDIR as i,ENOENT as a,ENOTDIR as o,ENOTEMPTY as s}from"./errors.js";import{dirname as c,normalize as l,resolve as u,split as d}from"./path-utils.js";import{modeFor as f}from"./types.js";const p=new Uint8Array,now=()=>Date.now();function toStatFields(e){return{kind:e.kind,size:e.kind===`file`?e.data.byteLength:e.kind===`symlink`?e.target.length:0,mode:e.mode,atimeMs:e.atimeMs,mtimeMs:e.mtimeMs,ctimeMs:e.ctimeMs,birthtimeMs:e.birthtimeMs,uid:e.uid,gid:e.gid,ino:e.ino,nlink:e.nlink}}var Volume=class{root;nextIno=2;fds=new Map;nextFd=3;mutationListeners=new Set;constructor(){this.root={kind:`dir`,children:new Map,...this.mkBase(`dir`,493),nlink:2},this.root.ino=1}subscribe(e){return this.mutationListeners.add(e),()=>{this.mutationListeners.delete(e)}}notifyMutation(){for(let e of this.mutationListeners)try{e()}catch{}}mkBase(e,t){let n=now();return{mode:f(e,t),uid:0,gid:0,atimeMs:n,mtimeMs:n,ctimeMs:n,birthtimeMs:n,ino:this.nextIno++,nlink:1}}mkNode(e,t){let n=this.mkBase(e,t);return e===`file`?{kind:`file`,data:p,...n}:e===`dir`?{kind:`dir`,children:new Map,...n,nlink:2}:{kind:`symlink`,target:``,...n}}lookup(e,t){let n=u(e);if(n===`/`)return this.root;let r=this.root;for(let e of d(n)){if(r.kind!==`dir`)throw o(t,n);let i=r.children.get(e);if(!i)throw a(t,n);r=i}return r}lookupParent(e,t){let n=u(e);if(n===`/`)throw r(t,n);let i=this.lookup(c(n),t);if(i.kind!==`dir`)throw o(t,c(n));let a=d(n);return{parent:i,name:a[a.length-1],abs:n}}existsSync(e){try{return this.lookup(e,`stat`),!0}catch{return!1}}statSync(e){let t=this.lookup(e,`stat`);return t.atimeMs=now(),toStatFields(t)}lstatSync(e){return this.statSync(e)}accessSync(e,t){this.lookup(e,`access`)}readFileSync(e){let t=this.lookup(e,`open`);if(t.kind===`dir`)throw i(`read`,u(e));if(t.kind===`symlink`)throw r(`read`,u(e));return t.atimeMs=now(),new Uint8Array(t.data)}writeFileSync(e,t,n=438){let a=u(e);try{let e=this.lookup(a,`open`);if(e.kind===`dir`)throw i(`open`,a);if(e.kind===`symlink`)throw r(`open`,a);e.data=new Uint8Array(t),e.mtimeMs=e.ctimeMs=now()}catch(e){if(e.code!==`ENOENT`)throw e;let{parent:r,name:i}=this.lookupParent(a,`open`),o=this.mkNode(`file`,n);o.data=new Uint8Array(t),r.children.set(i,o),r.mtimeMs=r.ctimeMs=now()}this.notifyMutation()}appendFileSync(e,t,n=438){let r=u(e);try{let e=this.lookup(r,`open`);if(e.kind!==`file`)throw i(`open`,r);let n=new Uint8Array(e.data.byteLength+t.byteLength);n.set(e.data,0),n.set(t,e.data.byteLength),e.data=n,e.mtimeMs=e.ctimeMs=now(),this.notifyMutation()}catch(e){if(e.code!==`ENOENT`)throw e;this.writeFileSync(r,t,n)}}truncateSync(e,t=0){let n=this.lookup(e,`open`);if(n.kind!==`file`)throw i(`open`,u(e));if(t<n.data.byteLength)n.data=n.data.slice(0,t);else if(t>n.data.byteLength){let e=new Uint8Array(t);e.set(n.data,0),n.data=e}n.mtimeMs=n.ctimeMs=now(),this.notifyMutation()}readdirSync(e){let t=this.lookup(e,`scandir`);if(t.kind!==`dir`)throw o(`scandir`,u(e));return[...t.children.keys()]}readdirEntriesSync(e){let t=this.lookup(e,`scandir`);if(t.kind!==`dir`)throw o(`scandir`,u(e));return[...t.children.entries()].map(([e,t])=>({name:e,kind:t.kind}))}mkdirSync(e,t={}){let r=u(e);if(r===`/`){if(t.recursive)return;throw n(`mkdir`,r)}let i=d(r),s=t.mode??511,c,l=this.root,f=``;for(let e=0;e<i.length;e++){let u=i[e];f+=`/`+u;let d=l.children.get(u);if(!d){if(!t.recursive&&e!==i.length-1)throw a(`mkdir`,r);let n=this.mkNode(`dir`,s);l.children.set(u,n),l.mtimeMs=l.ctimeMs=now(),c===void 0&&(c=f),l=n}else if(d.kind!==`dir`)throw o(`mkdir`,f);else if(e===i.length-1&&!t.recursive)throw n(`mkdir`,r);else l=d}return c!==void 0&&this.notifyMutation(),c}rmdirSync(t,n={}){let r=u(t);if(r===`/`)throw e(`rmdir`,r);let{parent:i,name:c}=this.lookupParent(r,`rmdir`),l=i.children.get(c);if(!l)throw a(`rmdir`,r);if(l.kind!==`dir`)throw o(`rmdir`,r);if(!n.recursive&&l.children.size>0)throw s(`rmdir`,r);i.children.delete(c),i.mtimeMs=i.ctimeMs=now(),this.notifyMutation()}unlinkSync(e){let t=u(e),{parent:n,name:r}=this.lookupParent(t,`unlink`),o=n.children.get(r);if(!o)throw a(`unlink`,t);if(o.kind===`dir`)throw i(`unlink`,t);n.children.delete(r),n.mtimeMs=n.ctimeMs=now(),this.notifyMutation()}rmSync(e,t={}){let n=u(e),r;try{r=this.lookup(n,`unlink`)}catch(e){if(t.force&&e.code===`ENOENT`)return;throw e}if(r.kind===`dir`){if(!t.recursive)throw i(`unlink`,n);this.rmdirSync(n,{recursive:!0});return}this.unlinkSync(n)}renameSync(e,t){let n=u(e),r=u(t);if(n===r)return;let{parent:i,name:o}=this.lookupParent(n,`rename`),c=i.children.get(o);if(!c)throw a(`rename`,n);let{parent:l,name:d}=this.lookupParent(r,`rename`),f=l.children.get(d);if(f?.kind===`dir`&&f.children.size>0)throw s(`rename`,r);i.children.delete(o),l.children.set(d,c);let p=now();i.mtimeMs=i.ctimeMs=p,l.mtimeMs=l.ctimeMs=p,c.ctimeMs=p,this.notifyMutation()}copyFileSync(e,t,r=0){let a=this.lookup(e,`copyfile`);if(a.kind!==`file`)throw i(`copyfile`,u(e));if(r&1&&this.existsSync(t))throw n(`copyfile`,u(t));this.writeFileSync(t,a.data,a.mode&511)}linkSync(e,t){let r=this.lookup(e,`link`);if(r.kind!==`file`)throw i(`link`,u(e));let{parent:a,name:o}=this.lookupParent(t,`link`);if(a.children.has(o))throw n(`link`,u(t));r.nlink+=1,a.children.set(o,{...r,kind:`file`}),a.mtimeMs=a.ctimeMs=now(),this.notifyMutation()}symlinkSync(e,t){let r=u(t),{parent:i,name:a}=this.lookupParent(r,`symlink`);if(i.children.has(a))throw n(`symlink`,r);let o=this.mkNode(`symlink`,511);o.target=e,i.children.set(a,o),i.mtimeMs=i.ctimeMs=now(),this.notifyMutation()}readlinkSync(e){let t=this.lookup(e,`readlink`);if(t.kind!==`symlink`)throw r(`readlink`,u(e));return t.target}realpathSync(e){let t=u(e);return this.lookup(t,`lstat`),t}chmodSync(e,t){let n=this.lookup(e,`chmod`);n.mode=n.mode&-4096|t&4095,n.ctimeMs=now(),this.notifyMutation()}chownSync(e,t,n){let r=this.lookup(e,`chown`);r.uid=t,r.gid=n,r.ctimeMs=now(),this.notifyMutation()}utimesSync(e,t,n){let r=this.lookup(e,`utimes`);r.atimeMs=t,r.mtimeMs=n,r.ctimeMs=now(),this.notifyMutation()}openSync(e,t,r=438){let a=u(e),o=t.includes(`w`)||t.includes(`a`)||t.includes(`x`),s=t===`w`||t===`w+`,c=t.includes(`x`),l;try{let e=this.lookup(a,`open`);if(e.kind!==`file`)throw i(`open`,a);if(c)throw n(`open`,a);l=e,s&&(l.data=p,l.mtimeMs=l.ctimeMs=now())}catch(e){if(e.code!==`ENOENT`||!o)throw e;let{parent:t,name:n}=this.lookupParent(a,`open`);l=this.mkNode(`file`,r),t.children.set(n,l),t.mtimeMs=t.ctimeMs=now()}let d=this.nextFd++;return this.fds.set(d,{node:l,path:a,position:t.includes(`a`)?l.data.byteLength:0,flags:t}),d}closeSync(e){if(!this.fds.delete(e))throw t(`close`)}readSync(e,n,r,i,a){let o=this.fds.get(e);if(!o)throw t(`read`);let s=a??o.position,c=o.node.data,l=Math.max(0,Math.min(s+i,c.byteLength)-s);return l>0&&n.set(c.subarray(s,s+l),r),a===null&&(o.position+=l),o.node.atimeMs=now(),l}writeSync(e,n,r,i,a){let o=this.fds.get(e);if(!o)throw t(`write`);let s=a??o.position,c=n.subarray(r,r+i),l=s+c.byteLength;if(l>o.node.data.byteLength){let e=new Uint8Array(l);e.set(o.node.data,0),o.node.data=e}return o.node.data.set(c,s),a===null&&(o.position=l),o.node.mtimeMs=o.node.ctimeMs=now(),this.notifyMutation(),c.byteLength}toJSON(){let e={},walk=(t,n)=>{t.children.size===0&&n!==`/`&&(e[n]=null);for(let[r,i]of t.children){let t=n===`/`?`/`+r:n+`/`+r;i.kind===`dir`?walk(i,t):i.kind===`file`?e[t]=new TextDecoder().decode(i.data):e[t]=`[symlink → ${i.target}]`}};return walk(this.root,`/`),e}fromJSON(e,t=`/`){for(let[n,r]of Object.entries(e)){let e=u(t,n);if(this.mkdirSync(c(e),{recursive:!0}),r===null)try{this.mkdirSync(e,{recursive:!0})}catch{}else{let t=typeof r==`string`?new TextEncoder().encode(r):r;this.writeFileSync(e,t)}}}reset(){this.root.children.clear(),this.fds.clear(),this.nextIno=2,this.nextFd=3}};const m=new Volume;function absolutise(e){if(typeof e==`string`)return u(l(e));if(e instanceof URL){if(e.protocol!==`file:`)throw TypeError(`unsupported URL scheme: ${e.protocol}`);return u(decodeURIComponent(e.pathname))}if(e&&typeof e.toString==`function`)return u(e.toString());throw TypeError(`path must be a string, Buffer, or URL`)}export{Volume,m as __defaultVolume,absolutise};
|
package/lib/esm/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{COPYFILE_EXCL as ee,COPYFILE_FICLONE as te,COPYFILE_FICLONE_FORCE as e,F_OK as t,O_APPEND as n,O_CREAT as r,O_DIRECTORY as i,O_EXCL as a,O_NOFOLLOW as ne,O_NONBLOCK as o,O_RDONLY as s,O_RDWR as c,O_SYNC as l,O_TRUNC as u,O_WRONLY as d,R_OK as f,S_IFBLK as p,S_IFCHR as m,S_IFDIR as h,S_IFIFO as g,S_IFLNK as _,S_IFMT as v,S_IFREG as y,S_IFSOCK as b,S_IRGRP as x,S_IROTH as S,S_IRUSR as C,S_IRWXG as w,S_IRWXO as T,S_IRWXU as E,S_IWGRP as D,S_IWOTH as O,S_IWUSR as k,S_IXGRP as A,S_IXOTH as j,S_IXUSR as M,W_OK as N,X_OK as P,constants as F}from"./browser/constants.js";import{BigIntStats as I,Dirent as L,Stats as R}from"./browser/types.js";import{Volume as z,__defaultVolume as B}from"./browser/volume.js";import{accessSync as V,appendFileSync as H,chmodSync as U,chownSync as W,closeSync as G,copyFileSync as K,existsSync as q,linkSync as J,lstatSync as Y,mkdirSync as X,mkdtempSync as Z,openSync as re,readFileSync as ie,readSync as ae,readdirSync as oe,readlinkSync as se,realpathSync as Q,renameSync as ce,rmSync as le,rmdirSync as ue,statSync as de,symlinkSync as fe,sync_exports as pe,truncateSync as me,unlinkSync as he,utimesSync as ge,writeFileSync as _e,writeSync as ve}from"./browser/sync.js";import{access as ye,appendFile as be,async_exports as xe,chmod as Se,chown as Ce,close as we,copyFile as Te,exists as Ee,link as De,lstat as Oe,mkdir as ke,mkdtemp as Ae,open as je,read as Me,readFile as Ne,readdir as Pe,readlink as Fe,realpath as Ie,rename as Le,rm as Re,rmdir as ze,stat as Be,symlink as Ve,truncate as He,unlink as Ue,utimes as We,write as Ge,writeFile as Ke}from"./browser/async.js";import{FSWatcher as qe,ReadStream as Je,StatWatcher as Ye,WriteStream as Xe,createReadStream as Ze,createWriteStream as Qe,stream_exports as $e,unwatchFile as et,watch as tt,watchFile as nt}from"./browser/stream.js";import{promises_exports as $}from"./browser/promises.js";const
|
|
1
|
+
import{COPYFILE_EXCL as ee,COPYFILE_FICLONE as te,COPYFILE_FICLONE_FORCE as e,F_OK as t,O_APPEND as n,O_CREAT as r,O_DIRECTORY as i,O_EXCL as a,O_NOFOLLOW as ne,O_NONBLOCK as o,O_RDONLY as s,O_RDWR as c,O_SYNC as l,O_TRUNC as u,O_WRONLY as d,R_OK as f,S_IFBLK as p,S_IFCHR as m,S_IFDIR as h,S_IFIFO as g,S_IFLNK as _,S_IFMT as v,S_IFREG as y,S_IFSOCK as b,S_IRGRP as x,S_IROTH as S,S_IRUSR as C,S_IRWXG as w,S_IRWXO as T,S_IRWXU as E,S_IWGRP as D,S_IWOTH as O,S_IWUSR as k,S_IXGRP as A,S_IXOTH as j,S_IXUSR as M,W_OK as N,X_OK as P,constants as F}from"./browser/constants.js";import{BigIntStats as I,Dirent as L,Stats as R}from"./browser/types.js";import{Volume as z,__defaultVolume as B}from"./browser/volume.js";import{accessSync as V,appendFileSync as H,chmodSync as U,chownSync as W,closeSync as G,copyFileSync as K,existsSync as q,linkSync as J,lstatSync as Y,mkdirSync as X,mkdtempSync as Z,openSync as re,readFileSync as ie,readSync as ae,readdirSync as oe,readlinkSync as se,realpathSync as Q,renameSync as ce,rmSync as le,rmdirSync as ue,statSync as de,symlinkSync as fe,sync_exports as pe,truncateSync as me,unlinkSync as he,utimesSync as ge,writeFileSync as _e,writeSync as ve}from"./browser/sync.js";import{access as ye,appendFile as be,async_exports as xe,chmod as Se,chown as Ce,close as we,copyFile as Te,exists as Ee,link as De,lstat as Oe,mkdir as ke,mkdtemp as Ae,open as je,read as Me,readFile as Ne,readdir as Pe,readlink as Fe,realpath as Ie,rename as Le,rm as Re,rmdir as ze,stat as Be,symlink as Ve,truncate as He,unlink as Ue,utimes as We,write as Ge,writeFile as Ke}from"./browser/async.js";import{FSWatcher as qe,ReadStream as Je,StatWatcher as Ye,WriteStream as Xe,createReadStream as Ze,createWriteStream as Qe,stream_exports as $e,unwatchFile as et,watch as tt,watchFile as nt}from"./browser/stream.js";import{enableOpfsPersistence as rt,hasOpfs as it}from"./browser/opfs.js";import{promises_exports as $}from"./browser/promises.js";const at={constants:F,Volume:z,__defaultVolume:B,Stats:R,BigIntStats:I,Dirent:L,...pe,...xe,...$e,promises:$};export{I as BigIntStats,ee as COPYFILE_EXCL,te as COPYFILE_FICLONE,e as COPYFILE_FICLONE_FORCE,L as Dirent,qe as FSWatcher,t as F_OK,n as O_APPEND,r as O_CREAT,i as O_DIRECTORY,a as O_EXCL,ne as O_NOFOLLOW,o as O_NONBLOCK,s as O_RDONLY,c as O_RDWR,l as O_SYNC,u as O_TRUNC,d as O_WRONLY,f as R_OK,Je as ReadStream,p as S_IFBLK,m as S_IFCHR,h as S_IFDIR,g as S_IFIFO,_ as S_IFLNK,v as S_IFMT,y as S_IFREG,b as S_IFSOCK,x as S_IRGRP,S as S_IROTH,C as S_IRUSR,w as S_IRWXG,T as S_IRWXO,E as S_IRWXU,D as S_IWGRP,O as S_IWOTH,k as S_IWUSR,A as S_IXGRP,j as S_IXOTH,M as S_IXUSR,Ye as StatWatcher,R as Stats,z as Volume,N as W_OK,Xe as WriteStream,P as X_OK,B as __defaultVolume,ye as access,V as accessSync,be as appendFile,H as appendFileSync,Se as chmod,U as chmodSync,Ce as chown,W as chownSync,we as close,G as closeSync,F as constants,Te as copyFile,K as copyFileSync,Ze as createReadStream,Qe as createWriteStream,at as default,rt as enableOpfsPersistence,Ee as exists,q as existsSync,it as hasOpfs,De as link,J as linkSync,Oe as lstat,Y as lstatSync,ke as mkdir,X as mkdirSync,Ae as mkdtemp,Z as mkdtempSync,je as open,re as openSync,$ as promises,Me as read,Ne as readFile,ie as readFileSync,ae as readSync,Pe as readdir,oe as readdirSync,Fe as readlink,se as readlinkSync,Ie as realpath,Q as realpathSync,Le as rename,ce as renameSync,Re as rm,le as rmSync,ze as rmdir,ue as rmdirSync,Be as stat,de as statSync,Ve as symlink,fe as symlinkSync,He as truncate,me as truncateSync,Ue as unlink,he as unlinkSync,et as unwatchFile,We as utimes,ge as utimesSync,tt as watch,nt as watchFile,Ge as write,Ke as writeFile,_e as writeFileSync,ve as writeSync};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Volume } from './volume.js';
|
|
2
|
+
/** Options for {@link enableOpfsPersistence}. */
|
|
3
|
+
export interface OpfsPersistenceOptions {
|
|
4
|
+
/** Volume to persist. Defaults to the process-wide `__defaultVolume`. */
|
|
5
|
+
volume?: Volume;
|
|
6
|
+
/**
|
|
7
|
+
* Sub-directory inside the origin's private file system to mirror the
|
|
8
|
+
* volume into. Lets multiple independent volumes share one origin without
|
|
9
|
+
* clobbering each other. Default: `'gjsify-fs'`.
|
|
10
|
+
*/
|
|
11
|
+
rootDir?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Debounce window (ms) before a burst of mutations is flushed to OPFS.
|
|
14
|
+
* Default: `50`. Set to `0` to flush on every microtask turn.
|
|
15
|
+
*/
|
|
16
|
+
flushDelayMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Handle returned by {@link enableOpfsPersistence}. */
|
|
19
|
+
export interface OpfsPersistenceController {
|
|
20
|
+
/** Whether OPFS was available and persistence is active. */
|
|
21
|
+
readonly enabled: boolean;
|
|
22
|
+
/** If `enabled` is false, a short machine-readable reason. */
|
|
23
|
+
readonly reason?: 'no-opfs' | 'error';
|
|
24
|
+
/** Force an immediate flush of the volume to OPFS. Resolves when written. */
|
|
25
|
+
flush(): Promise<void>;
|
|
26
|
+
/** Stop persisting: unsubscribe the mutation listener (does not wipe OPFS). */
|
|
27
|
+
disable(): void;
|
|
28
|
+
}
|
|
29
|
+
/** Feature-detect the main-thread OPFS root accessor. */
|
|
30
|
+
export declare function hasOpfs(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Enable OPFS-backed persistence for a memfs `Volume`.
|
|
33
|
+
*
|
|
34
|
+
* Hydrates the volume from OPFS (so a prior session's files reappear) and then
|
|
35
|
+
* mirrors every subsequent mutation back to OPFS on a debounced schedule. The
|
|
36
|
+
* synchronous `fs.*Sync` API surface is untouched — reads and writes still hit
|
|
37
|
+
* the in-memory volume; OPFS is a write-behind durability layer.
|
|
38
|
+
*
|
|
39
|
+
* When OPFS is unavailable the returned controller has `enabled: false` and the
|
|
40
|
+
* volume continues to work purely in-memory. This never throws for a missing
|
|
41
|
+
* platform — only an actual OPFS I/O error during setup yields `reason: 'error'`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function enableOpfsPersistence(options?: OpfsPersistenceOptions): Promise<OpfsPersistenceController>;
|
|
@@ -4,21 +4,21 @@ export { constants } from './constants.js';
|
|
|
4
4
|
declare const _default: {
|
|
5
5
|
readFile: (path: string | URL | {
|
|
6
6
|
toString(): string;
|
|
7
|
-
}, opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
7
|
+
}, opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | import("./sync.js").ReadFileOpts) => Promise<string | Uint8Array<ArrayBufferLike>>;
|
|
8
8
|
writeFile: (path: string | URL | {
|
|
9
9
|
toString(): string;
|
|
10
10
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
11
11
|
buffer: ArrayBufferLike;
|
|
12
12
|
byteOffset?: number;
|
|
13
13
|
byteLength?: number;
|
|
14
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
14
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | import("./sync.js").WriteFileOpts) => Promise<void>;
|
|
15
15
|
appendFile: (path: string | URL | {
|
|
16
16
|
toString(): string;
|
|
17
17
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
18
18
|
buffer: ArrayBufferLike;
|
|
19
19
|
byteOffset?: number;
|
|
20
20
|
byteLength?: number;
|
|
21
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
21
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | import("./sync.js").WriteFileOpts) => Promise<void>;
|
|
22
22
|
stat: (path: string | URL | {
|
|
23
23
|
toString(): string;
|
|
24
24
|
}, opts?: import("./sync.js").StatOpts) => Promise<import("./types.js").Stats | import("./types.js").BigIntStats>;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import * as sync from './sync.js';
|
|
2
2
|
export declare const readFile: (path: string | URL | {
|
|
3
3
|
toString(): string;
|
|
4
|
-
}, opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
4
|
+
}, opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | sync.ReadFileOpts) => Promise<string | Uint8Array<ArrayBufferLike>>;
|
|
5
5
|
export declare const writeFile: (path: string | URL | {
|
|
6
6
|
toString(): string;
|
|
7
7
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
8
8
|
buffer: ArrayBufferLike;
|
|
9
9
|
byteOffset?: number;
|
|
10
10
|
byteLength?: number;
|
|
11
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
11
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | sync.WriteFileOpts) => Promise<void>;
|
|
12
12
|
export declare const appendFile: (path: string | URL | {
|
|
13
13
|
toString(): string;
|
|
14
14
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
15
15
|
buffer: ArrayBufferLike;
|
|
16
16
|
byteOffset?: number;
|
|
17
17
|
byteLength?: number;
|
|
18
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
18
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | sync.WriteFileOpts) => Promise<void>;
|
|
19
19
|
export declare const stat: (path: string | URL | {
|
|
20
20
|
toString(): string;
|
|
21
21
|
}, opts?: sync.StatOpts) => Promise<import("./types.js").Stats | import("./types.js").BigIntStats>;
|
|
@@ -5,7 +5,17 @@ export declare class Volume {
|
|
|
5
5
|
private nextIno;
|
|
6
6
|
private fds;
|
|
7
7
|
private nextFd;
|
|
8
|
+
private mutationListeners;
|
|
8
9
|
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* Register a listener invoked after every mutation (write / mkdir / unlink /
|
|
12
|
+
* rename / chmod / …). Returns an unsubscribe function. The OPFS persistence
|
|
13
|
+
* bridge uses this to debounce-flush the volume back to the Origin Private
|
|
14
|
+
* File System; it has no effect on the in-memory semantics.
|
|
15
|
+
*/
|
|
16
|
+
subscribe(listener: () => void): () => void;
|
|
17
|
+
/** Notify all mutation listeners. A listener failure never breaks the fs op. */
|
|
18
|
+
notifyMutation(): void;
|
|
9
19
|
private mkBase;
|
|
10
20
|
private mkNode;
|
|
11
21
|
private lookup;
|
package/lib/types/browser.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { Stats, BigIntStats, Dirent } from './browser/types.js';
|
|
|
5
5
|
export * from './browser/sync.js';
|
|
6
6
|
export * from './browser/async.js';
|
|
7
7
|
export { createReadStream, ReadStream, createWriteStream, WriteStream, FSWatcher, StatWatcher, watch, watchFile, unwatchFile, } from './browser/stream.js';
|
|
8
|
+
export { enableOpfsPersistence, hasOpfs, type OpfsPersistenceOptions, type OpfsPersistenceController, } from './browser/opfs.js';
|
|
8
9
|
import * as promises from './browser/promises.js';
|
|
9
10
|
export { promises };
|
|
10
11
|
import * as syncApi from './browser/sync.js';
|
|
@@ -55,21 +56,21 @@ declare const defaultExport: {
|
|
|
55
56
|
write(fd: number, buf: Uint8Array | string, offsetOrCb?: number | ((err: NodeJS.ErrnoException | null, value?: number) => void), lengthOrEnc?: number | string, positionOrCb?: number | null | ((err: NodeJS.ErrnoException | null, value?: number) => void), maybeCb?: (err: NodeJS.ErrnoException | null, value?: number) => void): void;
|
|
56
57
|
readFileSync(path: string | URL | {
|
|
57
58
|
toString(): string;
|
|
58
|
-
}, opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
59
|
+
}, opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | syncApi.ReadFileOpts): string | Uint8Array;
|
|
59
60
|
writeFileSync(path: string | URL | {
|
|
60
61
|
toString(): string;
|
|
61
62
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
62
63
|
buffer: ArrayBufferLike;
|
|
63
64
|
byteOffset?: number;
|
|
64
65
|
byteLength?: number;
|
|
65
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
66
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | syncApi.WriteFileOpts): void;
|
|
66
67
|
appendFileSync(path: string | URL | {
|
|
67
68
|
toString(): string;
|
|
68
69
|
}, data: string | (Uint8Array<ArrayBufferLike> | {
|
|
69
70
|
buffer: ArrayBufferLike;
|
|
70
71
|
byteOffset?: number;
|
|
71
72
|
byteLength?: number;
|
|
72
|
-
}), opts?: ("utf8" | "utf-8" | "ascii" | "binary" | "
|
|
73
|
+
}), opts?: ("base64" | "utf8" | "utf-8" | "ascii" | "binary" | "hex") | syncApi.WriteFileOpts): void;
|
|
73
74
|
statSync(path: string | URL | {
|
|
74
75
|
toString(): string;
|
|
75
76
|
}, opts?: syncApi.StatOpts): StatsCls | BigIntStatsCls | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/fs",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.38",
|
|
4
4
|
"description": "Node.js fs module for Gjs",
|
|
5
5
|
"module": "lib/esm/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -40,6 +40,10 @@
|
|
|
40
40
|
"./browser/stream": {
|
|
41
41
|
"types": "./lib/types/browser/stream.d.ts",
|
|
42
42
|
"default": "./lib/esm/browser/stream.js"
|
|
43
|
+
},
|
|
44
|
+
"./browser/opfs": {
|
|
45
|
+
"types": "./lib/types/browser/opfs.d.ts",
|
|
46
|
+
"default": "./lib/esm/browser/opfs.js"
|
|
43
47
|
}
|
|
44
48
|
},
|
|
45
49
|
"scripts": {
|
|
@@ -51,6 +55,7 @@
|
|
|
51
55
|
"build:test": "gjsify run build:test:gjs && gjsify run build:test:node",
|
|
52
56
|
"build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
|
|
53
57
|
"build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
|
|
58
|
+
"build:test:browser": "gjsify build src/test.browser.mts --app browser --outfile dist/test.browser.mjs",
|
|
54
59
|
"test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:node && gjsify run test:gjs",
|
|
55
60
|
"test:gjs": "gjsify run test.gjs.mjs",
|
|
56
61
|
"test:node": "node test.node.mjs"
|
|
@@ -61,25 +66,26 @@
|
|
|
61
66
|
"fs"
|
|
62
67
|
],
|
|
63
68
|
"devDependencies": {
|
|
64
|
-
"@gjsify/cli": "^0.4.
|
|
65
|
-
"@gjsify/unit": "^0.4.
|
|
69
|
+
"@gjsify/cli": "^0.4.38",
|
|
70
|
+
"@gjsify/unit": "^0.4.38",
|
|
66
71
|
"@types/node": "^25.9.1",
|
|
67
|
-
"typescript": "^
|
|
72
|
+
"typescript": "^6.0.3"
|
|
68
73
|
},
|
|
69
74
|
"dependencies": {
|
|
70
75
|
"@girs/gio-2.0": "2.88.0-4.0.4",
|
|
71
76
|
"@girs/glib-2.0": "2.88.0-4.0.4",
|
|
72
|
-
"@gjsify/buffer": "^0.4.
|
|
73
|
-
"@gjsify/events": "^0.4.
|
|
74
|
-
"@gjsify/stream": "^0.4.
|
|
75
|
-
"@gjsify/url": "^0.4.
|
|
76
|
-
"@gjsify/utils": "^0.4.
|
|
77
|
+
"@gjsify/buffer": "^0.4.38",
|
|
78
|
+
"@gjsify/events": "^0.4.38",
|
|
79
|
+
"@gjsify/stream": "^0.4.38",
|
|
80
|
+
"@gjsify/url": "^0.4.38",
|
|
81
|
+
"@gjsify/utils": "^0.4.38"
|
|
77
82
|
},
|
|
78
83
|
"gjsify": {
|
|
79
84
|
"runtimes": {
|
|
80
85
|
"gjs": "polyfill",
|
|
81
86
|
"node": "none",
|
|
82
|
-
"browser": "partial"
|
|
87
|
+
"browser": "partial",
|
|
88
|
+
"nativescript": "none"
|
|
83
89
|
}
|
|
84
90
|
},
|
|
85
91
|
"license": "MIT",
|