diff --git a/Cargo.toml b/Cargo.toml index 61df84a..fbefef7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,10 +10,9 @@ futures = "0.3" http = "0.2" reqwest = { version = "0.11", default-features = true, features = ["json", "blocking"] } tokio = { version = "1.1", features = ["full"] } -wasmtime = "0.23" -wasmtime-wasi = "0.23" -wasi-common = "0.23" -wasi-cap-std-sync = "0.23" +wasmtime = "0.22" +wasmtime-wasi = "0.22" +wasi-common = "0.22" wasi-experimental-http = {path = "crates/wasi-experimental-http"} wasi-experimental-http-wasmtime = {path = "crates/wasi-experimental-http-wasmtime"} @@ -21,5 +20,5 @@ wasi-experimental-http-wasmtime = {path = "crates/wasi-experimental-http-wasmtim members = [ "crates/wasi-experimental-http", "crates/wasi-experimental-http-wasmtime", - "tests/simple" + "tests/rust" ] diff --git a/build.rs b/build.rs index 56685e5..5186851 100644 --- a/build.rs +++ b/build.rs @@ -1,13 +1,17 @@ use std::process; const TESTS_DIR: &str = "tests"; -const SIMPLE_EXAMPLE: &str = "simple"; +const RUST_EXAMPLE: &str = "rust"; +const AS_EXAMPLE: &str = "as"; fn main() { - println!("cargo:rerun-if-changed=tests/simple/src/lib.rs"); + println!("cargo:rerun-if-changed=tests/rust/src/lib.rs"); println!("cargo:rerun-if-changed=crates/wasi-experimental-http/src/lib.rs"); + println!("cargo:rerun-if-changed=tests/as/index.ts"); + println!("cargo:rerun-if-changed=crates/as/index.ts"); - cargo_build_example(TESTS_DIR.to_string(), SIMPLE_EXAMPLE.to_string()) + cargo_build_example(TESTS_DIR.to_string(), RUST_EXAMPLE.to_string()); + as_build_example(TESTS_DIR.to_string(), AS_EXAMPLE.to_string()); } fn cargo_build_example(dir: String, example: String) { @@ -23,3 +27,21 @@ fn cargo_build_example(dir: String, example: String) { .arg("--release"); cmd.output().unwrap(); } + +fn as_build_example(dir: String, example: String) { + let dir = format!("{}/{}", dir, example); + + let mut cmd = process::Command::new("npm"); + cmd.current_dir(dir.clone()); + cmd.stdout(process::Stdio::piped()); + cmd.stderr(process::Stdio::piped()); + cmd.arg("install"); + cmd.output().unwrap(); + + let mut cmd = process::Command::new("npm"); + cmd.current_dir(dir); + cmd.stdout(process::Stdio::piped()); + cmd.stderr(process::Stdio::piped()); + cmd.arg("run").arg("asbuild"); + cmd.output().unwrap(); +} diff --git a/crates/as/index.ts b/crates/as/index.ts index 9d7819d..5b55905 100644 --- a/crates/as/index.ts +++ b/crates/as/index.ts @@ -2,37 +2,352 @@ // @ts-ignore import * as wasi from "as-wasi"; +/** Send an HTTP request and return an HTTP response. + * + * It is recommended to use the `RequestBuilder` helper class. + */ +export function request(req: Request): Response { + return raw_request(req.url, methodEnumToString(req.method), headersToString(req.headers), req.body); +} + +/** An HTTP response. */ +export class Response { + /** The HTTP response status code. */ + public status: StatusCode; + /** The HTTP response headers. + * + * TODO + * + * For now, the response headers are represented + * as a string, which makes it difficult to actually + * use by a consumer. This should be represented as a + * `Map`. + */ + public headers: string; + /** The response body as a byte array. + * + * It should be decoded by the consumer accordingly. + * If expecting a UTF string, use the built-in functions + * to decode. + */ + public body: ArrayBuffer; + + constructor(status: u16, headers: string, body: ArrayBuffer) { + this.status = status; + this.headers = headers; + this.body = body; + } +} + +/** An HTTP request. + * + * It is recommended to use the a `RequestBuilder` + * to create and send HTTP requests. + */ +export class Request { + /** The URL of the request. */ + public url: string; + /** The HTTP method of the request. */ + public method: Method; + /** The request headers. */ + public headers: Map; + /** The request body as bytes. */ + public body: ArrayBuffer; + + constructor( + url: string, + method: Method = Method.GET, + headers: Map = new Map(), + body: ArrayBuffer = new ArrayBuffer(0) + ) { + this.url = url; + this.method = method; + this.headers = headers; + this.body = body; + } +} + +/** Helper class for creating and sending an HTTP request. + * ``` + let body = String.UTF8.encode("testing the body"); + let res = new RequestBuilder("https://SOME-URL") + .header("Content-Type", "text/plain") + .method(Method.POST) + .body(body) + .send(); + wasi.Console.log(res.status.toString()) + wasi.Console.log(res.headers); + let result = String.UTF8.decode(res.body); + wasi.Console.log(result); + * ``` +*/ +export class RequestBuilder { + private request: Request; + + constructor(url: string) { + this.request = new Request(url); + } + + /** Set the request's HTTP method. */ + public method(m: Method): RequestBuilder { + this.request.method = m; + return this; + } + + /** Add a new pair of header key and header value to the request. */ + public header(key: string, value: string): RequestBuilder { + this.request.headers.set(key, value); + return this; + } + + /** Set the request's body. */ + public body(b: ArrayBuffer): RequestBuilder { + this.request.body = b; + return this; + } + + /** Send the request and return an HTTP response. */ + public send(): Response { + wasi.Console.log("sending http request to " + this.request.url); + return request(this.request); + } +} + // @ts-ignore: decorator @external("wasi_experimental_http", "req") -@unsafe export declare function req(url_ptr: usize, url_len_ptr: usize, bytes_written_ptr: usize): usize; +@unsafe declare function req( + url_ptr: usize, + url_len_ptr: usize, + method_ptr: usize, + method_len_ptr: usize, + req_body_ptr: usize, + req_body_len_ptr: usize, + heders_ptr: usize, + headers_len_ptr: usize, + body_res_ptr: usize, + body_written_ptr: usize, + headers_written_ptr: usize, + headers_res_ptr: usize, + status_code_ptr: usize, + err_ptr: usize, + err_len_ptr: usize + ): u32; -export function _start(): void { - let res = request("https://api.brigade.sh/healthz"); - wasi.Console.log(res); -} +function raw_request( + url: string, + method: string, + headers: string, + body: ArrayBuffer + ): Response { -export function request(url: string): string { let url_buf = String.UTF8.encode(url); - let url_len = url_buf.byteLength; let url_len_ptr = memory.data(8); - store(url_len_ptr, url_len); + store(url_len_ptr, url_buf.byteLength); let url_ptr = changetype(url_buf); - let bytes_written_ptr = memory.data(8); - let body_ptr = req(url_ptr, url_len_ptr, bytes_written_ptr); - // @ts-ignore: cast - return String.UTF8.decodeUnsafe(body_ptr, load(bytes_written_ptr)); + + let method_buf = String.UTF8.encode(method); + let method_len_ptr = memory.data(8); + store(method_len_ptr, method_buf.byteLength); + let method_ptr = changetype(method_buf); + + let headers_buf = String.UTF8.encode(headers); + let headers_len_ptr = memory.data(8); + store(headers_len_ptr, headers_buf.byteLength); + let headers_ptr = changetype(headers_buf); + + let req_body_ptr = changetype(body); + let req_body_len_ptr = memory.data(8); + store(req_body_len_ptr, body.byteLength); + + let body_res_ptr = memory.data(8); + let body_written_ptr = memory.data(8); + let headers_res_ptr = memory.data(8); + let headers_written_ptr = memory.data(8); + let status_code_ptr = memory.data(8); + let err_ptr = memory.data(8); + let err_len_ptr = memory.data(8); + + let err = req( + url_ptr, + url_len_ptr, + method_ptr, + method_len_ptr, + req_body_ptr, + req_body_len_ptr, + headers_ptr, + headers_len_ptr, + body_res_ptr, + body_written_ptr, + headers_written_ptr, + headers_res_ptr, + status_code_ptr, + err_ptr, + err_len_ptr + ); + + if (err != 0) { + // Based on the error code, read and log the error. + wasi.Console.log("ERROR CODE: " + err.toString()); + + // Error code 1 means no error message was written. + if (err == 1) { + wasi.Console.log("Runtime error: cannot find exorted alloc function or memory"); + abort(); + } + + // An error code was written. Read it, then abort. + let err_len = load(err_len_ptr) as u32; + let err_buf = new ArrayBuffer(err_len); + memory.copy(changetype(err_buf), err_ptr, err_len); + wasi.Console.log("Runtime error: " + String.UTF8.decode(err_buf)); + abort(); + } + + let status = load(status_code_ptr) as u16; + + let body_size = load(body_written_ptr) as u32; + let body_res = new ArrayBuffer(body_size); + memory.copy(changetype(body_res), load(body_res_ptr), body_size); + + let headers_length = load(headers_written_ptr) as u32; + let headers_res_buf = new ArrayBuffer(headers_length); + memory.copy(changetype(headers_res_buf), load(headers_res_ptr), headers_length); + let headers_res = String.UTF8.decode(headers_res_buf); + + return new Response(status, headers_res, body_res); +} + +/** Transform the header map into a string. */ +function headersToString(headers: Map): string { + let res: string = "{"; + let keys = headers.keys() as Array; + let values = headers.values() as Array; + for (let index = 0; index < keys.length; ++index) { + res += '"' + keys[index] + '"' + ":" + '"' + values[index] + '"'; + if (index != keys.length - 1) { + res += ","; + } + } + res += "}"; + + return res; +} + +/** The standard HTTP methods. */ +export enum Method{ + GET, + HEAD, + POST, + PUT, + DELETE, + CONNECT, + OPTIONS, + TRACE, + PATCH } -// Allocate memory for a new byte array of -// size `len` and return the offset into -// the module's linear memory to the start -// of the block. +/** Return the string representation of the HTTP method. */ +function methodEnumToString(m: Method): string { + switch(m) { + case Method.GET: + return "GET"; + case Method.HEAD: + return "HEAD"; + case Method.POST: + return "POST"; + case Method.PUT: + return "PUT"; + case Method.DELETE: + return "DELET"; + case Method.CONNECT: + return "CONNECT"; + case Method.OPTIONS: + return "OPTIONS"; + case Method.TRACE: + return "TRACE"; + case Method.PATCH: + return "PATCH"; + + default: + return ""; + } +} + +/** The standard HTTP status codes. */ +export enum StatusCode { + CONTINUE = 100, + SWITCHING_PROTOCOL = 101, + PROCESSING = 102, + EARLY_HINTS = 103, + + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, + + MULTIPLE_CHOICE = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + UNUSED = 306, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, + + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + PAYMENT_REQUIRED = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + NOT_ACCEPTABLE = 406, + PROXY_AUTHENTICATION_REQUIRED = 407, + REQUEST_TIMEOUT = 408, + CONFLICT = 409, + GONE = 410, + LENGTH_REQUIRED = 411, + PRECONDITION_FAILED = 412, + PAYLOAD_TOO_LARGE = 413, + URI_TOO_LONG = 414, + UNSUPPORTED_MEDIA_TYPE = 415, + RANGE_NOT_SATISFIABLE = 416, + EXPECTATION_FAILED = 417, + IM_A_TEAPOT = 418, + MISDIRECTED_REQUEST = 421, + UNPROCESSABLE_ENTITY = 422, + LOCKED = 423, + FAILED_DEPENDENCY = 424, + TOO_EARLY = 425, + UPGRADE_REQUIRED = 426, + PRECONDITION_REQURIED = 428, + TOO_MANY_REQUESTS = 429, + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + UNAVAILABLE_FOR_LEGAL_REASONS = 451, + + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLELENTED = 501, + BAD_GATEWAY = 502, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATES = 506, + INSUFFICIENT_STORAGE = 507, + LOOP_DETECTED = 508, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511 +} + +/** Allocate memory for a new byte array of size `len` + * and return the offset into the module's linear memory + * to the start of the block. */ export function alloc(len: i32): usize { - // create a new AssemblyScript byte array - let buf = new Array(len); - let buf_ptr = memory.data(8); - // create a pointer to the byte array and - // return it - store>(buf_ptr, buf); - return buf_ptr; - } + let buf = new ArrayBuffer(len); + return changetype(buf); +} diff --git a/crates/as/package-lock.json b/crates/as/package-lock.json index ce6d35e..91b843c 100644 --- a/crates/as/package-lock.json +++ b/crates/as/package-lock.json @@ -1,30 +1,31 @@ { - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "as-wasi": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/as-wasi/-/as-wasi-0.2.0.tgz", - "integrity": "sha512-dQ9b0YXZx8B7t0BhGNKRbugZkyQY6dca3rOFQcoN/grlOYnPUygtYCdOKU2iLLtbCan+dgt9Ww1zgDxeRs9U/g==" - }, - "assemblyscript": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.16.1.tgz", - "integrity": "sha512-btb/Q2cs42O7NaVRLDpUIb4fF+o4H4id0kjOOOzS25KCOx0voiyGBeWYqfnrOeufMQacvDNqGkjJuGkdTJIrQQ==", - "requires": { - "binaryen": "97.0.0-nightly.20201008", - "long": "^4.0.0" - } - }, - "binaryen": { - "version": "97.0.0-nightly.20201008", - "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-97.0.0-nightly.20201008.tgz", - "integrity": "sha512-GWV30FOQqz+vBIZRbc7GSasLNhh8BNLKH+2u2j5BjqM0WOEqqaP5iSj0mq72We2aVYqpBajJPI/CORY6o2RBxA==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - } + "name": "@deislabs/wasi-experimental-http", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "as-wasi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/as-wasi/-/as-wasi-0.2.0.tgz", + "integrity": "sha512-dQ9b0YXZx8B7t0BhGNKRbugZkyQY6dca3rOFQcoN/grlOYnPUygtYCdOKU2iLLtbCan+dgt9Ww1zgDxeRs9U/g==" + }, + "assemblyscript": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.18.12.tgz", + "integrity": "sha512-a0zJlb4xgEtxdadrrIP9MuLmQuRE6ZVzXPi2RZoVG6zgz+nLYLt1mkiP/TbJRY+4wvf1peTCZok+vyRAxFjppQ==", + "requires": { + "binaryen": "98.0.0-nightly.20210106", + "long": "^4.0.0" + } + }, + "binaryen": { + "version": "98.0.0-nightly.20210106", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", + "integrity": "sha512-iunAgesqT9PXVYCc72FA4h0sCCKLifruT6NuUH63xqlFJGpChhZLgOtyIb/fIgTibN5Pd692cxfBViyCWFsJ9Q==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" } + } } diff --git a/crates/as/package.json b/crates/as/package.json index c43ff40..5c734e4 100644 --- a/crates/as/package.json +++ b/crates/as/package.json @@ -1,9 +1,12 @@ { - "scripts": { - "asbuild": "asc index.ts -b build/optimized.wasm --use abort=wasi_abort --debug" - }, - "dependencies": { - "as-wasi": "0.2.0", - "assemblyscript": "^0.16.0" - } + "name": "@deislabs/wasi-experimental-http", + "main": "index.ts", + "types": "index.ts", + "scripts": { + "asbuild": "asc index.ts -b build/optimized.wasm --use abort=wasi_abort --debug" + }, + "dependencies": { + "as-wasi": "0.2.0", + "assemblyscript": "^0.18.12" + } } diff --git a/crates/wasi-experimental-http-wasmtime/Cargo.toml b/crates/wasi-experimental-http-wasmtime/Cargo.toml index f1a0304..105edb4 100644 --- a/crates/wasi-experimental-http-wasmtime/Cargo.toml +++ b/crates/wasi-experimental-http-wasmtime/Cargo.toml @@ -11,7 +11,7 @@ futures = "0.3" http = "0.2" reqwest = { version = "0.11", default-features = true, features = ["json", "blocking"] } tokio = { version = "1.1", features = ["full"] } -wasmtime = "0.23" -wasmtime-wasi = "0.23" -wasi-common = "0.23" +wasmtime = "0.22" +wasmtime-wasi = "0.22" +wasi-common = "0.22" wasi-experimental-http = {path = "../wasi-experimental-http"} diff --git a/readme.md b/readme.md index baf6538..140fe4d 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,10 @@ # `wasi-experimental-http` This projects adds experimental and _temporary_ outgoing HTTP support for WASI -modules. It is currently unstable and incomplete. +modules. It is currently unstable and incomplete. This project does not aim to +replace WASI's native networking and sockets API, but rather provide a temporary +workaround for guest modules to make outbound HTTP requests until WASI +stabilizes the networking API. ### Writing a module that makes an HTTP request @@ -80,11 +83,41 @@ wasi_experimental_http::write_guest_memory:: written 374 bytes Note that the Wasmtime version currently supported is [0.23](https://docs.rs/wasmtime/0.23.0/wasmtime/). +### Sending HTTP requests from AssemblyScript + +This repository also contains an AssemblyScript implementation for sending HTTP +requests: + +```typescript +// @ts-ignore +import * as wasi from "as-wasi"; +import { + Method, + RequestBuilder, + Response, +} from "@deislabs/wasi-experimental-http"; +export { alloc } from "@deislabs/wasi-experimental-http"; + +export function _start_(): void { + let body = String.UTF8.encode("testing the body"); + let res = new RequestBuilder("https://postman-echo.com/post") + .header("Content-Type", "text/plain") + .method(Method.POST) + .body(body) + .send(); + wasi.Console.log(res.status.toString()); + wasi.Console.log(res.headers); + wasi.Console.log(String.UTF8.decode(res.body)); +} +``` + ### Known limitations - request and response bodies are [`Bytes`](https://docs.rs/bytes/1.0.1/bytes/). -- handling headers is currently very inefficient. +- handling headers in Rust is currently very inefficient. - there are no WITX definitions, which means we have to manually keep the host call and guest implementation in sync. Adding WITX definitions could also enable support for other WASI runtimes. -- the AssemblyScript implementation is currently incomplete. +- the `alloc` function in AssemblyScript has to be re-exported in order for the + runtime to use it. There probably is a decorator or Binaryen setting to avoid + removing it, but for now this has to be re-exported. diff --git a/src/main.rs b/src/main.rs index ee8c33c..38a39e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,27 @@ use anyhow::Error; use std::time::Instant; -use wasi_cap_std_sync::WasiCtxBuilder; use wasi_experimental_http_wasmtime::link_http; use wasmtime::*; -use wasmtime_wasi::Wasi; +use wasmtime_wasi::{Wasi, WasiCtxBuilder}; #[tokio::main] async fn main() -> Result<(), Error> { - let instance = - create_instance("target/wasm32-wasi/release/simple_wasi_http_tests.wasm".to_string())?; - // let instance = create_instance("crates/as/build/optimized.wasm".to_string())?; - + let modules = vec![ + "target/wasm32-wasi/release/simple_wasi_http_tests.wasm", + "tests/as/build/optimized.wasm", + ]; let test_funcs = vec!["get", "post"]; - run_start(&instance, &test_funcs) + + for module in modules { + let instance = create_instance(module.to_string())?; + run_tests(&instance, &test_funcs.clone())?; + } + + Ok(()) } /// Execute the module's `_start` function. -fn run_start(instance: &Instance, test_funcs: &Vec<&str>) -> Result<(), Error> { +fn run_tests(instance: &Instance, test_funcs: &Vec<&str>) -> Result<(), Error> { for func in test_funcs.iter() { let func = instance.get_func(func).expect("cannot find function"); func.call(&vec![])?; diff --git a/tests/as/index.ts b/tests/as/index.ts new file mode 100644 index 0000000..5e83be7 --- /dev/null +++ b/tests/as/index.ts @@ -0,0 +1,28 @@ +// @ts-ignore +import * as wasi from "as-wasi"; +import { Method, RequestBuilder, Response } from "../../crates/as"; +export { alloc } from "../../crates/as"; + +export function post(): void { + let body = String.UTF8.encode("testing the body"); + let res = new RequestBuilder("https://postman-echo.com/post") + .header("Content-Type", "text/plain") + .method(Method.POST) + .body(body) + .send(); + print(res); +} + +export function get(): void { + let res = new RequestBuilder("https://api.brigade.sh/healthz") + .method(Method.GET) + .send(); + print(res); +} + +function print(res: Response): void { + wasi.Console.log(res.status.toString()); + wasi.Console.log(res.headers); + let result = String.UTF8.decode(res.body); + wasi.Console.log(result); +} diff --git a/tests/as/package-lock.json b/tests/as/package-lock.json new file mode 100644 index 0000000..2c3f1de --- /dev/null +++ b/tests/as/package-lock.json @@ -0,0 +1,30 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "as-wasi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/as-wasi/-/as-wasi-0.2.0.tgz", + "integrity": "sha512-dQ9b0YXZx8B7t0BhGNKRbugZkyQY6dca3rOFQcoN/grlOYnPUygtYCdOKU2iLLtbCan+dgt9Ww1zgDxeRs9U/g==" + }, + "assemblyscript": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.18.12.tgz", + "integrity": "sha512-a0zJlb4xgEtxdadrrIP9MuLmQuRE6ZVzXPi2RZoVG6zgz+nLYLt1mkiP/TbJRY+4wvf1peTCZok+vyRAxFjppQ==", + "requires": { + "binaryen": "98.0.0-nightly.20210106", + "long": "^4.0.0" + } + }, + "binaryen": { + "version": "98.0.0-nightly.20210106", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-98.0.0-nightly.20210106.tgz", + "integrity": "sha512-iunAgesqT9PXVYCc72FA4h0sCCKLifruT6NuUH63xqlFJGpChhZLgOtyIb/fIgTibN5Pd692cxfBViyCWFsJ9Q==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + } + } +} diff --git a/tests/as/package.json b/tests/as/package.json new file mode 100644 index 0000000..2b6c5fd --- /dev/null +++ b/tests/as/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "asbuild": "asc index.ts -b build/optimized.wasm --use abort=wasi_abort --debug" + }, + "dependencies": { + "as-wasi": "0.2.0", + "assemblyscript": "^0.18.12" + } +} diff --git a/tests/as/tsconfig.json b/tests/as/tsconfig.json new file mode 100644 index 0000000..9682388 --- /dev/null +++ b/tests/as/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "./node_modules/assemblyscript/std/assembly.json", + "include": ["./**/*.ts"] +} diff --git a/tests/simple/Cargo.toml b/tests/rust/Cargo.toml similarity index 100% rename from tests/simple/Cargo.toml rename to tests/rust/Cargo.toml diff --git a/tests/simple/src/lib.rs b/tests/rust/src/lib.rs similarity index 100% rename from tests/simple/src/lib.rs rename to tests/rust/src/lib.rs