mirror of
https://github.com/denoland/deno.git
synced 2024-11-27 16:10:57 -05:00
Merge branch 'main' into feat/coverage-ignore-comments
This commit is contained in:
commit
a6843777ce
66 changed files with 1236 additions and 189 deletions
2
.github/workflows/ci.generate.ts
vendored
2
.github/workflows/ci.generate.ts
vendored
|
@ -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 = 24;
|
||||
const cacheVersion = 25;
|
||||
|
||||
const ubuntuX86Runner = "ubuntu-24.04";
|
||||
const ubuntuX86XlRunner = "ubuntu-24.04-xl";
|
||||
|
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -361,8 +361,8 @@ jobs:
|
|||
path: |-
|
||||
~/.cargo/registry/index
|
||||
~/.cargo/registry/cache
|
||||
key: '24-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '24-cargo-home-${{ matrix.os }}-${{ matrix.arch }}'
|
||||
key: '25-cargo-home-${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles(''Cargo.lock'') }}'
|
||||
restore-keys: '25-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: '24-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-'
|
||||
restore-keys: '25-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: '24-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
key: '25-cargo-target-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.profile }}-${{ matrix.job }}-${{ github.sha }}'
|
||||
publish-canary:
|
||||
name: publish canary
|
||||
runs-on: ubuntu-24.04
|
||||
|
|
62
Cargo.lock
generated
62
Cargo.lock
generated
|
@ -1154,7 +1154,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno"
|
||||
version = "2.0.5"
|
||||
version = "2.0.6"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"async-trait",
|
||||
|
@ -1323,7 +1323,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_bench_util"
|
||||
version = "0.170.0"
|
||||
version = "0.171.0"
|
||||
dependencies = [
|
||||
"bencher",
|
||||
"deno_core",
|
||||
|
@ -1332,7 +1332,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.170.0"
|
||||
version = "0.171.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1343,7 +1343,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_cache"
|
||||
version = "0.108.0"
|
||||
version = "0.109.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1376,7 +1376,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_canvas"
|
||||
version = "0.45.0"
|
||||
version = "0.46.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_webgpu",
|
||||
|
@ -1411,7 +1411,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_console"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
]
|
||||
|
@ -1456,7 +1456,7 @@ checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1"
|
|||
|
||||
[[package]]
|
||||
name = "deno_cron"
|
||||
version = "0.56.0"
|
||||
version = "0.57.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1469,7 +1469,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_crypto"
|
||||
version = "0.190.0"
|
||||
version = "0.191.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
@ -1531,7 +1531,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fetch"
|
||||
version = "0.200.0"
|
||||
version = "0.201.0"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
|
@ -1564,7 +1564,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_ffi"
|
||||
version = "0.163.0"
|
||||
version = "0.164.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1584,7 +1584,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_fs"
|
||||
version = "0.86.0"
|
||||
version = "0.87.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base32",
|
||||
|
@ -1635,7 +1635,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_http"
|
||||
version = "0.174.0"
|
||||
version = "0.175.0"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"async-trait",
|
||||
|
@ -1674,7 +1674,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_io"
|
||||
version = "0.86.0"
|
||||
version = "0.87.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deno_core",
|
||||
|
@ -1695,7 +1695,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_kv"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -1767,7 +1767,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_napi"
|
||||
version = "0.107.0"
|
||||
version = "0.108.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1795,7 +1795,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_net"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_permissions",
|
||||
|
@ -1812,7 +1812,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_node"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
dependencies = [
|
||||
"aead-gcm-stream",
|
||||
"aes",
|
||||
|
@ -1961,7 +1961,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_permissions"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_path_util",
|
||||
|
@ -1979,7 +1979,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_resolver"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base32",
|
||||
|
@ -1995,7 +1995,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_runtime"
|
||||
version = "0.185.0"
|
||||
version = "0.186.0"
|
||||
dependencies = [
|
||||
"color-print",
|
||||
"deno_ast",
|
||||
|
@ -2113,7 +2113,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_tls"
|
||||
version = "0.163.0"
|
||||
version = "0.164.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_native_certs",
|
||||
|
@ -2162,7 +2162,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_url"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_console",
|
||||
|
@ -2174,7 +2174,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_web"
|
||||
version = "0.207.0"
|
||||
version = "0.208.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64-simd 0.8.0",
|
||||
|
@ -2196,7 +2196,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webgpu"
|
||||
version = "0.143.0"
|
||||
version = "0.144.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"raw-window-handle",
|
||||
|
@ -2209,7 +2209,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webidl"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
dependencies = [
|
||||
"deno_bench_util",
|
||||
"deno_core",
|
||||
|
@ -2217,7 +2217,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_websocket"
|
||||
version = "0.181.0"
|
||||
version = "0.182.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"deno_core",
|
||||
|
@ -2239,7 +2239,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_webstorage"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
dependencies = [
|
||||
"deno_core",
|
||||
"deno_web",
|
||||
|
@ -4561,7 +4561,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "napi_sym"
|
||||
version = "0.106.0"
|
||||
version = "0.107.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -4616,7 +4616,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "node_resolver"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -8485,9 +8485,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zeromq"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb0560d00172817b7f7c2265060783519c475702ae290b154115ca75e976d4d0"
|
||||
checksum = "6a4528179201f6eecf211961a7d3276faa61554c82651ecc66387f68fc3004bd"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"asynchronous-codec",
|
||||
|
|
58
Cargo.toml
58
Cargo.toml
|
@ -48,16 +48,16 @@ repository = "https://github.com/denoland/deno"
|
|||
deno_ast = { version = "=0.43.3", features = ["transpiling"] }
|
||||
deno_core = { version = "0.318.0" }
|
||||
|
||||
deno_bench_util = { version = "0.170.0", path = "./bench_util" }
|
||||
deno_bench_util = { version = "0.171.0", path = "./bench_util" }
|
||||
deno_lockfile = "=0.23.1"
|
||||
deno_media_type = { version = "0.2.0", features = ["module_specifier"] }
|
||||
deno_npm = "=0.25.4"
|
||||
deno_path_util = "=0.2.1"
|
||||
deno_permissions = { version = "0.36.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.185.0", path = "./runtime" }
|
||||
deno_permissions = { version = "0.37.0", path = "./runtime/permissions" }
|
||||
deno_runtime = { version = "0.186.0", path = "./runtime" }
|
||||
deno_semver = "=0.5.16"
|
||||
deno_terminal = "0.2.0"
|
||||
napi_sym = { version = "0.106.0", path = "./ext/napi/sym" }
|
||||
napi_sym = { version = "0.107.0", path = "./ext/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.170.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.108.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.45.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.176.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.56.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.190.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.200.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.163.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.86.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.174.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.86.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.84.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.107.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.168.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.113.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.163.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.176.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.207.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.143.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.176.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.181.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.171.0", path = "./ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.171.0", path = "./ext/broadcast_channel" }
|
||||
deno_cache = { version = "0.109.0", path = "./ext/cache" }
|
||||
deno_canvas = { version = "0.46.0", path = "./ext/canvas" }
|
||||
deno_console = { version = "0.177.0", path = "./ext/console" }
|
||||
deno_cron = { version = "0.57.0", path = "./ext/cron" }
|
||||
deno_crypto = { version = "0.191.0", path = "./ext/crypto" }
|
||||
deno_fetch = { version = "0.201.0", path = "./ext/fetch" }
|
||||
deno_ffi = { version = "0.164.0", path = "./ext/ffi" }
|
||||
deno_fs = { version = "0.87.0", path = "./ext/fs" }
|
||||
deno_http = { version = "0.175.0", path = "./ext/http" }
|
||||
deno_io = { version = "0.87.0", path = "./ext/io" }
|
||||
deno_kv = { version = "0.85.0", path = "./ext/kv" }
|
||||
deno_napi = { version = "0.108.0", path = "./ext/napi" }
|
||||
deno_net = { version = "0.169.0", path = "./ext/net" }
|
||||
deno_node = { version = "0.114.0", path = "./ext/node" }
|
||||
deno_tls = { version = "0.164.0", path = "./ext/tls" }
|
||||
deno_url = { version = "0.177.0", path = "./ext/url" }
|
||||
deno_web = { version = "0.208.0", path = "./ext/web" }
|
||||
deno_webgpu = { version = "0.144.0", path = "./ext/webgpu" }
|
||||
deno_webidl = { version = "0.177.0", path = "./ext/webidl" }
|
||||
deno_websocket = { version = "0.182.0", path = "./ext/websocket" }
|
||||
deno_webstorage = { version = "0.172.0", path = "./ext/webstorage" }
|
||||
|
||||
# resolvers
|
||||
deno_resolver = { version = "0.8.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.15.0", path = "./resolvers/node" }
|
||||
deno_resolver = { version = "0.9.0", path = "./resolvers/deno" }
|
||||
node_resolver = { version = "0.16.0", path = "./resolvers/node" }
|
||||
|
||||
aes = "=0.8.3"
|
||||
anyhow = "1.0.57"
|
||||
|
@ -204,7 +204,7 @@ webpki-root-certs = "0.26.5"
|
|||
webpki-roots = "0.26"
|
||||
which = "4.2.5"
|
||||
yoke = { version = "0.7.4", features = ["derive"] }
|
||||
zeromq = { version = "=0.4.0", default-features = false, features = ["tcp-transport", "tokio-runtime"] }
|
||||
zeromq = { version = "=0.4.1", default-features = false, features = ["tcp-transport", "tokio-runtime"] }
|
||||
zstd = "=0.12.4"
|
||||
|
||||
# crypto
|
||||
|
|
12
Releases.md
12
Releases.md
|
@ -6,6 +6,18 @@ https://github.com/denoland/deno/releases
|
|||
We also have one-line install commands at:
|
||||
https://github.com/denoland/deno_install
|
||||
|
||||
### 2.0.6 / 2024.11.10
|
||||
|
||||
- feat(ext/http): abort event when request is cancelled (#26781)
|
||||
- feat(ext/http): abort signal when request is cancelled (#26761)
|
||||
- feat(lsp): auto-import completions from byonm dependencies (#26680)
|
||||
- fix(ext/cache): don't panic when creating cache (#26780)
|
||||
- fix(ext/node): better inspector support (#26471)
|
||||
- fix(fmt): don't use self-closing tags in HTML (#26754)
|
||||
- fix(install): cache jsr deps from all workspace config files (#26779)
|
||||
- fix(node:zlib): gzip & gzipSync should accept ArrayBuffer (#26762)
|
||||
- fix: performance.timeOrigin (#26787)
|
||||
|
||||
### 2.0.5 / 2024.11.05
|
||||
|
||||
- fix(add): better error message when adding package that only has pre-release
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_bench_util"
|
||||
version = "0.170.0"
|
||||
version = "0.171.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno"
|
||||
version = "2.0.5"
|
||||
version = "2.0.6"
|
||||
authors.workspace = true
|
||||
default-run = "deno"
|
||||
edition.workspace = true
|
||||
|
|
|
@ -10,6 +10,7 @@ use super::tsc;
|
|||
use super::urls::url_to_uri;
|
||||
|
||||
use crate::args::jsr_url;
|
||||
use crate::lsp::logging::lsp_warn;
|
||||
use crate::lsp::search::PackageSearchApi;
|
||||
use crate::tools::lint::CliLinter;
|
||||
use crate::util::path::relative_specifier;
|
||||
|
@ -747,8 +748,14 @@ pub fn ts_changes_to_edit(
|
|||
) -> Result<Option<lsp::WorkspaceEdit>, AnyError> {
|
||||
let mut text_document_edits = Vec::new();
|
||||
for change in changes {
|
||||
let text_document_edit = change.to_text_document_edit(language_server)?;
|
||||
text_document_edits.push(text_document_edit);
|
||||
let edit = match change.to_text_document_edit(language_server) {
|
||||
Ok(e) => e,
|
||||
Err(err) => {
|
||||
lsp_warn!("Couldn't covert text document edit: {:#}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
text_document_edits.push(edit);
|
||||
}
|
||||
Ok(Some(lsp::WorkspaceEdit {
|
||||
changes: None,
|
||||
|
|
|
@ -18,6 +18,7 @@ pub struct BinEntries<'a> {
|
|||
seen_names: HashMap<&'a str, &'a NpmPackageId>,
|
||||
/// The bin entries
|
||||
entries: Vec<(&'a NpmResolutionPackage, PathBuf)>,
|
||||
sorted: bool,
|
||||
}
|
||||
|
||||
/// Returns the name of the default binary for the given package.
|
||||
|
@ -31,6 +32,20 @@ fn default_bin_name(package: &NpmResolutionPackage) -> &str {
|
|||
.map_or(package.id.nv.name.as_str(), |(_, name)| name)
|
||||
}
|
||||
|
||||
pub fn warn_missing_entrypoint(
|
||||
bin_name: &str,
|
||||
package_path: &Path,
|
||||
entrypoint: &Path,
|
||||
) {
|
||||
log::warn!(
|
||||
"{} Trying to set up '{}' bin for \"{}\", but the entry point \"{}\" doesn't exist.",
|
||||
deno_terminal::colors::yellow("Warning"),
|
||||
bin_name,
|
||||
package_path.display(),
|
||||
entrypoint.display()
|
||||
);
|
||||
}
|
||||
|
||||
impl<'a> BinEntries<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
|
@ -42,6 +57,7 @@ impl<'a> BinEntries<'a> {
|
|||
package: &'a NpmResolutionPackage,
|
||||
package_path: PathBuf,
|
||||
) {
|
||||
self.sorted = false;
|
||||
// check for a new collision, if we haven't already
|
||||
// found one
|
||||
match package.bin.as_ref().unwrap() {
|
||||
|
@ -79,16 +95,21 @@ impl<'a> BinEntries<'a> {
|
|||
&str, // bin name
|
||||
&str, // bin script
|
||||
) -> Result<(), AnyError>,
|
||||
mut filter: impl FnMut(&NpmResolutionPackage) -> bool,
|
||||
) -> Result<(), AnyError> {
|
||||
if !self.collisions.is_empty() {
|
||||
if !self.collisions.is_empty() && !self.sorted {
|
||||
// walking the dependency tree to find out the depth of each package
|
||||
// is sort of expensive, so we only do it if there's a collision
|
||||
sort_by_depth(snapshot, &mut self.entries, &mut self.collisions);
|
||||
self.sorted = true;
|
||||
}
|
||||
|
||||
let mut seen = HashSet::new();
|
||||
|
||||
for (package, package_path) in &self.entries {
|
||||
if !filter(package) {
|
||||
continue;
|
||||
}
|
||||
if let Some(bin_entries) = &package.bin {
|
||||
match bin_entries {
|
||||
deno_npm::registry::NpmPackageVersionBinEntry::String(script) => {
|
||||
|
@ -118,8 +139,8 @@ impl<'a> BinEntries<'a> {
|
|||
}
|
||||
|
||||
/// Collect the bin entries into a vec of (name, script path)
|
||||
pub fn into_bin_files(
|
||||
mut self,
|
||||
pub fn collect_bin_files(
|
||||
&mut self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
) -> Vec<(String, PathBuf)> {
|
||||
let mut bins = Vec::new();
|
||||
|
@ -131,17 +152,18 @@ impl<'a> BinEntries<'a> {
|
|||
bins.push((name.to_string(), package_path.join(script)));
|
||||
Ok(())
|
||||
},
|
||||
|_| true,
|
||||
)
|
||||
.unwrap();
|
||||
bins
|
||||
}
|
||||
|
||||
/// Finish setting up the bin entries, writing the necessary files
|
||||
/// to disk.
|
||||
pub fn finish(
|
||||
fn set_up_entries_filtered(
|
||||
mut self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
bin_node_modules_dir_path: &Path,
|
||||
filter: impl FnMut(&NpmResolutionPackage) -> bool,
|
||||
mut handler: impl FnMut(&EntrySetupOutcome<'_>),
|
||||
) -> Result<(), AnyError> {
|
||||
if !self.entries.is_empty() && !bin_node_modules_dir_path.exists() {
|
||||
std::fs::create_dir_all(bin_node_modules_dir_path).with_context(
|
||||
|
@ -160,18 +182,54 @@ impl<'a> BinEntries<'a> {
|
|||
Ok(())
|
||||
},
|
||||
|package, package_path, name, script| {
|
||||
set_up_bin_entry(
|
||||
let outcome = set_up_bin_entry(
|
||||
package,
|
||||
name,
|
||||
script,
|
||||
package_path,
|
||||
bin_node_modules_dir_path,
|
||||
)
|
||||
)?;
|
||||
handler(&outcome);
|
||||
Ok(())
|
||||
},
|
||||
filter,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Finish setting up the bin entries, writing the necessary files
|
||||
/// to disk.
|
||||
pub fn finish(
|
||||
self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
bin_node_modules_dir_path: &Path,
|
||||
handler: impl FnMut(&EntrySetupOutcome<'_>),
|
||||
) -> Result<(), AnyError> {
|
||||
self.set_up_entries_filtered(
|
||||
snapshot,
|
||||
bin_node_modules_dir_path,
|
||||
|_| true,
|
||||
handler,
|
||||
)
|
||||
}
|
||||
|
||||
/// Finish setting up the bin entries, writing the necessary files
|
||||
/// to disk.
|
||||
pub fn finish_only(
|
||||
self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
bin_node_modules_dir_path: &Path,
|
||||
handler: impl FnMut(&EntrySetupOutcome<'_>),
|
||||
only: &HashSet<&NpmPackageId>,
|
||||
) -> Result<(), AnyError> {
|
||||
self.set_up_entries_filtered(
|
||||
snapshot,
|
||||
bin_node_modules_dir_path,
|
||||
|package| only.contains(&package.id),
|
||||
handler,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// walk the dependency tree to find out the depth of each package
|
||||
|
@ -233,16 +291,17 @@ fn sort_by_depth(
|
|||
});
|
||||
}
|
||||
|
||||
pub fn set_up_bin_entry(
|
||||
package: &NpmResolutionPackage,
|
||||
bin_name: &str,
|
||||
pub fn set_up_bin_entry<'a>(
|
||||
package: &'a NpmResolutionPackage,
|
||||
bin_name: &'a str,
|
||||
#[allow(unused_variables)] bin_script: &str,
|
||||
#[allow(unused_variables)] package_path: &Path,
|
||||
#[allow(unused_variables)] package_path: &'a Path,
|
||||
bin_node_modules_dir_path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<EntrySetupOutcome<'a>, AnyError> {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
set_up_bin_shim(package, bin_name, bin_node_modules_dir_path)?;
|
||||
Ok(EntrySetupOutcome::Success)
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
|
@ -252,9 +311,8 @@ pub fn set_up_bin_entry(
|
|||
bin_script,
|
||||
package_path,
|
||||
bin_node_modules_dir_path,
|
||||
)?;
|
||||
)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -301,14 +359,39 @@ fn make_executable_if_exists(path: &Path) -> Result<bool, AnyError> {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
pub enum EntrySetupOutcome<'a> {
|
||||
#[cfg_attr(windows, allow(dead_code))]
|
||||
MissingEntrypoint {
|
||||
bin_name: &'a str,
|
||||
package_path: &'a Path,
|
||||
entrypoint: PathBuf,
|
||||
package: &'a NpmResolutionPackage,
|
||||
},
|
||||
Success,
|
||||
}
|
||||
|
||||
impl<'a> EntrySetupOutcome<'a> {
|
||||
pub fn warn_if_failed(&self) {
|
||||
match self {
|
||||
EntrySetupOutcome::MissingEntrypoint {
|
||||
bin_name,
|
||||
package_path,
|
||||
entrypoint,
|
||||
..
|
||||
} => warn_missing_entrypoint(bin_name, package_path, entrypoint),
|
||||
EntrySetupOutcome::Success => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn symlink_bin_entry(
|
||||
_package: &NpmResolutionPackage,
|
||||
bin_name: &str,
|
||||
fn symlink_bin_entry<'a>(
|
||||
package: &'a NpmResolutionPackage,
|
||||
bin_name: &'a str,
|
||||
bin_script: &str,
|
||||
package_path: &Path,
|
||||
package_path: &'a Path,
|
||||
bin_node_modules_dir_path: &Path,
|
||||
) -> Result<(), AnyError> {
|
||||
) -> Result<EntrySetupOutcome<'a>, AnyError> {
|
||||
use std::io;
|
||||
use std::os::unix::fs::symlink;
|
||||
let link = bin_node_modules_dir_path.join(bin_name);
|
||||
|
@ -318,14 +401,12 @@ fn symlink_bin_entry(
|
|||
format!("Can't set up '{}' bin at {}", bin_name, original.display())
|
||||
})?;
|
||||
if !found {
|
||||
log::warn!(
|
||||
"{} Trying to set up '{}' bin for \"{}\", but the entry point \"{}\" doesn't exist.",
|
||||
deno_terminal::colors::yellow("Warning"),
|
||||
return Ok(EntrySetupOutcome::MissingEntrypoint {
|
||||
bin_name,
|
||||
package_path.display(),
|
||||
original.display()
|
||||
);
|
||||
return Ok(());
|
||||
package_path,
|
||||
entrypoint: original,
|
||||
package,
|
||||
});
|
||||
}
|
||||
|
||||
let original_relative =
|
||||
|
@ -348,7 +429,7 @@ fn symlink_bin_entry(
|
|||
original_relative.display()
|
||||
)
|
||||
})?;
|
||||
return Ok(());
|
||||
return Ok(EntrySetupOutcome::Success);
|
||||
}
|
||||
return Err(err).with_context(|| {
|
||||
format!(
|
||||
|
@ -359,5 +440,5 @@ fn symlink_bin_entry(
|
|||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(EntrySetupOutcome::Success)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use deno_runtime::deno_io::FromRawIoHandle;
|
|||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
|
||||
use std::path::Path;
|
||||
|
@ -61,7 +62,7 @@ impl<'a> LifecycleScripts<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_lifecycle_scripts(
|
||||
pub fn has_lifecycle_scripts(
|
||||
package: &NpmResolutionPackage,
|
||||
package_path: &Path,
|
||||
) -> bool {
|
||||
|
@ -83,7 +84,7 @@ fn is_broken_default_install_script(script: &str, package_path: &Path) -> bool {
|
|||
}
|
||||
|
||||
impl<'a> LifecycleScripts<'a> {
|
||||
fn can_run_scripts(&self, package_nv: &PackageNv) -> bool {
|
||||
pub fn can_run_scripts(&self, package_nv: &PackageNv) -> bool {
|
||||
if !self.strategy.can_run_scripts() {
|
||||
return false;
|
||||
}
|
||||
|
@ -98,6 +99,9 @@ impl<'a> LifecycleScripts<'a> {
|
|||
PackagesAllowedScripts::None => false,
|
||||
}
|
||||
}
|
||||
pub fn has_run_scripts(&self, package: &NpmResolutionPackage) -> bool {
|
||||
self.strategy.has_run(package)
|
||||
}
|
||||
/// Register a package for running lifecycle scripts, if applicable.
|
||||
///
|
||||
/// `package_path` is the path containing the package's code (its root dir).
|
||||
|
@ -110,12 +114,12 @@ impl<'a> LifecycleScripts<'a> {
|
|||
) {
|
||||
if has_lifecycle_scripts(package, &package_path) {
|
||||
if self.can_run_scripts(&package.id.nv) {
|
||||
if !self.strategy.has_run(package) {
|
||||
if !self.has_run_scripts(package) {
|
||||
self
|
||||
.packages_with_scripts
|
||||
.push((package, package_path.into_owned()));
|
||||
}
|
||||
} else if !self.strategy.has_run(package)
|
||||
} else if !self.has_run_scripts(package)
|
||||
&& (self.config.explicit_install || !self.strategy.has_warned(package))
|
||||
{
|
||||
// Skip adding `esbuild` as it is known that it can work properly without lifecycle script
|
||||
|
@ -149,22 +153,32 @@ impl<'a> LifecycleScripts<'a> {
|
|||
self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
packages: &[NpmResolutionPackage],
|
||||
root_node_modules_dir_path: Option<&Path>,
|
||||
root_node_modules_dir_path: &Path,
|
||||
progress_bar: &ProgressBar,
|
||||
) -> Result<(), AnyError> {
|
||||
self.warn_not_run_scripts()?;
|
||||
let get_package_path =
|
||||
|p: &NpmResolutionPackage| self.strategy.package_path(p);
|
||||
let mut failed_packages = Vec::new();
|
||||
let mut bin_entries = BinEntries::new();
|
||||
if !self.packages_with_scripts.is_empty() {
|
||||
let package_ids = self
|
||||
.packages_with_scripts
|
||||
.iter()
|
||||
.map(|(p, _)| &p.id)
|
||||
.collect::<HashSet<_>>();
|
||||
// get custom commands for each bin available in the node_modules dir (essentially
|
||||
// the scripts that are in `node_modules/.bin`)
|
||||
let base =
|
||||
resolve_baseline_custom_commands(snapshot, packages, get_package_path)?;
|
||||
let base = resolve_baseline_custom_commands(
|
||||
&mut bin_entries,
|
||||
snapshot,
|
||||
packages,
|
||||
get_package_path,
|
||||
)?;
|
||||
let init_cwd = &self.config.initial_cwd;
|
||||
let process_state = crate::npm::managed::npm_process_state(
|
||||
snapshot.as_valid_serialized(),
|
||||
root_node_modules_dir_path,
|
||||
Some(root_node_modules_dir_path),
|
||||
);
|
||||
|
||||
let mut env_vars = crate::task_runner::real_env_vars();
|
||||
|
@ -221,7 +235,7 @@ impl<'a> LifecycleScripts<'a> {
|
|||
custom_commands: custom_commands.clone(),
|
||||
init_cwd,
|
||||
argv: &[],
|
||||
root_node_modules_dir: root_node_modules_dir_path,
|
||||
root_node_modules_dir: Some(root_node_modules_dir_path),
|
||||
stdio: Some(crate::task_runner::TaskIo {
|
||||
stderr: TaskStdio::piped(),
|
||||
stdout: TaskStdio::piped(),
|
||||
|
@ -262,6 +276,17 @@ impl<'a> LifecycleScripts<'a> {
|
|||
}
|
||||
self.strategy.did_run_scripts(package)?;
|
||||
}
|
||||
|
||||
// re-set up bin entries for the packages which we've run scripts for.
|
||||
// lifecycle scripts can create files that are linked to by bin entries,
|
||||
// and the only reliable way to handle this is to re-link bin entries
|
||||
// (this is what PNPM does as well)
|
||||
bin_entries.finish_only(
|
||||
snapshot,
|
||||
&root_node_modules_dir_path.join(".bin"),
|
||||
|outcome| outcome.warn_if_failed(),
|
||||
&package_ids,
|
||||
)?;
|
||||
}
|
||||
if failed_packages.is_empty() {
|
||||
Ok(())
|
||||
|
@ -281,9 +306,10 @@ impl<'a> LifecycleScripts<'a> {
|
|||
// take in all (non copy) packages from snapshot,
|
||||
// and resolve the set of available binaries to create
|
||||
// custom commands available to the task runner
|
||||
fn resolve_baseline_custom_commands(
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
packages: &[NpmResolutionPackage],
|
||||
fn resolve_baseline_custom_commands<'a>(
|
||||
bin_entries: &mut BinEntries<'a>,
|
||||
snapshot: &'a NpmResolutionSnapshot,
|
||||
packages: &'a [NpmResolutionPackage],
|
||||
get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf,
|
||||
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
|
||||
let mut custom_commands = crate::task_runner::TaskCustomCommands::new();
|
||||
|
@ -306,6 +332,7 @@ fn resolve_baseline_custom_commands(
|
|||
// doing it for packages that are set up already.
|
||||
// realistically, scripts won't be run very often so it probably isn't too big of an issue.
|
||||
resolve_custom_commands_from_packages(
|
||||
bin_entries,
|
||||
custom_commands,
|
||||
snapshot,
|
||||
packages,
|
||||
|
@ -320,12 +347,12 @@ fn resolve_custom_commands_from_packages<
|
|||
'a,
|
||||
P: IntoIterator<Item = &'a NpmResolutionPackage>,
|
||||
>(
|
||||
bin_entries: &mut BinEntries<'a>,
|
||||
mut commands: crate::task_runner::TaskCustomCommands,
|
||||
snapshot: &'a NpmResolutionSnapshot,
|
||||
packages: P,
|
||||
get_package_path: impl Fn(&'a NpmResolutionPackage) -> PathBuf,
|
||||
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
|
||||
let mut bin_entries = BinEntries::new();
|
||||
for package in packages {
|
||||
let package_path = get_package_path(package);
|
||||
|
||||
|
@ -333,7 +360,7 @@ fn resolve_custom_commands_from_packages<
|
|||
bin_entries.add(package, package_path);
|
||||
}
|
||||
}
|
||||
let bins = bin_entries.into_bin_files(snapshot);
|
||||
let bins: Vec<(String, PathBuf)> = bin_entries.collect_bin_files(snapshot);
|
||||
for (bin_name, script_path) in bins {
|
||||
commands.insert(
|
||||
bin_name.clone(),
|
||||
|
@ -356,7 +383,9 @@ fn resolve_custom_commands_from_deps(
|
|||
snapshot: &NpmResolutionSnapshot,
|
||||
get_package_path: impl Fn(&NpmResolutionPackage) -> PathBuf,
|
||||
) -> Result<crate::task_runner::TaskCustomCommands, AnyError> {
|
||||
let mut bin_entries = BinEntries::new();
|
||||
resolve_custom_commands_from_packages(
|
||||
&mut bin_entries,
|
||||
baseline,
|
||||
snapshot,
|
||||
package
|
||||
|
|
|
@ -55,6 +55,7 @@ use crate::util::progress_bar::ProgressMessagePrompt;
|
|||
use super::super::cache::NpmCache;
|
||||
use super::super::cache::TarballCache;
|
||||
use super::super::resolution::NpmResolution;
|
||||
use super::common::bin_entries;
|
||||
use super::common::NpmPackageFsResolver;
|
||||
use super::common::RegistryReadPermissionChecker;
|
||||
|
||||
|
@ -329,8 +330,7 @@ async fn sync_resolution_with_fs(
|
|||
let mut cache_futures = FuturesUnordered::new();
|
||||
let mut newest_packages_by_name: HashMap<&String, &NpmResolutionPackage> =
|
||||
HashMap::with_capacity(package_partitions.packages.len());
|
||||
let bin_entries =
|
||||
Rc::new(RefCell::new(super::common::bin_entries::BinEntries::new()));
|
||||
let bin_entries = Rc::new(RefCell::new(bin_entries::BinEntries::new()));
|
||||
let mut lifecycle_scripts =
|
||||
super::common::lifecycle_scripts::LifecycleScripts::new(
|
||||
lifecycle_scripts,
|
||||
|
@ -658,7 +658,28 @@ async fn sync_resolution_with_fs(
|
|||
// 7. Set up `node_modules/.bin` entries for packages that need it.
|
||||
{
|
||||
let bin_entries = std::mem::take(&mut *bin_entries.borrow_mut());
|
||||
bin_entries.finish(snapshot, &bin_node_modules_dir_path)?;
|
||||
bin_entries.finish(
|
||||
snapshot,
|
||||
&bin_node_modules_dir_path,
|
||||
|setup_outcome| {
|
||||
match setup_outcome {
|
||||
bin_entries::EntrySetupOutcome::MissingEntrypoint {
|
||||
package,
|
||||
package_path,
|
||||
..
|
||||
} if super::common::lifecycle_scripts::has_lifecycle_scripts(
|
||||
package,
|
||||
package_path,
|
||||
) && lifecycle_scripts.can_run_scripts(&package.id.nv)
|
||||
&& !lifecycle_scripts.has_run_scripts(package) =>
|
||||
{
|
||||
// ignore, it might get fixed when the lifecycle scripts run.
|
||||
// if not, we'll warn then
|
||||
}
|
||||
outcome => outcome.warn_if_failed(),
|
||||
}
|
||||
},
|
||||
)?;
|
||||
}
|
||||
|
||||
// 8. Create symlinks for the workspace packages
|
||||
|
@ -708,7 +729,7 @@ async fn sync_resolution_with_fs(
|
|||
.finish(
|
||||
snapshot,
|
||||
&package_partitions.packages,
|
||||
Some(root_node_modules_dir_path),
|
||||
root_node_modules_dir_path,
|
||||
progress_bar,
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.170.0"
|
||||
version = "0.171.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
2
ext/cache/Cargo.toml
vendored
2
ext/cache/Cargo.toml
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cache"
|
||||
version = "0.108.0"
|
||||
version = "0.109.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_canvas"
|
||||
version = "0.45.0"
|
||||
version = "0.46.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_console"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_cron"
|
||||
version = "0.56.0"
|
||||
version = "0.57.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_crypto"
|
||||
version = "0.190.0"
|
||||
version = "0.191.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fetch"
|
||||
version = "0.200.0"
|
||||
version = "0.201.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_ffi"
|
||||
version = "0.163.0"
|
||||
version = "0.164.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fs"
|
||||
version = "0.86.0"
|
||||
version = "0.87.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_http"
|
||||
version = "0.174.0"
|
||||
version = "0.175.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -564,6 +564,7 @@ fn is_request_compressible(
|
|||
match accept_encoding.to_str() {
|
||||
// Firefox and Chrome send this -- no need to parse
|
||||
Ok("gzip, deflate, br") => return Compression::Brotli,
|
||||
Ok("gzip, deflate, br, zstd") => return Compression::Brotli,
|
||||
Ok("gzip") => return Compression::GZip,
|
||||
Ok("br") => return Compression::Brotli,
|
||||
_ => (),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_io"
|
||||
version = "0.86.0"
|
||||
version = "0.87.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_kv"
|
||||
version = "0.84.0"
|
||||
version = "0.85.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct KvConfig {
|
||||
pub(crate) max_write_key_size_bytes: usize,
|
||||
pub(crate) max_read_key_size_bytes: usize,
|
||||
pub(crate) max_value_size_bytes: usize,
|
||||
pub(crate) max_read_ranges: usize,
|
||||
pub(crate) max_read_entries: usize,
|
||||
pub(crate) max_checks: usize,
|
||||
pub(crate) max_mutations: usize,
|
||||
pub(crate) max_watched_keys: usize,
|
||||
pub(crate) max_total_mutation_size_bytes: usize,
|
||||
pub(crate) max_total_key_size_bytes: usize,
|
||||
pub max_write_key_size_bytes: usize,
|
||||
pub max_read_key_size_bytes: usize,
|
||||
pub max_value_size_bytes: usize,
|
||||
pub max_read_ranges: usize,
|
||||
pub max_read_entries: usize,
|
||||
pub max_checks: usize,
|
||||
pub max_mutations: usize,
|
||||
pub max_watched_keys: usize,
|
||||
pub max_total_mutation_size_bytes: usize,
|
||||
pub max_total_key_size_bytes: usize,
|
||||
}
|
||||
|
||||
impl KvConfig {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_napi"
|
||||
version = "0.107.0"
|
||||
version = "0.108.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "napi_sym"
|
||||
version = "0.106.0"
|
||||
version = "0.107.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_net"
|
||||
version = "0.168.0"
|
||||
version = "0.169.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_node"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
const { JSONStringify, SymbolFor } = primordials;
|
||||
const { JSONStringify, SafeArrayIterator, SymbolFor } = primordials;
|
||||
import { format, inspect } from "ext:deno_node/internal/util/inspect.mjs";
|
||||
import { codes } from "ext:deno_node/internal/error_codes.ts";
|
||||
import {
|
||||
|
@ -1874,6 +1874,11 @@ export class ERR_SOCKET_CLOSED extends NodeError {
|
|||
super("ERR_SOCKET_CLOSED", `Socket is closed`);
|
||||
}
|
||||
}
|
||||
export class ERR_SOCKET_CONNECTION_TIMEOUT extends NodeError {
|
||||
constructor() {
|
||||
super("ERR_SOCKET_CONNECTION_TIMEOUT", `Socket connection timeout`);
|
||||
}
|
||||
}
|
||||
export class ERR_SOCKET_DGRAM_IS_CONNECTED extends NodeError {
|
||||
constructor() {
|
||||
super("ERR_SOCKET_DGRAM_IS_CONNECTED", `Already connected`);
|
||||
|
@ -2633,11 +2638,30 @@ export function aggregateTwoErrors(
|
|||
}
|
||||
return innerError || outerError;
|
||||
}
|
||||
|
||||
export class NodeAggregateError extends AggregateError {
|
||||
code: string;
|
||||
constructor(errors, message) {
|
||||
super(new SafeArrayIterator(errors), message);
|
||||
this.code = errors[0]?.code;
|
||||
}
|
||||
|
||||
get [kIsNodeError]() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// deno-lint-ignore adjacent-overload-signatures
|
||||
get ["constructor"]() {
|
||||
return AggregateError;
|
||||
}
|
||||
}
|
||||
|
||||
codes.ERR_IPC_CHANNEL_CLOSED = ERR_IPC_CHANNEL_CLOSED;
|
||||
codes.ERR_INVALID_ARG_TYPE = ERR_INVALID_ARG_TYPE;
|
||||
codes.ERR_INVALID_ARG_VALUE = ERR_INVALID_ARG_VALUE;
|
||||
codes.ERR_OUT_OF_RANGE = ERR_OUT_OF_RANGE;
|
||||
codes.ERR_SOCKET_BAD_PORT = ERR_SOCKET_BAD_PORT;
|
||||
codes.ERR_SOCKET_CONNECTION_TIMEOUT = ERR_SOCKET_CONNECTION_TIMEOUT;
|
||||
codes.ERR_BUFFER_OUT_OF_BOUNDS = ERR_BUFFER_OUT_OF_BOUNDS;
|
||||
codes.ERR_UNKNOWN_ENCODING = ERR_UNKNOWN_ENCODING;
|
||||
codes.ERR_PARSE_ARGS_INVALID_OPTION_VALUE = ERR_PARSE_ARGS_INVALID_OPTION_VALUE;
|
||||
|
|
|
@ -95,4 +95,5 @@ export function makeSyncWrite(fd: number) {
|
|||
};
|
||||
}
|
||||
|
||||
export const kReinitializeHandle = Symbol("kReinitializeHandle");
|
||||
export const normalizedArgsSymbol = Symbol("normalizedArgs");
|
||||
|
|
|
@ -530,10 +530,12 @@ export function mapSysErrnoToUvErrno(sysErrno: number): number {
|
|||
|
||||
export const UV_EAI_MEMORY = codeMap.get("EAI_MEMORY")!;
|
||||
export const UV_EBADF = codeMap.get("EBADF")!;
|
||||
export const UV_ECANCELED = codeMap.get("ECANCELED")!;
|
||||
export const UV_EEXIST = codeMap.get("EEXIST");
|
||||
export const UV_EINVAL = codeMap.get("EINVAL")!;
|
||||
export const UV_ENOENT = codeMap.get("ENOENT");
|
||||
export const UV_ENOTSOCK = codeMap.get("ENOTSOCK")!;
|
||||
export const UV_ETIMEDOUT = codeMap.get("ETIMEDOUT")!;
|
||||
export const UV_UNKNOWN = codeMap.get("UNKNOWN")!;
|
||||
|
||||
export function errname(errno: number): string {
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
isIP,
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
kReinitializeHandle,
|
||||
normalizedArgsSymbol,
|
||||
} from "ext:deno_node/internal/net.ts";
|
||||
import { Duplex } from "node:stream";
|
||||
|
@ -50,9 +51,11 @@ import {
|
|||
ERR_SERVER_ALREADY_LISTEN,
|
||||
ERR_SERVER_NOT_RUNNING,
|
||||
ERR_SOCKET_CLOSED,
|
||||
ERR_SOCKET_CONNECTION_TIMEOUT,
|
||||
errnoException,
|
||||
exceptionWithHostPort,
|
||||
genericNodeError,
|
||||
NodeAggregateError,
|
||||
uvExceptionWithHostPort,
|
||||
} from "ext:deno_node/internal/errors.ts";
|
||||
import type { ErrnoException } from "ext:deno_node/internal/errors.ts";
|
||||
|
@ -80,6 +83,7 @@ import { Buffer } from "node:buffer";
|
|||
import type { LookupOneOptions } from "ext:deno_node/internal/dns/utils.ts";
|
||||
import {
|
||||
validateAbortSignal,
|
||||
validateBoolean,
|
||||
validateFunction,
|
||||
validateInt32,
|
||||
validateNumber,
|
||||
|
@ -100,13 +104,25 @@ import { ShutdownWrap } from "ext:deno_node/internal_binding/stream_wrap.ts";
|
|||
import { assert } from "ext:deno_node/_util/asserts.ts";
|
||||
import { isWindows } from "ext:deno_node/_util/os.ts";
|
||||
import { ADDRCONFIG, lookup as dnsLookup } from "node:dns";
|
||||
import { codeMap } from "ext:deno_node/internal_binding/uv.ts";
|
||||
import {
|
||||
codeMap,
|
||||
UV_ECANCELED,
|
||||
UV_ETIMEDOUT,
|
||||
} from "ext:deno_node/internal_binding/uv.ts";
|
||||
import { guessHandleType } from "ext:deno_node/internal_binding/util.ts";
|
||||
import { debuglog } from "ext:deno_node/internal/util/debuglog.ts";
|
||||
import type { DuplexOptions } from "ext:deno_node/_stream.d.ts";
|
||||
import type { BufferEncoding } from "ext:deno_node/_global.d.ts";
|
||||
import type { Abortable } from "ext:deno_node/_events.d.ts";
|
||||
import { channel } from "node:diagnostics_channel";
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
|
||||
const {
|
||||
ArrayPrototypeIncludes,
|
||||
ArrayPrototypePush,
|
||||
FunctionPrototypeBind,
|
||||
MathMax,
|
||||
} = primordials;
|
||||
|
||||
let debug = debuglog("net", (fn) => {
|
||||
debug = fn;
|
||||
|
@ -120,6 +136,9 @@ const kBytesWritten = Symbol("kBytesWritten");
|
|||
const DEFAULT_IPV4_ADDR = "0.0.0.0";
|
||||
const DEFAULT_IPV6_ADDR = "::";
|
||||
|
||||
let autoSelectFamilyDefault = true;
|
||||
let autoSelectFamilyAttemptTimeoutDefault = 250;
|
||||
|
||||
type Handle = TCP | Pipe;
|
||||
|
||||
interface HandleOptions {
|
||||
|
@ -214,6 +233,8 @@ interface TcpSocketConnectOptions extends ConnectOptions {
|
|||
hints?: number;
|
||||
family?: number;
|
||||
lookup?: LookupFunction;
|
||||
autoSelectFamily?: boolean | undefined;
|
||||
autoSelectFamilyAttemptTimeout?: number | undefined;
|
||||
}
|
||||
|
||||
interface IpcSocketConnectOptions extends ConnectOptions {
|
||||
|
@ -316,12 +337,6 @@ export function _normalizeArgs(args: unknown[]): NormalizedArgs {
|
|||
return arr;
|
||||
}
|
||||
|
||||
function _isTCPConnectWrap(
|
||||
req: TCPConnectWrap | PipeConnectWrap,
|
||||
): req is TCPConnectWrap {
|
||||
return "localAddress" in req && "localPort" in req;
|
||||
}
|
||||
|
||||
function _afterConnect(
|
||||
status: number,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
|
@ -372,7 +387,7 @@ function _afterConnect(
|
|||
socket.connecting = false;
|
||||
let details;
|
||||
|
||||
if (_isTCPConnectWrap(req)) {
|
||||
if (req.localAddress && req.localPort) {
|
||||
details = req.localAddress + ":" + req.localPort;
|
||||
}
|
||||
|
||||
|
@ -384,7 +399,7 @@ function _afterConnect(
|
|||
details,
|
||||
);
|
||||
|
||||
if (_isTCPConnectWrap(req)) {
|
||||
if (details) {
|
||||
ex.localAddress = req.localAddress;
|
||||
ex.localPort = req.localPort;
|
||||
}
|
||||
|
@ -393,6 +408,107 @@ function _afterConnect(
|
|||
}
|
||||
}
|
||||
|
||||
function _createConnectionError(req, status) {
|
||||
let details;
|
||||
|
||||
if (req.localAddress && req.localPort) {
|
||||
details = req.localAddress + ":" + req.localPort;
|
||||
}
|
||||
|
||||
const ex = exceptionWithHostPort(
|
||||
status,
|
||||
"connect",
|
||||
req.address,
|
||||
req.port,
|
||||
details,
|
||||
);
|
||||
if (details) {
|
||||
ex.localAddress = req.localAddress;
|
||||
ex.localPort = req.localPort;
|
||||
}
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
function _afterConnectMultiple(
|
||||
context,
|
||||
current,
|
||||
status,
|
||||
handle,
|
||||
req,
|
||||
readable,
|
||||
writable,
|
||||
) {
|
||||
debug(
|
||||
"connect/multiple: connection attempt to %s:%s completed with status %s",
|
||||
req.address,
|
||||
req.port,
|
||||
status,
|
||||
);
|
||||
|
||||
// Make sure another connection is not spawned
|
||||
clearTimeout(context[kTimeout]);
|
||||
|
||||
// One of the connection has completed and correctly dispatched but after timeout, ignore this one
|
||||
if (status === 0 && current !== context.current - 1) {
|
||||
debug(
|
||||
"connect/multiple: ignoring successful but timedout connection to %s:%s",
|
||||
req.address,
|
||||
req.port,
|
||||
);
|
||||
handle.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const self = context.socket;
|
||||
|
||||
// Some error occurred, add to the list of exceptions
|
||||
if (status !== 0) {
|
||||
const ex = _createConnectionError(req, status);
|
||||
ArrayPrototypePush(context.errors, ex);
|
||||
|
||||
self.emit(
|
||||
"connectionAttemptFailed",
|
||||
req.address,
|
||||
req.port,
|
||||
req.addressType,
|
||||
ex,
|
||||
);
|
||||
|
||||
// Try the next address, unless we were aborted
|
||||
if (context.socket.connecting) {
|
||||
_internalConnectMultiple(context, status === UV_ECANCELED);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_afterConnect(status, self._handle, req, readable, writable);
|
||||
}
|
||||
|
||||
function _internalConnectMultipleTimeout(context, req, handle) {
|
||||
debug(
|
||||
"connect/multiple: connection to %s:%s timed out",
|
||||
req.address,
|
||||
req.port,
|
||||
);
|
||||
context.socket.emit(
|
||||
"connectionAttemptTimeout",
|
||||
req.address,
|
||||
req.port,
|
||||
req.addressType,
|
||||
);
|
||||
|
||||
req.oncomplete = undefined;
|
||||
ArrayPrototypePush(context.errors, _createConnectionError(req, UV_ETIMEDOUT));
|
||||
handle.close();
|
||||
|
||||
// Try the next address, unless we were aborted
|
||||
if (context.socket.connecting) {
|
||||
_internalConnectMultiple(context);
|
||||
}
|
||||
}
|
||||
|
||||
function _checkBindError(err: number, port: number, handle: TCP) {
|
||||
// EADDRINUSE may not be reported until we call `listen()` or `connect()`.
|
||||
// To complicate matters, a failed `bind()` followed by `listen()` or `connect()`
|
||||
|
@ -495,6 +611,131 @@ function _internalConnect(
|
|||
}
|
||||
}
|
||||
|
||||
function _internalConnectMultiple(context, canceled?: boolean) {
|
||||
clearTimeout(context[kTimeout]);
|
||||
const self = context.socket;
|
||||
|
||||
// We were requested to abort. Stop all operations
|
||||
if (self._aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// All connections have been tried without success, destroy with error
|
||||
if (canceled || context.current === context.addresses.length) {
|
||||
if (context.errors.length === 0) {
|
||||
self.destroy(new ERR_SOCKET_CONNECTION_TIMEOUT());
|
||||
return;
|
||||
}
|
||||
|
||||
self.destroy(new NodeAggregateError(context.errors));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(self.connecting);
|
||||
|
||||
const current = context.current++;
|
||||
|
||||
if (current > 0) {
|
||||
self[kReinitializeHandle](new TCP(TCPConstants.SOCKET));
|
||||
}
|
||||
|
||||
const { localPort, port, flags } = context;
|
||||
const { address, family: addressType } = context.addresses[current];
|
||||
let localAddress;
|
||||
let err;
|
||||
|
||||
if (localPort) {
|
||||
if (addressType === 4) {
|
||||
localAddress = DEFAULT_IPV4_ADDR;
|
||||
err = self._handle.bind(localAddress, localPort);
|
||||
} else { // addressType === 6
|
||||
localAddress = DEFAULT_IPV6_ADDR;
|
||||
err = self._handle.bind6(localAddress, localPort, flags);
|
||||
}
|
||||
|
||||
debug(
|
||||
"connect/multiple: binding to localAddress: %s and localPort: %d (addressType: %d)",
|
||||
localAddress,
|
||||
localPort,
|
||||
addressType,
|
||||
);
|
||||
|
||||
err = _checkBindError(err, localPort, self._handle);
|
||||
if (err) {
|
||||
ArrayPrototypePush(
|
||||
context.errors,
|
||||
exceptionWithHostPort(err, "bind", localAddress, localPort),
|
||||
);
|
||||
_internalConnectMultiple(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
debug(
|
||||
"connect/multiple: attempting to connect to %s:%d (addressType: %d)",
|
||||
address,
|
||||
port,
|
||||
addressType,
|
||||
);
|
||||
self.emit("connectionAttempt", address, port, addressType);
|
||||
|
||||
const req = new TCPConnectWrap();
|
||||
req.oncomplete = FunctionPrototypeBind(
|
||||
_afterConnectMultiple,
|
||||
undefined,
|
||||
context,
|
||||
current,
|
||||
);
|
||||
req.address = address;
|
||||
req.port = port;
|
||||
req.localAddress = localAddress;
|
||||
req.localPort = localPort;
|
||||
req.addressType = addressType;
|
||||
|
||||
ArrayPrototypePush(
|
||||
self.autoSelectFamilyAttemptedAddresses,
|
||||
`${address}:${port}`,
|
||||
);
|
||||
|
||||
if (addressType === 4) {
|
||||
err = self._handle.connect(req, address, port);
|
||||
} else {
|
||||
err = self._handle.connect6(req, address, port);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
const sockname = self._getsockname();
|
||||
let details;
|
||||
|
||||
if (sockname) {
|
||||
details = sockname.address + ":" + sockname.port;
|
||||
}
|
||||
|
||||
const ex = exceptionWithHostPort(err, "connect", address, port, details);
|
||||
ArrayPrototypePush(context.errors, ex);
|
||||
|
||||
self.emit("connectionAttemptFailed", address, port, addressType, ex);
|
||||
_internalConnectMultiple(context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current < context.addresses.length - 1) {
|
||||
debug(
|
||||
"connect/multiple: setting the attempt timeout to %d ms",
|
||||
context.timeout,
|
||||
);
|
||||
|
||||
// If the attempt has not returned an error, start the connection timer
|
||||
context[kTimeout] = setTimeout(
|
||||
_internalConnectMultipleTimeout,
|
||||
context.timeout,
|
||||
context,
|
||||
req,
|
||||
self._handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a better error message when we call end() as a result
|
||||
// of the other side sending a FIN. The standard "write after end"
|
||||
// is overly vague, and makes it seem like the user's code is to blame.
|
||||
|
@ -597,7 +838,7 @@ function _lookupAndConnect(
|
|||
) {
|
||||
const { localAddress, localPort } = options;
|
||||
const host = options.host || "localhost";
|
||||
let { port } = options;
|
||||
let { port, autoSelectFamilyAttemptTimeout, autoSelectFamily } = options;
|
||||
|
||||
if (localAddress && !isIP(localAddress)) {
|
||||
throw new ERR_INVALID_IP_ADDRESS(localAddress);
|
||||
|
@ -621,6 +862,22 @@ function _lookupAndConnect(
|
|||
|
||||
port |= 0;
|
||||
|
||||
if (autoSelectFamily != null) {
|
||||
validateBoolean(autoSelectFamily, "options.autoSelectFamily");
|
||||
} else {
|
||||
autoSelectFamily = autoSelectFamilyDefault;
|
||||
}
|
||||
|
||||
if (autoSelectFamilyAttemptTimeout !== undefined) {
|
||||
validateInt32(autoSelectFamilyAttemptTimeout);
|
||||
|
||||
if (autoSelectFamilyAttemptTimeout < 10) {
|
||||
autoSelectFamilyAttemptTimeout = 10;
|
||||
}
|
||||
} else {
|
||||
autoSelectFamilyAttemptTimeout = autoSelectFamilyAttemptTimeoutDefault;
|
||||
}
|
||||
|
||||
// If host is an IP, skip performing a lookup
|
||||
const addressType = isIP(host);
|
||||
if (addressType) {
|
||||
|
@ -649,6 +906,7 @@ function _lookupAndConnect(
|
|||
const dnsOpts = {
|
||||
family: options.family,
|
||||
hints: options.hints || 0,
|
||||
all: false,
|
||||
};
|
||||
|
||||
if (
|
||||
|
@ -665,6 +923,31 @@ function _lookupAndConnect(
|
|||
self._host = host;
|
||||
const lookup = options.lookup || dnsLookup;
|
||||
|
||||
if (
|
||||
dnsOpts.family !== 4 && dnsOpts.family !== 6 && !localAddress &&
|
||||
autoSelectFamily
|
||||
) {
|
||||
debug("connect: autodetecting");
|
||||
|
||||
dnsOpts.all = true;
|
||||
defaultTriggerAsyncIdScope(self[asyncIdSymbol], function () {
|
||||
_lookupAndConnectMultiple(
|
||||
self,
|
||||
asyncIdSymbol,
|
||||
lookup,
|
||||
host,
|
||||
options,
|
||||
dnsOpts,
|
||||
port,
|
||||
localAddress,
|
||||
localPort,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
defaultTriggerAsyncIdScope(self[asyncIdSymbol], function () {
|
||||
lookup(
|
||||
host,
|
||||
|
@ -719,6 +1002,143 @@ function _lookupAndConnect(
|
|||
});
|
||||
}
|
||||
|
||||
function _lookupAndConnectMultiple(
|
||||
self: Socket,
|
||||
asyncIdSymbol: number,
|
||||
// deno-lint-ignore no-explicit-any
|
||||
lookup: any,
|
||||
host: string,
|
||||
options: TcpSocketConnectOptions,
|
||||
dnsopts,
|
||||
port: number,
|
||||
localAddress: string,
|
||||
localPort: number,
|
||||
timeout: number | undefined,
|
||||
) {
|
||||
defaultTriggerAsyncIdScope(self[asyncIdSymbol], function emitLookup() {
|
||||
lookup(host, dnsopts, function emitLookup(err, addresses) {
|
||||
// It's possible we were destroyed while looking this up.
|
||||
// XXX it would be great if we could cancel the promise returned by
|
||||
// the look up.
|
||||
if (!self.connecting) {
|
||||
return;
|
||||
} else if (err) {
|
||||
self.emit("lookup", err, undefined, undefined, host);
|
||||
|
||||
// net.createConnection() creates a net.Socket object and immediately
|
||||
// calls net.Socket.connect() on it (that's us). There are no event
|
||||
// listeners registered yet so defer the error event to the next tick.
|
||||
nextTick(_connectErrorNT, self, err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter addresses by only keeping the one which are either IPv4 or IPV6.
|
||||
// The first valid address determines which group has preference on the
|
||||
// alternate family sorting which happens later.
|
||||
const validAddresses = [[], []];
|
||||
const validIps = [[], []];
|
||||
let destinations;
|
||||
for (let i = 0, l = addresses.length; i < l; i++) {
|
||||
const address = addresses[i];
|
||||
const { address: ip, family: addressType } = address;
|
||||
self.emit("lookup", err, ip, addressType, host);
|
||||
// It's possible we were destroyed while looking this up.
|
||||
if (!self.connecting) {
|
||||
return;
|
||||
}
|
||||
if (isIP(ip) && (addressType === 4 || addressType === 6)) {
|
||||
destinations ||= addressType === 6 ? { 6: 0, 4: 1 } : { 4: 0, 6: 1 };
|
||||
|
||||
const destination = destinations[addressType];
|
||||
|
||||
// Only try an address once
|
||||
if (!ArrayPrototypeIncludes(validIps[destination], ip)) {
|
||||
ArrayPrototypePush(validAddresses[destination], address);
|
||||
ArrayPrototypePush(validIps[destination], ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When no AAAA or A records are available, fail on the first one
|
||||
if (!validAddresses[0].length && !validAddresses[1].length) {
|
||||
const { address: firstIp, family: firstAddressType } = addresses[0];
|
||||
|
||||
if (!isIP(firstIp)) {
|
||||
err = new ERR_INVALID_IP_ADDRESS(firstIp);
|
||||
nextTick(_connectErrorNT, self, err);
|
||||
} else if (firstAddressType !== 4 && firstAddressType !== 6) {
|
||||
err = new ERR_INVALID_ADDRESS_FAMILY(
|
||||
firstAddressType,
|
||||
options.host,
|
||||
options.port,
|
||||
);
|
||||
nextTick(_connectErrorNT, self, err);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort addresses alternating families
|
||||
const toAttempt = [];
|
||||
for (
|
||||
let i = 0,
|
||||
l = MathMax(validAddresses[0].length, validAddresses[1].length);
|
||||
i < l;
|
||||
i++
|
||||
) {
|
||||
if (i in validAddresses[0]) {
|
||||
ArrayPrototypePush(toAttempt, validAddresses[0][i]);
|
||||
}
|
||||
if (i in validAddresses[1]) {
|
||||
ArrayPrototypePush(toAttempt, validAddresses[1][i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (toAttempt.length === 1) {
|
||||
debug(
|
||||
"connect/multiple: only one address found, switching back to single connection",
|
||||
);
|
||||
const { address: ip, family: addressType } = toAttempt[0];
|
||||
|
||||
self._unrefTimer();
|
||||
defaultTriggerAsyncIdScope(
|
||||
self[asyncIdSymbol],
|
||||
_internalConnect,
|
||||
self,
|
||||
ip,
|
||||
port,
|
||||
addressType,
|
||||
localAddress,
|
||||
localPort,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self.autoSelectFamilyAttemptedAddresses = [];
|
||||
debug("connect/multiple: will try the following addresses", toAttempt);
|
||||
|
||||
const context = {
|
||||
socket: self,
|
||||
addresses: toAttempt,
|
||||
current: 0,
|
||||
port,
|
||||
localPort,
|
||||
timeout,
|
||||
[kTimeout]: null,
|
||||
errors: [],
|
||||
};
|
||||
|
||||
self._unrefTimer();
|
||||
defaultTriggerAsyncIdScope(
|
||||
self[asyncIdSymbol],
|
||||
_internalConnectMultiple,
|
||||
context,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function _afterShutdown(this: ShutdownWrap<TCP>) {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const self: any = this.handle[ownerSymbol];
|
||||
|
@ -777,6 +1197,7 @@ export class Socket extends Duplex {
|
|||
_host: string | null = null;
|
||||
// deno-lint-ignore no-explicit-any
|
||||
_parent: any = null;
|
||||
autoSelectFamilyAttemptedAddresses: AddressInfo[] | undefined = undefined;
|
||||
|
||||
constructor(options: SocketOptions | number) {
|
||||
if (typeof options === "number") {
|
||||
|
@ -1546,6 +1967,16 @@ export class Socket extends Duplex {
|
|||
set _handle(v: Handle | null) {
|
||||
this[kHandle] = v;
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
[kReinitializeHandle](handle: any) {
|
||||
this._handle?.close();
|
||||
|
||||
this._handle = handle;
|
||||
this._handle[ownerSymbol] = this;
|
||||
|
||||
_initSocketHandle(this);
|
||||
}
|
||||
}
|
||||
|
||||
export const Stream = Socket;
|
||||
|
@ -1593,6 +2024,33 @@ export function connect(...args: unknown[]) {
|
|||
|
||||
export const createConnection = connect;
|
||||
|
||||
/** https://docs.deno.com/api/node/net/#namespace_getdefaultautoselectfamily */
|
||||
export function getDefaultAutoSelectFamily() {
|
||||
return autoSelectFamilyDefault;
|
||||
}
|
||||
|
||||
/** https://docs.deno.com/api/node/net/#namespace_setdefaultautoselectfamily */
|
||||
export function setDefaultAutoSelectFamily(value: boolean) {
|
||||
validateBoolean(value, "value");
|
||||
autoSelectFamilyDefault = value;
|
||||
}
|
||||
|
||||
/** https://docs.deno.com/api/node/net/#namespace_getdefaultautoselectfamilyattempttimeout */
|
||||
export function getDefaultAutoSelectFamilyAttemptTimeout() {
|
||||
return autoSelectFamilyAttemptTimeoutDefault;
|
||||
}
|
||||
|
||||
/** https://docs.deno.com/api/node/net/#namespace_setdefaultautoselectfamilyattempttimeout */
|
||||
export function setDefaultAutoSelectFamilyAttemptTimeout(value: number) {
|
||||
validateInt32(value, "value", 1);
|
||||
|
||||
if (value < 10) {
|
||||
value = 10;
|
||||
}
|
||||
|
||||
autoSelectFamilyAttemptTimeoutDefault = value;
|
||||
}
|
||||
|
||||
export interface ListenOptions extends Abortable {
|
||||
fd?: number;
|
||||
port?: number | undefined;
|
||||
|
@ -2478,15 +2936,19 @@ export { BlockList, isIP, isIPv4, isIPv6, SocketAddress };
|
|||
export default {
|
||||
_createServerHandle,
|
||||
_normalizeArgs,
|
||||
isIP,
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
BlockList,
|
||||
SocketAddress,
|
||||
connect,
|
||||
createConnection,
|
||||
createServer,
|
||||
getDefaultAutoSelectFamily,
|
||||
getDefaultAutoSelectFamilyAttemptTimeout,
|
||||
isIP,
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
Server,
|
||||
setDefaultAutoSelectFamily,
|
||||
setDefaultAutoSelectFamilyAttemptTimeout,
|
||||
Socket,
|
||||
SocketAddress,
|
||||
Stream,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_tls"
|
||||
version = "0.163.0"
|
||||
version = "0.164.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_url"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_web"
|
||||
version = "0.207.0"
|
||||
version = "0.208.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webgpu"
|
||||
version = "0.143.0"
|
||||
version = "0.144.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition.workspace = true
|
||||
license = "MIT"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webidl"
|
||||
version = "0.176.0"
|
||||
version = "0.177.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -28,6 +28,7 @@ const {
|
|||
ArrayPrototypePush,
|
||||
ArrayPrototypeShift,
|
||||
ArrayPrototypeSome,
|
||||
Error,
|
||||
ErrorPrototypeToString,
|
||||
ObjectDefineProperties,
|
||||
ObjectPrototypeIsPrototypeOf,
|
||||
|
@ -488,8 +489,11 @@ class WebSocket extends EventTarget {
|
|||
/* error */
|
||||
this[_readyState] = CLOSED;
|
||||
|
||||
const message = op_ws_get_error(rid);
|
||||
const error = new Error(message);
|
||||
const errorEv = new ErrorEvent("error", {
|
||||
message: op_ws_get_error(rid),
|
||||
error,
|
||||
message,
|
||||
});
|
||||
this.dispatchEvent(errorEv);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_websocket"
|
||||
version = "0.181.0"
|
||||
version = "0.182.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webstorage"
|
||||
version = "0.171.0"
|
||||
version = "0.172.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_resolver"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "node_resolver"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_runtime"
|
||||
version = "0.185.0"
|
||||
version = "0.186.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -623,7 +623,7 @@ fn get_ffi_call_error_class(e: &CallError) -> &'static str {
|
|||
fn get_webstorage_class_name(e: &WebStorageError) -> &'static str {
|
||||
match e {
|
||||
WebStorageError::ContextNotSupported => "DOMExceptionNotSupportedError",
|
||||
WebStorageError::Sqlite(_) => todo!(),
|
||||
WebStorageError::Sqlite(_) => "Error",
|
||||
WebStorageError::Io(e) => get_io_error_class(e),
|
||||
WebStorageError::StorageExceeded => "DOMExceptionQuotaExceededError",
|
||||
}
|
||||
|
|
|
@ -756,14 +756,17 @@ fn check_run_permission(
|
|||
if !env_var_names.is_empty() {
|
||||
// we don't allow users to launch subprocesses with any LD_ or DYLD_*
|
||||
// env vars set because this allows executing code (ex. LD_PRELOAD)
|
||||
return Err(CheckRunPermissionError::Other(deno_core::error::custom_error(
|
||||
return Err(CheckRunPermissionError::Other(
|
||||
deno_core::error::custom_error(
|
||||
"NotCapable",
|
||||
format!(
|
||||
"Requires --allow-all permissions to spawn subprocess with {} environment variable{}.",
|
||||
"Requires --allow-run permissions to spawn subprocess with {0} environment variable{1}. Alternatively, spawn with {2} environment variable{1} unset.",
|
||||
env_var_names.join(", "),
|
||||
if env_var_names.len() != 1 { "s" } else { "" }
|
||||
)
|
||||
)));
|
||||
if env_var_names.len() != 1 { "s" } else { "" },
|
||||
if env_var_names.len() != 1 { "these" } else { "the" }
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
permissions.check_run(cmd, api_name)?;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_permissions"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
@ -40,8 +40,8 @@ pub use prompter::PromptResponse;
|
|||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Requires {access}, {}", format_permission_error(.name))]
|
||||
pub struct PermissionDeniedError {
|
||||
access: String,
|
||||
name: &'static str,
|
||||
pub access: String,
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
fn format_permission_error(name: &'static str) -> String {
|
||||
|
@ -1461,7 +1461,7 @@ pub struct SysDescriptor(String);
|
|||
impl SysDescriptor {
|
||||
pub fn parse(kind: String) -> Result<Self, SysDescriptorParseError> {
|
||||
match kind.as_str() {
|
||||
"hostname" | "osRelease" | "osUptime" | "loadavg"
|
||||
"hostname" | "inspector" | "osRelease" | "osUptime" | "loadavg"
|
||||
| "networkInterfaces" | "systemMemoryInfo" | "uid" | "gid" | "cpus"
|
||||
| "homedir" | "getegid" | "statfs" | "getPriority" | "setPriority"
|
||||
| "userInfo" => Ok(Self(kind)),
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
"test-fs-rmdir-recursive.js",
|
||||
"test-fs-write-file.js",
|
||||
"test-http-url.parse-https.request.js",
|
||||
"test-net-autoselectfamily.js",
|
||||
"test-net-better-error-messages-path.js",
|
||||
"test-net-connect-buffer.js",
|
||||
"test-net-connect-buffer2.js",
|
||||
|
@ -404,6 +405,7 @@
|
|||
"test-http-url.parse-only-support-http-https-protocol.js",
|
||||
"test-icu-transcode.js",
|
||||
"test-net-access-byteswritten.js",
|
||||
"test-net-autoselectfamily.js",
|
||||
"test-net-better-error-messages-listen-path.js",
|
||||
"test-net-better-error-messages-path.js",
|
||||
"test-net-better-error-messages-port-hostname.js",
|
||||
|
|
|
@ -1767,7 +1767,6 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
|
|||
- [parallel/test-net-autoselectfamily-commandline-option.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-autoselectfamily-commandline-option.js)
|
||||
- [parallel/test-net-autoselectfamily-default.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-autoselectfamily-default.js)
|
||||
- [parallel/test-net-autoselectfamily-ipv4first.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-autoselectfamily-ipv4first.js)
|
||||
- [parallel/test-net-autoselectfamily.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-autoselectfamily.js)
|
||||
- [parallel/test-net-better-error-messages-listen.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-better-error-messages-listen.js)
|
||||
- [parallel/test-net-binary.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-binary.js)
|
||||
- [parallel/test-net-bind-twice.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-net-bind-twice.js)
|
||||
|
|
|
@ -19,6 +19,7 @@ import { magenta } from "@std/fmt/colors";
|
|||
import { pooledMap } from "@std/async/pool";
|
||||
import { dirname, fromFileUrl, join } from "@std/path";
|
||||
import { assertEquals, fail } from "@std/assert";
|
||||
import { distinct } from "@std/collections";
|
||||
import {
|
||||
config,
|
||||
getPathsFromTestSuites,
|
||||
|
@ -36,6 +37,9 @@ const testPaths = partitionParallelTestPaths(
|
|||
getPathsFromTestSuites(config.ignore),
|
||||
),
|
||||
);
|
||||
testPaths.sequential = distinct(testPaths.sequential);
|
||||
testPaths.parallel = distinct(testPaths.parallel);
|
||||
|
||||
const cwd = new URL(".", import.meta.url);
|
||||
const windowsIgnorePaths = new Set(
|
||||
getPathsFromTestSuites(config.windowsIgnore),
|
||||
|
|
|
@ -473,6 +473,7 @@ const pwdCommand = isWindows ?
|
|||
|
||||
module.exports = {
|
||||
allowGlobals,
|
||||
defaultAutoSelectFamilyAttemptTimeout: 2500,
|
||||
expectsError,
|
||||
expectWarning,
|
||||
getArrayBufferViews,
|
||||
|
|
312
tests/node_compat/test/parallel/test-net-autoselectfamily.js
Normal file
312
tests/node_compat/test/parallel/test-net-autoselectfamily.js
Normal file
|
@ -0,0 +1,312 @@
|
|||
// deno-fmt-ignore-file
|
||||
// deno-lint-ignore-file
|
||||
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
// Taken from Node 18.12.1
|
||||
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||||
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const { parseDNSPacket, writeDNSPacket } = require('../common/dns');
|
||||
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const { Resolver } = require('dns');
|
||||
const { createConnection, createServer } = require('net');
|
||||
|
||||
// Test that happy eyeballs algorithm is properly implemented.
|
||||
|
||||
// Purposely not using setDefaultAutoSelectFamilyAttemptTimeout here to test the
|
||||
// parameter is correctly used in options.
|
||||
//
|
||||
// Some of the machines in the CI need more time to establish connection
|
||||
const autoSelectFamilyAttemptTimeout = common.defaultAutoSelectFamilyAttemptTimeout;
|
||||
|
||||
function _lookup(resolver, hostname, options, cb) {
|
||||
resolver.resolve(hostname, 'ANY', (err, replies) => {
|
||||
assert.notStrictEqual(options.family, 4);
|
||||
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
const hosts = replies
|
||||
.map((r) => ({ address: r.address, family: r.type === 'AAAA' ? 6 : 4 }))
|
||||
.sort((a, b) => b.family - a.family);
|
||||
|
||||
if (options.all === true) {
|
||||
return cb(null, hosts);
|
||||
}
|
||||
|
||||
return cb(null, hosts[0].address, hosts[0].family);
|
||||
});
|
||||
}
|
||||
|
||||
function createDnsServer(ipv6Addrs, ipv4Addrs, cb) {
|
||||
if (!Array.isArray(ipv6Addrs)) {
|
||||
ipv6Addrs = [ipv6Addrs];
|
||||
}
|
||||
|
||||
if (!Array.isArray(ipv4Addrs)) {
|
||||
ipv4Addrs = [ipv4Addrs];
|
||||
}
|
||||
|
||||
// Create a DNS server which replies with a AAAA and a A record for the same host
|
||||
const socket = dgram.createSocket('udp4');
|
||||
|
||||
// TODO(kt3k): We use common.mustCallAtLeast instead of common.mustCall
|
||||
// because Deno sends multiple requests to the DNS server.
|
||||
// This can be addressed if Deno.resolveDns supports ANY record type.
|
||||
// See https://github.com/denoland/deno/issues/14492
|
||||
socket.on('message', common.mustCallAtLeast((msg, { address, port }) => {
|
||||
const parsed = parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
assert.strictEqual(domain, 'example.org');
|
||||
|
||||
socket.send(writeDNSPacket({
|
||||
id: parsed.id,
|
||||
questions: parsed.questions,
|
||||
answers: [
|
||||
...ipv6Addrs.map((address) => ({ type: 'AAAA', address, ttl: 123, domain: 'example.org' })),
|
||||
...ipv4Addrs.map((address) => ({ type: 'A', address, ttl: 123, domain: 'example.org' })),
|
||||
]
|
||||
}), port, address);
|
||||
}));
|
||||
|
||||
socket.bind(0, () => {
|
||||
const resolver = new Resolver();
|
||||
resolver.setServers([`127.0.0.1:${socket.address().port}`]);
|
||||
|
||||
cb({ dnsServer: socket, lookup: _lookup.bind(null, resolver) });
|
||||
});
|
||||
}
|
||||
|
||||
// Test that IPV4 is reached if IPV6 is not reachable
|
||||
{
|
||||
createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
|
||||
const ipv4Server = createServer((socket) => {
|
||||
socket.on('data', common.mustCall(() => {
|
||||
socket.write('response-ipv4');
|
||||
socket.end();
|
||||
}));
|
||||
});
|
||||
|
||||
ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
|
||||
const port = ipv4Server.address().port;
|
||||
|
||||
const connection = createConnection({
|
||||
host: 'example.org',
|
||||
port: port,
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
|
||||
let response = '';
|
||||
connection.setEncoding('utf-8');
|
||||
|
||||
connection.on('ready', common.mustCall(() => {
|
||||
assert.deepStrictEqual(connection.autoSelectFamilyAttemptedAddresses, [`::1:${port}`, `127.0.0.1:${port}`]);
|
||||
}));
|
||||
|
||||
connection.on('data', (chunk) => {
|
||||
response += chunk;
|
||||
});
|
||||
|
||||
connection.on('end', common.mustCall(() => {
|
||||
assert.strictEqual(response, 'response-ipv4');
|
||||
ipv4Server.close();
|
||||
dnsServer.close();
|
||||
}));
|
||||
|
||||
connection.write('request');
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Test that only the last successful connection is established.
|
||||
{
|
||||
createDnsServer(
|
||||
['2606:4700::6810:85e5', '2606:4700::6810:84e5', "::1"],
|
||||
// TODO(kt3k): Comment out ipv4 addresses to make the test pass faster.
|
||||
// Enable this when Deno.connect() call becomes cancellable.
|
||||
// See https://github.com/denoland/deno/issues/26819
|
||||
// ['104.20.22.46', '104.20.23.46', '127.0.0.1'],
|
||||
['127.0.0.1'],
|
||||
common.mustCall(function({ dnsServer, lookup }) {
|
||||
const ipv4Server = createServer((socket) => {
|
||||
socket.on('data', common.mustCall(() => {
|
||||
socket.write('response-ipv4');
|
||||
socket.end();
|
||||
}));
|
||||
});
|
||||
|
||||
ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
|
||||
const port = ipv4Server.address().port;
|
||||
|
||||
const connection = createConnection({
|
||||
host: 'example.org',
|
||||
port: port,
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
|
||||
let response = '';
|
||||
connection.setEncoding('utf-8');
|
||||
|
||||
connection.on('ready', common.mustCall(() => {
|
||||
assert.deepStrictEqual(
|
||||
connection.autoSelectFamilyAttemptedAddresses,
|
||||
[
|
||||
`2606:4700::6810:85e5:${port}`,
|
||||
`104.20.22.46:${port}`,
|
||||
`2606:4700::6810:84e5:${port}`,
|
||||
`104.20.23.46:${port}`,
|
||||
`::1:${port}`,
|
||||
`127.0.0.1:${port}`,
|
||||
]
|
||||
);
|
||||
}));
|
||||
|
||||
connection.on('data', (chunk) => {
|
||||
response += chunk;
|
||||
});
|
||||
|
||||
connection.on('end', common.mustCall(() => {
|
||||
assert.strictEqual(response, 'response-ipv4');
|
||||
ipv4Server.close();
|
||||
dnsServer.close();
|
||||
}));
|
||||
|
||||
connection.write('request');
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Test that IPV4 is NOT reached if IPV6 is reachable
|
||||
if (common.hasIPv6) {
|
||||
createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
|
||||
const ipv4Server = createServer((socket) => {
|
||||
socket.on('data', common.mustNotCall(() => {
|
||||
socket.write('response-ipv4');
|
||||
socket.end();
|
||||
}));
|
||||
});
|
||||
|
||||
const ipv6Server = createServer((socket) => {
|
||||
socket.on('data', common.mustCall(() => {
|
||||
socket.write('response-ipv6');
|
||||
socket.end();
|
||||
}));
|
||||
});
|
||||
|
||||
ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
|
||||
const port = ipv4Server.address().port;
|
||||
|
||||
ipv6Server.listen(port, '::1', common.mustCall(() => {
|
||||
const connection = createConnection({
|
||||
host: 'example.org',
|
||||
port,
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
|
||||
let response = '';
|
||||
connection.setEncoding('utf-8');
|
||||
|
||||
connection.on('ready', common.mustCall(() => {
|
||||
assert.deepStrictEqual(connection.autoSelectFamilyAttemptedAddresses, [`::1:${port}`]);
|
||||
}));
|
||||
|
||||
connection.on('data', (chunk) => {
|
||||
response += chunk;
|
||||
});
|
||||
|
||||
connection.on('end', common.mustCall(() => {
|
||||
assert.strictEqual(response, 'response-ipv6');
|
||||
ipv4Server.close();
|
||||
ipv6Server.close();
|
||||
dnsServer.close();
|
||||
}));
|
||||
|
||||
connection.write('request');
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Test that when all errors are returned when no connections succeeded
|
||||
{
|
||||
createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
|
||||
const connection = createConnection({
|
||||
host: 'example.org',
|
||||
port: 10,
|
||||
lookup,
|
||||
autoSelectFamily: true,
|
||||
autoSelectFamilyAttemptTimeout,
|
||||
});
|
||||
|
||||
connection.on('ready', common.mustNotCall());
|
||||
connection.on('error', common.mustCall((error) => {
|
||||
assert.deepStrictEqual(connection.autoSelectFamilyAttemptedAddresses, ['::1:10', '127.0.0.1:10']);
|
||||
assert.strictEqual(error.constructor.name, 'AggregateError');
|
||||
assert.strictEqual(error.errors.length, 2);
|
||||
|
||||
const errors = error.errors.map((e) => e.message);
|
||||
assert.ok(errors.includes('connect ECONNREFUSED 127.0.0.1:10'));
|
||||
|
||||
if (common.hasIPv6) {
|
||||
assert.ok(errors.includes('connect ECONNREFUSED ::1:10'));
|
||||
}
|
||||
|
||||
dnsServer.close();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Test that the option can be disabled
|
||||
{
|
||||
createDnsServer('::1', '127.0.0.1', common.mustCall(function({ dnsServer, lookup }) {
|
||||
const ipv4Server = createServer((socket) => {
|
||||
socket.on('data', common.mustCall(() => {
|
||||
socket.write('response-ipv4');
|
||||
socket.end();
|
||||
}));
|
||||
});
|
||||
|
||||
ipv4Server.listen(0, '127.0.0.1', common.mustCall(() => {
|
||||
const port = ipv4Server.address().port;
|
||||
|
||||
const connection = createConnection({
|
||||
host: 'example.org',
|
||||
port,
|
||||
lookup,
|
||||
autoSelectFamily: false,
|
||||
});
|
||||
|
||||
connection.on('ready', common.mustNotCall());
|
||||
connection.on('error', common.mustCall((error) => {
|
||||
assert.strictEqual(connection.autoSelectFamilyAttemptedAddresses, undefined);
|
||||
|
||||
if (common.hasIPv6) {
|
||||
assert.strictEqual(error.code, 'ECONNREFUSED');
|
||||
assert.strictEqual(error.message, `connect ECONNREFUSED ::1:${port}`);
|
||||
} else if (error.code === 'EAFNOSUPPORT') {
|
||||
assert.strictEqual(error.message, `connect EAFNOSUPPORT ::1:${port} - Local (undefined:undefined)`);
|
||||
} else if (error.code === 'EUNATCH') {
|
||||
assert.strictEqual(error.message, `connect EUNATCH ::1:${port} - Local (:::0)`);
|
||||
} else {
|
||||
assert.strictEqual(error.code, 'EADDRNOTAVAIL');
|
||||
assert.strictEqual(error.message, `connect EADDRNOTAVAIL ::1:${port} - Local (:::0)`);
|
||||
}
|
||||
|
||||
ipv4Server.close();
|
||||
dnsServer.close();
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import * as fs from "node:fs";
|
||||
|
||||
fs.writeFileSync("./testbin.js", "#!/usr/bin/env node\nconsole.log('run testbin');");
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "@denotest/bin-created-by-lifecycle",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"install": "node install.mjs"
|
||||
},
|
||||
"bin": {
|
||||
"testbin": "testbin.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"tempDir": true,
|
||||
"tests": {
|
||||
"all_at_once": {
|
||||
"steps": [
|
||||
{
|
||||
"args": "install --allow-scripts",
|
||||
"output": "all_at_once_install.out"
|
||||
},
|
||||
{ "args": "task run-testbin", "output": "run_testbin.out" }
|
||||
]
|
||||
},
|
||||
"separate_steps": {
|
||||
"steps": [
|
||||
{ "if": "unix", "args": "install", "output": "install_warn.out" },
|
||||
{
|
||||
"if": "windows",
|
||||
"args": "install",
|
||||
"output": "install_warn_windows.out"
|
||||
},
|
||||
{
|
||||
"args": "install --allow-scripts",
|
||||
"output": "Initialize @denotest/bin-created-by-lifecycle@1.0.0: running 'install' script\n"
|
||||
},
|
||||
{ "args": "task run-testbin", "output": "run_testbin.out" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Download http://localhost:4260/@denotest%2fbin-created-by-lifecycle
|
||||
Download http://localhost:4260/@denotest/bin-created-by-lifecycle/1.0.0.tgz
|
||||
Initialize @denotest/bin-created-by-lifecycle@1.0.0
|
||||
Initialize @denotest/bin-created-by-lifecycle@1.0.0: running 'install' script
|
|
@ -0,0 +1,10 @@
|
|||
Download http://localhost:4260/@denotest%2fbin-created-by-lifecycle
|
||||
Download http://localhost:4260/@denotest/bin-created-by-lifecycle/1.0.0.tgz
|
||||
Initialize @denotest/bin-created-by-lifecycle@1.0.0
|
||||
Warning Trying to set up 'testbin' bin for "[WILDCARD]bin-created-by-lifecycle", but the entry point "[WILDCARD]testbin.js" doesn't exist.
|
||||
Warning The following packages contained npm lifecycle scripts (preinstall/install/postinstall) that were not executed:
|
||||
┠─ npm:@denotest/bin-created-by-lifecycle@1.0.0
|
||||
┃
|
||||
┠─ This may cause the packages to not work correctly.
|
||||
┖─ To run lifecycle scripts, use the `--allow-scripts` flag with `deno install`:
|
||||
deno install --allow-scripts=npm:@denotest/bin-created-by-lifecycle@1.0.0
|
|
@ -0,0 +1,9 @@
|
|||
Download http://localhost:4260/@denotest%2fbin-created-by-lifecycle
|
||||
Download http://localhost:4260/@denotest/bin-created-by-lifecycle/1.0.0.tgz
|
||||
Initialize @denotest/bin-created-by-lifecycle@1.0.0
|
||||
Warning The following packages contained npm lifecycle scripts (preinstall/install/postinstall) that were not executed:
|
||||
┠─ npm:@denotest/bin-created-by-lifecycle@1.0.0
|
||||
┃
|
||||
┠─ This may cause the packages to not work correctly.
|
||||
┖─ To run lifecycle scripts, use the `--allow-scripts` flag with `deno install`:
|
||||
deno install --allow-scripts=npm:@denotest/bin-created-by-lifecycle@1.0.0
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@denotest/bin-created-by-lifecycle": "1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"run-testbin": "testbin"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
Task run-testbin testbin
|
||||
run testbin
|
|
@ -1,8 +1,8 @@
|
|||
NotCapable: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable.
|
||||
NotCapable: Requires --allow-run permissions to spawn subprocess with LD_PRELOAD environment variable. Alternatively, spawn with the environment variable unset.
|
||||
[WILDCARD]
|
||||
name: "NotCapable"
|
||||
}
|
||||
NotCapable: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable.
|
||||
NotCapable: Requires --allow-run permissions to spawn subprocess with LD_PRELOAD environment variable. Alternatively, spawn with the environment variable unset.
|
||||
[WILDCARD]
|
||||
name: "NotCapable"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
try {
|
||||
new Deno.Command("echo", {
|
||||
new Deno.Command("curl", {
|
||||
env: {
|
||||
"LD_PRELOAD": "./libpreload.so",
|
||||
},
|
||||
|
@ -10,7 +10,7 @@ try {
|
|||
|
||||
try {
|
||||
Deno.run({
|
||||
cmd: ["echo"],
|
||||
cmd: ["curl"],
|
||||
env: {
|
||||
"LD_PRELOAD": "./libpreload.so",
|
||||
},
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
NotCapable: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable.
|
||||
NotCapable: Requires --allow-run permissions to spawn subprocess with LD_PRELOAD environment variable. Alternatively, spawn with the environment variable unset.
|
||||
[WILDCARD]
|
||||
name: "NotCapable"
|
||||
}
|
||||
NotCapable: Requires --allow-all permissions to spawn subprocess with DYLD_FALLBACK_LIBRARY_PATH, LD_PRELOAD environment variables.
|
||||
NotCapable: Requires --allow-run permissions to spawn subprocess with DYLD_FALLBACK_LIBRARY_PATH, LD_PRELOAD environment variables. Alternatively, spawn with these environment variables unset.
|
||||
[WILDCARD]
|
||||
name: "NotCapable"
|
||||
}
|
||||
|
|
|
@ -453,7 +453,8 @@ Deno.test("invalid server", async () => {
|
|||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
const ws = new WebSocket("ws://localhost:2121");
|
||||
let err = false;
|
||||
ws.onerror = () => {
|
||||
ws.onerror = (e) => {
|
||||
assert("error" in e);
|
||||
err = true;
|
||||
};
|
||||
ws.onclose = () => {
|
||||
|
|
|
@ -10,6 +10,11 @@ import * as net from "node:net";
|
|||
import { assert, assertEquals } from "@std/assert";
|
||||
import { curlRequest } from "../unit/test_util.ts";
|
||||
|
||||
// Increase the timeout for the auto select family to avoid flakiness
|
||||
net.setDefaultAutoSelectFamilyAttemptTimeout(
|
||||
net.getDefaultAutoSelectFamilyAttemptTimeout() * 30,
|
||||
);
|
||||
|
||||
for (const url of ["http://localhost:4246", "https://localhost:4247"]) {
|
||||
Deno.test(`[node/http2 client] ${url}`, {
|
||||
ignore: Deno.build.os === "windows",
|
||||
|
|
Loading…
Reference in a new issue