diff --git a/.gitmodules b/.gitmodules
index c9f05a1..2d9d707 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,3 +5,7 @@
path = test/wasi-testsuite
url = https://github.com/WebAssembly/wasi-testsuite
branch = prod/testsuite-base
+[submodule "examples/wasi_multi_threads_rustc/rust_wasm"]
+ path = examples/wasi_multi_threads_rustc/rust_wasm
+ url = https://github.com/oligamiq/rust_wasm
+ sharrow = true
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..ce072c8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "editor.tabSize": 2
+}
diff --git a/examples/package-lock.json b/examples/package-lock.json
index 9dd8988..d01cb3c 100644
--- a/examples/package-lock.json
+++ b/examples/package-lock.json
@@ -1,43 +1,53 @@
{
- "name": "browser_wasi_shim_examples",
- "version": "0.0.0",
- "lockfileVersion": 2,
- "requires": true,
- "packages": {
- "": {
- "name": "browser_wasi_shim_examples",
- "version": "0.0.0",
- "license": "MIT OR Apache-2.0",
- "dependencies": {
- "xterm": "^4.18.0",
- "xterm-addon-fit": "^0.5.0"
- }
- },
- "node_modules/xterm": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.18.0.tgz",
- "integrity": "sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ=="
- },
- "node_modules/xterm-addon-fit": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz",
- "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==",
- "peerDependencies": {
- "xterm": "^4.0.0"
- }
- }
- },
- "dependencies": {
- "xterm": {
- "version": "4.18.0",
- "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.18.0.tgz",
- "integrity": "sha512-JQoc1S0dti6SQfI0bK1AZvGnAxH4MVw45ZPFSO6FHTInAiau3Ix77fSxNx3mX4eh9OL4AYa8+4C8f5UvnSfppQ=="
- },
- "xterm-addon-fit": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz",
- "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==",
- "requires": {}
- }
- }
+ "name": "browser_wasi_shim_examples",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "browser_wasi_shim_examples",
+ "version": "0.0.0",
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@oligami/shared-object": "^0.1.1",
+ "browser_wasi_shim_examples": "file:",
+ "xterm": "^4.18.0",
+ "xterm-addon-fit": "^0.5.0"
+ }
+ },
+ "node_modules/@oligami/shared-object": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@oligami/shared-object/-/shared-object-0.1.1.tgz",
+ "integrity": "sha512-1N5k8IL+JjD0lPiLR+NXT7BFzvnlPaBioMry9RZOL+4YI54TpW4fmkgys9rlyVo4hZB0DL5t8pgzXxq+IIO7fg==",
+ "license": "MIT",
+ "dependencies": {
+ "shared-object": "file:"
+ }
+ },
+ "node_modules/browser_wasi_shim_examples": {
+ "resolved": "",
+ "link": true
+ },
+ "node_modules/shared-object": {
+ "resolved": "node_modules/@oligami/shared-object",
+ "link": true
+ },
+ "node_modules/xterm": {
+ "version": "4.19.0",
+ "resolved": "https://registry.npmjs.org/xterm/-/xterm-4.19.0.tgz",
+ "integrity": "sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==",
+ "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
+ "license": "MIT"
+ },
+ "node_modules/xterm-addon-fit": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz",
+ "integrity": "sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==",
+ "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
+ "license": "MIT",
+ "peerDependencies": {
+ "xterm": "^4.0.0"
+ }
+ }
+ }
}
diff --git a/examples/package.json b/examples/package.json
index cd22ce6..e06354d 100644
--- a/examples/package.json
+++ b/examples/package.json
@@ -1,20 +1,22 @@
{
- "name": "browser_wasi_shim_examples",
- "publish": false,
- "version": "0.0.0",
- "license": "MIT OR Apache-2.0",
- "description": "",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bjorn3/browser_wasi_shim.git"
- },
- "author": "bjorn3",
- "bugs": {
- "url": "https://github.com/bjorn3/browser_wasi_shim/issues"
- },
- "homepage": "https://github.com/bjorn3/browser_wasi_shim#readme",
- "dependencies": {
- "xterm": "^4.18.0",
- "xterm-addon-fit": "^0.5.0"
- }
+ "name": "browser_wasi_shim_examples",
+ "publish": false,
+ "version": "0.0.0",
+ "license": "MIT OR Apache-2.0",
+ "description": "",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/bjorn3/browser_wasi_shim.git"
+ },
+ "author": "bjorn3",
+ "bugs": {
+ "url": "https://github.com/bjorn3/browser_wasi_shim/issues"
+ },
+ "homepage": "https://github.com/bjorn3/browser_wasi_shim#readme",
+ "dependencies": {
+ "@oligami/shared-object": "^0.1.1",
+ "browser_wasi_shim_examples": "file:",
+ "xterm": "^4.18.0",
+ "xterm-addon-fit": "^0.5.0"
+ }
}
diff --git a/examples/wasi_multi_threads/index.html b/examples/wasi_multi_threads/index.html
new file mode 100644
index 0000000..c3ae7e3
--- /dev/null
+++ b/examples/wasi_multi_threads/index.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/examples/wasi_multi_threads/main.rs b/examples/wasi_multi_threads/main.rs
new file mode 100644
index 0000000..86d14dd
--- /dev/null
+++ b/examples/wasi_multi_threads/main.rs
@@ -0,0 +1,13 @@
+fn main() {
+ println!("Hello, world!");
+
+ let _: std::thread::JoinHandle<()> = std::thread::spawn(|| {
+ for i in 1..1000 {
+ println!("hi number {} from the spawned thread!", i);
+ }
+ });
+
+ for i in 1..1000 {
+ println!("hi number {} from the main thread!", i);
+ }
+}
diff --git a/examples/wasi_multi_threads/multi_thread_echo.wasm b/examples/wasi_multi_threads/multi_thread_echo.wasm
new file mode 100644
index 0000000..894878b
Binary files /dev/null and b/examples/wasi_multi_threads/multi_thread_echo.wasm differ
diff --git a/examples/wasi_multi_threads/thread_spawn.js b/examples/wasi_multi_threads/thread_spawn.js
new file mode 100644
index 0000000..3761fb9
--- /dev/null
+++ b/examples/wasi_multi_threads/thread_spawn.js
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../dist/wasi_farm/shared_array_buffer/thread_spawn.js";
+
+self.onmessage = (event) => {
+ thread_spawn_on_worker(event.data);
+}
diff --git a/examples/wasi_multi_threads/worker.js b/examples/wasi_multi_threads/worker.js
new file mode 100644
index 0000000..913a976
--- /dev/null
+++ b/examples/wasi_multi_threads/worker.js
@@ -0,0 +1,32 @@
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+self.onmessage = async (e) => {
+ const { wasi_ref } = e.data;
+
+ const wasm = await WebAssembly.compileStreaming(fetch("./multi_thread_echo.wasm"));
+
+ const wasi = new WASIFarmAnimal(
+ wasi_ref,
+ [], // args
+ [], // env
+ {
+ debug: true,
+ can_thread_spawn: true,
+ thread_spawn_worker_url: (new URL("./thread_spawn.js", import.meta.url)).href,
+ // thread_spawn_worker_url: "./thread_spawn.js",
+ thread_spawn_wasm: wasm,
+ }
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ let inst = await WebAssembly.instantiate(wasm, {
+ "env": {
+ memory: wasi.get_share_memory(),
+ },
+ "wasi": wasi.wasiThreadImport,
+ "wasi_snapshot_preview1": wasi.wasiImport,
+ });
+
+ wasi.start(inst);
+}
diff --git a/examples/wasi_multi_threads_channel/channel.wasm b/examples/wasi_multi_threads_channel/channel.wasm
new file mode 100644
index 0000000..369c3b5
Binary files /dev/null and b/examples/wasi_multi_threads_channel/channel.wasm differ
diff --git a/examples/wasi_multi_threads_channel/index.html b/examples/wasi_multi_threads_channel/index.html
new file mode 100644
index 0000000..44539a0
--- /dev/null
+++ b/examples/wasi_multi_threads_channel/index.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/examples/wasi_multi_threads_channel/main.rs b/examples/wasi_multi_threads_channel/main.rs
new file mode 100644
index 0000000..216800c
--- /dev/null
+++ b/examples/wasi_multi_threads_channel/main.rs
@@ -0,0 +1,16 @@
+// https://doc.rust-lang.org/book/ch16-02-message-passing.html
+
+use std::sync::mpsc;
+use std::thread;
+
+fn main() {
+ let (tx, rx) = mpsc::channel();
+
+ thread::spawn(move || {
+ let val = String::from("hi");
+ tx.send(val).unwrap();
+ });
+
+ let received = rx.recv().unwrap();
+ println!("Got: {received}");
+}
diff --git a/examples/wasi_multi_threads_channel/thread_spawn.js b/examples/wasi_multi_threads_channel/thread_spawn.js
new file mode 100644
index 0000000..3761fb9
--- /dev/null
+++ b/examples/wasi_multi_threads_channel/thread_spawn.js
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../dist/wasi_farm/shared_array_buffer/thread_spawn.js";
+
+self.onmessage = (event) => {
+ thread_spawn_on_worker(event.data);
+}
diff --git a/examples/wasi_multi_threads_channel/worker.js b/examples/wasi_multi_threads_channel/worker.js
new file mode 100644
index 0000000..c91ecb4
--- /dev/null
+++ b/examples/wasi_multi_threads_channel/worker.js
@@ -0,0 +1,32 @@
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+self.onmessage = async (e) => {
+ const { wasi_ref } = e.data;
+
+ const wasm = await WebAssembly.compileStreaming(fetch("./channel.wasm"));
+
+ const wasi = new WASIFarmAnimal(
+ wasi_ref,
+ [], // args
+ [], // env
+ {
+ debug: true,
+ can_thread_spawn: true,
+ thread_spawn_worker_url: (new URL("./thread_spawn.js", import.meta.url)).href,
+ // thread_spawn_worker_url: "./thread_spawn.js",
+ thread_spawn_wasm: wasm,
+ }
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ let inst = await WebAssembly.instantiate(wasm, {
+ "env": {
+ memory: wasi.get_share_memory(),
+ },
+ "wasi": wasi.wasiThreadImport,
+ "wasi_snapshot_preview1": wasi.wasiImport,
+ });
+
+ wasi.start(inst);
+}
diff --git a/examples/wasi_multi_threads_rustc/cargo.js b/examples/wasi_multi_threads_rustc/cargo.js
new file mode 100644
index 0000000..b55ea3d
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/cargo.js
@@ -0,0 +1,58 @@
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let wasm;
+let shared;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(
+ fetch("./rust_wasm/rustc_llvm_with_lld/cargo_opt.wasm"),
+ );
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ [], // args
+ [
+ "RUST_MIN_STACK=16777216",
+ "HOME=/home/wasi",
+ "RUST_LOG=debug",
+ "RUST_BACKTRACE=full",
+ // This is made up of forced patches. Usually not available.
+ "RUSTC_SYSROOT=/sysroot-with-lld",
+ "RUSTFLAGS=",
+ ], // env
+ {
+ // debug: true,
+ can_thread_spawn: true,
+ thread_spawn_worker_url: new URL("./thread_spawn.js", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.js",
+ thread_spawn_wasm: wasm,
+ extend_imports: true,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ wasi.get_share_memory().grow(200);
+
+ console.log("Waiting for worker background worker...");
+
+ await promise;
+
+ shared = new SharedObject.SharedObject((...args) => {
+ console.log("wasi.start");
+ wasi.args = ["cargo", ...args];
+ wasi.block_start_on_thread();
+ console.log("wasi.start done");
+ }, "cargo");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/cat.js b/examples/wasi_multi_threads_rustc/cat.js
new file mode 100644
index 0000000..fdd91d1
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/cat.js
@@ -0,0 +1,47 @@
+import { strace, WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let inst;
+let wasm;
+
+let shared;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(fetch("./cat.wasm"));
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ ["cat"], // args
+ [], // env
+ {
+ debug: false,
+ },
+ );
+
+ // Memory is rewritten at this time.
+ inst = await WebAssembly.instantiate(wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ await promise;
+
+ const memory_reset = inst.exports.memory.buffer;
+ const memory_reset_view = new Uint8Array(memory_reset).slice();
+
+ shared = new SharedObject.SharedObject((...args) => {
+ // If I don't reset memory, I get some kind of error.
+ wasi.args = ["cat", ...args];
+ const memory_view = new Uint8Array(inst.exports.memory.buffer);
+ memory_view.set(memory_reset_view);
+ wasi.start(inst);
+ }, "cat");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/cat.rs b/examples/wasi_multi_threads_rustc/cat.rs
new file mode 100644
index 0000000..147cb14
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/cat.rs
@@ -0,0 +1,20 @@
+// cat alt
+
+use std::io::BufRead;
+
+pub fn main() {
+ let args: Vec = std::env::args().collect();
+ if args.len() < 2 {
+ eprintln!("Usage: {} ", args[0]);
+ std::process::exit(1);
+ }
+
+ let path = &args[1];
+ let file = std::fs::File::open(path).unwrap();
+ let reader = std::io::BufReader::new(file);
+ for line in reader.lines() {
+ println!("{}", line.unwrap());
+ }
+}
+
+// rustc cat.rs --target=wasm32-wasip1
diff --git a/examples/wasi_multi_threads_rustc/cat.wasm b/examples/wasi_multi_threads_rustc/cat.wasm
new file mode 100644
index 0000000..3278929
Binary files /dev/null and b/examples/wasi_multi_threads_rustc/cat.wasm differ
diff --git a/examples/wasi_multi_threads_rustc/clang.js b/examples/wasi_multi_threads_rustc/clang.js
new file mode 100644
index 0000000..e306138
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/clang.js
@@ -0,0 +1,78 @@
+import { strace, WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let inst;
+let wasm;
+
+let shared_clang;
+let shared_tools;
+let shared_wasm_ld;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(
+ fetch("./rust_wasm/llvm-tools/llvm-opt.wasm"),
+ );
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ ["llvm"], // args
+ [], // env
+ {
+ debug: false,
+ },
+ );
+
+ // Memory is rewritten at this time.
+ // inst = await WebAssembly.instantiate(wasm, {
+ // wasi_snapshot_preview1: wasi.wasiImport,
+ // });
+ inst = await WebAssembly.instantiate(wasm, {
+ wasi_snapshot_preview1: strace(wasi.wasiImport, []),
+ });
+
+ console.log("wasi.start, inst", inst);
+
+ await promise;
+
+ const memory_reset = inst.exports.memory.buffer;
+ const memory_reset_view = new Uint8Array(memory_reset).slice();
+
+ shared_clang = new SharedObject.SharedObject((...args) => {
+ console.log("clang args", args);
+ // If I don't reset memory, I get some kind of error.
+ wasi.args = ["llvm", "clang", ...args];
+ const memory_view = new Uint8Array(inst.exports.memory.buffer);
+ memory_view.set(memory_reset_view);
+ wasi.start(inst);
+ console.log("clang wasi.start done");
+ }, "clang");
+
+ shared_tools = new SharedObject.SharedObject((...args) => {
+ console.log("tools args", args);
+ // If I don't reset memory, I get some kind of error.
+ wasi.args = ["llvm-tools", ...args];
+ const memory_view = new Uint8Array(inst.exports.memory.buffer);
+ memory_view.set(memory_reset_view);
+ wasi.start(inst);
+ console.log("tools wasi.start done");
+ }, "llvm-tools");
+
+ shared_wasm_ld = new SharedObject.SharedObject((...args) => {
+ console.log("wasm-ld args", args);
+ // If I don't reset memory, I get some kind of error.
+ wasi.args = ["llvm-tools", "wasm-ld", ...args];
+ const memory_view = new Uint8Array(inst.exports.memory.buffer);
+ memory_view.set(memory_reset_view);
+ wasi.start(inst);
+ console.log("wasm-ld wasi.start done");
+ }, "wasm-ld");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/depend_clang_files.js b/examples/wasi_multi_threads_rustc/depend_clang_files.js
new file mode 100644
index 0000000..969c184
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/depend_clang_files.js
@@ -0,0 +1,80 @@
+import {
+ PreopenDirectory,
+ WASIFarm,
+ Directory,
+ File,
+} from "../../dist/index.js";
+
+async function load_external_file(path) {
+ return new File(await (await (await fetch(path)).blob()).arrayBuffer());
+}
+
+const wasi_libs = new Map();
+for (const file of [
+ "crt1-command.o",
+ "crt1-reactor.o",
+ "crt1.o",
+ "libc-printscan-long-double.a",
+ "libc-printscan-no-floating-point.a",
+ "libc.a",
+ "libc.imports",
+ "libc++.a",
+ "libc++.modules.json",
+ "libc++abi.a",
+ "libc++experimental.a",
+ "libcrypt.a",
+ "libdl.a",
+ "libm.a",
+ "libpthread.a",
+ "libresolv.a",
+ "librt.a",
+ "libsetjmp.a",
+ "libutil.a",
+ "libwasi-emulated-getpid.a",
+ "libwasi-emulated-mman.a",
+ "libwasi-emulated-process-clocks.a",
+ "libwasi-emulated-signal.a",
+ "libxnet.a",
+]) {
+ wasi_libs.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/llvm-tools/dist/lib/wasm32-wasip1/${file}`,
+ ),
+ );
+}
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory("/sysroot-clang", [
+ [
+ "lib",
+ new Directory([
+ [
+ "wasm32-unknown-wasip1",
+ new Directory([
+ [
+ "libclang_rt.builtins.a",
+ await load_external_file(
+ "./rust_wasm/llvm-tools/dist/lib/wasm32-unknown-wasip1/libclang_rt.builtins.a",
+ ),
+ ],
+ ]),
+ ],
+ ["wasm32-wasip1", wasi_libs],
+ ]),
+ ],
+ ]),
+ ],
+ {
+ // allocator_size: 1024 * 1024 * 1024,
+ // debug: true,
+ },
+);
+
+const ret = await farm.get_ref();
+
+postMessage({ wasi_ref: ret });
diff --git a/examples/wasi_multi_threads_rustc/depend_rustc_files.js b/examples/wasi_multi_threads_rustc/depend_rustc_files.js
new file mode 100644
index 0000000..b1ea3fe
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/depend_rustc_files.js
@@ -0,0 +1,154 @@
+import {
+ PreopenDirectory,
+ WASIFarm,
+ Directory,
+ File,
+} from "../../dist/index.js";
+
+async function load_external_file(path) {
+ return new File(await (await (await fetch(path)).blob()).arrayBuffer());
+}
+
+const linux_libs_promise = (async () => {
+ const dir = new Map();
+ for (const file of [
+ "libaddr2line-b8754aeb03c02354.rlib",
+ "libadler-05c3545f6cd12159.rlib",
+ "liballoc-0dab879bc41cd6bd.rlib",
+ "libcfg_if-c7fd2cef50341546.rlib",
+ "libcompiler_builtins-a99947d020d809d6.rlib",
+ "libcore-4b8e8a815d049db3.rlib",
+ "libgetopts-bbb75529e85d129d.rlib",
+ "libgimli-598847d27d7a3cbf.rlib",
+ "libhashbrown-d2ff91fdf93cacb2.rlib",
+ "liblibc-dc63949c664c3fce.rlib",
+ "libmemchr-2d3a423be1a6cb96.rlib",
+ "libminiz_oxide-b109506a0ccc4c6a.rlib",
+ "libobject-7b48def7544c748b.rlib",
+ "libpanic_abort-c93441899b93b849.rlib",
+ "libpanic_unwind-11d9ba05b60bf694.rlib",
+ "libproc_macro-1a7f7840bb9983dc.rlib",
+ "librustc_demangle-59342a335246393d.rlib",
+ "librustc_std_workspace_alloc-552b185085090ff6.rlib",
+ "librustc_std_workspace_core-5d8a121daa7eeaa9.rlib",
+ "librustc_std_workspace_std-97f43841ce452f7d.rlib",
+ "libstd-bdedb7706a556da2.rlib",
+ "libstd-bdedb7706a556da2.so",
+ "libstd_detect-cca21eebc4281add.rlib",
+ "libsysroot-f654e185be3ffebd.rlib",
+ "libtest-f06fa3fbc201c558.rlib",
+ "libunicode_width-19a0dcd589fa0877.rlib",
+ "libunwind-747b693f90af9445.rlib",
+ ]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm/dist/lib/rustlib/x86_64-unknown-linux-gnu/lib/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const threads_libs_promise = (async () => {
+ const dir = new Map();
+ for (const file of [
+ "libaddr2line-a47658bebc67c3a1.rlib",
+ "libadler-38ddbcf07afd45fc.rlib",
+ "liballoc-1fc4f6ca1d836e4c.rlib",
+ "libcfg_if-fd15f5d506df7899.rlib",
+ "libcompiler_builtins-3dc6223f56552b05.rlib",
+ "libcore-0ec7cb16e8553802.rlib",
+ "libgetopts-6248a91c42a854a0.rlib",
+ "libgimli-4425159eeeeb18dd.rlib",
+ "libhashbrown-243f98c4e4e641ea.rlib",
+ "liblibc-9149392e3841960d.rlib",
+ "libmemchr-9ac950afd37fa4c7.rlib",
+ "libminiz_oxide-91aaa0ee7402d39e.rlib",
+ "libobject-361b96ef5df8a7f9.rlib",
+ "libpanic_abort-f91052098501e46b.rlib",
+ "libpanic_unwind-fc376dcf47815f10.rlib",
+ "libproc_macro-9cab37e4d11f0e52.rlib",
+ "librustc_demangle-1af142f261139812.rlib",
+ "librustc_std_workspace_alloc-f0d62212c413dd0e.rlib",
+ "librustc_std_workspace_core-ea396731d16229a8.rlib",
+ "librustc_std_workspace_std-7434133be68a4a89.rlib",
+ "libstd_detect-083332b3c8180bc9.rlib",
+ "libstd-5ddf10249e9580fe.rlib",
+ "libsysroot-8b3608099dad3b42.rlib",
+ "libtest-8ebd431ae5608538.rlib",
+ "libunicode_width-7e2396fcd7049a8b.rlib",
+ "libunwind-e7408208cf4a3c79.rlib",
+ "libwasi-f0b9e157c50fe586.rlib",
+ ]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm/dist/lib/rustlib/wasm32-wasip1-threads/lib/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const threads_self_contained_promise = (async () => {
+ const dir = new Map();
+ for (const file of ["crt1-command.o", "crt1-reactor.o", "libc.a"]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm/dist/lib/rustlib/wasm32-wasip1-threads/lib/self-contained/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const [linux_libs, threads_libs, threads_self_contained, components] =
+ await Promise.all([
+ linux_libs_promise,
+ threads_libs_promise,
+ threads_self_contained_promise,
+ await load_external_file(
+ "./rust_wasm/rustc_llvm/dist/lib/rustlib/components",
+ ),
+ ]);
+
+threads_libs.set("self-contained", new Directory(threads_self_contained));
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory("/sysroot", [
+ [
+ "lib",
+ new Directory([
+ [
+ "rustlib",
+ new Directory([
+ ["components", components],
+ [
+ "wasm32-wasip1-threads",
+ new Directory([["lib", new Directory(threads_libs)]]),
+ ],
+ [
+ "x86_64-unknown-linux-gnu",
+ new Directory([["lib", new Directory(linux_libs)]]),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ {
+ allocator_size: 1024 * 1024 * 1024,
+ // debug: true,
+ },
+);
+
+const ret = await farm.get_ref();
+
+postMessage({ wasi_ref: ret });
diff --git a/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.js b/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.js
new file mode 100644
index 0000000..fb302ce
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.js
@@ -0,0 +1,154 @@
+import {
+ PreopenDirectory,
+ WASIFarm,
+ Directory,
+ File,
+} from "../../dist/index.js";
+
+async function load_external_file(path) {
+ return new File(await (await (await fetch(path)).blob()).arrayBuffer());
+}
+
+const linux_libs_promise = (async () => {
+ const dir = new Map();
+ for (const file of [
+ "libaddr2line-d2445d88f0df8258.rlib",
+ "libadler-6095b59b8443d84e.rlib",
+ "liballoc-19b196c8c1c1b105.rlib",
+ "libcfg_if-d04d665f43a7a5c9.rlib",
+ "libcompiler_builtins-f3e5bc67a3085e50.rlib",
+ "libcore-24518d8502db248c.rlib",
+ "libgetopts-4bb89b05e2b4cc6e.rlib",
+ "libgimli-85e2d283537da979.rlib",
+ "libhashbrown-1436b1713a4e6650.rlib",
+ "liblibc-a012fa771333437a.rlib",
+ "libmemchr-b50e0c33c9e9768d.rlib",
+ "libminiz_oxide-937a56bed56199f4.rlib",
+ "libobject-4e591f1863579f49.rlib",
+ "libpanic_abort-90cfe20cb97a5e4c.rlib",
+ "libpanic_unwind-9ad8c03a583f4dc7.rlib",
+ "libproc_macro-32b9efef039a24fe.rlib",
+ "librustc_demangle-ca292a161705fdb4.rlib",
+ "librustc_std_workspace_alloc-bba69521e853a996.rlib",
+ "librustc_std_workspace_core-3da34b7f5e59869a.rlib",
+ "librustc_std_workspace_std-c35ef78edc033606.rlib",
+ "libstd_detect-776a1ebea822ca12.rlib",
+ "libstd-6924b036e1bec7ce.rlib",
+ "libstd-6924b036e1bec7ce.so",
+ "libsysroot-0b7644c6027c414e.rlib",
+ "libtest-3d5766d8038a0e74.rlib",
+ "libunicode_width-dff2b02e7e936b79.rlib",
+ "libunwind-c99628283276f21f.rlib",
+ ]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm_with_lld/dist/lib/rustlib/x86_64-unknown-linux-gnu/lib/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const threads_libs_promise = (async () => {
+ const dir = new Map();
+ for (const file of [
+ "libaddr2line-02cc3b87379ea949.rlib",
+ "libgimli-a80bd3f5fe54def6.rlib",
+ "libpanic_unwind-05c50d12758b6d01.rlib",
+ "libstd_detect-a196185ed7f17cfc.rlib",
+ "libadler-a6b90b86640ec179.rlib",
+ "libhashbrown-35a68b834152af94.rlib",
+ "libproc_macro-2aa22b2ed111e644.rlib",
+ "libsysroot-856cc79af2fd1ee2.rlib",
+ "liballoc-be9b2b68a2d6adbd.rlib",
+ "liblibc-374b1b6cc5790f18.rlib",
+ "librustc_demangle-710d955f336192eb.rlib",
+ "libtest-4fcaddbdfa4f37f9.rlib",
+ "libcfg_if-75a956684c8aceef.rlib",
+ "libmemchr-b8580e949eadd97a.rlib",
+ "librustc_std_workspace_alloc-9c960f87e9d5a453.rlib",
+ "libunicode_width-be3becba43cd1b78.rlib",
+ "libcompiler_builtins-3a0795e4489d8e8b.rlib",
+ "libminiz_oxide-0bc4b046969a6755.rlib",
+ "librustc_std_workspace_core-4e237761d66d6cde.rlib",
+ "libunwind-2e570680d1c4cd0a.rlib",
+ "libcore-3e70038323b3a06e.rlib",
+ "libobject-3d83ea5d7ed5636f.rlib",
+ "librustc_std_workspace_std-5aa56e0a1970dc72.rlib",
+ "libwasi-f7d0229d2fe97cfd.rlib",
+ "libgetopts-b3d0219ad62c74a7.rlib",
+ "libpanic_abort-431cc2501a123c59.rlib",
+ "libstd-c7f97b33ddfcbfbf.rlib",
+ ]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm_with_lld/dist/lib/rustlib/wasm32-wasip1/lib/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const threads_self_contained_promise = (async () => {
+ const dir = new Map();
+ for (const file of ["crt1-command.o", "crt1-reactor.o", "libc.a"]) {
+ dir.set(
+ file,
+ await load_external_file(
+ `./rust_wasm/rustc_llvm_with_lld/dist/lib/rustlib/wasm32-wasip1/lib/self-contained/${file}`,
+ ),
+ );
+ }
+ return dir;
+})();
+
+const [linux_libs, threads_libs, threads_self_contained, components] =
+ await Promise.all([
+ linux_libs_promise,
+ threads_libs_promise,
+ threads_self_contained_promise,
+ await load_external_file(
+ "./rust_wasm/rustc_llvm_with_lld/dist/lib/rustlib/components",
+ ),
+ ]);
+
+threads_libs.set("self-contained", new Directory(threads_self_contained));
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory("/sysroot-with-lld", [
+ [
+ "lib",
+ new Directory([
+ [
+ "rustlib",
+ new Directory([
+ ["components", components],
+ [
+ "wasm32-wasip1",
+ new Directory([["lib", new Directory(threads_libs)]]),
+ ],
+ [
+ "x86_64-unknown-linux-gnu",
+ new Directory([["lib", new Directory(linux_libs)]]),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ {
+ allocator_size: 1024 * 1024 * 1024,
+ // debug: true,
+ },
+);
+
+const ret = await farm.get_ref();
+
+postMessage({ wasi_ref: ret });
diff --git a/examples/wasi_multi_threads_rustc/index.html b/examples/wasi_multi_threads_rustc/index.html
new file mode 100644
index 0000000..8883c82
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/index.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/wasi_multi_threads_rustc/rust_wasm b/examples/wasi_multi_threads_rustc/rust_wasm
new file mode 160000
index 0000000..bff31e3
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/rust_wasm
@@ -0,0 +1 @@
+Subproject commit bff31e3be735bcb22fef2a9e24a5143a872f6f23
diff --git a/examples/wasi_multi_threads_rustc/rustc.js b/examples/wasi_multi_threads_rustc/rustc.js
new file mode 100644
index 0000000..1dd1bf8
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/rustc.js
@@ -0,0 +1,48 @@
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let wasm;
+let shared;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(
+ fetch("./rust_wasm/rustc_llvm/rustc_opt.wasm"),
+ );
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ [], // args
+ ["RUST_MIN_STACK=16777216"], // env
+ {
+ // debug: true,
+ can_thread_spawn: true,
+ thread_spawn_worker_url: new URL("./thread_spawn.js", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.js",
+ thread_spawn_wasm: wasm,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ wasi.get_share_memory().grow(200);
+
+ console.log("Waiting for worker background worker...");
+
+ await promise;
+
+ shared = new SharedObject.SharedObject((...args) => {
+ wasi.args = ["rustc", ...args];
+ wasi.block_start_on_thread();
+ console.log("wasi.start done");
+ }, "rustc");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/rustc_with_lld.js b/examples/wasi_multi_threads_rustc/rustc_with_lld.js
new file mode 100644
index 0000000..58633d8
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/rustc_with_lld.js
@@ -0,0 +1,48 @@
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let wasm;
+let shared;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(
+ fetch("./rust_wasm/rustc_llvm_with_lld/rustc_opt.wasm"),
+ );
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ [], // args
+ ["RUST_MIN_STACK=16777216"], // env
+ {
+ // debug: true,
+ can_thread_spawn: true,
+ thread_spawn_worker_url: new URL("./thread_spawn.js", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.js",
+ thread_spawn_wasm: wasm,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ wasi.get_share_memory().grow(200);
+
+ console.log("Waiting for worker background worker...");
+
+ await promise;
+
+ shared = new SharedObject.SharedObject((...args) => {
+ wasi.args = ["rustc_with_lld", ...args];
+ wasi.block_start_on_thread();
+ console.log("wasi.start done");
+ }, "rustc_with_lld");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/save_stdout.js b/examples/wasi_multi_threads_rustc/save_stdout.js
new file mode 100644
index 0000000..4739ac3
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/save_stdout.js
@@ -0,0 +1,54 @@
+import { WASIFarm, Fd } from "../../dist/index.js";
+
+await import("../node_modules/@oligami/shared-object/dist/index.js");
+
+const term = new SharedObject.SharedObjectRef("term").proxy();
+
+class Stdout extends Fd {
+ buffer = new Uint8Array(0);
+
+ async fd_write(data /*: Uint8Array*/) /*: {ret: number, nwritten: number}*/ {
+ const new_buffer = new Uint8Array(this.buffer.length + data.length);
+ new_buffer.set(this.buffer);
+ new_buffer.set(data, this.buffer.length);
+ this.buffer = new_buffer;
+
+ await term.writeUtf8(data);
+
+ return { ret: 0, nwritten: data.byteLength };
+ }
+}
+
+const std_out = new Stdout();
+
+const std_err = new Stdout();
+
+const shared_std_out = new SharedObject.SharedObject(
+ {
+ get() {
+ return new TextDecoder().decode(std_out.buffer);
+ },
+ reset() {
+ std_out.buffer = new Uint8Array(0);
+ },
+ },
+ "std_out_keep",
+);
+
+const shared_std_err = new SharedObject.SharedObject(
+ {
+ get() {
+ return new TextDecoder().decode(std_err.buffer);
+ },
+ reset() {
+ std_err.buffer = new Uint8Array(0);
+ },
+ },
+ "std_err_keep",
+);
+
+const farm = new WASIFarm(undefined, std_out, std_err);
+
+const ret = await farm.get_ref();
+
+postMessage({ wasi_ref: ret });
diff --git a/examples/wasi_multi_threads_rustc/thread_spawn.js b/examples/wasi_multi_threads_rustc/thread_spawn.js
new file mode 100644
index 0000000..bed9b51
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/thread_spawn.js
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../dist/index.js";
+
+self.onmessage = async (event) => {
+ await thread_spawn_on_worker(event.data);
+};
diff --git a/examples/wasi_multi_threads_rustc/tmp_dir.js b/examples/wasi_multi_threads_rustc/tmp_dir.js
new file mode 100644
index 0000000..d243fff
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/tmp_dir.js
@@ -0,0 +1,84 @@
+import {
+ PreopenDirectory,
+ WASIFarm,
+ File,
+ Directory,
+} from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+const root_dir = new PreopenDirectory("/", [
+ [
+ "hello.rs",
+ new File(
+ new TextEncoder("utf-8").encode(
+ `fn main() { println!("Hello World!"); }`,
+ ),
+ ),
+ ],
+ ["sysroot", new Directory([])],
+ ["sysroot-with-lld", new Directory([])],
+ ["tmp", new Directory([])],
+]);
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ // new PreopenDirectory(".", [
+ // ["tmp-tmp", new File(new TextEncoder("utf-8").encode("Hello World!"))],
+ // ["tmp-dir", new Directory([])],
+ // ]),
+ // new PreopenDirectory("tmp-dir", [
+ // [
+ // "tmp-dir_inner",
+ // new Directory([
+ // [
+ // "tmp-dir_inner-file",
+ // new File(new TextEncoder("utf-8").encode("Hello World!!!!!")),
+ // ],
+ // ]),
+ // ],
+ // ]),
+ new PreopenDirectory("/tmp", []),
+ root_dir,
+ new PreopenDirectory("~", [
+ [
+ "####.rs",
+ new File(
+ new TextEncoder("utf-8").encode(
+ `fn main() { println!("Hello World!"); }`,
+ ),
+ ),
+ ],
+ ["sysroot", new Directory([])],
+ ]),
+ ],
+ // { debug: true },
+);
+
+const ret = await farm.get_ref();
+
+await promise;
+
+const shared = new SharedObject.SharedObject(
+ {
+ get_file(path_str) {
+ console.log(root_dir);
+ const path = {
+ parts: [path_str],
+ is_dir: false,
+ };
+ const { ret, entry } = root_dir.dir.get_entry_for_path(path);
+ if (ret !== 0) {
+ throw new Error(`get_file: ${path_str} failed`);
+ }
+ return entry.data;
+ },
+ },
+ "root_dir",
+);
+
+postMessage({ wasi_ref: ret });
diff --git a/examples/wasi_multi_threads_rustc/tre_opt.wasm b/examples/wasi_multi_threads_rustc/tre_opt.wasm
new file mode 100644
index 0000000..67f06df
Binary files /dev/null and b/examples/wasi_multi_threads_rustc/tre_opt.wasm differ
diff --git a/examples/wasi_multi_threads_rustc/tree.js b/examples/wasi_multi_threads_rustc/tree.js
new file mode 100644
index 0000000..a2bc7e0
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/tree.js
@@ -0,0 +1,47 @@
+import { strace, WASIFarmAnimal } from "../../dist/index.js";
+
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+
+let wasi;
+let inst;
+let wasm;
+
+let shared;
+
+onmessage = async function (e) {
+ const { wasi_refs } = e.data;
+
+ if (wasi_refs) {
+ wasm = await WebAssembly.compileStreaming(fetch("./tre_opt.wasm"));
+
+ wasi = new WASIFarmAnimal(
+ wasi_refs,
+ ["tre"], // args
+ [], // env
+ {
+ debug: false,
+ },
+ );
+
+ // Memory is rewritten at this time.
+ inst = await WebAssembly.instantiate(wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ await promise;
+
+ const memory_reset = inst.exports.memory.buffer;
+ const memory_reset_view = new Uint8Array(memory_reset).slice();
+
+ shared = new SharedObject.SharedObject((...args) => {
+ // If I don't reset memory, I get some kind of error.
+ wasi.args = ["tre", ...args];
+ const memory_view = new Uint8Array(inst.exports.memory.buffer);
+ memory_view.set(memory_reset_view);
+ wasi.start(inst);
+ }, "tree");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/examples/wasi_multi_threads_rustc/worker.js b/examples/wasi_multi_threads_rustc/worker.js
new file mode 100644
index 0000000..b0e11cf
--- /dev/null
+++ b/examples/wasi_multi_threads_rustc/worker.js
@@ -0,0 +1,415 @@
+const { promise, resolve } = Promise.withResolvers();
+import("../node_modules/@oligami/shared-object/dist/index.js").then(resolve);
+import { WASIFarmAnimal } from "../../dist/index.js";
+
+let tree;
+let term;
+let rustc;
+let rustc_with_lld;
+let clang;
+let llvm_tools;
+let wasm_ld;
+let cargo;
+let std_out_keep;
+let std_err_keep;
+let root_dir;
+let cat;
+
+const blueText = "\x1b[34m";
+const resetText = "\x1b[0m";
+
+self.onmessage = async (e) => {
+ const { wasi_ref } = e.data;
+
+ const {
+ promise: depend_rustc_files_promise,
+ resolve: depend_rustc_files_resolve,
+ } = Promise.withResolvers();
+ const {
+ promise: depend_rustc_with_lld_promise,
+ resolve: depend_rustc_with_lld_resolve,
+ } = Promise.withResolvers();
+ const {
+ promise: depend_clang_files_promise,
+ resolve: depend_clang_files_resolve,
+ } = Promise.withResolvers();
+ const { promise: tmp_dir_promise, resolve: tmp_dir_resolve } =
+ Promise.withResolvers();
+ const { promise: save_stdout_promise, resolve: save_stdout_resolve } =
+ Promise.withResolvers();
+
+ const depend_rustc_files_manage_worker = new Worker("depend_rustc_files.js", {
+ type: "module",
+ });
+ depend_rustc_files_manage_worker.onmessage = (e) => {
+ depend_rustc_files_resolve(e.data);
+ };
+
+ const depend_rustc_with_lld_manage_worker = new Worker(
+ "depend_rustc_with_lld.js",
+ {
+ type: "module",
+ },
+ );
+ depend_rustc_with_lld_manage_worker.onmessage = (e) => {
+ depend_rustc_with_lld_resolve(e.data);
+ };
+
+ const depend_clang_files_manage_worker = new Worker("depend_clang_files.js", {
+ type: "module",
+ });
+ depend_clang_files_manage_worker.onmessage = (e) => {
+ depend_clang_files_resolve(e.data);
+ };
+
+ const tmp_dir_manage_worker = new Worker("tmp_dir.js", {
+ type: "module",
+ });
+ tmp_dir_manage_worker.onmessage = (e) => {
+ tmp_dir_resolve(e.data);
+ };
+
+ const save_stdout_manage_worker = new Worker("save_stdout.js", {
+ type: "module",
+ });
+ save_stdout_manage_worker.onmessage = (e) => {
+ save_stdout_resolve(e.data);
+ };
+
+ const [
+ depend_rustc_files,
+ depend_rustc_with_lld,
+ depend_clang_files,
+ tmp_dir,
+ save_stdout,
+ ] = await Promise.all([
+ depend_rustc_files_promise,
+ depend_rustc_with_lld_promise,
+ depend_clang_files_promise,
+ tmp_dir_promise,
+ save_stdout_promise,
+ ]);
+ const { wasi_ref: wasi_ref_depend_rustc_files } = depend_rustc_files;
+ const { wasi_ref: wasi_ref_depend_rustc_with_lld_files } =
+ depend_rustc_with_lld;
+ const { wasi_ref: wasi_ref_depend_clang_files } = depend_clang_files;
+ const { wasi_ref: wasi_ref_tmp_dir } = tmp_dir;
+ const { wasi_ref: wasi_ref_save_stdout } = save_stdout;
+
+ const wasi_refs = [
+ wasi_ref_depend_rustc_files,
+ wasi_ref_depend_rustc_with_lld_files,
+ wasi_ref_depend_clang_files,
+ wasi_ref_tmp_dir,
+ wasi_ref,
+ ];
+
+ const { promise: tree_promise, resolve: tree_resolve } =
+ Promise.withResolvers();
+ const { promise: rustc_promise, resolve: rustc_resolve } =
+ Promise.withResolvers();
+ const { promise: rustc_with_lld_promise, resolve: rustc_with_lld_resolve } =
+ Promise.withResolvers();
+ const { promise: clang_promise, resolve: clang_resolve } =
+ Promise.withResolvers();
+ const { promise: cargo_promise, resolve: cargo_resolve } =
+ Promise.withResolvers();
+ const { promise: cat_promise, resolve: cat_resolve } =
+ Promise.withResolvers();
+
+ const tree_worker = new Worker("tree.js", {
+ type: "module",
+ });
+ tree_worker.onmessage = (e) => {
+ console.log("tree onmessage");
+ tree_resolve(e.data);
+ };
+
+ const rustc_worker = new Worker("rustc.js", {
+ type: "module",
+ });
+ rustc_worker.onmessage = (e) => {
+ console.log("rustc onmessage");
+ rustc_resolve(e.data);
+ };
+
+ const rustc_with_lld_worker = new Worker("rustc_with_lld.js", {
+ type: "module",
+ });
+ rustc_with_lld_worker.onmessage = (e) => {
+ console.log("rustc_with_lld onmessage");
+ rustc_with_lld_resolve(e.data);
+ };
+
+ const clang_worker = new Worker("clang.js", {
+ type: "module",
+ });
+ clang_worker.onmessage = (e) => {
+ console.log("clang onmessage");
+ clang_resolve(e.data);
+ };
+
+ const cargo_worker = new Worker("cargo.js", {
+ type: "module",
+ });
+ cargo_worker.onmessage = (e) => {
+ console.log("cargo onmessage");
+ cargo_resolve(e.data);
+ };
+
+ const cat_worker = new Worker("cat.js", {
+ type: "module",
+ });
+ cat_worker.onmessage = (e) => {
+ console.log("cat onmessage");
+ cat_resolve(e.data);
+ };
+
+ tree_worker.postMessage({
+ wasi_refs,
+ });
+ rustc_worker.postMessage({
+ wasi_refs: [wasi_ref_save_stdout, ...wasi_refs],
+ });
+ rustc_with_lld_worker.postMessage({
+ wasi_refs,
+ });
+ clang_worker.postMessage({
+ wasi_refs,
+ });
+ cargo_worker.postMessage({
+ wasi_refs,
+ });
+ cat_worker.postMessage({
+ wasi_refs,
+ });
+
+ console.log("Waiting for tree and rustc to finish...");
+
+ await Promise.all([
+ tree_promise,
+ rustc_promise,
+ rustc_with_lld_promise,
+ clang_promise,
+ cargo_promise,
+ cat_promise,
+ ]);
+
+ console.log("Sending run message...");
+
+ await promise;
+
+ tree = new SharedObject.SharedObjectRef("tree").proxy();
+
+ term = new SharedObject.SharedObjectRef("term").proxy();
+
+ rustc = new SharedObject.SharedObjectRef("rustc").proxy();
+
+ rustc_with_lld = new SharedObject.SharedObjectRef("rustc_with_lld").proxy();
+
+ clang = new SharedObject.SharedObjectRef("clang").proxy();
+
+ llvm_tools = new SharedObject.SharedObjectRef("llvm-tools").proxy();
+
+ wasm_ld = new SharedObject.SharedObjectRef("wasm-ld").proxy();
+
+ std_out_keep = new SharedObject.SharedObjectRef("std_out_keep").proxy();
+
+ std_err_keep = new SharedObject.SharedObjectRef("std_err_keep").proxy();
+
+ root_dir = new SharedObject.SharedObjectRef("root_dir").proxy();
+
+ cargo = new SharedObject.SharedObjectRef("cargo").proxy();
+
+ cat = new SharedObject.SharedObjectRef("cat").proxy();
+
+ // cargo -h
+ await term.writeln(`\n$${blueText} cargo -h${resetText}`);
+ await cargo("-h");
+
+ // cargo new -h
+ await term.writeln(`\n$${blueText} cargo new -h${resetText}`);
+ await cargo("new", "-h");
+
+ // cargo new --bin
+ await term.writeln(`\n$${blueText} cargo new --bin helloworld${resetText}`);
+ await cargo("new", "--bin", "helloworld");
+
+ // cat /helloworld/src/main.rs
+ await term.writeln(`\n$${blueText} cat /helloworld/src/main.rs${resetText}`);
+ await cat("/helloworld/src/main.rs");
+
+ // cat /helloworld/Cargo.toml
+ await term.writeln(`\n$${blueText} cat /helloworld/Cargo.toml${resetText}`);
+ await cat("/helloworld/Cargo.toml");
+
+ // cargo run -h
+ await term.writeln(`\n$${blueText} cargo run -h${resetText}`);
+ await cargo("run", "-h");
+
+ // cargo run --manifest-path /helloworld/Cargo.toml --jobs 1 -- --sysroot /sysroot-with-lld
+ await term.writeln(
+ `\n$${blueText} cargo run --manifest-path /helloworld/Cargo.toml --jobs 1`,
+ );
+ await cargo(
+ "run",
+ "--manifest-path",
+ "/helloworld/Cargo.toml",
+ "--jobs",
+ "1",
+ );
+
+ // llvm-tools
+ await term.writeln(`$${blueText} llvm-tools${resetText}`);
+ await llvm_tools();
+
+ // clang -h
+ await term.writeln(`\n$${blueText} clang --help${resetText}`);
+ await clang("--help");
+
+ // clang -v
+ await term.writeln(`\n$${blueText} clang -v${resetText}`);
+ await clang("-v");
+
+ // wasm-ld --help
+ await term.writeln(`\n$${blueText} wasm-ld --help${resetText}`);
+ await wasm_ld("--help");
+
+ // wasm-ld -v
+ await term.writeln(`\n$${blueText} wasm-ld -v${resetText}`);
+ await wasm_ld("-v");
+
+ // tree -h
+ await term.writeln(`\n$${blueText} tree -h${resetText}`);
+ await tree("-h");
+
+ // tree /
+ await term.writeln(`\n$${blueText} tree /${resetText}`);
+ await tree("/");
+
+ // rustc -h
+ await std_out_keep.reset();
+ await std_err_keep.reset();
+ await term.writeln(`\n$${blueText} rustc -h${resetText}`);
+ await rustc("-h");
+ const rustc_help = await std_out_keep.get();
+ const rustc_help_err = await std_err_keep.get();
+ console.log(rustc_help);
+ console.warn(rustc_help_err);
+
+ // rustc /hello.rs --sysroot /sysroot --target wasm32-wasip1-threads -Csave-temps --out-dir /tmp
+ await term.writeln(
+ `\n$${blueText} rustc /hello.rs --sysroot /sysroot --target wasm32-wasip1-threads -Csave-temps --out-dir /tmp${resetText}`,
+ );
+ try {
+ await std_out_keep.reset();
+ await std_err_keep.reset();
+ await rustc(
+ "/hello.rs",
+ "--sysroot",
+ "/sysroot",
+ "--target",
+ "wasm32-wasip1-threads",
+ "-Csave-temps",
+ "--out-dir",
+ "/tmp",
+ );
+ } catch (e) {
+ console.error(e);
+ }
+ const out = await std_out_keep.get();
+ const err = await std_err_keep.get();
+ console.log(out);
+ console.warn(err);
+
+ // tree /
+ await term.writeln(`\n$${blueText} tree /${resetText}`);
+ await tree("/");
+
+ // If the glob pattern is used,
+ // it seems to be passed directly to path_open,
+ // so it is necessary to specify it carefully.
+ if (!err.includes("error: could not exec the linker")) {
+ throw new Error("cannot get lld arguments");
+ }
+ // extract lld arguments line
+ const lld_args_and_etc = err
+ .split("\n")
+ .find((line) => line.includes("rust-lld") && line.includes("note: "));
+ const lld_args_str = lld_args_and_etc.split('"rust-lld"')[1].trim();
+ const lld_args_with_wrap = lld_args_str.split(" ");
+ let lld_args = lld_args_with_wrap.map((arg) => arg.slice(1, -1));
+ // rm -flavor wasm
+ lld_args = lld_args.filter((arg) => arg !== "-flavor" && arg !== "wasm");
+ // rm -Wl
+ lld_args = lld_args.map((arg) => {
+ if (arg.includes("-Wl,")) {
+ return arg.slice(4);
+ }
+ return arg;
+ });
+ console.log(lld_args);
+
+ await term.writeln(
+ `\n$${blueText} wasm-ld ${lld_args.join(" ")}${resetText}`,
+ );
+ try {
+ await wasm_ld(lld_args);
+ } catch (error) {
+ console.error(error);
+ const redText = "\x1b[31m";
+ const boldText = "\x1b[1m";
+
+ const message = `${boldText}${redText}Error: ${error.message}${resetText}\n`;
+ const stack = `${redText}Stack Trace: ${error.stack}${resetText}`;
+
+ await term.writeln(message + stack);
+ }
+
+ // tree /
+ await term.writeln(`\n$${blueText} tree /${resetText}`);
+ await tree("/");
+
+ // rustc_with_lld /hello.rs --sysroot /sysroot --target wasm32-wasip1
+ await term.writeln(
+ `\n$${blueText} rustc_with_lld /hello.rs --sysroot /sysroot-with-lld --target wasm32-wasip1${resetText}`,
+ );
+ try {
+ await rustc_with_lld(
+ "/hello.rs",
+ "--sysroot",
+ "/sysroot-with-lld",
+ "--target",
+ "wasm32-wasip1",
+ );
+ } catch (e) {
+ console.error(e);
+ }
+
+ // tree /
+ await term.writeln(`\n$${blueText} tree /${resetText}`);
+ await tree("/");
+
+ // run /hello.wasm
+ await term.writeln(`\n$${blueText} run /hello.wasm${resetText}`);
+ const created_wasm_buffer = await root_dir.get_file("hello.wasm");
+ const created_wasm = await WebAssembly.compile(created_wasm_buffer);
+ const wasi = new WASIFarmAnimal(
+ wasi_refs,
+ [], // args
+ [], // env
+ {
+ debug: false,
+ },
+ );
+
+ // Memory is rewritten at this time.
+ const inst = await WebAssembly.instantiate(created_wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ wasi.start(inst);
+
+ // all done
+ await term.writeln(`\n$${blueText} All done!${resetText}`);
+};
diff --git a/examples/wasi_workers/echo_and_rewrite.wasm b/examples/wasi_workers/echo_and_rewrite.wasm
new file mode 100644
index 0000000..1f4e413
Binary files /dev/null and b/examples/wasi_workers/echo_and_rewrite.wasm differ
diff --git a/examples/wasi_workers/index.html b/examples/wasi_workers/index.html
new file mode 100644
index 0000000..f59f8d3
--- /dev/null
+++ b/examples/wasi_workers/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/examples/wasi_workers/main.rs b/examples/wasi_workers/main.rs
new file mode 100644
index 0000000..41a744c
--- /dev/null
+++ b/examples/wasi_workers/main.rs
@@ -0,0 +1,52 @@
+fn main() {
+ // ファイル名を受けとる
+ let args: Vec = std::env::args().collect();
+ let filename = &args[1];
+
+ println!("reading file: {}", filename);
+
+ // ファイルを読み込む
+ let file = std::fs::read_to_string(filename).expect("ファイルが読み込めませんでした");
+
+ // ファイルの内容を表示
+ println!("{}", file);
+
+ // ファイルの内容を書き換え
+ // 二つ目の引数の文字列を二つ目の文字列に書き換える
+ let replaced = file.replace(&args[2], &args[3]);
+
+ // 書き換えた内容を表示
+ println!("{}", replaced);
+
+ println!("random replace start");
+
+ let start = std::env::args().nth(4).unwrap().parse::().unwrap();
+ let end = std::env::args().nth(5).unwrap().parse::().unwrap();
+
+ // 新しいfileを作る
+ let new_file = format!("{}-{}~{}.txt", filename, start, end);
+ std::fs::write(&new_file, "$$$$$$$$$").expect("ファイルが書き込めませんでした");
+
+ let loop_n = std::env::args().nth(6).unwrap_or("100".to_string()).parse::().unwrap();
+
+ // loop {
+ for _ in 0..loop_n {
+ // ファイルを読み込む
+ let file = std::fs::read_to_string(filename).expect("ファイルが読み込めませんでした");
+
+ // ランダムな数値を生成
+ let random = rand::random::() % (end - start) + start;
+
+ // 生成した数値をkファイルの内容に書き換える
+ let replaced = format!("{}, {}", file, random);
+
+ // 書き換えた内容を表示
+ println!("{}", replaced);
+
+ // ファイルを書き換える
+ std::fs::write(filename, &replaced).expect("ファイルが書き込めませんでした");
+
+ // 1秒待つ
+ // std::thread::sleep(std::time::Duration::from_secs(1));
+ }
+}
diff --git a/examples/wasi_workers/worker.js b/examples/wasi_workers/worker.js
new file mode 100644
index 0000000..b443ab3
--- /dev/null
+++ b/examples/wasi_workers/worker.js
@@ -0,0 +1,20 @@
+
+import { File, OpenFile, ConsoleStdout, PreopenDirectory, WASIFarm } from "../../dist/index.js";
+
+let wasi_farm;
+(async () => {
+ wasi_farm = new WASIFarm(
+ undefined,
+ ConsoleStdout.lineBuffered(msg => console.log(`[WASI stdout on worker] ${msg}`)),
+ undefined,
+ [
+ new PreopenDirectory("hello2", [
+ ["hello2.txt", new File(new TextEncoder().encode("Hello, world!!!!!"))],
+ ]),
+ ],
+ { debug: true },
+ );
+ console.log("WASI farm created");
+ let wasi_ref = await wasi_farm.get_ref();
+ self.postMessage({ wasi_ref });
+})();
diff --git a/examples/wasi_workers/worker1.js b/examples/wasi_workers/worker1.js
new file mode 100644
index 0000000..7c1c9e2
--- /dev/null
+++ b/examples/wasi_workers/worker1.js
@@ -0,0 +1,19 @@
+import { WASIFarmAnimal } from "../../dist/wasi_farm/animals.js";
+
+self.onmessage = async function (e) {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref, wasi_ref2],
+ ["echo_and_rewrite", "hello2/hello2.txt", "world", "new_world", "0", "100", "100"], // args
+ [""], // env
+ // options
+ );
+ let wasm = await fetch("./echo_and_rewrite.wasm");
+ let buff = await wasm.arrayBuffer();
+ let { instance } = await WebAssembly.instantiate(buff, {
+ "wasi_snapshot_preview1": wasi.wasiImport,
+ });
+ wasi.start(instance);
+}
+
diff --git a/examples/wasi_workers/worker2.js b/examples/wasi_workers/worker2.js
new file mode 100644
index 0000000..8064cb3
--- /dev/null
+++ b/examples/wasi_workers/worker2.js
@@ -0,0 +1,18 @@
+import { WASIFarmAnimal } from "../../dist/wasi_farm/animals.js";
+
+self.onmessage = async function (e) {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref, wasi_ref2],
+ ["echo_and_rewrite", "hello.txt", "world", "new_world", "100", "200"], // args
+ [""], // env
+ // options
+ );
+ let wasm = await fetch("./echo_and_rewrite.wasm");
+ let buff = await wasm.arrayBuffer();
+ let { instance } = await WebAssembly.instantiate(buff, {
+ "wasi_snapshot_preview1": wasi.wasiImport,
+ });
+ wasi.start(instance);
+}
diff --git a/examples/wasi_workers/worker3.js b/examples/wasi_workers/worker3.js
new file mode 100644
index 0000000..400608c
--- /dev/null
+++ b/examples/wasi_workers/worker3.js
@@ -0,0 +1,18 @@
+import { WASIFarmAnimal } from "../../dist/wasi_farm/animals.js";
+
+self.onmessage = async function (e) {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref2, wasi_ref],
+ ["echo_and_rewrite", "hello.txt", "world", "new_world", "200", "300"], // args
+ [""], // env
+ // options
+ );
+ let wasm = await fetch("./echo_and_rewrite.wasm");
+ let buff = await wasm.arrayBuffer();
+ let { instance } = await WebAssembly.instantiate(buff, {
+ "wasi_snapshot_preview1": wasi.wasiImport,
+ });
+ wasi.start(instance);
+}
diff --git a/examples/wasi_workers_rustc/rustc.html b/examples/wasi_workers_rustc/rustc.html
new file mode 100644
index 0000000..a3b081c
--- /dev/null
+++ b/examples/wasi_workers_rustc/rustc.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Note: the failure to invoke the linker at the end is expected.
+ WASI doesn't have a way to invoke external processes and rustc doesn't have a builtin linker.
+ This demo highlights how far `rustc` can get on this polyfill before failing due to other reasons.
+
+
+
+
diff --git a/examples/wasi_workers_rustc/worker.js b/examples/wasi_workers_rustc/worker.js
new file mode 100644
index 0000000..a251f88
--- /dev/null
+++ b/examples/wasi_workers_rustc/worker.js
@@ -0,0 +1,59 @@
+import { strace, WASIFarmAnimal } from "../../dist/index.js";
+
+console.log("worker.js");
+
+onmessage = async function (e) {
+ let wasm = await WebAssembly.compileStreaming(fetch("../wasm-rustc/bin/rustc.wasm"));
+
+ console.log("worker.js onmessage", e.data);
+
+ const { wasi_ref } = e.data;
+
+ let args = ["rustc", "/hello.rs", "--sysroot", "/sysroot", "--target", "x86_64-unknown-linux-gnu", "-Cpanic=abort", "-Ccodegen-units=1"];
+ let env = ["RUSTC_LOG=info"];
+
+ console.log("wasi_ref", wasi_ref);
+
+ const w = new WASIFarmAnimal(
+ wasi_ref,
+ args,
+ env,
+ {
+ debug: true
+ }
+ );
+
+ let next_thread_id = 1;
+
+ let inst = await WebAssembly.instantiate(wasm, {
+ "env": { memory: new WebAssembly.Memory({ initial: 256, maximum: 16384, shared: true }) },
+ "wasi": {
+ "thread-spawn": function(start_arg) {
+ console.log("thread-spawn", start_arg);
+
+ let thread_id = next_thread_id++;
+ inst.exports.wasi_thread_start(thread_id, start_arg);
+ return thread_id;
+ }
+ },
+ "wasi_snapshot_preview1": strace(w.wasiImport, ["fd_prestat_get"]),
+ });
+
+ postMessage({
+ "term": "\x1B[93mExecuting\x1B[0m",
+ });
+ console.log(inst.exports);
+ try { w.start(inst); } catch(e) {
+ postMessage({
+ term: "Exception: " + e.message,
+ });
+ // /*term.writeln("backtrace:"); term.writeln(e.stack);*/
+ }
+ postMessage({
+ "term": "\x1B[92mDone\x1B[0m",
+ });
+
+ console.log(fds);
+ console.log(fds[5].dir);
+ console.log(fds[5].dir.contents.get("hello.hello.65c991d23c885d45-cgu.0.rcgu.o").data);
+}
diff --git a/examples/wasi_workers_single/echo_and_rewrite.wasm b/examples/wasi_workers_single/echo_and_rewrite.wasm
new file mode 100644
index 0000000..d03ed2d
Binary files /dev/null and b/examples/wasi_workers_single/echo_and_rewrite.wasm differ
diff --git a/examples/wasi_workers_single/index.html b/examples/wasi_workers_single/index.html
new file mode 100644
index 0000000..0dd4721
--- /dev/null
+++ b/examples/wasi_workers_single/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 6891208..7967411 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,9 @@
"name": "@bjorn3/browser_wasi_shim",
"version": "0.3.0",
"license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@bjorn3/browser_wasi_shim": "file:"
+ },
"devDependencies": {
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.37",
@@ -16,23 +19,17 @@
"eslint": "^8.50.0",
"playwright": "^1.40.1",
"prettier": "^3.0.3",
- "typescript": "^4.9.5"
+ "typescript": "^5.6.2"
}
},
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
+ "node_modules/@bjorn3/browser_wasi_shim": {
+ "resolved": "",
+ "link": true
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"eslint-visitor-keys": "^3.3.0"
},
@@ -44,19 +41,17 @@
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz",
- "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==",
+ "version": "4.11.1",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
- "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
+ "version": "2.1.4",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
@@ -75,34 +70,71 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+ "version": "3.1.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
"node_modules/@eslint/js": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz",
- "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==",
+ "version": "8.57.1",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.11",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
- "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
+ "version": "0.13.0",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
+ "@humanwhocodes/object-schema": "^2.0.3",
+ "debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": {
"node": ">=10.10.0"
}
},
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+ "version": "3.1.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
"node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=12.22"
},
@@ -112,16 +144,14 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
+ "version": "2.0.3",
+ "dev": true,
+ "license": "BSD-3-Clause"
},
"node_modules/@mole-inc/bin-wrapper": {
"version": "8.0.1",
- "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz",
- "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"bin-check": "^4.1.0",
"bin-version-check": "^5.0.0",
@@ -138,9 +168,8 @@
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
@@ -151,18 +180,16 @@
},
"node_modules/@nodelib/fs.stat": {
"version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
"version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
@@ -173,9 +200,8 @@
},
"node_modules/@sindresorhus/is": {
"version": "4.6.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
- "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -184,14 +210,14 @@
}
},
"node_modules/@swc/cli": {
- "version": "0.1.62",
- "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz",
- "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==",
+ "version": "0.1.65",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@mole-inc/bin-wrapper": "^8.0.1",
"commander": "^7.1.0",
"fast-glob": "^3.2.5",
+ "minimatch": "^9.0.3",
"semver": "^7.3.8",
"slash": "3.0.0",
"source-map": "^0.7.3"
@@ -215,11 +241,14 @@
}
},
"node_modules/@swc/core": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.37.tgz",
- "integrity": "sha512-VOFlEQ1pReOM73N9A7R8rt561GU8Rxsq833jiimWDUB2sXEN3V6n6wFTgYmZuMz2T4/R0cQA1nV48KkaT4gkFw==",
+ "version": "1.7.26",
"dev": true,
"hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3",
+ "@swc/types": "^0.1.12"
+ },
"engines": {
"node": ">=10"
},
@@ -228,138 +257,33 @@
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
- "@swc/core-darwin-arm64": "1.3.37",
- "@swc/core-darwin-x64": "1.3.37",
- "@swc/core-linux-arm-gnueabihf": "1.3.37",
- "@swc/core-linux-arm64-gnu": "1.3.37",
- "@swc/core-linux-arm64-musl": "1.3.37",
- "@swc/core-linux-x64-gnu": "1.3.37",
- "@swc/core-linux-x64-musl": "1.3.37",
- "@swc/core-win32-arm64-msvc": "1.3.37",
- "@swc/core-win32-ia32-msvc": "1.3.37",
- "@swc/core-win32-x64-msvc": "1.3.37"
- }
- },
- "node_modules/@swc/core-darwin-arm64": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.37.tgz",
- "integrity": "sha512-iIyVqqioUpVeT/hbBVfkrsjfCyL4idNH+LVKGmoTAWaTTSB0+UNhNuA7Wh2CqIHWh1Mv7IlumitWPcqsVDdoEw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-darwin-x64": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.37.tgz",
- "integrity": "sha512-dao5nXPWKxtaxqak4ZkRyBoApNIelW/glantQhPhj0FjMjuIQc+v03ldJ8XDByWOG+6xuVUTheANCtEccxoQBw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm-gnueabihf": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.37.tgz",
- "integrity": "sha512-/mVrc8H/f062CUkqKGmBiil2VIYu4mKawHxERfeP1y38X5K/OwjG5s9MgO9TVxy+Ly6vejwj70kRhSa3hVp1Bw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-gnu": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.37.tgz",
- "integrity": "sha512-eRQ3KaZI0j5LidTfOIi/kUVOOMuVmw1HCdt/Z1TAUKoHMLVxY8xcJ3pEE3/+ednI60EmHpwpJRs6LelXyL6uzQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-arm64-musl": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.37.tgz",
- "integrity": "sha512-w2BRLODyxNQY2rfHZMZ5ir6QrrnGBPlnIslTrgKmVbn1OjZoxUCtuqhrYnCmybaAc4DOkeH02TqynEFXrm+EMw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-linux-x64-gnu": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.37.tgz",
- "integrity": "sha512-CfoH8EsZJZ9kunjMUjBNYD5fFuO86zw+K/o4wEw72Yg6ZEiqPmeIlCKU8tpTv4sK+CbhUXrmVzMB5tqsb2jALQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
+ "@swc/core-darwin-arm64": "1.7.26",
+ "@swc/core-darwin-x64": "1.7.26",
+ "@swc/core-linux-arm-gnueabihf": "1.7.26",
+ "@swc/core-linux-arm64-gnu": "1.7.26",
+ "@swc/core-linux-arm64-musl": "1.7.26",
+ "@swc/core-linux-x64-gnu": "1.7.26",
+ "@swc/core-linux-x64-musl": "1.7.26",
+ "@swc/core-win32-arm64-msvc": "1.7.26",
+ "@swc/core-win32-ia32-msvc": "1.7.26",
+ "@swc/core-win32-x64-msvc": "1.7.26"
+ },
+ "peerDependencies": {
+ "@swc/helpers": "*"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
}
},
- "node_modules/@swc/core-linux-x64-musl": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.37.tgz",
- "integrity": "sha512-9YPrHYNdoG7PK11gV51GfL45biI2dic+YTqHUDKyykemsD7Ot1zUFX7Ty//pdvpKcKSff6SrHbfFACD5ziNirA==",
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.7.26",
"cpu": [
"x64"
],
"dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@swc/core-win32-arm64-msvc": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.37.tgz",
- "integrity": "sha512-h17Ek8/wCDje6BrXOvCXBM80oBRmTSMMdLyt87whTl5xqYlWYYs9oQIzZndNRTlNpTgjGO8Ns2eo4kwVxIkBIA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
+ "license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"win32"
@@ -368,43 +292,23 @@
"node": ">=10"
}
},
- "node_modules/@swc/core-win32-ia32-msvc": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.37.tgz",
- "integrity": "sha512-1BR175E1olGy/zdt94cgdb6ps/lBNissAOaxyBk8taFpcjy3zpdP30yAoH0GIsC6isnZ5JfArbOJNRXXO5tE0Q==",
- "cpu": [
- "ia32"
- ],
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
- }
+ "license": "Apache-2.0"
},
- "node_modules/@swc/core-win32-x64-msvc": {
- "version": "1.3.37",
- "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.37.tgz",
- "integrity": "sha512-1siDQ7dccQ1pesJmgAL3BUBbRPtfbNInOWnZOkiie/DfFqGQ117QKnCVyjUvwFKfTQx1+3UUTDmMSlRd00SlXg==",
- "cpu": [
- "x64"
- ],
+ "node_modules/@swc/types": {
+ "version": "0.1.12",
"dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=10"
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
- "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
- "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"defer-to-connect": "^2.0.0"
},
@@ -414,15 +318,13 @@
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
- "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/cacheable-request": {
"version": "6.0.3",
- "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
- "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/http-cache-semantics": "*",
"@types/keyv": "^3.1.4",
@@ -431,58 +333,54 @@
}
},
"node_modules/@types/http-cache-semantics": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
- "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==",
- "dev": true
+ "version": "4.0.4",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/json-schema": {
- "version": "7.0.13",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz",
- "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==",
- "dev": true
+ "version": "7.0.15",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/keyv": {
"version": "3.1.4",
- "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
- "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/node": {
- "version": "18.14.6",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
- "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==",
- "dev": true
+ "version": "22.5.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
},
"node_modules/@types/responselike": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
- "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
+ "version": "1.0.3",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/semver": {
- "version": "7.5.3",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz",
- "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==",
- "dev": true
+ "version": "7.5.8",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz",
- "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.7.4",
- "@typescript-eslint/type-utils": "6.7.4",
- "@typescript-eslint/utils": "6.7.4",
- "@typescript-eslint/visitor-keys": "6.7.4",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/type-utils": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@@ -508,15 +406,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz",
- "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==",
+ "version": "6.21.0",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/scope-manager": "6.7.4",
- "@typescript-eslint/types": "6.7.4",
- "@typescript-eslint/typescript-estree": "6.7.4",
- "@typescript-eslint/visitor-keys": "6.7.4",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
"debug": "^4.3.4"
},
"engines": {
@@ -536,13 +433,12 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
- "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "6.7.4",
- "@typescript-eslint/visitor-keys": "6.7.4"
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -553,13 +449,12 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz",
- "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/typescript-estree": "6.7.4",
- "@typescript-eslint/utils": "6.7.4",
+ "@typescript-eslint/typescript-estree": "6.21.0",
+ "@typescript-eslint/utils": "6.21.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
},
@@ -580,10 +475,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
- "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
@@ -593,16 +487,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
- "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
+ "version": "6.21.0",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/types": "6.7.4",
- "@typescript-eslint/visitor-keys": "6.7.4",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/visitor-keys": "6.21.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
@@ -619,18 +513,31 @@
}
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.3",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@typescript-eslint/utils": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz",
- "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.7.4",
- "@typescript-eslint/types": "6.7.4",
- "@typescript-eslint/typescript-estree": "6.7.4",
+ "@typescript-eslint/scope-manager": "6.21.0",
+ "@typescript-eslint/types": "6.21.0",
+ "@typescript-eslint/typescript-estree": "6.21.0",
"semver": "^7.5.4"
},
"engines": {
@@ -645,12 +552,11 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.7.4",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
- "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
+ "version": "6.21.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "6.7.4",
+ "@typescript-eslint/types": "6.21.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
@@ -661,11 +567,15 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/acorn": {
- "version": "8.10.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
- "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+ "version": "8.12.1",
"dev": true,
+ "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -675,18 +585,16 @@
},
"node_modules/acorn-jsx": {
"version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
+ "license": "MIT",
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -700,18 +608,16 @@
},
"node_modules/ansi-regex": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -724,8 +630,6 @@
},
"node_modules/arch": {
"version": "2.2.0",
- "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
- "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
"dev": true,
"funding": [
{
@@ -740,34 +644,31 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/argparse": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
+ "dev": true,
+ "license": "Python-2.0"
},
"node_modules/array-union": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/bin-check": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz",
- "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"execa": "^0.7.0",
"executable": "^4.1.0"
@@ -778,9 +679,8 @@
},
"node_modules/bin-version": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz",
- "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"execa": "^5.0.0",
"find-versions": "^5.0.0"
@@ -793,14 +693,13 @@
}
},
"node_modules/bin-version-check": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.0.0.tgz",
- "integrity": "sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==",
+ "version": "5.1.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
"bin-version": "^6.0.0",
- "semver": "^7.3.5",
- "semver-truncate": "^2.0.0"
+ "semver": "^7.5.3",
+ "semver-truncate": "^3.0.0"
},
"engines": {
"node": ">=12"
@@ -809,25 +708,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bin-version/node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/bin-version/node_modules/execa": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.0",
@@ -846,11 +730,10 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "node_modules/bin-version/node_modules/get-stream": {
+ "node_modules/bin-version/node_modules/execa/node_modules/get-stream": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -858,11 +741,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bin-version/node_modules/is-stream": {
+ "node_modules/bin-version/node_modules/execa/node_modules/is-stream": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -870,11 +752,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bin-version/node_modules/npm-run-path": {
+ "node_modules/bin-version/node_modules/execa/node_modules/npm-run-path": {
"version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^3.0.0"
},
@@ -882,68 +763,20 @@
"node": ">=8"
}
},
- "node_modules/bin-version/node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bin-version/node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bin-version/node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/bin-version/node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "2.0.1",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "balanced-match": "^1.0.0"
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -951,18 +784,16 @@
},
"node_modules/cacheable-lookup": {
"version": "5.0.4",
- "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
- "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10.6.0"
}
},
"node_modules/cacheable-request": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
- "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
+ "version": "7.0.4",
"dev": true,
+ "license": "MIT",
"dependencies": {
"clone-response": "^1.0.2",
"get-stream": "^5.1.0",
@@ -978,9 +809,8 @@
},
"node_modules/cacheable-request/node_modules/get-stream": {
"version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"pump": "^3.0.0"
},
@@ -993,18 +823,16 @@
},
"node_modules/callsites": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/chalk": {
"version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -1018,9 +846,8 @@
},
"node_modules/clone-response": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
- "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mimic-response": "^1.0.0"
},
@@ -1028,11 +855,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/clone-response/node_modules/mimic-response": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -1042,30 +876,26 @@
},
"node_modules/color-name": {
"version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/commander": {
"version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/content-disposition": {
"version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
@@ -1074,23 +904,24 @@
}
},
"node_modules/cross-spawn": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
- "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
+ "version": "7.0.3",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "lru-cache": "^4.0.1",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
}
},
"node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.3.7",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -1103,9 +934,8 @@
},
"node_modules/decompress-response": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
- "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mimic-response": "^3.1.0"
},
@@ -1116,38 +946,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/decompress-response/node_modules/mimic-response": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
- "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/deep-is": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
- "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/dir-glob": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-type": "^4.0.0"
},
@@ -1157,9 +972,8 @@
},
"node_modules/doctrine": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
@@ -1169,38 +983,36 @@
},
"node_modules/end-of-stream": {
"version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"once": "^1.4.0"
}
},
"node_modules/escape-string-regexp": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
- "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "version": "4.0.0",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=12"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint": {
- "version": "8.50.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz",
- "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==",
+ "version": "8.57.1",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "8.50.0",
- "@humanwhocodes/config-array": "^0.11.11",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.1",
+ "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -1244,9 +1056,8 @@
},
"node_modules/eslint-scope": {
"version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -1260,9 +1071,8 @@
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -1270,94 +1080,30 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint/node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/eslint/node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint/node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/eslint/node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "node_modules/eslint/node_modules/minimatch": {
+ "version": "3.1.2",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "shebang-regex": "^3.0.0"
+ "brace-expansion": "^1.1.7"
},
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/eslint/node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
+ "node": "*"
}
},
- "node_modules/eslint/node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "node_modules/eslint/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "1.1.11",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
}
},
"node_modules/espree": {
"version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
@@ -1371,10 +1117,9 @@
}
},
"node_modules/esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+ "version": "1.6.0",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"estraverse": "^5.1.0"
},
@@ -1384,9 +1129,8 @@
},
"node_modules/esrecurse": {
"version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -1396,27 +1140,24 @@
},
"node_modules/estraverse": {
"version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=4.0"
}
},
"node_modules/esutils": {
"version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
+ "license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/execa": {
"version": "0.7.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
- "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"cross-spawn": "^5.0.1",
"get-stream": "^3.0.0",
@@ -1430,11 +1171,50 @@
"node": ">=4"
}
},
+ "node_modules/execa/node_modules/cross-spawn": {
+ "version": "5.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/execa/node_modules/cross-spawn/node_modules/shebang-command": {
+ "version": "1.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/execa/node_modules/cross-spawn/node_modules/shebang-command/node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/execa/node_modules/cross-spawn/node_modules/which": {
+ "version": "1.3.1",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
"node_modules/executable": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
- "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"pify": "^2.2.0"
},
@@ -1444,9 +1224,8 @@
},
"node_modules/ext-list": {
"version": "2.2.2",
- "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
- "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mime-db": "^1.28.0"
},
@@ -1456,9 +1235,8 @@
},
"node_modules/ext-name": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
- "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ext-list": "^2.0.0",
"sort-keys-length": "^1.0.0"
@@ -1469,15 +1247,13 @@
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.2",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -1489,32 +1265,39 @@
"node": ">=8.6.0"
}
},
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fastq": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
- "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "version": "1.17.1",
"dev": true,
+ "license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"flat-cache": "^3.0.4"
},
@@ -1524,9 +1307,8 @@
},
"node_modules/file-type": {
"version": "17.1.6",
- "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz",
- "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"readable-web-to-node-stream": "^3.0.2",
"strtok3": "^7.0.0-alpha.9",
@@ -1541,9 +1323,8 @@
},
"node_modules/filename-reserved-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz",
- "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -1553,9 +1334,8 @@
},
"node_modules/filenamify": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz",
- "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"filename-reserved-regex": "^3.0.0",
"strip-outer": "^2.0.0",
@@ -1569,10 +1349,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1582,9 +1361,8 @@
},
"node_modules/find-up": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"locate-path": "^6.0.0",
"path-exists": "^4.0.0"
@@ -1598,9 +1376,8 @@
},
"node_modules/find-versions": {
"version": "5.1.0",
- "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz",
- "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"semver-regex": "^4.0.5"
},
@@ -1612,59 +1389,40 @@
}
},
"node_modules/flat-cache": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz",
- "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==",
+ "version": "3.2.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "flatted": "^3.2.7",
+ "flatted": "^3.2.9",
"keyv": "^4.5.3",
"rimraf": "^3.0.2"
},
"engines": {
- "node": ">=12.0.0"
+ "node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/flatted": {
- "version": "3.2.9",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
- "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
- "dev": true
+ "version": "3.3.1",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/fs.realpath": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
+ "license": "ISC"
},
"node_modules/get-stream": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
- "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/glob": {
"version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -1681,22 +1439,40 @@
}
},
"node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "version": "6.0.2",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "is-glob": "^4.0.1"
+ "is-glob": "^4.0.3"
},
"engines": {
- "node": ">= 6"
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "3.1.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
}
},
"node_modules/globals": {
- "version": "13.22.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz",
- "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==",
+ "version": "13.24.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
"type-fest": "^0.20.2"
},
@@ -1709,9 +1485,8 @@
},
"node_modules/globby": {
"version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
@@ -1729,9 +1504,8 @@
},
"node_modules/got": {
"version": "11.8.6",
- "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
- "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@sindresorhus/is": "^4.0.0",
"@szmarczak/http-timer": "^4.0.5",
@@ -1754,30 +1528,26 @@
},
"node_modules/graphemer": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/has-flag": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/http-cache-semantics": {
"version": "4.1.1",
- "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
- "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
- "dev": true
+ "dev": true,
+ "license": "BSD-2-Clause"
},
"node_modules/http2-wrapper": {
"version": "1.0.3",
- "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
- "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0"
@@ -1788,17 +1558,14 @@
},
"node_modules/human-signals": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
- "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=10.17.0"
}
},
"node_modules/ieee754": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
@@ -1813,22 +1580,21 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "BSD-3-Clause"
},
"node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "version": "5.3.2",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/import-fresh": {
"version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
@@ -1842,18 +1608,16 @@
},
"node_modules/imurmurhash": {
"version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.8.19"
}
},
"node_modules/inflight": {
"version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
@@ -1861,24 +1625,21 @@
},
"node_modules/inherits": {
"version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/is-extglob": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -1888,51 +1649,45 @@
},
"node_modules/is-number": {
"version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-path-inside": {
"version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-plain-obj": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-stream": {
"version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/isexe": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/js-yaml": {
"version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -1942,36 +1697,31 @@
},
"node_modules/json-buffer": {
"version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/keyv": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
- "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
+ "version": "4.5.4",
"dev": true,
+ "license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
}
},
"node_modules/levn": {
"version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1",
"type-check": "~0.4.0"
@@ -1982,9 +1732,8 @@
},
"node_modules/locate-path": {
"version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"p-locate": "^5.0.0"
},
@@ -1997,24 +1746,21 @@
},
"node_modules/lodash.merge": {
"version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/lowercase-keys": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
- "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/lru-cache": {
"version": "4.1.5",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
- "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
@@ -2022,26 +1768,23 @@
},
"node_modules/merge-stream": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/merge2": {
"version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -2049,61 +1792,60 @@
}
},
"node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "version": "1.53.0",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-fn": {
"version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/mimic-response": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
- "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "version": "3.1.0",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=4"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "version": "9.0.5",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": "*"
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
+ "version": "2.1.3",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/normalize-url": {
"version": "6.1.0",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
- "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -2113,9 +1855,8 @@
},
"node_modules/npm-run-path": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"path-key": "^2.0.0"
},
@@ -2123,20 +1864,26 @@
"node": ">=4"
}
},
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/onetime": {
"version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"mimic-fn": "^2.1.0"
},
@@ -2148,17 +1895,16 @@
}
},
"node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "version": "0.9.4",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
@@ -2166,9 +1912,8 @@
},
"node_modules/os-filter-obj": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz",
- "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"arch": "^2.1.0"
},
@@ -2178,27 +1923,24 @@
},
"node_modules/p-cancelable": {
"version": "2.1.1",
- "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
- "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/p-finally": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"yocto-queue": "^0.1.0"
},
@@ -2211,9 +1953,8 @@
},
"node_modules/p-locate": {
"version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"p-limit": "^3.0.2"
},
@@ -2226,9 +1967,8 @@
},
"node_modules/parent-module": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
@@ -2238,45 +1978,40 @@
},
"node_modules/path-exists": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+ "version": "3.1.1",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=4"
+ "node": ">=8"
}
},
"node_modules/path-type": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/peek-readable": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
- "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==",
+ "version": "5.2.0",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=14.16"
},
@@ -2287,9 +2022,8 @@
},
"node_modules/picomatch": {
"version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8.6"
},
@@ -2299,57 +2033,52 @@
},
"node_modules/pify": {
"version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/playwright": {
- "version": "1.40.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz",
- "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==",
+ "version": "1.47.2",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.40.1"
+ "playwright-core": "1.47.2"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
- "version": "1.40.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz",
- "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==",
+ "version": "1.47.2",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
- "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+ "version": "3.3.3",
"dev": true,
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -2362,33 +2091,28 @@
},
"node_modules/pseudomap": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "version": "3.0.2",
"dev": true,
+ "license": "MIT",
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
+ "version": "2.3.1",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
@@ -2403,13 +2127,13 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/quick-lru": {
"version": "5.1.1",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
- "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -2418,10 +2142,9 @@
}
},
"node_modules/readable-stream": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz",
- "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==",
+ "version": "3.6.2",
"dev": true,
+ "license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
@@ -2433,9 +2156,8 @@
},
"node_modules/readable-web-to-node-stream": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
- "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"readable-stream": "^3.6.0"
},
@@ -2449,24 +2171,21 @@
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
- "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
- "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/resolve-from": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/responselike": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
- "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"lowercase-keys": "^2.0.0"
},
@@ -2476,9 +2195,8 @@
},
"node_modules/reusify": {
"version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
+ "license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
@@ -2486,9 +2204,8 @@
},
"node_modules/rimraf": {
"version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
@@ -2501,8 +2218,6 @@
},
"node_modules/run-parallel": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
@@ -2518,14 +2233,13 @@
"url": "https://feross.org/support"
}
],
+ "license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
@@ -2540,16 +2254,13 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "version": "7.6.3",
"dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -2559,9 +2270,8 @@
},
"node_modules/semver-regex": {
"version": "4.0.5",
- "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz",
- "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -2570,85 +2280,55 @@
}
},
"node_modules/semver-truncate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-2.0.0.tgz",
- "integrity": "sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==",
+ "version": "3.0.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "semver": "^6.0.0"
+ "semver": "^7.3.5"
},
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/semver-truncate/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/semver/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
+ "node": ">=12"
},
- "engines": {
- "node": ">=10"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/semver/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
"node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "version": "2.0.0",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "shebang-regex": "^1.0.0"
+ "shebang-regex": "^3.0.0"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">=8"
}
},
"node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "version": "3.0.0",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": ">=8"
}
},
"node_modules/signal-exit": {
"version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/slash": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/sort-keys": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
- "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-plain-obj": "^1.0.0"
},
@@ -2658,9 +2338,8 @@
},
"node_modules/sort-keys-length": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
- "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"sort-keys": "^1.0.0"
},
@@ -2670,27 +2349,24 @@
},
"node_modules/source-map": {
"version": "0.7.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
- "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true,
+ "license": "BSD-3-Clause",
"engines": {
"node": ">= 8"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -2700,27 +2376,24 @@
},
"node_modules/strip-eof": {
"version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-final-newline": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -2730,9 +2403,8 @@
},
"node_modules/strip-outer": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz",
- "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -2741,16 +2413,15 @@
}
},
"node_modules/strtok3": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
- "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
+ "version": "7.1.1",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
- "peek-readable": "^5.0.0"
+ "peek-readable": "^5.1.3"
},
"engines": {
- "node": ">=14.16"
+ "node": ">=16"
},
"funding": {
"type": "github",
@@ -2759,9 +2430,8 @@
},
"node_modules/supports-color": {
"version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -2771,15 +2441,13 @@
},
"node_modules/text-table": {
"version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/to-regex-range": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -2789,9 +2457,8 @@
},
"node_modules/token-types": {
"version": "5.0.1",
- "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
- "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
@@ -2806,9 +2473,8 @@
},
"node_modules/trim-repeated": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz",
- "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"escape-string-regexp": "^5.0.0"
},
@@ -2816,13 +2482,23 @@
"node": ">=12"
}
},
+ "node_modules/trim-repeated/node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/ts-api-utils": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
- "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+ "version": "1.3.0",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=16.13.0"
+ "node": ">=16"
},
"peerDependencies": {
"typescript": ">=4.2.0"
@@ -2830,9 +2506,8 @@
},
"node_modules/type-check": {
"version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"prelude-ls": "^1.2.1"
},
@@ -2842,9 +2517,8 @@
},
"node_modules/type-fest": {
"version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
+ "license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=10"
},
@@ -2853,62 +2527,71 @@
}
},
"node_modules/typescript": {
- "version": "4.9.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
- "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "version": "5.6.2",
"dev": true,
+ "license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
- "node": ">=4.2.0"
+ "node": ">=14.17"
}
},
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/uri-js": {
"version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "version": "2.0.2",
"dev": true,
+ "license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
},
"bin": {
- "which": "bin/which"
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/yallist": {
"version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
- "dev": true
+ "dev": true,
+ "license": "ISC"
},
"node_modules/yocto-queue": {
"version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=10"
},
diff --git a/package.json b/package.json
index f9610a1..5684b24 100644
--- a/package.json
+++ b/package.json
@@ -5,12 +5,13 @@
"description": "A pure javascript shim for WASI",
"type": "module",
"scripts": {
- "build": "swc src -d dist -s true && tsc --emitDeclarationOnly",
+ "build": "npm run worker && swc src -d dist -s true && tsc --emitDeclarationOnly",
"prepare": "swc src -d dist && tsc --emitDeclarationOnly",
"test:node": "./test/run-testsuite.sh node",
"test:browser": "playwright-core install && ./test/run-testsuite.sh browser",
"test": "npm run test:node && npm run test:browser",
- "check": "tsc --noEmit && prettier src -c && eslint src/"
+ "check": "tsc --noEmit && prettier src -c && eslint src/",
+ "worker": "spack --config ./src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs && node src/wasi_farm/shared_array_buffer/worker_background/minify.js"
},
"repository": {
"type": "git",
@@ -39,6 +40,9 @@
"eslint": "^8.50.0",
"playwright": "^1.40.1",
"prettier": "^3.0.3",
- "typescript": "^4.9.5"
+ "typescript": "^5.6.2"
+ },
+ "dependencies": {
+ "@bjorn3/browser_wasi_shim": "file:"
}
}
diff --git a/src/fd.ts b/src/fd.ts
index 4e3b6f5..a9dd115 100644
--- a/src/fd.ts
+++ b/src/fd.ts
@@ -78,6 +78,7 @@ export abstract class Fd {
mtim: bigint,
fst_flags: number,
): number {
+ console.warn("path_filestat_set_times not implemented");
return wasi.ERRNO_NOTSUP;
}
path_link(path: string, inode: Inode, allow_dir: boolean): number {
@@ -117,11 +118,18 @@ export abstract class Fd {
}
export abstract class Inode {
+ file_stat: wasi.Filestat;
+ constructor(file_stat: wasi.Filestat) {
+ this.file_stat = file_stat;
+ }
+
abstract path_open(
oflags: number,
fs_rights_base: bigint,
fd_flags: number,
): { ret: number; fd_obj: Fd | null };
- abstract stat(): wasi.Filestat;
+ stat(): wasi.Filestat {
+ return this.file_stat;
+ }
}
diff --git a/src/fs_mem.ts b/src/fs_mem.ts
index 6f540ee..fad93bf 100644
--- a/src/fs_mem.ts
+++ b/src/fs_mem.ts
@@ -119,6 +119,16 @@ export class OpenFile extends Fd {
fd_filestat_get(): { ret: number; filestat: wasi.Filestat } {
return { ret: 0, filestat: this.file.stat() };
}
+
+ fd_filestat_set_times(atim: bigint, mtim: bigint, fst_flags: number): number {
+ if (fst_flags & wasi.FSTFLAGS_ATIM) {
+ this.file.file_stat.atim = atim;
+ }
+ if (fst_flags & wasi.FSTFLAGS_MTIM) {
+ this.file.file_stat.mtim = mtim;
+ }
+ return wasi.ERRNO_SUCCESS;
+ }
}
export class OpenDirectory extends Fd {
@@ -128,7 +138,7 @@ export class OpenDirectory extends Fd {
super();
this.dir = dir;
}
-
+ OpenDirectory;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fd_seek(offset: bigint, whence: number): { ret: number; offset: bigint } {
return { ret: wasi.ERRNO_BADF, offset: 0n };
@@ -199,6 +209,31 @@ export class OpenDirectory extends Fd {
return { ret: 0, filestat: entry.stat() };
}
+ path_filestat_set_times(
+ flags: number,
+ path_str: string,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ): number {
+ const { ret: path_err, path } = Path.from(path_str);
+ if (path == null) {
+ return path_err;
+ }
+
+ const { ret, entry } = this.dir.get_entry_for_path(path);
+ if (entry == null) {
+ return ret;
+ }
+
+ if (fst_flags & wasi.FSTFLAGS_ATIM) {
+ entry.file_stat.atim = atim;
+ entry.file_stat.mtim = mtim;
+ }
+
+ return wasi.ERRNO_SUCCESS;
+ }
+
path_lookup(
path_str: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -471,7 +506,12 @@ export class File extends Inode {
readonly: boolean;
}>,
) {
- super();
+ super(
+ new wasi.Filestat(
+ wasi.FILETYPE_REGULAR_FILE,
+ BigInt(new Uint8Array(data).byteLength),
+ ),
+ );
this.data = new Uint8Array(data);
this.readonly = !!options?.readonly;
}
@@ -496,12 +536,20 @@ export class File extends Inode {
return { ret: wasi.ERRNO_SUCCESS, fd_obj: file };
}
- get size(): bigint {
- return BigInt(this.data.byteLength);
+ path_filestat_set_times(
+ flags: number,
+ path_str: string,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ): number {
+ this.file_stat.atim = atim;
+ this.file_stat.mtim = mtim;
+ return wasi.ERRNO_SUCCESS;
}
- stat(): wasi.Filestat {
- return new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, this.size);
+ get size(): bigint {
+ return BigInt(this.data.byteLength);
}
}
@@ -549,7 +597,7 @@ export class Directory extends Inode {
contents: Map;
constructor(contents: Map | [string, Inode][]) {
- super();
+ super(new wasi.Filestat(wasi.FILETYPE_DIRECTORY, 0n));
if (contents instanceof Array) {
this.contents = new Map(contents);
} else {
@@ -562,10 +610,6 @@ export class Directory extends Inode {
return { ret: wasi.ERRNO_SUCCESS, fd_obj: new OpenDirectory(this) };
}
- stat(): wasi.Filestat {
- return new wasi.Filestat(wasi.FILETYPE_DIRECTORY, 0n);
- }
-
get_entry_for_path(path: Path): { ret: number; entry: Inode | null } {
let entry: Inode = this;
for (const component of path.parts) {
@@ -576,7 +620,7 @@ export class Directory extends Inode {
if (child !== undefined) {
entry = child;
} else {
- debug.log(component);
+ debug.log("no such entry", component);
return { ret: wasi.ERRNO_NOENT, entry: null };
}
}
diff --git a/src/fs_opfs.ts b/src/fs_opfs.ts
index 7cdde8d..91f602c 100644
--- a/src/fs_opfs.ts
+++ b/src/fs_opfs.ts
@@ -28,7 +28,9 @@ export class SyncOPFSFile extends Inode {
readonly: boolean;
}>,
) {
- super();
+ super(
+ new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, BigInt(handle.getSize())),
+ );
this.handle = handle;
this.readonly = !!options?.readonly;
}
@@ -56,10 +58,6 @@ export class SyncOPFSFile extends Inode {
get size(): bigint {
return BigInt(this.handle.getSize());
}
-
- stat(): wasi.Filestat {
- return new wasi.Filestat(wasi.FILETYPE_REGULAR_FILE, this.size);
- }
}
export class OpenSyncOPFSFile extends Fd {
diff --git a/src/index.ts b/src/index.ts
index 5f80030..a3ed42a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,8 @@
import WASI, { WASIProcExit } from "./wasi.js";
export { WASI, WASIProcExit };
-
+import { WASIFarm, WASIFarmRef, WASIFarmAnimal } from "./wasi_farm/index.js";
+export { WASIFarm, WASIFarmRef, WASIFarmAnimal };
+export { thread_spawn_on_worker } from "./wasi_farm/index.js";
export { Fd, Inode } from "./fd.js";
export {
File,
diff --git a/src/serialize_error.ts b/src/serialize_error.ts
new file mode 100644
index 0000000..0672412
--- /dev/null
+++ b/src/serialize_error.ts
@@ -0,0 +1,23 @@
+export type SerializedError = {
+ message: string;
+ name: string;
+ stack: string;
+ cause?: unknown;
+};
+
+export const serialize = (error: Error): SerializedError => {
+ return {
+ message: error.message,
+ name: error.name,
+ stack: error.stack,
+ cause: error.cause,
+ };
+};
+
+export const deserialize = (serializedError: SerializedError): Error => {
+ const error = new Error(serializedError.message);
+ error.name = serializedError.name;
+ error.stack = serializedError.stack.replace(/.wasm:/g, ".wasm\n");
+ error.cause = serializedError.cause;
+ return error;
+};
diff --git a/src/wasi.ts b/src/wasi.ts
index 4cb409b..b5e2428 100644
--- a/src/wasi.ts
+++ b/src/wasi.ts
@@ -16,10 +16,10 @@ export class WASIProcExit extends Error {
}
export default class WASI {
- args: Array = [];
- env: Array = [];
- fds: Array = [];
- inst: { exports: { memory: WebAssembly.Memory } };
+ private args: Array = [];
+ private env: Array = [];
+ private fds: Array = [];
+ private inst: { exports: { memory: WebAssembly.Memory } };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
wasiImport: { [key: string]: (...args: Array) => unknown };
diff --git a/src/wasi_farm/animals.ts b/src/wasi_farm/animals.ts
new file mode 100644
index 0000000..c835c3c
--- /dev/null
+++ b/src/wasi_farm/animals.ts
@@ -0,0 +1,1470 @@
+import { debug } from "../debug.js";
+import { type Options, WASIProcExit } from "../wasi.js";
+import * as wasi from "../wasi_defs.js";
+import type { WASIFarmRef } from "./ref.js";
+import type { WASIFarmRefObject } from "./ref.js";
+import type { FdCloseSender } from "./sender.js";
+import { WASIFarmRefUseArrayBuffer } from "./shared_array_buffer/index.js";
+import type { WASIFarmRefUseArrayBufferObject } from "./shared_array_buffer/index.js";
+import { ThreadSpawner } from "./shared_array_buffer/index.js";
+
+export class WASIFarmAnimal {
+ args: Array;
+ env: Array;
+
+ private wasi_farm_refs: WASIFarmRef[];
+
+ private id_in_wasi_farm_ref: Array;
+
+ private extend_imports: boolean;
+
+ inst: { exports: { memory: WebAssembly.Memory } };
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ wasiImport: { [key: string]: (...args: Array) => unknown };
+
+ wasiThreadImport: {
+ "thread-spawn": (start_arg: number) => number;
+ };
+
+ extendImport: {
+ fetch_open: (
+ url_ptr: number,
+ url_len: number,
+ method_ptr: number,
+ method_len: number,
+ serialized_headers_ptr: number,
+ serialized_headers_len: number,
+ body_ptr: number,
+ body_len: number,
+ ) => number;
+ };
+
+ private can_array_buffer;
+
+ private can_thread_spawn: boolean;
+
+ private thread_spawner: ThreadSpawner;
+
+ async wait_worker_background_worker(): Promise {
+ await this.thread_spawner.wait_worker_background_worker();
+ }
+
+ check_worker_background_worker(): void {
+ this.thread_spawner.check_worker_background_worker();
+ }
+
+ // Each process has a specific fd that it can access.
+ // If it does not exist in the map, it cannot be accessed.
+ // child process can access parent process's fd.
+ // so, it is necessary to manage the fd on global scope.
+ // [fd, wasi_ref_n]
+ protected fd_map: Array<[number, number]>;
+
+ protected get_fd_and_wasi_ref(
+ fd: number,
+ ): [number | undefined, WASIFarmRef | undefined] {
+ const mapped_fd_and_wasi_ref_n = this.fd_map[fd];
+ if (!mapped_fd_and_wasi_ref_n) {
+ // console.log("fd", fd, "is not found");
+ return [undefined, undefined];
+ }
+ const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n;
+ // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n);
+ return [mapped_fd, this.wasi_farm_refs[wasi_ref_n]];
+ }
+
+ protected get_fd_and_wasi_ref_n(
+ fd: number,
+ ): [number | undefined, number | undefined] {
+ const mapped_fd_and_wasi_ref_n = this.fd_map[fd];
+ if (!mapped_fd_and_wasi_ref_n) {
+ // console.log("fd", fd, "is not found");
+ return [undefined, undefined];
+ }
+ const [mapped_fd, wasi_ref_n] = mapped_fd_and_wasi_ref_n;
+ // console.log("fd", fd, "is found", "mapped_fd", mapped_fd, "wasi_ref_n", wasi_ref_n);
+ return [mapped_fd, wasi_ref_n];
+ }
+
+ /// Start a WASI command
+ start(instance: {
+ // FIXME v0.3: close opened Fds after execution
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ }) {
+ this.inst = instance;
+
+ try {
+ instance.exports._start();
+
+ if (this.can_thread_spawn) {
+ this.thread_spawner.done_notify(0);
+ }
+
+ return 0;
+ } catch (e) {
+ if (e instanceof WASIProcExit) {
+ if (this.can_thread_spawn) {
+ this.thread_spawner.done_notify(e.code);
+ }
+
+ return e.code;
+ }
+ throw e;
+ }
+ }
+
+ /// Start a WASI command on a thread
+ /// If a module has child threads and a child thread throws an error,
+ /// the main thread should also be stopped,
+ /// but there is no way to stop it,
+ /// so the entire worker is stopped.
+ /// If it is not necessary, do not use it.
+ /// Custom imports are not implemented,
+ /// function because it cannot be passed to other threads.
+ /// If the sharedObject library someday supports synchronization, it could be used to support this.
+ async async_start_on_thread(): Promise {
+ if (!this.can_thread_spawn) {
+ throw new Error("thread_spawn is not supported");
+ }
+
+ await this.wait_worker_background_worker();
+
+ if (this.inst) {
+ throw new Error("what happened?");
+ }
+
+ const view = new Uint8Array(this.get_share_memory().buffer);
+ view.fill(0);
+
+ await this.thread_spawner.async_start_on_thread(
+ this.args,
+ this.env,
+ this.extend_imports,
+ );
+
+ const code = await this.thread_spawner.async_wait_done_or_error();
+
+ return code;
+ }
+
+ block_start_on_thread(): number {
+ if (!this.can_thread_spawn) {
+ throw new Error("thread_spawn is not supported");
+ }
+
+ console.log("block_start_on_thread");
+
+ this.check_worker_background_worker();
+
+ console.log("block_start_on_thread");
+
+ if (this.inst) {
+ throw new Error("what happened?");
+ }
+
+ const view = new Uint8Array(this.get_share_memory().buffer);
+ view.fill(0);
+
+ console.log("block_start_on_thread: start");
+
+ this.thread_spawner.block_start_on_thread(
+ this.args,
+ this.env,
+ this.extend_imports,
+ );
+
+ console.log("block_start_on_thread: wait");
+
+ const code = this.thread_spawner.block_wait_done_or_error();
+
+ console.log("block_start_on_thread: done");
+
+ return code;
+ }
+
+ wasi_thread_start(
+ instance: {
+ exports: {
+ memory: WebAssembly.Memory;
+ wasi_thread_start: (thread_id: number, start_arg: number) => void;
+ };
+ },
+ thread_id: number,
+ start_arg: number,
+ ) {
+ this.inst = instance;
+ try {
+ instance.exports.wasi_thread_start(thread_id, start_arg);
+ return 0;
+ } catch (e) {
+ if (e instanceof WASIProcExit) {
+ return e.code;
+ }
+ throw e;
+ }
+ }
+
+ /// Initialize a WASI reactor
+ initialize(instance: {
+ exports: { memory: WebAssembly.Memory; _initialize?: () => unknown };
+ }) {
+ this.inst = instance;
+ if (instance.exports._initialize) {
+ instance.exports._initialize();
+ }
+ }
+
+ private mapping_fds(
+ wasi_farm_refs: Array,
+ override_fd_maps?: Array,
+ ) {
+ this.fd_map = [undefined, undefined, undefined];
+
+ // console.log("wasi_farm_refs", wasi_farm_refs);
+ for (let i = 0; i < wasi_farm_refs.length; i++) {
+ // console.log("fd_map", [...this.fd_map]);
+
+ const wasi_farm_ref = wasi_farm_refs[i];
+ // console.log("override_fd_map", wasi_farm_ref.default_fds);
+ const override_fd_map = override_fd_maps
+ ? override_fd_maps[i]
+ : wasi_farm_ref.default_fds;
+ // console.log("override_fd_map", override_fd_map);
+ const stdin = wasi_farm_ref.get_stdin();
+ const stdout = wasi_farm_ref.get_stdout();
+ const stderr = wasi_farm_ref.get_stderr();
+ // console.log("stdin", stdin, "stdout", stdout, "stderr", stderr);
+ if (stdin !== undefined) {
+ if (this.fd_map[0] === undefined) {
+ if (override_fd_map.includes(stdin)) {
+ this.fd_map[0] = [stdin, i];
+ }
+ }
+ }
+ if (stdout !== undefined) {
+ // console.log("stdout", stdout, i, "override_fd_map", override_fd_map);
+ if (this.fd_map[1] === undefined) {
+ if (override_fd_map.includes(stdout)) {
+ // console.log("stdout defined");
+ this.fd_map[1] = [stdout, i];
+ }
+ }
+ }
+ if (stderr !== undefined) {
+ if (this.fd_map[2] === undefined) {
+ if (override_fd_map.includes(stderr)) {
+ this.fd_map[2] = [stderr, i];
+ }
+ }
+ }
+ for (const j of override_fd_map) {
+ if (j === stdin || j === stdout || j === stderr) {
+ continue;
+ }
+ this.map_new_fd(j, i);
+ }
+ wasi_farm_ref.set_park_fds_map(override_fd_map);
+
+ // console.log("fd_map", this.fd_map);
+ }
+
+ if (this.fd_map[0] === undefined) {
+ throw new Error("stdin is not found");
+ }
+ if (this.fd_map[1] === undefined) {
+ throw new Error("stdout is not found");
+ }
+ if (this.fd_map[2] === undefined) {
+ throw new Error("stderr is not found");
+ }
+ }
+
+ private map_new_fd(fd: number, wasi_ref_n: number): number {
+ let n = -1;
+ // 0, 1, 2 are reserved for stdin, stdout, stderr
+ for (let i = 3; i < this.fd_map.length; i++) {
+ if (this.fd_map[i] === undefined) {
+ n = i;
+ break;
+ }
+ }
+ if (n === -1) {
+ n = this.fd_map.push(undefined) - 1;
+ }
+ this.fd_map[n] = [fd, wasi_ref_n];
+ return n;
+ }
+
+ private map_new_fd_and_notify(fd: number, wasi_ref_n: number): number {
+ const n = this.map_new_fd(fd, wasi_ref_n);
+ // console.log("animals: fd", fd, "is mapped to", n);
+ // console.log("wasi_ref_n", wasi_ref_n);
+ this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]);
+ return n;
+ }
+
+ private map_set_fd_and_notify(fd: number, wasi_ref_n: number, index: number) {
+ if (this.fd_map[index] !== undefined) {
+ throw new Error("fd is already mapped");
+ }
+ this.fd_map[index] = [fd, wasi_ref_n];
+ this.wasi_farm_refs[wasi_ref_n].set_park_fds_map([fd]);
+ }
+
+ private check_fds() {
+ const rm_fds: Array<[number, number]> = [];
+ for (let i = 0; i < this.id_in_wasi_farm_ref.length; i++) {
+ const id = this.id_in_wasi_farm_ref[i];
+ const removed_fds = (this.wasi_farm_refs[i] as FdCloseSender).get(id);
+ if (removed_fds) {
+ for (const fd of removed_fds) {
+ rm_fds.push([fd, i]);
+ }
+ }
+ }
+
+ if (rm_fds.length > 0) {
+ for (let i = 0; i < this.fd_map.length; i++) {
+ const fd_and_wasi_ref_n = this.fd_map[i];
+ // biome-ignore lint/suspicious/noDoubleEquals:
+ if (fd_and_wasi_ref_n == undefined) {
+ continue;
+ }
+ // console.log("fd_and_wasi_ref_n", fd_and_wasi_ref_n);
+ const [fd, wasi_ref_n] = fd_and_wasi_ref_n;
+ for (const [rm_fd_fd, rm_fd_wasi_ref_n] of rm_fds) {
+ if (fd === rm_fd_fd && wasi_ref_n === rm_fd_wasi_ref_n) {
+ this.fd_map[i] = undefined;
+ // console.log("fd", i, "is removed");
+ break;
+ }
+ }
+ // console.log("fd_and_wasi_ref_n", fd_and_wasi_ref_n);
+ }
+ // console.log("rm_fds.length", rm_fds.length);
+ // console.log("rm_fds", rm_fds);
+ }
+ }
+
+ get_share_memory(): WebAssembly.Memory {
+ return this.thread_spawner.get_share_memory();
+ }
+
+ constructor(
+ wasi_farm_refs: WASIFarmRefObject[] | WASIFarmRefObject,
+ args: Array,
+ env: Array,
+ options: Options & {
+ can_thread_spawn?: boolean;
+ thread_spawn_worker_url?: string;
+ thread_spawn_wasm?: WebAssembly.Module;
+ extend_imports?: boolean;
+ hand_override_fd_map?: Array<[number, number]>;
+ } = {},
+ override_fd_maps?: Array,
+ thread_spawner?: ThreadSpawner,
+ ) {
+ debug.enable(options.debug);
+
+ this.extend_imports = options.extend_imports || false;
+
+ let wasi_farm_refs_tmp: WASIFarmRefObject[];
+ if (Array.isArray(wasi_farm_refs)) {
+ wasi_farm_refs_tmp =
+ wasi_farm_refs as unknown as Array;
+ } else {
+ wasi_farm_refs_tmp = [wasi_farm_refs as unknown as WASIFarmRefObject];
+ }
+
+ try {
+ new SharedArrayBuffer(4);
+ this.can_array_buffer = true;
+ } catch (_) {
+ this.can_array_buffer = false;
+ }
+
+ this.id_in_wasi_farm_ref = [];
+ this.wasi_farm_refs = [];
+ for (let i = 0; i < wasi_farm_refs_tmp.length; i++) {
+ if (this.can_array_buffer) {
+ this.wasi_farm_refs.push(
+ WASIFarmRefUseArrayBuffer.init_self(
+ wasi_farm_refs_tmp[i] as WASIFarmRefUseArrayBufferObject,
+ ),
+ );
+ } else {
+ throw new Error("Non SharedArrayBuffer is not supported yet");
+ }
+ this.id_in_wasi_farm_ref.push(this.wasi_farm_refs[i].set_id());
+ }
+
+ // console.log("this.wasi_farm_refs", this.wasi_farm_refs);
+
+ if (options.can_thread_spawn) {
+ this.can_thread_spawn = options.can_thread_spawn;
+
+ if (thread_spawner) {
+ if (!(thread_spawner instanceof ThreadSpawner)) {
+ throw new Error("thread_spawner is not ThreadSpawner");
+ }
+
+ this.thread_spawner = thread_spawner;
+ } else {
+ if (options.thread_spawn_worker_url === undefined) {
+ throw new Error("thread_spawn_worker_url is not defined");
+ }
+ if (options.thread_spawn_wasm === undefined) {
+ throw new Error("thread_spawn_wasm is not defined");
+ }
+
+ this.thread_spawner = new ThreadSpawner(
+ options.thread_spawn_worker_url,
+ wasi_farm_refs_tmp,
+ undefined,
+ undefined,
+ undefined,
+ options.thread_spawn_wasm,
+ );
+ }
+ }
+
+ this.mapping_fds(this.wasi_farm_refs, override_fd_maps);
+ if (options.hand_override_fd_map) {
+ this.fd_map = options.hand_override_fd_map;
+ }
+
+ // console.log("this.fd_map", this.fd_map);
+
+ this.args = args;
+ this.env = env;
+ const self = this;
+ this.wasiImport = {
+ args_sizes_get(argc: number, argv_buf_size: number): number {
+ self.check_fds();
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setUint32(argc, self.args.length, true);
+ let buf_size = 0;
+ for (const arg of self.args) {
+ buf_size += arg.length + 1;
+ }
+ buffer.setUint32(argv_buf_size, buf_size, true);
+ // debug.log(
+ // buffer.getUint32(argc, true),
+ // buffer.getUint32(argv_buf_size, true),
+ // );
+ debug.log("read args_sizes_get: len", self.args.length);
+ return 0;
+ },
+ args_get(argv: number, argv_buf: number): number {
+ self.check_fds();
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const orig_argv_buf = argv_buf;
+ for (let i = 0; i < self.args.length; i++) {
+ buffer.setUint32(argv, argv_buf, true);
+ argv += 4;
+ const arg = new TextEncoder().encode(self.args[i]);
+ buffer8.set(arg, argv_buf);
+ buffer.setUint8(argv_buf + arg.length, 0);
+ argv_buf += arg.length + 1;
+ }
+ // if (debug.enabled) {
+ debug.log(
+ "read args_get: args",
+ new TextDecoder("utf-8").decode(
+ buffer8.slice(orig_argv_buf, argv_buf),
+ ),
+ );
+ // }
+ return 0;
+ },
+ environ_sizes_get(environ_count: number, environ_size: number): number {
+ self.check_fds();
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setUint32(environ_count, self.env.length, true);
+ let buf_size = 0;
+ for (const environ of self.env) {
+ buf_size += environ.length + 1;
+ }
+ buffer.setUint32(environ_size, buf_size, true);
+ // debug.log(
+ // buffer.getUint32(environ_count, true),
+ // buffer.getUint32(environ_size, true),
+ // );
+ debug.log("read environ_sizes_get: len", self.env.length);
+ return 0;
+ },
+ environ_get(environ: number, environ_buf: number): number {
+ self.check_fds();
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const orig_environ_buf = environ_buf;
+ for (let i = 0; i < self.env.length; i++) {
+ buffer.setUint32(environ, environ_buf, true);
+ environ += 4;
+ const e = new TextEncoder().encode(self.env[i]);
+ buffer8.set(e, environ_buf);
+ buffer.setUint8(environ_buf + e.length, 0);
+ environ_buf += e.length + 1;
+ }
+ // if (debug.enabled) {
+ debug.log(
+ "read environ_get: environ",
+ new TextDecoder("utf-8").decode(
+ buffer8.slice(orig_environ_buf, environ_buf),
+ ),
+ );
+ // }
+ return 0;
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ clock_res_get(id: number, res_ptr: number): number {
+ self.check_fds();
+ let resolutionValue: bigint;
+ switch (id) {
+ case wasi.CLOCKID_MONOTONIC: {
+ // https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
+ // > Resolution in isolated contexts: 5 microseconds
+ resolutionValue = 5_000n; // 5 microseconds
+ break;
+ }
+ case wasi.CLOCKID_REALTIME: {
+ resolutionValue = 1_000_000n; // 1 millisecond?
+ break;
+ }
+ default:
+ return wasi.ERRNO_NOSYS;
+ }
+ const view = new DataView(self.inst.exports.memory.buffer);
+ view.setBigUint64(res_ptr, resolutionValue, true);
+ return wasi.ERRNO_SUCCESS;
+ },
+ clock_time_get(id: number, precision: bigint, time: number): number {
+ self.check_fds();
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ if (id === wasi.CLOCKID_REALTIME) {
+ buffer.setBigUint64(
+ time,
+ BigInt(new Date().getTime()) * 1_000_000n,
+ true,
+ );
+ } else if (id === wasi.CLOCKID_MONOTONIC) {
+ let monotonic_time: bigint;
+ try {
+ monotonic_time = BigInt(Math.round(performance.now() * 1000000));
+ } catch (e) {
+ // performance.now() is only available in browsers.
+ // TODO use the perf_hooks builtin module for NodeJS
+ monotonic_time = 0n;
+ }
+ buffer.setBigUint64(time, monotonic_time, true);
+ } else {
+ // TODO
+ buffer.setBigUint64(time, 0n, true);
+ }
+ return 0;
+ },
+ fd_advise(
+ fd: number,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ offset: bigint,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ len: bigint,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ advice: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_advise(mapped_fd);
+ },
+ fd_allocate(fd: number, offset: bigint, len: bigint) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_allocate(mapped_fd, offset, len);
+ },
+ fd_close(fd: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const ret = wasi_farm_ref.fd_close(mapped_fd);
+ self.check_fds();
+ return ret;
+ },
+ fd_datasync(fd: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_datasync(mapped_fd);
+ },
+ fd_fdstat_get(fd: number, fdstat_ptr: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const [fdstat, ret] = wasi_farm_ref.fd_fdstat_get(mapped_fd);
+ if (fdstat) {
+ fdstat.write_bytes(
+ new DataView(self.inst.exports.memory.buffer),
+ fdstat_ptr,
+ );
+ }
+ return ret;
+ },
+ fd_fdstat_set_flags(fd: number, flags: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_fdstat_set_flags(mapped_fd, flags);
+ },
+ fd_fdstat_set_rights(
+ fd: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_fdstat_set_rights(
+ mapped_fd,
+ fs_rights_base,
+ fs_rights_inheriting,
+ );
+ },
+ fd_filestat_get(fd: number, filestat_ptr: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const [filestat, ret] = wasi_farm_ref.fd_filestat_get(mapped_fd);
+ if (filestat) {
+ filestat.write_bytes(
+ new DataView(self.inst.exports.memory.buffer),
+ filestat_ptr,
+ );
+ }
+ return ret;
+ },
+ fd_filestat_set_size(fd: number, size: bigint) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_filestat_set_size(mapped_fd, size);
+ },
+ fd_filestat_set_times(
+ fd: number,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_filestat_set_times(
+ mapped_fd,
+ atim,
+ mtim,
+ fst_flags,
+ );
+ },
+ fd_pread(
+ fd: number,
+ iovs_ptr: number,
+ iovs_len: number,
+ offset: bigint,
+ nread_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const iovs_view = new Uint32Array(
+ buffer.buffer,
+ iovs_ptr,
+ iovs_len * 2,
+ );
+ const [nerad_and_read_data, ret] = wasi_farm_ref.fd_pread(
+ mapped_fd,
+ iovs_view,
+ offset,
+ );
+ if (nerad_and_read_data) {
+ const iovecs = wasi.Iovec.read_bytes_array(
+ buffer,
+ iovs_ptr,
+ iovs_len,
+ );
+ const [nread, read_data] = nerad_and_read_data;
+ buffer.setUint32(nread_ptr, nread, true);
+ let nreaded = 0;
+ for (const iovec of iovecs) {
+ if (nreaded + iovec.buf_len >= read_data.length) {
+ buffer8.set(read_data, iovec.buf);
+ break;
+ }
+ buffer8.set(
+ read_data.slice(nreaded, nreaded + iovec.buf_len),
+ iovec.buf,
+ );
+ nreaded += iovec.buf_len;
+ }
+ }
+ return ret;
+ },
+ fd_prestat_get(fd: number, prestat_ptr: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const [prestat, ret] = wasi_farm_ref.fd_prestat_get(mapped_fd);
+ if (prestat) {
+ const [tag, name_len] = prestat;
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setUint32(prestat_ptr, tag, true);
+ buffer.setUint32(prestat_ptr + 4, name_len, true);
+ }
+ return ret;
+ },
+ fd_prestat_dir_name(fd: number, path_ptr: number, path_len: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ // console.log("fd_prestat_dir_name: fd", mapped_fd, "path_len", path_len);
+ const [path, ret] = wasi_farm_ref.fd_prestat_dir_name(
+ mapped_fd,
+ path_len,
+ );
+ if (path) {
+ // console.log("fd_prestat_dir_name", new TextDecoder().decode(path));
+ // console.log("fd_prestat_dir_name", path);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ buffer8.set(path, path_ptr);
+ }
+ return ret;
+ },
+ fd_pwrite(
+ fd: number,
+ iovs_ptr: number,
+ iovs_len: number,
+ offset: bigint,
+ nwritten_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
+ const data = new Uint8Array(
+ iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0),
+ );
+ let nwritten = 0;
+ for (const iovec of iovecs) {
+ data.set(
+ buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len),
+ nwritten,
+ );
+ nwritten += iovec.buf_len;
+ }
+ const [written, ret] = wasi_farm_ref.fd_pwrite(mapped_fd, data, offset);
+ if (written) {
+ buffer.setUint32(nwritten_ptr, written, true);
+ }
+ return ret;
+ },
+ fd_read(
+ fd: number,
+ iovs_ptr: number,
+ iovs_len: number,
+ nread_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const iovs_view = new Uint32Array(
+ buffer.buffer,
+ iovs_ptr,
+ iovs_len * 2,
+ );
+
+ const [nerad_and_read_data, ret] = wasi_farm_ref.fd_read(
+ mapped_fd,
+ iovs_view,
+ );
+ if (nerad_and_read_data) {
+ const iovecs = wasi.Iovec.read_bytes_array(
+ buffer,
+ iovs_ptr,
+ iovs_len,
+ );
+ const [nread, read_data] = nerad_and_read_data;
+
+ // console.log("fd_read: nread", nread, new TextDecoder().decode(read_data));
+
+ // fd_read: ref: 14 30 14
+ // animals.ts:325 fd_read: nread 14 Hello, world!
+
+ buffer.setUint32(nread_ptr, nread, true);
+ let nreaded = 0;
+ for (const iovec of iovecs) {
+ if (nreaded + iovec.buf_len >= read_data.length) {
+ buffer8.set(read_data, iovec.buf);
+ break;
+ }
+ buffer8.set(
+ read_data.slice(nreaded, nreaded + iovec.buf_len),
+ iovec.buf,
+ );
+ nreaded += iovec.buf_len;
+ }
+ }
+ return ret;
+ },
+ fd_readdir(
+ fd: number,
+ buf_ptr: number,
+ buf_len: number,
+ cookie: bigint,
+ buf_used_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const [nerad_and_read_data, ret] = wasi_farm_ref.fd_readdir(
+ mapped_fd,
+ buf_len,
+ cookie,
+ );
+ if (nerad_and_read_data) {
+ const [read_data, buf_used] = nerad_and_read_data;
+ buffer.setUint32(buf_used_ptr, buf_used, true);
+ buffer8.set(read_data, buf_ptr);
+ }
+ return ret;
+ },
+ fd_renumber(fd: number, to: number) {
+ self.check_fds();
+
+ const [mapped_to, wasi_farm_ref_to] = self.get_fd_and_wasi_ref(to);
+
+ if (mapped_to !== undefined && wasi_farm_ref_to !== undefined) {
+ const ret = wasi_farm_ref_to.fd_close(mapped_to);
+ self.check_fds();
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ return ret;
+ }
+ }
+
+ if (self.fd_map[to]) {
+ throw new Error("fd is already mapped");
+ }
+
+ self.fd_map[to] = self.fd_map[fd];
+
+ self.fd_map[fd] = undefined;
+
+ return wasi.ERRNO_SUCCESS;
+ },
+ fd_seek(
+ fd: number,
+ offset: bigint,
+ whence: number,
+ newoffset_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const [newoffset, ret] = wasi_farm_ref.fd_seek(
+ mapped_fd,
+ offset,
+ whence,
+ );
+ if (newoffset) {
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+
+ // wasi.ts use BigInt for offset, but API use Uint64
+ buffer.setBigUint64(newoffset_ptr, newoffset, true);
+ }
+ return ret;
+ },
+ fd_sync(fd: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ return wasi_farm_ref.fd_sync(mapped_fd);
+ },
+ fd_tell(fd: number, newoffset_ptr: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const [newoffset, ret] = wasi_farm_ref.fd_tell(mapped_fd);
+ if (newoffset) {
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setBigUint64(newoffset_ptr, newoffset, true);
+ }
+ return ret;
+ },
+ fd_write(
+ fd: number,
+ iovs_ptr: number,
+ iovs_len: number,
+ nwritten_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+
+ // console.log("fd_write", fd, iovs_ptr, iovs_len, nwritten_ptr);
+
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const iovecs = wasi.Ciovec.read_bytes_array(buffer, iovs_ptr, iovs_len);
+ // console.log("iovecs", iovecs);
+ const data = new Uint8Array(
+ iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0),
+ );
+ // console.log("data", data);
+ let nwritten = 0;
+ for (const iovec of iovecs) {
+ data.set(
+ buffer8.slice(iovec.buf, iovec.buf + iovec.buf_len),
+ nwritten,
+ );
+ nwritten += iovec.buf_len;
+ }
+
+ // console.log("fd_write: ", fd, new TextDecoder().decode(data));
+
+ const [written, ret] = wasi_farm_ref.fd_write(mapped_fd, data);
+
+ // console.log("fd_write end", fd, ret, written);
+
+ if (written) {
+ buffer.setUint32(nwritten_ptr, written, true);
+ }
+ return ret;
+ },
+ path_create_directory(fd: number, path_ptr: number, path_len: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ return wasi_farm_ref.path_create_directory(mapped_fd, path);
+ },
+ path_filestat_get(
+ fd: number,
+ flags: number,
+ path_ptr: number,
+ path_len: number,
+ filestat_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ const [filestat, ret] = wasi_farm_ref.path_filestat_get(
+ mapped_fd,
+ flags,
+ path,
+ );
+ if (filestat) {
+ filestat.write_bytes(buffer, filestat_ptr);
+ }
+ return ret;
+ },
+ path_filestat_set_times(
+ fd: number,
+ flags: number,
+ path_ptr: number,
+ path_len: number,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ return wasi_farm_ref.path_filestat_set_times(
+ mapped_fd,
+ flags,
+ path,
+ atim,
+ mtim,
+ fst_flags,
+ );
+ },
+ // TODO! Make it work with different wasi_farm_ref
+ path_link(
+ old_fd: number,
+ old_flags: number,
+ old_path_ptr: number,
+ old_path_len: number,
+ new_fd: number,
+ new_path_ptr: number,
+ new_path_len: number,
+ ) {
+ self.check_fds();
+ const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd);
+ const [mapped_new_fd, wasi_farm_ref_new] =
+ self.get_fd_and_wasi_ref(new_fd);
+ if (
+ mapped_old_fd === undefined ||
+ wasi_farm_ref === undefined ||
+ mapped_new_fd === undefined ||
+ wasi_farm_ref_new === undefined
+ ) {
+ return wasi.ERRNO_BADF;
+ }
+ if (wasi_farm_ref !== wasi_farm_ref_new) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const old_path = buffer8.slice(
+ old_path_ptr,
+ old_path_ptr + old_path_len,
+ );
+ const new_path = buffer8.slice(
+ new_path_ptr,
+ new_path_ptr + new_path_len,
+ );
+ return wasi_farm_ref.path_link(
+ mapped_old_fd,
+ old_flags,
+ old_path,
+ mapped_new_fd,
+ new_path,
+ );
+ },
+ path_open(
+ fd: number,
+ dirflags: number,
+ path_ptr: number,
+ path_len: number,
+ oflags: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ fs_flags: number,
+ opened_fd_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(fd);
+ if (mapped_fd === undefined || wasi_farm_ref_n === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const wasi_farm_ref = self.wasi_farm_refs[wasi_farm_ref_n];
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ const [opened_fd, ret] = wasi_farm_ref.path_open(
+ mapped_fd,
+ dirflags,
+ path,
+ oflags,
+ fs_rights_base,
+ fs_rights_inheriting,
+ fs_flags,
+ );
+ if (opened_fd) {
+ if (self.fd_map.includes([opened_fd, wasi_farm_ref_n])) {
+ throw new Error("opened_fd already exists");
+ }
+ const mapped_opened_fd = self.map_new_fd_and_notify(
+ opened_fd,
+ wasi_farm_ref_n,
+ );
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setUint32(opened_fd_ptr, mapped_opened_fd, true);
+ }
+ return ret;
+ },
+ path_readlink(
+ fd: number,
+ path_ptr: number,
+ path_len: number,
+ buf_ptr: number,
+ buf_len: number,
+ buf_used_ptr: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return [undefined, wasi.ERRNO_BADF];
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ const [buf, ret] = wasi_farm_ref.path_readlink(
+ mapped_fd,
+ path,
+ buf_len,
+ );
+ if (buf) {
+ const buffer = new DataView(self.inst.exports.memory.buffer);
+ buffer.setUint32(buf_used_ptr, buf.length, true);
+ buffer8.set(buf, buf_ptr);
+ }
+ return ret;
+ },
+ path_remove_directory(fd: number, path_ptr: number, path_len: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ return wasi_farm_ref.path_remove_directory(mapped_fd, path);
+ },
+ // TODO! Make it work with different wasi_farm_ref
+ path_rename(
+ old_fd: number,
+ old_path_ptr: number,
+ old_path_len: number,
+ new_fd: number,
+ new_path_ptr: number,
+ new_path_len: number,
+ ) {
+ if (old_fd === new_fd) {
+ return wasi.ERRNO_SUCCESS;
+ }
+ console.log("path_rename", old_fd, new_fd);
+ self.check_fds();
+ console.log("path_rename", old_fd, new_fd);
+ const [mapped_old_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(old_fd);
+ const [mapped_new_fd, wasi_farm_ref_new] =
+ self.get_fd_and_wasi_ref(new_fd);
+ if (
+ mapped_old_fd === undefined ||
+ wasi_farm_ref === undefined ||
+ mapped_new_fd === undefined ||
+ wasi_farm_ref_new === undefined
+ ) {
+ return wasi.ERRNO_BADF;
+ }
+ if (wasi_farm_ref !== wasi_farm_ref_new) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const old_path = buffer8.slice(
+ old_path_ptr,
+ old_path_ptr + old_path_len,
+ );
+ const new_path = buffer8.slice(
+ new_path_ptr,
+ new_path_ptr + new_path_len,
+ );
+ return wasi_farm_ref.path_rename(
+ mapped_old_fd,
+ old_path,
+ mapped_new_fd,
+ new_path,
+ );
+ },
+ path_symlink(
+ old_path_ptr: number,
+ old_path_len: number,
+ fd: number,
+ new_path_ptr: number,
+ new_path_len: number,
+ ) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const old_path = buffer8.slice(
+ old_path_ptr,
+ old_path_ptr + old_path_len,
+ );
+ const new_path = buffer8.slice(
+ new_path_ptr,
+ new_path_ptr + new_path_len,
+ );
+ return wasi_farm_ref.path_symlink(old_path, mapped_fd, new_path);
+ },
+ path_unlink_file(fd: number, path_ptr: number, path_len: number) {
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref] = self.get_fd_and_wasi_ref(fd);
+ if (mapped_fd === undefined || wasi_farm_ref === undefined) {
+ return wasi.ERRNO_BADF;
+ }
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+ const path = buffer8.slice(path_ptr, path_ptr + path_len);
+ return wasi_farm_ref.path_unlink_file(mapped_fd, path);
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ poll_oneoff(in_, out, nsubscriptions) {
+ self.check_fds();
+ throw "async io not supported";
+ },
+ proc_exit(exit_code: number) {
+ self.check_fds();
+ throw new WASIProcExit(exit_code);
+ },
+ proc_raise(sig: number) {
+ self.check_fds();
+ throw `raised signal ${sig}`;
+ },
+ sched_yield() {
+ self.check_fds();
+ },
+ random_get(buf: number, buf_len: number) {
+ self.check_fds();
+ const buffer8 = new Uint8Array(
+ self.inst.exports.memory.buffer,
+ ).subarray(buf, buf + buf_len);
+
+ if (
+ "crypto" in globalThis &&
+ !(self.inst.exports.memory.buffer instanceof SharedArrayBuffer)
+ ) {
+ for (let i = 0; i < buf_len; i += 65536) {
+ crypto.getRandomValues(buffer8.subarray(i, i + 65536));
+ }
+ } else {
+ for (let i = 0; i < buf_len; i++) {
+ buffer8[i] = (Math.random() * 256) | 0;
+ }
+ }
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ sock_recv(fd: number, ri_data, ri_flags) {
+ self.check_fds();
+ throw "sockets not supported";
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ sock_send(fd: number, si_data, si_flags) {
+ self.check_fds();
+ throw "sockets not supported";
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ sock_shutdown(fd: number, how) {
+ self.check_fds();
+ throw "sockets not supported";
+ },
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ sock_accept(fd: number, flags) {
+ self.check_fds();
+ throw "sockets not supported";
+ },
+ };
+
+ this.wasiThreadImport = {
+ "thread-spawn": (start_arg: number) => {
+ self.check_fds();
+ if (!self.can_thread_spawn) {
+ throw new Error("thread_spawn is not allowed");
+ }
+
+ const thread_id = self.thread_spawner.thread_spawn(
+ start_arg,
+ self.args,
+ self.env,
+ self.fd_map,
+ self.extend_imports,
+ );
+
+ return thread_id;
+ },
+ };
+
+ if (this.extend_imports) {
+ this.extendImport = {
+ fetch_open: (
+ // i32
+ url_ptr: number,
+ // i32
+ url_len: number,
+ // i32
+ method_ptr: number,
+ // i32
+ method_len: number,
+ // i32
+ serialized_headers_ptr: number,
+ // i32
+ serialized_headers_len: number,
+ // i32
+ body_ptr: number,
+ // i32
+ body_len: number,
+ // fd
+ ): number => {
+ console.log("fetch_open", url_ptr, url_len, method_ptr, method_len);
+
+ const buffer8 = new Uint8Array(self.inst.exports.memory.buffer);
+
+ const url_buf = buffer8.slice(url_ptr, url_ptr + url_len);
+ const method_buf = buffer8.slice(method_ptr, method_ptr + method_len);
+ const serialized_headers_buf = buffer8.slice(
+ serialized_headers_ptr,
+ serialized_headers_ptr + serialized_headers_len,
+ );
+ const body_buf = buffer8.slice(body_ptr, body_ptr + body_len);
+
+ const url = new TextDecoder().decode(url_buf);
+ const method = new TextDecoder().decode(method_buf);
+ const serialized_headers_txt = new TextDecoder().decode(
+ serialized_headers_buf,
+ );
+ const body = new TextDecoder().decode(body_buf);
+ console.log("fetch_open", url, method, serialized_headers_txt, body);
+ const serialized_headers = JSON.parse(serialized_headers_txt);
+ console.log("fetch_open", serialized_headers);
+
+ const request = new XMLHttpRequest();
+ // `false` makes the request synchronous
+ request.open(method, url, false);
+ request.timeout = 10000;
+
+ for (const [key, value] of Object.entries(serialized_headers)) {
+ request.setRequestHeader(key as string, value as string);
+ }
+
+ request.send(body);
+
+ const status = request.status;
+
+ const response_headers_str = request.getAllResponseHeaders();
+
+ console.log("fetch_open", status, response_headers_str);
+
+ // Vec<(String, String)>
+ const response_headers: Array<[string, string]> = [];
+
+ for (const line of response_headers_str.split("\r\n")) {
+ if (line === "") {
+ continue;
+ }
+ const [key, value] = line.split(": ");
+ response_headers.push([key, value]);
+ }
+
+ const response_body = request.response;
+
+ let response_body_u8: Uint8Array;
+
+ console.log(
+ "fetch_open",
+ status,
+ response_headers,
+ response_body,
+ request.responseType,
+ );
+
+ switch (request.responseType) {
+ case "arraybuffer":
+ response_body_u8 = new Uint8Array(response_body);
+ break;
+ case "text":
+ response_body_u8 = new TextEncoder().encode(
+ response_body as string,
+ );
+ break;
+ default:
+ throw new Error(
+ `unsupported response type: ${request.responseType}`,
+ );
+ }
+
+ const response_headers_u8 = new TextEncoder().encode(
+ JSON.stringify(response_headers),
+ );
+
+ // first byte is status le_bytes i32
+ // second byte is headers byte length i32
+ const ret_bytes: ArrayBuffer = new ArrayBuffer(
+ 2 + response_headers_u8.length + response_body_u8.length,
+ );
+
+ const ret_bytes32 = new DataView(ret_bytes);
+ ret_bytes32.setInt32(0, status, true);
+ ret_bytes32.setInt32(4, response_headers_u8.length, true);
+
+ const ret_bytes8 = new Uint8Array(ret_bytes);
+ ret_bytes8.set(response_headers_u8, 8);
+ ret_bytes8.set(response_body_u8, 8 + response_headers_u8.length);
+
+ // open fd on first wasi_ref
+ // lock input fd and call create_fd on it
+ self.check_fds();
+ const [mapped_fd, wasi_farm_ref_n] = self.get_fd_and_wasi_ref_n(0);
+ if (mapped_fd === undefined || wasi_farm_ref_n === undefined) {
+ throw new Error("fetch_open: bad fd");
+ }
+ const wasi_farm_ref = self.wasi_farm_refs[wasi_farm_ref_n];
+ const [opened_fd, ret] = wasi_farm_ref.open_fd_with_buff(
+ mapped_fd,
+ ret_bytes8,
+ );
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ throw new Error("fetch_open: failed to open fd");
+ }
+ if (opened_fd) {
+ if (self.fd_map.includes([opened_fd, wasi_farm_ref_n])) {
+ throw new Error("opened_fd already exists");
+ }
+ const mapped_opened_fd = self.map_new_fd_and_notify(
+ opened_fd,
+ wasi_farm_ref_n,
+ );
+ return mapped_opened_fd;
+ }
+ throw new Error("fetch_open: failed to open fd");
+ },
+ };
+ }
+ }
+}
diff --git a/src/wasi_farm/farm.ts b/src/wasi_farm/farm.ts
new file mode 100644
index 0000000..7966339
--- /dev/null
+++ b/src/wasi_farm/farm.ts
@@ -0,0 +1,111 @@
+import { debug } from "../debug.js";
+import type { Fd } from "../fd.js";
+import type { Options } from "../wasi.js";
+import type { WASIFarmPark } from "./park.js";
+import type { WASIFarmRefObject } from "./ref.js";
+import { WASIFarmParkUseArrayBuffer } from "./shared_array_buffer/index.js";
+
+export class WASIFarm {
+ private fds: Array;
+ private park: WASIFarmPark;
+
+ private can_array_buffer;
+
+ constructor(
+ stdin?: Fd,
+ stdout?: Fd,
+ stderr?: Fd,
+ fds: Array = [],
+ options: Options & {
+ allocator_size?: number;
+ } = {},
+ ) {
+ debug.enable(options.debug);
+
+ const new_fds = [];
+ let stdin_ = undefined;
+ let stdout_ = undefined;
+ let stderr_ = undefined;
+ if (stdin) {
+ new_fds.push(stdin);
+ stdin_ = new_fds.length - 1;
+ }
+ if (stdout) {
+ new_fds.push(stdout);
+ stdout_ = new_fds.length - 1;
+ }
+ if (stderr) {
+ new_fds.push(stderr);
+ stderr_ = new_fds.length - 1;
+ }
+ new_fds.push(...fds);
+
+ const default_allow_fds = [];
+ for (let i = 0; i < new_fds.length; i++) {
+ default_allow_fds.push(i);
+ }
+
+ this.fds = new_fds;
+
+ // WebAssembly.Memory can be used to create a SharedArrayBuffer, but it cannot be transferred by postMessage.
+ // Uncaught (in promise) DataCloneError:
+ // Failed to execute 'postMessage' on 'Worker':
+ // SharedArrayBuffer transfer requires self.crossOriginIsolated.
+ try {
+ new SharedArrayBuffer(4);
+ this.can_array_buffer = true;
+ } catch (e) {
+ this.can_array_buffer = false;
+ console.warn("SharedArrayBuffer is not supported:", e);
+
+ if (!crossOriginIsolated) {
+ console.warn(
+ "SharedArrayBuffer is not supported because crossOriginIsolated is not enabled.",
+ );
+ }
+ }
+
+ if (this.can_array_buffer) {
+ this.park = new WASIFarmParkUseArrayBuffer(
+ this.fds_ref(),
+ stdin_,
+ stdout_,
+ stderr_,
+ default_allow_fds,
+ options?.allocator_size,
+ );
+ } else {
+ throw new Error("Non SharedArrayBuffer is not supported yet");
+ }
+
+ this.park.listen();
+ }
+
+ private fds_ref(): Array {
+ const fds = new Proxy([] as Array, {
+ get: (_, prop) => {
+ // console.log("fds", prop);
+
+ if (prop === "push") {
+ return (fd: Fd) => {
+ const len = this.fds.push(fd);
+ return len;
+ };
+ }
+ return this.fds[prop];
+ },
+
+ set: (_, prop, value) => {
+ // console.log("fds", prop, value);
+ this.fds[prop] = value;
+ return true;
+ },
+ });
+
+ return fds;
+ }
+
+ get_ref(): WASIFarmRefObject {
+ return this.park.get_ref();
+ }
+}
diff --git a/src/wasi_farm/index.ts b/src/wasi_farm/index.ts
new file mode 100644
index 0000000..76b6389
--- /dev/null
+++ b/src/wasi_farm/index.ts
@@ -0,0 +1,5 @@
+import { WASIFarmAnimal } from "./animals.js";
+import { WASIFarm } from "./farm.js";
+import { WASIFarmRef } from "./ref.js";
+import { thread_spawn_on_worker } from "./shared_array_buffer/index.js";
+export { WASIFarm, WASIFarmRef, WASIFarmAnimal, thread_spawn_on_worker };
diff --git a/src/wasi_farm/park.ts b/src/wasi_farm/park.ts
new file mode 100644
index 0000000..31e760a
--- /dev/null
+++ b/src/wasi_farm/park.ts
@@ -0,0 +1,619 @@
+import { debug } from "../debug.js";
+import type { Fd } from "../fd.js";
+import { File, OpenFile } from "../fs_mem.js";
+import * as wasi from "../wasi_defs.js";
+import type { WASIFarmRefObject } from "./ref.js";
+
+export abstract class WASIFarmPark {
+ abstract get_ref(): WASIFarmRefObject;
+ abstract listen(): void;
+ abstract notify_set_fd(fd: number): void;
+ abstract notify_rm_fd(fd: number): void;
+ abstract can_set_new_fd(fd: number): [boolean, Promise | undefined];
+
+ protected fds: Array;
+ protected stdin: number | undefined;
+ protected stdout: number | undefined;
+ protected stderr: number | undefined;
+ protected default_allow_fds: Array;
+
+ constructor(
+ fds: Array,
+ stdin: number | undefined,
+ stdout: number | undefined,
+ stderr: number | undefined,
+ default_allow_fds: Array,
+ ) {
+ this.fds = fds;
+ this.stdin = stdin;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ this.default_allow_fds = default_allow_fds;
+ this.fds_map = new Array(fds.length);
+ for (let i = 0; i < fds.length; i++) {
+ this.fds_map[i] = [];
+ }
+ // console.log("first fds_map", this.fds_map);
+ }
+
+ private get_new_fd_lock = new Array<() => Promise>();
+
+ // fdに対して、現在そのfdにidがアクセス可能かを示す。
+ protected fds_map: Array;
+
+ // If the reassigned value is accessed after being closed,
+ // it will be strange,
+ // but the programmer should have written it
+ // so that this does not happen in the first place.
+ private async get_new_fd(): Promise<[() => Promise, number]> {
+ const promise = new Promise<[() => Promise, number]>((resolve) => {
+ const len = this.get_new_fd_lock.push(async () => {
+ let ret = -1;
+ for (let i = 0; i < this.fds.length; i++) {
+ if (this.fds[i] === undefined) {
+ ret = i;
+ break;
+ }
+ }
+ if (ret === -1) {
+ ret = this.fds.length;
+ // console.log("push_fd", this.fds.length)
+ this.fds.push(undefined);
+ this.fds_map.push([]);
+ // console.log("push_fd", this.fds.length)
+ }
+
+ const [can, promise] = this.can_set_new_fd(ret);
+ if (!can) {
+ await promise;
+ }
+
+ // If it's assigned, it's resolved.
+ resolve([
+ async () => {
+ this.get_new_fd_lock.shift();
+ const fn = this.get_new_fd_lock[0];
+ if (fn !== undefined) {
+ fn();
+ }
+ // assigned and notify
+ await this.notify_set_fd(ret);
+ },
+ ret,
+ ]);
+ });
+ if (len === 1) {
+ this.get_new_fd_lock[0]();
+ }
+ });
+ return promise;
+ }
+
+ protected fd_advise(fd: number): number {
+ if (this.fds[fd] !== undefined) {
+ return wasi.ERRNO_SUCCESS;
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_allocate(fd: number, offset: bigint, len: bigint): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_allocate(offset, len);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected async fd_close(fd: number): Promise {
+ if (this.fds[fd] !== undefined) {
+ const ret = this.fds[fd].fd_close();
+ this.fds[fd] = undefined;
+ // console.log("fd_close1", fd);
+ await this.notify_rm_fd(fd);
+ // console.log("fd_close2", fd);
+ return ret;
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_datasync(fd: number): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_sync();
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, fdstat } = this.fds[fd].fd_fdstat_get();
+ if (fdstat != null) {
+ return [fdstat, ret];
+ }
+ return [undefined, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_fdstat_set_flags(fd: number, flags: number): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_fdstat_set_flags(flags);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_fdstat_set_rights(
+ fd: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ ): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_fdstat_set_rights(
+ fs_rights_base,
+ fs_rights_inheriting,
+ );
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, filestat } = this.fds[fd].fd_filestat_get();
+ if (filestat != null) {
+ return [filestat, ret];
+ }
+ return [undefined, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_filestat_set_size(fd: number, size: bigint): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_filestat_set_size(size);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_filestat_set_times(
+ fd: number,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_filestat_set_times(atim, mtim, fst_flags);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_pread(
+ fd: number,
+ iovecs: Array,
+ offset: bigint,
+ ): [[number, Uint8Array] | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ let nread = 0;
+
+ let buffer8 = new Uint8Array(0);
+ for (const iovec of iovecs) {
+ const { ret, data } = this.fds[fd].fd_pread(iovec.buf_len, offset);
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ return [[nread, buffer8], ret];
+ }
+ const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength);
+ new_buffer.set(buffer8);
+ new_buffer.set(data, buffer8.byteLength);
+ buffer8 = new_buffer;
+ nread += data.byteLength;
+ if (data.byteLength !== iovec.buf_len) {
+ break;
+ }
+ }
+ return [[nread, buffer8], wasi.ERRNO_SUCCESS];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_prestat_get(fd: number): [wasi.Prestat | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, prestat } = this.fds[fd].fd_prestat_get();
+ if (prestat != null) {
+ return [prestat, ret];
+ }
+ return [undefined, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_prestat_dir_name(
+ fd: number,
+ path_len: number,
+ ): [Uint8Array | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, prestat } = this.fds[fd].fd_prestat_get();
+ if (prestat) {
+ const prestat_dir_name = prestat.inner.pr_name;
+
+ // console.log("fd_prestat_dir_name: park: inner: ", prestat_dir_name);
+ // console.log("fd_prestat_dir_name: park: inner: ", new TextDecoder().decode(prestat_dir_name));
+
+ // console.log("fd_prestat_dir_name: park: path_len: ", path_len);
+
+ if (prestat_dir_name.length <= path_len) {
+ // console.log("fd_prestat_dir_name: park: A");
+ return [prestat_dir_name, ret];
+ }
+
+ // console.log("fd_prestat_dir_name: park: B");
+ return [prestat_dir_name.slice(0, path_len), wasi.ERRNO_NAMETOOLONG];
+ }
+ // console.log("fd_prestat_dir_name: park: C");
+ return [undefined, ret];
+ }
+ // console.log("fd_prestat_dir_name: park: D");
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_pwrite(
+ fd: number,
+ write_data: Uint8Array,
+ offset: bigint,
+ ): [number | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, nwritten } = this.fds[fd].fd_pwrite(write_data, offset);
+ return [nwritten, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_read(
+ fd: number,
+ iovecs: Array,
+ ): [[number, Uint8Array] | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ let nread = 0;
+
+ // console.log("fd_read: park: iovecs: ", iovecs);
+
+ // const sum_len = iovecs.reduce((acc, iovec) => acc + iovec.buf_len, 0);
+
+ // console.warn("fd_read: park: sum_len: ", sum_len);
+
+ let buffer8 = new Uint8Array(0);
+ for (const iovec of iovecs) {
+ const { ret, data } = this.fds[fd].fd_read(iovec.buf_len);
+ // console.log("fd_read: park: data: ", data);
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ return [[nread, buffer8], ret];
+ }
+ const new_buffer = new Uint8Array(buffer8.byteLength + data.byteLength);
+ new_buffer.set(buffer8);
+ new_buffer.set(data, buffer8.byteLength);
+ buffer8 = new_buffer;
+ nread += data.byteLength;
+ if (data.byteLength !== iovec.buf_len) {
+ break;
+ }
+ }
+
+ // console.log("fd_read: park: nread: ", nread);
+
+ return [[nread, buffer8], wasi.ERRNO_SUCCESS];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_readdir(
+ fd: number,
+ buf_len: number,
+ cookie: bigint,
+ ): [[Uint8Array, number] | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const array = new Uint8Array(buf_len);
+
+ let buf_used = 0;
+ let offset = 0;
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const { ret, dirent } = this.fds[fd].fd_readdir_single(cookie);
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ return [[array, buf_used], ret];
+ }
+ if (dirent == null) {
+ break;
+ }
+ if (buf_len - buf_used < dirent.head_length()) {
+ buf_used = buf_len;
+ break;
+ }
+
+ const head_bytes = new ArrayBuffer(dirent.head_length());
+ dirent.write_head_bytes(new DataView(head_bytes), 0);
+ array.set(
+ new Uint8Array(head_bytes).slice(
+ 0,
+ Math.min(head_bytes.byteLength, buf_len - buf_used),
+ ),
+ offset,
+ );
+ offset += head_bytes.byteLength;
+ buf_used += head_bytes.byteLength;
+
+ if (buf_len - buf_used < dirent.name_length()) {
+ buf_used = buf_len;
+ break;
+ }
+
+ dirent.write_name_bytes(array, offset, buf_len - buf_used);
+ offset += dirent.name_length();
+ buf_used += dirent.name_length();
+
+ cookie = dirent.d_next;
+ }
+
+ return [[array, buf_used], wasi.ERRNO_SUCCESS];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ // protected async fd_renumber(fd: number, to: number): Promise {
+ // if (this.fds[fd] != undefined) {
+ // const ret = this.fds[to].fd_close();
+ // if (ret != wasi.ERRNO_SUCCESS) {
+ // return ret;
+ // }
+ // this.fds[to] = this.fds[fd];
+ // this.fds[fd] = undefined;
+ // await this.notify_rm_fd(fd);
+ // return wasi.ERRNO_SUCCESS;
+ // } else {
+ // return wasi.ERRNO_BADF;
+ // }
+ // }
+
+ protected fd_seek(
+ fd: number,
+ offset: bigint,
+ whence: number,
+ ): [bigint | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, offset: new_offset } = this.fds[fd].fd_seek(offset, whence);
+ return [new_offset, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected fd_sync(fd: number): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].fd_sync();
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected fd_tell(fd: number): [bigint | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, offset } = this.fds[fd].fd_tell();
+ return [offset, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected async fd_write(
+ fd: number,
+ write_data: Uint8Array,
+ ): Promise<[number | undefined, number]> {
+ if (this.fds[fd] !== undefined) {
+ const fd_ret = this.fds[fd].fd_write(write_data);
+ let ret: number;
+ let nwritten: number;
+ if (fd_ret instanceof Promise) {
+ ({ ret, nwritten } = await fd_ret);
+ } else {
+ ({ ret, nwritten } = fd_ret);
+ }
+ return [nwritten, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected path_create_directory(fd: number, path: string): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].path_create_directory(path);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected path_filestat_get(
+ fd: number,
+ flags: number,
+ path: string,
+ ): [wasi.Filestat | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ const { ret, filestat } = this.fds[fd].path_filestat_get(flags, path);
+ if (filestat != null) {
+ return [filestat, ret];
+ }
+ return [undefined, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected path_filestat_set_times(
+ fd: number,
+ flags: number,
+ path: string,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].path_filestat_set_times(
+ flags,
+ path,
+ atim,
+ mtim,
+ fst_flags,
+ );
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected path_link(
+ old_fd: number,
+ old_flags: number,
+ old_path: string,
+ new_fd: number,
+ new_path: string,
+ ): number {
+ if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) {
+ const { ret, inode_obj } = this.fds[old_fd].path_lookup(
+ old_path,
+ old_flags,
+ );
+ if (inode_obj == null) {
+ return ret;
+ }
+ return this.fds[new_fd].path_link(new_path, inode_obj, false);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected async path_open(
+ fd: number,
+ dirflags: number,
+ path: string,
+ oflags: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ fs_flags: number,
+ ): Promise<[number | undefined, number]> {
+ if (this.fds[fd] !== undefined) {
+ debug.log("path_open", path);
+ const { ret, fd_obj } = this.fds[fd].path_open(
+ dirflags,
+ path,
+ oflags,
+ fs_rights_base,
+ fs_rights_inheriting,
+ fs_flags,
+ );
+ console.log("path_open: park: ", path, "fd_obj", fd_obj, "ret", ret);
+
+ // print self dir path
+ console.log("path_open: self: ", this.fds[fd]);
+
+ // console.log("path_open: park: ", ret, fd_obj);
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ return [undefined, ret];
+ }
+
+ const [resolve, opened_fd] = await this.get_new_fd();
+
+ // console.log("path_open: park: ", path, "opened_fd" ,opened_fd);
+
+ this.fds[opened_fd] = fd_obj;
+
+ console.log("path_open: park: ", path, "opened_fd", opened_fd);
+
+ await resolve();
+
+ // console.log("path_open: park: len: ", len);
+
+ // console.log("path_open: park: ", opened_fd);
+
+ return [opened_fd, wasi.ERRNO_SUCCESS];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected path_readlink(
+ fd: number,
+ path: string,
+ buf_len: number,
+ ): [Uint8Array | undefined, number] {
+ if (this.fds[fd] !== undefined) {
+ debug.log("path_readlink", path);
+ const { ret, data } = this.fds[fd].path_readlink(path);
+ if (data != null) {
+ const data_buf = new TextEncoder().encode(data);
+ if (data_buf.byteLength > buf_len) {
+ // wasi.ts use ERRNO_BADF. I think it should be ERRNO_OVERFLOW.
+ return [data_buf.slice(0, buf_len), wasi.ERRNO_OVERFLOW];
+ }
+ return [data_buf, ret];
+ }
+ return [undefined, ret];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ protected path_remove_directory(fd: number, path: string): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].path_remove_directory(path);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected path_rename(
+ old_fd: number,
+ old_path: string,
+ new_fd: number,
+ new_path: string,
+ ): number {
+ if (this.fds[old_fd] !== undefined && this.fds[new_fd] !== undefined) {
+ // eslint-disable-next-line prefer-const
+ let { ret, inode_obj } = this.fds[old_fd].path_unlink(old_path);
+ if (inode_obj == null) {
+ return ret;
+ }
+ ret = this.fds[new_fd].path_link(new_path, inode_obj, true);
+ if (ret !== wasi.ERRNO_SUCCESS) {
+ if (
+ this.fds[old_fd].path_link(old_path, inode_obj, true) !==
+ wasi.ERRNO_SUCCESS
+ ) {
+ throw "path_link should always return success when relinking an inode back to the original place";
+ }
+ }
+ return ret;
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected path_symlink(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ old_path: string,
+ fd: number,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ new_path: string,
+ ): number {
+ if (this.fds[fd] !== undefined) {
+ return wasi.ERRNO_NOTSUP;
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected path_unlink_file(fd: number, path: string): number {
+ if (this.fds[fd] !== undefined) {
+ return this.fds[fd].path_unlink_file(path);
+ }
+ return wasi.ERRNO_BADF;
+ }
+
+ protected async open_fd_with_buff(
+ fd: number,
+ buf: Uint8Array,
+ ): Promise<[number | undefined, number]> {
+ if (this.fds[fd] !== undefined) {
+ const fd_obj = new OpenFile(new File(buf));
+
+ const [resolve, opened_fd] = await this.get_new_fd();
+
+ this.fds[opened_fd] = fd_obj;
+
+ await resolve();
+
+ return [opened_fd, wasi.ERRNO_SUCCESS];
+ }
+ return [undefined, wasi.ERRNO_BADF];
+ }
+}
diff --git a/src/wasi_farm/polyfill.js b/src/wasi_farm/polyfill.js
new file mode 100644
index 0000000..bde01dd
--- /dev/null
+++ b/src/wasi_farm/polyfill.js
@@ -0,0 +1,147 @@
+// https://github.com/tc39/proposal-atomics-wait-async/blob/master/polyfill.js
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: Lars T Hansen, lhansen@mozilla.com
+ */
+
+/* Polyfill for Atomics.waitAsync() for web browsers.
+ *
+ * Any kind of agent that is able to create a new Worker can use this polyfill.
+ *
+ * Load this file in all agents that will use Atomics.waitAsync.
+ *
+ * Agents that don't call Atomics.waitAsync need do nothing special.
+ *
+ * Any kind of agent can wake another agent that is sleeping in
+ * Atomics.waitAsync by just calling Atomics.notify for the location being slept
+ * on, as normal.
+ *
+ * The implementation is not completely faithful to the proposed semantics: in
+ * the case where an agent first asyncWaits and then waits on the same location:
+ * when it is woken, the two waits will be woken in order, while in the real
+ * semantics, the sync wait will be woken first.
+ *
+ * In this polyfill Atomics.waitAsync is not very fast.
+ */
+
+/* Implementation:
+ *
+ * For every wait we fork off a Worker to perform the wait. Workers are reused
+ * when possible. The worker communicates with its parent using postMessage.
+ */
+
+(() => {
+ if (typeof Atomics.waitAsync === "function") return;
+
+ const helperCode = `
+ onmessage = function (ev) {
+ try {
+ switch (ev.data[0]) {
+ case 'wait': {
+ let [_, ia, index, value, timeout] = ev.data;
+ let result = Atomics.wait(ia, index, value, timeout)
+ postMessage(['ok', result]);
+ break;
+ }
+ default: {
+ throw new Error("Bogus message sent to wait helper: " + ev.data.join(','));
+ }
+ }
+ } catch (e) {
+ console.log("Exception in wait helper");
+ postMessage(['error', 'Exception']);
+ }
+ }
+ `;
+
+ const helpers = [];
+
+ function allocHelper() {
+ if (helpers.length > 0) return helpers.pop();
+ const h = new Worker(
+ `data:application/javascript,${encodeURIComponent(helperCode)}`,
+ );
+ return h;
+ }
+
+ function freeHelper(h) {
+ helpers.push(h);
+ }
+
+ // Atomics.waitAsync always returns a promise. Throws standard errors
+ // for parameter validation. The promise is resolved with a string as from
+ // Atomics.wait, or, in the case something went completely wrong, it is
+ // rejected with an error string.
+
+ function waitAsync(ia, index_, value_, timeout_) {
+ if (
+ typeof ia !== "object" ||
+ !(ia instanceof Int32Array) ||
+ !(ia.buffer instanceof SharedArrayBuffer)
+ )
+ throw new TypeError("Expected shared memory");
+
+ // These conversions only approximate the desired semantics but are
+ // close enough for the polyfill.
+
+ const index = index_ | 0;
+ const value = value_ | 0;
+ const timeout =
+ timeout_ === undefined ? Number.POSITIVE_INFINITY : +timeout_;
+
+ // Range checking for the index.
+
+ ia[index];
+
+ // Optimization, avoid the helper thread in this common case.
+
+ if (Atomics.load(ia, index) !== value) return Promise.resolve("not-equal");
+
+ // General case, we must wait.
+
+ return new Promise((resolve, reject) => {
+ const h = allocHelper();
+ h.onmessage = (ev) => {
+ // Free the helper early so that it can be reused if the resolution
+ // needs a helper.
+ freeHelper(h);
+ switch (ev.data[0]) {
+ case "ok":
+ resolve(ev.data[1]);
+ break;
+ case "error":
+ // Note, rejection is not in the spec, it is an artifact of the polyfill.
+ // The helper already printed an error to the console.
+ reject(ev.data[1]);
+ break;
+ }
+ };
+
+ // It's possible to do better here if the ia is already known to the
+ // helper. In that case we can communicate the other data through
+ // shared memory and wake the agent. And it is possible to make ia
+ // known to the helper by waking it with a special value so that it
+ // checks its messages, and then posting the ia to the helper. Some
+ // caching / decay scheme is useful no doubt, to improve performance
+ // and avoid leaks.
+ //
+ // In the event we wake the helper directly, we can micro-wait here
+ // for a quick result. We'll need to restructure some code to make
+ // that work out properly, and some synchronization is necessary for
+ // the helper to know that we've picked up the result and no
+ // postMessage is necessary.
+
+ h.postMessage(["wait", ia, index, value, timeout]);
+ });
+ }
+
+ Object.defineProperty(Atomics, "waitAsync", {
+ value: waitAsync,
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ });
+})();
diff --git a/src/wasi_farm/ref.ts b/src/wasi_farm/ref.ts
new file mode 100644
index 0000000..4f0f773
--- /dev/null
+++ b/src/wasi_farm/ref.ts
@@ -0,0 +1,190 @@
+import type * as wasi from "../wasi_defs.js";
+import type { FdCloseSender } from "./sender.js";
+
+export type WASIFarmRefObject = {
+ stdin: number | undefined;
+ stdout: number | undefined;
+ stderr: number | undefined;
+ fd_close_receiver: FdCloseSender;
+ default_fds: Array;
+};
+
+export abstract class WASIFarmRef {
+ abstract get_fds_len(): number;
+ // please implement this method
+ // abstract init_self(sl: WASIFarmRef): WASIFarmRef;
+
+ protected stdin: number | undefined;
+ protected stdout: number | undefined;
+ protected stderr: number | undefined;
+
+ protected id: number;
+
+ fd_close_receiver: FdCloseSender;
+
+ default_fds: Array = [];
+
+ async send(targets: Array, fd: number): Promise {
+ await this.fd_close_receiver.send(targets, fd);
+ }
+
+ get(id: number): Array | undefined {
+ return this.fd_close_receiver.get(id);
+ }
+
+ abstract set_park_fds_map(fds: Array);
+
+ abstract set_id(): number;
+
+ constructor(
+ stdin: number | undefined,
+ stdout: number | undefined,
+ stderr: number | undefined,
+ fd_close_receiver: FdCloseSender,
+ default_fds?: Array,
+ ) {
+ this.stdin = stdin;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ this.fd_close_receiver = fd_close_receiver;
+ if (default_fds !== undefined) {
+ this.default_fds = default_fds;
+ }
+ }
+
+ get_stdin(): number | undefined {
+ return this.stdin;
+ }
+
+ get_stdout(): number | undefined {
+ return this.stdout;
+ }
+
+ get_stderr(): number | undefined {
+ return this.stderr;
+ }
+
+ abstract fd_advise(fd: number | undefined): number;
+ abstract fd_allocate(
+ fd: number | undefined,
+ offset: bigint,
+ len: bigint,
+ ): number;
+ abstract fd_close(fd: number | undefined): number;
+ abstract fd_datasync(fd: number | undefined): number;
+ abstract fd_fdstat_get(
+ fd: number | undefined,
+ ): [wasi.Fdstat | undefined, number];
+ abstract fd_fdstat_set_flags(fd: number | undefined, flags: number): number;
+ abstract fd_fdstat_set_rights(
+ fd: number | undefined,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ ): number;
+ abstract fd_filestat_get(
+ fd: number | undefined,
+ ): [wasi.Filestat | undefined, number];
+ abstract fd_filestat_set_size(fd: number | undefined, size: bigint): number;
+ abstract fd_filestat_set_times(
+ fd: number | undefined,
+ atim: bigint,
+ mtim: bigint,
+ fst_flags: number,
+ ): number;
+ abstract fd_pread(
+ fd: number | undefined,
+ iovs: Uint32Array,
+ offset: bigint,
+ ): [[number, Uint8Array] | undefined, number];
+ abstract fd_prestat_get(
+ fd: number | undefined,
+ ): [[number, number] | undefined, number];
+ abstract fd_prestat_dir_name(
+ fd: number | undefined,
+ path_len: number,
+ ): [Uint8Array | undefined, number];
+ abstract fd_pwrite(
+ fd: number | undefined,
+ iovs: Uint8Array,
+ offset: bigint,
+ ): [number | undefined, number];
+ abstract fd_read(
+ fd: number | undefined,
+ iovs: Uint32Array,
+ ): [[number, Uint8Array] | undefined, number];
+ abstract fd_readdir(
+ fd: number | undefined,
+ limit_buf_len: number,
+ cookie: bigint,
+ ): [[Uint8Array, number] | undefined, number];
+ // abstract fd_renumber(fd: number | undefined, to: number): number;
+ abstract fd_seek(
+ fd: number | undefined,
+ offset: bigint,
+ whence: number,
+ ): [bigint | undefined, number];
+ abstract fd_sync(fd: number | undefined): number;
+ abstract fd_tell(fd: number | undefined): [bigint, number];
+ abstract fd_write(
+ fd: number | undefined,
+ iovs: Uint8Array,
+ ): [number | undefined, number];
+ abstract path_create_directory(
+ fd: number | undefined,
+ path: Uint8Array,
+ ): number;
+ abstract path_filestat_get(
+ fd: number | undefined,
+ flags: number,
+ path: Uint8Array,
+ ): [wasi.Filestat | undefined, number];
+ abstract path_filestat_set_times(
+ fd: number | undefined,
+ flags: number,
+ path: Uint8Array,
+ st_atim: bigint,
+ st_mtim: bigint,
+ fst_flags: number,
+ ): number;
+ abstract path_link(
+ old_fd: number | undefined,
+ old_flags: number,
+ old_path: Uint8Array,
+ new_fd: number | undefined,
+ new_path: Uint8Array,
+ ): number;
+ abstract path_open(
+ fd: number | undefined,
+ dirflags: number,
+ path: Uint8Array,
+ oflags: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ fs_flags: number,
+ ): [number, number];
+ abstract path_readlink(
+ fd: number | undefined,
+ path: Uint8Array,
+ buf_len: number,
+ ): [Uint8Array | undefined, number];
+ abstract path_remove_directory(
+ fd: number | undefined,
+ path: Uint8Array,
+ ): number;
+ abstract path_rename(
+ old_fd: number | undefined,
+ old_path: Uint8Array,
+ new_fd: number | undefined,
+ new_path: Uint8Array,
+ ): number;
+ abstract path_symlink(
+ old_path: Uint8Array,
+ fd: number | undefined,
+ new_path: Uint8Array,
+ ): number;
+ abstract path_unlink_file(fd: number | undefined, path: Uint8Array): number;
+ abstract open_fd_with_buff(
+ fd: number | undefined,
+ buf: Uint8Array,
+ ): [number, number];
+}
diff --git a/src/wasi_farm/sender.ts b/src/wasi_farm/sender.ts
new file mode 100644
index 0000000..ed9d30a
--- /dev/null
+++ b/src/wasi_farm/sender.ts
@@ -0,0 +1,4 @@
+export interface FdCloseSender {
+ send(targets: Array, fd: number): Promise;
+ get(id: number): Array | undefined;
+}
diff --git a/src/wasi_farm/shared_array_buffer/allocator.ts b/src/wasi_farm/shared_array_buffer/allocator.ts
new file mode 100644
index 0000000..8cd3edf
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/allocator.ts
@@ -0,0 +1,215 @@
+// @ts-ignore
+// import { debug } from "../../debug.js";
+// import "../polyfill.js";
+
+export type AllocatorUseArrayBufferObject = {
+ share_arrays_memory: SharedArrayBuffer;
+};
+
+export class AllocatorUseArrayBuffer {
+ // Pass a !Sized type
+ // The first 4 bytes are for a lock value: i32
+ // The next 4 bytes are for the current number of arrays: m: i32
+ // The next 4 bytes are for the length of the occupied space in share_arrays_memory: n: i32
+ // Once it is no longer busy, it should become empty immediately, so reset only when it is empty.
+ // Even if it becomes too long, it should be fine due to the browser's virtualization.
+ // Using an algorithm even simpler than First-Fit
+ // SharedArrayBuffer.grow is supported by all major browsers except Android WebView,
+ // which does not support SharedArrayBuffer in the first place,
+ // but es2024 and the type system does not support it,
+ // so the size is fixed from the beginning
+
+ // share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer(12, {
+ // // 10MB
+ // maxByteLength: 10 * 1024 * 1024,
+ // });
+
+ // Even if 100MB is allocated, due to browser virtualization,
+ // the memory should not actually be used until it is needed.
+ share_arrays_memory: SharedArrayBuffer;
+
+ // When adding data, use Atomics.wait to wait until the first 4 bytes become 0.
+ // After that, use Atomics.compareExchange to set the first 4 bytes to 1.
+ // Then, use Atomics.add to increment the next 4 bytes by 1.
+ // If the return value is 0, proceed to *1.
+ // If the return value is 1, use Atomics.wait to wait until the first 4 bytes become 0.
+ // *1: Increment the second by 1 using Atomics.add. If the return value is 0, reset it.
+ // Add the data. Extend if there is not enough space.
+ // To release, just decrement by 1 using Atomics.sub.
+
+ // Since postMessage makes the class an object,
+ // it must be able to receive and assign a SharedArrayBuffer.
+ constructor(
+ share_arrays_memory: SharedArrayBuffer = new SharedArrayBuffer(
+ 10 * 1024 * 1024,
+ ),
+ ) {
+ this.share_arrays_memory = share_arrays_memory;
+ const view = new Int32Array(this.share_arrays_memory);
+ Atomics.store(view, 0, 0);
+ Atomics.store(view, 1, 0);
+ Atomics.store(view, 2, 12);
+ }
+
+ // Since postMessage converts classes to objects,
+ // it must be able to convert objects to classes.
+ static init_self(sl: AllocatorUseArrayBufferObject): AllocatorUseArrayBuffer {
+ return new AllocatorUseArrayBuffer(sl.share_arrays_memory);
+ }
+
+ // Writes without blocking threads when acquiring locks
+ async async_write(
+ data: Uint8Array | Uint32Array,
+ memory: SharedArrayBuffer,
+ // ptr, len
+ // Pass I32Array ret_ptr
+ ret_ptr: number,
+ ): Promise<[number, number]> {
+ const view = new Int32Array(this.share_arrays_memory);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ let lock: "not-equal" | "timed-out" | "ok";
+ const { value } = Atomics.waitAsync(view, 0, 1);
+ if (value instanceof Promise) {
+ lock = await value;
+ } else {
+ lock = value;
+ }
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+
+ const ret = this.write_inner(data, memory, ret_ptr);
+
+ // release lock
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+
+ return ret;
+ }
+ }
+
+ // Blocking threads for writing when acquiring locks
+ block_write(
+ data: Uint8Array | Uint32Array,
+ memory: SharedArrayBuffer,
+ // ptr, len
+ ret_ptr: number,
+ ): [number, number] {
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const view = new Int32Array(this.share_arrays_memory);
+ const lock = Atomics.wait(view, 0, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+
+ const ret = this.write_inner(data, memory, ret_ptr);
+
+ // release lock
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+
+ return ret;
+ }
+ }
+
+ // Function to write after acquiring a lock
+ write_inner(
+ data: Uint8Array | Uint32Array,
+ memory: SharedArrayBuffer,
+ // ptr, len
+ ret_ptr: number,
+ ): [number, number] {
+ // console.log("data", data);
+
+ const view = new Int32Array(this.share_arrays_memory);
+ const view8 = new Uint8Array(this.share_arrays_memory);
+
+ // Indicates more users using memory
+ const old_num = Atomics.add(view, 1, 1);
+ let share_arrays_memory_kept: number;
+ if (old_num === 0) {
+ // Reset because there were no users.
+ // debug.log("reset allocator");
+ share_arrays_memory_kept = Atomics.store(view, 2, 12);
+ } else {
+ share_arrays_memory_kept = Atomics.load(view, 2);
+ }
+ // console.log("num", Atomics.load(view, 1));
+
+ const memory_len = this.share_arrays_memory.byteLength;
+ const len = data.byteLength;
+ const new_memory_len = share_arrays_memory_kept + len;
+ if (memory_len < new_memory_len) {
+ // extend memory
+ // support from es2024
+ // this.share_arrays_memory.grow(new_memory_len);
+ throw new Error(
+ "size is bigger than memory. \nTODO! fix memory limit. support big size another way.",
+ );
+ }
+
+ let data8: Uint8Array;
+ if (data instanceof Uint8Array) {
+ data8 = data;
+ } else if (data instanceof Uint32Array) {
+ // data to uint8
+ const tmp = new ArrayBuffer(data.byteLength);
+ new Uint32Array(tmp).set(data);
+ data8 = new Uint8Array(tmp);
+ }
+
+ view8.set(new Uint8Array(data8), share_arrays_memory_kept);
+ Atomics.store(view, 2, new_memory_len);
+
+ const memory_view = new Int32Array(memory);
+ Atomics.store(memory_view, ret_ptr, share_arrays_memory_kept);
+ Atomics.store(memory_view, ret_ptr + 1, len);
+
+ // console.log("allocator: allocate", share_arrays_memory_kept, len);
+
+ return [share_arrays_memory_kept, len];
+ }
+
+ // free allocated memory
+ free(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ pointer: number,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ len: number,
+ ) {
+ Atomics.sub(new Int32Array(this.share_arrays_memory), 1, 1);
+
+ // console.log("allocator: free", pointer, len);
+ }
+
+ // get memory from pointer and length
+ get_memory(ptr: number, len: number): ArrayBuffer {
+ const data = new ArrayBuffer(len);
+ const view = new Uint8Array(data);
+ view.set(new Uint8Array(this.share_arrays_memory).slice(ptr, ptr + len));
+ return data;
+ }
+
+ // Write again to the memory before releasing
+ // Not used because the situation for using it does not exist.
+ use_defined_memory(ptr: number, len: number, data: ArrayBufferLike) {
+ const memory = new Uint8Array(this.share_arrays_memory);
+ memory.set(new Uint8Array(data).slice(0, len), ptr);
+ }
+
+ get_object(): AllocatorUseArrayBufferObject {
+ return {
+ share_arrays_memory: this.share_arrays_memory,
+ };
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/fd_close_sender.ts b/src/wasi_farm/shared_array_buffer/fd_close_sender.ts
new file mode 100644
index 0000000..a137e77
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/fd_close_sender.ts
@@ -0,0 +1,62 @@
+import type { FdCloseSender } from "../sender.js";
+import {
+ ToRefSenderUseArrayBuffer,
+ type ToRefSenderUseArrayBufferObject,
+} from "./sender.js";
+
+export type FdCloseSenderUseArrayBufferObject = {
+ max_share_arrays_memory?: number;
+ share_arrays_memory?: SharedArrayBuffer;
+} & ToRefSenderUseArrayBufferObject;
+
+// Object to tell other processes,
+// such as child processes,
+// that the file descriptor has been closed
+export class FdCloseSenderUseArrayBuffer
+ extends ToRefSenderUseArrayBuffer
+ implements FdCloseSender
+{
+ // Should be able to change the size of memory as it accumulates more and more on memory
+ constructor(
+ max_share_arrays_memory?: number,
+ share_arrays_memory?: SharedArrayBuffer,
+ ) {
+ super(4, max_share_arrays_memory, share_arrays_memory);
+ }
+
+ // Send the closed file descriptor to the target process
+ async send(targets: Array, fd: number): Promise {
+ if (targets === undefined || targets.length === 0) {
+ throw new Error("targets is empty");
+ }
+ // console.log("fd_close_sender send", targets, fd);
+
+ await this.async_send(targets, new Uint32Array([fd]));
+ }
+
+ // Get the closed file descriptor from the target process
+ get(id: number): Array | undefined {
+ const data = this.get_data(id);
+ if (data === undefined) {
+ return undefined;
+ }
+
+ // console.log("fd_close_sender get", data);
+
+ const array = [];
+ for (const i of data) {
+ array.push(i[0]);
+ }
+
+ return array;
+ }
+
+ // Initialize the class from object
+ static init_self(sl: FdCloseSenderUseArrayBufferObject): FdCloseSender {
+ const sel = ToRefSenderUseArrayBuffer.init_self_inner(sl);
+ return new FdCloseSenderUseArrayBuffer(
+ sel.max_share_arrays_memory,
+ sel.share_arrays_memory,
+ );
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/index.ts b/src/wasi_farm/shared_array_buffer/index.ts
new file mode 100644
index 0000000..0e2d34a
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/index.ts
@@ -0,0 +1,13 @@
+import { WASIFarmParkUseArrayBuffer } from "./park.js";
+import { WASIFarmRefUseArrayBuffer } from "./ref.js";
+import type { WASIFarmRefUseArrayBufferObject } from "./ref.js";
+import { ThreadSpawner } from "./thread_spawn.js";
+import { thread_spawn_on_worker } from "./thread_spawn.js";
+
+export {
+ WASIFarmRefUseArrayBuffer,
+ type WASIFarmRefUseArrayBufferObject,
+ WASIFarmParkUseArrayBuffer,
+ ThreadSpawner,
+ thread_spawn_on_worker,
+};
diff --git a/src/wasi_farm/shared_array_buffer/park.ts b/src/wasi_farm/shared_array_buffer/park.ts
new file mode 100644
index 0000000..0096397
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/park.ts
@@ -0,0 +1,1016 @@
+import type { Fd } from "../../fd.js";
+import * as wasi from "../../wasi_defs.js";
+import { WASIFarmPark } from "../park.js";
+import type { FdCloseSender } from "../sender.js";
+import { AllocatorUseArrayBuffer } from "./allocator.js";
+import { FdCloseSenderUseArrayBuffer } from "./fd_close_sender.js";
+import type { WASIFarmRefUseArrayBufferObject } from "./ref.js";
+import { get_func_name_from_number } from "./util.js";
+
+export const fd_func_sig_u32_size: number = 18;
+export const fd_func_sig_bytes: number = fd_func_sig_u32_size * 4;
+
+export class WASIFarmParkUseArrayBuffer extends WASIFarmPark {
+ private allocator: AllocatorUseArrayBuffer;
+
+ // args and env do not change, so copying them is fine.
+ // Functions that do not depend on fds are skipped.
+ // Since it is wasm32, the pointer is u32.
+ // errno is u8.
+ // https://github.com/WebAssembly/WASI/blob/4feaf733e946c375b610cc5d39ea2e1a68046e62/legacy/preview1/docs.md
+ // The first item is the function signature, and the second (if it exists) represents data that must be communicated in Park. If they are the same, it is not written.
+ // From here, direct access to fd begins.
+ // fd_advise: (fd: u32, offset: u64, len: u64, advice: u8) => errno;
+ // (fd: u32) => errno;
+ // fd_allocate: (fd: u32, offset: u64, len: u64) => errno;
+ // fd_close: (fd: u32) => errno;
+ // fd_datasync: (fd: u32) => errno;
+ // fd_fdstat_get: (fd: u32, fdstat_ptr: pointer) => errno;
+ // (fd: u32) => [wasi.Fdstat(u32 * 6)], errno];
+ // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno;
+ // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno;
+ // fd_filestat_get: (fd: u32, filestat_ptr: pointer) => errno;
+ // (fd: u32) => [wasi.Filestat(u32 * 16)], errno];
+ // fd_filestat_set_size: (fd: u32, size: u64) => errno;
+ // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno;
+ // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno];
+ // fd_prestat_get: (fd: u32, prestat_ptr: pointer) => errno;
+ // (fd: u32) => [wasi.Prestat(u32 * 2)], errno];
+ // fd_prestat_dir_name: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ // (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno];
+ // fd_pwrite: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno];
+ // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno];
+ // fd_readdir: (fd: u32, buf_ptr: pointer, buf_len: u32, cookie: u64) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno];
+ // fd_renumber: (fd: u32, to: u32) => errno;
+ // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno];
+ // fd_sync: (fd: u32) => errno;
+ // fd_tell: (fd: u32) => [u64, errno];
+ // fd_write: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno];
+ // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno];
+ // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno;
+ // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno];
+ // note: fdsにpushするが、既存のfdに影響しないので、競合しない。
+ // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_ptr: pointer, buf_len: u32) => [u32, errno];
+ // use share_arrays_memory;
+ // (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno];
+ // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+
+ // Lock when you want to use fd
+ // Array<[lock, call_func]>
+ private lock_fds: SharedArrayBuffer;
+
+ // 1 bytes: fds.length
+ // 1 bytes: wasi_farm_ref num(id)
+ // Actually, as long as it is working properly, fds.length is not used
+ private fds_len_and_num: SharedArrayBuffer;
+
+ // listen promise keep
+ private listen_fds: Array> = [];
+
+ // The largest size is u32 * 18 + 1
+ // Alignment is troublesome, so make it u32 * 18 + 4
+ // In other words, one size is 76 bytes
+ private fd_func_sig: SharedArrayBuffer;
+
+ // listen base handle keep
+ private listen_base_handle: Promise;
+
+ // listen base lock and call etc
+ private base_func_util: SharedArrayBuffer;
+
+ // tell other processes that the file descriptor has been closed
+ private fd_close_receiver: FdCloseSender;
+
+ // this is not send by postMessage,
+ // so it is not necessary to keep shared_array_buffer
+ // this class is not used by user,
+ // to avoid mistakes, all constructors are now required to be passed in.
+ constructor(
+ fds: Array,
+ // stdin fd number
+ stdin: number | undefined,
+ // stdout fd number
+ stdout: number | undefined,
+ // stderr fd number
+ stderr: number | undefined,
+ // wasi_farm_ref default allow fds
+ default_allow_fds: Array,
+ allocator_size?: number,
+ ) {
+ super(fds, stdin, stdout, stderr, default_allow_fds);
+
+ if (allocator_size === undefined) {
+ this.allocator = new AllocatorUseArrayBuffer();
+ } else {
+ this.allocator = new AllocatorUseArrayBuffer(
+ new SharedArrayBuffer(allocator_size),
+ );
+ }
+ const max_fds_len = 128;
+ this.lock_fds = new SharedArrayBuffer(4 * max_fds_len * 3);
+ this.fd_func_sig = new SharedArrayBuffer(
+ fd_func_sig_u32_size * 4 * max_fds_len,
+ );
+ this.fds_len_and_num = new SharedArrayBuffer(8);
+
+ const view = new Int32Array(this.fds_len_and_num);
+ Atomics.store(view, 0, fds.length);
+ Atomics.store(view, 1, 0);
+
+ this.fd_close_receiver = new FdCloseSenderUseArrayBuffer();
+ this.base_func_util = new SharedArrayBuffer(24);
+ }
+
+ /// Send this return by postMessage.
+ get_ref(): WASIFarmRefUseArrayBufferObject {
+ return {
+ allocator: this.allocator,
+ lock_fds: this.lock_fds,
+ fds_len_and_num: this.fds_len_and_num,
+ fd_func_sig: this.fd_func_sig,
+ base_func_util: this.base_func_util,
+ fd_close_receiver: this.fd_close_receiver,
+ stdin: this.stdin,
+ stdout: this.stdout,
+ stderr: this.stderr,
+ default_fds: this.default_allow_fds,
+ };
+ }
+
+ // abstract methods implementation
+ // from fd set ex) path_open
+ // received and listen the fd
+ // and set fds.length
+ async notify_set_fd(fd: number) {
+ if (this.fds[fd] === undefined) {
+ throw new Error("fd is not defined");
+ }
+ if (fd >= 128) {
+ throw new Error("fd is too big. expand is not supported yet");
+ }
+ if (this.listen_fds[fd] !== undefined) {
+ if (this.listen_fds[fd] instanceof Promise) {
+ console.warn("fd is already set yet");
+ await this.listen_fds[fd];
+ }
+ }
+ this.listen_fds[fd] = this.listen_fd(fd);
+
+ const view = new Int32Array(this.fds_len_and_num);
+ Atomics.store(view, 0, this.fds.length);
+ // const len = Atomics.store(view, 0, this.fds.length);
+ // console.log("notify_set_fd: len: ", len);
+ }
+
+ // abstract methods implementation
+ // called by fd close ex) fd_close
+ async notify_rm_fd(fd: number) {
+ (async () => {
+ await this.listen_fds[fd];
+ this.listen_fds[fd] = undefined;
+ })();
+
+ // console.log("notify_rm_fd", fd);
+ // console.log("fds", this.fds);
+ // console.log("fds_map", this.fds_map);
+
+ // console.log("notify_rm_fd: fds_map", this.fds_map);
+ // console.log("notify_rm_fd: fd", fd);
+
+ // console.log("notify_rm_fd: fds_map[fd]", [...this.fds_map[fd]]);
+
+ await this.fd_close_receiver.send(this.fds_map[fd], fd);
+
+ this.fds_map[fd] = [];
+ }
+
+ // abstract methods implementation
+ // wait to close old listener
+ can_set_new_fd(fd: number): [boolean, Promise | undefined] {
+ if (this.listen_fds[fd] instanceof Promise) {
+ return [false, this.listen_fds[fd]];
+ }
+ return [true, undefined];
+ }
+
+ // listen all fds and base
+ // Must be called before was_ref_id is instantiated
+ listen() {
+ this.listen_fds = [];
+ for (let n = 0; n < this.fds.length; n++) {
+ this.listen_fds.push(this.listen_fd(n));
+ }
+ this.listen_base_handle = this.listen_base();
+ }
+
+ // listen base
+ // ex) set_fds_map
+ // if close fd and send to other process,
+ // it need targets wasi_farm_ref id
+ // so, set fds_map
+ async listen_base() {
+ const lock_view = new Int32Array(this.base_func_util);
+ Atomics.store(lock_view, 0, 0);
+ Atomics.store(lock_view, 1, 0);
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ try {
+ let lock: "not-equal" | "timed-out" | "ok";
+
+ const { value } = Atomics.waitAsync(lock_view, 1, 0);
+ if (value instanceof Promise) {
+ lock = await value;
+ } else {
+ lock = value;
+ }
+ if (lock === "timed-out") {
+ throw new Error("timed-out");
+ }
+
+ const func_number = Atomics.load(lock_view, 2);
+
+ switch (func_number) {
+ // set_fds_map: (fds_ptr: u32, fds_len: u32);
+ case 0: {
+ // console.log("set_fds_map");
+ const ptr = Atomics.load(lock_view, 3);
+ const len = Atomics.load(lock_view, 4);
+ // console.log("set_fds_map", ptr, len);
+ const data = new Uint32Array(this.allocator.get_memory(ptr, len));
+ this.allocator.free(ptr, len);
+ const wasi_farm_ref_id = Atomics.load(lock_view, 5);
+
+ // console.log("listen_base set_fds_map", data, "from", wasi_farm_ref_id);
+
+ // console.log("listen_base fds_map", this.fds_map);
+
+ for (let i = 0; i < len / 4; i++) {
+ const fd = data[i];
+ if (this.fds_map[fd] === undefined) {
+ this.fds_map[fd] = [];
+ console.error("listen_base fd is not defined");
+ }
+ this.fds_map[fd].push(wasi_farm_ref_id);
+ // console.log("this.fds_map", this.fds_map);
+ // console.log("this.fds_map[fd]", this.fds_map[fd]);
+ // console.log("this.fds_map[1]", this.fds_map[1]);
+ // console.log("fd", fd, "wasi_farm_ref_id", wasi_farm_ref_id);
+ }
+
+ // console.log("listen_base fds_map", this.fds_map);
+
+ // sleep 1000ms
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ break;
+ }
+ }
+
+ const old_call_lock = Atomics.exchange(lock_view, 1, 0);
+ if (old_call_lock !== 1) {
+ throw new Error("Lock is already set");
+ }
+ const num = Atomics.notify(lock_view, 1, 1);
+ if (num !== 1) {
+ if (num === 0) {
+ console.warn("notify failed, waiter is late");
+ continue;
+ }
+ throw new Error(`notify failed: ${num}`);
+ }
+ } catch (e) {
+ console.error("error", e);
+ Atomics.store(lock_view, 1, 0);
+ Atomics.notify(lock_view, 1, 1);
+ }
+ }
+ }
+
+ // listen fd
+ async listen_fd(fd_n: number) {
+ const lock_view = new Int32Array(this.lock_fds, fd_n * 12);
+ const bytes_offset = fd_n * fd_func_sig_bytes;
+ const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_i32 = new Int32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Int32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+ const errno_offset = fd_func_sig_u32_size - 1;
+ Atomics.store(lock_view, 0, 0);
+ Atomics.store(lock_view, 1, 0);
+ Atomics.store(func_sig_view_i32, errno_offset, -1);
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ try {
+ let lock: "not-equal" | "timed-out" | "ok";
+
+ const { value } = Atomics.waitAsync(lock_view, 1, 0);
+ if (value instanceof Promise) {
+ // console.log("listen", fd_n, 1);
+ lock = await value;
+ } else {
+ lock = value;
+ }
+ if (lock === "timed-out") {
+ throw new Error("timed-out");
+ }
+
+ const func_lock = Atomics.load(lock_view, 1);
+
+ if (func_lock !== 1) {
+ throw new Error(`func_lock is already set: ${func_lock}`);
+ }
+
+ // console.log("func_lock", func_lock);
+
+ // console.log("called", fd_n, 1);
+
+ const set_error = (errno: number) => {
+ // console.log("set_error", errno, "pointer", errno_offset);
+ Atomics.store(func_sig_view_i32, errno_offset, errno);
+ };
+
+ const func_number = Atomics.load(func_sig_view_u32, 0);
+
+ // console.log("called: func: ", get_func_name_from_number(func_number), "fd: ", fd_n);
+
+ switch (func_number) {
+ // fd_advise: (fd: u32) => errno;
+ case 7: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const error = this.fd_advise(fd);
+
+ set_error(error);
+ break;
+ }
+ // fd_allocate: (fd: u32, offset: u64, len: u64) => errno;
+ case 8: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const offset = Atomics.load(func_sig_view_u64, 1);
+ const len = Atomics.load(func_sig_view_u64, 2);
+
+ const error = this.fd_allocate(fd, offset, len);
+
+ set_error(error);
+ break;
+ }
+ // fd_close: (fd: u32) => errno;
+ case 9: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const error = await this.fd_close(fd);
+
+ // console.log("fd_close", fd, error);
+
+ set_error(error);
+ break;
+ }
+ // fd_datasync: (fd: u32) => errno;
+ case 10: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const error = this.fd_datasync(fd);
+
+ set_error(error);
+ break;
+ }
+ // fd_fdstat_get: (fd: u32) => [wasi.Fdstat(u32 * 6)], errno];
+ case 11: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const [fdstat, ret] = this.fd_fdstat_get(fd);
+
+ if (fdstat) {
+ Atomics.store(func_sig_view_u8, 0, fdstat.fs_filetype);
+ Atomics.store(func_sig_view_u16, 2, fdstat.fs_flags);
+ Atomics.store(func_sig_view_u64, 1, fdstat.fs_rights_base);
+ Atomics.store(func_sig_view_u64, 2, fdstat.fs_rights_inherited);
+ }
+ set_error(ret);
+ break;
+ }
+ // fd_fdstat_set_flags: (fd: u32, flags: u16) => errno;
+ case 12: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const flags = Atomics.load(func_sig_view_u16, 4);
+
+ const error = this.fd_fdstat_set_flags(fd, flags);
+
+ set_error(error);
+ break;
+ }
+ // fd_fdstat_set_rights: (fd: u32, fs_rights_base: u64, fs_rights_inheriting: u64) => errno;
+ case 13: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const fs_rights_base = Atomics.load(func_sig_view_u64, 1);
+ const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2);
+
+ const error = this.fd_fdstat_set_rights(
+ fd,
+ fs_rights_base,
+ fs_rights_inheriting,
+ );
+
+ set_error(error);
+ break;
+ }
+ // fd_filestat_get: (fd: u32) => [wasi.Filestat(u32 * 16)], errno];
+ case 14: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const [filestat, ret] = this.fd_filestat_get(fd);
+
+ if (filestat) {
+ Atomics.store(func_sig_view_u64, 0, filestat.dev);
+ Atomics.store(func_sig_view_u64, 1, filestat.ino);
+ Atomics.store(func_sig_view_u8, 16, filestat.filetype);
+ Atomics.store(func_sig_view_u64, 3, filestat.nlink);
+ Atomics.store(func_sig_view_u64, 4, filestat.size);
+ Atomics.store(func_sig_view_u64, 5, filestat.atim);
+ Atomics.store(func_sig_view_u64, 6, filestat.mtim);
+ Atomics.store(func_sig_view_u64, 7, filestat.ctim);
+ }
+
+ set_error(ret);
+ break;
+ }
+ // fd_filestat_set_size: (fd: u32, size: u64) => errno;
+ case 15: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const size = Atomics.load(func_sig_view_u64, 1);
+
+ const error = this.fd_filestat_set_size(fd, size);
+
+ set_error(error);
+ break;
+ }
+ // fd_filestat_set_times: (fd: u32, atim: u64, mtim: u64, fst_flags: u16) => errno;
+ case 16: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const atim = Atomics.load(func_sig_view_u64, 1);
+ const mtim = Atomics.load(func_sig_view_u64, 2);
+ const fst_flags = Atomics.load(func_sig_view_u16, 12);
+
+ const error = this.fd_filestat_set_times(fd, atim, mtim, fst_flags);
+
+ set_error(error);
+ break;
+ }
+ // fd_pread: (fd: u32, iovs_ptr: pointer, iovs_len: u32, offset: u64) => [u32, data_ptr, errno];
+ case 17: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const iovs_ptr = Atomics.load(func_sig_view_u32, 2);
+ const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3);
+ const offset = Atomics.load(func_sig_view_u64, 2);
+ const data = new Uint32Array(
+ this.allocator.get_memory(iovs_ptr, iovs_ptr_len),
+ );
+ this.allocator.free(iovs_ptr, iovs_ptr_len);
+
+ const iovecs = new Array();
+ for (let i = 0; i < iovs_ptr_len; i += 8) {
+ const iovec = new wasi.Iovec();
+ iovec.buf = data[i * 2];
+ iovec.buf_len = data[i * 2 + 1];
+ iovecs.push(iovec);
+ }
+
+ const [[nread, buffer8], error] = this.fd_pread(fd, iovecs, offset);
+
+ if (nread !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, nread);
+ }
+ if (buffer8) {
+ await this.allocator.async_write(
+ buffer8,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 1,
+ );
+ }
+ set_error(error);
+ break;
+ }
+ // fd_prestat_get: (fd: u32) => [wasi.Prestat(u32 * 2)], errno];
+ case 18: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const [prestat, ret] = this.fd_prestat_get(fd);
+
+ // console.log("fd_prestat_get", prestat, ret);
+
+ if (prestat) {
+ Atomics.store(func_sig_view_u32, 0, prestat.tag);
+ Atomics.store(
+ func_sig_view_u32,
+ 1,
+ prestat.inner.pr_name.byteLength,
+ );
+ }
+ set_error(ret);
+ break;
+ }
+ // fd_prestat_dir_name: (fd: u32, path_len: u32) => [path_ptr: pointer, path_len: u32, errno];
+ case 19: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const path_len = Atomics.load(func_sig_view_u32, 2);
+
+ const [prestat_dir_name, ret] = this.fd_prestat_dir_name(
+ fd,
+ path_len,
+ );
+
+ // console.log("fd_prestat_dir_name: park: ", prestat_dir_name);
+
+ if (
+ prestat_dir_name &&
+ (ret === wasi.ERRNO_SUCCESS || ret === wasi.ERRNO_NAMETOOLONG)
+ ) {
+ await this.allocator.async_write(
+ prestat_dir_name,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size,
+ );
+ }
+ set_error(ret);
+ break;
+ }
+ // fd_pwrite: (fd: u32, write_data: pointer, write_data_len: u32, offset: u64) => [u32, errno];
+ case 20: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const write_data_ptr = Atomics.load(func_sig_view_u32, 2);
+ const write_data_len = Atomics.load(func_sig_view_u32, 3);
+ const offset = Atomics.load(func_sig_view_u64, 2);
+
+ const data = new Uint8Array(
+ this.allocator.get_memory(write_data_ptr, write_data_len),
+ );
+ this.allocator.free(write_data_ptr, write_data_len);
+
+ const [nwritten, error] = this.fd_pwrite(fd, data, offset);
+
+ if (nwritten !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, nwritten);
+ }
+ set_error(error);
+ break;
+ }
+ // fd_read: (fd: u32, iovs_ptr: pointer, iovs_len: u32) => [u32, data_ptr, errno];
+ case 21: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const iovs_ptr = Atomics.load(func_sig_view_u32, 2);
+ const iovs_ptr_len = Atomics.load(func_sig_view_u32, 3);
+ // console.log("fd_read: park: iovs: Uint8Array", this.allocator.get_memory(iovs_ptr, iovs_ptr_len));
+ // console.log("ptr_len", iovs_ptr_len);
+ const iovs = new Uint32Array(
+ this.allocator.get_memory(iovs_ptr, iovs_ptr_len),
+ );
+ this.allocator.free(iovs_ptr, iovs_ptr_len);
+
+ // console.log("fd_read: park: iovs", iovs);
+
+ const iovecs = new Array();
+ for (let i = 0; i < iovs_ptr_len; i += 8) {
+ const iovec = new wasi.Iovec();
+ iovec.buf = iovs[i * 2];
+ iovec.buf_len = iovs[i * 2 + 1];
+ iovecs.push(iovec);
+ }
+
+ // console.log("fd_read: park: iovecs", iovecs);
+
+ const [[nread, buffer8], error] = this.fd_read(fd, iovecs);
+
+ // console.log("fd_read: park: buffer8", new TextDecoder().decode(buffer8));
+
+ if (nread !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, nread);
+ }
+ if (buffer8) {
+ await this.allocator.async_write(
+ buffer8,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 1,
+ );
+ }
+ set_error(error);
+ break;
+ }
+ // fd_readdir: (fd: u32, buf_len: u32, cookie: u64) => [buf_ptr: pointer, buf_len: u32, buf_used: u32, errno];
+ case 22: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const buf_len = Atomics.load(func_sig_view_u32, 2);
+ const cookie = Atomics.load(func_sig_view_u64, 2);
+
+ const [[array, buf_used], error] = this.fd_readdir(
+ fd,
+ buf_len,
+ cookie,
+ );
+
+ if (array) {
+ await this.allocator.async_write(
+ array,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size,
+ );
+ }
+ if (buf_used !== undefined) {
+ Atomics.store(func_sig_view_u32, 2, buf_used);
+ }
+ set_error(error);
+ break;
+ }
+ // fd_seek: (fd: u32, offset: i64, whence: u8) => [u64, errno];
+ case 24: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const offset = Atomics.load(func_sig_view_u64, 1);
+ const whence = Atomics.load(func_sig_view_u8, 16);
+
+ const [new_offset, error] = this.fd_seek(fd, offset, whence);
+
+ if (new_offset !== undefined) {
+ Atomics.store(func_sig_view_u64, 0, new_offset);
+ }
+ set_error(error);
+ break;
+ }
+ // fd_sync: (fd: u32) => errno;
+ case 25: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const error = this.fd_sync(fd);
+
+ set_error(error);
+ break;
+ }
+ // fd_tell: (fd: u32) => [u64, errno];
+ case 26: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+
+ const [offset, error] = this.fd_tell(fd);
+
+ if (offset !== undefined) {
+ Atomics.store(func_sig_view_u64, 0, offset);
+ }
+ set_error(error);
+ break;
+ }
+ // fd_write: (fd: u32, write_data: pointer, write_data_len: u32) => [u32, errno];
+ case 27: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const write_data_ptr = Atomics.load(func_sig_view_u32, 2);
+ const write_data_len = Atomics.load(func_sig_view_u32, 3);
+
+ const data = new Uint8Array(
+ this.allocator.get_memory(write_data_ptr, write_data_len),
+ );
+ this.allocator.free(write_data_ptr, write_data_len);
+
+ // console.log("allocator", this.allocator);
+
+ console.log(
+ "fd_write: park: write_data",
+ "fd: ", fd,
+ new TextDecoder().decode(data),
+ );
+
+ const [nwritten, error] = await this.fd_write(fd, data);
+
+ // console.log("fd_write: park: error", error);
+
+ if (nwritten !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, nwritten);
+ }
+ set_error(error);
+ break;
+ }
+ // path_create_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ case 28: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const path_ptr = Atomics.load(func_sig_view_u32, 2);
+ const path_len = Atomics.load(func_sig_view_u32, 3);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const error = this.path_create_directory(fd, path_str);
+
+ set_error(error);
+ break;
+ }
+ // path_filestat_get: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32) => [wasi.Filestat(u32 * 16), errno];
+ case 29: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const flags = Atomics.load(func_sig_view_u32, 2);
+ const path_ptr = Atomics.load(func_sig_view_u32, 3);
+ const path_len = Atomics.load(func_sig_view_u32, 4);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const [filestat, ret] = this.path_filestat_get(fd, flags, path_str);
+
+ if (filestat) {
+ Atomics.store(func_sig_view_u64, 0, filestat.dev);
+ Atomics.store(func_sig_view_u64, 1, filestat.ino);
+ Atomics.store(func_sig_view_u8, 16, filestat.filetype);
+ Atomics.store(func_sig_view_u64, 3, filestat.nlink);
+ Atomics.store(func_sig_view_u64, 4, filestat.size);
+ Atomics.store(func_sig_view_u64, 5, filestat.atim);
+ Atomics.store(func_sig_view_u64, 6, filestat.mtim);
+ Atomics.store(func_sig_view_u64, 7, filestat.ctim);
+ }
+ set_error(ret);
+ break;
+ }
+ // path_filestat_set_times: (fd: u32, flags: u32, path_ptr: pointer, path_len: u32, atim: u64, mtim: u64, fst_flags: u16) => errno;
+ case 30: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const flags = Atomics.load(func_sig_view_u32, 2);
+ const path_ptr = Atomics.load(func_sig_view_u32, 3);
+ const path_len = Atomics.load(func_sig_view_u32, 4);
+ const atim = Atomics.load(func_sig_view_u64, 3);
+ const mtim = Atomics.load(func_sig_view_u64, 4);
+ const fst_flags = Atomics.load(func_sig_view_u16, 12);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const error = this.path_filestat_set_times(
+ fd,
+ flags,
+ path_str,
+ atim,
+ mtim,
+ fst_flags,
+ );
+
+ set_error(error);
+ break;
+ }
+ // path_link: (old_fd: u32, old_flags: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ case 31: {
+ const old_fd = Atomics.load(func_sig_view_u32, 1);
+ const old_flags = Atomics.load(func_sig_view_u32, 2);
+ const old_path_ptr = Atomics.load(func_sig_view_u32, 3);
+ const old_path_len = Atomics.load(func_sig_view_u32, 4);
+ const new_fd = Atomics.load(func_sig_view_u32, 5);
+ const new_path_ptr = Atomics.load(func_sig_view_u32, 6);
+ const new_path_len = Atomics.load(func_sig_view_u32, 7);
+
+ const old_path = new Uint8Array(
+ this.allocator.get_memory(old_path_ptr, old_path_len),
+ );
+ const old_path_str = new TextDecoder().decode(old_path);
+ this.allocator.free(old_path_ptr, old_path_len);
+ const new_path = new Uint8Array(
+ this.allocator.get_memory(new_path_ptr, new_path_len),
+ );
+ const new_path_str = new TextDecoder().decode(new_path);
+ this.allocator.free(new_path_ptr, new_path_len);
+
+ const error = this.path_link(
+ old_fd,
+ old_flags,
+ old_path_str,
+ new_fd,
+ new_path_str,
+ );
+
+ set_error(error);
+ break;
+ }
+ // path_open: (fd: u32, dirflags: u32, path_ptr: pointer, path_len: u32, oflags: u32, fs_rights_base: u64, fs_rights_inheriting: u64, fdflags: u16) => [u32, errno];
+ case 32: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const dirflags = Atomics.load(func_sig_view_u32, 2);
+ const path_ptr = Atomics.load(func_sig_view_u32, 3);
+ const path_len = Atomics.load(func_sig_view_u32, 4);
+ const oflags = Atomics.load(func_sig_view_u32, 5);
+ const fs_rights_base = Atomics.load(func_sig_view_u64, 3);
+ const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 4);
+ const fd_flags = Atomics.load(func_sig_view_u16, 20);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const [opened_fd, error] = await this.path_open(
+ fd,
+ dirflags,
+ path_str,
+ oflags,
+ fs_rights_base,
+ fs_rights_inheriting,
+ fd_flags,
+ );
+
+ // console.log("path_open: opend_fd", opened_fd, error);
+
+ if (opened_fd !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, opened_fd);
+ }
+ set_error(error);
+ break;
+ }
+ // path_readlink: (fd: u32, path_ptr: pointer, path_len: u32, buf_len: u32) => [buf_len: u32, data_ptr: pointer, data_len: u32, errno];
+ case 33: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const path_ptr = Atomics.load(func_sig_view_u32, 2);
+ const path_len = Atomics.load(func_sig_view_u32, 3);
+ const buf_len = Atomics.load(func_sig_view_u32, 4);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const [buf, error] = this.path_readlink(fd, path_str, buf_len);
+
+ if (buf) {
+ await this.allocator.async_write(
+ buf,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 1,
+ );
+ Atomics.store(func_sig_view_u32, 0, buf.byteLength);
+ }
+ set_error(error);
+ break;
+ }
+ // path_remove_directory: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ case 34: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const path_ptr = Atomics.load(func_sig_view_u32, 2);
+ const path_len = Atomics.load(func_sig_view_u32, 3);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ const error = this.path_remove_directory(fd, path_str);
+
+ set_error(error);
+ break;
+ }
+ // path_rename: (old_fd: u32, old_path_ptr: pointer, old_path_len: u32, new_fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ case 35: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const old_path_ptr = Atomics.load(func_sig_view_u32, 2);
+ const old_path_len = Atomics.load(func_sig_view_u32, 3);
+ const new_fd = Atomics.load(func_sig_view_u32, 4);
+ const new_path_ptr = Atomics.load(func_sig_view_u32, 5);
+ const new_path_len = Atomics.load(func_sig_view_u32, 6);
+
+ const old_path = new Uint8Array(
+ this.allocator.get_memory(old_path_ptr, old_path_len),
+ );
+ const old_path_str = new TextDecoder().decode(old_path);
+ this.allocator.free(old_path_ptr, old_path_len);
+ const new_path = new Uint8Array(
+ this.allocator.get_memory(new_path_ptr, new_path_len),
+ );
+ const new_path_str = new TextDecoder().decode(new_path);
+ this.allocator.free(new_path_ptr, new_path_len);
+
+ const error = this.path_rename(
+ fd,
+ old_path_str,
+ new_fd,
+ new_path_str,
+ );
+
+ set_error(error);
+ break;
+ }
+ // path_symlink: (old_path_ptr: pointer, old_path_len: u32, fd: u32, new_path_ptr: pointer, new_path_len: u32) => errno;
+ case 36: {
+ const old_path_ptr = Atomics.load(func_sig_view_u32, 1);
+ const old_path_len = Atomics.load(func_sig_view_u32, 2);
+ const fd = Atomics.load(func_sig_view_u32, 3);
+ const new_path_ptr = Atomics.load(func_sig_view_u32, 4);
+ const new_path_len = Atomics.load(func_sig_view_u32, 5);
+
+ const old_path = new Uint8Array(
+ this.allocator.get_memory(old_path_ptr, old_path_len),
+ );
+ const old_path_str = new TextDecoder().decode(old_path);
+ this.allocator.free(old_path_ptr, old_path_len);
+ const new_path = new Uint8Array(
+ this.allocator.get_memory(new_path_ptr, new_path_len),
+ );
+ const new_path_str = new TextDecoder().decode(new_path);
+ this.allocator.free(new_path_ptr, new_path_len);
+
+ set_error(this.path_symlink(old_path_str, fd, new_path_str));
+ break;
+ }
+ // path_unlink_file: (fd: u32, path_ptr: pointer, path_len: u32) => errno;
+ case 37: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const path_ptr = Atomics.load(func_sig_view_u32, 2);
+ const path_len = Atomics.load(func_sig_view_u32, 3);
+
+ const path = new Uint8Array(
+ this.allocator.get_memory(path_ptr, path_len),
+ );
+ const path_str = new TextDecoder().decode(path);
+ this.allocator.free(path_ptr, path_len);
+
+ set_error(this.path_unlink_file(fd, path_str));
+ break;
+ }
+ // open_fd_with_buff: (fd: u32, buf: pointer, buf_len: u32) => [u32, errno];
+ case 38: {
+ const fd = Atomics.load(func_sig_view_u32, 1);
+ const buf_ptr = Atomics.load(func_sig_view_u32, 2);
+ const buf_len = Atomics.load(func_sig_view_u32, 3);
+
+ const buf = new Uint8Array(
+ this.allocator.get_memory(buf_ptr, buf_len),
+ );
+ this.allocator.free(buf_ptr, buf_len);
+
+ const [opened_fd, error] = await this.open_fd_with_buff(fd, buf);
+
+ if (opened_fd !== undefined) {
+ Atomics.store(func_sig_view_u32, 0, opened_fd);
+ }
+ set_error(error);
+ break;
+ }
+ default: {
+ throw new Error(`Unknown function number: ${func_number}`);
+ }
+ }
+
+ const old_call_lock = Atomics.exchange(lock_view, 1, 0);
+ if (old_call_lock !== 1) {
+ throw new Error(
+ `Call is already set: ${old_call_lock}\nfunc: ${get_func_name_from_number(func_number)}\nfd: ${fd_n}`,
+ );
+ }
+
+ // console.log("called end: func: ", get_func_name_from_number(func_number), "fd: ", fd_n);
+
+ const n = Atomics.notify(lock_view, 1);
+ if (n !== 1) {
+ if (n === 0) {
+ console.warn("notify number is 0. ref is late?");
+ } else {
+ console.warn(`notify number is not 1: ${n}`);
+ }
+ }
+
+ if (this.fds[fd_n] === undefined) {
+ break;
+ }
+ } catch (e) {
+ console.error(e);
+
+ // sleep 1000ms
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+
+ const lock_view = new Int32Array(this.lock_fds);
+ Atomics.exchange(lock_view, 1, 0);
+ const func_sig_view = new Int32Array(this.fd_func_sig);
+ Atomics.exchange(func_sig_view, 16, -1);
+ }
+ }
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/ref.ts b/src/wasi_farm/shared_array_buffer/ref.ts
new file mode 100644
index 0000000..d0dfffb
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/ref.ts
@@ -0,0 +1,1437 @@
+import * as wasi from "../../wasi_defs.js";
+import { WASIFarmRef, type WASIFarmRefObject } from "../ref.js";
+import {
+ AllocatorUseArrayBuffer,
+ type AllocatorUseArrayBufferObject,
+} from "./allocator.js";
+import {
+ FdCloseSenderUseArrayBuffer,
+ type FdCloseSenderUseArrayBufferObject,
+} from "./fd_close_sender.js";
+import { fd_func_sig_bytes, fd_func_sig_u32_size } from "./park.js";
+
+export type WASIFarmRefUseArrayBufferObject = {
+ allocator: AllocatorUseArrayBuffer;
+ lock_fds: SharedArrayBuffer;
+ fds_len_and_num: SharedArrayBuffer;
+ fd_func_sig: SharedArrayBuffer;
+ base_func_util: SharedArrayBuffer;
+} & WASIFarmRefObject;
+
+// Transmittable objects to communicate with Park
+export class WASIFarmRefUseArrayBuffer extends WASIFarmRef {
+ // For more information on member variables, see . See /park.ts
+ allocator: AllocatorUseArrayBuffer;
+ lock_fds: SharedArrayBuffer;
+ // byte 1: fds_len
+ // byte 2: all wasi_farm_ref num
+ fds_len_and_num: SharedArrayBuffer;
+ fd_func_sig: SharedArrayBuffer;
+ base_func_util: SharedArrayBuffer;
+
+ constructor(
+ allocator: AllocatorUseArrayBufferObject,
+ lock_fds: SharedArrayBuffer,
+ fds_len_and_num: SharedArrayBuffer,
+ fd_func_sig: SharedArrayBuffer,
+ base_func_util: SharedArrayBuffer,
+ fd_close_receiver: FdCloseSenderUseArrayBufferObject,
+ stdin: number | undefined,
+ stdout: number | undefined,
+ stderr: number | undefined,
+ default_fds: Array,
+ ) {
+ super(
+ stdin,
+ stdout,
+ stderr,
+ FdCloseSenderUseArrayBuffer.init_self(fd_close_receiver),
+ default_fds,
+ );
+ this.allocator = AllocatorUseArrayBuffer.init_self(allocator);
+ this.lock_fds = lock_fds;
+ this.fd_func_sig = fd_func_sig;
+ this.base_func_util = base_func_util;
+ this.fds_len_and_num = fds_len_and_num;
+
+ // console.log("fds_len_and_num", this.fds_len_and_num);
+
+ // const view = new Int32Array(this.fds_len_and_num);
+ // Atomics.store(view, 0, 0);
+ }
+
+ get_fds_len(): number {
+ const view = new Int32Array(this.fds_len_and_num);
+ return Atomics.load(view, 0);
+ }
+
+ static init_self(sl: WASIFarmRefUseArrayBufferObject): WASIFarmRef {
+ return new WASIFarmRefUseArrayBuffer(
+ sl.allocator,
+ sl.lock_fds,
+ sl.fds_len_and_num,
+ sl.fd_func_sig,
+ sl.base_func_util,
+ sl.fd_close_receiver as unknown as FdCloseSenderUseArrayBufferObject,
+ sl.stdin,
+ sl.stdout,
+ sl.stderr,
+ sl.default_fds,
+ );
+ }
+
+ // allocate a new id on wasi_farm_ref and return it
+ set_id(): number {
+ const view = new Int32Array(this.fds_len_and_num);
+ const id = Atomics.add(view, 1, 1);
+ this.id = id;
+ return id;
+ }
+
+ // lock base_func
+ private lock_base_func(): void {
+ const view = new Int32Array(this.base_func_util);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const lock = Atomics.wait(view, 0, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ // call base_func
+ private call_base_func(): void {
+ const view = new Int32Array(this.base_func_util);
+ const old = Atomics.exchange(view, 1, 1);
+ if (old !== 0) {
+ console.error("what happened?");
+ }
+ Atomics.notify(view, 1, 1);
+ }
+
+ // wait base_func
+ private wait_base_func(): void {
+ const view = new Int32Array(this.base_func_util);
+ const lock = Atomics.wait(view, 1, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ }
+
+ // release base_func
+ private release_base_func(): void {
+ const view = new Int32Array(this.base_func_util);
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+ }
+
+ // set park_fds_map
+ set_park_fds_map(fds: Array): void {
+ this.lock_base_func();
+ const view = new Int32Array(this.base_func_util);
+ Atomics.store(view, 2, 0);
+ const fds_array = new Uint32Array(fds);
+ // console.log("fds_array", fds_array);
+ this.allocator.block_write(fds_array, this.base_func_util, 3);
+ Atomics.store(view, 5, this.id);
+ this.call_base_func();
+ this.wait_base_func();
+ this.release_base_func();
+ }
+
+ private lock_fd(fd: number) {
+ // console.log("lock_fd start", fd);
+ const view = new Int32Array(this.lock_fds, fd * 12);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const now_value = Atomics.load(view, 0);
+ if (now_value !== 0) {
+ const value = Atomics.wait(view, 0, now_value);
+ if (value === "timed-out") {
+ console.error("lock_fd timed-out");
+ continue;
+ }
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old === 0) {
+ // console.log("lock_fd success", fd);
+ return;
+ }
+ }
+ }
+
+ private release_fd(fd: number) {
+ // console.log("release_fd", fd);
+ const view = new Int32Array(this.lock_fds, fd * 12);
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+ }
+
+ private lock_double_fd(fd1: number, fd2: number) {
+ // console.log("lock_double_fd", fd1, fd2);
+ const view = new Int32Array(this.lock_fds);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const now_value1 = Atomics.load(view, fd1 * 3);
+ const value = Atomics.wait(view, fd1 * 3, now_value1);
+ if (value === "timed-out") {
+ console.error("lock_double_fd timed-out");
+ continue;
+ }
+ const old1 = Atomics.exchange(view, fd1 * 3, 2);
+ if (old1 === 0) {
+ const now_value2 = Atomics.load(view, fd2 * 3);
+ if (now_value2 === 2) {
+ // It's nearly deadlocked.
+ if (fd1 < fd2) {
+ // release fd1
+ Atomics.store(view, fd1 * 3, 0);
+ Atomics.notify(view, fd1 * 3, 1);
+ continue;
+ }
+ }
+ const value = Atomics.wait(view, fd2 * 3, now_value2);
+ if (value === "timed-out") {
+ console.error("lock_double_fd timed-out");
+ continue;
+ }
+ const old2 = Atomics.exchange(view, fd2 * 3, 2);
+ if (old2 === 0) {
+ return;
+ }
+ Atomics.store(view, fd1 * 3, 0);
+ Atomics.notify(view, fd1 * 3, 1);
+ }
+ }
+ }
+
+ private release_double_fd(fd1: number, fd2: number) {
+ // console.log("release_double_fd", fd1, fd2);
+ const view = new Int32Array(this.lock_fds);
+ Atomics.store(view, fd1 * 3, 0);
+ Atomics.notify(view, fd1 * 3, 1);
+ Atomics.store(view, fd2 * 3, 0);
+ Atomics.notify(view, fd2 * 3, 1);
+ }
+
+ private invoke_fd_func(fd: number): boolean {
+ if (fd === undefined) {
+ return false;
+ }
+ // console.log("invoke_fd_func", fd);
+ const view = new Int32Array(this.lock_fds, fd * 12 + 4);
+ const old = Atomics.exchange(view, 0, 1);
+ if (old === 1) {
+ console.error(`invoke_fd_func already invoked\nfd: ${fd}`);
+ return;
+ }
+ const n = Atomics.notify(view, 0);
+ if (n !== 1) {
+ if (n === 0) {
+ const len = this.get_fds_len();
+ if (len <= fd) {
+ const lock = Atomics.exchange(view, 0, 0);
+ if (lock !== 1) {
+ console.error("what happened?");
+ }
+ Atomics.notify(view, 0, 1);
+ console.error("what happened?: len", len, "fd", fd);
+ return true;
+ }
+ console.warn("invoke_func_loop is late");
+ return true;
+ }
+ console.error("invoke_fd_func notify failed:", n);
+ return false;
+ }
+ return true;
+ }
+
+ private wait_fd_func(fd: number) {
+ // console.log("wait_fd_func", fd);
+ const view = new Int32Array(this.lock_fds, fd * 12 + 4);
+ const value = Atomics.wait(view, 0, 1);
+ if (value === "timed-out") {
+ console.error("wait call park_fd_func timed-out");
+ }
+ }
+
+ private call_fd_func(fd: number): boolean {
+ if (!this.invoke_fd_func(fd)) {
+ return false;
+ }
+ // console.log("call_fd_func", fd);
+ this.wait_fd_func(fd);
+ // console.log("wait_fd_func", fd);
+ // console.log("call_fd_func released", fd);
+ return true;
+ }
+
+ private get_error(fd: number): number {
+ const func_sig_view_i32 = new Int32Array(
+ this.fd_func_sig,
+ fd * fd_func_sig_bytes,
+ );
+ const errno_offset = fd_func_sig_u32_size - 1;
+ // console.log("get_error: offset", errno_offset);
+ return Atomics.load(func_sig_view_i32, errno_offset);
+ }
+
+ fd_advise(fd: number): number {
+ this.lock_fd(fd);
+
+ const func_sig_view_u32 = new Uint32Array(
+ this.fd_func_sig,
+ fd * fd_func_sig_bytes,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 7);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_allocate(fd: number, offset: bigint, len: bigint): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 8);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u64, 1, offset);
+ Atomics.store(func_sig_view_u64, 2, len);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_close(fd: number): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 9);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ // console.log("fd_close: ref", fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ // console.log("fd_close: ref2", fd);
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ // console.log("fd_close: ref3", fd);
+
+ return error;
+ }
+
+ fd_datasync(fd: number): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 10);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_fdstat_get(fd: number): [wasi.Fdstat | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 11);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error !== wasi.ERRNO_SUCCESS) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const fs_filetype = Atomics.load(func_sig_view_u8, 0);
+ const fs_flags = Atomics.load(func_sig_view_u16, 2);
+ const fs_rights_base = Atomics.load(func_sig_view_u64, 1);
+ const fs_rights_inheriting = Atomics.load(func_sig_view_u64, 2);
+
+ this.release_fd(fd);
+
+ const fd_stat = new wasi.Fdstat(fs_filetype, fs_flags);
+ fd_stat.fs_rights_base = fs_rights_base;
+ fd_stat.fs_rights_inherited = fs_rights_inheriting;
+
+ return [fd_stat, error];
+ }
+
+ fd_fdstat_set_flags(fd: number, flags: number): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 12);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u16, 4, flags);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_fdstat_set_rights(
+ fd: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ ): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 13);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u64, 1, fs_rights_base);
+ Atomics.store(func_sig_view_u64, 2, fs_rights_inheriting);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_filestat_get(fd: number): [wasi.Filestat | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 14);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error !== wasi.ERRNO_SUCCESS) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const fs_dev = Atomics.load(func_sig_view_u64, 0);
+ const fs_ino = Atomics.load(func_sig_view_u64, 1);
+ const fs_filetype = Atomics.load(func_sig_view_u8, 16);
+ const fs_nlink = Atomics.load(func_sig_view_u64, 3);
+ const fs_size = Atomics.load(func_sig_view_u64, 4);
+ const fs_atim = Atomics.load(func_sig_view_u64, 5);
+ const fs_mtim = Atomics.load(func_sig_view_u64, 6);
+ const fs_ctim = Atomics.load(func_sig_view_u64, 7);
+
+ this.release_fd(fd);
+
+ const file_stat = new wasi.Filestat(fs_filetype, fs_size);
+ file_stat.dev = fs_dev;
+ file_stat.ino = fs_ino;
+ file_stat.nlink = fs_nlink;
+ file_stat.atim = fs_atim;
+ file_stat.mtim = fs_mtim;
+ file_stat.ctim = fs_ctim;
+
+ return [file_stat, error];
+ }
+
+ fd_filestat_set_size(fd: number, size: bigint): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 15);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u64, 1, size);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_filestat_set_times(
+ fd: number,
+ st_atim: bigint,
+ st_mtim: bigint,
+ fst_flags: number,
+ ): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 16);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u64, 1, st_atim);
+ Atomics.store(func_sig_view_u64, 2, st_mtim);
+ Atomics.store(func_sig_view_u16, 12, fst_flags);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_pread(
+ fd: number,
+ iovs: Uint32Array,
+ offset: bigint,
+ ): [[number, Uint8Array] | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 17);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ iovs,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+ Atomics.store(func_sig_view_u64, 2, offset);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ const nread = Atomics.load(func_sig_view_u32, 0);
+ const buf_ptr = Atomics.load(func_sig_view_u32, 1);
+ const buf_len = Atomics.load(func_sig_view_u32, 2);
+ this.release_fd(fd);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.allocator.free(buf_ptr, buf_len);
+ return [undefined, error];
+ }
+
+ const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len));
+
+ if (nread !== buf_len) {
+ console.error("pread nread !== buf_len");
+ }
+
+ this.allocator.free(buf_ptr, buf_len);
+
+ return [[nread, buf], error];
+ }
+
+ fd_prestat_get(fd: number): [[number, number] | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 18);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error !== wasi.ERRNO_SUCCESS) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const pr_tag = Atomics.load(func_sig_view_u32, 0);
+ const pr_name_len = Atomics.load(func_sig_view_u32, 1);
+
+ this.release_fd(fd);
+
+ return [[pr_tag, pr_name_len], error];
+ }
+
+ fd_prestat_dir_name(
+ fd: number,
+ path_len: number,
+ ): [Uint8Array | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 19);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u32, 2, path_len);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ const ret_path_ptr = Atomics.load(func_sig_view_u32, 0);
+ const ret_path_len = Atomics.load(func_sig_view_u32, 1);
+
+ this.release_fd(fd);
+ if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) {
+ this.allocator.free(ret_path_ptr, ret_path_len);
+ return [undefined, error];
+ }
+
+ const ret_path = new Uint8Array(
+ this.allocator.get_memory(ret_path_ptr, ret_path_len),
+ );
+ this.allocator.free(ret_path_ptr, ret_path_len);
+
+ return [ret_path, error];
+ }
+
+ fd_pwrite(
+ fd: number,
+ write_data: Uint8Array,
+ offset: bigint,
+ ): [number | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 20);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ write_data,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+ Atomics.store(func_sig_view_u64, 2, offset);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const nwritten = Atomics.load(func_sig_view_u32, 0);
+
+ this.release_fd(fd);
+
+ return [nwritten, error];
+ }
+
+ fd_read(
+ fd: number,
+ iovs: Uint32Array,
+ ): [[number, Uint8Array] | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 21);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ // console.log("fd_read: ref: iovs", iovs);
+ // console.log("iovs.buffer", iovs.buffer.slice(0, iovs.byteLength));
+
+ const [ptr, len] = this.allocator.block_write(
+ iovs,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ // console.log("fd_read: ref: iovs", iovs);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ const nread = Atomics.load(func_sig_view_u32, 0);
+ const buf_ptr = Atomics.load(func_sig_view_u32, 1);
+ const buf_len = Atomics.load(func_sig_view_u32, 2);
+ this.release_fd(fd);
+
+ // console.log("fd_read: ref: ", nread, buf_ptr, buf_len);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.allocator.free(buf_ptr, buf_len);
+ return [undefined, error];
+ }
+
+ // fd_read: ref: 14 30 14
+ // animals.ts:325 fd_read: nread 14 Hello, world!
+ // fd_read: ref: 21 52 32
+ // ref.ts:655 fd_read: ref: 21
+ const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len));
+ // console.log("fd_read: ref: ", nread, new TextDecoder().decode(buf));
+
+ // console.log("fd_read: nread", nread, new TextDecoder().decode(buf));
+
+ if (nread !== buf_len) {
+ console.error("read nread !== buf_len");
+ }
+
+ this.allocator.free(buf_ptr, buf_len);
+
+ return [[nread, buf], error];
+ }
+
+ fd_readdir(
+ fd: number,
+ limit_buf_len: number,
+ cookie: bigint,
+ ): [[Uint8Array, number] | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 22);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u32, 2, limit_buf_len);
+ Atomics.store(func_sig_view_u64, 2, cookie);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ const buf_ptr = Atomics.load(func_sig_view_u32, 0);
+ const buf_len = Atomics.load(func_sig_view_u32, 1);
+ const buf_used = Atomics.load(func_sig_view_u32, 2);
+ this.release_fd(fd);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.allocator.free(buf_ptr, buf_len);
+ return [undefined, error];
+ }
+
+ const buf = new Uint8Array(this.allocator.get_memory(buf_ptr, buf_len));
+
+ this.allocator.free(buf_ptr, buf_len);
+
+ return [[buf, buf_used], error];
+ }
+
+ // fd_renumber(
+ // fd: number,
+ // to: number,
+ // ): number {
+ // this.lock_double_fd(fd, to);
+
+ // const bytes_offset = fd * fd_func_sig_bytes;
+ // const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ // // fd
+ // Atomics.store(func_sig_view_u32, 0, 23);
+ // Atomics.store(func_sig_view_u32, 1, fd);
+ // Atomics.store(func_sig_view_u32, 2, to);
+
+ // if (!this.call_fd_func(fd)) {
+ // this.release_fd(fd);
+ // return wasi.ERRNO_BADF;
+ // }
+
+ // const error = this.get_error(fd);
+
+ // this.release_double_fd(fd, to);
+
+ // return error;
+ // }
+
+ fd_seek(
+ fd: number,
+ offset: bigint,
+ whence: number,
+ ): [bigint | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 24);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u64, 1, offset);
+ Atomics.store(func_sig_view_u8, 16, whence);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const new_offset = Atomics.load(func_sig_view_u64, 0);
+
+ this.release_fd(fd);
+
+ return [new_offset, error];
+ }
+
+ fd_sync(fd: number): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 25);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ fd_tell(fd: number): [bigint | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 26);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ if (!this.call_fd_func(fd)) {
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const offset = Atomics.load(func_sig_view_u64, 0);
+
+ this.release_fd(fd);
+
+ return [offset, error];
+ }
+
+ fd_write(fd: number, write_data: Uint8Array): [number | undefined, number] {
+ this.lock_fd(fd);
+
+ // console.log("fd_write: ref: write_data", new TextDecoder().decode(write_data));
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 27);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ write_data,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ // console.log("fd_write: ref: error", "wasi.ERRNO_BADF");
+
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ // console.log("fd_write: ref: error", this.get_error(fd));
+
+ // console.log("fd_write: ref: error", error);
+
+ if (error === wasi.ERRNO_BADF) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const nwritten = Atomics.load(func_sig_view_u32, 0);
+
+ this.release_fd(fd);
+
+ return [nwritten, error];
+ }
+
+ path_create_directory(fd: number, path: Uint8Array): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 28);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ path_filestat_get(
+ fd: number,
+ flags: number,
+ path: Uint8Array,
+ ): [wasi.Filestat | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u8 = new Uint8Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 29);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u32, 2, flags);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 3,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error !== wasi.ERRNO_SUCCESS) {
+ this.release_fd(fd);
+ return [undefined, error];
+ }
+
+ const fs_dev = Atomics.load(func_sig_view_u64, 0);
+ const fs_ino = Atomics.load(func_sig_view_u64, 1);
+ const fs_filetype = Atomics.load(func_sig_view_u8, 16);
+ const fs_nlink = Atomics.load(func_sig_view_u64, 3);
+ const fs_size = Atomics.load(func_sig_view_u64, 4);
+ const fs_atim = Atomics.load(func_sig_view_u64, 5);
+ const fs_mtim = Atomics.load(func_sig_view_u64, 6);
+ const fs_ctim = Atomics.load(func_sig_view_u64, 7);
+
+ this.release_fd(fd);
+
+ const file_stat = new wasi.Filestat(fs_filetype, fs_size);
+ file_stat.dev = fs_dev;
+ file_stat.ino = fs_ino;
+ file_stat.nlink = fs_nlink;
+ file_stat.atim = fs_atim;
+ file_stat.mtim = fs_mtim;
+ file_stat.ctim = fs_ctim;
+
+ return [file_stat, error];
+ }
+
+ path_filestat_set_times(
+ fd: number,
+ flags: number,
+ path: Uint8Array,
+ st_atim: bigint,
+ st_mtim: bigint,
+ fst_flags: number,
+ ): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 30);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u32, 2, flags);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 3,
+ );
+ Atomics.store(func_sig_view_u64, 3, st_atim);
+ Atomics.store(func_sig_view_u64, 4, st_mtim);
+ Atomics.store(func_sig_view_u16, 12, fst_flags);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ path_link(
+ old_fd: number,
+ old_flags: number,
+ old_path: Uint8Array,
+ new_fd: number,
+ new_path: Uint8Array,
+ ): number {
+ this.lock_double_fd(old_fd, new_fd);
+
+ const bytes_offset = old_fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 31);
+ Atomics.store(func_sig_view_u32, 1, old_fd);
+ Atomics.store(func_sig_view_u32, 2, old_flags);
+ const [ptr1, len1] = this.allocator.block_write(
+ old_path,
+ this.fd_func_sig,
+ old_fd * fd_func_sig_u32_size + 3,
+ );
+ Atomics.store(func_sig_view_u32, 5, new_fd);
+ const [ptr2, len2] = this.allocator.block_write(
+ new_path,
+ this.fd_func_sig,
+ old_fd * fd_func_sig_u32_size + 6,
+ );
+
+ if (!this.call_fd_func(old_fd)) {
+ this.allocator.free(ptr1, len1);
+ this.allocator.free(ptr2, len2);
+ this.release_double_fd(old_fd, new_fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(old_fd);
+
+ this.release_double_fd(old_fd, new_fd);
+
+ return error;
+ }
+
+ path_open(
+ fd: number,
+ dirflags: number,
+ path: Uint8Array,
+ oflags: number,
+ fs_rights_base: bigint,
+ fs_rights_inheriting: bigint,
+ fs_flags: number,
+ ): [number | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u16 = new Uint16Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+ const func_sig_view_u64 = new BigUint64Array(
+ this.fd_func_sig,
+ bytes_offset,
+ );
+
+ Atomics.store(func_sig_view_u32, 0, 32);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ Atomics.store(func_sig_view_u32, 2, dirflags);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 3,
+ );
+ Atomics.store(func_sig_view_u32, 5, oflags);
+ Atomics.store(func_sig_view_u64, 3, fs_rights_base);
+ Atomics.store(func_sig_view_u64, 4, fs_rights_inheriting);
+ Atomics.store(func_sig_view_u16, 20, fs_flags);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error === wasi.ERRNO_SUCCESS) {
+ const new_fd = Atomics.load(func_sig_view_u32, 0);
+ this.release_fd(fd);
+ return [new_fd, error];
+ }
+
+ this.release_fd(fd);
+
+ return [undefined, error];
+ }
+
+ path_readlink(
+ fd: number,
+ path: Uint8Array,
+ buf_len: number,
+ ): [Uint8Array | undefined, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 33);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+ Atomics.store(func_sig_view_u32, 4, buf_len);
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ const nread = Atomics.load(func_sig_view_u32, 0);
+ const ret_path_ptr = Atomics.load(func_sig_view_u32, 1);
+ const ret_path_len = Atomics.load(func_sig_view_u32, 2);
+
+ this.release_fd(fd);
+ if (error !== wasi.ERRNO_SUCCESS && error !== wasi.ERRNO_NAMETOOLONG) {
+ this.allocator.free(ret_path_ptr, ret_path_len);
+ return [undefined, error];
+ }
+
+ const ret_path = new Uint8Array(
+ this.allocator.get_memory(ret_path_ptr, ret_path_len),
+ );
+ const ret_path_slice = ret_path.slice(0, nread);
+
+ return [ret_path_slice, error];
+ }
+
+ path_remove_directory(fd: number, path: Uint8Array): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 34);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ path_rename(
+ old_fd: number,
+ old_path: Uint8Array,
+ new_fd: number,
+ new_path: Uint8Array,
+ ): number {
+ this.lock_double_fd(old_fd, new_fd);
+
+ const bytes_offset = old_fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 35);
+ Atomics.store(func_sig_view_u32, 1, old_fd);
+ const [ptr1, len1] = this.allocator.block_write(
+ old_path,
+ this.fd_func_sig,
+ old_fd * fd_func_sig_u32_size + 2,
+ );
+ Atomics.store(func_sig_view_u32, 4, new_fd);
+ const [ptr2, len2] = this.allocator.block_write(
+ new_path,
+ this.fd_func_sig,
+ old_fd * fd_func_sig_u32_size + 5,
+ );
+
+ if (!this.call_fd_func(old_fd)) {
+ this.allocator.free(ptr1, len1);
+ this.allocator.free(ptr2, len2);
+ this.release_double_fd(old_fd, new_fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(old_fd);
+
+ this.release_double_fd(old_fd, new_fd);
+
+ return error;
+ }
+
+ path_symlink(old_path: Uint8Array, fd: number, new_path: Uint8Array): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 36);
+ const [ptr1, len1] = this.allocator.block_write(
+ old_path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 1,
+ );
+ Atomics.store(func_sig_view_u32, 3, fd);
+ const [ptr2, len2] = this.allocator.block_write(
+ new_path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 4,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr1, len1);
+ this.allocator.free(ptr2, len2);
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ path_unlink_file(fd: number, path: Uint8Array): number {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 37);
+ Atomics.store(func_sig_view_u32, 1, fd);
+ const [ptr, len] = this.allocator.block_write(
+ path,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return wasi.ERRNO_BADF;
+ }
+
+ const error = this.get_error(fd);
+
+ this.release_fd(fd);
+
+ return error;
+ }
+
+ open_fd_with_buff(fd: number, buf: Uint8Array): [number, number] {
+ this.lock_fd(fd);
+
+ const bytes_offset = fd * fd_func_sig_bytes;
+ const func_sig_view_u32 = new Uint32Array(this.fd_func_sig, bytes_offset);
+
+ Atomics.store(func_sig_view_u32, 0, 38);
+ Atomics.store(func_sig_view_u32, 1, fd);
+
+ const [ptr, len] = this.allocator.block_write(
+ buf,
+ this.fd_func_sig,
+ fd * fd_func_sig_u32_size + 2,
+ );
+
+ if (!this.call_fd_func(fd)) {
+ this.allocator.free(ptr, len);
+ this.release_fd(fd);
+ return [undefined, wasi.ERRNO_BADF];
+ }
+
+ const error = this.get_error(fd);
+
+ if (error === wasi.ERRNO_SUCCESS) {
+ const new_fd = Atomics.load(func_sig_view_u32, 0);
+ this.release_fd(fd);
+ return [new_fd, error];
+ }
+
+ this.release_fd(fd);
+
+ return [undefined, error];
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/sender.ts b/src/wasi_farm/shared_array_buffer/sender.ts
new file mode 100644
index 0000000..252e36b
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/sender.ts
@@ -0,0 +1,221 @@
+export type ToRefSenderUseArrayBufferObject = {
+ data_size: number;
+ share_arrays_memory?: SharedArrayBuffer;
+};
+
+// To ref sender abstract class
+export abstract class ToRefSenderUseArrayBuffer {
+ // The structure is similar to an allocator, but the mechanism is different
+
+ // Example of fd management
+ // This needs to be handled
+ // 1. Start of path_open
+ // 2. Removed by fd_close
+ // 2.1 Sent by ToRefSender
+ // 3. Reassigned by path_open
+ // < Closed by ToRefSender
+ // 3.1 The person who opened it can use it
+ // < Closed by ToRefSender — this alone will cause a bug
+ // Structurally, this shouldn't happen in the farm
+
+ // In the end, when receiving from this function, it should be done on the first call of each function
+
+ // The first 4 bytes are for lock value: i32
+ // The next 4 bytes are the current number of data: m: i32
+ // The next 4 bytes are the length of the area used by share_arrays_memory: n: i32
+ // Data header
+ // 4 bytes: remaining target count
+ // 4 bytes: target count (n)
+ // n * 4 bytes: target allocation numbers
+ // Data
+ // data_size bytes: data
+ private share_arrays_memory: SharedArrayBuffer;
+
+ // The size of the data
+ private data_size: number;
+
+ constructor(
+ // data is Uint32Array
+ // and data_size is data.length
+ data_size: number,
+ max_share_arrays_memory: number = 100 * 1024,
+ share_arrays_memory?: SharedArrayBuffer,
+ ) {
+ this.data_size = data_size;
+ if (share_arrays_memory) {
+ this.share_arrays_memory = share_arrays_memory;
+ } else {
+ this.share_arrays_memory = new SharedArrayBuffer(max_share_arrays_memory);
+ }
+ const view = new Int32Array(this.share_arrays_memory);
+ Atomics.store(view, 0, 0);
+ Atomics.store(view, 1, 0);
+ Atomics.store(view, 2, 12);
+ }
+
+ protected static init_self_inner(sl: ToRefSenderUseArrayBufferObject): {
+ data_size: number;
+ max_share_arrays_memory: number;
+ share_arrays_memory: SharedArrayBuffer;
+ } {
+ return {
+ data_size: sl.data_size,
+ max_share_arrays_memory: sl.share_arrays_memory.byteLength,
+ share_arrays_memory: sl.share_arrays_memory,
+ };
+ }
+
+ private async async_lock(): Promise {
+ const view = new Int32Array(this.share_arrays_memory);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ let lock: "not-equal" | "timed-out" | "ok";
+ const { value } = Atomics.waitAsync(view, 0, 1);
+ if (value instanceof Promise) {
+ lock = await value;
+ } else {
+ lock = value;
+ }
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ private block_lock(): void {
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const view = new Int32Array(this.share_arrays_memory);
+ const lock = Atomics.wait(view, 0, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ private release_lock(): void {
+ const view = new Int32Array(this.share_arrays_memory);
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+ }
+
+ protected async async_send(
+ targets: Array,
+ data: Uint32Array,
+ ): Promise {
+ await this.async_lock();
+
+ const view = new Int32Array(this.share_arrays_memory);
+ const used_len = Atomics.load(view, 2);
+ const data_len = data.byteLength;
+ if (data_len !== this.data_size) {
+ throw new Error(`invalid data size: ${data_len} !== ${this.data_size}`);
+ }
+ const new_used_len = used_len + data_len + 8 + targets.length * 4;
+ if (new_used_len > this.share_arrays_memory.byteLength) {
+ throw new Error("over memory");
+ }
+
+ Atomics.store(view, 2, new_used_len);
+
+ const header = new Int32Array(this.share_arrays_memory, used_len);
+ header[0] = targets.length;
+ header[1] = targets.length;
+ header.set(targets, 2);
+
+ const data_view = new Uint32Array(
+ this.share_arrays_memory,
+ used_len + 8 + targets.length * 4,
+ );
+ data_view.set(data);
+
+ // console.log("async_send send", targets, data);
+
+ Atomics.add(view, 1, 1);
+
+ this.release_lock();
+ }
+
+ protected get_data(id: number): Array | undefined {
+ const view = new Int32Array(this.share_arrays_memory);
+ const data_num_tmp = Atomics.load(view, 1);
+ if (data_num_tmp === 0) {
+ return undefined;
+ }
+
+ this.block_lock();
+
+ const data_num = Atomics.load(view, 1);
+
+ const return_data: Array = [];
+
+ let offset = 12;
+ // console.log("data_num", data_num);
+ for (let i = 0; i < data_num; i++) {
+ // console.log("this.share_arrays_memory", this.share_arrays_memory);
+ const header = new Int32Array(this.share_arrays_memory, offset);
+ const target_num = header[1];
+ const targets = new Int32Array(
+ this.share_arrays_memory,
+ offset + 8,
+ target_num,
+ );
+ const data_len = this.data_size;
+ if (targets.includes(id)) {
+ const data = new Uint32Array(
+ this.share_arrays_memory,
+ offset + 8 + target_num * 4,
+ data_len / 4,
+ );
+
+ // なぜかわからないが、上では正常に動作せず、以下のようにすると動作する
+ // return_data.push(new Uint32Array(data));
+ return_data.push(new Uint32Array([...data]));
+
+ const target_index = targets.indexOf(id);
+ Atomics.store(targets, target_index, -1);
+ const old_left_targets_num = Atomics.sub(header, 0, 1);
+ if (old_left_targets_num === 1) {
+ // rm data
+ Atomics.sub(view, 1, 1);
+ const used_len = Atomics.load(view, 2);
+ const new_used_len = used_len - data_len - 8 - target_num * 4;
+ Atomics.store(view, 2, new_used_len);
+ const next_data_offset = offset + data_len + 8 + target_num * 4;
+ const next_tail = new Int32Array(
+ this.share_arrays_memory,
+ next_data_offset,
+ );
+ const now_tail = new Int32Array(this.share_arrays_memory, offset);
+ now_tail.set(next_tail);
+ // console.log("new_used_len", new_used_len);
+ } else {
+ offset += data_len + 8 + target_num * 4;
+ }
+ } else {
+ offset += data_len + 8 + target_num * 4;
+ }
+ // console.log("offset", offset);
+ }
+
+ if (offset !== Atomics.load(view, 2)) {
+ throw new Error(`invalid offset: ${offset} !== ${Atomics.load(view, 2)}`);
+ }
+
+ this.release_lock();
+
+ // console.log("get_data get: return_data", return_data);
+
+ return return_data;
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/thread_spawn.ts b/src/wasi_farm/shared_array_buffer/thread_spawn.ts
new file mode 100644
index 0000000..fcaa2cd
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/thread_spawn.ts
@@ -0,0 +1,468 @@
+// (export "wasi_thread_start" (func $61879))
+// (func $61879 (param $0 i32) (param $1 i32)
+// (local $2 i32)
+// (local $3 i32)
+// (local $4 i32)
+// (local $5 i32)
+// (local $6 i32)
+// (local $7 i32)
+// (global.set $global$0
+// (i32.load
+// (local.get $1)
+// )
+// )
+
+// (import "wasi" "thread-spawn" (func $fimport$27 (param i32) (result i32)))
+
+import { strace } from "../../strace.js";
+import { WASIFarmAnimal } from "../animals.js";
+import type { WASIFarmRefObject } from "../ref.js";
+import type { WorkerBackgroundRefObject } from "./worker_background/index.js";
+import {
+ WorkerBackgroundRef,
+ worker_background_worker_url,
+} from "./worker_background/index.js";
+import { WorkerBackgroundRefObjectConstructor } from "./worker_background/worker_export.js";
+
+type ThreadSpawnerObject = {
+ share_memory: WebAssembly.Memory;
+ wasi_farm_refs_object: Array;
+ worker_url: string;
+ worker_background_ref_object: WorkerBackgroundRefObject;
+ // inst_default_buffer_kept: WebAssembly.Memory;
+};
+
+export class ThreadSpawner {
+ private share_memory: WebAssembly.Memory;
+ private wasi_farm_refs_object: Array;
+ private worker_url: string;
+ private worker_background_ref: WorkerBackgroundRef;
+ private worker_background_ref_object: WorkerBackgroundRefObject;
+ // inst_default_buffer_kept: WebAssembly.Memory;
+
+ // hold the worker to prevent GC.
+ private worker_background_worker?: Worker;
+ private worker_background_worker_promise?: Promise;
+
+ // https://github.com/rustwasm/wasm-pack/issues/479
+
+ constructor(
+ worker_url: string,
+ wasi_farm_refs_object: Array,
+ share_memory?: WebAssembly.Memory,
+ // 16MB for the time being.
+ // https://users.rust-lang.org/t/what-is-the-size-limit-of-threads-stack-in-rust/11867/3
+ MIN_STACK = 16777216,
+ worker_background_ref_object?: WorkerBackgroundRefObject,
+ thread_spawn_wasm?: WebAssembly.Module,
+ // inst_default_buffer_kept?: WebAssembly.Memory,
+ ) {
+ this.worker_url = worker_url;
+ this.wasi_farm_refs_object = wasi_farm_refs_object;
+
+ const min_initial_size = 1048576 / 65536; // Rust's default stack size is 1MB.
+ const initial_size = MIN_STACK / 65536;
+ if (initial_size < min_initial_size) {
+ throw new Error(
+ `The stack size must be at least ${min_initial_size} bytes.`,
+ );
+ }
+ const max_memory = 1073741824 / 65536; // Rust's default maximum memory size is 1GB.
+
+ // this.inst_default_buffer_kept =
+ // inst_default_buffer_kept ||
+ // new WebAssembly.Memory({
+ // initial: 1,
+ // maximum: max_memory,
+ // shared: true,
+ // });
+
+ this.share_memory =
+ share_memory ||
+ // WebAssembly.Memory's 1 page is 65536 bytes.
+ new WebAssembly.Memory({
+ initial: initial_size,
+ maximum: max_memory,
+ shared: true,
+ });
+
+ if (worker_background_ref_object === undefined) {
+ const worker_background_worker_url__ = worker_background_worker_url();
+ this.worker_background_worker = new Worker(
+ worker_background_worker_url__,
+ { type: "module" },
+ );
+ URL.revokeObjectURL(worker_background_worker_url__);
+ const { promise, resolve } = Promise.withResolvers();
+ this.worker_background_worker_promise = promise;
+ this.worker_background_worker.onmessage = () => {
+ this.worker_background_worker_promise = undefined;
+ resolve();
+ };
+ this.worker_background_ref_object =
+ WorkerBackgroundRefObjectConstructor();
+ this.worker_background_ref = WorkerBackgroundRef.init_self(
+ this.worker_background_ref_object,
+ );
+ this.worker_background_worker.postMessage({
+ override_object: {
+ sl_object: this.get_object(),
+ thread_spawn_wasm,
+ },
+ worker_background_ref_object: this.worker_background_ref_object,
+ });
+ } else {
+ this.worker_background_ref = WorkerBackgroundRef.init_self(
+ worker_background_ref_object,
+ );
+ }
+ }
+
+ // This cannot blocking.
+ async wait_worker_background_worker(): Promise {
+ if (this.worker_background_worker_promise) {
+ const promise = this.worker_background_worker_promise;
+
+ await promise;
+
+ return;
+ }
+ return;
+ }
+
+ check_worker_background_worker(): void {
+ if (this.worker_background_worker_promise) {
+ throw new Error("worker_background_worker is not ready.");
+ }
+ }
+
+ thread_spawn(
+ start_arg: number,
+ args: Array,
+ env: Array,
+ fd_map: Array<[number, number]>,
+ extend_imports: boolean,
+ ): number {
+ const worker = this.worker_background_ref.new_worker(
+ this.worker_url,
+ { type: "module" },
+ {
+ this_is_thread_spawn: true,
+ start_arg,
+ args,
+ env,
+ fd_map,
+ extend_imports,
+ },
+ );
+
+ const thread_id = worker.get_id();
+
+ return thread_id;
+ }
+
+ async async_start_on_thread(
+ args: Array,
+ env: Array,
+ extend_imports: boolean,
+ ): Promise {
+ if (!self.Worker.toString().includes("[native code]")) {
+ if (self.Worker.toString().includes("function")) {
+ console.warn("SubWorker(new Worker on Worker) is polyfilled maybe.");
+ } else {
+ throw new Error("SubWorker(new Worker on Worker) is not supported.");
+ }
+ }
+
+ await this.worker_background_ref.async_start_on_thread(
+ this.worker_url,
+ { type: "module" },
+ {
+ this_is_thread_spawn: true,
+ this_is_start: true,
+ args,
+ env,
+ extend_imports,
+ },
+ );
+ }
+
+ block_start_on_thread(
+ args: Array,
+ env: Array,
+ extend_imports: boolean,
+ ): void {
+ if (!self.Worker.toString().includes("[native code]")) {
+ if (self.Worker.toString().includes("function")) {
+ console.warn("SubWorker(new Worker on Worker) is polyfilled maybe.");
+ } else {
+ throw new Error("SubWorker(new Worker on Worker) is not supported.");
+ }
+ }
+
+ this.worker_background_ref.block_start_on_thread(
+ this.worker_url,
+ { type: "module" },
+ {
+ this_is_thread_spawn: true,
+ this_is_start: true,
+ args,
+ env,
+ extend_imports,
+ },
+ );
+ }
+
+ static init_self(sl: ThreadSpawnerObject): ThreadSpawner {
+ const thread_spawner = new ThreadSpawner(
+ sl.worker_url,
+ sl.wasi_farm_refs_object,
+ sl.share_memory,
+ undefined,
+ sl.worker_background_ref_object,
+ // undefined,
+ // sl.inst_default_buffer_kept,
+ );
+ return thread_spawner;
+ }
+
+ static init_self_with_worker_background_ref(
+ sl: ThreadSpawnerObject,
+ worker_background_ref_object: WorkerBackgroundRefObject,
+ ): ThreadSpawner {
+ const thread_spawner = new ThreadSpawner(
+ sl.worker_url,
+ sl.wasi_farm_refs_object,
+ sl.share_memory,
+ undefined,
+ worker_background_ref_object,
+ // undefined,
+ // sl.inst_default_buffer_kept,
+ );
+ return thread_spawner;
+ }
+
+ get_share_memory(): WebAssembly.Memory {
+ return this.share_memory;
+ }
+
+ get_object(): ThreadSpawnerObject {
+ return {
+ share_memory: this.share_memory,
+ wasi_farm_refs_object: this.wasi_farm_refs_object,
+ worker_url: this.worker_url,
+ worker_background_ref_object: this.worker_background_ref_object,
+ // inst_default_buffer_kept: this.inst_default_buffer_kept,
+ };
+ }
+
+ done_notify(code: number): void {
+ this.worker_background_ref.done_notify(code);
+ }
+
+ async async_wait_done_or_error(): Promise {
+ if (this.worker_background_worker === undefined) {
+ throw new Error("worker_background_worker is undefined.");
+ }
+
+ return await this.worker_background_ref.async_wait_done_or_error();
+ }
+
+ block_wait_done_or_error(): number {
+ if (this.worker_background_worker === undefined) {
+ throw new Error("worker_background_worker is undefined.");
+ }
+
+ return this.worker_background_ref.block_wait_done_or_error();
+ }
+}
+
+// send fd_map is not implemented yet.
+// issue: the fd passed to the child process is different from the parent process.
+export const thread_spawn_on_worker = async (msg: {
+ this_is_thread_spawn: boolean;
+ worker_id?: number;
+ start_arg: number;
+ worker_background_ref: WorkerBackgroundRefObject;
+ sl_object: ThreadSpawnerObject;
+ thread_spawn_wasm: WebAssembly.Module;
+ args: Array;
+ env: Array;
+ fd_map: [number, number][];
+ extend_imports: boolean;
+ this_is_start?: boolean;
+}): Promise => {
+ console.log("thread_spawn_on_worker", msg);
+
+ if (msg.this_is_thread_spawn) {
+ if (msg.this_is_start) {
+ const thread_spawner = ThreadSpawner.init_self_with_worker_background_ref(
+ msg.sl_object,
+ msg.worker_background_ref,
+ );
+
+ const wasi = new WASIFarmAnimal(
+ msg.sl_object.wasi_farm_refs_object,
+ msg.args,
+ msg.env,
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: msg.sl_object.worker_url,
+ extend_imports: msg.extend_imports,
+ },
+ undefined,
+ thread_spawner,
+ );
+
+ const imports: {
+ env: {
+ memory: WebAssembly.Memory;
+ };
+ wasi: {
+ "thread-spawn": (start_arg: number) => number;
+ };
+ wasi_snapshot_preview1: {
+ [key: string]: (...args: Array) => unknown;
+ };
+ extend_imports?: {
+ [key: string]: (...args: Array) => unknown;
+ };
+ } = {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ wasi_snapshot_preview1: wasi.wasiImport,
+ };
+
+ if (msg.extend_imports) {
+ imports.extend_imports = wasi.extendImport;
+ }
+
+ const inst = await WebAssembly.instantiate(
+ msg.thread_spawn_wasm,
+ imports,
+ );
+
+ wasi.start(
+ inst as unknown as {
+ exports: {
+ memory: WebAssembly.Memory;
+ _start: () => unknown;
+ };
+ },
+ );
+
+ globalThis.postMessage({
+ msg: "done",
+ });
+
+ return wasi;
+ }
+
+ const {
+ worker_id: thread_id,
+ start_arg,
+ args,
+ env,
+ sl_object,
+ thread_spawn_wasm,
+ } = msg;
+
+ console.log(`thread_spawn worker ${thread_id} start`);
+
+ const thread_spawner = ThreadSpawner.init_self_with_worker_background_ref(
+ sl_object,
+ msg.worker_background_ref,
+ );
+
+ const override_fd_map: Array = new Array(
+ sl_object.wasi_farm_refs_object.length,
+ );
+
+ // Possibly null (undefined)
+ for (const fd_and_wasi_ref_n of msg.fd_map) {
+ // biome-ignore lint/suspicious/noDoubleEquals:
+ if (fd_and_wasi_ref_n == undefined) {
+ continue;
+ }
+ const [fd, wasi_ref_n] = fd_and_wasi_ref_n;
+ if (override_fd_map[wasi_ref_n] === undefined) {
+ override_fd_map[wasi_ref_n] = [];
+ }
+ override_fd_map[wasi_ref_n].push(fd);
+ }
+
+ const wasi = new WASIFarmAnimal(
+ sl_object.wasi_farm_refs_object,
+ args,
+ env,
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: sl_object.worker_url,
+ extend_imports: msg.extend_imports,
+ hand_override_fd_map: msg.fd_map,
+ },
+ override_fd_map,
+ thread_spawner,
+ );
+
+ const imports: {
+ env: {
+ memory: WebAssembly.Memory;
+ };
+ wasi: {
+ "thread-spawn": (start_arg: number) => number;
+ };
+ wasi_snapshot_preview1: {
+ [key: string]: (...args: Array) => unknown;
+ };
+ extend_imports?: {
+ [key: string]: (...args: Array) => unknown;
+ };
+ } = {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ // wasi_snapshot_preview1: wasi.wasiImport,
+ wasi_snapshot_preview1: strace(wasi.wasiImport, []),
+ };
+
+ if (msg.extend_imports) {
+ imports.extend_imports = wasi.extendImport;
+ }
+
+ const inst = await WebAssembly.instantiate(thread_spawn_wasm, imports);
+
+ globalThis.postMessage({
+ msg: "ready",
+ });
+
+ try {
+ wasi.wasi_thread_start(
+ inst as unknown as {
+ exports: {
+ memory: WebAssembly.Memory;
+ wasi_thread_start: (thread_id: number, start_arg: number) => void;
+ };
+ },
+ thread_id,
+ start_arg,
+ );
+ } catch (e) {
+ globalThis.postMessage({
+ msg: "error",
+ error: e,
+ });
+
+ return wasi;
+ }
+
+ globalThis.postMessage({
+ msg: "done",
+ });
+
+ return wasi;
+ }
+};
diff --git a/src/wasi_farm/shared_array_buffer/util.ts b/src/wasi_farm/shared_array_buffer/util.ts
new file mode 100644
index 0000000..4ed230f
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/util.ts
@@ -0,0 +1,68 @@
+export const get_func_name_from_number = (num: number): string => {
+ switch (num) {
+ case 7:
+ return "fd_advise";
+ case 8:
+ return "fd_allocate";
+ case 9:
+ return "fd_close";
+ case 10:
+ return "fd_datasync";
+ case 11:
+ return "fd_fdstat_get";
+ case 12:
+ return "fd_fdstat_set_flags";
+ case 13:
+ return "fd_fdstat_set_rights";
+ case 14:
+ return "fd_filestat_get";
+ case 15:
+ return "fd_filestat_set_size";
+ case 16:
+ return "fd_filestat_set_times";
+ case 17:
+ return "fd_pread";
+ case 18:
+ return "fd_prestat_get";
+ case 19:
+ return "fd_prestat_dir_name";
+ case 20:
+ return "fd_pwrite";
+ case 21:
+ return "fd_read";
+ case 22:
+ return "fd_readdir";
+ case 23:
+ return "fd_renumber";
+ case 24:
+ return "fd_seek";
+ case 25:
+ return "fd_sync";
+ case 26:
+ return "fd_tell";
+ case 27:
+ return "fd_write";
+ case 28:
+ return "path_create_directory";
+ case 29:
+ return "path_filestat_get";
+ case 30:
+ return "path_filestat_set_times";
+ case 31:
+ return "path_link";
+ case 32:
+ return "path_open";
+ case 33:
+ return "path_readlink";
+ case 34:
+ return "path_remove_directory";
+ case 35:
+ return "path_rename";
+ case 36:
+ return "path_symlink";
+ case 37:
+ return "path_unlink_file";
+ default:
+ return "unknown";
+ }
+};
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/index.ts b/src/wasi_farm/shared_array_buffer/worker_background/index.ts
new file mode 100644
index 0000000..eb3e67c
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/index.ts
@@ -0,0 +1,10 @@
+import type { WorkerBackgroundRefObject } from "./worker_export.js";
+import { WorkerBackgroundRef, WorkerRef } from "./worker_background_ref.js";
+import { url as worker_background_worker_url } from "./worker_blob.js";
+
+export {
+ WorkerBackgroundRef,
+ WorkerRef,
+ type WorkerBackgroundRefObject,
+ worker_background_worker_url,
+};
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/minify.js b/src/wasi_farm/shared_array_buffer/worker_background/minify.js
new file mode 100644
index 0000000..eecb571
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/minify.js
@@ -0,0 +1,46 @@
+import swc from "@swc/core";
+
+import { readFileSync, writeFileSync } from "node:fs";
+
+const old_code = readFileSync(
+ "./dist/workers/worker_background_worker.js",
+ "utf8",
+);
+
+const { code } = await swc.minify(old_code, {
+ compress: {
+ reduce_funcs: true,
+ arguments: true,
+ booleans_as_integers: true,
+ hoist_funs: false,
+ keep_classnames: false,
+ unsafe: true,
+ },
+ mangle: true,
+});
+
+writeFileSync(
+ "./dist/workers/worker_background_worker_minify.js",
+ code,
+ "utf8",
+);
+
+// \n -> \\n
+
+const wrapper_code = `export const url = () => {
+ const code =
+ '${code.replace(/\\/g, "\\\\")}';
+
+ const blob = new Blob([code], { type: "application/javascript" });
+
+ const url = URL.createObjectURL(blob);
+
+ return url;
+};
+`;
+
+writeFileSync(
+ "./src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts",
+ wrapper_code,
+ "utf8",
+);
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs b/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs
new file mode 100644
index 0000000..2b498de
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/spack.config.cjs
@@ -0,0 +1,15 @@
+// https://swc.rs/docs/configuration/bundling
+
+const { config } = require("@swc/core/spack");
+
+console.log(__dirname);
+
+module.exports = config({
+ entry: {
+ web: `${__dirname}/worker.ts`,
+ },
+ output: {
+ path: `${__dirname}/../../../../dist/workers/`,
+ name: "worker_background_worker.js",
+ },
+});
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker.ts
new file mode 100644
index 0000000..9db336e
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/worker.ts
@@ -0,0 +1,290 @@
+// If you create a worker and try to increase the number of threads,
+// you will have to use Atomics.wait because they need to be synchronized.
+// However, this is essentially impossible because Atomics.wait blocks the threads.
+// Therefore, a dedicated worker that creates a subworker (worker in worker) is prepared.
+// The request is made using BroadcastChannel.
+
+import * as Serializer from "../../../serialize_error.js";
+import { AllocatorUseArrayBuffer } from "../allocator.js";
+import type { WorkerBackgroundRefObject } from "./worker_export.js";
+
+// Note that postMessage, etc.
+// cannot be used in a blocking environment such as during wasm execution.
+// (at least as far as I have tried)
+
+class WorkerBackground {
+ private override_object: T;
+ private allocator: AllocatorUseArrayBuffer;
+ private lock: SharedArrayBuffer;
+ private signature_input: SharedArrayBuffer;
+
+ private workers: Array = [undefined];
+
+ private start_worker?: Worker;
+
+ private listen_holder: Promise;
+
+ constructor(
+ override_object: T,
+ lock?: SharedArrayBuffer,
+ allocator?: AllocatorUseArrayBuffer,
+ signature_input?: SharedArrayBuffer,
+ ) {
+ this.override_object = override_object;
+ this.lock = lock ?? new SharedArrayBuffer(20);
+ this.allocator =
+ allocator ??
+ new AllocatorUseArrayBuffer(new SharedArrayBuffer(10 * 1024));
+ this.signature_input = signature_input ?? new SharedArrayBuffer(24);
+ this.listen_holder = this.listen();
+ }
+
+ static init_self(
+ override_object: T,
+ worker_background_ref_object: WorkerBackgroundRefObject,
+ ): WorkerBackground {
+ return new WorkerBackground(
+ override_object,
+ worker_background_ref_object.lock,
+ AllocatorUseArrayBuffer.init_self(worker_background_ref_object.allocator),
+ worker_background_ref_object.signature_input,
+ );
+ }
+
+ assign_worker_id(): number {
+ for (let i = 1; i < this.workers.length; i++) {
+ if (this.workers[i] === undefined) {
+ return i;
+ }
+ }
+ this.workers.push(undefined);
+ return this.workers.length - 1;
+ }
+
+ ref(): WorkerBackgroundRefObject {
+ return {
+ allocator: this.allocator.get_object(),
+ lock: this.lock,
+ signature_input: this.signature_input,
+ };
+ }
+
+ async listen(): Promise {
+ const lock_view = new Int32Array(this.lock);
+ Atomics.store(lock_view, 0, 0);
+ Atomics.store(lock_view, 1, 0);
+
+ const signature_input_view = new Int32Array(this.signature_input);
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ try {
+ let lock: "not-equal" | "timed-out" | "ok";
+
+ const { value } = Atomics.waitAsync(lock_view, 1, 0);
+ if (value instanceof Promise) {
+ lock = await value;
+ } else {
+ lock = value;
+ }
+ if (lock === "timed-out") {
+ throw new Error("timed-out");
+ }
+
+ const locked_value = Atomics.load(lock_view, 1);
+ if (locked_value !== 1) {
+ throw new Error("locked");
+ }
+
+ const signature_input = Atomics.load(signature_input_view, 0);
+ switch (signature_input) {
+ // create new worker
+ case 1: {
+ const url_ptr = Atomics.load(signature_input_view, 1);
+ const url_len = Atomics.load(signature_input_view, 2);
+ const url_buff = this.allocator.get_memory(url_ptr, url_len);
+ this.allocator.free(url_ptr, url_len);
+ const url = new TextDecoder().decode(url_buff);
+ const is_module = Atomics.load(signature_input_view, 3) === 1;
+ const worker = new Worker(url, {
+ type: is_module ? "module" : "classic",
+ });
+ const json_ptr = Atomics.load(signature_input_view, 4);
+ const json_len = Atomics.load(signature_input_view, 5);
+ const json_buff = this.allocator.get_memory(json_ptr, json_len);
+ this.allocator.free(json_ptr, json_len);
+ const json = new TextDecoder().decode(json_buff);
+ const obj = JSON.parse(json);
+
+ const worker_id = this.assign_worker_id();
+
+ console.log(`new worker ${worker_id}`);
+
+ this.workers[worker_id] = worker;
+
+ const { promise, resolve } = Promise.withResolvers();
+
+ worker.onmessage = async (e) => {
+ const { msg } = e.data;
+
+ if (msg === "ready") {
+ resolve();
+ }
+
+ if (msg === "done") {
+ this.workers[worker_id].terminate();
+ this.workers[worker_id] = undefined;
+
+ console.log(`worker ${worker_id} done so terminate`);
+ }
+
+ if (msg === "error") {
+ this.workers[worker_id].terminate();
+ this.workers[worker_id] = undefined;
+
+ let n = 0;
+ for (const worker of this.workers) {
+ if (worker !== undefined) {
+ worker.terminate();
+ console.warn(
+ `wasi throw error but child process exists, terminate ${n}`,
+ );
+ }
+ n++;
+ }
+ if (this.start_worker !== undefined) {
+ this.start_worker.terminate();
+ console.warn(
+ "wasi throw error but wasi exists, terminate wasi",
+ );
+ }
+
+ this.workers = [undefined];
+ this.start_worker = undefined;
+
+ const error = e.data.error;
+
+ const notify_view = new Int32Array(this.lock, 8);
+
+ const serialized_error = Serializer.serialize(error);
+
+ const [ptr, len] = await this.allocator.async_write(
+ new TextEncoder().encode(JSON.stringify(serialized_error)),
+ this.lock,
+ 3,
+ );
+
+ // notify error = code 1
+ const old = Atomics.compareExchange(notify_view, 0, 0, 1);
+
+ if (old !== 0) {
+ console.error("what happened?");
+
+ this.allocator.free(ptr, len);
+
+ return;
+ }
+
+ const num = Atomics.notify(notify_view, 0);
+
+ if (num === 0) {
+ console.error(error);
+
+ this.allocator.free(ptr, len);
+
+ Atomics.store(notify_view, 0, 0);
+ }
+ }
+ };
+
+ worker.postMessage({
+ ...this.override_object,
+ ...obj,
+ worker_id,
+ worker_background_ref: this.ref(),
+ });
+
+ await promise;
+
+ Atomics.store(signature_input_view, 0, worker_id);
+
+ break;
+ }
+ // create start
+ case 2: {
+ const url_ptr = Atomics.load(signature_input_view, 1);
+ const url_len = Atomics.load(signature_input_view, 2);
+ const url_buff = this.allocator.get_memory(url_ptr, url_len);
+ this.allocator.free(url_ptr, url_len);
+ const url = new TextDecoder().decode(url_buff);
+ const is_module = Atomics.load(signature_input_view, 3) === 1;
+ this.start_worker = new Worker(url, {
+ type: is_module ? "module" : "classic",
+ });
+ const json_ptr = Atomics.load(signature_input_view, 4);
+ const json_len = Atomics.load(signature_input_view, 5);
+ const json_buff = this.allocator.get_memory(json_ptr, json_len);
+ this.allocator.free(json_ptr, json_len);
+ const json = new TextDecoder().decode(json_buff);
+ const obj = JSON.parse(json);
+
+ this.start_worker.onmessage = async (e) => {
+ const { msg } = e.data;
+
+ if (msg === "done") {
+ let n = 0;
+ for (const worker of this.workers) {
+ if (worker !== undefined) {
+ worker.terminate();
+ console.warn(`wasi done but worker exists, terminate ${n}`);
+ }
+ n++;
+ }
+
+ this.start_worker.terminate();
+ this.start_worker = undefined;
+
+ console.log("start worker done so terminate");
+ }
+ };
+
+ this.start_worker.postMessage({
+ ...this.override_object,
+ ...obj,
+ worker_background_ref: this.ref(),
+ });
+
+ break;
+ }
+ }
+
+ const old_call_lock = Atomics.exchange(lock_view, 1, 0);
+ if (old_call_lock !== 1) {
+ throw new Error("Lock is already set");
+ }
+ const num = Atomics.notify(lock_view, 1, 1);
+ if (num !== 1) {
+ if (num === 0) {
+ console.warn("notify failed, waiter is late");
+ continue;
+ }
+ throw new Error(`notify failed: ${num}`);
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
+}
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+let worker_background: WorkerBackground;
+
+globalThis.onmessage = (e: MessageEvent) => {
+ const { override_object, worker_background_ref_object } = e.data;
+ worker_background = WorkerBackground.init_self(
+ override_object,
+ worker_background_ref_object,
+ );
+ postMessage("ready");
+};
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts
new file mode 100644
index 0000000..4d570df
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/worker_background_ref.ts
@@ -0,0 +1,311 @@
+import * as Serializer from "../../../serialize_error.js";
+import { AllocatorUseArrayBuffer } from "../allocator.js";
+import type { WorkerBackgroundRefObject } from "./worker_export.js";
+
+export class WorkerBackgroundRef {
+ private allocator: AllocatorUseArrayBuffer;
+ private lock: SharedArrayBuffer;
+ private signature_input: SharedArrayBuffer;
+
+ constructor(
+ allocator: AllocatorUseArrayBuffer,
+ lock: SharedArrayBuffer,
+ signature_input: SharedArrayBuffer,
+ ) {
+ this.allocator = allocator;
+ this.lock = lock;
+ this.signature_input = signature_input;
+ }
+
+ private block_lock_base_func(): void {
+ const view = new Int32Array(this.lock);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ const lock = Atomics.wait(view, 0, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ private async async_lock_base_func(): Promise {
+ const view = new Int32Array(this.lock);
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ let value: "timed-out" | "not-equal" | "ok";
+ const { value: _value } = Atomics.waitAsync(view, 0, 1);
+ if (_value instanceof Promise) {
+ value = await _value;
+ } else {
+ value = _value;
+ }
+ if (value === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ const old = Atomics.compareExchange(view, 0, 0, 1);
+ if (old !== 0) {
+ continue;
+ }
+ break;
+ }
+ }
+
+ private call_base_func(): void {
+ const view = new Int32Array(this.lock);
+ const old = Atomics.exchange(view, 1, 1);
+ if (old !== 0) {
+ console.error("what happened?");
+ }
+ Atomics.notify(view, 1, 1);
+ }
+
+ // wait base_func
+ private block_wait_base_func(): void {
+ const view = new Int32Array(this.lock);
+ const lock = Atomics.wait(view, 1, 1);
+ if (lock === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ }
+
+ private async async_wait_base_func(): Promise {
+ const view = new Int32Array(this.lock);
+ let value: "timed-out" | "not-equal" | "ok";
+ const { value: _value } = Atomics.waitAsync(view, 1, 1);
+ if (_value instanceof Promise) {
+ value = await _value;
+ } else {
+ value = _value;
+ }
+ if (value === "timed-out") {
+ throw new Error("timed-out lock");
+ }
+ }
+
+ // release base_func
+ private release_base_func(): void {
+ const view = new Int32Array(this.lock);
+ Atomics.store(view, 0, 0);
+ Atomics.notify(view, 0, 1);
+ }
+
+ new_worker(
+ url: string,
+ options?: WorkerOptions,
+ post_obj?: unknown,
+ ): WorkerRef {
+ this.block_lock_base_func();
+ const view = new Int32Array(this.signature_input);
+ Atomics.store(view, 0, 1);
+ const url_buffer = new TextEncoder().encode(url);
+ this.allocator.block_write(url_buffer, this.signature_input, 1);
+ Atomics.store(view, 3, options.type === "module" ? 1 : 0);
+ const obj_json = JSON.stringify(post_obj);
+ const obj_buffer = new TextEncoder().encode(obj_json);
+ this.allocator.block_write(obj_buffer, this.signature_input, 4);
+ this.call_base_func();
+ this.block_wait_base_func();
+
+ const id = Atomics.load(view, 0);
+
+ this.release_base_func();
+
+ return new WorkerRef(id);
+ }
+
+ async async_start_on_thread(
+ url: string,
+ options: WorkerOptions | undefined,
+ post_obj: unknown,
+ ) {
+ await this.async_lock_base_func();
+ const view = new Int32Array(this.signature_input);
+ Atomics.store(view, 0, 2);
+ const url_buffer = new TextEncoder().encode(url);
+ await this.allocator.async_write(url_buffer, this.signature_input, 1);
+ Atomics.store(view, 3, options?.type === "module" ? 1 : 0);
+ const obj_json = JSON.stringify(post_obj);
+ const obj_buffer = new TextEncoder().encode(obj_json);
+ await this.allocator.async_write(obj_buffer, this.signature_input, 4);
+ this.call_base_func();
+ await this.async_wait_base_func();
+
+ this.release_base_func();
+ }
+
+ block_start_on_thread(
+ url: string,
+ options: WorkerOptions | undefined,
+ post_obj: unknown,
+ ) {
+ this.block_lock_base_func();
+ const view = new Int32Array(this.signature_input);
+ Atomics.store(view, 0, 2);
+ const url_buffer = new TextEncoder().encode(url);
+ this.allocator.block_write(url_buffer, this.signature_input, 1);
+ Atomics.store(view, 3, options?.type === "module" ? 1 : 0);
+ const obj_json = JSON.stringify(post_obj);
+ const obj_buffer = new TextEncoder().encode(obj_json);
+ this.allocator.block_write(obj_buffer, this.signature_input, 4);
+ this.call_base_func();
+ this.block_wait_base_func();
+
+ this.release_base_func();
+ }
+
+ static init_self(sl: WorkerBackgroundRefObject): WorkerBackgroundRef {
+ return new WorkerBackgroundRef(
+ AllocatorUseArrayBuffer.init_self(sl.allocator),
+ sl.lock,
+ sl.signature_input,
+ );
+ }
+
+ done_notify(code: number): void {
+ const notify_view = new Int32Array(this.lock, 8);
+
+ // notify done = code 2
+ const old = Atomics.compareExchange(notify_view, 0, 0, 2);
+
+ if (old !== 0) {
+ console.error("what happened?");
+
+ return;
+ }
+
+ Atomics.store(notify_view, 1, code);
+
+ const num = Atomics.notify(notify_view, 0);
+
+ if (num === 0) {
+ Atomics.store(notify_view, 0, 0);
+ }
+ }
+
+ async async_wait_done_or_error(): Promise {
+ const notify_view = new Int32Array(this.lock, 8);
+
+ Atomics.store(notify_view, 0, 0);
+
+ let value: "timed-out" | "not-equal" | "ok";
+ const { value: _value } = Atomics.waitAsync(notify_view, 0, 0);
+ if (_value instanceof Promise) {
+ value = await _value;
+ } else {
+ value = _value;
+ }
+
+ if (value === "timed-out") {
+ throw new Error("timed-out");
+ }
+
+ if (value === "not-equal") {
+ throw new Error("not-equal");
+ }
+
+ const code = Atomics.load(notify_view, 0);
+
+ if (code === 2) {
+ const old = Atomics.compareExchange(notify_view, 0, 2, 0);
+
+ const code = Atomics.load(notify_view, 1);
+
+ if (old !== 2) {
+ console.error("what happened?");
+ }
+
+ return code;
+ }
+
+ if (code !== 1) {
+ throw new Error("unknown code");
+ }
+
+ // get error
+ const ptr = Atomics.load(notify_view, 1);
+ const size = Atomics.load(notify_view, 2);
+ const error_buffer = this.allocator.get_memory(ptr, size);
+ const error_txt = new TextDecoder().decode(error_buffer);
+ const error_serialized = JSON.parse(
+ error_txt,
+ ) as Serializer.SerializedError;
+ const error = Serializer.deserialize(error_serialized);
+
+ const old = Atomics.compareExchange(notify_view, 0, 1, 0);
+
+ if (old !== 1) {
+ console.error("what happened?");
+ }
+
+ throw error;
+ }
+
+ block_wait_done_or_error(): number {
+ const notify_view = new Int32Array(this.lock, 8);
+
+ Atomics.store(notify_view, 0, 0);
+
+ const value = Atomics.wait(notify_view, 0, 0);
+
+ if (value === "timed-out") {
+ throw new Error("timed-out");
+ }
+
+ if (value === "not-equal") {
+ throw new Error("not-equal");
+ }
+
+ const code = Atomics.load(notify_view, 0);
+
+ if (code === 2) {
+ const old = Atomics.compareExchange(notify_view, 0, 2, 0);
+
+ const code = Atomics.load(notify_view, 1);
+
+ if (old !== 2) {
+ console.error("what happened?");
+ }
+
+ return code;
+ }
+
+ if (code !== 1) {
+ throw new Error("unknown code");
+ }
+
+ // get error
+ const ptr = Atomics.load(notify_view, 1);
+ const size = Atomics.load(notify_view, 2);
+ const error_buffer = this.allocator.get_memory(ptr, size);
+ const error_txt = new TextDecoder().decode(error_buffer);
+ const error_serialized = JSON.parse(
+ error_txt,
+ ) as Serializer.SerializedError;
+ const error = Serializer.deserialize(error_serialized);
+
+ const old = Atomics.compareExchange(notify_view, 0, 1, 0);
+
+ if (old !== 1) {
+ console.error("what happened?");
+ }
+
+ throw error;
+ }
+}
+
+export class WorkerRef {
+ private id: number;
+
+ constructor(id: number) {
+ this.id = id;
+ }
+
+ get_id(): number {
+ return this.id;
+ }
+}
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts
new file mode 100644
index 0000000..8a1adf3
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/worker_blob.ts
@@ -0,0 +1,10 @@
+export const url = () => {
+ const code =
+ 'let worker_background;function _define_property(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}let serialize=e=>({message:e.message,name:e.name,stack:e.stack,cause:e.cause});class AllocatorUseArrayBuffer{static init_self(e){return new AllocatorUseArrayBuffer(e.share_arrays_memory)}async async_write(e,r,t){let o=new Int32Array(this.share_arrays_memory);for(;;){let{value:s}=Atomics.waitAsync(o,0,1);if("timed-out"===(s instanceof Promise?await s:s))throw Error("timed-out lock");if(0!==Atomics.compareExchange(o,0,0,1))continue;let i=this.write_inner(e,r,t);return Atomics.store(o,0,0),Atomics.notify(o,0,1),i}}block_write(e,r,t){for(;;){let o=new Int32Array(this.share_arrays_memory);if("timed-out"===Atomics.wait(o,0,1))throw Error("timed-out lock");if(0!==Atomics.compareExchange(o,0,0,1))continue;let s=this.write_inner(e,r,t);return Atomics.store(o,0,0),Atomics.notify(o,0,1),s}}write_inner(e,r,t){let o,s;let i=new Int32Array(this.share_arrays_memory),a=new Uint8Array(this.share_arrays_memory);o=0===Atomics.add(i,1,1)?Atomics.store(i,2,12):Atomics.load(i,2);let n=this.share_arrays_memory.byteLength,c=e.byteLength,l=o+c;if(n{let{msg:r}=e.data;if("ready"===r&&y(),"done"===r&&(this.workers[w].terminate(),this.workers[w]=void 0,console.log(`worker ${w} done so terminate`)),"error"===r){this.workers[w].terminate(),this.workers[w]=void 0;let r=0;for(let e of this.workers)void 0!==e&&(e.terminate(),console.warn("wasi throw error but child process exists, terminate "+r)),r++;void 0!==this.start_worker&&(this.start_worker.terminate(),console.warn("wasi throw error but wasi exists, terminate wasi")),this.workers=[void 0],this.start_worker=void 0;let t=e.data.error,o=new Int32Array(this.lock,8),s=serialize(t),[i,a]=await this.allocator.async_write(new TextEncoder().encode(JSON.stringify(s)),this.lock,3),n=Atomics.compareExchange(o,0,0,1);if(0!==n){console.error("what happened?"),this.allocator.free(i,a);return}let c=Atomics.notify(o,0);0===c&&(console.error(t),this.allocator.free(i,a),Atomics.store(o,0,0))}},a.postMessage({...this.override_object,...m,worker_id:w,worker_background_ref:this.ref()}),await d,Atomics.store(r,0,w);break}case 2:{let e=Atomics.load(r,1),t=Atomics.load(r,2),o=this.allocator.get_memory(e,t);this.allocator.free(e,t);let s=new TextDecoder().decode(o),i=1===Atomics.load(r,3);this.start_worker=new Worker(s,{type:i?"module":"classic"});let a=Atomics.load(r,4),n=Atomics.load(r,5),c=this.allocator.get_memory(a,n);this.allocator.free(a,n);let l=new TextDecoder().decode(c),h=JSON.parse(l);this.start_worker.onmessage=async e=>{let{msg:r}=e.data;if("done"===r){let e=0;for(let r of this.workers)void 0!==r&&(r.terminate(),console.warn("wasi done but worker exists, terminate "+e)),e++;this.start_worker.terminate(),this.start_worker=void 0,console.log("start worker done so terminate")}},this.start_worker.postMessage({...this.override_object,...h,worker_background_ref:this.ref()})}}let i=Atomics.exchange(e,1,0);if(1!==i)throw Error("Lock is already set");let a=Atomics.notify(e,1,1);if(1!==a){if(0===a){console.warn("notify failed, waiter is late");continue}throw Error("notify failed: "+a)}}catch(e){console.error(e)}}constructor(e,r,t,o){_define_property(this,"override_object",void 0),_define_property(this,"allocator",void 0),_define_property(this,"lock",void 0),_define_property(this,"signature_input",void 0),_define_property(this,"workers",[void 0]),_define_property(this,"start_worker",void 0),_define_property(this,"listen_holder",void 0),this.override_object=e,this.lock=r??new SharedArrayBuffer(20),this.allocator=t??new AllocatorUseArrayBuffer(new SharedArrayBuffer(10240)),this.signature_input=o??new SharedArrayBuffer(24),this.listen_holder=this.listen()}};globalThis.onmessage=e=>{let{override_object:r,worker_background_ref_object:t}=e.data;worker_background=WorkerBackground.init_self(r,t),postMessage("ready")};';
+
+ const blob = new Blob([code], { type: "application/javascript" });
+
+ const url = URL.createObjectURL(blob);
+
+ return url;
+};
diff --git a/src/wasi_farm/shared_array_buffer/worker_background/worker_export.ts b/src/wasi_farm/shared_array_buffer/worker_background/worker_export.ts
new file mode 100644
index 0000000..9f831a8
--- /dev/null
+++ b/src/wasi_farm/shared_array_buffer/worker_background/worker_export.ts
@@ -0,0 +1,18 @@
+import type { AllocatorUseArrayBufferObject } from "../allocator.js";
+
+export type WorkerBackgroundRefObject = {
+ allocator: AllocatorUseArrayBufferObject;
+ lock: SharedArrayBuffer;
+ signature_input: SharedArrayBuffer;
+};
+
+export const WorkerBackgroundRefObjectConstructor =
+ (): WorkerBackgroundRefObject => {
+ return {
+ allocator: {
+ share_arrays_memory: new SharedArrayBuffer(10 * 1024),
+ },
+ lock: new SharedArrayBuffer(20),
+ signature_input: new SharedArrayBuffer(24),
+ };
+ };
diff --git a/test/run-testsuite.sh b/test/run-testsuite.sh
old mode 100755
new mode 100644