diff --git a/.gitignore b/.gitignore
index 149320b..c7168c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
node_modules/
dist/
typings/
+.vscode/
diff --git a/.gitmodules b/.gitmodules
index c9f05a1..0303c62 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 "threads/examples/wasi_multi_threads_rustc/rust_wasm"]
+ path = threads/examples/wasi_multi_threads_rustc/rust_wasm
+ url = https://github.com/oligamiq/rust_wasm
+ sharrow = true
diff --git a/threads/.gitignore b/threads/.gitignore
new file mode 100644
index 0000000..03beadd
--- /dev/null
+++ b/threads/.gitignore
@@ -0,0 +1,4 @@
+/.vscode
+/dist
+/node_modules
+/types
diff --git a/threads/.swcrc b/threads/.swcrc
new file mode 100644
index 0000000..6363ccf
--- /dev/null
+++ b/threads/.swcrc
@@ -0,0 +1,18 @@
+{
+ "$schema": "https://json.schemastore.org/swcrc",
+ "jsc": {
+ "parser": {
+ "syntax": "typescript",
+ "tsx": false,
+ "dynamicImport": false,
+ "decorators": false,
+ "dts": true
+ },
+ "transform": {},
+ "target": "esnext",
+ "loose": false,
+ "externalHelpers": false,
+ "keepClassNames": true
+ },
+ "minify": true
+}
diff --git a/threads/README.md b/threads/README.md
new file mode 100644
index 0000000..5dc89ae
--- /dev/null
+++ b/threads/README.md
@@ -0,0 +1,24 @@
+# A pure javascript shim for WASI Preview 1 threads
+
+> [!WARNING]
+> The code in this directory is less production ready than the main browser_wasi_shim code.
+
+This project is implement threads on browser_wasi_shim
+
+# Features
+- [x] thread creation
+- [x] Filesystem wrapper accessible by multiple workers
+- [ ] thread pool
+
+# Building
+```sh
+$ npm install
+$ npm run build
+```
+
+# Running the demo
+```sh
+$ git submodule update --init
+$ cd examples && npm install && npm run dev
+```
+And visit http://localhost
diff --git a/threads/biome.json b/threads/biome.json
new file mode 100644
index 0000000..33e0c8e
--- /dev/null
+++ b/threads/biome.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.9.1/schema.json",
+ "vcs": {
+ "enabled": false,
+ "clientKind": "git",
+ "useIgnoreFile": false
+ },
+ "files": {
+ "ignoreUnknown": false,
+ "ignore": []
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "space"
+ },
+ "organizeImports": {
+ "enabled": true
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "double"
+ }
+ }
+}
diff --git a/threads/bun.lockb b/threads/bun.lockb
new file mode 100644
index 0000000..e0c24ec
Binary files /dev/null and b/threads/bun.lockb differ
diff --git a/threads/examples/bun.lockb b/threads/examples/bun.lockb
new file mode 100644
index 0000000..005949e
Binary files /dev/null and b/threads/examples/bun.lockb differ
diff --git a/threads/examples/package.json b/threads/examples/package.json
new file mode 100644
index 0000000..440b91e
--- /dev/null
+++ b/threads/examples/package.json
@@ -0,0 +1,8 @@
+{
+ "dependencies": {
+ "@oligami/shared-object": "^0.1.1",
+ "@xterm/xterm": "^5.5",
+ "xterm-addon-fit": "^0.8.0",
+ "@bjorn3/browser_wasi_shim": "^0.3.0"
+ }
+}
diff --git a/threads/examples/wasi_multi_threads/index.html b/threads/examples/wasi_multi_threads/index.html
new file mode 100644
index 0000000..f111ef3
--- /dev/null
+++ b/threads/examples/wasi_multi_threads/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/threads/examples/wasi_multi_threads/index.ts b/threads/examples/wasi_multi_threads/index.ts
new file mode 100644
index 0000000..f9f27af
--- /dev/null
+++ b/threads/examples/wasi_multi_threads/index.ts
@@ -0,0 +1,27 @@
+import { WASIFarm, WASIFarmAnimal } from "../../src";
+import {
+ File,
+ OpenFile,
+ ConsoleStdout,
+ PreopenDirectory,
+} from "@bjorn3/browser_wasi_shim";
+
+const farm = new WASIFarm(
+ new OpenFile(new File([])), // stdin
+ ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)),
+ ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
+ [],
+);
+
+console.log(farm);
+
+const worker = new Worker("worker.ts", { type: "module" });
+// const worker = new Worker(new URL("./worker.js", import.meta.url).href, { type: "module" });
+
+console.log(worker);
+
+worker.postMessage({
+ wasi_ref: farm.get_ref(),
+});
+
+console.log("Sent WASI ref to worker");
diff --git a/threads/examples/wasi_multi_threads/main.rs b/threads/examples/wasi_multi_threads/main.rs
new file mode 100644
index 0000000..86d14dd
--- /dev/null
+++ b/threads/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/threads/examples/wasi_multi_threads/multi_thread_echo.wasm b/threads/examples/wasi_multi_threads/multi_thread_echo.wasm
new file mode 100644
index 0000000..894878b
Binary files /dev/null and b/threads/examples/wasi_multi_threads/multi_thread_echo.wasm differ
diff --git a/threads/examples/wasi_multi_threads/thread_spawn.ts b/threads/examples/wasi_multi_threads/thread_spawn.ts
new file mode 100644
index 0000000..3bb3a39
--- /dev/null
+++ b/threads/examples/wasi_multi_threads/thread_spawn.ts
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../src";
+
+self.onmessage = (event) => {
+ thread_spawn_on_worker(event.data);
+};
diff --git a/threads/examples/wasi_multi_threads/worker.ts b/threads/examples/wasi_multi_threads/worker.ts
new file mode 100644
index 0000000..96bb99b
--- /dev/null
+++ b/threads/examples/wasi_multi_threads/worker.ts
@@ -0,0 +1,37 @@
+import { WASIFarmAnimal } from "../../src";
+
+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
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: new URL("./thread_spawn.ts", import.meta.url)
+ .href,
+ thread_spawn_wasm: wasm,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ const inst = await WebAssembly.instantiate(wasm, {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ wasi.start(
+ inst as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+ );
+};
diff --git a/threads/examples/wasi_multi_threads_channel/channel.wasm b/threads/examples/wasi_multi_threads_channel/channel.wasm
new file mode 100644
index 0000000..369c3b5
Binary files /dev/null and b/threads/examples/wasi_multi_threads_channel/channel.wasm differ
diff --git a/threads/examples/wasi_multi_threads_channel/index.html b/threads/examples/wasi_multi_threads_channel/index.html
new file mode 100644
index 0000000..f111ef3
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_channel/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/threads/examples/wasi_multi_threads_channel/index.ts b/threads/examples/wasi_multi_threads_channel/index.ts
new file mode 100644
index 0000000..1eca130
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_channel/index.ts
@@ -0,0 +1,15 @@
+import { OpenFile, File, ConsoleStdout } from "@bjorn3/browser_wasi_shim";
+import { WASIFarm } from "../../src";
+
+const farm = new WASIFarm(
+ new OpenFile(new File([])), // stdin
+ ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)),
+ ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
+ [],
+);
+
+const worker = new Worker("./worker.ts", { type: "module" });
+
+worker.postMessage({
+ wasi_ref: farm.get_ref(),
+});
diff --git a/threads/examples/wasi_multi_threads_channel/main.rs b/threads/examples/wasi_multi_threads_channel/main.rs
new file mode 100644
index 0000000..216800c
--- /dev/null
+++ b/threads/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/threads/examples/wasi_multi_threads_channel/thread_spawn.ts b/threads/examples/wasi_multi_threads_channel/thread_spawn.ts
new file mode 100644
index 0000000..3bb3a39
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_channel/thread_spawn.ts
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../src";
+
+self.onmessage = (event) => {
+ thread_spawn_on_worker(event.data);
+};
diff --git a/threads/examples/wasi_multi_threads_channel/worker.ts b/threads/examples/wasi_multi_threads_channel/worker.ts
new file mode 100644
index 0000000..0b926e0
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_channel/worker.ts
@@ -0,0 +1,36 @@
+import { WASIFarmAnimal } from "../../src";
+
+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
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: new URL("./thread_spawn.ts", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.ts",
+ thread_spawn_wasm: wasm,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ const inst = await WebAssembly.instantiate(wasm, {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ wasi.start(
+ inst as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+ );
+};
diff --git a/threads/examples/wasi_multi_threads_rustc/clang.ts b/threads/examples/wasi_multi_threads_rustc/clang.ts
new file mode 100644
index 0000000..6b43ac2
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/clang.ts
@@ -0,0 +1,76 @@
+import { strace } from "@bjorn3/browser_wasi_shim";
+import { WASIFarmAnimal } from "../../src";
+import { SharedObject } from "@oligami/shared-object";
+
+let wasi: WASIFarmAnimal;
+let inst: {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+};
+let wasm: WebAssembly.Module;
+
+let shared_clang: SharedObject;
+let shared_tools: SharedObject;
+let shared_wasm_ld: SharedObject;
+
+globalThis.onmessage = async (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
+ );
+
+ // 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, []),
+ })) as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ };
+
+ console.log("wasi.start, inst", inst);
+
+ const memory_reset = inst.exports.memory.buffer;
+ const memory_reset_view = new Uint8Array(memory_reset).slice();
+
+ shared_clang = new 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((...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((...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/threads/examples/wasi_multi_threads_rustc/depend_clang_files.ts b/threads/examples/wasi_multi_threads_rustc/depend_clang_files.ts
new file mode 100644
index 0000000..5f3a3a6
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/depend_clang_files.ts
@@ -0,0 +1,86 @@
+import { WASIFarm } from "../../src";
+import {
+ Directory,
+ File,
+ type Inode,
+ PreopenDirectory,
+} from "@bjorn3/browser_wasi_shim";
+
+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 toMap = (arr: Array<[string, Inode]>) => new Map(arr);
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory(
+ "/sysroot-clang",
+ toMap([
+ [
+ "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", new Directory(wasi_libs)],
+ ]),
+ ],
+ ]),
+ ),
+ ],
+ {
+ // allocator_size: 1024 * 1024 * 1024,
+ // debug: true,
+ },
+);
+
+const ret = await farm.get_ref();
+
+postMessage({ wasi_ref: ret });
diff --git a/threads/examples/wasi_multi_threads_rustc/depend_rustc_files.ts b/threads/examples/wasi_multi_threads_rustc/depend_rustc_files.ts
new file mode 100644
index 0000000..4dc8153
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/depend_rustc_files.ts
@@ -0,0 +1,160 @@
+import {
+ Directory,
+ PreopenDirectory,
+ File,
+ type Inode,
+} from "@bjorn3/browser_wasi_shim";
+import { WASIFarm } from "../../src";
+
+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 toMap = (arr: Array<[string, Inode]>) => new Map(arr);
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory(
+ "/sysroot",
+ toMap([
+ [
+ "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/threads/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.ts b/threads/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.ts
new file mode 100644
index 0000000..9dac3a1
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/depend_rustc_with_lld.ts
@@ -0,0 +1,161 @@
+import { WASIFarm } from "../../src";
+
+import {
+ File,
+ Directory,
+ PreopenDirectory,
+ type Inode,
+} from "@bjorn3/browser_wasi_shim";
+
+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 toMap = (arr: Array<[string, Inode]>) => new Map(arr);
+
+const farm = new WASIFarm(
+ undefined,
+ undefined,
+ undefined,
+ [
+ new PreopenDirectory(
+ "/sysroot-with-lld",
+ toMap([
+ [
+ "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/threads/examples/wasi_multi_threads_rustc/index.html b/threads/examples/wasi_multi_threads_rustc/index.html
new file mode 100644
index 0000000..0235f6b
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/threads/examples/wasi_multi_threads_rustc/index.ts b/threads/examples/wasi_multi_threads_rustc/index.ts
new file mode 100644
index 0000000..20cd1db
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/index.ts
@@ -0,0 +1,67 @@
+import { Terminal } from "@xterm/xterm";
+import { WASIFarm } from "../../src";
+import { FitAddon } from "xterm-addon-fit";
+import { SharedObject } from "@oligami/shared-object";
+import { Fd } from "@bjorn3/browser_wasi_shim";
+
+import "@xterm/xterm/css/xterm.css";
+
+const term = new Terminal({
+ convertEol: true,
+});
+const terminalElement = document.getElementById("terminal");
+
+if (!terminalElement) {
+ throw new Error("No terminal element found");
+}
+
+term.open(terminalElement);
+
+const fitAddon = new FitAddon();
+term.loadAddon(fitAddon);
+fitAddon.fit();
+
+// term.onData(data => {
+// term.write(data);
+// });
+
+const shared = new SharedObject(
+ {
+ writeln(data) {
+ term.writeln(data);
+ },
+ writeUtf8(data) {
+ term.write(new TextDecoder().decode(data));
+ },
+ },
+ "term",
+);
+
+term.writeln("Initializing WASI...");
+
+class XtermStdio extends Fd {
+ term: Terminal;
+
+ constructor(term: Terminal) {
+ super();
+ this.term = term;
+ }
+ fd_write(data: Uint8Array) /*: {ret: number, nwritten: number}*/ {
+ this.term.write(new TextDecoder().decode(data));
+ return { ret: 0, nwritten: data.byteLength };
+ }
+}
+
+const farm = new WASIFarm(
+ new XtermStdio(term),
+ new XtermStdio(term),
+ new XtermStdio(term),
+ [],
+ // { debug: true },
+);
+
+const worker = new Worker("./worker.ts", { type: "module" });
+
+worker.postMessage({
+ wasi_ref: farm.get_ref(),
+});
diff --git a/threads/examples/wasi_multi_threads_rustc/rust_wasm b/threads/examples/wasi_multi_threads_rustc/rust_wasm
new file mode 160000
index 0000000..76de7f7
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/rust_wasm
@@ -0,0 +1 @@
+Subproject commit 76de7f7133b0da1e89770ec30fd05026fdbc7e53
diff --git a/threads/examples/wasi_multi_threads_rustc/rustc.ts b/threads/examples/wasi_multi_threads_rustc/rustc.ts
new file mode 100644
index 0000000..b5683d6
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/rustc.ts
@@ -0,0 +1,49 @@
+import { SharedObject } from "@oligami/shared-object";
+import { WASIFarmAnimal } from "../../src";
+
+const { promise, resolve } = Promise.withResolvers();
+import("@oligami/shared-object").then(resolve);
+
+let wasi: WASIFarmAnimal;
+let wasm: WebAssembly.Module;
+let shared: SharedObject;
+
+globalThis.onmessage = async (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.ts", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.ts",
+ 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((...args) => {
+ wasi.args = ["rustc", ...args];
+ wasi.block_start_on_thread();
+ console.log("wasi.start done");
+ }, "rustc");
+
+ postMessage({ ready: true });
+ }
+};
diff --git a/threads/examples/wasi_multi_threads_rustc/rustc_with_lld.ts b/threads/examples/wasi_multi_threads_rustc/rustc_with_lld.ts
new file mode 100644
index 0000000..defb5ae
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/rustc_with_lld.ts
@@ -0,0 +1,44 @@
+import { SharedObject } from "@oligami/shared-object";
+import { WASIFarmAnimal } from "../../src";
+
+let wasi: WASIFarmAnimal;
+let wasm: WebAssembly.Module;
+let shared: SharedObject;
+
+globalThis.onmessage = async (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.ts", import.meta.url)
+ .href,
+ // thread_spawn_worker_url: "./thread_spawn.ts",
+ thread_spawn_wasm: wasm,
+ },
+ );
+
+ await wasi.wait_worker_background_worker();
+
+ wasi.get_share_memory().grow(200);
+
+ console.log("Waiting for worker background worker...");
+
+ shared = new 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/threads/examples/wasi_multi_threads_rustc/save_stdout.ts b/threads/examples/wasi_multi_threads_rustc/save_stdout.ts
new file mode 100644
index 0000000..4aa4819
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/save_stdout.ts
@@ -0,0 +1,63 @@
+import { SharedObject, SharedObjectRef } from "@oligami/shared-object";
+import { WASIFarm } from "../../src";
+import { Fd } from "@bjorn3/browser_wasi_shim";
+import { resolve } from "node:path";
+
+const term = new SharedObjectRef("term").proxy<{
+ writeln: (data) => Promise;
+ writeUtf8: (data) => Promise;
+}>();
+
+class Stdout extends Fd {
+ buffer = new Uint8Array(0);
+
+ fd_write(data: Uint8Array): { ret: number; nwritten: number } {
+ const { promise, resolve } = Promise.withResolvers();
+
+ (async () => {
+ 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);
+
+ resolve({ ret: 0, nwritten: data.byteLength });
+ })();
+
+ return promise as unknown as { ret: number; nwritten: number };
+ }
+}
+
+const std_out = new Stdout();
+
+const std_err = new Stdout();
+
+const shared_std_out = new 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(
+ {
+ 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/threads/examples/wasi_multi_threads_rustc/thread_spawn.ts b/threads/examples/wasi_multi_threads_rustc/thread_spawn.ts
new file mode 100644
index 0000000..7fc9aa2
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/thread_spawn.ts
@@ -0,0 +1,5 @@
+import { thread_spawn_on_worker } from "../../src";
+
+self.onmessage = async (event) => {
+ await thread_spawn_on_worker(event.data);
+};
diff --git a/threads/examples/wasi_multi_threads_rustc/tmp_dir.ts b/threads/examples/wasi_multi_threads_rustc/tmp_dir.ts
new file mode 100644
index 0000000..0ca6152
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/tmp_dir.ts
@@ -0,0 +1,86 @@
+import {
+ type Inode,
+ PreopenDirectory,
+ File,
+ Directory,
+} from "@bjorn3/browser_wasi_shim";
+import { WASIFarm } from "../../src";
+import { SharedObject } from "@oligami/shared-object";
+
+const toMap = (arr: Array<[string, Inode]>) => new Map(arr);
+
+const root_dir = new PreopenDirectory(
+ "/",
+ toMap([
+ [
+ "hello.rs",
+ new File(
+ new TextEncoder().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", toMap([])),
+ root_dir,
+ new PreopenDirectory(
+ "~",
+ toMap([
+ [
+ "####.rs",
+ new File(
+ new TextEncoder().encode(`fn main() { println!("Hello World!"); }`),
+ ),
+ ],
+ ["sysroot", new Directory([])],
+ ]),
+ ),
+ ],
+ // { debug: true },
+);
+
+const ret = await farm.get_ref();
+
+const shared = new SharedObject(
+ {
+ get_file(path_str) {
+ console.log(root_dir);
+ const path = {
+ parts: [path_str],
+ is_dir: false,
+ };
+ // biome-ignore lint/suspicious/noExplicitAny:
+ const { ret, entry } = root_dir.dir.get_entry_for_path(path as any);
+ if (ret !== 0 || entry === null) {
+ throw new Error(`get_file: ${path_str} failed`);
+ }
+ return (entry as File).data;
+ },
+ },
+ "root_dir",
+);
+
+postMessage({ wasi_ref: ret });
diff --git a/threads/examples/wasi_multi_threads_rustc/tre_opt.wasm b/threads/examples/wasi_multi_threads_rustc/tre_opt.wasm
new file mode 100644
index 0000000..67f06df
Binary files /dev/null and b/threads/examples/wasi_multi_threads_rustc/tre_opt.wasm differ
diff --git a/threads/examples/wasi_multi_threads_rustc/tree.ts b/threads/examples/wasi_multi_threads_rustc/tree.ts
new file mode 100644
index 0000000..c748799
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/tree.ts
@@ -0,0 +1,42 @@
+import { SharedObject } from "@oligami/shared-object";
+import { WASIFarmAnimal } from "../../src";
+
+let inst: { exports: { memory: WebAssembly.Memory; _start: () => unknown } };
+let wasi: WASIFarmAnimal;
+let wasm: WebAssembly.Module;
+
+let shared: SharedObject;
+
+globalThis.onmessage = async (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
+ );
+
+ // Memory is rewritten at this time.
+ inst = (await WebAssembly.instantiate(wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ })) as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ };
+
+ const memory_reset = inst.exports.memory.buffer;
+ const memory_reset_view = new Uint8Array(memory_reset).slice();
+
+ shared = new 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/threads/examples/wasi_multi_threads_rustc/worker.ts b/threads/examples/wasi_multi_threads_rustc/worker.ts
new file mode 100644
index 0000000..3777a60
--- /dev/null
+++ b/threads/examples/wasi_multi_threads_rustc/worker.ts
@@ -0,0 +1,370 @@
+import { SharedObjectRef } from "@oligami/shared-object";
+import { WASIFarmAnimal, type WASIFarmRef } from "../../src";
+
+let tree: (...args: string[]) => void;
+let term: {
+ writeln: (data) => Promise;
+ writeUtf8: (data) => Promise;
+};
+let rustc: (...args: string[]) => void;
+let rustc_with_lld: (...args: string[]) => void;
+let clang: (...args: string[]) => void;
+let llvm_tools: (...args: string[]) => void;
+let wasm_ld: (...args: string[]) => void;
+let std_out_keep: {
+ get: () => Promise;
+ reset: () => void;
+};
+let std_err_keep: {
+ get: () => Promise;
+ reset: () => void;
+};
+let root_dir: {
+ get_file: (path_str: string) => Promise;
+};
+
+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<{ wasi_ref: WASIFarmRef }>();
+ const {
+ promise: depend_rustc_with_lld_promise,
+ resolve: depend_rustc_with_lld_resolve,
+ } = Promise.withResolvers<{ wasi_ref: WASIFarmRef }>();
+ const {
+ promise: depend_clang_files_promise,
+ resolve: depend_clang_files_resolve,
+ } = Promise.withResolvers<{ wasi_ref: WASIFarmRef }>();
+ const { promise: tmp_dir_promise, resolve: tmp_dir_resolve } =
+ Promise.withResolvers<{ wasi_ref: WASIFarmRef }>();
+ const { promise: save_stdout_promise, resolve: save_stdout_resolve } =
+ Promise.withResolvers<{ wasi_ref: WASIFarmRef }>();
+
+ const depend_rustc_files_manage_worker = new Worker("depend_rustc_files.ts", {
+ 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.ts",
+ {
+ 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.ts", {
+ type: "module",
+ });
+ depend_clang_files_manage_worker.onmessage = (e) => {
+ depend_clang_files_resolve(e.data);
+ };
+
+ const tmp_dir_manage_worker = new Worker("tmp_dir.ts", {
+ type: "module",
+ });
+ tmp_dir_manage_worker.onmessage = (e) => {
+ tmp_dir_resolve(e.data);
+ };
+
+ const save_stdout_manage_worker = new Worker("save_stdout.ts", {
+ 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 tree_worker = new Worker("tree.ts", {
+ type: "module",
+ });
+ tree_worker.onmessage = (e) => {
+ console.log("tree onmessage");
+ tree_resolve(e.data);
+ };
+
+ const rustc_worker = new Worker("rustc.ts", {
+ type: "module",
+ });
+ rustc_worker.onmessage = (e) => {
+ console.log("rustc onmessage");
+ rustc_resolve(e.data);
+ };
+
+ const rustc_with_lld_worker = new Worker("rustc_with_lld.ts", {
+ 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.ts", {
+ type: "module",
+ });
+ clang_worker.onmessage = (e) => {
+ console.log("clang onmessage");
+ clang_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,
+ });
+
+ console.log("Waiting for tree and rustc to finish...");
+
+ await Promise.all([
+ tree_promise,
+ rustc_promise,
+ rustc_with_lld_promise,
+ clang_promise,
+ ]);
+
+ console.log("Sending run message...");
+
+ tree = new SharedObjectRef("tree").proxy<(...args: string[]) => void>();
+
+ term = new SharedObjectRef("term").proxy<{
+ writeln: (data) => Promise;
+ writeUtf8: (data) => Promise;
+ }>();
+
+ rustc = new SharedObjectRef("rustc").proxy<(...args: string[]) => void>();
+
+ rustc_with_lld = new SharedObjectRef("rustc_with_lld").proxy<
+ (...args: string[]) => void
+ >();
+
+ clang = new SharedObjectRef("clang").proxy<(...args: string[]) => void>();
+
+ llvm_tools = new SharedObjectRef("llvm-tools").proxy<
+ (...args: string[]) => void
+ >();
+
+ wasm_ld = new SharedObjectRef("wasm-ld").proxy<(...args: string[]) => void>();
+
+ std_out_keep = new SharedObjectRef("std_out_keep").proxy<{
+ get: () => Promise;
+ reset: () => void;
+ }>();
+
+ std_err_keep = new SharedObjectRef("std_err_keep").proxy<{
+ get: () => Promise;
+ reset: () => void;
+ }>();
+
+ root_dir = new SharedObjectRef("root_dir").proxy<{
+ get_file: (path_str: string) => Promise;
+ }>();
+
+ // 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: "));
+ if (!lld_args_and_etc) {
+ throw new Error("cannot get lld arguments");
+ }
+ 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
+ );
+
+ // Memory is rewritten at this time.
+ const inst = (await WebAssembly.instantiate(created_wasm, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ })) as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ };
+
+ wasi.start(inst);
+
+ // all done
+ await term.writeln(`\n$${blueText} All done!${resetText}`);
+};
diff --git a/threads/examples/wasi_workers/echo_and_rewrite.wasm b/threads/examples/wasi_workers/echo_and_rewrite.wasm
new file mode 100644
index 0000000..1f4e413
Binary files /dev/null and b/threads/examples/wasi_workers/echo_and_rewrite.wasm differ
diff --git a/threads/examples/wasi_workers/index.html b/threads/examples/wasi_workers/index.html
new file mode 100644
index 0000000..f111ef3
--- /dev/null
+++ b/threads/examples/wasi_workers/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ ####
+
+
+
+
+
diff --git a/threads/examples/wasi_workers/index.ts b/threads/examples/wasi_workers/index.ts
new file mode 100644
index 0000000..0df777d
--- /dev/null
+++ b/threads/examples/wasi_workers/index.ts
@@ -0,0 +1,41 @@
+import {
+ OpenFile,
+ File,
+ ConsoleStdout,
+ PreopenDirectory,
+ type Inode,
+ Directory,
+} from "@bjorn3/browser_wasi_shim";
+import { WASIFarm } from "../../src";
+
+const worker = new Worker("./worker.ts", { type: "module" });
+worker.onmessage = (event) => {
+ const { wasi_ref: wasi_ref2 } = event.data;
+
+ (async () => {
+ const current_directory = new Map();
+ current_directory.set(
+ "hello.txt",
+ new File(new TextEncoder().encode("Hello, world!")),
+ );
+ current_directory.set("hello2", new Directory(new Map()));
+
+ const wasi_farm = new WASIFarm(
+ new OpenFile(new File([])), // stdin
+ ConsoleStdout.lineBuffered((msg) =>
+ console.log(`[WASI stdout on main thread] ${msg}`),
+ ),
+ ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
+ [new PreopenDirectory(".", current_directory)],
+ );
+ console.log("WASI farm created");
+ const wasi_ref = await wasi_farm.get_ref();
+
+ const myWorker1 = new Worker("./worker1.ts", { type: "module" });
+ myWorker1.postMessage({ wasi_ref, wasi_ref2 });
+ const myWorker2 = new Worker("./worker2.ts", { type: "module" });
+ myWorker2.postMessage({ wasi_ref, wasi_ref2 });
+ const myWorker3 = new Worker("./worker3.ts", { type: "module" });
+ myWorker3.postMessage({ wasi_ref, wasi_ref2 });
+ })();
+};
diff --git a/threads/examples/wasi_workers/main.rs b/threads/examples/wasi_workers/main.rs
new file mode 100644
index 0000000..41a744c
--- /dev/null
+++ b/threads/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/threads/examples/wasi_workers/worker.ts b/threads/examples/wasi_workers/worker.ts
new file mode 100644
index 0000000..849ed41
--- /dev/null
+++ b/threads/examples/wasi_workers/worker.ts
@@ -0,0 +1,23 @@
+import {
+ ConsoleStdout,
+ type Inode,
+ PreopenDirectory,
+ File,
+} from "@bjorn3/browser_wasi_shim";
+import { WASIFarm } from "../../src";
+
+const dir = new Map();
+dir.set("hello2.txt", new File(new TextEncoder().encode("Hello, world!!!!!")));
+
+const wasi_farm = new WASIFarm(
+ undefined,
+ ConsoleStdout.lineBuffered((msg) =>
+ console.log(`[WASI stdout on worker] ${msg}`),
+ ),
+ undefined,
+ [new PreopenDirectory("hello2", dir)],
+);
+
+console.log("WASI farm created");
+const wasi_ref = await wasi_farm.get_ref();
+self.postMessage({ wasi_ref });
diff --git a/threads/examples/wasi_workers/worker1.ts b/threads/examples/wasi_workers/worker1.ts
new file mode 100644
index 0000000..981b876
--- /dev/null
+++ b/threads/examples/wasi_workers/worker1.ts
@@ -0,0 +1,36 @@
+import { WASIFarmAnimal } from "../../src";
+
+self.onmessage = async (e) => {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ console.dir(wasi_ref);
+ console.dir(wasi_ref2);
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref2, wasi_ref],
+ [
+ "echo_and_rewrite",
+ "hello2/hello2.txt",
+ "world",
+ "new_world",
+ "0",
+ "100",
+ "100",
+ ], // args
+ [""], // env
+ // options
+ );
+
+ console.dir(wasi, { depth: null });
+
+ const wasm = await fetch("./echo_and_rewrite.wasm");
+ const buff = await wasm.arrayBuffer();
+ const { instance } = await WebAssembly.instantiate(buff, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+ wasi.start(
+ instance as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+ );
+};
diff --git a/threads/examples/wasi_workers/worker2.ts b/threads/examples/wasi_workers/worker2.ts
new file mode 100644
index 0000000..b93a128
--- /dev/null
+++ b/threads/examples/wasi_workers/worker2.ts
@@ -0,0 +1,22 @@
+import { WASIFarmAnimal } from "../../src";
+
+self.onmessage = async (e) => {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref2, wasi_ref],
+ ["echo_and_rewrite", "hello.txt", "world", "new_world", "100", "200"], // args
+ [""], // env
+ // options
+ );
+ const wasm = await fetch("./echo_and_rewrite.wasm");
+ const buff = await wasm.arrayBuffer();
+ const { instance } = await WebAssembly.instantiate(buff, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+ wasi.start(
+ instance as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+ );
+};
diff --git a/threads/examples/wasi_workers/worker3.ts b/threads/examples/wasi_workers/worker3.ts
new file mode 100644
index 0000000..3862dcf
--- /dev/null
+++ b/threads/examples/wasi_workers/worker3.ts
@@ -0,0 +1,22 @@
+import { WASIFarmAnimal } from "../../src";
+
+self.onmessage = async (e) => {
+ const { wasi_ref, wasi_ref2 } = e.data;
+
+ const wasi = new WASIFarmAnimal(
+ [wasi_ref, wasi_ref2],
+ ["echo_and_rewrite", "hello.txt", "world", "new_world", "200", "300"], // args
+ [""], // env
+ // options
+ );
+ const wasm = await fetch("./echo_and_rewrite.wasm");
+ const buff = await wasm.arrayBuffer();
+ const { instance } = await WebAssembly.instantiate(buff, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+ wasi.start(
+ instance as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+ );
+};
diff --git a/threads/examples/wasi_workers_rustc/index.html b/threads/examples/wasi_workers_rustc/index.html
new file mode 100644
index 0000000..7f7413a
--- /dev/null
+++ b/threads/examples/wasi_workers_rustc/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 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/threads/examples/wasi_workers_rustc/index.ts b/threads/examples/wasi_workers_rustc/index.ts
new file mode 100644
index 0000000..4d9bf7a
--- /dev/null
+++ b/threads/examples/wasi_workers_rustc/index.ts
@@ -0,0 +1,195 @@
+import { WASIFarm } from "../../src";
+import {
+ Directory,
+ Fd,
+ File,
+ type Inode,
+ PreopenDirectory,
+} from "@bjorn3/browser_wasi_shim";
+import { Terminal } from "@xterm/xterm";
+import { FitAddon } from "xterm-addon-fit";
+import "@xterm/xterm/css/xterm.css";
+
+const term = new Terminal({
+ convertEol: true,
+});
+const terminalElement = document.getElementById("terminal");
+if (!terminalElement) {
+ throw new Error("Terminal element not found");
+}
+term.open(terminalElement);
+
+const fitAddon = new FitAddon();
+term.loadAddon(fitAddon);
+fitAddon.fit();
+
+class XtermStdio extends Fd {
+ /*:: term: Terminal*/
+ term: Terminal;
+
+ constructor(term: Terminal) {
+ super();
+ this.term = term;
+ }
+ fd_write(data /*: Uint8Array*/) /*: {ret: number, nwritten: number}*/ {
+ console.log(data);
+ this.term.write(new TextDecoder().decode(data));
+ return { ret: 0, nwritten: data.byteLength };
+ }
+}
+
+term.writeln("\x1B[93mDownloading\x1B[0m");
+//let wasm = await WebAssembly.compileStreaming(fetch("/rust_out.wasm"));
+term.writeln("\x1B[93mInstantiating\x1B[0m");
+
+async function load_external_file(path) {
+ return new File(await (await (await fetch(path)).blob()).arrayBuffer());
+}
+
+const toMap = (arr: Array<[string, Inode]>) => {
+ const map = new Map();
+ for (const [key, value] of arr) {
+ map.set(key, value);
+ }
+ return map;
+};
+
+const fds = [
+ new PreopenDirectory("/tmp", toMap([])),
+ new PreopenDirectory(
+ "/sysroot",
+ toMap([
+ [
+ "lib",
+ new Directory([
+ [
+ "rustlib",
+ new Directory([
+ ["wasm32-wasi", new Directory([["lib", new Directory([])]])],
+ [
+ "x86_64-unknown-linux-gnu",
+ new Directory([
+ [
+ "lib",
+ new Directory(
+ await (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(
+ `../wasi_multi_threads_rustc/rust_wasm/rustc_cranelift/dist/lib/rustlib/x86_64-unknown-linux-gnu/lib/${file}`,
+ ),
+ );
+ }
+ return dir;
+ })(),
+ ),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ ]),
+ ],
+ ]),
+ ),
+ new PreopenDirectory(
+ "/",
+ toMap([
+ [
+ "hello.rs",
+ new File(
+ new TextEncoder().encode(`fn main() { println!("Hello World!"); }`),
+ ),
+ ],
+ ]),
+ ),
+];
+
+const wasi_farm = new WASIFarm(
+ new XtermStdio(term),
+ new XtermStdio(term),
+ new XtermStdio(term),
+ fds,
+ {
+ allocator_size: 1024 * 1024 * 1024,
+ },
+);
+
+const wasi_ref = await wasi_farm.get_ref();
+
+const worker = new Worker("./worker.ts", { type: "module" });
+worker.postMessage({ wasi_ref });
+
+console.log("worker created", worker);
+
+worker.onmessage = (event) => {
+ const data = event.data;
+ const { term: write } = data;
+
+ term.writeln(write);
+};
+
+const downloadsElement = document.getElementById("downloads");
+
+if (!downloadsElement) {
+ throw new Error("Downloads element not found");
+}
+
+let content: Inode | undefined;
+while (true) {
+ content = fds[2].dir.contents.get(
+ "hello.hello.65c991d23c885d45-cgu.0.rcgu.o",
+ );
+ if (content) {
+ break;
+ }
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+}
+await new Promise((resolve) => setTimeout(resolve, 1000));
+downloadsElement.innerHTML += `Download object `;
+let content2: Inode | undefined;
+while (true) {
+ content2 = fds[2].dir.contents.get("hello.allocator_shim.rcgu.o");
+ if (content2) {
+ break;
+ }
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+}
+await new Promise((resolve) => setTimeout(resolve, 1000));
+downloadsElement.innerHTML += `Download allocator shim `;
diff --git a/threads/examples/wasi_workers_rustc/worker.ts b/threads/examples/wasi_workers_rustc/worker.ts
new file mode 100644
index 0000000..9b8e2ee
--- /dev/null
+++ b/threads/examples/wasi_workers_rustc/worker.ts
@@ -0,0 +1,76 @@
+import { strace } from "@bjorn3/browser_wasi_shim";
+import { WASIFarmAnimal } from "../../src";
+
+console.log("worker.js");
+
+globalThis.onmessage = async (e) => {
+ const wasm = await WebAssembly.compileStreaming(
+ fetch(
+ "../wasi_multi_threads_rustc/rust_wasm/rustc_cranelift/rustc_opt.wasm",
+ ),
+ );
+
+ console.log("worker.js onmessage", e.data);
+
+ const { wasi_ref } = e.data;
+
+ const args = [
+ "rustc",
+ "/hello.rs",
+ "--sysroot",
+ "/sysroot",
+ "--target",
+ "x86_64-unknown-linux-gnu",
+ "-Cpanic=abort",
+ "-Ccodegen-units=1",
+ ];
+ const env = ["RUSTC_LOG=info"];
+
+ console.log("wasi_ref", wasi_ref);
+
+ const w = new WASIFarmAnimal(wasi_ref, args, env, {});
+
+ let next_thread_id = 1;
+
+ const inst = (await WebAssembly.instantiate(wasm, {
+ env: {
+ memory: new WebAssembly.Memory({
+ initial: 256,
+ maximum: 16384,
+ shared: true,
+ }),
+ },
+ wasi: {
+ "thread-spawn": (start_arg) => {
+ console.log("thread-spawn", start_arg);
+
+ const 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"]),
+ })) as unknown as {
+ exports: {
+ wasi_thread_start: (thread_id: number, start_arg: number) => void;
+ memory: WebAssembly.Memory;
+ _start: () => unknown;
+ };
+ };
+
+ 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",
+ });
+};
diff --git a/threads/examples/wasi_workers_single/echo_and_rewrite.wasm b/threads/examples/wasi_workers_single/echo_and_rewrite.wasm
new file mode 100644
index 0000000..d03ed2d
Binary files /dev/null and b/threads/examples/wasi_workers_single/echo_and_rewrite.wasm differ
diff --git a/threads/examples/wasi_workers_single/index.html b/threads/examples/wasi_workers_single/index.html
new file mode 100644
index 0000000..c911479
--- /dev/null
+++ b/threads/examples/wasi_workers_single/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ ####
+
+
+
+
diff --git a/threads/examples/wasi_workers_single/index.ts b/threads/examples/wasi_workers_single/index.ts
new file mode 100644
index 0000000..255d858
--- /dev/null
+++ b/threads/examples/wasi_workers_single/index.ts
@@ -0,0 +1,43 @@
+import {
+ OpenFile,
+ File,
+ WASI,
+ ConsoleStdout,
+ PreopenDirectory,
+} from "@bjorn3/browser_wasi_shim";
+
+// sleep 1000
+await new Promise((resolve) => setTimeout(resolve, 1000));
+
+const toMap = (arr: Array<[string, File]>) => new Map(arr);
+
+const wasi = new WASI(
+ ["echo_and_rewrite", "hello.txt", "world", "new_world"], // args
+ ["FOO=bar"], // env
+ [
+ new OpenFile(new File([])), // stdin
+ ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)),
+ ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
+ new PreopenDirectory(
+ ".",
+ toMap([
+ ["hello.txt", new File(new TextEncoder().encode("Hello, world!"))],
+ ]),
+ ),
+ ],
+ { debug: true },
+);
+const wasm = await fetch("./echo_and_rewrite.wasm");
+const buff = await wasm.arrayBuffer();
+const { instance } = await WebAssembly.instantiate(buff, {
+ wasi_snapshot_preview1: wasi.wasiImport,
+});
+
+// sleep 1000ms
+await new Promise((resolve) => setTimeout(resolve, 1000));
+
+wasi.start(
+ instance as unknown as {
+ exports: { memory: WebAssembly.Memory; _start: () => unknown };
+ },
+);
diff --git a/threads/import-module-test/.gitignore b/threads/import-module-test/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/threads/import-module-test/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/threads/import-module-test/index.html b/threads/import-module-test/index.html
new file mode 100644
index 0000000..44a9335
--- /dev/null
+++ b/threads/import-module-test/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + TS
+
+
+
+
+
+
diff --git a/threads/import-module-test/package-lock.json b/threads/import-module-test/package-lock.json
new file mode 100644
index 0000000..c8be983
--- /dev/null
+++ b/threads/import-module-test/package-lock.json
@@ -0,0 +1,902 @@
+{
+ "name": "import-module-test",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "import-module-test",
+ "version": "0.0.0",
+ "dependencies": {
+ "@oligami/browser_wasi_shim-threads": "file:..",
+ "import-module-test": "file:"
+ },
+ "devDependencies": {
+ "typescript": "^5.5.3",
+ "vite": "^5.4.8"
+ }
+ },
+ "..": {
+ "name": "@oligami/browser_wasi_shim-threads",
+ "version": "0.1.0",
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0",
+ "@oligami/browser_wasi_shim-threads": "file:"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "1.9.3",
+ "@swc/cli": "^0.4.0",
+ "@swc/core": "^1.7.28",
+ "better-typescript-lib": "^2.8.0",
+ "npm-watch": "^0.13.0",
+ "typescript": "^5.6.2",
+ "unplugin-swc": "^1.5.1",
+ "vite": "^5.4.8",
+ "vite-plugin-dts": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@oligami/browser_wasi_shim-threads": {
+ "resolved": "..",
+ "link": true
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
+ "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
+ "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
+ "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
+ "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
+ "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
+ "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
+ "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
+ "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
+ "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
+ "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
+ "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
+ "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
+ "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
+ "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
+ "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
+ "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/import-module-test": {
+ "resolved": "",
+ "link": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
+ "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.24.0",
+ "@rollup/rollup-android-arm64": "4.24.0",
+ "@rollup/rollup-darwin-arm64": "4.24.0",
+ "@rollup/rollup-darwin-x64": "4.24.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.24.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.24.0",
+ "@rollup/rollup-linux-arm64-musl": "4.24.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.24.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-musl": "4.24.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.24.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.24.0",
+ "@rollup/rollup-win32-x64-msvc": "4.24.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/vite": {
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/threads/import-module-test/package.json b/threads/import-module-test/package.json
new file mode 100644
index 0000000..7b6191b
--- /dev/null
+++ b/threads/import-module-test/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "import-module-test",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "typescript": "^5.5.3",
+ "vite": "^5.4.8"
+ },
+ "dependencies": {
+ "@oligami/browser_wasi_shim-threads": "file:..",
+ "import-module-test": "file:"
+ }
+}
diff --git a/threads/import-module-test/public/vite.svg b/threads/import-module-test/public/vite.svg
new file mode 100644
index 0000000..e7b8dfb
--- /dev/null
+++ b/threads/import-module-test/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/threads/import-module-test/src/counter.ts b/threads/import-module-test/src/counter.ts
new file mode 100644
index 0000000..86cbb7d
--- /dev/null
+++ b/threads/import-module-test/src/counter.ts
@@ -0,0 +1,9 @@
+export function setupCounter(element: HTMLButtonElement) {
+ let counter = 0;
+ const setCounter = (count: number) => {
+ counter = count;
+ element.innerHTML = `count is ${counter}`;
+ };
+ element.addEventListener("click", () => setCounter(counter + 1));
+ setCounter(0);
+}
diff --git a/threads/import-module-test/src/main.ts b/threads/import-module-test/src/main.ts
new file mode 100644
index 0000000..6612535
--- /dev/null
+++ b/threads/import-module-test/src/main.ts
@@ -0,0 +1,32 @@
+import "./style.css";
+import typescriptLogo from "./typescript.svg";
+import viteLogo from "/vite.svg";
+import { setupCounter } from "./counter.ts";
+
+// biome-ignore lint/style/noNonNullAssertion:
+document.querySelector("#app")!.innerHTML = `
+
+
+
+
+
+
+
+
Vite + TypeScript
+
+
+
+
+ Click on the Vite and TypeScript logos to learn more
+
+
+`;
+
+// biome-ignore lint/style/noNonNullAssertion:
+setupCounter(document.querySelector("#counter")!);
+
+import { WASIFarm } from "@oligami/browser_wasi_shim-threads";
+
+// Create a new WASI farm
+const farm = new WASIFarm();
+console.dir(farm, { depth: null });
diff --git a/threads/import-module-test/src/style.css b/threads/import-module-test/src/style.css
new file mode 100644
index 0000000..f9c7350
--- /dev/null
+++ b/threads/import-module-test/src/style.css
@@ -0,0 +1,96 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.vanilla:hover {
+ filter: drop-shadow(0 0 2em #3178c6aa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/threads/import-module-test/src/typescript.svg b/threads/import-module-test/src/typescript.svg
new file mode 100644
index 0000000..d91c910
--- /dev/null
+++ b/threads/import-module-test/src/typescript.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/threads/import-module-test/src/vite-env.d.ts b/threads/import-module-test/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/threads/import-module-test/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/threads/import-module-test/tsconfig.json b/threads/import-module-test/tsconfig.json
new file mode 100644
index 0000000..0511b9f
--- /dev/null
+++ b/threads/import-module-test/tsconfig.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/threads/import-module-test/vite.config.ts b/threads/import-module-test/vite.config.ts
new file mode 100644
index 0000000..a5eb955
--- /dev/null
+++ b/threads/import-module-test/vite.config.ts
@@ -0,0 +1,10 @@
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ server: {
+ headers: {
+ "Cross-Origin-Embedder-Policy": "require-corp",
+ "Cross-Origin-Opener-Policy": "same-origin",
+ },
+ },
+});
diff --git a/threads/index.html b/threads/index.html
new file mode 100644
index 0000000..9fe0595
--- /dev/null
+++ b/threads/index.html
@@ -0,0 +1,48 @@
+
+
+
+
+
+ Examples
+
+
+
+
+ all link
+
+
+
+
diff --git a/threads/package-lock.json b/threads/package-lock.json
new file mode 100644
index 0000000..2bb48d4
--- /dev/null
+++ b/threads/package-lock.json
@@ -0,0 +1,4635 @@
+{
+ "name": "@oligami/browser_wasi_shim-threads",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@oligami/browser_wasi_shim-threads",
+ "version": "0.1.0",
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0",
+ "@oligami/browser_wasi_shim-threads": "file:"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "1.9.3",
+ "@swc/cli": "^0.4.0",
+ "@swc/core": "^1.7.28",
+ "better-typescript-lib": "^2.8.0",
+ "npm-watch": "^0.13.0",
+ "typescript": "^5.6.2",
+ "unplugin-swc": "^1.5.1",
+ "vite": "^5.4.8",
+ "vite-plugin-dts": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
+ "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
+ "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.7.tgz",
+ "integrity": "sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.25.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.7.tgz",
+ "integrity": "sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.25.7",
+ "@babel/helper-validator-identifier": "^7.25.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@biomejs/biome": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.9.3.tgz",
+ "integrity": "sha512-POjAPz0APAmX33WOQFGQrwLvlu7WLV4CFJMlB12b6ZSg+2q6fYu9kZwLCOA+x83zXfcPd1RpuWOKJW0GbBwLIQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT OR Apache-2.0",
+ "bin": {
+ "biome": "bin/biome"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/biome"
+ },
+ "optionalDependencies": {
+ "@biomejs/cli-darwin-arm64": "1.9.3",
+ "@biomejs/cli-darwin-x64": "1.9.3",
+ "@biomejs/cli-linux-arm64": "1.9.3",
+ "@biomejs/cli-linux-arm64-musl": "1.9.3",
+ "@biomejs/cli-linux-x64": "1.9.3",
+ "@biomejs/cli-linux-x64-musl": "1.9.3",
+ "@biomejs/cli-win32-arm64": "1.9.3",
+ "@biomejs/cli-win32-x64": "1.9.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.9.3.tgz",
+ "integrity": "sha512-QZzD2XrjJDUyIZK+aR2i5DDxCJfdwiYbUKu9GzkCUJpL78uSelAHAPy7m0GuPMVtF/Uo+OKv97W3P9nuWZangQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.9.3.tgz",
+ "integrity": "sha512-vSCoIBJE0BN3SWDFuAY/tRavpUtNoqiceJ5PrU3xDfsLcm/U6N93JSM0M9OAiC/X7mPPfejtr6Yc9vSgWlEgVw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.9.3.tgz",
+ "integrity": "sha512-vJkAimD2+sVviNTbaWOGqEBy31cW0ZB52KtpVIbkuma7PlfII3tsLhFa+cwbRAcRBkobBBhqZ06hXoZAN8NODQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.9.3.tgz",
+ "integrity": "sha512-VBzyhaqqqwP3bAkkBrhVq50i3Uj9+RWuj+pYmXrMDgjS5+SKYGE56BwNw4l8hR3SmYbLSbEo15GcV043CDSk+Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.9.3.tgz",
+ "integrity": "sha512-x220V4c+romd26Mu1ptU+EudMXVS4xmzKxPVb9mgnfYlN4Yx9vD5NZraSx/onJnd3Gh/y8iPUdU5CDZJKg9COA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64-musl": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.9.3.tgz",
+ "integrity": "sha512-TJmnOG2+NOGM72mlczEsNki9UT+XAsMFAOo8J0me/N47EJ/vkLXxf481evfHLlxMejTY6IN8SdRSiPVLv6AHlA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-arm64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.9.3.tgz",
+ "integrity": "sha512-lg/yZis2HdQGsycUvHWSzo9kOvnGgvtrYRgoCEwPBwwAL8/6crOp3+f47tPwI/LI1dZrhSji7PNsGKGHbwyAhw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-x64": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.9.3.tgz",
+ "integrity": "sha512-cQMy2zanBkVLpmmxXdK6YePzmZx0s5Z7KEnwmrW54rcXK3myCNbQa09SwGZ8i/8sLw0H9F3X7K4rxVNGU8/D4Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@bjorn3/browser_wasi_shim": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@bjorn3/browser_wasi_shim/-/browser_wasi_shim-0.3.0.tgz",
+ "integrity": "sha512-FlRBYttPRLcWORzBe6g8nmYTafBkOEFeOqMYM4tAHJzFsQy4+xJA94z85a9BCs8S+Uzfh9LrkpII7DXr2iUVFg==",
+ "license": "MIT OR Apache-2.0"
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@microsoft/api-extractor": {
+ "version": "7.47.7",
+ "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.47.7.tgz",
+ "integrity": "sha512-fNiD3G55ZJGhPOBPMKD/enozj8yxJSYyVJWxRWdcUtw842rvthDHJgUWq9gXQTensFlMHv2wGuCjjivPv53j0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@microsoft/api-extractor-model": "7.29.6",
+ "@microsoft/tsdoc": "~0.15.0",
+ "@microsoft/tsdoc-config": "~0.17.0",
+ "@rushstack/node-core-library": "5.7.0",
+ "@rushstack/rig-package": "0.5.3",
+ "@rushstack/terminal": "0.14.0",
+ "@rushstack/ts-command-line": "4.22.6",
+ "lodash": "~4.17.15",
+ "minimatch": "~3.0.3",
+ "resolve": "~1.22.1",
+ "semver": "~7.5.4",
+ "source-map": "~0.6.1",
+ "typescript": "5.4.2"
+ },
+ "bin": {
+ "api-extractor": "bin/api-extractor"
+ }
+ },
+ "node_modules/@microsoft/api-extractor-model": {
+ "version": "7.29.6",
+ "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.29.6.tgz",
+ "integrity": "sha512-gC0KGtrZvxzf/Rt9oMYD2dHvtN/1KPEYsrQPyMKhLHnlVuO/f4AFN3E4toqZzD2pt4LhkKoYmL2H9tX3yCOyRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@microsoft/tsdoc": "~0.15.0",
+ "@microsoft/tsdoc-config": "~0.17.0",
+ "@rushstack/node-core-library": "5.7.0"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/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,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/node_modules/minimatch": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
+ "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/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==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/node_modules/typescript": {
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
+ "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/@microsoft/api-extractor/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,
+ "license": "ISC"
+ },
+ "node_modules/@microsoft/tsdoc": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz",
+ "integrity": "sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@microsoft/tsdoc-config": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.0.tgz",
+ "integrity": "sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@microsoft/tsdoc": "0.15.0",
+ "ajv": "~8.12.0",
+ "jju": "~1.4.0",
+ "resolve": "~1.22.2"
+ }
+ },
+ "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",
+ "content-disposition": "^0.5.4",
+ "ext-name": "^5.0.0",
+ "file-type": "^17.1.6",
+ "filenamify": "^5.0.2",
+ "got": "^11.8.5",
+ "os-filter-obj": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/@napi-rs/nice": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz",
+ "integrity": "sha512-zM0mVWSXE0a0h9aKACLwKmD6nHcRiKrPpCfvaKqG1CqDEyjEawId0ocXxVzPMCAm6kkWr2P025msfxXEnt8UGQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 10"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "optionalDependencies": {
+ "@napi-rs/nice-android-arm-eabi": "1.0.1",
+ "@napi-rs/nice-android-arm64": "1.0.1",
+ "@napi-rs/nice-darwin-arm64": "1.0.1",
+ "@napi-rs/nice-darwin-x64": "1.0.1",
+ "@napi-rs/nice-freebsd-x64": "1.0.1",
+ "@napi-rs/nice-linux-arm-gnueabihf": "1.0.1",
+ "@napi-rs/nice-linux-arm64-gnu": "1.0.1",
+ "@napi-rs/nice-linux-arm64-musl": "1.0.1",
+ "@napi-rs/nice-linux-ppc64-gnu": "1.0.1",
+ "@napi-rs/nice-linux-riscv64-gnu": "1.0.1",
+ "@napi-rs/nice-linux-s390x-gnu": "1.0.1",
+ "@napi-rs/nice-linux-x64-gnu": "1.0.1",
+ "@napi-rs/nice-linux-x64-musl": "1.0.1",
+ "@napi-rs/nice-win32-arm64-msvc": "1.0.1",
+ "@napi-rs/nice-win32-ia32-msvc": "1.0.1",
+ "@napi-rs/nice-win32-x64-msvc": "1.0.1"
+ }
+ },
+ "node_modules/@napi-rs/nice-android-arm-eabi": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz",
+ "integrity": "sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-android-arm64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz",
+ "integrity": "sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-darwin-arm64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.0.1.tgz",
+ "integrity": "sha512-91k3HEqUl2fsrz/sKkuEkscj6EAj3/eZNCLqzD2AA0TtVbkQi8nqxZCZDMkfklULmxLkMxuUdKe7RvG/T6s2AA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-darwin-x64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz",
+ "integrity": "sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-freebsd-x64": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz",
+ "integrity": "sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-arm-gnueabihf": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz",
+ "integrity": "sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-arm64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz",
+ "integrity": "sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-arm64-musl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz",
+ "integrity": "sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-ppc64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz",
+ "integrity": "sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-riscv64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz",
+ "integrity": "sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-s390x-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz",
+ "integrity": "sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-x64-gnu": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz",
+ "integrity": "sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-linux-x64-musl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz",
+ "integrity": "sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-win32-arm64-msvc": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz",
+ "integrity": "sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-win32-ia32-msvc": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz",
+ "integrity": "sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@napi-rs/nice-win32-x64-msvc": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz",
+ "integrity": "sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@oligami/browser_wasi_shim-threads": {
+ "resolved": "",
+ "link": true
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz",
+ "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
+ "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
+ "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
+ "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
+ "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
+ "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
+ "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
+ "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
+ "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
+ "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
+ "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
+ "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
+ "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
+ "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
+ "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
+ "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
+ "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rushstack/node-core-library": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.7.0.tgz",
+ "integrity": "sha512-Ff9Cz/YlWu9ce4dmqNBZpA45AEya04XaBFIjV7xTVeEf+y/kTjEasmozqFELXlNG4ROdevss75JrrZ5WgufDkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "~8.13.0",
+ "ajv-draft-04": "~1.0.0",
+ "ajv-formats": "~3.0.1",
+ "fs-extra": "~7.0.1",
+ "import-lazy": "~4.0.0",
+ "jju": "~1.4.0",
+ "resolve": "~1.22.1",
+ "semver": "~7.5.4"
+ },
+ "peerDependencies": {
+ "@types/node": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rushstack/node-core-library/node_modules/ajv": {
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+ "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.4.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/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,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/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==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@rushstack/node-core-library/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,
+ "license": "ISC"
+ },
+ "node_modules/@rushstack/rig-package": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz",
+ "integrity": "sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve": "~1.22.1",
+ "strip-json-comments": "~3.1.1"
+ }
+ },
+ "node_modules/@rushstack/terminal": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.0.tgz",
+ "integrity": "sha512-juTKMAMpTIJKudeFkG5slD8Z/LHwNwGZLtU441l/u82XdTBfsP+LbGKJLCNwP5se+DMCT55GB8x9p6+C4UL7jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rushstack/node-core-library": "5.7.0",
+ "supports-color": "~8.1.1"
+ },
+ "peerDependencies": {
+ "@types/node": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rushstack/terminal/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/@rushstack/terminal/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/@rushstack/ts-command-line": {
+ "version": "4.22.6",
+ "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.22.6.tgz",
+ "integrity": "sha512-QSRqHT/IfoC5nk9zn6+fgyqOPXHME0BfchII9EUPR19pocsNp/xSbeBCbD3PIR2Lg+Q5qk7OFqk1VhWPMdKHJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rushstack/terminal": "0.14.0",
+ "@types/argparse": "1.0.38",
+ "argparse": "~1.0.9",
+ "string-argv": "~0.3.1"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@swc/cli": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.4.0.tgz",
+ "integrity": "sha512-4JdVrPtF/4rCMXp6Q1h5I6YkYZrCCcqod7Wk97ZQq7K8vNGzJUryBv4eHCvqx5sJOJBrbYm9fcswe1B0TygNoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@mole-inc/bin-wrapper": "^8.0.1",
+ "@swc/counter": "^0.1.3",
+ "commander": "^8.3.0",
+ "fast-glob": "^3.2.5",
+ "minimatch": "^9.0.3",
+ "piscina": "^4.3.0",
+ "semver": "^7.3.8",
+ "slash": "3.0.0",
+ "source-map": "^0.7.3"
+ },
+ "bin": {
+ "spack": "bin/spack.js",
+ "swc": "bin/swc.js",
+ "swcx": "bin/swcx.js"
+ },
+ "engines": {
+ "node": ">= 16.14.0"
+ },
+ "peerDependencies": {
+ "@swc/core": "^1.2.66",
+ "chokidar": "^3.5.1"
+ },
+ "peerDependenciesMeta": {
+ "chokidar": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.28.tgz",
+ "integrity": "sha512-XapcMgsOS0cKh01AFEj+qXOk6KM4NZhp7a5vPicdhkRR8RzvjrCa7DTtijMxfotU8bqaEHguxmiIag2HUlT8QQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3",
+ "@swc/types": "^0.1.12"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.7.28",
+ "@swc/core-darwin-x64": "1.7.28",
+ "@swc/core-linux-arm-gnueabihf": "1.7.28",
+ "@swc/core-linux-arm64-gnu": "1.7.28",
+ "@swc/core-linux-arm64-musl": "1.7.28",
+ "@swc/core-linux-x64-gnu": "1.7.28",
+ "@swc/core-linux-x64-musl": "1.7.28",
+ "@swc/core-win32-arm64-msvc": "1.7.28",
+ "@swc/core-win32-ia32-msvc": "1.7.28",
+ "@swc/core-win32-x64-msvc": "1.7.28"
+ },
+ "peerDependencies": {
+ "@swc/helpers": "*"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.28.tgz",
+ "integrity": "sha512-BNkj6enHo2pdzOpCtQGKZbXT2A/qWIr0CVtbTM4WkJ3MCK/glbFsyO6X59p1r8+gfaZG4bWYnTTu+RuUAcsL5g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.28.tgz",
+ "integrity": "sha512-96zQ+X5Fd6P/RNPkOyikTJgEc2M4TzznfYvjRd2hye5h22jhxCLL/csoauDgN7lYfd7mwsZ/sVXwJTMKl+vZSA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.28.tgz",
+ "integrity": "sha512-l2100Wx6LdXMOmOW3+KoHhBhyZrGdz8ylkygcVOC0QHp6YIATfuG+rRHksfyEWCSOdL3anM9MJZJX26KT/s+XQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.28.tgz",
+ "integrity": "sha512-03m6iQ5Bv9u2VPnNRyaBmE8eHi056eE39L0gXcqGoo46GAGuoqYHt9pDz8wS6EgoN4t85iBMUZrkCNqFKkN6ZQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.28.tgz",
+ "integrity": "sha512-vqVOpG/jc8mvTKQjaPBLhr7tnWyzuztOHsPnJqMWmg7zGcMeQC/2c5pU4uzRAfXMTp25iId6s4Y4wWfPS1EeDw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.28.tgz",
+ "integrity": "sha512-HGwpWuB83Kr+V0E+zT5UwIIY9OxiS8aLd0UVMRVWuO8SrQyKm9HKJ46+zoAb8tfJrpZftfxvbn2ayZWR7gqosA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.28.tgz",
+ "integrity": "sha512-q2Y2T8y8EgFtIiRyInnAXNe94aaHX74F0ha1Bl9VdRxE0u1/So+3VLbPvtp4V3Z6pj5pOePfCQJKifnllgAQ9A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.28.tgz",
+ "integrity": "sha512-bCqh4uBT/59h3dWK1v91In6qzz8rKoWoFRxCtNQLIK4jP55K0U231ZK9oN7neZD6bzcOUeFvOGgcyMAgDfFWfA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.28.tgz",
+ "integrity": "sha512-XTHbHrksnrqK3JSJ2sbuMWvdJ6/G0roRpgyVTmNDfhTYPOwcVaL/mSrPGLwbksYUbq7ckwoKzrobhdxvQzPsDA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.7.28",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.28.tgz",
+ "integrity": "sha512-jyXeoq6nX8abiCy2EpporsC5ywNENs4ocYuvxo1LSxDktWN1E2MTXq3cdJcEWB2Vydxq0rDcsGyzkRPMzFhkZw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@swc/types": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz",
+ "integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==",
+ "dev": true,
+ "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"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/@types/argparse": {
+ "version": "1.0.38",
+ "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz",
+ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==",
+ "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",
+ "@types/node": "*",
+ "@types/responselike": "^1.0.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/http-cache-semantics": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
+ "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": "22.7.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
+ "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.19.2"
+ }
+ },
+ "node_modules/@types/responselike": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
+ "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@typescript/lib-decorators": {
+ "name": "@better-typescript-lib/decorators",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/decorators/-/decorators-2.9.0.tgz",
+ "integrity": "sha512-l7JqR0EFD01ucYRILPuhcdxCcST+f3dSMj+/39gqjl1RdAIWtRGV2K2DOsqW4ye++A39In12++7LnaZLQZEVUQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-dom": {
+ "name": "@better-typescript-lib/dom",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/dom/-/dom-2.9.0.tgz",
+ "integrity": "sha512-UONr6zeUg5Inl4cNoSK9FgW2Hc0tjACSxKWs2ftgdaCmdokd4hZdqgEBiDyP5Xynx5UECNXA7krLGbHi9VUR3w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2015": {
+ "name": "@better-typescript-lib/es2015",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2015/-/es2015-2.9.0.tgz",
+ "integrity": "sha512-l/2PVV8bE/1jg0lvdodrxXX/vu2iiPNUjkcyuhXMLIKk4r48Pka1G87TisXtF4fptWEcqrry9C2fSuwVj59jSA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2016": {
+ "name": "@better-typescript-lib/es2016",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2016/-/es2016-2.9.0.tgz",
+ "integrity": "sha512-87jtcF08MkmJe3+hTjhP/SPz167O5A6PyldG8+1jOvEA23aUNTezpXEt0Y91g295qGwg6U3ATyOcJ6h5PzZEYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2017": {
+ "name": "@better-typescript-lib/es2017",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2017/-/es2017-2.9.0.tgz",
+ "integrity": "sha512-245luMwR3nBlg/q2qzqnkqS/ZbJuNoeAVeriAu4QzUwIXDQxBteawJwiB8qO8EgYgAWhvPJUZzhqUJyYrCBAtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2018": {
+ "name": "@better-typescript-lib/es2018",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2018/-/es2018-2.9.0.tgz",
+ "integrity": "sha512-6pqeRyMwg2ub5VxY3TA7IbfqTNxY1oVw06DEskpnXuvsA5lSDhZVQxhegCryf8dsRbL2SY+JsDvqGPz2BB8qYA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2019": {
+ "name": "@better-typescript-lib/es2019",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2019/-/es2019-2.9.0.tgz",
+ "integrity": "sha512-8iT42/M3E93gsAL9wsB+nU39UBe1syLUHfxoGdlx9zLZw8vNnLxKmpFTO2vC2BVBWTTB5ZkLKtlg6+UaYiqQZg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2020": {
+ "name": "@better-typescript-lib/es2020",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2020/-/es2020-2.9.0.tgz",
+ "integrity": "sha512-1j4kkZQALxXRZ4yxszf8+GfrILq+Gt4cFNWTfLzdlm5cGmoWWbWci81HsudbvveWqfNKaSKcQIY5Z9bVrQCyeg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2021": {
+ "name": "@better-typescript-lib/es2021",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2021/-/es2021-2.9.0.tgz",
+ "integrity": "sha512-mA1VcDvXzkekL646fZ/AazRQwuG6reyuHf3kL5B5Wn/HeihfwHh96FGSblaQWyDwoTZjUTP0s9m7Mtj5SgGxGQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2022": {
+ "name": "@better-typescript-lib/es2022",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2022/-/es2022-2.9.0.tgz",
+ "integrity": "sha512-iDUAglx7axyGVlGrEk6gnzIYZK4drnu59OvHFieeg2dMyc1EJEedsmL9jK9XJcahZtpt/JEPqWJnE5os+N4Rgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es2023": {
+ "name": "@better-typescript-lib/es2023",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es2023/-/es2023-2.9.0.tgz",
+ "integrity": "sha512-OhFg1gIoO1IXdcWexLiFUpNiMeI54eSxi5p/r+VQgqbXtwqa2DvC17hR0kV1w6axjUsb/PFc8rAordS23xdb2A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es5": {
+ "name": "@better-typescript-lib/es5",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es5/-/es5-2.9.0.tgz",
+ "integrity": "sha512-jP76ajsZgAuMl1iaSGjFct70RwPeWkohAb7p6FgT9QG+KOpiXjZLLmRX2iRTnhib2pgoEvafuHjXOiqNmFYO+A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-es6": {
+ "name": "@better-typescript-lib/es6",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/es6/-/es6-2.9.0.tgz",
+ "integrity": "sha512-Xczl4Z43CFkjXCEqrD2K2W1/Wh4RUYVS8IU6eC21H2zZK1G3znTPo2BG3H5N5MncyvTGdiyExRLGo7jUfWgMAA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-esnext": {
+ "name": "@better-typescript-lib/esnext",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/esnext/-/esnext-2.9.0.tgz",
+ "integrity": "sha512-G2xT/xJkpXlXQK8kCBy2yueMQvFBH8fXp/pTi+snMH11NrH1tOmX9bFnskQmATE4tTzlsc6PBxY19/8oxF5UQA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-scripthost": {
+ "name": "@better-typescript-lib/scripthost",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/scripthost/-/scripthost-2.9.0.tgz",
+ "integrity": "sha512-NlW35v/PbGCB6K1eqep3u5ckUbTS2LzF+tGoOxHRtgeRdLaLi0G9s9CJOT5a5Yl1X2gAogqT2KQMPyLeN4JcYw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@typescript/lib-webworker": {
+ "name": "@better-typescript-lib/webworker",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@better-typescript-lib/webworker/-/webworker-2.9.0.tgz",
+ "integrity": "sha512-3jRXXzU9N8cQ6wdLKGoiCU0qBgxcmO9ALAYAe++IJqjXb1e1jaoKrA6LQO2xboy4UhbFwxyfKcr3Hl68EzTMqw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.6.tgz",
+ "integrity": "sha512-FxUfxaB8sCqvY46YjyAAV6c3mMIq/NWQMVvJ+uS4yxr1KzOvyg61gAuOnNvgCvO4TZ7HcLExBEsWcDu4+K4E8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.6"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.6.tgz",
+ "integrity": "sha512-Nsh7UW2ruK+uURIPzjJgF0YRGP5CX9nQHypA2OMqdM2FKy7rh+uv3XgPnWPw30JADbKvZ5HuBzG4gSbVDYVtiw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.6.tgz",
+ "integrity": "sha512-NMIrA7y5OOqddL9VtngPWYmdQU03htNKFtAYidbYfWA0TOhyGVd9tfcP4TsLWQ+RBWDZCbBqsr8xzU0ZOxYTCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.6",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.11",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.11.tgz",
+ "integrity": "sha512-PwAdxs7/9Hc3ieBO12tXzmTD+Ln4qhT/56S+8DvrrZ4kLDn4Z/AMUr8tXJD0axiJBS0RKIoNaR0yMuQB9v9Udg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.3",
+ "@vue/shared": "3.5.11",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.11",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.11.tgz",
+ "integrity": "sha512-pyGf8zdbDDRkBrEzf8p7BQlMKNNF5Fk/Cf/fQ6PiUz9at4OaUfyXW0dGJTo2Vl1f5U9jSLCNf0EZJEogLXoeew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.11",
+ "@vue/shared": "3.5.11"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+ "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/language-core": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.6.tgz",
+ "integrity": "sha512-MW569cSky9R/ooKMh6xa2g1D0AtRKbL56k83dzus/bx//RDJk24RHWkMzbAlXjMdDNyxAaagKPRquBIxkxlCkg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "~2.4.1",
+ "@vue/compiler-dom": "^3.4.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.4.0",
+ "computeds": "^0.0.1",
+ "minimatch": "^9.0.3",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.11",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.11.tgz",
+ "integrity": "sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/better-typescript-lib": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/better-typescript-lib/-/better-typescript-lib-2.9.0.tgz",
+ "integrity": "sha512-wW/QvxcVu2qscos4u6Gbq61yKaAe3SuxBrPKefucxkXaBVJld5tG5Ba22btKbW+VW590UB5k7AvoAZcG+ktdZQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@typescript/lib-decorators": "npm:@better-typescript-lib/decorators@2.9.0",
+ "@typescript/lib-dom": "npm:@better-typescript-lib/dom@2.9.0",
+ "@typescript/lib-es2015": "npm:@better-typescript-lib/es2015@2.9.0",
+ "@typescript/lib-es2016": "npm:@better-typescript-lib/es2016@2.9.0",
+ "@typescript/lib-es2017": "npm:@better-typescript-lib/es2017@2.9.0",
+ "@typescript/lib-es2018": "npm:@better-typescript-lib/es2018@2.9.0",
+ "@typescript/lib-es2019": "npm:@better-typescript-lib/es2019@2.9.0",
+ "@typescript/lib-es2020": "npm:@better-typescript-lib/es2020@2.9.0",
+ "@typescript/lib-es2021": "npm:@better-typescript-lib/es2021@2.9.0",
+ "@typescript/lib-es2022": "npm:@better-typescript-lib/es2022@2.9.0",
+ "@typescript/lib-es2023": "npm:@better-typescript-lib/es2023@2.9.0",
+ "@typescript/lib-es5": "npm:@better-typescript-lib/es5@2.9.0",
+ "@typescript/lib-es6": "npm:@better-typescript-lib/es6@2.9.0",
+ "@typescript/lib-esnext": "npm:@better-typescript-lib/esnext@2.9.0",
+ "@typescript/lib-scripthost": "npm:@better-typescript-lib/scripthost@2.9.0",
+ "@typescript/lib-webworker": "npm:@better-typescript-lib/webworker@2.9.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.5.2"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bin-version-check": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz",
+ "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bin-version": "^6.0.0",
+ "semver": "^7.5.3",
+ "semver-truncate": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "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,
+ "license": "MIT",
+ "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",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/bin-version/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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bin-version/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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bin-version/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"
+ },
+ "engines": {
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "MIT",
+ "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,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
+ "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^6.0.1",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=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"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/compare-versions": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz",
+ "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/computeds": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz",
+ "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/confbox": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+ "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"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/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/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "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",
+ "token-types": "^5.0.0-alpha.2"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/file-type?sponsor=1"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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",
+ "trim-repeated": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=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"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "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",
+ "@types/cacheable-request": "^6.0.1",
+ "@types/responselike": "^1.0.0",
+ "cacheable-lookup": "^5.0.3",
+ "cacheable-request": "^7.0.2",
+ "decompress-response": "^6.0.0",
+ "http2-wrapper": "^1.0.0-beta.5.2",
+ "lowercase-keys": "^2.0.0",
+ "p-cancelable": "^2.0.0",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/got?sponsor=1"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "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,
+ "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"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "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": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/import-lazy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
+ "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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,
+ "license": "ISC"
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
+ "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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-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,
+ "license": "ISC"
+ },
+ "node_modules/jju": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
+ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/kolorist": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
+ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/load-tsconfig": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz",
+ "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/local-pkg": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "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"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.11",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
+ "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
+ "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,
+ "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.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.53.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.53.0.tgz",
+ "integrity": "sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==",
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "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/mlly": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.2.tgz",
+ "integrity": "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "pathe": "^1.1.2",
+ "pkg-types": "^1.2.0",
+ "ufo": "^1.5.4"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
+ "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/nodemon/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/npm-watch": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.13.0.tgz",
+ "integrity": "sha512-MYcgocqCzYA44feZhFoYj69FfSaO0EeRE1gcRcmPaXIpNhUMAhNJ1pwic2C4Hn0OPOQmZKSl90CPgmwvOsVhTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "nodemon": "^3.0.1",
+ "through2": "^4.0.2"
+ },
+ "bin": {
+ "npm-watch": "cli.js"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/peek-readable": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.2.0.tgz",
+ "integrity": "sha512-U94a+eXHzct7vAd19GH3UQ2dH4Satbng0MyYTMaQatL0pvYYL5CTPR25HBhKtecl+4bfu1/i3vC6k0hydO5Vcw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "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/piscina": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.7.0.tgz",
+ "integrity": "sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "@napi-rs/nice": "^1.0.1"
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz",
+ "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.7",
+ "mlly": "^1.7.1",
+ "pathe": "^1.1.2"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "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,
+ "license": "ISC"
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pump": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
+ "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "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": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.24.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
+ "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.24.0",
+ "@rollup/rollup-android-arm64": "4.24.0",
+ "@rollup/rollup-darwin-arm64": "4.24.0",
+ "@rollup/rollup-darwin-x64": "4.24.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.24.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.24.0",
+ "@rollup/rollup-linux-arm64-musl": "4.24.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.24.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-gnu": "4.24.0",
+ "@rollup/rollup-linux-x64-musl": "4.24.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.24.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.24.0",
+ "@rollup/rollup-win32-x64-msvc": "4.24.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "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": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "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": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/semver-truncate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz",
+ "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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,
+ "license": "ISC"
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "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/string-argv": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
+ "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.19"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strtok3": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.1.1.tgz",
+ "integrity": "sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tokenizer/token": "^0.3.0",
+ "peek-readable": "^5.1.3"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "3"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Borewit"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "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"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
+ "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undici-types": {
+ "version": "6.19.8",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
+ "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/unplugin": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.14.1.tgz",
+ "integrity": "sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.12.1",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "webpack-sources": "^3"
+ },
+ "peerDependenciesMeta": {
+ "webpack-sources": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unplugin-swc": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/unplugin-swc/-/unplugin-swc-1.5.1.tgz",
+ "integrity": "sha512-/ZLrPNjChhGx3Z95pxJ4tQgfI6rWqukgYHKflrNB4zAV1izOQuDhkTn55JWeivpBxDCoK7M/TStb2aS/14PS/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.1.0",
+ "load-tsconfig": "^0.2.5",
+ "unplugin": "^1.11.0"
+ },
+ "peerDependencies": {
+ "@swc/core": "^1.2.108"
+ }
+ },
+ "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,
+ "license": "MIT"
+ },
+ "node_modules/vite": {
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz",
+ "integrity": "sha512-FqrItQ4DT1NC4zCUqMB4c4AZORMKIa0m8/URVCZ77OZ/QSNeJ54bU1vrFADbDsuwfIPcgknRkmqakQcgnL4GiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-dts": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.2.3.tgz",
+ "integrity": "sha512-O5NalzHANQRwVw1xj8KQun3Bv8OSDAlNJXrnqoAz10BOuW8FVvY5g4ygj+DlJZL5mtSPuMu9vd3OfrdW5d4k6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@microsoft/api-extractor": "7.47.7",
+ "@rollup/pluginutils": "^5.1.0",
+ "@volar/typescript": "^2.4.4",
+ "@vue/language-core": "2.1.6",
+ "compare-versions": "^6.1.1",
+ "debug": "^4.3.6",
+ "kolorist": "^1.8.0",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.11"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "typescript": "*",
+ "vite": "*"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
+ "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/webpack-virtual-modules": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+ "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==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "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,
+ "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,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/threads/package.json b/threads/package.json
new file mode 100644
index 0000000..7ac794d
--- /dev/null
+++ b/threads/package.json
@@ -0,0 +1,74 @@
+{
+ "name": "@oligami/browser_wasi_shim-threads",
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "npm run worker && vite build",
+ "prepare": "npm run build",
+ "fmt": "biome format --write .",
+ "lint": "biome lint src examples import-module-test",
+ "check": "biome check && tsc --noEmit",
+ "worker": "spack --config ./src/shared_array_buffer/worker_background/spack.config.cjs && node src/shared_array_buffer/worker_background/minify.js",
+ "watch": "npm-watch worker"
+ },
+ "watch": {
+ "worker": "src/shared_array_buffer/worker_background/*.ts"
+ },
+ "devDependencies": {
+ "@biomejs/biome": "1.9.3",
+ "@swc/cli": "^0.4.0",
+ "@swc/core": "^1.7.28",
+ "better-typescript-lib": "^2.8.0",
+ "npm-watch": "^0.13.0",
+ "typescript": "^5.6.2",
+ "unplugin-swc": "^1.5.1",
+ "vite": "^5.4.8",
+ "vite-plugin-dts": "^4.2.3"
+ },
+ "dependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0",
+ "@oligami/browser_wasi_shim-threads": "file:"
+ },
+ "peerDependencies": {
+ "@bjorn3/browser_wasi_shim": "^0.3.0"
+ },
+ "private": false,
+ "publishConfig": {
+ "access": "public"
+ },
+ "author": "oligami (https://github.com/oligamiq)",
+ "license": "MIT OR Apache-2.0",
+ "description": "A pure javascript shim for WASI with support for threads",
+ "homepage": "https://github.com/bjorn3/browser_wasi_shim/tree/main/threads#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/bjorn3/browser_wasi_shim.git"
+ },
+ "bugs": {
+ "url": "https://github.com/bjorn3/browser_wasi_shim/issues"
+ },
+ "main": "./dist/browser-wasi-shim-threads.es.js",
+ "types": "./dist/index.d.ts",
+ "exports": {
+ ".": {
+ "import": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/browser-wasi-shim-threads.es.js"
+ },
+ "require": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/browser-wasi-shim-threads.cjs.js"
+ },
+ "node": {
+ "types": "./dist/index.d.ts",
+ "default": "./dist/browser-wasi-shim-threads.cjs.js"
+ },
+ "types": "./dist/index.d.ts",
+ "default": "./dist/browser-wasi-shim-threads.es.js"
+ }
+ },
+ "files": ["dist", "src"],
+ "module": "dist/browser-wasi-shim-threads.es.js",
+ "keywords": ["wasi", "webassembly", "threads", "worker", "webworker"]
+}
diff --git a/threads/src/animals.ts b/threads/src/animals.ts
new file mode 100644
index 0000000..1282977
--- /dev/null
+++ b/threads/src/animals.ts
@@ -0,0 +1,1322 @@
+import { WASIProcExit } from "@bjorn3/browser_wasi_shim";
+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";
+import { wasi } from "@bjorn3/browser_wasi_shim";
+
+export class WASIFarmAnimal {
+ args: Array;
+ env: Array;
+
+ private wasi_farm_refs: WASIFarmRef[];
+
+ private id_in_wasi_farm_ref: Array;
+
+ inst: { exports: { memory: WebAssembly.Memory } } | undefined;
+ // biome-ignore lint/suspicious/noExplicitAny:
+ wasiImport: { [key: string]: (...args: Array) => unknown };
+
+ wasiThreadImport: {
+ "thread-spawn": (start_arg: 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) {
+ if (!this.thread_spawner) {
+ throw new Error("thread_spawner is not defined");
+ }
+ this.thread_spawner.done_notify(0);
+ }
+
+ return 0;
+ } catch (e) {
+ if (e instanceof WASIProcExit) {
+ if (this.can_thread_spawn) {
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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 || !this.thread_spawner) {
+ 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.fd_map,
+ );
+
+ const code = await this.thread_spawner.async_wait_done_or_error();
+
+ return code;
+ }
+
+ block_start_on_thread(): number {
+ if (!this.can_thread_spawn || !this.thread_spawner) {
+ 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.fd_map);
+
+ 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] as unknown as Array<
+ [number, number]
+ >;
+
+ // console.log("wasi_farm_refs", wasi_farm_refs);
+ for (let i = 0; i < wasi_farm_refs.length; i++) {
+ // console.log("fd_map", [...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("this.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 as Array<[number, number] | undefined>).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;
+ }
+
+ // @ts-ignore
+ 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];
+ if (!fd_and_wasi_ref_n) {
+ continue;
+ }
+ 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 as Array<[number, number] | undefined>)[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 {
+ if (!this.thread_spawner) {
+ throw new Error("thread_spawner is not defined");
+ }
+
+ return this.thread_spawner.get_share_memory();
+ }
+
+ constructor(
+ wasi_farm_refs: WASIFarmRefObject[] | WASIFarmRefObject,
+ args: Array,
+ env: Array,
+ options: {
+ can_thread_spawn?: boolean;
+ thread_spawn_worker_url?: string;
+ thread_spawn_wasm?: WebAssembly.Module;
+ hand_override_fd_map?: Array<[number, number]>;
+ } = {},
+ override_fd_maps?: Array,
+ thread_spawner?: ThreadSpawner,
+ ) {
+ 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();
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+ return 0;
+ },
+ args_get(argv: number, argv_buf: number): number {
+ self.check_fds();
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer8 = new Uint8Array(self.inst!.exports.memory.buffer);
+ for (let i = 0; i < self.args.length; i++) {
+ buffer.setUint32(argv, argv_buf, true);
+ // biome-ignore lint/style/noParameterAssign:
+ argv += 4;
+ const arg = new TextEncoder().encode(self.args[i]);
+ buffer8.set(arg, argv_buf);
+ buffer.setUint8(argv_buf + arg.length, 0);
+ // biome-ignore lint/style/noParameterAssign:
+ argv_buf += arg.length + 1;
+ }
+ return 0;
+ },
+ environ_sizes_get(environ_count: number, environ_size: number): number {
+ self.check_fds();
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+ return 0;
+ },
+ environ_get(environ: number, environ_buf: number): number {
+ self.check_fds();
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer8 = new Uint8Array(self.inst!.exports.memory.buffer);
+ for (let i = 0; i < self.env.length; i++) {
+ buffer.setUint32(environ, environ_buf, true);
+ // biome-ignore lint/style/noParameterAssign:
+ environ += 4;
+ const e = new TextEncoder().encode(self.env[i]);
+ buffer8.set(e, environ_buf);
+ buffer.setUint8(environ_buf + e.length, 0);
+ // biome-ignore lint/style/noParameterAssign:
+ environ_buf += e.length + 1;
+ }
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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();
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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(
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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(
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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];
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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 as Array<[number, number] | undefined>)[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) {
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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) {
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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];
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ const buffer = new DataView(self.inst!.exports.memory.buffer);
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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];
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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];
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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,
+ );
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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];
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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) {
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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;
+ }
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+ },
+ 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(
+ // biome-ignore lint/style/noNonNullAssertion:
+ self.inst!.exports.memory.buffer,
+ ).subarray(buf, buf + buf_len);
+
+ if (
+ "crypto" in globalThis &&
+ // biome-ignore lint/style/noNonNullAssertion:
+ !(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 || !self.thread_spawner) {
+ 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,
+ );
+
+ return thread_id;
+ },
+ };
+ }
+}
diff --git a/threads/src/farm.ts b/threads/src/farm.ts
new file mode 100644
index 0000000..f2455dc
--- /dev/null
+++ b/threads/src/farm.ts
@@ -0,0 +1,109 @@
+import type { Fd } from "@bjorn3/browser_wasi_shim";
+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: boolean;
+
+ constructor(
+ stdin?: Fd,
+ stdout?: Fd,
+ stderr?: Fd,
+ fds: Array = [],
+ options: {
+ allocator_size?: number;
+ } = {},
+ ) {
+ 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 (
+ !(globalThis as unknown as { crossOriginIsolated: unknown })
+ .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) => {
+ if (prop === "push") {
+ return (fd: Fd) => {
+ const len = this.fds.push(fd);
+ return len;
+ };
+ }
+ // @ts-ignore
+ return this.fds[prop];
+ },
+
+ set: (_, prop, value) => {
+ // @ts-ignore
+ this.fds[prop] = value;
+ return true;
+ },
+ });
+
+ return fds;
+ }
+
+ get_ref(): WASIFarmRefObject {
+ return this.park.get_ref();
+ }
+}
diff --git a/threads/src/index.ts b/threads/src/index.ts
new file mode 100644
index 0000000..f5ec1d6
--- /dev/null
+++ b/threads/src/index.ts
@@ -0,0 +1,5 @@
+import { WASIFarmAnimal } from "./animals.js";
+import { WASIFarm } from "./farm.js";
+import { WASIFarmRef } from "./ref.js";
+export { thread_spawn_on_worker } from "./shared_array_buffer/index.js";
+export { WASIFarm, WASIFarmRef, WASIFarmAnimal };
diff --git a/threads/src/park.ts b/threads/src/park.ts
new file mode 100644
index 0000000..b652648
--- /dev/null
+++ b/threads/src/park.ts
@@ -0,0 +1,593 @@
+import { type Fd, wasi } from "@bjorn3/browser_wasi_shim";
+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 as Array).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 as Array)[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();
+
+ // biome-ignore lint/style/noParameterAssign:
+ 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) {
+ // @ts-ignore
+ ({ 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) {
+ 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: ", 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);
+
+ if (!fd_obj) {
+ throw "fd_obj should not be null";
+ }
+
+ this.fds[opened_fd] = fd_obj;
+
+ 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) {
+ 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(
+ _old_path: string,
+ fd: number,
+ _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;
+ }
+}
diff --git a/threads/src/polyfill.js b/threads/src/polyfill.js
new file mode 100644
index 0000000..bde01dd
--- /dev/null
+++ b/threads/src/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/threads/src/ref.ts b/threads/src/ref.ts
new file mode 100644
index 0000000..a7dce7f
--- /dev/null
+++ b/threads/src/ref.ts
@@ -0,0 +1,186 @@
+import type { FdCloseSender } from "./sender.js";
+import type { wasi } from "@bjorn3/browser_wasi_shim";
+
+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): void;
+
+ 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 | undefined, 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 | undefined, 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;
+}
diff --git a/threads/src/sender.ts b/threads/src/sender.ts
new file mode 100644
index 0000000..ed9d30a
--- /dev/null
+++ b/threads/src/sender.ts
@@ -0,0 +1,4 @@
+export interface FdCloseSender {
+ send(targets: Array, fd: number): Promise;
+ get(id: number): Array | undefined;
+}
diff --git a/threads/src/shared_array_buffer/allocator.ts b/threads/src/shared_array_buffer/allocator.ts
new file mode 100644
index 0000000..98ed3db
--- /dev/null
+++ b/threads/src/shared_array_buffer/allocator.ts
@@ -0,0 +1,211 @@
+// @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);
+ }
+
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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(_pointer: number, _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/threads/src/shared_array_buffer/fd_close_sender.ts b/threads/src/shared_array_buffer/fd_close_sender.ts
new file mode 100644
index 0000000..a137e77
--- /dev/null
+++ b/threads/src/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/threads/src/shared_array_buffer/index.ts b/threads/src/shared_array_buffer/index.ts
new file mode 100644
index 0000000..0e2d34a
--- /dev/null
+++ b/threads/src/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/threads/src/shared_array_buffer/park.ts b/threads/src/shared_array_buffer/park.ts
new file mode 100644
index 0000000..cd77671
--- /dev/null
+++ b/threads/src/shared_array_buffer/park.ts
@@ -0,0 +1,1000 @@
+import { type Fd, wasi } from "@bjorn3/browser_wasi_shim";
+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
+ // @ts-ignore
+ 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 as Array | undefined>)[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);
+ const [nread_and_buffer, error] = this.fd_pread(fd, iovecs, offset);
+ const [nread, buffer8] = nread_and_buffer ?? [undefined, undefined];
+
+ 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_and_buffer, error] = this.fd_read(fd, iovecs);
+ const [nread, buffer8] = nread_and_buffer ?? [undefined, undefined];
+
+ // 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_and_buf_used, error] = this.fd_readdir(
+ fd,
+ buf_len,
+ cookie,
+ );
+ const [array, buf_used] = array_and_buf_used ?? [
+ undefined,
+ undefined,
+ ];
+
+ 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", 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;
+ }
+ 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/threads/src/shared_array_buffer/ref.ts b/threads/src/shared_array_buffer/ref.ts
new file mode 100644
index 0000000..55d6503
--- /dev/null
+++ b/threads/src/shared_array_buffer/ref.ts
@@ -0,0 +1,1411 @@
+import { wasi } from "@bjorn3/browser_wasi_shim";
+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);
+ if (fd1 === fd2) {
+ this.lock_fd(fd1);
+ return;
+ }
+ 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);
+ if (fd1 === fd2) {
+ this.release_fd(fd1);
+ return;
+ }
+ 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 false;
+ }
+ 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;
+ }
+}
diff --git a/threads/src/shared_array_buffer/sender.ts b/threads/src/shared_array_buffer/sender.ts
new file mode 100644
index 0000000..510df3a
--- /dev/null
+++ b/threads/src/shared_array_buffer/sender.ts
@@ -0,0 +1,223 @@
+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,
+ // biome-ignore lint/style/noNonNullAssertion:
+ max_share_arrays_memory: sl.share_arrays_memory!.byteLength,
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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/threads/src/shared_array_buffer/serialize_error.ts b/threads/src/shared_array_buffer/serialize_error.ts
new file mode 100644
index 0000000..fe78306
--- /dev/null
+++ b/threads/src/shared_array_buffer/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/threads/src/shared_array_buffer/thread_spawn.ts b/threads/src/shared_array_buffer/thread_spawn.ts
new file mode 100644
index 0000000..835e90c
--- /dev/null
+++ b/threads/src/shared_array_buffer/thread_spawn.ts
@@ -0,0 +1,418 @@
+// (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 { 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_object = worker_background_ref_object;
+ this.worker_background_ref = WorkerBackgroundRef.init_self(
+ this.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]>,
+ ): 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,
+ },
+ );
+
+ const thread_id = worker.get_id();
+
+ return thread_id;
+ }
+
+ async async_start_on_thread(
+ args: Array,
+ env: Array,
+ fd_map: Array<[number, number]>,
+ ): 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,
+ fd_map,
+ },
+ );
+ }
+
+ block_start_on_thread(
+ args: Array,
+ env: Array,
+ fd_map: Array<[number, number]>,
+ ): 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,
+ fd_map,
+ },
+ );
+ }
+
+ 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][];
+ this_is_start?: boolean;
+}): Promise => {
+ if (msg.this_is_thread_spawn) {
+ const {
+ sl_object,
+ fd_map,
+ worker_background_ref,
+ thread_spawn_wasm,
+ args,
+ env,
+ } = msg;
+
+ 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 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 thread_spawner = ThreadSpawner.init_self_with_worker_background_ref(
+ sl_object,
+ worker_background_ref,
+ );
+
+ if (msg.this_is_start) {
+ const wasi = new WASIFarmAnimal(
+ sl_object.wasi_farm_refs_object,
+ args,
+ env,
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: sl_object.worker_url,
+ hand_override_fd_map: fd_map,
+ },
+ override_fd_map,
+ thread_spawner,
+ );
+
+ const inst = await WebAssembly.instantiate(thread_spawn_wasm, {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ 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 } = msg;
+
+ console.log(`thread_spawn worker ${thread_id} start`);
+
+ const wasi = new WASIFarmAnimal(
+ sl_object.wasi_farm_refs_object,
+ args,
+ env,
+ {
+ can_thread_spawn: true,
+ thread_spawn_worker_url: sl_object.worker_url,
+ hand_override_fd_map: fd_map,
+ },
+ override_fd_map,
+ thread_spawner,
+ );
+
+ const inst = await WebAssembly.instantiate(thread_spawn_wasm, {
+ env: {
+ memory: wasi.get_share_memory(),
+ },
+ wasi: wasi.wasiThreadImport,
+ wasi_snapshot_preview1: wasi.wasiImport,
+ });
+
+ 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;
+ };
+ },
+ // biome-ignore lint/style/noNonNullAssertion:
+ thread_id!,
+ start_arg,
+ );
+ } catch (e) {
+ globalThis.postMessage({
+ msg: "error",
+ error: e,
+ });
+
+ return wasi;
+ }
+
+ globalThis.postMessage({
+ msg: "done",
+ });
+
+ return wasi;
+ }
+};
diff --git a/threads/src/shared_array_buffer/util.ts b/threads/src/shared_array_buffer/util.ts
new file mode 100644
index 0000000..4ed230f
--- /dev/null
+++ b/threads/src/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/threads/src/shared_array_buffer/worker_background/index.ts b/threads/src/shared_array_buffer/worker_background/index.ts
new file mode 100644
index 0000000..eb3e67c
--- /dev/null
+++ b/threads/src/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/threads/src/shared_array_buffer/worker_background/minify.js b/threads/src/shared_array_buffer/worker_background/minify.js
new file mode 100644
index 0000000..9f4435e
--- /dev/null
+++ b/threads/src/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/shared_array_buffer/worker_background/worker_blob.ts",
+ wrapper_code,
+ "utf8",
+);
diff --git a/threads/src/shared_array_buffer/worker_background/spack.config.cjs b/threads/src/shared_array_buffer/worker_background/spack.config.cjs
new file mode 100644
index 0000000..9e285a2
--- /dev/null
+++ b/threads/src/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/threads/src/shared_array_buffer/worker_background/worker.ts b/threads/src/shared_array_buffer/worker_background/worker.ts
new file mode 100644
index 0000000..a1bdfe4
--- /dev/null
+++ b/threads/src/shared_array_buffer/worker_background/worker.ts
@@ -0,0 +1,299 @@
+///
+
+// 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;
+
+ // worker_id starts from 1
+ private workers: Array = [undefined];
+
+ private start_worker?: Worker;
+
+ // @ts-ignore
+ 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 gen_worker = () => {
+ console.log("gen_worker");
+ 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;
+ return new Worker(url, {
+ type: is_module ? "module" : "classic",
+ });
+ };
+
+ // biome-ignore lint/complexity/noBannedTypes:
+ const gen_obj = (): Object => {
+ console.log("gen_obj");
+ 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);
+ // biome-ignore lint/complexity/noBannedTypes:
+ return JSON.parse(json) as Object;
+ };
+
+ const signature_input = Atomics.load(signature_input_view, 0);
+ switch (signature_input) {
+ // create new worker
+ case 1: {
+ const worker = gen_worker();
+ const obj = gen_obj();
+
+ 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") {
+ // biome-ignore lint/style/noNonNullAssertion:
+ this.workers[worker_id]!.terminate();
+ this.workers[worker_id] = undefined;
+
+ console.log(`worker ${worker_id} done so terminate`);
+ }
+
+ if (msg === "error") {
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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: {
+ this.start_worker = gen_worker();
+ const obj = gen_obj();
+
+ 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++;
+ }
+
+ // biome-ignore lint/style/noNonNullAssertion:
+ 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);
+
+ // sleep 1000
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ }
+ }
+}
+
+// @ts-ignore
+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/threads/src/shared_array_buffer/worker_background/worker_background_ref.ts b/threads/src/shared_array_buffer/worker_background/worker_background_ref.ts
new file mode 100644
index 0000000..17e9924
--- /dev/null
+++ b/threads/src/shared_array_buffer/worker_background/worker_background_ref.ts
@@ -0,0 +1,314 @@
+import { AllocatorUseArrayBuffer } from "../allocator.js";
+import type {
+ WorkerBackgroundRefObject,
+ WorkerOptions,
+} from "./worker_export.js";
+import * as Serializer from "../serialize_error.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/threads/src/shared_array_buffer/worker_background/worker_blob.ts b/threads/src/shared_array_buffer/worker_background/worker_blob.ts
new file mode 100644
index 0000000..b47847b
--- /dev/null
+++ b/threads/src/shared_array_buffer/worker_background/worker_blob.ts
@@ -0,0 +1,10 @@
+export const url = () => {
+ const code =
+ 'let worker_background;let serialize=r=>({message:r.message,name:r.name,stack:r.stack,cause:r.cause});class AllocatorUseArrayBuffer{share_arrays_memory;constructor(r=new SharedArrayBuffer(0xa00000)){this.share_arrays_memory=r;let e=new Int32Array(this.share_arrays_memory);Atomics.store(e,0,0),Atomics.store(e,1,0),Atomics.store(e,2,12)}static init_self(r){return new AllocatorUseArrayBuffer(r.share_arrays_memory)}async async_write(r,e,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(r,e,t);return Atomics.store(o,0,0),Atomics.notify(o,0,1),i}}block_write(r,e,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(r,e,t);return Atomics.store(o,0,0),Atomics.notify(o,0,1),s}}write_inner(r,e,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,l=r.byteLength,c=o+l;if(n{console.log("gen_worker");let r=Atomics.load(e,1),t=Atomics.load(e,2),o=this.allocator.get_memory(r,t);this.allocator.free(r,t);let s=new TextDecoder().decode(o),i=1===Atomics.load(e,3);return new Worker(s,{type:i?"module":"classic"})},a=()=>{console.log("gen_obj");let r=Atomics.load(e,4),t=Atomics.load(e,5),o=this.allocator.get_memory(r,t);this.allocator.free(r,t);let s=new TextDecoder().decode(o);return JSON.parse(s)};switch(Atomics.load(e,0)){case 1:{let r=i(),t=a(),o=this.assign_worker_id();console.log("new worker "+o),this.workers[o]=r;let{promise:s,resolve:n}=Promise.withResolvers();r.onmessage=async r=>{let{msg:e}=r.data;if("ready"===e&&n(),"done"===e&&(this.workers[o].terminate(),this.workers[o]=void 0,console.log(`worker ${o} done so terminate`)),"error"===e){this.workers[o].terminate(),this.workers[o]=void 0;let e=0;for(let r of this.workers)void 0!==r&&(r.terminate(),console.warn("wasi throw error but child process exists, terminate "+e)),e++;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=r.data.error,s=new Int32Array(this.lock,8),i=serialize(t),[a,n]=await this.allocator.async_write(new TextEncoder().encode(JSON.stringify(i)),this.lock,3),l=Atomics.compareExchange(s,0,0,1);if(0!==l){console.error("what happened?"),this.allocator.free(a,n);return}let c=Atomics.notify(s,0);0===c&&(console.error(t),this.allocator.free(a,n),Atomics.store(s,0,0))}},r.postMessage({...this.override_object,...t,worker_id:o,worker_background_ref:this.ref()}),await s,Atomics.store(e,0,o);break}case 2:{this.start_worker=i();let r=a();this.start_worker.onmessage=async r=>{let{msg:e}=r.data;if("done"===e){let r=0;for(let e of this.workers)void 0!==e&&(e.terminate(),console.warn("wasi done but worker exists, terminate "+r)),r++;this.start_worker.terminate(),this.start_worker=void 0,console.log("start worker done so terminate")}},this.start_worker.postMessage({...this.override_object,...r,worker_background_ref:this.ref()})}}let n=Atomics.exchange(r,1,0);if(1!==n)throw Error("Lock is already set");let l=Atomics.notify(r,1,1);if(1!==l){if(0===l){console.warn("notify failed, waiter is late");continue}throw Error("notify failed: "+l)}}catch(r){console.error(r),await new Promise(r=>setTimeout(r,1e3))}}};globalThis.onmessage=r=>{let{override_object:e,worker_background_ref_object:t}=r.data;worker_background=WorkerBackground.init_self(e,t),postMessage("ready")};';
+
+ const blob = new Blob([code], { type: "application/javascript" });
+
+ const url = URL.createObjectURL(blob);
+
+ return url;
+};
diff --git a/threads/src/shared_array_buffer/worker_background/worker_export.ts b/threads/src/shared_array_buffer/worker_background/worker_export.ts
new file mode 100644
index 0000000..f0758a2
--- /dev/null
+++ b/threads/src/shared_array_buffer/worker_background/worker_export.ts
@@ -0,0 +1,22 @@
+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),
+ };
+ };
+
+export type WorkerOptions = {
+ type: "module" | "";
+};
diff --git a/threads/tsconfig.json b/threads/tsconfig.json
new file mode 100644
index 0000000..6a2b7c9
--- /dev/null
+++ b/threads/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ESNext", "DOM"],
+ "skipLibCheck": true,
+ /* Bundler mode */
+ "incremental": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "moduleDetection": "force",
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "declarationMap": true,
+ "outDir": "./dist",
+ "declarationDir": "./types",
+ "esModuleInterop": true,
+ /* Linting */
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["./src"]
+}
diff --git a/threads/vite.config.ts b/threads/vite.config.ts
new file mode 100644
index 0000000..a358b42
--- /dev/null
+++ b/threads/vite.config.ts
@@ -0,0 +1,28 @@
+// https://zenn.dev/seapolis/articles/3605c4befc8465
+
+import { resolve } from "node:path";
+import { defineConfig } from "vite";
+import dts from "vite-plugin-dts";
+import swc from "unplugin-swc";
+
+export default defineConfig({
+ server: {
+ headers: {
+ "Cross-Origin-Embedder-Policy": "require-corp",
+ "Cross-Origin-Opener-Policy": "same-origin",
+ },
+ },
+ build: {
+ lib: {
+ entry: resolve(__dirname, "src/index.ts"),
+ name: "wasi-shim-threads",
+ formats: ["es", "umd", "cjs"],
+ fileName: (format) => `browser-wasi-shim-threads.${format}.js`,
+ },
+ sourcemap: true,
+ minify: true,
+ copyPublicDir: false,
+ },
+ // plugins: [dts({ rollupTypes: true })],
+ plugins: [swc.vite(), swc.rollup(), dts({ rollupTypes: true })],
+});