@statewalker/webrun-files 0.1.0 → 0.2.0

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/dist/index-umd.js CHANGED
@@ -1,4 +1,4 @@
1
- // @statewalker/webrun-files v0.1.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
1
+ // @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
4
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -823,46 +823,46 @@ async function openBrowserFilesApi({
823
823
  throw new Error("Can not access to the folder. Please try again.");
824
824
  }
825
825
  return new BrowserFilesApi({ rootHandler });
826
+ }
826
827
 
827
- async function isHandlerAccessible(fileHandle) {
828
- // We need to perform a real read operation with the handler
829
- // to check if the file/directory still exists.
830
- let exists = false;
831
- try {
832
- if (fileHandle.kind === "file") {
833
- await fileHandle.getFile();
834
- } else {
835
- for await (let item of fileHandle.values()) {
836
- break;
837
- }
828
+ async function isHandlerAccessible(fileHandle) {
829
+ // We need to perform a real read operation with the handler
830
+ // to check if the file/directory still exists.
831
+ let exists = false;
832
+ try {
833
+ if (fileHandle.kind === "file") {
834
+ await fileHandle.getFile();
835
+ } else {
836
+ for await (let item of fileHandle.values()) {
837
+ break;
838
838
  }
839
- exists = true;
840
- } catch (error) {
841
- console.log(error, fileHandle);
842
- exists = false;
843
839
  }
844
- return exists;
840
+ exists = true;
841
+ } catch (error) {
842
+ console.log(error, fileHandle);
843
+ exists = false;
845
844
  }
845
+ return exists;
846
+ }
846
847
 
847
- async function verifyPermission(fileHandle, readWrite) {
848
- const options = {};
849
- if (readWrite) {
850
- options.mode = "readwrite";
851
- }
852
- let granted = false;
853
- // Check if permission was already granted. If so, return true.
854
- if ((await fileHandle.queryPermission(options)) === "granted") {
855
- granted = true;
856
- }
857
- // Request permission. If the user grants permission, return true.
858
- if (
859
- !granted && (await fileHandle.requestPermission(options)) === "granted"
860
- ) {
861
- granted = true;
862
- }
863
- // The user didn't grant permission, so return false.
864
- return granted;
848
+ async function verifyPermission(fileHandle, readWrite) {
849
+ const options = {};
850
+ if (readWrite) {
851
+ options.mode = "readwrite";
852
+ }
853
+ let granted = false;
854
+ // Check if permission was already granted. If so, return true.
855
+ if ((await fileHandle.queryPermission(options)) === "granted") {
856
+ granted = true;
857
+ }
858
+ // Request permission. If the user grants permission, return true.
859
+ if (
860
+ !granted && (await fileHandle.requestPermission(options)) === "granted"
861
+ ) {
862
+ granted = true;
865
863
  }
864
+ // The user didn't grant permission, so return false.
865
+ return granted;
866
866
  }
867
867
 
868
868
  exports.BrowserFilesApi = BrowserFilesApi;
@@ -872,10 +872,12 @@ exports.NodeFilesApi = NodeFilesApi;
872
872
  exports.addFilesApiLogger = addFilesApiLogger;
873
873
  exports.extensionToMimeType = extensionToMimeType;
874
874
  exports.getMimeType = getMimeType;
875
+ exports.isHandlerAccessible = isHandlerAccessible;
875
876
  exports.mimeTypeToExtensions = mimeTypeToExtensions;
876
877
  exports.mimeTypes = mimeTypes;
877
878
  exports.mimeTypesDescriptions = mimeTypesDescriptions;
878
879
  exports.normalizePath = normalizePath;
879
880
  exports.openBrowserFilesApi = openBrowserFilesApi;
881
+ exports.verifyPermission = verifyPermission;
880
882
 
881
883
  }));
@@ -1,2 +1,2 @@
1
- // @statewalker/webrun-files v0.1.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker["webrun-files"]=e.statewalker["webrun-files"]||{}))}(this,(function(e){"use strict";function t(e){const t=e.split("/").filter((e=>!!e&&"."!==e));return 0===t.length&&t.push(""),t.unshift(""),t.join("/")}function i(){throw new Error("Not implemented.")}class n{constructor(e){this.options=e||{}}async*list(e,t={}){yield i()}async stats(e){return i()}async remove(e){return i()}async write(e,t){return i()}async*read(e,t){yield i()}async copy(e,t,i={}){const n=async(e,t,i)=>{t=`${t}${i.path.substring(e.length)}`;const n=this.read(i);return await this.write(t,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(e);if("directory"===o.kind)for await(const o of this.list(e,{...i,recursive:s}))"directory"!==o.kind&&await n(e,t,o);else await n(e,t,o);return!0}async move(e,t,i={}){return!!await this.copy(e,t,i)&&(await this.remove(e),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const s=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],o=s.reduce(((e,t)=>(e[t.mime]=t.description,e)),{}),a=s.reduce(((e,t)=>{for(const i of t.extensions)e[i]=t.mime;return e}),{}),r=s.reduce(((e,t)=>(e[t.mime]=t.extensions,e)),{});function c(e){const t=e=e||"",i=(e=(e=e.split("?").shift()).split("/").pop()).split(".").pop();let n=a[i];return n||(n=t.match(/api\.observablehq\.com/)||t.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}function p(e){const t=e.split("/");return t.pop(),t.join("/")}function d(...e){let t=e.map((e=>e.split("/"))).reduce(((e,t)=>(e.push(...t),e)),[]);const i=t.shift();return t=t.filter((e=>!!e&&"."!==e)),t.unshift(i),t.join("/")}async function m(e,t){try{const i=await e.stat(t);if(i&&i.isDirectory())return!0}catch(e){}const i=p(t);return t!==i&&(await m(e,i),await e.mkdir(t,{recursive:!0}),!0)}async function l(e,t){try{if((await e.stat(t)).isDirectory()){for await(let i of f(e,t,!1))await l(e,i.path);await e.rmdir(t)}else await e.unlink(t)}catch(e){if("ENOENT"!==e.code)throw e}}async function*f(e,t,i){try{if((await e.stat(t)).isDirectory()){const n=await e.readdir(t);for(const s of n.sort()){const n=d(t,s);let o=await e.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(e,n,!0))}}}catch(e){if("ENOENT"!==e.code)throw e}}class h extends n{constructor(e){if(super(e),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(e,{recursive:t=!1}={}){const i=this._getPathSegments(e),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*e(t,i,n){for await(const o of i.values())yield await s._getFileInfo([...t,o.name],o),n&&"directory"==o.kind&&(yield*e([...t,o.name],o,n))}(i,n,t))}async stats(e){const t=this._getPathSegments(e),i=await this._getHandler(t,!1);return i?await this._getFileInfo(t,i):null}async remove(e){let t=this._getPathSegments(e);const i=t.pop(),n=await this._getHandler(t,!1),s=[];if(i)s.push(i);else for await(const e of n.values())s.push(e.name);for(const e of s)await n.removeEntry(e,{recursive:!0});return!0}async write(e,t){const i=this._getPathSegments(e),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof t&&(t=t());for await(let e of t)await s.write(e.buffer?e.buffer:e)}finally{await s.close()}}async*read(e){const t=this._getPathSegments(e),i=await this._getFileHandler(t,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let e;for(;(e=await n.read())&&!e.done;)yield e.value}finally{n.cancel&&n.cancel()}}async _getHandler(e,t=!1){let i;try{i=await this._getFileHandler(e,t)}catch(n){try{i=await this._getDirectoryHandler(e,t)}catch(e){}}return i}async _getDirectoryHandler(e,t=!0){e=[...e];let i=this.rootHandler;for(let n of e)i=await i.getDirectoryHandle(n,{create:t});return i}async _getFileHandler(e,t=!0){const i=(e=[...e]).pop();let n=this.rootHandler;for(let t of e)n=await n.getDirectoryHandle(t,{create:!0});return await n.getFileHandle(i,{create:t})}async _getFileInfo(e,t){const i=(e=[...e])[e.length-1];e.unshift("");const n=e.join("/"),s={kind:"",path:n,name:i};if("directory"===t.kind)s.kind="directory";else{s.kind="file";const e=await t.getFile();s.size=e.size,s.type=c(n),s.lastModified=e.lastModified}return s}_getPathSegments(e){return("object"==typeof e?e.path:e+"").split("/").filter((e=>!!e))}}e.BrowserFilesApi=h,e.FilesApi=n,e.MemFilesApi=class extends n{constructor(e){super(e),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(e,{recursive:t=!1}={}){await this._init();const i=this.normalizePath(e),n=this._getPaths();for(const e of n){if(0!==e.indexOf(i)||e===i)continue;const n=e.substring(i.length+1).split("/");(t||1===n.length)&&(yield this._getFileInfo(e))}}async stats(e){await this._init();const t=this.normalizePath(e);return this._getFileInfo(t)}async remove(e){await this._init();const t=await this.stats(e);if(!t)return!1;for await(const{path:e}of this.list(t,{recursive:!0}))"/"!==e&&delete this.index[e];delete this.index[t.path]}async write(e,t){await this._init(),await this._doWrite(e,t)}async*read(e){await this._init();const t=this.normalizePath(e),i=this.index[t];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(e,t){const i=this.normalizePath(e).split("/").filter((e=>!!e)),n=[""];let s;for(let e=0;e<i.length;e++){const t=i[e];n.push(t);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:t,kind:"directory"}}s.kind="file",s.content=[],s.type=c(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof t&&(t=t());for await(let e of t)e=new Uint8Array(e),s.content.push(e),s.size+=e.length}async _addEntries(e={}){for(let[t,i]of Object.entries(e))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(t,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(e){return Object.keys(e).sort((function(e,t){return e>t?1:e<t?-1:0}))}_getFileInfo(e){const t=this.index[e];if(!t)return null;const i={...t};return delete i.content,i}},e.NodeFilesApi=class extends n{constructor(e){if(super(e),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const e=this.rootDir;return await m(this.fs,e)})()}async*list(e,{recursive:t=!1}={}){await this._init();const i=this._expandPath(e),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let e of f(this.fs,i,t))yield this._getFileInfo(e.path,e.stat)}async stats(e){await this._init();const t=this._expandPath(e);return this._stats(t)}async remove(e){await this._init();const t=this._expandPath(e);return await l(this.fs,t)}async write(e,t){await this._init();const i=this._expandPath(e),n=p(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof t&&(t=t()),await s.writeFile(t)}finally{s&&await s.close()}}async*read(e,{start:t=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(e);let s;try{s=await this.fs.open(n,"r");const e=0;for(let n=t,o=0;;n+=o){const t=new Uint8ClampedArray(i),a=await s.read(t,e,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(e){try{const t=await this.fs.stat(e);return this._getFileInfo(e,t)}catch(e){if("ENOENT"!==e.code)throw e;return null}}_getFileInfo(e,t){const i=this._toPathSegments(e).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:e=i.join("/"),name:n,kind:""};return t.isFile()?(s.size=t.size||0,s.type=c(e),s.kind="file",s.lastModified=new Date(t.mtime).getTime()):s.kind="directory",s}_toPathSegments(e){return(e=this.normalizePath(e)).split("/")}_expandPath(e){const t="object"==typeof e?e.path:e+"",i=this._toPathSegments(t).filter((e=>!!e));return i.unshift(...this.rootDirSegments),i.join("/")}},e.addFilesApiLogger=function({filesApi:e,log:t=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=e[n].bind(e);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return t(o),o.result=s.call(e,...i)}catch(e){o.error=e}finally{o.stage="exit",t(o)}},i}),i)},e.extensionToMimeType=a,e.getMimeType=c,e.mimeTypeToExtensions=r,e.mimeTypes=s,e.mimeTypesDescriptions=o,e.normalizePath=t,e.openBrowserFilesApi=async function({handlerKey:e="root-dir",readwrite:t=!0,index:i={},get:n=(async e=>i[e]),set:s=(async(e,t)=>i[e]=t),del:o=(async e=>delete i[e])}={}){let a=await n(e);if(a||(a=await window.showDirectoryPicker(),await s(e,a)),!await async function(e,t){const i={};t&&(i.mode="readwrite");let n=!1;"granted"===await e.queryPermission(i)&&(n=!0);n||"granted"!==await e.requestPermission(i)||(n=!0);return n}(a,t))throw new Error("Access was not granted");if(!await async function(e){let t=!1;try{if("file"===e.kind)await e.getFile();else for await(let t of e.values())break;t=!0}catch(i){console.log(i,e),t=!1}return t}(a))throw await o(e),new Error("Can not access to the folder. Please try again.");return new h({rootHandler:a})}}));
1
+ // @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker["webrun-files"]=e.statewalker["webrun-files"]||{}))}(this,(function(e){"use strict";function t(e){const t=e.split("/").filter((e=>!!e&&"."!==e));return 0===t.length&&t.push(""),t.unshift(""),t.join("/")}function i(){throw new Error("Not implemented.")}class n{constructor(e){this.options=e||{}}async*list(e,t={}){yield i()}async stats(e){return i()}async remove(e){return i()}async write(e,t){return i()}async*read(e,t){yield i()}async copy(e,t,i={}){const n=async(e,t,i)=>{t=`${t}${i.path.substring(e.length)}`;const n=this.read(i);return await this.write(t,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(e);if("directory"===o.kind)for await(const o of this.list(e,{...i,recursive:s}))"directory"!==o.kind&&await n(e,t,o);else await n(e,t,o);return!0}async move(e,t,i={}){return!!await this.copy(e,t,i)&&(await this.remove(e),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const s=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],o=s.reduce(((e,t)=>(e[t.mime]=t.description,e)),{}),a=s.reduce(((e,t)=>{for(const i of t.extensions)e[i]=t.mime;return e}),{}),r=s.reduce(((e,t)=>(e[t.mime]=t.extensions,e)),{});function c(e){const t=e=e||"",i=(e=(e=e.split("?").shift()).split("/").pop()).split(".").pop();let n=a[i];return n||(n=t.match(/api\.observablehq\.com/)||t.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}function p(e){const t=e.split("/");return t.pop(),t.join("/")}function d(...e){let t=e.map((e=>e.split("/"))).reduce(((e,t)=>(e.push(...t),e)),[]);const i=t.shift();return t=t.filter((e=>!!e&&"."!==e)),t.unshift(i),t.join("/")}async function m(e,t){try{const i=await e.stat(t);if(i&&i.isDirectory())return!0}catch(e){}const i=p(t);return t!==i&&(await m(e,i),await e.mkdir(t,{recursive:!0}),!0)}async function l(e,t){try{if((await e.stat(t)).isDirectory()){for await(let i of f(e,t,!1))await l(e,i.path);await e.rmdir(t)}else await e.unlink(t)}catch(e){if("ENOENT"!==e.code)throw e}}async function*f(e,t,i){try{if((await e.stat(t)).isDirectory()){const n=await e.readdir(t);for(const s of n.sort()){const n=d(t,s);let o=await e.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(e,n,!0))}}}catch(e){if("ENOENT"!==e.code)throw e}}class h extends n{constructor(e){if(super(e),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(e,{recursive:t=!1}={}){const i=this._getPathSegments(e),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*e(t,i,n){for await(const o of i.values())yield await s._getFileInfo([...t,o.name],o),n&&"directory"==o.kind&&(yield*e([...t,o.name],o,n))}(i,n,t))}async stats(e){const t=this._getPathSegments(e),i=await this._getHandler(t,!1);return i?await this._getFileInfo(t,i):null}async remove(e){let t=this._getPathSegments(e);const i=t.pop(),n=await this._getHandler(t,!1),s=[];if(i)s.push(i);else for await(const e of n.values())s.push(e.name);for(const e of s)await n.removeEntry(e,{recursive:!0});return!0}async write(e,t){const i=this._getPathSegments(e),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof t&&(t=t());for await(let e of t)await s.write(e.buffer?e.buffer:e)}finally{await s.close()}}async*read(e){const t=this._getPathSegments(e),i=await this._getFileHandler(t,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let e;for(;(e=await n.read())&&!e.done;)yield e.value}finally{n.cancel&&n.cancel()}}async _getHandler(e,t=!1){let i;try{i=await this._getFileHandler(e,t)}catch(n){try{i=await this._getDirectoryHandler(e,t)}catch(e){}}return i}async _getDirectoryHandler(e,t=!0){e=[...e];let i=this.rootHandler;for(let n of e)i=await i.getDirectoryHandle(n,{create:t});return i}async _getFileHandler(e,t=!0){const i=(e=[...e]).pop();let n=this.rootHandler;for(let t of e)n=await n.getDirectoryHandle(t,{create:!0});return await n.getFileHandle(i,{create:t})}async _getFileInfo(e,t){const i=(e=[...e])[e.length-1];e.unshift("");const n=e.join("/"),s={kind:"",path:n,name:i};if("directory"===t.kind)s.kind="directory";else{s.kind="file";const e=await t.getFile();s.size=e.size,s.type=c(n),s.lastModified=e.lastModified}return s}_getPathSegments(e){return("object"==typeof e?e.path:e+"").split("/").filter((e=>!!e))}}async function u(e){let t=!1;try{if("file"===e.kind)await e.getFile();else for await(let t of e.values())break;t=!0}catch(i){console.log(i,e),t=!1}return t}async function x(e,t){const i={};t&&(i.mode="readwrite");let n=!1;return"granted"===await e.queryPermission(i)&&(n=!0),n||"granted"!==await e.requestPermission(i)||(n=!0),n}e.BrowserFilesApi=h,e.FilesApi=n,e.MemFilesApi=class extends n{constructor(e){super(e),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(e,{recursive:t=!1}={}){await this._init();const i=this.normalizePath(e),n=this._getPaths();for(const e of n){if(0!==e.indexOf(i)||e===i)continue;const n=e.substring(i.length+1).split("/");(t||1===n.length)&&(yield this._getFileInfo(e))}}async stats(e){await this._init();const t=this.normalizePath(e);return this._getFileInfo(t)}async remove(e){await this._init();const t=await this.stats(e);if(!t)return!1;for await(const{path:e}of this.list(t,{recursive:!0}))"/"!==e&&delete this.index[e];delete this.index[t.path]}async write(e,t){await this._init(),await this._doWrite(e,t)}async*read(e){await this._init();const t=this.normalizePath(e),i=this.index[t];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(e,t){const i=this.normalizePath(e).split("/").filter((e=>!!e)),n=[""];let s;for(let e=0;e<i.length;e++){const t=i[e];n.push(t);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:t,kind:"directory"}}s.kind="file",s.content=[],s.type=c(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof t&&(t=t());for await(let e of t)e=new Uint8Array(e),s.content.push(e),s.size+=e.length}async _addEntries(e={}){for(let[t,i]of Object.entries(e))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(t,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(e){return Object.keys(e).sort((function(e,t){return e>t?1:e<t?-1:0}))}_getFileInfo(e){const t=this.index[e];if(!t)return null;const i={...t};return delete i.content,i}},e.NodeFilesApi=class extends n{constructor(e){if(super(e),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const e=this.rootDir;return await m(this.fs,e)})()}async*list(e,{recursive:t=!1}={}){await this._init();const i=this._expandPath(e),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let e of f(this.fs,i,t))yield this._getFileInfo(e.path,e.stat)}async stats(e){await this._init();const t=this._expandPath(e);return this._stats(t)}async remove(e){await this._init();const t=this._expandPath(e);return await l(this.fs,t)}async write(e,t){await this._init();const i=this._expandPath(e),n=p(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof t&&(t=t()),await s.writeFile(t)}finally{s&&await s.close()}}async*read(e,{start:t=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(e);let s;try{s=await this.fs.open(n,"r");const e=0;for(let n=t,o=0;;n+=o){const t=new Uint8ClampedArray(i),a=await s.read(t,e,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(e){try{const t=await this.fs.stat(e);return this._getFileInfo(e,t)}catch(e){if("ENOENT"!==e.code)throw e;return null}}_getFileInfo(e,t){const i=this._toPathSegments(e).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:e=i.join("/"),name:n,kind:""};return t.isFile()?(s.size=t.size||0,s.type=c(e),s.kind="file",s.lastModified=new Date(t.mtime).getTime()):s.kind="directory",s}_toPathSegments(e){return(e=this.normalizePath(e)).split("/")}_expandPath(e){const t="object"==typeof e?e.path:e+"",i=this._toPathSegments(t).filter((e=>!!e));return i.unshift(...this.rootDirSegments),i.join("/")}},e.addFilesApiLogger=function({filesApi:e,log:t=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=e[n].bind(e);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return t(o),o.result=s.call(e,...i)}catch(e){o.error=e}finally{o.stage="exit",t(o)}},i}),i)},e.extensionToMimeType=a,e.getMimeType=c,e.isHandlerAccessible=u,e.mimeTypeToExtensions=r,e.mimeTypes=s,e.mimeTypesDescriptions=o,e.normalizePath=t,e.openBrowserFilesApi=async function({handlerKey:e="root-dir",readwrite:t=!0,index:i={},get:n=(async e=>i[e]),set:s=(async(e,t)=>i[e]=t),del:o=(async e=>delete i[e])}={}){let a=await n(e);if(a||(a=await window.showDirectoryPicker(),await s(e,a)),!await x(a,t))throw new Error("Access was not granted");if(!await u(a))throw await o(e),new Error("Can not access to the folder. Please try again.");return new h({rootHandler:a})},e.verifyPermission=x}));
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // @statewalker/webrun-files v0.1.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
1
+ // @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
2
  function normalizePath(filePath) {
3
3
  const segments = filePath.split("/").filter((s) => !!s && s !== ".");
4
4
  if (segments.length === 0) {
@@ -817,46 +817,46 @@ async function openBrowserFilesApi({
817
817
  throw new Error("Can not access to the folder. Please try again.");
818
818
  }
819
819
  return new BrowserFilesApi({ rootHandler });
820
+ }
820
821
 
821
- async function isHandlerAccessible(fileHandle) {
822
- // We need to perform a real read operation with the handler
823
- // to check if the file/directory still exists.
824
- let exists = false;
825
- try {
826
- if (fileHandle.kind === "file") {
827
- await fileHandle.getFile();
828
- } else {
829
- for await (let item of fileHandle.values()) {
830
- break;
831
- }
822
+ async function isHandlerAccessible(fileHandle) {
823
+ // We need to perform a real read operation with the handler
824
+ // to check if the file/directory still exists.
825
+ let exists = false;
826
+ try {
827
+ if (fileHandle.kind === "file") {
828
+ await fileHandle.getFile();
829
+ } else {
830
+ for await (let item of fileHandle.values()) {
831
+ break;
832
832
  }
833
- exists = true;
834
- } catch (error) {
835
- console.log(error, fileHandle);
836
- exists = false;
837
833
  }
838
- return exists;
834
+ exists = true;
835
+ } catch (error) {
836
+ console.log(error, fileHandle);
837
+ exists = false;
839
838
  }
839
+ return exists;
840
+ }
840
841
 
841
- async function verifyPermission(fileHandle, readWrite) {
842
- const options = {};
843
- if (readWrite) {
844
- options.mode = "readwrite";
845
- }
846
- let granted = false;
847
- // Check if permission was already granted. If so, return true.
848
- if ((await fileHandle.queryPermission(options)) === "granted") {
849
- granted = true;
850
- }
851
- // Request permission. If the user grants permission, return true.
852
- if (
853
- !granted && (await fileHandle.requestPermission(options)) === "granted"
854
- ) {
855
- granted = true;
856
- }
857
- // The user didn't grant permission, so return false.
858
- return granted;
842
+ async function verifyPermission(fileHandle, readWrite) {
843
+ const options = {};
844
+ if (readWrite) {
845
+ options.mode = "readwrite";
846
+ }
847
+ let granted = false;
848
+ // Check if permission was already granted. If so, return true.
849
+ if ((await fileHandle.queryPermission(options)) === "granted") {
850
+ granted = true;
851
+ }
852
+ // Request permission. If the user grants permission, return true.
853
+ if (
854
+ !granted && (await fileHandle.requestPermission(options)) === "granted"
855
+ ) {
856
+ granted = true;
859
857
  }
858
+ // The user didn't grant permission, so return false.
859
+ return granted;
860
860
  }
861
861
 
862
- export { BrowserFilesApi, FilesApi, MemFilesApi, NodeFilesApi, addFilesApiLogger, extensionToMimeType, getMimeType, mimeTypeToExtensions, mimeTypes, mimeTypesDescriptions, normalizePath, openBrowserFilesApi };
862
+ export { BrowserFilesApi, FilesApi, MemFilesApi, NodeFilesApi, addFilesApiLogger, extensionToMimeType, getMimeType, isHandlerAccessible, mimeTypeToExtensions, mimeTypes, mimeTypesDescriptions, normalizePath, openBrowserFilesApi, verifyPermission };
package/dist/index.min.js CHANGED
@@ -1,2 +1,2 @@
1
- // @statewalker/webrun-files v0.1.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
- function t(t){const e=t.split("/").filter((t=>!!t&&"."!==t));return 0===e.length&&e.push(""),e.unshift(""),e.join("/")}function e(){throw new Error("Not implemented.")}class i{constructor(t){this.options=t||{}}async*list(t,i={}){yield e()}async stats(t){return e()}async remove(t){return e()}async write(t,i){return e()}async*read(t,i){yield e()}async copy(t,e,i={}){const n=async(t,e,i)=>{e=`${e}${i.path.substring(t.length)}`;const n=this.read(i);return await this.write(e,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(t);if("directory"===o.kind)for await(const o of this.list(t,{...i,recursive:s}))"directory"!==o.kind&&await n(t,e,o);else await n(t,e,o);return!0}async move(t,e,i={}){return!!await this.copy(t,e,i)&&(await this.remove(t),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const n=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],s=n.reduce(((t,e)=>(t[e.mime]=e.description,t)),{}),o=n.reduce(((t,e)=>{for(const i of e.extensions)t[i]=e.mime;return t}),{}),a=n.reduce(((t,e)=>(t[e.mime]=e.extensions,t)),{});function r(t){const e=t=t||"",i=(t=(t=t.split("?").shift()).split("/").pop()).split(".").pop();let n=o[i];return n||(n=e.match(/api\.observablehq\.com/)||e.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}class c extends i{constructor(t){super(t),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(t,{recursive:e=!1}={}){await this._init();const i=this.normalizePath(t),n=this._getPaths();for(const t of n){if(0!==t.indexOf(i)||t===i)continue;const n=t.substring(i.length+1).split("/");(e||1===n.length)&&(yield this._getFileInfo(t))}}async stats(t){await this._init();const e=this.normalizePath(t);return this._getFileInfo(e)}async remove(t){await this._init();const e=await this.stats(t);if(!e)return!1;for await(const{path:t}of this.list(e,{recursive:!0}))"/"!==t&&delete this.index[t];delete this.index[e.path]}async write(t,e){await this._init(),await this._doWrite(t,e)}async*read(t){await this._init();const e=this.normalizePath(t),i=this.index[e];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(t,e){const i=this.normalizePath(t).split("/").filter((t=>!!t)),n=[""];let s;for(let t=0;t<i.length;t++){const e=i[t];n.push(e);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:e,kind:"directory"}}s.kind="file",s.content=[],s.type=r(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof e&&(e=e());for await(let t of e)t=new Uint8Array(t),s.content.push(t),s.size+=t.length}async _addEntries(t={}){for(let[e,i]of Object.entries(t))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(e,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(t){return Object.keys(t).sort((function(t,e){return t>e?1:t<e?-1:0}))}_getFileInfo(t){const e=this.index[t];if(!e)return null;const i={...e};return delete i.content,i}}class p extends i{constructor(t){if(super(t),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const t=this.rootDir;return await l(this.fs,t)})()}async*list(t,{recursive:e=!1}={}){await this._init();const i=this._expandPath(t),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let t of f(this.fs,i,e))yield this._getFileInfo(t.path,t.stat)}async stats(t){await this._init();const e=this._expandPath(t);return this._stats(e)}async remove(t){await this._init();const e=this._expandPath(t);return await h(this.fs,e)}async write(t,e){await this._init();const i=this._expandPath(t),n=d(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof e&&(e=e()),await s.writeFile(e)}finally{s&&await s.close()}}async*read(t,{start:e=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(t);let s;try{s=await this.fs.open(n,"r");const t=0;for(let n=e,o=0;;n+=o){const e=new Uint8ClampedArray(i),a=await s.read(e,t,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(t){try{const e=await this.fs.stat(t);return this._getFileInfo(t,e)}catch(t){if("ENOENT"!==t.code)throw t;return null}}_getFileInfo(t,e){const i=this._toPathSegments(t).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:t=i.join("/"),name:n,kind:""};return e.isFile()?(s.size=e.size||0,s.type=r(t),s.kind="file",s.lastModified=new Date(e.mtime).getTime()):s.kind="directory",s}_toPathSegments(t){return(t=this.normalizePath(t)).split("/")}_expandPath(t){const e="object"==typeof t?t.path:t+"",i=this._toPathSegments(e).filter((t=>!!t));return i.unshift(...this.rootDirSegments),i.join("/")}}function d(t){const e=t.split("/");return e.pop(),e.join("/")}function m(...t){let e=t.map((t=>t.split("/"))).reduce(((t,e)=>(t.push(...e),t)),[]);const i=e.shift();return e=e.filter((t=>!!t&&"."!==t)),e.unshift(i),e.join("/")}async function l(t,e){try{const i=await t.stat(e);if(i&&i.isDirectory())return!0}catch(t){}const i=d(e);return e!==i&&(await l(t,i),await t.mkdir(e,{recursive:!0}),!0)}async function h(t,e){try{if((await t.stat(e)).isDirectory()){for await(let i of f(t,e,!1))await h(t,i.path);await t.rmdir(e)}else await t.unlink(e)}catch(t){if("ENOENT"!==t.code)throw t}}async function*f(t,e,i){try{if((await t.stat(e)).isDirectory()){const n=await t.readdir(e);for(const s of n.sort()){const n=m(e,s);let o=await t.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(t,n,!0))}}}catch(t){if("ENOENT"!==t.code)throw t}}class u extends i{constructor(t){if(super(t),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(t,{recursive:e=!1}={}){const i=this._getPathSegments(t),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*t(e,i,n){for await(const o of i.values())yield await s._getFileInfo([...e,o.name],o),n&&"directory"==o.kind&&(yield*t([...e,o.name],o,n))}(i,n,e))}async stats(t){const e=this._getPathSegments(t),i=await this._getHandler(e,!1);return i?await this._getFileInfo(e,i):null}async remove(t){let e=this._getPathSegments(t);const i=e.pop(),n=await this._getHandler(e,!1),s=[];if(i)s.push(i);else for await(const t of n.values())s.push(t.name);for(const t of s)await n.removeEntry(t,{recursive:!0});return!0}async write(t,e){const i=this._getPathSegments(t),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof e&&(e=e());for await(let t of e)await s.write(t.buffer?t.buffer:t)}finally{await s.close()}}async*read(t){const e=this._getPathSegments(t),i=await this._getFileHandler(e,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let t;for(;(t=await n.read())&&!t.done;)yield t.value}finally{n.cancel&&n.cancel()}}async _getHandler(t,e=!1){let i;try{i=await this._getFileHandler(t,e)}catch(n){try{i=await this._getDirectoryHandler(t,e)}catch(t){}}return i}async _getDirectoryHandler(t,e=!0){t=[...t];let i=this.rootHandler;for(let n of t)i=await i.getDirectoryHandle(n,{create:e});return i}async _getFileHandler(t,e=!0){const i=(t=[...t]).pop();let n=this.rootHandler;for(let e of t)n=await n.getDirectoryHandle(e,{create:!0});return await n.getFileHandle(i,{create:e})}async _getFileInfo(t,e){const i=(t=[...t])[t.length-1];t.unshift("");const n=t.join("/"),s={kind:"",path:n,name:i};if("directory"===e.kind)s.kind="directory";else{s.kind="file";const t=await e.getFile();s.size=t.size,s.type=r(n),s.lastModified=t.lastModified}return s}_getPathSegments(t){return("object"==typeof t?t.path:t+"").split("/").filter((t=>!!t))}}function x({filesApi:t,log:e=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=t[n].bind(t);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return e(o),o.result=s.call(t,...i)}catch(t){o.error=t}finally{o.stage="exit",e(o)}},i}),i)}async function w({handlerKey:t="root-dir",readwrite:e=!0,index:i={},get:n=(async t=>i[t]),set:s=(async(t,e)=>i[t]=e),del:o=(async t=>delete i[t])}={}){let a=await n(t);if(a||(a=await window.showDirectoryPicker(),await s(t,a)),!await async function(t,e){const i={};e&&(i.mode="readwrite");let n=!1;"granted"===await t.queryPermission(i)&&(n=!0);n||"granted"!==await t.requestPermission(i)||(n=!0);return n}(a,e))throw new Error("Access was not granted");if(!await async function(t){let e=!1;try{if("file"===t.kind)await t.getFile();else for await(let e of t.values())break;e=!0}catch(i){console.log(i,t),e=!1}return e}(a))throw await o(t),new Error("Can not access to the folder. Please try again.");return new u({rootHandler:a})}export{u as BrowserFilesApi,i as FilesApi,c as MemFilesApi,p as NodeFilesApi,x as addFilesApiLogger,o as extensionToMimeType,r as getMimeType,a as mimeTypeToExtensions,n as mimeTypes,s as mimeTypesDescriptions,t as normalizePath,w as openBrowserFilesApi};
1
+ // @statewalker/webrun-files v0.2.0 https://github.com/statewalker/webrun-files Copyright 2023 Mikhail Kotelnikov
2
+ function t(t){const e=t.split("/").filter((t=>!!t&&"."!==t));return 0===e.length&&e.push(""),e.unshift(""),e.join("/")}function e(){throw new Error("Not implemented.")}class i{constructor(t){this.options=t||{}}async*list(t,i={}){yield e()}async stats(t){return e()}async remove(t){return e()}async write(t,i){return e()}async*read(t,i){yield e()}async copy(t,e,i={}){const n=async(t,e,i)=>{e=`${e}${i.path.substring(t.length)}`;const n=this.read(i);return await this.write(e,n)},s=void 0===i.recursive||!!i.recursive,o=await this.stats(t);if("directory"===o.kind)for await(const o of this.list(t,{...i,recursive:s}))"directory"!==o.kind&&await n(t,e,o);else await n(t,e,o);return!0}async move(t,e,i={}){return!!await this.copy(t,e,i)&&(await this.remove(t),!0)}normalizePath(e){return t("object"==typeof e?e.path:e+"")}}const n=[{extensions:["aac"],mime:"audio/aac",description:"AAC audio"},{extensions:["abw"],mime:"application/x-abiword",description:"AbiWord document"},{extensions:["arc"],mime:"application/x-freearc",description:"Archive document (multiple files embedded)"},{extensions:["avi"],mime:"video/x-msvideo",description:"AVI: Audio Video Interleave"},{extensions:["azw"],mime:"application/vnd.amazon.ebook",description:"Amazon Kindle eBook format"},{extensions:["bin"],mime:"application/octet-stream",description:"Any kind of binary data"},{extensions:["bmp"],mime:"image/bmp",description:"Windows OS/2 Bitmap Graphics"},{extensions:["bz"],mime:"application/x-bzip",description:"BZip archive"},{extensions:["bz2"],mime:"application/x-bzip2",description:"BZip2 archive"},{extensions:["csh"],mime:"application/x-csh",description:"C-Shell script"},{extensions:["css"],mime:"text/css",description:"Cascading Style Sheets (CSS)"},{extensions:["csv"],mime:"text/csv",description:"Comma-separated values (CSV)"},{extensions:["doc"],mime:"application/msword",description:"Microsoft Word"},{extensions:["docx"],mime:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",description:"Microsoft Word (OpenXML)"},{extensions:["eot"],mime:"application/vnd.ms-fontobject",description:"MS Embedded OpenType fonts"},{extensions:["epub"],mime:"application/epub+zip",description:"Electronic publication (EPUB)"},{extensions:["gz"],mime:"application/gzip",description:"GZip Compressed Archive"},{extensions:["gif"],mime:"image/gif",description:"Graphics Interchange Format (GIF)"},{extensions:["htm","html"],mime:"text/html",description:"HyperText Markup Language (HTML)"},{extensions:["ico"],mime:"image/vnd.microsoft.icon",description:"Icon format"},{extensions:["ics"],mime:"text/calendar",description:"iCalendar format"},{extensions:["jar"],mime:"application/java-archive",description:"Java Archive (JAR)"},{extensions:["jpg","jpeg"],mime:"image/jpeg",description:"JPEG images"},{extensions:["js"],mime:"text/javascript",description:"JavaScript per the following specifications: https://html.spec.whatwg.org/multipage/#scriptingLanguages, https://html.spec.whatwg.org/multipage/#dependencies:willful-violation, https://datatracker.ietf.org/doc/draft-ietf-dispatch-javascript-mjs/"},{extensions:["json"],mime:"application/json",description:"JSON format"},{extensions:["jsonld"],mime:"application/ld+json",description:"JSON-LD format"},{extensions:["mid","midi"],mime:"application/ld+json",description:"Musical Instrument Digital Interface (MIDI)\taudio/midi audio/x-midi"},{extensions:["mjs"],mime:"text/javascript",description:"JavaScript module"},{extensions:["mp3"],mime:"audio/mpeg",description:"MP3 audio"},{extensions:["md"],mime:"text/markdown",description:"Markdown"},{extensions:["mpeg"],mime:"video/mpeg",description:"MPEG Video"},{extensions:["mpkg"],mime:"application/vnd.apple.installer+xml",description:"Apple Installer Package"},{extensions:["odp"],mime:"application/vnd.oasis.opendocument.presentation",description:"OpenDocument presentation document"},{extensions:["ods"],mime:"application/vnd.oasis.opendocument.spreadsheet",description:"OpenDocument spreadsheet document"},{extensions:["odt"],mime:"application/vnd.oasis.opendocument.text",description:"OpenDocument text document"},{extensions:["oga"],mime:"audio/ogg",description:"OGG audio"},{extensions:["ogv"],mime:"video/ogg",description:"OGG video"},{extensions:["ogx"],mime:"application/ogg",description:"OGG"},{extensions:["opus"],mime:"audio/opus",description:"Opus audio"},{extensions:["otf"],mime:"font/otf",description:"OpenType font"},{extensions:["png"],mime:"image/png",description:"Portable Network Graphics"},{extensions:["pdf"],mime:"application/pdf",description:"Adobe Portable Document Format (PDF)"},{extensions:["php"],mime:"application/x-httpd-php",description:"Hypertext Preprocessor (Personal Home Page)"},{extensions:["ppt"],mime:"application/vnd.ms-powerpoint",description:"Microsoft PowerPoint"},{extensions:["pptx"],mime:"application/vnd.openxmlformats-officedocument.presentationml.presentation",description:"Microsoft PowerPoint (OpenXML)"},{extensions:["rar"],mime:"application/vnd.rar",description:"RAR archive"},{extensions:["rtf"],mime:"application/rtf",description:"Rich Text Format (RTF)"},{extensions:["sh"],mime:"application/x-sh",description:"Bourne shell script"},{extensions:["svg"],mime:"image/svg+xml",description:"Scalable Vector Graphics (SVG)"},{extensions:["swf"],mime:"application/x-shockwave-flash",description:"Small web format (SWF) or Adobe Flash document"},{extensions:["tar"],mime:"application/x-tar",description:"Tape Archive (TAR)"},{extensions:["tif","tiff"],mime:"image/tiff",description:"Tagged Image File Format (TIFF)"},{extensions:["ttf"],mime:"font/ttf",description:"TrueType Font"},{extensions:["txt"],mime:"text/plain",description:"Text, (generally ASCII or ISO 8859-n)"},{extensions:["vsd"],mime:"application/vnd.visio",description:"Microsoft Visio"},{extensions:["wav"],mime:"audio/wav",description:"Waveform Audio Format"},{extensions:["weba"],mime:"audio/webm",description:"WEBM audio"},{extensions:["webm"],mime:"video/webm",description:"WEBM video"},{extensions:["webp"],mime:"image/webp",description:"WEBP image"},{extensions:["woff"],mime:"font/woff",description:"Web Open Font Format (WOFF)"},{extensions:["woff2"],mime:"font/woff2",description:"Web Open Font Format (WOFF)"},{extensions:["xhtml"],mime:"application/xhtml+xml",description:"XHTML"},{extensions:["xls"],mime:"application/vnd.ms-excel",description:"Microsoft Excel"},{extensions:["xlsx"],mime:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",description:"Microsoft Excel (OpenXML)"},{extensions:["xml"],mime:"application/xml",description:"XML; application/xml - if not readable from casual users (RFC 3023, section 3); text/xml - if readable from casual users (RFC 3023, section 3)"},{extensions:["xul"],mime:"application/vnd.mozilla.xul+xml",description:"XUL"},{extensions:["zip"],mime:"application/zip",description:"ZIP archive"},{extensions:["3gp"],mime:"video/3gpp",description:"3GPP audio/video container"},{extensions:["3g2"],mime:"video/3gpp2",description:"3GPP2 audio/video container; audio/3gpp if it doesn't contain video; audio/3gpp2 if it doesn't contain video"},{extensions:["7z"],mime:"application/x-7z-compressed",description:"7-zip archive"},{extensions:["jsx"],mime:"text/jsx",description:"JavaScript Syntax Extension / JavaScript XML format"},{extensions:["ts"],mime:"text/ts",description:"TypeScript format"},{extensions:["tsx"],mime:"text/tsx",description:"TypeScript Syntax Extension / TypeScript XML format"}],s=n.reduce(((t,e)=>(t[e.mime]=e.description,t)),{}),o=n.reduce(((t,e)=>{for(const i of e.extensions)t[i]=e.mime;return t}),{}),a=n.reduce(((t,e)=>(t[e.mime]=e.extensions,t)),{});function r(t){const e=t=t||"",i=(t=(t=t.split("?").shift()).split("/").pop()).split(".").pop();let n=o[i];return n||(n=e.match(/api\.observablehq\.com/)||e.match(/\.ojs$/)?"application/javascript-observable":"application/binary"),n}class c extends i{constructor(t){super(t),this.index={"/":{kind:"directory",path:"/",name:""}}}async*list(t,{recursive:e=!1}={}){await this._init();const i=this.normalizePath(t),n=this._getPaths();for(const t of n){if(0!==t.indexOf(i)||t===i)continue;const n=t.substring(i.length+1).split("/");(e||1===n.length)&&(yield this._getFileInfo(t))}}async stats(t){await this._init();const e=this.normalizePath(t);return this._getFileInfo(e)}async remove(t){await this._init();const e=await this.stats(t);if(!e)return!1;for await(const{path:t}of this.list(e,{recursive:!0}))"/"!==t&&delete this.index[t];delete this.index[e.path]}async write(t,e){await this._init(),await this._doWrite(t,e)}async*read(t){await this._init();const e=this.normalizePath(t),i=this.index[e];if(!i||"file"!==i.kind)return;const n=i.content;yield*n}async _init(){return this._initPromise=this._initPromise||Promise.resolve().then((()=>this._addEntries(this.options.files)))}async _doWrite(t,e){const i=this.normalizePath(t).split("/").filter((t=>!!t)),n=[""];let s;for(let t=0;t<i.length;t++){const e=i[t];n.push(e);const o=n.join("/");s=this.index[o]=this.index[o]||{path:o,name:e,kind:"directory"}}s.kind="file",s.content=[],s.type=r(s.path),s.size=0,s.lastModified=Date.now(),"function"==typeof e&&(e=e());for await(let t of e)t=new Uint8Array(t),s.content.push(t),s.size+=t.length}async _addEntries(t={}){for(let[e,i]of Object.entries(t))"string"==typeof i?i=[(new TextEncoder).encode(i)]:i instanceof Uint8Array&&(i=[i]),await this._doWrite(e,i)}_getPaths(){return this._getIndexPaths(this.index)}_getIndexPaths(t){return Object.keys(t).sort((function(t,e){return t>e?1:t<e?-1:0}))}_getFileInfo(t){const e=this.index[t];if(!e)return null;const i={...e};return delete i.content,i}}class p extends i{constructor(t){if(super(t),!this.fs)throw new Error("File System is not defined.");if(!this.rootDir)throw new Error("Root directory is not defined.")}get rootDirSegments(){return this._rootDirSegments||(this._rootDirSegments=this._toPathSegments(this.options.rootDir||"./")),this._rootDirSegments}get rootDir(){return this._rootDir||(this._rootDir=this.rootDirSegments.join("/")),this._rootDir}get fs(){return this.options.fs}async _init(){return this._initialized=this._initialized||(async()=>{const t=this.rootDir;return await l(this.fs,t)})()}async*list(t,{recursive:e=!1}={}){await this._init();const i=this._expandPath(t),n=await this._stats(i);if(n&&"directory"===n.kind)for await(let t of f(this.fs,i,e))yield this._getFileInfo(t.path,t.stat)}async stats(t){await this._init();const e=this._expandPath(t);return this._stats(e)}async remove(t){await this._init();const e=this._expandPath(t);return await h(this.fs,e)}async write(t,e){await this._init();const i=this._expandPath(t),n=d(i);let s;await this.fs.mkdir(n,{recursive:!0});try{s=await this.fs.open(i,"w"),"function"==typeof e&&(e=e()),await s.writeFile(e)}finally{s&&await s.close()}}async*read(t,{start:e=0,bufferSize:i=8192}={}){await this._init();const n=this._expandPath(t);let s;try{s=await this.fs.open(n,"r");const t=0;for(let n=e,o=0;;n+=o){const e=new Uint8ClampedArray(i),a=await s.read(e,t,i,n);if(o=a.bytesRead,0===o)break;yield o<i?a.buffer.slice(0,o):a.buffer}}finally{s&&await s.close()}}async _stats(t){try{const e=await this.fs.stat(t);return this._getFileInfo(t,e)}catch(t){if("ENOENT"!==t.code)throw t;return null}}_getFileInfo(t,e){const i=this._toPathSegments(t).slice(this.rootDirSegments.length);i.unshift("");const n=i[i.length-1];let s={path:t=i.join("/"),name:n,kind:""};return e.isFile()?(s.size=e.size||0,s.type=r(t),s.kind="file",s.lastModified=new Date(e.mtime).getTime()):s.kind="directory",s}_toPathSegments(t){return(t=this.normalizePath(t)).split("/")}_expandPath(t){const e="object"==typeof t?t.path:t+"",i=this._toPathSegments(e).filter((t=>!!t));return i.unshift(...this.rootDirSegments),i.join("/")}}function d(t){const e=t.split("/");return e.pop(),e.join("/")}function m(...t){let e=t.map((t=>t.split("/"))).reduce(((t,e)=>(t.push(...e),t)),[]);const i=e.shift();return e=e.filter((t=>!!t&&"."!==t)),e.unshift(i),e.join("/")}async function l(t,e){try{const i=await t.stat(e);if(i&&i.isDirectory())return!0}catch(t){}const i=d(e);return e!==i&&(await l(t,i),await t.mkdir(e,{recursive:!0}),!0)}async function h(t,e){try{if((await t.stat(e)).isDirectory()){for await(let i of f(t,e,!1))await h(t,i.path);await t.rmdir(e)}else await t.unlink(e)}catch(t){if("ENOENT"!==t.code)throw t}}async function*f(t,e,i){try{if((await t.stat(e)).isDirectory()){const n=await t.readdir(e);for(const s of n.sort()){const n=m(e,s);let o=await t.stat(n);yield{path:n,stat:o},i&&o.isDirectory()&&(yield*f(t,n,!0))}}}catch(t){if("ENOENT"!==t.code)throw t}}class u extends i{constructor(t){if(super(t),!this.rootHandler)throw new Error("Root directory handler is not defined")}get rootHandler(){return this.options.rootHandler}async*list(t,{recursive:e=!1}={}){const i=this._getPathSegments(t),n=await this._getHandler(i,!1),s=this;"directory"===n.kind&&(yield*async function*t(e,i,n){for await(const o of i.values())yield await s._getFileInfo([...e,o.name],o),n&&"directory"==o.kind&&(yield*t([...e,o.name],o,n))}(i,n,e))}async stats(t){const e=this._getPathSegments(t),i=await this._getHandler(e,!1);return i?await this._getFileInfo(e,i):null}async remove(t){let e=this._getPathSegments(t);const i=e.pop(),n=await this._getHandler(e,!1),s=[];if(i)s.push(i);else for await(const t of n.values())s.push(t.name);for(const t of s)await n.removeEntry(t,{recursive:!0});return!0}async write(t,e){const i=this._getPathSegments(t),n=await this._getFileHandler(i),s=await n.createWritable();try{"function"==typeof e&&(e=e());for await(let t of e)await s.write(t.buffer?t.buffer:t)}finally{await s.close()}}async*read(t){const e=this._getPathSegments(t),i=await this._getFileHandler(e,!1);if(!i)return;const n=(await i.getFile()).stream().getReader();try{let t;for(;(t=await n.read())&&!t.done;)yield t.value}finally{n.cancel&&n.cancel()}}async _getHandler(t,e=!1){let i;try{i=await this._getFileHandler(t,e)}catch(n){try{i=await this._getDirectoryHandler(t,e)}catch(t){}}return i}async _getDirectoryHandler(t,e=!0){t=[...t];let i=this.rootHandler;for(let n of t)i=await i.getDirectoryHandle(n,{create:e});return i}async _getFileHandler(t,e=!0){const i=(t=[...t]).pop();let n=this.rootHandler;for(let e of t)n=await n.getDirectoryHandle(e,{create:!0});return await n.getFileHandle(i,{create:e})}async _getFileInfo(t,e){const i=(t=[...t])[t.length-1];t.unshift("");const n=t.join("/"),s={kind:"",path:n,name:i};if("directory"===e.kind)s.kind="directory";else{s.kind="file";const t=await e.getFile();s.size=t.size,s.type=r(n),s.lastModified=t.lastModified}return s}_getPathSegments(t){return("object"==typeof t?t.path:t+"").split("/").filter((t=>!!t))}}function x({filesApi:t,log:e=console.log,wrapper:i={}}){return["list","stats","remove","write","read","copy","move"].reduce(((i,n)=>{const s=t[n].bind(t);return i[n]=(...i)=>{let o={method:n,stage:"enter",args:i};try{return e(o),o.result=s.call(t,...i)}catch(t){o.error=t}finally{o.stage="exit",e(o)}},i}),i)}async function w({handlerKey:t="root-dir",readwrite:e=!0,index:i={},get:n=(async t=>i[t]),set:s=(async(t,e)=>i[t]=e),del:o=(async t=>delete i[t])}={}){let a=await n(t);if(a||(a=await window.showDirectoryPicker(),await s(t,a)),!await y(a,e))throw new Error("Access was not granted");if(!await g(a))throw await o(t),new Error("Can not access to the folder. Please try again.");return new u({rootHandler:a})}async function g(t){let e=!1;try{if("file"===t.kind)await t.getFile();else for await(let e of t.values())break;e=!0}catch(i){console.log(i,t),e=!1}return e}async function y(t,e){const i={};e&&(i.mode="readwrite");let n=!1;return"granted"===await t.queryPermission(i)&&(n=!0),n||"granted"!==await t.requestPermission(i)||(n=!0),n}export{u as BrowserFilesApi,i as FilesApi,c as MemFilesApi,p as NodeFilesApi,x as addFilesApiLogger,o as extensionToMimeType,r as getMimeType,g as isHandlerAccessible,a as mimeTypeToExtensions,n as mimeTypes,s as mimeTypesDescriptions,t as normalizePath,w as openBrowserFilesApi,y as verifyPermission};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statewalker/webrun-files",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Basic files API",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/statewalker/webrun-files",
package/src/index.js CHANGED
@@ -7,4 +7,4 @@ export { default as addFilesApiLogger } from "./addFilesApiLogger.js";
7
7
 
8
8
  export { default as getMimeType } from "./getMimeType.js";
9
9
  export * from "./mimeTypes.js";
10
- export { default as openBrowserFilesApi } from "./openBrowserFilesApi.js";
10
+ export * from "./openBrowserFilesApi.js";
@@ -1,6 +1,6 @@
1
1
  import BrowserFilesApi from "./BrowserFilesApi.js";
2
2
 
3
- export default async function openBrowserFilesApi({
3
+ export async function openBrowserFilesApi({
4
4
  handlerKey = "root-dir",
5
5
  readwrite = true,
6
6
  // Methods below could be replaced by persistent implementation
@@ -24,44 +24,44 @@ export default async function openBrowserFilesApi({
24
24
  throw new Error("Can not access to the folder. Please try again.");
25
25
  }
26
26
  return new BrowserFilesApi({ rootHandler });
27
+ }
27
28
 
28
- async function isHandlerAccessible(fileHandle) {
29
- // We need to perform a real read operation with the handler
30
- // to check if the file/directory still exists.
31
- let exists = false;
32
- try {
33
- if (fileHandle.kind === "file") {
34
- await fileHandle.getFile();
35
- } else {
36
- for await (let item of fileHandle.values()) {
37
- break;
38
- }
29
+ export async function isHandlerAccessible(fileHandle) {
30
+ // We need to perform a real read operation with the handler
31
+ // to check if the file/directory still exists.
32
+ let exists = false;
33
+ try {
34
+ if (fileHandle.kind === "file") {
35
+ await fileHandle.getFile();
36
+ } else {
37
+ for await (let item of fileHandle.values()) {
38
+ break;
39
39
  }
40
- exists = true;
41
- } catch (error) {
42
- console.log(error, fileHandle);
43
- exists = false;
44
40
  }
45
- return exists;
41
+ exists = true;
42
+ } catch (error) {
43
+ console.log(error, fileHandle);
44
+ exists = false;
46
45
  }
46
+ return exists;
47
+ }
47
48
 
48
- async function verifyPermission(fileHandle, readWrite) {
49
- const options = {};
50
- if (readWrite) {
51
- options.mode = "readwrite";
52
- }
53
- let granted = false;
54
- // Check if permission was already granted. If so, return true.
55
- if ((await fileHandle.queryPermission(options)) === "granted") {
56
- granted = true;
57
- }
58
- // Request permission. If the user grants permission, return true.
59
- if (
60
- !granted && (await fileHandle.requestPermission(options)) === "granted"
61
- ) {
62
- granted = true;
63
- }
64
- // The user didn't grant permission, so return false.
65
- return granted;
49
+ export async function verifyPermission(fileHandle, readWrite) {
50
+ const options = {};
51
+ if (readWrite) {
52
+ options.mode = "readwrite";
53
+ }
54
+ let granted = false;
55
+ // Check if permission was already granted. If so, return true.
56
+ if ((await fileHandle.queryPermission(options)) === "granted") {
57
+ granted = true;
58
+ }
59
+ // Request permission. If the user grants permission, return true.
60
+ if (
61
+ !granted && (await fileHandle.requestPermission(options)) === "granted"
62
+ ) {
63
+ granted = true;
66
64
  }
65
+ // The user didn't grant permission, so return false.
66
+ return granted;
67
67
  }