@utoo/web 1.2.0-rc.9 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -7,35 +7,6 @@ const statCache = {};
7
7
  const pkgJsonCache = {};
8
8
  const resolutionCache = {};
9
9
  const searchPathsCache = {};
10
- const statSync = (p) => {
11
- if (p.includes("node_modules") &&
12
- Object.prototype.hasOwnProperty.call(statCache, p)) {
13
- if (statCache[p] === false) {
14
- throw new Error("ENOENT");
15
- }
16
- return statCache[p];
17
- }
18
- try {
19
- const res = fs.statSync(p);
20
- if (p.includes("node_modules"))
21
- statCache[p] = res;
22
- return res;
23
- }
24
- catch (e) {
25
- if (p.includes("node_modules"))
26
- statCache[p] = false;
27
- throw e;
28
- }
29
- };
30
- const existsSync = (p) => {
31
- try {
32
- statSync(p);
33
- return true;
34
- }
35
- catch (e) {
36
- return false;
37
- }
38
- };
39
10
  const executeModule = (moduleCode, moduleId, id, importMaps, entrypoint) => {
40
11
  if (installedModules[moduleId]) {
41
12
  return installedModules[moduleId].exports;
@@ -108,7 +79,7 @@ const loadModule = (id, context, importMaps, entrypoint) => {
108
79
  // 1. Resolve
109
80
  let resolvedId = id;
110
81
  if (id.startsWith(".")) {
111
- resolvedId = path.resolve(context, id);
82
+ resolvedId = path.join(context, id);
112
83
  }
113
84
  // 2. Check Cache (SystemJS)
114
85
  let dependency = System.get(resolvedId);
@@ -259,8 +230,9 @@ const loadModule = (id, context, importMaps, entrypoint) => {
259
230
  resolutionCache[cacheKey] = moduleId;
260
231
  return executeModule(moduleCode, moduleId, id, importMaps, entrypoint);
261
232
  }
262
- console.error(`Worker: Dependency ${id} (resolved: ${resolvedId}) not found. Context: ${context}`);
263
- return {};
233
+ const error = new Error(`Worker: Dependency ${id} (resolved: ${resolvedId}) not found. Context: ${context}`);
234
+ console.error(error);
235
+ throw error;
264
236
  };
265
237
  export async function cjs(entrypoint, importMaps) {
266
238
  // Clear caches to avoid stale data across runs
@@ -1,5 +1,4 @@
1
- import * as sabcom from "../utils/sabcom";
2
- import initWasm, { Project as ProjectInternal, registerWorkerScheduler, workerCreated, } from "../utoo";
1
+ import initWasm, { registerWorkerScheduler, workerCreated, } from "../utoo";
3
2
  let nextWorkerId = 0;
4
3
  const loaderWorkers = {};
5
4
  export const runLoaderWorkerPool = async (binding, projectCwd, loaderWorkerUrl, loadersImportMap) => {
@@ -7,24 +6,7 @@ export const runLoaderWorkerPool = async (binding, projectCwd, loaderWorkerUrl,
7
6
  const { options: { filename, cwd }, } = creation;
8
7
  nextWorkerId += 1;
9
8
  const workerId = nextWorkerId;
10
- const sab = new SharedArrayBuffer(1024 * 1024 * 10); // 10MB
11
- const sabHost = new sabcom.SabComHost(sab);
12
9
  const worker = new Worker(loaderWorkerUrl, { name: filename });
13
- worker.onmessage = async (event) => {
14
- if (event.data === "sab_request") {
15
- await sabcom.handleSabRequest(sabHost, {
16
- read: (path) => ProjectInternal.read(path),
17
- readDir: (path) => ProjectInternal.readDir(path),
18
- writeString: (path, content) => ProjectInternal.writeString(path, content),
19
- createDirAll: (path) => ProjectInternal.createDirAll(path),
20
- createDir: (path) => ProjectInternal.createDir(path),
21
- metadata: (path) => ProjectInternal.metadata(path),
22
- removeFile: (path) => ProjectInternal.removeFile(path),
23
- removeDir: (path, recursive) => ProjectInternal.removeDir(path, recursive),
24
- copyFile: (src, dst) => ProjectInternal.copyFile(src, dst),
25
- });
26
- }
27
- };
28
10
  let finalCwd = cwd;
29
11
  let finalFilename = filename;
30
12
  if (projectCwd) {
@@ -69,7 +51,6 @@ export const runLoaderWorkerPool = async (binding, projectCwd, loaderWorkerUrl,
69
51
  importMaps: { ...loadersImportMap },
70
52
  entrypoint: finalFilename,
71
53
  },
72
- sab,
73
54
  },
74
55
  ]);
75
56
  const workers = loaderWorkers[filename] || (loaderWorkers[filename] = new Map());
@@ -1,7 +1,6 @@
1
1
  import { Buffer } from "buffer";
2
2
  import path from "path";
3
3
  import { Stats } from "../../types";
4
- import * as sabcom from "../../utils/sabcom";
5
4
  import { promises } from "./fsPromisesPolyfill";
6
5
  function resolvePath(p) {
7
6
  var _a, _b, _c;
@@ -9,14 +8,6 @@ function resolvePath(p) {
9
8
  const cwd = ((_b = (_a = self.process) === null || _a === void 0 ? void 0 : _a.cwd) === null || _b === void 0 ? void 0 : _b.call(_a)) || ((_c = self.workerData) === null || _c === void 0 ? void 0 : _c.cwd) || "/";
10
9
  return path.resolve(cwd, p);
11
10
  }
12
- function getSabClient() {
13
- // @ts-ignore
14
- const client = self.workerData.sabClient;
15
- if (!client) {
16
- throw new Error("Sync fs not supported (no sabClient)");
17
- }
18
- return client;
19
- }
20
11
  function getFs() {
21
12
  // @ts-ignore
22
13
  const fs = self.workerData.fs;
@@ -25,22 +16,21 @@ function getFs() {
25
16
  }
26
17
  return fs;
27
18
  }
28
- // --- Synchronous API (via sabcom) ---
19
+ // --- Synchronous API (via WASM Project Sync APIs) ---
20
+ const textDecoder = new TextDecoder();
29
21
  export function readFileSync(path, options) {
30
- const client = getSabClient();
31
- const result = client.call(sabcom.SAB_OP_READ_FILE, resolvePath(path));
22
+ const fs = getFs();
23
+ const result = fs.readSync(resolvePath(path));
32
24
  if (options === "utf8" ||
33
25
  options === "utf-8" ||
34
26
  (options && (options.encoding === "utf8" || options.encoding === "utf-8"))) {
35
- return new TextDecoder().decode(result);
27
+ return textDecoder.decode(result);
36
28
  }
37
29
  return Buffer.from(result);
38
30
  }
39
31
  export function readdirSync(path, options) {
40
- const client = getSabClient();
41
- const result = client.call(sabcom.SAB_OP_READ_DIR, resolvePath(path));
42
- const json = new TextDecoder().decode(result);
43
- const entries = JSON.parse(json);
32
+ const fs = getFs();
33
+ const entries = fs.readDirSync(resolvePath(path));
44
34
  if (options === null || options === void 0 ? void 0 : options.withFileTypes) {
45
35
  return entries.map((e) => ({
46
36
  name: e.name,
@@ -52,48 +42,69 @@ export function readdirSync(path, options) {
52
42
  return entries.map((e) => e.name);
53
43
  }
54
44
  export function writeFileSync(path, data, options) {
55
- const client = getSabClient();
56
- // TODO: handle binary data properly
57
- const content = typeof data === "string" ? data : new TextDecoder().decode(data);
58
- const payload = JSON.stringify({ path: resolvePath(path), data: content });
59
- client.call(sabcom.SAB_OP_WRITE_FILE, payload);
45
+ const fs = getFs();
46
+ let content;
47
+ if (typeof data === "string") {
48
+ content = new TextEncoder().encode(data);
49
+ }
50
+ else {
51
+ content = data;
52
+ }
53
+ fs.writeSync(resolvePath(path), content);
60
54
  }
61
55
  export function mkdirSync(path, options) {
62
- const client = getSabClient();
56
+ const fs = getFs();
63
57
  const recursive = (options === null || options === void 0 ? void 0 : options.recursive) || false;
64
- const payload = JSON.stringify({ path: resolvePath(path), recursive });
65
- client.call(sabcom.SAB_OP_MKDIR, payload);
58
+ if (recursive) {
59
+ fs.createDirAllSync(resolvePath(path));
60
+ }
61
+ else {
62
+ fs.createDirSync(resolvePath(path));
63
+ }
66
64
  }
67
65
  export function rmSync(path, options) {
68
- const client = getSabClient();
66
+ const fs = getFs();
69
67
  const recursive = (options === null || options === void 0 ? void 0 : options.recursive) || false;
70
- const payload = JSON.stringify({ path: resolvePath(path), recursive });
71
- client.call(sabcom.SAB_OP_RM, payload);
68
+ if (recursive) {
69
+ fs.removeDirSync(resolvePath(path), true);
70
+ }
71
+ else {
72
+ fs.removeFileSync(resolvePath(path));
73
+ }
72
74
  }
73
75
  export function rmdirSync(path, options) {
74
- const client = getSabClient();
76
+ const fs = getFs();
75
77
  const recursive = (options === null || options === void 0 ? void 0 : options.recursive) || false;
76
- const payload = JSON.stringify({ path: resolvePath(path), recursive });
77
- client.call(sabcom.SAB_OP_RMDIR, payload);
78
+ fs.removeDirSync(resolvePath(path), recursive);
78
79
  }
79
80
  export function copyFileSync(src, dst) {
80
- const client = getSabClient();
81
- const payload = JSON.stringify({
82
- src: resolvePath(src),
83
- dst: resolvePath(dst),
84
- });
85
- client.call(sabcom.SAB_OP_COPY_FILE, payload);
81
+ const fs = getFs();
82
+ fs.copyFileSync(resolvePath(src), resolvePath(dst));
86
83
  }
87
84
  export function statSync(p) {
88
- const client = getSabClient();
89
- const struct = client.callStat(resolvePath(p));
85
+ const fs = getFs();
86
+ const metadata = fs.metadataSync(resolvePath(p));
87
+ let type, size;
88
+ // @ts-ignore
89
+ if (typeof metadata.toJSON === "function") {
90
+ // @ts-ignore
91
+ const json = metadata.toJSON();
92
+ type = json.type;
93
+ size = json.file_size;
94
+ }
95
+ else {
96
+ // @ts-ignore
97
+ type = metadata.type;
98
+ // @ts-ignore
99
+ size = metadata.file_size;
100
+ }
90
101
  return new Stats({
91
- type: struct.type === sabcom.STAT_TYPE_DIR ? "directory" : "file",
92
- size: Number(struct.size),
93
- atimeMs: struct.atimeMs,
94
- mtimeMs: struct.mtimeMs,
95
- ctimeMs: struct.ctimeMs,
96
- birthtimeMs: struct.birthtimeMs,
102
+ type: type === "directory" ? "directory" : "file",
103
+ size: Number(size || 0),
104
+ atimeMs: Date.now(),
105
+ mtimeMs: Date.now(),
106
+ ctimeMs: Date.now(),
107
+ birthtimeMs: Date.now(),
97
108
  });
98
109
  }
99
110
  export function lstatSync(p) {
@@ -8,5 +8,4 @@ export interface LoaderRunnerMeta {
8
8
  importMaps: Record<string, string>;
9
9
  entrypoint: string;
10
10
  };
11
- sab?: SharedArrayBuffer;
12
11
  }
@@ -1,4 +1,3 @@
1
- import { SabComClient } from "../utils/sabcom";
2
1
  import initWasm, { Project, recvTaskMessageInWorker, sendTaskMessage, workerCreated, } from "../utoo";
3
2
  import { cjs } from "./cjs";
4
3
  const binding = {
@@ -13,11 +12,6 @@ export function startLoaderWorker() {
13
12
  console.log(err);
14
13
  throw err;
15
14
  });
16
- const sabClient = meta.sab
17
- ? new SabComClient(meta.sab, () => {
18
- self.postMessage("sab_request");
19
- })
20
- : undefined;
21
15
  // Initialize the thread-local state (tokio runtime).
22
16
  // We don't need to pass threadWorkerUrl here because it's already stored in a global static in Rust.
23
17
  Project.init("");
@@ -27,7 +21,6 @@ export function startLoaderWorker() {
27
21
  cwd: meta.workerData.cwd,
28
22
  projectRoot: meta.workerData.projectRoot,
29
23
  binding,
30
- sabClient,
31
24
  fs: Project,
32
25
  };
33
26
  self.process = {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@utoo/web",
3
- "version": "1.2.0-rc.9",
3
+ "version": "1.2.1",
4
4
  "module": "esm/index.js",
5
5
  "types": "esm/index.d.ts",
6
6
  "files": [
7
- "esm/*"
7
+ "esm"
8
8
  ],
9
9
  "scripts": {
10
- "install-toolchain": "cargo install wasm-bindgen-cli@0.2.104 && brew install binaryen",
10
+ "install-toolchain": "cargo install wasm-bindgen-cli@0.2.106 && brew install binaryen llvm",
11
11
  "build-wasm": "cargo build -p utoo-wasm --target wasm32-unknown-unknown -Z build-std=panic_abort,std",
12
12
  "build-wasm:pm": "cargo build -p utoo-wasm --target wasm32-unknown-unknown --no-default-features -Z build-std=panic_abort,std",
13
13
  "bindgen-dev": "wasm-bindgen ../../target/wasm32-unknown-unknown/wasm-dev/utoo_wasm.wasm --out-dir src/utoo --out-name index --target web --debug --keep-debug --no-demangle",
@@ -18,15 +18,15 @@
18
18
  "build:shared": "npx turbo run build --filter=@utoo/pack-shared",
19
19
  "dev": "npm run build-wasm -- --profile wasm-dev && npm run bindgen-dev && npx turbo run tsc --filter=@utoo/web && npm run build-loaderWorker && npm run copy-wasm",
20
20
  "dev:pm": "npm run build-wasm:pm -- --profile wasm-dev && npm run bindgen-dev && npm run tsc && npm run copy-wasm",
21
- "wasm-opt": "wasm-opt src/utoo/index_bg.wasm -o esm/utoo/index_bg.wasm --enable-threads --enable-bulk-memory --enable-nontrapping-float-to-int -Oz",
21
+ "wasm-opt": "wasm-opt src/utoo/index_bg.wasm -o esm/utoo/index_bg.wasm --enable-threads --enable-bulk-memory --enable-reference-types --enable-simd --enable-exception-handling --enable-tail-call --enable-nontrapping-float-to-int -Oz",
22
22
  "build": "npm run build-wasm -- --release && npm run bindgen-build && npm run tsc && npm run build-loaderWorker && npm run wasm-opt",
23
- "build:local": "npm run build-wasm -- --profile release-local && npm run bindgen-build:local && npm run build:shared && npm run tsc && npm run build-loaderWorker && npm run copy-wasm",
23
+ "build:local": "CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ npm run build-wasm -- --profile release-local && npm run bindgen-build:local && npm run build:shared && npm run tsc && npm run build-loaderWorker && npm run copy-wasm",
24
24
  "build-loaderWorker": "node cli/umd.js -e ./src/webpackLoaders/worker.ts -o ./esm/loaderWorker.js -t webworker",
25
25
  "clean": "rm -rf esm src/utoo",
26
26
  "prepublishOnly": "turbo run build --filter=@utoo/web"
27
27
  },
28
28
  "dependencies": {
29
- "@utoo/pack-shared": "^0.0.7",
29
+ "@utoo/pack-shared": "^1.1.12",
30
30
  "comlink": "^4.4.2",
31
31
  "systemjs": "^6.15.1"
32
32
  },
Binary file
@@ -1,61 +0,0 @@
1
- export declare const SAB_STATE_IDLE = 0;
2
- export declare const SAB_STATE_REQUEST = 1;
3
- export declare const SAB_STATE_RESPONSE = 2;
4
- export declare const SAB_STATE_ERROR = 3;
5
- export declare const SAB_OP_READ_FILE = 1;
6
- export declare const SAB_OP_READ_DIR = 2;
7
- export declare const SAB_OP_WRITE_FILE = 3;
8
- export declare const SAB_OP_MKDIR = 4;
9
- export declare const SAB_OP_RM = 5;
10
- export declare const SAB_OP_RMDIR = 6;
11
- export declare const SAB_OP_COPY_FILE = 7;
12
- export declare const SAB_OP_STAT = 8;
13
- export declare const STAT_TYPE_FILE = 0;
14
- export declare const STAT_TYPE_DIR = 1;
15
- export declare const SAB_INDEX_STATE = 0;
16
- export declare const SAB_INDEX_OP = 1;
17
- export declare const SAB_INDEX_DATA_LEN = 2;
18
- export declare const SAB_DATA_OFFSET = 12;
19
- export declare class SabComHost {
20
- private sab;
21
- private int32;
22
- private uint8;
23
- private dataView;
24
- constructor(sab: SharedArrayBuffer);
25
- readRequest(): {
26
- op: number;
27
- data: string;
28
- };
29
- writeResponse(data: Uint8Array | string): void;
30
- writeError(message: string): void;
31
- writeStat(type: number, size: bigint, atimeMs: number, mtimeMs: number, ctimeMs: number, birthtimeMs: number): void;
32
- }
33
- export declare class SabComClient {
34
- private sab;
35
- private notifyHost;
36
- private int32;
37
- private uint8;
38
- private dataView;
39
- constructor(sab: SharedArrayBuffer, notifyHost: () => void);
40
- call(op: number, data: string): Uint8Array<ArrayBuffer>;
41
- callStat(path: string): {
42
- type: number;
43
- size: bigint;
44
- atimeMs: number;
45
- mtimeMs: number;
46
- ctimeMs: number;
47
- birthtimeMs: number;
48
- };
49
- }
50
- export interface SabFileSystem {
51
- read(path: string): Promise<Uint8Array>;
52
- readDir(path: string): Promise<any[]>;
53
- writeString(path: string, content: string): Promise<void>;
54
- createDirAll(path: string): Promise<void>;
55
- createDir(path: string): Promise<void>;
56
- metadata(path: string): Promise<any>;
57
- removeFile(path: string): Promise<void>;
58
- removeDir(path: string, recursive: boolean): Promise<void>;
59
- copyFile(src: string, dst: string): Promise<void>;
60
- }
61
- export declare const handleSabRequest: (sabHost: SabComHost, fs: SabFileSystem) => Promise<void>;
@@ -1,203 +0,0 @@
1
- export const SAB_STATE_IDLE = 0;
2
- export const SAB_STATE_REQUEST = 1;
3
- export const SAB_STATE_RESPONSE = 2;
4
- export const SAB_STATE_ERROR = 3;
5
- export const SAB_OP_READ_FILE = 1;
6
- export const SAB_OP_READ_DIR = 2;
7
- export const SAB_OP_WRITE_FILE = 3;
8
- export const SAB_OP_MKDIR = 4;
9
- export const SAB_OP_RM = 5;
10
- export const SAB_OP_RMDIR = 6;
11
- export const SAB_OP_COPY_FILE = 7;
12
- export const SAB_OP_STAT = 8;
13
- export const STAT_TYPE_FILE = 0;
14
- export const STAT_TYPE_DIR = 1;
15
- export const SAB_INDEX_STATE = 0;
16
- export const SAB_INDEX_OP = 1;
17
- export const SAB_INDEX_DATA_LEN = 2;
18
- export const SAB_DATA_OFFSET = 12;
19
- // Stat struct layout (starts at byte 12)
20
- // type: Uint8 (1 byte) -> offset 0
21
- // padding: 7 bytes
22
- // size: BigUint64 (8 bytes) -> offset 8
23
- // atimeMs: Float64 (8 bytes) -> offset 16
24
- // mtimeMs: Float64 (8 bytes) -> offset 24
25
- // ctimeMs: Float64 (8 bytes) -> offset 32
26
- // birthtimeMs: Float64 (8 bytes) -> offset 40
27
- const STAT_OFFSET_TYPE = 0;
28
- const STAT_OFFSET_SIZE = 8;
29
- const STAT_OFFSET_ATIME = 16;
30
- const STAT_OFFSET_MTIME = 24;
31
- const STAT_OFFSET_CTIME = 32;
32
- const STAT_OFFSET_BIRTHTIME = 40;
33
- // Layout:
34
- // 0: State (Int32)
35
- // 1: Op (Int32)
36
- // 2: Data Length (Int32)
37
- // 12...: Data (Uint8) - Start at byte 12 (3 * 4 bytes)
38
- export class SabComHost {
39
- constructor(sab) {
40
- this.sab = sab;
41
- this.int32 = new Int32Array(sab);
42
- this.uint8 = new Uint8Array(sab);
43
- this.dataView = new DataView(sab);
44
- }
45
- readRequest() {
46
- const op = this.int32[SAB_INDEX_OP];
47
- const len = this.int32[SAB_INDEX_DATA_LEN];
48
- const data = new TextDecoder().decode(this.uint8.slice(SAB_DATA_OFFSET, SAB_DATA_OFFSET + len));
49
- return { op, data };
50
- }
51
- writeResponse(data) {
52
- if (typeof data === "string") {
53
- data = new TextEncoder().encode(data);
54
- }
55
- // TODO: Check size overflow
56
- this.int32[SAB_INDEX_DATA_LEN] = data.length;
57
- this.uint8.set(data, SAB_DATA_OFFSET);
58
- Atomics.store(this.int32, SAB_INDEX_STATE, SAB_STATE_RESPONSE);
59
- Atomics.notify(this.int32, SAB_INDEX_STATE);
60
- }
61
- writeError(message) {
62
- const data = new TextEncoder().encode(message);
63
- this.int32[SAB_INDEX_DATA_LEN] = data.length;
64
- this.uint8.set(data, SAB_DATA_OFFSET);
65
- Atomics.store(this.int32, SAB_INDEX_STATE, SAB_STATE_ERROR);
66
- Atomics.notify(this.int32, SAB_INDEX_STATE);
67
- }
68
- writeStat(type, size, atimeMs, mtimeMs, ctimeMs, birthtimeMs) {
69
- const base = SAB_DATA_OFFSET;
70
- this.dataView.setUint8(base + STAT_OFFSET_TYPE, type);
71
- this.dataView.setBigUint64(base + STAT_OFFSET_SIZE, size, true);
72
- this.dataView.setFloat64(base + STAT_OFFSET_ATIME, atimeMs, true);
73
- this.dataView.setFloat64(base + STAT_OFFSET_MTIME, mtimeMs, true);
74
- this.dataView.setFloat64(base + STAT_OFFSET_CTIME, ctimeMs, true);
75
- this.dataView.setFloat64(base + STAT_OFFSET_BIRTHTIME, birthtimeMs, true);
76
- Atomics.store(this.int32, SAB_INDEX_STATE, SAB_STATE_RESPONSE);
77
- Atomics.notify(this.int32, SAB_INDEX_STATE);
78
- }
79
- }
80
- export class SabComClient {
81
- constructor(sab, notifyHost) {
82
- this.sab = sab;
83
- this.notifyHost = notifyHost;
84
- this.int32 = new Int32Array(sab);
85
- this.uint8 = new Uint8Array(sab);
86
- this.dataView = new DataView(sab);
87
- }
88
- call(op, data) {
89
- const encoded = new TextEncoder().encode(data);
90
- this.int32[SAB_INDEX_OP] = op;
91
- this.int32[SAB_INDEX_DATA_LEN] = encoded.length;
92
- this.uint8.set(encoded, SAB_DATA_OFFSET);
93
- Atomics.store(this.int32, SAB_INDEX_STATE, SAB_STATE_REQUEST);
94
- this.notifyHost();
95
- Atomics.wait(this.int32, SAB_INDEX_STATE, SAB_STATE_REQUEST);
96
- const state = Atomics.load(this.int32, SAB_INDEX_STATE);
97
- if (state === SAB_STATE_ERROR) {
98
- const len = this.int32[SAB_INDEX_DATA_LEN];
99
- const msg = new TextDecoder().decode(this.uint8.slice(SAB_DATA_OFFSET, SAB_DATA_OFFSET + len));
100
- throw new Error(msg);
101
- }
102
- const len = this.int32[SAB_INDEX_DATA_LEN];
103
- return this.uint8.slice(SAB_DATA_OFFSET, SAB_DATA_OFFSET + len);
104
- }
105
- callStat(path) {
106
- const encoded = new TextEncoder().encode(path);
107
- this.int32[SAB_INDEX_OP] = SAB_OP_STAT;
108
- this.int32[SAB_INDEX_DATA_LEN] = encoded.length;
109
- this.uint8.set(encoded, SAB_DATA_OFFSET);
110
- Atomics.store(this.int32, SAB_INDEX_STATE, SAB_STATE_REQUEST);
111
- this.notifyHost();
112
- Atomics.wait(this.int32, SAB_INDEX_STATE, SAB_STATE_REQUEST);
113
- const state = Atomics.load(this.int32, SAB_INDEX_STATE);
114
- if (state === SAB_STATE_ERROR) {
115
- const len = this.int32[SAB_INDEX_DATA_LEN];
116
- const msg = new TextDecoder().decode(this.uint8.slice(SAB_DATA_OFFSET, SAB_DATA_OFFSET + len));
117
- throw new Error(msg);
118
- }
119
- const base = SAB_DATA_OFFSET;
120
- return {
121
- type: this.dataView.getUint8(base + STAT_OFFSET_TYPE),
122
- size: this.dataView.getBigUint64(base + STAT_OFFSET_SIZE, true),
123
- atimeMs: this.dataView.getFloat64(base + STAT_OFFSET_ATIME, true),
124
- mtimeMs: this.dataView.getFloat64(base + STAT_OFFSET_MTIME, true),
125
- ctimeMs: this.dataView.getFloat64(base + STAT_OFFSET_CTIME, true),
126
- birthtimeMs: this.dataView.getFloat64(base + STAT_OFFSET_BIRTHTIME, true),
127
- };
128
- }
129
- }
130
- export const handleSabRequest = async (sabHost, fs) => {
131
- const { op, data: path } = sabHost.readRequest();
132
- try {
133
- if (op === SAB_OP_READ_FILE) {
134
- const bytes = await fs.read(path);
135
- sabHost.writeResponse(bytes);
136
- }
137
- else if (op === SAB_OP_READ_DIR) {
138
- const entries = await fs.readDir(path);
139
- sabHost.writeResponse(JSON.stringify(entries.map((e) => e.toJSON())));
140
- }
141
- else if (op === SAB_OP_WRITE_FILE) {
142
- const { path: filePath, data: fileContent } = JSON.parse(path);
143
- // TODO: handle binary content (base64?)
144
- await fs.writeString(filePath, fileContent);
145
- sabHost.writeResponse("ok");
146
- }
147
- else if (op === SAB_OP_MKDIR) {
148
- const { path: dirPath, recursive } = JSON.parse(path);
149
- if (recursive) {
150
- await fs.createDirAll(dirPath);
151
- }
152
- else {
153
- await fs.createDir(dirPath);
154
- }
155
- sabHost.writeResponse("ok");
156
- }
157
- else if (op === SAB_OP_RM) {
158
- const { path: rmPath, recursive } = JSON.parse(path);
159
- // Mimic internalProject.rm logic
160
- const metadata = await fs.metadata(rmPath);
161
- const json = metadata.toJSON
162
- ? metadata.toJSON()
163
- : metadata;
164
- const type = json.type;
165
- if (type === "file") {
166
- await fs.removeFile(rmPath);
167
- }
168
- else if (type === "directory") {
169
- await fs.removeDir(rmPath, !!recursive);
170
- }
171
- sabHost.writeResponse("ok");
172
- }
173
- else if (op === SAB_OP_RMDIR) {
174
- const { path: rmPath, recursive } = JSON.parse(path);
175
- await fs.removeDir(rmPath, !!recursive);
176
- sabHost.writeResponse("ok");
177
- }
178
- else if (op === SAB_OP_COPY_FILE) {
179
- const { src, dst } = JSON.parse(path);
180
- await fs.copyFile(src, dst);
181
- sabHost.writeResponse("ok");
182
- }
183
- else if (op === SAB_OP_STAT) {
184
- const metadata = await fs.metadata(path);
185
- const json = metadata.toJSON
186
- ? metadata.toJSON()
187
- : metadata;
188
- const type = json.type === "directory" ? STAT_TYPE_DIR : STAT_TYPE_FILE;
189
- const size = BigInt(json.file_size || 0);
190
- const atimeMs = Number(json.atimeMs || 0);
191
- const mtimeMs = Number(json.mtimeMs || 0);
192
- const ctimeMs = Number(json.ctimeMs || 0);
193
- const birthtimeMs = Number(json.birthtimeMs || 0);
194
- sabHost.writeStat(type, size, atimeMs, mtimeMs, ctimeMs, birthtimeMs);
195
- }
196
- else {
197
- sabHost.writeError("Unknown op");
198
- }
199
- }
200
- catch (e) {
201
- sabHost.writeError(e.message);
202
- }
203
- };