UNPKG

one

Version:

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

440 lines (439 loc) • 14 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var classes_exports = {}; __export(classes_exports, { Directory: () => Directory, File: () => File, FileHandle: () => FileHandle, FileMode: () => import_types.FileMode, Paths: () => Paths }); module.exports = __toCommonJS(classes_exports); var import_opfs = require("./opfs.cjs"); var import_paths = require("./paths.cjs"); var import_streams = require("./streams.cjs"); var import_types = require("./types.cjs"); var import_validate = require("./validate.cjs"); function unavailable(member) { return new Error(`${member} is not available on web`); } function server() { return typeof window === "undefined"; } function toBytes(content) { if (content instanceof ArrayBuffer) return new Uint8Array(content); if (content.buffer instanceof ArrayBuffer) { return new Uint8Array(content.buffer, content.byteOffset, content.byteLength); } const copy = new Uint8Array(content.byteLength); copy.set(content); return copy; } function toBase64(bytes) { let binary = ""; for (let i = 0; i < bytes.length; i += 32768) { binary += String.fromCharCode(...bytes.subarray(i, i + 32768)); } return btoa(binary); } async function fileEntry(uri) { const handle = await (0, import_opfs.entry)((0, import_opfs.parts)(uri)); if (handle.kind !== "file") throw new Error("FileSystem: expected a file"); return handle; } async function readWholeFile(uri) { return new Uint8Array(await (await (await fileEntry(uri)).getFile()).arrayBuffer()); } async function writePositioned(uri, position, data) { const handle = await fileEntry(uri); const writable = await handle.createWritable({ keepExistingData: true }); try { await writable.write({ type: "write", position, data }); await writable.close(); } catch (error) { await writable.abort().catch(() => {}); throw error; } } var FileHandle = class { targetUri; mode; offsetValue = 0; closed = false; truncatePending; appendPending; constructor(uri, mode = import_types.FileMode.ReadWrite) { (0, import_validate.assertUri)(uri, "FileHandle"); (0, import_validate.assertMode)(mode, "FileHandle"); this.targetUri = uri; this.mode = mode; this.truncatePending = mode === import_types.FileMode.Truncate; this.appendPending = mode === import_types.FileMode.Append; } get offset() { if (this.closed) return null; return this.offsetValue; } set offset(value) { this.assertOpen("offset"); (0, import_validate.assertOffset)(value, "FileHandle.offset"); this.offsetValue = value; this.appendPending = false; } get size() { if (this.closed) return null; throw unavailable("FileHandle.size"); } close() { this.closed = true; } readBytes(length) { this.assertOpen("readBytes"); (0, import_validate.assertReadable)(this.mode, "FileHandle.readBytes"); (0, import_validate.assertByteLength)(length, "FileHandle.readBytes"); if (server()) return Promise.resolve(new Uint8Array()); return (0, import_opfs.serial)(async () => { await this.prepare(); const bytes = await readWholeFile(this.targetUri); const slice = bytes.slice(this.offsetValue, this.offsetValue + length); this.offsetValue += slice.length; return slice; }); } readBytesSync(_length) { throw unavailable("FileHandle.readBytesSync"); } writeBytes(bytes) { this.assertOpen("writeBytes"); (0, import_validate.assertWritable)(this.mode, "FileHandle.writeBytes"); (0, import_validate.assertWriteBytes)(bytes, "FileHandle.writeBytes"); if (server()) return Promise.resolve(); const data = toBytes(bytes); return (0, import_opfs.serial)(async () => { await this.prepare(); let size = 0; try { size = (await (await fileEntry(this.targetUri)).getFile()).size; } catch (error) { if (error.name !== "NotFoundError") throw error; if (this.mode === import_types.FileMode.ReadOnly || this.mode === import_types.FileMode.ReadWrite) throw error; const names = (0, import_opfs.parts)(this.targetUri); await (await (0, import_opfs.parent)(names)).getFileHandle(names.at(-1), { create: true }); } const position = Math.min(this.offsetValue, size); await writePositioned(this.targetUri, position, data); this.offsetValue = position + data.length; }); } writeBytesSync(_bytes) { throw unavailable("FileHandle.writeBytesSync"); } async prepare() { if (this.truncatePending) { this.truncatePending = false; this.offsetValue = 0; const names = (0, import_opfs.parts)(this.targetUri); await (0, import_opfs.write)(await (await (0, import_opfs.parent)(names)).getFileHandle(names.at(-1), { create: true }), ""); } else if (this.appendPending) { this.appendPending = false; try { this.offsetValue = (await (await fileEntry(this.targetUri)).getFile()).size; } catch (error) { if (error.name !== "NotFoundError") throw error; this.offsetValue = 0; } } } assertOpen(verb) { if (this.closed) throw new Error(`FileHandle.${verb}: the handle is closed`); } }; function resolveDestination(source, destination, verb) { (0, import_validate.assertDestination)(destination, verb); if (destination instanceof Directory) { return import_paths.PathUtilities.join(destination.uri, source.name); } if (destination instanceof File) return destination.uri; throw new Error(`${verb}: expected a File or Directory destination`); } async function relocate(source, to, move, overwrite) { if (overwrite && (0, import_opfs.parts)(to).length === 1) { throw new Error("FileSystem: app root directories are protected"); } if (overwrite) { const names = (0, import_opfs.parts)(to); await (await (0, import_opfs.parent)(names)).removeEntry(names.at(-1), { recursive: true }).catch((error) => { if (error.name !== "NotFoundError") throw error; }); } await (0, import_opfs.transfer)(source, to, move); } var File = class { currentUri; constructor(...uris) { const joined = import_paths.PathUtilities.join(...uris); (0, import_validate.assertUri)(joined, "File"); this.currentUri = joined; } get uri() { return this.currentUri; } get name() { return import_paths.PathUtilities.basename(this.currentUri); } get extension() { return import_paths.PathUtilities.extname(this.currentUri); } get parentDirectory() { return new Directory(import_paths.PathUtilities.dirname(this.currentUri)); } get exists() { throw unavailable("File.exists"); } get size() { throw unavailable("File.size"); } get type() { throw unavailable("File.type"); } get creationTime() { throw unavailable("File.creationTime"); } get lastModified() { throw unavailable("File.lastModified"); } text() { if (server()) return Promise.resolve(""); const uri = this.currentUri; return (0, import_opfs.serial)(async () => (await (await fileEntry(uri)).getFile()).text()); } textSync() { throw unavailable("File.textSync"); } bytes() { if (server()) return Promise.resolve(new Uint8Array()); const uri = this.currentUri; return (0, import_opfs.serial)(() => readWholeFile(uri)); } bytesSync() { throw unavailable("File.bytesSync"); } base64() { if (server()) return Promise.resolve(""); return this.bytes().then(toBase64); } base64Sync() { throw unavailable("File.base64Sync"); } async arrayBuffer() { return (await this.bytes()).buffer; } async json() { return JSON.parse(await this.text()); } info() { throw unavailable("File.info"); } digest(algorithm) { (0, import_validate.assertAlgorithm)(algorithm, "File.digest"); if (server()) return Promise.reject(new Error("File.digest is not available on the server")); if (algorithm === "MD5") { return Promise.reject(new Error("File.digest: MD5 is not available on web")); } if (!globalThis.crypto?.subtle) return Promise.reject(unavailable("File.digest")); return this.bytes().then(async (bytes) => { const hash = await globalThis.crypto.subtle.digest(algorithm, bytes); return Array.from(new Uint8Array(hash)).map((byte) => byte.toString(16).padStart(2, "0")).join(""); }); } write(content, options) { (0, import_validate.assertWriteContent)(content, "File.write"); if (server()) return Promise.resolve(); const append = options?.append ?? false; let data; if (typeof content === "string") { const encoding = options?.encoding ?? "utf8"; (0, import_validate.assertEncoding)(encoding, "File.write"); if (encoding === "base64") { if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(content)) { throw new Error("FileSystem: invalid base64 contents"); } data = Uint8Array.from(atob(content), (char) => char.charCodeAt(0)); } else { data = content; } } else { if (options?.encoding !== void 0) (0, import_validate.assertEncoding)(options.encoding, "File.write"); data = toBytes(content); } const uri = this.currentUri; return (0, import_opfs.serial)(async () => { if (append) { let existing = new Uint8Array(); try { existing = await readWholeFile(uri); } catch (error) { if (error.name !== "NotFoundError") throw error; } const next = typeof data === "string" ? new TextEncoder().encode(data) : data; const combined = new Uint8Array(existing.length + next.length); combined.set(existing); combined.set(next, existing.length); data = combined; } const names = (0, import_opfs.parts)(uri); await (0, import_opfs.write)(await (await (0, import_opfs.parent)(names)).getFileHandle(names.at(-1), { create: true }), data); }); } writeSync(_content, _options) { throw unavailable("File.writeSync"); } create(_options) { throw unavailable("File.create"); } delete() { throw unavailable("File.delete"); } copy(destination, options) { const to = resolveDestination(this, destination, "File.copy"); if (server()) return Promise.resolve(); const from = this.currentUri; return (0, import_opfs.serial)(() => relocate(from, to, false, options?.overwrite ?? false)); } copySync(_destination, _options) { throw unavailable("File.copySync"); } move(destination, options) { const to = resolveDestination(this, destination, "File.move"); if (to === this.currentUri || server()) return Promise.resolve(); const from = this.currentUri; return (0, import_opfs.serial)(() => relocate(from, to, true, options?.overwrite ?? false).then(() => { this.currentUri = to; })); } moveSync(_destination, _options) { throw unavailable("File.moveSync"); } rename(_newName) { throw unavailable("File.rename"); } open(mode = import_types.FileMode.ReadWrite) { (0, import_validate.assertMode)(mode, "File.open"); return new FileHandle(this.currentUri, mode); } readableStream() { return new ReadableStream(new import_streams.FileSystemReadableStreamSource(this.open(import_types.FileMode.ReadOnly))); } writableStream() { return new WritableStream(new import_streams.FileSystemWritableSink(this.open(import_types.FileMode.WriteOnly))); } stream() { return this.readableStream(); } }; var Directory = class Directory { currentUri; constructor(...uris) { const joined = import_paths.PathUtilities.join(...uris); (0, import_validate.assertUri)(joined, "Directory"); this.currentUri = joined; } get uri() { return this.currentUri; } get name() { return import_paths.PathUtilities.basename(this.currentUri); } get parentDirectory() { return new Directory(import_paths.PathUtilities.join(this.currentUri, "..")); } get exists() { throw unavailable("Directory.exists"); } get size() { throw unavailable("Directory.size"); } list() { throw unavailable("Directory.list"); } info() { throw unavailable("Directory.info"); } create(_options) { throw unavailable("Directory.create"); } createFile(_name, _mimeType) { throw unavailable("Directory.createFile"); } createDirectory(_name) { throw unavailable("Directory.createDirectory"); } delete() { throw unavailable("Directory.delete"); } copy(destination, options) { const to = resolveDestination(this, destination, "Directory.copy"); if (server()) return Promise.resolve(); const from = this.currentUri; return (0, import_opfs.serial)(() => relocate(from, to, false, options?.overwrite ?? false)); } copySync(_destination, _options) { throw unavailable("Directory.copySync"); } move(destination, options) { const to = resolveDestination(this, destination, "Directory.move"); if (to === this.currentUri || server()) return Promise.resolve(); const from = this.currentUri; return (0, import_opfs.serial)(() => relocate(from, to, true, options?.overwrite ?? false).then(() => { this.currentUri = to; })); } moveSync(_destination, _options) { throw unavailable("Directory.moveSync"); } rename(_newName) { throw unavailable("Directory.rename"); } }; var Paths = class extends import_paths.PathUtilities { static get cache() { return new Directory(import_opfs.directories.cache); } static get document() { return new Directory(import_opfs.directories.documents); } static get bundle() { throw unavailable("Paths.bundle"); } static get totalDiskSpace() { throw unavailable("Paths.totalDiskSpace"); } static get availableDiskSpace() { throw unavailable("Paths.availableDiskSpace"); } static info(..._uris) { throw unavailable("Paths.info"); } };