diff --git a/.gitignore b/.gitignore index b9c8bc6e2..5e46eb408 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ target .wireit node_modules -dist \ No newline at end of file +dist +lib +*.tsbuildinfo diff --git a/Cargo.lock b/Cargo.lock index 26808daa5..e5688df2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,13 +327,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "example-crate" -version = "0.1.0" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1396,6 +1389,22 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags", + "bytes", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.2" @@ -1558,10 +1567,12 @@ dependencies = [ name = "usuba" version = "0.1.0" dependencies = [ + "anyhow", "async-trait", "axum", "blake3", "bytes", + "hyper-util", "mime_guess", "redb", "rust-embed", @@ -1570,16 +1581,19 @@ dependencies = [ "tempfile", "thiserror", "tokio", + "tower-http", "tracing", "tracing-subscriber", "utoipa", "utoipa-swagger-ui", + "wit-parser 0.208.1", ] [[package]] name = "usuba-compat" version = "0.1.0" dependencies = [ + "blake3", "js-component-bindgen", "wasmtime-environ", "wit-bindgen", diff --git a/Cargo.toml b/Cargo.toml index d1bc1843c..faa2002a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "rust/example-crate", "rust/usuba", "rust/usuba-compat" ] @@ -9,10 +8,12 @@ members = [ resolver = "2" [workspace.dependencies] +anyhow = { version = "1" } async-trait = { version = "0.1" } axum = { version = "0.7" } blake3 = { version = "1.5" } bytes = { version = "1" } +hyper-util = { version = "0.1", features = ["client", "client-legacy"] } js-component-bindgen = { version = "1", features = ["transpile-bindgen"] } js-sys = { version = "0.3" } mime_guess = { version = "2" } @@ -23,6 +24,7 @@ serde_json = { version = "1" } tempfile = { version = "3" } thiserror = { version = "1" } tokio = { version = "1" } +tower-http = { version = "0.5" } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = ["env-filter", "tracing-log", "json"] } tracing-web = { version = "0.1" } @@ -32,7 +34,8 @@ wasm-bindgen = { version = "0.2" } wasmtime-environ = { version = "20" } web-sys = { version = "0.3" } wit-bindgen = { version = "0.25" } +wit-parser = { version = "0.208" } [profile.release] opt-level = 'z' -lto = true \ No newline at end of file +lto = true diff --git a/rust/example-crate/Cargo.toml b/rust/example-crate/Cargo.toml deleted file mode 100644 index 25ee8d9d8..000000000 --- a/rust/example-crate/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "example-crate" -version = "0.1.0" -edition = "2021" -description = "A Rust library that works on the web, in Deno and natively" -keywords = ["example"] -categories = [ - "command-line interface" -] -rust-version = "1.75.0" -license = "UNLICENSED" -documentation = "https://github.com/commontoolsinc/labs" -repository = "https://github.com/commontoolsinc/labs" -homepage = "https://github.com/commontoolsinc/labs" -readme = "README.md" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -wit-bindgen = { workspace = true } - diff --git a/rust/example-crate/README.md b/rust/example-crate/README.md deleted file mode 100644 index 2570cd8f5..000000000 --- a/rust/example-crate/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Example Crate - -This crate implements a simple Rust library. It is able to be used in typical Rust programs, and it is also able to be compiled as a Wasm Component and run anywhere such a thing may be run (e.g., web browsers, Deno etc). - -## Usage - -To run a demo on your local target: `cargo run`. - -To build a Wasm Component for the web: `./build-wasm-component.sh` - -## References - -- Wasm components: https://github.com/WebAssembly/component-model -- WIT: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md -- WASI interfaces: https://wasi.dev/interfaces -- `wasm-tools`: https://github.com/bytecodealliance/wasm-tools -- `cargo-component`: https://github.com/bytecodealliance/cargo-component -- `warg`: https://warg.io/ - - "A secure registry protocol for Wasm packages" -- "Making JavaScript run fast on WebAssembly": https://bytecodealliance.org/articles/making-javascript-run-fast-on-webassembly -- "Changes to Rust's WASI targets": https://blog.rust-lang.org/2024/04/09/updates-to-rusts-wasi-targets.html \ No newline at end of file diff --git a/rust/example-crate/build-wasm-component.sh b/rust/example-crate/build-wasm-component.sh deleted file mode 100755 index a4c17503a..000000000 --- a/rust/example-crate/build-wasm-component.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -set -euxo pipefail - -SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) -pushd $SCRIPT_DIR - -cargo build --release --target wasm32-wasi - -pushd ../../target/wasm32-wasi/release - -if [[ ! -f ./wasi_snapshot_preview1_reactor.wasm ]]; then - wget https://github.com/bytecodealliance/wasmtime/releases/download/v20.0.2/wasi_snapshot_preview1.reactor.wasm -fi - -wasm-tools component new \ - ./example_crate.wasm \ - -o example_component.wasm \ - --adapt ./wasi_snapshot_preview1.reactor.wasm - -jco transpile ./example_component.wasm \ - -o ./example_component_package - -popd -popd \ No newline at end of file diff --git a/rust/example-crate/src/bin/cowsay.rs b/rust/example-crate/src/bin/cowsay.rs deleted file mode 100644 index 085c73523..000000000 --- a/rust/example-crate/src/bin/cowsay.rs +++ /dev/null @@ -1,6 +0,0 @@ -use example_crate::{Cows, Cowsayer}; - -pub fn main() { - println!("{}", Cowsayer::say("moo".into(), None)); - println!("{}", Cowsayer::say("hoo".into(), Some(Cows::Owl))); -} diff --git a/rust/example-crate/src/cowsayer/component.rs b/rust/example-crate/src/cowsayer/component.rs deleted file mode 100644 index 111c8738a..000000000 --- a/rust/example-crate/src/cowsayer/component.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Generates a "guest" trait based on the specified [WIT][1] definition -// -// [1]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md -wit_bindgen::generate!({ - world: "cowsay", -}); - -use super::native::{Cows as NativeCows, Cowsayer as NativeCowsayer}; -use exports::cow::{Cows, Guest}; - -impl From for NativeCows { - fn from(value: Cows) -> Self { - match value { - Cows::Default => NativeCows::Cow, - Cows::Owl => NativeCows::Owl, - } - } -} - -struct Cowsayer; - -impl Guest for Cowsayer { - fn say(text: String, cow: Option) -> String { - NativeCowsayer::say(text, cow.map(|cow| cow.into())) - } -} - -// Macro generates exportable Wasm Component functions that call into our -// implementation -export!(Cowsayer); diff --git a/rust/example-crate/src/cowsayer/mod.rs b/rust/example-crate/src/cowsayer/mod.rs deleted file mode 100644 index 9fc3ac236..000000000 --- a/rust/example-crate/src/cowsayer/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod native; - -pub use native::*; - -#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] -mod component; - -#[cfg(all(target_arch = "wasm32", target_os = "wasi"))] -pub use component::*; diff --git a/rust/example-crate/src/cowsayer/native.rs b/rust/example-crate/src/cowsayer/native.rs deleted file mode 100644 index 8960e3b69..000000000 --- a/rust/example-crate/src/cowsayer/native.rs +++ /dev/null @@ -1,33 +0,0 @@ -pub enum Cows { - Cow, - Owl, -} - -// A token struct that will implement the "guest" trait -pub struct Cowsayer; - -impl Cowsayer { - pub fn say(text: String, cow: Option) -> String { - match cow { - Some(Cows::Owl) => { - format!( - r#"{text} - ___ - (o o) - ( V ) -/--m-m-"# - ) - } - _ => { - format!( - r#"{text} - \\ ^__^ - \\ (oo)\\______ - (__)\\ )\/\\ - ||----w | - || ||"# - ) - } - } - } -} diff --git a/rust/example-crate/src/lib.rs b/rust/example-crate/src/lib.rs deleted file mode 100644 index 9e29fbbbf..000000000 --- a/rust/example-crate/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod cowsayer; - -pub use cowsayer::*; diff --git a/rust/example-crate/wit/cowsay.wit b/rust/example-crate/wit/cowsay.wit deleted file mode 100644 index 45c41c2e7..000000000 --- a/rust/example-crate/wit/cowsay.wit +++ /dev/null @@ -1,12 +0,0 @@ -package local:cowsay; - -world cowsay { - export cow: interface { - enum cows { - default, - owl - } - - say: func(text: string, cow: option) -> string; - } -} \ No newline at end of file diff --git a/rust/usuba-compat/Cargo.toml b/rust/usuba-compat/Cargo.toml index 2eb428e60..dcceeead1 100644 --- a/rust/usuba-compat/Cargo.toml +++ b/rust/usuba-compat/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" crate-type = ["cdylib", "rlib"] [dependencies] +blake3 = { workspace = true } js-component-bindgen = { workspace = true } wit-bindgen = { workspace = true } wasmtime-environ = { workspace = true, features = ["component-model", "compile"] } \ No newline at end of file diff --git a/rust/usuba-compat/build-wasm-component.sh b/rust/usuba-compat/build-wasm-component.sh index 3a8f8ede2..01dc2a771 100755 --- a/rust/usuba-compat/build-wasm-component.sh +++ b/rust/usuba-compat/build-wasm-component.sh @@ -18,7 +18,7 @@ wasm-tools component new \ -o usuba_compat.component.wasm \ --adapt ./wasi_snapshot_preview1.reactor.wasm -jco transpile -O --tla-compat ./usuba_compat.component.wasm \ +jco transpile --tla-compat ./usuba_compat.component.wasm \ -o ./usuba_compat popd diff --git a/rust/usuba-compat/src/lib.rs b/rust/usuba-compat/src/lib.rs index 9620f27ab..3b7d5adb1 100644 --- a/rust/usuba-compat/src/lib.rs +++ b/rust/usuba-compat/src/lib.rs @@ -1,4 +1,4 @@ -use js_component_bindgen::{transpile, TranspileOpts, Transpiled}; +use js_component_bindgen::{transpile, InstantiationMode, TranspileOpts, Transpiled}; use wasmtime_environ::component::Export as WasmtimeExport; wit_bindgen::generate!({ @@ -15,7 +15,10 @@ impl Guest for Polyfill { .mappings .map(|mappings| mappings.into_iter().collect()), no_typescript: true, - instantiation: None, + instantiation: options + .instantiation + .unwrap_or_else(|| Instantiation::Automatic) + .into(), import_bindings: None, no_nodejs_compat: true, base64_cutoff: 1024, @@ -30,10 +33,23 @@ impl Guest for Polyfill { .map(|transpiled| transpiled.into()) .map_err(|error| format!("{}", error)) } + + fn hash(bytes: Vec) -> String { + blake3::hash(&bytes).to_string() + } } export!(Polyfill); +impl From for Option { + fn from(value: Instantiation) -> Self { + match value { + Instantiation::Automatic => None, + Instantiation::Manual => Some(InstantiationMode::Async), + } + } +} + impl From for Artifacts { fn from(value: Transpiled) -> Self { Artifacts { diff --git a/rust/usuba-compat/wit/usuba-compat.wit b/rust/usuba-compat/wit/usuba-compat.wit index 04e25250f..fd4bd5510 100644 --- a/rust/usuba-compat/wit/usuba-compat.wit +++ b/rust/usuba-compat/wit/usuba-compat.wit @@ -6,7 +6,13 @@ world usuba-compat { record polyfill-options { name: string, - mappings: option + mappings: option, + instantiation: option + } + + enum instantiation { + automatic, + manual } enum export-type { @@ -21,4 +27,5 @@ world usuba-compat { } export polyfill: func(component: list, options: polyfill-options) -> result; + export hash: func(bytes: list) -> string; } \ No newline at end of file diff --git a/rust/usuba/Cargo.toml b/rust/usuba/Cargo.toml index effb467cb..d49d5c8c9 100644 --- a/rust/usuba/Cargo.toml +++ b/rust/usuba/Cargo.toml @@ -7,10 +7,12 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = { workspace = true } async-trait = { workspace = true } axum = { workspace = true, features = ["multipart"] } blake3 = { workspace = true } bytes = { workspace = true } +hyper-util = { workspace = true } mime_guess = { workspace = true } redb = { workspace = true } rust-embed = { workspace = true } @@ -19,9 +21,11 @@ serde_json = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread", "io-util", "process", "fs"] } +tower-http = { workspace = true, features = ["cors"] } tracing = { workspace = true } tracing-subscriber = { workspace = true } utoipa = { workspace = true, features = ["axum_extras"] } utoipa-swagger-ui = { workspace = true, features = ["axum"] } +wit-parser = { workspace = true } # gcloud-sdk = { version = "0.24.6", features = ["google-cloud-aiplatform-v1"] } diff --git a/rust/usuba/src/bake/bake.rs b/rust/usuba/src/bake/bake.rs index 638521c6e..27dba5694 100644 --- a/rust/usuba/src/bake/bake.rs +++ b/rust/usuba/src/bake/bake.rs @@ -4,5 +4,11 @@ use bytes::Bytes; #[async_trait] pub trait Bake { - async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result; + async fn bake( + &self, + world: &str, + wit: Vec, + source_code: Bytes, + library: Vec, + ) -> Result; } diff --git a/rust/usuba/src/bake/fs.rs b/rust/usuba/src/bake/fs.rs new file mode 100644 index 000000000..a2b586e0b --- /dev/null +++ b/rust/usuba/src/bake/fs.rs @@ -0,0 +1,12 @@ +use std::{io::Cursor, path::PathBuf}; + +use bytes::Bytes; + +use crate::UsubaError; + +pub async fn write_file(path: PathBuf, bytes: Bytes) -> Result<(), UsubaError> { + let mut file = tokio::fs::File::create(&path).await?; + let mut cursor = Cursor::new(bytes.as_ref()); + tokio::io::copy(&mut cursor, &mut file).await?; + Ok(()) +} diff --git a/rust/usuba/src/bake/javascript.rs b/rust/usuba/src/bake/javascript.rs index ed7a4baee..70decac21 100644 --- a/rust/usuba/src/bake/javascript.rs +++ b/rust/usuba/src/bake/javascript.rs @@ -1,4 +1,3 @@ -use std::io::Cursor; use tracing::instrument; use super::Bake; @@ -7,6 +6,9 @@ use bytes::Bytes; use tempfile::TempDir; use tokio::process::Command; +use tokio::task::JoinSet; + +use crate::write_file; #[derive(Debug)] pub struct JavaScriptBaker {} @@ -14,7 +16,13 @@ pub struct JavaScriptBaker {} #[async_trait] impl Bake for JavaScriptBaker { #[instrument] - async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result { + async fn bake( + &self, + world: &str, + wit: Vec, + source_code: Bytes, + library: Vec, + ) -> Result { let workspace = TempDir::new()?; debug!( "Created temporary workspace in {}", @@ -23,31 +31,42 @@ impl Bake for JavaScriptBaker { let wasm_path = workspace.path().join("module.wasm"); let js_path = workspace.path().join("module.js"); - let wit_path = workspace.path().join("module.wit"); - let (mut wit_file, mut js_file) = tokio::try_join!( - tokio::fs::File::create(&wit_path), - tokio::fs::File::create(&js_path), - )?; + debug!(?workspace, "Created temporary workspace"); + + let wit_path = workspace.path().join("wit"); + let wit_deps_path = wit_path.join("deps"); - debug!(?wit_path, ?js_path, "Created temporary input files"); + tokio::fs::create_dir_all(&wit_deps_path).await?; - let mut wit_cursor = Cursor::new(wit); - let mut js_cursor = Cursor::new(source_code); + let mut writes = JoinSet::new(); - tokio::try_join!( - tokio::io::copy(&mut wit_cursor, &mut wit_file), - tokio::io::copy(&mut js_cursor, &mut js_file), - )?; + wit.into_iter() + .enumerate() + .map(|(i, wit)| write_file(wit_path.join(format!("module{}.wit", i)), wit)) + .chain([write_file(js_path.clone(), source_code)]) + .chain( + library.into_iter().enumerate().map(|(i, wit)| { + write_file(wit_deps_path.join(format!("library{}.wit", i)), wit) + }), + ) + .for_each(|fut| { + writes.spawn(fut); + }); + + while let Some(result) = writes.try_join_next() { + result??; + continue; + } - debug!(?wit_path, ?js_path, "Populated temporary input files"); + debug!(?workspace, "Populated temporary input files"); let mut command = Command::new("jco"); command .arg("componentize") .arg("-w") - .arg(wit_path.display().to_string()) + .arg(wit_path) .arg("-o") .arg(wasm_path.display().to_string()) .arg(js_path.display().to_string()); diff --git a/rust/usuba/src/bake/mod.rs b/rust/usuba/src/bake/mod.rs index fde35aff0..3e4935879 100644 --- a/rust/usuba/src/bake/mod.rs +++ b/rust/usuba/src/bake/mod.rs @@ -1,21 +1,41 @@ mod bake; +mod fs; mod javascript; +mod python; pub use bake::*; +pub use fs::*; pub use javascript::*; +pub use python::*; use async_trait::async_trait; use bytes::Bytes; pub enum Baker { JavaScript, + Python, } #[async_trait] impl Bake for Baker { - async fn bake(&self, wit: Bytes, source_code: Bytes) -> Result { + async fn bake( + &self, + world: &str, + wit: Vec, + source_code: Bytes, + library: Vec, + ) -> Result { match self { - Baker::JavaScript => (JavaScriptBaker {}).bake(wit, source_code).await, + Baker::JavaScript => { + (JavaScriptBaker {}) + .bake(world, wit, source_code, library) + .await + } + Baker::Python => { + (PythonBaker {}) + .bake(world, wit, source_code, library) + .await + } } } } diff --git a/rust/usuba/src/bake/python.rs b/rust/usuba/src/bake/python.rs new file mode 100644 index 000000000..262bb7bca --- /dev/null +++ b/rust/usuba/src/bake/python.rs @@ -0,0 +1,89 @@ +use async_trait::async_trait; +use bytes::Bytes; +use tempfile::TempDir; +use tokio::{process::Command, task::JoinSet}; + +use crate::{write_file, Bake}; + +#[derive(Debug)] +pub struct PythonBaker {} + +#[async_trait] +impl Bake for PythonBaker { + #[instrument] + async fn bake( + &self, + world: &str, + wit: Vec, + source_code: Bytes, + library: Vec, + ) -> Result { + let workspace = TempDir::new()?; + debug!( + "Created temporary workspace in {}", + workspace.path().display() + ); + + let wasm_path = workspace.path().join("module.wasm"); + let python_path = workspace.path().join("module.py"); + + debug!(?workspace, "Created temporary workspace"); + + let wit_path = workspace.path().join("wit"); + let wit_deps_path = wit_path.join("deps"); + + tokio::fs::create_dir_all(&wit_deps_path).await?; + + let mut writes = JoinSet::new(); + + wit.into_iter() + .enumerate() + .map(|(i, wit)| write_file(wit_path.join(format!("module{}.wit", i)), wit)) + .chain([write_file(python_path.clone(), source_code)]) + .chain( + library.into_iter().enumerate().map(|(i, wit)| { + write_file(wit_deps_path.join(format!("library{}.wit", i)), wit) + }), + ) + .for_each(|fut| { + writes.spawn(fut); + }); + + while let Some(result) = writes.try_join_next() { + result??; + continue; + } + + debug!(?workspace, "Populated temporary input files"); + + let mut command = Command::new("componentize-py"); + + command + .current_dir(workspace.path()) + .arg("-d") + .arg(wit_path) + .arg("-w") + .arg(world) + .arg("componentize") + .arg("-p") + .arg(workspace.path().display().to_string()) + .arg("-o") + .arg("module.wasm") + .arg("module"); + + let child = command.spawn()?; + let output = child.wait_with_output().await?; + + if output.stderr.len() > 0 { + warn!("{}", String::from_utf8_lossy(&output.stderr)); + } + + debug!("Finished building with componentize-py"); + + let wasm_bytes = tokio::fs::read(&wasm_path).await?; + + info!("Finished baking"); + + Ok(wasm_bytes.into()) + } +} diff --git a/rust/usuba/src/bin/usuba.rs b/rust/usuba/src/bin/usuba.rs index b5fb5e29a..15119b545 100644 --- a/rust/usuba/src/bin/usuba.rs +++ b/rust/usuba/src/bin/usuba.rs @@ -17,10 +17,16 @@ pub async fn main() -> Result<(), UsubaError> { let port = std::option_env!("PORT").unwrap_or("8080"); let socket_address: SocketAddr = format!("0.0.0.0:{port}").parse()?; let listener = tokio::net::TcpListener::bind(socket_address).await?; + let upstream = std::option_env!("UPSTREAM") + .map(|upstream| upstream.parse().ok()) + .unwrap_or(None); info!("Server listening on {}", socket_address); + if let Some(upstream) = &upstream { + info!("Reverse proxying requests to {}", upstream); + } - serve(listener).await?; + serve(listener, upstream).await?; Ok(()) } diff --git a/rust/usuba/src/error.rs b/rust/usuba/src/error.rs index eaaa76771..a2a03e50c 100644 --- a/rust/usuba/src/error.rs +++ b/rust/usuba/src/error.rs @@ -1,10 +1,16 @@ // use std::fmt::Display; -use axum::{extract::multipart::MultipartError, http::StatusCode, response::IntoResponse, Json}; +use axum::{ + extract::multipart::MultipartError, + http::{uri::InvalidUri, StatusCode}, + response::IntoResponse, + Json, +}; use blake3::HexError; use redb::{CommitError, DatabaseError, StorageError, TableError, TransactionError}; use serde::{Deserialize, Serialize}; use thiserror::Error; +use tokio::task::JoinError; use tracing::subscriber::SetGlobalDefaultError; use utoipa::ToSchema; @@ -16,8 +22,12 @@ pub enum UsubaError { BakeFailure(String), #[error("Invalid configuration: {0}")] InvalidConfiguration(String), + #[error("Invalid module: {0}")] + InvalidModule(String), #[error("Module not found")] ModuleNotFound, + #[error("Upstream request failed: {0}")] + UpstreamError(String), #[error("An internal error occurred")] Internal(String), } @@ -89,14 +99,43 @@ impl From for UsubaError { } } +impl From for UsubaError { + fn from(value: JoinError) -> Self { + error!("{}", value); + UsubaError::Internal(format!("{}", value)) + } +} + +impl From for UsubaError { + fn from(value: anyhow::Error) -> Self { + error!("{}", value); + UsubaError::Internal(format!("{}", value)) + } +} + +impl From for UsubaError { + fn from(value: hyper_util::client::legacy::Error) -> Self { + UsubaError::UpstreamError(format!("{}", value)) + } +} + +impl From for UsubaError { + fn from(value: InvalidUri) -> Self { + warn!("{}", value); + UsubaError::BadRequest + } +} + impl IntoResponse for UsubaError { fn into_response(self) -> axum::response::Response { let status = match self { UsubaError::BadRequest => StatusCode::BAD_REQUEST, + UsubaError::InvalidModule(_) => StatusCode::BAD_REQUEST, UsubaError::BakeFailure(_) => StatusCode::INTERNAL_SERVER_ERROR, UsubaError::InvalidConfiguration(_) => StatusCode::BAD_REQUEST, UsubaError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, UsubaError::ModuleNotFound => StatusCode::NOT_FOUND, + UsubaError::UpstreamError(_) => StatusCode::BAD_GATEWAY, }; ( diff --git a/rust/usuba/src/routes/module/build.rs b/rust/usuba/src/routes/module/build.rs index 518542758..182c9cbc8 100644 --- a/rust/usuba/src/routes/module/build.rs +++ b/rust/usuba/src/routes/module/build.rs @@ -8,12 +8,16 @@ use axum::{ use bytes::Bytes; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +use wit_parser::UnresolvedPackage; use crate::{Bake, Baker, HashStorage, UsubaError, UsubaState}; #[derive(ToSchema)] +/// A `multipart/form-data` payload that consists of module WIT + source code as +/// well as additional (optional) library WIT files pub struct BuildModuleRequest { - pub files: Vec>, + pub module: Vec>, + pub library: Vec>, } #[derive(Serialize, Deserialize, ToSchema)] @@ -38,45 +42,75 @@ impl IntoResponse for BuildModuleResponse { ) )] pub async fn build_module( - State(UsubaState { mut storage }): State, + State(UsubaState { mut storage, .. }): State, mut form_data: Multipart, ) -> Result { - let mut wit: Option = None; + let mut world_name: Option = None; + let mut wit: Vec = Vec::new(); + let mut library: Vec = Vec::new(); let mut source_code: Option = None; let mut baker: Option = None; - 'collect_files: while let Some(field) = form_data.next_field().await? { + while let Some(field) = form_data.next_field().await? { if let Some(file_name) = field.file_name() { let file_name = PathBuf::from(file_name); - if let Some(extension) = file_name.extension() { - match extension.to_str() { - Some("wit") => { - wit = Some(field.bytes().await?); - } - Some("js") => { - source_code = Some(field.bytes().await?); - baker = Some(Baker::JavaScript); - } - _ => (), - }; - } - } + match field.name() { + Some("module") => { + if let Some(extension) = file_name.extension() { + match extension.to_str() { + Some("wit") => { + let module_wit = field.bytes().await?; + let wit_package = UnresolvedPackage::parse( + &PathBuf::from("module.wit"), + String::from_utf8_lossy(&module_wit).as_ref(), + )?; - match (&wit, &source_code, &baker) { - (Some(_), Some(_), Some(_)) => break 'collect_files, - _ => (), + wit.push(module_wit); + + world_name = Some( + wit_package + .worlds + .iter() + .nth(0) + .map(|(_, world)| world.name.clone()) + .ok_or_else(|| { + UsubaError::InvalidModule(format!( + "Module WIT does not contain a world" + )) + })?, + ); + } + Some("js") => { + source_code = Some(field.bytes().await?); + baker = Some(Baker::JavaScript); + } + Some("py") => { + source_code = Some(field.bytes().await?); + baker = Some(Baker::Python); + } + _ => (), + }; + } + } + Some("library") => { + library.push(field.bytes().await?); + } + Some(name) => warn!("Unexpected multipart content: {name}"), + _ => warn!("Skipping unnamed multipart content"), + }; } } - if let (Some(wit), Some(source_code), Some(baker)) = (wit, source_code, baker) { - let wasm = baker.bake(wit, source_code).await?; + if let (Some(world_name), Some(source_code), Some(baker)) = (world_name, source_code, baker) { + let wasm = baker.bake(&world_name, wit, source_code, library).await?; let hash = storage.write(wasm).await?; Ok(BuildModuleResponse { id: hash.to_string(), }) } else { + warn!("Insufficient payload inputs to build the module"); Err(UsubaError::BadRequest) } } diff --git a/rust/usuba/src/routes/module/retrieve.rs b/rust/usuba/src/routes/module/retrieve.rs index 94ff668ad..15d6791ae 100644 --- a/rust/usuba/src/routes/module/retrieve.rs +++ b/rust/usuba/src/routes/module/retrieve.rs @@ -15,7 +15,7 @@ use crate::{HashStorage, UsubaError, UsubaState}; ) )] pub async fn retrieve_module( - State(UsubaState { storage }): State, + State(UsubaState { storage, .. }): State, Path((id,)): Path<(String,)>, ) -> Result { let hash = Hash::from_str(&id)?; diff --git a/rust/usuba/src/routes/ui.rs b/rust/usuba/src/routes/ui.rs index fbd1b6f49..873ba0f29 100644 --- a/rust/usuba/src/routes/ui.rs +++ b/rust/usuba/src/routes/ui.rs @@ -1,9 +1,12 @@ use axum::{ + extract::{Request, State}, http::{header, StatusCode, Uri}, response::{IntoResponse, Response}, }; use rust_embed::Embed; +use crate::{UsubaError, UsubaState}; + #[derive(Embed)] #[folder = "../../typescript/packages/usuba-ui/dist"] struct Asset; @@ -27,11 +30,45 @@ where } } -pub async fn ui_file(uri: Uri) -> impl IntoResponse { +pub async fn ui_file( + uri: Uri, + State(UsubaState { + client, upstream, .. + }): State, + mut request: Request, +) -> Result { let path = uri.path().trim_start_matches('/').to_string(); - StaticFile(path) + let ui_response = StaticFile(path.clone()).into_response(); + + match (ui_response.status(), upstream) { + (StatusCode::NOT_FOUND, Some(upstream)) => { + *request.uri_mut() = Uri::try_from(format!( + "{}://{}/{}", + upstream + .scheme() + .map(|scheme| scheme.as_str()) + .unwrap_or("http"), + upstream + .authority() + .map(|authority| authority.as_str()) + .unwrap_or("localhost"), + path + ))?; + + client + .request(request) + .await + .map(|response| response.into_response()) + .map_err(|error| UsubaError::from(error)) + } + _ => Ok(ui_response), + } +} + +pub async fn upstream_index(state: State, request: Request) -> impl IntoResponse { + ui_file("/index.html".parse::().unwrap(), state, request).await } -pub async fn ui_index() -> impl IntoResponse { - ui_file("/index.html".parse::().unwrap()).await +pub async fn ui_index(state: State, request: Request) -> impl IntoResponse { + ui_file("/$.html".parse::().unwrap(), state, request).await } diff --git a/rust/usuba/src/serve.rs b/rust/usuba/src/serve.rs index 929bb75a7..833d2c578 100644 --- a/rust/usuba/src/serve.rs +++ b/rust/usuba/src/serve.rs @@ -1,33 +1,59 @@ +use std::time::Duration; + use axum::{ + body::Body, + http::{Method, Uri}, routing::{get, post}, Router, }; +use hyper_util::{ + client::legacy::{connect::HttpConnector, Client}, + rt::TokioExecutor, +}; use tokio::net::TcpListener; +use tower_http::cors::{Any, CorsLayer}; use utoipa::OpenApi; use utoipa_swagger_ui::SwaggerUi; use crate::{ error::UsubaError, openapi::OpenApiDocs, - routes::{build_module, retrieve_module, ui_file, ui_index}, + routes::{build_module, retrieve_module, ui_file, ui_index, upstream_index}, PersistedHashStorage, }; +pub type HttpClient = hyper_util::client::legacy::Client; + #[derive(Clone)] pub struct UsubaState { pub storage: PersistedHashStorage, + pub client: HttpClient, + pub upstream: Option, } -pub async fn serve(listener: TcpListener) -> Result<(), UsubaError> { +pub async fn serve(listener: TcpListener, upstream: Option) -> Result<(), UsubaError> { let storage = PersistedHashStorage::temporary()?; + let client: HttpClient = Client::<(), ()>::builder(TokioExecutor::new()) + .pool_idle_timeout(Duration::from_secs(30)) + .build_http(); + + let cors = CorsLayer::new() + .allow_methods([Method::GET, Method::POST]) + .allow_origin(Any); let app = Router::new() .merge(SwaggerUi::new("/swagger-ui").url("/openapi.json", OpenApiDocs::openapi())) .route("/api/v0/module", post(build_module)) .route("/api/v0/module/:id", get(retrieve_module)) - .route("/", get(ui_index)) + .route("/", get(upstream_index)) + .route("/$", get(ui_index)) .route("/*file", get(ui_file)) - .with_state(UsubaState { storage }); + .with_state(UsubaState { + storage, + client, + upstream, + }) + .layer(cors); axum::serve(listener, app.into_make_service()).await?; diff --git a/typescript/package-lock.json b/typescript/package-lock.json index ab156b71e..3798405cd 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -32,12 +32,64 @@ "url": "https://github.com/sponsors/philsturgeon" } }, + "node_modules/@bytecodealliance/jco": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco/-/jco-1.2.4.tgz", + "integrity": "sha512-uuOm9UkYqWp5uElYDNzlhjbdrAmczEvETgQdI1hFTk79h+mrmHPRV32pgRP5o1eHVwMIpuk4XQkDIhFbksurUw==", + "dev": true, + "workspaces": [ + "packages/preview2-shim" + ], + "dependencies": { + "@bytecodealliance/preview2-shim": "^0.16.2", + "binaryen": "^116.0.0", + "chalk-template": "^1", + "commander": "^12", + "mkdirp": "^3", + "ora": "^8", + "terser": "^5" + }, + "bin": { + "jco": "src/jco.js" + } + }, + "node_modules/@bytecodealliance/jco/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@bytecodealliance/preview2-shim": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.16.2.tgz", "integrity": "sha512-36MwesmbLSf3Y5/OHcS85iBaF0N92CQ4gpjtDVKSbrjxmrBKCWlWVfoQ03F/cqDg8k5K7pzVaVBH0XBIbTCfTQ==", "dev": true }, + "node_modules/@commontools/runtime-demo": { + "resolved": "packages/runtime-demo", + "link": true + }, + "node_modules/@commontools/std": { + "resolved": "packages/std", + "link": true + }, + "node_modules/@commontools/usuba-api": { + "resolved": "packages/usuba-api", + "link": true + }, + "node_modules/@commontools/usuba-rt": { + "resolved": "packages/usuba-rt", + "link": true + }, "node_modules/@commontools/usuba-sw": { "resolved": "packages/usuba-sw", "link": true @@ -114,6 +166,64 @@ "typescript": "^5.x" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -289,6 +399,18 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -320,6 +442,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/binaryen": { + "version": "116.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-116.0.0.tgz", + "integrity": "sha512-Hp0dXC6Cb/rTwWEoUS2BRghObE7g/S9umKtxuTDt3f61G6fNTE/YVew/ezyy3IdHcLx3f17qfh6LwETgCfvWkQ==", + "dev": true, + "bin": { + "wasm-opt": "bin/wasm-opt", + "wasm2js": "bin/wasm2js" + } + }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -332,6 +464,12 @@ "node": ">=8" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "node_modules/c12": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/c12/-/c12-1.10.0.tgz", @@ -364,6 +502,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.0.tgz", + "integrity": "sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -406,6 +571,33 @@ "consola": "^3.2.3" } }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -479,6 +671,12 @@ "url": "https://dotenvx.com" } }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, "node_modules/esbuild": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", @@ -517,10 +715,6 @@ "@esbuild/win32-x64": "0.20.2" } }, - "node_modules/example-package": { - "resolved": "packages/example-package", - "link": true - }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -617,6 +811,18 @@ "node": ">=8" } }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -729,6 +935,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -750,6 +968,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unicode-supported": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz", + "integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -811,6 +1041,34 @@ "@types/trusted-types": "^2.0.2" } }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -1024,6 +1282,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.0.1.tgz", + "integrity": "sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1160,6 +1441,46 @@ "node": ">=8.10.0" } }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -1282,6 +1603,60 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/strip-final-newline": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", @@ -1311,6 +1686,30 @@ "node": ">=10" } }, + "node_modules/terser": { + "version": "5.31.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz", + "integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1323,6 +1722,12 @@ "node": ">=8.0" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/typescript": { "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", @@ -1462,6 +1867,7 @@ }, "packages/example-package": { "version": "0.0.1", + "extraneous": true, "license": "UNLICENSED", "devDependencies": { "@bytecodealliance/preview2-shim": "^0.16.2", @@ -1470,10 +1876,58 @@ "wireit": "^0.14.4" } }, + "packages/runtime-demo": { + "name": "@commontools/runtime-demo", + "version": "0.0.1", + "license": "UNLICENSED", + "devDependencies": { + "@commontools/usuba-rt": "^0.0.1", + "@shoelace-style/shoelace": "^2.15.1", + "typescript": "^5.2.2", + "vite": "^5.2.0", + "wireit": "^0.14.4" + } + }, + "packages/std": { + "name": "@commontools/std", + "version": "0.0.1", + "license": "UNLICENSED", + "devDependencies": { + "@bytecodealliance/jco": "^1.2.4", + "typescript": "^5.2.2", + "wireit": "^0.14.4" + } + }, + "packages/usuba-api": { + "name": "@commontools/usuba-api", + "version": "0.0.1", + "license": "UNLICENSED", + "devDependencies": { + "@hey-api/openapi-ts": "^0.46.0", + "typescript": "^5.2.2", + "wireit": "^0.14.4" + } + }, + "packages/usuba-rt": { + "name": "@commontools/usuba-rt", + "version": "0.0.1", + "license": "UNLICENSED", + "dependencies": { + "@commontools/usuba-api": "^0.0.1" + }, + "devDependencies": { + "tslib": "^2.6.2", + "typescript": "^5.2.2", + "wireit": "^0.14.4" + } + }, "packages/usuba-sw": { "name": "@commontools/usuba-sw", "version": "0.0.1", "license": "UNLICENSED", + "dependencies": { + "@commontools/usuba-api": "^0.0.1" + }, "devDependencies": { "@bytecodealliance/preview2-shim": "^0.16.2", "@hey-api/openapi-ts": "^0.46.0", @@ -1491,6 +1945,7 @@ "@shoelace-style/shoelace": "^2.15.1" }, "devDependencies": { + "@commontools/usuba-api": "^0.0.1", "@commontools/usuba-sw": "^0.0.1", "typescript": "^5.2.2", "vite": "^5.2.0", diff --git a/typescript/package.json b/typescript/package.json index fd257608b..d5aab8573 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -10,7 +10,8 @@ "./packages/*" ], "scripts": { - "build": "wireit" + "build": "wireit", + "clean": "wireit" }, "repository": { "type": "git", @@ -26,10 +27,19 @@ "wireit": { "build": { "dependencies": [ - "./packages/example-package:build", + "./packages/usuba-rt:build", + "./packages/usuba-api:build", "./packages/usuba-sw:build", "./packages/usuba-ui:build" ] + }, + "clean": { + "dependencies": [ + "./packages/usuba-rt:clean", + "./packages/usuba-api:clean", + "./packages/usuba-sw:clean", + "./packages/usuba-ui:clean" + ] } } -} \ No newline at end of file +} diff --git a/typescript/packages/example-package/index.html b/typescript/packages/example-package/index.html deleted file mode 100644 index e73947fd4..000000000 --- a/typescript/packages/example-package/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - Cowsayer Web - - - - - - -

Vite + Lit

-
- - - \ No newline at end of file diff --git a/typescript/packages/example-package/package-lock.json b/typescript/packages/example-package/package-lock.json deleted file mode 100644 index 0c658987d..000000000 --- a/typescript/packages/example-package/package-lock.json +++ /dev/null @@ -1,1313 +0,0 @@ -{ - "name": "example-package", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "example-package", - "version": "0.0.1", - "license": "UNLICENSED", - "dependencies": { - "@bytecodealliance/preview2-shim": "^0.16.2", - "typescript": "^5.2.2", - "vite": "^5.2.0" - }, - "devDependencies": { - "@rollup/plugin-node-resolve": "^15.2.3", - "wireit": "^0.14.4" - } - }, - "node_modules/@bytecodealliance/preview2-shim": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.16.2.tgz", - "integrity": "sha512-36MwesmbLSf3Y5/OHcS85iBaF0N92CQ4gpjtDVKSbrjxmrBKCWlWVfoQ03F/cqDg8k5K7pzVaVBH0XBIbTCfTQ==" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", - "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", - "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/vite": { - "version": "5.2.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", - "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", - "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/wireit": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/wireit/-/wireit-0.14.4.tgz", - "integrity": "sha512-WNAXEw2cJs1nSRNJNRcPypARZNumgtsRTJFTNpd6turCA6JZ6cEwl4ZU3C1IHc/3IaXoPu9LdxcI5TBTdD6/pg==", - "dev": true, - "workspaces": [ - "vscode-extension", - "website" - ], - "dependencies": { - "braces": "^3.0.2", - "chokidar": "^3.5.3", - "fast-glob": "^3.2.11", - "jsonc-parser": "^3.0.0", - "proper-lockfile": "^4.1.2" - }, - "bin": { - "wireit": "bin/wireit.js" - }, - "engines": { - "node": ">=14.14.0" - } - } - } -} diff --git a/typescript/packages/example-package/package.json b/typescript/packages/example-package/package.json deleted file mode 100644 index 9d6e5bf34..000000000 --- a/typescript/packages/example-package/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "example-package", - "author": "The Common Authors", - "version": "0.0.1", - "description": "An example TypeScript + Wasm package for web, Deno and Node.js", - "license": "UNLICENSED", - "private": true, - "type": "module", - "scripts": { - "build": "wireit", - "deno": "wireit", - "serve": "wireit" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/commontoolsinc/labs.git" - }, - "bugs": { - "url": "https://github.com/commontoolsinc/labs/issues" - }, - "homepage": "https://github.com/commontoolsinc/labs#readme", - "devDependencies": { - "@bytecodealliance/preview2-shim": "^0.16.2", - "typescript": "^5.2.2", - "vite": "^5.2.0", - "wireit": "^0.14.4" - }, - "wireit": { - "build:wasm": { - "command": "../../../rust/example-crate/build-wasm-component.sh", - "files": [ - "../../../rust/**/*.rs" - ], - "output": [ - "./src/cowsayer-wasm/**" - ] - }, - "build": { - "command": "tsc && vite build", - "dependencies": [ - "build:wasm" - ] - }, - "serve": { - "command": "vite", - "service": true - }, - "preview": { - "command": "vite preview" - }, - "deno": { - "command": "deno run -q --allow-env --allow-read ./src/cowsayer.ts" - } - } -} \ No newline at end of file diff --git a/typescript/packages/example-package/src/cowsayer-wasm b/typescript/packages/example-package/src/cowsayer-wasm deleted file mode 120000 index 5834d5522..000000000 --- a/typescript/packages/example-package/src/cowsayer-wasm +++ /dev/null @@ -1 +0,0 @@ -../../../../target/wasm32-wasi/release/example_component_package \ No newline at end of file diff --git a/typescript/packages/example-package/src/cowsayer.ts b/typescript/packages/example-package/src/cowsayer.ts deleted file mode 100644 index dd361fdd7..000000000 --- a/typescript/packages/example-package/src/cowsayer.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { cow } from './cowsayer-wasm/example_component.js'; - -const cowSays = cow.say('moo', undefined); -const owlSays = cow.say('hoo', 'owl'); - -if (typeof document !== 'undefined') { - document.documentElement.innerHTML = ` -
-
-${cowSays}
-
-
- -
-
-${owlSays}
-
-
`; -} else { - console.log(cowSays); - console.log(owlSays); -} diff --git a/typescript/packages/example-package/tsconfig.json b/typescript/packages/example-package/tsconfig.json deleted file mode 100644 index efa6bfdf2..000000000 --- a/typescript/packages/example-package/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": false, - - /* Bundler mode */ - "moduleResolution": "node", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": [ - "src", - "node_modules/@bytecodealliance" - ] -} diff --git a/typescript/packages/example-package/vite.config.js b/typescript/packages/example-package/vite.config.js deleted file mode 100644 index 216a2f1bb..000000000 --- a/typescript/packages/example-package/vite.config.js +++ /dev/null @@ -1,8 +0,0 @@ -export default { - build: { - target: 'esnext' - }, - resolve: { - preserveSymlinks: true - } -}; \ No newline at end of file diff --git a/typescript/packages/runtime-demo/index.html b/typescript/packages/runtime-demo/index.html new file mode 100644 index 000000000..cc8e35529 --- /dev/null +++ b/typescript/packages/runtime-demo/index.html @@ -0,0 +1,31 @@ + + + + + + + Runtime Sandbox + + + + + + + +
+ + + + +
+ + + + + \ No newline at end of file diff --git a/typescript/packages/runtime-demo/package.json b/typescript/packages/runtime-demo/package.json new file mode 100644 index 000000000..0dbfcf435 --- /dev/null +++ b/typescript/packages/runtime-demo/package.json @@ -0,0 +1,39 @@ +{ + "name": "@commontools/runtime-demo", + "author": "The Common Authors", + "version": "0.0.1", + "description": "Testbed for usuba-rt", + "license": "UNLICENSED", + "private": true, + "type": "module", + "scripts": { + "build": "wireit", + "clean": "wireit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/commontoolsinc/labs.git" + }, + "bugs": { + "url": "https://github.com/commontoolsinc/labs/issues" + }, + "homepage": "https://github.com/commontoolsinc/labs#readme", + "devDependencies": { + "@commontools/usuba-rt": "^0.0.1", + "@shoelace-style/shoelace": "^2.15.1", + "typescript": "^5.2.2", + "vite": "^5.2.0", + "wireit": "^0.14.4" + }, + "wireit": { + "build": { + "dependencies": [ + "../usuba-rt:build" + ], + "command": "vite build" + }, + "clean": { + "command": "rm -rf ./lib ./dist ./.wireit" + } + } +} \ No newline at end of file diff --git a/typescript/packages/runtime-demo/public/shoelace b/typescript/packages/runtime-demo/public/shoelace new file mode 120000 index 000000000..07a2f6e41 --- /dev/null +++ b/typescript/packages/runtime-demo/public/shoelace @@ -0,0 +1 @@ +../../../node_modules/@shoelace-style/shoelace \ No newline at end of file diff --git a/typescript/packages/usuba-ui/public/styles.css b/typescript/packages/runtime-demo/public/styles.css similarity index 100% rename from typescript/packages/usuba-ui/public/styles.css rename to typescript/packages/runtime-demo/public/styles.css diff --git a/typescript/packages/runtime-demo/src/demo1.ts b/typescript/packages/runtime-demo/src/demo1.ts new file mode 100644 index 000000000..955215862 --- /dev/null +++ b/typescript/packages/runtime-demo/src/demo1.ts @@ -0,0 +1,80 @@ +import { Runtime } from '@commontools/usuba-rt'; + +export const COMMON_DIRECTORY_WIT = ` +package common:directory; + +interface lookup { + entry: func(index: u32) -> string; +} + +world directory { + export lookup; +}`; + +export const EXAMPLE_HELLO_WIT = ` +package example:hello; + +world hello { + import common:directory/lookup; + + export hello: func() -> string; +}`; + +export const EXAMPLE_HELLO_JS = ` +import { entry } from 'common:directory/lookup'; + +export function hello() { + let value = entry(Math.floor(Math.random() * 10)); + return 'Hello, Agent ' + value; +}`; + +export const demo = async () => { + console.log('Initializing Runtime'); + + const rt = new Runtime([COMMON_DIRECTORY_WIT]); + + console.log('Defining Module'); + + type ExpectedExports = { + hello: () => string; + }; + + const module = await rt.defineModule({ + contentType: 'text/javascript', + wit: EXAMPLE_HELLO_WIT, + sourceCode: EXAMPLE_HELLO_JS, + }); + + console.log('Instantiating Module'); + + const agents = [ + 'Marnie', + 'Orange', + 'Frank', + 'Moon', + 'Sparrow', + 'River', + 'Archer', + 'Bard', + 'Helman', + 'Poisson', + ]; + + const { hello } = await module.instantiate({ + 'common:directory/lookup': { + entry(index: number) { + return agents[Math.floor(index) % 10]; + }, + }, + }); + + console.log('Invoking Module API:'); + + console.log(`%c${hello()}`, 'font-size: 1.5em; font-weight: bold;'); + + (self as any).demos ||= {}; + (self as any).demos.one = { + hello, + }; + console.log('fin'); +}; diff --git a/typescript/packages/runtime-demo/src/demo2.ts b/typescript/packages/runtime-demo/src/demo2.ts new file mode 100644 index 000000000..d79398f03 --- /dev/null +++ b/typescript/packages/runtime-demo/src/demo2.ts @@ -0,0 +1,131 @@ +import { Runtime } from '@commontools/usuba-rt'; + +export const COMMON_ITERATOR_WIT = ` +package common:iterator; + +interface iterator { + variant value { + %string(string), + number(f64), + boolean(bool), + buffer(list) + } + + resource iterable { + next: func() -> option; + value: func() -> option; + } + + create: func() -> iterable; +} + +world common { + export iterator; +}`; + +export const USER_MODULE_JS = ` +class Iterable { + #iter; + #value; + + constructor(iter) { + this.#iter = iter; + this.#value = iter.next(); + } + + next() { + this.#value = this.#iter.next(); + if (this.#value.done) { + return; + } + return this; + } + + value() { + return { + tag: 'number', + val: this.#value.value + }; + } +} + +function *doWork() { + for (let i = 0; i < 10; ++i) { + yield i; + } +} + +export const iterator = { + Iterable, + create() { + const i = new Iterable(doWork()); + console.log('Doing work', i); + return new Iterable(doWork()); + } +};`; + +export const demo = async () => { + console.log('Initializing Runtime'); + + const rt = new Runtime([]); + + console.log('Defining Module'); + + type Value = + | { + tag: 'number'; + val: number; + } + | { + tag: 'string'; + val: string; + } + | { + tag: 'boolean'; + val: boolean; + } + | { + tag: 'buffer'; + val: Uint8Array; + }; + interface Iterator { + next(): Iterator | void; + value(): Value | void; + } + type ExpectedExports = { + iterator: { + create: () => Iterator; + }; + }; + + const module = await rt.defineModule({ + contentType: 'text/javascript', + wit: COMMON_ITERATOR_WIT, + sourceCode: USER_MODULE_JS, + }); + + console.log('Instantiating Module'); + + const { + iterator: { create: createIterator }, + } = await module.instantiate({}); + + console.log('Invoking Module API:'); + + for ( + let iterator: Iterator | void = createIterator(); + iterator; + iterator = iterator.next() + ) { + console.log( + `%cValue: ${iterator?.value()?.val}`, + 'font-size: 1.5em; font-weight: bold;' + ); + } + + (self as any).demos ||= {}; + (self as any).demos.four = { + createIterator, + }; + console.log('fin'); +}; diff --git a/typescript/packages/runtime-demo/src/demo3.ts b/typescript/packages/runtime-demo/src/demo3.ts new file mode 100644 index 000000000..8eb83ff92 --- /dev/null +++ b/typescript/packages/runtime-demo/src/demo3.ts @@ -0,0 +1,76 @@ +import { Runtime } from '@commontools/usuba-rt'; +import { + COMMON_DIRECTORY_WIT, + EXAMPLE_HELLO_WIT, + EXAMPLE_HELLO_JS, +} from './demo1.js'; + +export const COMMON_DIRECTORY_JS = ` +const agents = [ + 'Marnie', + 'Orange', + 'Frank', + 'Moon', + 'Sparrow', + 'River', + 'Archer', + 'Bard', + 'Helman', + 'Poisson', +]; + +export const lookup = { + entry: (index) => agents[Math.floor(Math.random() * agents.length)] +}; +`; + +export const demo = async () => { + console.log('Initializing first Runtime'); + + const rtOne = new Runtime([]); + + console.log('Defining first Module'); + + type ExpectedExportsOne = { + lookup: { + entry(index: number): string; + }; + }; + + const moduleOne = await rtOne.defineModule({ + contentType: 'text/javascript', + wit: COMMON_DIRECTORY_WIT, + sourceCode: COMMON_DIRECTORY_JS, + }); + + const rtTwo = new Runtime([COMMON_DIRECTORY_WIT]); + + console.log('Defining second Module'); + + type ExpectedExportsTwo = { + hello: () => string; + }; + + const moduleTwo = await rtTwo.defineModule({ + contentType: 'text/javascript', + wit: EXAMPLE_HELLO_WIT, + sourceCode: EXAMPLE_HELLO_JS, + }); + + console.log('Instantiating both Modules'); + + const { hello } = await moduleTwo.instantiate({ + 'common:directory/lookup': (await moduleOne.instantiate({})).lookup, + }); + + console.log('Invoking final Module API:'); + + console.log(`%c${hello()}`, 'font-size: 1.5em; font-weight: bold;'); + + (self as any).demos ||= {}; + (self as any).demos.two = { + hello, + }; + + console.log('fin'); +}; diff --git a/typescript/packages/runtime-demo/src/demo4.ts b/typescript/packages/runtime-demo/src/demo4.ts new file mode 100644 index 000000000..096700c1c --- /dev/null +++ b/typescript/packages/runtime-demo/src/demo4.ts @@ -0,0 +1,62 @@ +import { Runtime } from '@commontools/usuba-rt'; +import { COMMON_DIRECTORY_WIT, EXAMPLE_HELLO_WIT } from './demo1.js'; +import { COMMON_DIRECTORY_JS } from './demo3.js'; + +export const EXAMPLE_HELLO_PY = ` +import random +import hello +from hello.imports import lookup + +class Hello(hello.Hello): + def hello(self) -> str: + return "Hello, Agent %s!" % lookup.entry(random.randint(0, 9)) +`; + +export const demo = async () => { + console.log('Initializing first Runtime'); + + const rtOne = new Runtime([]); + + console.log('Defining first Module'); + + type ExpectedExportsOne = { + lookup: { + entry(index: number): string; + }; + }; + + const moduleOne = await rtOne.defineModule({ + contentType: 'text/javascript', + wit: COMMON_DIRECTORY_WIT, + sourceCode: COMMON_DIRECTORY_JS, + }); + + const rtTwo = new Runtime([COMMON_DIRECTORY_WIT]); + + console.log('Defining second Module'); + + type ExpectedExportsTwo = { + hello: () => string; + }; + + const moduleTwo = await rtTwo.defineModule({ + contentType: 'text/x-python', + wit: EXAMPLE_HELLO_WIT, + sourceCode: EXAMPLE_HELLO_PY, + }); + + console.log('Instantiating both Modules'); + + const { hello } = await moduleTwo.instantiate({ + 'common:directory/lookup': (await moduleOne.instantiate({})).lookup, + }); + + console.log('Invoking final Module API:'); + + console.log(`%c${hello()}`, 'font-size: 1.5em; font-weight: bold;'); + (self as any).demos ||= {}; + (self as any).demos.three = { + hello, + }; + console.log('fin'); +}; diff --git a/typescript/packages/runtime-demo/src/index.ts b/typescript/packages/runtime-demo/src/index.ts new file mode 100644 index 000000000..886cb67fc --- /dev/null +++ b/typescript/packages/runtime-demo/src/index.ts @@ -0,0 +1,9 @@ +import { demo as demoOne } from './demo1.js'; +import { demo as demoTwo } from './demo2.js'; +import { demo as demoThree } from './demo3.js'; +import { demo as demoFour } from './demo4.js'; + +(self as any).demoOne = demoOne; +(self as any).demoTwo = demoTwo; +(self as any).demoThree = demoThree; +(self as any).demoFour = demoFour; diff --git a/typescript/packages/runtime-demo/tsconfig.json b/typescript/packages/runtime-demo/tsconfig.json new file mode 100644 index 000000000..df767e62f --- /dev/null +++ b/typescript/packages/runtime-demo/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["es2022", "DOM"], + "outDir": "./lib", + "rootDir": "./src", + }, + "include": [ + "src/**/*" + ] +} diff --git a/typescript/packages/runtime-demo/vite.config.js b/typescript/packages/runtime-demo/vite.config.js new file mode 100644 index 000000000..edb6fa879 --- /dev/null +++ b/typescript/packages/runtime-demo/vite.config.js @@ -0,0 +1,12 @@ +// vite.config.js +import { resolve } from 'path' +import { defineConfig } from 'vite' + +export default defineConfig({ + build: { + target: 'esnext' + }, + resolve: { + preserveSymlinks: true + } +}) \ No newline at end of file diff --git a/typescript/packages/usuba-api/.gitignore b/typescript/packages/usuba-api/.gitignore new file mode 100644 index 000000000..eb5155b41 --- /dev/null +++ b/typescript/packages/usuba-api/.gitignore @@ -0,0 +1,2 @@ +openapi-client +lib diff --git a/typescript/packages/usuba-api/openapi.json b/typescript/packages/usuba-api/openapi.json new file mode 100644 index 000000000..5c840421b --- /dev/null +++ b/typescript/packages/usuba-api/openapi.json @@ -0,0 +1,154 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "usuba", + "description": "An anything-to-Common-Wasm build server", + "license": { + "name": "" + }, + "version": "0.1.0" + }, + "paths": { + "/api/v0/module": { + "post": { + "tags": [ + "crate::routes" + ], + "operationId": "build_module", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/BuildModuleRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successfully built the module", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BuildModuleResponse" + } + } + } + }, + "400": { + "description": "Bad request body", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/v0/module/{id}": { + "get": { + "tags": [ + "crate::routes" + ], + "operationId": "retrieve_module", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successfully retrieved the module", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Module not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "BuildModuleRequest": { + "type": "object", + "description": "A `multipart/form-data` payload that consists of module WIT + source code as\nwell as additional (optional) library WIT files", + "required": [ + "module", + "library" + ], + "properties": { + "library": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + }, + "module": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + } + }, + "BuildModuleResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + } + } + }, + "ErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "properties": { + "error": { + "type": "string" + } + } + } + } + } +} diff --git a/typescript/packages/usuba-api/package.json b/typescript/packages/usuba-api/package.json new file mode 100644 index 000000000..f78329074 --- /dev/null +++ b/typescript/packages/usuba-api/package.json @@ -0,0 +1,67 @@ +{ + "name": "@commontools/usuba-api", + "author": "The Common Authors", + "version": "0.0.1", + "description": "Auto-generated REST API client for the Usuba build server", + "license": "UNLICENSED", + "private": true, + "type": "module", + "scripts": { + "build": "wireit", + "clean": "wireit", + "update-openapi-spec": "wireit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/commontoolsinc/labs.git" + }, + "bugs": { + "url": "https://github.com/commontoolsinc/labs/issues" + }, + "homepage": "https://github.com/commontoolsinc/labs#readme", + "files": [ + "./lib/**/*" + ], + "exports": "./lib/index.js", + "devDependencies": { + "@hey-api/openapi-ts": "^0.46.0", + "typescript": "^5.2.2", + "wireit": "^0.14.4" + }, + "wireit": { + "update-openapi-spec": { + "command": "./scripts/update-openapi-spec.sh", + "files": [ + "./scripts/update-openapi-spec.sh" + ], + "output": [ + "./openapi.json" + ] + }, + "build:openapi-client": { + "command": "npx @hey-api/openapi-ts -i ./openapi.json -o ./src/openapi-client && ./scripts/fix-paths.sh", + "files": [ + "./scripts/fix-paths.sh", + "./openapi.json" + ], + "output": [ + "./src/openapi-client/**/*" + ] + }, + "build": { + "dependencies": [ + "build:openapi-client" + ], + "files": [ + "./src/**/*" + ], + "output": [ + "./lib/**/*" + ], + "command": "tsc --build -f" + }, + "clean": { + "command": "rm -rf ./lib ./.wireit" + } + } +} \ No newline at end of file diff --git a/typescript/packages/usuba-api/scripts/fix-paths.sh b/typescript/packages/usuba-api/scripts/fix-paths.sh new file mode 100755 index 000000000..348a002eb --- /dev/null +++ b/typescript/packages/usuba-api/scripts/fix-paths.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +# The autogenerated REST client has module specifiers that omit their `.js` +# extensions, which means they are incompatible with TypeScript's NodeNext +# module resolution. Since the code is autogenerated anyway, we post-process the +# specifiers here to "fix" them. + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +set -euo pipefail + +pushd $SCRIPT_DIR/../src/openapi-client + +find ./ -type f -exec sed -i "/import\|export/ s/\(.* '\.\/[^']*\)/\0.js/g" {} + + +popd + + + diff --git a/typescript/packages/usuba-sw/scripts/update-openapi-spec.sh b/typescript/packages/usuba-api/scripts/update-openapi-spec.sh similarity index 100% rename from typescript/packages/usuba-sw/scripts/update-openapi-spec.sh rename to typescript/packages/usuba-api/scripts/update-openapi-spec.sh diff --git a/typescript/packages/usuba-api/src/index.ts b/typescript/packages/usuba-api/src/index.ts new file mode 100644 index 000000000..a2eea3b30 --- /dev/null +++ b/typescript/packages/usuba-api/src/index.ts @@ -0,0 +1 @@ +export * from './openapi-client/index.js'; diff --git a/typescript/packages/usuba-api/tsconfig.json b/typescript/packages/usuba-api/tsconfig.json new file mode 100644 index 000000000..19199d7df --- /dev/null +++ b/typescript/packages/usuba-api/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2022", "WebWorker"], + "outDir": "./lib", + "rootDir": "./src", + }, + "include": [ + "src/**/*" + ] +} diff --git a/typescript/packages/usuba-rt/package.json b/typescript/packages/usuba-rt/package.json new file mode 100644 index 000000000..2fa2c694e --- /dev/null +++ b/typescript/packages/usuba-rt/package.json @@ -0,0 +1,50 @@ +{ + "name": "@commontools/usuba-rt", + "author": "The Common Authors", + "version": "0.0.1", + "description": "A Runtime for managing the invocation of Usuba-produced Modules", + "license": "UNLICENSED", + "private": true, + "type": "module", + "scripts": { + "build": "wireit", + "clean": "wireit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/commontoolsinc/labs.git" + }, + "bugs": { + "url": "https://github.com/commontoolsinc/labs/issues" + }, + "homepage": "https://github.com/commontoolsinc/labs#readme", + "exports": "./lib/index.js", + "files": [ + "./lib/*.js" + ], + "dependencies": { + "@commontools/usuba-api": "^0.0.1" + }, + "devDependencies": { + "tslib": "^2.6.2", + "typescript": "^5.2.2", + "wireit": "^0.14.4" + }, + "wireit": { + "build": { + "dependencies": [ + "../usuba-api:build" + ], + "files": [ + "./src/**/*" + ], + "output": [ + "./lib/**/*" + ], + "command": "tsc --build -f" + }, + "clean": { + "command": "rm -rf ./lib ./.wireit" + } + } +} \ No newline at end of file diff --git a/typescript/packages/usuba-rt/src/index.ts b/typescript/packages/usuba-rt/src/index.ts new file mode 100644 index 000000000..537a635fd --- /dev/null +++ b/typescript/packages/usuba-rt/src/index.ts @@ -0,0 +1,219 @@ +import * as apiClient from '@commontools/usuba-api'; + +export type SourceCode = string | Uint8Array; +export type PendingSourceCode = SourceCode | Promise; + +export type ContentType = 'text/javascript' | 'text/x-python'; + +export type ContentTypeFileExtensions = { + [C in ContentType]: string; +}; + +export interface ModuleDefinition { + contentType: ContentType; + wit: PendingSourceCode; + sourceCode: PendingSourceCode; +} + +export type Import = { + [index: string]: any; +}; + +export type ImportMap = { + [index: string]: Import; +}; + +export type Importable = string | Import | Promise; + +export type ImportableMap = { + [index: string]: Importable; +}; + +const FILE_EXTENSIONS: ContentTypeFileExtensions = { + 'text/javascript': 'js', + 'text/x-python': 'py', +}; + +const serviceWorkerActivates = (async () => { + if (typeof navigator.serviceWorker == 'undefined') { + throw new Error( + 'Service Worker is not supported in this browser; Usuba will not work here.' + ); + } + + try { + const registration = await navigator.serviceWorker.register( + '/usuba-sw.js', + { + type: 'module', + scope: '/', + } + ); + + const hasPending = + registration.active && (registration.installing || registration.waiting); + + let installationFinishes = !hasPending + ? Promise.resolve() + : new Promise((resolve) => { + if (registration.waiting) { + return self.location.reload(); + } + + registration.installing?.addEventListener( + 'statechange', + async (_) => { + if (registration.waiting) { + self.location.reload(); + } else { + resolve(undefined); + } + } + ); + }); + + await installationFinishes; + + console.log('Usuba Service Worker is active!'); + } catch (error) { + console.error(`Registration failed with ${error}`); + } +})(); + +/** + * A Runtime embodies: + * + * - A Standard Library interface, defined as WIT + * - A REST client for producing On-demand Isolated Modules + * + * Its main interface enables the user to Prepare a Module for future + * instantiation. + * + * When constructing a Runtime, the provided library may be a mix of actual WIT + * definitions or promises that resolve to WIT definitions. + */ +export class Runtime { + #serviceWorkerActivates: Promise = serviceWorkerActivates; + #library: Promise; + #usubaHost: URL; + + constructor( + library: PendingSourceCode[], + usubaHost: URL = new URL(window.location.origin) + ) { + this.#library = Promise.all(library).then((library) => + library.map( + (item, index) => + new File( + [new Blob([item], { type: 'text/plain' })], + `library-${index}.wit` + ) + ) + ); + this.#usubaHost = usubaHost; + } + + /** + * Prepares a module for instantiation by converting the provided source + * definition to a Wasm Component, and then subsequently polyfilling it for + * browser-based Core Wasm. The resulting prepared module can be instantiated + * by providing it with a working implementation of the library associated + * with the runtime that defined it. + * + * @param definition The essential details of the module being defined + * @returns A promise that resolves to the prepared + */ + async defineModule( + definition: ModuleDefinition + ): Promise> { + const [library, wit, sourceCode, _] = await Promise.all([ + this.#library, + definition.wit, + definition.sourceCode, + this.#serviceWorkerActivates, + ]); + + apiClient.OpenAPI.BASE = this.#usubaHost.origin; + const { id } = await apiClient.buildModule({ + formData: { + library, + module: [ + new File([new Blob([wit], { type: 'text/plain' })], 'module.wit'), + new File( + [new Blob([sourceCode], { type: definition.contentType })], + `module.${FILE_EXTENSIONS[definition.contentType]}` + ), + ], + }, + }); + + const { instantiate } = await import( + /* @vite-ignore */ `${ + this.#usubaHost.origin + }/module/transpiled/runtime/${id}.js` + ); + + return new PreparedModule( + instantiate as (imports: ImportMap) => Promise + ); + } +} + +/** + * A PreparedModule embodies: + * + * - Polyfill artifacts consisting of Wasm Modules and JavaScript bindings + * - Association to the Runtime that created it through its Standard Library + * + * Its main interface enables the user to Instantiate a Module with a + * just-in-time Standard Library. The product of successful instantiation is + * always an implementation of the interface defined by the Module's WIT. + */ +export class PreparedModule { + #instantiate: (imports: ImportMap) => Promise; + + constructor(instantiate: any) { + this.#instantiate = instantiate; + } + + /** + * Instantiates a prepared module, yielding a promise that resolves to the + * module's API (as defined in its WIT). + * + * In order to instantiate the prepared module, you must provide it with a + * mapping of module specifiers to concrete implementations. These will be + * used to populate the "library" associated with the prepared module's + * runtime. Only the imports that are made use of by the code in the prepared + * module need to be specified. + * + * This method uses different techniques to resolve a concrete library + * implemenetation depending on the value type in the provided mapping: + * + * - string: the value will be treated as a module specifier, and will be + * resolved using a dynamic import + * - promise: the value will be the resolved value of the promise + * - all other types are treated as a candidate implementation of the library + * + * @param importables A mapping of library imports to their eventual + * implementations + * @returns A promise that resolves to the instantiated module's API + */ + async instantiate(importables: ImportableMap): Promise { + const importedEntries = (await Promise.all( + Object.entries(importables).map(async ([key, importable]) => { + if (typeof importable == 'string') { + importable = import(/* @vite-ignore */ importable) as Promise; + } + + return [key, await importable]; + }) + )) as [string, Import][]; + + const imports = importedEntries.reduce((map, [key, imported]) => { + map[key] = imported; + return map; + }, {} as ImportMap); + + return await this.#instantiate(imports); + } +} diff --git a/typescript/packages/usuba-rt/tsconfig.json b/typescript/packages/usuba-rt/tsconfig.json new file mode 100644 index 000000000..d40c067b9 --- /dev/null +++ b/typescript/packages/usuba-rt/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["es2022", "DOM", "DOM.Iterable"], + "outDir": "./lib", + "rootDir": "./src", + }, + "include": [ + "src/**/*", + ] +} diff --git a/typescript/packages/usuba-sw/openapi.json b/typescript/packages/usuba-sw/openapi.json index 58b8bbaa0..5c840421b 100644 --- a/typescript/packages/usuba-sw/openapi.json +++ b/typescript/packages/usuba-sw/openapi.json @@ -105,11 +105,20 @@ "schemas": { "BuildModuleRequest": { "type": "object", + "description": "A `multipart/form-data` payload that consists of module WIT + source code as\nwell as additional (optional) library WIT files", "required": [ - "files" + "module", + "library" ], "properties": { - "files": { + "library": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + }, + "module": { "type": "array", "items": { "type": "string", diff --git a/typescript/packages/usuba-sw/package.json b/typescript/packages/usuba-sw/package.json index cb3b2ce63..89d21dcd8 100644 --- a/typescript/packages/usuba-sw/package.json +++ b/typescript/packages/usuba-sw/package.json @@ -8,7 +8,7 @@ "type": "module", "scripts": { "build": "wireit", - "update-openapi-spec": "wireit" + "clean": "wireit" }, "repository": { "type": "git", @@ -21,7 +21,9 @@ "files": [ "./dist/usuba-sw.js" ], - "dependencies": {}, + "dependencies": { + "@commontools/usuba-api": "^0.0.1" + }, "devDependencies": { "@bytecodealliance/preview2-shim": "^0.16.2", "@hey-api/openapi-ts": "^0.46.0", @@ -31,15 +33,6 @@ "wireit": "^0.14.4" }, "wireit": { - "update-openapi-spec": { - "command": "./scripts/update-openapi-spec.sh" - }, - "build:openapi-client": { - "files": [ - "./openapi.json" - ], - "command": "npx @hey-api/openapi-ts -i ./openapi.json -o ./src/openapi-client" - }, "build:wasm": { "command": "../../../rust/usuba-compat/build-wasm-component.sh", "files": [ @@ -51,13 +44,20 @@ }, "build": { "dependencies": [ - "build:wasm", - "build:openapi-client" + "../usuba-api:build", + "build:wasm" ], "files": [ "./src/**/*" ], + "output": [ + "./lib/**/*", + "./dist/*" + ], "command": "tsc --build -f && cp -r ./src/usuba_compat ./lib/usuba_compat && vite build" + }, + "clean": { + "command": "rm -rf ./lib ./dist ./.wireit" } } } \ No newline at end of file diff --git a/typescript/packages/usuba-sw/src/index.ts b/typescript/packages/usuba-sw/src/index.ts index 50b6bbf29..d16f3c849 100644 --- a/typescript/packages/usuba-sw/src/index.ts +++ b/typescript/packages/usuba-sw/src/index.ts @@ -1,123 +1,334 @@ -import * as apiClient from './openapi-client/services.gen'; -import { polyfill } from './usuba_compat/usuba_compat.component.js'; +import * as apiClient from '@commontools/usuba-api'; +import { polyfill, hash } from './usuba_compat/usuba_compat.component.js'; + +const SERVICE_WORKER_VERSION = '0.0.1-alpha.6'; self.addEventListener('install', (_event) => { - console.log('Usuba Service Worker installed'); + console.log( + `Usuba Service Worker installed (version ${SERVICE_WORKER_VERSION})` + ); }); -self.addEventListener('fetch', async (event: FetchEvent) => { - if (event.request.method !== 'GET') { - return; +const WASI_SHIM_MAP = { + 'wasi:cli/*': '/wasi-shim/cli.js#*', + 'wasi:clocks/*': '/wasi-shim/clocks.js#*', + 'wasi:filesystem/*': '/wasi-shim/filesystem.js#*', + 'wasi:http/*': '/wasi-shim/http.js#*', + 'wasi:io/*': '/wasi-shim/io.js#*', + 'wasi:random/*': '/wasi-shim/random.js#*', + 'wasi:sockets/*': '/wasi-shim/sockets.js#*', +}; + +const ON_DEMAND_TRANSPILED_MODULES_CACHE_NAME = + 'v1/modules/transpiled/on-demand'; +const RUNTIME_TRANSPILED_MODULES_CACHE_NAME = 'v1/modules/transpiled/runtime'; + +const ON_DEMAND_TRANSPILED_MODULE_DIRNAME = '/module/transpiled/on-demand'; +const ON_DEMAND_BUILD_DIRNAME = '/module/on-demand'; + +const RUNTIME_TRANSPILED_MODULE_DIRNAME = '/module/transpiled/runtime'; +const RUNTIME_BUILD_DIRNAME = '/api/v0/module'; + +/** + * For a given request, if an item in the specified cache matches a specified + * URL (which may be different from the request URL), respond from the cache. + * Otherwise, forward the request. + */ +const respondFromCache = (event: FetchEvent, url: URL, cacheName: string) => { + event.respondWith( + (async () => { + const cache = await caches.open(cacheName); + const cacheResponse = await cache.match(url); + + if (cacheResponse) { + return cacheResponse; + } else { + return fetch(event.request); + } + })() + ); +}; + +/** + * Perform the steps to build a Module, first by invoking the Build Server + * and then by transpiling the resulting Wasm Component. Returns the artifacts + * of a successful transpilation. + */ +const buildModule = async ( + slug: string, + module: File[], + library: File[], + instantiation: 'automatic' | 'manual' = 'automatic' +): Promise> => { + const moduleId = ( + await apiClient.buildModule({ + formData: { + library, + module, + }, + }) + ).id; + + const moduleBytes = new Uint8Array( + await ( + await apiClient.retrieveModule({ + id: moduleId, + }) + ).arrayBuffer() + ); + + return polyfill(moduleBytes, { + name: slug, + mappings: Object.entries(WASI_SHIM_MAP), + instantiation, + }); +}; + +/** + * Cache build artifacts, and generate / cache an entrypoint "wrapper" + * that re-exports the transpiled Wasm Component. + */ +const shrinkWrap = async ( + entrypointUrl: URL, + wrapperModule: string, + files: [string, Uint8Array][], + cacheName: string, + dirName: string +): Promise => { + const cache = await caches.open(cacheName); + + for (const [filename, bytes] of files) { + console.log('Caching artifact:', filename); + + const blob = new Blob([bytes], { + type: filename.endsWith('.wasm') ? 'application/wasm' : 'text/javascript', + }); + + const nextUrl = new URL(`${dirName}/${filename}`, entrypointUrl.origin); + await cache.put(nextUrl, new Response(blob)); } - const requestUrl = new URL(event.request.url); + const blob = new Blob([wrapperModule], { type: 'text/javascript' }); + const response = new Response(blob); + + await cache.put(entrypointUrl, response.clone()); + + return response; +}; + +/** + * The on-demand build flow is distinguished in two ways: + * + * 1. The flow starts with a GET request and yields an importable module + * 2. Module instantiation is automatic (its imports aren't configurable) + */ +const buildOnDemandModule = (event: FetchEvent, url: URL) => { + event.respondWith( + (async () => { + console.log('On-demand module generation detected...'); + url.pathname.split('/').slice(2); + + const [ext, witBase64, sourceCodeBase64] = url.pathname + .split('/') + .slice(3); + + console.log('Attempting to parse on-demand path fragment...'); + + if (ext && witBase64 && sourceCodeBase64) { + const encoder = new TextEncoder(); + const polyfilledModuleId = hash( + encoder.encode(`${witBase64}.${sourceCodeBase64}`) + ); + const cache = await caches.open( + ON_DEMAND_TRANSPILED_MODULES_CACHE_NAME + ); + const moduleShortId = polyfilledModuleId.slice(0, 6); + const moduleSlug = `module-${moduleShortId}`; - if (requestUrl.pathname.startsWith('/module/transpiled')) { - console.log('Pulling generated artifact from cache...'); - event.respondWith( - (async () => { - const cache = await caches.open('v0/modules/transpiled'); - const cacheResponse = await cache.match(requestUrl); - if (cacheResponse) { - return cacheResponse; - } else { - return fetch(event.request); + const entrypointModule = `${ON_DEMAND_TRANSPILED_MODULE_DIRNAME}/${moduleSlug}-wrapper.js`; + const entrypointUrl = new URL(entrypointModule, url.origin); + + const cacheItem = await cache.match(entrypointUrl); + + if (typeof cacheItem != 'undefined') { + console.log('Polyfilled on-demand module found in cache!'); + return cacheItem; } - })() - ); - } else if (requestUrl.pathname.startsWith('/module/on-demand')) { - console.log('On-demand module generation detected...'); - requestUrl.pathname.split('/').slice(2); - - const [ext, witBase64, sourceCodeBase64] = requestUrl.pathname - .split('/') - .slice(3); - - console.log('Attempting to parse on-demand path fragment...'); - - if (ext && witBase64 && sourceCodeBase64) { - const wit = atob(witBase64); - const sourceCode = atob(sourceCodeBase64); - - console.log('File extension:', ext); - console.log('WIT:\n', wit); - console.log('Source Code:\n', sourceCode); - - const witFile = new File([new Blob([wit])], 'module.wit'); - const sourceCodeFile = new File( - [new Blob([sourceCode])], - `module.${ext}` - ); - event.respondWith( - (async () => { - const moduleId = ( - await apiClient.buildModule({ - formData: { - files: [witFile, sourceCodeFile], - }, - }) - ).id; - - const moduleBytes = new Uint8Array( - await ( - await apiClient.retrieveModule({ - id: moduleId, - }) - ).arrayBuffer() - ); - const cache = await caches.open('v0/modules/transpiled'); - const fileSlug = `module-${moduleId.slice(0, 6)}`; - - const entrypointModule = `/module/transpiled/${fileSlug}.js`; - const maybeHotUrl = new URL(entrypointModule, requestUrl.origin); - - if (!(await cache.match(maybeHotUrl))) { - const { - files, - imports: _imports, - exports: _exports, - } = polyfill(moduleBytes, { - name: fileSlug, - mappings: Object.entries({ - 'wasi:cli/*': '/wasi-shim/cli.js#*', - 'wasi:clocks/*': '/wasi-shim/clocks.js#*', - 'wasi:filesystem/*': '/wasi-shim/filesystem.js#*', - 'wasi:http/*': '/wasi-shim/http.js#*', - 'wasi:io/*': '/wasi-shim/io.js#*', - 'wasi:random/*': '/wasi-shim/random.js#*', - 'wasi:sockets/*': '/wasi-shim/sockets.js#*', - }), - }); - - for (const [filename, bytes] of files) { - console.log('Caching artifact:', filename); - const blob = new Blob([bytes], { - type: filename.endsWith('.wasm') - ? 'application/wasm' - : 'text/javascript', - }); - const url = new URL( - `/module/transpiled/${filename}`, - requestUrl.origin - ); - - await cache.put(url, new Response(blob)); - } - } - - const wrapperModule = `export * from '/module/transpiled/${fileSlug}.js'`; - const blob = new Blob([wrapperModule], { type: 'text/javascript' }); - - return new Response(blob); - })() + console.log("Nothing found in cache; we'll do it live!"); + + const wit = atob(witBase64); + const sourceCode = atob(sourceCodeBase64); + + console.log('File extension:', ext); + console.log('WIT:\n', wit); + console.log('Source Code:\n', sourceCode); + + const witFile = new File([new Blob([wit])], 'module.wit'); + const sourceCodeFile = new File( + [new Blob([sourceCode])], + `module.${ext}` + ); + + const { + files, + imports: _imports, + exports: _exports, + } = await buildModule( + moduleSlug, + [witFile, sourceCodeFile], + [], + 'automatic' + ); + + const wrapperModule = `export * from '${ON_DEMAND_TRANSPILED_MODULE_DIRNAME}/${moduleSlug}.js'`; + + return await shrinkWrap( + entrypointUrl, + wrapperModule, + files, + ON_DEMAND_TRANSPILED_MODULES_CACHE_NAME, + ON_DEMAND_TRANSPILED_MODULE_DIRNAME + ); + } else { + return new Response(new Blob([], { type: 'text/html' }), { + status: 404, + }); + } + })() + ); +}; + +/** + * A Runtime Module is built when the Service Worker intercepts an API request + * to the Build Server. The Wasm Component (produced by the Build Server) is + * transpiled and cached locally, and a derived Module ID is given to the caller + * (not the original Wasm Component ID). This allows the caller to provide an + * arbitrary number of input files with an initial POST, and then instantiate + * the Runtime Module "just in time" using a secondary import. + * + * Instantiation of a Runtime Module is manual, which means that it allows for + * imports to be configured at instantiation time. But, it also means that a + * Runtime Module cannot be imported transparently the way an On-demand Module + * can. Instead, the result of importing a Runtime Module is an `instantiate` + * function that yields the actual module. + */ +const buildRuntimeModule = (event: FetchEvent, url: URL) => { + event.respondWith( + (async () => { + console.log('Preparing to build Runtime Module...'); + const formData = await event.request.formData(); + const moduleFiles = formData.getAll('module') as File[]; + const libraryFiles = formData.getAll('library') as File[]; + + const allFiles = moduleFiles.concat(libraryFiles); + + const runtimeModuleId = hash( + new Uint8Array( + await new Blob( + await Promise.all(allFiles.map((file) => file.arrayBuffer())) + ).arrayBuffer() + ) ); + + const cache = await caches.open(RUNTIME_TRANSPILED_MODULES_CACHE_NAME); + const moduleShortId = runtimeModuleId.slice(0, 6); + const moduleSlug = `module-${moduleShortId}`; + + const buildResultPath = `${RUNTIME_TRANSPILED_MODULE_DIRNAME}/result-${moduleSlug}.json`; + const buildResultUrl = new URL(buildResultPath, url.origin); + + const cacheItem = await cache.match(buildResultUrl); + + if (typeof cacheItem != 'undefined') { + console.log('Polyfilled runtime module build result found in cache!'); + return cacheItem; + } + + const { + files, + imports: _imports, + exports: _exports, + } = await buildModule(moduleSlug, moduleFiles, libraryFiles, 'manual'); + + const wrapperModule = `import {instantiate as innerInstantiate} from '${RUNTIME_TRANSPILED_MODULE_DIRNAME}/${moduleSlug}.js'; +import {shim as wasiShimImportPromises} from '/wasi.js'; + +const wasiShimImports = Promise.all( + Object.entries(wasiShimImportPromises) + .map(([specifier, importPromise]) => + importPromise.then((importResult) => [specifier, importResult]) + ) +); + +export const instantiate = async (imports) => { + const resolvedWasiShimImports = await wasiShimImports; + + for (const [name, shimImport] of resolvedWasiShimImports) { + if (typeof imports[name] == 'undefined') { + imports[name] = shimImport; } } -}); -/* - + const getCoreModule = async (name) => fetch('${RUNTIME_TRANSPILED_MODULE_DIRNAME}/' + name).then(WebAssembly.compileStreaming); + console.log('Instantiating module with these resolved imports:', imports); + + return innerInstantiate(getCoreModule, imports); +};`; + + await shrinkWrap( + new URL( + `${RUNTIME_TRANSPILED_MODULE_DIRNAME}/${runtimeModuleId}.js`, + url.origin + ), + wrapperModule, + files, + RUNTIME_TRANSPILED_MODULES_CACHE_NAME, + RUNTIME_TRANSPILED_MODULE_DIRNAME + ); + + const response = new Response( + new Blob([JSON.stringify({ id: runtimeModuleId })], { + type: 'application/json', + }) + ); + + await cache.put(buildResultUrl, response.clone()); - -*/ + return response; + })() + ); +}; + +self.addEventListener('fetch', async (event: FetchEvent) => { + const requestUrl = new URL(event.request.url); + + switch (event.request.method) { + case 'GET': + if (requestUrl.pathname.startsWith(ON_DEMAND_TRANSPILED_MODULE_DIRNAME)) { + respondFromCache( + event, + requestUrl, + ON_DEMAND_TRANSPILED_MODULES_CACHE_NAME + ); + } else if ( + requestUrl.pathname.startsWith(RUNTIME_TRANSPILED_MODULE_DIRNAME) + ) { + respondFromCache( + event, + requestUrl, + RUNTIME_TRANSPILED_MODULES_CACHE_NAME + ); + } else if (requestUrl.pathname.startsWith(ON_DEMAND_BUILD_DIRNAME)) { + buildOnDemandModule(event, requestUrl); + } + break; + case 'POST': + if (requestUrl.pathname.startsWith(RUNTIME_BUILD_DIRNAME)) { + buildRuntimeModule(event, requestUrl); + } + break; + default: + break; + } +}); diff --git a/typescript/packages/usuba-sw/tsconfig.json b/typescript/packages/usuba-sw/tsconfig.json index e0ddf35f7..de354019b 100644 --- a/typescript/packages/usuba-sw/tsconfig.json +++ b/typescript/packages/usuba-sw/tsconfig.json @@ -1,29 +1,8 @@ { + "extends": "../../tsconfig.base.json", "compilerOptions": { - "composite": true, - "target": "es2021", - "module": "es6", - "lib": ["es2021"], - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "inlineSources": true, "outDir": "./lib", "rootDir": "./src", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitThis": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "importHelpers": true, - "stripInternal": true, - "noImplicitOverride": true, - "types": [] }, "include": [ "src/**/*", diff --git a/typescript/packages/usuba-sw/tsconfig.tsbuildinfo b/typescript/packages/usuba-sw/tsconfig.tsbuildinfo deleted file mode 100644 index 164f511dd..000000000 --- a/typescript/packages/usuba-sw/tsconfig.tsbuildinfo +++ /dev/null @@ -1 +0,0 @@ -{"program":{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","./src/openapi-client/core/CancelablePromise.ts","./src/openapi-client/core/ApiRequestOptions.ts","./src/openapi-client/core/OpenAPI.ts","./src/openapi-client/core/ApiResult.ts","./src/openapi-client/core/ApiError.ts","./src/openapi-client/core/request.ts","./src/openapi-client/types.gen.ts","./src/openapi-client/services.gen.ts","./src/usuba_compat/interfaces/wasi-cli-environment.d.ts","./src/usuba_compat/interfaces/wasi-cli-exit.d.ts","./src/usuba_compat/interfaces/wasi-io-error.d.ts","./src/usuba_compat/interfaces/wasi-io-streams.d.ts","./src/usuba_compat/interfaces/wasi-cli-stderr.d.ts","./src/usuba_compat/interfaces/wasi-cli-stdin.d.ts","./src/usuba_compat/interfaces/wasi-cli-stdout.d.ts","./src/usuba_compat/interfaces/wasi-clocks-wall-clock.d.ts","./src/usuba_compat/interfaces/wasi-filesystem-types.d.ts","./src/usuba_compat/interfaces/wasi-filesystem-preopens.d.ts","./src/usuba_compat/interfaces/wasi-random-random.d.ts","./src/usuba_compat/usuba_compat.component.d.ts","./src/index.ts","./src/openapi-client/schemas.gen.ts","./src/openapi-client/index.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-environment.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-exit.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-run.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-io-error.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-io-poll.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-io-streams.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-stderr.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-stdin.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-stdout.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-terminal-input.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-terminal-output.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-terminal-stderr.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-terminal-stdin.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-cli-terminal-stdout.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/cli.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-clocks-monotonic-clock.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-clocks-wall-clock.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/clocks.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-filesystem-types.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-filesystem-preopens.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/filesystem.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-http-types.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-http-incoming-handler.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-http-outgoing-handler.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/http.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/io.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-random-insecure-seed.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-random-insecure.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-random-random.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/random.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-network.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-instance-network.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-ip-name-lookup.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-tcp.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-tcp-create-socket.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-udp.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/interfaces/wasi-sockets-udp-create-socket.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/sockets.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/index.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/wasi-cli-command.d.ts","../../node_modules/@bytecodealliance/preview2-shim/types/wasi-http-proxy.d.ts","../../node_modules/@types/serviceworker/iterable.d.ts","../../node_modules/@types/serviceworker/index.d.ts"],"fileInfos":[{"version":"824cb491a40f7e8fdeb56f1df5edf91b23f3e3ee6b4cde84d4a99be32338faee","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569",{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"ea011c76963fb15ef1cdd7ce6a6808b46322c527de2077b6cfdf23ae6f5f9ec7","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"b20fe0eca9a4e405f1a5ae24a2b3290b37cf7f21eba6cbe4fc3fab979237d4f3","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"5e07ed3809d48205d5b985642a59f2eba47c402374a7cf8006b686f79efadcbd","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"8073890e29d2f46fdbc19b8d6d2eb9ea58db9a2052f8640af20baff9afbc8640","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true},{"version":"51e547984877a62227042850456de71a5c45e7fe86b7c975c6e68896c86fa23b","affectsGlobalScope":true},{"version":"956d27abdea9652e8368ce029bb1e0b9174e9678a273529f426df4b3d90abd60","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},{"version":"663237e06287606be7ccdb892ddc9562352aec15dedca983ac84004c2b1b17cc","signature":"11a746b4d1023300a23da9afb502364b8a67874b00f34fd92c3adcf605e49368"},{"version":"f49f644231f39b74684e103ae64a56952d8eb263b79bf35574d8379e0a01056e","signature":"133b004d5fec7847b2043006864672606223edffb06fe0726b5506da919500e5"},{"version":"64d75e977b227615ff85a8fc46bc56148eeb5143cb86c9d4bc196fabc89d4ea9","signature":"c209b0f634e8337bb9ef368d842d38d3a95f32cbd8b0df3b1c5ffa386e2fb067"},{"version":"8b8a47fd8c3b647c999ac6f83c85e7f0b851a8954c148a787d9e8e90f3b7da4e","signature":"1499eebe9457d103b9b5782b243797305ca7f26e198d384c2e0b2a25d6f10bde"},{"version":"95f506c7f6b38262bd5932f87820faab73121e08bd9306ce440b732a9443fe95","signature":"358537bc98289ec8e0a883558469c877a4fbe38a15d023f7e0456e4a4f72bcd8"},{"version":"eabebdebcb2173d4679f69c60d9dd32d4fdc5beefeea62fdce60e91d949e08f4","signature":"7d67dcebda39234142a94b0f3949b1410ffcae09318dfe2f98af3c0d68babd75"},{"version":"fa7afa288e7f17ed0f9618b510333a3b8449cba201af4c1132fff13cedd22c2f","signature":"a4c847ed607f44f7b2b1c1e7fd254b572faa1c54f82b4ca2d39a6a40b14e4b67"},{"version":"98c47f37dba0f3c9b0807003aa56195eeed9dc70bee53b2d0034ff2841667992","signature":"bf5be703ddfcada43840ed728f03d8fd1529fdce43b2ca35eaaabd7bb17cf68f"},"5c972c15e17460c7187ca686ad4f849ec67fd80973dd081040d101cbb6289c0f","6d978b7e6fe437e74fd706a46aa068e95ce527707fc1bcd0581b42ad2d6cd857","051889e07ae7cce2fda01c0205b2094e4b6af8fc15d94c1fbf74e243791367e9","4771dc75aef3e1ca2c94755fafa3a2fabe901e2c228f44863396304225574e12","40b503e330de157566a04cf9c3d2fa25884202627182383aa9a93241f9aa181e","afa98d3b6a0444ae8c3917468410fe970fd89b591b74fc05613cde891923448d","f7b9b849771d5ad94c0b7942ad7ad9a8b9be8c06bb9ca9b87808be9b035e9e11","389dc524ad7c8b880df9287266597830f9fa6eff0279cac2e41cc626508e5344","bfd13eb3b7b5d7be0ebf666ab855eed9f6f78faef9efea64d41f966807dbf53b","7f071c1d1eb9b7cb04bcf38f765ddaebcbba2baf00f4958913e6c888529b2144","db671aadda72ca3d173bf3540d52366e0b7727855a83c64526eacdcfa751b372","3ade56ac91b009a34bdd91d2de3dfee48da335de8a7fd9192fdb9ddd45df95f0",{"version":"114c5a0b52752c12622b5733a176dbf61f27cb6bc4c70a7b031751bdae7ea1bc","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"cf3464cf28790cf6ff84a62c082940148bd7a05967c5a9a216f6b853a669c8a7","signature":"b01c7ed36a99de419dcb74dffb8ef99b2daf87e64522d9a9198be94fb240e3c7"},{"version":"7b2931f49e92fdcd2af4f577707392ad2c3d3a71a8ee78c07418d83b7540fcdf","signature":"139558747accfba69018e47cc01ffa611a8afdfc75fcc218276ec7aad96f246b"},"8a95678ae9f5199675902f24f3fd2a2b1759d1246198f53d0076890c8f3a89ca","648cdcd5baccca30b3c217976c52463269071a3a0a8f6784a95e7818f7b8abad","c033bb2c56ec100557bb616c98f8ad4648ca263062ad9f9f8a1e8bc71694052c","7ae0338b32bd72df596a5f49daa37c4ba5046d44ca77dd294325a8a0a612b744","8d52b8d32199c9f1e9bec474d5fff4a80dbc2079a277f68d5548e6b2649590d8","5ee4bd3be80e194388bf521245bbcf8d44d5c148d18b6bb262d3617b89e91421","40b503e330de157566a04cf9c3d2fa25884202627182383aa9a93241f9aa181e","afa98d3b6a0444ae8c3917468410fe970fd89b591b74fc05613cde891923448d","f7b9b849771d5ad94c0b7942ad7ad9a8b9be8c06bb9ca9b87808be9b035e9e11","9179a85ab76d3118975c391f747d408172ff0544f8b46763639a74883f437bfd","e06a866dcb1161b68602c62bc03c3f1cedede1576003e3697babd853bd3edefc","3f464b0aa7697aae1d05cd4cdc05e84e5befed0a4613279bbfaabca912d9f814","3a8c7f5622f3618a8c5b73537207cc4bbff8ba4ce5acdaaf6a67f13bf5e0badd","9186c8a514ea5cced20eb6b5c8dec2368fa16bba618891b9a69b241965e14947","007395c473f26cfcb59ab5be0582d7c4eeff8b5c72abb3cb18b9036ef0578bb7","a50a4ee87a7bde63aa3a35edd3bdb9cf4c3af8759104dbb9af08b87126ab6a9a","c9ba76f88d66712c51a5a119d632f62bcaa732c2fa5c8462fe7915684e57ff67","f67fac478210657611e869e2362d223e4d61f917c070e8240e9a60986f4f8637","42d3551eccf74ddce49fc958867627299b20c5731d4574d5c0f6b9816280faa0","5e6077e37d029ce395176871abb5d9e7f57ee5081e795dd5b298230a647b0553","c3d442c17548ba48cf94807da3d921bc116a4ef290ce2cb3d250ca4908fbf288","555887e71cdaf0778cf5d0c7e3ff29e939eb936d1ea3ee41243c3953a27ce045","6e993216d537448a8c69aad1589937cbc7bf669170f4be096581b6bc6817c6ff","8c54633bd9f570d76382a2d9dc80bc22edd5ca6c328add090812475c6728ec64","2a04c5392e50c6130127a09e8e938c71bd434ec57561fd27c916cf9622476b02","21d40f8dedbedd15e1c8d8f9ee192113aea300fd301ae2d790c53d927004102f","a8ec6e7afa929f5b4b623b03caf71bc9f3da37db2ffe76834c8e8fdefc59849f","446f1e6d9689df03c60c5a304e40b7edbdf505f188a914c105f2e58e1e641698","2c984aa8ea779bc70295121d6b9345c1de3c1fbc785ab793407ceb723835ca02","50b16d3ba0174d213d96f10068a2a01835286e8ac965b25c5aa658c5e60bc11f","5c7c053f85a15696cb4d3d466f3f2151be10b8b5fb0670b44d5f064b8897cc1e","2c993e1ec6fbdd02a472028d5203809ef8f2c76c2bc274110a7b01926dfe2b8c","8dafcb5fb479acabc058b87fa4347cba6104f7e960522f560a5b97818bca48a5","78dd0065f3d11c46b4d77028bdb0c29ee0a736cfea9f8d80a7815a02e2abaf7f","c88d9f88f24fe30f65be0b070060a030464fe89447e508b8529524970cde6aa6","1ea9b70fb2a0fe796ffdb9131c0c2a34176375fa6a4a888e6db613089a7e6782","ef66473f8402eff2a1d498a5026b7c333e849431465b2fa09b001ae0bac21ace","3a54a9ef2660e17912988954069c5b4143cf8f75227c8d8bf8eed6d1d0afd49f","86c18f2c92063f5dae9b954ca61b9798b4e59a7aec23d7d66fa182e009d7d31a","739d47f59b244557f360604ddfcba5293e24de25c7e3fe84c6cf4961dc620b9c","1c9c6ddba8ecb02562d0822a5e3c37046177866a4079b4ca166b923b72edeb16",{"version":"79fec4fbe74b8c013dd5f5e783c7ae1bc25ad38be5529f716168f47417e32203","affectsGlobalScope":true},{"version":"36fe69661e343cb4be10ff09db41af3abed1309a5edcb089e2e001f3c935efaf","affectsGlobalScope":true}],"root":[[50,115]],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"experimentalDecorators":true,"importHelpers":true,"inlineSources":true,"module":5,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitOverride":true,"noImplicitReturns":true,"noImplicitThis":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./lib","rootDir":"./src","sourceMap":true,"strict":true,"stripInternal":true,"target":8},"fileIdsList":[[73,74,75,79,80,81,82,83,84,85,86],[88,89],[91,92],[94,95,96],[87,90,93,97,98,102,110],[78],[83],[82],[77],[91],[78,89],[94],[76,77,78,88],[76,77],[103],[77,103],[103,106],[77,78,88,103],[103,108],[76,77,78],[99,100,101],[103,104,105,106,107,108,109],[73,74,75,76,77,78,79,80,81,82,83,84,85,86,88,89,91,92,99,100,101,103,104,105,106,107,108,109],[76,77,78,79,80,81,88,89,94,95,96,101],[114],[57,69],[51,53],[51],[50,51,52,53,54],[50,52,54,56,57,71],[50,52,55,56],[61],[66],[61,65],[60],[58,59,60,61,62,63,64,65,66,67,68],[50,51,52,53],[50,56]],"referencedMap":[[87,1],[90,2],[93,3],[97,4],[111,5],[79,6],[80,6],[81,6],[84,7],[85,8],[86,7],[88,9],[92,10],[91,11],[95,12],[96,12],[94,13],[78,14],[104,15],[105,16],[107,17],[106,18],[109,19],[108,16],[98,20],[102,21],[110,22],[112,23],[113,24],[115,25],[70,26],[54,27],[52,28],[55,29],[72,30],[57,31],[62,32],[63,32],[64,32],[67,33],[66,34],[61,35],[69,36]],"exportedModulesMap":[[87,1],[90,2],[93,3],[97,4],[111,5],[79,6],[80,6],[81,6],[84,7],[85,8],[86,7],[88,9],[92,10],[91,11],[95,12],[96,12],[94,13],[78,14],[104,15],[105,16],[107,17],[106,18],[109,19],[108,16],[98,20],[102,21],[110,22],[112,23],[113,24],[115,25],[54,27],[52,28],[55,37],[72,30],[57,38],[62,32],[63,32],[64,32],[67,33],[66,34],[61,35],[69,36]],"semanticDiagnosticsPerFile":[87,90,93,97,111,73,74,75,79,80,81,82,83,84,85,86,88,89,92,91,95,96,94,76,77,78,99,100,101,104,105,103,107,106,109,108,98,102,110,112,113,115,114,48,49,10,9,2,11,12,13,14,15,16,17,18,3,19,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,8,47,44,45,46,1,70,54,51,53,50,52,55,72,71,57,56,58,59,62,63,64,65,67,66,60,61,68,69],"latestChangedDtsFile":"./lib/openapi-client/index.d.ts"},"version":"5.4.5"} \ No newline at end of file diff --git a/typescript/packages/usuba-ui/index.html b/typescript/packages/usuba-ui/index.html index 1f042f847..7a1971c5a 100644 --- a/typescript/packages/usuba-ui/index.html +++ b/typescript/packages/usuba-ui/index.html @@ -7,7 +7,7 @@ Usuba - + @@ -27,6 +27,9 @@ + special btn + + diff --git a/typescript/packages/usuba-ui/package.json b/typescript/packages/usuba-ui/package.json index af360375a..2dc728c4d 100644 --- a/typescript/packages/usuba-ui/package.json +++ b/typescript/packages/usuba-ui/package.json @@ -7,7 +7,8 @@ "private": true, "type": "module", "scripts": { - "build": "wireit" + "build": "wireit", + "clean": "wireit" }, "repository": { "type": "git", @@ -22,6 +23,7 @@ }, "devDependencies": { "@commontools/usuba-sw": "^0.0.1", + "@commontools/usuba-api": "^0.0.1", "typescript": "^5.2.2", "vite": "^5.2.0", "wireit": "^0.14.4" @@ -29,9 +31,13 @@ "wireit": { "build": { "dependencies": [ + "../usuba-rt:build", "../usuba-sw:build" ], - "command": "vite build" + "command": "vite build && mv ./dist/index.html ./dist/$.html" + }, + "clean": { + "command": "rm -rf ./lib ./dist ./.wireit" } } -} +} \ No newline at end of file diff --git a/typescript/packages/usuba-ui/public/usuba-ui/styles.css b/typescript/packages/usuba-ui/public/usuba-ui/styles.css new file mode 100644 index 000000000..952318d3d --- /dev/null +++ b/typescript/packages/usuba-ui/public/usuba-ui/styles.css @@ -0,0 +1,36 @@ +body { + font-family: var(--sl-font-sans, sans-serif); + padding: 1em; +} + +* { + box-sizing: border-box; +} + +sl-textarea { + min-height: 360px; + flex: 1; +} +sl-textarea::part(textarea) { + font-family: var(--sl-font-mono, mono); + font-size: 0.85rem; +} + +sl-input { + flex: 1; +} + +#specifier { + display: flex; + flex-direction: row; + align-items: center; + margin-bottom: 1em; + gap: 1em; + margin-right: 1em; +} + +#code { + display: flex; + flex-direction: row; + gap: 1em; +} \ No newline at end of file diff --git a/typescript/packages/usuba-ui/public/wasi.js b/typescript/packages/usuba-ui/public/wasi.js new file mode 100644 index 000000000..46f863bd0 --- /dev/null +++ b/typescript/packages/usuba-ui/public/wasi.js @@ -0,0 +1,17 @@ +import * as cli from '/wasi-shim/cli.js'; +import * as clocks from '/wasi-shim/clocks.js'; +import * as filesystem from '/wasi-shim/filesystem.js'; +import * as http from '/wasi-shim/http.js'; +import * as io from '/wasi-shim/io.js'; +import * as random from '/wasi-shim/random.js'; +import * as sockets from '/wasi-shim/sockets.js'; + +export const shim = { + '/wasi-shim/cli.js': Promise.resolve(cli), + '/wasi-shim/clocks.js': Promise.resolve(clocks), + '/wasi-shim/filesystem.js': Promise.resolve(filesystem), + '/wasi-shim/http.js': Promise.resolve(http), + '/wasi-shim/io.js': Promise.resolve(io), + '/wasi-shim/random.js': Promise.resolve(random), + '/wasi-shim/sockets.js': Promise.resolve(sockets), +}; \ No newline at end of file diff --git a/typescript/packages/usuba-ui/src/index.ts b/typescript/packages/usuba-ui/src/index.ts index c07176ba8..e177c5f2d 100644 --- a/typescript/packages/usuba-ui/src/index.ts +++ b/typescript/packages/usuba-ui/src/index.ts @@ -9,10 +9,11 @@ import type SlTextarea from '@shoelace-style/shoelace/dist/components/textarea/t import type SlInput from '@shoelace-style/shoelace/dist/components/input/input.js'; import type SlCopyButton from '@shoelace-style/shoelace/dist/components/copy-button/copy-button.js'; import type SlSelect from '@shoelace-style/shoelace/dist/components/select/select.js'; +import * as apiClient from '@commontools/usuba-api'; setBasePath('/shoelace/dist'); -const $ = (s) => document.querySelector(s); +const $ = (s: string) => document.querySelector(s); const witTextArea = $('sl-textarea[label="WIT"]') as SlTextarea; const sourceCodeTextArea = $('sl-textarea[label="Source Code"]') as SlTextarea; @@ -45,3 +46,33 @@ const updateSpecifier = () => { }; updateSpecifier(); + +// $('sl-button')!.addEventListener('click', async () => { +// console.log('Lfgggg'); +// const result = await apiClient.buildModule({ +// formData: { +// library: [], +// module: [ +// new File( +// [new Blob([witTextArea.value], { type: 'text/plain' })], +// 'module.wit' +// ), +// new File( +// [new Blob([sourceCodeTextArea.value], { type: 'text/javascript' })], +// 'module.js' +// ), +// ], +// }, +// }); +// console.log('DONE!', result); + +// const { instantiate } = await import( +// /* @vite-ignore */ `/module/transpiled/runtime/${result.id}.js` +// ); + +// console.log(instantiate); + +// const { hello } = await instantiate({}); + +// console.log(hello()); +// }); diff --git a/typescript/packages/usuba-ui/tsconfig.json b/typescript/packages/usuba-ui/tsconfig.json new file mode 100644 index 000000000..df767e62f --- /dev/null +++ b/typescript/packages/usuba-ui/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["es2022", "DOM"], + "outDir": "./lib", + "rootDir": "./src", + }, + "include": [ + "src/**/*" + ] +} diff --git a/typescript/packages/usuba-ui/vite.config.js b/typescript/packages/usuba-ui/vite.config.js index edb6fa879..c5a2dd64c 100644 --- a/typescript/packages/usuba-ui/vite.config.js +++ b/typescript/packages/usuba-ui/vite.config.js @@ -3,6 +3,7 @@ import { resolve } from 'path' import { defineConfig } from 'vite' export default defineConfig({ + base: '', build: { target: 'esnext' }, diff --git a/typescript/tsconfig.base.json b/typescript/tsconfig.base.json new file mode 100644 index 000000000..3a0c2422f --- /dev/null +++ b/typescript/tsconfig.base.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "composite": true, + "target": "es2022", + "module": "NodeNext", + "lib": ["es2022"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "inlineSources": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitThis": true, + "moduleResolution": "NodeNext", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "importHelpers": true, + "stripInternal": true, + "noImplicitOverride": true, + "skipLibCheck": true, + "types": [] + }, + "include": [ + "src/**/*" + ] +}