'use strict'; var invariant = require('tiny-invariant'); var posix = require('@std/path/posix'); var happyRusty = require('happy-rusty'); var fetchT = require('@happy-ts/fetch-t'); var fflate = require('fflate/browser'); var tinyFuture = require('tiny-future'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var fflate__namespace = /*#__PURE__*/_interopNamespaceDefault(fflate); const NOT_FOUND_ERROR = "NotFoundError"; const ROOT_DIR = "/"; const CURRENT_DIR = "."; const TMP_DIR = "/tmp"; function assertAbsolutePath(path) { invariant(typeof path === "string", () => `Path must be a string but received ${path}`); invariant(path[0] === ROOT_DIR, () => `Path must start with / but received ${path}`); } function assertFileUrl(fileUrl) { invariant(typeof fileUrl === "string", () => `File url must be a string but received ${fileUrl}`); } let fsRoot; async function getFsRoot() { fsRoot ??= await navigator.storage.getDirectory(); return fsRoot; } function isRootPath(path) { return path === ROOT_DIR; } async function getChildDirHandle(dirHandle, dirName, options) { try { const handle = await dirHandle.getDirectoryHandle(dirName, options); return happyRusty.Ok(handle); } catch (e) { const err = e; const error = new Error(`${err.name}: ${err.message} When get child directory '${dirName}' from directory '${dirHandle.name || ROOT_DIR}'.`); error.name = err.name; return happyRusty.Err(error); } } async function getChildFileHandle(dirHandle, fileName, options) { try { const handle = await dirHandle.getFileHandle(fileName, options); return happyRusty.Ok(handle); } catch (e) { const err = e; const error = new Error(`${err.name}: ${err.message} When get child file '${fileName}' from directory '${dirHandle.name || ROOT_DIR}'.`); error.name = err.name; return happyRusty.Err(error); } } async function getDirHandle(dirPath, options) { let dirHandle = await getFsRoot(); if (isRootPath(dirPath)) { return happyRusty.Ok(dirHandle); } let childDirPath = dirPath.slice(1); while (childDirPath) { let dirName = ""; const index = childDirPath.indexOf(posix.SEPARATOR); if (index === -1) { dirName = childDirPath; childDirPath = ""; } else { dirName = childDirPath.slice(0, index); childDirPath = childDirPath.slice(index + 1); if (index === 0) { continue; } } const dirHandleRes = await getChildDirHandle(dirHandle, dirName, options); if (dirHandleRes.isErr()) { return dirHandleRes; } dirHandle = dirHandleRes.unwrap(); } return happyRusty.Ok(dirHandle); } async function getFileHandle(filePath, options) { const isCreate = options?.create ?? false; const dirPath = posix.dirname(filePath); const fileName = posix.basename(filePath); const dirHandleRes = await getDirHandle(dirPath, { create: isCreate }); return dirHandleRes.andThenAsync((dirHandle) => { return getChildFileHandle(dirHandle, fileName, { create: isCreate }); }); } function isNotFoundError(err) { return err.name === NOT_FOUND_ERROR; } async function getFinalResult(tasks) { const allRes = await Promise.all(tasks); const fail = allRes.find((x) => x.isErr()); return fail ?? happyRusty.RESULT_VOID; } function createAbortError() { const error = new Error(); error.name = fetchT.ABORT_ERROR; return error; } function generateTempPath(options) { const { isDirectory = false, basename = "tmp", extname = "" } = options ?? {}; const base = basename ? `${basename}-` : ""; const ext = isDirectory ? "" : extname; return posix.join(TMP_DIR, `${base}${crypto.randomUUID()}${ext}`); } function isTempPath(path) { return path.startsWith(`${TMP_DIR}${posix.SEPARATOR}`); } async function toFileSystemHandleLike(handle) { const { name, kind } = handle; if (isFileHandle(handle)) { const file = await handle.getFile(); const { size, lastModified, type } = file; const fileHandle = { name, kind, type, size, lastModified }; return fileHandle; } const handleLike = { name, kind }; return handleLike; } function isFileHandle(handle) { return handle.kind === "file"; } function isDirectoryHandle(handle) { return handle.kind === "directory"; } function isFileHandleLike(handle) { return handle.kind === "file"; } async function getFileDataByHandle(handle) { const file = await handle.getFile(); const ab = await file.arrayBuffer(); return new Uint8Array(ab); } async function createFile(filePath) { assertAbsolutePath(filePath); const fileHandleRes = await getFileHandle(filePath, { create: true }); return fileHandleRes.and(happyRusty.RESULT_VOID); } async function mkdir(dirPath) { assertAbsolutePath(dirPath); const dirHandleRes = await getDirHandle(dirPath, { create: true }); return dirHandleRes.and(happyRusty.RESULT_VOID); } async function readDir(dirPath, options) { assertAbsolutePath(dirPath); const dirHandleRes = await getDirHandle(dirPath); async function* read(dirHandle, subDirPath) { const entries = dirHandle.entries(); for await (const [name, handle] of entries) { const path = subDirPath === dirPath ? name : posix.join(subDirPath, name); yield { path, handle }; if (isDirectoryHandle(handle) && options?.recursive) { yield* read(await dirHandle.getDirectoryHandle(name), path); } } } return dirHandleRes.andThen((x) => happyRusty.Ok(read(x, dirPath))); } async function readFile(filePath, options) { assertAbsolutePath(filePath); const fileHandleRes = await getFileHandle(filePath); return fileHandleRes.andThenAsync(async (fileHandle) => { const file = await fileHandle.getFile(); switch (options?.encoding) { case "blob": { return happyRusty.Ok(file); } case "utf8": { const text = await file.text(); return happyRusty.Ok(text); } default: { const data = await file.arrayBuffer(); return happyRusty.Ok(data); } } }); } async function remove(path) { assertAbsolutePath(path); const dirPath = posix.dirname(path); const childName = posix.basename(path); const dirHandleRes = await getDirHandle(dirPath); return (await dirHandleRes.andThenAsync(async (dirHandle) => { try { if (isRootPath(dirPath) && isRootPath(childName)) { await dirHandle.remove({ recursive: true }); } else { await dirHandle.removeEntry(childName, { recursive: true }); } } catch (e) { return happyRusty.Err(e); } return happyRusty.RESULT_VOID; })).orElse((err) => { return isNotFoundError(err) ? happyRusty.RESULT_VOID : happyRusty.Err(err); }); } async function stat(path) { assertAbsolutePath(path); const dirPath = posix.dirname(path); const childName = posix.basename(path); const dirHandleRes = await getDirHandle(dirPath); if (!childName) { return dirHandleRes; } return dirHandleRes.andThenAsync(async (dirHandle) => { for await (const [name, handle] of dirHandle.entries()) { if (name === childName) { return happyRusty.Ok(handle); } } const err = new Error(`${NOT_FOUND_ERROR}: '${childName}' does not exist. Full path is '${path}'.`); err.name = NOT_FOUND_ERROR; return happyRusty.Err(err); }); } async function writeFile(filePath, contents, options) { assertAbsolutePath(filePath); const { append = false, create = true } = options ?? {}; const fileHandleRes = await getFileHandle(filePath, { create }); return fileHandleRes.andThenAsync(async (fileHandle) => { const writable = await fileHandle.createWritable({ keepExistingData: append }); const params = { type: "write", data: contents }; if (append) { const { size } = await fileHandle.getFile(); params.position = size; } await writable.write(params); await writable.close(); return happyRusty.RESULT_VOID; }); } function downloadFile(fileUrl, filePath, requestInit) { assertFileUrl(fileUrl); let saveToTemp = false; if (typeof filePath === "string") { assertAbsolutePath(filePath); } else { requestInit = filePath; filePath = generateTempPath({ extname: posix.extname(fileUrl) }); saveToTemp = true; } let aborted = false; const fetchTask = fetchT.fetchT(fileUrl, { redirect: "follow", ...requestInit, abortable: true }); const response = (async () => { const responseRes = await fetchTask.response; return responseRes.andThenAsync(async (response2) => { const blob = await response2.blob(); if (aborted) { return happyRusty.Err(createAbortError()); } const writeRes = await writeFile(filePath, blob); return writeRes.and(happyRusty.Ok(response2)); }); })(); return { // eslint-disable-next-line @typescript-eslint/no-explicit-any abort(reason) { aborted = true; fetchTask.abort(reason); }, get aborted() { return aborted; }, get response() { return saveToTemp ? response.then((res) => { return res.map((rawResponse) => { return { tempFilePath: filePath, rawResponse }; }); }) : response; } }; } async function moveHandle(fileHandle, newPath) { const newDirPath = posix.dirname(newPath); return (await getDirHandle(newDirPath, { create: true })).andThenAsync(async (newDirHandle) => { const newName = posix.basename(newPath); try { await fileHandle.move(newDirHandle, newName); return happyRusty.RESULT_VOID; } catch (e) { return happyRusty.Err(e); } }); } async function mkDestFromSrc(srcPath, destPath, handler, overwrite = true) { assertAbsolutePath(destPath); return (await stat(srcPath)).andThenAsync(async (srcHandle) => { let destExists = false; const destHandleRes = await stat(destPath); if (destHandleRes.isErr()) { if (!isNotFoundError(destHandleRes.unwrapErr())) { return destHandleRes.asErr(); } } else { destExists = true; const destHandle = destHandleRes.unwrap(); if (!(isFileHandle(srcHandle) && isFileHandle(destHandle) || isDirectoryHandle(srcHandle) && isDirectoryHandle(destHandle))) { return happyRusty.Err(new Error(`Both 'srcPath' and 'destPath' must both be a file or directory.`)); } } if (isFileHandle(srcHandle)) { return overwrite || !destExists ? await handler(srcHandle, destPath) : happyRusty.RESULT_VOID; } const readDirRes = await readDir(srcPath, { recursive: true }); return readDirRes.andThenAsync(async (entries) => { const tasks = [ // make sure new dir created mkdir(destPath) ]; for await (const { path, handle } of entries) { const newEntryPath = posix.join(destPath, path); let newPathExists = false; if (destExists) { const existsRes = await exists(newEntryPath); if (existsRes.isErr()) { tasks.push(Promise.resolve(existsRes.asErr())); continue; } newPathExists = existsRes.unwrap(); } const res = isFileHandle(handle) ? overwrite || !newPathExists ? handler(handle, newEntryPath) : Promise.resolve(happyRusty.RESULT_VOID) : mkdir(newEntryPath); tasks.push(res); } return getFinalResult(tasks); }); }); } function appendFile(filePath, contents) { return writeFile(filePath, contents, { append: true }); } async function copy(srcPath, destPath, options) { const { overwrite = true } = options ?? {}; return mkDestFromSrc(srcPath, destPath, async (srcHandle, destPath2) => { return await writeFile(destPath2, await srcHandle.getFile()); }, overwrite); } async function emptyDir(dirPath) { const readDirRes = await readDir(dirPath); if (readDirRes.isErr()) { return isNotFoundError(readDirRes.unwrapErr()) ? mkdir(dirPath) : readDirRes.asErr(); } const tasks = []; for await (const { path } of readDirRes.unwrap()) { tasks.push(remove(posix.join(dirPath, path))); } return getFinalResult(tasks); } async function exists(path, options) { const { isDirectory = false, isFile = false } = options ?? {}; invariant(!(isDirectory && isFile), () => "ExistsOptions.isDirectory and ExistsOptions.isFile must not be true together."); const statRes = await stat(path); return statRes.andThen((handle) => { const notExist = isDirectory && isFileHandle(handle) || isFile && isDirectoryHandle(handle); return happyRusty.Ok(!notExist); }).orElse((err) => { return isNotFoundError(err) ? happyRusty.RESULT_FALSE : statRes.asErr(); }); } async function move(srcPath, destPath, options) { const { overwrite = true } = options ?? {}; return (await mkDestFromSrc(srcPath, destPath, moveHandle, overwrite)).andThenAsync(() => { return remove(srcPath); }); } function readBlobFile(filePath) { return readFile(filePath, { encoding: "blob" }); } async function readJsonFile(filePath) { return (await readTextFile(filePath)).andThenAsync(async (contents) => { try { return happyRusty.Ok(JSON.parse(contents)); } catch (e) { return happyRusty.Err(e); } }); } function readTextFile(filePath) { return readFile(filePath, { encoding: "utf8" }); } async function mkTemp(options) { const { isDirectory = false } = options ?? {}; const path = generateTempPath(options); const res = await (isDirectory ? mkdir : createFile)(path); return res.and(happyRusty.Ok(path)); } function deleteTemp() { return remove(TMP_DIR); } async function pruneTemp(expired) { invariant(expired instanceof Date, () => `Expired must be a Date but received ${expired}`); const readDirRes = await readDir(TMP_DIR, { recursive: true }); return readDirRes.andThenAsync(async (entries) => { try { for await (const { handle } of entries) { if (isFileHandle(handle) && (await handle.getFile()).lastModified <= expired.getTime()) { await handle.remove(); } } } catch (e) { return happyRusty.Err(e); } return happyRusty.RESULT_VOID; }); } async function unzipBufferToTarget(buffer, targetPath) { const data = new Uint8Array(buffer); const future = new tinyFuture.Future(); fflate__namespace.unzip(data, async (err, unzipped) => { if (err) { future.resolve(happyRusty.Err(err)); return; } const tasks = []; for (const path in unzipped) { if (path.at(-1) !== posix.SEPARATOR) { tasks.push(writeFile(posix.join(targetPath, path), unzipped[path])); } } future.resolve(getFinalResult(tasks)); }); return await future.promise; } async function unzip(zipFilePath, targetPath) { assertAbsolutePath(targetPath); const fileRes = await readFile(zipFilePath); return fileRes.andThenAsync((buffer) => { return unzipBufferToTarget(buffer, targetPath); }); } async function unzipFromUrl(zipFileUrl, targetPath, requestInit) { assertFileUrl(zipFileUrl); assertAbsolutePath(targetPath); const fetchRes = await fetchT.fetchT(zipFileUrl, { redirect: "follow", ...requestInit, responseType: "arraybuffer", abortable: false }); return fetchRes.andThenAsync((buffer) => { return unzipBufferToTarget(buffer, targetPath); }); } function uploadFile(filePath, fileUrl, requestInit) { assertFileUrl(fileUrl); let aborted = false; let fetchTask; const response = (async () => { const fileRes = await readBlobFile(filePath); return fileRes.andThenAsync(async (file) => { if (aborted) { return happyRusty.Err(createAbortError()); } const { // default file name filename = posix.basename(filePath), ...rest } = requestInit ?? {}; const formData = new FormData(); formData.append(filename, file, filename); fetchTask = fetchT.fetchT(fileUrl, { method: "POST", ...rest, abortable: true, body: formData }); return fetchTask.response; }); })(); return { // eslint-disable-next-line @typescript-eslint/no-explicit-any abort(reason) { aborted = true; fetchTask?.abort(reason); }, get aborted() { return aborted; }, get response() { return response; } }; } async function zipTo(zippable, zipFilePath) { const future = new tinyFuture.Future(); fflate__namespace.zip(zippable, { consume: true }, async (err, u8a) => { if (err) { future.resolve(happyRusty.Err(err)); return; } if (zipFilePath) { const res = await writeFile(zipFilePath, u8a); future.resolve(res); } else { future.resolve(happyRusty.Ok(u8a)); } }); return await future.promise; } async function zip(sourcePath, zipFilePath, options) { if (typeof zipFilePath === "string") { assertAbsolutePath(zipFilePath); } else { options = zipFilePath; zipFilePath = void 0; } const statRes = await stat(sourcePath); return statRes.andThenAsync(async (handle) => { const sourceName = posix.basename(sourcePath); const zippable = {}; if (isFileHandle(handle)) { const data = await getFileDataByHandle(handle); zippable[sourceName] = data; } else { const readDirRes = await readDir(sourcePath, { recursive: true }); if (readDirRes.isErr()) { return readDirRes.asErr(); } const preserveRoot = options?.preserveRoot ?? true; for await (const { path, handle: handle2 } of readDirRes.unwrap()) { if (isFileHandle(handle2)) { const entryName = preserveRoot ? posix.join(sourceName, path) : path; const data = await getFileDataByHandle(handle2); zippable[entryName] = data; } } } return zipTo(zippable, zipFilePath); }); } async function zipFromUrl(sourceUrl, zipFilePath, requestInit) { assertFileUrl(sourceUrl); if (typeof zipFilePath === "string") { assertAbsolutePath(zipFilePath); } else { requestInit = zipFilePath; zipFilePath = void 0; } const fetchRes = await fetchT.fetchT(sourceUrl, { redirect: "follow", ...requestInit, responseType: "arraybuffer", abortable: false }); return fetchRes.andThenAsync((buffer) => { const sourceName = posix.basename(sourceUrl); const zippable = {}; zippable[sourceName] = new Uint8Array(buffer); return zipTo(zippable, zipFilePath); }); } function isOPFSSupported() { return typeof navigator?.storage?.getDirectory === "function"; } function serializeError(error) { return error ? { name: error.name, message: error.message } : error; } function deserializeError(error) { const err = new Error(error.message); err.name = error.name; return err; } async function serializeFile(file) { const ab = await file.arrayBuffer(); return { name: file.name, type: file.type, lastModified: file.lastModified, size: ab.byteLength, data: ab }; } let globalOpTimeout = 1e3; function setGlobalOpTimeout(timeout) { globalOpTimeout = timeout; } function sleepUntil(condition) { const start = Date.now(); while (!condition()) { if (Date.now() - start > globalOpTimeout) { const error = new Error("Operating Timeout"); error.name = fetchT.TIMEOUT_ERROR; throw error; } } } var WorkerAsyncOp = /* @__PURE__ */ ((WorkerAsyncOp2) => { WorkerAsyncOp2[WorkerAsyncOp2["createFile"] = 0] = "createFile"; WorkerAsyncOp2[WorkerAsyncOp2["mkdir"] = 1] = "mkdir"; WorkerAsyncOp2[WorkerAsyncOp2["move"] = 2] = "move"; WorkerAsyncOp2[WorkerAsyncOp2["readDir"] = 3] = "readDir"; WorkerAsyncOp2[WorkerAsyncOp2["remove"] = 4] = "remove"; WorkerAsyncOp2[WorkerAsyncOp2["stat"] = 5] = "stat"; WorkerAsyncOp2[WorkerAsyncOp2["writeFile"] = 6] = "writeFile"; WorkerAsyncOp2[WorkerAsyncOp2["appendFile"] = 7] = "appendFile"; WorkerAsyncOp2[WorkerAsyncOp2["copy"] = 8] = "copy"; WorkerAsyncOp2[WorkerAsyncOp2["emptyDir"] = 9] = "emptyDir"; WorkerAsyncOp2[WorkerAsyncOp2["exists"] = 10] = "exists"; WorkerAsyncOp2[WorkerAsyncOp2["deleteTemp"] = 11] = "deleteTemp"; WorkerAsyncOp2[WorkerAsyncOp2["mkTemp"] = 12] = "mkTemp"; WorkerAsyncOp2[WorkerAsyncOp2["pruneTemp"] = 13] = "pruneTemp"; WorkerAsyncOp2[WorkerAsyncOp2["readBlobFile"] = 14] = "readBlobFile"; WorkerAsyncOp2[WorkerAsyncOp2["unzip"] = 15] = "unzip"; WorkerAsyncOp2[WorkerAsyncOp2["zip"] = 16] = "zip"; return WorkerAsyncOp2; })(WorkerAsyncOp || {}); const MAIN_LOCK_INDEX = 0; const WORKER_LOCK_INDEX = 1; const DATA_INDEX = 2; const MAIN_LOCKED = 1; const MAIN_UNLOCKED = 0; const WORKER_LOCKED = MAIN_UNLOCKED; const WORKER_UNLOCKED = MAIN_LOCKED; let encoder; let decoder; function getEncoder() { encoder ??= new TextEncoder(); return encoder; } function getDecoder() { decoder ??= new TextDecoder(); return decoder; } function encodeToBuffer(data) { const str = JSON.stringify(data); return getEncoder().encode(str); } function decodeFromBuffer(data) { const str = decodeToString(data); return JSON.parse(str); } function decodeToString(data) { return getDecoder().decode(data); } class SyncMessenger { // View of SharedArrayBuffer, used to communicate between main thread and worker. i32a; // View of the same SharedArrayBuffer, used to read and write binary data. u8a; // 4 int: MAIN_LOCK_INDEX WORKER_LOCK_INDEX DATA_INDEX NOT_USE headerLength = 4 * 4; // maximum length of data to be sent. If data is longer than this, it will throw an error. maxDataLength; constructor(sab) { this.i32a = new Int32Array(sab); this.u8a = new Uint8Array(sab); this.maxDataLength = sab.byteLength - this.headerLength; } } function callWorkerFromMain(messenger, data) { const { i32a, u8a, headerLength, maxDataLength } = messenger; const requestLength = data.byteLength; if (requestLength > maxDataLength) { throw new RangeError(`Request is too large: ${requestLength} > ${maxDataLength}. Consider grow the size of SharedArrayBuffer.`); } Atomics.store(i32a, MAIN_LOCK_INDEX, MAIN_LOCKED); i32a[DATA_INDEX] = requestLength; u8a.set(data, headerLength); Atomics.store(i32a, WORKER_LOCK_INDEX, WORKER_UNLOCKED); sleepUntil(() => Atomics.load(i32a, MAIN_LOCK_INDEX) === MAIN_UNLOCKED); const responseLength = i32a[DATA_INDEX]; const response = u8a.slice(headerLength, headerLength + responseLength); return response; } async function respondToMainFromWorker(messenger, transfer) { const { i32a, u8a, headerLength, maxDataLength } = messenger; while (true) { if (Atomics.load(i32a, WORKER_LOCK_INDEX) === WORKER_UNLOCKED) { break; } } const requestLength = i32a[DATA_INDEX]; const data = u8a.slice(headerLength, headerLength + requestLength); let response = await transfer(data); const responseLength = response.byteLength; if (responseLength > maxDataLength) { const message = `Response is too large: ${responseLength} > ${maxDataLength}. Consider grow the size of SharedArrayBuffer.`; response = encodeToBuffer([{ name: "RangeError", message }]); if (response.byteLength > maxDataLength) { Atomics.store(i32a, WORKER_LOCK_INDEX, WORKER_LOCKED); throw new RangeError(message); } } i32a[DATA_INDEX] = response.byteLength; u8a.set(response, headerLength); Atomics.store(i32a, WORKER_LOCK_INDEX, WORKER_LOCKED); Atomics.store(i32a, MAIN_LOCK_INDEX, MAIN_UNLOCKED); } const asyncOps = { [WorkerAsyncOp.createFile]: createFile, [WorkerAsyncOp.mkdir]: mkdir, [WorkerAsyncOp.move]: move, [WorkerAsyncOp.readDir]: readDir, [WorkerAsyncOp.remove]: remove, [WorkerAsyncOp.stat]: stat, [WorkerAsyncOp.writeFile]: writeFile, [WorkerAsyncOp.appendFile]: appendFile, [WorkerAsyncOp.copy]: copy, [WorkerAsyncOp.emptyDir]: emptyDir, [WorkerAsyncOp.exists]: exists, [WorkerAsyncOp.deleteTemp]: deleteTemp, [WorkerAsyncOp.mkTemp]: mkTemp, [WorkerAsyncOp.pruneTemp]: pruneTemp, [WorkerAsyncOp.readBlobFile]: readBlobFile, [WorkerAsyncOp.unzip]: unzip, [WorkerAsyncOp.zip]: zip }; let messenger$1; function startSyncAgent() { if (typeof window !== "undefined") { throw new Error("Only can use in worker"); } if (messenger$1) { throw new Error("Worker messenger already started"); } addEventListener("message", (event) => { const sab = event.data; if (!(sab instanceof SharedArrayBuffer)) { throw new TypeError("Only can post SharedArrayBuffer to Worker"); } messenger$1 = new SyncMessenger(sab); postMessage(true); runWorkerLoop(); }); } async function runWorkerLoop() { while (true) { try { await respondToMainFromWorker(messenger$1, async (data) => { const [op, ...args] = decodeFromBuffer(data); if (op === WorkerAsyncOp.writeFile || op === WorkerAsyncOp.appendFile) { if (Array.isArray(args[1])) { args[1] = new Uint8Array(args[1]); } } else if (op === WorkerAsyncOp.pruneTemp) { args[0] = new Date(args[0]); } let response; const handle = asyncOps[op]; try { const res = await handle(...args); if (res.isErr()) { response = encodeToBuffer([serializeError(res.unwrapErr())]); } else { let rawResponse; if (op === WorkerAsyncOp.readBlobFile) { const file = res.unwrap(); const fileLike = await serializeFile(file); rawResponse = { ...fileLike, // for serialize data: [...new Uint8Array(fileLike.data)] }; } else if (op === WorkerAsyncOp.readDir) { const iterator = res.unwrap(); const entries = []; for await (const { path, handle: handle2 } of iterator) { const handleLike = await toFileSystemHandleLike(handle2); entries.push({ path, handle: handleLike }); } rawResponse = entries; } else if (op === WorkerAsyncOp.stat) { const handle2 = res.unwrap(); const data2 = await toFileSystemHandleLike(handle2); rawResponse = data2; } else if (op === WorkerAsyncOp.zip) { const data2 = res.unwrap(); rawResponse = data2 instanceof Uint8Array ? [...data2] : data2; } else { rawResponse = res.unwrap(); } response = encodeToBuffer([null, rawResponse]); } } catch (e) { response = encodeToBuffer([serializeError(e)]); } return response; }); } catch (err) { console.error(err instanceof Error ? err.stack : err); } } } let messenger; function connectSyncAgent(options) { if (typeof window === "undefined") { throw new Error("Only can use in main thread"); } if (messenger) { throw new Error("Main messenger already started"); } return new Promise((resolve) => { const { worker, bufferLength = 1024 * 1024, opTimeout = 1e3 } = options; invariant(worker instanceof Worker || worker instanceof URL || typeof worker === "string" && worker, () => "worker must be Worker or valid URL(string)"); invariant(bufferLength > 16 && bufferLength % 4 === 0, () => "bufferLength must be a multiple of 4"); invariant(Number.isInteger(opTimeout) && opTimeout > 0, () => "opTimeout must be integer and greater than 0"); setGlobalOpTimeout(opTimeout); const workerAdapter = worker instanceof Worker ? worker : new Worker(worker); const sab = new SharedArrayBuffer(bufferLength); workerAdapter.addEventListener("message", (event) => { if (event.data) { messenger = new SyncMessenger(sab); resolve(); } }); workerAdapter.postMessage(sab); }); } function callWorkerOp(op, ...args) { if (!messenger) { return happyRusty.Err(new Error("Worker not initialized. Come back later.")); } const request = [op, ...args]; const requestData = encodeToBuffer(request); try { const response = callWorkerFromMain(messenger, requestData); const decodedResponse = decodeFromBuffer(response); const err = decodedResponse[0]; const result = err ? happyRusty.Err(deserializeError(err)) : happyRusty.Ok(decodedResponse[1] ?? void 0); return result; } catch (err) { return happyRusty.Err(err); } } function createFileSync(filePath) { return callWorkerOp(WorkerAsyncOp.createFile, filePath); } function mkdirSync(dirPath) { return callWorkerOp(WorkerAsyncOp.mkdir, dirPath); } function moveSync(srcPath, destPath, options) { return callWorkerOp(WorkerAsyncOp.move, srcPath, destPath, options); } function readDirSync(dirPath, options) { return callWorkerOp(WorkerAsyncOp.readDir, dirPath, options); } function readFileSync(filePath, options) { const res = callWorkerOp(WorkerAsyncOp.readBlobFile, filePath); return res.map((file) => { const u8a = new Uint8Array(file.data); file.data = u8a.buffer.slice(u8a.byteOffset, u8a.byteOffset + u8a.byteLength); switch (options?.encoding) { case "blob": { return file; } case "utf8": { return decodeToString(new Uint8Array(file.data)); } default: { return file.data; } } }); } function removeSync(path) { return callWorkerOp(WorkerAsyncOp.remove, path); } function statSync(path) { return callWorkerOp(WorkerAsyncOp.stat, path); } function serializeWriteContents(contents) { return contents instanceof ArrayBuffer ? [...new Uint8Array(contents)] : ArrayBuffer.isView(contents) ? [...new Uint8Array(contents.buffer)] : contents; } function writeFileSync(filePath, contents, options) { return callWorkerOp(WorkerAsyncOp.writeFile, filePath, serializeWriteContents(contents), options); } function appendFileSync(filePath, contents) { return callWorkerOp(WorkerAsyncOp.appendFile, filePath, serializeWriteContents(contents)); } function copySync(srcPath, destPath, options) { return callWorkerOp(WorkerAsyncOp.copy, srcPath, destPath, options); } function emptyDirSync(dirPath) { return callWorkerOp(WorkerAsyncOp.emptyDir, dirPath); } function existsSync(path, options) { return callWorkerOp(WorkerAsyncOp.exists, path, options); } function deleteTempSync() { return callWorkerOp(WorkerAsyncOp.deleteTemp); } function mkTempSync(options) { return callWorkerOp(WorkerAsyncOp.mkTemp, options); } function pruneTempSync(expired) { return callWorkerOp(WorkerAsyncOp.pruneTemp, expired); } function readBlobFileSync(filePath) { return readFileSync(filePath, { encoding: "blob" }); } function readJsonFileSync(filePath) { return readTextFileSync(filePath).andThen((contents) => { try { return happyRusty.Ok(JSON.parse(contents)); } catch (e) { return happyRusty.Err(e); } }); } function readTextFileSync(filePath) { return readFileSync(filePath, { encoding: "utf8" }); } function unzipSync(zipFilePath, targetPath) { return callWorkerOp(WorkerAsyncOp.unzip, zipFilePath, targetPath); } function zipSync(sourcePath, zipFilePath, options) { const res = callWorkerOp(WorkerAsyncOp.zip, sourcePath, zipFilePath, options); return res.map((data) => { return data ? new Uint8Array(data) : data; }); } Object.defineProperty(exports, "ABORT_ERROR", { enumerable: true, get: function () { return fetchT.ABORT_ERROR; } }); Object.defineProperty(exports, "TIMEOUT_ERROR", { enumerable: true, get: function () { return fetchT.TIMEOUT_ERROR; } }); exports.CURRENT_DIR = CURRENT_DIR; exports.NOT_FOUND_ERROR = NOT_FOUND_ERROR; exports.ROOT_DIR = ROOT_DIR; exports.TMP_DIR = TMP_DIR; exports.appendFile = appendFile; exports.appendFileSync = appendFileSync; exports.assertAbsolutePath = assertAbsolutePath; exports.assertFileUrl = assertFileUrl; exports.connectSyncAgent = connectSyncAgent; exports.copy = copy; exports.copySync = copySync; exports.createFile = createFile; exports.createFileSync = createFileSync; exports.deleteTemp = deleteTemp; exports.deleteTempSync = deleteTempSync; exports.downloadFile = downloadFile; exports.emptyDir = emptyDir; exports.emptyDirSync = emptyDirSync; exports.exists = exists; exports.existsSync = existsSync; exports.generateTempPath = generateTempPath; exports.getFileDataByHandle = getFileDataByHandle; exports.isDirectoryHandle = isDirectoryHandle; exports.isFileHandle = isFileHandle; exports.isFileHandleLike = isFileHandleLike; exports.isOPFSSupported = isOPFSSupported; exports.isTempPath = isTempPath; exports.mkTemp = mkTemp; exports.mkTempSync = mkTempSync; exports.mkdir = mkdir; exports.mkdirSync = mkdirSync; exports.move = move; exports.moveSync = moveSync; exports.pruneTemp = pruneTemp; exports.pruneTempSync = pruneTempSync; exports.readBlobFile = readBlobFile; exports.readBlobFileSync = readBlobFileSync; exports.readDir = readDir; exports.readDirSync = readDirSync; exports.readFile = readFile; exports.readFileSync = readFileSync; exports.readJsonFile = readJsonFile; exports.readJsonFileSync = readJsonFileSync; exports.readTextFile = readTextFile; exports.readTextFileSync = readTextFileSync; exports.remove = remove; exports.removeSync = removeSync; exports.startSyncAgent = startSyncAgent; exports.stat = stat; exports.statSync = statSync; exports.toFileSystemHandleLike = toFileSystemHandleLike; exports.unzip = unzip; exports.unzipFromUrl = unzipFromUrl; exports.unzipSync = unzipSync; exports.uploadFile = uploadFile; exports.writeFile = writeFile; exports.writeFileSync = writeFileSync; exports.zip = zip; exports.zipFromUrl = zipFromUrl; exports.zipSync = zipSync; //# sourceMappingURL=main.cjs.map