UNPKG

opfs-tools

Version:

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

1 lines 32.2 kB
{"version":3,"file":"opfs-tools.umd.cjs","sources":["../src/access-worker.ts","../src/common.ts","../src/directory.ts","../src/file.ts","../src/tmpfile.ts","../src/rollfile.ts"],"sourcesContent":["import { FileSystemSyncAccessHandle } from './common';\nimport OPFSWorker from './opfs-worker?worker&inline';\n\nexport type OPFSWorkerAccessHandle = {\n read: (offset: number, size: number) => Promise<ArrayBuffer>;\n write: FileSystemSyncAccessHandle['write'];\n close: FileSystemSyncAccessHandle['close'];\n truncate: FileSystemSyncAccessHandle['truncate'];\n getSize: FileSystemSyncAccessHandle['getSize'];\n flush: FileSystemSyncAccessHandle['flush'];\n};\n\nexport async function createOPFSAccess(\n filePath: string\n): Promise<OPFSWorkerAccessHandle> {\n const postMsg = getWorkerMsger();\n await postMsg('register', { filePath });\n return {\n read: async (offset, size) =>\n (await postMsg('read', {\n filePath,\n offset,\n size,\n })) as ArrayBuffer,\n write: async (data, opts) =>\n (await postMsg(\n 'write',\n {\n filePath,\n data,\n opts,\n },\n [ArrayBuffer.isView(data) ? data.buffer : data]\n )) as number,\n close: async () =>\n (await postMsg('close', {\n filePath,\n })) as void,\n truncate: async (newSize: number) =>\n (await postMsg('truncate', {\n filePath,\n newSize,\n })) as void,\n getSize: async () =>\n (await postMsg('getSize', {\n filePath,\n })) as number,\n flush: async () =>\n (await postMsg('flush', {\n filePath,\n })) as void,\n };\n}\n\nconst msgerCache: Array<Function> = [];\nlet nextMsgerIdx = 0;\nfunction getWorkerMsger() {\n // Create a maximum of three workers\n if (msgerCache.length < 3) {\n const msger = create();\n msgerCache.push(msger);\n return msger;\n } else {\n const msger = msgerCache[nextMsgerIdx];\n nextMsgerIdx = (nextMsgerIdx + 1) % msgerCache.length;\n return msger;\n }\n\n function create() {\n const worker = new OPFSWorker();\n\n let cbId = 0;\n let cbFns: Record<number, { resolve: Function; reject: Function }> = {};\n\n worker.onmessage = ({\n data,\n }: {\n data: {\n cbId: number;\n returnVal?: unknown;\n evtType: string;\n errMsg: string;\n };\n }) => {\n if (data.evtType === 'callback') {\n cbFns[data.cbId]?.resolve(data.returnVal);\n } else if (data.evtType === 'throwError') {\n cbFns[data.cbId]?.reject(Error(data.errMsg));\n }\n delete cbFns[data.cbId];\n };\n\n return async function postMsg(\n evtType: string,\n args: unknown,\n trans: Transferable[] = []\n ) {\n cbId += 1;\n\n const rsP = new Promise((resolve, reject) => {\n cbFns[cbId] = { resolve, reject };\n });\n worker.postMessage(\n {\n cbId,\n evtType,\n args,\n },\n trans\n );\n\n return rsP;\n };\n }\n}\n","export interface FileSystemSyncAccessHandle {\n read: (container: ArrayBuffer, opts: { at: number }) => Promise<number>;\n write: (\n data: ArrayBuffer | ArrayBufferView,\n opts?: { at: number }\n ) => Promise<number>;\n flush: () => Promise<void>;\n close: () => Promise<void>;\n truncate: (newSize: number) => Promise<void>;\n getSize: () => Promise<number>;\n}\n\nexport function parsePath(path: string) {\n if (path === '/') return { parent: null, name: '' };\n\n const pathArr = path.split('/').filter((s) => s.length > 0);\n if (pathArr.length === 0) throw Error('Invalid path');\n\n const name = pathArr[pathArr.length - 1];\n\n const parent = '/' + pathArr.slice(0, -1).join('/');\n\n return { name, parent };\n}\n\nexport async function getFSHandle<\n ISFile extends boolean,\n ISCreate extends boolean,\n T = ISFile extends true ? FileSystemFileHandle : FileSystemDirectoryHandle,\n RT = ISCreate extends true ? T : T | null\n>(\n path: string,\n opts: {\n create?: ISCreate;\n isFile?: ISFile;\n }\n): Promise<RT> {\n const { parent, name } = parsePath(path);\n\n if (parent == null) return (await navigator.storage.getDirectory()) as RT;\n\n const dirPaths = parent.split('/').filter((s) => s.length > 0);\n\n try {\n let dirHandle = await navigator.storage.getDirectory();\n for (const p of dirPaths) {\n dirHandle = await dirHandle.getDirectoryHandle(p, {\n create: opts.create,\n });\n }\n if (opts.isFile) {\n return (await dirHandle.getFileHandle(name, {\n create: opts.create,\n })) as RT;\n } else {\n return (await dirHandle.getDirectoryHandle(name, {\n create: opts.create,\n })) as RT;\n }\n } catch (err) {\n if ((err as Error).name === 'NotFoundError') {\n return null as RT;\n }\n throw err;\n }\n}\n\nexport async function remove(path: string) {\n const { parent, name } = parsePath(path);\n if (parent == null) {\n const root = await navigator.storage.getDirectory();\n for await (const it of root.keys()) {\n await root.removeEntry(it, { recursive: true });\n }\n return;\n }\n\n const dirHandle = (await getFSHandle(parent, {\n create: false,\n isFile: false,\n })) as FileSystemDirectoryHandle | null;\n if (dirHandle == null) return;\n\n await dirHandle.removeEntry(name, { recursive: true });\n}\n\nexport function joinPath(p1: string, p2: string) {\n return `${p1}/${p2}`.replace('//', '/');\n}\n","import { getFSHandle, joinPath, parsePath, remove } from './common';\nimport { file, OPFSFileWrap } from './file';\n\ndeclare global {\n interface FileSystemDirectoryHandle {\n keys: () => AsyncIterable<string>;\n values: () => AsyncIterable<\n FileSystemDirectoryHandle | FileSystemFileHandle\n >;\n }\n}\n\n/**\n * Represents a directory with utility functions.\n * @param {string} dirPath - The path of the directory.\n * @returns An object with directory utility functions.\n * \n * @example\n // Create a directory\n await dir('/path/to/directory').create();\n\n // Check if the directory exists\n const exists = await dir('/path/to/directory').exists();\n\n // Remove the directory\n\n // Retrieve children of the directory\n const children = await dir('/path/to/parent_directory').children();\n */\nexport function dir(dirPath: string) {\n return new OPFSDirWrap(dirPath);\n}\n\nexport class OPFSDirWrap {\n get kind(): 'dir' {\n return 'dir';\n }\n\n get name() {\n return this.#name;\n }\n\n get path() {\n return this.#path;\n }\n\n get parent(): OPFSDirWrap | null {\n return this.#parentPath == null ? null : dir(this.#parentPath);\n }\n\n #path: string;\n #name: string;\n #parentPath: string | null;\n\n constructor(dirPath: string) {\n this.#path = dirPath;\n const { parent, name } = parsePath(dirPath);\n this.#name = name;\n this.#parentPath = parent;\n }\n\n /**\n * Creates the directory.\n * return A promise that resolves when the directory is created.\n */\n async create() {\n await getFSHandle(this.#path, {\n create: true,\n isFile: false,\n });\n return dir(this.#path);\n }\n\n /**\n * Checks if the directory exists.\n * return A promise that resolves to true if the directory exists, otherwise false.\n */\n async exists() {\n return (\n (await getFSHandle(this.#path, {\n create: false,\n isFile: false,\n })) instanceof FileSystemDirectoryHandle\n );\n }\n\n /**\n * Removes the directory.\n * return A promise that resolves when the directory is removed.\n */\n async remove() {\n for (const it of await this.children()) {\n try {\n await it.remove();\n } catch (err) {\n console.warn(err);\n }\n }\n try {\n await remove(this.#path);\n } catch (err) {\n console.warn(err);\n }\n }\n\n /**\n * Retrieves the children of the directory.\n * return A promise that resolves to an array of objects representing the children.\n */\n async children(): Promise<Array<OPFSDirWrap | OPFSFileWrap>> {\n const handle = (await getFSHandle(this.#path, {\n create: false,\n isFile: false,\n })) as FileSystemDirectoryHandle;\n if (handle == null) return [];\n\n const rs = [];\n for await (const it of handle.values()) {\n rs.push((it.kind === 'file' ? file : dir)(joinPath(this.#path, it.name)));\n }\n return rs;\n }\n\n /**\n * If the dest folder exists, copy the current directory into the dest folder;\n * if the dest folder does not exist, rename the current directory to dest name.\n */\n async copyTo(dest: OPFSDirWrap) {\n if (!(await this.exists())) {\n throw Error(`dir ${this.path} not exists`);\n }\n const newDir = (await dest.exists())\n ? dir(joinPath(dest.path, this.name))\n : dest;\n await newDir.create();\n await Promise.all((await this.children()).map((it) => it.copyTo(newDir)));\n\n return newDir;\n }\n\n /**\n * move directory, copy then remove current\n */\n async moveTo(dest: OPFSDirWrap): Promise<OPFSDirWrap> {\n const newDir = await this.copyTo(dest);\n await this.remove();\n\n return newDir;\n }\n}\n","import { OPFSWorkerAccessHandle, createOPFSAccess } from './access-worker';\nimport { getFSHandle, joinPath, parsePath, remove } from './common';\nimport { OPFSDirWrap, dir } from './directory';\n\nconst fileCache = new Map<string, OPFSFileWrap>();\n/**\n * Retrieves a file wrapper instance for the specified file path.\n * @param {string} filePath - The path of the file.\n * return A file wrapper instance.\n * \n * @example\n * // Read content from a file\n const fileContent = await file('/path/to/file.txt').text();\n console.log('File content:', fileContent);\n\n // Check if a file exists\n const fileExists = await file('/path/to/file.txt').exists();\n console.log('File exists:', fileExists);\n\n // Remove a file\n await file('/path/to/file.txt').remove();\n */\nexport function file(filePath: string) {\n const f = fileCache.get(filePath) ?? new OPFSFileWrap(filePath);\n fileCache.set(filePath, f);\n return f;\n}\n\n/**\n * Writes content to the specified file.\n * @param {string} target - The path of the file.\n * @param {string | BufferSource | ReadableStream<BufferSource>} content - The content to write to the file.\n * return A promise that resolves when the content is written to the file.\n * \n * @example\n * // Write content to a file\n await write('/path/to/file.txt', 'Hello, world!');\n */\nexport async function write(\n target: string | OPFSFileWrap,\n content: string | BufferSource | ReadableStream<BufferSource> | OPFSFileWrap,\n opts = { overwrite: true }\n) {\n if (content instanceof OPFSFileWrap) {\n await write(target, await content.stream(), opts);\n return;\n }\n\n const writer = await (target instanceof OPFSFileWrap\n ? target\n : file(target)\n ).createWriter();\n try {\n if (opts.overwrite) await writer.truncate(0);\n if (content instanceof ReadableStream) {\n const reader = content.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n await writer.write(value);\n }\n } else {\n await writer.write(content);\n }\n } catch (err) {\n throw err;\n } finally {\n await writer.close();\n }\n}\n\n/**\n * Represents a wrapper for interacting with a file in the filesystem.\n */\nexport class OPFSFileWrap {\n get kind(): 'file' {\n return 'file';\n }\n\n get path() {\n return this.#path;\n }\n\n get name() {\n return this.#name;\n }\n\n get parent(): ReturnType<typeof dir> | null {\n return this.#parentPath == null ? null : dir(this.#parentPath);\n }\n\n #path: string;\n #parentPath: string | null;\n #name: string;\n\n constructor(filePath: string) {\n this.#path = filePath;\n const { parent, name } = parsePath(filePath);\n this.#name = name;\n this.#parentPath = parent;\n }\n\n #referCnt = 0;\n #getAccessHandle = (() => {\n let accPromise: Promise<\n [OPFSWorkerAccessHandle, () => Promise<void>]\n > | null = null;\n\n return () => {\n this.#referCnt += 1;\n if (accPromise != null) return accPromise;\n\n return (accPromise = new Promise(async (resolve, reject) => {\n try {\n const accHandle = await createOPFSAccess(this.#path);\n resolve([\n accHandle,\n async () => {\n this.#referCnt -= 1;\n if (this.#referCnt > 0) return;\n\n accPromise = null;\n await accHandle.close();\n },\n ]);\n } catch (err) {\n reject(err);\n }\n }));\n };\n })();\n\n #writing = false;\n /**\n * Random write to file\n */\n async createWriter() {\n if (this.#writing) throw Error('Other writer have not been closed');\n this.#writing = true;\n\n const txtEC = new TextEncoder();\n\n // append content by default\n const [accHandle, unref] = await this.#getAccessHandle();\n let pos = await accHandle.getSize();\n let closed = false;\n return {\n write: async (\n chunk: string | BufferSource,\n opts: { at?: number } = {}\n ) => {\n if (closed) throw Error('Writer is closed');\n const content = typeof chunk === 'string' ? txtEC.encode(chunk) : chunk;\n const at = opts.at ?? pos;\n const contentSize = content.byteLength;\n pos = at + contentSize;\n return await accHandle.write(content, { at });\n },\n truncate: async (size: number) => {\n if (closed) throw Error('Writer is closed');\n await accHandle.truncate(size);\n if (pos > size) pos = size;\n },\n flush: async () => {\n if (closed) throw Error('Writer is closed');\n await accHandle.flush();\n },\n close: async () => {\n if (closed) throw Error('Writer is closed');\n closed = true;\n this.#writing = false;\n await unref();\n },\n };\n }\n\n /**\n * Random access to file\n */\n async createReader() {\n const [accHandle, unref] = await this.#getAccessHandle();\n\n let closed = false;\n let pos = 0;\n return {\n read: async (size: number, opts: { at?: number } = {}) => {\n if (closed) throw Error('Reader is closed');\n const offset = opts.at ?? pos;\n const buf = await accHandle.read(offset, size);\n pos = offset + buf.byteLength;\n return buf;\n },\n getSize: async () => {\n if (closed) throw Error('Reader is closed');\n return await accHandle.getSize();\n },\n close: async () => {\n if (closed) return;\n closed = true;\n await unref();\n },\n };\n }\n\n async text() {\n return new TextDecoder().decode(await this.arrayBuffer());\n }\n\n async arrayBuffer() {\n const fh = await getFSHandle(this.#path, { create: false, isFile: true });\n if (fh == null) return new ArrayBuffer(0);\n return (await fh.getFile()).arrayBuffer();\n }\n\n async stream() {\n const ofile = await this.getOriginFile();\n if (ofile == null) {\n return new ReadableStream<Uint8Array>({\n pull: (ctrl) => {\n ctrl.close();\n },\n });\n }\n\n return ofile.stream();\n }\n\n async getOriginFile() {\n return (\n await getFSHandle(this.#path, { create: false, isFile: true })\n )?.getFile();\n }\n\n async getSize() {\n const fh = await getFSHandle(this.#path, { create: false, isFile: true });\n if (fh == null) return 0;\n return (await fh.getFile()).size;\n }\n\n async exists() {\n return (\n (await getFSHandle(this.#path, {\n create: false,\n isFile: true,\n })) instanceof FileSystemFileHandle\n );\n }\n\n async remove() {\n if (this.#referCnt) throw Error('exists unclosed reader/writer');\n await remove(this.#path);\n // fileCache.delete(this.#path);\n }\n\n /**\n * If the target is a file, use current overwrite the target;\n * if the target is a folder, copy the current file into that folder.\n */\n async copyTo(target: OPFSDirWrap | OPFSFileWrap): Promise<OPFSFileWrap> {\n if (!(await this.exists())) {\n throw Error(`file ${this.path} not exists`);\n }\n\n if (target instanceof OPFSFileWrap) {\n if (file(target.path) === this) return this;\n\n await write(target.path, this);\n return file(target.path);\n } else if (target instanceof OPFSDirWrap) {\n return await this.copyTo(file(joinPath(target.path, this.name)));\n }\n throw Error('Illegal target type');\n }\n\n /**\n * move file, copy then remove current\n */\n async moveTo(target: OPFSDirWrap | OPFSFileWrap): Promise<OPFSFileWrap> {\n const newFile = await this.copyTo(target);\n await this.remove();\n return newFile;\n }\n}\n","import { OPFSDirWrap, dir } from './directory';\nimport { OPFSFileWrap, file } from './file';\n\nconst TMP_DIR = '/.opfs-tools-temp-dir';\n\nasync function safeRemove(it: OPFSFileWrap | OPFSDirWrap) {\n try {\n if (it.kind === 'file') {\n if (!(await it.exists())) return true;\n\n const writer = await it.createWriter();\n await writer.truncate(0);\n await writer.close();\n await it.remove();\n } else {\n await it.remove();\n }\n return true;\n } catch (e) {\n console.warn(e);\n return false;\n }\n}\n\n// 'export' is for ease of testing\nexport function delByInterval() {\n setInterval(async () => {\n const timeOf3Days = 1000 * 60 * 60 * 24 * 3;\n for (const it of await dir(TMP_DIR).children()) {\n const match = /^\\d+-(\\d+)$/.exec(it.name);\n if (match == null || Date.now() - Number(match[1]) > timeOf3Days) {\n // Delete files that are older than three days and are not in writing\n await safeRemove(it);\n }\n }\n }, 60 * 1000);\n}\n\nconst currentPageTMPFiles: string[] = [];\nlet bindedUnloadEvt = false;\n\n// 'export' is for ease of testing\nexport async function delMarkFiles() {\n if (globalThis.localStorage == null) return;\n\n const opfsToolsExpires = 'OPFS_TOOLS_EXPIRES_TMP_FILES';\n\n if (!bindedUnloadEvt) {\n bindedUnloadEvt = true;\n globalThis.addEventListener('unload', () => {\n if (currentPageTMPFiles.length === 0) return;\n localStorage.setItem(\n opfsToolsExpires,\n `${\n localStorage.getItem(opfsToolsExpires) ?? ''\n },${currentPageTMPFiles.join(',')}`\n );\n });\n }\n\n let markStr = localStorage.getItem(opfsToolsExpires) ?? '';\n for (const name of markStr.split(',')) {\n if (name.length === 0) continue;\n if (await safeRemove(file(`${TMP_DIR}/${name}`))) {\n markStr = markStr.replace(name, '');\n }\n }\n localStorage.setItem(opfsToolsExpires, markStr.replace(/,{2,}/g, ','));\n}\n\ndeclare global {\n module globalThis {\n var __opfs_tools_tmpfile_init__: boolean;\n }\n}\n\n(async function init() {\n if (globalThis.__opfs_tools_tmpfile_init__ === true) return;\n globalThis.__opfs_tools_tmpfile_init__ = true;\n\n // not web context\n if (\n globalThis.FileSystemDirectoryHandle == null ||\n globalThis.FileSystemFileHandle == null ||\n globalThis.navigator?.storage.getDirectory == null\n ) {\n return;\n }\n\n // clear tmpfile\n delByInterval();\n await delMarkFiles();\n})();\n\n/**\n * Create a temporary file that will automatically be cleared to avoid occupying too much storage space.\n * The temporary file name will be automatically generated and stored in a specific directory.\n */\nexport function tmpfile() {\n const name = `${Math.random().toString().slice(2)}-${Date.now()}`;\n currentPageTMPFiles.push(name);\n return file(`${TMP_DIR}/${name}`);\n}\n","import { file } from './file';\n\nexport function rollfile(filePath: string, maxSize: number) {\n let f = file(filePath);\n\n let size = 0;\n let writerPromise: ReturnType<typeof f.createWriter> = f.createWriter();\n let readerPromise = f.createReader();\n\n const reset = async (writer: Awaited<typeof writerPromise>) => {\n const reader = await readerPromise;\n const data = await reader.read(size, { at: Math.round(size * 0.3) });\n size = await writer.write(data, { at: 0 });\n await writer.truncate(size);\n };\n\n return {\n append: async (content: string) => {\n const writer = await writerPromise;\n size += await writer.write(content);\n if (size >= maxSize) await reset(writer);\n },\n text: f.text.bind(f),\n remove: async () => {\n await (await readerPromise).close();\n await (await writerPromise).close();\n await f.remove();\n },\n getSize: async () => size,\n };\n}\n"],"names":["createOPFSAccess","filePath","postMsg","getWorkerMsger","offset","size","data","opts","newSize","msgerCache","nextMsgerIdx","msger","create","worker","OPFSWorker","cbId","cbFns","_a","_b","evtType","args","trans","rsP","resolve","reject","parsePath","path","pathArr","s","name","parent","getFSHandle","dirPaths","dirHandle","p","err","remove","root","it","joinPath","p1","p2","dir","dirPath","OPFSDirWrap","__privateAdd","_path","_name","_parentPath","__privateSet","__privateGet","handle","rs","file","dest","newDir","fileCache","f","OPFSFileWrap","write","target","content","writer","reader","done","value","_OPFSFileWrap","_referCnt","_getAccessHandle","accPromise","accHandle","_writing","txtEC","unref","pos","closed","chunk","at","contentSize","buf","fh","ofile","ctrl","newFile","TMP_DIR","safeRemove","delByInterval","match","currentPageTMPFiles","bindedUnloadEvt","delMarkFiles","opfsToolsExpires","markStr","tmpfile","rollfile","maxSize","writerPromise","readerPromise","reset"],"mappings":"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"}