Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); // fs-proxy.js /** * @param {unknown} value */ const getType = (value) => { if (value === void 0) return 0; if (value === null) return 1; if (isBuffer(value)) return 10; const t = typeof value; if (t === "boolean") return 2; if (t === "number") return 3; if (t === "string") return 4; if (t === "object") return 6; if (t === "bigint") return 9; return -1; }; /** * @param {unknown} value * @returns {value is Uint8Array} */ const isBuffer = (value) => { const BufferCtor = globalThis.Buffer; if (typeof BufferCtor?.isBuffer === "function") return BufferCtor.isBuffer(value); return value instanceof Uint8Array && value.constructor?.name === "Buffer"; }; const RESPONSE_HEADER_SIZE = 16; const RESPONSE_PAYLOAD_SIZE = 10240; const RESPONSE_BUFFER_SIZE = 10256; /** * @param {Int32Array} sab * @param {Uint8Array} payload */ const writeResponsePayload = (sab, payload) => { if (payload.length > RESPONSE_PAYLOAD_SIZE) throw new RangeError("payload overflow"); new Uint8Array(sab.buffer).set(payload, RESPONSE_HEADER_SIZE); }; /** * @param {import('memfs').IFs} memfs * @param {any} value * @param {ReturnType} type * @returns {Uint8Array} */ const encodeValue = (memfs, value, type) => { switch (type) { case 0: case 1: return /* @__PURE__ */ new Uint8Array(0); case 2: { const view = /* @__PURE__ */ new Int32Array(1); view[0] = value ? 1 : 0; return new Uint8Array(view.buffer); } case 3: { const view = /* @__PURE__ */ new Float64Array(1); view[0] = value; return new Uint8Array(view.buffer); } case 4: return new TextEncoder().encode(value); case 10: return new Uint8Array(value); case 6: { function storeConstructor(obj, memfs, processed = /* @__PURE__ */ new WeakSet()) { if (!obj || typeof obj !== "object") return; if (processed.has(obj)) return; processed.add(obj); const [entry] = Object.entries(memfs).filter(([_key, v]) => v === obj.constructor)[0] ?? []; if (entry) Object.defineProperty(obj, "__constructor__", { configurable: true, writable: true, enumerable: true, value: entry }); for (const value of Object.values(obj)) storeConstructor(value, memfs, processed); } storeConstructor(value, memfs); const json = JSON.stringify(value, (_, value) => { if (typeof value === "bigint") return `BigInt(${String(value)})`; if (value instanceof Error) return { ...value, message: value.message, stack: value.stack, __error__: value.constructor.name }; return value; }); return new TextEncoder().encode(json); } case 9: return new TextEncoder().encode(String(value)); default: throw new Error("unsupported data"); } }; /** * @param {typeof import('memfs')} memfs * @param {Uint8Array} payload * @param {number} type * @returns {any} */ const decodeValue = (memfs, payload, type) => { if (type === 0) return void 0; if (type === 1) return null; if (type === 2) return Boolean(new Int32Array(payload.buffer, payload.byteOffset, 1)[0]); if (type === 3) return new Float64Array(payload.buffer, payload.byteOffset, 1)[0]; if (type === 4) return new TextDecoder().decode(payload.slice()); if (type === 10) { const BufferCtor = globalThis.Buffer; if (typeof BufferCtor?.from === "function") return BufferCtor.from(payload); return payload.slice(); } if (type === 6) { const obj = JSON.parse(new TextDecoder().decode(payload.slice()), (_key, value) => { if (typeof value === "string") { const matched = value.match(/^BigInt\((-?\d+)\)$/); if (matched && matched[1]) return BigInt(matched[1]); } return value; }); function loadConstructor(obj, memfs, processed = /* @__PURE__ */ new WeakSet()) { if (!obj || typeof obj !== "object") return; if (processed.has(obj)) return; processed.add(obj); if (obj.__constructor__) { const ctor = obj.__constructor__; delete obj.__constructor__; Object.setPrototypeOf(obj, memfs[ctor].prototype); } for (const value of Object.values(obj)) loadConstructor(value, memfs, processed); } loadConstructor(obj, memfs); if (obj.__error__) { const name = obj.__error__; const ErrorConstructor = globalThis[name] || Error; delete obj.__error__; const err = new ErrorConstructor(obj.message); Object.defineProperty(err, "stack", { configurable: true, enumerable: false, writable: true, value: err.stack }); Object.defineProperty(err, Symbol.toStringTag, { configurable: true, enumerable: false, writable: true, value: name }); for (const [k, v] of Object.entries(obj)) { if (k === "message" || k === "stack") continue; err[k] = v; } return err; } return obj; } if (type === 9) return BigInt(new TextDecoder().decode(payload.slice())); throw new Error("unsupported data"); }; /** * @param {import('memfs').IFs} fs * @returns {(e: { data: { __fs__: { sab: Int32Array, type: keyof import('memfs').IFs, payload: any[] } } }) => void} */ const createOnMessage = (fs) => function onMessage(e) { if (e.data.__fs__) { /** * 0..4 status(int32_t): 21(waiting) 0(success) 1(error) * 5..8 type(napi_valuetype): 0(undefined) 1(null) 2(boolean) 3(number) 4(string) 6(jsonstring) 9(bigint) 10(buffer) -1(unsupported) * 9..16 payload_size(uint32_t) <= 10240 * 16..16 + payload_size payload_content */ const { sab, type, payload } = e.data.__fs__; const fn = fs[type]; try { const ret = fn.apply(fs, payload); const t = getType(ret); Atomics.store(sab, 1, t); const v = encodeValue(fs, ret, t); Atomics.store(sab, 2, v.length); writeResponsePayload(sab, v); Atomics.store(sab, 0, 0); } catch (err) { let t = getType(err); let v; try { if (t === -1) throw new Error("unsupported data"); v = encodeValue(fs, err, t); } catch { const fallback = (() => { try { return String(err); } catch { return "Unserializable thrown value"; } })(); t = getType(fallback); v = encodeValue(fs, fallback, t); } if (v.length > RESPONSE_PAYLOAD_SIZE) { const overflowErr = /* @__PURE__ */ new RangeError("payload overflow"); t = getType(overflowErr); v = encodeValue(fs, overflowErr, t); } Atomics.store(sab, 1, t); Atomics.store(sab, 2, v.length); writeResponsePayload(sab, v); Atomics.store(sab, 0, 1); } finally { Atomics.notify(sab, 0); } } }; /** * @param {typeof import('memfs')} memfs */ const createFsProxy = (memfs) => new Proxy({}, { get(_target, p, _receiver) { /** * @param {any[]} args */ return function(...args) { const sab = new SharedArrayBuffer(RESPONSE_BUFFER_SIZE); const i32arr = new Int32Array(sab); Atomics.store(i32arr, 0, 21); postMessage({ __fs__: { sab: i32arr, type: p, payload: args } }); Atomics.wait(i32arr, 0, 21); const status = Atomics.load(i32arr, 0); const type = Atomics.load(i32arr, 1); const size = Atomics.load(i32arr, 2); const content = new Uint8Array(sab, RESPONSE_HEADER_SIZE, size); const value = decodeValue(memfs, content, type); if (status === 1) throw value; return value; }; } }); exports.createFsProxy = createFsProxy; exports.createOnMessage = createOnMessage;