From 0648aa0fd435b0ece74e0ed67652ce6939e32264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=83=A5=EB=83=90=EC=B1=A0?= Date: Mon, 6 May 2024 14:11:03 +0900 Subject: [PATCH] feat: correctly handle import statement with JSR specifier (#336) * fix: we should handle jsr specifier now since deno HQ seems to have decided to use it on prod * stamp: add an integration test for import statement with jsr specifier * stamp: add an example for import statement with jsr specifier * stamp(base): unpin oak version in `test_cases` * stamp: update oak related integration tests --- .../test_cases/oak-v12-file-upload/index.ts | 35 ++++++++++++++++++ crates/base/test_cases/oak-with-jsr/index.ts | 17 +++++++++ crates/base/test_cases/oak/index.ts | 37 ++----------------- crates/base/tests/integration_tests.rs | 20 +++++++++- .../standalone/standalone_module_loader.rs | 15 ++++++-- examples/oak-with-jsr/index.ts | 17 +++++++++ 6 files changed, 103 insertions(+), 38 deletions(-) create mode 100644 crates/base/test_cases/oak-v12-file-upload/index.ts create mode 100644 crates/base/test_cases/oak-with-jsr/index.ts create mode 100644 examples/oak-with-jsr/index.ts diff --git a/crates/base/test_cases/oak-v12-file-upload/index.ts b/crates/base/test_cases/oak-v12-file-upload/index.ts new file mode 100644 index 00000000..20bad3f1 --- /dev/null +++ b/crates/base/test_cases/oak-v12-file-upload/index.ts @@ -0,0 +1,35 @@ +import { Application, Router } from 'https://deno.land/x/oak@v12.3.0/mod.ts'; + +const MB = 1024 * 1024; + +const router = new Router(); + +router + .post('/file-upload', async (ctx) => { + try { + const body = ctx.request.body({ type: 'form-data' }); + const formData = await body.value.read({ + // Need to set the maxSize so files will be stored in memory. + // This is necessary as Edge Functions don't have disk write access. + // We are setting the max size as 10MB (an Edge Function has a max memory limit of 150MB) + // For more config options, check: https://deno.land/x/oak@v11.1.0/mod.ts?s=FormDataReadOptions + maxSize: 1 * MB, + }); + const file = formData.files[0]; + + ctx.response.status = 201; + ctx.response.body = `file-type: ${file.contentType}`; + } catch (e) { + console.log('error occurred'); + console.log(e); + ctx.response.status = 500; + ctx.response.body = 'Error!'; + } + }); + +const app = new Application(); + +app.use(router.routes()); +app.use(router.allowedMethods()); + +await app.listen(); diff --git a/crates/base/test_cases/oak-with-jsr/index.ts b/crates/base/test_cases/oak-with-jsr/index.ts new file mode 100644 index 00000000..86c45f04 --- /dev/null +++ b/crates/base/test_cases/oak-with-jsr/index.ts @@ -0,0 +1,17 @@ +import { Application } from "jsr:@oak/oak/application"; +import { Router } from "jsr:@oak/oak/router"; + +const router = new Router(); + +router + // Note: path will be prefixed with function name + .get("/oak-with-jsr", (context) => { + context.response.body = "meow"; + }); + +const app = new Application(); + +app.use(router.routes()); +app.use(router.allowedMethods()); + +await app.listen(); diff --git a/crates/base/test_cases/oak/index.ts b/crates/base/test_cases/oak/index.ts index f8b39c50..e98f8091 100644 --- a/crates/base/test_cases/oak/index.ts +++ b/crates/base/test_cases/oak/index.ts @@ -1,48 +1,19 @@ -import { Application, Router } from 'https://deno.land/x/oak@v12.3.0/mod.ts'; - -const MB = 1024 * 1024; +import { Application, Router } from 'https://deno.land/x/oak/mod.ts'; const router = new Router(); + router // Note: path will be prefixed with function name .get('/oak', (context) => { context.response.body = 'This is an example Oak server running on Edge Functions!'; }) - .post('/oak/greet', async (context) => { - // Note: request body will be streamed to the function as chunks, set limit to 0 to fully read it. - const result = context.request.body({ type: 'json', limit: 0 }); - const body = await result.value; - const name = body.name || 'you'; - - context.response.body = { msg: `Hey ${name}!` }; - }) .get('/oak/redirect', (context) => { context.response.redirect('https://www.example.com'); - }) - .post('/file-upload', async (ctx) => { - try { - const body = ctx.request.body({ type: 'form-data' }); - const formData = await body.value.read({ - // Need to set the maxSize so files will be stored in memory. - // This is necessary as Edge Functions don't have disk write access. - // We are setting the max size as 10MB (an Edge Function has a max memory limit of 150MB) - // For more config options, check: https://deno.land/x/oak@v11.1.0/mod.ts?s=FormDataReadOptions - maxSize: 1 * MB, - }); - const file = formData.files[0]; - - ctx.response.status = 201; - ctx.response.body = `file-type: ${file.contentType}`; - } catch (e) { - console.log('error occurred'); - console.log(e); - ctx.response.status = 500; - ctx.response.body = 'Error!'; - } }); const app = new Application(); + app.use(router.routes()); app.use(router.allowedMethods()); -await app.listen({ port: 8000 }); +await app.listen(); diff --git a/crates/base/tests/integration_tests.rs b/crates/base/tests/integration_tests.rs index 45ba3118..b9ec6f53 100644 --- a/crates/base/tests/integration_tests.rs +++ b/crates/base/tests/integration_tests.rs @@ -608,7 +608,7 @@ async fn test_file_upload() { let request_builder = Some(original); integration_test!( - "./test_cases/oak", + "./test_cases/oak-v12-file-upload", NON_SECURE_PORT, "", None, @@ -1279,6 +1279,24 @@ async fn send_partial_payload_into_closed_pipe_should_not_be_affected_worker_sta tb.exit(Duration::from_secs(TESTBED_DEADLINE_SEC)).await; } +#[tokio::test] +#[serial] +async fn oak_with_jsr_specifier() { + integration_test!( + "./test_cases/main", + NON_SECURE_PORT, + "oak-with-jsr", + None, + None, + None, + None, + (|resp| async { + assert_eq!(resp.unwrap().text().await.unwrap(), "meow"); + }), + TerminationToken::new() + ); +} + trait TlsExt { fn client(&self) -> reqwest::Client; fn schema(&self) -> &'static str; diff --git a/crates/sb_module_loader/standalone/standalone_module_loader.rs b/crates/sb_module_loader/standalone/standalone_module_loader.rs index 27cef866..9082116d 100644 --- a/crates/sb_module_loader/standalone/standalone_module_loader.rs +++ b/crates/sb_module_loader/standalone/standalone_module_loader.rs @@ -71,6 +71,7 @@ impl ModuleLoader for EmbeddedModuleLoader { .as_ref() .map(|r| r.as_str()) .unwrap_or(specifier); + if let Ok(reference) = NpmPackageReqReference::from_str(specifier_text) { return self.shared.node_resolver.resolve_req_reference( &reference, @@ -79,12 +80,18 @@ impl ModuleLoader for EmbeddedModuleLoader { ); } - match maybe_mapped { - Some(resolved) => Ok(resolved), - None => { - deno_core::resolve_import(specifier, referrer.as_str()).map_err(|err| err.into()) + let specifier = match maybe_mapped { + Some(resolved) => resolved, + None => deno_core::resolve_import(specifier, referrer.as_str())?, + }; + + if specifier.scheme() == "jsr" { + if let Some(module) = self.shared.eszip.get_module(specifier.as_str()) { + return Ok(ModuleSpecifier::parse(&module.specifier).unwrap()); } } + + Ok(specifier) } fn load( diff --git a/examples/oak-with-jsr/index.ts b/examples/oak-with-jsr/index.ts new file mode 100644 index 00000000..36f33e7a --- /dev/null +++ b/examples/oak-with-jsr/index.ts @@ -0,0 +1,17 @@ +import { Application } from "jsr:@oak/oak/application"; +import { Router } from "jsr:@oak/oak/router"; + +const router = new Router(); + +router + // Note: path will be prefixed with function name + .get("/oak-with-jsr", (context) => { + context.response.body = "This is an example Oak server running on Edge Functions!"; + }); + +const app = new Application(); + +app.use(router.routes()); +app.use(router.allowedMethods()); + +await app.listen();