From 55c2a88099760be6c00838b3c3202f732f84e651 Mon Sep 17 00:00:00 2001 From: denobot <33910674+denobot@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:27:34 -0400 Subject: [PATCH 01/39] chore: release deno_* crates (#25987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing once again if the crates are being properly released. --------- Co-authored-by: bartlomieju Co-authored-by: Bartek Iwańczuk --- .github/workflows/ci.generate.ts | 2 +- .github/workflows/ci.yml | 8 ++--- Cargo.lock | 56 ++++++++++++++++---------------- Cargo.toml | 56 ++++++++++++++++---------------- bench_util/Cargo.toml | 2 +- cli/napi/sym/Cargo.toml | 2 +- ext/broadcast_channel/Cargo.toml | 2 +- ext/cache/Cargo.toml | 2 +- ext/canvas/Cargo.toml | 2 +- ext/console/Cargo.toml | 2 +- ext/cron/Cargo.toml | 2 +- ext/crypto/Cargo.toml | 2 +- ext/fetch/Cargo.toml | 2 +- ext/ffi/Cargo.toml | 2 +- ext/fs/Cargo.toml | 2 +- ext/http/Cargo.toml | 2 +- ext/io/Cargo.toml | 2 +- ext/kv/Cargo.toml | 2 +- ext/napi/Cargo.toml | 2 +- ext/net/Cargo.toml | 2 +- ext/node/Cargo.toml | 2 +- ext/tls/Cargo.toml | 2 +- ext/url/Cargo.toml | 2 +- ext/web/Cargo.toml | 2 +- ext/webgpu/Cargo.toml | 2 +- ext/webidl/Cargo.toml | 2 +- ext/websocket/Cargo.toml | 2 +- ext/webstorage/Cargo.toml | 2 +- resolvers/deno/Cargo.toml | 2 +- resolvers/node/Cargo.toml | 2 +- runtime/Cargo.toml | 2 +- runtime/permissions/Cargo.toml | 2 +- 32 files changed, 89 insertions(+), 89 deletions(-) diff --git a/.github/workflows/ci.generate.ts b/.github/workflows/ci.generate.ts index f1fa7edf65..95404d245e 100755 --- a/.github/workflows/ci.generate.ts +++ b/.github/workflows/ci.generate.ts @@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify"; // Bump this number when you want to purge the cache. // Note: the tools/release/01_bump_crate_versions.ts script will update this version // automatically via regex, so ensure that this line maintains this format. -const cacheVersion = 16; +const cacheVersion = 17; const ubuntuX86Runner = "ubuntu-22.04"; const ubuntuX86XlRunner = "ubuntu-22.04-xl"; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 728d1deb21..c114286a2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -367,8 +367,8 @@ jobs: path: |- ~/.cargo/registry/index ~/.cargo/registry/cache - key: '16-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' - restore-keys: '16-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' + key: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' + restore-keys: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' if: '!(matrix.skip)' - name: Restore cache build output (PR) uses: actions/cache/restore@v4 @@ -381,7 +381,7 @@ jobs: !./target/*/*.zip !./target/*/*.tar.gz key: never_saved - restore-keys: '16-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' + restore-keys: '17-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' - name: Apply and update mtime cache if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' uses: ./.github/mtime_cache @@ -691,7 +691,7 @@ jobs: !./target/*/*.zip !./target/*/*.sha256sum !./target/*/*.tar.gz - key: '16-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' + key: '17-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' publish-canary: name: publish canary runs-on: ubuntu-22.04 diff --git a/Cargo.lock b/Cargo.lock index 0ab2d96eaa..3638e2cbe7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1317,7 +1317,7 @@ dependencies = [ [[package]] name = "deno_bench_util" -version = "0.163.0" +version = "0.164.0" dependencies = [ "bencher", "deno_core", @@ -1326,7 +1326,7 @@ dependencies = [ [[package]] name = "deno_broadcast_channel" -version = "0.163.0" +version = "0.164.0" dependencies = [ "async-trait", "deno_core", @@ -1336,7 +1336,7 @@ dependencies = [ [[package]] name = "deno_cache" -version = "0.101.0" +version = "0.102.0" dependencies = [ "async-trait", "deno_core", @@ -1368,7 +1368,7 @@ dependencies = [ [[package]] name = "deno_canvas" -version = "0.38.0" +version = "0.39.0" dependencies = [ "deno_core", "deno_webgpu", @@ -1401,7 +1401,7 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.169.0" +version = "0.170.0" dependencies = [ "deno_core", ] @@ -1446,7 +1446,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" [[package]] name = "deno_cron" -version = "0.49.0" +version = "0.50.0" dependencies = [ "anyhow", "async-trait", @@ -1458,7 +1458,7 @@ dependencies = [ [[package]] name = "deno_crypto" -version = "0.183.0" +version = "0.184.0" dependencies = [ "aes", "aes-gcm", @@ -1518,7 +1518,7 @@ dependencies = [ [[package]] name = "deno_fetch" -version = "0.193.0" +version = "0.194.0" dependencies = [ "base64 0.21.7", "bytes", @@ -1550,7 +1550,7 @@ dependencies = [ [[package]] name = "deno_ffi" -version = "0.156.0" +version = "0.157.0" dependencies = [ "deno_core", "deno_permissions", @@ -1567,7 +1567,7 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.79.0" +version = "0.80.0" dependencies = [ "async-trait", "base32", @@ -1617,7 +1617,7 @@ dependencies = [ [[package]] name = "deno_http" -version = "0.167.0" +version = "0.168.0" dependencies = [ "async-compression", "async-trait", @@ -1656,7 +1656,7 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.79.0" +version = "0.80.0" dependencies = [ "async-trait", "deno_core", @@ -1677,7 +1677,7 @@ dependencies = [ [[package]] name = "deno_kv" -version = "0.77.0" +version = "0.78.0" dependencies = [ "anyhow", "async-trait", @@ -1748,7 +1748,7 @@ dependencies = [ [[package]] name = "deno_napi" -version = "0.100.0" +version = "0.101.0" dependencies = [ "deno_core", "deno_permissions", @@ -1770,7 +1770,7 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.161.0" +version = "0.162.0" dependencies = [ "deno_core", "deno_permissions", @@ -1786,7 +1786,7 @@ dependencies = [ [[package]] name = "deno_node" -version = "0.106.0" +version = "0.107.0" dependencies = [ "aead-gcm-stream", "aes", @@ -1935,7 +1935,7 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.29.0" +version = "0.30.0" dependencies = [ "deno_core", "deno_path_util", @@ -1952,7 +1952,7 @@ dependencies = [ [[package]] name = "deno_resolver" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "base32", @@ -1967,7 +1967,7 @@ dependencies = [ [[package]] name = "deno_runtime" -version = "0.178.0" +version = "0.179.0" dependencies = [ "deno_ast", "deno_broadcast_channel", @@ -2082,7 +2082,7 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.156.0" +version = "0.157.0" dependencies = [ "deno_core", "deno_native_certs", @@ -2130,7 +2130,7 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.169.0" +version = "0.170.0" dependencies = [ "deno_bench_util", "deno_console", @@ -2141,7 +2141,7 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.200.0" +version = "0.201.0" dependencies = [ "async-trait", "base64-simd 0.8.0", @@ -2162,7 +2162,7 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.136.0" +version = "0.137.0" dependencies = [ "deno_core", "raw-window-handle", @@ -2174,7 +2174,7 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.169.0" +version = "0.170.0" dependencies = [ "deno_bench_util", "deno_core", @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "deno_websocket" -version = "0.174.0" +version = "0.175.0" dependencies = [ "bytes", "deno_core", @@ -2203,7 +2203,7 @@ dependencies = [ [[package]] name = "deno_webstorage" -version = "0.164.0" +version = "0.165.0" dependencies = [ "deno_core", "deno_web", @@ -4488,7 +4488,7 @@ dependencies = [ [[package]] name = "napi_sym" -version = "0.99.0" +version = "0.100.0" dependencies = [ "quote", "serde", @@ -4557,7 +4557,7 @@ dependencies = [ [[package]] name = "node_resolver" -version = "0.8.0" +version = "0.9.0" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 26ef3be19b..e5c4f59e1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,16 +48,16 @@ repository = "https://github.com/denoland/deno" deno_ast = { version = "=0.42.1", features = ["transpiling"] } deno_core = { version = "0.311.0" } -deno_bench_util = { version = "0.163.0", path = "./bench_util" } +deno_bench_util = { version = "0.164.0", path = "./bench_util" } deno_lockfile = "=0.23.1" deno_media_type = { version = "0.1.4", features = ["module_specifier"] } deno_npm = "=0.25.2" deno_path_util = "=0.2.0" -deno_permissions = { version = "0.29.0", path = "./runtime/permissions" } -deno_runtime = { version = "0.178.0", path = "./runtime" } +deno_permissions = { version = "0.30.0", path = "./runtime/permissions" } +deno_runtime = { version = "0.179.0", path = "./runtime" } deno_semver = "=0.5.14" deno_terminal = "0.2.0" -napi_sym = { version = "0.99.0", path = "./cli/napi/sym" } +napi_sym = { version = "0.100.0", path = "./cli/napi/sym" } test_util = { package = "test_server", path = "./tests/util/server" } denokv_proto = "0.8.1" @@ -66,32 +66,32 @@ denokv_remote = "0.8.1" denokv_sqlite = { default-features = false, version = "0.8.2" } # exts -deno_broadcast_channel = { version = "0.163.0", path = "./ext/broadcast_channel" } -deno_cache = { version = "0.101.0", path = "./ext/cache" } -deno_canvas = { version = "0.38.0", path = "./ext/canvas" } -deno_console = { version = "0.169.0", path = "./ext/console" } -deno_cron = { version = "0.49.0", path = "./ext/cron" } -deno_crypto = { version = "0.183.0", path = "./ext/crypto" } -deno_fetch = { version = "0.193.0", path = "./ext/fetch" } -deno_ffi = { version = "0.156.0", path = "./ext/ffi" } -deno_fs = { version = "0.79.0", path = "./ext/fs" } -deno_http = { version = "0.167.0", path = "./ext/http" } -deno_io = { version = "0.79.0", path = "./ext/io" } -deno_kv = { version = "0.77.0", path = "./ext/kv" } -deno_napi = { version = "0.100.0", path = "./ext/napi" } -deno_net = { version = "0.161.0", path = "./ext/net" } -deno_node = { version = "0.106.0", path = "./ext/node" } -deno_tls = { version = "0.156.0", path = "./ext/tls" } -deno_url = { version = "0.169.0", path = "./ext/url" } -deno_web = { version = "0.200.0", path = "./ext/web" } -deno_webgpu = { version = "0.136.0", path = "./ext/webgpu" } -deno_webidl = { version = "0.169.0", path = "./ext/webidl" } -deno_websocket = { version = "0.174.0", path = "./ext/websocket" } -deno_webstorage = { version = "0.164.0", path = "./ext/webstorage" } +deno_broadcast_channel = { version = "0.164.0", path = "./ext/broadcast_channel" } +deno_cache = { version = "0.102.0", path = "./ext/cache" } +deno_canvas = { version = "0.39.0", path = "./ext/canvas" } +deno_console = { version = "0.170.0", path = "./ext/console" } +deno_cron = { version = "0.50.0", path = "./ext/cron" } +deno_crypto = { version = "0.184.0", path = "./ext/crypto" } +deno_fetch = { version = "0.194.0", path = "./ext/fetch" } +deno_ffi = { version = "0.157.0", path = "./ext/ffi" } +deno_fs = { version = "0.80.0", path = "./ext/fs" } +deno_http = { version = "0.168.0", path = "./ext/http" } +deno_io = { version = "0.80.0", path = "./ext/io" } +deno_kv = { version = "0.78.0", path = "./ext/kv" } +deno_napi = { version = "0.101.0", path = "./ext/napi" } +deno_net = { version = "0.162.0", path = "./ext/net" } +deno_node = { version = "0.107.0", path = "./ext/node" } +deno_tls = { version = "0.157.0", path = "./ext/tls" } +deno_url = { version = "0.170.0", path = "./ext/url" } +deno_web = { version = "0.201.0", path = "./ext/web" } +deno_webgpu = { version = "0.137.0", path = "./ext/webgpu" } +deno_webidl = { version = "0.170.0", path = "./ext/webidl" } +deno_websocket = { version = "0.175.0", path = "./ext/websocket" } +deno_webstorage = { version = "0.165.0", path = "./ext/webstorage" } # resolvers -deno_resolver = { version = "0.1.0", path = "./resolvers/deno" } -node_resolver = { version = "0.8.0", path = "./resolvers/node" } +deno_resolver = { version = "0.2.0", path = "./resolvers/deno" } +node_resolver = { version = "0.9.0", path = "./resolvers/node" } aes = "=0.8.3" anyhow = "1.0.57" diff --git a/bench_util/Cargo.toml b/bench_util/Cargo.toml index d668d3a944..1eab1685e2 100644 --- a/bench_util/Cargo.toml +++ b/bench_util/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_bench_util" -version = "0.163.0" +version = "0.164.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/cli/napi/sym/Cargo.toml b/cli/napi/sym/Cargo.toml index 849d3cc87f..baabf0b7a6 100644 --- a/cli/napi/sym/Cargo.toml +++ b/cli/napi/sym/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "napi_sym" -version = "0.99.0" +version = "0.100.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/broadcast_channel/Cargo.toml b/ext/broadcast_channel/Cargo.toml index da8cef30bd..24e09543ce 100644 --- a/ext/broadcast_channel/Cargo.toml +++ b/ext/broadcast_channel/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_broadcast_channel" -version = "0.163.0" +version = "0.164.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cache/Cargo.toml b/ext/cache/Cargo.toml index 225870944a..aae0eaf91f 100644 --- a/ext/cache/Cargo.toml +++ b/ext/cache/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cache" -version = "0.101.0" +version = "0.102.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/canvas/Cargo.toml b/ext/canvas/Cargo.toml index db59822049..3cfc180ecd 100644 --- a/ext/canvas/Cargo.toml +++ b/ext/canvas/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_canvas" -version = "0.38.0" +version = "0.39.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/console/Cargo.toml b/ext/console/Cargo.toml index d2125bbcc1..a61d821d6b 100644 --- a/ext/console/Cargo.toml +++ b/ext/console/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_console" -version = "0.169.0" +version = "0.170.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cron/Cargo.toml b/ext/cron/Cargo.toml index 9d3fa20092..c0f5f097ea 100644 --- a/ext/cron/Cargo.toml +++ b/ext/cron/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cron" -version = "0.49.0" +version = "0.50.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 5c0865e20a..667867efa7 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_crypto" -version = "0.183.0" +version = "0.184.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index 732bf47c27..5196abd92d 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fetch" -version = "0.193.0" +version = "0.194.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/ffi/Cargo.toml b/ext/ffi/Cargo.toml index 158ab1b489..0839fec241 100644 --- a/ext/ffi/Cargo.toml +++ b/ext/ffi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_ffi" -version = "0.156.0" +version = "0.157.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml index fc223e1dc8..b3eb85bfcc 100644 --- a/ext/fs/Cargo.toml +++ b/ext/fs/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fs" -version = "0.79.0" +version = "0.80.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/http/Cargo.toml b/ext/http/Cargo.toml index 2c47903f01..ba07636aa5 100644 --- a/ext/http/Cargo.toml +++ b/ext/http/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_http" -version = "0.167.0" +version = "0.168.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/io/Cargo.toml b/ext/io/Cargo.toml index 72cdfcc7e3..9dd2dbb878 100644 --- a/ext/io/Cargo.toml +++ b/ext/io/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_io" -version = "0.79.0" +version = "0.80.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/kv/Cargo.toml b/ext/kv/Cargo.toml index 7d002aa122..a948ca422d 100644 --- a/ext/kv/Cargo.toml +++ b/ext/kv/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_kv" -version = "0.77.0" +version = "0.78.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/napi/Cargo.toml b/ext/napi/Cargo.toml index 9f3a2951b2..c259dc46cb 100644 --- a/ext/napi/Cargo.toml +++ b/ext/napi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_napi" -version = "0.100.0" +version = "0.101.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index c75367a4b1..36857a16c0 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_net" -version = "0.161.0" +version = "0.162.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 29f7722999..459908f59e 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_node" -version = "0.106.0" +version = "0.107.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml index fac2f691ee..fff9662b2e 100644 --- a/ext/tls/Cargo.toml +++ b/ext/tls/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_tls" -version = "0.156.0" +version = "0.157.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/url/Cargo.toml b/ext/url/Cargo.toml index cced5cae59..063b44ce1b 100644 --- a/ext/url/Cargo.toml +++ b/ext/url/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_url" -version = "0.169.0" +version = "0.170.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml index b2b7e7084a..cf5aede920 100644 --- a/ext/web/Cargo.toml +++ b/ext/web/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_web" -version = "0.200.0" +version = "0.201.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 17d8cbe580..786beee459 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webgpu" -version = "0.136.0" +version = "0.137.0" authors = ["the Deno authors"] edition.workspace = true license = "MIT" diff --git a/ext/webidl/Cargo.toml b/ext/webidl/Cargo.toml index 5ff37d2be4..734fc75c2b 100644 --- a/ext/webidl/Cargo.toml +++ b/ext/webidl/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webidl" -version = "0.169.0" +version = "0.170.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 49d059771f..4758c9d04f 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_websocket" -version = "0.174.0" +version = "0.175.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webstorage/Cargo.toml b/ext/webstorage/Cargo.toml index 3c78fb49ac..7b86f4e8b7 100644 --- a/ext/webstorage/Cargo.toml +++ b/ext/webstorage/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webstorage" -version = "0.164.0" +version = "0.165.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/resolvers/deno/Cargo.toml b/resolvers/deno/Cargo.toml index 70f95c43c8..1b9aab1e6e 100644 --- a/resolvers/deno/Cargo.toml +++ b/resolvers/deno/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_resolver" -version = "0.1.0" +version = "0.2.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/resolvers/node/Cargo.toml b/resolvers/node/Cargo.toml index 153b4a38d4..d4e9b041ca 100644 --- a/resolvers/node/Cargo.toml +++ b/resolvers/node/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "node_resolver" -version = "0.8.0" +version = "0.9.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5bffd7980e..6d84d0466c 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_runtime" -version = "0.178.0" +version = "0.179.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/permissions/Cargo.toml b/runtime/permissions/Cargo.toml index 29ef9db134..bb8ebb97c4 100644 --- a/runtime/permissions/Cargo.toml +++ b/runtime/permissions/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_permissions" -version = "0.29.0" +version = "0.30.0" authors.workspace = true edition.workspace = true license.workspace = true From ebc8a6169e95e37d68c2996de50100d19698427a Mon Sep 17 00:00:00 2001 From: David Sherret Date: Wed, 2 Oct 2024 16:10:49 +0100 Subject: [PATCH 02/39] fix(no-slow-types): better `override` handling (#25989) * https://github.com/denoland/deno_graph/pull/534 Closes https://github.com/denoland/deno/issues/25322 --- Cargo.lock | 4 ++-- cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3638e2cbe7..eac520d092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1588,9 +1588,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.83.0" +version = "0.83.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20088a4497b1a212482883dc7b0365e99f703d575fb512d4a793531cdc92ea76" +checksum = "8c62ce152f24a4c0580e7a91431f75de48281157cf645459de8e9d7268dd95b2" dependencies = [ "anyhow", "async-trait", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2cc32c880b..2bde2df032 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -68,7 +68,7 @@ deno_cache_dir = { workspace = true } deno_config = { version = "=0.35.0", features = ["workspace", "sync"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "0.150.1", features = ["html", "syntect"] } -deno_graph = { version = "=0.83.0" } +deno_graph = { version = "=0.83.1" } deno_lint = { version = "=0.67.0", features = ["docs"] } deno_lockfile.workspace = true deno_npm.workspace = true From 18beb13f0ea750ba36b7f062f3cfdcc08c610431 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Wed, 2 Oct 2024 16:20:51 +0100 Subject: [PATCH 03/39] fix(workspace): handle when config has members when specified via --config (#25988) Closes #25847 --- Cargo.lock | 9 +++++---- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eac520d092..9bb75aac86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1378,12 +1378,13 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.35.0" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105864a9e0a7fbc22f1106784b2d263f402f157be1c3e1a9905f53d182700c9f" +checksum = "3cb7a1723676fba5964f8d7441d8b53748f9e74d6d4241be7de9730da021859a" dependencies = [ "anyhow", "deno_package_json", + "deno_path_util", "deno_semver", "glob", "ignore", @@ -1910,9 +1911,9 @@ dependencies = [ [[package]] name = "deno_package_json" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf6ea5cc98ea7ad58b0e84593773bea03fc0431071a296017bed4151e3dc1d" +checksum = "6cbc4c4d3eb0960b58e8f43f9fc2d3f620fcac9a03cd85203e08db5b04e83c1f" dependencies = [ "deno_semver", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index e5c4f59e1e..f605229077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,7 +111,7 @@ dashmap = "5.5.3" data-encoding = "2.3.3" data-url = "=0.3.0" deno_cache_dir = "=0.13.0" -deno_package_json = { version = "0.1.1", default-features = false } +deno_package_json = { version = "0.1.2", default-features = false } dlopen2 = "0.6.1" ecb = "=0.1.2" elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 2bde2df032..41636c961e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -65,7 +65,7 @@ winres.workspace = true [dependencies] deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] } deno_cache_dir = { workspace = true } -deno_config = { version = "=0.35.0", features = ["workspace", "sync"] } +deno_config = { version = "=0.37.1", features = ["workspace", "sync"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "0.150.1", features = ["html", "syntect"] } deno_graph = { version = "=0.83.1" } From 1837aed79b77b3137563d4730d02e466c85b2b87 Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Wed, 2 Oct 2024 09:02:46 -0700 Subject: [PATCH 04/39] Revert "fix(urlpattern): fallback to empty string for undefined group values" (#25961) --- ext/url/01_urlpattern.js | 9 +++++-- tests/unit/urlpattern_test.ts | 6 ----- tests/wpt/runner/expectation.json | 40 ------------------------------- 3 files changed, 7 insertions(+), 48 deletions(-) diff --git a/ext/url/01_urlpattern.js b/ext/url/01_urlpattern.js index 58a6d6bce0..6e27563089 100644 --- a/ext/url/01_urlpattern.js +++ b/ext/url/01_urlpattern.js @@ -31,6 +31,7 @@ import * as webidl from "ext:deno_webidl/00_webidl.js"; import { createFilteredInspectProxy } from "ext:deno_console/01_console.js"; const _components = Symbol("components"); +const urlPatternSettings = { groupStringFallback: false }; /** * @typedef Components @@ -349,7 +350,11 @@ class URLPattern { const groups = res.groups; for (let i = 0; i < groupList.length; ++i) { // TODO(lucacasonato): this is vulnerable to override mistake - groups[groupList[i]] = match[i + 1] ?? ""; // TODO(@crowlKats): remove fallback for 2.0 + if (urlPatternSettings.groupStringFallback) { + groups[groupList[i]] = match[i + 1] ?? ""; + } else { + groups[groupList[i]] = match[i + 1]; + } } break; } @@ -422,4 +427,4 @@ webidl.converters.URLPatternOptions = webidl }, ]); -export { URLPattern }; +export { URLPattern, urlPatternSettings }; diff --git a/tests/unit/urlpattern_test.ts b/tests/unit/urlpattern_test.ts index 65c2241737..3c1fb0cf19 100644 --- a/tests/unit/urlpattern_test.ts +++ b/tests/unit/urlpattern_test.ts @@ -63,9 +63,3 @@ Deno.test(function urlPatternWithPrototypePollution() { RegExp.prototype.exec = originalExec; } }); - -Deno.test(function urlPatternEmptyFallback() { - const p = new URLPattern({ pathname: "/foo/bar{/:qaz}?" }); - const match = p.exec("https://example.com/foo/bar"); - assertEquals(match!.pathname.groups.qaz, ""); -}); diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 1b31f26e5a..4449c5d15e 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -12297,18 +12297,8 @@ "Component: hash Left: {\"hash\":\"a\"} Right: {\"hash\":\"b\"}" ], "urlpattern.any.html": [ - "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", "Pattern: [{\"hostname\":\"bad\\\\:hostname\"}] Inputs: undefined", "Pattern: [] Inputs: []", - "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/a\"}]", @@ -12317,18 +12307,8 @@ "Pattern: [{\"pathname\":\"/([\\\\d&&[0-1]])\"}] Inputs: [{\"pathname\":\"/3\"}]" ], "urlpattern.any.worker.html": [ - "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", "Pattern: [{\"hostname\":\"bad\\\\:hostname\"}] Inputs: undefined", "Pattern: [] Inputs: []", - "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/a\"}]", @@ -12337,18 +12317,8 @@ "Pattern: [{\"pathname\":\"/([\\\\d&&[0-1]])\"}] Inputs: [{\"pathname\":\"/3\"}]" ], "urlpattern.https.any.html": [ - "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", "Pattern: [{\"hostname\":\"bad\\\\:hostname\"}] Inputs: undefined", "Pattern: [] Inputs: []", - "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/a\"}]", @@ -12357,18 +12327,8 @@ "Pattern: [{\"pathname\":\"/([\\\\d&&[0-1]])\"}] Inputs: [{\"pathname\":\"/3\"}]" ], "urlpattern.https.any.worker.html": [ - "Pattern: [{\"pathname\":\"/foo/:bar?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/:bar*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/*?\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/(.*)*\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [{\"pathname\":\"/foo/**\"}] Inputs: [{\"pathname\":\"/foo\"}]", - "Pattern: [\"https://(sub.)?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"https://(sub(?:.))?example.com/foo\"] Inputs: [\"https://example.com/foo\"]", - "Pattern: [\"data\\\\:text/javascript,let x = 100/:tens?5;\"] Inputs: [\"data:text/javascript,let x = 100/5;\"]", "Pattern: [{\"hostname\":\"bad\\\\:hostname\"}] Inputs: undefined", "Pattern: [] Inputs: []", - "Pattern: [{\"pathname\":\"*{}**?\"}] Inputs: [{\"pathname\":\"foobar\"}]", "Pattern: [{\"pathname\":\"/foo/bar\"},{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO/BAR\"}]", "Pattern: [\"https://example.com:8080/foo?bar#baz\",{\"ignoreCase\":true}] Inputs: [{\"pathname\":\"/FOO\",\"search\":\"BAR\",\"hash\":\"BAZ\",\"baseURL\":\"https://example.com:8080\"}]", "Pattern: [{\"pathname\":\"/([[a-z]--a])\"}] Inputs: [{\"pathname\":\"/a\"}]", From bbd4ae1bc12dc6b34d4a455015096b7113a5cec5 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 2 Oct 2024 10:43:42 -0700 Subject: [PATCH 05/39] fix(node): implement libuv APIs needed to support `npm:sqlite3` (#25893) Fixes #24740. Implements the `uv_mutex_*` and `uv_async_*` APIs. The mutex API is implemented exactly as libuv, a thin wrapper over the OS's native mutex. The async API is implemented in terms of napi_async_work. As documented in the napi docs, you really shouldn't call `napi_queue_async_work` multiple times (it is documented as undefined behavior). However, our implementation doesn't have any issue with this, so I believe it suits our purpose here. --- Cargo.lock | 47 +++- Cargo.toml | 2 +- cli/Cargo.toml | 2 + cli/build.rs | 2 + .../generated_symbol_exports_list_linux.def | 2 +- .../generated_symbol_exports_list_macos.def | 9 +- .../generated_symbol_exports_list_windows.def | 9 +- cli/napi/mod.rs | 1 + cli/napi/node_api.rs | 13 +- cli/napi/sym/symbol_exports.json | 9 +- cli/napi/uv.rs | 231 ++++++++++++++++++ tests/napi/Cargo.toml | 1 + tests/napi/src/lib.rs | 3 + tests/napi/src/uv.rs | 206 ++++++++++++++++ tests/napi/uv_test.js | 18 ++ 15 files changed, 539 insertions(+), 16 deletions(-) create mode 100644 cli/napi/uv.rs create mode 100644 tests/napi/src/uv.rs create mode 100644 tests/napi/uv_test.js diff --git a/Cargo.lock b/Cargo.lock index 9bb75aac86..f264f41e38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -471,6 +471,26 @@ dependencies = [ "which 4.4.2", ] +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease 0.2.17", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.72", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -688,7 +708,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.3", + "libloading 0.8.5", ] [[package]] @@ -1064,7 +1084,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" dependencies = [ "bitflags 2.6.0", - "libloading 0.8.3", + "libloading 0.8.5", "winapi", ] @@ -1205,6 +1225,7 @@ dependencies = [ "lazy-regex", "libc", "libsui", + "libuv-sys-lite", "libz-sys", "log", "lsp-types", @@ -1253,6 +1274,7 @@ dependencies = [ "walkdir", "which 4.4.2", "winapi", + "windows-sys 0.52.0", "winres", "yoke", "zeromq", @@ -4039,7 +4061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.3", + "libloading 0.8.5", "pkg-config", ] @@ -4144,9 +4166,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.4", @@ -4192,6 +4214,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "libuv-sys-lite" +version = "1.48.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8dfd1a173826d193e3b955e07c22765829890f62c677a59c4a410cb4f47c01" +dependencies = [ + "bindgen 0.70.1", + "libloading 0.8.5", +] + [[package]] name = "libz-sys" version = "1.1.16" @@ -7205,6 +7237,7 @@ dependencies = [ name = "test_napi" version = "0.1.0" dependencies = [ + "libuv-sys-lite", "napi-build", "napi-sys", "test_server", @@ -7891,7 +7924,7 @@ version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5" dependencies = [ - "bindgen", + "bindgen 0.69.4", "bitflags 2.6.0", "fslock", "gzip-header", @@ -8158,7 +8191,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.3", + "libloading 0.8.5", "log", "metal", "naga", diff --git a/Cargo.toml b/Cargo.toml index f605229077..22f3575b98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -225,7 +225,7 @@ nix = "=0.26.2" # windows deps junction = "=0.2.0" winapi = "=0.3.9" -windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry"] } +windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry", "Win32_System_Kernel"] } winres = "=0.1.12" # NB: the `bench` and `release` profiles must remain EXACTLY the same. diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 41636c961e..6167baa0b2 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -170,12 +170,14 @@ zstd.workspace = true [target.'cfg(windows)'.dependencies] junction.workspace = true winapi = { workspace = true, features = ["knownfolders", "mswsock", "objbase", "shlobj", "tlhelp32", "winbase", "winerror", "winsock2"] } +windows-sys.workspace = true [target.'cfg(unix)'.dependencies] nix.workspace = true [dev-dependencies] deno_bench_util.workspace = true +libuv-sys-lite = "=1.48.2" pretty_assertions.workspace = true test_util.workspace = true diff --git a/cli/build.rs b/cli/build.rs index c3b6f8b045..aa5d3d18c6 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -387,6 +387,8 @@ fn main() { "Missing symbols list! Generate using tools/napi/generate_symbols_lists.js", ); + println!("cargo:rustc-rerun-if-changed={}", symbols_path.display()); + #[cfg(target_os = "windows")] println!( "cargo:rustc-link-arg-bin=deno=/DEF:{}", diff --git a/cli/napi/generated_symbol_exports_list_linux.def b/cli/napi/generated_symbol_exports_list_linux.def index 06e94f05bb..614880ebfa 100644 --- a/cli/napi/generated_symbol_exports_list_linux.def +++ b/cli/napi/generated_symbol_exports_list_linux.def @@ -1 +1 @@ -{ "node_api_create_syntax_error"; "napi_make_callback"; "napi_has_named_property"; "napi_async_destroy"; "napi_coerce_to_object"; "napi_get_arraybuffer_info"; "napi_detach_arraybuffer"; "napi_get_undefined"; "napi_reference_unref"; "napi_fatal_error"; "napi_open_callback_scope"; "napi_close_callback_scope"; "napi_get_value_uint32"; "napi_create_function"; "napi_create_arraybuffer"; "napi_get_value_int64"; "napi_get_all_property_names"; "napi_resolve_deferred"; "napi_is_detached_arraybuffer"; "napi_create_string_utf8"; "napi_create_threadsafe_function"; "node_api_throw_syntax_error"; "napi_create_bigint_int64"; "napi_wrap"; "napi_set_property"; "napi_get_value_bigint_int64"; "napi_open_handle_scope"; "napi_create_error"; "napi_create_buffer"; "napi_cancel_async_work"; "napi_is_exception_pending"; "napi_acquire_threadsafe_function"; "napi_create_external"; "napi_get_threadsafe_function_context"; "napi_get_null"; "napi_create_string_utf16"; "node_api_create_external_string_utf16"; "napi_get_value_bigint_uint64"; "napi_module_register"; "napi_is_typedarray"; "napi_create_external_buffer"; "napi_get_new_target"; "napi_get_instance_data"; "napi_close_handle_scope"; "napi_get_value_string_utf16"; "napi_get_property_names"; "napi_is_arraybuffer"; "napi_get_cb_info"; "napi_define_properties"; "napi_add_env_cleanup_hook"; "node_api_get_module_file_name"; "napi_get_node_version"; "napi_create_int64"; "napi_create_double"; "napi_get_and_clear_last_exception"; "napi_create_reference"; "napi_get_typedarray_info"; "napi_call_threadsafe_function"; "napi_get_last_error_info"; "napi_create_array_with_length"; "napi_coerce_to_number"; "napi_get_global"; "napi_is_error"; "napi_set_instance_data"; "napi_create_typedarray"; "napi_throw_type_error"; "napi_has_property"; "napi_get_value_external"; "napi_create_range_error"; "napi_typeof"; "napi_ref_threadsafe_function"; "napi_create_bigint_uint64"; "napi_get_prototype"; "napi_adjust_external_memory"; "napi_release_threadsafe_function"; "napi_delete_async_work"; "napi_create_string_latin1"; "node_api_create_external_string_latin1"; "napi_is_array"; "napi_unref_threadsafe_function"; "napi_throw_error"; "napi_has_own_property"; "napi_get_reference_value"; "napi_remove_env_cleanup_hook"; "napi_get_value_string_utf8"; "napi_is_promise"; "napi_get_boolean"; "napi_run_script"; "napi_get_element"; "napi_get_named_property"; "napi_get_buffer_info"; "napi_get_value_bool"; "napi_reference_ref"; "napi_create_object"; "napi_create_promise"; "napi_create_int32"; "napi_escape_handle"; "napi_open_escapable_handle_scope"; "napi_throw"; "napi_get_value_double"; "napi_set_named_property"; "napi_call_function"; "napi_create_date"; "napi_object_freeze"; "napi_get_uv_event_loop"; "napi_get_value_string_latin1"; "napi_reject_deferred"; "napi_add_finalizer"; "napi_create_array"; "napi_delete_reference"; "napi_get_date_value"; "napi_create_dataview"; "napi_get_version"; "napi_define_class"; "napi_is_date"; "napi_remove_wrap"; "napi_delete_property"; "napi_instanceof"; "napi_create_buffer_copy"; "napi_delete_element"; "napi_object_seal"; "napi_queue_async_work"; "napi_get_value_bigint_words"; "napi_is_buffer"; "napi_get_array_length"; "napi_get_property"; "napi_new_instance"; "napi_set_element"; "napi_create_bigint_words"; "napi_strict_equals"; "napi_is_dataview"; "napi_close_escapable_handle_scope"; "napi_get_dataview_info"; "napi_get_value_int32"; "napi_unwrap"; "napi_throw_range_error"; "napi_coerce_to_bool"; "napi_create_uint32"; "napi_has_element"; "napi_create_external_arraybuffer"; "napi_create_symbol"; "node_api_symbol_for"; "napi_coerce_to_string"; "napi_create_type_error"; "napi_fatal_exception"; "napi_create_async_work"; "napi_async_init"; "node_api_create_property_key_utf16"; "napi_type_tag_object"; "napi_check_object_type_tag"; "node_api_post_finalizer"; "napi_add_async_cleanup_hook"; "napi_remove_async_cleanup_hook"; }; \ No newline at end of file +{ "node_api_create_syntax_error"; "napi_make_callback"; "napi_has_named_property"; "napi_async_destroy"; "napi_coerce_to_object"; "napi_get_arraybuffer_info"; "napi_detach_arraybuffer"; "napi_get_undefined"; "napi_reference_unref"; "napi_fatal_error"; "napi_open_callback_scope"; "napi_close_callback_scope"; "napi_get_value_uint32"; "napi_create_function"; "napi_create_arraybuffer"; "napi_get_value_int64"; "napi_get_all_property_names"; "napi_resolve_deferred"; "napi_is_detached_arraybuffer"; "napi_create_string_utf8"; "napi_create_threadsafe_function"; "node_api_throw_syntax_error"; "napi_create_bigint_int64"; "napi_wrap"; "napi_set_property"; "napi_get_value_bigint_int64"; "napi_open_handle_scope"; "napi_create_error"; "napi_create_buffer"; "napi_cancel_async_work"; "napi_is_exception_pending"; "napi_acquire_threadsafe_function"; "napi_create_external"; "napi_get_threadsafe_function_context"; "napi_get_null"; "napi_create_string_utf16"; "node_api_create_external_string_utf16"; "napi_get_value_bigint_uint64"; "napi_module_register"; "napi_is_typedarray"; "napi_create_external_buffer"; "napi_get_new_target"; "napi_get_instance_data"; "napi_close_handle_scope"; "napi_get_value_string_utf16"; "napi_get_property_names"; "napi_is_arraybuffer"; "napi_get_cb_info"; "napi_define_properties"; "napi_add_env_cleanup_hook"; "node_api_get_module_file_name"; "napi_get_node_version"; "napi_create_int64"; "napi_create_double"; "napi_get_and_clear_last_exception"; "napi_create_reference"; "napi_get_typedarray_info"; "napi_call_threadsafe_function"; "napi_get_last_error_info"; "napi_create_array_with_length"; "napi_coerce_to_number"; "napi_get_global"; "napi_is_error"; "napi_set_instance_data"; "napi_create_typedarray"; "napi_throw_type_error"; "napi_has_property"; "napi_get_value_external"; "napi_create_range_error"; "napi_typeof"; "napi_ref_threadsafe_function"; "napi_create_bigint_uint64"; "napi_get_prototype"; "napi_adjust_external_memory"; "napi_release_threadsafe_function"; "napi_delete_async_work"; "napi_create_string_latin1"; "node_api_create_external_string_latin1"; "napi_is_array"; "napi_unref_threadsafe_function"; "napi_throw_error"; "napi_has_own_property"; "napi_get_reference_value"; "napi_remove_env_cleanup_hook"; "napi_get_value_string_utf8"; "napi_is_promise"; "napi_get_boolean"; "napi_run_script"; "napi_get_element"; "napi_get_named_property"; "napi_get_buffer_info"; "napi_get_value_bool"; "napi_reference_ref"; "napi_create_object"; "napi_create_promise"; "napi_create_int32"; "napi_escape_handle"; "napi_open_escapable_handle_scope"; "napi_throw"; "napi_get_value_double"; "napi_set_named_property"; "napi_call_function"; "napi_create_date"; "napi_object_freeze"; "napi_get_uv_event_loop"; "napi_get_value_string_latin1"; "napi_reject_deferred"; "napi_add_finalizer"; "napi_create_array"; "napi_delete_reference"; "napi_get_date_value"; "napi_create_dataview"; "napi_get_version"; "napi_define_class"; "napi_is_date"; "napi_remove_wrap"; "napi_delete_property"; "napi_instanceof"; "napi_create_buffer_copy"; "napi_delete_element"; "napi_object_seal"; "napi_queue_async_work"; "napi_get_value_bigint_words"; "napi_is_buffer"; "napi_get_array_length"; "napi_get_property"; "napi_new_instance"; "napi_set_element"; "napi_create_bigint_words"; "napi_strict_equals"; "napi_is_dataview"; "napi_close_escapable_handle_scope"; "napi_get_dataview_info"; "napi_get_value_int32"; "napi_unwrap"; "napi_throw_range_error"; "napi_coerce_to_bool"; "napi_create_uint32"; "napi_has_element"; "napi_create_external_arraybuffer"; "napi_create_symbol"; "node_api_symbol_for"; "napi_coerce_to_string"; "napi_create_type_error"; "napi_fatal_exception"; "napi_create_async_work"; "napi_async_init"; "node_api_create_property_key_utf16"; "napi_type_tag_object"; "napi_check_object_type_tag"; "node_api_post_finalizer"; "napi_add_async_cleanup_hook"; "napi_remove_async_cleanup_hook"; "uv_mutex_init"; "uv_mutex_lock"; "uv_mutex_unlock"; "uv_mutex_destroy"; "uv_async_init"; "uv_async_send"; "uv_close"; }; \ No newline at end of file diff --git a/cli/napi/generated_symbol_exports_list_macos.def b/cli/napi/generated_symbol_exports_list_macos.def index cac7100c6f..36b2f37fa5 100644 --- a/cli/napi/generated_symbol_exports_list_macos.def +++ b/cli/napi/generated_symbol_exports_list_macos.def @@ -150,4 +150,11 @@ _napi_type_tag_object _napi_check_object_type_tag _node_api_post_finalizer _napi_add_async_cleanup_hook -_napi_remove_async_cleanup_hook \ No newline at end of file +_napi_remove_async_cleanup_hook +_uv_mutex_init +_uv_mutex_lock +_uv_mutex_unlock +_uv_mutex_destroy +_uv_async_init +_uv_async_send +_uv_close \ No newline at end of file diff --git a/cli/napi/generated_symbol_exports_list_windows.def b/cli/napi/generated_symbol_exports_list_windows.def index 5386b46e54..b7355112e7 100644 --- a/cli/napi/generated_symbol_exports_list_windows.def +++ b/cli/napi/generated_symbol_exports_list_windows.def @@ -152,4 +152,11 @@ EXPORTS napi_check_object_type_tag node_api_post_finalizer napi_add_async_cleanup_hook - napi_remove_async_cleanup_hook \ No newline at end of file + napi_remove_async_cleanup_hook + uv_mutex_init + uv_mutex_lock + uv_mutex_unlock + uv_mutex_destroy + uv_async_init + uv_async_send + uv_close \ No newline at end of file diff --git a/cli/napi/mod.rs b/cli/napi/mod.rs index 122d2ff060..811efb1ecc 100644 --- a/cli/napi/mod.rs +++ b/cli/napi/mod.rs @@ -18,3 +18,4 @@ pub mod js_native_api; pub mod node_api; pub mod util; +pub mod uv; diff --git a/cli/napi/node_api.rs b/cli/napi/node_api.rs index 81cb800a7d..2efb71c267 100644 --- a/cli/napi/node_api.rs +++ b/cli/napi/node_api.rs @@ -547,11 +547,16 @@ fn napi_delete_async_work(env: *mut Env, work: napi_async_work) -> napi_status { } #[napi_sym] -fn napi_get_uv_event_loop(env: *mut Env, uv_loop: *mut *mut ()) -> napi_status { - let env = check_env!(env); +fn napi_get_uv_event_loop( + env_ptr: *mut Env, + uv_loop: *mut *mut (), +) -> napi_status { + let env = check_env!(env_ptr); check_arg!(env, uv_loop); - // There is no uv_loop in Deno - napi_set_last_error(env, napi_generic_failure) + unsafe { + *uv_loop = env_ptr.cast(); + } + 0 } #[napi_sym] diff --git a/cli/napi/sym/symbol_exports.json b/cli/napi/sym/symbol_exports.json index 64b548d496..00946b8ed7 100644 --- a/cli/napi/sym/symbol_exports.json +++ b/cli/napi/sym/symbol_exports.json @@ -152,6 +152,13 @@ "napi_check_object_type_tag", "node_api_post_finalizer", "napi_add_async_cleanup_hook", - "napi_remove_async_cleanup_hook" + "napi_remove_async_cleanup_hook", + "uv_mutex_init", + "uv_mutex_lock", + "uv_mutex_unlock", + "uv_mutex_destroy", + "uv_async_init", + "uv_async_send", + "uv_close" ] } diff --git a/cli/napi/uv.rs b/cli/napi/uv.rs new file mode 100644 index 0000000000..d4cb5c0b36 --- /dev/null +++ b/cli/napi/uv.rs @@ -0,0 +1,231 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use deno_core::parking_lot::Mutex; +use deno_runtime::deno_napi::*; +use std::mem::MaybeUninit; +use std::ptr::addr_of_mut; + +#[allow(clippy::print_stderr)] +fn assert_ok(res: c_int) -> c_int { + if res != 0 { + eprintln!("bad result in uv polyfill: {res}"); + // don't panic because that might unwind into + // c/c++ + std::process::abort(); + } + res +} + +use crate::napi::js_native_api::napi_create_string_utf8; +use crate::napi::node_api::napi_create_async_work; +use crate::napi::node_api::napi_delete_async_work; +use crate::napi::node_api::napi_queue_async_work; +use std::ffi::c_int; + +const UV_MUTEX_SIZE: usize = { + #[cfg(unix)] + { + std::mem::size_of::() + } + #[cfg(windows)] + { + std::mem::size_of::( + ) + } +}; + +#[repr(C)] +struct uv_mutex_t { + mutex: Mutex<()>, + _padding: [MaybeUninit; const { + (UV_MUTEX_SIZE - size_of::>()) / size_of::() + }], +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_init(lock: *mut uv_mutex_t) -> c_int { + unsafe { + addr_of_mut!((*lock).mutex).write(Mutex::new(())); + 0 + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_lock(lock: *mut uv_mutex_t) { + unsafe { + let guard = (*lock).mutex.lock(); + // forget the guard so it doesn't unlock when it goes out of scope. + // we're going to unlock it manually + std::mem::forget(guard); + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_unlock(lock: *mut uv_mutex_t) { + unsafe { + (*lock).mutex.force_unlock(); + } +} + +#[no_mangle] +unsafe extern "C" fn uv_mutex_destroy(_lock: *mut uv_mutex_t) { + // no cleanup required +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +#[allow(dead_code)] +enum uv_handle_type { + UV_UNKNOWN_HANDLE = 0, + UV_ASYNC, + UV_CHECK, + UV_FS_EVENT, + UV_FS_POLL, + UV_HANDLE, + UV_IDLE, + UV_NAMED_PIPE, + UV_POLL, + UV_PREPARE, + UV_PROCESS, + UV_STREAM, + UV_TCP, + UV_TIMER, + UV_TTY, + UV_UDP, + UV_SIGNAL, + UV_FILE, + UV_HANDLE_TYPE_MAX, +} + +const UV_HANDLE_SIZE: usize = 96; + +#[repr(C)] +struct uv_handle_t { + // public members + pub data: *mut c_void, + pub r#loop: *mut uv_loop_t, + pub r#type: uv_handle_type, + + _padding: [MaybeUninit; const { + (UV_HANDLE_SIZE + - size_of::<*mut c_void>() + - size_of::<*mut uv_loop_t>() + - size_of::()) + / size_of::() + }], +} + +#[cfg(unix)] +const UV_ASYNC_SIZE: usize = 128; + +#[cfg(windows)] +const UV_ASYNC_SIZE: usize = 224; + +#[repr(C)] +struct uv_async_t { + // public members + pub data: *mut c_void, + pub r#loop: *mut uv_loop_t, + pub r#type: uv_handle_type, + // private + async_cb: uv_async_cb, + work: napi_async_work, + _padding: [MaybeUninit; const { + (UV_ASYNC_SIZE + - size_of::<*mut c_void>() + - size_of::<*mut uv_loop_t>() + - size_of::() + - size_of::() + - size_of::()) + / size_of::() + }], +} + +type uv_loop_t = Env; +type uv_async_cb = extern "C" fn(handle: *mut uv_async_t); +#[no_mangle] +unsafe extern "C" fn uv_async_init( + r#loop: *mut uv_loop_t, + // probably uninitialized + r#async: *mut uv_async_t, + async_cb: uv_async_cb, +) -> c_int { + unsafe { + addr_of_mut!((*r#async).r#loop).write(r#loop); + addr_of_mut!((*r#async).r#type).write(uv_handle_type::UV_ASYNC); + addr_of_mut!((*r#async).async_cb).write(async_cb); + + let mut resource_name: MaybeUninit = MaybeUninit::uninit(); + assert_ok(napi_create_string_utf8( + r#loop, + c"uv_async".as_ptr(), + usize::MAX, + resource_name.as_mut_ptr(), + )); + let resource_name = resource_name.assume_init(); + + let res = napi_create_async_work( + r#loop, + None::>.into(), + resource_name, + Some(async_exec_wrap), + None, + r#async.cast(), + addr_of_mut!((*r#async).work), + ); + -res + } +} + +#[no_mangle] +unsafe extern "C" fn uv_async_send(handle: *mut uv_async_t) -> c_int { + unsafe { -napi_queue_async_work((*handle).r#loop, (*handle).work) } +} + +type uv_close_cb = unsafe extern "C" fn(*mut uv_handle_t); + +#[no_mangle] +unsafe extern "C" fn uv_close(handle: *mut uv_handle_t, close: uv_close_cb) { + unsafe { + if handle.is_null() { + close(handle); + return; + } + if let uv_handle_type::UV_ASYNC = (*handle).r#type { + let handle: *mut uv_async_t = handle.cast(); + napi_delete_async_work((*handle).r#loop, (*handle).work); + } + close(handle); + } +} + +unsafe extern "C" fn async_exec_wrap(_env: napi_env, data: *mut c_void) { + let data: *mut uv_async_t = data.cast(); + unsafe { + ((*data).async_cb)(data); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sizes() { + assert_eq!( + std::mem::size_of::(), + UV_MUTEX_SIZE + ); + assert_eq!( + std::mem::size_of::(), + UV_HANDLE_SIZE + ); + assert_eq!( + std::mem::size_of::(), + UV_ASYNC_SIZE + ); + assert_eq!(std::mem::size_of::(), UV_MUTEX_SIZE); + assert_eq!(std::mem::size_of::(), UV_HANDLE_SIZE); + assert_eq!(std::mem::size_of::(), UV_ASYNC_SIZE); + } +} diff --git a/tests/napi/Cargo.toml b/tests/napi/Cargo.toml index 611d6d5507..e3de253683 100644 --- a/tests/napi/Cargo.toml +++ b/tests/napi/Cargo.toml @@ -13,6 +13,7 @@ repository.workspace = true crate-type = ["cdylib"] [dependencies] +libuv-sys-lite = "=1.48.2" napi-sys = { version = "=2.2.2", default-features = false, features = ["napi7"] } [dev-dependencies] diff --git a/tests/napi/src/lib.rs b/tests/napi/src/lib.rs index f6fe6e189a..8c6190ad3e 100644 --- a/tests/napi/src/lib.rs +++ b/tests/napi/src/lib.rs @@ -31,6 +31,7 @@ pub mod strings; pub mod symbol; pub mod tsfn; pub mod typedarray; +pub mod uv; #[macro_export] macro_rules! cstr { @@ -138,6 +139,7 @@ unsafe extern "C" fn napi_register_module_v1( #[cfg(windows)] { napi_sys::setup(); + libuv_sys_lite::setup(); } // We create a fresh exports object and leave the passed @@ -169,6 +171,7 @@ unsafe extern "C" fn napi_register_module_v1( symbol::init(env, exports); make_callback::init(env, exports); object::init(env, exports); + uv::init(env, exports); init_cleanup_hook(env, exports); diff --git a/tests/napi/src/uv.rs b/tests/napi/src/uv.rs new file mode 100644 index 0000000000..555470c008 --- /dev/null +++ b/tests/napi/src/uv.rs @@ -0,0 +1,206 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use crate::assert_napi_ok; +use crate::napi_get_callback_info; +use crate::napi_new_property; +use libuv_sys_lite::uv_async_init; +use libuv_sys_lite::uv_async_t; +use libuv_sys_lite::uv_close; +use libuv_sys_lite::uv_handle_t; +use libuv_sys_lite::uv_mutex_destroy; +use libuv_sys_lite::uv_mutex_lock; +use libuv_sys_lite::uv_mutex_t; +use libuv_sys_lite::uv_mutex_unlock; +use napi_sys::*; +use std::mem::MaybeUninit; +use std::ptr; +use std::ptr::addr_of_mut; +use std::ptr::null_mut; +use std::time::Duration; + +struct KeepAlive { + tsfn: napi_threadsafe_function, +} + +impl KeepAlive { + fn new(env: napi_env) -> Self { + let mut name = null_mut(); + assert_napi_ok!(napi_create_string_utf8( + env, + c"test_uv_async".as_ptr(), + 13, + &mut name + )); + + unsafe extern "C" fn dummy( + _env: napi_env, + _cb: napi_callback_info, + ) -> napi_value { + ptr::null_mut() + } + + let mut func = null_mut(); + assert_napi_ok!(napi_create_function( + env, + c"dummy".as_ptr(), + usize::MAX, + Some(dummy), + null_mut(), + &mut func, + )); + + let mut tsfn = null_mut(); + assert_napi_ok!(napi_create_threadsafe_function( + env, + func, + null_mut(), + name, + 0, + 1, + null_mut(), + None, + null_mut(), + None, + &mut tsfn, + )); + assert_napi_ok!(napi_ref_threadsafe_function(env, tsfn)); + Self { tsfn } + } +} + +impl Drop for KeepAlive { + fn drop(&mut self) { + assert_napi_ok!(napi_release_threadsafe_function( + self.tsfn, + ThreadsafeFunctionReleaseMode::release, + )); + } +} + +struct Async { + mutex: *mut uv_mutex_t, + env: napi_env, + value: u32, + callback: napi_ref, + _keep_alive: KeepAlive, +} + +#[derive(Clone, Copy)] +struct UvAsyncPtr(*mut uv_async_t); + +unsafe impl Send for UvAsyncPtr {} + +fn new_raw(t: T) -> *mut T { + Box::into_raw(Box::new(t)) +} + +unsafe extern "C" fn close_cb(handle: *mut uv_handle_t) { + let handle = handle.cast::(); + let async_ = (*handle).data as *mut Async; + let env = (*async_).env; + assert_napi_ok!(napi_delete_reference(env, (*async_).callback)); + + uv_mutex_destroy((*async_).mutex); + let _ = Box::from_raw((*async_).mutex); + let _ = Box::from_raw(async_); + let _ = Box::from_raw(handle); +} + +unsafe extern "C" fn callback(handle: *mut uv_async_t) { + eprintln!("callback"); + let async_ = (*handle).data as *mut Async; + uv_mutex_lock((*async_).mutex); + let env = (*async_).env; + let mut js_cb = null_mut(); + assert_napi_ok!(napi_get_reference_value( + env, + (*async_).callback, + &mut js_cb + )); + let mut global: napi_value = ptr::null_mut(); + assert_napi_ok!(napi_get_global(env, &mut global)); + + let mut result: napi_value = ptr::null_mut(); + let value = (*async_).value; + eprintln!("value is {value}"); + let mut value_js = ptr::null_mut(); + assert_napi_ok!(napi_create_uint32(env, value, &mut value_js)); + let args = &[value_js]; + assert_napi_ok!(napi_call_function( + env, + global, + js_cb, + 1, + args.as_ptr(), + &mut result, + )); + uv_mutex_unlock((*async_).mutex); + if value == 5 { + uv_close(handle.cast(), Some(close_cb)); + } +} + +unsafe fn uv_async_send(ptr: UvAsyncPtr) { + assert_napi_ok!(libuv_sys_lite::uv_async_send(ptr.0)); +} + +fn make_uv_mutex() -> *mut uv_mutex_t { + let mutex = new_raw(MaybeUninit::::uninit()); + assert_napi_ok!(libuv_sys_lite::uv_mutex_init(mutex.cast())); + mutex.cast() +} + +#[allow(unused_unsafe)] +extern "C" fn test_uv_async( + env: napi_env, + info: napi_callback_info, +) -> napi_value { + let (args, argc, _) = napi_get_callback_info!(env, info, 1); + assert_eq!(argc, 1); + + let mut loop_ = null_mut(); + assert_napi_ok!(napi_get_uv_event_loop(env, &mut loop_)); + let uv_async = new_raw(MaybeUninit::::uninit()); + let uv_async = uv_async.cast::(); + let mut js_cb = null_mut(); + assert_napi_ok!(napi_create_reference(env, args[0], 1, &mut js_cb)); + // let mut tsfn = null_mut(); + + let data = new_raw(Async { + env, + callback: js_cb, + mutex: make_uv_mutex(), + value: 0, + _keep_alive: KeepAlive::new(env), + }); + unsafe { + addr_of_mut!((*uv_async).data).write(data.cast()); + assert_napi_ok!(uv_async_init(loop_.cast(), uv_async, Some(callback))); + let uv_async = UvAsyncPtr(uv_async); + std::thread::spawn({ + move || { + let data = (*uv_async.0).data as *mut Async; + for _ in 0..5 { + uv_mutex_lock((*data).mutex); + (*data).value += 1; + uv_mutex_unlock((*data).mutex); + std::thread::sleep(Duration::from_millis(10)); + uv_async_send(uv_async); + } + } + }); + } + + ptr::null_mut() +} + +pub fn init(env: napi_env, exports: napi_value) { + let properties = &[napi_new_property!(env, "test_uv_async", test_uv_async)]; + + assert_napi_ok!(napi_define_properties( + env, + exports, + properties.len(), + properties.as_ptr() + )); +} diff --git a/tests/napi/uv_test.js b/tests/napi/uv_test.js new file mode 100644 index 0000000000..6d8ee26713 --- /dev/null +++ b/tests/napi/uv_test.js @@ -0,0 +1,18 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { assertEquals, loadTestLibrary } from "./common.js"; + +const uv = loadTestLibrary(); + +Deno.test("napi uv async", async () => { + let called = false; + await new Promise((resolve) => { + uv.test_uv_async((value) => { + called = true; + if (value === 5) { + resolve(); + } + }); + }); + assertEquals(called, true); +}); From cac28b52621975137b86d4fd6efc32cecc10d682 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Wed, 2 Oct 2024 21:17:39 +0100 Subject: [PATCH 06/39] feat(byonm): support `deno run npm:` when package is not in package.json (#25981) Closes https://github.com/denoland/deno/issues/25905 --- Cargo.lock | 1 + cli/args/flags.rs | 14 +++- cli/args/lockfile.rs | 72 +++++++++++-------- cli/args/mod.rs | 3 +- cli/lsp/config.rs | 7 +- cli/lsp/language_server.rs | 6 +- cli/main.rs | 17 +++++ cli/npm/byonm.rs | 4 +- cli/npm/managed/mod.rs | 11 ++- cli/npm/mod.rs | 12 +++- resolvers/deno/Cargo.toml | 1 + resolvers/deno/npm/byonm.rs | 43 ++++++----- resolvers/deno/npm/mod.rs | 1 + tests/specs/npm/byonm_run_npm/__test__.jsonc | 30 ++++++++ tests/specs/npm/byonm_run_npm/deno.json | 2 + tests/specs/npm/byonm_run_npm/not_in_deps.out | 8 +++ tests/specs/npm/byonm_run_npm/overwrite.ts | 4 ++ tests/specs/npm/byonm_run_npm/package.json | 4 ++ tools/format.js | 2 +- tools/lint.js | 2 +- 20 files changed, 178 insertions(+), 66 deletions(-) create mode 100644 tests/specs/npm/byonm_run_npm/__test__.jsonc create mode 100644 tests/specs/npm/byonm_run_npm/deno.json create mode 100644 tests/specs/npm/byonm_run_npm/not_in_deps.out create mode 100644 tests/specs/npm/byonm_run_npm/overwrite.ts create mode 100644 tests/specs/npm/byonm_run_npm/package.json diff --git a/Cargo.lock b/Cargo.lock index f264f41e38..8a51f541dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1985,6 +1985,7 @@ dependencies = [ "deno_semver", "node_resolver", "test_server", + "thiserror", "url", ] diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 6caef29d9f..a4dcb9e91a 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -580,6 +580,15 @@ pub struct UnstableConfig { pub features: Vec, // --unstabe-kv --unstable-cron } +#[derive(Clone, Debug, Eq, PartialEq, Default)] +pub struct InternalFlags { + /// Used when the language server is configured with an + /// explicit cache option. + pub cache_path: Option, + /// Only reads to the lockfile instead of writing to it. + pub lockfile_skip_write: bool, +} + #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct Flags { /// Vector of CLI arguments - these are user script arguments, all Deno @@ -591,9 +600,6 @@ pub struct Flags { pub ca_stores: Option>, pub ca_data: Option, pub cache_blocklist: Vec, - /// This is not exposed as an option in the CLI, it is used internally when - /// the language server is configured with an explicit cache option. - pub cache_path: Option, pub cached_only: bool, pub type_check_mode: TypeCheckMode, pub config_flag: ConfigFlag, @@ -602,6 +608,8 @@ pub struct Flags { pub enable_op_summary_metrics: bool, pub enable_testing_features: bool, pub ext: Option, + /// Flags that aren't exposed in the CLI, but are used internally. + pub internal: InternalFlags, pub ignore: Vec, pub import_map_path: Option, pub env_file: Option, diff --git a/cli/args/lockfile.rs b/cli/args/lockfile.rs index 59ec7f0ef5..1805d26426 100644 --- a/cli/args/lockfile.rs +++ b/cli/args/lockfile.rs @@ -24,11 +24,20 @@ use crate::args::InstallKind; use deno_lockfile::Lockfile; +#[derive(Debug)] +pub struct CliLockfileReadFromPathOptions { + pub file_path: PathBuf, + pub frozen: bool, + /// Causes the lockfile to only be read from, but not written to. + pub skip_write: bool, +} + #[derive(Debug)] pub struct CliLockfile { lockfile: Mutex, pub filename: PathBuf, - pub frozen: bool, + frozen: bool, + skip_write: bool, } pub struct Guard<'a, T> { @@ -50,15 +59,6 @@ impl<'a, T> std::ops::DerefMut for Guard<'a, T> { } impl CliLockfile { - pub fn new(lockfile: Lockfile, frozen: bool) -> Self { - let filename = lockfile.filename.clone(); - Self { - lockfile: Mutex::new(lockfile), - filename, - frozen, - } - } - /// Get the inner deno_lockfile::Lockfile. pub fn lock(&self) -> Guard { Guard { @@ -78,6 +78,10 @@ impl CliLockfile { } pub fn write_if_changed(&self) -> Result<(), AnyError> { + if self.skip_write { + return Ok(()); + } + self.error_if_changed()?; let mut lockfile = self.lockfile.lock(); let Some(bytes) = lockfile.resolve_write_bytes() else { @@ -142,7 +146,7 @@ impl CliLockfile { return Ok(None); } - let filename = match flags.lock { + let file_path = match flags.lock { Some(ref lock) => PathBuf::from(lock), None => match workspace.resolve_lockfile_path()? { Some(path) => path, @@ -160,7 +164,11 @@ impl CliLockfile { .unwrap_or(false) }); - let lockfile = Self::read_from_path(filename, frozen)?; + let lockfile = Self::read_from_path(CliLockfileReadFromPathOptions { + file_path, + frozen, + skip_write: flags.internal.lockfile_skip_write, + })?; // initialize the lockfile with the workspace's configuration let root_url = workspace.root_dir(); @@ -212,25 +220,29 @@ impl CliLockfile { } pub fn read_from_path( - file_path: PathBuf, - frozen: bool, + opts: CliLockfileReadFromPathOptions, ) -> Result { - match std::fs::read_to_string(&file_path) { - Ok(text) => Ok(CliLockfile::new( - Lockfile::new(deno_lockfile::NewLockfileOptions { - file_path, - content: &text, - overwrite: false, - })?, - frozen, - )), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok( - CliLockfile::new(Lockfile::new_empty(file_path, false), frozen), - ), - Err(err) => Err(err).with_context(|| { - format!("Failed reading lockfile '{}'", file_path.display()) - }), - } + let lockfile = match std::fs::read_to_string(&opts.file_path) { + Ok(text) => Lockfile::new(deno_lockfile::NewLockfileOptions { + file_path: opts.file_path, + content: &text, + overwrite: false, + })?, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + Lockfile::new_empty(opts.file_path, false) + } + Err(err) => { + return Err(err).with_context(|| { + format!("Failed reading lockfile '{}'", opts.file_path.display()) + }); + } + }; + Ok(CliLockfile { + filename: lockfile.filename.clone(), + lockfile: Mutex::new(lockfile), + frozen: opts.frozen, + skip_write: opts.skip_write, + }) } pub fn error_if_changed(&self) -> Result<(), AnyError> { diff --git a/cli/args/mod.rs b/cli/args/mod.rs index 2ae7098da5..f0cce4ab1b 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -44,6 +44,7 @@ pub use deno_config::glob::FilePatterns; pub use deno_json::check_warn_tsconfig; pub use flags::*; pub use lockfile::CliLockfile; +pub use lockfile::CliLockfileReadFromPathOptions; pub use package_json::NpmInstallDepsProvider; use deno_ast::ModuleSpecifier; @@ -828,7 +829,7 @@ impl CliOptions { let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache); let deno_dir_provider = - Arc::new(DenoDirProvider::new(flags.cache_path.clone())); + Arc::new(DenoDirProvider::new(flags.internal.cache_path.clone())); let maybe_node_modules_folder = resolve_node_modules_folder( &initial_cwd, &flags, diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index c54de3a235..07fdd3c65a 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -53,6 +53,7 @@ use super::logging::lsp_log; use crate::args::discover_npmrc_from_workspace; use crate::args::has_flag_env_var; use crate::args::CliLockfile; +use crate::args::CliLockfileReadFromPathOptions; use crate::args::ConfigFile; use crate::args::LintFlags; use crate::args::LintOptions; @@ -1931,7 +1932,11 @@ fn resolve_lockfile_from_path( lockfile_path: PathBuf, frozen: bool, ) -> Option { - match CliLockfile::read_from_path(lockfile_path, frozen) { + match CliLockfile::read_from_path(CliLockfileReadFromPathOptions { + file_path: lockfile_path, + frozen, + skip_write: false, + }) { Ok(value) => { if value.filename.exists() { if let Ok(specifier) = ModuleSpecifier::from_file_path(&value.filename) diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 6ddbb1a514..90a2579f4d 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -96,6 +96,7 @@ use crate::args::CaData; use crate::args::CacheSetting; use crate::args::CliOptions; use crate::args::Flags; +use crate::args::InternalFlags; use crate::args::UnstableFmtOptions; use crate::factory::CliFactory; use crate::file_fetcher::FileFetcher; @@ -3605,7 +3606,10 @@ impl Inner { }; let cli_options = CliOptions::new( Arc::new(Flags { - cache_path: Some(self.cache.deno_dir().root.clone()), + internal: InternalFlags { + cache_path: Some(self.cache.deno_dir().root.clone()), + ..Default::default() + }, ca_stores: workspace_settings.certificate_stores.clone(), ca_data: workspace_settings.tls_certificate.clone().map(CaData::File), unsafely_ignore_certificate_errors: workspace_settings diff --git a/cli/main.rs b/cli/main.rs index 31bebc882f..93bd97e2aa 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -37,6 +37,7 @@ use crate::util::v8::get_v8_flags_from_env; use crate::util::v8::init_v8_flags; use args::TaskFlags; +use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError; use deno_runtime::WorkerExecutionMode; pub use deno_runtime::UNSTABLE_GRANULAR_FLAGS; @@ -51,6 +52,7 @@ use deno_runtime::fmt_errors::FixSuggestion; use deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics; use deno_terminal::colors; use factory::CliFactory; +use npm::ResolvePkgFolderFromDenoReqError; use standalone::MODULE_NOT_FOUND; use standalone::UNSUPPORTED_SCHEME; use std::env; @@ -182,6 +184,21 @@ async fn run_subcommand(flags: Arc) -> Result { match result { Ok(v) => Ok(v), Err(script_err) => { + if let Some(ResolvePkgFolderFromDenoReqError::Byonm(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq(_))) = script_err.downcast_ref::() { + if flags.node_modules_dir.is_none() { + let mut flags = flags.deref().clone(); + let watch = match &flags.subcommand { + DenoSubcommand::Run(run_flags) => run_flags.watch.clone(), + _ => unreachable!(), + }; + flags.node_modules_dir = Some(deno_config::deno_json::NodeModulesDirMode::None); + // use the current lockfile, but don't write it out + if flags.frozen_lockfile.is_none() { + flags.internal.lockfile_skip_write = true; + } + return tools::run::run_script(WorkerExecutionMode::Run, Arc::new(flags), watch).await; + } + } let script_err_msg = script_err.to_string(); if script_err_msg.starts_with(MODULE_NOT_FOUND) || script_err_msg.starts_with(UNSUPPORTED_SCHEME) { if run_flags.bare { diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index ceef68135a..02c2e6da81 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -21,6 +21,7 @@ use crate::resolver::CliDenoResolverFs; use super::CliNpmResolver; use super::InnerCliNpmResolverRef; +use super::ResolvePkgFolderFromDenoReqError; pub type CliByonmNpmResolverCreateOptions = ByonmNpmResolverCreateOptions; @@ -90,10 +91,11 @@ impl CliNpmResolver for CliByonmNpmResolver { &self, req: &PackageReq, referrer: &Url, - ) -> Result { + ) -> Result { ByonmNpmResolver::resolve_pkg_folder_from_deno_module_req( self, req, referrer, ) + .map_err(ResolvePkgFolderFromDenoReqError::Byonm) } fn check_state_hash(&self) -> Option { diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index 6f6fa4bf87..7bb254cb52 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -51,6 +51,7 @@ use self::resolvers::NpmPackageFsResolver; use super::CliNpmResolver; use super::InnerCliNpmResolverRef; +use super::ResolvePkgFolderFromDenoReqError; mod cache; mod registry; @@ -649,9 +650,13 @@ impl CliNpmResolver for ManagedCliNpmResolver { &self, req: &PackageReq, _referrer: &ModuleSpecifier, - ) -> Result { - let pkg_id = self.resolve_pkg_id_from_pkg_req(req)?; - self.resolve_pkg_folder_from_pkg_id(&pkg_id) + ) -> Result { + let pkg_id = self + .resolve_pkg_id_from_pkg_req(req) + .map_err(|err| ResolvePkgFolderFromDenoReqError::Managed(err.into()))?; + self + .resolve_pkg_folder_from_pkg_id(&pkg_id) + .map_err(ResolvePkgFolderFromDenoReqError::Managed) } fn check_state_hash(&self) -> Option { diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 1e3c752aee..53baaf77b4 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -14,11 +14,13 @@ use deno_core::error::AnyError; use deno_core::serde_json; use deno_npm::registry::NpmPackageInfo; use deno_resolver::npm::ByonmNpmResolver; +use deno_resolver::npm::ByonmResolvePkgFolderFromDenoReqError; use deno_runtime::deno_node::NodeRequireResolver; use deno_runtime::ops::process::NpmProcessStateProvider; use deno_semver::package::PackageNv; use deno_semver::package::PackageReq; use node_resolver::NpmResolver; +use thiserror::Error; use crate::args::npm_registry_url; use crate::file_fetcher::FileFetcher; @@ -29,6 +31,14 @@ pub use self::managed::CliNpmResolverManagedCreateOptions; pub use self::managed::CliNpmResolverManagedSnapshotOption; pub use self::managed::ManagedCliNpmResolver; +#[derive(Debug, Error)] +pub enum ResolvePkgFolderFromDenoReqError { + #[error(transparent)] + Managed(deno_core::error::AnyError), + #[error(transparent)] + Byonm(#[from] ByonmResolvePkgFolderFromDenoReqError), +} + pub enum CliNpmResolverCreateOptions { Managed(CliNpmResolverManagedCreateOptions), Byonm(CliByonmNpmResolverCreateOptions), @@ -93,7 +103,7 @@ pub trait CliNpmResolver: NpmResolver { &self, req: &PackageReq, referrer: &ModuleSpecifier, - ) -> Result; + ) -> Result; /// Returns a hash returning the state of the npm resolver /// or `None` if the state currently can't be determined. diff --git a/resolvers/deno/Cargo.toml b/resolvers/deno/Cargo.toml index 1b9aab1e6e..5900f9269b 100644 --- a/resolvers/deno/Cargo.toml +++ b/resolvers/deno/Cargo.toml @@ -22,6 +22,7 @@ deno_package_json.features = ["sync"] deno_path_util.workspace = true deno_semver.workspace = true node_resolver.workspace = true +thiserror.workspace = true url.workspace = true [dev-dependencies] diff --git a/resolvers/deno/npm/byonm.rs b/resolvers/deno/npm/byonm.rs index c847cee0f2..5bc4e62b2c 100644 --- a/resolvers/deno/npm/byonm.rs +++ b/resolvers/deno/npm/byonm.rs @@ -5,8 +5,6 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; -use anyhow::bail; -use anyhow::Error as AnyError; use deno_package_json::PackageJson; use deno_package_json::PackageJsonDepValue; use deno_path_util::url_to_file_path; @@ -18,6 +16,7 @@ use node_resolver::errors::PackageJsonLoadError; use node_resolver::errors::PackageNotFoundError; use node_resolver::load_pkg_json; use node_resolver::NpmResolver; +use thiserror::Error; use url::Url; use crate::fs::DenoPkgJsonFsAdapter; @@ -25,6 +24,18 @@ use crate::fs::DenoResolverFs; use super::local::normalize_pkg_name_for_node_modules_deno_folder; +#[derive(Debug, Error)] +pub enum ByonmResolvePkgFolderFromDenoReqError { + #[error("Could not find \"{}\" in a node_modules folder. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`?", .0)] + MissingAlias(String), + #[error(transparent)] + PackageJson(#[from] PackageJsonLoadError), + #[error("Could not find a matching package for 'npm:{}' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `\"nodeModulesDir\": \"auto\"` in your deno.json file.", .0)] + UnmatchedReq(PackageReq), + #[error(transparent)] + Io(#[from] std::io::Error), +} + pub struct ByonmNpmResolverCreateOptions { pub fs: Fs, // todo(dsherret): investigate removing this @@ -100,12 +111,12 @@ impl ByonmNpmResolver { &self, req: &PackageReq, referrer: &Url, - ) -> Result { + ) -> Result { fn node_resolve_dir( fs: &Fs, alias: &str, start_dir: &Path, - ) -> Result, AnyError> { + ) -> std::io::Result> { for ancestor in start_dir.ancestors() { let node_modules_folder = ancestor.join("node_modules"); let sub_dir = join_package_name(&node_modules_folder, alias); @@ -131,14 +142,7 @@ impl ByonmNpmResolver { return Ok(resolved); } - bail!( - concat!( - "Could not find \"{}\" in a node_modules folder. ", - "Deno expects the node_modules/ directory to be up to date. ", - "Did you forget to run `deno install`?" - ), - alias, - ); + Err(ByonmResolvePkgFolderFromDenoReqError::MissingAlias(alias)) } None => { // now check if node_modules/.deno/ matches this constraint @@ -146,16 +150,9 @@ impl ByonmNpmResolver { return Ok(folder); } - bail!( - concat!( - "Could not find a matching package for 'npm:{}' in the node_modules ", - "directory. Ensure you have all your JSR and npm dependencies listed ", - "in your deno.json or package.json, then run `deno install`. Alternatively, ", - r#"turn on auto-install by specifying `"nodeModulesDir": "auto"` in your "#, - "deno.json file." - ), - req, - ); + Err(ByonmResolvePkgFolderFromDenoReqError::UnmatchedReq( + req.clone(), + )) } } } @@ -164,7 +161,7 @@ impl ByonmNpmResolver { &self, req: &PackageReq, referrer: &Url, - ) -> Result, String)>, AnyError> { + ) -> Result, String)>, PackageJsonLoadError> { fn resolve_alias_from_pkg_json( req: &PackageReq, pkg_json: &PackageJson, diff --git a/resolvers/deno/npm/mod.rs b/resolvers/deno/npm/mod.rs index 2e24144cd6..9d885cad31 100644 --- a/resolvers/deno/npm/mod.rs +++ b/resolvers/deno/npm/mod.rs @@ -5,4 +5,5 @@ mod local; pub use byonm::ByonmNpmResolver; pub use byonm::ByonmNpmResolverCreateOptions; +pub use byonm::ByonmResolvePkgFolderFromDenoReqError; pub use local::normalize_pkg_name_for_node_modules_deno_folder; diff --git a/tests/specs/npm/byonm_run_npm/__test__.jsonc b/tests/specs/npm/byonm_run_npm/__test__.jsonc new file mode 100644 index 0000000000..4f0b21b0ff --- /dev/null +++ b/tests/specs/npm/byonm_run_npm/__test__.jsonc @@ -0,0 +1,30 @@ +{ + "tests": { + "not_in_deps": { + "steps": [{ + "args": "run -A --quiet npm:cowsay moo", + "output": "not_in_deps.out" + }, { + // ensure it doesn't make any lockfile modifications and thus doesn't write to the lockfile + "args": [ + "eval", + "try { Deno.statSync('deno.lock') } catch (e) { console.log(e instanceof Deno.errors.NotFound); }" + ], + "output": "true\n" + }] + }, + "in_deps": { + "tempDir": true, + "steps": [{ + "args": "install npm:cowsay", + "output": "[WILDCARD]" + }, { + "args": "run --allow-write overwrite.ts", + "output": "[WILDCARD]" + }, { + "args": "run -A npm:cowsay moo", + "output": "replaced\n" + }] + } + } +} diff --git a/tests/specs/npm/byonm_run_npm/deno.json b/tests/specs/npm/byonm_run_npm/deno.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/tests/specs/npm/byonm_run_npm/deno.json @@ -0,0 +1,2 @@ +{ +} diff --git a/tests/specs/npm/byonm_run_npm/not_in_deps.out b/tests/specs/npm/byonm_run_npm/not_in_deps.out new file mode 100644 index 0000000000..dc07eb43ee --- /dev/null +++ b/tests/specs/npm/byonm_run_npm/not_in_deps.out @@ -0,0 +1,8 @@ + _____ +< moo > + ----- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || diff --git a/tests/specs/npm/byonm_run_npm/overwrite.ts b/tests/specs/npm/byonm_run_npm/overwrite.ts new file mode 100644 index 0000000000..3749c5e4e8 --- /dev/null +++ b/tests/specs/npm/byonm_run_npm/overwrite.ts @@ -0,0 +1,4 @@ +Deno.writeTextFileSync( + "node_modules/cowsay/cli.js", + "console.log('replaced');", +); diff --git a/tests/specs/npm/byonm_run_npm/package.json b/tests/specs/npm/byonm_run_npm/package.json new file mode 100644 index 0000000000..9664f260a7 --- /dev/null +++ b/tests/specs/npm/byonm_run_npm/package.json @@ -0,0 +1,4 @@ +{ + "dependencies": { + } +} diff --git a/tools/format.js b/tools/format.js index 74c608644b..b29667ca77 100755 --- a/tools/format.js +++ b/tools/format.js @@ -1,4 +1,4 @@ -#!/usr/bin/env -S deno run --allow-write --allow-read --allow-run=deno --allow-net --config=tests/config/deno.json +#!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. import { join, ROOT_PATH } from "./util.js"; diff --git a/tools/lint.js b/tools/lint.js index a4302b3788..edf800c4e1 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -1,4 +1,4 @@ -#!/usr/bin/env -S deno run --allow-write --allow-read --allow-run --allow-net --config=tests/config/deno.json +#!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // deno-lint-ignore-file no-console From cb74975ab2b88a984c11a9bbb33ff2a36ccb2acb Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:11:43 -0700 Subject: [PATCH 07/39] fix(install): compare versions directly to decide whether to create a child node_modules dir for a workspace member (#26001) Fixes #25861. Previously we were attempting to match the version requirement against the version already present in `node_modules` root, and if they didn't match we would create a node_modules dir in the workspace member's directory with the dependency. Aside from the fact that this caused the panic, on second thought it just doesn't make sense in general. We shouldn't be semver matching, as resolution has already occurred and decided what package versions are required. Instead, we can just compare the versions directly. --- cli/npm/managed/resolvers/local.rs | 6 +++--- .../install/workspace_member_with_tag_dep/__test__.jsonc | 9 +++++++++ .../install/workspace_member_with_tag_dep/install.out | 3 +++ .../install/workspace_member_with_tag_dep/package.json | 6 ++++++ .../workspace_member_with_tag_dep/package1/package.json | 5 +++++ 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/specs/install/workspace_member_with_tag_dep/__test__.jsonc create mode 100644 tests/specs/install/workspace_member_with_tag_dep/install.out create mode 100644 tests/specs/install/workspace_member_with_tag_dep/package.json create mode 100644 tests/specs/install/workspace_member_with_tag_dep/package1/package.json diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 59ba27d059..edc7c7ea0f 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -518,9 +518,9 @@ async fn sync_resolution_with_fs( // linked into the root match found_names.entry(remote_alias) { Entry::Occupied(nv) => { - alias_clashes - || remote.req.name != nv.get().name // alias to a different package (in case of duplicate aliases) - || !remote.req.version_req.matches(&nv.get().version) // incompatible version + // alias to a different package (in case of duplicate aliases) + // or the version doesn't match the version in the root node_modules + alias_clashes || &remote_pkg.id.nv != *nv.get() } Entry::Vacant(entry) => { entry.insert(&remote_pkg.id.nv); diff --git a/tests/specs/install/workspace_member_with_tag_dep/__test__.jsonc b/tests/specs/install/workspace_member_with_tag_dep/__test__.jsonc new file mode 100644 index 0000000000..254fe8b989 --- /dev/null +++ b/tests/specs/install/workspace_member_with_tag_dep/__test__.jsonc @@ -0,0 +1,9 @@ +{ + "tempDir": true, + "steps": [ + { + "args": "install", + "output": "install.out" + } + ] +} diff --git a/tests/specs/install/workspace_member_with_tag_dep/install.out b/tests/specs/install/workspace_member_with_tag_dep/install.out new file mode 100644 index 0000000000..b8114c12a0 --- /dev/null +++ b/tests/specs/install/workspace_member_with_tag_dep/install.out @@ -0,0 +1,3 @@ +Download http://localhost:4260/@denotest/esm-basic +Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz +Initialize @denotest/esm-basic@1.0.0 diff --git a/tests/specs/install/workspace_member_with_tag_dep/package.json b/tests/specs/install/workspace_member_with_tag_dep/package.json new file mode 100644 index 0000000000..58aa5d5cc6 --- /dev/null +++ b/tests/specs/install/workspace_member_with_tag_dep/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@denotest/esm-basic": "latest" + }, + "workspaces": ["package1"] +} diff --git a/tests/specs/install/workspace_member_with_tag_dep/package1/package.json b/tests/specs/install/workspace_member_with_tag_dep/package1/package.json new file mode 100644 index 0000000000..150a7df6af --- /dev/null +++ b/tests/specs/install/workspace_member_with_tag_dep/package1/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@denotest/esm-basic": "latest" + } +} From 1e0c9b8c5b85c6c18ecdef0374a945b361d6e79d Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:41:58 -0700 Subject: [PATCH 08/39] chore: disable flaky uv_test.js for now (#26003) Will re-enable once I figure out the issue --- tests/napi/uv_test.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/napi/uv_test.js b/tests/napi/uv_test.js index 6d8ee26713..af20b26493 100644 --- a/tests/napi/uv_test.js +++ b/tests/napi/uv_test.js @@ -4,15 +4,19 @@ import { assertEquals, loadTestLibrary } from "./common.js"; const uv = loadTestLibrary(); -Deno.test("napi uv async", async () => { - let called = false; - await new Promise((resolve) => { - uv.test_uv_async((value) => { - called = true; - if (value === 5) { - resolve(); - } +Deno.test({ + name: "napi uv async", + ignore: true, + fn: async () => { + let called = false; + await new Promise((resolve) => { + uv.test_uv_async((value) => { + called = true; + if (value === 5) { + resolve(); + } + }); }); - }); - assertEquals(called, true); + assertEquals(called, true); + }, }); From 275418473e7bda2b0bd33c86ae54cf3ac8ac5341 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:16:46 -0700 Subject: [PATCH 09/39] fix(install): store tags associated with package in node_modules dir (#26000) Fixes #25998. Fixes https://github.com/denoland/deno/issues/25928. Originally I was just going to make this an error message instead of a panic, but once I got to a minimal repro I felt that this really should work. The panic occurs when you have `nodeModulesDir: manual` (or a package.json present), and you have an npm package with a tag in your deno.json (see the spec test that illustrates this). This code path only actually executes when trying to choose an appropriate package version from `node_modules/.deno`, so we should be able to fix it by storing some extra data at install time. The fix proposed here is to repurpose the `.initialized` file that we store in `node_modules` to store the tags associated with a package. Basically, if you have a version requirement with a tag (e.g. `npm:chalk@latest`), when we set up the node_modules folder for that package, we store the tag (`latest`) in `.initialized`. Then, when doing BYONM resolution, if we have a version requirement with a tag, we read that file and check if the tag is present. The downside is that we do more work when setting up `node_modules`. We _could_ do this only when BYONM is enabled, but that would have the downside of needing to re-run `deno install` when you switch from auto -> manual, though maybe that's not a big deal. --- cli/npm/managed/resolvers/local.rs | 33 +++++++++++++- resolvers/deno/npm/byonm.rs | 19 +++++++- .../__test__.jsonc | 44 +++++++++++++++++++ .../byonm_run_tag_after_install/deno.json | 5 +++ .../byonm_run_tag_after_install/main.ts | 1 + .../node_modules_out_of_date.out | 2 + .../byonm_run_tag_after_install/package.json | 1 + .../replace-version-req.ts | 7 +++ 8 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 tests/specs/install/byonm_run_tag_after_install/__test__.jsonc create mode 100644 tests/specs/install/byonm_run_tag_after_install/deno.json create mode 100644 tests/specs/install/byonm_run_tag_after_install/main.ts create mode 100644 tests/specs/install/byonm_run_tag_after_install/node_modules_out_of_date.out create mode 100644 tests/specs/install/byonm_run_tag_after_install/package.json create mode 100644 tests/specs/install/byonm_run_tag_after_install/replace-version-req.ts diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index edc7c7ea0f..258c9bf3d5 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -343,6 +343,14 @@ async fn sync_resolution_with_fs( }, ); let packages_with_deprecation_warnings = Arc::new(Mutex::new(Vec::new())); + + let mut package_tags: HashMap<&PackageNv, Vec<&str>> = HashMap::new(); + for (package_req, package_nv) in snapshot.package_reqs() { + if let Some(tag) = package_req.version_req.tag() { + package_tags.entry(package_nv).or_default().push(tag); + } + } + for package in &package_partitions.packages { if let Some(current_pkg) = newest_packages_by_name.get_mut(&package.id.nv.name) @@ -357,11 +365,29 @@ async fn sync_resolution_with_fs( let package_folder_name = get_package_folder_id_folder_name(&package.get_package_cache_folder_id()); let folder_path = deno_local_registry_dir.join(&package_folder_name); + let tags = package_tags + .get(&package.id.nv) + .map(|tags| tags.join(",")) + .unwrap_or_default(); + enum PackageFolderState { + UpToDate, + Uninitialized, + TagsOutdated, + } let initialized_file = folder_path.join(".initialized"); + let package_state = std::fs::read_to_string(&initialized_file) + .map(|s| { + if s != tags { + PackageFolderState::TagsOutdated + } else { + PackageFolderState::UpToDate + } + }) + .unwrap_or(PackageFolderState::Uninitialized); if !cache .cache_setting() .should_use_for_npm_package(&package.id.nv.name) - || !initialized_file.exists() + || matches!(package_state, PackageFolderState::Uninitialized) { // cache bust the dep from the dep setup cache so the symlinks // are forced to be recreated @@ -371,6 +397,7 @@ async fn sync_resolution_with_fs( let bin_entries_to_setup = bin_entries.clone(); let packages_with_deprecation_warnings = packages_with_deprecation_warnings.clone(); + cache_futures.push(async move { tarball_cache .ensure_package(&package.id.nv, &package.dist) @@ -389,7 +416,7 @@ async fn sync_resolution_with_fs( move || { clone_dir_recursive(&cache_folder, &package_path)?; // write out a file that indicates this folder has been initialized - fs::write(initialized_file, "")?; + fs::write(initialized_file, tags)?; Ok::<_, AnyError>(()) } @@ -410,6 +437,8 @@ async fn sync_resolution_with_fs( drop(pb_guard); // explicit for clarity Ok::<_, AnyError>(()) }); + } else if matches!(package_state, PackageFolderState::TagsOutdated) { + fs::write(initialized_file, tags)?; } let sub_node_modules = folder_path.join("node_modules"); diff --git a/resolvers/deno/npm/byonm.rs b/resolvers/deno/npm/byonm.rs index 5bc4e62b2c..3394b3e501 100644 --- a/resolvers/deno/npm/byonm.rs +++ b/resolvers/deno/npm/byonm.rs @@ -253,7 +253,24 @@ impl ByonmNpmResolver { let Ok(version) = Version::parse_from_npm(version) else { continue; }; - if req.version_req.matches(&version) { + if let Some(tag) = req.version_req.tag() { + let initialized_file = + node_modules_deno_dir.join(&entry.name).join(".initialized"); + let Ok(contents) = self.fs.read_to_string_lossy(&initialized_file) + else { + continue; + }; + let mut tags = contents.split(',').map(str::trim); + if tags.any(|t| t == tag) { + if let Some((best_version_version, _)) = &best_version { + if version > *best_version_version { + best_version = Some((version, entry.name)); + } + } else { + best_version = Some((version, entry.name)); + } + } + } else if req.version_req.matches(&version) { if let Some((best_version_version, _)) = &best_version { if version > *best_version_version { best_version = Some((version, entry.name)); diff --git a/tests/specs/install/byonm_run_tag_after_install/__test__.jsonc b/tests/specs/install/byonm_run_tag_after_install/__test__.jsonc new file mode 100644 index 0000000000..3803fd26f7 --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/__test__.jsonc @@ -0,0 +1,44 @@ +{ + "tempDir": true, + + "tests": { + "tag_with_byonm": { + "steps": [ + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "run -A main.ts", + "output": "" + } + ] + }, + "no_tag_then_tag": { + "steps": [ + { + "args": "run -A replace-version-req.ts 1.0.0", + "output": "" + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { + "args": "run -A replace-version-req.ts latest", + "output": "" + }, + { + "args": "run -A main.ts", + "output": "node_modules_out_of_date.out", + "exitCode": 1 + }, + { + "args": "install", + "output": "[WILDCARD]" + }, + { "args": "run -A main.ts", "output": "" } + ] + } + } +} diff --git a/tests/specs/install/byonm_run_tag_after_install/deno.json b/tests/specs/install/byonm_run_tag_after_install/deno.json new file mode 100644 index 0000000000..13238b1697 --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/deno.json @@ -0,0 +1,5 @@ +{ + "imports": { + "@denotest/esm-basic": "npm:@denotest/esm-basic@latest" + } +} diff --git a/tests/specs/install/byonm_run_tag_after_install/main.ts b/tests/specs/install/byonm_run_tag_after_install/main.ts new file mode 100644 index 0000000000..7feb95f96a --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/main.ts @@ -0,0 +1 @@ +import { add } from "@denotest/esm-basic"; diff --git a/tests/specs/install/byonm_run_tag_after_install/node_modules_out_of_date.out b/tests/specs/install/byonm_run_tag_after_install/node_modules_out_of_date.out new file mode 100644 index 0000000000..2d7fc81d17 --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/node_modules_out_of_date.out @@ -0,0 +1,2 @@ +error: Could not find a matching package for 'npm:@denotest/esm-basic@latest' in the node_modules directory. Ensure you have all your JSR and npm dependencies listed in your deno.json or package.json, then run `deno install`. Alternatively, turn on auto-install by specifying `"nodeModulesDir": "auto"` in your deno.json file. + at [WILDCARD]main.ts:1:21 diff --git a/tests/specs/install/byonm_run_tag_after_install/package.json b/tests/specs/install/byonm_run_tag_after_install/package.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/package.json @@ -0,0 +1 @@ +{} diff --git a/tests/specs/install/byonm_run_tag_after_install/replace-version-req.ts b/tests/specs/install/byonm_run_tag_after_install/replace-version-req.ts new file mode 100644 index 0000000000..6f86ce2b71 --- /dev/null +++ b/tests/specs/install/byonm_run_tag_after_install/replace-version-req.ts @@ -0,0 +1,7 @@ +const newReq = Deno.args[0]?.trim(); +if (!newReq) { + throw new Error("Missing required argument"); +} +const config = JSON.parse(Deno.readTextFileSync("deno.json")); +config.imports["@denotest/esm-basic"] = `npm:@denotest/esm-basic@${newReq}`; +Deno.writeTextFileSync("deno.json", JSON.stringify(config)); From c7cba4eda73e000baa6bfbce6a156f9974edee36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 3 Oct 2024 02:24:18 +0100 Subject: [PATCH 10/39] v2.0.0-rc.10 (#26002) --- Cargo.lock | 2 +- cli/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a51f541dd..07c9db5030 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,7 +1166,7 @@ dependencies = [ [[package]] name = "deno" -version = "2.0.0-rc.9" +version = "2.0.0-rc.10" dependencies = [ "anstream", "async-trait", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 6167baa0b2..0a4dd78ff0 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno" -version = "2.0.0-rc.9" +version = "2.0.0-rc.10" authors.workspace = true default-run = "deno" edition.workspace = true From 93b29b5feb949e31b8ff90d1b78efbce94fe9b7c Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 09:00:11 +0530 Subject: [PATCH 11/39] fix: enable `Win32_Security` feature in `windows-sys` (#26007) Fixes https://github.com/denoland/deno/issues/25922 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 22f3575b98..769adb6d20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -225,7 +225,7 @@ nix = "=0.26.2" # windows deps junction = "=0.2.0" winapi = "=0.3.9" -windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry", "Win32_System_Kernel"] } +windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_Security", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry", "Win32_System_Kernel"] } winres = "=0.1.12" # NB: the `bench` and `release` profiles must remain EXACTLY the same. From f5caf9dd1b0f612e2a03e802d4dca41cb13a006b Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 09:33:00 +0530 Subject: [PATCH 12/39] perf: Use -O3 for sui in release builds (#26010) --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 769adb6d20..b121917ce7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -393,6 +393,8 @@ opt-level = 3 opt-level = 3 [profile.release.package.serde_v8] opt-level = 3 +[profile.release.package.libsui] +opt-level = 3 [profile.release.package.test_napi] opt-level = 3 [profile.release.package.tokio] From ac73b1042b4dda6416ad82d5468c57de6d53d038 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 3 Oct 2024 11:05:46 +0100 Subject: [PATCH 13/39] feat(permissions): allow importing from cdn.jsdelivr.net by default (#26013) The exploit `--allow-import` is preventing against requires a compromised host. To make things easier and given its popularity, we're going to have the default `--allow-import` value include `cdn.jsdelivr.net:443`, but this can be overridden by replacing the `--allow-import` value with something else. --- cli/args/flags.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cli/args/flags.rs b/cli/args/flags.rs index a4dcb9e91a..06ce507838 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -696,9 +696,10 @@ impl PermissionFlags { } let builtin_allowed_import_hosts = [ + "jsr.io:443", "deno.land:443", "esm.sh:443", - "jsr.io:443", + "cdn.jsdelivr.net:443", "raw.githubusercontent.com:443", "gist.githubusercontent.com:443", ]; @@ -3261,7 +3262,7 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command { -W, --allow-write[=<...] Allow file system write access. Optionally specify allowed paths. --allow-write | --allow-write="/etc,/var/log.txt" -I, --allow-import[=<...] Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. - Default value: deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443 + Default value: deno.land:443,jsr.io:443,esm.sh:443,cdn.jsdelivr.net:443,raw.githubusercontent.com:443,user.githubusercontent.com:443 --allow-import | --allow-import="example.com,github.com" -N, --allow-net[=<...] Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary. --allow-net | --allow-net="localhost:8080,deno.land" @@ -3671,7 +3672,7 @@ fn allow_import_arg() -> Arg { .require_equals(true) .value_name("IP_OR_HOSTNAME") .help(cstr!( - "Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. Default value: deno.land:443,jsr.io:443,esm.sh:443,raw.githubusercontent.com:443,user.githubusercontent.com:443" + "Allow importing from remote hosts. Optionally specify allowed IP addresses and host names, with ports as necessary. Default value: deno.land:443,jsr.io:443,esm.sh:443,cdn.jsdelivr.net:443,raw.githubusercontent.com:443,user.githubusercontent.com:443" )) .value_parser(flags_net::validator) } From e54809f2d56c8e91089d55d60e674cba37fd2863 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 16:46:48 +0530 Subject: [PATCH 14/39] fix(ext/crypto): fix identity test for x25519 derive bits (#26011) --- ext/crypto/x25519.rs | 4 +- tests/unit/webcrypto_test.ts | 40 +++++++++++++++++ tests/wpt/runner/expectation.json | 72 ++----------------------------- 3 files changed, 46 insertions(+), 70 deletions(-) diff --git a/ext/crypto/x25519.rs b/ext/crypto/x25519.rs index 8fcad3ef21..cdbd1d7c8f 100644 --- a/ext/crypto/x25519.rs +++ b/ext/crypto/x25519.rs @@ -47,10 +47,10 @@ pub fn op_crypto_derive_bits_x25519( let sh_sec = x25519_dalek::x25519(k, u); let point = MontgomeryPoint(sh_sec); if point.ct_eq(&MONTGOMERY_IDENTITY).unwrap_u8() == 1 { - return false; + return true; } secret.copy_from_slice(&sh_sec); - true + false } // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 } diff --git a/tests/unit/webcrypto_test.ts b/tests/unit/webcrypto_test.ts index 57aa19eaee..09552a0587 100644 --- a/tests/unit/webcrypto_test.ts +++ b/tests/unit/webcrypto_test.ts @@ -2045,3 +2045,43 @@ Deno.test(async function p521Generate() { assert(key.privateKey instanceof CryptoKey); assert(key.publicKey instanceof CryptoKey); }); + +Deno.test(async function x25519SharedSecret() { + const alicesKeyPair = await crypto.subtle.generateKey( + { + name: "X25519", + }, + false, + ["deriveBits"], + ) as CryptoKeyPair; + + const bobsKeyPair = await crypto.subtle.generateKey( + { + name: "X25519", + }, + false, + ["deriveBits"], + ) as CryptoKeyPair; + + const sharedSecret1 = await crypto.subtle.deriveBits( + { + name: "X25519", + public: bobsKeyPair.publicKey, + }, + alicesKeyPair.privateKey, + 128, + ); + + const sharedSecret2 = await crypto.subtle.deriveBits( + { + name: "X25519", + public: alicesKeyPair.publicKey, + }, + bobsKeyPair.privateKey, + 128, + ); + + assertEquals(sharedSecret1.byteLength, sharedSecret2.byteLength); + assertEquals(sharedSecret1.byteLength, 16); + assertEquals(new Uint8Array(sharedSecret1), new Uint8Array(sharedSecret2)); +}); diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index 4449c5d15e..f7da5e51f0 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -54,23 +54,12 @@ "pbkdf2.https.any.worker.html?7001-8000": true, "pbkdf2.https.any.worker.html?8001-last": true, "cfrg_curves_bits.https.any.html": [ - "X25519 key derivation checks for all-zero value result with a key of order 0", - "X25519 key derivation checks for all-zero value result with a key of order 1", - "X25519 key derivation checks for all-zero value result with a key of order 8", - "X25519 key derivation checks for all-zero value result with a key of order p-1 (order 2)", - "X25519 key derivation checks for all-zero value result with a key of order p (=0, order 4)", - "X25519 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", "X448 key derivation checks for all-zero value result with a key of order 0", "X448 key derivation checks for all-zero value result with a key of order 1", "X448 key derivation checks for all-zero value result with a key of order p-1 (order 2)", "X448 key derivation checks for all-zero value result with a key of order p (=0, order 4)", "X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", - "X25519 good parameters", - "X25519 mixed case parameters", - "X25519 short result", - "X25519 non-multiple of 8 bits", "X25519 mismatched algorithms", - "X25519 no deriveBits usage for base key", "X448 good parameters", "X448 mixed case parameters", "X448 short result", @@ -83,23 +72,12 @@ "X448 asking for too many bits" ], "cfrg_curves_bits.https.any.worker.html": [ - "X25519 key derivation checks for all-zero value result with a key of order 0", - "X25519 key derivation checks for all-zero value result with a key of order 1", - "X25519 key derivation checks for all-zero value result with a key of order 8", - "X25519 key derivation checks for all-zero value result with a key of order p-1 (order 2)", - "X25519 key derivation checks for all-zero value result with a key of order p (=0, order 4)", - "X25519 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", "X448 key derivation checks for all-zero value result with a key of order 0", "X448 key derivation checks for all-zero value result with a key of order 1", "X448 key derivation checks for all-zero value result with a key of order p-1 (order 2)", "X448 key derivation checks for all-zero value result with a key of order p (=0, order 4)", "X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", - "X25519 good parameters", - "X25519 mixed case parameters", - "X25519 short result", - "X25519 non-multiple of 8 bits", "X25519 mismatched algorithms", - "X25519 no deriveBits usage for base key", "X448 good parameters", "X448 mixed case parameters", "X448 short result", @@ -112,21 +90,12 @@ "X448 asking for too many bits" ], "cfrg_curves_keys.https.any.html": [ - "X25519 deriveBits checks for all-zero value result with a key of order 0", - "X25519 deriveBits checks for all-zero value result with a key of order 1", - "X25519 deriveBits checks for all-zero value result with a key of order 8", - "X25519 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", - "X25519 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", - "X25519 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", "X448 deriveBits checks for all-zero value result with a key of order 0", "X448 deriveBits checks for all-zero value result with a key of order 1", "X448 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", "X448 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", "X448 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", - "Key derivation using a X25519 generated keys.", "Key derivation using a X448 generated keys.", - "X25519 good parameters", - "X25519 mixed case parameters", "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", @@ -137,21 +106,12 @@ "X448 public property value is a secret key" ], "cfrg_curves_keys.https.any.worker.html": [ - "X25519 deriveBits checks for all-zero value result with a key of order 0", - "X25519 deriveBits checks for all-zero value result with a key of order 1", - "X25519 deriveBits checks for all-zero value result with a key of order 8", - "X25519 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", - "X25519 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", - "X25519 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", "X448 deriveBits checks for all-zero value result with a key of order 0", "X448 deriveBits checks for all-zero value result with a key of order 1", "X448 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", "X448 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", "X448 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", - "Key derivation using a X25519 generated keys.", "Key derivation using a X448 generated keys.", - "X25519 good parameters", - "X25519 mixed case parameters", "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", @@ -161,20 +121,8 @@ "X448 public property value is a private key", "X448 public property value is a secret key" ], - "derived_bits_length.https.any.html": [ - "X25519 derivation with 256 as 'length' parameter", - "X25519 derivation with 0 as 'length' parameter", - "X25519 derivation with null as 'length' parameter", - "X25519 derivation with undefined as 'length' parameter", - "X25519 derivation with omitted as 'length' parameter" - ], - "derived_bits_length.https.any.worker.html": [ - "X25519 derivation with 256 as 'length' parameter", - "X25519 derivation with 0 as 'length' parameter", - "X25519 derivation with null as 'length' parameter", - "X25519 derivation with undefined as 'length' parameter", - "X25519 derivation with omitted as 'length' parameter" - ] + "derived_bits_length.https.any.html": true, + "derived_bits_length.https.any.worker.html": true }, "digest": { "digest.https.any.html": true, @@ -1530,20 +1478,8 @@ "crypto-subtle-secure-context-available.https.sub.html": true }, "wrapKey_unwrapKey": { - "wrapKey_unwrapKey.https.any.html": [ - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CTR", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CBC", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-GCM", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-KW", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and RSA-OAEP" - ], - "wrapKey_unwrapKey.https.any.worker.html": [ - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CTR", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CBC", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-GCM", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-KW", - "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and RSA-OAEP" - ] + "wrapKey_unwrapKey.https.any.html": true, + "wrapKey_unwrapKey.https.any.worker.html": true } }, "console": { From 19a9990f60a7d38137af6239cfa3a7573b883d7d Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 16:48:40 +0530 Subject: [PATCH 15/39] chore: remove custom `bench` profile (#26008) --- Cargo.toml | 82 ------------------------------------------------------ 1 file changed, 82 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b121917ce7..c83543a944 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -228,7 +228,6 @@ winapi = "=0.3.9" windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Media", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_WindowsProgramming", "Wdk", "Wdk_System", "Wdk_System_SystemInformation", "Win32_Security", "Win32_System_Pipes", "Wdk_Storage_FileSystem", "Win32_System_Registry", "Win32_System_Kernel"] } winres = "=0.1.12" -# NB: the `bench` and `release` profiles must remain EXACTLY the same. [profile.release] codegen-units = 1 incremental = true @@ -246,13 +245,6 @@ inherits = "release" codegen-units = 128 lto = "thin" -# NB: the `bench` and `release` profiles must remain EXACTLY the same. -[profile.bench] -codegen-units = 1 -incremental = true -lto = true -opt-level = 'z' # Optimize for size - # Key generation is too slow on `debug` [profile.dev.package.num-bigint-dig] opt-level = 3 @@ -261,80 +253,6 @@ opt-level = 3 [profile.dev.package.v8] opt-level = 1 -# Optimize these packages for performance. -# NB: the `bench` and `release` profiles must remain EXACTLY the same. -[profile.bench.package.async-compression] -opt-level = 3 -[profile.bench.package.base64-simd] -opt-level = 3 -[profile.bench.package.brotli] -opt-level = 3 -[profile.bench.package.brotli-decompressor] -opt-level = 3 -[profile.bench.package.bytes] -opt-level = 3 -[profile.bench.package.deno_bench_util] -opt-level = 3 -[profile.bench.package.deno_broadcast_channel] -opt-level = 3 -[profile.bench.package.deno_core] -opt-level = 3 -[profile.bench.package.deno_crypto] -opt-level = 3 -[profile.bench.package.deno_fetch] -opt-level = 3 -[profile.bench.package.deno_ffi] -opt-level = 3 -[profile.bench.package.deno_http] -opt-level = 3 -[profile.bench.package.deno_napi] -opt-level = 3 -[profile.bench.package.deno_net] -opt-level = 3 -[profile.bench.package.deno_node] -opt-level = 3 -[profile.bench.package.deno_runtime] -opt-level = 3 -[profile.bench.package.deno_tls] -opt-level = 3 -[profile.bench.package.deno_url] -opt-level = 3 -[profile.bench.package.deno_web] -opt-level = 3 -[profile.bench.package.deno_websocket] -opt-level = 3 -[profile.bench.package.fastwebsockets] -opt-level = 3 -[profile.bench.package.flate2] -opt-level = 3 -[profile.bench.package.futures-util] -opt-level = 3 -[profile.bench.package.hyper] -opt-level = 3 -[profile.bench.package.miniz_oxide] -opt-level = 3 -[profile.bench.package.num-bigint-dig] -opt-level = 3 -[profile.bench.package.rand] -opt-level = 3 -[profile.bench.package.serde] -opt-level = 3 -[profile.bench.package.serde_v8] -opt-level = 3 -[profile.bench.package.test_napi] -opt-level = 3 -[profile.bench.package.tokio] -opt-level = 3 -[profile.bench.package.url] -opt-level = 3 -[profile.bench.package.v8] -opt-level = 3 -[profile.bench.package.zstd] -opt-level = 3 -[profile.bench.package.zstd-sys] -opt-level = 3 - -# NB: the `bench` and `release` profiles must remain EXACTLY the same. [profile.release.package.async-compression] opt-level = 3 [profile.release.package.base64-simd] From da7edf1c0c92dc8b0b746b015da911d5820c64ba Mon Sep 17 00:00:00 2001 From: Simon Lecoq <22963968+lowlighter@users.noreply.github.com> Date: Thu, 3 Oct 2024 08:28:38 -0400 Subject: [PATCH 16/39] fix: don't prompt when using `Deno.permissions.request` with `--no-prompt` (#25811) --- runtime/permissions/lib.rs | 7 ++++++- tests/integration/run_tests.rs | 16 ++++++++++++++++ .../testdata/run/permission_request_no_prompt.ts | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/testdata/run/permission_request_no_prompt.ts diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index 77038ff2fa..efabd0b171 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -476,6 +476,9 @@ impl UnaryPermission { if state != PermissionState::Prompt { return state; } + if !self.prompt { + return PermissionState::Denied; + } let mut message = String::with_capacity(40); message.push_str(&format!("{} access", TQuery::flag_name())); if let Some(desc) = desc { @@ -3906,7 +3909,8 @@ mod tests { fn test_request() { set_prompter(Box::new(TestPrompter)); let parser = TestPermissionDescriptorParser; - let mut perms: Permissions = Permissions::none_without_prompt(); + let mut perms: Permissions = Permissions::none_with_prompt(); + let mut perms_no_prompt: Permissions = Permissions::none_without_prompt(); let read_query = |path: &str| parser.parse_path_query(path).unwrap().into_read(); let write_query = @@ -3955,6 +3959,7 @@ mod tests { assert_eq!(perms.run.query(None), PermissionState::Prompt); prompt_value.set(false); assert_eq!(perms.run.request(Some(&run_query)), PermissionState::Granted); + assert_eq!(perms_no_prompt.read.request(Some(&read_query("/foo"))), PermissionState::Denied); }; } diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index 1e1d6ed61b..b3ad15c813 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -3512,6 +3512,22 @@ itest!(no_prompt_flag { output_str: Some(""), }); +#[test] +fn permission_request_with_no_prompt() { + TestContext::default() + .new_command() + .env("NO_COLOR", "1") + .args_vec([ + "run", + "--quiet", + "--no-prompt", + "run/permission_request_no_prompt.ts", + ]) + .with_pty(|mut console| { + console.expect("PermissionStatus { state: \"denied\", onchange: null }"); + }); +} + #[test] fn deno_no_prompt_environment_variable() { let output = util::deno_cmd() diff --git a/tests/testdata/run/permission_request_no_prompt.ts b/tests/testdata/run/permission_request_no_prompt.ts new file mode 100644 index 0000000000..e33ffe3ce8 --- /dev/null +++ b/tests/testdata/run/permission_request_no_prompt.ts @@ -0,0 +1 @@ +console.log(await Deno.permissions.request({ name: "read" })); From 54467015e0017a7a5fe9dd56eb21458325e2f3e9 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 18:31:36 +0530 Subject: [PATCH 17/39] chore: show expectation diff for wpt tests (#26014) Closes https://github.com/denoland/deno/issues/26012 ``` ======================================== failures: "/WebCryptoAPI/wrapKey_unwrapKey/wrapKey_unwrapKey.https.any.html - Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CTR" final result: failed. 1 passed; 1 failed; 0 expected failure; total 2 (15646ms) diff --git a/Users/divy/gh/deno/tests/wpt/runner/expectation.json b/var/folders/ll/ltqsx4nx72v5_r7rlsl36pgm0000gn/T/375d79f1257b05cd index fb2063935..4449c5d15 100644 --- a/Users/divy/gh/deno/tests/wpt/runner/expectation.json +++ b/var/folders/ll/ltqsx4nx72v5_r7rlsl36pgm0000gn/T/375d79f1257b05cd @@ -1531,6 +1531,7 @@ }, "wrapKey_unwrapKey": { "wrapKey_unwrapKey.https.any.html": [ + "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CTR", "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-CBC", "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-GCM", "Can wrap and unwrap X25519 private key keys as non-extractable using pkcs8 and AES-KW", ``` --- tests/wpt/runner/utils.ts | 21 ++++++++++++++++++--- tests/wpt/wpt.ts | 32 +++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/tests/wpt/runner/utils.ts b/tests/wpt/runner/utils.ts index 1674419cd1..140c388ec2 100644 --- a/tests/wpt/runner/utils.ts +++ b/tests/wpt/runner/utils.ts @@ -76,7 +76,10 @@ export function getManifest(): Manifest { /// WPT TEST EXPECTATIONS -const EXPECTATION_PATH = join(ROOT_PATH, "./tests/wpt/runner/expectation.json"); +export const EXPECTATION_PATH = join( + ROOT_PATH, + "./tests/wpt/runner/expectation.json", +); export interface Expectation { [key: string]: Expectation | boolean | string[] | { ignore: boolean }; @@ -87,9 +90,12 @@ export function getExpectation(): Expectation { return JSON.parse(expectationText); } -export function saveExpectation(expectation: Expectation) { +export function saveExpectation( + expectation: Expectation, + path: string = EXPECTATION_PATH, +) { Deno.writeTextFileSync( - EXPECTATION_PATH, + path, JSON.stringify(expectation, undefined, " ") + "\n", ); } @@ -134,6 +140,15 @@ export function runPy>( }).spawn(); } +export async function runGitDiff(args: string[]): string { + await new Deno.Command("git", { + args: ["diff", ...args], + stdout: "inherit", + stderr: "inherit", + cwd: ROOT_PATH, + }).output(); +} + export async function checkPy3Available() { const { success, stdout } = await runPy(["--version"], { stdout: "piped", diff --git a/tests/wpt/wpt.ts b/tests/wpt/wpt.ts index c42ff51e6e..b13a10cf4c 100755 --- a/tests/wpt/wpt.ts +++ b/tests/wpt/wpt.ts @@ -18,6 +18,7 @@ import { checkPy3Available, escapeLoneSurrogates, Expectation, + EXPECTATION_PATH, generateRunInfo, getExpectation, getExpectFailForCase, @@ -30,6 +31,7 @@ import { noIgnore, quiet, rest, + runGitDiff, runPy, updateManifest, wptreport, @@ -256,7 +258,16 @@ async function run() { await Deno.writeTextFile(wptreport, JSON.stringify(report) + "\n"); } + const newExpectations = newExpectation(results); + const tmp = Deno.makeTempFileSync(); + saveExpectation(newExpectations, tmp); + const code = reportFinal(results, endTime - startTime); + + // Run git diff to see what changed + await runGitDiff([EXPECTATION_PATH, tmp]); + Deno.removeSync(tmp); + Deno.exit(code); } @@ -390,6 +401,19 @@ async function update() { await Deno.writeTextFile(json, JSON.stringify(results) + "\n"); } + const newExpectations = newExpectation(results); + saveExpectation(newExpectations); + + reportFinal(results, endTime - startTime); + + console.log(blue("Updated expectation.json to match reality.")); + + Deno.exit(0); +} + +function newExpectation( + results: { test: TestToRun; result: TestResult }[], +): Expectation { const resultTests: Record< string, { passed: string[]; failed: string[]; testSucceeded: boolean } @@ -431,13 +455,7 @@ async function update() { ); } - saveExpectation(currentExpectation); - - reportFinal(results, endTime - startTime); - - console.log(blue("Updated expectation.json to match reality.")); - - Deno.exit(0); + return currentExpectation; } function insertExpectation( From 91860b34f52e498913e69bef3fc734fdf1ff817c Mon Sep 17 00:00:00 2001 From: David Sherret Date: Thu, 3 Oct 2024 14:07:12 +0100 Subject: [PATCH 18/39] fix(task): use current executable for deno even when not named deno (#26019) Closes https://github.com/denoland/deno/issues/26005 --- Cargo.lock | 4 ++-- cli/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07c9db5030..f26a7135d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2069,9 +2069,9 @@ dependencies = [ [[package]] name = "deno_task_shell" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6413ffc1654cad015edb5c4ab574069acdc929a6efafed23bc947901bcff1a" +checksum = "4f444918f7102c1a5a143e9d57809e499fb4d365070519bf2e8bdb16d586af2a" dependencies = [ "anyhow", "futures", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0a4dd78ff0..e0a4b4e7c1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -77,7 +77,7 @@ deno_path_util.workspace = true deno_resolver.workspace = true deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_semver.workspace = true -deno_task_shell = "=0.17.0" +deno_task_shell = "=0.18.1" deno_terminal.workspace = true eszip = "=0.79.1" libsui = "0.4.0" From e41df20ad9ba0e5acee028a161ab55b81987acb8 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Thu, 3 Oct 2024 19:48:36 +0530 Subject: [PATCH 19/39] fix(npm): root package has peer dependency on itself (#26022) https://github.com/denoland/deno_npm/pull/70 Fixes https://github.com/denoland/deno/issues/26006 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f26a7135d7..a679504108 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1899,9 +1899,9 @@ dependencies = [ [[package]] name = "deno_npm" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1809e2d77d8a06bc2800dc10c1d4acb664197e518e289a86e336411c1feba785" +checksum = "8050bcc2513046cbc0134ae1bc0f3b251a58b95012f3b81e0ea09a7f069c301b" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index c83543a944..734c3665e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ deno_core = { version = "0.311.0" } deno_bench_util = { version = "0.164.0", path = "./bench_util" } deno_lockfile = "=0.23.1" deno_media_type = { version = "0.1.4", features = ["module_specifier"] } -deno_npm = "=0.25.2" +deno_npm = "=0.25.3" deno_path_util = "=0.2.0" deno_permissions = { version = "0.30.0", path = "./runtime/permissions" } deno_runtime = { version = "0.179.0", path = "./runtime" } From 779a98cd39b781091427e68b1548d4f3189a8595 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Thu, 3 Oct 2024 21:56:55 +0530 Subject: [PATCH 20/39] tests: enable specs::run::package_json::invalid_value (#25826) Towards https://github.com/denoland/deno/issues/25241 Co-authored-by: David Sherret --- .../package_json/invalid_value/__test__.jsonc | 49 +++++++++++++++---- .../run/package_json/invalid_value/error.out | 2 + .../{error.ts.out => error_auto.out} | 3 ++ .../package_json/invalid_value/install.out | 3 ++ .../run/package_json/invalid_value/ok.ts.out | 3 -- .../run/package_json/invalid_value/task.out | 3 -- 6 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 tests/specs/run/package_json/invalid_value/error.out rename tests/specs/run/package_json/invalid_value/{error.ts.out => error_auto.out} (50%) create mode 100644 tests/specs/run/package_json/invalid_value/install.out diff --git a/tests/specs/run/package_json/invalid_value/__test__.jsonc b/tests/specs/run/package_json/invalid_value/__test__.jsonc index 7f85713cb5..0b3c63384b 100644 --- a/tests/specs/run/package_json/invalid_value/__test__.jsonc +++ b/tests/specs/run/package_json/invalid_value/__test__.jsonc @@ -1,23 +1,54 @@ { "tempDir": true, - // TODO(2.0): update the tests, should probably run install first - "ignore": true, "tests": { // should run fine when not referencing a failing dep entry - "run_ok": { - "args": "run ok.ts", + "run_ok_auto": { + "args": "run --quiet --node-modules-dir=auto ok.ts", "output": "ok.ts.out" }, + "run_ok_byonm": { + "steps": [ + { + "args": "install", + "output": "install.out" + }, + { + "args": "run ok.ts", + "output": "ok.ts.out" + } + ] + }, // should fail when referencing a failing dep entry - "run_error": { - "args": "run error.ts", + "run_error_auto": { + "args": "run --node-modules-dir=auto error.ts", "exitCode": 1, - "output": "error.ts.out" + "output": "error_auto.out" + }, + "run_error_byonm": { + "steps": [ + { + "args": "install", + "output": "install.out" + }, + { + "args": "run error.ts", + "exitCode": 1, + "output": "error.out" + } + ] }, // should output a warning about the failing dep entry "task_test": { - "args": "task test", - "output": "task.out" + "steps": [ + { + "args": "install", + "output": "install.out" + }, + { + "args": "task test", + "output": "task.out" + } + ] } } } diff --git a/tests/specs/run/package_json/invalid_value/error.out b/tests/specs/run/package_json/invalid_value/error.out new file mode 100644 index 0000000000..5975351131 --- /dev/null +++ b/tests/specs/run/package_json/invalid_value/error.out @@ -0,0 +1,2 @@ +error: Could not resolve "@denotest/cjs-default-export", but found it in a package.json. Deno expects the node_modules/ directory to be up to date. Did you forget to run `deno install`? + at file:///[WILDCARD]/error.ts:2:23 diff --git a/tests/specs/run/package_json/invalid_value/error.ts.out b/tests/specs/run/package_json/invalid_value/error_auto.out similarity index 50% rename from tests/specs/run/package_json/invalid_value/error.ts.out rename to tests/specs/run/package_json/invalid_value/error_auto.out index 37796d6da1..7641a4d863 100644 --- a/tests/specs/run/package_json/invalid_value/error.ts.out +++ b/tests/specs/run/package_json/invalid_value/error_auto.out @@ -1,3 +1,6 @@ +Download http://localhost:4260/@denotest/esm-basic +Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz +Initialize @denotest/esm-basic@1.0.0 error: Invalid version requirement 0: Unexpected character. invalid stuff that won't parse diff --git a/tests/specs/run/package_json/invalid_value/install.out b/tests/specs/run/package_json/invalid_value/install.out new file mode 100644 index 0000000000..b8114c12a0 --- /dev/null +++ b/tests/specs/run/package_json/invalid_value/install.out @@ -0,0 +1,3 @@ +Download http://localhost:4260/@denotest/esm-basic +Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz +Initialize @denotest/esm-basic@1.0.0 diff --git a/tests/specs/run/package_json/invalid_value/ok.ts.out b/tests/specs/run/package_json/invalid_value/ok.ts.out index e8fff7ed7a..0cfbf08886 100644 --- a/tests/specs/run/package_json/invalid_value/ok.ts.out +++ b/tests/specs/run/package_json/invalid_value/ok.ts.out @@ -1,4 +1 @@ -Download http://localhost:4260/@denotest/esm-basic -Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz -Initialize @denotest/esm-basic@1.0.0 2 diff --git a/tests/specs/run/package_json/invalid_value/task.out b/tests/specs/run/package_json/invalid_value/task.out index d0adb05256..79249d1757 100644 --- a/tests/specs/run/package_json/invalid_value/task.out +++ b/tests/specs/run/package_json/invalid_value/task.out @@ -1,5 +1,2 @@ -Download http://localhost:4260/@denotest/esm-basic -Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz -Initialize @denotest/esm-basic@1.0.0 Task test echo 1 1 From b8a9a4a862e4d61630c5bc8089261c7a177ec97a Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 4 Oct 2024 08:16:35 +0100 Subject: [PATCH 21/39] Revert "feat: warn when using --allow-run with no allow list" (#26021) Although using `--allow-run` without an allow list gives basically no security, I think we should remove this warning because it gets in the way and the only way to disable it is via --quiet. --- cli/args/mod.rs | 23 ------------------- .../deny_run_binary_absolute_path/main.out | 1 - .../__test__.jsonc | 8 ------- .../run/allow_run_insecure_warnings/main.ts | 0 .../no_allow_list.out | 1 - .../run/deny_some_permission_args.out | 1 - 6 files changed, 34 deletions(-) delete mode 100644 tests/specs/run/allow_run_insecure_warnings/__test__.jsonc delete mode 100644 tests/specs/run/allow_run_insecure_warnings/main.ts delete mode 100644 tests/specs/run/allow_run_insecure_warnings/no_allow_list.out diff --git a/cli/args/mod.rs b/cli/args/mod.rs index f0cce4ab1b..07906a86ac 100644 --- a/cli/args/mod.rs +++ b/cli/args/mod.rs @@ -825,8 +825,6 @@ impl CliOptions { } } - warn_insecure_allow_run_flags(&flags); - let maybe_lockfile = maybe_lockfile.filter(|_| !force_global_cache); let deno_dir_provider = Arc::new(DenoDirProvider::new(flags.internal.cache_path.clone())); @@ -1711,27 +1709,6 @@ impl CliOptions { } } -/// Warns for specific uses of `--allow-run`. This function is not -/// intended to catch every single possible insecure use of `--allow-run`, -/// but is just an attempt to discourage some common pitfalls. -fn warn_insecure_allow_run_flags(flags: &Flags) { - let permissions = &flags.permissions; - if permissions.allow_all { - return; - } - let Some(allow_run_list) = permissions.allow_run.as_ref() else { - return; - }; - - // discourage using --allow-run without an allow list - if allow_run_list.is_empty() { - log::warn!( - "{} --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/#running-subprocesses)", - colors::yellow("Warning") - ); - } -} - /// Resolves the path to use for a local node_modules folder. fn resolve_node_modules_folder( cwd: &Path, diff --git a/tests/specs/permission/deny_run_binary_absolute_path/main.out b/tests/specs/permission/deny_run_binary_absolute_path/main.out index fef29eae75..45b2283879 100644 --- a/tests/specs/permission/deny_run_binary_absolute_path/main.out +++ b/tests/specs/permission/deny_run_binary_absolute_path/main.out @@ -1,4 +1,3 @@ -Warning --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/#running-subprocesses) NotCapable: Requires run access to "deno", run again with the --allow-run flag at [WILDCARD] { name: "NotCapable" diff --git a/tests/specs/run/allow_run_insecure_warnings/__test__.jsonc b/tests/specs/run/allow_run_insecure_warnings/__test__.jsonc deleted file mode 100644 index b64146ee95..0000000000 --- a/tests/specs/run/allow_run_insecure_warnings/__test__.jsonc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "tests": { - "no_allow_list": { - "args": "run --allow-run main.ts", - "output": "no_allow_list.out" - } - } -} diff --git a/tests/specs/run/allow_run_insecure_warnings/main.ts b/tests/specs/run/allow_run_insecure_warnings/main.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/specs/run/allow_run_insecure_warnings/no_allow_list.out b/tests/specs/run/allow_run_insecure_warnings/no_allow_list.out deleted file mode 100644 index 293b4446ad..0000000000 --- a/tests/specs/run/allow_run_insecure_warnings/no_allow_list.out +++ /dev/null @@ -1 +0,0 @@ -Warning --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/#running-subprocesses) diff --git a/tests/testdata/run/deny_some_permission_args.out b/tests/testdata/run/deny_some_permission_args.out index be2e832fec..abb5274eed 100644 --- a/tests/testdata/run/deny_some_permission_args.out +++ b/tests/testdata/run/deny_some_permission_args.out @@ -1,4 +1,3 @@ -Warning --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/#running-subprocesses) PermissionStatus { state: "granted", onchange: null, partial: true } PermissionStatus { state: "denied", onchange: null } PermissionStatus { state: "granted", onchange: null } From edac9166040dc09674072ce57af6a9c5ea958d85 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 4 Oct 2024 08:52:00 +0100 Subject: [PATCH 22/39] fix(install): surface package.json dependency errors (#26023) --- cli/args/flags.rs | 2 + cli/args/package_json.rs | 20 ++++++-- cli/npm/managed/mod.rs | 21 +++++++++ cli/tools/installer.rs | 4 ++ cli/tools/registry/pm.rs | 33 +++++++++---- cli/tools/registry/pm/cache_deps.rs | 1 + .../package_json/invalid_value/__test__.jsonc | 46 +++++-------------- .../run/package_json/invalid_value/add.out | 8 ++++ .../package_json/invalid_value/install.out | 10 ++-- .../run/package_json/invalid_value/task.out | 3 ++ 10 files changed, 96 insertions(+), 52 deletions(-) create mode 100644 tests/specs/run/package_json/invalid_value/add.out diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 06ce507838..258712ca92 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -2910,6 +2910,7 @@ List all available tasks: .help("Specify the directory to run the task in") .value_hint(ValueHint::DirPath), ) + .arg(node_modules_dir_arg()) }) } @@ -4974,6 +4975,7 @@ fn task_parse(flags: &mut Flags, matches: &mut ArgMatches) { .unwrap_or(ConfigFlag::Discover); unstable_args_parse(flags, matches, UnstableArgsConfig::ResolutionAndRuntime); + node_modules_arg_parse(flags, matches); let mut task_flags = TaskFlags { cwd: matches.remove_one::("cwd"), diff --git a/cli/args/package_json.rs b/cli/args/package_json.rs index 2529e54fdf..2ef39a30d2 100644 --- a/cli/args/package_json.rs +++ b/cli/args/package_json.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use deno_config::workspace::Workspace; use deno_core::serde_json; use deno_package_json::PackageJsonDepValue; +use deno_package_json::PackageJsonDepValueParseError; use deno_semver::npm::NpmPackageReqReference; use deno_semver::package::PackageReq; @@ -26,6 +27,7 @@ pub struct InstallNpmWorkspacePkg { pub struct NpmInstallDepsProvider { remote_pkgs: Vec, workspace_pkgs: Vec, + pkg_json_dep_errors: Vec, } impl NpmInstallDepsProvider { @@ -37,6 +39,7 @@ impl NpmInstallDepsProvider { // todo(dsherret): estimate capacity? let mut workspace_pkgs = Vec::new(); let mut remote_pkgs = Vec::new(); + let mut pkg_json_dep_errors = Vec::new(); let workspace_npm_pkgs = workspace.npm_packages(); for (_, folder) in workspace.config_folders() { @@ -83,8 +86,12 @@ impl NpmInstallDepsProvider { let deps = pkg_json.resolve_local_package_json_deps(); let mut pkg_pkgs = Vec::with_capacity(deps.len()); for (alias, dep) in deps { - let Ok(dep) = dep else { - continue; + let dep = match dep { + Ok(dep) => dep, + Err(err) => { + pkg_json_dep_errors.push(err); + continue; + } }; match dep { PackageJsonDepValue::Req(pkg_req) => { @@ -131,14 +138,19 @@ impl NpmInstallDepsProvider { Self { remote_pkgs, workspace_pkgs, + pkg_json_dep_errors, } } - pub fn remote_pkgs(&self) -> &Vec { + pub fn remote_pkgs(&self) -> &[InstallNpmRemotePkg] { &self.remote_pkgs } - pub fn workspace_pkgs(&self) -> &Vec { + pub fn workspace_pkgs(&self) -> &[InstallNpmWorkspacePkg] { &self.workspace_pkgs } + + pub fn pkg_json_dep_errors(&self) -> &[PackageJsonDepValueParseError] { + &self.pkg_json_dep_errors + } } diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index 7bb254cb52..225cd6c29c 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -20,6 +20,7 @@ use deno_npm::resolution::ValidSerializedNpmResolutionSnapshot; use deno_npm::NpmPackageId; use deno_npm::NpmResolutionPackage; use deno_npm::NpmSystemInfo; +use deno_runtime::colors; use deno_runtime::deno_fs::FileSystem; use deno_runtime::deno_node::NodePermissions; use deno_runtime::deno_node::NodeRequireResolver; @@ -478,6 +479,25 @@ impl ManagedCliNpmResolver { self.resolution.resolve_pkg_id_from_pkg_req(req) } + pub fn ensure_no_pkg_json_dep_errors(&self) -> Result<(), AnyError> { + for err in self.npm_install_deps_provider.pkg_json_dep_errors() { + match err { + deno_package_json::PackageJsonDepValueParseError::VersionReq(_) => { + return Err( + AnyError::from(err.clone()) + .context("Failed to install from package.json"), + ); + } + deno_package_json::PackageJsonDepValueParseError::Unsupported { + .. + } => { + log::warn!("{} {} in package.json", colors::yellow("Warning"), err) + } + } + } + Ok(()) + } + /// Ensures that the top level `package.json` dependencies are installed. /// This may set up the `node_modules` directory. /// @@ -489,6 +509,7 @@ impl ManagedCliNpmResolver { if !self.top_level_install_flag.raise() { return Ok(false); // already did this } + let pkg_json_remote_pkgs = self.npm_install_deps_provider.remote_pkgs(); if pkg_json_remote_pkgs.is_empty() { return Ok(false); diff --git a/cli/tools/installer.rs b/cli/tools/installer.rs index bc8769de1c..ed86e86c79 100644 --- a/cli/tools/installer.rs +++ b/cli/tools/installer.rs @@ -298,6 +298,10 @@ async fn install_local( } InstallFlagsLocal::TopLevel => { let factory = CliFactory::from_flags(flags); + // surface any errors in the package.json + if let Some(npm_resolver) = factory.npm_resolver().await?.as_managed() { + npm_resolver.ensure_no_pkg_json_dep_errors()?; + } crate::tools::registry::cache_top_level_deps(&factory, None).await?; if let Some(lockfile) = factory.cli_options()?.maybe_lockfile() { diff --git a/cli/tools/registry/pm.rs b/cli/tools/registry/pm.rs index c92710f460..f56774e8eb 100644 --- a/cli/tools/registry/pm.rs +++ b/cli/tools/registry/pm.rs @@ -558,12 +558,7 @@ pub async fn add( result.context("Failed to update configuration file")?; } - // clear the previously cached package.json from memory before reloading it - node_resolver::PackageJsonThreadLocalCache::clear(); - // make a new CliFactory to pick up the updated config file - let cli_factory = CliFactory::from_flags(flags); - // cache deps - cache_deps::cache_top_level_deps(&cli_factory, Some(jsr_resolver)).await?; + npm_install_after_modification(flags, Some(jsr_resolver)).await?; Ok(()) } @@ -786,15 +781,33 @@ pub async fn remove( config.commit().await?; } - // Update deno.lock - node_resolver::PackageJsonThreadLocalCache::clear(); - let cli_factory = CliFactory::from_flags(flags); - cache_deps::cache_top_level_deps(&cli_factory, None).await?; + npm_install_after_modification(flags, None).await?; } Ok(()) } +async fn npm_install_after_modification( + flags: Arc, + // explicitly provided to prevent redownloading + jsr_resolver: Option>, +) -> Result<(), AnyError> { + // clear the previously cached package.json from memory before reloading it + node_resolver::PackageJsonThreadLocalCache::clear(); + + // make a new CliFactory to pick up the updated config file + let cli_factory = CliFactory::from_flags(flags); + // surface any errors in the package.json + let npm_resolver = cli_factory.npm_resolver().await?; + if let Some(npm_resolver) = npm_resolver.as_managed() { + npm_resolver.ensure_no_pkg_json_dep_errors()?; + } + // npm install + cache_deps::cache_top_level_deps(&cli_factory, jsr_resolver).await?; + + Ok(()) +} + fn update_config_file_content< I: IntoIterator)>, >( diff --git a/cli/tools/registry/pm/cache_deps.rs b/cli/tools/registry/pm/cache_deps.rs index 7d1773b343..c8258e6009 100644 --- a/cli/tools/registry/pm/cache_deps.rs +++ b/cli/tools/registry/pm/cache_deps.rs @@ -11,6 +11,7 @@ use deno_core::futures::StreamExt; use deno_semver::package::PackageReq; pub async fn cache_top_level_deps( + // todo(dsherret): don't pass the factory into this function. Instead use ctor deps factory: &CliFactory, jsr_resolver: Option>, ) -> Result<(), AnyError> { diff --git a/tests/specs/run/package_json/invalid_value/__test__.jsonc b/tests/specs/run/package_json/invalid_value/__test__.jsonc index 0b3c63384b..195734d95f 100644 --- a/tests/specs/run/package_json/invalid_value/__test__.jsonc +++ b/tests/specs/run/package_json/invalid_value/__test__.jsonc @@ -6,49 +6,25 @@ "args": "run --quiet --node-modules-dir=auto ok.ts", "output": "ok.ts.out" }, - "run_ok_byonm": { - "steps": [ - { - "args": "install", - "output": "install.out" - }, - { - "args": "run ok.ts", - "output": "ok.ts.out" - } - ] - }, // should fail when referencing a failing dep entry "run_error_auto": { "args": "run --node-modules-dir=auto error.ts", "exitCode": 1, "output": "error_auto.out" }, - "run_error_byonm": { - "steps": [ - { - "args": "install", - "output": "install.out" - }, - { - "args": "run error.ts", - "exitCode": 1, - "output": "error.out" - } - ] + "install_error_byonm": { + "args": "install", + "output": "install.out", + "exitCode": 1 + }, + "add_error_byonm": { + "args": "add npm:cowsay", + "output": "add.out", + "exitCode": 1 }, - // should output a warning about the failing dep entry "task_test": { - "steps": [ - { - "args": "install", - "output": "install.out" - }, - { - "args": "task test", - "output": "task.out" - } - ] + "args": "task --node-modules-dir=auto test", + "output": "task.out" } } } diff --git a/tests/specs/run/package_json/invalid_value/add.out b/tests/specs/run/package_json/invalid_value/add.out new file mode 100644 index 0000000000..9b7493c1a2 --- /dev/null +++ b/tests/specs/run/package_json/invalid_value/add.out @@ -0,0 +1,8 @@ +Add npm:cowsay@1.5.0 +error: Failed to install from package.json + +Caused by: + 0: Invalid version requirement + 1: Unexpected character. + invalid stuff that won't parse + ~ diff --git a/tests/specs/run/package_json/invalid_value/install.out b/tests/specs/run/package_json/invalid_value/install.out index b8114c12a0..cc82b345b0 100644 --- a/tests/specs/run/package_json/invalid_value/install.out +++ b/tests/specs/run/package_json/invalid_value/install.out @@ -1,3 +1,7 @@ -Download http://localhost:4260/@denotest/esm-basic -Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz -Initialize @denotest/esm-basic@1.0.0 +error: Failed to install from package.json + +Caused by: + 0: Invalid version requirement + 1: Unexpected character. + invalid stuff that won't parse + ~ diff --git a/tests/specs/run/package_json/invalid_value/task.out b/tests/specs/run/package_json/invalid_value/task.out index 79249d1757..d0adb05256 100644 --- a/tests/specs/run/package_json/invalid_value/task.out +++ b/tests/specs/run/package_json/invalid_value/task.out @@ -1,2 +1,5 @@ +Download http://localhost:4260/@denotest/esm-basic +Download http://localhost:4260/@denotest/esm-basic/1.0.0.tgz +Initialize @denotest/esm-basic@1.0.0 Task test echo 1 1 From 7b509e492ed6c7ace0f3860c3f4e8e7be3452fda Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Fri, 4 Oct 2024 15:26:13 +0530 Subject: [PATCH 23/39] tests: enable package_json_node_modules_none (#25825) Co-authored-by: David Sherret --- tests/integration/task_tests.rs | 13 ------------- .../__test__.jsonc | 6 ++++++ .../task/package_json_node_modules_dir_none/bin.out | 8 ++++++++ .../package_json_node_modules_dir_none/deno.json | 3 +++ .../package.json | 2 +- .../package_json_node_modules_dir_false/bin.out | 2 -- .../package_json_node_modules_dir_false/deno.json | 3 --- tools/lint.js | 2 +- 8 files changed, 19 insertions(+), 20 deletions(-) create mode 100644 tests/specs/task/package_json_node_modules_dir_none/__test__.jsonc create mode 100644 tests/specs/task/package_json_node_modules_dir_none/bin.out create mode 100644 tests/specs/task/package_json_node_modules_dir_none/deno.json rename tests/{testdata/task/package_json_node_modules_dir_false => specs/task/package_json_node_modules_dir_none}/package.json (67%) delete mode 100644 tests/testdata/task/package_json_node_modules_dir_false/bin.out delete mode 100644 tests/testdata/task/package_json_node_modules_dir_false/deno.json diff --git a/tests/integration/task_tests.rs b/tests/integration/task_tests.rs index d198a3be6f..56bab2970d 100644 --- a/tests/integration/task_tests.rs +++ b/tests/integration/task_tests.rs @@ -18,19 +18,6 @@ // http_server: true, // }); -// TODO(2.0): decide what to do with this test -// should not auto-install the packages in the package.json -// when using nodeModulesDir: false -// itest!(task_package_json_node_modules_dir_false { -// args: "task echo", -// cwd: Some("task/package_json_node_modules_dir_false/"), -// output: "task/package_json_node_modules_dir_false/bin.out", -// copy_temp_dir: Some("task/package_json_node_modules_dir_false/"), -// envs: env_vars_for_npm_tests(), -// exit_code: 0, -// http_server: true, -// }); - // TODO(2.0): not entirely clear what's wrong with this test but it hangs for more than 60s // itest!(task_npx_on_own { // args: "task on-own", diff --git a/tests/specs/task/package_json_node_modules_dir_none/__test__.jsonc b/tests/specs/task/package_json_node_modules_dir_none/__test__.jsonc new file mode 100644 index 0000000000..21d9d73ba0 --- /dev/null +++ b/tests/specs/task/package_json_node_modules_dir_none/__test__.jsonc @@ -0,0 +1,6 @@ +{ + "tempDir": true, + "args": "task echo", + "output": "bin.out", + "exitCode": 0 +} diff --git a/tests/specs/task/package_json_node_modules_dir_none/bin.out b/tests/specs/task/package_json_node_modules_dir_none/bin.out new file mode 100644 index 0000000000..c86261d9e1 --- /dev/null +++ b/tests/specs/task/package_json_node_modules_dir_none/bin.out @@ -0,0 +1,8 @@ +[UNORDERED_START] +Download http://localhost:4260/@denotest/bin +Download http://localhost:4260/@denotest/bin/1.0.0.tgz +Download http://localhost:4260/@denotest/bin/0.5.0.tgz +[UNORDERED_END] +Task echo deno eval 'console.log(1)' && cli-esm hi +1 +hi diff --git a/tests/specs/task/package_json_node_modules_dir_none/deno.json b/tests/specs/task/package_json_node_modules_dir_none/deno.json new file mode 100644 index 0000000000..38af4024b0 --- /dev/null +++ b/tests/specs/task/package_json_node_modules_dir_none/deno.json @@ -0,0 +1,3 @@ +{ + "nodeModulesDir": "none" +} diff --git a/tests/testdata/task/package_json_node_modules_dir_false/package.json b/tests/specs/task/package_json_node_modules_dir_none/package.json similarity index 67% rename from tests/testdata/task/package_json_node_modules_dir_false/package.json rename to tests/specs/task/package_json_node_modules_dir_none/package.json index 081e076b9f..713a9dc5b4 100644 --- a/tests/testdata/task/package_json_node_modules_dir_false/package.json +++ b/tests/specs/task/package_json_node_modules_dir_none/package.json @@ -1,6 +1,6 @@ { "scripts": { - "echo": "deno eval 'console.log(1)'" + "echo": "deno eval 'console.log(1)' && cli-esm hi" }, "dependencies": { "@denotest/bin": "0.5", diff --git a/tests/testdata/task/package_json_node_modules_dir_false/bin.out b/tests/testdata/task/package_json_node_modules_dir_false/bin.out deleted file mode 100644 index d5d59d5515..0000000000 --- a/tests/testdata/task/package_json_node_modules_dir_false/bin.out +++ /dev/null @@ -1,2 +0,0 @@ -Task echo deno eval 'console.log(1)' -1 diff --git a/tests/testdata/task/package_json_node_modules_dir_false/deno.json b/tests/testdata/task/package_json_node_modules_dir_false/deno.json deleted file mode 100644 index 23a325cfc2..0000000000 --- a/tests/testdata/task/package_json_node_modules_dir_false/deno.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "nodeModulesDir": false -} diff --git a/tools/lint.js b/tools/lint.js index edf800c4e1..1f3f56498b 100755 --- a/tools/lint.js +++ b/tools/lint.js @@ -220,7 +220,7 @@ async function ensureNoNewITests() { "repl_tests.rs": 0, "run_tests.rs": 331, "shared_library_tests.rs": 0, - "task_tests.rs": 3, + "task_tests.rs": 2, "test_tests.rs": 0, "upgrade_tests.rs": 0, "vendor_tests.rs": 1, From dd8cbf5e29d9949e3adac9b9d8ce5fb73b5b0ad0 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Fri, 4 Oct 2024 09:26:32 -0700 Subject: [PATCH 24/39] fix(node): fix worker_threads issues blocking Angular support (#26024) Fixes #22995. Fixes #23000. There were a handful of bugs here causing the hang (each with a corresponding minimized test): - We were canceling recv futures when `receiveMessageOnPort` was called, but this caused the "receive loop" in the message port to exit. This was due to the fact that `CancelHandle`s are never reset (i.e., once you `cancel` a `CancelHandle`, it remains cancelled). That meant that after `receieveMessageOnPort` was called, the subsequent calls to `op_message_port_recv_message` would throw `Interrupted` exceptions, and we would exit the loop. The cancellation, however, isn't actually necessary. `op_message_port_recv_message` only borrows the underlying port for long enough to poll the receiver, so the borrow there could never overlap with `op_message_port_recv_message_sync`. - Calling `MessagePort.unref()` caused the "receive loop" in the message port to exit. This was because we were setting `messageEventListenerCount` to 0 on unref. Not only does that break the counter when multiple `MessagePort`s are present in the same thread, but we also exited the "receive loop" whenever the listener count was 0. I assume this was to prevent the recv promise from keeping the event loop open. Instead of this, I chose to just unref the recv promise as needed to control the event loop. - The last bug causing the hang (which was a doozy to debug) ended up being an unfortunate interaction between how we implement our messageport "receive loop" and a pattern found in `npm:piscina` (which angular uses). The gist of it is that piscina uses an atomic wait loop along with `receiveMessageOnPort` in its worker threads, and as the worker is getting started, the following incredibly convoluted series of events occurs: 1. Parent sends a MessagePort `p` to worker 2. Parent sends a message `m` to the port `p` 3. Parent notifies the worker with `Atomics.notify` that a new message is available 4. Worker receives message, adds "message" listener to port `p` 5. Adding the listener triggers `MessagePort.start()` on `p` 6. Receive loop in MessagePort.start receives the message `m`, but then hits an await point and yields (before dispatching the "message" event) 7. Worker continues execution, starts the atomic wait loop, and immediately receives the existing notification from the parent that a message is available 8. Worker attempts to receive the new message `m` with `receiveMessageOnPort`, but this returns `undefined` because the receive loop already took the message in 6 9. Atomic wait loop continues to next iteration, waiting for the next message with `Atomic.wait` 10. `Atomic.wait` blocks the worker thread, which prevents the receive loop from continuing and dispatching the "message" event for the received message 11. The parent waits for the worker to respond to the first message, and waits 12. The thread can't make any more progress, and the whole process hangs The fix I've chosen here (which I don't particularly love, but it works) is to just delay the `MessagePort.start` call until the end of the event loop turn, so that the atomic wait loop receives the message first. This prevents the hang. --- Those were the main issues causing the hang. There ended up being a few other small bugs as well, namely `exit` being emitted multiple times, and not patching up the message port when it's received by `receiveMessageOnPort`. --- ext/node/polyfills/worker_threads.ts | 12 +- ext/web/13_message_port.js | 88 ++++++++--- ext/web/message_port.rs | 1 - runtime/js/99_main.js | 5 +- tests/unit_node/worker_threads_test.ts | 201 +++++++++++++++++++++++++ 5 files changed, 278 insertions(+), 29 deletions(-) diff --git a/ext/node/polyfills/worker_threads.ts b/ext/node/polyfills/worker_threads.ts index 5ff4446f73..d4b75fb30c 100644 --- a/ext/node/polyfills/worker_threads.ts +++ b/ext/node/polyfills/worker_threads.ts @@ -302,8 +302,8 @@ class NodeWorker extends EventEmitter { if (this.#status !== "TERMINATED") { this.#status = "TERMINATED"; op_host_terminate_worker(this.#id); + this.emit("exit", 0); } - this.emit("exit", 0); return PromiseResolve(0); } @@ -422,7 +422,11 @@ internals.__initWorkerThreads = ( parentPort.once = function (this: ParentPort, name, listener) { // deno-lint-ignore no-explicit-any - const _listener = (ev: any) => listener(ev.data); + const _listener = (ev: any) => { + const message = ev.data; + patchMessagePortIfFound(message); + return listener(message); + }; listeners.set(listener, _listener); this.addEventListener(name, _listener); return this; @@ -494,7 +498,9 @@ export function receiveMessageOnPort(port: MessagePort): object | undefined { port[MessagePortReceiveMessageOnPortSymbol] = true; const data = op_message_port_recv_message_sync(port[MessagePortIdSymbol]); if (data === null) return undefined; - return { message: deserializeJsMessageData(data)[0] }; + const message = deserializeJsMessageData(data)[0]; + patchMessagePortIfFound(message); + return { message }; } class NodeMessageChannel { diff --git a/ext/web/13_message_port.js b/ext/web/13_message_port.js index 04697d6aa8..cf72c43e6f 100644 --- a/ext/web/13_message_port.js +++ b/ext/web/13_message_port.js @@ -22,6 +22,7 @@ const { Symbol, SymbolFor, SymbolIterator, + PromiseResolve, SafeArrayIterator, TypeError, } = primordials; @@ -41,7 +42,10 @@ import { import { isDetachedBuffer } from "./06_streams.js"; import { DOMException } from "./01_dom_exception.js"; -let messageEventListenerCount = 0; +// counter of how many message ports are actively refed +// either due to the existence of "message" event listeners or +// explicit calls to ref/unref (in the case of node message ports) +let refedMessagePortsCount = 0; class MessageChannel { /** @type {MessagePort} */ @@ -93,6 +97,7 @@ const MessagePortReceiveMessageOnPortSymbol = Symbol( ); const _enabled = Symbol("enabled"); const _refed = Symbol("refed"); +const _messageEventListenerCount = Symbol("messageEventListenerCount"); const nodeWorkerThreadCloseCb = Symbol("nodeWorkerThreadCloseCb"); const nodeWorkerThreadCloseCbInvoked = Symbol("nodeWorkerThreadCloseCbInvoked"); export const refMessagePort = Symbol("refMessagePort"); @@ -109,6 +114,9 @@ function createMessagePort(id) { port[core.hostObjectBrand] = core.hostObjectBrand; setEventTargetData(port); port[_id] = id; + port[_enabled] = false; + port[_messageEventListenerCount] = 0; + port[_refed] = false; return port; } @@ -122,12 +130,18 @@ function nodeWorkerThreadMaybeInvokeCloseCb(port) { } } +const _isRefed = Symbol("isRefed"); +const _dataPromise = Symbol("dataPromise"); + class MessagePort extends EventTarget { /** @type {number | null} */ [_id] = null; /** @type {boolean} */ [_enabled] = false; [_refed] = false; + /** @type {Promise | undefined} */ + [_dataPromise] = undefined; + [_messageEventListenerCount] = 0; constructor() { super(); @@ -193,24 +207,21 @@ class MessagePort extends EventTarget { this[_enabled] = true; while (true) { if (this[_id] === null) break; - // Exit if no message event listeners are present in Node compat mode. - if ( - typeof this[nodeWorkerThreadCloseCb] == "function" && - messageEventListenerCount === 0 - ) break; let data; try { - data = await op_message_port_recv_message( + this[_dataPromise] = op_message_port_recv_message( this[_id], ); + if ( + typeof this[nodeWorkerThreadCloseCb] === "function" && + !this[_refed] + ) { + core.unrefOpPromise(this[_dataPromise]); + } + data = await this[_dataPromise]; + this[_dataPromise] = undefined; } catch (err) { if (ObjectPrototypeIsPrototypeOf(InterruptedPrototype, err)) { - // If we were interrupted, check if the interruption is coming - // from `receiveMessageOnPort` API from Node compat, if so, continue. - if (this[MessagePortReceiveMessageOnPortSymbol]) { - this[MessagePortReceiveMessageOnPortSymbol] = false; - continue; - } break; } nodeWorkerThreadMaybeInvokeCloseCb(this); @@ -246,12 +257,26 @@ class MessagePort extends EventTarget { } [refMessagePort](ref) { - if (ref && !this[_refed]) { - this[_refed] = true; - messageEventListenerCount++; - } else if (!ref && this[_refed]) { - this[_refed] = false; - messageEventListenerCount = 0; + if (ref) { + if (!this[_refed]) { + refedMessagePortsCount++; + if ( + this[_dataPromise] + ) { + core.refOpPromise(this[_dataPromise]); + } + this[_refed] = true; + } + } else if (!ref) { + if (this[_refed]) { + refedMessagePortsCount--; + if ( + this[_dataPromise] + ) { + core.unrefOpPromise(this[_dataPromise]); + } + this[_refed] = false; + } } } @@ -266,15 +291,20 @@ class MessagePort extends EventTarget { removeEventListener(...args) { if (args[0] == "message") { - messageEventListenerCount--; + if (--this[_messageEventListenerCount] === 0 && this[_refed]) { + refedMessagePortsCount--; + this[_refed] = false; + } } super.removeEventListener(...new SafeArrayIterator(args)); } addEventListener(...args) { if (args[0] == "message") { - messageEventListenerCount++; - if (!this[_refed]) this[_refed] = true; + if (++this[_messageEventListenerCount] === 1 && !this[_refed]) { + refedMessagePortsCount++; + this[_refed] = true; + } } super.addEventListener(...new SafeArrayIterator(args)); } @@ -295,7 +325,17 @@ class MessagePort extends EventTarget { } defineEventHandler(MessagePort.prototype, "message", function (self) { - self.start(); + if (self[nodeWorkerThreadCloseCb]) { + (async () => { + // delay `start()` until he end of this event loop turn, to give `receiveMessageOnPort` + // a chance to receive a message first. this is primarily to resolve an issue with + // a pattern used in `npm:piscina` that results in an indefinite hang + await PromiseResolve(); + self.start(); + })(); + } else { + self.start(); + } }); defineEventHandler(MessagePort.prototype, "messageerror"); @@ -463,12 +503,12 @@ function structuredClone(value, options) { export { deserializeJsMessageData, MessageChannel, - messageEventListenerCount, MessagePort, MessagePortIdSymbol, MessagePortPrototype, MessagePortReceiveMessageOnPortSymbol, nodeWorkerThreadCloseCb, + refedMessagePortsCount, serializeJsMessageData, structuredClone, }; diff --git a/ext/web/message_port.rs b/ext/web/message_port.rs index c069037f81..fa299475d9 100644 --- a/ext/web/message_port.rs +++ b/ext/web/message_port.rs @@ -239,7 +239,6 @@ pub fn op_message_port_recv_message_sync( #[smi] rid: ResourceId, ) -> Result, AnyError> { let resource = state.resource_table.get::(rid)?; - resource.cancel.cancel(); let mut rx = resource.port.rx.borrow_mut(); match rx.try_recv() { diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 0da2072b84..56a5b411bb 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -169,8 +169,11 @@ let isClosing = false; let globalDispatchEvent; function hasMessageEventListener() { + // the function name is kind of a misnomer, but we want to behave + // as if we have message event listeners if a node message port is explicitly + // refed (and the inverse as well) return event.listenerCount(globalThis, "message") > 0 || - messagePort.messageEventListenerCount > 0; + messagePort.refedMessagePortsCount > 0; } async function pollForMessages() { diff --git a/tests/unit_node/worker_threads_test.ts b/tests/unit_node/worker_threads_test.ts index ac797601f5..24a9107898 100644 --- a/tests/unit_node/worker_threads_test.ts +++ b/tests/unit_node/worker_threads_test.ts @@ -621,3 +621,204 @@ Deno.test({ worker.terminate(); }, }); + +Deno.test({ + name: "[node/worker_threads] receiveMessageOnPort doesn't exit receive loop", + async fn() { + const worker = new workerThreads.Worker( + ` + import { parentPort, receiveMessageOnPort } from "node:worker_threads"; + parentPort.on("message", (msg) => { + const port = msg.port; + port.on("message", (msg2) => { + if (msg2 === "c") { + port.postMessage("done"); + port.unref(); + parentPort.unref(); + } + }); + parentPort.postMessage("ready"); + const msg2 = receiveMessageOnPort(port); + }); + `, + { eval: true }, + ); + + const { port1, port2 } = new workerThreads.MessageChannel(); + + worker.postMessage({ port: port2 }, [port2]); + + const done = Promise.withResolvers(); + + port1.on("message", (msg) => { + assertEquals(msg, "done"); + worker.unref(); + port1.close(); + done.resolve(true); + }); + worker.on("message", (msg) => { + assertEquals(msg, "ready"); + port1.postMessage("a"); + port1.postMessage("b"); + port1.postMessage("c"); + }); + + const timeout = setTimeout(() => { + fail("Test timed out"); + }, 20_000); + try { + const result = await done.promise; + assertEquals(result, true); + } finally { + clearTimeout(timeout); + } + }, +}); + +Deno.test({ + name: "[node/worker_threads] MessagePort.unref doesn't exit receive loop", + async fn() { + const worker = new workerThreads.Worker( + ` + import { parentPort } from "node:worker_threads"; + const assertEquals = (a, b) => { + if (a !== b) { + throw new Error(); + } + }; + let state = 0; + parentPort.on("message", (msg) => { + const port = msg.port; + const expect = ["a", "b", "c"]; + port.on("message", (msg2) => { + assertEquals(msg2, expect[state++]); + if (msg2 === "c") { + port.postMessage({ type: "done", got: msg2 }); + parentPort.unref(); + } + }); + port.unref(); + parentPort.postMessage("ready"); + }); + `, + { eval: true }, + ); + + const { port1, port2 } = new workerThreads.MessageChannel(); + + const done = Promise.withResolvers(); + + port1.on("message", (msg) => { + assertEquals(msg.type, "done"); + assertEquals(msg.got, "c"); + worker.unref(); + port1.close(); + done.resolve(true); + }); + worker.on("message", (msg) => { + assertEquals(msg, "ready"); + port1.postMessage("a"); + port1.postMessage("b"); + port1.postMessage("c"); + }); + worker.postMessage({ port: port2 }, [port2]); + + const timeout = setTimeout(() => { + fail("Test timed out"); + }, 20_000); + try { + const result = await done.promise; + assertEquals(result, true); + } finally { + clearTimeout(timeout); + } + }, +}); + +Deno.test({ + name: "[node/worker_threads] npm:piscina wait loop hang regression", + async fn() { + const worker = new workerThreads.Worker( + ` + import { assert, assertEquals } from "@std/assert"; + import { parentPort, receiveMessageOnPort } from "node:worker_threads"; + + assert(parentPort !== null); + + let currentTasks = 0; + let lastSeen = 0; + + parentPort.on("message", (msg) => { + (async () => { + assert(typeof msg === "object" && msg !== null); + assert(msg.buf !== undefined); + assert(msg.port !== undefined); + const { buf, port } = msg; + port.postMessage("ready"); + port.on("message", (msg) => onMessage(msg, buf, port)); + atomicsWaitLoop(buf, port); + })(); + }); + + function onMessage(msg, buf, port) { + currentTasks++; + (async () => { + assert(msg.taskName !== undefined); + port.postMessage({ type: "response", taskName: msg.taskName }); + currentTasks--; + atomicsWaitLoop(buf, port); + })(); + } + + function atomicsWaitLoop(buf, port) { + while (currentTasks === 0) { + Atomics.wait(buf, 0, lastSeen); + lastSeen = Atomics.load(buf, 0); + let task; + while ((task = receiveMessageOnPort(port)) !== undefined) { + onMessage(task.message, buf, port); + } + } + } + `, + { eval: true }, + ); + + const sab = new SharedArrayBuffer(4); + const buf = new Int32Array(sab); + const { port1, port2 } = new workerThreads.MessageChannel(); + + const done = Promise.withResolvers(); + + port1.unref(); + + worker.postMessage({ + type: "init", + buf, + port: port2, + }, [port2]); + + let count = 0; + port1.on("message", (msg) => { + if (count++ === 0) { + assertEquals(msg, "ready"); + } else { + assertEquals(msg.type, "response"); + port1.close(); + done.resolve(true); + } + }); + + port1.postMessage({ + taskName: "doThing", + }); + + Atomics.add(buf, 0, 1); + Atomics.notify(buf, 0, 1); + + worker.unref(); + + const result = await done.promise; + assertEquals(result, true); + }, +}); From f288730c38bd4f13b464a9bd67eb901a8c790bc4 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 4 Oct 2024 20:55:03 +0100 Subject: [PATCH 25/39] chore: enable lock_deno_json_package_json_deps (#26029) --- tests/integration/run_tests.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/integration/run_tests.rs b/tests/integration/run_tests.rs index b3ad15c813..db83acb19d 100644 --- a/tests/integration/run_tests.rs +++ b/tests/integration/run_tests.rs @@ -926,9 +926,7 @@ fn lock_redirects() { ); } -// TODO(2.0): this should be rewritten to a spec test and first run `deno install` #[test] -#[ignore] fn lock_deno_json_package_json_deps() { let context = TestContextBuilder::new() .use_temp_cwd() @@ -942,6 +940,7 @@ fn lock_deno_json_package_json_deps() { // add a jsr and npm dependency deno_json.write_json(&json!({ + "nodeModulesDir": "auto", "imports": { "esm-basic": "npm:@denotest/esm-basic", "module_graph": "jsr:@denotest/module-graph@1.4", @@ -984,6 +983,7 @@ fn lock_deno_json_package_json_deps() { // now remove the npm dependency from the deno.json and move // it to a package.json that uses an alias deno_json.write_json(&json!({ + "nodeModulesDir": "auto", "imports": { "module_graph": "jsr:@denotest/module-graph@1.4", } @@ -1060,7 +1060,9 @@ fn lock_deno_json_package_json_deps() { })); // now remove the deps from the deno.json - deno_json.write("{}"); + deno_json.write_json(&json!({ + "nodeModulesDir": "auto" + })); main_ts.write(""); context .new_command() From 2de4faa483982478e9a36ad4ab891a887b4779f1 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 4 Oct 2024 20:55:41 +0100 Subject: [PATCH 26/39] refactor: improve node permission checks (#26028) Does less work when requesting permissions with `-A` --- cli/npm/byonm.rs | 12 ++- cli/npm/managed/mod.rs | 7 +- cli/npm/managed/resolvers/common.rs | 40 ++++---- cli/npm/managed/resolvers/global.rs | 6 +- cli/npm/managed/resolvers/local.rs | 6 +- ext/node/lib.rs | 12 ++- ext/node/ops/require.rs | 24 +++-- ext/node/ops/worker_threads.rs | 12 ++- runtime/permissions/lib.rs | 54 ++++++++-- runtime/snapshot.rs | 3 + tests/unit/permissions_test.ts | 152 ++++++++++++++++------------ 11 files changed, 207 insertions(+), 121 deletions(-) diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index 02c2e6da81..fc095ab16f 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -32,18 +33,19 @@ pub type CliByonmNpmResolver = ByonmNpmResolver; struct CliByonmWrapper(Arc); impl NodeRequireResolver for CliByonmWrapper { - fn ensure_read_permission( + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError> { + path: &'a Path, + ) -> Result, AnyError> { if !path .components() .any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules") { - _ = permissions.check_read_path(path)?; + permissions.check_read_path(path) + } else { + Ok(Cow::Borrowed(path)) } - Ok(()) } } diff --git a/cli/npm/managed/mod.rs b/cli/npm/managed/mod.rs index 225cd6c29c..ec50a9c65a 100644 --- a/cli/npm/managed/mod.rs +++ b/cli/npm/managed/mod.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; @@ -593,11 +594,11 @@ impl NpmResolver for ManagedCliNpmResolver { } impl NodeRequireResolver for ManagedCliNpmResolver { - fn ensure_read_permission( + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError> { + path: &'a Path, + ) -> Result, AnyError> { self.fs_resolver.ensure_read_permission(permissions, path) } } diff --git a/cli/npm/managed/resolvers/common.rs b/cli/npm/managed/resolvers/common.rs index 8df4debc5c..867bb4168a 100644 --- a/cli/npm/managed/resolvers/common.rs +++ b/cli/npm/managed/resolvers/common.rs @@ -3,6 +3,7 @@ pub mod bin_entries; pub mod lifecycle_scripts; +use std::borrow::Cow; use std::collections::HashMap; use std::io::ErrorKind; use std::path::Path; @@ -62,11 +63,12 @@ pub trait NpmPackageFsResolver: Send + Sync { async fn cache_packages(&self) -> Result<(), AnyError>; - fn ensure_read_permission( + #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError>; + path: &'a Path, + ) -> Result, AnyError>; } #[derive(Debug)] @@ -85,11 +87,15 @@ impl RegistryReadPermissionChecker { } } - pub fn ensure_registry_read_permission( + pub fn ensure_registry_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError> { + path: &'a Path, + ) -> Result, AnyError> { + if permissions.query_read_all() { + return Ok(Cow::Borrowed(path)); // skip permissions checks below + } + // allow reading if it's in the node_modules let is_path_in_node_modules = path.starts_with(&self.registry_path) && path @@ -118,20 +124,20 @@ impl RegistryReadPermissionChecker { }, } }; - let Some(registry_path_canon) = canonicalize(&self.registry_path)? else { - return Ok(()); // not exists, allow reading - }; - let Some(path_canon) = canonicalize(path)? else { - return Ok(()); // not exists, allow reading - }; - - if path_canon.starts_with(registry_path_canon) { - return Ok(()); + if let Some(registry_path_canon) = canonicalize(&self.registry_path)? { + if let Some(path_canon) = canonicalize(path)? { + if path_canon.starts_with(registry_path_canon) { + return Ok(Cow::Owned(path_canon)); + } + } else if path.starts_with(registry_path_canon) + || path.starts_with(&self.registry_path) + { + return Ok(Cow::Borrowed(path)); + } } } - _ = permissions.check_read_path(path)?; - Ok(()) + permissions.check_read_path(path) } } diff --git a/cli/npm/managed/resolvers/global.rs b/cli/npm/managed/resolvers/global.rs index ca5722c869..5be315e992 100644 --- a/cli/npm/managed/resolvers/global.rs +++ b/cli/npm/managed/resolvers/global.rs @@ -183,11 +183,11 @@ impl NpmPackageFsResolver for GlobalNpmPackageResolver { Ok(()) } - fn ensure_read_permission( + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError> { + path: &'a Path, + ) -> Result, AnyError> { self .registry_read_permission_checker .ensure_registry_read_permission(permissions, path) diff --git a/cli/npm/managed/resolvers/local.rs b/cli/npm/managed/resolvers/local.rs index 258c9bf3d5..63a972a431 100644 --- a/cli/npm/managed/resolvers/local.rs +++ b/cli/npm/managed/resolvers/local.rs @@ -257,11 +257,11 @@ impl NpmPackageFsResolver for LocalNpmPackageResolver { .await } - fn ensure_read_permission( + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError> { + path: &'a Path, + ) -> Result, AnyError> { self .registry_read_permission_checker .ensure_registry_read_permission(permissions, path) diff --git a/ext/node/lib.rs b/ext/node/lib.rs index d23c072042..03462f36fa 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -66,6 +66,7 @@ pub trait NodePermissions { &mut self, path: &'a Path, ) -> Result, AnyError>; + fn query_read_all(&mut self) -> bool; fn check_sys(&mut self, kind: &str, api_name: &str) -> Result<(), AnyError>; #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn check_write_with_api_name( @@ -103,6 +104,10 @@ impl NodePermissions for deno_permissions::PermissionsContainer { deno_permissions::PermissionsContainer::check_read_path(self, path, None) } + fn query_read_all(&mut self) -> bool { + deno_permissions::PermissionsContainer::query_read_all(self) + } + #[inline(always)] fn check_write_with_api_name( &mut self, @@ -124,11 +129,12 @@ pub type NodeRequireResolverRc = deno_fs::sync::MaybeArc; pub trait NodeRequireResolver: std::fmt::Debug + MaybeSend + MaybeSync { - fn ensure_read_permission( + #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] + fn ensure_read_permission<'a>( &self, permissions: &mut dyn NodePermissions, - path: &Path, - ) -> Result<(), AnyError>; + path: &'a Path, + ) -> Result, AnyError>; } pub static NODE_ENV_VAR_ALLOWLIST: Lazy> = Lazy::new(|| { diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index 15667aae73..5473369815 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -15,6 +15,7 @@ use deno_path_util::normalize_path; use node_resolver::NodeModuleKind; use node_resolver::NodeResolutionMode; use node_resolver::REQUIRE_CONDITIONS; +use std::borrow::Cow; use std::cell::RefCell; use std::path::Path; use std::path::PathBuf; @@ -25,10 +26,11 @@ use crate::NodeRequireResolverRc; use crate::NodeResolverRc; use crate::NpmResolverRc; -fn ensure_read_permission

( +#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] +fn ensure_read_permission<'a, P>( state: &mut OpState, - file_path: &Path, -) -> Result<(), AnyError> + file_path: &'a Path, +) -> Result, AnyError> where P: NodePermissions + 'static, { @@ -107,7 +109,7 @@ where deno_path_util::normalize_path(current_dir.join(from)) }; - ensure_read_permission::

(state, &from)?; + let from = ensure_read_permission::

(state, &from)?; if cfg!(windows) { // return root node_modules when path is 'D:\\'. @@ -129,7 +131,7 @@ where } let mut paths = Vec::with_capacity(from.components().count()); - let mut current_path = from.as_path(); + let mut current_path = from.as_ref(); let mut maybe_parent = Some(current_path); while let Some(parent) = maybe_parent { if !parent.ends_with("node_modules") { @@ -267,7 +269,7 @@ where P: NodePermissions + 'static, { let path = PathBuf::from(path); - ensure_read_permission::

(state, &path)?; + let path = ensure_read_permission::

(state, &path)?; let fs = state.borrow::(); if let Ok(metadata) = fs.stat_sync(&path) { if metadata.is_file { @@ -290,7 +292,7 @@ where P: NodePermissions + 'static, { let path = PathBuf::from(request); - ensure_read_permission::

(state, &path)?; + let path = ensure_read_permission::

(state, &path)?; let fs = state.borrow::(); let canonicalized_path = deno_core::strip_unc_prefix(fs.realpath_sync(&path)?); @@ -362,7 +364,7 @@ where if parent_id == "" || parent_id == "internal/preload" { let fs = state.borrow::(); if let Ok(cwd) = fs.cwd() { - ensure_read_permission::

(state, &cwd)?; + let cwd = ensure_read_permission::

(state, &cwd)?; return Ok(Some(cwd.to_string_lossy().into_owned())); } } @@ -443,7 +445,7 @@ where P: NodePermissions + 'static, { let file_path = PathBuf::from(file_path); - ensure_read_permission::

(state, &file_path)?; + let file_path = ensure_read_permission::

(state, &file_path)?; let fs = state.borrow::(); Ok(fs.read_text_file_lossy_sync(&file_path, None)?) } @@ -528,7 +530,7 @@ where P: NodePermissions + 'static, { let filename = PathBuf::from(filename); - ensure_read_permission::

(state, filename.parent().unwrap())?; + // permissions: allow reading the closest package.json files let node_resolver = state.borrow::().clone(); node_resolver .get_closest_package_json_from_path(&filename) @@ -567,7 +569,7 @@ where P: NodePermissions + 'static, { let referrer_path = PathBuf::from(&referrer_filename); - ensure_read_permission::

(state, &referrer_path)?; + let referrer_path = ensure_read_permission::

(state, &referrer_path)?; let node_resolver = state.borrow::(); let Some(pkg) = node_resolver.get_closest_package_json_from_path(&referrer_path)? diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index c7ea4c52c2..4c50092f28 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -7,6 +7,7 @@ use deno_core::url::Url; use deno_core::OpState; use deno_fs::FileSystemRc; use node_resolver::NodeResolution; +use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; @@ -14,10 +15,11 @@ use crate::NodePermissions; use crate::NodeRequireResolverRc; use crate::NodeResolverRc; -fn ensure_read_permission

( +#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] +fn ensure_read_permission<'a, P>( state: &mut OpState, - file_path: &Path, -) -> Result<(), AnyError> + file_path: &'a Path, +) -> Result, AnyError> where P: NodePermissions + 'static, { @@ -47,7 +49,7 @@ where "Relative path entries must start with '.' or '..'", )); } - ensure_read_permission::

(state, &path)?; + let path = ensure_read_permission::

(state, &path)?; let fs = state.borrow::(); let canonicalized_path = deno_core::strip_unc_prefix(fs.realpath_sync(&path)?); @@ -57,7 +59,7 @@ where let url_path = url .to_file_path() .map_err(|e| generic_error(format!("URL to Path-String: {:#?}", e)))?; - ensure_read_permission::

(state, &url_path)?; + let url_path = ensure_read_permission::

(state, &url_path)?; let fs = state.borrow::(); if !fs.exists_sync(&url_path) { return Err(generic_error(format!("File not found [{:?}]", url_path))); diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index efabd0b171..2904242dae 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -2285,6 +2285,11 @@ impl PermissionsContainer { self.inner.lock().read.check_all(Some(api_name)) } + #[inline(always)] + pub fn query_read_all(&self) -> bool { + self.inner.lock().read.query(None) == PermissionState::Granted + } + #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] #[inline(always)] pub fn check_write( @@ -2614,8 +2619,13 @@ impl PermissionsContainer { &self, path: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.read; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().read.query( + permission.query( path .map(|path| { Result::<_, AnyError>::Ok( @@ -2633,8 +2643,13 @@ impl PermissionsContainer { &self, path: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.write; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().write.query( + permission.query( path .map(|path| { Result::<_, AnyError>::Ok( @@ -2652,8 +2667,13 @@ impl PermissionsContainer { &self, host: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.net; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().net.query( + permission.query( match host { None => None, Some(h) => Some(self.descriptor_parser.parse_net_descriptor(h)?), @@ -2665,7 +2685,12 @@ impl PermissionsContainer { #[inline(always)] pub fn query_env(&self, var: Option<&str>) -> PermissionState { - self.inner.lock().env.query(var) + let inner = self.inner.lock(); + let permission = &inner.env; + if permission.is_allow_all() { + return PermissionState::Granted; + } + permission.query(var) } #[inline(always)] @@ -2673,8 +2698,13 @@ impl PermissionsContainer { &self, kind: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.sys; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().sys.query( + permission.query( kind .map(|kind| self.descriptor_parser.parse_sys_descriptor(kind)) .transpose()? @@ -2688,8 +2718,13 @@ impl PermissionsContainer { &self, cmd: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.run; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().run.query( + permission.query( cmd .map(|request| self.descriptor_parser.parse_run_query(request)) .transpose()? @@ -2703,8 +2738,13 @@ impl PermissionsContainer { &self, path: Option<&str>, ) -> Result { + let inner = self.inner.lock(); + let permission = &inner.ffi; + if permission.is_allow_all() { + return Ok(PermissionState::Granted); + } Ok( - self.inner.lock().ffi.query( + permission.query( path .map(|path| { Result::<_, AnyError>::Ok( diff --git a/runtime/snapshot.rs b/runtime/snapshot.rs index 456810e6a6..041132f971 100644 --- a/runtime/snapshot.rs +++ b/runtime/snapshot.rs @@ -97,6 +97,9 @@ impl deno_node::NodePermissions for Permissions { ) -> Result { unreachable!("snapshotting!") } + fn query_read_all(&mut self) -> bool { + unreachable!("snapshotting!") + } fn check_write_with_api_name( &mut self, _p: &str, diff --git a/tests/unit/permissions_test.ts b/tests/unit/permissions_test.ts index 82524d556c..f981b10fd6 100644 --- a/tests/unit/permissions_test.ts +++ b/tests/unit/permissions_test.ts @@ -20,54 +20,72 @@ Deno.test(function permissionInvalidNameSync() { }, TypeError); }); -Deno.test(async function permissionNetInvalidHost() { - await assertRejects(async () => { - await Deno.permissions.query({ name: "net", host: ":" }); - }, URIError); -}); +Deno.test( + { permissions: { net: [] } }, + async function permissionNetInvalidHost() { + await assertRejects(async () => { + await Deno.permissions.query({ name: "net", host: ":" }); + }, URIError); + }, +); -Deno.test(function permissionNetInvalidHostSync() { - assertThrows(() => { - Deno.permissions.querySync({ name: "net", host: ":" }); - }, URIError); -}); +Deno.test( + { permissions: { net: [] } }, + function permissionNetInvalidHostSync() { + assertThrows(() => { + Deno.permissions.querySync({ name: "net", host: ":" }); + }, URIError); + }, +); -Deno.test(async function permissionSysValidKind() { - await Deno.permissions.query({ name: "sys", kind: "loadavg" }); - await Deno.permissions.query({ name: "sys", kind: "osRelease" }); - await Deno.permissions.query({ name: "sys", kind: "osUptime" }); - await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" }); - await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" }); - await Deno.permissions.query({ name: "sys", kind: "hostname" }); - await Deno.permissions.query({ name: "sys", kind: "uid" }); - await Deno.permissions.query({ name: "sys", kind: "gid" }); - await Deno.permissions.query({ name: "sys", kind: "cpus" }); -}); +Deno.test( + { permissions: { sys: [] } }, + async function permissionSysValidKind() { + await Deno.permissions.query({ name: "sys", kind: "loadavg" }); + await Deno.permissions.query({ name: "sys", kind: "osRelease" }); + await Deno.permissions.query({ name: "sys", kind: "osUptime" }); + await Deno.permissions.query({ name: "sys", kind: "networkInterfaces" }); + await Deno.permissions.query({ name: "sys", kind: "systemMemoryInfo" }); + await Deno.permissions.query({ name: "sys", kind: "hostname" }); + await Deno.permissions.query({ name: "sys", kind: "uid" }); + await Deno.permissions.query({ name: "sys", kind: "gid" }); + await Deno.permissions.query({ name: "sys", kind: "cpus" }); + }, +); -Deno.test(function permissionSysValidKindSync() { - Deno.permissions.querySync({ name: "sys", kind: "loadavg" }); - Deno.permissions.querySync({ name: "sys", kind: "osRelease" }); - Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" }); - Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" }); - Deno.permissions.querySync({ name: "sys", kind: "hostname" }); - Deno.permissions.querySync({ name: "sys", kind: "uid" }); - Deno.permissions.querySync({ name: "sys", kind: "gid" }); - Deno.permissions.querySync({ name: "sys", kind: "cpus" }); -}); +Deno.test( + { permissions: { sys: [] } }, + function permissionSysValidKindSync() { + Deno.permissions.querySync({ name: "sys", kind: "loadavg" }); + Deno.permissions.querySync({ name: "sys", kind: "osRelease" }); + Deno.permissions.querySync({ name: "sys", kind: "networkInterfaces" }); + Deno.permissions.querySync({ name: "sys", kind: "systemMemoryInfo" }); + Deno.permissions.querySync({ name: "sys", kind: "hostname" }); + Deno.permissions.querySync({ name: "sys", kind: "uid" }); + Deno.permissions.querySync({ name: "sys", kind: "gid" }); + Deno.permissions.querySync({ name: "sys", kind: "cpus" }); + }, +); -Deno.test(async function permissionSysInvalidKind() { - await assertRejects(async () => { - // deno-lint-ignore no-explicit-any - await Deno.permissions.query({ name: "sys", kind: "abc" as any }); - }, TypeError); -}); +Deno.test( + { permissions: { sys: [] } }, + async function permissionSysInvalidKind() { + await assertRejects(async () => { + // deno-lint-ignore no-explicit-any + await Deno.permissions.query({ name: "sys", kind: "abc" as any }); + }, TypeError); + }, +); -Deno.test(function permissionSysInvalidKindSync() { - assertThrows(() => { - // deno-lint-ignore no-explicit-any - Deno.permissions.querySync({ name: "sys", kind: "abc" as any }); - }, TypeError); -}); +Deno.test( + { permissions: { sys: [] } }, + function permissionSysInvalidKindSync() { + assertThrows(() => { + // deno-lint-ignore no-explicit-any + Deno.permissions.querySync({ name: "sys", kind: "abc" as any }); + }, TypeError); + }, +); Deno.test(async function permissionQueryReturnsEventTarget() { const status = await Deno.permissions.query({ name: "read", path: "." }); @@ -134,29 +152,35 @@ Deno.test(function permissionStatusIllegalConstructor() { }); // Regression test for https://github.com/denoland/deno/issues/17020 -Deno.test(async function permissionURL() { - const path = new URL(".", import.meta.url); +Deno.test( + { permissions: { read: [], write: [], ffi: [], run: [] } }, + async function permissionURL() { + const path = new URL(".", import.meta.url); - await Deno.permissions.query({ name: "read", path }); - await Deno.permissions.query({ name: "write", path }); - await Deno.permissions.query({ name: "ffi", path }); - await Deno.permissions.query({ name: "run", command: path }); -}); + await Deno.permissions.query({ name: "read", path }); + await Deno.permissions.query({ name: "write", path }); + await Deno.permissions.query({ name: "ffi", path }); + await Deno.permissions.query({ name: "run", command: path }); + }, +); -Deno.test(function permissionURLSync() { - Deno.permissions.querySync({ - name: "read", - path: new URL(".", import.meta.url), - }); - Deno.permissions.querySync({ - name: "write", - path: new URL(".", import.meta.url), - }); - Deno.permissions.querySync({ - name: "run", - command: new URL(".", import.meta.url), - }); -}); +Deno.test( + { permissions: { read: [], write: [], ffi: [], run: [] } }, + function permissionURLSync() { + Deno.permissions.querySync({ + name: "read", + path: new URL(".", import.meta.url), + }); + Deno.permissions.querySync({ + name: "write", + path: new URL(".", import.meta.url), + }); + Deno.permissions.querySync({ + name: "run", + command: new URL(".", import.meta.url), + }); + }, +); Deno.test(async function permissionDescriptorValidation() { for (const value of [undefined, null, {}]) { From 39a2034967207b89069cf64a76308e1446b1ad26 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 7 Oct 2024 16:34:40 +0530 Subject: [PATCH 27/39] feat(ext/crypto): X448 support (#26043) Signed-off-by: Divy Srivastava --- Cargo.lock | 21 +- ext/crypto/00_crypto.js | 377 ++++++++++++++++++++++++++++++ ext/crypto/Cargo.toml | 1 + ext/crypto/lib.rs | 11 +- ext/crypto/x448.rs | 147 ++++++++++++ tests/wpt/runner/expectation.json | 194 +++++++-------- 6 files changed, 640 insertions(+), 111 deletions(-) create mode 100644 ext/crypto/x448.rs diff --git a/Cargo.lock b/Cargo.lock index a679504108..a63da555de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1060,7 +1060,7 @@ dependencies = [ "cpufeatures", "curve25519-dalek-derive", "digest", - "fiat-crypto", + "fiat-crypto 0.2.7", "rustc_version 0.4.0", "subtle", "zeroize", @@ -1493,6 +1493,7 @@ dependencies = [ "curve25519-dalek", "deno_core", "deno_web", + "ed448-goldilocks", "elliptic-curve", "num-traits", "once_cell", @@ -2716,6 +2717,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed448-goldilocks" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06924531e9e90130842b012e447f85bdaf9161bc8a0f8092be8cb70b01ebe092" +dependencies = [ + "fiat-crypto 0.1.20", + "hex", + "subtle", + "zeroize", +] + [[package]] name = "editpe" version = "0.1.0" @@ -2978,6 +2991,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "fiat-crypto" version = "0.2.7" diff --git a/ext/crypto/00_crypto.js b/ext/crypto/00_crypto.js index 8e43b76f7c..63b1905145 100644 --- a/ext/crypto/00_crypto.js +++ b/ext/crypto/00_crypto.js @@ -18,21 +18,27 @@ import { op_crypto_decrypt, op_crypto_derive_bits, op_crypto_derive_bits_x25519, + op_crypto_derive_bits_x448, op_crypto_encrypt, op_crypto_export_key, op_crypto_export_pkcs8_ed25519, op_crypto_export_pkcs8_x25519, + op_crypto_export_pkcs8_x448, op_crypto_export_spki_ed25519, op_crypto_export_spki_x25519, + op_crypto_export_spki_x448, op_crypto_generate_ed25519_keypair, op_crypto_generate_key, op_crypto_generate_x25519_keypair, + op_crypto_generate_x448_keypair, op_crypto_get_random_values, op_crypto_import_key, op_crypto_import_pkcs8_ed25519, op_crypto_import_pkcs8_x25519, + op_crypto_import_pkcs8_x448, op_crypto_import_spki_ed25519, op_crypto_import_spki_x25519, + op_crypto_import_spki_x448, op_crypto_jwk_x_ed25519, op_crypto_random_uuid, op_crypto_sign_ed25519, @@ -134,6 +140,7 @@ const supportedAlgorithms = { "AES-KW": "AesKeyGenParams", "HMAC": "HmacKeyGenParams", "X25519": null, + "X448": null, "Ed25519": null, }, "sign": { @@ -165,12 +172,14 @@ const supportedAlgorithms = { "AES-KW": null, "Ed25519": null, "X25519": null, + "X448": null, }, "deriveBits": { "HKDF": "HkdfParams", "PBKDF2": "Pbkdf2Params", "ECDH": "EcdhKeyDeriveParams", "X25519": "EcdhKeyDeriveParams", + "X448": "EcdhKeyDeriveParams", }, "encrypt": { "RSA-OAEP": "RsaOaepParams", @@ -1037,6 +1046,10 @@ class SubtleCrypto { result = exportKeyEd25519(format, key, innerKey); break; } + case "X448": { + result = exportKeyX448(format, key, innerKey); + break; + } case "X25519": { result = exportKeyX25519(format, key, innerKey); break; @@ -1954,6 +1967,48 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { return generateKeyAES(normalizedAlgorithm, extractable, usages); } + case "X448": { + if ( + ArrayPrototypeFind( + usages, + (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), + ) !== undefined + ) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + const privateKeyData = new Uint8Array(56); + const publicKeyData = new Uint8Array(56); + + op_crypto_generate_x448_keypair(privateKeyData, publicKeyData); + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData); + + const publicHandle = {}; + WeakMapPrototypeSet(KEY_STORE, publicHandle, publicKeyData); + + const algorithm = { + name: algorithmName, + }; + + const publicKey = constructKey( + "public", + true, + usageIntersection(usages, []), + algorithm, + publicHandle, + ); + + const privateKey = constructKey( + "private", + extractable, + usageIntersection(usages, ["deriveKey", "deriveBits"]), + algorithm, + handle, + ); + + return { publicKey, privateKey }; + } case "X25519": { if ( ArrayPrototypeFind( @@ -2100,6 +2155,211 @@ async function generateKey(normalizedAlgorithm, extractable, usages) { } } +function importKeyX448( + format, + keyData, + extractable, + keyUsages, +) { + switch (format) { + case "raw": { + // 1. + if (keyUsages.length > 0) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, keyData); + + // 2-3. + const algorithm = { + name: "X448", + }; + + // 4-6. + return constructKey( + "public", + extractable, + [], + algorithm, + handle, + ); + } + case "spki": { + // 1. + if (keyUsages.length > 0) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + + const publicKeyData = new Uint8Array(56); + if (!op_crypto_import_spki_x448(keyData, publicKeyData)) { + throw new DOMException("Invalid key data", "DataError"); + } + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData); + + const algorithm = { + name: "X448", + }; + + return constructKey( + "public", + extractable, + [], + algorithm, + handle, + ); + } + case "pkcs8": { + // 1. + if ( + ArrayPrototypeFind( + keyUsages, + (u) => !ArrayPrototypeIncludes(["deriveKey", "deriveBits"], u), + ) !== undefined + ) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + + const privateKeyData = new Uint8Array(32); + if (!op_crypto_import_pkcs8_x448(keyData, privateKeyData)) { + throw new DOMException("Invalid key data", "DataError"); + } + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData); + + const algorithm = { + name: "X448", + }; + + return constructKey( + "private", + extractable, + usageIntersection(keyUsages, recognisedUsages), + algorithm, + handle, + ); + } + case "jwk": { + // 1. + const jwk = keyData; + + // 2. + if (jwk.d !== undefined) { + if ( + ArrayPrototypeFind( + keyUsages, + (u) => + !ArrayPrototypeIncludes( + ["deriveKey", "deriveBits"], + u, + ), + ) !== undefined + ) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + } + + // 3. + if (jwk.d === undefined && keyUsages.length > 0) { + throw new DOMException("Invalid key usage", "SyntaxError"); + } + + // 4. + if (jwk.kty !== "OKP") { + throw new DOMException("Invalid key type", "DataError"); + } + + // 5. + if (jwk.crv !== "X448") { + throw new DOMException("Invalid curve", "DataError"); + } + + // 6. + if (keyUsages.length > 0 && jwk.use !== undefined) { + if (jwk.use !== "enc") { + throw new DOMException("Invalid key use", "DataError"); + } + } + + // 7. + if (jwk.key_ops !== undefined) { + if ( + ArrayPrototypeFind( + jwk.key_ops, + (u) => !ArrayPrototypeIncludes(recognisedUsages, u), + ) !== undefined + ) { + throw new DOMException( + "'key_ops' property of JsonWebKey is invalid", + "DataError", + ); + } + + if ( + !ArrayPrototypeEvery( + jwk.key_ops, + (u) => ArrayPrototypeIncludes(keyUsages, u), + ) + ) { + throw new DOMException( + "'key_ops' property of JsonWebKey is invalid", + "DataError", + ); + } + } + + // 8. + if (jwk.ext !== undefined && jwk.ext === false && extractable) { + throw new DOMException("Invalid key extractability", "DataError"); + } + + // 9. + if (jwk.d !== undefined) { + // https://www.rfc-editor.org/rfc/rfc8037#section-2 + const privateKeyData = op_crypto_base64url_decode(jwk.d); + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, privateKeyData); + + const algorithm = { + name: "X448", + }; + + return constructKey( + "private", + extractable, + usageIntersection(keyUsages, ["deriveKey", "deriveBits"]), + algorithm, + handle, + ); + } else { + // https://www.rfc-editor.org/rfc/rfc8037#section-2 + const publicKeyData = op_crypto_base64url_decode(jwk.x); + + const handle = {}; + WeakMapPrototypeSet(KEY_STORE, handle, publicKeyData); + + const algorithm = { + name: "X448", + }; + + return constructKey( + "public", + extractable, + [], + algorithm, + handle, + ); + } + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } +} + function importKeyEd25519( format, keyData, @@ -3358,6 +3618,14 @@ async function importKeyInner( ["wrapKey", "unwrapKey"], ); } + case "X448": { + return importKeyX448( + format, + keyData, + extractable, + keyUsages, + ); + } case "X25519": { return importKeyX25519( format, @@ -4162,6 +4430,66 @@ function exportKeyEd25519(format, key, innerKey) { } } +function exportKeyX448(format, key, innerKey) { + switch (format) { + case "raw": { + // 1. + if (key[_type] !== "public") { + throw new DOMException( + "Key is not a public key", + "InvalidAccessError", + ); + } + + // 2-3. + return TypedArrayPrototypeGetBuffer(innerKey); + } + case "spki": { + // 1. + if (key[_type] !== "public") { + throw new DOMException( + "Key is not a public key", + "InvalidAccessError", + ); + } + + const spkiDer = op_crypto_export_spki_x448(innerKey); + return TypedArrayPrototypeGetBuffer(spkiDer); + } + case "pkcs8": { + // 1. + if (key[_type] !== "private") { + throw new DOMException( + "Key is not a private key", + "InvalidAccessError", + ); + } + + const pkcs8Der = op_crypto_export_pkcs8_x448( + new Uint8Array([0x04, 0x22, ...new SafeArrayIterator(innerKey)]), + ); + pkcs8Der[15] = 0x20; + return TypedArrayPrototypeGetBuffer(pkcs8Der); + } + case "jwk": { + if (key[_type] === "private") { + throw new DOMException("Not implemented", "NotSupportedError"); + } + const x = op_crypto_base64url_encode(innerKey); + const jwk = { + kty: "OKP", + crv: "X448", + x, + "key_ops": key.usages, + ext: key[_extractable], + }; + return jwk; + } + default: + throw new DOMException("Not implemented", "NotSupportedError"); + } +} + function exportKeyX25519(format, key, innerKey) { switch (format) { case "raw": { @@ -4519,6 +4847,55 @@ async function deriveBits(normalizedAlgorithm, baseKey, length) { return TypedArrayPrototypeGetBuffer(buf); } + case "X448": { + // 1. + if (baseKey[_type] !== "private") { + throw new DOMException("Invalid key type", "InvalidAccessError"); + } + // 2. + const publicKey = normalizedAlgorithm.public; + // 3. + if (publicKey[_type] !== "public") { + throw new DOMException("Invalid key type", "InvalidAccessError"); + } + // 4. + if (publicKey[_algorithm].name !== baseKey[_algorithm].name) { + throw new DOMException( + "Algorithm mismatch", + "InvalidAccessError", + ); + } + + // 5. + const kHandle = baseKey[_handle]; + const k = WeakMapPrototypeGet(KEY_STORE, kHandle); + + const uHandle = publicKey[_handle]; + const u = WeakMapPrototypeGet(KEY_STORE, uHandle); + + const secret = new Uint8Array(56); + const isIdentity = op_crypto_derive_bits_x448(k, u, secret); + + // 6. + if (isIdentity) { + throw new DOMException("Invalid key", "OperationError"); + } + + // 7. + if (length === null) { + return TypedArrayPrototypeGetBuffer(secret); + } else if ( + TypedArrayPrototypeGetByteLength(secret) * 8 < length + ) { + throw new DOMException("Invalid length", "OperationError"); + } else { + return ArrayBufferPrototypeSlice( + TypedArrayPrototypeGetBuffer(secret), + 0, + MathCeil(length / 8), + ); + } + } case "X25519": { // 1. if (baseKey[_type] !== "private") { diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 667867efa7..0425b1e5e8 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -24,6 +24,7 @@ ctr = "0.9.1" curve25519-dalek = "4.1.3" deno_core.workspace = true deno_web.workspace = true +ed448-goldilocks = { version = "0.8.3", features = ["zeroize"] } elliptic-curve = { version = "0.13.1", features = ["std", "pem"] } num-traits = "0.2.14" once_cell.workspace = true diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 7aa3462c76..c96029bf4a 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -64,6 +64,7 @@ mod import_key; mod key; mod shared; mod x25519; +mod x448; pub use crate::decrypt::op_crypto_decrypt; pub use crate::encrypt::op_crypto_encrypt; @@ -98,6 +99,14 @@ deno_core::extension!(deno_crypto, x25519::op_crypto_derive_bits_x25519, x25519::op_crypto_import_spki_x25519, x25519::op_crypto_import_pkcs8_x25519, + x25519::op_crypto_export_spki_x25519, + x25519::op_crypto_export_pkcs8_x25519, + x448::op_crypto_generate_x448_keypair, + x448::op_crypto_derive_bits_x448, + x448::op_crypto_import_spki_x448, + x448::op_crypto_import_pkcs8_x448, + x448::op_crypto_export_spki_x448, + x448::op_crypto_export_pkcs8_x448, ed25519::op_crypto_generate_ed25519_keypair, ed25519::op_crypto_import_spki_ed25519, ed25519::op_crypto_import_pkcs8_ed25519, @@ -106,8 +115,6 @@ deno_core::extension!(deno_crypto, ed25519::op_crypto_export_spki_ed25519, ed25519::op_crypto_export_pkcs8_ed25519, ed25519::op_crypto_jwk_x_ed25519, - x25519::op_crypto_export_spki_x25519, - x25519::op_crypto_export_pkcs8_x25519, ], esm = [ "00_crypto.js" ], options = { diff --git a/ext/crypto/x448.rs b/ext/crypto/x448.rs new file mode 100644 index 0000000000..3c8f24c319 --- /dev/null +++ b/ext/crypto/x448.rs @@ -0,0 +1,147 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_core::error::custom_error; +use deno_core::error::AnyError; +use deno_core::op2; +use deno_core::ToJsBuffer; +use ed448_goldilocks::curve::MontgomeryPoint; +use ed448_goldilocks::Scalar; +use elliptic_curve::pkcs8::PrivateKeyInfo; +use elliptic_curve::subtle::ConstantTimeEq; +use rand::rngs::OsRng; +use rand::RngCore; +use spki::der::asn1::BitString; +use spki::der::Decode; +use spki::der::Encode; + +#[op2(fast)] +pub fn op_crypto_generate_x448_keypair( + #[buffer] pkey: &mut [u8], + #[buffer] pubkey: &mut [u8], +) { + let mut rng = OsRng; + rng.fill_bytes(pkey); + + // x448(pkey, 5) + let point = &MontgomeryPoint::generator() + * &Scalar::from_bytes(pkey.try_into().unwrap()); + pubkey.copy_from_slice(&point.0); +} + +const MONTGOMERY_IDENTITY: MontgomeryPoint = MontgomeryPoint([0; 56]); + +#[op2(fast)] +pub fn op_crypto_derive_bits_x448( + #[buffer] k: &[u8], + #[buffer] u: &[u8], + #[buffer] secret: &mut [u8], +) -> bool { + let k: [u8; 56] = k.try_into().expect("Expected byteLength 56"); + let u: [u8; 56] = u.try_into().expect("Expected byteLength 56"); + + // x448(k, u) + let point = &MontgomeryPoint(u) * &Scalar::from_bytes(k); + if point.ct_eq(&MONTGOMERY_IDENTITY).unwrap_u8() == 1 { + return true; + } + + secret.copy_from_slice(&point.0); + false +} + +// id-X448 OBJECT IDENTIFIER ::= { 1 3 101 111 } +const X448_OID: const_oid::ObjectIdentifier = + const_oid::ObjectIdentifier::new_unwrap("1.3.101.111"); + +#[op2] +#[serde] +pub fn op_crypto_export_spki_x448( + #[buffer] pubkey: &[u8], +) -> Result { + let key_info = spki::SubjectPublicKeyInfo { + algorithm: spki::AlgorithmIdentifierRef { + oid: X448_OID, + parameters: None, + }, + subject_public_key: BitString::from_bytes(pubkey)?, + }; + Ok( + key_info + .to_der() + .map_err(|_| { + custom_error("DOMExceptionOperationError", "Failed to export key") + })? + .into(), + ) +} + +#[op2] +#[serde] +pub fn op_crypto_export_pkcs8_x448( + #[buffer] pkey: &[u8], +) -> Result { + use rsa::pkcs1::der::Encode; + + let pk_info = rsa::pkcs8::PrivateKeyInfo { + public_key: None, + algorithm: rsa::pkcs8::AlgorithmIdentifierRef { + oid: X448_OID, + parameters: None, + }, + private_key: pkey, // OCTET STRING + }; + + let mut buf = Vec::new(); + pk_info.encode_to_vec(&mut buf)?; + Ok(buf.into()) +} + +#[op2(fast)] +pub fn op_crypto_import_spki_x448( + #[buffer] key_data: &[u8], + #[buffer] out: &mut [u8], +) -> bool { + // 2-3. + let pk_info = match spki::SubjectPublicKeyInfoRef::try_from(key_data) { + Ok(pk_info) => pk_info, + Err(_) => return false, + }; + // 4. + let alg = pk_info.algorithm.oid; + if alg != X448_OID { + return false; + } + // 5. + if pk_info.algorithm.parameters.is_some() { + return false; + } + out.copy_from_slice(pk_info.subject_public_key.raw_bytes()); + true +} + +#[op2(fast)] +pub fn op_crypto_import_pkcs8_x448( + #[buffer] key_data: &[u8], + #[buffer] out: &mut [u8], +) -> bool { + // 2-3. + let pk_info = match PrivateKeyInfo::from_der(key_data) { + Ok(pk_info) => pk_info, + Err(_) => return false, + }; + // 4. + let alg = pk_info.algorithm.oid; + if alg != X448_OID { + return false; + } + // 5. + if pk_info.algorithm.parameters.is_some() { + return false; + } + // 6. + // CurvePrivateKey ::= OCTET STRING + if pk_info.private_key.len() != 56 { + return false; + } + out.copy_from_slice(&pk_info.private_key[2..]); + true +} diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index f7da5e51f0..ce73f5d05d 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -59,14 +59,12 @@ "X448 key derivation checks for all-zero value result with a key of order p-1 (order 2)", "X448 key derivation checks for all-zero value result with a key of order p (=0, order 4)", "X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", - "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", "X448 short result", "X448 non-multiple of 8 bits", "X448 mismatched algorithms", "X448 no deriveBits usage for base key", - "X448 base key is not a private key", "X448 public property value is a private key", "X448 public property value is a secret key", "X448 asking for too many bits" @@ -77,14 +75,12 @@ "X448 key derivation checks for all-zero value result with a key of order p-1 (order 2)", "X448 key derivation checks for all-zero value result with a key of order p (=0, order 4)", "X448 key derivation checks for all-zero value result with a key of order p+1 (=1, order 1)", - "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", "X448 short result", "X448 non-multiple of 8 bits", "X448 mismatched algorithms", "X448 no deriveBits usage for base key", - "X448 base key is not a private key", "X448 public property value is a private key", "X448 public property value is a secret key", "X448 asking for too many bits" @@ -95,13 +91,10 @@ "X448 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", "X448 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", "X448 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", - "Key derivation using a X448 generated keys.", - "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", "X448 mismatched algorithms", "X448 no deriveKey usage for base key", - "X448 base key is not a private key", "X448 public property value is a private key", "X448 public property value is a secret key" ], @@ -111,13 +104,10 @@ "X448 deriveBits checks for all-zero value result with a key of order p-1 (order 2)", "X448 deriveBits checks for all-zero value result with a key of order p (=0, order 4)", "X448 deriveBits checks for all-zero value result with a key of order p+1 (=1, order 1)", - "Key derivation using a X448 generated keys.", - "X25519 mismatched algorithms", "X448 good parameters", "X448 mixed case parameters", "X448 mismatched algorithms", "X448 no deriveKey usage for base key", - "X448 base key is not a private key", "X448 public property value is a private key", "X448 public property value is a secret key" ], @@ -767,82 +757,16 @@ ], "failures_X25519.https.any.html": true, "failures_X25519.https.any.worker.html": true, - "failures_X448.https.any.html": [ - "Bad usages: generateKey({name: X448}, true, [encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])", - "Bad usages: generateKey({name: X448}, true, [decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])", - "Bad usages: generateKey({name: X448}, true, [sign])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])", - "Bad usages: generateKey({name: X448}, true, [verify])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])", - "Bad usages: generateKey({name: X448}, true, [wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", - "Empty usages: generateKey({name: X448}, false, [])", - "Empty usages: generateKey({name: X448}, true, [])" - ], - "failures_X448.https.any.worker.html": [ - "Bad usages: generateKey({name: X448}, true, [encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, encrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, encrypt])", - "Bad usages: generateKey({name: X448}, true, [decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, decrypt])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, decrypt])", - "Bad usages: generateKey({name: X448}, true, [sign])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, sign])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, sign])", - "Bad usages: generateKey({name: X448}, true, [verify])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, verify])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, verify])", - "Bad usages: generateKey({name: X448}, true, [wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, wrapKey])", - "Bad usages: generateKey({name: X448}, true, [unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, deriveKey, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveBits, unwrapKey])", - "Bad usages: generateKey({name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits, deriveKey, deriveBits, unwrapKey])", - "Empty usages: generateKey({name: X448}, false, [])", - "Empty usages: generateKey({name: X448}, true, [])" - ], + "failures_X448.https.any.html": true, + "failures_X448.https.any.worker.html": true, "successes_Ed25519.https.any.html": true, "successes_Ed25519.https.any.worker.html": true, "successes_Ed448.https.any.html": false, "successes_Ed448.https.any.worker.html": false, "successes_X25519.https.any.html": true, "successes_X25519.https.any.worker.html": true, - "successes_X448.https.any.html": false, - "successes_X448.https.any.worker.html": false + "successes_X448.https.any.html": true, + "successes_X448.https.any.worker.html": true }, "historical.any.html": false, "historical.any.worker.html": false, @@ -929,10 +853,6 @@ "Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])", "Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, [])", - "Good parameters: X448 bits (jwk, object(kty, crv, x), {name: X448}, true, [])", - "Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), {name: X448}, true, [])", - "Good parameters: X448 bits (raw, buffer(56), {name: X448}, true, [])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey])", "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])", "Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])", @@ -945,17 +865,10 @@ "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (spki, buffer(68), {name: X448}, false, [])", - "Good parameters: X448 bits (jwk, object(kty, crv, x), {name: X448}, false, [])", - "Good parameters: X448 bits (raw, buffer(56), {name: X448}, false, [])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveBits, deriveKey])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveBits, deriveKey])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveBits])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveBits])", - "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])" + "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])" ], "okp_importKey.https.any.worker.html": [ "Good parameters: Ed448 bits (spki, buffer(69), {name: Ed448}, true, [verify])", @@ -997,10 +910,6 @@ "Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])", "Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, [])", - "Good parameters: X448 bits (jwk, object(kty, crv, x), {name: X448}, true, [])", - "Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), {name: X448}, true, [])", - "Good parameters: X448 bits (raw, buffer(56), {name: X448}, true, [])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey])", "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])", "Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])", @@ -1013,17 +922,10 @@ "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", "Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (spki, buffer(68), {name: X448}, false, [])", - "Good parameters: X448 bits (jwk, object(kty, crv, x), {name: X448}, false, [])", - "Good parameters: X448 bits (raw, buffer(56), {name: X448}, false, [])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveBits, deriveKey])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveBits, deriveKey])", "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveBits])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveBits])", - "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", - "Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])" + "Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])" ], "okp_importKey_failures_Ed25519.https.any.html": [ "Bad key length: importKey(raw, {name: Ed25519}, true, [verify])", @@ -1103,8 +1005,62 @@ "Invalid key pair: importKey(jwk(private), {name: X25519}, true, [deriveBits])", "Invalid key pair: importKey(jwk(private), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])" ], - "okp_importKey_failures_X448.https.any.html": false, - "okp_importKey_failures_X448.https.any.worker.html": false, + "okp_importKey_failures_X448.https.any.html": [ + "Empty usages: importKey(pkcs8, {name: X448}, true, [])", + "Empty usages: importKey(pkcs8, {name: X448}, false, [])", + "Bad key length: importKey(raw, {name: X448}, true, [])", + "Bad key length: importKey(raw, {name: X448}, false, [])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveBits, deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad key length: importKey(jwk (public) , {name: X448}, true, [])", + "Bad key length: importKey(jwk (public) , {name: X448}, false, [])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveBits, deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])" + ], + "okp_importKey_failures_X448.https.any.worker.html": [ + "Empty usages: importKey(pkcs8, {name: X448}, true, [])", + "Empty usages: importKey(pkcs8, {name: X448}, false, [])", + "Bad key length: importKey(raw, {name: X448}, true, [])", + "Bad key length: importKey(raw, {name: X448}, false, [])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveBits, deriveKey])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad key length: importKey(jwk(private), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Bad key length: importKey(jwk (public) , {name: X448}, true, [])", + "Bad key length: importKey(jwk (public) , {name: X448}, false, [])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveBits, deriveKey])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Missing JWK 'x' parameter: importKey(jwk(private), {name: X448}, false, [deriveKey, deriveBits, deriveKey, deriveBits])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveKey])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits])", + "Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveKey, deriveBits, deriveKey, deriveBits])" + ], "crashtests": { "importKey-unsettled-promise.https.any.html": true, "importKey-unsettled-promise.https.any.worker.html": true @@ -1478,8 +1434,30 @@ "crypto-subtle-secure-context-available.https.sub.html": true }, "wrapKey_unwrapKey": { - "wrapKey_unwrapKey.https.any.html": true, - "wrapKey_unwrapKey.https.any.worker.html": true + "wrapKey_unwrapKey.https.any.html": [ + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-CTR", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-CTR", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-CBC", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-CBC", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-GCM", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-GCM", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-KW", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-KW", + "Can wrap and unwrap X448 private key keys using pkcs8 and RSA-OAEP", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and RSA-OAEP" + ], + "wrapKey_unwrapKey.https.any.worker.html": [ + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-CTR", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-CTR", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-CBC", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-CBC", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-GCM", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-GCM", + "Can wrap and unwrap X448 private key keys using pkcs8 and AES-KW", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and AES-KW", + "Can wrap and unwrap X448 private key keys using pkcs8 and RSA-OAEP", + "Can wrap and unwrap X448 private key keys as non-extractable using pkcs8 and RSA-OAEP" + ] } }, "console": { From 9a92603a142f8bc8bfe36d2eec3d1dd86722651b Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Mon, 7 Oct 2024 07:59:27 -0700 Subject: [PATCH 28/39] fix(ext/webstorage): make `getOwnPropertyDescriptor` with symbol return `undefined` (#13348) Closes #13347 --- ext/webstorage/01_webstorage.js | 3 +++ tests/unit/webstorage_test.ts | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/ext/webstorage/01_webstorage.js b/ext/webstorage/01_webstorage.js index 3cbdd708dd..9e86366563 100644 --- a/ext/webstorage/01_webstorage.js +++ b/ext/webstorage/01_webstorage.js @@ -143,6 +143,9 @@ function createStorage(persistent) { if (ReflectHas(target, key)) { return undefined; } + if (typeof key === "symbol") { + return undefined; + } const value = target.getItem(key); if (value === null) { return undefined; diff --git a/tests/unit/webstorage_test.ts b/tests/unit/webstorage_test.ts index 9dc560af1b..aa832b1c4b 100644 --- a/tests/unit/webstorage_test.ts +++ b/tests/unit/webstorage_test.ts @@ -50,3 +50,8 @@ Deno.test(function webstorageProxy() { assertEquals(localStorage[symbol as any], "bar"); assertEquals(symbol in localStorage, true); }); + +Deno.test(function webstorageGetOwnPropertyDescriptorSymbol() { + localStorage.clear(); + Object.getOwnPropertyDescriptor(localStorage, Symbol("foo")); +}); From fc293c68b5e08f5e2cf766cf9356cb42c904a3ca Mon Sep 17 00:00:00 2001 From: Nathan Whitaker <17734409+nathanwhit@users.noreply.github.com> Date: Mon, 7 Oct 2024 08:11:31 -0700 Subject: [PATCH 29/39] chore: remove protoc dep from CI (#26050) It shouldn't be needed anymore --- .devcontainer/Dockerfile | 3 +-- .github/workflows/cargo_publish.yml | 6 ------ .github/workflows/ci.generate.ts | 6 ------ .github/workflows/ci.yml | 6 ------ 4 files changed, 1 insertion(+), 20 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a823829419..4e7a8d7618 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,9 +1,8 @@ FROM mcr.microsoft.com/vscode/devcontainers/rust:1-bullseye -# Install cmake and protobuf-compiler +# Install cmake RUN apt-get update \ && apt-get install -y cmake \ - && apt-get install -y protobuf-compiler \ && rm -rf /var/lib/apt/lists/* # Install Deno diff --git a/.github/workflows/cargo_publish.yml b/.github/workflows/cargo_publish.yml index 45f075b579..f77286c7d4 100644 --- a/.github/workflows/cargo_publish.yml +++ b/.github/workflows/cargo_publish.yml @@ -32,12 +32,6 @@ jobs: with: deno-version: v1.x - - name: Install protoc - uses: arduino/setup-protoc@v3 - with: - version: '21.12' - repo-token: '${{ secrets.GITHUB_TOKEN }}' - - name: Publish env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/.github/workflows/ci.generate.ts b/.github/workflows/ci.generate.ts index 95404d245e..28130efab6 100755 --- a/.github/workflows/ci.generate.ts +++ b/.github/workflows/ci.generate.ts @@ -191,11 +191,6 @@ const installNodeStep = { uses: "actions/setup-node@v4", with: { "node-version": 18 }, }; -const installProtocStep = { - name: "Install protoc", - uses: "arduino/setup-protoc@v3", - with: { "version": "21.12", "repo-token": "${{ secrets.GITHUB_TOKEN }}" }, -}; const installDenoStep = { name: "Install Deno", uses: "denoland/setup-deno@v1", @@ -494,7 +489,6 @@ const ci = { if: "matrix.job == 'bench' || matrix.job == 'test'", ...installNodeStep, }, - installProtocStep, { if: [ "matrix.profile == 'release' &&", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c114286a2c..339c38b717 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,12 +199,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - - name: Install protoc - uses: arduino/setup-protoc@v3 - with: - version: '21.12' - repo-token: '${{ secrets.GITHUB_TOKEN }}' - if: '!(matrix.skip)' - if: |- !(matrix.skip) && (matrix.profile == 'release' && matrix.job == 'test' && From 719b8dcfde074e2347f0305bd2dec170fd9c4b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 7 Oct 2024 17:45:50 +0100 Subject: [PATCH 30/39] feat(lsp): add a message when someone runs 'deno lsp' manually (#26051) --- cli/main.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cli/main.rs b/cli/main.rs index 93bd97e2aa..ddb6078af4 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -57,6 +57,7 @@ use standalone::MODULE_NOT_FOUND; use standalone::UNSUPPORTED_SCHEME; use std::env; use std::future::Future; +use std::io::IsTerminal; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -161,7 +162,19 @@ async fn run_subcommand(flags: Arc) -> Result { DenoSubcommand::Uninstall(uninstall_flags) => spawn_subcommand(async { tools::installer::uninstall(flags, uninstall_flags).await }), - DenoSubcommand::Lsp => spawn_subcommand(async { lsp::start().await }), + DenoSubcommand::Lsp => spawn_subcommand(async { + if std::io::stderr().is_terminal() { + log::warn!( + "{} command is intended to be run by text editors and IDEs and shouldn't be run manually. + + Visit https://docs.deno.com/runtime/getting_started/setup_your_environment/ for instruction + how to setup your favorite text editor. + + Press Ctrl+C to exit. + ", colors::cyan("deno lsp")); + } + lsp::start().await + }), DenoSubcommand::Lint(lint_flags) => spawn_subcommand(async { if lint_flags.rules { tools::lint::print_rules_list( From 053894b9e0899757f156b8cd956fd467e0e11a63 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Mon, 7 Oct 2024 18:20:45 +0100 Subject: [PATCH 31/39] fix(lsp): exclude missing import quick fixes with bad resolutions (#26025) --- cli/lsp/analysis.rs | 48 ++++++++++++++++++------ cli/lsp/language_server.rs | 1 + tests/integration/lsp_tests.rs | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index d189ab2534..4890221d9e 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -228,6 +228,7 @@ pub struct TsResponseImportMapper<'a> { documents: &'a Documents, maybe_import_map: Option<&'a ImportMap>, resolver: &'a LspResolver, + file_referrer: ModuleSpecifier, } impl<'a> TsResponseImportMapper<'a> { @@ -235,11 +236,13 @@ impl<'a> TsResponseImportMapper<'a> { documents: &'a Documents, maybe_import_map: Option<&'a ImportMap>, resolver: &'a LspResolver, + file_referrer: &ModuleSpecifier, ) -> Self { Self { documents, maybe_import_map, resolver, + file_referrer: file_referrer.clone(), } } @@ -260,8 +263,6 @@ impl<'a> TsResponseImportMapper<'a> { } } - let file_referrer = self.documents.get_file_referrer(referrer); - if let Some(jsr_path) = specifier.as_str().strip_prefix(jsr_url().as_str()) { let mut segments = jsr_path.split('/'); @@ -276,7 +277,7 @@ impl<'a> TsResponseImportMapper<'a> { let export = self.resolver.jsr_lookup_export_for_path( &nv, &path, - file_referrer.as_deref(), + Some(&self.file_referrer), )?; let sub_path = (export != ".").then_some(export); let mut req = None; @@ -302,7 +303,7 @@ impl<'a> TsResponseImportMapper<'a> { req = req.or_else(|| { self .resolver - .jsr_lookup_req_for_nv(&nv, file_referrer.as_deref()) + .jsr_lookup_req_for_nv(&nv, Some(&self.file_referrer)) }); let spec_str = if let Some(req) = req { let req_ref = PackageReqReference { req, sub_path }; @@ -332,7 +333,7 @@ impl<'a> TsResponseImportMapper<'a> { if let Some(npm_resolver) = self .resolver - .maybe_managed_npm_resolver(file_referrer.as_deref()) + .maybe_managed_npm_resolver(Some(&self.file_referrer)) { if npm_resolver.in_npm_package(specifier) { if let Ok(Some(pkg_id)) = @@ -468,6 +469,26 @@ impl<'a> TsResponseImportMapper<'a> { } None } + + pub fn is_valid_import( + &self, + specifier_text: &str, + referrer: &ModuleSpecifier, + ) -> bool { + self + .resolver + .as_graph_resolver(Some(&self.file_referrer)) + .resolve( + specifier_text, + &deno_graph::Range { + specifier: referrer.clone(), + start: deno_graph::Position::zeroed(), + end: deno_graph::Position::zeroed(), + }, + deno_graph::source::ResolutionMode::Types, + ) + .is_ok() + } } fn try_reverse_map_package_json_exports( @@ -580,7 +601,7 @@ fn fix_ts_import_action( referrer: &ModuleSpecifier, action: &tsc::CodeFixAction, import_mapper: &TsResponseImportMapper, -) -> Result { +) -> Result, AnyError> { if matches!( action.fix_name.as_str(), "import" | "fixMissingFunctionDeclaration" @@ -623,19 +644,21 @@ fn fix_ts_import_action( }) .collect(); - return Ok(tsc::CodeFixAction { + return Ok(Some(tsc::CodeFixAction { description, changes, commands: None, fix_name: action.fix_name.clone(), fix_id: None, fix_all_description: None, - }); + })); + } else if !import_mapper.is_valid_import(specifier, referrer) { + return Ok(None); } } } - Ok(action.clone()) + Ok(Some(action.clone())) } /// Determines if two TypeScript diagnostic codes are effectively equivalent. @@ -976,11 +999,14 @@ impl CodeActionCollection { "The action returned from TypeScript is unsupported.", )); } - let action = fix_ts_import_action( + let Some(action) = fix_ts_import_action( specifier, action, &language_server.get_ts_response_import_mapper(specifier), - )?; + )? + else { + return Ok(()); + }; let edit = ts_changes_to_edit(&action.changes, language_server)?; let code_action = lsp::CodeAction { title: action.description.clone(), diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 90a2579f4d..8269dc8515 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -1918,6 +1918,7 @@ impl Inner { // as the import map is an implementation detail .and_then(|d| d.resolver.maybe_import_map()), self.resolver.as_ref(), + file_referrer, ) } diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs index fc54375947..19ea89a54b 100644 --- a/tests/integration/lsp_tests.rs +++ b/tests/integration/lsp_tests.rs @@ -8504,6 +8504,74 @@ fn lsp_completions_auto_import_and_quick_fix_with_import_map() { client.shutdown(); } +// Regression test for https://github.com/denoland/deno/issues/25775. +#[test] +fn lsp_quick_fix_missing_import_exclude_bare_node_builtins() { + let context = TestContextBuilder::new() + .use_http_server() + .use_temp_cwd() + .add_npm_env_vars() + .build(); + let temp_dir = context.temp_dir(); + temp_dir.write( + "package.json", + json!({ + "dependencies": { + "@types/node": "*", + }, + }) + .to_string(), + ); + context.run_npm("install"); + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + let diagnostics = client.did_open(json!({ + "textDocument": { + "uri": temp_dir.url().join("file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + // Include node:buffer import to ensure @types/node is in the dep graph. + "text": "import \"node:buffer\";\nassert();\n", + }, + })); + let diagnostic = diagnostics + .all() + .into_iter() + .find(|d| d.message == "Cannot find name 'assert'.") + .unwrap(); + let res = client.write_request( + "textDocument/codeAction", + json!({ + "textDocument": { + "uri": temp_dir.url().join("file.ts").unwrap(), + }, + "range": { + "start": { "line": 1, "character": 0 }, + "end": { "line": 1, "character": 6 }, + }, + "context": { + "diagnostics": [&diagnostic], + "only": ["quickfix"], + }, + }), + ); + let code_actions = + serde_json::from_value::>(res).unwrap(); + let titles = code_actions + .iter() + .map(|a| a.title.clone()) + .collect::>(); + assert_eq!( + json!(titles), + json!([ + "Add import from \"node:assert\"", + "Add import from \"node:console\"", + "Add missing function declaration 'assert'", + ]), + ); + client.shutdown(); +} + #[test] fn lsp_completions_snippet() { let context = TestContextBuilder::new().use_temp_cwd().build(); From 2d488e4bfb9ffdfd2d043cc4bba9e6037b4cc24e Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Tue, 8 Oct 2024 12:10:19 +0200 Subject: [PATCH 32/39] fix(console): missing cause property on non-error objects (#26061) Fixes https://github.com/denoland/deno/issues/26047 --- ext/console/01_console.js | 4 +++- tests/unit/console_test.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ext/console/01_console.js b/ext/console/01_console.js index 1ca23d5a49..d9acc958a0 100644 --- a/ext/console/01_console.js +++ b/ext/console/01_console.js @@ -1301,7 +1301,9 @@ function getKeys(value, showHidden) { ArrayPrototypePushApply(keys, ArrayPrototypeFilter(symbols, filter)); } } - keys = ArrayPrototypeFilter(keys, (key) => key !== "cause"); + if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, value)) { + keys = ArrayPrototypeFilter(keys, (key) => key !== "cause"); + } return keys; } diff --git a/tests/unit/console_test.ts b/tests/unit/console_test.ts index 201d18f004..878d17ae33 100644 --- a/tests/unit/console_test.ts +++ b/tests/unit/console_test.ts @@ -1913,6 +1913,21 @@ Deno.test(function consoleLogWhenCauseIsAssignedShouldNotPrintCauseTwice() { }); }); +Deno.test(function consoleLogCauseNotFilteredOnNonError() { + mockConsole((console, out) => { + const foo = { + a: 1, + b: 2, + cause: 3, + }; + console.log(foo); + + const result = stripAnsiCode(out.toString()); + const expected = "{ a: 1, b: 2, cause: 3 }\n"; + assertEquals(result.trim(), expected.trim()); + }); +}); + // console.log(new Proxy(new RegExp(), {})) Deno.test(function consoleLogShouldNotThrowErrorWhenInputIsProxiedRegExp() { mockConsole((console, out) => { From ff4e682ff95af37b52c404d694ffcfcfa57bb127 Mon Sep 17 00:00:00 2001 From: Satya Rohith Date: Tue, 8 Oct 2024 16:11:32 +0530 Subject: [PATCH 33/39] fix(ext/node): internal buffer length in readSync (#26064) Closes https://github.com/denoland/deno/issues/26054 --- ext/node/polyfills/_fs/_fs_read.ts | 2 +- tests/unit_node/fs_test.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ext/node/polyfills/_fs/_fs_read.ts b/ext/node/polyfills/_fs/_fs_read.ts index dec3a8bbdf..df4f5e375d 100644 --- a/ext/node/polyfills/_fs/_fs_read.ts +++ b/ext/node/polyfills/_fs/_fs_read.ts @@ -173,7 +173,7 @@ export function readSync( validateBuffer(buffer); if (length == null) { - length = 0; + length = buffer.byteLength; } if (typeof offsetOrOpt === "number") { diff --git a/tests/unit_node/fs_test.ts b/tests/unit_node/fs_test.ts index b1f7c53e8d..2d1465aec6 100644 --- a/tests/unit_node/fs_test.ts +++ b/tests/unit_node/fs_test.ts @@ -4,13 +4,16 @@ import { assert, assertEquals, assertThrows } from "@std/assert"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { + closeSync, constants, createWriteStream, existsSync, lstatSync, mkdtempSync, + openSync, promises, readFileSync, + readSync, Stats, statSync, writeFileSync, @@ -201,3 +204,11 @@ Deno.test( assertEquals(res, [0, 1, 2, 3, 4, 5]); }, ); + +Deno.test("[node/fs] readSync works", () => { + const fd = openSync("tests/testdata/assets/hello.txt", "r"); + const buf = new Uint8Array(256); + const bytesRead = readSync(fd!, buf); + assertEquals(bytesRead, 12); + closeSync(fd!); +}); From 3fc9e49613547bbedcad1b02361db40c7f513b1f Mon Sep 17 00:00:00 2001 From: David Sherret Date: Tue, 8 Oct 2024 12:48:29 +0100 Subject: [PATCH 34/39] refactor: remove usage of full_range (#26065) For https://github.com/denoland/deno_graph/pull/538/files This was removed because the deserialization was not backwards compatible. --- Cargo.lock | 4 ++-- cli/Cargo.toml | 2 +- cli/lsp/analysis.rs | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a63da555de..75101170cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1612,9 +1612,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.83.1" +version = "0.83.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c62ce152f24a4c0580e7a91431f75de48281157cf645459de8e9d7268dd95b2" +checksum = "77163c46755676d8f793fc19e365537ba660a8db173cd1e02d21eb010c0b3cef" dependencies = [ "anyhow", "async-trait", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index e0a4b4e7c1..bdb47c98ed 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -68,7 +68,7 @@ deno_cache_dir = { workspace = true } deno_config = { version = "=0.37.1", features = ["workspace", "sync"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } deno_doc = { version = "0.150.1", features = ["html", "syntect"] } -deno_graph = { version = "=0.83.1" } +deno_graph = { version = "=0.83.3" } deno_lint = { version = "=0.67.0", features = ["docs"] } deno_lockfile.workspace = true deno_npm.workspace = true diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index 4890221d9e..8c2e8bb1dc 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -44,6 +44,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::collections::HashSet; use std::path::Path; +use text_lines::LineAndColumnIndex; use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types::Position; use tower_lsp::lsp_types::Range; @@ -1187,6 +1188,34 @@ impl CodeActionCollection { range: &lsp::Range, language_server: &language_server::Inner, ) { + fn import_start_from_specifier( + document: &Document, + import: &deno_graph::Import, + ) -> Option { + // find the top level statement that contains the specifier + let parsed_source = document.maybe_parsed_source()?.as_ref().ok()?; + let text_info = parsed_source.text_info_lazy(); + let specifier_range = SourceRange::new( + text_info.loc_to_source_pos(LineAndColumnIndex { + line_index: import.specifier_range.start.line, + column_index: import.specifier_range.start.character, + }), + text_info.loc_to_source_pos(LineAndColumnIndex { + line_index: import.specifier_range.end.line, + column_index: import.specifier_range.end.character, + }), + ); + + match parsed_source.program_ref() { + deno_ast::swc::ast::Program::Module(module) => module + .body + .iter() + .find(|i| i.range().contains(&specifier_range)) + .map(|i| text_info.line_and_column_index(i.range().start)), + deno_ast::swc::ast::Program::Script(_) => None, + } + } + async fn deno_types_for_npm_action( document: &Document, range: &lsp::Range, @@ -1207,14 +1236,15 @@ impl CodeActionCollection { range.end.line as usize, range.end.character as usize, ); - let import_range = dependency.imports.iter().find_map(|i| { + let import_start = dependency.imports.iter().find_map(|i| { if json!(i.kind) != json!("es") && json!(i.kind) != json!("tsType") { return None; } if !i.specifier_range.includes(&position) { return None; } - i.full_range.as_ref() + + import_start_from_specifier(document, i) })?; let referrer = document.specifier(); let file_referrer = document.file_referrer(); @@ -1301,8 +1331,8 @@ impl CodeActionCollection { .specifier_to_uri(referrer, file_referrer) .ok()?; let position = lsp::Position { - line: import_range.start.line as u32, - character: import_range.start.character as u32, + line: import_start.line_index as u32, + character: import_start.column_index as u32, }; let new_text = format!( "{}// @deno-types=\"{}\"\n", From b2504b7b4d6c17d415d48be2b744aecdcc27a8ff Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Tue, 8 Oct 2024 06:15:28 -0700 Subject: [PATCH 35/39] fix: disable same-origin.html WPT (#26067) It's very flaky on CI --- tests/wpt/runner/expectation.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/wpt/runner/expectation.json b/tests/wpt/runner/expectation.json index ce73f5d05d..3477d8d9bf 100644 --- a/tests/wpt/runner/expectation.json +++ b/tests/wpt/runner/expectation.json @@ -11625,9 +11625,6 @@ "ctor-1.html": false, "ctor-null.html": false, "ctor-undefined.html": false, - "same-origin.html": [ - "non-parsable URL" - ], "terminate.html": true, "use-base-url.html": false }, From 94adfeec78ae66d29e186f21e85efee2f179558f Mon Sep 17 00:00:00 2001 From: Leo Kettmeir Date: Tue, 8 Oct 2024 06:55:44 -0700 Subject: [PATCH 36/39] fix: use tree-sitter for deno_doc (#26066) --- Cargo.lock | 374 ++++++++++++++++++++--------------------------- Cargo.toml | 2 +- cli/Cargo.toml | 2 +- cli/tools/doc.rs | 9 +- 4 files changed, 166 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75101170cd..911613b1b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,19 +128,6 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" -[[package]] -name = "ammonia" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170" -dependencies = [ - "html5ever", - "maplit", - "once_cell", - "tendril", - "url", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -651,12 +638,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.10" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -860,9 +848,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comrak" -version = "0.26.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ab67843c57df5a4ee29d610740828dbc928cc64ecf0f2a1d5cd0e98e107a9" +checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" dependencies = [ "caseless", "derive_builder", @@ -1242,7 +1230,7 @@ dependencies = [ "p256", "pathdiff", "percent-encoding", - "phf 0.11.2", + "phf", "pretty_assertions", "pretty_yaml", "quick-junit", @@ -1415,7 +1403,7 @@ dependencies = [ "jsonc-parser", "log", "percent-encoding", - "phf 0.11.2", + "phf", "serde", "serde_json", "thiserror", @@ -1516,11 +1504,10 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.150.1" +version = "0.152.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0841188bc852535b76e53be6c3d13c61cfc6751a731969b8959fe31fa696c73f" +checksum = "a8d237256ad99d6064b271324485120028e843329fd0fa0e93175d5e98f17033" dependencies = [ - "ammonia", "anyhow", "cfg-if", "comrak", @@ -1536,8 +1523,18 @@ dependencies = [ "regex", "serde", "serde_json", - "syntect", "termcolor", + "tree-sitter-bash", + "tree-sitter-css", + "tree-sitter-highlight", + "tree-sitter-html", + "tree-sitter-javascript", + "tree-sitter-json", + "tree-sitter-md", + "tree-sitter-regex", + "tree-sitter-rust", + "tree-sitter-typescript", + "tree-sitter-xml", ] [[package]] @@ -1666,7 +1663,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "phf 0.11.2", + "phf", "pin-project", "rand", "ring", @@ -1741,7 +1738,7 @@ dependencies = [ "if_chain", "log", "once_cell", - "phf 0.11.2", + "phf", "regex", "serde", "serde_json", @@ -3180,16 +3177,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures" version = "0.3.30" @@ -3488,9 +3475,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "ce25b617d1375ef96eeb920ae717e3da34a02fc979fe632c75128350f9e1f74a" dependencies = [ "heck 0.5.0", "log", @@ -3606,7 +3593,7 @@ dependencies = [ "hashbrown", "new_debug_unreachable", "once_cell", - "phf 0.11.2", + "phf", "rustc-hash 1.1.0", "triomphe", ] @@ -3620,20 +3607,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "http" version = "0.2.12" @@ -4212,9 +4185,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.30.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "6b694a822684ddb75df4d657029161431bcb4a85c1856952f845b76912bc6fec" dependencies = [ "cc", "pkg-config", @@ -4246,9 +4219,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "cmake", @@ -4316,12 +4289,6 @@ dependencies = [ "serde_repr", ] -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - [[package]] name = "malloc_buf" version = "0.0.6" @@ -4344,26 +4311,6 @@ dependencies = [ "tiny_pretty", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen", - "string_cache", - "string_cache_codegen", - "tendril", -] - [[package]] name = "markup_fmt" version = "0.13.1" @@ -4786,28 +4733,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags 1.3.2", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "opaque-debug" version = "0.3.1" @@ -5059,15 +4984,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - [[package]] name = "phf" version = "0.11.2" @@ -5075,27 +4991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand", + "phf_shared", ] [[package]] @@ -5104,7 +5000,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ - "phf_shared 0.11.2", + "phf_shared", "rand", ] @@ -5114,22 +5010,13 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.72", ] -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - [[package]] name = "phf_shared" version = "0.11.2" @@ -5252,12 +5139,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "pretty_assertions" version = "1.4.0" @@ -5891,9 +5772,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.32.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +checksum = "1cdbe9230a57259b37f7257d0aff38b8c9dbda3513edba2105e59b130189d82f" dependencies = [ "bitflags 2.6.0", "fallible-iterator", @@ -6588,32 +6469,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - [[package]] name = "string_enum" version = "0.4.4" @@ -6800,7 +6655,7 @@ dependencies = [ "bitflags 2.6.0", "is-macro", "num-bigint", - "phf 0.11.2", + "phf", "scoped-tls", "serde", "string_enum", @@ -6864,7 +6719,7 @@ dependencies = [ "new_debug_unreachable", "num-bigint", "num-traits", - "phf 0.11.2", + "phf", "serde", "smallvec", "smartstring", @@ -6886,7 +6741,7 @@ dependencies = [ "bitflags 2.6.0", "indexmap", "once_cell", - "phf 0.11.2", + "phf", "rustc-hash 1.1.0", "serde", "smallvec", @@ -7166,26 +7021,6 @@ dependencies = [ "syn 2.0.72", ] -[[package]] -name = "syntect" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" -dependencies = [ - "bincode", - "bitflags 1.3.2", - "flate2", - "fnv", - "once_cell", - "onig", - "regex-syntax", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "walkdir", -] - [[package]] name = "tap" version = "1.0.1" @@ -7215,17 +7050,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - [[package]] name = "termcolor" version = "1.4.1" @@ -7628,6 +7452,128 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tree-sitter" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7cc499ceadd4dcdf7ec6d4cbc34ece92c3fa07821e287aedecd4416c516dca" +dependencies = [ + "cc", + "regex", +] + +[[package]] +name = "tree-sitter-bash" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5244703ad2e08a616d859a0557d7aa290adcd5e0990188a692e628ffe9dce40" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-css" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e08e324b1cf60fd3291774b49724c66de2ce8fcf4d358d0b4b82e37b41b1c9b" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-highlight" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaca0fe34fa96eec6aaa8e63308dbe1bafe65a6317487c287f93938959b21907" +dependencies = [ + "lazy_static", + "regex", + "thiserror", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-html" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8766b5ad3721517f8259e6394aefda9c686aebf7a8c74ab8624f2c3b46902fd5" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-javascript" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8710a71bc6779e33811a8067bdda3ed08bed1733296ff915e44faf60f8c533d7" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-json" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b737dcb73c35d74b7d64a5f3dde158113c86a012bf3cee2bfdf2150d23b05db" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-md" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c3cfd068f2527250bbd8ff407431164e12b17863e7eafb76e311dd3f96965a" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-regex" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ff1286fe9651b2797484839ffa37aa76c8618d4ccb6836d7e31765dfd60c0d5" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-rust" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "277690f420bf90741dea984f3da038ace46c4fe6047cba57a66822226cde1c93" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-typescript" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb35d98a688378e56c18c9c159824fd16f730ccbea19aacf4f206e5d5438ed9" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-xml" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c3a1b08e9842143f84fde1a18ac40ee77ca80a80b14077e4ca67a3b4808b8b" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "triomphe" version = "0.1.13" diff --git a/Cargo.toml b/Cargo.toml index 734c3665e4..f505ac9169 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -139,7 +139,7 @@ ipnet = "2.3" jsonc-parser = { version = "=0.23.0", features = ["serde"] } lazy-regex = "3" libc = "0.2.126" -libz-sys = { version = "1.1", default-features = false } +libz-sys = { version = "1.1.20", default-features = false } log = "0.4.20" lsp-types = "=0.97.0" # used by tower-lsp and "proposed" feature is unstable in patch releases memmem = "0.1.1" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index bdb47c98ed..d2ee5f76ac 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -67,7 +67,7 @@ deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposa deno_cache_dir = { workspace = true } deno_config = { version = "=0.37.1", features = ["workspace", "sync"] } deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] } -deno_doc = { version = "0.150.1", features = ["html", "syntect"] } +deno_doc = { version = "0.152.0", features = ["html"] } deno_graph = { version = "=0.83.3" } deno_lint = { version = "=0.67.0", features = ["docs"] } deno_lockfile.workspace = true diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 8f37632c84..5e18546a28 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -195,7 +195,7 @@ pub async fn doc( kind_with_drilldown: deno_doc::html::DocNodeKindWithDrilldown::Other(node.kind()), inner: Rc::new(node), - drilldown_parent_kind: None, + drilldown_name: None, parent: None, }) .collect::>(), @@ -262,7 +262,7 @@ pub async fn doc( } struct DocResolver { - deno_ns: std::collections::HashSet>, + deno_ns: std::collections::HashMap, Option>>, strip_trailing_html: bool, } @@ -286,7 +286,7 @@ impl deno_doc::html::HrefResolver for DocResolver { } fn resolve_global_symbol(&self, symbol: &[String]) -> Option { - if self.deno_ns.contains(symbol) { + if self.deno_ns.contains_key(symbol) { Some(format!( "https://deno.land/api@v{}?s={}", env!("CARGO_PKG_VERSION"), @@ -455,7 +455,7 @@ impl deno_doc::html::HrefResolver for NodeDocResolver { fn generate_docs_directory( doc_nodes_by_url: IndexMap>, html_options: &DocHtmlFlag, - deno_ns: std::collections::HashSet>, + deno_ns: std::collections::HashMap, Option>>, rewrite_map: Option>, ) -> Result<(), AnyError> { let cwd = std::env::current_dir().context("Failed to get CWD")?; @@ -513,7 +513,6 @@ fn generate_docs_directory( rewrite_map, href_resolver, usage_composer: None, - composable_output: false, category_docs, disable_search: internal_env.is_some(), symbol_redirect_map, From a62c7e036ab6851c0293f407ead635a7331445b7 Mon Sep 17 00:00:00 2001 From: denobot <33910674+denobot@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:37:28 -0400 Subject: [PATCH 37/39] 2.0.0 (#26063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumped versions for 2.0.0 Co-authored-by: bartlomieju Co-authored-by: Bartek Iwańczuk --- .github/workflows/ci.generate.ts | 2 +- .github/workflows/ci.yml | 8 +- Cargo.lock | 58 +++--- Cargo.toml | 56 ++--- Releases.md | 343 +++++++++++++++++++++++++++++++ bench_util/Cargo.toml | 2 +- cli/Cargo.toml | 2 +- cli/napi/sym/Cargo.toml | 2 +- ext/broadcast_channel/Cargo.toml | 2 +- ext/cache/Cargo.toml | 2 +- ext/canvas/Cargo.toml | 2 +- ext/console/Cargo.toml | 2 +- ext/cron/Cargo.toml | 2 +- ext/crypto/Cargo.toml | 2 +- ext/fetch/Cargo.toml | 2 +- ext/ffi/Cargo.toml | 2 +- ext/fs/Cargo.toml | 2 +- ext/http/Cargo.toml | 2 +- ext/io/Cargo.toml | 2 +- ext/kv/Cargo.toml | 2 +- ext/napi/Cargo.toml | 2 +- ext/net/Cargo.toml | 2 +- ext/node/Cargo.toml | 2 +- ext/tls/Cargo.toml | 2 +- ext/url/Cargo.toml | 2 +- ext/web/Cargo.toml | 2 +- ext/webgpu/Cargo.toml | 2 +- ext/webidl/Cargo.toml | 2 +- ext/websocket/Cargo.toml | 2 +- ext/webstorage/Cargo.toml | 2 +- resolvers/deno/Cargo.toml | 2 +- resolvers/node/Cargo.toml | 2 +- runtime/Cargo.toml | 2 +- runtime/permissions/Cargo.toml | 2 +- 34 files changed, 434 insertions(+), 91 deletions(-) diff --git a/.github/workflows/ci.generate.ts b/.github/workflows/ci.generate.ts index 28130efab6..c03f10bc92 100755 --- a/.github/workflows/ci.generate.ts +++ b/.github/workflows/ci.generate.ts @@ -5,7 +5,7 @@ import { stringify } from "jsr:@std/yaml@^0.221/stringify"; // Bump this number when you want to purge the cache. // Note: the tools/release/01_bump_crate_versions.ts script will update this version // automatically via regex, so ensure that this line maintains this format. -const cacheVersion = 17; +const cacheVersion = 18; const ubuntuX86Runner = "ubuntu-22.04"; const ubuntuX86XlRunner = "ubuntu-22.04-xl"; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 339c38b717..701d67f93c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -361,8 +361,8 @@ jobs: path: |- ~/.cargo/registry/index ~/.cargo/registry/cache - key: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' - restore-keys: '17-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' + key: '18-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}' + restore-keys: '18-cargo-home-${{ matrix.os }}-${{ matrix.arch }}' if: '!(matrix.skip)' - name: Restore cache build output (PR) uses: actions/cache/restore@v4 @@ -375,7 +375,7 @@ jobs: !./target/*/*.zip !./target/*/*.tar.gz key: never_saved - restore-keys: '17-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' + restore-keys: '18-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-' - name: Apply and update mtime cache if: '!(matrix.skip) && (!startsWith(github.ref, ''refs/tags/''))' uses: ./.github/mtime_cache @@ -685,7 +685,7 @@ jobs: !./target/*/*.zip !./target/*/*.sha256sum !./target/*/*.tar.gz - key: '17-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' + key: '18-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}' publish-canary: name: publish canary runs-on: ubuntu-22.04 diff --git a/Cargo.lock b/Cargo.lock index 911613b1b4..c5abeb3d40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1154,7 +1154,7 @@ dependencies = [ [[package]] name = "deno" -version = "2.0.0-rc.10" +version = "2.0.0" dependencies = [ "anstream", "async-trait", @@ -1327,7 +1327,7 @@ dependencies = [ [[package]] name = "deno_bench_util" -version = "0.164.0" +version = "0.165.0" dependencies = [ "bencher", "deno_core", @@ -1336,7 +1336,7 @@ dependencies = [ [[package]] name = "deno_broadcast_channel" -version = "0.164.0" +version = "0.165.0" dependencies = [ "async-trait", "deno_core", @@ -1346,7 +1346,7 @@ dependencies = [ [[package]] name = "deno_cache" -version = "0.102.0" +version = "0.103.0" dependencies = [ "async-trait", "deno_core", @@ -1378,7 +1378,7 @@ dependencies = [ [[package]] name = "deno_canvas" -version = "0.39.0" +version = "0.40.0" dependencies = [ "deno_core", "deno_webgpu", @@ -1412,7 +1412,7 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.170.0" +version = "0.171.0" dependencies = [ "deno_core", ] @@ -1457,7 +1457,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" [[package]] name = "deno_cron" -version = "0.50.0" +version = "0.51.0" dependencies = [ "anyhow", "async-trait", @@ -1469,7 +1469,7 @@ dependencies = [ [[package]] name = "deno_crypto" -version = "0.184.0" +version = "0.185.0" dependencies = [ "aes", "aes-gcm", @@ -1539,7 +1539,7 @@ dependencies = [ [[package]] name = "deno_fetch" -version = "0.194.0" +version = "0.195.0" dependencies = [ "base64 0.21.7", "bytes", @@ -1571,7 +1571,7 @@ dependencies = [ [[package]] name = "deno_ffi" -version = "0.157.0" +version = "0.158.0" dependencies = [ "deno_core", "deno_permissions", @@ -1588,7 +1588,7 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.80.0" +version = "0.81.0" dependencies = [ "async-trait", "base32", @@ -1638,7 +1638,7 @@ dependencies = [ [[package]] name = "deno_http" -version = "0.168.0" +version = "0.169.0" dependencies = [ "async-compression", "async-trait", @@ -1677,7 +1677,7 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.80.0" +version = "0.81.0" dependencies = [ "async-trait", "deno_core", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "deno_kv" -version = "0.78.0" +version = "0.79.0" dependencies = [ "anyhow", "async-trait", @@ -1769,7 +1769,7 @@ dependencies = [ [[package]] name = "deno_napi" -version = "0.101.0" +version = "0.102.0" dependencies = [ "deno_core", "deno_permissions", @@ -1791,7 +1791,7 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.162.0" +version = "0.163.0" dependencies = [ "deno_core", "deno_permissions", @@ -1807,7 +1807,7 @@ dependencies = [ [[package]] name = "deno_node" -version = "0.107.0" +version = "0.108.0" dependencies = [ "aead-gcm-stream", "aes", @@ -1956,7 +1956,7 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.30.0" +version = "0.31.0" dependencies = [ "deno_core", "deno_path_util", @@ -1973,7 +1973,7 @@ dependencies = [ [[package]] name = "deno_resolver" -version = "0.2.0" +version = "0.3.0" dependencies = [ "anyhow", "base32", @@ -1989,7 +1989,7 @@ dependencies = [ [[package]] name = "deno_runtime" -version = "0.179.0" +version = "0.180.0" dependencies = [ "deno_ast", "deno_broadcast_channel", @@ -2104,7 +2104,7 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.157.0" +version = "0.158.0" dependencies = [ "deno_core", "deno_native_certs", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.170.0" +version = "0.171.0" dependencies = [ "deno_bench_util", "deno_console", @@ -2163,7 +2163,7 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.201.0" +version = "0.202.0" dependencies = [ "async-trait", "base64-simd 0.8.0", @@ -2184,7 +2184,7 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.137.0" +version = "0.138.0" dependencies = [ "deno_core", "raw-window-handle", @@ -2196,7 +2196,7 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.170.0" +version = "0.171.0" dependencies = [ "deno_bench_util", "deno_core", @@ -2204,7 +2204,7 @@ dependencies = [ [[package]] name = "deno_websocket" -version = "0.175.0" +version = "0.176.0" dependencies = [ "bytes", "deno_core", @@ -2225,7 +2225,7 @@ dependencies = [ [[package]] name = "deno_webstorage" -version = "0.165.0" +version = "0.166.0" dependencies = [ "deno_core", "deno_web", @@ -4488,7 +4488,7 @@ dependencies = [ [[package]] name = "napi_sym" -version = "0.100.0" +version = "0.101.0" dependencies = [ "quote", "serde", @@ -4557,7 +4557,7 @@ dependencies = [ [[package]] name = "node_resolver" -version = "0.9.0" +version = "0.10.0" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index f505ac9169..d811d44b53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,16 +48,16 @@ repository = "https://github.com/denoland/deno" deno_ast = { version = "=0.42.1", features = ["transpiling"] } deno_core = { version = "0.311.0" } -deno_bench_util = { version = "0.164.0", path = "./bench_util" } +deno_bench_util = { version = "0.165.0", path = "./bench_util" } deno_lockfile = "=0.23.1" deno_media_type = { version = "0.1.4", features = ["module_specifier"] } deno_npm = "=0.25.3" deno_path_util = "=0.2.0" -deno_permissions = { version = "0.30.0", path = "./runtime/permissions" } -deno_runtime = { version = "0.179.0", path = "./runtime" } +deno_permissions = { version = "0.31.0", path = "./runtime/permissions" } +deno_runtime = { version = "0.180.0", path = "./runtime" } deno_semver = "=0.5.14" deno_terminal = "0.2.0" -napi_sym = { version = "0.100.0", path = "./cli/napi/sym" } +napi_sym = { version = "0.101.0", path = "./cli/napi/sym" } test_util = { package = "test_server", path = "./tests/util/server" } denokv_proto = "0.8.1" @@ -66,32 +66,32 @@ denokv_remote = "0.8.1" denokv_sqlite = { default-features = false, version = "0.8.2" } # exts -deno_broadcast_channel = { version = "0.164.0", path = "./ext/broadcast_channel" } -deno_cache = { version = "0.102.0", path = "./ext/cache" } -deno_canvas = { version = "0.39.0", path = "./ext/canvas" } -deno_console = { version = "0.170.0", path = "./ext/console" } -deno_cron = { version = "0.50.0", path = "./ext/cron" } -deno_crypto = { version = "0.184.0", path = "./ext/crypto" } -deno_fetch = { version = "0.194.0", path = "./ext/fetch" } -deno_ffi = { version = "0.157.0", path = "./ext/ffi" } -deno_fs = { version = "0.80.0", path = "./ext/fs" } -deno_http = { version = "0.168.0", path = "./ext/http" } -deno_io = { version = "0.80.0", path = "./ext/io" } -deno_kv = { version = "0.78.0", path = "./ext/kv" } -deno_napi = { version = "0.101.0", path = "./ext/napi" } -deno_net = { version = "0.162.0", path = "./ext/net" } -deno_node = { version = "0.107.0", path = "./ext/node" } -deno_tls = { version = "0.157.0", path = "./ext/tls" } -deno_url = { version = "0.170.0", path = "./ext/url" } -deno_web = { version = "0.201.0", path = "./ext/web" } -deno_webgpu = { version = "0.137.0", path = "./ext/webgpu" } -deno_webidl = { version = "0.170.0", path = "./ext/webidl" } -deno_websocket = { version = "0.175.0", path = "./ext/websocket" } -deno_webstorage = { version = "0.165.0", path = "./ext/webstorage" } +deno_broadcast_channel = { version = "0.165.0", path = "./ext/broadcast_channel" } +deno_cache = { version = "0.103.0", path = "./ext/cache" } +deno_canvas = { version = "0.40.0", path = "./ext/canvas" } +deno_console = { version = "0.171.0", path = "./ext/console" } +deno_cron = { version = "0.51.0", path = "./ext/cron" } +deno_crypto = { version = "0.185.0", path = "./ext/crypto" } +deno_fetch = { version = "0.195.0", path = "./ext/fetch" } +deno_ffi = { version = "0.158.0", path = "./ext/ffi" } +deno_fs = { version = "0.81.0", path = "./ext/fs" } +deno_http = { version = "0.169.0", path = "./ext/http" } +deno_io = { version = "0.81.0", path = "./ext/io" } +deno_kv = { version = "0.79.0", path = "./ext/kv" } +deno_napi = { version = "0.102.0", path = "./ext/napi" } +deno_net = { version = "0.163.0", path = "./ext/net" } +deno_node = { version = "0.108.0", path = "./ext/node" } +deno_tls = { version = "0.158.0", path = "./ext/tls" } +deno_url = { version = "0.171.0", path = "./ext/url" } +deno_web = { version = "0.202.0", path = "./ext/web" } +deno_webgpu = { version = "0.138.0", path = "./ext/webgpu" } +deno_webidl = { version = "0.171.0", path = "./ext/webidl" } +deno_websocket = { version = "0.176.0", path = "./ext/websocket" } +deno_webstorage = { version = "0.166.0", path = "./ext/webstorage" } # resolvers -deno_resolver = { version = "0.2.0", path = "./resolvers/deno" } -node_resolver = { version = "0.9.0", path = "./resolvers/node" } +deno_resolver = { version = "0.3.0", path = "./resolvers/deno" } +node_resolver = { version = "0.10.0", path = "./resolvers/node" } aes = "=0.8.3" anyhow = "1.0.57" diff --git a/Releases.md b/Releases.md index a6e4d84e7b..80fdc7fb8d 100644 --- a/Releases.md +++ b/Releases.md @@ -6,6 +6,349 @@ https://github.com/denoland/deno/releases We also have one-line install commands at: https://github.com/denoland/deno_install +### 2.0.0 / 2024.10.09 + +Read announcement blog post at: https://deno.com/blog/v2 + +- BREAKING: `DENO_FUTURE=1` by default, or welcome to Deno 2.0 (#25213) +- BREAKING: disallow `new Deno.FsFile()` (#25478) +- BREAKING: drop support for Deno.run.{clearEnv,gid,uid} (#25371) +- BREAKING: improve types for `Deno.serve` (#25369) +- BREAKING: improved error code accuracy (#25383) +- BREAKING: make supported compilerOptions an allow list (#25432) +- BREAKING: move `width` and `height` options to `UnsafeWindowSurface` + constructor (#24200) +- BREAKING: remove --allow-hrtime (#25367) +- BREAKING: remove "emit" and "map" from deno info output (#25468) +- BREAKING: remove `--allow-none` flag (#25337) +- BREAKING: remove `--jobs` flag (#25336) +- BREAKING: remove `--trace-ops` (#25344) +- BREAKING: remove `--ts` flag (#25338) +- BREAKING: remove `--unstable` flag (#25522) +- BREAKING: remove `deno bundle` (#25339) +- BREAKING: remove `deno vendor` (#25343) +- BREAKING: remove `Deno.[Tls]Listener.prototype.rid` (#25556) +- BREAKING: remove `Deno.{Conn,TlsConn,TcpConn,UnixConn}.prototype.rid` (#25446) +- BREAKING: remove `Deno.{Reader,Writer}[Sync]` and `Deno.Closer` (#25524) +- BREAKING: remove `Deno.Buffer` (#25441) +- BREAKING: remove `Deno.close()` (#25347) +- BREAKING: remove `Deno.ConnectTlsOptions.{certChain,certFile,privateKey}` and + `Deno.ListenTlsOptions.certChain,certFile,keyFile}` (#25525) +- BREAKING: remove `Deno.copy()` (#25345) +- BREAKING: remove `Deno.customInspect` (#25348) +- BREAKING: remove `Deno.fdatasync[Sync]()` (#25520) +- BREAKING: remove `Deno.File` (#25447) +- BREAKING: remove `Deno.flock[Sync]()` (#25350) +- BREAKING: remove `Deno.FsFile.prototype.rid` (#25499) +- BREAKING: remove `Deno.fstat[Sync]()` (#25351) +- BREAKING: remove `Deno.FsWatcher.prototype.rid` (#25444) +- BREAKING: remove `Deno.fsync[Sync]()` (#25448) +- BREAKING: remove `Deno.ftruncate[Sync]()` (#25412) +- BREAKING: remove `Deno.funlock[Sync]()` (#25442) +- BREAKING: remove `Deno.futime[Sync]()` (#25252) +- BREAKING: remove `Deno.iter[Sync]()` (#25346) +- BREAKING: remove `Deno.read[Sync]()` (#25409) +- BREAKING: remove `Deno.readAll[Sync]()` (#25386) +- BREAKING: remove `Deno.seek[Sync]()` (#25449) +- BREAKING: remove `Deno.Seeker[Sync]` (#25551) +- BREAKING: remove `Deno.shutdown()` (#25253) +- BREAKING: remove `Deno.write[Sync]()` (#25408) +- BREAKING: remove `Deno.writeAll[Sync]()` (#25407) +- BREAKING: remove deprecated `UnsafeFnPointer` constructor type with untyped + `Deno.PointerObject` parameter (#25577) +- BREAKING: remove deprecated files config (#25535) +- BREAKING: Remove obsoleted Temporal APIs part 2 (#25505) +- BREAKING: remove remaining web types for compatibility (#25334) +- BREAKING: remove support for remote import maps in deno.json (#25836) +- BREAKING: rename "deps" remote cache folder to "remote" (#25969) +- BREAKING: soft-remove `Deno.isatty()` (#25410) +- BREAKING: soft-remove `Deno.run()` (#25403) +- BREAKING: soft-remove `Deno.serveHttp()` (#25451) +- BREAKING: undeprecate `Deno.FsWatcher.prototype.return()` (#25623) +- feat: add `--allow-import` flag (#25469) +- feat: Add a hint on error about 'Relative import path ... not prefixed with + ...' (#25430) +- feat: Add better error messages for unstable APIs (#25519) +- feat: Add suggestion for packages using Node-API addons (#25975) +- feat: Allow importing .cjs files (#25426) +- feat: default to TS for file extension and support ext flag in more scenarios + (#25472) +- feat: deprecate import assertions (#25281) +- feat: Don't warn about --allow-script when using esbuild (#25894) +- feat: hide several --unstable-* flags (#25378) +- feat: improve lockfile v4 to store normalized version constraints and be more + terse (#25247) +- feat: improve warnings for deprecations and lifecycle script for npm packages + (#25694) +- feat: include version number in all --json based outputs (#25335) +- feat: lockfile v4 by default (#25165) +- feat: make 'globalThis.location' a configurable property (#25812) +- feat: print `Listening on` messages on stderr instead of stdout (#25491) +- feat: remove `--lock-write` flag (#25214) +- feat: require jsr prefix for `deno install` and `deno add` (#25698) +- feat: require(esm) (#25501) +- feat: Show hints when using `window` global (#25805) +- feat: stabilize `Deno.createHttpClient()` (#25569) +- feat: suggest `deno install --entrypoint` instead of `deno cache` (#25228) +- feat: support DENO_LOG env var instead of RUST_LOG (#25356) +- feat: TypeScript 5.6 and `npm:@types/node@22` (#25614) +- feat: Update no-window lint rule (#25486) +- feat: update warning message for --allow-run with no list (#25693) +- feat: warn when using `--allow-run` with no allow list (#25215) +- feat(add): Add npm packages to package.json if present (#25477) +- feat(add): strip package subpath when adding a package (#25419) +- feat(add/install): Flag to add dev dependency to package.json (#25495) +- feat(byonm): support `deno run npm:` when package is not in + package.json (#25981) +- feat(check): turn on noImplicitOverride (#25695) +- feat(check): turn on useUnknownInCatchVariables (#25465) +- feat(cli): evaluate code snippets in JSDoc and markdown (#25220) +- feat(cli): give access to `process` global everywhere (#25291) +- feat(cli): use NotCapable error for permission errors (#25431) +- feat(config): Node modules option for 2.0 (#25299) +- feat(ext/crypto): import and export p521 keys (#25789) +- feat(ext/crypto): X448 support (#26043) +- feat(ext/kv): configurable limit params (#25174) +- feat(ext/node): add abort helpers, process & streams fix (#25262) +- feat(ext/node): add rootCertificates to node:tls (#25707) +- feat(ext/node): buffer.transcode() (#25972) +- feat(ext/node): export 'promises' symbol from 'node:timers' (#25589) +- feat(ext/node): export missing constants from 'zlib' module (#25584) +- feat(ext/node): export missing symbols from domain, puncode, repl, tls + (#25585) +- feat(ext/node): export more symbols from streams and timers/promises (#25582) +- feat(ext/node): expose ES modules for _ modules (#25588) +- feat(flags): allow double commas to escape values in path based flags (#25453) +- feat(flags): support user provided args in repl subcommand (#25605) +- feat(fmt): better error on malfored HTML files (#25853) +- feat(fmt): stabilize CSS, HTML and YAML formatters (#25753) +- feat(fmt): support vto and njk extensions (#25831) +- feat(fmt): upgrade markup_fmt (#25768) +- feat(install): deno install with entrypoint (#25411) +- feat(install): warn repeatedly about not-run lifecycle scripts on explicit + installs (#25878) +- feat(lint): add `no-process-global` lint rule (#25709) +- feat(lsp): add a message when someone runs 'deno lsp' manually (#26051) +- feat(lsp): auto-import types with 'import type' (#25662) +- feat(lsp): html/css/yaml file formatting (#25353) +- feat(lsp): quick fix for @deno-types="npm:@types/*" (#25954) +- feat(lsp): turn on useUnknownInCatchVariables (#25474) +- feat(lsp): unstable setting as list (#25552) +- feat(permissions): `Deno.mainModule` doesn't require permissions (#25667) +- feat(permissions): allow importing from cdn.jsdelivr.net by default (#26013) +- feat(serve): Support second parameter in deno serve (#25606) +- feat(tools/doc): display subitems in symbol overviews where applicable + (#25885) +- feat(uninstall): alias to 'deno remove' if -g flag missing (#25461) +- feat(upgrade): better error message on failure (#25503) +- feat(upgrade): print info links for Deno 2 RC releases (#25225) +- feat(upgrade): support LTS release channel (#25123) +- fix: add link to env var docs (#25557) +- fix: add suggestion how to fix importing CJS module (#21764) +- fix: add test ensuring als works across dynamic import (#25593) +- fix: better error for Deno.UnsafeWindowSurface, correct HttpClient name, + cleanup unused code (#25833) +- fix: cjs resolution cases (#25739) +- fix: consistent with deno_config and treat `"experimentalDecorators"` as + deprecated (#25735) +- fix: delete old Deno 1.x headers file when loading cache (#25283) +- fix: do not panic running invalid file specifier (#25530) +- fix: don't include extensionless files in file collection for lint & fmt by + default (#25721) +- fix: don't prompt when using `Deno.permissions.request` with `--no-prompt` + (#25811) +- fix: eagerly error for specifier with empty version constraint (#25944) +- fix: enable `Win32_Security` feature in `windows-sys` (#26007) +- fix: error on unsupported compiler options (#25714) +- fix: error out if a valid flag is passed before a subcommand (#25830) +- fix: fix jupyter display function type (#25326) +- fix: Float16Array type (#25506) +- fix: handle showing warnings while the progress bar is shown (#25187) +- fix: Hide 'deno cache' from help output (#25960) +- fix: invalid ipv6 hostname on `deno serve` (#25482) +- fix: linux canonicalization checks (#24641) +- fix: lock down allow-run permissions more (#25370) +- fix: make some warnings more standard (#25324) +- fix: no cmd prefix in help output go links (#25459) +- fix: only enable byonm if workspace root has pkg json (#25379) +- fix: panic when require(esm) (#25769) +- fix: precompile preserve SVG camelCase attributes (#25945) +- fix: reland async context (#25140) +- fix: remove --allow-run warning when using deno without args or subcommand + (#25684) +- fix: remove entrypoint hack for Deno 2.0 (#25332) +- fix: remove recently added deno.json node_modules aliasing (#25542) +- fix: remove the typo in the help message (#25962) +- fix: removed unstable-htttp from deno help (#25216) +- fix: replace `npm install` hint with `deno install` hint (#25244) +- fix: trim space around DENO_AUTH_TOKENS (#25147) +- fix: update deno_doc (#25290) +- fix: Update deno_npm to fix `deno install` with crossws (#25837) +- fix: update hint for `deno add ` (#25455) +- fix: update malva in deno to support astro css comments (#25553) +- fix: update nodeModulesDir config JSON schema (#25653) +- fix: update patchver to 0.2 (#25952) +- fix: update sui to 0.4 (#25942) +- fix: upgrade deno_ast 0.42 (#25313) +- fix: upgrade deno_core to 0.307.0 (#25287) +- fix(add/install): default to "latest" tag for npm packages in + `deno add npm:pkg` (#25858) +- fix(bench): Fix table column alignments and NO_COLOR=1 (#25190) +- fix(BREAKING): make dns record types have consistent naming (#25357) +- fix(byonm): resolve npm deps of jsr deps (#25399) +- fix(check): ignore noImplicitOverrides in remote modules (#25854) +- fix(check): move is cjs check from resolving to loading (#25597) +- fix(check): properly surface dependency errors in types file of js file + (#25860) +- fix(cli): `deno task` exit with status 0 (#25637) +- fix(cli): Default to auto with --node-modules-dir flag (#25772) +- fix(cli): handle edge cases around `export`s in doc tests and default export + (#25720) +- fix(cli): Map error kind to `PermissionDenied` when symlinking fails due to + permissions (#25398) +- fix(cli): Only set allow net flag for deno serve if not already allowed all + (#25743) +- fix(cli): Warn on not-run lifecycle scripts with global cache (#25786) +- fix(cli/tools): correct `deno init --serve` template behavior (#25318) +- fix(compile): support 'deno compile' in RC and LTS releases (#25875) +- fix(config): validate export names (#25436) +- fix(coverage): ignore urls from doc testing (#25736) +- fix(doc): surface graph errors as warnings (#25888) +- fix(dts): stabilize `fetch` declaration for use with `Deno.HttpClient` + (#25683) +- fix(ext/console): more precision in console.time (#25723) +- fix(ext/console): prevent duplicate error printing when the cause is assigned + (#25327) +- fix(ext/crypto): ensure EC public keys are exported uncompressed (#25766) +- fix(ext/crypto): fix identity test for x25519 derive bits (#26011) +- fix(ext/crypto): reject empty usages in SubtleCrypto#importKey (#25759) +- fix(ext/crypto): support md4 digest algorithm (#25656) +- fix(ext/crypto): throw DataError for invalid EC key import (#25181) +- fix(ext/fetch): fix lowercase http_proxy classified as https (#25686) +- fix(ext/fetch): percent decode userinfo when parsing proxies (#25229) +- fix(ext/http): do not set localhost to hostname unnecessarily (#24777) +- fix(ext/http): gracefully handle Response.error responses (#25712) +- fix(ext/node): add `FileHandle#writeFile` (#25555) +- fix(ext/node): add `vm.constants` (#25630) +- fix(ext/node): Add missing `node:path` exports (#25567) +- fix(ext/node): Add missing node:fs and node:constants exports (#25568) +- fix(ext/node): add stubs for `node:trace_events` (#25628) +- fix(ext/node): attach console stream properties (#25617) +- fix(ext/node): avoid showing `UNKNOWN` error from TCP handle (#25550) +- fix(ext/node): close upgraded socket when the underlying http connection is + closed (#25387) +- fix(ext/node): delay accept() call 2 ticks in net.Server#listen (#25481) +- fix(ext/node): don't throw error for unsupported signal binding on windows + (#25699) +- fix(ext/node): emit `online` event after worker thread is initialized (#25243) +- fix(ext/node): export `process.allowedNodeEnvironmentFlags` (#25629) +- fix(ext/node): export JWK public key (#25239) +- fix(ext/node): export request and response clases from `http2` module (#25592) +- fix(ext/node): fix `Cipheriv#update(string, undefined)` (#25571) +- fix(ext/node): fix Decipheriv when autoPadding disabled (#25598) +- fix(ext/node): fix process.stdin.pause() (#25864) +- fix(ext/node): Fix vm sandbox object panic (#24985) +- fix(ext/node): http2session ready state (#25143) +- fix(ext/node): Implement detached option in `child_process` (#25218) +- fix(ext/node): import EC JWK keys (#25266) +- fix(ext/node): import JWK octet key pairs (#25180) +- fix(ext/node): import RSA JWK keys (#25267) +- fix(ext/node): register `node:wasi` built-in (#25134) +- fix(ext/node): remove unimplemented promiseHook stubs (#25979) +- fix(ext/node): report freemem() on Linux in bytes (#25511) +- fix(ext/node): Rewrite `node:v8` serialize/deserialize (#25439) +- fix(ext/node): session close during stream setup (#25170) +- fix(ext/node): Stream should be instance of EventEmitter (#25527) +- fix(ext/node): stub `inspector/promises` (#25635) +- fix(ext/node): stub `process.cpuUsage()` (#25462) +- fix(ext/node): stub cpu_info() for OpenBSD (#25807) +- fix(ext/node): support x509 certificates in `createPublicKey` (#25731) +- fix(ext/node): throw when loading `cpu-features` module (#25257) +- fix(ext/node): update aead-gcm-stream to 0.3 (#25261) +- fix(ext/node): use primordials in `ext/node/polyfills/console.ts` (#25572) +- fix(ext/node): use primordials in ext/node/polyfills/wasi.ts (#25608) +- fix(ext/node): validate input lengths in `Cipheriv` and `Decipheriv` (#25570) +- fix(ext/web): don't ignore capture in EventTarget.removeEventListener (#25788) +- fix(ext/webgpu): allow to build on unsupported platforms (#25202) +- fix(ext/webgpu): sync category comment (#25580) +- fix(ext/webstorage): make `getOwnPropertyDescriptor` with symbol return + `undefined` (#13348) +- fix(flags): --allow-all should conflict with lower permissions (#25909) +- fix(flags): don't treat empty run command as task subcommand (#25708) +- fix(flags): move some content from docs.deno.com into help output (#25951) +- fix(flags): properly error out for urls (#25770) +- fix(flags): require global flag for permission flags in install subcommand + (#25391) +- fix(fmt): --check was broken for CSS, YAML and HTML (#25848) +- fix(fmt): fix incorrect quotes in components (#25249) +- fix(fmt): fix tabs in YAML (#25536) +- fix(fmt/markdown): fix regression with multi-line footnotes and inline math + (#25222) +- fix(info): error instead of panic for npm specifiers when using byonm (#25947) +- fix(info): move "version" field to top of json output (#25890) +- fix(inspector): Fix panic when re-entering runtime ops (#25537) +- fix(install): compare versions directly to decide whether to create a child + node_modules dir for a workspace member (#26001) +- fix(install): Make sure target node_modules exists when symlinking (#25494) +- fix(install): recommend using `deno install -g` when using a single http url + (#25388) +- fix(install): store tags associated with package in node_modules dir (#26000) +- fix(install): surface package.json dependency errors (#26023) +- fix(install): Use relative symlinks in deno install (#25164) +- fix(installl): make bin entries executable even if not put in + `node_modules/.bin` (#25873) +- fix(jupyter): allow unstable flags (#25483) +- fix(lint): correctly handle old jsx in linter (#25902) +- fix(lint): support linting jsr pkg without version field (#25230) +- fix(lockfile): use loose deserialization for version constraints (#25660) +- fix(lsp): encode url parts before parsing as uri (#25509) +- fix(lsp): exclude missing import quick fixes with bad resolutions (#26025) +- fix(lsp): panic on url_to_uri() (#25238) +- fix(lsp): properly resolve jsxImportSource for caching (#25688) +- fix(lsp): update diagnostics on npm install (#25352) +- fix(napi): Don't run microtasks in napi_resolve_deferred (#25246) +- fix(napi): Fix worker threads importing already-loaded NAPI addon (#25245) +- fix(no-slow-types): better `override` handling (#25989) +- fix(node): Don't error out if we fail to statically analyze CJS re-export + (#25748) +- fix(node): fix worker_threads issues blocking Angular support (#26024) +- fix(node): implement libuv APIs needed to support `npm:sqlite3` (#25893) +- fix(node): Include "node" condition during CJS re-export analysis (#25785) +- fix(node): Pass NPM_PROCESS_STATE to subprocesses via temp file instead of env + var (#25896) +- fix(node/byonm): do not accidentally resolve bare node built-ins (#25543) +- fix(node/cluster): improve stubs to make log4js work (#25146) +- fix(npm): better error handling for remote npm deps (#25670) +- fix(npm): root package has peer dependency on itself (#26022) +- fix(permissions): disallow any `LD_` or `DYLD_` prefixed env var without full + --allow-run permissions (#25271) +- fix(permissions): disallow launching subprocess with LD_PRELOAD env var + without full run permissions (#25221) +- fix(publish): ensure provenance is spec compliant (#25200) +- fix(regression): do not expose resolved path in Deno.Command permission denied + error (#25434) +- fix(runtime): don't error `child.output()` on consumed stream (#25657) +- fix(runtime): use more null proto objects again (#25040) +- fix(runtime/web_worker): populate `SnapshotOptions` for `WebWorker` when + instantiated without snapshot (#25280) +- fix(task): correct name for scoped npm package binaries (#25390) +- fix(task): support tasks with colons in name in `deno run` (#25233) +- fix(task): use current executable for deno even when not named deno (#26019) +- fix(types): simplify mtls related types (#25658) +- fix(upgrade): more informative information on invalid version (#25319) +- fix(windows): Deno.Command - align binary resolution with linux and mac + (#25429) +- fix(workspace): handle when config has members when specified via --config + (#25988) +- perf: fast path for cached dyn imports (#25636) +- perf: Use -O3 for sui in release builds (#26010) +- perf(cache): single cache file for remote modules (#24983) +- perf(cache): single cache file for typescript emit (#24994) +- perf(ext/fetch): improve decompression throughput by upgrading `tower_http` + (#25806) +- perf(ext/node): reduce some allocations in require (#25197) +- perf(ext/web): optimize performance.measure() (#25774) + ### 1.46.3 / 2024.09.04 - feat(upgrade): print info links for Deno 2 RC releases (#25225) diff --git a/bench_util/Cargo.toml b/bench_util/Cargo.toml index 1eab1685e2..4b886a2907 100644 --- a/bench_util/Cargo.toml +++ b/bench_util/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_bench_util" -version = "0.164.0" +version = "0.165.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d2ee5f76ac..ae57df4f7c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno" -version = "2.0.0-rc.10" +version = "2.0.0" authors.workspace = true default-run = "deno" edition.workspace = true diff --git a/cli/napi/sym/Cargo.toml b/cli/napi/sym/Cargo.toml index baabf0b7a6..fef749fc46 100644 --- a/cli/napi/sym/Cargo.toml +++ b/cli/napi/sym/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "napi_sym" -version = "0.100.0" +version = "0.101.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/broadcast_channel/Cargo.toml b/ext/broadcast_channel/Cargo.toml index 24e09543ce..3caf7b9efd 100644 --- a/ext/broadcast_channel/Cargo.toml +++ b/ext/broadcast_channel/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_broadcast_channel" -version = "0.164.0" +version = "0.165.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cache/Cargo.toml b/ext/cache/Cargo.toml index aae0eaf91f..71ca34380c 100644 --- a/ext/cache/Cargo.toml +++ b/ext/cache/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cache" -version = "0.102.0" +version = "0.103.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/canvas/Cargo.toml b/ext/canvas/Cargo.toml index 3cfc180ecd..47c37560ec 100644 --- a/ext/canvas/Cargo.toml +++ b/ext/canvas/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_canvas" -version = "0.39.0" +version = "0.40.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/console/Cargo.toml b/ext/console/Cargo.toml index a61d821d6b..5c143ca18c 100644 --- a/ext/console/Cargo.toml +++ b/ext/console/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_console" -version = "0.170.0" +version = "0.171.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/cron/Cargo.toml b/ext/cron/Cargo.toml index c0f5f097ea..a773521f5b 100644 --- a/ext/cron/Cargo.toml +++ b/ext/cron/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_cron" -version = "0.50.0" +version = "0.51.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/crypto/Cargo.toml b/ext/crypto/Cargo.toml index 0425b1e5e8..c81c8f6a70 100644 --- a/ext/crypto/Cargo.toml +++ b/ext/crypto/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_crypto" -version = "0.184.0" +version = "0.185.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fetch/Cargo.toml b/ext/fetch/Cargo.toml index 5196abd92d..cc9e4f03d3 100644 --- a/ext/fetch/Cargo.toml +++ b/ext/fetch/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fetch" -version = "0.194.0" +version = "0.195.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/ffi/Cargo.toml b/ext/ffi/Cargo.toml index 0839fec241..23a2aee1cd 100644 --- a/ext/ffi/Cargo.toml +++ b/ext/ffi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_ffi" -version = "0.157.0" +version = "0.158.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/fs/Cargo.toml b/ext/fs/Cargo.toml index b3eb85bfcc..606c00ad8c 100644 --- a/ext/fs/Cargo.toml +++ b/ext/fs/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fs" -version = "0.80.0" +version = "0.81.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/http/Cargo.toml b/ext/http/Cargo.toml index ba07636aa5..b7637bec33 100644 --- a/ext/http/Cargo.toml +++ b/ext/http/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_http" -version = "0.168.0" +version = "0.169.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/io/Cargo.toml b/ext/io/Cargo.toml index 9dd2dbb878..d45834a8fe 100644 --- a/ext/io/Cargo.toml +++ b/ext/io/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_io" -version = "0.80.0" +version = "0.81.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/kv/Cargo.toml b/ext/kv/Cargo.toml index a948ca422d..14c3514ffd 100644 --- a/ext/kv/Cargo.toml +++ b/ext/kv/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_kv" -version = "0.78.0" +version = "0.79.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/napi/Cargo.toml b/ext/napi/Cargo.toml index c259dc46cb..ade789ff80 100644 --- a/ext/napi/Cargo.toml +++ b/ext/napi/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_napi" -version = "0.101.0" +version = "0.102.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/net/Cargo.toml b/ext/net/Cargo.toml index 36857a16c0..9f72456b90 100644 --- a/ext/net/Cargo.toml +++ b/ext/net/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_net" -version = "0.162.0" +version = "0.163.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 459908f59e..c5f07210b2 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_node" -version = "0.107.0" +version = "0.108.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/tls/Cargo.toml b/ext/tls/Cargo.toml index fff9662b2e..6c1554241e 100644 --- a/ext/tls/Cargo.toml +++ b/ext/tls/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_tls" -version = "0.157.0" +version = "0.158.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/url/Cargo.toml b/ext/url/Cargo.toml index 063b44ce1b..13aca99539 100644 --- a/ext/url/Cargo.toml +++ b/ext/url/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_url" -version = "0.170.0" +version = "0.171.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml index cf5aede920..4120e978e0 100644 --- a/ext/web/Cargo.toml +++ b/ext/web/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_web" -version = "0.201.0" +version = "0.202.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webgpu/Cargo.toml b/ext/webgpu/Cargo.toml index 786beee459..4c709b9c30 100644 --- a/ext/webgpu/Cargo.toml +++ b/ext/webgpu/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webgpu" -version = "0.137.0" +version = "0.138.0" authors = ["the Deno authors"] edition.workspace = true license = "MIT" diff --git a/ext/webidl/Cargo.toml b/ext/webidl/Cargo.toml index 734fc75c2b..8a25be3662 100644 --- a/ext/webidl/Cargo.toml +++ b/ext/webidl/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webidl" -version = "0.170.0" +version = "0.171.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/websocket/Cargo.toml b/ext/websocket/Cargo.toml index 4758c9d04f..6bef387b44 100644 --- a/ext/websocket/Cargo.toml +++ b/ext/websocket/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_websocket" -version = "0.175.0" +version = "0.176.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ext/webstorage/Cargo.toml b/ext/webstorage/Cargo.toml index 7b86f4e8b7..08ed8b0f29 100644 --- a/ext/webstorage/Cargo.toml +++ b/ext/webstorage/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_webstorage" -version = "0.165.0" +version = "0.166.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/resolvers/deno/Cargo.toml b/resolvers/deno/Cargo.toml index 5900f9269b..62504c8303 100644 --- a/resolvers/deno/Cargo.toml +++ b/resolvers/deno/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_resolver" -version = "0.2.0" +version = "0.3.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/resolvers/node/Cargo.toml b/resolvers/node/Cargo.toml index d4e9b041ca..f05b209fdb 100644 --- a/resolvers/node/Cargo.toml +++ b/resolvers/node/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "node_resolver" -version = "0.9.0" +version = "0.10.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 6d84d0466c..ba9dc6243f 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_runtime" -version = "0.179.0" +version = "0.180.0" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/runtime/permissions/Cargo.toml b/runtime/permissions/Cargo.toml index bb8ebb97c4..8f0b0dd3de 100644 --- a/runtime/permissions/Cargo.toml +++ b/runtime/permissions/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_permissions" -version = "0.30.0" +version = "0.31.0" authors.workspace = true edition.workspace = true license.workspace = true From 0dfd333649acd85508e62bb60e3be4946e543597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 9 Oct 2024 09:04:15 +0100 Subject: [PATCH 38/39] fix(jupyter): keep running event loop when waiting for messages (#26049) Closes https://github.com/denoland/deno/issues/24421 --- cli/tools/jupyter/mod.rs | 108 +++++++++++++++++------------ tests/integration/jupyter_tests.rs | 34 +++++++++ 2 files changed, 97 insertions(+), 45 deletions(-) diff --git a/cli/tools/jupyter/mod.rs b/cli/tools/jupyter/mod.rs index 71e947dddb..0ffd0da1ee 100644 --- a/cli/tools/jupyter/mod.rs +++ b/cli/tools/jupyter/mod.rs @@ -357,56 +357,74 @@ pub struct JupyterReplSession { impl JupyterReplSession { pub async fn start(&mut self) { + let mut poll_worker = true; loop { - let Some(msg) = self.rx.recv().await else { - break; - }; - let resp = match msg { - JupyterReplRequest::LspCompletions { - line_text, - position, - } => JupyterReplResponse::LspCompletions( - self.lsp_completions(&line_text, position).await, - ), - JupyterReplRequest::JsGetProperties { object_id } => { - JupyterReplResponse::JsGetProperties( - self.get_properties(object_id).await, - ) - } - JupyterReplRequest::JsEvaluate { expr } => { - JupyterReplResponse::JsEvaluate(self.evaluate(expr).await) - } - JupyterReplRequest::JsGlobalLexicalScopeNames => { - JupyterReplResponse::JsGlobalLexicalScopeNames( - self.global_lexical_scope_names().await, - ) - } - JupyterReplRequest::JsEvaluateLineWithObjectWrapping { line } => { - JupyterReplResponse::JsEvaluateLineWithObjectWrapping( - self.evaluate_line_with_object_wrapping(&line).await, - ) - } - JupyterReplRequest::JsCallFunctionOnArgs { - function_declaration, - args, - } => JupyterReplResponse::JsCallFunctionOnArgs( - self - .call_function_on_args(function_declaration, &args) - .await, - ), - JupyterReplRequest::JsCallFunctionOn { arg0, arg1 } => { - JupyterReplResponse::JsCallFunctionOn( - self.call_function_on(arg0, arg1).await, - ) - } - }; + tokio::select! { + biased; - let Ok(()) = self.tx.send(resp) else { - break; - }; + maybe_message = self.rx.recv() => { + let Some(msg) = maybe_message else { + break; + }; + if self.handle_message(msg).await.is_err() { + break; + } + poll_worker = true; + }, + _ = self.repl_session.run_event_loop(), if poll_worker => { + poll_worker = false; + } + } } } + async fn handle_message( + &mut self, + msg: JupyterReplRequest, + ) -> Result<(), AnyError> { + let resp = match msg { + JupyterReplRequest::LspCompletions { + line_text, + position, + } => JupyterReplResponse::LspCompletions( + self.lsp_completions(&line_text, position).await, + ), + JupyterReplRequest::JsGetProperties { object_id } => { + JupyterReplResponse::JsGetProperties( + self.get_properties(object_id).await, + ) + } + JupyterReplRequest::JsEvaluate { expr } => { + JupyterReplResponse::JsEvaluate(self.evaluate(expr).await) + } + JupyterReplRequest::JsGlobalLexicalScopeNames => { + JupyterReplResponse::JsGlobalLexicalScopeNames( + self.global_lexical_scope_names().await, + ) + } + JupyterReplRequest::JsEvaluateLineWithObjectWrapping { line } => { + JupyterReplResponse::JsEvaluateLineWithObjectWrapping( + self.evaluate_line_with_object_wrapping(&line).await, + ) + } + JupyterReplRequest::JsCallFunctionOnArgs { + function_declaration, + args, + } => JupyterReplResponse::JsCallFunctionOnArgs( + self + .call_function_on_args(function_declaration, &args) + .await, + ), + JupyterReplRequest::JsCallFunctionOn { arg0, arg1 } => { + JupyterReplResponse::JsCallFunctionOn( + self.call_function_on(arg0, arg1).await, + ) + } + }; + + self.tx.send(resp).map_err(|e| e.into()) + } + pub async fn lsp_completions( &mut self, line_text: &str, diff --git a/tests/integration/jupyter_tests.rs b/tests/integration/jupyter_tests.rs index 1b2c213118..e99780a276 100644 --- a/tests/integration/jupyter_tests.rs +++ b/tests/integration/jupyter_tests.rs @@ -628,3 +628,37 @@ async fn jupyter_store_history_false() -> Result<()> { Ok(()) } + +#[tokio::test] +async fn jupyter_http_server() -> Result<()> { + let (_ctx, client, _process) = setup().await; + client + .send( + Shell, + "execute_request", + json!({ + "silent": false, + "store_history": false, + "code": r#"Deno.serve({ port: 10234 }, (req) => Response.json({ hello: "world" }))"#, + }), + ) + .await?; + + let reply = client.recv(Shell).await?; + assert_eq!(reply.header.msg_type, "execute_reply"); + assert_json_subset( + reply.content, + json!({ + "status": "ok", + "execution_count": 0, + }), + ); + + for _ in 0..3 { + let resp = reqwest::get("http://localhost:10234").await.unwrap(); + let text: serde_json::Value = resp.json().await.unwrap(); + assert_eq!(text, json!({ "hello": "world" })); + } + + Ok(()) +} From 20ae8db50d7d48ad020b83ebe78dc0e9e9eab3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Wed, 9 Oct 2024 09:04:44 +0100 Subject: [PATCH 39/39] fix(repl): importing json files (#26053) Closes https://github.com/denoland/deno/issues/26041 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- tests/integration/repl_tests.rs | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5abeb3d40..c559611cd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1283,9 +1283,9 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ea2fd038c9c7e3e87e624fd708303cd33f39c33707f6c48fa9a65d65fefc47" +checksum = "b2b9d03b1bbeeecdac54367f075d572131736d06c5be3bc49037855bc5ab1bbb" dependencies = [ "base64 0.21.7", "deno_media_type", diff --git a/Cargo.toml b/Cargo.toml index d811d44b53..badc84992f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ license = "MIT" repository = "https://github.com/denoland/deno" [workspace.dependencies] -deno_ast = { version = "=0.42.1", features = ["transpiling"] } +deno_ast = { version = "=0.42.2", features = ["transpiling"] } deno_core = { version = "0.311.0" } deno_bench_util = { version = "0.165.0", path = "./bench_util" } diff --git a/tests/integration/repl_tests.rs b/tests/integration/repl_tests.rs index 3f137ce7cb..4e00398ce6 100644 --- a/tests/integration/repl_tests.rs +++ b/tests/integration/repl_tests.rs @@ -1136,3 +1136,22 @@ fn eval_file_promise_error() { assert_contains!(out, "Uncaught undefined"); assert!(err.is_empty()); } + +#[test] +fn repl_json_imports() { + let context = TestContextBuilder::default().use_temp_cwd().build(); + let temp_dir = context.temp_dir(); + temp_dir.write("./data.json", r#"{"hello": "world"}"#); + context + .new_command() + .env("NO_COLOR", "1") + .args_vec(["repl", "-A"]) + .with_pty(|mut console| { + console.write_line_raw( + "import data from './data.json' with { type: 'json' };", + ); + console.expect("undefined"); + console.write_line_raw("data"); + console.expect(r#"{ hello: "world" }"#); + }); +}