diff --git a/.vscode/settings.json b/.vscode/settings.json index b48948ab..69ae6071 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "rust-analyzer.showUnlinkedFileNotification": false + "rust-analyzer.showUnlinkedFileNotification": false, + "rust-analyzer.cargo.features": "all" } diff --git a/Cargo.toml b/Cargo.toml index 369dd7f4..01f71811 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,12 @@ members = [ "crates/wasm-bridge", "crates/wasm-bridge-js", "crates/wasm-bridge-macros", - "examples/wit_components/*/*", - "examples/wasi_components/*/*", + + "examples/wit_components/", + "examples/wit_components/guest/*/", + + "examples/wasi_components/", + "examples/wasi_components/guest/*", ] exclude = [ diff --git a/crates/wasm-bridge-js/Cargo.toml b/crates/wasm-bridge-js/Cargo.toml index 2612720a..8c0c175c 100644 --- a/crates/wasm-bridge-js/Cargo.toml +++ b/crates/wasm-bridge-js/Cargo.toml @@ -12,12 +12,14 @@ categories.workspace = true js-sys = { version = "0.3.64" } wasm-bindgen = "0.2.87" wasm-bindgen-futures = { version = "0.4.37" } -wat = { version = "1.0.66", optional = true } +wat = { version = "1.0.70", git = "https://github.com/bytecodealliance/wasm-tools", optional = true } wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } js-component-bindgen = { version = "0.9.5", optional = true } anyhow = { version = "1.0.22" } -heck = { version = "0.4.1" } rand_core = { version = "0.6.4", optional = true } +getrandom = { version = "0.2.10", optional = true } +tracing = "0.1" +convert_case = "0.6.0" [dev-dependencies] wasm-bindgen-test = "0.3.37" @@ -25,5 +27,5 @@ wasm-bindgen-test = "0.3.37" [features] component-model = ["wasm-bridge-macros", "js-component-bindgen"] async = ["wasm-bridge-macros/async"] -wasi = ["async", "rand_core"] +wasi = ["async", "rand_core", "getrandom", "getrandom/js"] error-logging = [] diff --git a/crates/wasm-bridge-js/src/component/component.rs b/crates/wasm-bridge-js/src/component/component.rs index 1de94576..e7bc38d9 100644 --- a/crates/wasm-bridge-js/src/component/component.rs +++ b/crates/wasm-bridge-js/src/component/component.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::{collections::HashMap, io::Write, rc::Rc}; use js_sys::{Function, WebAssembly}; use wasm_bindgen::prelude::*; @@ -50,6 +50,7 @@ impl Component { import_object: &JsValue, closures: Rc<[DropHandle]>, ) -> Result { + tracing::debug!("instantiate {:#?}", import_object); let exports = self .instantiate .call3( diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index 53612623..d6601514 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -1,3 +1,5 @@ +use std::io::Write; + use anyhow::{bail, Context}; use js_component_bindgen::{transpile, TranspileOpts}; use js_sys::Function; @@ -29,6 +31,8 @@ impl ComponentLoader { if name.ends_with(".wasm") { wasm_cores.push((name, bytes)); } else if name.ends_with(".js") { + tracing::debug!(s = %&*String::from_utf8_lossy(&bytes), "js loader"); + // panic!("{}", String::from_utf8_lossy(&bytes)); // TODO: test that instantiate is not already Some? instantiate = Some(load_instantiate_fn(&bytes)?); } diff --git a/crates/wasm-bridge-js/src/component/exports.rs b/crates/wasm-bridge-js/src/component/exports.rs index 0589dacc..05745f64 100644 --- a/crates/wasm-bridge-js/src/component/exports.rs +++ b/crates/wasm-bridge-js/src/component/exports.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, marker::PhantomData, rc::Rc}; use anyhow::Context; -use heck::ToLowerCamelCase; +use convert_case::Casing; use js_sys::{Object, Reflect}; use wasm_bindgen::JsValue; @@ -61,7 +61,7 @@ impl ExportsRoot { pub fn typed_func(&self, name: &str) -> Result> { // TODO: converting in the opposite direction when storing would be slightly faster - let name = name.to_lower_camel_case(); + let name = name.to_case(convert_case::Case::Camel); let func = self .exported_fns @@ -77,7 +77,10 @@ impl ExportsRoot { self.exported_objects .get(name) // TODO: This is a workaround for https://github.com/bytecodealliance/jco/issues/110 - .or_else(|| self.exported_objects.get(&name.to_lower_camel_case()))?, + .or_else(|| { + self.exported_objects + .get(&name.to_case(convert_case::Case::Camel)) + })?, )) } } diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index 27b0c692..27dae771 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -1,6 +1,6 @@ -use std::{collections::HashMap, rc::Rc}; +use std::{collections::HashMap, iter::once, rc::Rc}; -use heck::ToLowerCamelCase; +use convert_case::Casing; use js_sys::{Object, Reflect}; use wasm_bindgen::JsValue; @@ -29,9 +29,12 @@ impl Linker { component: &Component, ) -> Result { let import_object = js_sys::Object::new(); + if let Some(imports) = &self.wasi_imports { + tracing::debug!("assign wasi imports"); js_sys::Object::assign(&import_object, imports); } + let import_object: JsValue = import_object.into(); let mut closures = Vec::with_capacity(self.fns.len()); @@ -42,15 +45,22 @@ impl Linker { closures.push(drop_handle); } + // JCO makes instance functions use camel case for (instance_name, instance_linker) in self.instances.iter() { + let _span = tracing::debug_span!("link instance", instance_name).entered(); + let instance_obj = Object::new(); for function in instance_linker.fns.iter() { + tracing::debug!(function = function.name.as_str(), "link instance func"); + let drop_handle = function.add_to_instance_imports(&instance_obj, data_handle.clone()); + closures.push(drop_handle); } + tracing::debug!(instance_name, "assign instance"); Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); } @@ -72,7 +82,7 @@ impl Linker { self } - pub fn func_wrap(&mut self, name: &str, func: F) -> Result<()> + pub fn func_wrap(&mut self, name: &str, func: F) -> Result<&mut Self> where T: 'static, F: IntoMakeClosure, @@ -80,10 +90,10 @@ impl Linker { self.fns .push(PreparedFn::new(name, func.into_make_closure())); - Ok(()) + Ok(self) } - pub fn func_wrap_async(&mut self, name: &str, func: F) -> Result<()> + pub fn func_wrap_async(&mut self, name: &str, func: F) -> Result<&mut Self> where T: 'static, F: IntoMakeClosure, @@ -98,11 +108,6 @@ impl Linker { .entry(name.to_owned()) .or_insert_with(|| Linker::new(&Engine {}))) // TODO: engine re-creation } - - #[cfg(feature = "wasi")] - pub(crate) fn set_wasi_imports(&mut self, imports: Object) { - self.wasi_imports = Some(imports); - } } struct PreparedFn { @@ -121,6 +126,7 @@ impl PreparedFn { #[must_use] fn add_to_imports(&self, imports: &JsValue, handle: DataHandle) -> DropHandle { + tracing::debug!("import func {}", self.name); let (js_val, handler) = (self.creator)(handle); let object: JsValue = Object::new().into(); @@ -135,8 +141,11 @@ impl PreparedFn { fn add_to_instance_imports(&self, imports: &JsValue, handle: DataHandle) -> DropHandle { let (js_val, handler) = (self.creator)(handle); - Reflect::set(imports, &self.name.to_lower_camel_case().into(), &js_val) - .expect("imports is object"); + let name = self.name.to_case(convert_case::Case::Camel); + + tracing::debug!(?name, "instance func"); + + Reflect::set(imports, &name.into(), &js_val).expect("imports is object"); handler } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs new file mode 100644 index 00000000..5c0a9187 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -0,0 +1,79 @@ +use anyhow::bail; +use js_sys::Object; + +use crate::component::Linker; +use crate::wasi::preview2::{clocks, WasiView}; +use crate::{Result, StoreContextMut}; + +use super::{environment, filesystem, preopens, stdio, streams, terminal}; + +pub fn add_to_linker(linker: &mut Linker) -> Result<()> { + // Overrides + // linker.instance("wasi:io/streams")?.func_wrap( + // "read", + // |data: StoreContextMut, (id, max_bytes): (u32, u64)| { + // if id != STDIN_IDENT { + // bail!("unexpected read stream id: {id}"); + // } + + // let mut bytes = vec![0u8; max_bytes as usize]; + + // let (bytes_written, stream_ended) = data.ctx_mut().stdin().read(&mut bytes)?; + + // bytes.truncate(bytes_written as _); + + // Ok((bytes, stream_ended)) + // }, + // )?; + + // linker.instance("wasi:io/streams")?.func_wrap( + // "write", + // |data: StoreContextMut, (id, buffer): (u32, Vec)| { + // let bytes_written = match id { + // STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + + // STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + + // id => bail!("unexpected write stream id: {id}"), + // }; + // Ok(bytes_written) + // }, + // )?; + + linker.instance("wasi:random/random")?.func_wrap( + "get-random-bytes", + |data: StoreContextMut, (len,): (u64,)| { + let random = data.ctx_mut().random(); + let mut bytes = vec![0u8; len as _]; + random.fill_bytes(&mut bytes); + Ok(bytes) + }, + )?; + + linker + .instance("wasi:random/random")? + .func_wrap("get-random-u64", |data: StoreContextMut, (): ()| { + Ok(data.ctx_mut().random().next_u64()) + })?; + + linker.instance("wasi:cli/exit")?.func_wrap( + "exit", + |_data: StoreContextMut, + (_status,): (std::result::Result<(), ()>,)| + -> anyhow::Result<()> { + todo!("exit called"); + // Ok(()) + }, + )?; + + clocks::add_to_linker(linker)?; + stdio::add_to_linker(linker)?; + + environment::add_to_linker(linker)?; + preopens::add_to_linker(linker)?; + filesystem::add_to_linker(linker)?; + terminal::add_to_linker(linker)?; + streams::add_to_linker(linker)?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs new file mode 100644 index 00000000..d0d3f238 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs @@ -0,0 +1,30 @@ +//! Provides environment interaction for WASI. +//! +//! See: + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +/// Adds environment integration to the linker +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:cli/environment")? + .func_wrap("get-environment", |data: StoreContextMut, (): ()| { + Ok(data + .ctx() + .environment() + .iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect::>()) + })? + .func_wrap( + "get-arguments", + |_data: StoreContextMut, (): ()| -> Result { unimplemented!() }, + )? + .func_wrap("initial-cwd", |_data: StoreContextMut, (): ()| { + Ok(String::from(".")) + })?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs new file mode 100644 index 00000000..cec39a05 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs @@ -0,0 +1,46 @@ +use std::io; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{stream, WasiView}; + +pub type Descriptor = u32; +pub type OutputStream = u32; +pub type InputStream = u32; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:filesystem/types")? + .func_wrap( + "append-via-stream", + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result { + Err(io::Error::new(io::ErrorKind::Unsupported, "append-via-stream").into()) + }, + )? + .func_wrap( + "drop-descriptor", + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result<()> { + Err(io::Error::new(io::ErrorKind::Unsupported, "drop-descriptor").into()) + }, + )? + .func_wrap( + "get-type", + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result { + Err(io::Error::new(io::ErrorKind::Unsupported, "get-type").into()) + }, + )? + .func_wrap( + "read-via-stream", + |_data: StoreContextMut, (_this, _off): (Descriptor, u64)| -> Result { + Err(io::Error::new(io::ErrorKind::Unsupported, "read-via-stream").into()) + }, + )? + .func_wrap( + "write-via-stream", + |_data: StoreContextMut, (_this, _off): (Descriptor, u64)| -> Result { + Err(io::Error::new(io::ErrorKind::Unsupported, "write-via-stream").into()) + }, + )?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 10c5e5e0..213b6bb3 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,16 +1,17 @@ +mod streams; mod wasi_ctx_builder; -pub use wasi_ctx_builder::*; +pub use wasi_ctx_builder::{IsATTY, WasiCtxBuilder}; mod wasi_ctx; -pub use wasi_ctx::*; +pub use wasi_ctx::WasiCtx; mod table; -pub use table::*; +pub use table::Table; mod wasi_view; -pub use wasi_view::*; +pub use wasi_view::WasiView; -pub mod wasi; +pub mod command; pub mod stream; pub use stream::*; @@ -20,3 +21,9 @@ pub use clocks::*; mod random; pub(crate) use random::*; + +pub(crate) mod environment; +pub(crate) mod filesystem; +pub(crate) mod preopens; +pub(crate) mod stdio; +pub(crate) mod terminal; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs new file mode 100644 index 00000000..95275d3d --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs @@ -0,0 +1,12 @@ +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker.instance("wasi:filesystem/preopens")?.func_wrap( + "get-directories", + |_data: StoreContextMut, (): ()| -> Result> { Ok(vec![]) }, + )?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs new file mode 100644 index 00000000..a7a55663 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs @@ -0,0 +1,28 @@ +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +pub(crate) const STDIN_IDENT: u32 = 0; +pub(crate) const STDOUT_IDENT: u32 = 1; +pub(crate) const STDERR_IDENT: u32 = 2; +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:cli/stdout")? + .func_wrap("get-stdout", |_data: StoreContextMut, (): ()| { + Ok(STDOUT_IDENT) + })?; + + linker + .instance("wasi:cli/stderr")? + .func_wrap("get-stderr", |_data: StoreContextMut, (): ()| { + Ok(STDERR_IDENT) + })?; + + linker + .instance("wasi:cli/stdin")? + .func_wrap("get-stdin", |_data: StoreContextMut, (): ()| { + Ok(STDIN_IDENT) + })?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs index 78921337..70f1f549 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs @@ -1,11 +1,13 @@ use crate::Result; +use super::StreamStatus; + pub trait InputStream: Send { fn as_any(&self) -> &dyn std::any::Any; fn readable(&self) -> Result<()>; - fn read(&mut self, buf: &mut [u8]) -> Result<(u64, bool)>; + fn read(&mut self, buf: &mut [u8]) -> Result<(u64, StreamStatus)>; fn num_ready_bytes(&self) -> Result; } @@ -21,8 +23,8 @@ impl InputStream for VoidStream { Ok(()) } - fn read(&mut self, _buf: &mut [u8]) -> Result<(u64, bool)> { - Ok((0, true)) + fn read(&mut self, _buf: &mut [u8]) -> Result<(u64, StreamStatus)> { + Ok((0, StreamStatus::Ended)) } fn num_ready_bytes(&self) -> Result { diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs index 4faee984..59b3c96a 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs @@ -5,3 +5,16 @@ pub use output_stream::*; mod input_stream; pub use input_stream::*; + +pub enum StreamStatus { + Open, + Ended, +} +impl StreamStatus { + pub(crate) fn to_variant(&self) -> String { + match self { + Self::Open => "open".into(), + Self::Ended => "ended".into(), + } + } +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs index 8aa71670..d1a76176 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs @@ -3,12 +3,14 @@ use wasm_bindgen::JsValue; use crate::{helpers::map_js_error, Result}; +use super::StreamStatus; + pub trait OutputStream: Send { fn as_any(&self) -> &dyn std::any::Any; fn writable(&self) -> Result<()>; - fn write(&mut self, buf: &[u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)>; } struct VoidingStream; @@ -22,8 +24,9 @@ impl OutputStream for VoidingStream { Ok(()) } - fn write(&mut self, buf: &[u8]) -> Result { - Ok(buf.len() as _) + /// Non blocking write + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { + Ok((buf.len(), StreamStatus::Open)) } } @@ -42,7 +45,7 @@ impl OutputStream for InheritStream { Ok(()) } - fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { let text = String::from_utf8_lossy(buf); // Do not store the js Function, it makes the stream not Send @@ -55,7 +58,7 @@ impl OutputStream for InheritStream { .call1(&JsValue::UNDEFINED, &text.as_ref().into()) .map_err(map_js_error("Call output stream function"))?; - Ok(buf.len() as _) + Ok((buf.len() as _, StreamStatus::Open)) } } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs new file mode 100644 index 00000000..30bc603e --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs @@ -0,0 +1,88 @@ +use anyhow::bail; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{ + stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}, + WasiView, +}; + +// See: +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:io/streams")? + .func_wrap( + "read", + |data: StoreContextMut, + (id, max_bytes): (u32, u64)| + -> Result, String), ()>> { + // tracing::debug!(?id, ?max_bytes, "read"); + if id != STDIN_IDENT { + bail!("unexpected read stream id: {id}") + } + + let mut bytes = vec![0u8; max_bytes as usize]; + + let (count, status) = data.ctx_mut().stdin().read(&mut bytes)?; + + bytes.truncate(count as _); + + Ok(Ok((bytes, status.to_variant()))) + }, + )? + .func_wrap( + "blocking-read", + |data: StoreContextMut, + (id, max_bytes): (u32, u64)| + -> Result, String), ()>> { + tracing::debug!(?id, ?max_bytes, "blocking-read"); + if id != STDIN_IDENT { + bail!("unexpected read stream id: {id}") + } + + let mut bytes = vec![0u8; max_bytes as usize]; + + let (bytes_written, status) = data.ctx_mut().stdin().read(&mut bytes)?; + + bytes.truncate(bytes_written as _); + + Ok(Ok((bytes, status.to_variant()))) + }, + )? + .func_wrap( + "write", + |data: StoreContextMut, + (id, buffer): (u32, Vec)| + -> Result> { + let (bytes_written, status) = match id { + STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + + STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + + id => bail!("unexpected write stream id: {id}"), + }; + + Ok(Ok((bytes_written as u64, status.to_variant()))) + }, + )? + // blocking write has the same signature, thank god + .func_wrap( + "blocking-write", + |data: StoreContextMut, + (id, buffer): (u32, Vec)| + -> Result> { + tracing::debug!(?id, "blocking-write"); + let (bytes_written, status) = match id { + STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + + STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + + id => bail!("unexpected write stream id: {id}"), + }; + + Ok(Ok((bytes_written as u64, status.to_variant()))) + }, + )?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs new file mode 100644 index 00000000..6ec156ee --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs @@ -0,0 +1,34 @@ +use std::io; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{stream, WasiView}; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker.instance("wasi:cli/terminal-input")?.func_wrap( + "drop-terminal-input", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; + + linker.instance("wasi:cli/terminal-output")?.func_wrap( + "drop-terminal-output", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; + + linker.instance("wasi:cli/terminal-stdin")?.func_wrap( + "get-terminal-stdin", + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, + )?; + + linker.instance("wasi:cli/terminal-stdout")?.func_wrap( + "get-terminal-stdout", + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, + )?; + + linker.instance("wasi:cli/terminal-stderr")?.func_wrap( + "get-terminal-stderr", + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, + )?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs deleted file mode 100644 index 3c4b7b6c..00000000 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs +++ /dev/null @@ -1,88 +0,0 @@ -use anyhow::bail; -use js_sys::Object; - -use crate::component::Linker; -use crate::wasi::preview2::{clocks, WasiView}; -use crate::{Result, StoreContextMut}; - -static WASI_IMPORTS_STR: &str = - include_str!("../../../../../../resources/transformed/preview2-shim/bundled.js"); - -const STDIN_IDENT: u32 = 0; -const STDOUT_IDENT: u32 = 1; -const STDERR_IDENT: u32 = 2; - -pub fn add_to_linker(linker: &mut Linker) -> Result<()> { - // Default imports - linker.set_wasi_imports(get_imports()); - - // Overrides - linker.instance("wasi:io/streams")?.func_wrap( - "read", - |data: StoreContextMut, (id, max_bytes): (u32, u64)| { - if id != STDIN_IDENT { - bail!("unexpected read stream id: {id}"); - } - - let mut bytes = vec![0u8; max_bytes as usize]; - - let (bytes_written, stream_ended) = data.ctx_mut().stdin().read(&mut bytes)?; - - bytes.truncate(bytes_written as _); - - Ok((bytes, stream_ended)) - }, - )?; - - linker.instance("wasi:io/streams")?.func_wrap( - "write", - |data: StoreContextMut, (id, buffer): (u32, Vec)| { - let bytes_written = match id { - STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, - - STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, - - id => bail!("unexpected write stream id: {id}"), - }; - Ok(bytes_written) - }, - )?; - - linker.instance("wasi:random/random")?.func_wrap( - "get-random-bytes", - |data: StoreContextMut, (len,): (u64,)| { - let random = data.ctx_mut().random(); - let mut bytes = vec![0u8; len as _]; - random.fill_bytes(&mut bytes); - Ok(bytes) - }, - )?; - - linker - .instance("wasi:random/random")? - .func_wrap("get-random-u64", |data: StoreContextMut, (): ()| { - Ok(data.ctx_mut().random().next_u64()) - })?; - - clocks::add_to_linker(linker)?; - - Ok(()) -} - -fn get_imports() -> Object { - let imports = js_sys::eval(WASI_IMPORTS_STR).expect("eval bundled wasi imports"); - - assert!(imports.is_object(), "wasi imports must be an object"); - - imports.into() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[wasm_bindgen_test::wasm_bindgen_test] - fn should_get_imports() { - let _ = get_imports(); - } -} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs deleted file mode 100644 index 9fe79612..00000000 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod command; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs index 8b78b4d2..04731854 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use super::*; pub struct WasiCtx { @@ -9,6 +11,8 @@ pub struct WasiCtx { wall_clock: Box, monotonic_clock: Box, + + env: HashMap, } impl WasiCtx { @@ -19,6 +23,7 @@ impl WasiCtx { random: Option, wall_clock: Option>, monotonic_clock: Option>, + env: HashMap, ) -> Self { Self { stdin: stdin.unwrap_or_else(|| Box::new(void_stream())), @@ -27,6 +32,7 @@ impl WasiCtx { random: random.unwrap_or_else(js_rand), wall_clock: wall_clock.unwrap_or_else(|| Box::new(real_wall_clock())), monotonic_clock: monotonic_clock.unwrap_or_else(|| Box::new(default_monotonic_clock())), + env, } } @@ -53,4 +59,8 @@ impl WasiCtx { pub(crate) fn monotonic_clock(&self) -> &dyn HostMonotonicClock { &*self.monotonic_clock } + + pub(crate) fn environment(&self) -> &HashMap { + &self.env + } } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs index d2fc49ec..153d3a90 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs @@ -1,8 +1,15 @@ +use std::collections::HashMap; + use rand_core::RngCore; use super::*; use crate::Result; +pub enum IsATTY { + Yes, + No, +} + #[derive(Default)] pub struct WasiCtxBuilder { stdin: Option>, @@ -13,6 +20,7 @@ pub struct WasiCtxBuilder { wall_clock: Option>, monotonic_clock: Option>, + env: HashMap, } impl WasiCtxBuilder { @@ -20,89 +28,89 @@ impl WasiCtxBuilder { Default::default() } - pub fn build(self, _table: &mut Table) -> Result { + pub fn build(&mut self, _table: &mut Table) -> Result { + let v = std::mem::take(self); + tracing::debug!("stdin {}", v.stdin.is_some()); + Ok(WasiCtx::new( - self.stdin, - self.stdout, - self.stderr, - self.random, - self.wall_clock, - self.monotonic_clock, + v.stdin, + v.stdout, + v.stderr, + v.random, + v.wall_clock, + v.monotonic_clock, + v.env, )) } - pub fn set_stdin(self, in_stream: impl InputStream + 'static) -> Self { - Self { - stdin: Some(Box::new(in_stream)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stdin(&mut self, in_stream: impl InputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stdin = Some(Box::new(in_stream)); + self } - pub fn set_stdout(self, out: impl OutputStream + 'static) -> Self { - Self { - stdout: Some(Box::new(out)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stdout(&mut self, out: impl OutputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stdout = Some(Box::new(out)); + self } - pub fn set_stderr(self, err: impl OutputStream + 'static) -> Self { - Self { - stderr: Some(Box::new(err)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stderr(&mut self, err: impl OutputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stderr = Some(Box::new(err)); + self } - pub fn inherit_stdin(self) -> Self { + pub fn inherit_stdin(&mut self) -> &mut Self { // TODO: could be implemented at least on node, but readline is asynchronous self } - pub fn inherit_stdout(self) -> Self { - Self { - stdout: Some(Box::new(console_log_stream())), - ..self - } + pub fn inherit_stdout(&mut self) -> &mut Self { + self.stdout = Some(Box::new(console_log_stream())); + self } - pub fn inherit_stderr(self) -> Self { - Self { - stderr: Some(Box::new(console_error_stream())), - ..self - } + pub fn inherit_stderr(&mut self) -> &mut Self { + self.stderr = Some(Box::new(console_error_stream())); + self } - pub fn inherit_stdio(self) -> Self { + pub fn inherit_stdio(&mut self) -> &mut Self { self.inherit_stdin().inherit_stdout().inherit_stderr() } - pub fn set_secure_random(self) -> Self { - Self { - random: None, // Will be filled later - ..self - } + pub fn set_secure_random(&mut self) -> &mut Self { + self.random = None; + self } pub fn set_secure_random_to_custom_generator( - self, + &mut self, random: impl RngCore + Send + Sync + 'static, - ) -> Self { - Self { - random: Some(Box::new(random)), - ..self - } + ) -> &mut Self { + self.random = Some(Box::new(random)); + self + } + + pub fn set_wall_clock(&mut self, wall_clock: impl HostWallClock + 'static) -> &mut Self { + self.wall_clock = Some(Box::new(wall_clock)); + self } - pub fn set_wall_clock(self, wall_clock: impl HostWallClock + 'static) -> Self { - Self { - wall_clock: Some(Box::new(wall_clock)), - ..self - } + pub fn set_monotonic_clock( + &mut self, + monotonic_clock: impl HostMonotonicClock + 'static, + ) -> &mut Self { + self.monotonic_clock = Some(Box::new(monotonic_clock)); + self } - pub fn set_monotonic_clock(self, monotonic_clock: impl HostMonotonicClock + 'static) -> Self { - Self { - monotonic_clock: Some(Box::new(monotonic_clock)), - ..self - } + pub fn set_env(mut self, env: &[(impl AsRef, impl AsRef)]) -> Self { + self.env = env + .iter() + .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())) + .collect(); + self } } diff --git a/crates/wasm-bridge/Cargo.toml b/crates/wasm-bridge/Cargo.toml index f036a8a7..a4a35246 100644 --- a/crates/wasm-bridge/Cargo.toml +++ b/crates/wasm-bridge/Cargo.toml @@ -10,8 +10,8 @@ categories.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmtime = { version = "12.0.0", default-features = false, features = ["cranelift"] } -wasmtime-wasi = { version = "12.0.0", optional = true } +wasmtime = { version = "14.0.0", git = "https://github.com/bytecodealliance/wasmtime", default-features = false, features = ["cranelift"] } +wasmtime-wasi = { version = "14.0.0", git = "https://github.com/bytecodealliance/wasmtime", optional = true } wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } async-trait = { version = "0.1.73", optional = true } @@ -24,6 +24,7 @@ default = ["wat", "error-logging"] wat = ["wasmtime/wat", "wasm-bridge-js/wat"] component-model = ["wasmtime/component-model", "wasm-bridge-macros", "wasm-bridge-js/component-model"] async = ["wasmtime/async", "async-trait", "wasm-bridge-macros/async", "wasm-bridge-js/async"] +sync = ["wasmtime-wasi/sync"] wasi = ["wasmtime-wasi", "wasm-bridge-js/wasi", "async"] error-logging = ["wasm-bridge-js/error-logging"] diff --git a/examples/wasi_components/Cargo.toml b/examples/wasi_components/Cargo.toml new file mode 100644 index 00000000..ec173de4 --- /dev/null +++ b/examples/wasi_components/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "wasi-components-tests" +edition.workspace = true +version = "0.0.0" + +[dependencies] +wasm-bridge = { path = "../../crates/wasm-bridge/", features = ["component-model", "async", "wasi"]} +wasm-bindgen-test = "0.3" +bytes = "1.4" + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies] +tokio = { version = "1.32", features = ["full"] } + +[dev-dependencies] +tracing-web = "0.1" +tracing-subscriber = { version = "0.3", features = ["time"] } +wasm-bindgen-test = "0.3" diff --git a/examples/wasi_components/build_guest.sh b/examples/wasi_components/build_guest.sh new file mode 100755 index 00000000..a255d144 --- /dev/null +++ b/examples/wasi_components/build_guest.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +if [[ $1 ]]; then + echo "-> Building $1" + EXAMPLES=$1 +else + EXAMPLES=`ls guest` +fi + + +# Build the guest +for EXAMPLE in $EXAMPLES; do + echo "-> Building $EXAMPLE" + cargo component build -p $EXAMPLE-guest +done diff --git a/examples/wasi_components/io_redirect/guest/.gitignore b/examples/wasi_components/guest/io/.gitignore similarity index 100% rename from examples/wasi_components/io_redirect/guest/.gitignore rename to examples/wasi_components/guest/io/.gitignore diff --git a/examples/wit_components/records/guest/Cargo.toml b/examples/wasi_components/guest/io/Cargo.toml similarity index 85% rename from examples/wit_components/records/guest/Cargo.toml rename to examples/wasi_components/guest/io/Cargo.toml index cc2058fc..73265c22 100644 --- a/examples/wit_components/records/guest/Cargo.toml +++ b/examples/wasi_components/guest/io/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example-records-guest" +name = "io-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wasi_components/io_redirect/guest/src/lib.rs b/examples/wasi_components/guest/io/src/lib.rs similarity index 92% rename from examples/wasi_components/io_redirect/guest/src/lib.rs rename to examples/wasi_components/guest/io/src/lib.rs index 9caf4069..7a944819 100644 --- a/examples/wasi_components/io_redirect/guest/src/lib.rs +++ b/examples/wasi_components/guest/io/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../protocol.wit", + path: "../../io_redirect.wit", world: "io-redirect", }); diff --git a/examples/wasi_components/io_redirect/protocol.wit b/examples/wasi_components/io_redirect.wit similarity index 100% rename from examples/wasi_components/io_redirect/protocol.wit rename to examples/wasi_components/io_redirect.wit diff --git a/examples/wasi_components/io_redirect/host/.gitignore b/examples/wasi_components/io_redirect/host/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wasi_components/io_redirect/host/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wasi_components/io_redirect/host/Cargo.toml b/examples/wasi_components/io_redirect/host/Cargo.toml deleted file mode 100644 index 53c9051c..00000000 --- a/examples/wasi_components/io_redirect/host/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "example-io_redirect-host" -edition = "2021" -version = "0.0.0" - -[dependencies] -wasm-bridge = { path = "../../../../crates/wasm-bridge/", default-features = false, features = ["component-model", "wasi"]} -rand_core = { version = "0.6.4" } -tokio = { version = "1.29.1", features = ["macros", "rt"] } -async-trait = "0.1" -bytes = "1.4" - diff --git a/examples/wasi_components/run_examples.sh b/examples/wasi_components/run_examples.sh deleted file mode 100755 index 7b364145..00000000 --- a/examples/wasi_components/run_examples.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -e - -if [[ $1 ]]; then - echo "-> Building $1" - EXAMPLES=$1 -else - EXAMPLES=`ls ` -fi - - -# Build the guest -for example in $EXAMPLES; do - if [[ ! -d $example ]]; then - continue - fi - - echo "-> Running $example" - cargo component build -p example-$example-guest - cargo run -p example-$example-host -done diff --git a/examples/wasi_components/src/lib.rs b/examples/wasi_components/src/lib.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/wasi_components/src/lib.rs @@ -0,0 +1 @@ + diff --git a/examples/wasi_components/io_redirect/host/src/main.rs b/examples/wasi_components/tests/io.rs similarity index 82% rename from examples/wasi_components/io_redirect/host/src/main.rs rename to examples/wasi_components/tests/io.rs index b7c25aac..d37e4a02 100644 --- a/examples/wasi_components/io_redirect/host/src/main.rs +++ b/examples/wasi_components/tests/io.rs @@ -7,10 +7,13 @@ use wasm_bridge::{ use wasm_bridge::wasi::preview2::*; -use std::sync::{Arc, Mutex}; +use std::{ + io::Write, + sync::{Arc, Mutex}, +}; wasm_bridge::component::bindgen!({ - path: "../protocol.wit", + path: "./io_redirect.wit", world: "io-redirect", async: true, }); @@ -35,10 +38,21 @@ impl WasiView for State { } } -#[tokio::main] -pub async fn main() -> Result<()> { - const GUEST_BYTES: &[u8] = - include_bytes!("../../../../../target/wasm32-wasi/debug/example_io_redirect_guest.wasm"); +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +pub async fn test() -> Result<()> { + use tracing_subscriber::prelude::*; + #[cfg(target_arch = "wasm32")] + let fmt_layer = tracing_subscriber::fmt::layer() + .with_ansi(true) // Only partially supported across browsers + .without_time() + .with_writer(tracing_web::MakeConsoleWriter); // write events to the console + + #[cfg(not(target_arch = "wasm32"))] + let fmt_layer = tracing_subscriber::fmt::layer().with_ansi(true); + + tracing_subscriber::registry().with(fmt_layer).init(); + const GUEST_BYTES: &[u8] = include_bytes!("../../../target/wasm32-wasi/debug/io_guest.wasm"); no_config(GUEST_BYTES).await?; inherit(GUEST_BYTES).await?; @@ -58,7 +72,7 @@ async fn no_config(component_bytes: &[u8]) -> Result<()> { let engine = Engine::new(&config)?; let mut store = Store::new(&engine, State { table, wasi }); - let component = Component::new(&store.engine(), &component_bytes)?; + let component = Component::new(store.engine(), component_bytes)?; let mut linker = Linker::new(store.engine()); wasi::preview2::command::add_to_linker(&mut linker)?; @@ -71,6 +85,7 @@ async fn no_config(component_bytes: &[u8]) -> Result<()> { instance .call_writeln_to_stdout(&mut store, "NO_PRINT") .await?; + instance .call_writeln_to_stderr(&mut store, "NO_PRINT") .await?; @@ -103,6 +118,7 @@ async fn inherit(component_bytes: &[u8]) -> Result<()> { instance .call_writeln_to_stdout(&mut store, "PRINT_OUT_1") .await?; + instance .call_writeln_to_stderr(&mut store, "PRINT_ERR_1") .await?; @@ -136,9 +152,9 @@ async fn capture(component_bytes: &[u8]) -> Result<()> { let mut table = Table::new(); let wasi = WasiCtxBuilder::new() - .set_stdin(in_stream) - .set_stdout(out_stream) - .set_stderr(err_stream) + .stdin(in_stream, IsATTY::No) + .stdout(out_stream, IsATTY::No) + .stderr(err_stream, IsATTY::No) .build(&mut table)?; let engine = Engine::new(&config)?; @@ -196,15 +212,15 @@ impl OutputStream for OutStream { Ok(()) } - async fn write(&mut self, buf: &[u8]) -> Result { + async fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { let amount = buf.len().min(self.max); self.data.try_lock().unwrap().extend(&buf[..amount]); - Ok(amount as u64) + Ok((amount as usize, StreamStatus::Open)) } } #[cfg(not(target_arch = "wasm32"))] -#[async_trait::async_trait] +#[wasm_bridge::async_trait] impl HostOutputStream for OutStream { fn write(&mut self, bytes: Bytes) -> Result<(usize, StreamState), wasm_bridge::Error> { let amount = bytes.len().min(self.max); @@ -234,22 +250,30 @@ impl InputStream for InStream { Ok(()) } - async fn read(&mut self, buf: &mut [u8]) -> Result<(u64, bool)> { + async fn read(&mut self, buf: &mut [u8]) -> Result<(u64, StreamStatus)> { let len = buf.len().min(self.data.len() - self.offset).min(self.max); let from_slice = &self.data[self.offset..(self.offset + len)]; (&mut buf[..len]).copy_from_slice(from_slice); self.offset += len; - Ok((len as _, self.data.len() == self.offset)) + Ok(( + len as _, + if self.data.len() == self.offset { + StreamStatus::Ended + } else { + StreamStatus::Open + }, + )) } async fn num_ready_bytes(&self) -> Result { Ok((self.data.len() - self.offset) as _) } } + #[cfg(not(target_arch = "wasm32"))] -#[async_trait::async_trait] +#[wasm_bridge::async_trait] impl HostInputStream for InStream { fn read(&mut self, size: usize) -> Result<(Bytes, StreamState), wasm_bridge::Error> { let len = size.min(self.data.len() - self.offset).min(self.max); diff --git a/examples/wit_components/Cargo.toml b/examples/wit_components/Cargo.toml new file mode 100644 index 00000000..d5926644 --- /dev/null +++ b/examples/wit_components/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "wit-components-tests" +edition.workspace = true +version = "0.0.0" + +[dependencies] +wasm-bridge = { path = "../../crates/wasm-bridge/", features = ["component-model"]} +wasm-bindgen-test = "0.3" + +[dev-dependencies] +tracing-web = "0.1" +tracing-subscriber = { version = "0.3", features = ["time"] } +wasm-bindgen-test = "0.3" diff --git a/examples/wit_components/build_guest.sh b/examples/wit_components/build_guest.sh new file mode 100755 index 00000000..acc0e2bd --- /dev/null +++ b/examples/wit_components/build_guest.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +if [[ $1 ]]; then + echo "-> Building $1" + EXAMPLES=$1 +else + EXAMPLES=`ls guest` +fi + + +# Build the guest +for EXAMPLE in $EXAMPLES; do + echo "-> Building $EXAMPLE" + cargo component build --target wasm32-unknown-unknown -p $EXAMPLE-guest +done diff --git a/examples/wasi_components/io_redirect/guest/Cargo.toml b/examples/wit_components/guest/records/Cargo.toml similarity index 84% rename from examples/wasi_components/io_redirect/guest/Cargo.toml rename to examples/wit_components/guest/records/Cargo.toml index 2cb29574..ce0b9ebf 100644 --- a/examples/wasi_components/io_redirect/guest/Cargo.toml +++ b/examples/wit_components/guest/records/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example-io_redirect-guest" +name = "records-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wit_components/records/guest/src/lib.rs b/examples/wit_components/guest/records/src/lib.rs similarity index 86% rename from examples/wit_components/records/guest/src/lib.rs rename to examples/wit_components/guest/records/src/lib.rs index 15837ce7..a1074edf 100644 --- a/examples/wit_components/records/guest/src/lib.rs +++ b/examples/wit_components/guest/records/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../protocol.wit", + path: "../../records.wit", world: "records", }); diff --git a/examples/wit_components/records/protocol.wit b/examples/wit_components/records.wit similarity index 100% rename from examples/wit_components/records/protocol.wit rename to examples/wit_components/records.wit diff --git a/examples/wit_components/records/guest/.gitignore b/examples/wit_components/records/guest/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wit_components/records/guest/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wit_components/records/host/.gitignore b/examples/wit_components/records/host/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wit_components/records/host/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wit_components/records/host/Cargo.toml b/examples/wit_components/records/host/Cargo.toml deleted file mode 100644 index 73a809c0..00000000 --- a/examples/wit_components/records/host/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "example-records-host" -edition.workspace = true -version = "0.0.0" - -[dependencies] -wasm-bridge = { path = "../../../../crates/wasm-bridge/", features = ["component-model"]} - diff --git a/examples/wit_components/run_examples.sh b/examples/wit_components/run_examples.sh deleted file mode 100755 index 627fac2d..00000000 --- a/examples/wit_components/run_examples.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -e - -if [[ $1 ]]; then - echo "-> Building $1" - EXAMPLES=$1 -else - EXAMPLES=`ls ` -fi - - -# Build the guest -for example in $EXAMPLES; do - if [[ ! -d $example ]]; then - continue - fi - - echo "-> Running $example" - cargo component build --target wasm32-unknown-unknown -p example-$example-guest - cargo run -p example-$example-host -done diff --git a/examples/wit_components/src/lib.rs b/examples/wit_components/src/lib.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/wit_components/src/lib.rs @@ -0,0 +1 @@ + diff --git a/examples/wit_components/records/host/src/main.rs b/examples/wit_components/tests/records.rs similarity index 61% rename from examples/wit_components/records/host/src/main.rs rename to examples/wit_components/tests/records.rs index 14123507..2e2c8ebd 100644 --- a/examples/wit_components/records/host/src/main.rs +++ b/examples/wit_components/tests/records.rs @@ -1,10 +1,14 @@ +use wasm_bindgen_test::wasm_bindgen_test; use wasm_bridge::{ component::{Component, Linker}, Config, Engine, Result, Store, }; +const GUEST_BYTES: &[u8] = + include_bytes!("../../../target/wasm32-unknown-unknown/debug/records_guest.wasm"); + wasm_bridge::component::bindgen!({ - path: "../protocol.wit", + path: "./records.wit", world: "records", }); @@ -15,10 +19,21 @@ impl RecordsImports for Host { } } -const GUEST_BYTES: &[u8] = - include_bytes!("../../../../../target/wasm32-unknown-unknown/debug/example_records_guest.wasm"); +#[test] +#[wasm_bindgen_test] +fn records() { + use tracing_subscriber::prelude::*; + #[cfg(target_arch = "wasm32")] + let fmt_layer = tracing_subscriber::fmt::layer() + .with_ansi(true) // Only partially supported across browsers + .without_time() + .with_writer(tracing_web::MakeConsoleWriter); // write events to the console + + #[cfg(not(target_arch = "wasm32"))] + let fmt_layer = tracing_subscriber::fmt::layer().with_ansi(true); + + tracing_subscriber::registry().with(fmt_layer).init(); -fn main() -> Result<()> { let mut config = Config::new(); config.wasm_component_model(true); @@ -43,6 +58,4 @@ fn main() -> Result<()> { .unwrap(); assert_eq!(result, vec![2, 6, 7]); - - Ok(()) } diff --git a/recipes.json b/recipes.json new file mode 100644 index 00000000..bf4dc901 --- /dev/null +++ b/recipes.json @@ -0,0 +1,24 @@ +{ + "test-wasi": { + "cmd": [ + "wasm-pack", + "test", + "--node", + "./examples/wasi_components/" + ], + "qf": { + "compiler": "cargo" + } + }, + "test-wit": { + "cmd": [ + "wasm-pack", + "test", + "--node", + "./examples/wit_components/" + ], + "qf": { + "compiler": "cargo" + } + } +} diff --git a/resources/original/.gitignore b/resources/original/.gitignore deleted file mode 100644 index 428fb5ce..00000000 --- a/resources/original/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/jco-repo/ diff --git a/resources/original/README.md b/resources/original/README.md deleted file mode 100644 index 6918c061..00000000 --- a/resources/original/README.md +++ /dev/null @@ -1,4 +0,0 @@ -### Source - -The folders in this repo are "cloned" from the [jco repo](https://github.com/bytecodealliance/jco), -and come with their "Apache-2.0 WITH LLVM-exception" license. diff --git a/resources/original/fetch_original.sh b/resources/original/fetch_original.sh deleted file mode 100755 index cceecc50..00000000 --- a/resources/original/fetch_original.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/sh -set -e - -## First, clone and update the repo - -# clone the repo if it doesn't exist -if [ ! -d "./jco-repo" ]; then - git clone https://github.com/bytecodealliance/jco.git jco-repo -fi - -# update the repo -cd jco-repo -git reset --hard -git pull -cd .. - - -## Preview shim - -# copy the wasi shims from jco -rm -rf preview2-shim/browser -rm -rf preview2-shim/http -cp -r jco-repo/packages/preview2-shim/lib/browser ./preview2-shim/ -cp -r jco-repo/packages/preview2-shim/lib/http ./preview2-shim/ - -# remove uneeded files from the shim -rm -rf preview2-shim/nodejs diff --git a/resources/original/preview2-shim/LICENSE b/resources/original/preview2-shim/LICENSE deleted file mode 100644 index f9d81955..00000000 --- a/resources/original/preview2-shim/LICENSE +++ /dev/null @@ -1,220 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - diff --git a/resources/original/preview2-shim/README.md b/resources/original/preview2-shim/README.md deleted file mode 100644 index 820e8f3e..00000000 --- a/resources/original/preview2-shim/README.md +++ /dev/null @@ -1,14 +0,0 @@ -### Source - -This folder is a direct copy of the -[`packages/preview2-shim/lib`](https://github.com/bytecodealliance/jco/tree/main/packages/preview2-shim/lib) -folder in jco. - -### License - -The code in this folder is licensed under the "Apache-2.0 WITH LLVM-exception" license, -see [LICENSE](./LICENSE). - -### Changes - -- Removed the `nodejs` folder diff --git a/resources/original/preview2-shim/browser/cli.js b/resources/original/preview2-shim/browser/cli.js deleted file mode 100644 index 4d9acebf..00000000 --- a/resources/original/preview2-shim/browser/cli.js +++ /dev/null @@ -1,86 +0,0 @@ -let _env, _args = [], _cwd = null; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export function _setArgs (args) { - _args = args; -} - -export function _setCwd (cwd) { - _cwd = cwd; -} - -export const environment = { - getEnvironment () { - if (!_env) _setEnv(process.env); - return _env; - }, - getArguments () { - return _args; - }, - initialCwd () { - return _cwd; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; - -export const terminalInput = { - dropTerminalInput () { - - } -}; - -export const terminalOutput = { - dropTerminalOutput () { - - } -}; - -export const terminalStderr = { - getTerminalStderr () { - return 0; - } -}; - -export const terminalStdin = { - getTerminalStdin () { - return 1; - } -}; - -export const terminalStdout = { - getTerminalStdout () { - return 2; - } -}; diff --git a/resources/original/preview2-shim/browser/clocks.js b/resources/original/preview2-shim/browser/clocks.js deleted file mode 100644 index 1500a420..00000000 --- a/resources/original/preview2-shim/browser/clocks.js +++ /dev/null @@ -1,46 +0,0 @@ -function _hrtimeBigint () { - // performance.now() is in milliseconds, but we want nanoseconds - return BigInt(Math.floor(performance.now() * 1e6)); -} - -let _hrStart = _hrtimeBigint(); - -export const monotonicClock = { - resolution() { - return 1n; - }, - now () { - return _hrtimeBigint() - _hrStart; - }, - subscribe (_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } -}; - -export const timezone = { - display (timezone, when) { - console.log(`[timezone] DISPLAY ${timezone} ${when}`); - }, - - utcOffset (timezone, when) { - console.log(`[timezone] UTC OFFSET ${timezone} ${when}`); - return 0; - }, - - dropTimezone (timezone) { - console.log(`[timezone] DROP ${timezone}`); - } -}; - -export const wallClock = { - now() { - let now = Date.now(); // in milliseconds - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = (now % 1e3) * 1e6; - return { seconds, nanoseconds }; - }, - - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } -}; diff --git a/resources/original/preview2-shim/browser/filesystem.js b/resources/original/preview2-shim/browser/filesystem.js deleted file mode 100644 index d0a1e4ab..00000000 --- a/resources/original/preview2-shim/browser/filesystem.js +++ /dev/null @@ -1,157 +0,0 @@ -export const preopens = { - getDirectories () { - return []; - } -} - -export const types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } -}; - -export { types as filesystemTypes } diff --git a/resources/original/preview2-shim/browser/http.js b/resources/original/preview2-shim/browser/http.js deleted file mode 100644 index 592b3ad4..00000000 --- a/resources/original/preview2-shim/browser/http.js +++ /dev/null @@ -1,146 +0,0 @@ -import { UnexpectedError } from "../http/error.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {string} - */ -export function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : undefined; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(': '); - var key = parts.shift(); - var value = parts.join(': '); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body, - }; - } catch (err) { - throw new UnexpectedError(err.message); - } -} - -export const incomingHandler = { - handle () { - - } -}; - -export const outgoingHandler = { - handle () { - - } -}; - -export const types = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } -}; diff --git a/resources/original/preview2-shim/browser/index.js b/resources/original/preview2-shim/browser/index.js deleted file mode 100644 index 11add6fa..00000000 --- a/resources/original/preview2-shim/browser/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import * as clocks from "./clocks.js"; -import * as filesystem from "./filesystem.js"; -import * as http from "./http.js"; -import * as io from "./io.js"; -import * as logging from "./logging.js"; -import * as poll from "./poll.js"; -import * as random from "./random.js"; -import * as sockets from "./sockets.js"; -import * as cli from "./cli.js"; - -export const importObject = { - clocks, - filesystem, - http, - io, - logging, - poll, - random, - sockets, - cli, -}; - -export { WasiHttp } from "../http/wasi-http.js"; - -export default importObject; diff --git a/resources/original/preview2-shim/browser/io.js b/resources/original/preview2-shim/browser/io.js deleted file mode 100644 index 3422382d..00000000 --- a/resources/original/preview2-shim/browser/io.js +++ /dev/null @@ -1,60 +0,0 @@ -export const streams = { - read(s, len) { - console.log(`[streams] Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } -}; diff --git a/resources/original/preview2-shim/browser/logging.js b/resources/original/preview2-shim/browser/logging.js deleted file mode 100644 index 9c963ac7..00000000 --- a/resources/original/preview2-shim/browser/logging.js +++ /dev/null @@ -1,14 +0,0 @@ -const levels = ["trace", "debug", "info", "warn", "error", "critical"]; - -let logLevel = levels.indexOf("warn"); - -export const logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) return; - console[level](`(${context}) ${msg}\n`); - } -}; - -export function setLevel(level) { - logLevel = levels.indexOf(level); -} diff --git a/resources/original/preview2-shim/browser/poll.js b/resources/original/preview2-shim/browser/poll.js deleted file mode 100644 index 52d2fe36..00000000 --- a/resources/original/preview2-shim/browser/poll.js +++ /dev/null @@ -1,9 +0,0 @@ -export const poll = { - dropPollable (pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff (input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } -}; diff --git a/resources/original/preview2-shim/browser/random.js b/resources/original/preview2-shim/browser/random.js deleted file mode 100644 index 5ec1d7c5..00000000 --- a/resources/original/preview2-shim/browser/random.js +++ /dev/null @@ -1,56 +0,0 @@ -const MAX_BYTES = 65536; - -let insecureRandomValue1, insecureRandomValue2; - -export const insecure = { - getInsecureRandomBytes (len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64 () { - return random.getRandomU64(); - } -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed () { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - } -}; - -export const random = { - getRandomBytes(len) { - const bytes = new Uint8Array(Number(len)); - - if (len > MAX_BYTES) { - // this is the max bytes crypto.getRandomValues - // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues - for (var generated = 0; generated < len; generated += MAX_BYTES) { - // buffer.slice automatically checks if the end is past the end of - // the buffer so we don't have to here - crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)); - } - } else { - crypto.getRandomValues(bytes); - } - - return bytes; - }, - - getRandomU64 () { - return crypto.getRandomValues(new BigUint64Array(1))[0]; - }, - - insecureRandom () { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - } -}; diff --git a/resources/original/preview2-shim/browser/sockets.js b/resources/original/preview2-shim/browser/sockets.js deleted file mode 100644 index 19aae42a..00000000 --- a/resources/original/preview2-shim/browser/sockets.js +++ /dev/null @@ -1,200 +0,0 @@ -export const instanceNetwork = { - instanceNetwork () { - console.log(`[sockets] instance network`); - } -}; - -export const ipNameLookup = { - dropResolveAddressStream () { - - }, - subscribe () { - - }, - resolveAddresses () { - - }, - resolveNextAddress () { - - }, - nonBlocking () { - - }, - setNonBlocking () { - - }, -}; - -export const network = { - dropNetwork () { - - } -}; - -export const tcpCreateSocket = { - createTcpSocket () { - - } -}; - -export const tcp = { - subscribe () { - - }, - dropTcpSocket() { - - }, - bind() { - - }, - connect() { - - }, - listen() { - - }, - accept() { - - }, - localAddress() { - - }, - remoteAddress() { - - }, - addressFamily() { - - }, - ipv6Only() { - - }, - setIpv6Only() { - - }, - setListenBacklogSize() { - - }, - keepAlive() { - - }, - setKeepAlive() { - - }, - noDelay() { - - }, - setNoDelay() { - - }, - unicastHopLimit() { - - }, - setUnicastHopLimit() { - - }, - receiveBufferSize() { - - }, - setReceiveBufferSize() { - - }, - sendBufferSize() { - - }, - setSendBufferSize() { - - }, - nonBlocking() { - - }, - setNonBlocking() { - - }, - shutdown() { - - } -}; - -export const udp = { - subscribe () { - - }, - - dropUdpSocket () { - - }, - - bind () { - - }, - - connect () { - - }, - - receive () { - - }, - - send () { - - }, - - localAddress () { - - }, - - remoteAddress () { - - }, - - addressFamily () { - - }, - - ipv6Only () { - - }, - - setIpv6Only () { - - }, - - unicastHopLimit () { - - }, - - setUnicastHopLimit () { - - }, - - receiveBufferSize () { - - }, - - setReceiveBufferSize () { - - }, - - sendBufferSize () { - - }, - - setSendBufferSize () { - - }, - - nonBlocking () { - - }, - - setNonBlocking () { - - } -}; - -export const udpCreateSocket = { - createUdpSocket () { - - } -}; diff --git a/resources/original/preview2-shim/http/error.js b/resources/original/preview2-shim/http/error.js deleted file mode 100644 index 748f20cb..00000000 --- a/resources/original/preview2-shim/http/error.js +++ /dev/null @@ -1,11 +0,0 @@ -export class UnexpectedError extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message, - }; - } -} diff --git a/resources/original/preview2-shim/http/make-request.js b/resources/original/preview2-shim/http/make-request.js deleted file mode 100644 index ee743244..00000000 --- a/resources/original/preview2-shim/http/make-request.js +++ /dev/null @@ -1,30 +0,0 @@ -import { runAsWorker } from "./synckit/index.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {Promise} - */ -async function makeRequest(req) { - try { - let headers = new Headers(req.headers); - const resp = await fetch(req.uri, { - method: req.method.toString(), - headers, - body: req.body && req.body.length > 0 ? req.body : undefined, - redirect: "manual", - }); - let arrayBuffer = await resp.arrayBuffer(); - return JSON.stringify({ - status: resp.status, - headers: Array.from(resp.headers.entries()), - body: - arrayBuffer.byteLength > 0 - ? Buffer.from(arrayBuffer).toString("base64") - : undefined, - }); - } catch (err) { - return JSON.stringify({ message: err.toString() }); - } -} - -runAsWorker(makeRequest); diff --git a/resources/original/preview2-shim/http/synckit/index.d.ts b/resources/original/preview2-shim/http/synckit/index.d.ts deleted file mode 100644 index 73e2e8f9..00000000 --- a/resources/original/preview2-shim/http/synckit/index.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/// -import { MessagePort } from "node:worker_threads"; -export type AnyFn = (...args: T) => R; -export type AnyPromise = Promise; -export type AnyAsyncFn = AnyFn>; -export type Syncify = T extends ( - ...args: infer Args -) => Promise - ? (...args: Args) => R - : never; -export type PromiseType = T extends Promise - ? R - : never; -export interface MainToWorkerMessage { - sharedBuffer: SharedArrayBuffer; - id: number; - args: T; -} -export interface WorkerData { - workerPort: MessagePort; -} -export interface DataMessage { - result?: T; - error?: unknown; - properties?: unknown; -} -export interface WorkerToMainMessage extends DataMessage { - id: number; -} -export interface SyncifyOptions { - bufferSize?: number; - timeout?: number; - execArgv?: string[]; -} -export declare function createSyncFn( - workerPath: string, - bufferSize?: number, - timeout?: number -): Syncify; -export declare function createSyncFn( - workerPath: string, - options?: SyncifyOptions -): Syncify; -export declare function runAsWorker< - R = unknown, - T extends AnyAsyncFn = AnyAsyncFn ->(fn: T): void; diff --git a/resources/original/preview2-shim/http/synckit/index.js b/resources/original/preview2-shim/http/synckit/index.js deleted file mode 100644 index 22ce198e..00000000 --- a/resources/original/preview2-shim/http/synckit/index.js +++ /dev/null @@ -1,141 +0,0 @@ -// Based on: https://github.com/un-ts/synckit -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -import path from "node:path"; -import { - MessageChannel, - Worker, - receiveMessageOnPort, - workerData, - parentPort, -} from "node:worker_threads"; - -const DEFAULT_WORKER_BUFFER_SIZE = 1024; -const syncFnCache = new Map(); - -function extractProperties(object) { - if (object && typeof object === "object") { - const properties = {}; - for (const key in object) { - properties[key] = object[key]; - } - return properties; - } -} - -export function createSyncFn(workerPath, bufferSizeOrOptions, timeout) { - if (!path.isAbsolute(workerPath)) { - throw new Error("`workerPath` must be absolute"); - } - const cachedSyncFn = syncFnCache.get(workerPath); - if (cachedSyncFn) { - return cachedSyncFn; - } - const syncFn = startWorkerThread( - workerPath, - typeof bufferSizeOrOptions === "number" - ? { bufferSize: bufferSizeOrOptions, timeout } - : bufferSizeOrOptions - ); - syncFnCache.set(workerPath, syncFn); - return syncFn; -} - -function startWorkerThread( - workerPath, - { - bufferSize = DEFAULT_WORKER_BUFFER_SIZE, - timeout = undefined, - execArgv = [], - } = {} -) { - const { port1: mainPort, port2: workerPort } = new MessageChannel(); - const worker = new Worker(workerPath, { - workerData: { workerPort }, - transferList: [workerPort], - execArgv: execArgv, - }); - let nextID = 0; - const syncFn = (...args) => { - const id = nextID++; - const sharedBuffer = new SharedArrayBuffer(bufferSize); - const sharedBufferView = new Int32Array(sharedBuffer); - const msg = { sharedBuffer, id, args }; - worker.postMessage(msg); - const status = Atomics.wait(sharedBufferView, 0, 0, timeout); - if (!["ok", "not-equal"].includes(status)) { - throw new Error("Internal error: Atomics.wait() failed: " + status); - } - const { - id: id2, - result, - error, - properties, - } = receiveMessageOnPort(mainPort).message; - if (id !== id2) { - throw new Error(`Internal error: Expected id ${id} but got id ${id2}`); - } - if (error) { - throw Object.assign(error, properties); - } - return result; - }; - worker.unref(); - return syncFn; -} - -export function runAsWorker(fn) { - if (!workerData) { - return; - } - const { workerPort } = workerData; - try { - parentPort.on("message", ({ sharedBuffer, id, args }) => { - (async () => { - const sharedBufferView = new Int32Array(sharedBuffer); - let msg; - try { - msg = { id, result: await fn(...args) }; - } catch (error) { - msg = { id, error, properties: extractProperties(error) }; - } - workerPort.postMessage(msg); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - })(); - }); - } catch (error) { - parentPort.on("message", ({ sharedBuffer, id }) => { - const sharedBufferView = new Int32Array(sharedBuffer); - workerPort.postMessage({ - id, - error, - properties: extractProperties(error), - }); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - }); - } -} diff --git a/resources/original/preview2-shim/http/wasi-http.js b/resources/original/preview2-shim/http/wasi-http.js deleted file mode 100644 index 76947b9d..00000000 --- a/resources/original/preview2-shim/http/wasi-http.js +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '@bytecodealliance/preview2-shim/io'; -import * as http from '@bytecodealliance/preview2-shim/http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/README.md b/resources/transformed/README.md deleted file mode 100644 index 906ddd26..00000000 --- a/resources/transformed/README.md +++ /dev/null @@ -1,4 +0,0 @@ -### Source - -The folders in this repo are "forked" from the [jco repo](https://github.com/bytecodealliance/jco), -and come with their "Apache-2.0 WITH LLVM-exception" license. diff --git a/resources/transformed/preview2-shim/LICENSE b/resources/transformed/preview2-shim/LICENSE deleted file mode 100644 index f9d81955..00000000 --- a/resources/transformed/preview2-shim/LICENSE +++ /dev/null @@ -1,220 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - diff --git a/resources/transformed/preview2-shim/README.md b/resources/transformed/preview2-shim/README.md deleted file mode 100644 index 6c69811b..00000000 --- a/resources/transformed/preview2-shim/README.md +++ /dev/null @@ -1,17 +0,0 @@ -### Source - -This folder is a "fork" of the -[`packages/preview2-shim/lib`](https://github.com/bytecodealliance/jco/tree/main/packages/preview2-shim/lib) -folder in jco. - -### License - -The code in this folder is licensed under the "Apache-2.0 WITH LLVM-exception" license, -see [LICENSE](./LICENSE). - -### Changes - -- Replaced import path in `/http/wasi-http.js` -- Added the `index.js` file -- Added the `bundled.js` file -- Replaced `/browser/random.js` file with a "dummy" replacement diff --git a/resources/transformed/preview2-shim/browser/cli-base.js b/resources/transformed/preview2-shim/browser/cli-base.js deleted file mode 100644 index 34a44a16..00000000 --- a/resources/transformed/preview2-shim/browser/cli-base.js +++ /dev/null @@ -1,48 +0,0 @@ -let _env; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export const environment = { - getEnvironment () { - if (!_env) _env = []; - return _env; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const preopens = { - getDirectories () { - return []; - } -} - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; diff --git a/resources/transformed/preview2-shim/browser/cli.js b/resources/transformed/preview2-shim/browser/cli.js deleted file mode 100644 index 4d9acebf..00000000 --- a/resources/transformed/preview2-shim/browser/cli.js +++ /dev/null @@ -1,86 +0,0 @@ -let _env, _args = [], _cwd = null; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export function _setArgs (args) { - _args = args; -} - -export function _setCwd (cwd) { - _cwd = cwd; -} - -export const environment = { - getEnvironment () { - if (!_env) _setEnv(process.env); - return _env; - }, - getArguments () { - return _args; - }, - initialCwd () { - return _cwd; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; - -export const terminalInput = { - dropTerminalInput () { - - } -}; - -export const terminalOutput = { - dropTerminalOutput () { - - } -}; - -export const terminalStderr = { - getTerminalStderr () { - return 0; - } -}; - -export const terminalStdin = { - getTerminalStdin () { - return 1; - } -}; - -export const terminalStdout = { - getTerminalStdout () { - return 2; - } -}; diff --git a/resources/transformed/preview2-shim/browser/clocks.js b/resources/transformed/preview2-shim/browser/clocks.js deleted file mode 100644 index 1500a420..00000000 --- a/resources/transformed/preview2-shim/browser/clocks.js +++ /dev/null @@ -1,46 +0,0 @@ -function _hrtimeBigint () { - // performance.now() is in milliseconds, but we want nanoseconds - return BigInt(Math.floor(performance.now() * 1e6)); -} - -let _hrStart = _hrtimeBigint(); - -export const monotonicClock = { - resolution() { - return 1n; - }, - now () { - return _hrtimeBigint() - _hrStart; - }, - subscribe (_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } -}; - -export const timezone = { - display (timezone, when) { - console.log(`[timezone] DISPLAY ${timezone} ${when}`); - }, - - utcOffset (timezone, when) { - console.log(`[timezone] UTC OFFSET ${timezone} ${when}`); - return 0; - }, - - dropTimezone (timezone) { - console.log(`[timezone] DROP ${timezone}`); - } -}; - -export const wallClock = { - now() { - let now = Date.now(); // in milliseconds - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = (now % 1e3) * 1e6; - return { seconds, nanoseconds }; - }, - - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } -}; diff --git a/resources/transformed/preview2-shim/browser/filesystem.js b/resources/transformed/preview2-shim/browser/filesystem.js deleted file mode 100644 index d0a1e4ab..00000000 --- a/resources/transformed/preview2-shim/browser/filesystem.js +++ /dev/null @@ -1,157 +0,0 @@ -export const preopens = { - getDirectories () { - return []; - } -} - -export const types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } -}; - -export { types as filesystemTypes } diff --git a/resources/transformed/preview2-shim/browser/http.js b/resources/transformed/preview2-shim/browser/http.js deleted file mode 100644 index 592b3ad4..00000000 --- a/resources/transformed/preview2-shim/browser/http.js +++ /dev/null @@ -1,146 +0,0 @@ -import { UnexpectedError } from "../http/error.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {string} - */ -export function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : undefined; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(': '); - var key = parts.shift(); - var value = parts.join(': '); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body, - }; - } catch (err) { - throw new UnexpectedError(err.message); - } -} - -export const incomingHandler = { - handle () { - - } -}; - -export const outgoingHandler = { - handle () { - - } -}; - -export const types = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } -}; diff --git a/resources/transformed/preview2-shim/browser/index.js b/resources/transformed/preview2-shim/browser/index.js deleted file mode 100644 index 11add6fa..00000000 --- a/resources/transformed/preview2-shim/browser/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import * as clocks from "./clocks.js"; -import * as filesystem from "./filesystem.js"; -import * as http from "./http.js"; -import * as io from "./io.js"; -import * as logging from "./logging.js"; -import * as poll from "./poll.js"; -import * as random from "./random.js"; -import * as sockets from "./sockets.js"; -import * as cli from "./cli.js"; - -export const importObject = { - clocks, - filesystem, - http, - io, - logging, - poll, - random, - sockets, - cli, -}; - -export { WasiHttp } from "../http/wasi-http.js"; - -export default importObject; diff --git a/resources/transformed/preview2-shim/browser/io.js b/resources/transformed/preview2-shim/browser/io.js deleted file mode 100644 index 3422382d..00000000 --- a/resources/transformed/preview2-shim/browser/io.js +++ /dev/null @@ -1,60 +0,0 @@ -export const streams = { - read(s, len) { - console.log(`[streams] Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } -}; diff --git a/resources/transformed/preview2-shim/browser/logging.js b/resources/transformed/preview2-shim/browser/logging.js deleted file mode 100644 index 9c963ac7..00000000 --- a/resources/transformed/preview2-shim/browser/logging.js +++ /dev/null @@ -1,14 +0,0 @@ -const levels = ["trace", "debug", "info", "warn", "error", "critical"]; - -let logLevel = levels.indexOf("warn"); - -export const logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) return; - console[level](`(${context}) ${msg}\n`); - } -}; - -export function setLevel(level) { - logLevel = levels.indexOf(level); -} diff --git a/resources/transformed/preview2-shim/browser/poll.js b/resources/transformed/preview2-shim/browser/poll.js deleted file mode 100644 index 52d2fe36..00000000 --- a/resources/transformed/preview2-shim/browser/poll.js +++ /dev/null @@ -1,9 +0,0 @@ -export const poll = { - dropPollable (pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff (input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } -}; diff --git a/resources/transformed/preview2-shim/browser/random.js b/resources/transformed/preview2-shim/browser/random.js deleted file mode 100644 index cd9a3f91..00000000 --- a/resources/transformed/preview2-shim/browser/random.js +++ /dev/null @@ -1,41 +0,0 @@ -export const insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - }, -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - }, -}; - -export const random = { - getRandomBytes(len) { - // We don't really care about this impl, it will be overridden anyway - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - - getRandomU64() { - // We don't really care about this impl, it will be overridden anyway - return 0n; - }, - - insecureRandom() { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - }, -}; diff --git a/resources/transformed/preview2-shim/browser/sockets.js b/resources/transformed/preview2-shim/browser/sockets.js deleted file mode 100644 index 19aae42a..00000000 --- a/resources/transformed/preview2-shim/browser/sockets.js +++ /dev/null @@ -1,200 +0,0 @@ -export const instanceNetwork = { - instanceNetwork () { - console.log(`[sockets] instance network`); - } -}; - -export const ipNameLookup = { - dropResolveAddressStream () { - - }, - subscribe () { - - }, - resolveAddresses () { - - }, - resolveNextAddress () { - - }, - nonBlocking () { - - }, - setNonBlocking () { - - }, -}; - -export const network = { - dropNetwork () { - - } -}; - -export const tcpCreateSocket = { - createTcpSocket () { - - } -}; - -export const tcp = { - subscribe () { - - }, - dropTcpSocket() { - - }, - bind() { - - }, - connect() { - - }, - listen() { - - }, - accept() { - - }, - localAddress() { - - }, - remoteAddress() { - - }, - addressFamily() { - - }, - ipv6Only() { - - }, - setIpv6Only() { - - }, - setListenBacklogSize() { - - }, - keepAlive() { - - }, - setKeepAlive() { - - }, - noDelay() { - - }, - setNoDelay() { - - }, - unicastHopLimit() { - - }, - setUnicastHopLimit() { - - }, - receiveBufferSize() { - - }, - setReceiveBufferSize() { - - }, - sendBufferSize() { - - }, - setSendBufferSize() { - - }, - nonBlocking() { - - }, - setNonBlocking() { - - }, - shutdown() { - - } -}; - -export const udp = { - subscribe () { - - }, - - dropUdpSocket () { - - }, - - bind () { - - }, - - connect () { - - }, - - receive () { - - }, - - send () { - - }, - - localAddress () { - - }, - - remoteAddress () { - - }, - - addressFamily () { - - }, - - ipv6Only () { - - }, - - setIpv6Only () { - - }, - - unicastHopLimit () { - - }, - - setUnicastHopLimit () { - - }, - - receiveBufferSize () { - - }, - - setReceiveBufferSize () { - - }, - - sendBufferSize () { - - }, - - setSendBufferSize () { - - }, - - nonBlocking () { - - }, - - setNonBlocking () { - - } -}; - -export const udpCreateSocket = { - createUdpSocket () { - - } -}; diff --git a/resources/transformed/preview2-shim/bundled.js b/resources/transformed/preview2-shim/bundled.js deleted file mode 100644 index 259ead6e..00000000 --- a/resources/transformed/preview2-shim/bundled.js +++ /dev/null @@ -1,742 +0,0 @@ -(() => { - var __defProp = Object.defineProperty; - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - - // browser/clocks.js - var clocks_exports = {}; - __export(clocks_exports, { - monotonicClock: () => monotonicClock, - timezone: () => timezone, - wallClock: () => wallClock - }); - function _hrtimeBigint() { - return BigInt(Math.floor(performance.now() * 1e6)); - } - var _hrStart = _hrtimeBigint(); - var monotonicClock = { - resolution() { - return 1n; - }, - now() { - return _hrtimeBigint() - _hrStart; - }, - subscribe(_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } - }; - var timezone = { - display(timezone2, when) { - console.log(`[timezone] DISPLAY ${timezone2} ${when}`); - }, - utcOffset(timezone2, when) { - console.log(`[timezone] UTC OFFSET ${timezone2} ${when}`); - return 0; - }, - dropTimezone(timezone2) { - console.log(`[timezone] DROP ${timezone2}`); - } - }; - var wallClock = { - now() { - let now = Date.now(); - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = now % 1e3 * 1e6; - return { seconds, nanoseconds }; - }, - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } - }; - - // browser/filesystem.js - var filesystem_exports = {}; - __export(filesystem_exports, { - filesystemTypes: () => types, - preopens: () => preopens, - types: () => types - }); - var preopens = { - getDirectories() { - return []; - } - }; - var types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } - }; - - // browser/http.js - var http_exports = {}; - __export(http_exports, { - incomingHandler: () => incomingHandler, - outgoingHandler: () => outgoingHandler, - send: () => send, - types: () => types2 - }); - - // http/error.js - var UnexpectedError = class extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message - }; - } - }; - - // browser/http.js - function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : void 0; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(": "); - var key = parts.shift(); - var value = parts.join(": "); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body - }; - } catch (err) { - throw new UnexpectedError(err.message); - } - } - var incomingHandler = { - handle() { - } - }; - var outgoingHandler = { - handle() { - } - }; - var types2 = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } - }; - - // browser/io.js - var io_exports = {}; - __export(io_exports, { - streams: () => streams - }); - var streams = { - read(s, len) { - console.log(`[streams] Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), "ended"]; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), "ended"]; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } - }; - - // browser/logging.js - var logging_exports = {}; - __export(logging_exports, { - logging: () => logging, - setLevel: () => setLevel - }); - var levels = ["trace", "debug", "info", "warn", "error", "critical"]; - var logLevel = levels.indexOf("warn"); - var logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) - return; - console[level](`(${context}) ${msg} -`); - } - }; - function setLevel(level) { - logLevel = levels.indexOf(level); - } - - // browser/poll.js - var poll_exports = {}; - __export(poll_exports, { - poll: () => poll - }); - var poll = { - dropPollable(pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff(input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } - }; - - // browser/random.js - var random_exports = {}; - __export(random_exports, { - insecure: () => insecure, - insecureSeed: () => insecureSeed, - random: () => random - }); - var insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - } - }; - var insecureSeedValue1; - var insecureSeedValue2; - var insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === void 0) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - } - }; - var random = { - getRandomBytes(len) { - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - getRandomU64() { - return 0n; - }, - insecureRandom() { - if (insecureRandomValue1 === void 0) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - } - }; - - // browser/sockets.js - var sockets_exports = {}; - __export(sockets_exports, { - instanceNetwork: () => instanceNetwork, - ipNameLookup: () => ipNameLookup, - network: () => network, - tcp: () => tcp, - tcpCreateSocket: () => tcpCreateSocket, - udp: () => udp, - udpCreateSocket: () => udpCreateSocket - }); - var instanceNetwork = { - instanceNetwork() { - console.log(`[sockets] instance network`); - } - }; - var ipNameLookup = { - dropResolveAddressStream() { - }, - subscribe() { - }, - resolveAddresses() { - }, - resolveNextAddress() { - }, - nonBlocking() { - }, - setNonBlocking() { - } - }; - var network = { - dropNetwork() { - } - }; - var tcpCreateSocket = { - createTcpSocket() { - } - }; - var tcp = { - subscribe() { - }, - dropTcpSocket() { - }, - bind() { - }, - connect() { - }, - listen() { - }, - accept() { - }, - localAddress() { - }, - remoteAddress() { - }, - addressFamily() { - }, - ipv6Only() { - }, - setIpv6Only() { - }, - setListenBacklogSize() { - }, - keepAlive() { - }, - setKeepAlive() { - }, - noDelay() { - }, - setNoDelay() { - }, - unicastHopLimit() { - }, - setUnicastHopLimit() { - }, - receiveBufferSize() { - }, - setReceiveBufferSize() { - }, - sendBufferSize() { - }, - setSendBufferSize() { - }, - nonBlocking() { - }, - setNonBlocking() { - }, - shutdown() { - } - }; - var udp = { - subscribe() { - }, - dropUdpSocket() { - }, - bind() { - }, - connect() { - }, - receive() { - }, - send() { - }, - localAddress() { - }, - remoteAddress() { - }, - addressFamily() { - }, - ipv6Only() { - }, - setIpv6Only() { - }, - unicastHopLimit() { - }, - setUnicastHopLimit() { - }, - receiveBufferSize() { - }, - setReceiveBufferSize() { - }, - sendBufferSize() { - }, - setSendBufferSize() { - }, - nonBlocking() { - }, - setNonBlocking() { - } - }; - var udpCreateSocket = { - createUdpSocket() { - } - }; - - // browser/cli.js - var cli_exports = {}; - __export(cli_exports, { - _setArgs: () => _setArgs, - _setCwd: () => _setCwd, - _setEnv: () => _setEnv, - environment: () => environment, - exit: () => exit, - stderr: () => stderr, - stdin: () => stdin, - stdout: () => stdout, - terminalInput: () => terminalInput, - terminalOutput: () => terminalOutput, - terminalStderr: () => terminalStderr, - terminalStdin: () => terminalStdin, - terminalStdout: () => terminalStdout - }); - var _env; - var _args = []; - var _cwd = null; - function _setEnv(envObj) { - _env = Object.entries(envObj); - } - function _setArgs(args) { - _args = args; - } - function _setCwd(cwd) { - _cwd = cwd; - } - var environment = { - getEnvironment() { - if (!_env) - _setEnv(process.env); - return _env; - }, - getArguments() { - return _args; - }, - initialCwd() { - return _cwd; - } - }; - var ComponentExit = class extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? "successfully" : "with error"}`); - this.code = code; - } - }; - var exit = { - exit(status) { - throw new ComponentExit(status.tag === "err" ? 1 : 0); - } - }; - var stdin = { - getStdin() { - return 0; - } - }; - var stdout = { - getStdout() { - return 1; - } - }; - var stderr = { - getStderr() { - return 2; - } - }; - var terminalInput = { - dropTerminalInput() { - } - }; - var terminalOutput = { - dropTerminalOutput() { - } - }; - var terminalStderr = { - getTerminalStderr() { - return 0; - } - }; - var terminalStdin = { - getTerminalStdin() { - return 1; - } - }; - var terminalStdout = { - getTerminalStdout() { - return 2; - } - }; - - // browser/index.js - var importObject = { - clocks: clocks_exports, - filesystem: filesystem_exports, - http: http_exports, - io: io_exports, - logging: logging_exports, - poll: poll_exports, - random: random_exports, - sockets: sockets_exports, - cli: cli_exports - }; - var browser_default = importObject; - - // index.js - function getWasiImports() { - let exports = { ...browser_default, "cli-base": browser_default.cliBase }; - let wasiExports = {}; - for (let package_name in exports) { - for (let export_name in exports[package_name]) { - let export_name_tr = export_name; - if (export_name == "monotonicClock") { - export_name_tr = "monotonic-clock"; - } - if (export_name == "wallClock") { - export_name_tr = "wall-clock"; - } - wasiExports[`wasi:${package_name}/${export_name_tr}`] = exports[package_name][export_name]; - } - } - return wasiExports; - } -})(); diff --git a/resources/transformed/preview2-shim/bundled_new.js b/resources/transformed/preview2-shim/bundled_new.js deleted file mode 100644 index e69de29b..00000000 diff --git a/resources/transformed/preview2-shim/http/error.js b/resources/transformed/preview2-shim/http/error.js deleted file mode 100644 index 748f20cb..00000000 --- a/resources/transformed/preview2-shim/http/error.js +++ /dev/null @@ -1,11 +0,0 @@ -export class UnexpectedError extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message, - }; - } -} diff --git a/resources/transformed/preview2-shim/http/make-request.js b/resources/transformed/preview2-shim/http/make-request.js deleted file mode 100644 index ee743244..00000000 --- a/resources/transformed/preview2-shim/http/make-request.js +++ /dev/null @@ -1,30 +0,0 @@ -import { runAsWorker } from "./synckit/index.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {Promise} - */ -async function makeRequest(req) { - try { - let headers = new Headers(req.headers); - const resp = await fetch(req.uri, { - method: req.method.toString(), - headers, - body: req.body && req.body.length > 0 ? req.body : undefined, - redirect: "manual", - }); - let arrayBuffer = await resp.arrayBuffer(); - return JSON.stringify({ - status: resp.status, - headers: Array.from(resp.headers.entries()), - body: - arrayBuffer.byteLength > 0 - ? Buffer.from(arrayBuffer).toString("base64") - : undefined, - }); - } catch (err) { - return JSON.stringify({ message: err.toString() }); - } -} - -runAsWorker(makeRequest); diff --git a/resources/transformed/preview2-shim/http/synckit/index.d.ts b/resources/transformed/preview2-shim/http/synckit/index.d.ts deleted file mode 100644 index 73e2e8f9..00000000 --- a/resources/transformed/preview2-shim/http/synckit/index.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/// -import { MessagePort } from "node:worker_threads"; -export type AnyFn = (...args: T) => R; -export type AnyPromise = Promise; -export type AnyAsyncFn = AnyFn>; -export type Syncify = T extends ( - ...args: infer Args -) => Promise - ? (...args: Args) => R - : never; -export type PromiseType = T extends Promise - ? R - : never; -export interface MainToWorkerMessage { - sharedBuffer: SharedArrayBuffer; - id: number; - args: T; -} -export interface WorkerData { - workerPort: MessagePort; -} -export interface DataMessage { - result?: T; - error?: unknown; - properties?: unknown; -} -export interface WorkerToMainMessage extends DataMessage { - id: number; -} -export interface SyncifyOptions { - bufferSize?: number; - timeout?: number; - execArgv?: string[]; -} -export declare function createSyncFn( - workerPath: string, - bufferSize?: number, - timeout?: number -): Syncify; -export declare function createSyncFn( - workerPath: string, - options?: SyncifyOptions -): Syncify; -export declare function runAsWorker< - R = unknown, - T extends AnyAsyncFn = AnyAsyncFn ->(fn: T): void; diff --git a/resources/transformed/preview2-shim/http/synckit/index.js b/resources/transformed/preview2-shim/http/synckit/index.js deleted file mode 100644 index 22ce198e..00000000 --- a/resources/transformed/preview2-shim/http/synckit/index.js +++ /dev/null @@ -1,141 +0,0 @@ -// Based on: https://github.com/un-ts/synckit -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -import path from "node:path"; -import { - MessageChannel, - Worker, - receiveMessageOnPort, - workerData, - parentPort, -} from "node:worker_threads"; - -const DEFAULT_WORKER_BUFFER_SIZE = 1024; -const syncFnCache = new Map(); - -function extractProperties(object) { - if (object && typeof object === "object") { - const properties = {}; - for (const key in object) { - properties[key] = object[key]; - } - return properties; - } -} - -export function createSyncFn(workerPath, bufferSizeOrOptions, timeout) { - if (!path.isAbsolute(workerPath)) { - throw new Error("`workerPath` must be absolute"); - } - const cachedSyncFn = syncFnCache.get(workerPath); - if (cachedSyncFn) { - return cachedSyncFn; - } - const syncFn = startWorkerThread( - workerPath, - typeof bufferSizeOrOptions === "number" - ? { bufferSize: bufferSizeOrOptions, timeout } - : bufferSizeOrOptions - ); - syncFnCache.set(workerPath, syncFn); - return syncFn; -} - -function startWorkerThread( - workerPath, - { - bufferSize = DEFAULT_WORKER_BUFFER_SIZE, - timeout = undefined, - execArgv = [], - } = {} -) { - const { port1: mainPort, port2: workerPort } = new MessageChannel(); - const worker = new Worker(workerPath, { - workerData: { workerPort }, - transferList: [workerPort], - execArgv: execArgv, - }); - let nextID = 0; - const syncFn = (...args) => { - const id = nextID++; - const sharedBuffer = new SharedArrayBuffer(bufferSize); - const sharedBufferView = new Int32Array(sharedBuffer); - const msg = { sharedBuffer, id, args }; - worker.postMessage(msg); - const status = Atomics.wait(sharedBufferView, 0, 0, timeout); - if (!["ok", "not-equal"].includes(status)) { - throw new Error("Internal error: Atomics.wait() failed: " + status); - } - const { - id: id2, - result, - error, - properties, - } = receiveMessageOnPort(mainPort).message; - if (id !== id2) { - throw new Error(`Internal error: Expected id ${id} but got id ${id2}`); - } - if (error) { - throw Object.assign(error, properties); - } - return result; - }; - worker.unref(); - return syncFn; -} - -export function runAsWorker(fn) { - if (!workerData) { - return; - } - const { workerPort } = workerData; - try { - parentPort.on("message", ({ sharedBuffer, id, args }) => { - (async () => { - const sharedBufferView = new Int32Array(sharedBuffer); - let msg; - try { - msg = { id, result: await fn(...args) }; - } catch (error) { - msg = { id, error, properties: extractProperties(error) }; - } - workerPort.postMessage(msg); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - })(); - }); - } catch (error) { - parentPort.on("message", ({ sharedBuffer, id }) => { - const sharedBufferView = new Int32Array(sharedBuffer); - workerPort.postMessage({ - id, - error, - properties: extractProperties(error), - }); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - }); - } -} diff --git a/resources/transformed/preview2-shim/http/wasi-http.js b/resources/transformed/preview2-shim/http/wasi-http.js deleted file mode 100644 index 170f85fe..00000000 --- a/resources/transformed/preview2-shim/http/wasi-http.js +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '../browser//io'; -import * as http from '../browser//http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/preview2-shim/http/wasi-http.js-E b/resources/transformed/preview2-shim/http/wasi-http.js-E deleted file mode 100644 index 76947b9d..00000000 --- a/resources/transformed/preview2-shim/http/wasi-http.js-E +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '@bytecodealliance/preview2-shim/io'; -import * as http from '@bytecodealliance/preview2-shim/http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/preview2-shim/index.js b/resources/transformed/preview2-shim/index.js deleted file mode 100644 index 44b0d4e6..00000000 --- a/resources/transformed/preview2-shim/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import importObject from "./browser"; - -export function getWasiImports() { - let exports = { ...importObject, "cli-base": importObject.cliBase }; - - let wasiExports = {}; - - for (let package_name in exports) { - for (let export_name in exports[package_name]) { - let export_name_tr = export_name; - if (export_name == "monotonicClock") { - export_name_tr = "monotonic-clock"; - } - if (export_name == "wallClock") { - export_name_tr = "wall-clock"; - } - - wasiExports[`wasi:${package_name}/${export_name_tr}`] = - exports[package_name][export_name]; - } - } - - return wasiExports; -} diff --git a/resources/transformed/random.js b/resources/transformed/random.js deleted file mode 100644 index cd9a3f91..00000000 --- a/resources/transformed/random.js +++ /dev/null @@ -1,41 +0,0 @@ -export const insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - }, -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - }, -}; - -export const random = { - getRandomBytes(len) { - // We don't really care about this impl, it will be overridden anyway - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - - getRandomU64() { - // We don't really care about this impl, it will be overridden anyway - return 0n; - }, - - insecureRandom() { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - }, -}; diff --git a/resources/transformed/transform.sh b/resources/transformed/transform.sh deleted file mode 100755 index b0cd0d7a..00000000 --- a/resources/transformed/transform.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/sh -set -e - -## Wasi shim - -# copy the files -rm -rf /browser -rm -rf preview2-shim/http - -cp -r ../original/preview2-shim/browser preview2-shim -cp -r ../original/preview2-shim/http preview2-shim - -# change the import path -cd preview2-shim -sed -i -E 's#@bytecodealliance/preview2-shim#../browser/#' http/wasi-http.js - -# TODO: Crypto is not defined ... -cp ../random.js browser/random.js - -# bundle the files into a single file -esbuild index.js --bundle --outfile=bundled.js - -# return the import object from the bundle -head -n -1 bundled.js > bundled_new.js -echo >> bundled_new.js -echo ' return getWasiImports();' >> bundled_new.js -echo '})();' >> bundled_new.js -mv bundled_new.js bundled.js - -cd ..