UNPKG

one

Version:

One is a React framework for web, iOS, and Android apps.

108 lines (106 loc) • 3.52 kB
const folders = [ "documents", "cache", "applicationSupport", "temporary" ]; const directories = Object.fromEntries(folders.map((name) => [name, `opfs://one/${name}/`])); function parts(uri) { const url = new URL(uri); if (url.protocol !== "opfs:" || url.host !== "one" || url.search || url.hash) { throw new Error("FileSystem: expected an opfs://one/ URI"); } const names = url.pathname.split("/").filter(Boolean).map(decodeURIComponent); if (!folders.includes(names[0]) || names.some((name) => name === "." || name === ".." || /[/\\\0]/.test(name))) { throw new Error("FileSystem: invalid path"); } return names; } async function root() { if (!navigator.storage?.getDirectory) throw new Error("FileSystem: Origin Private File System is unavailable"); const handle = await navigator.storage.getDirectory(); for (const name of folders) await handle.getDirectoryHandle(name, { create: true }); return handle; } async function parent(names, create = false) { let handle = await root(); for (const name of names.slice(0, -1)) handle = await handle.getDirectoryHandle(name, { create }); return handle; } async function entry(names) { const handle = await parent(names); const name = names.at(-1); try { return await handle.getFileHandle(name); } catch (error) { if (error.name !== "TypeMismatchError") throw error; return handle.getDirectoryHandle(name); } } async function info(uri) { const names = parts(uri); try { const handle = await entry(names); if (handle.kind === "directory") return { uri, exists: true, isDirectory: true }; const file = await handle.getFile(); return { uri, exists: true, isDirectory: false, size: file.size, modifiedAt: file.lastModified }; } catch (error) { if (error.name !== "NotFoundError") throw error; return { uri, exists: false, isDirectory: false }; } } async function write(handle, data) { const writable = await handle.createWritable(); try { await writable.write(data); await writable.close(); } catch (error) { await writable.abort().catch(() => {}); throw error; } } async function copyEntry(source, target, name) { if (source.kind === "file") { await write(await target.getFileHandle(name, { create: true }), await source.getFile()); } else { const directory = await target.getDirectoryHandle(name, { create: true }); for await (const [childName, child] of source.entries()) await copyEntry(child, directory, childName); } } async function transfer(fromUri, toUri, move) { const from = parts(fromUri), to = parts(toUri); if (move && from.length === 1) throw new Error("FileSystem: app root directories are protected"); if (to.length <= from.length && to.every((name, i) => name === from[i]) || from.every((name, i) => name === to[i])) throw new Error("FileSystem: overlapping paths"); const source = await entry(from); if ((await info(toUri)).exists) throw new Error("FileSystem: destination already exists"); const destination = await parent(to); try { await copyEntry(source, destination, to.at(-1)); } catch (error) { await destination.removeEntry(to.at(-1), { recursive: true }).catch(() => {}); throw error; } if (move) await (await parent(from)).removeEntry(from.at(-1), { recursive: true }); } let tail = Promise.resolve(); function serial(work) { const next = tail.then(work); tail = next.catch(() => {}); return next; } export { directories, entry, folders, info, parent, parts, root, serial, transfer, write }; //# sourceMappingURL=opfs.mjs.map