diff --git a/Cargo.lock b/Cargo.lock index 350ecfc8..ee752757 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2187,6 +2187,8 @@ dependencies = [ "bytes", "data-url", "deno_core", + "deno_fs", + "deno_io", "deno_path_util", "deno_permissions", "deno_tls", diff --git a/crates/base/src/runtime/mod.rs b/crates/base/src/runtime/mod.rs index 6c2a09d4..3216531f 100644 --- a/crates/base/src/runtime/mod.rs +++ b/crates/base/src/runtime/mod.rs @@ -752,6 +752,7 @@ where deno_fetch::Options { user_agent: deno::versions::user_agent().to_string(), root_cert_store_provider: Some(root_cert_store_provider.clone()), + file_fetch_handler: Rc::new(deno_fetch::FsFetchHandler), ..Default::default() }, ), diff --git a/crates/base/test_cases/fetch-local-npm-file/index.ts b/crates/base/test_cases/fetch-local-npm-file/index.ts new file mode 100644 index 00000000..f5483f79 --- /dev/null +++ b/crates/base/test_cases/fetch-local-npm-file/index.ts @@ -0,0 +1,10 @@ +import * as _meow from "npm:@imagemagick/magick-wasm@0.0.30"; + +const url = import.meta.resolve("npm:@imagemagick/magick-wasm@0.0.30"); + +export default { + async fetch() { + const text = await (await fetch(url)).text(); + return new Response(text); + }, +}; diff --git a/crates/base/test_cases/main/index.ts b/crates/base/test_cases/main/index.ts index 0639fa9c..edf88ffa 100644 --- a/crates/base/test_cases/main/index.ts +++ b/crates/base/test_cases/main/index.ts @@ -97,6 +97,7 @@ Deno.serve(async (req: Request) => { noNpm, envVars, context, + staticPatterns: ["**/*.wasm"], }); }; diff --git a/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.d.ts b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.d.ts new file mode 100644 index 00000000..fbf99b5e --- /dev/null +++ b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.d.ts @@ -0,0 +1,4 @@ +/* tslint:disable */ +/* eslint-disable */ + +export function add(a: number, b: number): number; diff --git a/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.js b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.js new file mode 100644 index 00000000..5c26f5a5 --- /dev/null +++ b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm.js @@ -0,0 +1,38 @@ +/* @ts-self-types="./add_wasm.d.ts" */ + +/** + * @param {number} a + * @param {number} b + * @returns {number} + */ +export function add(a, b) { + const ret = wasm.add(a, b); + return ret >>> 0; +} + +function __wbg_get_imports() { + const import0 = { + __proto__: null, + __wbindgen_init_externref_table: function () { + const table = wasm.__wbindgen_externrefs; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); + }, + }; + return { + __proto__: null, + "./add_wasm_bg.js": import0, + }; +} + +const wasmUrl = new URL("add_wasm_bg.wasm", import.meta.url); +const wasmInstantiated = await WebAssembly.instantiateStreaming( + fetch(wasmUrl), + __wbg_get_imports(), +); +const wasm = wasmInstantiated.instance.exports; +wasm.__wbindgen_start(); diff --git a/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm new file mode 100644 index 00000000..58aed5a8 Binary files /dev/null and b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm differ diff --git a/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts new file mode 100644 index 00000000..1a00d2d7 --- /dev/null +++ b/crates/base/test_cases/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export const add: (a: number, b: number) => number; +export const __wbindgen_externrefs: WebAssembly.Table; +export const __wbindgen_start: () => void; diff --git a/crates/base/test_cases/wasm-module/index.ts b/crates/base/test_cases/wasm-module/index.ts new file mode 100644 index 00000000..d9b3601b --- /dev/null +++ b/crates/base/test_cases/wasm-module/index.ts @@ -0,0 +1,7 @@ +import { add } from "./add-wasm/pkg/add_wasm.js"; + +Deno.serve(async (req) => { + const result = add(1, 2); + + return new Response(`${result}`, { status: 200 }); // result: 3 +}); diff --git a/crates/base/tests/integration_tests.rs b/crates/base/tests/integration_tests.rs index c79af3c9..c6b6f575 100644 --- a/crates/base/tests/integration_tests.rs +++ b/crates/base/tests/integration_tests.rs @@ -2371,6 +2371,63 @@ async fn test_declarative_style_fetch_handler() { ); } +#[tokio::test] +#[serial] +async fn test_fetch_local_file_handler() { + let (tx, mut rx) = mpsc::unbounded_channel(); + let tb = TestBedBuilder::new("./test_cases/main") + .with_per_worker_policy(None) + .with_worker_event_sender(Some(tx)) + .build() + .await; + + let mut resp = tb + .request(|b| { + b.uri("/fetch-local-npm-file") + .body(Body::empty()) + .context("can't make request") + }) + .await + .unwrap(); + + let status = resp.status().as_u16(); + let body = to_bytes(resp.body_mut()).await.unwrap(); + let body = String::from_utf8_lossy(&body).to_string(); + + if status != 200 || body.is_empty() { + rx.close(); + tb.exit(Duration::from_secs(TESTBED_DEADLINE_SEC)).await; + + while let Some(ev) = rx.recv().await { + if let WorkerEvents::Log(ev) = ev.event { + eprintln!("[worker-log] {}", ev.msg); + } + } + } + + assert_eq!(status, 200); + assert!(!body.is_empty()); +} + +// https://github.com/supabase/edge-runtime/issues/640 +#[tokio::test] +#[serial] +async fn test_wasm_module() { + integration_test!( + "./test_cases/main", + NON_SECURE_PORT, + "wasm-module", + None, + None, + None, + (|resp| async { + // Testing mod add(1, 2) === 3; + assert_eq!(resp.unwrap().text().await.unwrap(), "3"); + }), + TerminationToken::new() + ); +} + #[tokio::test] #[serial] async fn test_issue_208() { diff --git a/examples/main/index.ts b/examples/main/index.ts index e2ea10f8..6c66125b 100644 --- a/examples/main/index.ts +++ b/examples/main/index.ts @@ -191,6 +191,7 @@ Deno.serve(async (req: Request) => { const cpuTimeHardLimitMs = 20000; const staticPatterns = [ "./examples/**/*.html", + "./examples/**/*.wasm", ]; return await EdgeRuntime.userWorkers.create({ diff --git a/examples/wasm-module/add-wasm/Cargo.lock b/examples/wasm-module/add-wasm/Cargo.lock new file mode 100644 index 00000000..d36b4261 --- /dev/null +++ b/examples/wasm-module/add-wasm/Cargo.lock @@ -0,0 +1,114 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "add-wasm" +version = "0.1.0" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] diff --git a/examples/wasm-module/add-wasm/Cargo.toml b/examples/wasm-module/add-wasm/Cargo.toml new file mode 100644 index 00000000..63ee0931 --- /dev/null +++ b/examples/wasm-module/add-wasm/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "add-wasm" +version = "0.1.0" +edition = "2021" +license = "MIT/Apache-2.0" +description = "A simple wasm module that adds two numbers" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-bindgen = "0.2" diff --git a/examples/wasm-module/add-wasm/pkg/add_wasm.d.ts b/examples/wasm-module/add-wasm/pkg/add_wasm.d.ts new file mode 100644 index 00000000..fbf99b5e --- /dev/null +++ b/examples/wasm-module/add-wasm/pkg/add_wasm.d.ts @@ -0,0 +1,4 @@ +/* tslint:disable */ +/* eslint-disable */ + +export function add(a: number, b: number): number; diff --git a/examples/wasm-module/add-wasm/pkg/add_wasm.js b/examples/wasm-module/add-wasm/pkg/add_wasm.js new file mode 100644 index 00000000..5c26f5a5 --- /dev/null +++ b/examples/wasm-module/add-wasm/pkg/add_wasm.js @@ -0,0 +1,38 @@ +/* @ts-self-types="./add_wasm.d.ts" */ + +/** + * @param {number} a + * @param {number} b + * @returns {number} + */ +export function add(a, b) { + const ret = wasm.add(a, b); + return ret >>> 0; +} + +function __wbg_get_imports() { + const import0 = { + __proto__: null, + __wbindgen_init_externref_table: function () { + const table = wasm.__wbindgen_externrefs; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); + }, + }; + return { + __proto__: null, + "./add_wasm_bg.js": import0, + }; +} + +const wasmUrl = new URL("add_wasm_bg.wasm", import.meta.url); +const wasmInstantiated = await WebAssembly.instantiateStreaming( + fetch(wasmUrl), + __wbg_get_imports(), +); +const wasm = wasmInstantiated.instance.exports; +wasm.__wbindgen_start(); diff --git a/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm b/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm new file mode 100644 index 00000000..58aed5a8 Binary files /dev/null and b/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm differ diff --git a/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts b/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts new file mode 100644 index 00000000..1a00d2d7 --- /dev/null +++ b/examples/wasm-module/add-wasm/pkg/add_wasm_bg.wasm.d.ts @@ -0,0 +1,6 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export const add: (a: number, b: number) => number; +export const __wbindgen_externrefs: WebAssembly.Table; +export const __wbindgen_start: () => void; diff --git a/examples/wasm-module/add-wasm/src/lib.rs b/examples/wasm-module/add-wasm/src/lib.rs new file mode 100644 index 00000000..bf829869 --- /dev/null +++ b/examples/wasm-module/add-wasm/src/lib.rs @@ -0,0 +1,5 @@ +use wasm_bindgen::prelude::*; +#[wasm_bindgen] +pub fn add(a: u32, b: u32) -> u32 { + a + b +} diff --git a/examples/wasm-module/add_wasm_bg.wasm b/examples/wasm-module/add_wasm_bg.wasm new file mode 100644 index 00000000..58aed5a8 Binary files /dev/null and b/examples/wasm-module/add_wasm_bg.wasm differ diff --git a/examples/wasm-module/index.ts b/examples/wasm-module/index.ts new file mode 100644 index 00000000..1bfa5e5e --- /dev/null +++ b/examples/wasm-module/index.ts @@ -0,0 +1,8 @@ +import { add } from "./add-wasm/pkg/add_wasm.js"; + +Deno.serve(async (req) => { + const { a, b } = await req.json(); + const result = add(a, b); + + return Response.json({ result }); +}); diff --git a/types/global.d.ts b/types/global.d.ts index e2693df4..dceade28 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -231,7 +231,7 @@ declare namespace Supabase { } export class Session { - init: Promise + init: Promise; /** * Create a new model session using given model */ diff --git a/vendor/deno_fetch/Cargo.toml b/vendor/deno_fetch/Cargo.toml index 716d268a..74e9e3e1 100644 --- a/vendor/deno_fetch/Cargo.toml +++ b/vendor/deno_fetch/Cargo.toml @@ -18,6 +18,8 @@ base64.workspace = true bytes.workspace = true data-url.workspace = true deno_core.workspace = true +deno_fs.workspace = true +deno_io.workspace = true deno_path_util.workspace = true deno_permissions.workspace = true deno_tls.workspace = true diff --git a/vendor/deno_fetch/fs_fetch_handler.rs b/vendor/deno_fetch/fs_fetch_handler.rs index c236dd9c..b5e3a399 100644 --- a/vendor/deno_fetch/fs_fetch_handler.rs +++ b/vendor/deno_fetch/fs_fetch_handler.rs @@ -6,35 +6,38 @@ use crate::FetchHandler; use deno_core::futures::FutureExt; use deno_core::futures::TryFutureExt; -use deno_core::futures::TryStreamExt; use deno_core::url::Url; use deno_core::CancelFuture; use deno_core::OpState; +use deno_fs::FileSystemRc; use http::StatusCode; use http_body_util::BodyExt; use std::rc::Rc; -use tokio_util::io::ReaderStream; /// An implementation which tries to read file URLs from the file system via -/// tokio::fs. +/// the runtime's configured file system. #[derive(Clone)] pub struct FsFetchHandler; impl FetchHandler for FsFetchHandler { fn fetch_file( &self, - _state: &mut OpState, + state: &mut OpState, url: &Url, ) -> (CancelableResponseFuture, Option>) { let cancel_handle = CancelHandle::new_rc(); let path_result = url.to_file_path(); + let fs = state.borrow::().clone(); let response_fut = async move { let path = path_result?; - let file = tokio::fs::File::open(path).map_err(|_| ()).await?; - let stream = ReaderStream::new(file) - .map_ok(hyper::body::Frame::data) - .map_err(Into::into); - let body = http_body_util::StreamBody::new(stream).boxed(); + let body = fs + .read_file_async(path, None) + .await + .map_err(|_| ())? + .into_owned(); + let body = http_body_util::Full::new(body.into()) + .map_err(|never| match never {}) + .boxed(); let response = http::Response::builder() .status(StatusCode::OK) .body(body)