### Install Javy CLI Globally Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-building.md Build the Javy plugin and then install the Javy CLI globally using Cargo. ```bash $ cargo build -p javy-plugin --target=wasm32-wasip1 -r $ cargo install --path crates/cli ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/bytecodealliance/javy/blob/main/wpt/README.md Install project dependencies using pnpm. This command is necessary after initializing submodules. ```bash $ pnpm install ``` -------------------------------- ### Install Javy CLI Globally Source: https://github.com/bytecodealliance/javy/blob/main/npm/javy-cli/README.md Installs the javy-cli package globally on your system. ```bash # Install javy globally $ npm install -g javy-cli ``` -------------------------------- ### Create a WASI Preview 2 Javy Plugin Source: https://github.com/bytecodealliance/javy/blob/main/crates/plugin-api/README.md This example demonstrates the basic structure for creating a WASI preview 2 Javy plugin. It includes setting up configuration, modifying the runtime, and defining the plugin's entry point. ```rust use javy_plugin_api::{ javy::{quickjs::prelude::Func, Runtime}, javy_plugin, Config, }; wit_bindgen::generate!({ world: "my-javy-plugin-v1", generate_all }); fn config() -> Config { let mut config = Config::default(); config .text_encoding(true) .javy_stream_io(true); config } fn modify_runtime(runtime: Runtime) -> Runtime { runtime.context().with(|ctx| { ctx.globals().set("plugin", true).unwrap(); }); runtime } struct Component; // Dynamically linked modules will use `my_javy_plugin_v1` as the import // namespace. javy_plugin!("my-javy-plugin-v1", Component, config, modify_runtime); export!(Component); ``` -------------------------------- ### Javy FS Usage Example Source: https://github.com/bytecodealliance/javy/blob/main/npm/javy/README.md Demonstrates reading from standard input, processing the text, and writing to standard output and standard error using Javy's file system functions. ```javascript import { readFileSync, writeFileSync, STDIO } from `javy/fs` const textEncoder = new TextEncoder(); const inputBuffer = readFileSync(STDIO.Stdin); const inputText = new TextDecoder().decode(inputBuffer); const stdoutContent = `${inputText} -- out`; const stderrContent = `${inputText} -- err`; writeFileSync(STDIO.Stdout, textEncoder.encode(stdoutContent)); writeFileSync(STDIO.Stderr, textEncoder.encode(stderrContent)); ``` -------------------------------- ### Run All Tests Source: https://github.com/bytecodealliance/javy/blob/main/wpt/README.md Execute all configured Web Platform Tests. This command bundles tests, compiles them to WebAssembly using Javy, and runs them with wasmtime. Ensure wasmtime is installed and Javy is built locally. ```bash $ pnpm test ``` -------------------------------- ### JavaScript Example for Javy Source: https://github.com/bytecodealliance/javy/blob/main/README.md This JavaScript code demonstrates reading input from stdin, processing it with a function, and writing the result to stdout. It includes helper functions for reading and writing data, and the main function logic. ```javascript // Read input from stdin const input = readInput(); // Call the function with the input const result = foo(input); // Write the result to stdout writeOutput(result); // The main function. function foo(input) { return { foo: input.n + 1, newBar: input.bar + "!" }; } // Read input from stdin function readInput() { const chunkSize = 1024; const inputChunks = []; let totalBytes = 0; // Read all the available bytes while (1) { const buffer = new Uint8Array(chunkSize); // Stdin file descriptor const fd = 0; const bytesRead = Javy.IO.readSync(fd, buffer); totalBytes += bytesRead; if (bytesRead === 0) { break; } inputChunks.push(buffer.subarray(0, bytesRead)); } // Assemble input into a single Uint8Array const { finalBuffer } = inputChunks.reduce((context, chunk) => { context.finalBuffer.set(chunk, context.bufferOffset); context.bufferOffset += chunk.length; return context; }, { bufferOffset: 0, finalBuffer: new Uint8Array(totalBytes) }); return JSON.parse(new TextDecoder().decode(finalBuffer)); } // Write output to stdout function writeOutput(output) { const encodedOutput = new TextEncoder().encode(JSON.stringify(output)); const buffer = new Uint8Array(encodedOutput); // Stdout file descriptor const fd = 1; Javy.IO.writeSync(fd, buffer); } ``` -------------------------------- ### Rust Code for a WASI Preview 1 Javy Plugin Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Implement the 'initialize-runtime' function in Rust to set up your Javy plugin. This example demonstrates setting a global JavaScript variable and exposing a host-imported function to the JavaScript environment. ```rust use javy_plugin_api::{import_namespace, javy::quickjs::prelude::Func, Config}; // Set your plugin's import namespace. import_namespace!("my_plugin_name"); // If you want to import a function from the host, here's how to do it. #[link(wasm_import_module = "some_other_namespace")] extern "C" { fn imported_function(); } #[export_name = "initialize-runtime"] pub extern "C" fn initialize_runtime() { let config = Config::default(); javy_plugin_api::initialize_runtime(config, |runtime| { runtime.context().with(|ctx| { // Creates a `plugin` variable on the global set to `true`. ctx.globals().set("plugin", true).unwrap(); // Creates an `importedFunc` function on the global which will call // the imported function. ctx.globals() .set("importedFunc", Func::from(|| unsafe { imported_function() })) .unwrap(); }); runtime }) .unwrap(); } ``` -------------------------------- ### Install Cargo Hack Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-testing-locally.md Install the cargo-hack tool, which is required for managing Rust dependencies and running tests. It's recommended to install the locked version. ```bash cargo +stable install cargo-hack --locked ``` -------------------------------- ### Invoke Javy CLI via npx Source: https://github.com/bytecodealliance/javy/blob/main/npm/javy-cli/README.md Executes the latest version of the javy-cli package using npx without a global installation. ```bash # Directly invoke it via npm $ npx javy-cli@latest ``` -------------------------------- ### Receiving Byte Arrays from Imported Functions Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md On the host side, use `memory.read` with the provided pointer and length to retrieve the byte array from the WebAssembly instance's memory. This setup is typically done within a linker function wrapper. ```rust use anyhow::Result; struct StoreContext { bytes: Vec, wasi: wasmtime_wasi::WasiCtx, } fn setup(linker: &mut wasmtime::Linker) -> Result<()> { wasmtime_wasi::sync::add_to_linker(&mut linker, |ctx: &mut StoreContext| &mut ctx.wasi)?; linker .func_wrap( "host", "my_import", |mut caller: wasmtime::Caller<'_, StoreContext>, ptr: u32, len: u32| { let mut bytes = Vec::with_capacity(len.try_into()?); caller .get_export("memory")? .into_memory() .unwrap() .read(&caller, ptr.try_into().unwrap(), &mut bytes)?; caller.data_mut().bytes = bytes; }, )?; Ok(()) } ``` -------------------------------- ### Get byte array from exported Wasm function on host Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md Read the pointer and length from the Wasm instance's memory, then read the actual byte array using the obtained pointer and length. Assumes little-endian encoding for integers. ```rust fn get_slice(instance: wasmtime::Instance, store: &mut wasmtime::Store) -> Result> { let your_fn = instance.get_typed_func::<(), u32>(&mut store, "your_fn")?; let ret_ptr = your_fn.call(&mut store, (ptr, len))?; let memory = instance.get_memory(&mut store, "memory")?; let mut ret_buffer = [0; 8]; memory.read(&mut store, ret_ptr.try_into()?, &mut ret_buffer)?; let bytecode_ptr = u32::from_le_bytes(ret_buffer[0..4].try_into()?); let bytecode_len = u32::from_le_bytes(ret_buffer[4..8].try_into()?); let mut bytecode = vec![0; bytecode_len.try_into()?]; memory.read(&mut store, bytecode_ptr.try_into()?, &mut bytecode)?; Ok(bytecode) } ``` -------------------------------- ### Initialize Git Submodules and Update Source: https://github.com/bytecodealliance/javy/blob/main/wpt/README.md Initialize and update Git submodules to fetch the Web Platform Tests. This is a prerequisite for running the tests. ```bash $ git submodule init $ git submodule update ``` -------------------------------- ### Execute Wasm Binary with Wasmtime Source: https://github.com/bytecodealliance/javy/blob/main/README.md Demonstrates executing a compiled WebAssembly binary using the Wasmtime runtime. Input is piped to the Wasmtime process, and the output is displayed. ```bash echo '{ "n": 2, "bar": "baz" }' | wasmtime index.wasm ``` -------------------------------- ### Build and Initialize Plugin Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Commands to build the Wasm module for the plugin and then initialize it using `javy init-plugin`. ```bash cargo build --target=wasm32-wasip2 --release javy init-plugin -o ``` -------------------------------- ### Evaluate JavaScript with Javy Runtime Source: https://github.com/bytecodealliance/javy/blob/main/crates/javy/README.md Demonstrates how to initialize the Javy runtime, create a context, expose a JavaScript function to the global scope, and then evaluate that function. ```rust use anyhow::Result; use javy::quickjs:: function::{MutFn, Rest}, Ctx, Function, Value ; use javy::{from_js_error, Runtime}; fn main() -> Result<()> { let runtime = Runtime::default(); let context = runtime.context(); context.with(|cx| { let globals = cx.globals(); globals.set( "print_hello", Function::new( cx.clone(), MutFn::new(|_: Ctx<'_>, _: Rest>| { println!("Hello, world!"); }), )?, ) })?; context.with(|cx| { cx.eval_with_options("print_hello();", Default::default()) .map_err(|e| from_js_error(cx.clone(), e)) .map(|_: ()| ()) })?; Ok(()) } ``` -------------------------------- ### Build Javy Plugin and CLI Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-building.md Use these commands to build the Javy plugin for wasm32-wasip1 and the Javy CLI in release mode. ```bash $ cargo build -p javy-plugin --target=wasm32-wasip1 -r $ cargo build -p javy-cli -r ``` -------------------------------- ### Initialize and Update Git Submodules Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-testing-locally.md Run these commands to ensure all git submodules are properly initialized and updated before proceeding with local testing. ```bash git submodule init git submodule update ``` -------------------------------- ### Run Formatting and Tests Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-testing-locally.md Execute the make command to run both code formatting checks and all tests. This is a common command for ensuring code quality. ```bash make fmt tests ``` -------------------------------- ### Run Host Application with Node.js Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-nodejs.md Executes a Node.js host script that interacts with compiled WebAssembly modules. Experimental warnings are suppressed. ```shell node --no-warnings=ExperimentalWarning host.mjs ``` -------------------------------- ### Set Release Versions for Javy Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing.md Run this command from the repository root to automatically set release versions in Cargo.toml before making a release. Requires jq. ```bash ./scripts/release.sh set-release-versions ``` -------------------------------- ### Add Global Variable Configuration to Javy Runtime Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-architecture.md Demonstrates how to add a new configuration option to the `javy` crate to set a global JavaScript variable. This involves modifying the `Config` struct, adding a setter method, and integrating the new configuration into the runtime's initialization logic. ```diff /// A configuration for [`Runtime`](crate::Runtime). #[derive(Debug)] pub struct Config { + pub(crate) javy_rocks: bool, } impl Default for Config { /// Creates a [`Config`] with default values. fn default() -> Self { Self { + javy_rocks: false, } } } impl Config { + /// Sets `globalThis.javy_rocks` to `true`. + pub fn javy_rocks(&mut self) -> &mut Self { + self.javy_rocks = true; + self + } } ``` ```rust pub struct JavyRocks; impl Instrinsic for JavyRocks { unsafe fn add_intrinsic(ctx: NonNull) { register(Ctx::from_raw(ctx)).expect("registering Javy Rocks to succeed") } } fn register<'js>(this: Ctx<'js>) -> Result<()> { let globals = this.globals(); globals.set("javy_rocks", true); } ``` ```diff + if cfg.javy_rocks { + unsafe { + JavyRocks::add_intrinsic(ctx.as_raw()) + } + } ``` -------------------------------- ### Emit Default Plugin Module Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-dynamic-linking.md Emits the default QuickJS plugin module to a specified file path. This module is required for dynamically linked Javy modules. ```bash javy emit-plugin -o plugin.wasm ``` -------------------------------- ### Build Dynamically Linked Wasm Module Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-dynamic-linking.md Builds a dynamically linked Wasm module from a JavaScript file. Requires the `-C dynamic` flag and the path to the plugin module. ```bash javy build -C dynamic -C plugin=plugin.wasm -o my_code.wasm my_code.js ``` -------------------------------- ### Returning Byte Arrays from Host to WebAssembly Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md Returning a byte array from the host involves allocating memory within the WebAssembly instance for both the byte array and a wide pointer. Use `memory.write` to place data and the wide pointer into the allocated memory. This requires access to a `cabi_realloc` function. ```rust fn setup(linker: &mut wasmtime::Linker) -> Result<()> { wasmtime_wasi::sync::add_to_linker(&mut linker, |ctx: &mut wasmtime_wasi::WasiContext| &mut ctx)?; linker .func_wrap( "host", "my_import", |mut caller: wasmtime::Caller<'_, StoreContext>| -> Result { let memory = caller.get_export("memory").unwrap().into_memory().unwrap(); let realloc = caller .get_export("cabi_realloc") .unwrap() .into_func() .unwrap() .typed::<(u32, u32, u32, u32), u32>(&caller)?; let bytes = todo!(); let original_ptr = 0; let original_size = 0; let alignment = 1; let ptr = realloc.call( &mut caller, ( original_ptr, original_size, alignment, bytes.len().try_into()?, ), )?; memory.write(&mut caller, ptr.try_into().unwrap(), &bytes)?; const LEN: usize = 8; let mut wide_ptr_buffer = [0u8; LEN]; wide_ptr_buffer[0..4].copy_from_slice(&ptr.to_le_bytes()); wide_ptr_buffer[4..8] .copy_from_slice(&TryInto::::try_into(bytes.len())?.to_le_bytes()); let wide_ptr = realloc.call( &mut caller, (original_ptr, original_size, alignment, LEN.try_into()?), )?; memory.write(&mut caller, wide_ptr.try_into()?, &wide_ptr_buffer)?; Ok(wide_ptr) }, ) .unwrap(); Ok(()) } ``` -------------------------------- ### Build JavaScript to Wasm with Javy CLI Source: https://github.com/bytecodealliance/javy/blob/main/README.md Use the Javy CLI to compile a JavaScript file into a WebAssembly binary. Specify the input JavaScript file and the output Wasm file path. ```bash javy build index.js -o destination/index.wasm ``` -------------------------------- ### Set Development Versions for Javy Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing.md Run this command from the repository root to automatically set development versions in Cargo.toml after a release. Requires jq. ```bash ./scripts/release.sh set-dev-versions ``` -------------------------------- ### compile_src Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Compiles JavaScript source code into QuickJS bytecode. The result is a pointer to a structure containing either the bytecode or an error message. ```APIDOC ## compile_src(src_ptr: i32, src_len: i32) -> result_wide_ptr: i32 ### Description This function compiles JavaScript source code to QuickJS bytecode. The return pointer points to a result type of `(discriminator: i32, ptr: i32, len: i32)` in the plugin instance's linear memory. If `discriminator` is `0`, `ptr` and `len` are the offset and length of the QuickJS bytecode. If the `discriminator` is `1`, `ptr` and `len` are the offset and length of a UTF-8 string containing an error message. ### Parameters #### Path Parameters - **src_ptr** (i32) - Required - Pointer to the source code in linear memory. - **src_len** (i32) - Required - Length of the source code. ### Return Value - **result_wide_ptr** (i32) - A pointer to a result structure containing either bytecode or an error message. ``` -------------------------------- ### Exporting a Default Arrow Function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-exports.md Demonstrates exporting a default arrow function in JavaScript, which corresponds to a 'default' export in the WIT definition. ```javascript export default () => { console.log("default"); } ``` -------------------------------- ### Rust Plugin Implementation with javy_plugin! Macro Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Implements a Javy plugin using the `javy_plugin!` macro, configuring the runtime and handling global variables and imported functions. ```rust use javy_plugin_api::{ javy::quickjs::prelude::Func, javy_plugin, Config, Runtime, }; wit_bindgen::generate!({ world: "my-javy-plugin", generate_all }); fn config() -> Config { Config::default() } fn modify_runtime(runtime: Runtime) -> Runtime { runtime.context().with(|ctx| { // Creates a `plugin` variable on the global set to `true`. ctx.globals().set("plugin", true).unwrap(); // Creates an `importedFunc` function on the global which will call // the imported function. ctx.globals() .set( "func", Func::from(|| { crate::imported_function(); }), ) .unwrap(); }); runtime } struct Component; // Set your plugin's import namespace. javy_plugin!("my-javy-plugin", Component, config, modify_runtime); export!(Component); ``` -------------------------------- ### Basic WIT World Definition Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Defines the exported functions for a Javy plugin's world, including compile-src, initialize-runtime, and invoke. ```wit package yournamespace:my-javy-plugin@1.0.0; world my-javy-plugin { export compile-src: func(src: list) -> result, string>; export initialize-runtime: func(); export invoke: func(bytecode: list, function: option); } ``` -------------------------------- ### Run Dynamically Linked Wasm Module with Wasmtime Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-dynamic-linking.md Executes a dynamically linked Wasm module using Wasmtime. The Javy plugin module must be preloaded using the `--preload` option. ```bash wasmtime run --preload javy-default-plugin-v4=plugin.wasm my_code.wasm ``` -------------------------------- ### javy/fs Module Source: https://github.com/bytecodealliance/javy/blob/main/npm/javy/README.md Provides functions for file system operations using file descriptors. ```APIDOC ## Module: javy/fs ### Description This module provides functions for reading from and writing to file descriptors, including standard input, output, and error streams. ### Functions #### readFileSync(fd) ##### Description Reads the entire content of a file descriptor and returns it as a `Uint8Array`. ##### Parameters - **fd** (number) - Required - The file descriptor to read from. ##### Returns - **Uint8Array** - The contents of the file descriptor. #### writeFileSync(fd, buffer) ##### Description Writes the provided `Uint8Array` buffer to the specified file descriptor. ##### Parameters - **fd** (number) - Required - The file descriptor to write to. - **buffer** (Uint8Array) - Required - The byte array to write. #### STDIO ##### Description An object containing integer file descriptors for standard input, standard output, and standard error. ##### Properties - **Stdin** (number) - File descriptor for standard input. - **Stdout** (number) - File descriptor for standard output. - **Stderr** (number) - File descriptor for standard error. ### Usage Example ```js import { readFileSync, writeFileSync, STDIO } from 'javy/fs' const textEncoder = new TextEncoder(); const inputBuffer = readFileSync(STDIO.Stdin); const inputText = new TextDecoder().decode(inputBuffer); const stdoutContent = `${inputText} -- out`; const stderrContent = `${inputText} -- err`; writeFileSync(STDIO.Stdout, textEncoder.encode(stdoutContent)); writeFileSync(STDIO.Stderr, textEncoder.encode(stderrContent)); ``` ``` -------------------------------- ### Plugin Cargo.toml Configuration Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Defines the package name, version, library type, and dependencies for a Javy plugin. ```toml [package] name = "my-plugin-name" version = "0.1.0" [lib] name = "my_plugin_name" crate-type = ["cdylib"] [dependencies] javy-plugin-api = "5.0.0" wit-bindgen = "0.47.0" ``` -------------------------------- ### Rust Plugin Implementation with Direct API Usage Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Implements a Javy plugin by directly using the underlying APIs from `javy_plugin_api` instead of the `javy_plugin!` macro. ```rust use std::process; use javy_plugin_api::javy::Runtime; use javy_plugin_api::{import_namespace, Config}; wit_bindgen::generate!({ world: "my-javy-plugin", generate_all }); // Set your plugin's import namespace. import_namespace!("my-javy-plugin"); struct Component; impl Guest for Component { fn invoke(bytecode: Vec, function: Option) { javy_plugin_api::invoke(&bytecode, function.as_deref()).unwrap_or_else(|e| { eprintln!("{e}"); process::abort(); }) } fn compile_src(src: Vec) -> Result, String> { javy_plugin_api::compile_src(&src).map_err(|e| e.to_string()) } fn initialize_runtime() { javy_plugin_api::initialize_runtime(config, modify_runtime).unwrap() } } export!(Component); fn config() -> Config { Config::default() } fn modify_runtime(runtime: Runtime) -> Runtime { runtime } ``` -------------------------------- ### Cargo.toml for a Javy Plugin Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Configure your Rust project's Cargo.toml to build a dynamic library suitable for a Javy plugin. Ensure the crate type is set to 'cdylib' and include the necessary 'javy-plugin-api' dependency. ```toml [package] name = "my-plugin-name" version = "0.1.0" [lib] name = "my_plugin_name" crate-type = ["cdylib"] [dependencies] javy-plugin-api = "5.0.0" ``` -------------------------------- ### Node.js Host Script for Wasm Interaction Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-nodejs.md This Node.js script orchestrates the compilation and execution of WebAssembly modules. It uses WASI for communication and handles file I/O for stdin, stdout, and stderr. ```javascript import { readFile, writeFile, open, rm } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { WASI } from "wasi"; try { const [embeddedModule, pluginModule] = await Promise.all([ compileModule("./embedded.wasm"), compileModule("./plugin.wasm"), ]); const result = await runJavy(pluginModule, embeddedModule, { n: 100 }); console.log("Success!", JSON.stringify(result, null, 2)); } catch (e) { console.log(e); } async function compileModule(wasmPath) { const bytes = await readFile(new URL(wasmPath, import.meta.url)); return WebAssembly.compile(bytes); } async function runJavy(pluginModule, embeddedModule, input) { const uniqueId = crypto.randomUUID(); // Use stdin/stdout/stderr to communicate with Wasm instance // See https://k33g.hashnode.dev/wasi-communication-between-nodejs-and-wasm-modules-another-way-with-stdin-and-stdout const workDir = tmpdir(); const stdinFilePath = join(workDir, `stdin.wasm.${uniqueId}.txt`); const stdoutFilePath = join(workDir, `stdout.wasm.${uniqueId}.txt`); const stderrFilePath = join(workDir, `stderr.wasm.${uniqueId}.txt`); // 👋 send data to the Wasm instance await writeFile(stdinFilePath, JSON.stringify(input), { encoding: "utf8" }); const [stdinFile, stdoutFile, stderrFile] = await Promise.all([ open(stdinFilePath, "r"), open(stdoutFilePath, "a"), open(stderrFilePath, "a"), ]); try { const wasi = new WASI({ version: "preview1", args: [], env: {}, stdin: stdinFile.fd, stdout: stdoutFile.fd, stderr: stderrFile.fd, returnOnExit: true, }); const pluginInstance = await WebAssembly.instantiate( pluginModule, wasi.getImportObject(), ); const instance = await WebAssembly.instantiate(embeddedModule, { "javy-default-plugin-v4": pluginInstance.exports, }); // Javy plugin is a WASI reactor see https://github.com/WebAssembly/WASI/blob/main/legacy/application-abi.md?plain=1 wasi.initialize(pluginInstance); instance.exports._start(); const [out, err] = await Promise.all([ readOutput(stdoutFilePath), readOutput(stderrFilePath), ]); if (err) { throw new Error(err); } return out; } catch (e) { if (e instanceof WebAssembly.RuntimeError) { const errorMessage = await readOutput(stderrFilePath); if (errorMessage) { throw new Error(errorMessage); } } throw e; } finally { await Promise.all([ stdinFile.close(), stdoutFile.close(), stderrFile.close(), rm(stdinFilePath), rm(stdoutFilePath), rm(stderrFilePath), ]); } } async function readOutput(filePath) { const str = (await readFile(filePath, "utf8")).trim(); try { return JSON.parse(str); } catch { return str; } } ``` -------------------------------- ### Exporting Multi-Word JavaScript Functions Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-exports.md Export JavaScript functions with multi-word names. The WIT file must use kebab-case, while the JavaScript export uses camelCase. Javy maps these correctly. ```javascript export function fooBar() { console.log("In foo-bar"); } ``` ```wit package local:main; world index { export foo-bar: func(); } ``` ```bash javy build index.js -C wit=index.wit -C wit-world=index -o index.wasm wasmtime run --invoke foo-bar index.wasm ``` -------------------------------- ### Compile JavaScript with Javy Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-nodejs.md Compiles an embedded JavaScript file into a WebAssembly module using Javy, with support for dynamic linking and a specified plugin. ```shell javy build -C dynamic -C plugin=plugin.wasm -o embedded.wasm embedded.js ``` -------------------------------- ### Generate Wasm Module with javy-codegen Source: https://github.com/bytecodealliance/javy/blob/main/crates/codegen/README.md Use this snippet to generate a Wasm module from a JavaScript file. It demonstrates loading JavaScript, initializing a Javy plugin, configuring the generator, and performing the asynchronous generation. Ensure that the JavaScript file and any plugin Wasm files exist at the specified paths. ```rust use std::path::Path; use javy_codegen::{Generator, LinkingKind, Plugin, JS}; #[tokio::main] async fn main() { // Load your target Javascript. let js = JS::from_file(Path::new("example.js")); // Load existing pre-initialized Javy plugin. let plugin = Plugin::new_from_path(Path::new("example-plugin.wasm")); // Configure code generator. let mut generator = Generator::new(); generator.plugin(plugin); generator.linking(LinkingKind::Static); // Generate your Wasm module. let wasm = generator.generate(&js).await?; } ``` -------------------------------- ### Exporting a Simple JavaScript Function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-exports.md Export a basic JavaScript function using ESM syntax. Ensure a corresponding WIT definition exists for the export. ```javascript export function foo() { console.log("Hello from foo!"); } console.log("Hello world!"); ``` ```wit package local:main; world index-world { export foo: func(); } ``` ```bash javy build index.js -C wit=index.wit -C wit-world=index-world -o index.wasm wasmtime run --invoke foo index.wasm ``` -------------------------------- ### WIT World with Imported Function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Extends the WIT world definition to include an imported function named 'imported-function'. ```wit package yournamespace:my-javy-plugin@1.0.0; world my-javy-plugin { export compile-src: func(src: list) -> result, string>; export initialize-runtime: func(); export invoke: func(bytecode: list, function: option); import imported-function: func(); } ``` -------------------------------- ### Passing Byte Arrays to Imported Functions Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md When passing a byte array to an imported WebAssembly function, provide the pointer and length to the imported function. Ensure the length is convertible to u32. ```rust use anyhow::Result; #[link(name = "host")] extern "C" { fn my_import(ptr: *const u32, len: u32); } fn call_the_import(bytes: &[u8]) -> Result<()> { unsafe { my_import(bytes.as_ptr(), bytes.len().try_into()?) }; } ``` -------------------------------- ### Run Fuzzing Target with Cargo Fuzz Source: https://github.com/bytecodealliance/javy/blob/main/fuzz/README.md Use this command to execute a specific fuzzing target. Replace `$TARGET` with the name of the desired target, such as 'json-differential'. ```sh cargo +nightly fuzz run $TARGET ``` -------------------------------- ### Reading Returned Byte Arrays from Host Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md When reading a byte array returned from the host, first obtain the wide pointer. Then, extract the actual pointer and length from the wide pointer to read the slice from memory. Ensure correct handling of raw pointers and type conversions. ```rust #[link(wasm_import_module = "host")] extern "C" { fn my_import() -> *const u32; } fn main() { let bytes = unsafe { let wide_ptr = my_import(); let [ptr, len] = std::slice::from_raw_parts(wide_ptr, 2) else { unreachable!() }; std::slice::from_raw_parts(*ptr as *const u8, (*len).try_into().unwrap()) }; todo!(); } ``` -------------------------------- ### import_namespace Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Defines the namespace for Wasm imports in dynamically linked modules. ```APIDOC ## import_namespace ### Description Contains a UTF-8 encoded string. This is used to determine the namespace that will be used for the Wasm imports in dynamically linked modules built with this plugin. ``` -------------------------------- ### Exporting a Default JavaScript Function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-exports.md Export a default JavaScript function or arrow function. The WIT definition should use 'export default'. ```javascript export default function () { console.log("In default"); } ``` ```wit package local:main; world index { export default: func(); } ``` ```bash javy build index.js -C wit=index.wit -C wit-world=index -o index.wasm wasmtime run --invoke default index.wasm ``` -------------------------------- ### Call exported function with byte array from host Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md Pass a byte array to an exported Wasm function by allocating memory, writing the bytes, and then calling the function with the pointer and length. Requires a `cabi_realloc` function in the Wasm module. ```rust use anyhow::Result; fn call_the_export(bytes: &[u8], instance: wasmtime::Instance, store: &mut wasmtime::Store) -> Result<()> { let memory = instance.get_memory(&mut store, "memory"); let realloc_fn = instance .get_typed_func::<(u32, u32, u32, u32), u32>(&mut store, "cabi_realloc")?; let len = bytes.len().try_into()?; let original_ptr = 0; let original_size = 0; let alignment = 1; let ptr = realloc_fn.call(&mut store, (original_ptr, original_size, alignment, len))?; memory.write(&mut store, ptr.try_into()?, bytes)?; let your_fn = instance.get_typed_func::<(u32, u32), ()>(&mut store, "your_fn")?; your_fn.call(&mut store, (ptr, len)?); Ok(()) } ``` -------------------------------- ### JavaScript Type Checking for BigInt Comparison Source: https://github.com/bytecodealliance/javy/wiki/Notes-on-number-representation-for-serialization-and-deserialization Provides a solution for safely comparing BigInts with other number types by checking the type of the variable before performing operations. This ensures that operations are only performed between compatible types. ```javascript var Shopify; Shopify = { // Let's assume that productId was serialized as BigInt main: (productId) => { var ty = typeof productId; switch (ty) { case 'number': // ... case 'bigint': // ... } } } ``` -------------------------------- ### invoke Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-extending.md Evaluates JavaScript code or calls an exported JavaScript function. This function takes compiled bytecode and optionally a function name to execute. ```APIDOC ## invoke(bytecode_ptr: i32, bytecode_len: i32, fn_name_discriminator: i32, fn_name_ptr: i32, fn_name_len: i32) -> () ### Description This function is used to evaluate the JavaScript code and optionally to call an exported JS function if `fn_name_discriminator` is not `0`. ### Parameters #### Path Parameters - **bytecode_ptr** (i32) - Required - Pointer to the compiled bytecode in linear memory. - **bytecode_len** (i32) - Required - Length of the compiled bytecode. - **fn_name_discriminator** (i32) - Required - Discriminator indicating if a function name is provided (non-zero if provided). - **fn_name_ptr** (i32) - Required - Pointer to the function name in linear memory (if `fn_name_discriminator` is non-zero). - **fn_name_len** (i32) - Required - Length of the function name (if `fn_name_discriminator` is non-zero). ### Return Value - **()** - This function does not return a value. ``` -------------------------------- ### Receive byte array in exported Wasm function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md In an exported Wasm function, use `std::slice::from_raw_parts` to create a slice from a raw pointer and length received as arguments. ```rust #[export_name = "your_fn"] pub unsafe extern "C" fn your_fn(ptr: *const u8, len: usize) { let bytes = std::slice::from_raw_parts(ptr, len); todo!(); // use `bytes` for something } ``` -------------------------------- ### Embedded JavaScript Logic Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-using-nodejs.md This JavaScript code is designed to be compiled into a WebAssembly module by Javy. It reads input from stdin, processes it using a 'foo' function, and writes the result to stdout. ```javascript // Read input from stdin const input = readInput(); // Call the function with the input const result = foo(input); // Write the result to stdout writeOutput(result); // The main function. function foo(input) { if (input && typeof input === "object" && typeof input.n === "number") { return { n: input.n + 1 }; } return { n: 0 }; } // Read input from stdin function readInput() { const chunkSize = 1024; const inputChunks = []; let totalBytes = 0; // Read all the available bytes while (1) { const buffer = new Uint8Array(chunkSize); // Stdin file descriptor const fd = 0; const bytesRead = Javy.IO.readSync(fd, buffer); totalBytes += bytesRead; if (bytesRead === 0) { break; } inputChunks.push(buffer.subarray(0, bytesRead)); } // Assemble input into a single Uint8Array const { finalBuffer } = inputChunks.reduce( (context, chunk) => { context.finalBuffer.set(chunk, context.bufferOffset); context.bufferOffset += chunk.length; return context; }, { bufferOffset: 0, finalBuffer: new Uint8Array(totalBytes) }, ); const maybeJson = new TextDecoder().decode(finalBuffer); try { return JSON.parse(maybeJson); } catch { return; } } // Write output to stdout function writeOutput(output) { const encodedOutput = new TextEncoder().encode(JSON.stringify(output)); const buffer = new Uint8Array(encodedOutput); // Stdout file descriptor const fd = 1; Javy.IO.writeSync(fd, buffer); } ``` -------------------------------- ### Return byte array from exported Wasm function Source: https://github.com/bytecodealliance/javy/blob/main/docs/docs-contributing-complex-data-types.md To return a byte array, leak the byte array and store its pointer and length in a static mutable array. The function returns a pointer to this array. ```rust static mut BYTES_RET_AREA: [u32; 2] = [0; 2]; #[export_name = "your_fn"] pub unsafe extern "C" fn your_fn() -> *const u32 { let bytes = todo!(); // fill in your own logic let len = bytes.len(); let ptr = Box::leak(bytes.into_boxed_slice()).as_ptr(); BYTES_RET_AREA[0] = ptr as u32; BYTES_RET_AREA[1] = len.try_into().unwrap(); BYTES_RET_AREA.as_ptr() } ``` -------------------------------- ### JavaScript BigInt Comparison Error Source: https://github.com/bytecodealliance/javy/wiki/Notes-on-number-representation-for-serialization-and-deserialization Illustrates a common error when comparing a BigInt with a regular JavaScript number without proper type checking. This comparison will fail because equality operations require operands of the same type. ```javascript var Shopify; Shopify = { // Let's assume that productId was serialized as BigInt main: (productId) => { if (productId === 42)) { // will throw since the equality operation must be applied to two BigInts or Numbers return "ok"; } throw new Error("i is not BigInt(42)"); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.