one
Version:
One is a React framework for web, iOS, and Android apps.
440 lines (439 loc) • 14 kB
JavaScript
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");
}
};