diff --git a/Cargo.lock b/Cargo.lock index b86b8acd945759..463d2f92ef0833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,29 +435,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools 0.10.5", - "lazy_static", - "lazycell", - "log", - "prettyplease 0.2.17", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.72", - "which 4.4.2", -] - [[package]] name = "bindgen" version = "0.70.1" @@ -1418,9 +1395,7 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.318.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cae2393219ff9278123f7b24799cdfab37c7d6561b69ca06ced115cac92111" +version = "0.319.0" dependencies = [ "anyhow", "bincode", @@ -1429,6 +1404,7 @@ dependencies = [ "bytes", "cooked-waker", "deno_core_icudata", + "deno_js_error", "deno_ops", "deno_unsync", "futures", @@ -1443,6 +1419,7 @@ dependencies = [ "smallvec", "sourcemap 8.0.1", "static_assertions", + "thiserror", "tokio", "url", "v8", @@ -1450,9 +1427,9 @@ dependencies = [ [[package]] name = "deno_core_icudata" -version = "0.0.73" +version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_cron" @@ -1693,6 +1670,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "deno_js_error" +version = "0.1.0" +dependencies = [ + "proc-macro-rules", + "proc-macro2", + "quote", + "strum", + "strum_macros", + "syn 2.0.72", +] + [[package]] name = "deno_kv" version = "0.85.0" @@ -1921,9 +1910,7 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.194.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f760b492bd638c1dc3e992d11672c259fbe9a233162099a8347591c9e22d0391" +version = "0.195.0" dependencies = [ "proc-macro-rules", "proc-macro2", @@ -4192,12 +4179,6 @@ dependencies = [ "spin", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" @@ -4289,7 +4270,7 @@ version = "1.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8dfd1a173826d193e3b955e07c22765829890f62c677a59c4a410cb4f47c01" dependencies = [ - "bindgen 0.70.1", + "bindgen", "libloading 0.8.5", ] @@ -6238,9 +6219,7 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.227.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a8294c2223c53bed343be8b80564ece4dc0d03b643b06fa86c4ccc0e064eda0" +version = "0.228.0" dependencies = [ "num-bigint", "serde", @@ -7740,11 +7719,11 @@ dependencies = [ [[package]] name = "v8" -version = "0.106.0" +version = "130.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5" +checksum = "c23b5c2caff00209b03a716609b275acae94b02dd3b63c4648e7232a84a8402f" dependencies = [ - "bindgen 0.69.4", + "bindgen", "bitflags 2.6.0", "fslock", "gzip-header", @@ -8554,3 +8533,7 @@ dependencies = [ "cc", "pkg-config", ] + +[[patch.unused]] +name = "v8" +version = "0.89.0" diff --git a/Cargo.toml b/Cargo.toml index d83ca2e4138a5e..3e45864552bd07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ repository = "https://github.com/denoland/deno" [workspace.dependencies] deno_ast = { version = "=0.43.3", features = ["transpiling"] } -deno_core = { version = "0.318.0" } +deno_core = { version = "0.319.0" } deno_bench_util = { version = "0.171.0", path = "./bench_util" } deno_lockfile = "=0.23.1" @@ -326,3 +326,11 @@ opt-level = 3 opt-level = 3 [profile.release.package.zstd-sys] opt-level = 3 + +[patch.crates-io] +deno_core = { path = "../deno_core/core" } +deno_ops = { path = "../deno_core/ops" } +deno_js_error = { path = "../deno_core/js_error" } +serde_v8 = { path = "../deno_core/serde_v8" } +v8 = { path = "../rusty_v8" } + diff --git a/cli/build.rs b/cli/build.rs index 2678a8dbb027e0..b33660da5c05fa 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -9,8 +9,7 @@ mod shared; mod ts { use super::*; - use deno_core::error::custom_error; - use deno_core::error::AnyError; + use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::OpState; use serde::Serialize; @@ -51,7 +50,7 @@ mod ts { fn op_script_version( _state: &mut OpState, #[string] _arg: &str, - ) -> Result, AnyError> { + ) -> Result, JsNativeError> { Ok(Some("1".to_string())) } @@ -70,7 +69,7 @@ mod ts { fn op_load( state: &mut OpState, #[string] load_specifier: &str, - ) -> Result { + ) -> Result { let op_crate_libs = state.borrow::>(); let path_dts = state.borrow::(); let re_asset = lazy_regex::regex!(r"asset:/{3}lib\.(\S+)\.d\.ts"); @@ -91,12 +90,12 @@ mod ts { // if it comes from an op crate, we were supplied with the path to the // file. let path = if let Some(op_crate_lib) = op_crate_libs.get(lib) { - PathBuf::from(op_crate_lib).canonicalize()? + PathBuf::from(op_crate_lib).canonicalize().map_err(JsNativeError::from_err)? // otherwise we will generate the path ourself } else { path_dts.join(format!("lib.{lib}.d.ts")) }; - let data = std::fs::read_to_string(path)?; + let data = std::fs::read_to_string(path).map_err(JsNativeError::from_err)?; Ok(LoadResponse { data, version: "1".to_string(), @@ -104,13 +103,13 @@ mod ts { script_kind: 3, }) } else { - Err(custom_error( + Err(JsNativeError::new( "InvalidSpecifier", format!("An invalid specifier was requested: {}", load_specifier), )) } } else { - Err(custom_error( + Err(JsNativeError::new( "InvalidSpecifier", format!("An invalid specifier was requested: {}", load_specifier), )) diff --git a/cli/module_loader.rs b/cli/module_loader.rs index 43c9e1aa0750e0..f535b8e0abedc0 100644 --- a/cli/module_loader.rs +++ b/cli/module_loader.rs @@ -1065,11 +1065,11 @@ impl NodeRequireLoader &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a Path, - ) -> Result, AnyError> { + ) -> Result, deno_runtime::deno_permissions::PermissionCheckError> { if let Ok(url) = deno_path_util::url_from_file_path(path) { // allow reading if it's in the module graph if self.graph_container.graph().get(&url).is_some() { - return Ok(std::borrow::Cow::Borrowed(path)); + return Ok(Cow::Borrowed(path)); } } self.npm_resolver.ensure_read_permission(permissions, path) diff --git a/cli/npm/byonm.rs b/cli/npm/byonm.rs index 45fa4cfd1f528c..c01cd7e4e5dfb6 100644 --- a/cli/npm/byonm.rs +++ b/cli/npm/byonm.rs @@ -84,12 +84,12 @@ impl CliNpmResolver for CliByonmNpmResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, - ) -> Result, AnyError> { + ) -> Result, deno_runtime::deno_permissions::PermissionCheckError> { if !path .components() .any(|c| c.as_os_str().to_ascii_lowercase() == "node_modules") { - permissions.check_read_path(path).map_err(Into::into) + permissions.check_read_path(path) } else { Ok(Cow::Borrowed(path)) } diff --git a/cli/npm/mod.rs b/cli/npm/mod.rs index 0d434ca27fb540..da9618cc6a8fc9 100644 --- a/cli/npm/mod.rs +++ b/cli/npm/mod.rs @@ -131,7 +131,7 @@ pub trait CliNpmResolver: NpmResolver { &self, permissions: &mut dyn NodePermissions, path: &'a Path, - ) -> Result, AnyError>; + ) -> Result, deno_runtime::deno_permissions::PermissionCheckError>; /// Returns a hash returning the state of the npm resolver /// or `None` if the state currently can't be determined. diff --git a/cli/standalone/mod.rs b/cli/standalone/mod.rs index 85610f4c20f1f7..e98d1594a97d41 100644 --- a/cli/standalone/mod.rs +++ b/cli/standalone/mod.rs @@ -411,7 +411,7 @@ impl NodeRequireLoader for EmbeddedModuleLoader { &self, permissions: &mut dyn deno_runtime::deno_node::NodePermissions, path: &'a std::path::Path, - ) -> Result, AnyError> { + ) -> Result, deno_runtime::deno_permissions::PermissionCheckError> { if self.shared.modules.has_file(path) { // allow reading if the file is in the snapshot return Ok(Cow::Borrowed(path)); diff --git a/cli/tools/bench/mod.rs b/cli/tools/bench/mod.rs index 272d06335512a6..6ff1a7300c1451 100644 --- a/cli/tools/bench/mod.rs +++ b/cli/tools/bench/mod.rs @@ -16,9 +16,9 @@ use crate::util::path::matches_pattern_or_exact_path; use crate::worker::CliMainWorkerFactory; use deno_config::glob::WalkEntry; -use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::error::JsError; +use deno_core::error::JsNativeError::generic; use deno_core::futures::future; use deno_core::futures::stream; use deno_core::futures::StreamExt; diff --git a/ext/broadcast_channel/lib.rs b/ext/broadcast_channel/lib.rs index c1de118a364fad..ee71ece9fe440d 100644 --- a/ext/broadcast_channel/lib.rs +++ b/ext/broadcast_channel/lib.rs @@ -10,6 +10,7 @@ use std::path::PathBuf; use std::rc::Rc; use async_trait::async_trait; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::JsBuffer; use deno_core::OpState; @@ -20,18 +21,22 @@ use tokio::sync::mpsc::error::SendError as MpscSendError; pub const UNSTABLE_FEATURE_NAME: &str = "broadcast-channel"; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum BroadcastChannelError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(GENERIC)] #[error(transparent)] MPSCSendError(MpscSendError>), + #[class(GENERIC)] #[error(transparent)] BroadcastSendError( BroadcastSendError>, ), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } impl From> @@ -101,10 +106,7 @@ pub fn op_broadcast_unsubscribe( where BC: BroadcastChannel + 'static, { - let resource = state - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.resource_table.get::(rid)?; let bc = state.borrow::(); bc.unsubscribe(&resource) } @@ -119,11 +121,7 @@ pub async fn op_broadcast_send( where BC: BroadcastChannel + 'static, { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.send(&resource, name, buf.to_vec()).await } @@ -137,11 +135,7 @@ pub async fn op_broadcast_recv( where BC: BroadcastChannel + 'static, { - let resource = state - .borrow() - .resource_table - .get::(rid) - .map_err(BroadcastChannelError::Resource)?; + let resource = state.borrow().resource_table.get::(rid)?; let bc = state.borrow().borrow::().clone(); bc.recv(&resource).await } diff --git a/ext/cache/lib.rs b/ext/cache/lib.rs index 524d4cea0574ab..f109dad0c08d78 100644 --- a/ext/cache/lib.rs +++ b/ext/cache/lib.rs @@ -6,11 +6,11 @@ use std::rc::Rc; use std::sync::Arc; use async_trait::async_trait; -use deno_core::error::type_error; use deno_core::op2; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; use deno_core::ByteString; +use deno_core::error::JsNativeError; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; @@ -18,18 +18,26 @@ use deno_core::ResourceId; mod sqlite; pub use sqlite::SqliteBackedCache; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CacheError { + #[class(TYPE)] + #[error("CacheStorage is not available in this context")] + ContextUnsupported, + #[class(GENERIC)] #[error(transparent)] Sqlite(#[from] rusqlite::Error), + #[class(GENERIC)] #[error(transparent)] JoinError(#[from] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), } #[derive(Clone)] @@ -233,13 +241,11 @@ where if let Some(cache) = state.try_borrow::() { Ok(cache.clone()) } else if let Some(create_cache) = state.try_borrow::>() { - let cache = create_cache.0()?; + let cache = create_cache.0(); state.put(cache); Ok(state.borrow::().clone()) } else { - Err(CacheError::Other(type_error( - "CacheStorage is not available in this context", - ))) + Err(CacheError::ContextUnsupported) } } diff --git a/ext/cache/sqlite.rs b/ext/cache/sqlite.rs index 6efceda11eaf42..2c7287ba692278 100644 --- a/ext/cache/sqlite.rs +++ b/ext/cache/sqlite.rs @@ -8,7 +8,6 @@ use std::time::SystemTime; use std::time::UNIX_EPOCH; use async_trait::async_trait; -use deno_core::error::AnyError; use deno_core::futures::future::poll_fn; use deno_core::parking_lot::Mutex; use deno_core::unsync::spawn_blocking; @@ -378,7 +377,10 @@ impl CacheResponseResource { } } - async fn read(self: Rc, data: &mut [u8]) -> Result { + async fn read( + self: Rc, + data: &mut [u8], + ) -> Result { let resource = deno_core::RcRef::map(&self, |r| &r.file); let mut file = resource.borrow_mut().await; let nread = file.read(data).await?; diff --git a/ext/canvas/lib.rs b/ext/canvas/lib.rs index defb288ac9d2dd..b84799cea35773 100644 --- a/ext/canvas/lib.rs +++ b/ext/canvas/lib.rs @@ -11,10 +11,12 @@ use serde::Deserialize; use serde::Serialize; use std::path::PathBuf; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CanvasError { + #[class(TYPE)] #[error("Color type '{0:?}' not supported")] UnsupportedColorType(ColorType), + #[class(GENERIC)] #[error(transparent)] Image(#[from] image::ImageError), } diff --git a/ext/cron/lib.rs b/ext/cron/lib.rs index feffb5e5112114..1f2c450b626ae2 100644 --- a/ext/cron/lib.rs +++ b/ext/cron/lib.rs @@ -6,9 +6,8 @@ pub mod local; use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; - +use deno_core::error::{JsErrorClass, JsNativeError}; pub use crate::interface::*; -use deno_core::error::get_custom_error_class; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -46,26 +45,35 @@ impl Resource for CronResource { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CronError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(TYPE)] #[error("Cron name cannot exceed 64 characters: current length {0}")] NameExceeded(usize), + #[class(TYPE)] #[error("Invalid cron name: only alphanumeric characters, whitespace, hyphens, and underscores are allowed")] NameInvalid, + #[class(TYPE)] #[error("Cron with this name already exists")] AlreadyExists, + #[class(TYPE)] #[error("Too many crons")] TooManyCrons, + #[class(TYPE)] #[error("Invalid cron schedule")] InvalidCron, + #[class(TYPE)] #[error("Invalid backoff schedule")] InvalidBackoff, + #[class(GENERIC)] #[error(transparent)] AcquireError(#[from] tokio::sync::AcquireError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } #[op2] @@ -118,7 +126,7 @@ where let resource = match state.resource_table.get::>(rid) { Ok(resource) => resource, Err(err) => { - if get_custom_error_class(&err) == Some("BadResource") { + if err.get_class() == "BadResource" { return Ok(false); } else { return Err(CronError::Resource(err)); diff --git a/ext/crypto/decrypt.rs b/ext/crypto/decrypt.rs index 1140475183e1cd..3aadb8cf604049 100644 --- a/ext/crypto/decrypt.rs +++ b/ext/crypto/decrypt.rs @@ -70,26 +70,36 @@ pub enum DecryptAlgorithm { }, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum DecryptError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), + #[class(GENERIC)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class("DOMExceptionOperationError")] #[error("Decryption failed")] Failed, + #[class(TYPE)] #[error("invalid length")] InvalidLength, + #[class(TYPE)] #[error("invalid counter length. Currently supported 32/64/128 bits")] InvalidCounterLength, + #[class(TYPE)] #[error("tag length not equal to 128")] InvalidTagLength, + #[class("DOMExceptionOperationError")] #[error("invalid key or iv")] InvalidKeyOrIv, + #[class("DOMExceptionOperationError")] #[error("tried to decrypt too much data")] TooMuchData, + #[class(TYPE)] #[error("iv length not equal to 12 or 16")] InvalidIvLength, + #[class("DOMExceptionOperationError")] #[error("{0}")] Rsa(rsa::Error), } diff --git a/ext/crypto/ed25519.rs b/ext/crypto/ed25519.rs index da34b7d25dbf05..8a58e8f85ce6fe 100644 --- a/ext/crypto/ed25519.rs +++ b/ext/crypto/ed25519.rs @@ -13,12 +13,15 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum Ed25519Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(GENERIC)] #[error(transparent)] Der(#[from] rsa::pkcs1::der::Error), + #[class(GENERIC)] #[error(transparent)] KeyRejected(#[from] ring::error::KeyRejected), } diff --git a/ext/crypto/encrypt.rs b/ext/crypto/encrypt.rs index 66b27657f8f055..fa56fbafd0b28a 100644 --- a/ext/crypto/encrypt.rs +++ b/ext/crypto/encrypt.rs @@ -71,20 +71,27 @@ pub enum EncryptAlgorithm { }, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum EncryptError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), + #[class(TYPE)] #[error("invalid length")] InvalidLength, + #[class("DOMExceptionOperationError")] #[error("invalid key or iv")] InvalidKeyOrIv, + #[class(TYPE)] #[error("iv length not equal to 12 or 16")] InvalidIvLength, + #[class(TYPE)] #[error("invalid counter length. Currently supported 32/64/128 bits")] InvalidCounterLength, + #[class("DOMExceptionOperationError")] #[error("tried to encrypt too much data")] TooMuchData, + #[class("DOMExceptionOperationError")] #[error("Encryption failed")] Failed, } diff --git a/ext/crypto/export_key.rs b/ext/crypto/export_key.rs index edf0d7239c70bb..4389bef9ca71ae 100644 --- a/ext/crypto/export_key.rs +++ b/ext/crypto/export_key.rs @@ -20,12 +20,15 @@ use spki::AlgorithmIdentifierOwned; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ExportKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), + #[class(GENERIC)] #[error(transparent)] Der(#[from] spki::der::Error), + #[class("DOMExceptionNotSupportedError")] #[error("Unsupported named curve")] UnsupportedNamedCurve, } diff --git a/ext/crypto/generate_key.rs b/ext/crypto/generate_key.rs index 3c0bd77c22641c..7c0682c855ac77 100644 --- a/ext/crypto/generate_key.rs +++ b/ext/crypto/generate_key.rs @@ -15,10 +15,12 @@ use serde::Deserialize; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class("DOMExceptionOperationError")] pub enum GenerateKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), #[error("Bad public exponent")] BadPublicExponent, #[error("Invalid HMAC key length")] diff --git a/ext/crypto/import_key.rs b/ext/crypto/import_key.rs index 3463ca2beb34e9..e9aa6baaf130db 100644 --- a/ext/crypto/import_key.rs +++ b/ext/crypto/import_key.rs @@ -14,10 +14,12 @@ use spki::der::Decode; use crate::shared::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class("DOMExceptionDataError")] pub enum ImportKeyError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), #[error("invalid modulus")] InvalidModulus, #[error("invalid public exponent")] diff --git a/ext/crypto/lib.rs b/ext/crypto/lib.rs index 69dcd1413a0641..42b2b54de87725 100644 --- a/ext/crypto/lib.rs +++ b/ext/crypto/lib.rs @@ -6,7 +6,7 @@ use aes_kw::KekAes256; use base64::prelude::BASE64_URL_SAFE_NO_PAD; use base64::Engine; -use deno_core::error::not_supported; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::ToJsBuffer; @@ -132,63 +132,87 @@ deno_core::extension!(deno_crypto, }, ); -#[derive(Debug, thiserror::Error)] -pub enum Error { +#[derive(Debug, thiserror::Error, deno_core::JsError)] +pub enum CryptoError { + #[class(inherit)] #[error(transparent)] - General(#[from] SharedError), + General(#[from] #[inherit] SharedError), + #[class(inherit)] #[error(transparent)] - JoinError(#[from] tokio::task::JoinError), + JoinError(#[from] #[inherit] tokio::task::JoinError), + #[class(GENERIC)] #[error(transparent)] Der(#[from] rsa::pkcs1::der::Error), + #[class(TYPE)] #[error("Missing argument hash")] MissingArgumentHash, + #[class(TYPE)] #[error("Missing argument saltLength")] MissingArgumentSaltLength, + #[class(TYPE)] #[error("unsupported algorithm")] UnsupportedAlgorithm, + #[class(GENERIC)] #[error(transparent)] KeyRejected(#[from] ring::error::KeyRejected), + #[class(GENERIC)] #[error(transparent)] RSA(#[from] rsa::Error), + #[class(GENERIC)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class(GENERIC)] #[error(transparent)] Unspecified(#[from] ring::error::Unspecified), + #[class(TYPE)] #[error("Invalid key format")] InvalidKeyFormat, + #[class(GENERIC)] #[error(transparent)] P256Ecdsa(#[from] p256::ecdsa::Error), + #[class(TYPE)] #[error("Unexpected error decoding private key")] DecodePrivateKey, + #[class(TYPE)] #[error("Missing argument publicKey")] MissingArgumentPublicKey, + #[class(TYPE)] #[error("Missing argument namedCurve")] MissingArgumentNamedCurve, + #[class(TYPE)] #[error("Missing argument info")] MissingArgumentInfo, + #[class("DOMExceptionOperationError")] #[error("The length provided for HKDF is too large")] HKDFLengthTooLarge, + #[class(GENERIC)] #[error(transparent)] Base64Decode(#[from] base64::DecodeError), + #[class(TYPE)] #[error("Data must be multiple of 8 bytes")] DataInvalidSize, + #[class(TYPE)] #[error("Invalid key length")] InvalidKeyLength, + #[class("DOMExceptionOperationError")] #[error("encryption error")] EncryptionError, + #[class("DOMExceptionOperationError")] #[error("decryption error - integrity check failed")] DecryptionError, + #[class("DOMExceptionQuotaExceededError")] #[error("The ArrayBufferView's byte length ({0}) exceeds the number of bytes of entropy available via this API (65536)")] ArrayBufferViewLengthExceeded(usize), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] #[inherit] JsNativeError), } #[op2] #[serde] pub fn op_crypto_base64url_decode( #[string] data: String, -) -> Result { +) -> Result { let data: Vec = BASE64_URL_SAFE_NO_PAD.decode(data)?; Ok(data.into()) } @@ -204,9 +228,9 @@ pub fn op_crypto_base64url_encode(#[buffer] data: JsBuffer) -> String { pub fn op_crypto_get_random_values( state: &mut OpState, #[buffer] out: &mut [u8], -) -> Result<(), Error> { +) -> Result<(), CryptoError> { if out.len() > 65536 { - return Err(Error::ArrayBufferViewLengthExceeded(out.len())); + return Err(CryptoError::ArrayBufferViewLengthExceeded(out.len())); } let maybe_seeded_rng = state.try_borrow_mut::(); @@ -258,7 +282,7 @@ pub struct SignArg { pub async fn op_crypto_sign_key( #[serde] args: SignArg, #[buffer] zero_copy: JsBuffer, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let data = &*zero_copy; let algorithm = args.algorithm; @@ -267,7 +291,7 @@ pub async fn op_crypto_sign_key( Algorithm::RsassaPkcs1v15 => { use rsa::pkcs1v15::SigningKey; let private_key = RsaPrivateKey::from_pkcs1_der(&args.key.data)?; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let signing_key = SigningKey::::new(private_key); signing_key.sign(data) @@ -292,11 +316,11 @@ pub async fn op_crypto_sign_key( let salt_len = args .salt_length - .ok_or_else(|| Error::MissingArgumentSaltLength)? + .ok_or_else(|| CryptoError::MissingArgumentSaltLength)? as usize; let mut rng = OsRng; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let signing_key = Pss::new_with_salt::(salt_len); let hashed = Sha1::digest(data); @@ -323,7 +347,7 @@ pub async fn op_crypto_sign_key( Algorithm::Ecdsa => { let curve: &EcdsaSigningAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(|| JsNativeError::not_supported())? .into(); let rng = RingRand::SystemRandom::new(); @@ -333,7 +357,7 @@ pub async fn op_crypto_sign_key( if let Some(hash) = args.hash { match hash { CryptoHash::Sha256 | CryptoHash::Sha384 => (), - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), } }; @@ -345,7 +369,7 @@ pub async fn op_crypto_sign_key( Algorithm::Hmac => { let hash: HmacAlgorithm = args .hash - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(|| JsNativeError::not_supported())? .into(); let key = HmacKey::new(hash, &args.key.data); @@ -353,7 +377,7 @@ pub async fn op_crypto_sign_key( let signature = ring::hmac::sign(&key, data); signature.as_ref().to_vec() } - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), }; Ok(signature.into()) @@ -376,7 +400,7 @@ pub struct VerifyArg { pub async fn op_crypto_verify_key( #[serde] args: VerifyArg, #[buffer] zero_copy: JsBuffer, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let data = &*zero_copy; let algorithm = args.algorithm; @@ -387,7 +411,7 @@ pub async fn op_crypto_verify_key( use rsa::pkcs1v15::VerifyingKey; let public_key = read_rsa_public_key(args.key)?; let signature: Signature = args.signature.as_ref().try_into()?; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let verifying_key = VerifyingKey::::new(public_key); verifying_key.verify(data, &signature).is_ok() @@ -412,10 +436,10 @@ pub async fn op_crypto_verify_key( let salt_len = args .salt_length - .ok_or_else(|| Error::MissingArgumentSaltLength)? + .ok_or_else(|| CryptoError::MissingArgumentSaltLength)? as usize; - match args.hash.ok_or_else(|| Error::MissingArgumentHash)? { + match args.hash.ok_or_else(|| CryptoError::MissingArgumentHash)? { CryptoHash::Sha1 => { let pss = Pss::new_with_salt::(salt_len); let hashed = Sha1::digest(data); @@ -441,7 +465,7 @@ pub async fn op_crypto_verify_key( Algorithm::Hmac => { let hash: HmacAlgorithm = args .hash - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(|| JsNativeError::not_supported())? .into(); let key = HmacKey::new(hash, &args.key.data); ring::hmac::verify(&key, data, &args.signature).is_ok() @@ -449,11 +473,11 @@ pub async fn op_crypto_verify_key( Algorithm::Ecdsa => { let signing_alg: &EcdsaSigningAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(|| JsNativeError::not_supported())? .into(); let verify_alg: &EcdsaVerificationAlgorithm = args .named_curve - .ok_or_else(|| Error::Other(not_supported()))? + .ok_or_else(|| JsNativeError::not_supported())? .into(); let private_key; @@ -467,7 +491,7 @@ pub async fn op_crypto_verify_key( private_key.public_key().as_ref() } KeyType::Public => &*args.key.data, - _ => return Err(Error::InvalidKeyFormat), + _ => return Err(CryptoError::InvalidKeyFormat), }; let public_key = @@ -475,7 +499,7 @@ pub async fn op_crypto_verify_key( public_key.verify(data, &args.signature).is_ok() } - _ => return Err(Error::UnsupportedAlgorithm), + _ => return Err(CryptoError::UnsupportedAlgorithm), }; Ok(verification) @@ -503,20 +527,20 @@ pub struct DeriveKeyArg { pub async fn op_crypto_derive_bits( #[serde] args: DeriveKeyArg, #[buffer] zero_copy: Option, -) -> Result { +) -> Result { deno_core::unsync::spawn_blocking(move || { let algorithm = args.algorithm; match algorithm { Algorithm::Pbkdf2 => { let zero_copy = - zero_copy.ok_or_else(|| Error::Other(not_supported()))?; + zero_copy.ok_or_else(|| JsNativeError::not_supported())?; let salt = &*zero_copy; // The caller must validate these cases. assert!(args.length > 0); assert!(args.length % 8 == 0); let algorithm = - match args.hash.ok_or_else(|| Error::Other(not_supported()))? { + match args.hash.ok_or_else(|| JsNativeError::not_supported())? { CryptoHash::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1, CryptoHash::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256, CryptoHash::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384, @@ -527,7 +551,7 @@ pub async fn op_crypto_derive_bits( let iterations = NonZeroU32::new( args .iterations - .ok_or_else(|| Error::Other(not_supported()))?, + .ok_or_else(|| JsNativeError::not_supported())?, ) .unwrap(); let secret = args.key.data; @@ -538,33 +562,33 @@ pub async fn op_crypto_derive_bits( Algorithm::Ecdh => { let named_curve = args .named_curve - .ok_or_else(|| Error::MissingArgumentNamedCurve)?; + .ok_or_else(|| CryptoError::MissingArgumentNamedCurve)?; let public_key = args .public_key - .ok_or_else(|| Error::MissingArgumentPublicKey)?; + .ok_or_else(|| CryptoError::MissingArgumentPublicKey)?; match named_curve { CryptoNamedCurve::P256 => { let secret_key = p256::SecretKey::from_pkcs8_der(&args.key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let public_key = match public_key.r#type { KeyType::Private => { p256::SecretKey::from_pkcs8_der(&public_key.data) - .map_err(|_| Error::DecodePrivateKey)? + .map_err(|_| CryptoError::DecodePrivateKey)? .public_key() } KeyType::Public => { let point = p256::EncodedPoint::from_bytes(public_key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let pk = p256::PublicKey::from_encoded_point(&point); // pk is a constant time Option. if pk.is_some().into() { pk.unwrap() } else { - return Err(Error::DecodePrivateKey); + return Err(CryptoError::DecodePrivateKey); } } _ => unreachable!(), @@ -580,24 +604,24 @@ pub async fn op_crypto_derive_bits( } CryptoNamedCurve::P384 => { let secret_key = p384::SecretKey::from_pkcs8_der(&args.key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let public_key = match public_key.r#type { KeyType::Private => { p384::SecretKey::from_pkcs8_der(&public_key.data) - .map_err(|_| Error::DecodePrivateKey)? + .map_err(|_| CryptoError::DecodePrivateKey)? .public_key() } KeyType::Public => { let point = p384::EncodedPoint::from_bytes(public_key.data) - .map_err(|_| Error::DecodePrivateKey)?; + .map_err(|_| CryptoError::DecodePrivateKey)?; let pk = p384::PublicKey::from_encoded_point(&point); // pk is a constant time Option. if pk.is_some().into() { pk.unwrap() } else { - return Err(Error::DecodePrivateKey); + return Err(CryptoError::DecodePrivateKey); } } _ => unreachable!(), @@ -615,17 +639,17 @@ pub async fn op_crypto_derive_bits( } Algorithm::Hkdf => { let zero_copy = - zero_copy.ok_or_else(|| Error::Other(not_supported()))?; + zero_copy.ok_or_else(|| JsNativeError::not_supported())?; let salt = &*zero_copy; let algorithm = - match args.hash.ok_or_else(|| Error::Other(not_supported()))? { + match args.hash.ok_or_else(|| JsNativeError::not_supported())? { CryptoHash::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY, CryptoHash::Sha256 => hkdf::HKDF_SHA256, CryptoHash::Sha384 => hkdf::HKDF_SHA384, CryptoHash::Sha512 => hkdf::HKDF_SHA512, }; - let info = args.info.ok_or_else(|| Error::MissingArgumentInfo)?; + let info = args.info.ok_or_else(|| CryptoError::MissingArgumentInfo)?; // IKM let secret = args.key.data; // L @@ -636,18 +660,18 @@ pub async fn op_crypto_derive_bits( let info = &[&*info]; let okm = prk .expand(info, HkdfOutput(length)) - .map_err(|_e| Error::HKDFLengthTooLarge)?; + .map_err(|_e| CryptoError::HKDFLengthTooLarge)?; let mut r = vec![0u8; length]; okm.fill(&mut r)?; Ok(r.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } }) .await? } -fn read_rsa_public_key(key_data: KeyData) -> Result { +fn read_rsa_public_key(key_data: KeyData) -> Result { let public_key = match key_data.r#type { KeyType::Private => { RsaPrivateKey::from_pkcs1_der(&key_data.data)?.to_public_key() @@ -660,7 +684,9 @@ fn read_rsa_public_key(key_data: KeyData) -> Result { #[op2] #[string] -pub fn op_crypto_random_uuid(state: &mut OpState) -> Result { +pub fn op_crypto_random_uuid( + state: &mut OpState, +) -> Result { let maybe_seeded_rng = state.try_borrow_mut::(); let uuid = if let Some(seeded_rng) = maybe_seeded_rng { let mut bytes = [0u8; 16]; @@ -681,7 +707,7 @@ pub fn op_crypto_random_uuid(state: &mut OpState) -> Result { pub async fn op_crypto_subtle_digest( #[serde] algorithm: CryptoHash, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let output = spawn_blocking(move || { digest::digest(algorithm.into(), &data) .as_ref() @@ -705,7 +731,7 @@ pub struct WrapUnwrapKeyArg { pub fn op_crypto_wrap_key( #[serde] args: WrapUnwrapKeyArg, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let algorithm = args.algorithm; match algorithm { @@ -713,20 +739,20 @@ pub fn op_crypto_wrap_key( let key = args.key.as_secret_key()?; if data.len() % 8 != 0 { - return Err(Error::DataInvalidSize); + return Err(CryptoError::DataInvalidSize); } let wrapped_key = match key.len() { 16 => KekAes128::new(key.into()).wrap_vec(&data), 24 => KekAes192::new(key.into()).wrap_vec(&data), 32 => KekAes256::new(key.into()).wrap_vec(&data), - _ => return Err(Error::InvalidKeyLength), + _ => return Err(CryptoError::InvalidKeyLength), } - .map_err(|_| Error::EncryptionError)?; + .map_err(|_| CryptoError::EncryptionError)?; Ok(wrapped_key.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } } @@ -735,27 +761,27 @@ pub fn op_crypto_wrap_key( pub fn op_crypto_unwrap_key( #[serde] args: WrapUnwrapKeyArg, #[buffer] data: JsBuffer, -) -> Result { +) -> Result { let algorithm = args.algorithm; match algorithm { Algorithm::AesKw => { let key = args.key.as_secret_key()?; if data.len() % 8 != 0 { - return Err(Error::DataInvalidSize); + return Err(CryptoError::DataInvalidSize); } let unwrapped_key = match key.len() { 16 => KekAes128::new(key.into()).unwrap_vec(&data), 24 => KekAes192::new(key.into()).unwrap_vec(&data), 32 => KekAes256::new(key.into()).unwrap_vec(&data), - _ => return Err(Error::InvalidKeyLength), + _ => return Err(CryptoError::InvalidKeyLength), } - .map_err(|_| Error::DecryptionError)?; + .map_err(|_| CryptoError::DecryptionError)?; Ok(unwrapped_key.into()) } - _ => Err(Error::UnsupportedAlgorithm), + _ => Err(CryptoError::UnsupportedAlgorithm), } } diff --git a/ext/crypto/shared.rs b/ext/crypto/shared.rs index f70d32856ccb40..61b400f5982819 100644 --- a/ext/crypto/shared.rs +++ b/ext/crypto/shared.rs @@ -60,26 +60,36 @@ pub enum RustRawKeyData { Public(ToJsBuffer), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum SharedError { + #[class(TYPE)] #[error("expected valid private key")] ExpectedValidPrivateKey, + #[class(TYPE)] #[error("expected valid public key")] ExpectedValidPublicKey, + #[class(TYPE)] #[error("expected valid private EC key")] ExpectedValidPrivateECKey, + #[class(TYPE)] #[error("expected valid public EC key")] ExpectedValidPublicECKey, + #[class(TYPE)] #[error("expected private key")] ExpectedPrivateKey, + #[class(TYPE)] #[error("expected public key")] ExpectedPublicKey, + #[class(TYPE)] #[error("expected secret key")] ExpectedSecretKey, + #[class("DOMExceptionOperationError")] #[error("failed to decode private key")] FailedDecodePrivateKey, + #[class("DOMExceptionOperationError")] #[error("failed to decode public key")] FailedDecodePublicKey, + #[class("DOMExceptionNotSupportedError")] #[error("unsupported format")] UnsupportedFormat, } diff --git a/ext/crypto/x25519.rs b/ext/crypto/x25519.rs index d2c4d986b98dec..3c8f4249f4e5b4 100644 --- a/ext/crypto/x25519.rs +++ b/ext/crypto/x25519.rs @@ -11,10 +11,12 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum X25519Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(GENERIC)] #[error(transparent)] Der(#[from] spki::der::Error), } diff --git a/ext/crypto/x448.rs b/ext/crypto/x448.rs index 89bf48e28bd1c0..764ad8acec1c29 100644 --- a/ext/crypto/x448.rs +++ b/ext/crypto/x448.rs @@ -12,10 +12,12 @@ use spki::der::asn1::BitString; use spki::der::Decode; use spki::der::Encode; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum X448Error { + #[class("DOMExceptionOperationError")] #[error("Failed to export key")] FailedExport, + #[class(GENERIC)] #[error(transparent)] Der(#[from] spki::der::Error), } diff --git a/ext/fetch/fs_fetch_handler.rs b/ext/fetch/fs_fetch_handler.rs index c236dd9c67127d..322e08d9dffd74 100644 --- a/ext/fetch/fs_fetch_handler.rs +++ b/ext/fetch/fs_fetch_handler.rs @@ -4,6 +4,7 @@ use crate::CancelHandle; use crate::CancelableResponseFuture; use crate::FetchHandler; +use deno_core::error::JsNativeError; use deno_core::futures::FutureExt; use deno_core::futures::TryFutureExt; use deno_core::futures::TryStreamExt; @@ -33,7 +34,7 @@ impl FetchHandler for FsFetchHandler { let file = tokio::fs::File::open(path).map_err(|_| ()).await?; let stream = ReaderStream::new(file) .map_ok(hyper::body::Frame::data) - .map_err(Into::into); + .map_err(JsNativeError::from_err); let body = http_body_util::StreamBody::new(stream).boxed(); let response = http::Response::builder() .status(StatusCode::OK) diff --git a/ext/fetch/lib.rs b/ext/fetch/lib.rs index 7ef26431c2b091..0577c6347df5f3 100644 --- a/ext/fetch/lib.rs +++ b/ext/fetch/lib.rs @@ -28,6 +28,7 @@ use deno_core::url; use deno_core::url::Url; use deno_core::AsyncRefCell; use deno_core::AsyncResult; +use deno_core::error::JsNativeError; use deno_core::BufView; use deno_core::ByteString; use deno_core::CancelFuture; @@ -86,7 +87,7 @@ pub struct Options { pub proxy: Option, #[allow(clippy::type_complexity)] pub request_builder_hook: Option< - fn(&mut http::Request) -> Result<(), deno_core::error::AnyError>, + fn(&mut http::Request) -> Result<(), JsNativeError>, >, pub unsafely_ignore_certificate_errors: Option>, pub client_cert_chain_and_key: TlsKeys, @@ -96,7 +97,7 @@ pub struct Options { impl Options { pub fn root_cert_store( &self, - ) -> Result, deno_core::error::AnyError> { + ) -> Result, JsNativeError> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -145,47 +146,67 @@ deno_core::extension!(deno_fetch, }, ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum FetchError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] PermissionCheckError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(TYPE)] #[error("NetworkError when attempting to fetch resource")] NetworkError, + #[class(TYPE)] #[error("Fetching files only supports the GET method: received {0}")] FsNotGet(Method), + #[class(TYPE)] #[error("Invalid URL {0}")] InvalidUrl(Url), + #[class(TYPE)] #[error(transparent)] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + #[class(TYPE)] #[error(transparent)] InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), + #[class(TYPE)] #[error("{0:?}")] DataUrl(data_url::DataUrlError), + #[class(TYPE)] #[error("{0:?}")] Base64(data_url::forgiving_base64::InvalidBase64), + #[class(TYPE)] #[error("Blob for the given URL not found.")] BlobNotFound, + #[class(TYPE)] #[error("Url scheme '{0}' not supported")] SchemeNotSupported(String), + #[class(TYPE)] #[error("Request was cancelled")] RequestCanceled, + #[class(GENERIC)] #[error(transparent)] Http(#[from] http::Error), + #[class(inherit)] #[error(transparent)] - ClientCreate(#[from] HttpClientCreateError), + ClientCreate(#[from] #[inherit] HttpClientCreateError), + #[class(inherit)] #[error(transparent)] - Url(#[from] url::ParseError), + Url(#[from] #[inherit] url::ParseError), + #[class(TYPE)] #[error(transparent)] Method(#[from] http::method::InvalidMethod), + #[class(TYPE)] #[error(transparent)] ClientSend(#[from] ClientSendError), + #[class(inherit)] #[error(transparent)] - RequestBuilderHook(deno_core::error::AnyError), + RequestBuilderHook(#[inherit] JsNativeError), + #[class(inherit)] #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), // Only used for node upgrade + #[class("Http")] #[error(transparent)] Hyper(#[from] hyper::Error), } @@ -274,9 +295,7 @@ pub fn create_client_from_options( #[allow(clippy::type_complexity)] pub struct ResourceToBodyAdapter( Rc, - Option< - Pin>>>, - >, + Option>>>>, ); impl ResourceToBodyAdapter { @@ -292,7 +311,7 @@ unsafe impl Send for ResourceToBodyAdapter {} unsafe impl Sync for ResourceToBodyAdapter {} impl Stream for ResourceToBodyAdapter { - type Item = Result; + type Item = Result; fn poll_next( self: Pin<&mut Self>, @@ -322,7 +341,7 @@ impl Stream for ResourceToBodyAdapter { impl hyper::body::Body for ResourceToBodyAdapter { type Data = Bytes; - type Error = deno_core::error::AnyError; + type Error = JsNativeError; fn poll_frame( self: Pin<&mut Self>, @@ -397,10 +416,7 @@ where FP: FetchPermissions + 'static, { let (client, allow_host) = if let Some(rid) = client_rid { - let r = state - .resource_table - .get::(rid) - .map_err(FetchError::Resource)?; + let r = state.resource_table.get::(rid)?; (r.client.clone(), r.allow_host) } else { (get_or_create_client_from_state(state)?, false) @@ -461,10 +477,7 @@ where .boxed() } (_, Some(resource)) => { - let resource = state - .resource_table - .take_any(resource) - .map_err(FetchError::Resource)?; + let resource = state.resource_table.take_any(resource)?; match resource.size_hint() { (body_size, Some(n)) if body_size == n && body_size > 0 => { con_len = Some(body_size); @@ -608,8 +621,7 @@ pub async fn op_fetch_send( let request = state .borrow_mut() .resource_table - .take::(rid) - .map_err(FetchError::Resource)?; + .take::(rid)?; let request = Rc::try_unwrap(request) .ok() @@ -789,7 +801,7 @@ impl Resource for FetchResponseResource { Some(_) => match reader.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), Err(err) => { - break Err(deno_core::error::type_error(err.to_string())) + break Err(JsNativeError::type_error(err.to_string())) } }, None => break Ok(BufView::empty()), @@ -798,7 +810,10 @@ impl Resource for FetchResponseResource { }; let cancel_handle = RcRef::map(self, |r| &r.cancel); - fut.try_or_cancel(cancel_handle).await + fut + .try_or_cancel(cancel_handle) + .await + .map_err(JsNativeError::from_err) }) } @@ -933,7 +948,8 @@ impl Default for CreateHttpClientOptions { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum HttpClientCreateError { #[error(transparent)] Tls(deno_tls::TlsError), @@ -943,8 +959,9 @@ pub enum HttpClientCreateError { InvalidProxyUrl, #[error("Cannot create Http Client: either `http1` or `http2` needs to be set to true")] HttpVersionSelectionInvalid, + #[class(inherit)] #[error(transparent)] - RootCertStore(deno_core::error::AnyError), + RootCertStore(#[inherit] JsNativeError), } /// Create new instance of async Client. This client supports @@ -1132,14 +1149,15 @@ impl Client { .oneshot(req) .await .map_err(|e| ClientSendError { uri, source: e })?; - Ok(resp.map(|b| b.map_err(|e| deno_core::anyhow::anyhow!(e)).boxed())) + Ok( + resp + .map(|b| b.map_err(|e| JsNativeError::generic(e.to_string())).boxed()), + ) } } -pub type ReqBody = - http_body_util::combinators::BoxBody; -pub type ResBody = - http_body_util::combinators::BoxBody; +pub type ReqBody = http_body_util::combinators::BoxBody; +pub type ResBody = http_body_util::combinators::BoxBody; /// Copied from https://github.com/seanmonstar/reqwest/blob/b9d62a0323d96f11672a61a17bf8849baec00275/src/async_impl/request.rs#L572 /// Check the request URL for a "username:password" type authority, and if diff --git a/ext/ffi/call.rs b/ext/ffi/call.rs index bbff0ee48f462d..6d06c73f4a43dd 100644 --- a/ext/ffi/call.rs +++ b/ext/ffi/call.rs @@ -23,20 +23,26 @@ use std::ffi::c_void; use std::future::Future; use std::rc::Rc; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CallError { + #[class(TYPE)] #[error(transparent)] IR(#[from] IRError), + #[class(GENERIC)] #[error("Nonblocking FFI call failed: {0}")] NonblockingCallFailure(#[source] tokio::task::JoinError), + #[class(TYPE)] #[error("Invalid FFI symbol name: '{0}'")] InvalidSymbol(String), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Callback(#[from] super::CallbackError), + Callback(#[from] #[inherit] super::CallbackError), } // SAFETY: Makes an FFI call @@ -344,10 +350,7 @@ pub fn op_ffi_call_nonblocking( ) -> Result>, CallError> { let symbol = { let state = state.borrow(); - let resource = state - .resource_table - .get::(rid) - .map_err(CallError::Resource)?; + let resource = state.resource_table.get::(rid)?; let symbols = &resource.symbols; *symbols .get(&symbol) diff --git a/ext/ffi/callback.rs b/ext/ffi/callback.rs index 29583c800cd36d..c7dde4d436605b 100644 --- a/ext/ffi/callback.rs +++ b/ext/ffi/callback.rs @@ -33,14 +33,17 @@ thread_local! { static LOCAL_THREAD_ID: RefCell = const { RefCell::new(0) }; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CallbackError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] #[inherit] deno_core::error::JsNativeError), } #[derive(Clone)] @@ -61,13 +64,8 @@ impl PtrSymbol { .clone() .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(CallbackError::Other)?, - def - .result - .clone() - .try_into() - .map_err(CallbackError::Other)?, + .collect::, _>>()?, + def.result.clone().try_into()?, ); Ok(Self { cif, ptr }) @@ -538,10 +536,8 @@ pub fn op_ffi_unsafe_callback_ref( #[smi] rid: ResourceId, ) -> Result, CallbackError> { let state = state.borrow(); - let callback_resource = state - .resource_table - .get::(rid) - .map_err(CallbackError::Resource)?; + let callback_resource = + state.resource_table.get::(rid)?; Ok(async move { let info: &mut CallbackInfo = @@ -608,10 +604,8 @@ where .parameters .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(CallbackError::Other)?, - libffi::middle::Type::try_from(args.result) - .map_err(CallbackError::Other)?, + .collect::, _>>()?, + libffi::middle::Type::try_from(args.result)?, ); // SAFETY: CallbackInfo is leaked, is not null and stays valid as long as the callback exists. @@ -647,10 +641,8 @@ pub fn op_ffi_unsafe_callback_close( // It is up to the user to know that it is safe to call the `close()` on the // UnsafeCallback instance. unsafe { - let callback_resource = state - .resource_table - .take::(rid) - .map_err(CallbackError::Resource)?; + let callback_resource = + state.resource_table.take::(rid)?; let info = Box::from_raw(callback_resource.info); let _ = v8::Global::from_raw(scope, info.callback); let _ = v8::Global::from_raw(scope, info.context); diff --git a/ext/ffi/dlfcn.rs b/ext/ffi/dlfcn.rs index 55909468f81044..fec19a4c39accf 100644 --- a/ext/ffi/dlfcn.rs +++ b/ext/ffi/dlfcn.rs @@ -6,6 +6,8 @@ use crate::symbol::Symbol; use crate::turbocall; use crate::turbocall::Turbocall; use crate::FfiPermissions; +use deno_core::error::{JsErrorClass}; +use deno_core::error::{JsNativeError}; use deno_core::op2; use deno_core::v8; use deno_core::GarbageCollected; @@ -19,20 +21,33 @@ use std::collections::HashMap; use std::ffi::c_void; use std::rc::Rc; -#[derive(Debug, thiserror::Error)] +deno_core::js_error_wrapper!(dlopen2::Error, JsDlopen2Error, |err| { + match err { + dlopen2::Error::NullCharacter(_) => "InvalidData", + dlopen2::Error::OpeningLibraryError(e) => e.get_class(), + dlopen2::Error::SymbolGettingError(e) => e.get_class(), + dlopen2::Error::AddrNotMatchingDll(e) => e.get_class(), + dlopen2::Error::NullSymbol => "NotFound", + }}); + +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum DlfcnError { + #[class(GENERIC)] #[error("Failed to register symbol {symbol}: {error}")] RegisterSymbol { symbol: String, #[source] error: dlopen2::Error, }, + #[class(GENERIC)] #[error(transparent)] Dlopen(#[from] dlopen2::Error), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] #[inherit] JsNativeError), } pub struct DynamicLibraryResource { @@ -184,13 +199,8 @@ where .clone() .into_iter() .map(libffi::middle::Type::try_from) - .collect::, _>>() - .map_err(DlfcnError::Other)?, - foreign_fn - .result - .clone() - .try_into() - .map_err(DlfcnError::Other)?, + .collect::, _>>()?, + foreign_fn.result.clone().try_into()?, ); let func_key = v8::String::new(scope, &symbol_key).unwrap(); @@ -297,9 +307,7 @@ fn sync_fn_impl<'s>( unsafe { result.to_v8(scope, data.symbol.result_type.clone()) }; rv.set(result); } - Err(err) => { - deno_core::_ops::throw_type_error(scope, err.to_string()); - } + Err(err) => err.throw(scope), }; } diff --git a/ext/ffi/ir.rs b/ext/ffi/ir.rs index 2e80842166fa7e..307c168b994b78 100644 --- a/ext/ffi/ir.rs +++ b/ext/ffi/ir.rs @@ -6,7 +6,8 @@ use libffi::middle::Arg; use std::ffi::c_void; use std::ptr; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum IRError { #[error("Invalid FFI u8 type, expected boolean")] InvalidU8ExpectedBoolean, diff --git a/ext/ffi/repr.rs b/ext/ffi/repr.rs index fd8a2c8e707336..d8e1716417bebb 100644 --- a/ext/ffi/repr.rs +++ b/ext/ffi/repr.rs @@ -9,7 +9,8 @@ use std::ffi::c_void; use std::ffi::CStr; use std::ptr; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum ReprError { #[error("Invalid pointer to offset, pointer is null")] InvalidOffset, @@ -45,8 +46,9 @@ pub enum ReprError { InvalidF64, #[error("Invalid pointer pointer, pointer is null")] InvalidPointer, + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), } #[op2(fast)] diff --git a/ext/ffi/static.rs b/ext/ffi/static.rs index 61b40593367f31..dec4080ea39ff8 100644 --- a/ext/ffi/static.rs +++ b/ext/ffi/static.rs @@ -8,16 +8,20 @@ use deno_core::OpState; use deno_core::ResourceId; use std::ptr; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum StaticError { + #[class(inherit)] #[error(transparent)] - Dlfcn(super::DlfcnError), + Dlfcn(#[inherit] super::DlfcnError), + #[class(TYPE)] #[error("Invalid FFI static type 'void'")] InvalidTypeVoid, + #[class(TYPE)] #[error("Invalid FFI static type 'struct'")] InvalidTypeStruct, + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), } #[op2] @@ -29,10 +33,7 @@ pub fn op_ffi_get_static<'scope>( #[serde] static_type: NativeType, optional: bool, ) -> Result, StaticError> { - let resource = state - .resource_table - .get::(rid) - .map_err(StaticError::Resource)?; + let resource = state.resource_table.get::(rid)?; let data_ptr = match resource.get_static(name) { Ok(data_ptr) => data_ptr, diff --git a/ext/ffi/symbol.rs b/ext/ffi/symbol.rs index cee1c7d33e94c6..217e77f2c7b068 100644 --- a/ext/ffi/symbol.rs +++ b/ext/ffi/symbol.rs @@ -1,7 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::type_error; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; /// Defines the accepted types that can be used as /// parameters and return values in FFI. @@ -29,7 +28,7 @@ pub enum NativeType { } impl TryFrom for libffi::middle::Type { - type Error = AnyError; + type Error = JsNativeError; fn try_from(native_type: NativeType) -> Result { Ok(match native_type { @@ -56,7 +55,7 @@ impl TryFrom for libffi::middle::Type { .map(|field| field.clone().try_into()) .collect::, _>>()?, false => { - return Err(type_error("Struct must have at least one field")) + return Err(JsNativeError::type_error("Struct must have at least one field")) } }) } diff --git a/ext/fs/ops.rs b/ext/fs/ops.rs index 9b76b49e613418..e843dbc6bc0b95 100644 --- a/ext/fs/ops.rs +++ b/ext/fs/ops.rs @@ -16,6 +16,8 @@ use crate::interface::FsDirEntry; use crate::interface::FsFileType; use crate::FsPermissions; use crate::OpenOptions; +use deno_core::error::JsNativeError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::CancelFuture; use deno_core::CancelHandle; @@ -32,31 +34,43 @@ use rand::thread_rng; use rand::Rng; use serde::Serialize; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum FsOpsError { + #[class(inherit)] #[error("{0}")] - Io(#[source] std::io::Error), + Io(#[source] #[inherit] std::io::Error), + #[class(inherit)] #[error("{0}")] - OperationError(#[source] OperationError), + OperationError(#[source] #[inherit] OperationError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] PermissionCheckError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] ResourceError), + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(GENERIC)] #[error("{0}")] StripPrefix(#[from] StripPrefixError), + #[class(inherit)] #[error("{0}")] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class(TYPE)] #[error("Invalid seek mode: {0}")] InvalidSeekMode(i32), + #[class(GENERIC)] #[error("Invalid control character in prefix or suffix: {0:?}")] InvalidControlCharacter(String), + #[class(GENERIC)] #[error("Invalid character in prefix or suffix: {0:?}")] InvalidCharacter(String), #[cfg(windows)] + #[class(GENERIC)] #[error("Invalid trailing character in suffix")] InvalidTrailingCharacter, + #[class("NotCapable")] #[error("Requires {err} access to {path}, {}", print_not_capable_info(*.standalone, .err))] NotCapableAccess { // NotCapable @@ -64,21 +78,21 @@ pub enum FsOpsError { err: &'static str, path: String, }, + #[class("NotCapable")] #[error("permission denied: {0}")] - NotCapable(&'static str), // NotCapable + NotCapable(&'static str), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } impl From for FsOpsError { fn from(err: FsError) -> Self { match err { FsError::Io(err) => FsOpsError::Io(err), - FsError::FileBusy => { - FsOpsError::Other(deno_core::error::resource_unavailable()) - } + FsError::FileBusy => FsOpsError::Resource(ResourceError::Unavailable), FsError::NotSupported => { - FsOpsError::Other(deno_core::error::not_supported()) + FsOpsError::Other(JsNativeError::not_supported()) } FsError::NotCapable(err) => FsOpsError::NotCapable(err), } @@ -1455,8 +1469,7 @@ pub fn op_fs_seek_sync( #[smi] whence: i32, ) -> Result { let pos = to_seek_from(offset, whence)?; - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; let cursor = file.seek_sync(pos)?; Ok(cursor) } @@ -1470,8 +1483,7 @@ pub async fn op_fs_seek_async( #[smi] whence: i32, ) -> Result { let pos = to_seek_from(offset, whence)?; - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; let cursor = file.seek_async(pos).await?; Ok(cursor) } @@ -1481,8 +1493,7 @@ pub fn op_fs_file_sync_data_sync( state: &mut OpState, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.datasync_sync()?; Ok(()) } @@ -1492,8 +1503,7 @@ pub async fn op_fs_file_sync_data_async( state: Rc>, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file.datasync_async().await?; Ok(()) } @@ -1503,8 +1513,7 @@ pub fn op_fs_file_sync_sync( state: &mut OpState, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.sync_sync()?; Ok(()) } @@ -1514,8 +1523,7 @@ pub async fn op_fs_file_sync_async( state: Rc>, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file.sync_async().await?; Ok(()) } @@ -1526,8 +1534,7 @@ pub fn op_fs_file_stat_sync( #[smi] rid: ResourceId, #[buffer] stat_out_buf: &mut [u32], ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; let stat = file.stat_sync()?; let serializable_stat = SerializableStat::from(stat); serializable_stat.write(stat_out_buf); @@ -1540,8 +1547,7 @@ pub async fn op_fs_file_stat_async( state: Rc>, #[smi] rid: ResourceId, ) -> Result { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; let stat = file.stat_async().await?; Ok(stat.into()) } @@ -1552,8 +1558,7 @@ pub fn op_fs_flock_sync( #[smi] rid: ResourceId, exclusive: bool, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.lock_sync(exclusive)?; Ok(()) } @@ -1564,8 +1569,7 @@ pub async fn op_fs_flock_async( #[smi] rid: ResourceId, exclusive: bool, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file.lock_async(exclusive).await?; Ok(()) } @@ -1575,8 +1579,7 @@ pub fn op_fs_funlock_sync( state: &mut OpState, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.unlock_sync()?; Ok(()) } @@ -1586,8 +1589,7 @@ pub async fn op_fs_funlock_async( state: Rc>, #[smi] rid: ResourceId, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file.unlock_async().await?; Ok(()) } @@ -1598,8 +1600,7 @@ pub fn op_fs_ftruncate_sync( #[smi] rid: ResourceId, #[number] len: u64, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.truncate_sync(len)?; Ok(()) } @@ -1610,8 +1611,7 @@ pub async fn op_fs_file_truncate_async( #[smi] rid: ResourceId, #[number] len: u64, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file.truncate_async(len).await?; Ok(()) } @@ -1625,8 +1625,7 @@ pub fn op_fs_futime_sync( #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, ) -> Result<(), FsOpsError> { - let file = - FileResource::get_file(state, rid).map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(state, rid)?; file.utime_sync(atime_secs, atime_nanos, mtime_secs, mtime_nanos)?; Ok(()) } @@ -1640,18 +1639,19 @@ pub async fn op_fs_futime_async( #[number] mtime_secs: i64, #[smi] mtime_nanos: u32, ) -> Result<(), FsOpsError> { - let file = FileResource::get_file(&state.borrow(), rid) - .map_err(FsOpsError::Resource)?; + let file = FileResource::get_file(&state.borrow(), rid)?; file .utime_async(atime_secs, atime_nanos, mtime_secs, mtime_nanos) .await?; Ok(()) } -#[derive(Debug)] +#[derive(Debug, deno_core::JsError)] +#[class(inherit)] pub struct OperationError { operation: &'static str, kind: OperationErrorKind, + #[inherit] pub err: FsError, } diff --git a/ext/http/http_next.rs b/ext/http/http_next.rs index c55e868352dd33..8ff0ef29bbc5e2 100644 --- a/ext/http/http_next.rs +++ b/ext/http/http_next.rs @@ -145,24 +145,32 @@ macro_rules! clone_external { }}; } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum HttpNextError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error("{0}")] - Io(#[from] io::Error), + Io(#[from] #[inherit] io::Error), + #[class(inherit)] #[error(transparent)] - WebSocketUpgrade(crate::websocket_upgrade::WebSocketUpgradeError), + WebSocketUpgrade(#[inherit] crate::websocket_upgrade::WebSocketUpgradeError), + #[class("Http")] #[error("{0}")] Hyper(#[from] hyper::Error), + #[class(inherit)] #[error(transparent)] - JoinError(#[from] tokio::task::JoinError), + JoinError(#[from] #[inherit] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), - #[error(transparent)] - HttpPropertyExtractor(deno_core::error::AnyError), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class(GENERIC)] #[error(transparent)] UpgradeUnavailable(#[from] crate::service::UpgradeUnavailableError), + #[class(inherit)] + #[error("{0}")] + Other(#[from] #[inherit] deno_core::error::JsNativeError), } #[op2(fast)] @@ -745,15 +753,9 @@ pub async fn op_http_set_response_body_resource( let resource = { let mut state = state.borrow_mut(); if auto_close { - state - .resource_table - .take_any(stream_rid) - .map_err(HttpNextError::Resource)? + state.resource_table.take_any(stream_rid)? } else { - state - .resource_table - .get_any(stream_rid) - .map_err(HttpNextError::Resource)? + state.resource_table.get_any(stream_rid)? } }; @@ -1033,8 +1035,7 @@ where HTTP: HttpPropertyExtractor, { let listener = - HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid) - .map_err(HttpNextError::Resource)?; + HTTP::get_listener_for_rid(&mut state.borrow_mut(), listener_rid)?; let listen_properties = HTTP::listen_properties_from_listener(&listener)?; @@ -1049,8 +1050,7 @@ where loop { let conn = HTTP::accept_connection_from_listener(&listener) .try_or_cancel(listen_cancel_clone.clone()) - .await - .map_err(HttpNextError::HttpPropertyExtractor)?; + .await?; serve_http_on::( conn, &listen_properties_clone, @@ -1084,8 +1084,7 @@ where HTTP: HttpPropertyExtractor, { let connection = - HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid) - .map_err(HttpNextError::Resource)?; + HTTP::get_connection_for_rid(&mut state.borrow_mut(), connection_rid)?; let listen_properties = HTTP::listen_properties_from_connection(&connection)?; @@ -1148,8 +1147,7 @@ pub async fn op_http_wait( let join_handle = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpNextError::Resource)?; + .get::(rid)?; let cancel = join_handle.listen_cancel_handle(); let next = async { @@ -1194,7 +1192,7 @@ pub fn op_http_cancel( state: &mut OpState, #[smi] rid: ResourceId, graceful: bool, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), deno_core::error::ResourceError> { let join_handle = state.resource_table.get::(rid)?; if graceful { @@ -1218,8 +1216,7 @@ pub async fn op_http_close( let join_handle = state .borrow_mut() .resource_table - .take::(rid) - .map_err(HttpNextError::Resource)?; + .take::(rid)?; if graceful { http_general_trace!("graceful shutdown"); @@ -1348,11 +1345,8 @@ pub async fn op_raw_write_vectored( #[buffer] buf1: JsBuffer, #[buffer] buf2: JsBuffer, ) -> Result { - let resource: Rc = state - .borrow() - .resource_table - .get::(rid) - .map_err(HttpNextError::Resource)?; + let resource: Rc = + state.borrow().resource_table.get::(rid)?; let nwritten = resource.write_vectored(&buf1, &buf2).await?; Ok(nwritten) } diff --git a/ext/http/lib.rs b/ext/http/lib.rs index 49893b1b921f21..428a730480634a 100644 --- a/ext/http/lib.rs +++ b/ext/http/lib.rs @@ -6,6 +6,7 @@ use async_compression::Level; use base64::prelude::BASE64_STANDARD; use base64::Engine; use cache_control::CacheControl; +use deno_core::error::JsNativeError; use deno_core::futures::channel::mpsc; use deno_core::futures::channel::oneshot; use deno_core::futures::future::pending; @@ -137,36 +138,50 @@ deno_core::extension!( esm = ["00_serve.ts", "01_http.js", "02_websocket.ts"], ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum HttpError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class("Http")] #[error("{0}")] HyperV014(#[source] Arc), + #[class(GENERIC)] #[error("{0}")] InvalidHeaderName(#[from] hyper_v014::header::InvalidHeaderName), + #[class(GENERIC)] #[error("{0}")] InvalidHeaderValue(#[from] hyper_v014::header::InvalidHeaderValue), + #[class(GENERIC)] #[error("{0}")] Http(#[from] hyper_v014::http::Error), + #[class("Http")] #[error("response headers already sent")] ResponseHeadersAlreadySent, + #[class("Http")] #[error("connection closed while sending response")] ConnectionClosedWhileSendingResponse, + #[class("Http")] #[error("already in use")] AlreadyInUse, + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class("Http")] #[error("no response headers")] NoResponseHeaders, + #[class("Http")] #[error("response already completed")] ResponseAlreadyCompleted, + #[class("Http")] #[error("cannot upgrade because request body was used")] UpgradeBodyUsed, + #[class("Http")] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[from] JsNativeError), } pub enum HttpSocketAddr { @@ -458,7 +473,9 @@ impl Resource for HttpStreamReadResource { Some(_) => match body.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), Err(err) => { - break Err(HttpError::HyperV014(Arc::new(err)).into()) + break Err(JsNativeError::from_err(HttpError::HyperV014( + Arc::new(err), + ))) } }, None => break Ok(BufView::empty()), @@ -582,11 +599,7 @@ async fn op_http_accept( state: Rc>, #[smi] rid: ResourceId, ) -> Result, HttpError> { - let conn = state - .borrow() - .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + let conn = state.borrow().resource_table.get::(rid)?; match conn.accept().await { Ok(Some((read_stream, write_stream, method, url))) => { @@ -701,8 +714,7 @@ async fn op_http_write_headers( let stream = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; // Track supported encoding let encoding = stream.accept_encoding; @@ -767,10 +779,7 @@ fn op_http_headers( state: &mut OpState, #[smi] rid: u32, ) -> Result, HttpError> { - let stream = state - .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + let stream = state.resource_table.get::(rid)?; let rd = RcRef::map(&stream, |r| &r.rd) .try_borrow() .ok_or(HttpError::AlreadyInUse)?; @@ -926,14 +935,9 @@ async fn op_http_write_resource( let http_stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&http_stream, |r| &r.wr).borrow_mut().await; - let resource = state - .borrow() - .resource_table - .get_any(stream) - .map_err(HttpError::Resource)?; + let resource = state.borrow().resource_table.get_any(stream)?; loop { match *wr { HttpResponseWriter::Headers(_) => { @@ -945,11 +949,7 @@ async fn op_http_write_resource( _ => {} }; - let view = resource - .clone() - .read(64 * 1024) - .await - .map_err(HttpError::Other)?; // 64KB + let view = resource.clone().read(64 * 1024).await?; // 64KB if view.is_empty() { break; } @@ -994,8 +994,7 @@ async fn op_http_write( let stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await; match &mut *wr { @@ -1047,8 +1046,7 @@ async fn op_http_shutdown( let stream = state .borrow() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut wr = RcRef::map(&stream, |r| &r.wr).borrow_mut().await; let wr = take(&mut *wr); match wr { @@ -1094,8 +1092,7 @@ async fn op_http_upgrade_websocket( let stream = state .borrow_mut() .resource_table - .get::(rid) - .map_err(HttpError::Resource)?; + .get::(rid)?; let mut rd = RcRef::map(&stream, |r| &r.rd).borrow_mut().await; let request = match &mut *rd { diff --git a/ext/http/request_body.rs b/ext/http/request_body.rs index f1c3f358ea977b..f071318704fcd4 100644 --- a/ext/http/request_body.rs +++ b/ext/http/request_body.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use bytes::Bytes; +use deno_core::error::JsNativeError; use deno_core::futures::stream::Peekable; use deno_core::futures::Stream; use deno_core::futures::StreamExt; @@ -82,7 +83,10 @@ impl Resource for HttpRequestBody { } fn read(self: Rc, limit: usize) -> AsyncResult { - Box::pin(HttpRequestBody::read(self, limit).map_err(Into::into)) + Box::pin( + HttpRequestBody::read(self, limit) + .map_err(|e| JsNativeError::new("Http", e.to_string())), + ) } fn size_hint(&self) -> (u64, Option) { diff --git a/ext/http/request_properties.rs b/ext/http/request_properties.rs index 39d35a79f14b82..4f01664a9a91dd 100644 --- a/ext/http/request_properties.rs +++ b/ext/http/request_properties.rs @@ -1,5 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::OpState; use deno_core::ResourceId; use deno_net::raw::take_network_stream_listener_resource; @@ -49,13 +49,13 @@ pub trait HttpPropertyExtractor { fn get_listener_for_rid( state: &mut OpState, listener_rid: ResourceId, - ) -> Result; + ) -> Result; /// Given a connection [`ResourceId`], returns the [`HttpPropertyExtractor::Connection`]. fn get_connection_for_rid( state: &mut OpState, connection_rid: ResourceId, - ) -> Result; + ) -> Result; /// Determines the listener properties. fn listen_properties_from_listener( @@ -70,7 +70,7 @@ pub trait HttpPropertyExtractor { /// Accept a new [`HttpPropertyExtractor::Connection`] from the given listener [`HttpPropertyExtractor::Listener`]. async fn accept_connection_from_listener( listener: &Self::Listener, - ) -> Result; + ) -> Result; /// Determines the connection properties. fn connection_properties( @@ -102,7 +102,7 @@ impl HttpPropertyExtractor for DefaultHttpPropertyExtractor { fn get_listener_for_rid( state: &mut OpState, listener_rid: ResourceId, - ) -> Result { + ) -> Result { take_network_stream_listener_resource( &mut state.resource_table, listener_rid, @@ -112,17 +112,18 @@ impl HttpPropertyExtractor for DefaultHttpPropertyExtractor { fn get_connection_for_rid( state: &mut OpState, stream_rid: ResourceId, - ) -> Result { + ) -> Result { take_network_stream_resource(&mut state.resource_table, stream_rid) + .map_err(JsNativeError::from_err) } async fn accept_connection_from_listener( listener: &NetworkStreamListener, - ) -> Result { + ) -> Result { listener .accept() .await - .map_err(Into::into) + .map_err(JsNativeError::from_err) .map(|(stm, _)| stm) } diff --git a/ext/http/response_body.rs b/ext/http/response_body.rs index bac43bf3c8be39..3826a27cb48a14 100644 --- a/ext/http/response_body.rs +++ b/ext/http/response_body.rs @@ -9,7 +9,7 @@ use brotli::enc::encode::BrotliEncoderStateStruct; use brotli::writer::StandardAlloc; use bytes::Bytes; use bytes::BytesMut; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::futures::ready; use deno_core::futures::FutureExt; use deno_core::AsyncResult; @@ -32,10 +32,12 @@ pub enum ResponseStreamResult { /// will only be returned from compression streams that require additional buffering. NoData, /// Stream failed. - Error(AnyError), + Error(JsNativeError), } -impl From for Option, AnyError>> { +impl From + for Option, JsNativeError>> +{ fn from(value: ResponseStreamResult) -> Self { match value { ResponseStreamResult::EndOfStream => None, @@ -411,7 +413,9 @@ impl PollFrame for GZipResponseStream { }; let len = stm.total_out() - start_out; let res = match res { - Err(err) => ResponseStreamResult::Error(err.into()), + Err(err) => { + ResponseStreamResult::Error(JsNativeError::generic(err.to_string())) + } Ok(flate2::Status::BufError) => { // This should not happen unreachable!("old={orig_state:?} new={state:?} buf_len={}", buf.len()); diff --git a/ext/http/service.rs b/ext/http/service.rs index ce24dea43f372c..793f69443f0f79 100644 --- a/ext/http/service.rs +++ b/ext/http/service.rs @@ -14,6 +14,7 @@ use hyper::body::SizeHint; use hyper::header::HeaderMap; use hyper::upgrade::OnUpgrade; +use deno_core::error::JsNativeError; use scopeguard::guard; use scopeguard::ScopeGuard; use std::cell::Cell; @@ -528,7 +529,7 @@ pub struct HttpRecordResponse(ManuallyDrop>); impl Body for HttpRecordResponse { type Data = BufView; - type Error = deno_core::error::AnyError; + type Error = JsNativeError; fn poll_frame( self: Pin<&mut Self>, diff --git a/ext/http/websocket_upgrade.rs b/ext/http/websocket_upgrade.rs index af9504717e3948..cc7c48bc32f123 100644 --- a/ext/http/websocket_upgrade.rs +++ b/ext/http/websocket_upgrade.rs @@ -12,22 +12,30 @@ use memmem::Searcher; use memmem::TwoWaySearcher; use once_cell::sync::OnceCell; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum WebSocketUpgradeError { + #[class("Http")] #[error("invalid headers")] InvalidHeaders, + #[class(GENERIC)] #[error("{0}")] HttpParse(#[from] httparse::Error), + #[class(GENERIC)] #[error("{0}")] Http(#[from] http::Error), + #[class(GENERIC)] #[error("{0}")] Utf8(#[from] std::str::Utf8Error), + #[class(GENERIC)] #[error("{0}")] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + #[class(GENERIC)] #[error("{0}")] InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), + #[class("Http")] #[error("invalid HTTP status line")] InvalidHttpStatusLine, + #[class("Http")] #[error("attempted to write to completed upgrade buffer")] UpgradeBufferAlreadyCompleted, } diff --git a/ext/io/fs.rs b/ext/io/fs.rs index 8854265209cd6c..d6a052820e3cc9 100644 --- a/ext/io/fs.rs +++ b/ext/io/fs.rs @@ -9,16 +9,21 @@ use std::time::UNIX_EPOCH; use deno_core::BufMutView; use deno_core::BufView; +use deno_core::error::{JsNativeError, ResourceError}; use deno_core::OpState; use deno_core::ResourceHandleFd; use deno_core::ResourceId; use tokio::task::JoinError; -#[derive(Debug)] +#[derive(Debug, deno_core::JsError)] pub enum FsError { - Io(io::Error), + #[class(inherit)] + Io(#[inherit] io::Error), + #[class("Busy")] FileBusy, + #[class("NotSupported")] NotSupported, + #[class("NotCapable")] NotCapable(&'static str), } @@ -265,18 +270,21 @@ impl FileResource { state: &OpState, rid: ResourceId, f: F, - ) -> Result + ) -> Result where - F: FnOnce(Rc) -> Result, + F: FnOnce(Rc) -> Result, { - let resource = state.resource_table.get::(rid)?; + let resource = state + .resource_table + .get::(rid) + .map_err(JsNativeError::from_err)?; f(resource) } pub fn get_file( state: &OpState, rid: ResourceId, - ) -> Result, deno_core::error::AnyError> { + ) -> Result, ResourceError> { let resource = state.resource_table.get::(rid)?; Ok(resource.file()) } @@ -285,9 +293,9 @@ impl FileResource { state: &OpState, rid: ResourceId, f: F, - ) -> Result + ) -> Result where - F: FnOnce(Rc) -> Result, + F: FnOnce(Rc) -> Result, { Self::with_resource(state, rid, |r| f(r.file.clone())) } @@ -309,7 +317,7 @@ impl deno_core::Resource for FileResource { .clone() .read(limit) .await - .map_err(|err| err.into()) + .map_err(JsNativeError::from_err) }) } @@ -323,7 +331,7 @@ impl deno_core::Resource for FileResource { .clone() .read_byob(buf) .await - .map_err(|err| err.into()) + .map_err(JsNativeError::from_err) }) } @@ -332,7 +340,12 @@ impl deno_core::Resource for FileResource { buf: BufView, ) -> deno_core::AsyncResult { Box::pin(async move { - self.file.clone().write(buf).await.map_err(|err| err.into()) + self + .file + .clone() + .write(buf) + .await + .map_err(JsNativeError::from_err) }) } @@ -343,22 +356,27 @@ impl deno_core::Resource for FileResource { .clone() .write_all(buf) .await - .map_err(|err| err.into()) + .map_err(JsNativeError::from_err) }) } fn read_byob_sync( self: Rc, data: &mut [u8], - ) -> Result { - self.file.clone().read_sync(data).map_err(|err| err.into()) + ) -> Result { + self + .file + .clone() + .read_sync(data) + .map_err(JsNativeError::from_err) } - fn write_sync( - self: Rc, - data: &[u8], - ) -> Result { - self.file.clone().write_sync(data).map_err(|err| err.into()) + fn write_sync(self: Rc, data: &[u8]) -> Result { + self + .file + .clone() + .write_sync(data) + .map_err(JsNativeError::from_err) } fn backing_fd(self: Rc) -> Option { diff --git a/ext/io/lib.rs b/ext/io/lib.rs index 5d183aa464d885..33163effd95f6b 100644 --- a/ext/io/lib.rs +++ b/ext/io/lib.rs @@ -47,6 +47,7 @@ use winapi::um::processenv::GetStdHandle; #[cfg(windows)] use winapi::um::winbase; +use deno_core::error::JsNativeError; use deno_core::futures::TryFutureExt; #[cfg(windows)] use parking_lot::Condvar; @@ -417,7 +418,7 @@ impl Resource for ChildStdinResource { deno_core::impl_writable!(); fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(|e| e.into())) + Box::pin(self.shutdown().map_err(JsNativeError::from_err)) } } @@ -1010,9 +1011,13 @@ pub fn op_print( state: &mut OpState, #[string] msg: &str, is_err: bool, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsNativeError> { let rid = if is_err { 2 } else { 1 }; FileResource::with_file(state, rid, move |file| { - Ok(file.write_all_sync(msg.as_bytes())?) + Ok( + file + .write_all_sync(msg.as_bytes()) + .map_err(JsNativeError::from_err)?, + ) }) } diff --git a/ext/kv/dynamic.rs b/ext/kv/dynamic.rs index 6d545d79f6407f..14f6066a063398 100644 --- a/ext/kv/dynamic.rs +++ b/ext/kv/dynamic.rs @@ -13,8 +13,8 @@ use crate::QueueMessageHandle; use crate::ReadRange; use crate::SnapshotReadOptions; use async_trait::async_trait; -use deno_core::error::type_error; use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::OpState; use denokv_proto::CommitResult; use denokv_proto::ReadRangeOutput; @@ -62,7 +62,7 @@ impl DatabaseHandler for MultiBackendDbHandler { &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { for (prefixes, handler) in &self.backends { for &prefix in *prefixes { if prefix.is_empty() { @@ -76,7 +76,7 @@ impl DatabaseHandler for MultiBackendDbHandler { } } } - Err(type_error(format!( + Err(JsNativeError::type_error(format!( "No backend supports the given path: {:?}", path ))) @@ -89,7 +89,7 @@ pub trait DynamicDbHandler { &self, state: Rc>, path: Option, - ) -> Result; + ) -> Result; } #[async_trait(?Send)] @@ -100,7 +100,7 @@ impl DatabaseHandler for Box { &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { (**self).dyn_open(state, path).await } } @@ -115,7 +115,7 @@ where &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { Ok(RcDynamicDb(Rc::new(self.open(state, path).await?))) } } diff --git a/ext/kv/interface.rs b/ext/kv/interface.rs index 9737a9366d3d1f..774aac56d74e8b 100644 --- a/ext/kv/interface.rs +++ b/ext/kv/interface.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use std::rc::Rc; use async_trait::async_trait; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::OpState; use denokv_proto::Database; @@ -16,5 +16,5 @@ pub trait DatabaseHandler { &self, state: Rc>, path: Option, - ) -> Result; + ) -> Result; } diff --git a/ext/kv/lib.rs b/ext/kv/lib.rs index a4ccfe3d63f5c9..e390a3b23b4862 100644 --- a/ext/kv/lib.rs +++ b/ext/kv/lib.rs @@ -16,7 +16,8 @@ use base64::prelude::BASE64_URL_SAFE; use base64::Engine; use chrono::DateTime; use chrono::Utc; -use deno_core::error::get_custom_error_class; +use deno_core::error::JsErrorClass; +use deno_core::error::JsNativeError; use deno_core::futures::StreamExt; use deno_core::op2; use deno_core::serde_v8::AnyValue; @@ -114,62 +115,90 @@ impl Resource for DatabaseWatcherResource { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum KvError { + #[class(inherit)] #[error(transparent)] - DatabaseHandler(deno_core::error::AnyError), + DatabaseHandler( #[inherit] JsNativeError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(TYPE)] #[error("Too many ranges (max {0})")] TooManyRanges(usize), + #[class(TYPE)] #[error("Too many entries (max {0})")] TooManyEntries(usize), + #[class(TYPE)] #[error("Too many checks (max {0})")] TooManyChecks(usize), + #[class(TYPE)] #[error("Too many mutations (max {0})")] TooManyMutations(usize), + #[class(TYPE)] #[error("Too many keys (max {0})")] TooManyKeys(usize), + #[class(TYPE)] #[error("limit must be greater than 0")] InvalidLimit, + #[class(TYPE)] #[error("Invalid boundary key")] InvalidBoundaryKey, + #[class(TYPE)] #[error("Key too large for read (max {0} bytes)")] KeyTooLargeToRead(usize), + #[class(TYPE)] #[error("Key too large for write (max {0} bytes)")] KeyTooLargeToWrite(usize), + #[class(TYPE)] #[error("Total mutation size too large (max {0} bytes)")] TotalMutationTooLarge(usize), + #[class(TYPE)] #[error("Total key size too large (max {0} bytes)")] TotalKeyTooLarge(usize), + #[class(GENERIC)] #[error(transparent)] Kv(deno_core::error::AnyError), + #[class(inherit)] #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(TYPE)] #[error("Queue message not found")] QueueMessageNotFound, + #[class(TYPE)] #[error("Start key is not in the keyspace defined by prefix")] StartKeyNotInKeyspace, + #[class(TYPE)] #[error("End key is not in the keyspace defined by prefix")] EndKeyNotInKeyspace, + #[class(TYPE)] #[error("Start key is greater than end key")] StartKeyGreaterThanEndKey, + #[class(inherit)] #[error("Invalid check")] - InvalidCheck(#[source] KvCheckError), + InvalidCheck(#[source] #[inherit] KvCheckError), + #[class(inherit)] #[error("Invalid mutation")] - InvalidMutation(#[source] KvMutationError), + InvalidMutation(#[source]#[inherit] KvMutationError), + #[class(inherit)] #[error("Invalid enqueue")] - InvalidEnqueue(#[source] std::io::Error), + InvalidEnqueue(#[source] #[inherit] std::io::Error), + #[class(TYPE)] #[error("key cannot be empty")] - EmptyKey, // TypeError + EmptyKey, + #[class(TYPE)] #[error("Value too large (max {0} bytes)")] - ValueTooLarge(usize), // TypeError + ValueTooLarge(usize), + #[class(TYPE)] #[error("enqueue payload too large (max {0} bytes)")] - EnqueuePayloadTooLarge(usize), // TypeError + EnqueuePayloadTooLarge(usize), + #[class(TYPE)] #[error("invalid cursor")] InvalidCursor, + #[class(TYPE)] #[error("cursor out of bounds")] CursorOutOfBounds, + #[class(TYPE)] #[error("Invalid range")] InvalidRange, } @@ -326,10 +355,8 @@ where { let db = { let state = state.borrow(); - let resource = state - .resource_table - .get::>(rid) - .map_err(KvError::Resource)?; + let resource = + state.resource_table.get::>(rid)?; resource.db.clone() }; @@ -412,7 +439,7 @@ where match state.resource_table.get::>(rid) { Ok(resource) => resource, Err(err) => { - if get_custom_error_class(&err) == Some("BadResource") { + if err.get_class() == "BadResource" { return Ok(None); } else { return Err(KvError::Resource(err)); @@ -445,10 +472,7 @@ fn op_kv_watch( where DBH: DatabaseHandler + 'static, { - let resource = state - .resource_table - .get::>(rid) - .map_err(KvError::Resource)?; + let resource = state.resource_table.get::>(rid)?; let config = state.borrow::>().clone(); if keys.len() > config.max_watched_keys { @@ -490,10 +514,7 @@ async fn op_kv_watch_next( ) -> Result>, KvError> { let resource = { let state = state.borrow(); - let resource = state - .resource_table - .get::(rid) - .map_err(KvError::Resource)?; + let resource = state.resource_table.get::(rid)?; resource.clone() }; @@ -562,12 +583,14 @@ where Ok(()) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum KvCheckError { + #[class(TYPE)] #[error("invalid versionstamp")] InvalidVersionstamp, + #[class(inherit)] #[error(transparent)] - Io(std::io::Error), + Io(#[inherit] std::io::Error), } type V8KvCheck = (KvKey, Option); @@ -591,14 +614,18 @@ fn check_from_v8(value: V8KvCheck) -> Result { }) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum KvMutationError { + #[class(GENERIC)] #[error(transparent)] BigInt(#[from] num_bigint::TryFromBigIntError), + #[class(inherit)] #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(TYPE)] #[error("Invalid mutation '{0}' with value")] InvalidMutationWithValue(String), + #[class(TYPE)] #[error("Invalid mutation '{0}' without value")] InvalidMutationWithoutValue(String), } @@ -852,10 +879,8 @@ where let current_timestamp = chrono::Utc::now(); let db = { let state = state.borrow(); - let resource = state - .resource_table - .get::>(rid) - .map_err(KvError::Resource)?; + let resource = + state.resource_table.get::>(rid)?; resource.db.clone() }; diff --git a/ext/kv/remote.rs b/ext/kv/remote.rs index 4930aacfe355c6..9e3c4e23bbb24a 100644 --- a/ext/kv/remote.rs +++ b/ext/kv/remote.rs @@ -9,9 +9,8 @@ use crate::DatabaseHandler; use anyhow::Context; use async_trait::async_trait; use bytes::Bytes; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::futures::Stream; +use deno_core::error::JsNativeError; +use deno_core::futures::{Stream, TryStreamExt}; use deno_core::OpState; use deno_fetch::create_http_client; use deno_fetch::CreateHttpClientOptions; @@ -37,7 +36,7 @@ pub struct HttpOptions { } impl HttpOptions { - pub fn root_cert_store(&self) -> Result, AnyError> { + pub fn root_cert_store(&self) -> Result, JsNativeError> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -143,7 +142,7 @@ impl RemoteResponse for FetchResponse { fn stream( self, ) -> impl Stream> + Send + Sync { - self.0.into_body().into_data_stream() + self.0.into_body().into_data_stream().map_err(anyhow::Error::from) } async fn text(self) -> Result { let bytes = self.bytes().await?; @@ -161,29 +160,29 @@ impl DatabaseHandler &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { const ENV_VAR_NAME: &str = "DENO_KV_ACCESS_TOKEN"; let Some(url) = path else { - return Err(type_error("Missing database url")); + return Err(JsNativeError::type_error("Missing database url")); }; let Ok(parsed_url) = Url::parse(&url) else { - return Err(type_error(format!("Invalid database url: {}", url))); + return Err(JsNativeError::type_error(format!("Invalid database url: {}", url))); }; { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - permissions.check_env(ENV_VAR_NAME)?; - permissions.check_net_url(&parsed_url, "Deno.openKv")?; + permissions.check_env(ENV_VAR_NAME).map_err(JsNativeError::from_err)?; + permissions.check_net_url(&parsed_url, "Deno.openKv").map_err(JsNativeError::from_err)?; } let access_token = std::env::var(ENV_VAR_NAME) .map_err(anyhow::Error::from) .with_context(|| { "Missing DENO_KV_ACCESS_TOKEN environment variable. Please set it to your access token from https://dash.deno.com/account." - })?; + }).map_err(|e| JsNativeError::generic(e.to_string()))?; let metadata_endpoint = MetadataEndpoint { url: parsed_url.clone(), @@ -210,7 +209,7 @@ impl DatabaseHandler http1: false, http2: true, }, - )?; + ).map_err(JsNativeError::from_err)?; let fetch_client = FetchClient(client); let permissions = PermissionChecker { diff --git a/ext/kv/sqlite.rs b/ext/kv/sqlite.rs index 9de5209275c28c..4a3476e0b5b613 100644 --- a/ext/kv/sqlite.rs +++ b/ext/kv/sqlite.rs @@ -15,8 +15,7 @@ use std::sync::OnceLock; use crate::DatabaseHandler; use async_trait::async_trait; -use deno_core::error::type_error; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::unsync::spawn_blocking; use deno_core::OpState; use deno_path_util::normalize_path; @@ -84,6 +83,8 @@ impl SqliteDbHandler

{ } } +deno_core::js_error_wrapper!(SqliteBackendError, JsSqliteBackendError, "TypeError"); + #[async_trait(?Send)] impl DatabaseHandler for SqliteDbHandler

{ type DB = denokv_sqlite::Sqlite; @@ -92,12 +93,12 @@ impl DatabaseHandler for SqliteDbHandler

{ &self, state: Rc>, path: Option, - ) -> Result { + ) -> Result { #[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"] fn validate_path( state: &RefCell, path: Option, - ) -> Result, AnyError> { + ) -> Result, JsNativeError> { let Some(path) = path else { return Ok(None); }; @@ -105,18 +106,22 @@ impl DatabaseHandler for SqliteDbHandler

{ return Ok(Some(path)); } if path.is_empty() { - return Err(type_error("Filename cannot be empty")); + return Err(JsNativeError::type_error("Filename cannot be empty")); } if path.starts_with(':') { - return Err(type_error( + return Err(JsNativeError::type_error( "Filename cannot start with ':' unless prefixed with './'", )); } { let mut state = state.borrow_mut(); let permissions = state.borrow_mut::

(); - let path = permissions.check_read(&path, "Deno.openKv")?; - let path = permissions.check_write(&path, "Deno.openKv")?; + let path = permissions + .check_read(&path, "Deno.openKv") + .map_err(JsNativeError::from_err)?; + let path = permissions + .check_write(&path, "Deno.openKv") + .map_err(JsNativeError::from_err)?; Ok(Some(path.to_string_lossy().to_string())) } } @@ -136,8 +141,7 @@ impl DatabaseHandler for SqliteDbHandler

{ (Some(path), _) => { let flags = OpenFlags::default().difference(OpenFlags::SQLITE_OPEN_URI); - let resolved_path = canonicalize_path(&PathBuf::from(path)) - .map_err(anyhow::Error::from)?; + let resolved_path = canonicalize_path(&PathBuf::from(path))?; let path = path.to_string(); ( Arc::new(move || { @@ -161,7 +165,8 @@ impl DatabaseHandler for SqliteDbHandler

{ }) }) .await - .unwrap()?; + .unwrap() + .map_err(|e| JsNativeError::from_err(JsSqliteBackendError::from(e)))?; let notifier = if let Some(notifier_key) = notifier_key { SQLITE_NOTIFIERS_MAP @@ -197,11 +202,14 @@ impl DatabaseHandler for SqliteDbHandler

{ notifier, config, ) + .map_err(|e| JsNativeError::generic(e.to_string())) } } /// Same as Path::canonicalize, but also handles non-existing paths. -fn canonicalize_path(path: &Path) -> Result { +fn canonicalize_path( + path: &Path, +) -> Result { let path = normalize_path(path); let mut path = path; let mut names_stack = Vec::new(); diff --git a/ext/napi/lib.rs b/ext/napi/lib.rs index 88b8c238dffa1f..e18c80a24bb3dc 100644 --- a/ext/napi/lib.rs +++ b/ext/napi/lib.rs @@ -34,18 +34,6 @@ use std::path::PathBuf; use std::rc::Rc; use std::thread_local; -#[derive(Debug, thiserror::Error)] -pub enum NApiError { - #[error("Invalid path")] - InvalidPath, - #[error(transparent)] - LibLoading(#[from] libloading::Error), - #[error("Unable to find register Node-API module at {}", .0.display())] - ModuleNotFound(PathBuf), - #[error(transparent)] - Permission(#[from] PermissionCheckError), -} - #[cfg(unix)] use libloading::os::unix::*; @@ -65,6 +53,22 @@ pub use value::napi_value; pub mod function; mod value; +#[derive(Debug, thiserror::Error, deno_core::JsError)] +pub enum NApiError { + #[class(TYPE)] + #[error("Invalid path")] + InvalidPath, + #[class(TYPE)] + #[error(transparent)] + LibLoading(#[from] libloading::Error), + #[class(TYPE)] + #[error("Unable to find register Node-API module at {}", .0.display())] + ModuleNotFound(PathBuf), + #[class(inherit)] + #[error(transparent)] + Permission(#[from] #[inherit] PermissionCheckError), +} + pub type napi_status = i32; pub type napi_env = *mut c_void; pub type napi_callback_info = *mut c_void; diff --git a/ext/net/io.rs b/ext/net/io.rs index 2907fa398b480a..9a0e4870d7c188 100644 --- a/ext/net/io.rs +++ b/ext/net/io.rs @@ -11,6 +11,7 @@ use deno_core::Resource; use socket2::SockRef; use std::borrow::Cow; use std::rc::Rc; +use deno_core::error::JsNativeError; use tokio::io::AsyncRead; use tokio::io::AsyncReadExt; use tokio::io::AsyncWrite; @@ -90,10 +91,12 @@ where } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum MapError { + #[class(inherit)] #[error("{0}")] - Io(std::io::Error), + Io(#[inherit] std::io::Error), + #[class(GENERIC)] #[error("Unable to get resources")] NoResources, } @@ -110,7 +113,7 @@ impl Resource for TcpStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsNativeError::from_err)) } fn close(self: Rc) { @@ -164,7 +167,7 @@ impl UnixStreamResource { #[allow(clippy::unused_async)] pub async fn shutdown( self: Rc, - ) -> Result<(), deno_core::error::AnyError> { + ) -> Result<(), JsNativeError> { unreachable!() } pub fn cancel_read_ops(&self) { @@ -181,7 +184,7 @@ impl Resource for UnixStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsNativeError::from_err)) } fn close(self: Rc) { diff --git a/ext/net/lib.rs b/ext/net/lib.rs index bf8f58aa272396..9cc58ad11161c3 100644 --- a/ext/net/lib.rs +++ b/ext/net/lib.rs @@ -9,7 +9,6 @@ pub mod raw; pub mod resolve_addr; mod tcp; -use deno_core::error::AnyError; use deno_core::OpState; use deno_permissions::PermissionCheckError; use deno_tls::rustls::RootCertStore; @@ -104,7 +103,7 @@ pub struct DefaultTlsOptions { } impl DefaultTlsOptions { - pub fn root_cert_store(&self) -> Result, AnyError> { + pub fn root_cert_store(&self) -> Result, deno_core::error::JsNativeError> { Ok(match &self.root_cert_store_provider { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, diff --git a/ext/net/ops.rs b/ext/net/ops.rs index 9a8b70f0f6d965..fab589bf692c60 100644 --- a/ext/net/ops.rs +++ b/ext/net/ops.rs @@ -65,60 +65,87 @@ impl From for IpAddr { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum NetError { + #[class("BadResource")] #[error("Listener has been closed")] ListenerClosed, + #[class("Busy")] #[error("Listener already in use")] ListenerBusy, + #[class("BadResource")] #[error("Socket has been closed")] SocketClosed, + #[class("NotConnected")] #[error("Socket has been closed")] SocketClosedNotConnected, + #[class("Busy")] #[error("Socket already in use")] SocketBusy, + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class("Busy")] #[error("Another accept task is ongoing")] AcceptTaskOngoing, + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(GENERIC)] #[error("No resolved address found")] NoResolvedAddress, + #[class(GENERIC)] #[error("{0}")] AddrParse(#[from] std::net::AddrParseError), + #[class(inherit)] #[error("{0}")] - Map(crate::io::MapError), + Map(#[inherit] crate::io::MapError), + #[class(inherit)] #[error("{0}")] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class("NotFound")] #[error("{0}")] DnsNotFound(ResolveError), + #[class("NotConnected")] #[error("{0}")] DnsNotConnected(ResolveError), + #[class("TimedOut")] #[error("{0}")] DnsTimedOut(ResolveError), + #[class(GENERIC)] #[error("{0}")] Dns(#[from] ResolveError), + #[class("NotSupported")] #[error("Provided record type is not supported")] UnsupportedRecordType, + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(GENERIC)] #[error("unexpected key type")] UnexpectedKeyType, + #[class(TYPE)] #[error("Invalid hostname: '{0}'")] - InvalidHostname(String), // TypeError + InvalidHostname(String), + #[class("Busy")] #[error("TCP stream is currently in use")] TcpStreamBusy, + #[class(GENERIC)] #[error("{0}")] Rustls(#[from] deno_tls::rustls::Error), + #[class(inherit)] #[error("{0}")] - Tls(#[from] deno_tls::TlsError), + Tls(#[from] #[inherit] deno_tls::TlsError), + #[class("InvalidData")] #[error("Error creating TLS certificate: Deno.listenTls requires a key")] - ListenTlsRequiresKey, // InvalidData + ListenTlsRequiresKey, + #[class(inherit)] #[error("{0}")] - RootCertStore(deno_core::anyhow::Error), + RootCertStore(#[inherit] deno_core::error::JsNativeError), + #[class(GENERIC)] #[error("{0}")] Reunite(tokio::net::tcp::ReuniteError), } @@ -701,10 +728,8 @@ pub fn op_set_nodelay_inner( rid: ResourceId, nodelay: bool, ) -> Result<(), NetError> { - let resource: Rc = state - .resource_table - .get::(rid) - .map_err(NetError::Resource)?; + let resource: Rc = + state.resource_table.get::(rid)?; resource.set_nodelay(nodelay).map_err(NetError::Map) } @@ -723,10 +748,8 @@ pub fn op_set_keepalive_inner( rid: ResourceId, keepalive: bool, ) -> Result<(), NetError> { - let resource: Rc = state - .resource_table - .get::(rid) - .map_err(NetError::Resource)?; + let resource: Rc = + state.resource_table.get::(rid)?; resource.set_keepalive(keepalive).map_err(NetError::Map) } diff --git a/ext/net/ops_tls.rs b/ext/net/ops_tls.rs index c7d65dd85ef7b8..9b967722f02a12 100644 --- a/ext/net/ops_tls.rs +++ b/ext/net/ops_tls.rs @@ -11,6 +11,7 @@ use crate::tcp::TcpListener; use crate::DefaultTlsOptions; use crate::NetPermissions; use crate::UnsafelyIgnoreCertificateErrors; +use deno_core::error::JsNativeError; use deno_core::futures::TryFutureExt; use deno_core::op2; use deno_core::v8; @@ -162,7 +163,7 @@ impl Resource for TlsStreamResource { } fn shutdown(self: Rc) -> AsyncResult<()> { - Box::pin(self.shutdown().map_err(Into::into)) + Box::pin(self.shutdown().map_err(JsNativeError::from_err)) } fn close(self: Rc) { diff --git a/ext/net/raw.rs b/ext/net/raw.rs index a2ebfb5acb5712..732ebb965dad48 100644 --- a/ext/net/raw.rs +++ b/ext/net/raw.rs @@ -1,9 +1,8 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::io::TcpStreamResource; use crate::ops_tls::TlsStreamResource; -use deno_core::error::bad_resource_id; -use deno_core::error::custom_error; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; +use deno_core::error::ResourceError; use deno_core::AsyncRefCell; use deno_core::CancelHandle; use deno_core::Resource; @@ -67,10 +66,11 @@ impl NetworkListenerResource { fn take( resource_table: &mut ResourceTable, listener_rid: ResourceId, - ) -> Result, AnyError> { + ) -> Result, JsNativeError> { if let Ok(resource_rc) = resource_table.take::(listener_rid) { - let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "Listener is currently in use"))?; + let resource = Rc::try_unwrap(resource_rc).map_err(|_| { + JsNativeError::new("Busy", "Listener is currently in use") + })?; return Ok(Some(resource.listener.into_inner().into())); } Ok(None) @@ -241,13 +241,13 @@ macro_rules! network_stream { /// Return a `NetworkStreamListener` if a resource exists for this `ResourceId` and it is currently /// not locked. - pub fn take_resource(resource_table: &mut ResourceTable, listener_rid: ResourceId) -> Result { + pub fn take_resource(resource_table: &mut ResourceTable, listener_rid: ResourceId) -> Result { $( if let Some(resource) = NetworkListenerResource::<$listener>::take(resource_table, listener_rid)? { return Ok(resource) } )* - Err(bad_resource_id()) + Err(JsNativeError::from_err(ResourceError::BadResourceId)) } } }; @@ -320,12 +320,36 @@ impl From for NetworkStreamAddress { } } +#[derive(Debug, thiserror::Error, deno_core::JsError)] +pub enum TakeNetworkStreamError { + #[class("Busy")] + #[error("TCP stream is currently in use")] + TcpBusy, + #[class("Busy")] + #[error("TLS stream is currently in use")] + TlsBusy, + #[cfg(unix)] + #[class("Busy")] + #[error("Unix socket is currently in use")] + UnixBusy, + #[class(GENERIC)] + #[error(transparent)] + ReuniteTcp(#[from] tokio::net::tcp::ReuniteError), + #[cfg(unix)] + #[class(GENERIC)] + #[error(transparent)] + ReuniteUnix(#[from] tokio::net::unix::ReuniteError), + #[class(inherit)] + #[error(transparent)] + Resource(#[inherit] deno_core::error::ResourceError), +} + /// In some cases it may be more efficient to extract the resource from the resource table and use it directly (for example, an HTTP server). /// This method will extract a stream from the resource table and return it, unwrapped. pub fn take_network_stream_resource( resource_table: &mut ResourceTable, stream_rid: ResourceId, -) -> Result { +) -> Result { // The stream we're attempting to unwrap may be in use somewhere else. If that's the case, we cannot proceed // with the process of unwrapping this connection, so we just return a bad resource error. // See also: https://github.com/denoland/deno/pull/16242 @@ -334,7 +358,7 @@ pub fn take_network_stream_resource( { // This TCP connection might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "TCP stream is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::TcpBusy)?; let (read_half, write_half) = resource.into_inner(); let tcp_stream = read_half.reunite(write_half)?; return Ok(NetworkStream::Tcp(tcp_stream)); @@ -344,7 +368,7 @@ pub fn take_network_stream_resource( { // This TLS connection might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "TLS stream is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::TlsBusy)?; let (read_half, write_half) = resource.into_inner(); let tls_stream = read_half.unsplit(write_half); return Ok(NetworkStream::Tls(tls_stream)); @@ -356,13 +380,15 @@ pub fn take_network_stream_resource( { // This UNIX socket might be used somewhere else. let resource = Rc::try_unwrap(resource_rc) - .map_err(|_| custom_error("Busy", "Unix socket is currently in use"))?; + .map_err(|_| TakeNetworkStreamError::UnixBusy)?; let (read_half, write_half) = resource.into_inner(); let unix_stream = read_half.reunite(write_half)?; return Ok(NetworkStream::Unix(unix_stream)); } - Err(bad_resource_id()) + Err(TakeNetworkStreamError::Resource( + ResourceError::BadResourceId, + )) } /// In some cases it may be more efficient to extract the resource from the resource table and use it directly (for example, an HTTP server). @@ -370,6 +396,6 @@ pub fn take_network_stream_resource( pub fn take_network_stream_listener_resource( resource_table: &mut ResourceTable, listener_rid: ResourceId, -) -> Result { +) -> Result { NetworkStreamListener::take_resource(resource_table, listener_rid) } diff --git a/ext/node/lib.rs b/ext/node/lib.rs index 9ca21e9941a162..f8e64e0d374525 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -8,7 +8,7 @@ use std::collections::HashSet; use std::path::Path; use std::path::PathBuf; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::url::Url; #[allow(unused_imports)] @@ -154,9 +154,9 @@ pub trait NodeRequireLoader { &self, permissions: &mut dyn NodePermissions, path: &'a Path, - ) -> Result, AnyError>; + ) -> Result, PermissionCheckError>; - fn load_text_file_lossy(&self, path: &Path) -> Result; + fn load_text_file_lossy(&self, path: &Path) -> Result; } pub static NODE_ENV_VAR_ALLOWLIST: Lazy> = Lazy::new(|| { diff --git a/ext/node/ops/blocklist.rs b/ext/node/ops/blocklist.rs index 6c64d68ecae653..373779e1ce8153 100644 --- a/ext/node/ops/blocklist.rs +++ b/ext/node/ops/blocklist.rs @@ -24,7 +24,8 @@ impl deno_core::GarbageCollected for BlockListResource {} #[derive(Serialize)] struct SocketAddressSerialization(String, String); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(GENERIC)] pub enum BlocklistError { #[error("{0}")] AddrParse(#[from] std::net::AddrParseError), diff --git a/ext/node/ops/buffer.rs b/ext/node/ops/buffer.rs index 01f878ec15bdd2..8037143a074dd6 100644 --- a/ext/node/ops/buffer.rs +++ b/ext/node/ops/buffer.rs @@ -1,7 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::anyhow::anyhow; -use deno_core::anyhow::Result; +use deno_core::error::JsNativeError; use deno_core::op2; #[op2(fast)] @@ -20,7 +19,7 @@ pub fn op_transcode( #[buffer] source: &[u8], #[string] from_encoding: &str, #[string] to_encoding: &str, -) -> Result> { +) -> Result, JsNativeError> { match (from_encoding, to_encoding) { ("utf8", "ascii") => Ok(utf8_to_ascii(source)), ("utf8", "latin1") => Ok(utf8_to_latin1(source)), @@ -29,7 +28,7 @@ pub fn op_transcode( ("latin1", "utf16le") | ("ascii", "utf16le") => { Ok(latin1_ascii_to_utf16le(source)) } - (from, to) => Err(anyhow!("Unable to transcode Buffer {from}->{to}")), + (from, to) => Err(JsNativeError::generic(format!("Unable to transcode Buffer {from}->{to}"))), } } @@ -42,18 +41,18 @@ fn latin1_ascii_to_utf16le(source: &[u8]) -> Vec { result } -fn utf16le_to_utf8(source: &[u8]) -> Result> { +fn utf16le_to_utf8(source: &[u8]) -> Result, JsNativeError> { let ucs2_vec: Vec = source .chunks(2) .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]])) .collect(); String::from_utf16(&ucs2_vec) .map(|utf8_string| utf8_string.into_bytes()) - .map_err(|e| anyhow!("Invalid UTF-16 sequence: {}", e)) + .map_err(|e|JsNativeError::generic(format!("Invalid UTF-16 sequence: {}", e))) } -fn utf8_to_utf16le(source: &[u8]) -> Result> { - let utf8_string = std::str::from_utf8(source)?; +fn utf8_to_utf16le(source: &[u8]) -> Result, JsNativeError> { + let utf8_string = std::str::from_utf8(source).map_err(JsNativeError::from_err)?; let ucs2_vec: Vec = utf8_string.encode_utf16().collect(); let bytes: Vec = ucs2_vec.iter().flat_map(|&x| x.to_le_bytes()).collect(); Ok(bytes) diff --git a/ext/node/ops/crypto/cipher.rs b/ext/node/ops/crypto/cipher.rs index ec45146b49aeaa..df114d8a0c18b1 100644 --- a/ext/node/ops/crypto/cipher.rs +++ b/ext/node/ops/crypto/cipher.rs @@ -47,14 +47,17 @@ pub struct DecipherContext { decipher: Rc>, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CipherContextError { + #[class(TYPE)] #[error("Cipher context is already in use")] ContextInUse, + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Cipher(#[from] CipherError), + Cipher(#[from] #[inherit] CipherError), } impl CipherContext { @@ -94,14 +97,17 @@ impl CipherContext { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum DecipherContextError { + #[class(TYPE)] #[error("Decipher context is already in use")] ContextInUse, + #[class(inherit)] #[error("{0}")] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Decipher(#[from] DecipherError), + Decipher(#[from] #[inherit] DecipherError), } impl DecipherContext { @@ -150,16 +156,21 @@ impl Resource for DecipherContext { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CipherError { + #[class(TYPE)] #[error("IV length must be 12 bytes")] InvalidIvLength, + #[class(RANGE)] #[error("Invalid key length")] InvalidKeyLength, + #[class(TYPE)] #[error("Invalid initialization vector")] InvalidInitializationVector, + #[class(TYPE)] #[error("Cannot pad the input data")] CannotPadInputData, + #[class(TYPE)] #[error("Unknown cipher {0}")] UnknownCipher(String), } @@ -360,22 +371,30 @@ impl Cipher { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum DecipherError { + #[class(TYPE)] #[error("IV length must be 12 bytes")] InvalidIvLength, + #[class(RANGE)] #[error("Invalid key length")] InvalidKeyLength, + #[class(TYPE)] #[error("Invalid initialization vector")] InvalidInitializationVector, + #[class(TYPE)] #[error("Cannot unpad the input data")] CannotUnpadInputData, + #[class(TYPE)] #[error("Failed to authenticate data")] DataAuthenticationFailed, + #[class(TYPE)] #[error("setAutoPadding(false) not supported for Aes128Gcm yet")] SetAutoPaddingFalseAes128GcmUnsupported, + #[class(TYPE)] #[error("setAutoPadding(false) not supported for Aes256Gcm yet")] SetAutoPaddingFalseAes256GcmUnsupported, + #[class(TYPE)] #[error("Unknown cipher {0}")] UnknownCipher(String), } diff --git a/ext/node/ops/crypto/digest.rs b/ext/node/ops/crypto/digest.rs index a7d8fb51f1b26c..1e966758813690 100644 --- a/ext/node/ops/crypto/digest.rs +++ b/ext/node/ops/crypto/digest.rs @@ -182,7 +182,8 @@ pub enum Hash { use Hash::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(GENERIC)] pub enum HashError { #[error("Output length mismatch for non-extendable algorithm")] OutputLengthMismatch, diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs index f164972d48afc6..bbe6869cae4da8 100644 --- a/ext/node/ops/crypto/keys.rs +++ b/ext/node/ops/crypto/keys.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::cell::RefCell; use base64::Engine; -use deno_core::error::type_error; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::serde_v8::BigInt as V8BigInt; use deno_core::unsync::spawn_blocking; @@ -364,55 +364,72 @@ impl<'a> TryFrom> for RsaPssParameters<'a> { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum X509PublicKeyError { + #[class(GENERIC)] #[error(transparent)] - X509(#[from] x509_parser::error::X509Error), + X509(#[from] X509Error), + #[class(GENERIC)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(GENERIC)] #[error(transparent)] Asn1(#[from] x509_parser::der_parser::asn1_rs::Error), + #[class(GENERIC)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(TYPE)] #[error("unsupported ec named curve")] UnsupportedEcNamedCurve, + #[class(TYPE)] #[error("missing ec parameters")] MissingEcParameters, + #[class(TYPE)] #[error("malformed DSS public key")] MalformedDssPublicKey, + #[class(TYPE)] #[error("unsupported x509 public key type")] UnsupportedX509KeyType, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum RsaJwkError { + #[class(GENERIC)] #[error(transparent)] Base64(#[from] base64::DecodeError), + #[class(GENERIC)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(TYPE)] #[error("missing RSA private component")] MissingRsaPrivateComponent, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum EcJwkError { + #[class(GENERIC)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(TYPE)] #[error("unsupported curve: {0}")] UnsupportedCurve(String), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum EdRawError { + #[class(GENERIC)] #[error(transparent)] Ed25519Signature(#[from] ed25519_dalek::SignatureError), + #[class(TYPE)] #[error("invalid Ed25519 key")] InvalidEd25519Key, + #[class(TYPE)] #[error("unsupported curve")] UnsupportedCurve, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum AsymmetricPrivateKeyError { #[error("invalid PEM private key: not valid utf8 starting at byte {0}")] InvalidPemPrivateKeyInvalidUtf8(usize), @@ -428,8 +445,9 @@ pub enum AsymmetricPrivateKeyError { InvalidSec1PrivateKey, #[error("unsupported PEM label: {0}")] UnsupportedPemLabel(String), + #[class(inherit)] #[error(transparent)] - RsaPssParamsParse(#[from] RsaPssParamsParseError), + RsaPssParamsParse(#[from] #[inherit] RsaPssParamsParseError), #[error("invalid encrypted PKCS#8 private key")] InvalidEncryptedPkcs8PrivateKey, #[error("invalid PKCS#8 private key")] @@ -462,58 +480,84 @@ pub enum AsymmetricPrivateKeyError { UnsupportedPrivateKeyOid, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum AsymmetricPublicKeyError { + #[class(TYPE)] #[error("invalid PEM private key: not valid utf8 starting at byte {0}")] InvalidPemPrivateKeyInvalidUtf8(usize), + #[class(TYPE)] #[error("invalid PEM public key")] InvalidPemPublicKey, + #[class(TYPE)] #[error("invalid PKCS#1 public key")] InvalidPkcs1PublicKey, + #[class(inherit)] #[error(transparent)] - AsymmetricPrivateKey(#[from] AsymmetricPrivateKeyError), + AsymmetricPrivateKey(#[from] #[inherit] AsymmetricPrivateKeyError), + #[class(TYPE)] #[error("invalid x509 certificate")] InvalidX509Certificate, + #[class(GENERIC)] #[error(transparent)] X509(#[from] x509_parser::nom::Err), + #[class(inherit)] #[error(transparent)] - X509PublicKey(#[from] X509PublicKeyError), + X509PublicKey(#[from] #[inherit] X509PublicKeyError), + #[class(TYPE)] #[error("unsupported PEM label: {0}")] UnsupportedPemLabel(String), + #[class(TYPE)] #[error("invalid SPKI public key")] InvalidSpkiPublicKey, + #[class(TYPE)] #[error("unsupported key type: {0}")] UnsupportedKeyType(String), + #[class(TYPE)] #[error("unsupported key format: {0}")] UnsupportedKeyFormat(String), + #[class(GENERIC)] #[error(transparent)] Spki(#[from] spki::Error), + #[class(GENERIC)] #[error(transparent)] Pkcs1(#[from] rsa::pkcs1::Error), + #[class(inherit)] #[error(transparent)] - RsaPssParamsParse(#[from] RsaPssParamsParseError), + RsaPssParamsParse(#[from] #[inherit] RsaPssParamsParseError), + #[class(TYPE)] #[error("malformed DSS public key")] MalformedDssPublicKey, + #[class(TYPE)] #[error("malformed or missing named curve in ec parameters")] MalformedOrMissingNamedCurveInEcParameters, + #[class(TYPE)] #[error("malformed or missing public key in ec spki")] MalformedOrMissingPublicKeyInEcSpki, + #[class(GENERIC)] #[error(transparent)] Ec(#[from] elliptic_curve::Error), + #[class(TYPE)] #[error("unsupported ec named curve")] UnsupportedEcNamedCurve, + #[class(TYPE)] #[error("malformed or missing public key in x25519 spki")] MalformedOrMissingPublicKeyInX25519Spki, + #[class(TYPE)] #[error("x25519 public key is too short")] X25519PublicKeyIsTooShort, + #[class(TYPE)] #[error("invalid Ed25519 public key")] InvalidEd25519PublicKey, + #[class(TYPE)] #[error("missing dh parameters")] MissingDhParameters, + #[class(TYPE)] #[error("malformed dh parameters")] MalformedDhParameters, + #[class(TYPE)] #[error("malformed or missing public key in dh spki")] MalformedOrMissingPublicKeyInDhSpki, + #[class(TYPE)] #[error("unsupported private key oid")] UnsupportedPrivateKeyOid, } @@ -1032,7 +1076,8 @@ impl KeyObjectHandle { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum RsaPssParamsParseError { #[error("malformed pss private key parameters")] MalformedPssPrivateKeyParameters, @@ -1107,7 +1152,8 @@ fn bytes_to_b64(bytes: &[u8]) -> String { BASE64_URL_SAFE_NO_PAD.encode(bytes) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum AsymmetricPublicKeyJwkError { #[error("key is not an asymmetric public key")] KeyIsNotAsymmetricPublicKey, @@ -1117,7 +1163,8 @@ pub enum AsymmetricPublicKeyJwkError { JwkExportNotImplementedForKeyType, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum AsymmetricPublicKeyDerError { #[error("key is not an asymmetric public key")] KeyIsNotAsymmetricPublicKey, @@ -1302,7 +1349,8 @@ impl AsymmetricPublicKey { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum AsymmetricPrivateKeyDerError { #[error("key is not an asymmetric private key")] KeyIsNotAsymmetricPrivateKey, @@ -1314,6 +1362,7 @@ pub enum AsymmetricPrivateKeyDerError { InvalidEcPrivateKey, #[error("exporting non-EC private key as SEC1 is not supported")] ExportingNonEcPrivateKeyAsSec1Unsupported, + #[class(TYPE)] #[error("exporting RSA-PSS private key as PKCS#8 is not supported yet")] ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported, #[error("invalid DSA private key")] @@ -1528,7 +1577,7 @@ pub fn op_node_create_secret_key( #[string] pub fn op_node_get_asymmetric_key_type( #[cppgc] handle: &KeyObjectHandle, -) -> Result<&'static str, deno_core::error::AnyError> { +) -> Result<&'static str, JsNativeError> { match handle { KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Rsa(_)) | KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Rsa(_)) => { @@ -1555,7 +1604,7 @@ pub fn op_node_get_asymmetric_key_type( KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Dh(_)) | KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Dh(_)) => Ok("dh"), KeyObjectHandle::Secret(_) => { - Err(type_error("symmetric key is not an asymmetric key")) + Err(JsNativeError::type_error("symmetric key is not an asymmetric key")) } } } @@ -1599,7 +1648,7 @@ pub enum AsymmetricKeyDetails { #[serde] pub fn op_node_get_asymmetric_key_details( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { match handle { KeyObjectHandle::AsymmetricPrivate(private_key) => match private_key { AsymmetricPrivateKey::Rsa(key) => { @@ -1708,7 +1757,7 @@ pub fn op_node_get_asymmetric_key_details( AsymmetricPublicKey::Dh(_) => Ok(AsymmetricKeyDetails::Dh), }, KeyObjectHandle::Secret(_) => { - Err(type_error("symmetric key is not an asymmetric key")) + Err(JsNativeError::type_error("symmetric key is not an asymmetric key")) } } } @@ -1717,11 +1766,11 @@ pub fn op_node_get_asymmetric_key_details( #[smi] pub fn op_node_get_symmetric_key_size( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { match handle { KeyObjectHandle::AsymmetricPrivate(_) | KeyObjectHandle::AsymmetricPublic(_) => { - Err(type_error("asymmetric key is not a symmetric key")) + Err(JsNativeError::type_error("asymmetric key is not a symmetric key")) } KeyObjectHandle::Secret(key) => Ok(key.len() * 8), } @@ -1825,7 +1874,8 @@ pub async fn op_node_generate_rsa_key_async( .unwrap() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] #[error("digest not allowed for RSA-PSS keys{}", .0.as_ref().map(|digest| format!(": {digest}")).unwrap_or_default())] pub struct GenerateRsaPssError(Option); @@ -1929,7 +1979,7 @@ pub async fn op_node_generate_rsa_pss_key_async( fn dsa_generate( modulus_length: usize, divisor_length: usize, -) -> Result { +) -> Result { let mut rng = rand::thread_rng(); use dsa::Components; use dsa::KeySize; @@ -1942,7 +1992,7 @@ fn dsa_generate( (2048, 256) => KeySize::DSA_2048_256, (3072, 256) => KeySize::DSA_3072_256, _ => { - return Err(type_error( + return Err(JsNativeError::type_error( "Invalid modulusLength+divisorLength combination", )) } @@ -1960,7 +2010,7 @@ fn dsa_generate( pub fn op_node_generate_dsa_key( #[smi] modulus_length: usize, #[smi] divisor_length: usize, -) -> Result { +) -> Result { dsa_generate(modulus_length, divisor_length) } @@ -1969,7 +2019,7 @@ pub fn op_node_generate_dsa_key( pub async fn op_node_generate_dsa_key_async( #[smi] modulus_length: usize, #[smi] divisor_length: usize, -) -> Result { +) -> Result { spawn_blocking(move || dsa_generate(modulus_length, divisor_length)) .await .unwrap() @@ -1977,7 +2027,7 @@ pub async fn op_node_generate_dsa_key_async( fn ec_generate( named_curve: &str, -) -> Result { +) -> Result { let mut rng = rand::thread_rng(); // TODO(@littledivy): Support public key point encoding. // Default is uncompressed. @@ -1995,7 +2045,7 @@ fn ec_generate( AsymmetricPrivateKey::Ec(EcPrivateKey::P384(key)) } _ => { - return Err(type_error(format!( + return Err(JsNativeError::type_error(format!( "unsupported named curve: {}", named_curve ))) @@ -2009,7 +2059,7 @@ fn ec_generate( #[cppgc] pub fn op_node_generate_ec_key( #[string] named_curve: &str, -) -> Result { +) -> Result { ec_generate(named_curve) } @@ -2017,7 +2067,7 @@ pub fn op_node_generate_ec_key( #[cppgc] pub async fn op_node_generate_ec_key_async( #[string] named_curve: String, -) -> Result { +) -> Result { spawn_blocking(move || ec_generate(&named_curve)) .await .unwrap() @@ -2073,7 +2123,7 @@ fn u32_slice_to_u8_slice(slice: &[u32]) -> &[u8] { fn dh_group_generate( group_name: &str, -) -> Result { +) -> Result { let (dh, prime, generator) = match group_name { "modp5" => ( dh::DiffieHellman::group::(), @@ -2105,7 +2155,7 @@ fn dh_group_generate( dh::Modp8192::MODULUS, dh::Modp8192::GENERATOR, ), - _ => return Err(type_error("Unsupported group name")), + _ => return Err(JsNativeError::type_error("Unsupported group name")), }; let params = DhParameter { prime: asn1::Int::new(u32_slice_to_u8_slice(prime)).unwrap(), @@ -2128,7 +2178,7 @@ fn dh_group_generate( #[cppgc] pub fn op_node_generate_dh_group_key( #[string] group_name: &str, -) -> Result { +) -> Result { dh_group_generate(group_name) } @@ -2136,7 +2186,7 @@ pub fn op_node_generate_dh_group_key( #[cppgc] pub async fn op_node_generate_dh_group_key_async( #[string] group_name: String, -) -> Result { +) -> Result { spawn_blocking(move || dh_group_generate(&group_name)) .await .unwrap() @@ -2210,10 +2260,10 @@ pub fn op_node_dh_keys_generate_and_export( #[buffer] pub fn op_node_export_secret_key( #[cppgc] handle: &KeyObjectHandle, -) -> Result, deno_core::error::AnyError> { +) -> Result, JsNativeError> { let key = handle .as_secret_key() - .ok_or_else(|| type_error("key is not a secret key"))?; + .ok_or_else(|| JsNativeError::type_error("key is not a secret key"))?; Ok(key.to_vec().into_boxed_slice()) } @@ -2221,10 +2271,10 @@ pub fn op_node_export_secret_key( #[string] pub fn op_node_export_secret_key_b64url( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { let key = handle .as_secret_key() - .ok_or_else(|| type_error("key is not a secret key"))?; + .ok_or_else(|| JsNativeError::type_error("key is not a secret key"))?; Ok(base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(key)) } @@ -2240,12 +2290,15 @@ pub fn op_node_export_public_key_jwk( public_key.export_jwk() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ExportPublicKeyPemError { + #[class(inherit)] #[error(transparent)] - AsymmetricPublicKeyDer(#[from] AsymmetricPublicKeyDerError), + AsymmetricPublicKeyDer(#[from] #[inherit] AsymmetricPublicKeyDerError), + #[class(TYPE)] #[error("very large data")] VeryLargeData, + #[class(GENERIC)] #[error(transparent)] Der(#[from] der::Error), } @@ -2290,12 +2343,15 @@ pub fn op_node_export_public_key_der( public_key.export_der(typ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ExportPrivateKeyPemError { + #[class(inherit)] #[error(transparent)] - AsymmetricPublicKeyDer(#[from] AsymmetricPrivateKeyDerError), + AsymmetricPublicKeyDer(#[from] #[inherit] AsymmetricPrivateKeyDerError), + #[class(TYPE)] #[error("very large data")] VeryLargeData, + #[class(GENERIC)] #[error(transparent)] Der(#[from] der::Error), } @@ -2355,9 +2411,9 @@ pub fn op_node_key_type(#[cppgc] handle: &KeyObjectHandle) -> &'static str { #[cppgc] pub fn op_node_derive_public_key_from_private_key( #[cppgc] handle: &KeyObjectHandle, -) -> Result { +) -> Result { let Some(private_key) = handle.as_private_key() else { - return Err(type_error("expected private key")); + return Err(JsNativeError::type_error("expected private key")); }; Ok(KeyObjectHandle::AsymmetricPublic( diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs index e90e820909cdad..7225886e474395 100644 --- a/ext/node/ops/crypto/mod.rs +++ b/ext/node/ops/crypto/mod.rs @@ -1,6 +1,5 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::generic_error; -use deno_core::error::type_error; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::unsync::spawn_blocking; use deno_core::JsBuffer; @@ -141,16 +140,21 @@ pub fn op_node_hash_clone( hasher.clone_inner(output_length.map(|l| l as usize)) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum PrivateEncryptDecryptError { + #[class(GENERIC)] #[error(transparent)] Pkcs8(#[from] pkcs8::Error), + #[class(GENERIC)] #[error(transparent)] Spki(#[from] spki::Error), + #[class(GENERIC)] #[error(transparent)] Utf8(#[from] std::str::Utf8Error), + #[class(GENERIC)] #[error(transparent)] Rsa(#[from] rsa::Error), + #[class(TYPE)] #[error("Unknown padding")] UnknownPadding, } @@ -272,7 +276,7 @@ pub fn op_node_cipheriv_final( let context = state .resource_table .take::(rid) - .map_err(cipher::CipherContextError::Resource)?; + ?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::CipherContextError::ContextInUse)?; context.r#final(auto_pad, input, output).map_err(Into::into) @@ -287,7 +291,7 @@ pub fn op_node_cipheriv_take( let context = state .resource_table .take::(rid) - .map_err(cipher::CipherContextError::Resource)?; + ?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::CipherContextError::ContextInUse)?; Ok(context.take_tag()) @@ -342,7 +346,7 @@ pub fn op_node_decipheriv_take( let context = state .resource_table .take::(rid) - .map_err(cipher::DecipherContextError::Resource)?; + ?; Rc::try_unwrap(context) .map_err(|_| cipher::DecipherContextError::ContextInUse)?; Ok(()) @@ -360,7 +364,7 @@ pub fn op_node_decipheriv_final( let context = state .resource_table .take::(rid) - .map_err(cipher::DecipherContextError::Resource)?; + ?; let context = Rc::try_unwrap(context) .map_err(|_| cipher::DecipherContextError::ContextInUse)?; context @@ -403,12 +407,14 @@ pub fn op_node_verify( ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum Pbkdf2Error { + #[class(TYPE)] #[error("unsupported digest: {0}")] UnsupportedDigest(String), + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join(#[from] #[inherit] tokio::task::JoinError), } fn pbkdf2_sync( @@ -475,16 +481,20 @@ pub async fn op_node_fill_random_async(#[smi] len: i32) -> ToJsBuffer { .unwrap() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum HkdfError { + #[class(TYPE)] #[error("expected secret key")] ExpectedSecretKey, + #[class(TYPE)] #[error("HKDF-Expand failed")] HkdfExpandFailed, + #[class(TYPE)] #[error("Unsupported digest: {0}")] UnsupportedDigest(String), + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join(#[from] #[inherit] tokio::task::JoinError), } fn hkdf_sync( @@ -576,7 +586,7 @@ fn scrypt( parallelization: u32, _maxmem: u32, output_buffer: &mut [u8], -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsNativeError> { // Construct Params let params = scrypt::Params::new( cost as u8, @@ -592,7 +602,7 @@ fn scrypt( Ok(()) } else { // TODO(lev): key derivation failed, so what? - Err(generic_error("scrypt key derivation failed")) + Err(JsNativeError::generic("scrypt key derivation failed")) } } @@ -607,7 +617,7 @@ pub fn op_node_scrypt_sync( #[smi] parallelization: u32, #[smi] maxmem: u32, #[anybuffer] output_buffer: &mut [u8], -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsNativeError> { scrypt( password, salt, @@ -620,12 +630,14 @@ pub fn op_node_scrypt_sync( ) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ScryptAsyncError { + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join(#[from] #[inherit] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } #[op2(async)] @@ -658,12 +670,15 @@ pub async fn op_node_scrypt_async( .await? } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum EcdhEncodePubKey { + #[class(TYPE)] #[error("Invalid public key")] InvalidPublicKey, + #[class(TYPE)] #[error("Unsupported curve")] UnsupportedCurve, + #[class(GENERIC)] #[error(transparent)] Sec1(#[from] sec1::Error), } @@ -743,7 +758,7 @@ pub fn op_node_ecdh_generate_keys( #[buffer] pubbuf: &mut [u8], #[buffer] privbuf: &mut [u8], #[string] format: &str, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), JsNativeError> { let mut rng = rand::thread_rng(); let compress = format == "compressed"; match curve { @@ -780,7 +795,7 @@ pub fn op_node_ecdh_generate_keys( Ok(()) } - &_ => Err(type_error(format!("Unsupported curve: {}", curve))), + &_ => Err(JsNativeError::type_error(format!("Unsupported curve: {}", curve))), } } @@ -913,7 +928,8 @@ pub async fn op_node_gen_prime_async( spawn_blocking(move || gen_prime(size)).await } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum DiffieHellmanError { #[error("Expected private key")] ExpectedPrivateKey, @@ -1005,7 +1021,8 @@ pub fn op_node_diffie_hellman( Ok(res) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum SignEd25519Error { #[error("Expected private key")] ExpectedPrivateKey, @@ -1037,7 +1054,8 @@ pub fn op_node_sign_ed25519( Ok(()) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum VerifyEd25519Error { #[error("Expected public key")] ExpectedPublicKey, diff --git a/ext/node/ops/crypto/sign.rs b/ext/node/ops/crypto/sign.rs index 30094c07654197..ee7644c222f31a 100644 --- a/ext/node/ops/crypto/sign.rs +++ b/ext/node/ops/crypto/sign.rs @@ -39,7 +39,8 @@ where } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(TYPE)] pub enum KeyObjectHandlePrehashedSignAndVerifyError { #[error("invalid DSA signature encoding")] InvalidDsaSignatureEncoding, @@ -47,10 +48,12 @@ pub enum KeyObjectHandlePrehashedSignAndVerifyError { KeyIsNotPrivate, #[error("digest not allowed for RSA signature: {0}")] DigestNotAllowedForRsaSignature(String), + #[class(GENERIC)] #[error("failed to sign digest with RSA")] FailedToSignDigestWithRsa, #[error("digest not allowed for RSA-PSS signature: {0}")] DigestNotAllowedForRsaPssSignature(String), + #[class(GENERIC)] #[error("failed to sign digest with RSA-PSS")] FailedToSignDigestWithRsaPss, #[error("failed to sign digest with DSA")] diff --git a/ext/node/ops/crypto/x509.rs b/ext/node/ops/crypto/x509.rs index ab8e52f703dc18..8ffc380f08ec05 100644 --- a/ext/node/ops/crypto/x509.rs +++ b/ext/node/ops/crypto/x509.rs @@ -61,11 +61,13 @@ impl<'a> Deref for CertificateView<'a> { } } +deno_core::js_error_wrapper!(X509Error, JsX509Error, "Error"); + #[op2] #[cppgc] pub fn op_node_x509_parse( #[buffer] buf: &[u8], -) -> Result { +) -> Result { let source = match pem::parse_x509_pem(buf) { Ok((_, pem)) => CertificateSources::Pem(pem), Err(_) => CertificateSources::Der(buf.to_vec().into_boxed_slice()), @@ -156,18 +158,18 @@ pub fn op_node_x509_fingerprint512( #[string] pub fn op_node_x509_get_issuer( #[cppgc] cert: &Certificate, -) -> Result { +) -> Result { let cert = cert.inner.get().deref(); - x509name_to_string(cert.issuer(), oid_registry()) + x509name_to_string(cert.issuer(), oid_registry()).map_err(Into::into) } #[op2] #[string] pub fn op_node_x509_get_subject( #[cppgc] cert: &Certificate, -) -> Result { +) -> Result { let cert = cert.inner.get().deref(); - x509name_to_string(cert.subject(), oid_registry()) + x509name_to_string(cert.subject(), oid_registry()).map_err(Into::into) } #[op2] diff --git a/ext/node/ops/fs.rs b/ext/node/ops/fs.rs index 9c0e4e1ccff212..d0e54a6195244f 100644 --- a/ext/node/ops/fs.rs +++ b/ext/node/ops/fs.rs @@ -10,27 +10,32 @@ use serde::Serialize; use crate::NodePermissions; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum FsError { + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), #[cfg(windows)] + #[class(GENERIC)] #[error("Path has no root.")] PathHasNoRoot, #[cfg(not(any(unix, windows)))] + #[class(GENERIC)] #[error("Unsupported platform.")] UnsupportedPlatform, + #[class(inherit)] #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs(#[from] #[inherit] deno_io::fs::FsError), } #[op2(fast)] pub fn op_node_fs_exists_sync

( state: &mut OpState, #[string] path: String, -) -> Result +) -> Result where P: NodePermissions + 'static, { diff --git a/ext/node/ops/http.rs b/ext/node/ops/http.rs index 69571078fe26e1..604892c60fa5f4 100644 --- a/ext/node/ops/http.rs +++ b/ext/node/ops/http.rs @@ -46,6 +46,7 @@ use http_body_util::BodyExt; use hyper::body::Frame; use hyper_util::rt::TokioIo; use std::cmp::min; +use deno_core::error::JsNativeError; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; @@ -455,7 +456,7 @@ impl Resource for NodeHttpFetchResponseResource { Some(_) => match reader.as_mut().next().await.unwrap() { Ok(chunk) => assert!(chunk.is_empty()), Err(err) => { - break Err(deno_core::error::type_error(err.to_string())) + break Err(JsNativeError::type_error(err.to_string())) } }, None => break Ok(BufView::empty()), @@ -481,7 +482,7 @@ impl Resource for NodeHttpFetchResponseResource { pub struct NodeHttpResourceToBodyAdapter( Rc, Option< - Pin>>>, + Pin>>>, >, ); @@ -498,7 +499,7 @@ unsafe impl Send for NodeHttpResourceToBodyAdapter {} unsafe impl Sync for NodeHttpResourceToBodyAdapter {} impl Stream for NodeHttpResourceToBodyAdapter { - type Item = Result; + type Item = Result; fn poll_next( self: Pin<&mut Self>, @@ -528,7 +529,7 @@ impl Stream for NodeHttpResourceToBodyAdapter { impl hyper::body::Body for NodeHttpResourceToBodyAdapter { type Data = Bytes; - type Error = deno_core::anyhow::Error; + type Error = JsNativeError; fn poll_frame( self: Pin<&mut Self>, diff --git a/ext/node/ops/http2.rs b/ext/node/ops/http2.rs index 53dada9f4119c9..4022aa18a719b9 100644 --- a/ext/node/ops/http2.rs +++ b/ext/node/ops/http2.rs @@ -15,6 +15,7 @@ use deno_core::BufView; use deno_core::ByteString; use deno_core::CancelFuture; use deno_core::CancelHandle; +use deno_core::error::ResourceError; use deno_core::JsBuffer; use deno_core::OpState; use deno_core::RcRef; @@ -109,14 +110,20 @@ impl Resource for Http2ServerSendResponse { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum Http2Error { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] ResourceError), + #[class(inherit)] #[error(transparent)] - UrlParse(#[from] url::ParseError), + UrlParse(#[from] #[inherit] url::ParseError), + #[class(GENERIC)] #[error(transparent)] H2(#[from] h2::Error), + #[class(inherit)] + #[error(transparent)] + TakeNetworkStream(#[from] #[inherit] deno_net::raw::TakeNetworkStreamError), } #[op2(async)] @@ -130,7 +137,7 @@ pub async fn op_http2_connect( let network_stream = { let mut state = state.borrow_mut(); take_network_stream_resource(&mut state.resource_table, rid) - .map_err(Http2Error::Resource)? + ? }; let url = Url::parse(&url)?; @@ -157,7 +164,7 @@ pub async fn op_http2_listen( ) -> Result { let stream = take_network_stream_resource(&mut state.borrow_mut().resource_table, rid) - .map_err(Http2Error::Resource)?; + ?; let conn = h2::server::Builder::new().handshake(stream).await?; Ok( @@ -183,7 +190,7 @@ pub async fn op_http2_accept( .borrow() .resource_table .get::(rid) - .map_err(Http2Error::Resource)?; + ?; let mut conn = RcRef::map(&resource, |r| &r.conn).borrow_mut().await; if let Some(res) = conn.accept().await { let (req, resp) = res?; @@ -250,7 +257,7 @@ pub async fn op_http2_send_response( .borrow() .resource_table .get::(rid) - .map_err(Http2Error::Resource)?; + ?; let mut send_response = RcRef::map(resource, |r| &r.send_response) .borrow_mut() .await; @@ -280,7 +287,7 @@ pub async fn op_http2_poll_client_connection( .borrow() .resource_table .get::(rid) - .map_err(Http2Error::Resource)?; + ?; let cancel_handle = RcRef::map(resource.clone(), |this| &this.cancel_handle); let mut conn = RcRef::map(resource, |this| &this.conn).borrow_mut().await; @@ -311,7 +318,7 @@ pub async fn op_http2_client_request( .borrow() .resource_table .get::(client_rid) - .map_err(Http2Error::Resource)?; + ?; let url = resource.url.clone(); @@ -347,7 +354,7 @@ pub async fn op_http2_client_request( state .resource_table .get::(client_rid) - .map_err(Http2Error::Resource)? + ? }; let mut client = RcRef::map(&resource, |r| &r.client).borrow_mut().await; poll_fn(|cx| client.poll_ready(cx)).await?; @@ -371,7 +378,7 @@ pub async fn op_http2_client_send_data( .borrow() .resource_table .get::(stream_rid) - .map_err(Http2Error::Resource)?; + ?; let mut stream = RcRef::map(&resource, |r| &r.stream).borrow_mut().await; stream.send_data(data.to_vec().into(), end_of_stream)?; @@ -383,7 +390,7 @@ pub async fn op_http2_client_reset_stream( state: Rc>, #[smi] stream_rid: ResourceId, #[smi] code: u32, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), ResourceError> { let resource = state .borrow() .resource_table @@ -403,7 +410,7 @@ pub async fn op_http2_client_send_trailers( .borrow() .resource_table .get::(stream_rid) - .map_err(Http2Error::Resource)?; + ?; let mut stream = RcRef::map(&resource, |r| &r.stream).borrow_mut().await; let mut trailers_map = http::HeaderMap::new(); @@ -436,7 +443,7 @@ pub async fn op_http2_client_get_response( .borrow() .resource_table .get::(stream_rid) - .map_err(Http2Error::Resource)?; + ?; let mut response_future = RcRef::map(&resource, |r| &r.response).borrow_mut().await; @@ -507,7 +514,7 @@ pub async fn op_http2_client_get_response_body_chunk( .borrow() .resource_table .get::(body_rid) - .map_err(Http2Error::Resource)?; + ?; let mut body = RcRef::map(&resource, |r| &r.body).borrow_mut().await; loop { @@ -550,7 +557,7 @@ pub async fn op_http2_client_get_response_body_chunk( pub async fn op_http2_client_get_response_trailers( state: Rc>, #[smi] body_rid: ResourceId, -) -> Result>, deno_core::error::AnyError> { +) -> Result>, ResourceError> { let resource = state .borrow() .resource_table diff --git a/ext/node/ops/idna.rs b/ext/node/ops/idna.rs index a3d85e77c2b6b5..0a38625fc7978f 100644 --- a/ext/node/ops/idna.rs +++ b/ext/node/ops/idna.rs @@ -9,16 +9,21 @@ use std::borrow::Cow; const PUNY_PREFIX: &str = "xn--"; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum IdnaError { + #[class(RANGE)] #[error("Invalid input")] InvalidInput, + #[class(GENERIC)] #[error("Input would take more than 63 characters to encode")] InputTooLong, + #[class(RANGE)] #[error("Illegal input >= 0x80 (not a basic code point)")] IllegalInput, } +deno_core::js_error_wrapper!(idna::Errors, JsIdnaErrors, "Error"); + /// map a domain by mapping each label with the given function fn map_domain( domain: &str, @@ -113,8 +118,8 @@ pub fn op_node_idna_punycode_to_unicode( #[string] pub fn op_node_idna_domain_to_ascii( #[string] domain: String, -) -> Result { - idna::domain_to_ascii(&domain) +) -> Result { + idna::domain_to_ascii(&domain).map_err(Into::into) } /// Converts a domain to Unicode as per the IDNA spec diff --git a/ext/node/ops/inspector.rs b/ext/node/ops/inspector.rs index 34a7e004c1d946..d6034d4a9acc91 100644 --- a/ext/node/ops/inspector.rs +++ b/ext/node/ops/inspector.rs @@ -1,8 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::NodePermissions; -use deno_core::anyhow::Error; -use deno_core::error::generic_error; +use deno_core::error::JsNativeError; use deno_core::futures::channel::mpsc; use deno_core::op2; use deno_core::v8; @@ -25,7 +24,7 @@ pub fn op_inspector_open

( _state: &mut OpState, _port: Option, #[string] _host: Option, -) -> Result<(), Error> +) -> Result<(), JsNativeError> where P: NodePermissions + 'static, { @@ -85,6 +84,16 @@ struct JSInspectorSession { impl GarbageCollected for JSInspectorSession {} +#[derive(Debug, thiserror::Error, deno_core::JsError)] +pub enum InspectorConnectError { + #[class(inherit)] + #[error(transparent)] + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(GENERIC)] + #[error("connectToMainThread not supported")] + ConnectToMainThreadUnsupported, +} + #[op2] #[cppgc] pub fn op_inspector_connect<'s, P>( @@ -93,7 +102,7 @@ pub fn op_inspector_connect<'s, P>( state: &mut OpState, connect_to_main_thread: bool, callback: v8::Local<'s, v8::Function>, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -102,7 +111,7 @@ where .check_sys("inspector", "inspector.Session.connect")?; if connect_to_main_thread { - return Err(generic_error("connectToMainThread not supported")); + return Err(InspectorConnectError::ConnectToMainThreadUnsupported); } let context = scope.get_current_context(); diff --git a/ext/node/ops/ipc.rs b/ext/node/ops/ipc.rs index 672cf0d70709ef..e372787caa9fe9 100644 --- a/ext/node/ops/ipc.rs +++ b/ext/node/ops/ipc.rs @@ -25,6 +25,7 @@ mod impl_ { use deno_core::AsyncRefCell; use deno_core::CancelFuture; use deno_core::CancelHandle; + use deno_core::error::JsNativeError; use deno_core::ExternalOpsTracker; use deno_core::OpState; use deno_core::RcRef; @@ -80,7 +81,7 @@ mod impl_ { } else if value.is_string_object() { let str = deno_core::serde_v8::to_utf8( value.to_string(scope).ok_or_else(|| { - S::Error::custom(deno_core::error::generic_error( + S::Error::custom(deno_core::error::JsNativeError::generic( "toString on string object failed", )) })?, @@ -153,7 +154,7 @@ mod impl_ { map.end() } else { // TODO(nathanwhit): better error message - Err(S::Error::custom(deno_core::error::type_error(format!( + Err(S::Error::custom(JsNativeError::type_error(format!( "Unsupported type: {}", value.type_repr() )))) @@ -178,16 +179,20 @@ mod impl_ { )) } - #[derive(Debug, thiserror::Error)] + #[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum IpcError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - IpcJsonStream(#[from] IpcJsonStreamError), + IpcJsonStream(#[from] #[inherit] IpcJsonStreamError), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class(inherit)] #[error("failed to serialize json value: {0}")] - SerdeJson(serde_json::Error), + SerdeJson(#[inherit] serde_json::Error), } #[op2(async)] @@ -212,7 +217,7 @@ mod impl_ { .borrow() .resource_table .get::(rid) - .map_err(IpcError::Resource)?; + ?; let old = stream .queued_bytes .fetch_add(serialized.len(), std::sync::atomic::Ordering::Relaxed); @@ -257,7 +262,7 @@ mod impl_ { .borrow() .resource_table .get::(rid) - .map_err(IpcError::Resource)?; + ?; let cancel = stream.cancel.clone(); let mut stream = RcRef::map(stream, |r| &r.read_half).borrow_mut().await; @@ -468,10 +473,12 @@ mod impl_ { } } - #[derive(Debug, thiserror::Error)] + #[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum IpcJsonStreamError { + #[class(inherit)] #[error("{0}")] - Io(#[source] std::io::Error), + Io(#[source] #[inherit] std::io::Error), + #[class(GENERIC)] #[error("{0}")] SimdJson(#[source] simd_json::Error), } diff --git a/ext/node/ops/os/mod.rs b/ext/node/ops/os/mod.rs index d291277ad4d896..f97e3b7e5f6b5d 100644 --- a/ext/node/ops/os/mod.rs +++ b/ext/node/ops/os/mod.rs @@ -5,20 +5,25 @@ use std::mem::MaybeUninit; use crate::NodePermissions; use deno_core::op2; use deno_core::OpState; +use deno_permissions::PermissionCheckError; mod cpus; pub mod priority; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum OsError { + #[class(inherit)] #[error(transparent)] - Priority(priority::PriorityError), + Priority(#[inherit] priority::PriorityError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(TYPE)] #[error("Failed to get cpu info")] FailedToGetCpuInfo, + #[class(inherit)] #[error("Failed to get user info")] - FailedToGetUserInfo(#[source] std::io::Error), + FailedToGetUserInfo(#[source] #[inherit] std::io::Error), } #[op2(fast)] @@ -215,7 +220,7 @@ where #[op2(fast)] pub fn op_geteuid

( state: &mut OpState, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -236,7 +241,7 @@ where #[op2(fast)] pub fn op_getegid

( state: &mut OpState, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -272,7 +277,7 @@ where #[string] pub fn op_homedir

( state: &mut OpState, -) -> Result, deno_core::error::AnyError> +) -> Result, PermissionCheckError> where P: NodePermissions + 'static, { diff --git a/ext/node/ops/os/priority.rs b/ext/node/ops/os/priority.rs index 9a1ebcca705c6a..9c89dfbcb69e73 100644 --- a/ext/node/ops/os/priority.rs +++ b/ext/node/ops/os/priority.rs @@ -2,11 +2,13 @@ pub use impl_::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum PriorityError { + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), #[cfg(windows)] + #[class(TYPE)] #[error("Invalid priority")] InvalidPriority, } diff --git a/ext/node/ops/process.rs b/ext/node/ops/process.rs index 282567226ea6cc..cd6ce70803ec49 100644 --- a/ext/node/ops/process.rs +++ b/ext/node/ops/process.rs @@ -50,7 +50,7 @@ pub fn op_node_process_kill( state: &mut OpState, #[smi] pid: i32, #[smi] sig: i32, -) -> Result { +) -> Result { state .borrow_mut::() .check_run_all("process.kill")?; diff --git a/ext/node/ops/require.rs b/ext/node/ops/require.rs index 30db8b629325d8..44d25e157fa293 100644 --- a/ext/node/ops/require.rs +++ b/ext/node/ops/require.rs @@ -18,7 +18,8 @@ use std::cell::RefCell; use std::path::Path; use std::path::PathBuf; use std::rc::Rc; - +use deno_core::error::JsNativeError; +use deno_permissions::PermissionCheckError; use crate::NodePermissions; use crate::NodeRequireLoaderRc; use crate::NodeResolverRc; @@ -29,7 +30,7 @@ use crate::PackageJsonResolverRc; fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, -) -> Result, deno_core::error::AnyError> +) -> Result, PermissionCheckError> where P: NodePermissions + 'static, { @@ -38,34 +39,45 @@ where loader.ensure_read_permission(permissions, file_path) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum RequireError { + #[class(inherit)] #[error(transparent)] - UrlParse(#[from] url::ParseError), + UrlParse(#[from] #[inherit] url::ParseError), + #[class(inherit)] #[error(transparent)] - Permission(deno_core::error::AnyError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(GENERIC)] #[error(transparent)] PackageExportsResolve( #[from] node_resolver::errors::PackageExportsResolveError, ), + #[class(GENERIC)] #[error(transparent)] PackageJsonLoad(#[from] node_resolver::errors::PackageJsonLoadError), + #[class(GENERIC)] #[error(transparent)] ClosestPkgJson(#[from] node_resolver::errors::ClosestPkgJsonError), + #[class(GENERIC)] #[error(transparent)] PackageImportsResolve( #[from] node_resolver::errors::PackageImportsResolveError, ), + #[class(GENERIC)] #[error(transparent)] FilePathConversion(#[from] deno_path_util::UrlToFilePathError), + #[class(GENERIC)] #[error(transparent)] UrlConversion(#[from] deno_path_util::PathToUrlError), + #[class(inherit)] #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs(#[from] #[inherit] deno_io::fs::FsError), + #[class(inherit)] #[error(transparent)] - ReadModule(deno_core::error::AnyError), + ReadModule(#[from] #[inherit] JsNativeError), + #[class(inherit)] #[error("Unable to get CWD: {0}")] - UnableToGetCwd(deno_io::fs::FsError), + UnableToGetCwd(#[inherit] deno_io::fs::FsError), } #[op2] @@ -293,7 +305,7 @@ pub fn op_require_path_is_absolute(#[string] p: String) -> bool { pub fn op_require_stat

( state: &mut OpState, #[string] path: String, -) -> Result +) -> Result where P: NodePermissions + 'static, { @@ -322,7 +334,7 @@ where { let path = PathBuf::from(request); let path = ensure_read_permission::

(state, &path) - .map_err(RequireError::Permission)?; + ?; let fs = state.borrow::(); let canonicalized_path = deno_path_util::strip_unc_prefix(fs.realpath_sync(&path)?); @@ -349,12 +361,12 @@ pub fn op_require_path_resolve(#[serde] parts: Vec) -> String { #[string] pub fn op_require_path_dirname( #[string] request: String, -) -> Result { +) -> Result { let p = PathBuf::from(request); if let Some(parent) = p.parent() { Ok(parent.to_string_lossy().into_owned()) } else { - Err(deno_core::error::generic_error( + Err(JsNativeError::generic( "Path doesn't have a parent", )) } @@ -364,12 +376,12 @@ pub fn op_require_path_dirname( #[string] pub fn op_require_path_basename( #[string] request: String, -) -> Result { +) -> Result { let p = PathBuf::from(request); if let Some(path) = p.file_name() { Ok(path.to_string_lossy().into_owned()) } else { - Err(deno_core::error::generic_error( + Err(JsNativeError::generic( "Path doesn't have a file name", )) } @@ -382,7 +394,7 @@ pub fn op_require_try_self_parent_path

( has_parent: bool, #[string] maybe_parent_filename: Option, #[string] maybe_parent_id: Option, -) -> Result, deno_core::error::AnyError> +) -> Result, PermissionCheckError> where P: NodePermissions + 'static, { @@ -482,7 +494,7 @@ where let file_path = PathBuf::from(file_path); // todo(dsherret): there's multiple borrows to NodeRequireLoaderRc here let file_path = ensure_read_permission::

(state, &file_path) - .map_err(RequireError::Permission)?; + ?; let loader = state.borrow::(); loader .load_text_file_lossy(&file_path) @@ -564,19 +576,21 @@ where })) } +deno_core::js_error_wrapper!(node_resolver::errors::ClosestPkgJsonError, JsClosestPkgJsonError, "Error"); + #[op2] #[serde] pub fn op_require_read_closest_package_json

( state: &mut OpState, #[string] filename: String, -) -> Result, node_resolver::errors::ClosestPkgJsonError> +) -> Result, JsClosestPkgJsonError> where P: NodePermissions + 'static, { let filename = PathBuf::from(filename); // permissions: allow reading the closest package.json files let pkg_json_resolver = state.borrow::(); - pkg_json_resolver.get_closest_package_json_from_path(&filename) + pkg_json_resolver.get_closest_package_json_from_path(&filename).map_err(Into::into) } #[op2] @@ -612,7 +626,7 @@ where { let referrer_path = PathBuf::from(&referrer_filename); let referrer_path = ensure_read_permission::

(state, &referrer_path) - .map_err(RequireError::Permission)?; + ?; let pkg_json_resolver = state.borrow::(); let Some(pkg) = pkg_json_resolver.get_closest_package_json_from_path(&referrer_path)? diff --git a/ext/node/ops/util.rs b/ext/node/ops/util.rs index 1c177ac0431d55..b4580716456c80 100644 --- a/ext/node/ops/util.rs +++ b/ext/node/ops/util.rs @@ -21,7 +21,7 @@ enum HandleType { pub fn op_node_guess_handle_type( state: &mut OpState, rid: u32, -) -> Result { +) -> Result { let handle = state.resource_table.get_handle(rid)?; let handle_type = match handle { diff --git a/ext/node/ops/v8.rs b/ext/node/ops/v8.rs index 61f67f11f73a27..966bfc8c8d8586 100644 --- a/ext/node/ops/v8.rs +++ b/ext/node/ops/v8.rs @@ -6,6 +6,7 @@ use deno_core::FastString; use deno_core::GarbageCollected; use deno_core::ToJsBuffer; use std::ptr::NonNull; +use deno_core::error::JsNativeError; use v8::ValueDeserializerHelper; use v8::ValueSerializerHelper; @@ -268,11 +269,11 @@ pub fn op_v8_new_deserializer( scope: &mut v8::HandleScope, obj: v8::Local, buffer: v8::Local, -) -> Result, deno_core::error::AnyError> { +) -> Result, JsNativeError> { let offset = buffer.byte_offset(); let len = buffer.byte_length(); let backing_store = buffer.get_backing_store().ok_or_else(|| { - deno_core::error::generic_error( + JsNativeError::generic( "deserialization buffer has no backing store", ) })?; @@ -316,10 +317,10 @@ pub fn op_v8_transfer_array_buffer_de( #[op2(fast)] pub fn op_v8_read_double( #[cppgc] deser: &Deserializer, -) -> Result { +) -> Result { let mut double = 0f64; if !deser.inner.read_double(&mut double) { - return Err(deno_core::error::type_error("ReadDouble() failed")); + return Err(JsNativeError::type_error("ReadDouble() failed")); } Ok(double) } @@ -354,10 +355,10 @@ pub fn op_v8_read_raw_bytes( #[op2(fast)] pub fn op_v8_read_uint32( #[cppgc] deser: &Deserializer, -) -> Result { +) -> Result { let mut value = 0; if !deser.inner.read_uint32(&mut value) { - return Err(deno_core::error::type_error("ReadUint32() failed")); + return Err(JsNativeError::type_error("ReadUint32() failed")); } Ok(value) @@ -367,10 +368,10 @@ pub fn op_v8_read_uint32( #[serde] pub fn op_v8_read_uint64( #[cppgc] deser: &Deserializer, -) -> Result<(u32, u32), deno_core::error::AnyError> { +) -> Result<(u32, u32), JsNativeError> { let mut val = 0; if !deser.inner.read_uint64(&mut val) { - return Err(deno_core::error::type_error("ReadUint64() failed")); + return Err(JsNativeError::type_error("ReadUint64() failed")); } Ok(((val >> 32) as u32, val as u32)) diff --git a/ext/node/ops/vm_internal.rs b/ext/node/ops/vm_internal.rs index 815f570eada65e..a611c7034e3d1c 100644 --- a/ext/node/ops/vm_internal.rs +++ b/ext/node/ops/vm_internal.rs @@ -1,8 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::create_host_defined_options; -use deno_core::error::type_error; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::v8; use deno_core::v8::MapFnTo; @@ -19,7 +18,7 @@ impl ContextifyScript { pub fn new( scope: &mut v8::HandleScope, source_str: v8::Local, - ) -> Result { + ) -> Result { let resource_name = v8::undefined(scope); let host_defined_options = create_host_defined_options(scope); let origin = v8::ScriptOrigin::new( @@ -44,7 +43,7 @@ impl ContextifyScript { v8::script_compiler::CompileOptions::NoCompileOptions, v8::script_compiler::NoCacheReason::NoReason, ) - .ok_or_else(|| type_error("Failed to compile script"))?; + .ok_or_else(|| JsNativeError::type_error("Failed to compile script"))?; let script = v8::Global::new(scope, unbound_script); Ok(Self { script }) } diff --git a/ext/node/ops/worker_threads.rs b/ext/node/ops/worker_threads.rs index d2e57588265360..4136bc56e70af4 100644 --- a/ext/node/ops/worker_threads.rs +++ b/ext/node/ops/worker_threads.rs @@ -7,7 +7,7 @@ use deno_fs::FileSystemRc; use std::borrow::Cow; use std::path::Path; use std::path::PathBuf; - +use deno_permissions::PermissionCheckError; use crate::NodePermissions; use crate::NodeRequireLoaderRc; @@ -15,7 +15,7 @@ use crate::NodeRequireLoaderRc; fn ensure_read_permission<'a, P>( state: &mut OpState, file_path: &'a Path, -) -> Result, deno_core::error::AnyError> +) -> Result, PermissionCheckError> where P: NodePermissions + 'static, { @@ -24,24 +24,32 @@ where loader.ensure_read_permission(permissions, file_path) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum WorkerThreadsFilenameError { + #[class(inherit)] #[error(transparent)] - Permission(deno_core::error::AnyError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(inherit)] #[error("{0}")] - UrlParse(#[from] url::ParseError), + UrlParse(#[from] #[inherit] url::ParseError), + #[class(GENERIC)] #[error("Relative path entries must start with '.' or '..'")] InvalidRelativeUrl, + #[class(GENERIC)] #[error("URL from Path-String")] UrlFromPathString, + #[class(GENERIC)] #[error("URL to Path-String")] UrlToPathString, + #[class(GENERIC)] #[error("URL to Path")] UrlToPath, + #[class(GENERIC)] #[error("File not found [{0:?}]")] FileNotFound(PathBuf), + #[class(inherit)] #[error(transparent)] - Fs(#[from] deno_io::fs::FsError), + Fs(#[from] #[inherit] deno_io::fs::FsError), } // todo(dsherret): we should remove this and do all this work inside op_create_worker @@ -65,7 +73,7 @@ where return Err(WorkerThreadsFilenameError::InvalidRelativeUrl); } let path = ensure_read_permission::

(state, &path) - .map_err(WorkerThreadsFilenameError::Permission)?; + ?; let fs = state.borrow::(); let canonicalized_path = deno_path_util::strip_unc_prefix(fs.realpath_sync(&path)?); @@ -76,7 +84,7 @@ where .to_file_path() .map_err(|_| WorkerThreadsFilenameError::UrlToPathString)?; let url_path = ensure_read_permission::

(state, &url_path) - .map_err(WorkerThreadsFilenameError::Permission)?; + ?; let fs = state.borrow::(); if !fs.exists_sync(&url_path) { return Err(WorkerThreadsFilenameError::FileNotFound( diff --git a/ext/node/ops/zlib/brotli.rs b/ext/node/ops/zlib/brotli.rs index 1a681ff7f719a6..45cb89944a0a07 100644 --- a/ext/node/ops/zlib/brotli.rs +++ b/ext/node/ops/zlib/brotli.rs @@ -17,20 +17,26 @@ use deno_core::ToJsBuffer; use std::cell::RefCell; use std::io::Read; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum BrotliError { + #[class(TYPE)] #[error("Invalid encoder mode")] InvalidEncoderMode, + #[class(TYPE)] #[error("Failed to compress")] CompressFailed, + #[class(TYPE)] #[error("Failed to decompress")] DecompressFailed, + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join(#[from] #[inherit] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error("{0}")] - Io(std::io::Error), + Io(#[inherit] std::io::Error), } fn encoder_mode(mode: u32) -> Result { @@ -169,7 +175,7 @@ pub fn op_brotli_compress_stream( let ctx = state .resource_table .get::(rid) - .map_err(BrotliError::Resource)?; + ?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -201,7 +207,7 @@ pub fn op_brotli_compress_stream_end( let ctx = state .resource_table .get::(rid) - .map_err(BrotliError::Resource)?; + ?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -279,7 +285,7 @@ pub fn op_brotli_decompress_stream( let ctx = state .resource_table .get::(rid) - .map_err(BrotliError::Resource)?; + ?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; @@ -310,7 +316,7 @@ pub fn op_brotli_decompress_stream_end( let ctx = state .resource_table .get::(rid) - .map_err(BrotliError::Resource)?; + ?; let mut inst = ctx.inst.borrow_mut(); let mut output_offset = 0; diff --git a/ext/node/ops/zlib/mod.rs b/ext/node/ops/zlib/mod.rs index e75ef050d23d7a..0b0a2ba12c064e 100644 --- a/ext/node/ops/zlib/mod.rs +++ b/ext/node/ops/zlib/mod.rs @@ -3,6 +3,7 @@ use deno_core::op2; use std::borrow::Cow; use std::cell::RefCell; +use deno_core::error::JsNativeError; use zlib::*; mod alloc; @@ -16,11 +17,11 @@ use mode::Mode; use self::stream::StreamWrapper; #[inline] -fn check(condition: bool, msg: &str) -> Result<(), deno_core::error::AnyError> { +fn check(condition: bool, msg: &str) -> Result<(), JsNativeError> { if condition { Ok(()) } else { - Err(deno_core::error::type_error(msg.to_string())) + Err(JsNativeError::type_error(msg.to_string())) } } @@ -55,7 +56,7 @@ impl ZlibInner { out_off: u32, out_len: u32, flush: Flush, - ) -> Result<(), deno_core::error::AnyError> { + ) -> Result<(), JsNativeError> { check(self.init_done, "write before init")?; check(!self.write_in_progress, "write already in progress")?; check(!self.pending_close, "close already in progress")?; @@ -64,11 +65,11 @@ impl ZlibInner { let next_in = input .get(in_off as usize..in_off as usize + in_len as usize) - .ok_or_else(|| deno_core::error::type_error("invalid input range"))? + .ok_or_else(|| JsNativeError::type_error("invalid input range"))? .as_ptr() as *mut _; let next_out = out .get_mut(out_off as usize..out_off as usize + out_len as usize) - .ok_or_else(|| deno_core::error::type_error("invalid output range"))? + .ok_or_else(|| JsNativeError::type_error("invalid output range"))? .as_mut_ptr(); self.strm.avail_in = in_len; @@ -83,7 +84,7 @@ impl ZlibInner { fn do_write( &mut self, flush: Flush, - ) -> Result<(), deno_core::error::AnyError> { + ) -> Result<(), JsNativeError> { self.flush = flush; match self.mode { Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => { @@ -129,7 +130,7 @@ impl ZlibInner { self.mode = Mode::Inflate; } } else if next_expected_header_byte.is_some() { - return Err(deno_core::error::type_error( + return Err(JsNativeError::type_error( "invalid number of gzip magic number bytes read", )); } @@ -183,7 +184,7 @@ impl ZlibInner { Ok(()) } - fn init_stream(&mut self) -> Result<(), deno_core::error::AnyError> { + fn init_stream(&mut self) -> Result<(), JsNativeError> { match self.mode { Mode::Gzip | Mode::Gunzip => self.window_bits += 16, Mode::Unzip => self.window_bits += 32, @@ -201,7 +202,7 @@ impl ZlibInner { Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => { self.strm.inflate_init(self.window_bits) } - Mode::None => return Err(deno_core::error::type_error("Unknown mode")), + Mode::None => return Err(JsNativeError::type_error("Unknown mode")), }; self.write_in_progress = false; @@ -210,7 +211,7 @@ impl ZlibInner { Ok(()) } - fn close(&mut self) -> Result { + fn close(&mut self) -> Result { if self.write_in_progress { self.pending_close = true; return Ok(false); @@ -256,14 +257,17 @@ pub fn op_zlib_new(#[smi] mode: i32) -> Result { }) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ZlibError { + #[class(TYPE)] #[error("zlib not initialized")] NotInitialized, + #[class(inherit)] #[error(transparent)] - Mode(#[from] mode::ModeError), + Mode(#[from] #[inherit] mode::ModeError), + #[class(inherit)] #[error(transparent)] - Other(#[from] deno_core::error::AnyError), + Other(#[from] #[inherit] JsNativeError), } #[op2(fast)] diff --git a/ext/node/ops/zlib/mode.rs b/ext/node/ops/zlib/mode.rs index 41565f9b1142df..ecd9bc300a2d87 100644 --- a/ext/node/ops/zlib/mode.rs +++ b/ext/node/ops/zlib/mode.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(GENERIC)] #[error("bad argument")] pub struct ModeError; diff --git a/ext/tls/lib.rs b/ext/tls/lib.rs index 883d2995e4b913..60fa8a874dda78 100644 --- a/ext/tls/lib.rs +++ b/ext/tls/lib.rs @@ -26,22 +26,29 @@ use std::io::BufReader; use std::io::Cursor; use std::net::IpAddr; use std::sync::Arc; +use deno_core::error::JsNativeError; mod tls_key; pub use tls_key::*; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum TlsError { + #[class(GENERIC)] #[error(transparent)] Rustls(#[from] rustls::Error), + #[class(inherit)] #[error("Unable to add pem file to certificate store: {0}")] - UnableAddPemFileToCert(std::io::Error), + UnableAddPemFileToCert(#[inherit] std::io::Error), + #[class("InvalidData")] #[error("Unable to decode certificate")] CertInvalid, + #[class("InvalidData")] #[error("No certificates found in certificate data")] CertsNotFound, + #[class("InvalidData")] #[error("No keys found in key data")] KeysNotFound, + #[class("InvalidData")] #[error("Unable to decode key")] KeyDecode, } @@ -53,7 +60,7 @@ pub enum TlsError { pub trait RootCertStoreProvider: Send + Sync { fn get_or_try_init( &self, - ) -> Result<&RootCertStore, deno_core::error::AnyError>; + ) -> Result<&RootCertStore, JsNativeError>; } // This extension has no runtime apis, it only exports some shared native functions. diff --git a/ext/url/lib.rs b/ext/url/lib.rs index f8946532ae613e..12a1c01e6ee1c5 100644 --- a/ext/url/lib.rs +++ b/ext/url/lib.rs @@ -2,8 +2,7 @@ mod urlpattern; -use deno_core::error::type_error; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::op2; use deno_core::url::form_urlencoded; use deno_core::url::quirks; @@ -220,7 +219,7 @@ pub fn op_url_reparse( pub fn op_url_parse_search_params( #[string] args: Option, #[buffer] zero_copy: Option, -) -> Result, AnyError> { +) -> Result, JsNativeError> { let params = match (args, zero_copy) { (None, Some(zero_copy)) => form_urlencoded::parse(&zero_copy) .into_iter() @@ -230,7 +229,7 @@ pub fn op_url_parse_search_params( .into_iter() .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned())) .collect(), - _ => return Err(type_error("invalid parameters")), + _ => return Err(JsNativeError::type_error("invalid parameters")), }; Ok(params) } diff --git a/ext/url/urlpattern.rs b/ext/url/urlpattern.rs index 7d4e8ee71b06de..711b82a3739128 100644 --- a/ext/url/urlpattern.rs +++ b/ext/url/urlpattern.rs @@ -7,9 +7,7 @@ use urlpattern::quirks::MatchInput; use urlpattern::quirks::StringOrInit; use urlpattern::quirks::UrlPattern; -#[derive(Debug, thiserror::Error)] -#[error(transparent)] -pub struct UrlPatternError(urlpattern::Error); +deno_core::js_error_wrapper!(urlpattern::Error, UrlPatternError, "TypeError"); #[op2] #[serde] @@ -19,11 +17,9 @@ pub fn op_urlpattern_parse( #[serde] options: urlpattern::UrlPatternOptions, ) -> Result { let init = - quirks::process_construct_pattern_input(input, base_url.as_deref()) - .map_err(UrlPatternError)?; + quirks::process_construct_pattern_input(input, base_url.as_deref())?; - let pattern = - quirks::parse_pattern(init, options).map_err(UrlPatternError)?; + let pattern = quirks::parse_pattern(init, options)?; Ok(pattern) } @@ -34,8 +30,7 @@ pub fn op_urlpattern_process_match_input( #[serde] input: StringOrInit, #[string] base_url: Option, ) -> Result, UrlPatternError> { - let res = quirks::process_match_input(input, base_url.as_deref()) - .map_err(UrlPatternError)?; + let res = quirks::process_match_input(input, base_url.as_deref())?; let (input, inputs) = match res { Some((input, inputs)) => (input, inputs), diff --git a/ext/web/blob.rs b/ext/web/blob.rs index bc64a0f27eba17..3ba6216e862973 100644 --- a/ext/web/blob.rs +++ b/ext/web/blob.rs @@ -17,14 +17,18 @@ use serde::Deserialize; use serde::Serialize; use uuid::Uuid; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum BlobError { + #[class(TYPE)] #[error("Blob part not found")] BlobPartNotFound, + #[class(TYPE)] #[error("start + len can not be larger than blob part size")] SizeLargerThanBlobPart, + #[class(TYPE)] #[error("Blob URLs are not supported in this context")] BlobURLsNotSupported, + #[class(GENERIC)] #[error(transparent)] Url(#[from] deno_core::url::ParseError), } diff --git a/ext/web/compression.rs b/ext/web/compression.rs index 6967009915d419..f21835adbb0649 100644 --- a/ext/web/compression.rs +++ b/ext/web/compression.rs @@ -11,16 +11,20 @@ use flate2::Compression; use std::cell::RefCell; use std::io::Write; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CompressionError { + #[class(TYPE)] #[error("Unsupported format")] UnsupportedFormat, + #[class(TYPE)] #[error("resource is closed")] ResourceClosed, + #[class(TYPE)] #[error(transparent)] IoTypeError(std::io::Error), + #[class(inherit)] #[error(transparent)] - Io(std::io::Error), + Io(#[inherit] std::io::Error), } #[derive(Debug)] diff --git a/ext/web/lib.rs b/ext/web/lib.rs index af0fc2c276563e..d6c9fe5b56588f 100644 --- a/ext/web/lib.rs +++ b/ext/web/lib.rs @@ -129,20 +129,27 @@ deno_core::extension!(deno_web, } ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum WebError { + #[class("DOMExceptionInvalidCharacterError")] #[error("Failed to decode base64")] Base64Decode, + #[class(RANGE)] #[error("The encoding label provided ('{0}') is invalid.")] InvalidEncodingLabel(String), + #[class(TYPE)] #[error("buffer exceeds maximum length")] BufferTooLong, + #[class(RANGE)] #[error("Value too large to decode")] ValueTooLarge, + #[class(RANGE)] #[error("Provided buffer too small")] BufferTooSmall, + #[class(TYPE)] #[error("The encoded data is not valid")] DataInvalid, + #[class(GENERIC)] #[error(transparent)] DataError(#[from] v8::DataError), } diff --git a/ext/web/message_port.rs b/ext/web/message_port.rs index 1a4a09073d176d..459ea2496ef835 100644 --- a/ext/web/message_port.rs +++ b/ext/web/message_port.rs @@ -21,18 +21,23 @@ use tokio::sync::mpsc::unbounded_channel; use tokio::sync::mpsc::UnboundedReceiver; use tokio::sync::mpsc::UnboundedSender; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum MessagePortError { + #[class(TYPE)] #[error("Invalid message port transfer")] InvalidTransfer, + #[class(TYPE)] #[error("Message port is not ready for transfer")] NotReady, + #[class(TYPE)] #[error("Can not transfer self message port")] TransferSelf, + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[inherit] deno_core::error::ResourceError), } pub enum Transferable { diff --git a/ext/web/stream_resource.rs b/ext/web/stream_resource.rs index c44a385ea9d59d..b544bce343a595 100644 --- a/ext/web/stream_resource.rs +++ b/ext/web/stream_resource.rs @@ -30,10 +30,12 @@ use std::task::Context; use std::task::Poll; use std::task::Waker; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum StreamResourceError { + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), + #[class(TYPE)] #[error("{0}")] Js(String), } @@ -403,7 +405,10 @@ impl Resource for ReadableStreamResource { } fn read(self: Rc, limit: usize) -> AsyncResult { - Box::pin(ReadableStreamResource::read(self, limit).map_err(|e| e.into())) + Box::pin( + ReadableStreamResource::read(self, limit) + .map_err(|e| deno_core::error::JsNativeError::from_err(e)), + ) } fn close(self: Rc) { diff --git a/ext/webgpu/binding.rs b/ext/webgpu/binding.rs index 41708acc7f1a43..7b8c8eb9b41311 100644 --- a/ext/webgpu/binding.rs +++ b/ext/webgpu/binding.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -169,7 +169,7 @@ pub fn op_webgpu_create_bind_group_layout( #[smi] device_rid: ResourceId, #[string] label: Cow, #[serde] entries: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -208,7 +208,7 @@ pub fn op_webgpu_create_pipeline_layout( #[smi] device_rid: ResourceId, #[string] label: Cow, #[serde] bind_group_layouts: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -222,7 +222,7 @@ pub fn op_webgpu_create_pipeline_layout( state.resource_table.get::(rid)?; Ok(bind_group_layout.1) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let descriptor = wgpu_core::binding_model::PipelineLayoutDescriptor { label: Some(label), @@ -255,7 +255,7 @@ pub fn op_webgpu_create_bind_group( #[string] label: Cow, #[smi] layout: ResourceId, #[serde] entries: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -303,7 +303,7 @@ pub fn op_webgpu_create_bind_group( }, }) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let bind_group_layout = state.resource_table.get::(layout)?; diff --git a/ext/webgpu/buffer.rs b/ext/webgpu/buffer.rs index c2b53890e0ccef..d73d52538a5dd5 100644 --- a/ext/webgpu/buffer.rs +++ b/ext/webgpu/buffer.rs @@ -13,12 +13,15 @@ use std::time::Duration; use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum BufferError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(TYPE)] #[error("usage is not valid")] InvalidUsage, + #[class("DOMExceptionOperationError")] #[error(transparent)] Access(wgpu_core::resource::BufferAccessError), } @@ -57,8 +60,7 @@ pub fn op_webgpu_create_buffer( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(BufferError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; let descriptor = wgpu_core::resource::BufferDescriptor { @@ -91,15 +93,12 @@ pub async fn op_webgpu_buffer_get_map_async( { let state_ = state.borrow(); let instance = state_.borrow::(); - let buffer_resource = state_ - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = + state_.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; let device_resource = state_ .resource_table - .get::(device_rid) - .map_err(BufferError::Resource)?; + .get::(device_rid)?; device = device_resource.1; let done_ = done.clone(); @@ -154,10 +153,7 @@ pub fn op_webgpu_buffer_get_mapped_range( #[buffer] buf: &mut [u8], ) -> Result { let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = state.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; let (slice_pointer, range_size) = @@ -191,13 +187,9 @@ pub fn op_webgpu_buffer_unmap( ) -> Result { let mapped_resource = state .resource_table - .take::(mapped_rid) - .map_err(BufferError::Resource)?; + .take::(mapped_rid)?; let instance = state.borrow::(); - let buffer_resource = state - .resource_table - .get::(buffer_rid) - .map_err(BufferError::Resource)?; + let buffer_resource = state.resource_table.get::(buffer_rid)?; let buffer = buffer_resource.1; if let Some(buf) = buf { diff --git a/ext/webgpu/bundle.rs b/ext/webgpu/bundle.rs index d9a5b29539aa93..0b57bc3b37892f 100644 --- a/ext/webgpu/bundle.rs +++ b/ext/webgpu/bundle.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -11,10 +12,12 @@ use std::rc::Rc; use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum BundleError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] ResourceError), + #[class(TYPE)] #[error("size must be larger than 0")] InvalidSize, } @@ -59,7 +62,7 @@ pub struct CreateRenderBundleEncoderArgs { pub fn op_webgpu_create_render_bundle_encoder( state: &mut OpState, #[serde] args: CreateRenderBundleEncoderArgs, -) -> Result { +) -> Result { let device_resource = state .resource_table .get::(args.device_rid)?; @@ -106,7 +109,7 @@ pub fn op_webgpu_render_bundle_encoder_finish( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -137,7 +140,7 @@ pub fn op_webgpu_render_bundle_encoder_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -177,7 +180,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -201,7 +204,7 @@ pub fn op_webgpu_render_bundle_encoder_push_debug_group( pub fn op_webgpu_render_bundle_encoder_pop_debug_group( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -220,7 +223,7 @@ pub fn op_webgpu_render_bundle_encoder_insert_debug_marker( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -245,7 +248,7 @@ pub fn op_webgpu_render_bundle_encoder_set_pipeline( state: &mut OpState, #[smi] render_bundle_encoder_rid: ResourceId, #[smi] pipeline: ResourceId, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table @@ -275,12 +278,11 @@ pub fn op_webgpu_render_bundle_encoder_set_index_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(BundleError::Resource)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(render_bundle_encoder_rid) - .map_err(BundleError::Resource)?; + .get::(buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(render_bundle_encoder_rid)?; let size = Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?); @@ -304,12 +306,11 @@ pub fn op_webgpu_render_bundle_encoder_set_vertex_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(BundleError::Resource)?; - let render_bundle_encoder_resource = state - .resource_table - .get::(render_bundle_encoder_rid) - .map_err(BundleError::Resource)?; + .get::(buffer)?; + let render_bundle_encoder_resource = + state + .resource_table + .get::(render_bundle_encoder_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(BundleError::InvalidSize)?) } else { @@ -336,7 +337,7 @@ pub fn op_webgpu_render_bundle_encoder_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -363,7 +364,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_bundle_encoder_resource = state .resource_table @@ -388,7 +389,7 @@ pub fn op_webgpu_render_bundle_encoder_draw_indirect( #[smi] render_bundle_encoder_rid: ResourceId, #[smi] indirect_buffer: ResourceId, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/ext/webgpu/byow.rs b/ext/webgpu/byow.rs index c9e1177b1efe53..c76f2f4f4044b1 100644 --- a/ext/webgpu/byow.rs +++ b/ext/webgpu/byow.rs @@ -11,21 +11,25 @@ use std::ffi::c_void; target_os = "openbsd" ))] use std::ptr::NonNull; - use crate::surface::WebGpuSurface; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ByowError { + #[class(TYPE)] #[error("Cannot create surface outside of WebGPU context. Did you forget to call `navigator.gpu.requestAdapter()`?")] WebGPUNotInitiated, + #[class(TYPE)] #[error("Invalid parameters")] InvalidParameters, + #[class(GENERIC)] #[error(transparent)] CreateSurface(wgpu_core::instance::CreateSurfaceError), #[cfg(target_os = "windows")] + #[class(TYPE)] #[error("Invalid system on Windows")] InvalidSystem, #[cfg(target_os = "macos")] + #[class(TYPE)] #[error("Invalid system on macOS")] InvalidSystem, #[cfg(any( @@ -33,6 +37,7 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(TYPE)] #[error("Invalid system on Linux/BSD")] InvalidSystem, #[cfg(any( @@ -41,6 +46,7 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(TYPE)] #[error("window is null")] NullWindow, #[cfg(any( @@ -48,9 +54,11 @@ pub enum ByowError { target_os = "freebsd", target_os = "openbsd" ))] + #[class(TYPE)] #[error("display is null")] NullDisplay, #[cfg(target_os = "macos")] + #[class(TYPE)] #[error("ns_view is null")] NSViewDisplay, } @@ -198,6 +206,6 @@ fn raw_window( _system: &str, _window: *const c_void, _display: *const c_void, -) -> Result { - Err(deno_core::error::type_error("Unsupported platform")) +) -> Result { + Err(deno_core::error::JsNativeError::type_error("Unsupported platform")) } diff --git a/ext/webgpu/command_encoder.rs b/ext/webgpu/command_encoder.rs index 4bee7aac301795..ca2fa6e1776fbc 100644 --- a/ext/webgpu/command_encoder.rs +++ b/ext/webgpu/command_encoder.rs @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use crate::WebGpuQuerySet; -use deno_core::error::AnyError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -49,7 +49,7 @@ pub fn op_webgpu_create_command_encoder( state: &mut OpState, #[smi] device_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -109,7 +109,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass( >, #[smi] occlusion_query_set: Option, #[serde] timestamp_writes: Option, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::(command_encoder_rid)?; @@ -148,7 +148,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass( }; Ok(rp_at) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let mut processed_depth_stencil_attachment = None; @@ -244,7 +244,7 @@ pub fn op_webgpu_command_encoder_begin_compute_pass( #[smi] command_encoder_rid: ResourceId, #[string] label: Cow, #[serde] timestamp_writes: Option, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::(command_encoder_rid)?; @@ -294,7 +294,7 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_buffer( #[smi] destination: ResourceId, #[number] destination_offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -346,7 +346,7 @@ pub fn op_webgpu_command_encoder_copy_buffer_to_texture( #[serde] source: GpuImageCopyBuffer, #[serde] destination: GpuImageCopyTexture, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -391,7 +391,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_buffer( #[serde] source: GpuImageCopyTexture, #[serde] destination: GpuImageCopyBuffer, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -436,7 +436,7 @@ pub fn op_webgpu_command_encoder_copy_texture_to_texture( #[serde] source: GpuImageCopyTexture, #[serde] destination: GpuImageCopyTexture, #[serde] copy_size: wgpu_types::Extent3d, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -479,7 +479,7 @@ pub fn op_webgpu_command_encoder_clear_buffer( #[smi] buffer_rid: ResourceId, #[number] offset: u64, #[number] size: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -503,7 +503,7 @@ pub fn op_webgpu_command_encoder_push_debug_group( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -518,7 +518,7 @@ pub fn op_webgpu_command_encoder_push_debug_group( pub fn op_webgpu_command_encoder_pop_debug_group( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -534,7 +534,7 @@ pub fn op_webgpu_command_encoder_insert_debug_marker( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -554,7 +554,7 @@ pub fn op_webgpu_command_encoder_write_timestamp( #[smi] command_encoder_rid: ResourceId, #[smi] query_set: ResourceId, query_index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -581,7 +581,7 @@ pub fn op_webgpu_command_encoder_resolve_query_set( query_count: u32, #[smi] destination: ResourceId, #[number] destination_offset: u64, -) -> Result { +) -> Result { let instance = state.borrow::(); let command_encoder_resource = state .resource_table @@ -610,7 +610,7 @@ pub fn op_webgpu_command_encoder_finish( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[string] label: Cow, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .take::(command_encoder_rid)?; diff --git a/ext/webgpu/compute_pass.rs b/ext/webgpu/compute_pass.rs index 17043c76713973..b52f5a818a30a7 100644 --- a/ext/webgpu/compute_pass.rs +++ b/ext/webgpu/compute_pass.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -25,7 +25,7 @@ pub fn op_webgpu_compute_pass_set_pipeline( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[smi] pipeline: ResourceId, -) -> Result { +) -> Result { let compute_pipeline_resource = state .resource_table @@ -50,7 +50,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups( x: u32, y: u32, z: u32, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -72,7 +72,7 @@ pub fn op_webgpu_compute_pass_dispatch_workgroups_indirect( #[smi] compute_pass_rid: ResourceId, #[smi] indirect_buffer: ResourceId, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; @@ -95,7 +95,7 @@ pub fn op_webgpu_compute_pass_end( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[smi] compute_pass_rid: ResourceId, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::( @@ -124,7 +124,7 @@ pub fn op_webgpu_compute_pass_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -158,7 +158,7 @@ pub fn op_webgpu_compute_pass_push_debug_group( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -177,7 +177,7 @@ pub fn op_webgpu_compute_pass_push_debug_group( pub fn op_webgpu_compute_pass_pop_debug_group( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; @@ -195,7 +195,7 @@ pub fn op_webgpu_compute_pass_insert_debug_marker( state: &mut OpState, #[smi] compute_pass_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let compute_pass_resource = state .resource_table .get::(compute_pass_rid)?; diff --git a/ext/webgpu/lib.rs b/ext/webgpu/lib.rs index 5dc8278e410b54..e376b81c55d06c 100644 --- a/ext/webgpu/lib.rs +++ b/ext/webgpu/lib.rs @@ -83,14 +83,18 @@ pub mod shader; pub mod surface; pub mod texture; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum InitError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(GENERIC)] #[error(transparent)] InvalidAdapter(wgpu_core::instance::InvalidAdapter), + #[class("DOMExceptionOperationError")] #[error(transparent)] RequestDevice(wgpu_core::instance::RequestDeviceError), + #[class(GENERIC)] #[error(transparent)] InvalidDevice(wgpu_core::device::InvalidDevice), } @@ -676,10 +680,8 @@ pub fn op_webgpu_request_device( #[serde] required_limits: Option, ) -> Result { let mut state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .take::(adapter_rid) - .map_err(InitError::Resource)?; + let adapter_resource = + state.resource_table.take::(adapter_rid)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -738,10 +740,8 @@ pub fn op_webgpu_request_adapter_info( #[smi] adapter_rid: ResourceId, ) -> Result { let state = state.borrow_mut(); - let adapter_resource = state - .resource_table - .get::(adapter_rid) - .map_err(InitError::Resource)?; + let adapter_resource = + state.resource_table.get::(adapter_rid)?; let adapter = adapter_resource.1; let instance = state.borrow::(); @@ -788,10 +788,8 @@ pub fn op_webgpu_create_query_set( state: &mut OpState, #[serde] args: CreateQuerySetArgs, ) -> Result { - let device_resource = state - .resource_table - .get::(args.device_rid) - .map_err(InitError::Resource)?; + let device_resource = + state.resource_table.get::(args.device_rid)?; let device = device_resource.1; let instance = state.borrow::(); diff --git a/ext/webgpu/pipeline.rs b/ext/webgpu/pipeline.rs index a6b0cb8cec8e11..abec788f47ed9a 100644 --- a/ext/webgpu/pipeline.rs +++ b/ext/webgpu/pipeline.rs @@ -1,6 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -use deno_core::error::AnyError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -87,7 +87,7 @@ pub fn op_webgpu_create_compute_pipeline( #[string] label: Cow, #[serde] layout: GPUPipelineLayoutOrGPUAutoLayoutMode, #[serde] compute: GpuProgrammableStage, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -155,7 +155,7 @@ pub fn op_webgpu_compute_pipeline_get_bind_group_layout( state: &mut OpState, #[smi] compute_pipeline_rid: ResourceId, index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let compute_pipeline_resource = state .resource_table @@ -334,7 +334,7 @@ pub struct CreateRenderPipelineArgs { pub fn op_webgpu_create_render_pipeline( state: &mut OpState, #[serde] args: CreateRenderPipelineArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -433,7 +433,7 @@ pub fn op_webgpu_render_pipeline_get_bind_group_layout( state: &mut OpState, #[smi] render_pipeline_rid: ResourceId, index: u32, -) -> Result { +) -> Result { let instance = state.borrow::(); let render_pipeline_resource = state .resource_table diff --git a/ext/webgpu/queue.rs b/ext/webgpu/queue.rs index 8c8bbec95efb93..93e3de7fa5a3f7 100644 --- a/ext/webgpu/queue.rs +++ b/ext/webgpu/queue.rs @@ -2,7 +2,7 @@ use crate::command_encoder::WebGpuCommandBuffer; use crate::Instance; -use deno_core::error::AnyError; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -30,7 +30,7 @@ pub fn op_webgpu_queue_submit( state: &mut OpState, #[smi] queue_rid: ResourceId, #[serde] command_buffers: Vec, -) -> Result { +) -> Result { let instance = state.borrow::(); let queue_resource = state.resource_table.get::(queue_rid)?; let queue = queue_resource.1; @@ -43,7 +43,7 @@ pub fn op_webgpu_queue_submit( let mut id = buffer_resource.1.borrow_mut(); Ok(id.take().unwrap()) }) - .collect::, AnyError>>()?; + .collect::, ResourceError>>()?; let maybe_err = gfx_select!(queue => instance.queue_submit(queue, &ids)).err(); @@ -84,7 +84,7 @@ pub fn op_webgpu_write_buffer( #[number] data_offset: usize, #[number] size: Option, #[buffer] buf: &[u8], -) -> Result { +) -> Result { let instance = state.borrow::(); let buffer_resource = state .resource_table @@ -117,7 +117,7 @@ pub fn op_webgpu_write_texture( #[serde] data_layout: GpuImageDataLayout, #[serde] size: wgpu_types::Extent3d, #[buffer] buf: &[u8], -) -> Result { +) -> Result { let instance = state.borrow::(); let texture_resource = state .resource_table diff --git a/ext/webgpu/render_pass.rs b/ext/webgpu/render_pass.rs index 9b9d87d9fc05a6..a0b19d5dd42a3d 100644 --- a/ext/webgpu/render_pass.rs +++ b/ext/webgpu/render_pass.rs @@ -1,5 +1,6 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -10,10 +11,12 @@ use std::cell::RefCell; use super::error::WebGpuResult; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum RenderPassError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] ResourceError), + #[class(TYPE)] #[error("size must be larger than 0")] InvalidSize, } @@ -44,7 +47,7 @@ pub struct RenderPassSetViewportArgs { pub fn op_webgpu_render_pass_set_viewport( state: &mut OpState, #[serde] args: RenderPassSetViewportArgs, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(args.render_pass_rid)?; @@ -71,7 +74,7 @@ pub fn op_webgpu_render_pass_set_scissor_rect( y: u32, width: u32, height: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -93,7 +96,7 @@ pub fn op_webgpu_render_pass_set_blend_constant( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] color: wgpu_types::Color, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -112,7 +115,7 @@ pub fn op_webgpu_render_pass_set_stencil_reference( state: &mut OpState, #[smi] render_pass_rid: ResourceId, reference: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -131,7 +134,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, query_index: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -149,7 +152,7 @@ pub fn op_webgpu_render_pass_begin_occlusion_query( pub fn op_webgpu_render_pass_end_occlusion_query( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -167,7 +170,7 @@ pub fn op_webgpu_render_pass_execute_bundles( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[serde] bundles: Vec, -) -> Result { +) -> Result { let bundles = bundles .iter() .map(|rid| { @@ -177,7 +180,7 @@ pub fn op_webgpu_render_pass_execute_bundles( .get::(*rid)?; Ok(render_bundle_resource.1) }) - .collect::, deno_core::error::AnyError>>()?; + .collect::, ResourceError>>()?; let render_pass_resource = state .resource_table @@ -197,7 +200,7 @@ pub fn op_webgpu_render_pass_end( state: &mut OpState, #[smi] command_encoder_rid: ResourceId, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let command_encoder_resource = state .resource_table .get::( @@ -223,7 +226,7 @@ pub fn op_webgpu_render_pass_set_bind_group( #[buffer] dynamic_offsets_data: &[u32], #[number] dynamic_offsets_data_start: usize, #[number] dynamic_offsets_data_length: usize, -) -> Result { +) -> Result { let bind_group_resource = state .resource_table @@ -257,7 +260,7 @@ pub fn op_webgpu_render_pass_push_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] group_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -276,7 +279,7 @@ pub fn op_webgpu_render_pass_push_debug_group( pub fn op_webgpu_render_pass_pop_debug_group( state: &mut OpState, #[smi] render_pass_rid: ResourceId, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -294,7 +297,7 @@ pub fn op_webgpu_render_pass_insert_debug_marker( state: &mut OpState, #[smi] render_pass_rid: ResourceId, #[string] marker_label: &str, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -314,7 +317,7 @@ pub fn op_webgpu_render_pass_set_pipeline( state: &mut OpState, #[smi] render_pass_rid: ResourceId, pipeline: u32, -) -> Result { +) -> Result { let render_pipeline_resource = state .resource_table @@ -343,12 +346,10 @@ pub fn op_webgpu_render_pass_set_index_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(RenderPassError::Resource)?; + .get::(buffer)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid) - .map_err(RenderPassError::Resource)?; + .get::(render_pass_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) @@ -378,12 +379,10 @@ pub fn op_webgpu_render_pass_set_vertex_buffer( ) -> Result { let buffer_resource = state .resource_table - .get::(buffer) - .map_err(RenderPassError::Resource)?; + .get::(buffer)?; let render_pass_resource = state .resource_table - .get::(render_pass_rid) - .map_err(RenderPassError::Resource)?; + .get::(render_pass_rid)?; let size = if let Some(size) = size { Some(std::num::NonZeroU64::new(size).ok_or(RenderPassError::InvalidSize)?) @@ -411,7 +410,7 @@ pub fn op_webgpu_render_pass_draw( instance_count: u32, first_vertex: u32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -437,7 +436,7 @@ pub fn op_webgpu_render_pass_draw_indexed( first_index: u32, base_vertex: i32, first_instance: u32, -) -> Result { +) -> Result { let render_pass_resource = state .resource_table .get::(render_pass_rid)?; @@ -461,7 +460,7 @@ pub fn op_webgpu_render_pass_draw_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; @@ -485,7 +484,7 @@ pub fn op_webgpu_render_pass_draw_indexed_indirect( #[smi] render_pass_rid: ResourceId, indirect_buffer: u32, #[number] indirect_offset: u64, -) -> Result { +) -> Result { let buffer_resource = state .resource_table .get::(indirect_buffer)?; diff --git a/ext/webgpu/sampler.rs b/ext/webgpu/sampler.rs index 9fc1269ea7b758..8933c3848cb47e 100644 --- a/ext/webgpu/sampler.rs +++ b/ext/webgpu/sampler.rs @@ -46,7 +46,7 @@ pub struct CreateSamplerArgs { pub fn op_webgpu_create_sampler( state: &mut OpState, #[serde] args: CreateSamplerArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/ext/webgpu/shader.rs b/ext/webgpu/shader.rs index 4653bd85bf05c6..1d8e9fb851de2e 100644 --- a/ext/webgpu/shader.rs +++ b/ext/webgpu/shader.rs @@ -30,7 +30,7 @@ pub fn op_webgpu_create_shader_module( #[smi] device_rid: ResourceId, #[string] label: Cow, #[string] code: Cow, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table diff --git a/ext/webgpu/surface.rs b/ext/webgpu/surface.rs index 297eaeb00874ae..0a85dfff2a4408 100644 --- a/ext/webgpu/surface.rs +++ b/ext/webgpu/surface.rs @@ -1,6 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use super::WebGpuResult; +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::Resource; @@ -10,12 +11,15 @@ use std::borrow::Cow; use std::rc::Rc; use wgpu_types::SurfaceStatus; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum SurfaceError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] ResourceError), + #[class(GENERIC)] #[error("Invalid Surface Status")] InvalidStatus, + #[class(GENERIC)] #[error(transparent)] Surface(wgpu_core::present::SurfaceError), } @@ -50,7 +54,7 @@ pub struct SurfaceConfigureArgs { pub fn op_webgpu_surface_configure( state: &mut OpState, #[serde] args: SurfaceConfigureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -88,13 +92,10 @@ pub fn op_webgpu_surface_get_current_texture( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(SurfaceError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; - let surface_resource = state - .resource_table - .get::(surface_rid) - .map_err(SurfaceError::Resource)?; + let surface_resource = + state.resource_table.get::(surface_rid)?; let surface = surface_resource.1; let output = @@ -124,13 +125,10 @@ pub fn op_webgpu_surface_present( let instance = state.borrow::(); let device_resource = state .resource_table - .get::(device_rid) - .map_err(SurfaceError::Resource)?; + .get::(device_rid)?; let device = device_resource.1; - let surface_resource = state - .resource_table - .get::(surface_rid) - .map_err(SurfaceError::Resource)?; + let surface_resource = + state.resource_table.get::(surface_rid)?; let surface = surface_resource.1; let _ = gfx_select!(device => instance.surface_present(surface)) diff --git a/ext/webgpu/texture.rs b/ext/webgpu/texture.rs index f8a5e05a3e2b15..aa6f8408ecbbe3 100644 --- a/ext/webgpu/texture.rs +++ b/ext/webgpu/texture.rs @@ -61,7 +61,7 @@ pub struct CreateTextureArgs { pub fn op_webgpu_create_texture( state: &mut OpState, #[serde] args: CreateTextureArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table @@ -110,7 +110,7 @@ pub struct CreateTextureViewArgs { pub fn op_webgpu_create_texture_view( state: &mut OpState, #[serde] args: CreateTextureViewArgs, -) -> Result { +) -> Result { let instance = state.borrow::(); let texture_resource = state .resource_table diff --git a/ext/websocket/lib.rs b/ext/websocket/lib.rs index a5734271cf17be..36b8992d7bc8e0 100644 --- a/ext/websocket/lib.rs +++ b/ext/websocket/lib.rs @@ -44,6 +44,7 @@ use std::num::NonZeroUsize; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; +use deno_core::error::JsNativeError; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; use tokio::io::ReadHalf; @@ -71,24 +72,32 @@ static USE_WRITEV: Lazy = Lazy::new(|| { false }); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum WebsocketError { + #[class(inherit)] #[error(transparent)] - Url(url::ParseError), + Url(#[inherit] url::ParseError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] PermissionCheckError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(GENERIC)] #[error(transparent)] Uri(#[from] http::uri::InvalidUri), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(TYPE)] #[error(transparent)] WebSocket(#[from] fastwebsockets::WebSocketError), + #[class("DOMExceptionNetworkError")] #[error("failed to connect to WebSocket: {0}")] ConnectionFailed(#[from] HandshakeError), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), } #[derive(Clone)] @@ -97,7 +106,7 @@ pub struct WsRootStoreProvider(Option>); impl WsRootStoreProvider { pub fn get_or_try_init( &self, - ) -> Result, deno_core::error::AnyError> { + ) -> Result, JsNativeError> { Ok(match &self.0 { Some(provider) => Some(provider.get_or_try_init()?.clone()), None => None, @@ -182,32 +191,45 @@ pub struct CreateResponse { extensions: String, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum HandshakeError { + #[class(TYPE)] #[error("Missing path in url")] MissingPath, + #[class(GENERIC)] #[error("Invalid status code {0}")] InvalidStatusCode(StatusCode), + #[class(GENERIC)] #[error(transparent)] Http(#[from] http::Error), + #[class(TYPE)] #[error(transparent)] WebSocket(#[from] fastwebsockets::WebSocketError), + #[class(GENERIC)] #[error("Didn't receive h2 alpn, aborting connection")] NoH2Alpn, + #[class(GENERIC)] #[error(transparent)] Rustls(#[from] deno_tls::rustls::Error), + #[class(inherit)] #[error(transparent)] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(GENERIC)] #[error(transparent)] H2(#[from] h2::Error), + #[class(TYPE)] #[error("Invalid hostname: '{0}'")] InvalidHostname(String), + #[class(inherit)] #[error(transparent)] - RootStoreError(deno_core::error::AnyError), + RootStoreError(#[inherit] JsNativeError), + #[class(inherit)] #[error(transparent)] - Tls(deno_tls::TlsError), + Tls(#[inherit] deno_tls::TlsError), + #[class(TYPE)] #[error(transparent)] HeaderName(#[from] http::header::InvalidHeaderName), + #[class(TYPE)] #[error(transparent)] HeaderValue(#[from] http::header::InvalidHeaderValue), } @@ -472,8 +494,7 @@ where let r = state .borrow_mut() .resource_table - .get::(cancel_rid) - .map_err(WebsocketError::Resource)?; + .get::(cancel_rid)?; Some(r.0.clone()) } else { None @@ -677,8 +698,7 @@ pub async fn op_ws_send_binary_async( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let data = data.to_vec(); let lock = resource.reserve_lock(); resource @@ -696,8 +716,7 @@ pub async fn op_ws_send_text_async( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let lock = resource.reserve_lock(); resource .write_frame( @@ -731,8 +750,7 @@ pub async fn op_ws_send_ping( let resource = state .borrow_mut() .resource_table - .get::(rid) - .map_err(WebsocketError::Resource)?; + .get::(rid)?; let lock = resource.reserve_lock(); resource .write_frame( diff --git a/ext/webstorage/lib.rs b/ext/webstorage/lib.rs index 40946f05a7ec81..035ab32c594468 100644 --- a/ext/webstorage/lib.rs +++ b/ext/webstorage/lib.rs @@ -2,24 +2,27 @@ // NOTE to all: use **cached** prepared statements when interfacing with SQLite. -use std::path::PathBuf; - use deno_core::op2; use deno_core::OpState; use rusqlite::params; use rusqlite::Connection; use rusqlite::OptionalExtension; +use std::path::PathBuf; pub use rusqlite; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum WebStorageError { + #[class("DOMExceptionNotSupportedError")] #[error("LocalStorage is not supported in this context.")] ContextNotSupported, + #[class(GENERIC)] #[error(transparent)] Sqlite(#[from] rusqlite::Error), + #[class(inherit)] #[error(transparent)] - Io(std::io::Error), + Io(#[inherit] std::io::Error), + #[class("DOMExceptionQuotaExceededError")] #[error("Exceeded maximum storage size")] StorageExceeded, } diff --git a/runtime/errors.rs b/runtime/errors.rs deleted file mode 100644 index 5716944b7e3940..00000000000000 --- a/runtime/errors.rs +++ /dev/null @@ -1,1932 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -//! There are many types of errors in Deno: -//! - AnyError: a generic wrapper that can encapsulate any type of error. -//! - JsError: a container for the error message and stack trace for exceptions -//! thrown in JavaScript code. We use this to pretty-print stack traces. -//! - Diagnostic: these are errors that originate in TypeScript's compiler. -//! They're similar to JsError, in that they have line numbers. But -//! Diagnostics are compile-time type errors, whereas JsErrors are runtime -//! exceptions. - -use crate::ops::fs_events::FsEventsError; -use crate::ops::http::HttpStartError; -use crate::ops::os::OsError; -use crate::ops::permissions::PermissionError; -use crate::ops::process::CheckRunPermissionError; -use crate::ops::process::ProcessError; -use crate::ops::signal::SignalError; -use crate::ops::tty::TtyError; -use crate::ops::web_worker::SyncFetchError; -use crate::ops::worker_host::CreateWorkerError; -use deno_broadcast_channel::BroadcastChannelError; -use deno_cache::CacheError; -use deno_canvas::CanvasError; -use deno_core::error::AnyError; -use deno_core::serde_json; -use deno_core::url; -use deno_core::ModuleResolutionError; -use deno_cron::CronError; -use deno_crypto::DecryptError; -use deno_crypto::EncryptError; -use deno_crypto::ExportKeyError; -use deno_crypto::GenerateKeyError; -use deno_crypto::ImportKeyError; -use deno_fetch::FetchError; -use deno_fetch::HttpClientCreateError; -use deno_ffi::CallError; -use deno_ffi::CallbackError; -use deno_ffi::DlfcnError; -use deno_ffi::IRError; -use deno_ffi::ReprError; -use deno_ffi::StaticError; -use deno_fs::FsOpsError; -use deno_http::HttpError; -use deno_http::HttpNextError; -use deno_http::WebSocketUpgradeError; -use deno_io::fs::FsError; -use deno_kv::KvCheckError; -use deno_kv::KvError; -use deno_kv::KvMutationError; -use deno_napi::NApiError; -use deno_net::ops::NetError; -use deno_permissions::ChildPermissionError; -use deno_permissions::NetDescriptorFromUrlParseError; -use deno_permissions::PathResolveError; -use deno_permissions::PermissionCheckError; -use deno_permissions::RunDescriptorParseError; -use deno_permissions::SysDescriptorParseError; -use deno_tls::TlsError; -use deno_web::BlobError; -use deno_web::CompressionError; -use deno_web::MessagePortError; -use deno_web::StreamResourceError; -use deno_web::WebError; -use deno_websocket::HandshakeError; -use deno_websocket::WebsocketError; -use deno_webstorage::WebStorageError; -use rustyline::error::ReadlineError; -use std::env; -use std::error::Error; -use std::io; -use std::sync::Arc; - -fn get_run_descriptor_parse_error(e: &RunDescriptorParseError) -> &'static str { - match e { - RunDescriptorParseError::Which(_) => "Error", - RunDescriptorParseError::PathResolve(e) => get_path_resolve_error(e), - RunDescriptorParseError::EmptyRunQuery => "Error", - } -} - -fn get_sys_descriptor_parse_error(e: &SysDescriptorParseError) -> &'static str { - match e { - SysDescriptorParseError::InvalidKind(_) => "TypeError", - SysDescriptorParseError::Empty => "Error", - } -} - -fn get_path_resolve_error(e: &PathResolveError) -> &'static str { - match e { - PathResolveError::CwdResolve(e) => get_io_error_class(e), - PathResolveError::EmptyPath => "Error", - } -} - -fn get_permission_error_class(e: &PermissionError) -> &'static str { - match e { - PermissionError::InvalidPermissionName(_) => "ReferenceError", - PermissionError::PathResolve(e) => get_path_resolve_error(e), - PermissionError::NetDescriptorParse(_) => "URIError", - PermissionError::SysDescriptorParse(e) => get_sys_descriptor_parse_error(e), - PermissionError::RunDescriptorParse(e) => get_run_descriptor_parse_error(e), - } -} - -fn get_permission_check_error_class(e: &PermissionCheckError) -> &'static str { - match e { - PermissionCheckError::PermissionDenied(_) => "NotCapable", - PermissionCheckError::InvalidFilePath(_) => "URIError", - PermissionCheckError::NetDescriptorForUrlParse(e) => match e { - NetDescriptorFromUrlParseError::MissingHost(_) => "TypeError", - NetDescriptorFromUrlParseError::Host(_) => "URIError", - }, - PermissionCheckError::SysDescriptorParse(e) => { - get_sys_descriptor_parse_error(e) - } - PermissionCheckError::PathResolve(e) => get_path_resolve_error(e), - PermissionCheckError::HostParse(_) => "URIError", - } -} - -fn get_dlopen_error_class(error: &dlopen2::Error) -> &'static str { - use dlopen2::Error::*; - match error { - NullCharacter(_) => "InvalidData", - OpeningLibraryError(ref e) => get_io_error_class(e), - SymbolGettingError(ref e) => get_io_error_class(e), - AddrNotMatchingDll(ref e) => get_io_error_class(e), - NullSymbol => "NotFound", - } -} - -fn get_env_var_error_class(error: &env::VarError) -> &'static str { - use env::VarError::*; - match error { - NotPresent => "NotFound", - NotUnicode(..) => "InvalidData", - } -} - -fn get_io_error_class(error: &io::Error) -> &'static str { - use io::ErrorKind::*; - match error.kind() { - NotFound => "NotFound", - PermissionDenied => "PermissionDenied", - ConnectionRefused => "ConnectionRefused", - ConnectionReset => "ConnectionReset", - ConnectionAborted => "ConnectionAborted", - NotConnected => "NotConnected", - AddrInUse => "AddrInUse", - AddrNotAvailable => "AddrNotAvailable", - BrokenPipe => "BrokenPipe", - AlreadyExists => "AlreadyExists", - InvalidInput => "TypeError", - InvalidData => "InvalidData", - TimedOut => "TimedOut", - Interrupted => "Interrupted", - WriteZero => "WriteZero", - UnexpectedEof => "UnexpectedEof", - Other => "Error", - WouldBlock => "WouldBlock", - // Non-exhaustive enum - might add new variants - // in the future - kind => { - let kind_str = kind.to_string(); - match kind_str.as_str() { - "FilesystemLoop" => "FilesystemLoop", - "IsADirectory" => "IsADirectory", - "NetworkUnreachable" => "NetworkUnreachable", - "NotADirectory" => "NotADirectory", - _ => "Error", - } - } - } -} - -fn get_module_resolution_error_class( - _: &ModuleResolutionError, -) -> &'static str { - "URIError" -} - -fn get_notify_error_class(error: ¬ify::Error) -> &'static str { - use notify::ErrorKind::*; - match error.kind { - Generic(_) => "Error", - Io(ref e) => get_io_error_class(e), - PathNotFound => "NotFound", - WatchNotFound => "NotFound", - InvalidConfig(_) => "InvalidData", - MaxFilesWatch => "Error", - } -} - -fn get_regex_error_class(error: ®ex::Error) -> &'static str { - use regex::Error::*; - match error { - Syntax(_) => "SyntaxError", - CompiledTooBig(_) => "RangeError", - _ => "Error", - } -} - -fn get_serde_json_error_class( - error: &serde_json::error::Error, -) -> &'static str { - use deno_core::serde_json::error::*; - match error.classify() { - Category::Io => error - .source() - .and_then(|e| e.downcast_ref::()) - .map(get_io_error_class) - .unwrap(), - Category::Syntax => "SyntaxError", - Category::Data => "InvalidData", - Category::Eof => "UnexpectedEof", - } -} - -fn get_url_parse_error_class(_error: &url::ParseError) -> &'static str { - "URIError" -} - -fn get_hyper_error_class(_error: &hyper::Error) -> &'static str { - "Http" -} - -fn get_hyper_util_error_class( - _error: &hyper_util::client::legacy::Error, -) -> &'static str { - "Http" -} - -fn get_hyper_v014_error_class(_error: &hyper_v014::Error) -> &'static str { - "Http" -} - -#[cfg(unix)] -pub fn get_nix_error_class(error: &nix::Error) -> &'static str { - match error { - nix::Error::ECHILD => "NotFound", - nix::Error::EINVAL => "TypeError", - nix::Error::ENOENT => "NotFound", - nix::Error::ENOTTY => "BadResource", - nix::Error::EPERM => "PermissionDenied", - nix::Error::ESRCH => "NotFound", - nix::Error::ELOOP => "FilesystemLoop", - nix::Error::ENOTDIR => "NotADirectory", - nix::Error::ENETUNREACH => "NetworkUnreachable", - nix::Error::EISDIR => "IsADirectory", - nix::Error::UnknownErrno => "Error", - &nix::Error::ENOTSUP => unreachable!(), - _ => "Error", - } -} - -fn get_webgpu_error_class(e: &deno_webgpu::InitError) -> &'static str { - match e { - deno_webgpu::InitError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::InitError::InvalidAdapter(_) => "Error", - deno_webgpu::InitError::RequestDevice(_) => "DOMExceptionOperationError", - deno_webgpu::InitError::InvalidDevice(_) => "Error", - } -} - -fn get_webgpu_buffer_error_class( - e: &deno_webgpu::buffer::BufferError, -) -> &'static str { - match e { - deno_webgpu::buffer::BufferError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::buffer::BufferError::InvalidUsage => "TypeError", - deno_webgpu::buffer::BufferError::Access(_) => "DOMExceptionOperationError", - } -} - -fn get_webgpu_bundle_error_class( - e: &deno_webgpu::bundle::BundleError, -) -> &'static str { - match e { - deno_webgpu::bundle::BundleError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::bundle::BundleError::InvalidSize => "TypeError", - } -} - -fn get_webgpu_byow_error_class( - e: &deno_webgpu::byow::ByowError, -) -> &'static str { - match e { - deno_webgpu::byow::ByowError::WebGPUNotInitiated => "TypeError", - deno_webgpu::byow::ByowError::InvalidParameters => "TypeError", - deno_webgpu::byow::ByowError::CreateSurface(_) => "Error", - deno_webgpu::byow::ByowError::InvalidSystem => "TypeError", - #[cfg(any( - target_os = "windows", - target_os = "linux", - target_os = "freebsd", - target_os = "openbsd" - ))] - deno_webgpu::byow::ByowError::NullWindow => "TypeError", - #[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "openbsd" - ))] - deno_webgpu::byow::ByowError::NullDisplay => "TypeError", - #[cfg(target_os = "macos")] - deno_webgpu::byow::ByowError::NSViewDisplay => "TypeError", - } -} - -fn get_webgpu_render_pass_error_class( - e: &deno_webgpu::render_pass::RenderPassError, -) -> &'static str { - match e { - deno_webgpu::render_pass::RenderPassError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::render_pass::RenderPassError::InvalidSize => "TypeError", - } -} - -fn get_webgpu_surface_error_class( - e: &deno_webgpu::surface::SurfaceError, -) -> &'static str { - match e { - deno_webgpu::surface::SurfaceError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - deno_webgpu::surface::SurfaceError::Surface(_) => "Error", - deno_webgpu::surface::SurfaceError::InvalidStatus => "Error", - } -} - -fn get_crypto_decrypt_error_class(e: &DecryptError) -> &'static str { - match e { - DecryptError::General(e) => get_crypto_shared_error_class(e), - DecryptError::Pkcs1(_) => "Error", - DecryptError::Failed => "DOMExceptionOperationError", - DecryptError::InvalidLength => "TypeError", - DecryptError::InvalidCounterLength => "TypeError", - DecryptError::InvalidTagLength => "TypeError", - DecryptError::InvalidKeyOrIv => "DOMExceptionOperationError", - DecryptError::TooMuchData => "DOMExceptionOperationError", - DecryptError::InvalidIvLength => "TypeError", - DecryptError::Rsa(_) => "DOMExceptionOperationError", - } -} - -fn get_crypto_encrypt_error_class(e: &EncryptError) -> &'static str { - match e { - EncryptError::General(e) => get_crypto_shared_error_class(e), - EncryptError::InvalidKeyOrIv => "DOMExceptionOperationError", - EncryptError::Failed => "DOMExceptionOperationError", - EncryptError::InvalidLength => "TypeError", - EncryptError::InvalidIvLength => "TypeError", - EncryptError::InvalidCounterLength => "TypeError", - EncryptError::TooMuchData => "DOMExceptionOperationError", - } -} - -fn get_crypto_shared_error_class(e: &deno_crypto::SharedError) -> &'static str { - match e { - deno_crypto::SharedError::ExpectedValidPrivateKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPublicKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPrivateECKey => "TypeError", - deno_crypto::SharedError::ExpectedValidPublicECKey => "TypeError", - deno_crypto::SharedError::ExpectedPrivateKey => "TypeError", - deno_crypto::SharedError::ExpectedPublicKey => "TypeError", - deno_crypto::SharedError::ExpectedSecretKey => "TypeError", - deno_crypto::SharedError::FailedDecodePrivateKey => { - "DOMExceptionOperationError" - } - deno_crypto::SharedError::FailedDecodePublicKey => { - "DOMExceptionOperationError" - } - deno_crypto::SharedError::UnsupportedFormat => { - "DOMExceptionNotSupportedError" - } - } -} - -fn get_crypto_ed25519_error_class( - e: &deno_crypto::Ed25519Error, -) -> &'static str { - match e { - deno_crypto::Ed25519Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::Ed25519Error::Der(_) => "Error", - deno_crypto::Ed25519Error::KeyRejected(_) => "Error", - } -} - -fn get_crypto_export_key_error_class(e: &ExportKeyError) -> &'static str { - match e { - ExportKeyError::General(e) => get_crypto_shared_error_class(e), - ExportKeyError::Der(_) => "Error", - ExportKeyError::UnsupportedNamedCurve => "DOMExceptionNotSupportedError", - } -} - -fn get_crypto_generate_key_error_class(e: &GenerateKeyError) -> &'static str { - match e { - GenerateKeyError::General(e) => get_crypto_shared_error_class(e), - GenerateKeyError::BadPublicExponent => "DOMExceptionOperationError", - GenerateKeyError::InvalidHMACKeyLength => "DOMExceptionOperationError", - GenerateKeyError::FailedRSAKeySerialization => "DOMExceptionOperationError", - GenerateKeyError::InvalidAESKeyLength => "DOMExceptionOperationError", - GenerateKeyError::FailedRSAKeyGeneration => "DOMExceptionOperationError", - GenerateKeyError::FailedECKeyGeneration => "DOMExceptionOperationError", - GenerateKeyError::FailedKeyGeneration => "DOMExceptionOperationError", - } -} - -fn get_crypto_import_key_error_class(e: &ImportKeyError) -> &'static str { - match e { - ImportKeyError::General(e) => get_crypto_shared_error_class(e), - ImportKeyError::InvalidModulus => "DOMExceptionDataError", - ImportKeyError::InvalidPublicExponent => "DOMExceptionDataError", - ImportKeyError::InvalidPrivateExponent => "DOMExceptionDataError", - ImportKeyError::InvalidFirstPrimeFactor => "DOMExceptionDataError", - ImportKeyError::InvalidSecondPrimeFactor => "DOMExceptionDataError", - ImportKeyError::InvalidFirstCRTExponent => "DOMExceptionDataError", - ImportKeyError::InvalidSecondCRTExponent => "DOMExceptionDataError", - ImportKeyError::InvalidCRTCoefficient => "DOMExceptionDataError", - ImportKeyError::InvalidB64Coordinate => "DOMExceptionDataError", - ImportKeyError::InvalidRSAPublicKey => "DOMExceptionDataError", - ImportKeyError::InvalidRSAPrivateKey => "DOMExceptionDataError", - ImportKeyError::UnsupportedAlgorithm => "DOMExceptionDataError", - ImportKeyError::PublicKeyTooLong => "DOMExceptionDataError", - ImportKeyError::PrivateKeyTooLong => "DOMExceptionDataError", - ImportKeyError::InvalidP256ECPoint => "DOMExceptionDataError", - ImportKeyError::InvalidP384ECPoint => "DOMExceptionDataError", - ImportKeyError::InvalidP521ECPoint => "DOMExceptionDataError", - ImportKeyError::UnsupportedNamedCurve => "DOMExceptionDataError", - ImportKeyError::CurveMismatch => "DOMExceptionDataError", - ImportKeyError::InvalidKeyData => "DOMExceptionDataError", - ImportKeyError::InvalidJWKPrivateKey => "DOMExceptionDataError", - ImportKeyError::EllipticCurve(_) => "DOMExceptionDataError", - ImportKeyError::ExpectedValidPkcs8Data => "DOMExceptionDataError", - ImportKeyError::MalformedParameters => "DOMExceptionDataError", - ImportKeyError::Spki(_) => "DOMExceptionDataError", - ImportKeyError::InvalidP256ECSPKIData => "DOMExceptionDataError", - ImportKeyError::InvalidP384ECSPKIData => "DOMExceptionDataError", - ImportKeyError::InvalidP521ECSPKIData => "DOMExceptionDataError", - ImportKeyError::Der(_) => "DOMExceptionDataError", - } -} - -fn get_crypto_x448_error_class(e: &deno_crypto::X448Error) -> &'static str { - match e { - deno_crypto::X448Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::X448Error::Der(_) => "Error", - } -} - -fn get_crypto_x25519_error_class(e: &deno_crypto::X25519Error) -> &'static str { - match e { - deno_crypto::X25519Error::FailedExport => "DOMExceptionOperationError", - deno_crypto::X25519Error::Der(_) => "Error", - } -} - -fn get_crypto_error_class(e: &deno_crypto::Error) -> &'static str { - match e { - deno_crypto::Error::Der(_) => "Error", - deno_crypto::Error::JoinError(_) => "Error", - deno_crypto::Error::MissingArgumentHash => "TypeError", - deno_crypto::Error::MissingArgumentSaltLength => "TypeError", - deno_crypto::Error::Other(e) => get_error_class_name(e).unwrap_or("Error"), - deno_crypto::Error::UnsupportedAlgorithm => "TypeError", - deno_crypto::Error::KeyRejected(_) => "Error", - deno_crypto::Error::RSA(_) => "Error", - deno_crypto::Error::Pkcs1(_) => "Error", - deno_crypto::Error::Unspecified(_) => "Error", - deno_crypto::Error::InvalidKeyFormat => "TypeError", - deno_crypto::Error::MissingArgumentPublicKey => "TypeError", - deno_crypto::Error::P256Ecdsa(_) => "Error", - deno_crypto::Error::DecodePrivateKey => "TypeError", - deno_crypto::Error::MissingArgumentNamedCurve => "TypeError", - deno_crypto::Error::MissingArgumentInfo => "TypeError", - deno_crypto::Error::HKDFLengthTooLarge => "DOMExceptionOperationError", - deno_crypto::Error::General(e) => get_crypto_shared_error_class(e), - deno_crypto::Error::Base64Decode(_) => "Error", - deno_crypto::Error::DataInvalidSize => "TypeError", - deno_crypto::Error::InvalidKeyLength => "TypeError", - deno_crypto::Error::EncryptionError => "DOMExceptionOperationError", - deno_crypto::Error::DecryptionError => "DOMExceptionOperationError", - deno_crypto::Error::ArrayBufferViewLengthExceeded(_) => { - "DOMExceptionQuotaExceededError" - } - } -} - -fn get_napi_error_class(e: &NApiError) -> &'static str { - match e { - NApiError::InvalidPath - | NApiError::LibLoading(_) - | NApiError::ModuleNotFound(_) => "TypeError", - NApiError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_web_error_class(e: &WebError) -> &'static str { - match e { - WebError::Base64Decode => "DOMExceptionInvalidCharacterError", - WebError::InvalidEncodingLabel(_) => "RangeError", - WebError::BufferTooLong => "TypeError", - WebError::ValueTooLarge => "RangeError", - WebError::BufferTooSmall => "RangeError", - WebError::DataInvalid => "TypeError", - WebError::DataError(_) => "Error", - } -} - -fn get_web_compression_error_class(e: &CompressionError) -> &'static str { - match e { - CompressionError::UnsupportedFormat => "TypeError", - CompressionError::ResourceClosed => "TypeError", - CompressionError::IoTypeError(_) => "TypeError", - CompressionError::Io(e) => get_io_error_class(e), - } -} - -fn get_web_message_port_error_class(e: &MessagePortError) -> &'static str { - match e { - MessagePortError::InvalidTransfer => "TypeError", - MessagePortError::NotReady => "TypeError", - MessagePortError::TransferSelf => "TypeError", - MessagePortError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - MessagePortError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_web_stream_resource_error_class( - e: &StreamResourceError, -) -> &'static str { - match e { - StreamResourceError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - StreamResourceError::Js(_) => "TypeError", - } -} - -fn get_web_blob_error_class(e: &BlobError) -> &'static str { - match e { - BlobError::BlobPartNotFound => "TypeError", - BlobError::SizeLargerThanBlobPart => "TypeError", - BlobError::BlobURLsNotSupported => "TypeError", - BlobError::Url(_) => "Error", - } -} - -fn get_ffi_repr_error_class(e: &ReprError) -> &'static str { - match e { - ReprError::InvalidOffset => "TypeError", - ReprError::InvalidArrayBuffer => "TypeError", - ReprError::DestinationLengthTooShort => "RangeError", - ReprError::InvalidCString => "TypeError", - ReprError::CStringTooLong => "TypeError", - ReprError::InvalidBool => "TypeError", - ReprError::InvalidU8 => "TypeError", - ReprError::InvalidI8 => "TypeError", - ReprError::InvalidU16 => "TypeError", - ReprError::InvalidI16 => "TypeError", - ReprError::InvalidU32 => "TypeError", - ReprError::InvalidI32 => "TypeError", - ReprError::InvalidU64 => "TypeError", - ReprError::InvalidI64 => "TypeError", - ReprError::InvalidF32 => "TypeError", - ReprError::InvalidF64 => "TypeError", - ReprError::InvalidPointer => "TypeError", - ReprError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_ffi_dlfcn_error_class(e: &DlfcnError) -> &'static str { - match e { - DlfcnError::RegisterSymbol { .. } => "Error", - DlfcnError::Dlopen(_) => "Error", - DlfcnError::Permission(e) => get_permission_check_error_class(e), - DlfcnError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_ffi_static_error_class(e: &StaticError) -> &'static str { - match e { - StaticError::Dlfcn(e) => get_ffi_dlfcn_error_class(e), - StaticError::InvalidTypeVoid => "TypeError", - StaticError::InvalidTypeStruct => "TypeError", - StaticError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_ffi_callback_error_class(e: &CallbackError) -> &'static str { - match e { - CallbackError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - CallbackError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - CallbackError::Permission(e) => get_permission_check_error_class(e), - } -} - -fn get_ffi_call_error_class(e: &CallError) -> &'static str { - match e { - CallError::IR(_) => "TypeError", - CallError::NonblockingCallFailure(_) => "Error", - CallError::InvalidSymbol(_) => "TypeError", - CallError::Permission(e) => get_permission_check_error_class(e), - CallError::Callback(e) => get_ffi_callback_error_class(e), - CallError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_webstorage_class_name(e: &WebStorageError) -> &'static str { - match e { - WebStorageError::ContextNotSupported => "DOMExceptionNotSupportedError", - WebStorageError::Sqlite(_) => todo!(), - WebStorageError::Io(e) => get_io_error_class(e), - WebStorageError::StorageExceeded => "DOMExceptionQuotaExceededError", - } -} - -fn get_tls_error_class(e: &TlsError) -> &'static str { - match e { - TlsError::Rustls(_) => "Error", - TlsError::UnableAddPemFileToCert(e) => get_io_error_class(e), - TlsError::CertInvalid - | TlsError::CertsNotFound - | TlsError::KeysNotFound - | TlsError::KeyDecode => "InvalidData", - } -} - -pub fn get_cron_error_class(e: &CronError) -> &'static str { - match e { - CronError::Resource(e) => { - deno_core::error::get_custom_error_class(e).unwrap_or("Error") - } - CronError::NameExceeded(_) => "TypeError", - CronError::NameInvalid => "TypeError", - CronError::AlreadyExists => "TypeError", - CronError::TooManyCrons => "TypeError", - CronError::InvalidCron => "TypeError", - CronError::InvalidBackoff => "TypeError", - CronError::AcquireError(_) => "Error", - CronError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_canvas_error(e: &CanvasError) -> &'static str { - match e { - CanvasError::UnsupportedColorType(_) => "TypeError", - CanvasError::Image(_) => "Error", - } -} - -pub fn get_cache_error(error: &CacheError) -> &'static str { - match error { - CacheError::Sqlite(_) => "Error", - CacheError::JoinError(_) => "Error", - CacheError::Resource(err) => { - deno_core::error::get_custom_error_class(err).unwrap_or("Error") - } - CacheError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - CacheError::Io(err) => get_io_error_class(err), - } -} - -fn get_broadcast_channel_error(error: &BroadcastChannelError) -> &'static str { - match error { - BroadcastChannelError::Resource(err) => { - deno_core::error::get_custom_error_class(err).unwrap() - } - BroadcastChannelError::MPSCSendError(_) => "Error", - BroadcastChannelError::BroadcastSendError(_) => "Error", - BroadcastChannelError::Other(err) => { - get_error_class_name(err).unwrap_or("Error") - } - } -} - -fn get_fetch_error(error: &FetchError) -> &'static str { - match error { - FetchError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - FetchError::Permission(e) => get_permission_check_error_class(e), - FetchError::NetworkError => "TypeError", - FetchError::FsNotGet(_) => "TypeError", - FetchError::InvalidUrl(_) => "TypeError", - FetchError::InvalidHeaderName(_) => "TypeError", - FetchError::InvalidHeaderValue(_) => "TypeError", - FetchError::DataUrl(_) => "TypeError", - FetchError::Base64(_) => "TypeError", - FetchError::BlobNotFound => "TypeError", - FetchError::SchemeNotSupported(_) => "TypeError", - FetchError::RequestCanceled => "TypeError", - FetchError::Http(_) => "Error", - FetchError::ClientCreate(e) => get_http_client_create_error(e), - FetchError::Url(e) => get_url_parse_error_class(e), - FetchError::Method(_) => "TypeError", - FetchError::ClientSend(_) => "TypeError", - FetchError::RequestBuilderHook(_) => "TypeError", - FetchError::Io(e) => get_io_error_class(e), - FetchError::Hyper(e) => get_hyper_error_class(e), - } -} - -fn get_http_client_create_error(error: &HttpClientCreateError) -> &'static str { - match error { - HttpClientCreateError::Tls(_) => "TypeError", - HttpClientCreateError::InvalidUserAgent(_) => "TypeError", - HttpClientCreateError::InvalidProxyUrl => "TypeError", - HttpClientCreateError::HttpVersionSelectionInvalid => "TypeError", - HttpClientCreateError::RootCertStore(_) => "TypeError", - } -} - -fn get_websocket_error(error: &WebsocketError) -> &'static str { - match error { - WebsocketError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - WebsocketError::Permission(e) => get_permission_check_error_class(e), - WebsocketError::Url(e) => get_url_parse_error_class(e), - WebsocketError::Io(e) => get_io_error_class(e), - WebsocketError::WebSocket(_) => "TypeError", - WebsocketError::ConnectionFailed(_) => "DOMExceptionNetworkError", - WebsocketError::Uri(_) => "Error", - WebsocketError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - } -} - -fn get_websocket_handshake_error(error: &HandshakeError) -> &'static str { - match error { - HandshakeError::RootStoreError(e) => { - get_error_class_name(e).unwrap_or("Error") - } - HandshakeError::Tls(e) => get_tls_error_class(e), - HandshakeError::MissingPath => "TypeError", - HandshakeError::Http(_) => "Error", - HandshakeError::InvalidHostname(_) => "TypeError", - HandshakeError::Io(e) => get_io_error_class(e), - HandshakeError::Rustls(_) => "Error", - HandshakeError::H2(_) => "Error", - HandshakeError::NoH2Alpn => "Error", - HandshakeError::InvalidStatusCode(_) => "Error", - HandshakeError::WebSocket(_) => "TypeError", - HandshakeError::HeaderName(_) => "TypeError", - HandshakeError::HeaderValue(_) => "TypeError", - } -} - -fn get_fs_ops_error(error: &FsOpsError) -> &'static str { - match error { - FsOpsError::Io(e) => get_io_error_class(e), - FsOpsError::OperationError(e) => get_fs_error(&e.err), - FsOpsError::Permission(e) => get_permission_check_error_class(e), - FsOpsError::Resource(e) | FsOpsError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - FsOpsError::InvalidUtf8(_) => "InvalidData", - FsOpsError::StripPrefix(_) => "Error", - FsOpsError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - FsOpsError::InvalidSeekMode(_) => "TypeError", - FsOpsError::InvalidControlCharacter(_) => "Error", - FsOpsError::InvalidCharacter(_) => "Error", - #[cfg(windows)] - FsOpsError::InvalidTrailingCharacter => "Error", - FsOpsError::NotCapableAccess { .. } => "NotCapable", - FsOpsError::NotCapable(_) => "NotCapable", - } -} - -fn get_kv_error(error: &KvError) -> &'static str { - match error { - KvError::DatabaseHandler(e) | KvError::Resource(e) | KvError::Kv(e) => { - get_error_class_name(e).unwrap_or("Error") - } - KvError::TooManyRanges(_) => "TypeError", - KvError::TooManyEntries(_) => "TypeError", - KvError::TooManyChecks(_) => "TypeError", - KvError::TooManyMutations(_) => "TypeError", - KvError::TooManyKeys(_) => "TypeError", - KvError::InvalidLimit => "TypeError", - KvError::InvalidBoundaryKey => "TypeError", - KvError::KeyTooLargeToRead(_) => "TypeError", - KvError::KeyTooLargeToWrite(_) => "TypeError", - KvError::TotalMutationTooLarge(_) => "TypeError", - KvError::TotalKeyTooLarge(_) => "TypeError", - KvError::Io(e) => get_io_error_class(e), - KvError::QueueMessageNotFound => "TypeError", - KvError::StartKeyNotInKeyspace => "TypeError", - KvError::EndKeyNotInKeyspace => "TypeError", - KvError::StartKeyGreaterThanEndKey => "TypeError", - KvError::InvalidCheck(e) => match e { - KvCheckError::InvalidVersionstamp => "TypeError", - KvCheckError::Io(e) => get_io_error_class(e), - }, - KvError::InvalidMutation(e) => match e { - KvMutationError::BigInt(_) => "Error", - KvMutationError::Io(e) => get_io_error_class(e), - KvMutationError::InvalidMutationWithValue(_) => "TypeError", - KvMutationError::InvalidMutationWithoutValue(_) => "TypeError", - }, - KvError::InvalidEnqueue(e) => get_io_error_class(e), - KvError::EmptyKey => "TypeError", - KvError::ValueTooLarge(_) => "TypeError", - KvError::EnqueuePayloadTooLarge(_) => "TypeError", - KvError::InvalidCursor => "TypeError", - KvError::CursorOutOfBounds => "TypeError", - KvError::InvalidRange => "TypeError", - } -} - -fn get_net_error(error: &NetError) -> &'static str { - match error { - NetError::ListenerClosed => "BadResource", - NetError::ListenerBusy => "Busy", - NetError::SocketClosed => "BadResource", - NetError::SocketClosedNotConnected => "NotConnected", - NetError::SocketBusy => "Busy", - NetError::Io(e) => get_io_error_class(e), - NetError::AcceptTaskOngoing => "Busy", - NetError::RootCertStore(e) | NetError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - NetError::Permission(e) => get_permission_check_error_class(e), - NetError::NoResolvedAddress => "Error", - NetError::AddrParse(_) => "Error", - NetError::Map(e) => get_net_map_error(e), - NetError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - NetError::DnsNotFound(_) => "NotFound", - NetError::DnsNotConnected(_) => "NotConnected", - NetError::DnsTimedOut(_) => "TimedOut", - NetError::Dns(_) => "Error", - NetError::UnsupportedRecordType => "NotSupported", - NetError::InvalidUtf8(_) => "InvalidData", - NetError::UnexpectedKeyType => "Error", - NetError::InvalidHostname(_) => "TypeError", - NetError::TcpStreamBusy => "Busy", - NetError::Rustls(_) => "Error", - NetError::Tls(e) => get_tls_error_class(e), - NetError::ListenTlsRequiresKey => "InvalidData", - NetError::Reunite(_) => "Error", - } -} - -fn get_net_map_error(error: &deno_net::io::MapError) -> &'static str { - match error { - deno_net::io::MapError::Io(e) => get_io_error_class(e), - deno_net::io::MapError::NoResources => "Error", - } -} - -fn get_child_permission_error(e: &ChildPermissionError) -> &'static str { - match e { - ChildPermissionError::Escalation => "NotCapable", - ChildPermissionError::PathResolve(e) => get_path_resolve_error(e), - ChildPermissionError::NetDescriptorParse(_) => "URIError", - ChildPermissionError::EnvDescriptorParse(_) => "Error", - ChildPermissionError::SysDescriptorParse(e) => { - get_sys_descriptor_parse_error(e) - } - ChildPermissionError::RunDescriptorParse(e) => { - get_run_descriptor_parse_error(e) - } - } -} - -fn get_create_worker_error(error: &CreateWorkerError) -> &'static str { - match error { - CreateWorkerError::ClassicWorkers => "DOMExceptionNotSupportedError", - CreateWorkerError::Permission(e) => get_child_permission_error(e), - CreateWorkerError::ModuleResolution(e) => { - get_module_resolution_error_class(e) - } - CreateWorkerError::Io(e) => get_io_error_class(e), - CreateWorkerError::MessagePort(e) => get_web_message_port_error_class(e), - } -} - -fn get_tty_error(error: &TtyError) -> &'static str { - match error { - TtyError::Resource(e) | TtyError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - TtyError::Io(e) => get_io_error_class(e), - #[cfg(unix)] - TtyError::Nix(e) => get_nix_error_class(e), - } -} - -fn get_readline_error(error: &ReadlineError) -> &'static str { - match error { - ReadlineError::Io(e) => get_io_error_class(e), - ReadlineError::Eof => "Error", - ReadlineError::Interrupted => "Error", - #[cfg(unix)] - ReadlineError::Errno(e) => get_nix_error_class(e), - ReadlineError::WindowResized => "Error", - #[cfg(windows)] - ReadlineError::Decode(_) => "Error", - #[cfg(windows)] - ReadlineError::SystemError(_) => "Error", - _ => "Error", - } -} - -fn get_signal_error(error: &SignalError) -> &'static str { - match error { - SignalError::InvalidSignalStr(_) => "TypeError", - SignalError::InvalidSignalInt(_) => "TypeError", - SignalError::SignalNotAllowed(_) => "TypeError", - SignalError::Io(e) => get_io_error_class(e), - } -} - -fn get_fs_events_error(error: &FsEventsError) -> &'static str { - match error { - FsEventsError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - FsEventsError::Permission(e) => get_permission_check_error_class(e), - FsEventsError::Notify(e) => get_notify_error_class(e), - FsEventsError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - } -} - -fn get_http_start_error(error: &HttpStartError) -> &'static str { - match error { - HttpStartError::TcpStreamInUse => "Busy", - HttpStartError::TlsStreamInUse => "Busy", - HttpStartError::UnixSocketInUse => "Busy", - HttpStartError::ReuniteTcp(_) => "Error", - #[cfg(unix)] - HttpStartError::ReuniteUnix(_) => "Error", - HttpStartError::Io(e) => get_io_error_class(e), - HttpStartError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -fn get_process_error(error: &ProcessError) -> &'static str { - match error { - ProcessError::SpawnFailed { error, .. } => get_process_error(error), - ProcessError::FailedResolvingCwd(e) | ProcessError::Io(e) => { - get_io_error_class(e) - } - ProcessError::Permission(e) => get_permission_check_error_class(e), - ProcessError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - ProcessError::BorrowMut(_) => "Error", - ProcessError::Which(_) => "Error", - ProcessError::ChildProcessAlreadyTerminated => "TypeError", - ProcessError::Signal(e) => get_signal_error(e), - ProcessError::MissingCmd => "Error", - ProcessError::InvalidPid => "TypeError", - #[cfg(unix)] - ProcessError::Nix(e) => get_nix_error_class(e), - ProcessError::RunPermission(e) => match e { - CheckRunPermissionError::Permission(e) => { - get_permission_check_error_class(e) - } - CheckRunPermissionError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - }, - } -} - -fn get_http_error(error: &HttpError) -> &'static str { - match error { - HttpError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - HttpError::HyperV014(e) => get_hyper_v014_error_class(e), - HttpError::InvalidHeaderName(_) => "Error", - HttpError::InvalidHeaderValue(_) => "Error", - HttpError::Http(_) => "Error", - HttpError::ResponseHeadersAlreadySent => "Http", - HttpError::ConnectionClosedWhileSendingResponse => "Http", - HttpError::AlreadyInUse => "Http", - HttpError::Io(e) => get_io_error_class(e), - HttpError::NoResponseHeaders => "Http", - HttpError::ResponseAlreadyCompleted => "Http", - HttpError::UpgradeBodyUsed => "Http", - HttpError::Resource(e) | HttpError::Other(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } -} - -fn get_http_next_error(error: &HttpNextError) -> &'static str { - match error { - HttpNextError::Io(e) => get_io_error_class(e), - HttpNextError::WebSocketUpgrade(e) => get_websocket_upgrade_error(e), - HttpNextError::Hyper(e) => get_hyper_error_class(e), - HttpNextError::JoinError(_) => "Error", - HttpNextError::Canceled(e) => { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - HttpNextError::UpgradeUnavailable(_) => "Error", - HttpNextError::HttpPropertyExtractor(e) | HttpNextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } -} - -fn get_websocket_upgrade_error(error: &WebSocketUpgradeError) -> &'static str { - match error { - WebSocketUpgradeError::InvalidHeaders => "Http", - WebSocketUpgradeError::HttpParse(_) => "Error", - WebSocketUpgradeError::Http(_) => "Error", - WebSocketUpgradeError::Utf8(_) => "Error", - WebSocketUpgradeError::InvalidHeaderName(_) => "Error", - WebSocketUpgradeError::InvalidHeaderValue(_) => "Error", - WebSocketUpgradeError::InvalidHttpStatusLine => "Http", - WebSocketUpgradeError::UpgradeBufferAlreadyCompleted => "Http", - } -} - -fn get_fs_error(e: &FsError) -> &'static str { - match &e { - FsError::Io(e) => get_io_error_class(e), - FsError::FileBusy => "Busy", - FsError::NotSupported => "NotSupported", - FsError::NotCapable(_) => "NotCapable", - } -} - -mod node { - use super::get_error_class_name; - use super::get_io_error_class; - use super::get_permission_check_error_class; - use super::get_serde_json_error_class; - use super::get_url_parse_error_class; - pub use deno_node::ops::blocklist::BlocklistError; - pub use deno_node::ops::crypto::cipher::CipherContextError; - pub use deno_node::ops::crypto::cipher::CipherError; - pub use deno_node::ops::crypto::cipher::DecipherContextError; - pub use deno_node::ops::crypto::cipher::DecipherError; - pub use deno_node::ops::crypto::digest::HashError; - pub use deno_node::ops::crypto::keys::AsymmetricPrivateKeyDerError; - pub use deno_node::ops::crypto::keys::AsymmetricPrivateKeyError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyDerError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyError; - pub use deno_node::ops::crypto::keys::AsymmetricPublicKeyJwkError; - pub use deno_node::ops::crypto::keys::EcJwkError; - pub use deno_node::ops::crypto::keys::EdRawError; - pub use deno_node::ops::crypto::keys::ExportPrivateKeyPemError; - pub use deno_node::ops::crypto::keys::ExportPublicKeyPemError; - pub use deno_node::ops::crypto::keys::GenerateRsaPssError; - pub use deno_node::ops::crypto::keys::RsaJwkError; - pub use deno_node::ops::crypto::keys::RsaPssParamsParseError; - pub use deno_node::ops::crypto::keys::X509PublicKeyError; - pub use deno_node::ops::crypto::sign::KeyObjectHandlePrehashedSignAndVerifyError; - pub use deno_node::ops::crypto::x509::X509Error; - pub use deno_node::ops::crypto::DiffieHellmanError; - pub use deno_node::ops::crypto::EcdhEncodePubKey; - pub use deno_node::ops::crypto::HkdfError; - pub use deno_node::ops::crypto::Pbkdf2Error; - pub use deno_node::ops::crypto::PrivateEncryptDecryptError; - pub use deno_node::ops::crypto::ScryptAsyncError; - pub use deno_node::ops::crypto::SignEd25519Error; - pub use deno_node::ops::crypto::VerifyEd25519Error; - pub use deno_node::ops::fs::FsError; - pub use deno_node::ops::http2::Http2Error; - pub use deno_node::ops::idna::IdnaError; - pub use deno_node::ops::ipc::IpcError; - pub use deno_node::ops::ipc::IpcJsonStreamError; - use deno_node::ops::os::priority::PriorityError; - pub use deno_node::ops::os::OsError; - pub use deno_node::ops::require::RequireError; - pub use deno_node::ops::worker_threads::WorkerThreadsFilenameError; - pub use deno_node::ops::zlib::brotli::BrotliError; - pub use deno_node::ops::zlib::mode::ModeError; - pub use deno_node::ops::zlib::ZlibError; - - pub fn get_blocklist_error(error: &BlocklistError) -> &'static str { - match error { - BlocklistError::AddrParse(_) => "Error", - BlocklistError::IpNetwork(_) => "Error", - BlocklistError::InvalidAddress => "Error", - BlocklistError::IpVersionMismatch => "Error", - } - } - - pub fn get_fs_error(error: &FsError) -> &'static str { - match error { - FsError::Permission(e) => get_permission_check_error_class(e), - FsError::Io(e) => get_io_error_class(e), - #[cfg(windows)] - FsError::PathHasNoRoot => "Error", - #[cfg(not(any(unix, windows)))] - FsError::UnsupportedPlatform => "Error", - FsError::Fs(e) => super::get_fs_error(e), - } - } - - pub fn get_idna_error(error: &IdnaError) -> &'static str { - match error { - IdnaError::InvalidInput => "RangeError", - IdnaError::InputTooLong => "Error", - IdnaError::IllegalInput => "RangeError", - } - } - - pub fn get_ipc_json_stream_error(error: &IpcJsonStreamError) -> &'static str { - match error { - IpcJsonStreamError::Io(e) => get_io_error_class(e), - IpcJsonStreamError::SimdJson(_) => "Error", - } - } - - pub fn get_ipc_error(error: &IpcError) -> &'static str { - match error { - IpcError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - IpcError::IpcJsonStream(e) => get_ipc_json_stream_error(e), - IpcError::Canceled(e) => { - let io_err: std::io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - } - IpcError::SerdeJson(e) => get_serde_json_error_class(e), - } - } - - pub fn get_worker_threads_filename_error( - error: &WorkerThreadsFilenameError, - ) -> &'static str { - match error { - WorkerThreadsFilenameError::Permission(e) => { - get_error_class_name(e).unwrap_or("Error") - } - WorkerThreadsFilenameError::UrlParse(e) => get_url_parse_error_class(e), - WorkerThreadsFilenameError::InvalidRelativeUrl => "Error", - WorkerThreadsFilenameError::UrlFromPathString => "Error", - WorkerThreadsFilenameError::UrlToPathString => "Error", - WorkerThreadsFilenameError::UrlToPath => "Error", - WorkerThreadsFilenameError::FileNotFound(_) => "Error", - WorkerThreadsFilenameError::Fs(e) => super::get_fs_error(e), - } - } - - pub fn get_require_error(error: &RequireError) -> &'static str { - match error { - RequireError::UrlParse(e) => get_url_parse_error_class(e), - RequireError::Permission(e) => get_error_class_name(e).unwrap_or("Error"), - RequireError::PackageExportsResolve(_) - | RequireError::PackageJsonLoad(_) - | RequireError::ClosestPkgJson(_) - | RequireError::FilePathConversion(_) - | RequireError::UrlConversion(_) - | RequireError::ReadModule(_) - | RequireError::PackageImportsResolve(_) => "Error", - RequireError::Fs(e) | RequireError::UnableToGetCwd(e) => { - super::get_fs_error(e) - } - } - } - - pub fn get_http2_error(error: &Http2Error) -> &'static str { - match error { - Http2Error::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - Http2Error::UrlParse(e) => get_url_parse_error_class(e), - Http2Error::H2(_) => "Error", - } - } - - pub fn get_os_error(error: &OsError) -> &'static str { - match error { - OsError::Priority(e) => match e { - PriorityError::Io(e) => get_io_error_class(e), - #[cfg(windows)] - PriorityError::InvalidPriority => "TypeError", - }, - OsError::Permission(e) => get_permission_check_error_class(e), - OsError::FailedToGetCpuInfo => "TypeError", - OsError::FailedToGetUserInfo(e) => get_io_error_class(e), - } - } - - pub fn get_brotli_error(error: &BrotliError) -> &'static str { - match error { - BrotliError::InvalidEncoderMode => "TypeError", - BrotliError::CompressFailed => "TypeError", - BrotliError::DecompressFailed => "TypeError", - BrotliError::Join(_) => "Error", - BrotliError::Resource(e) => get_error_class_name(e).unwrap_or("Error"), - BrotliError::Io(e) => get_io_error_class(e), - } - } - - pub fn get_mode_error(_: &ModeError) -> &'static str { - "Error" - } - - pub fn get_zlib_error(e: &ZlibError) -> &'static str { - match e { - ZlibError::NotInitialized => "TypeError", - ZlibError::Mode(e) => get_mode_error(e), - ZlibError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } - } - - pub fn get_crypto_cipher_context_error( - e: &CipherContextError, - ) -> &'static str { - match e { - CipherContextError::ContextInUse => "TypeError", - CipherContextError::Cipher(e) => get_crypto_cipher_error(e), - CipherContextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } - } - - pub fn get_crypto_cipher_error(e: &CipherError) -> &'static str { - match e { - CipherError::InvalidIvLength => "TypeError", - CipherError::InvalidKeyLength => "RangeError", - CipherError::InvalidInitializationVector => "TypeError", - CipherError::CannotPadInputData => "TypeError", - CipherError::UnknownCipher(_) => "TypeError", - } - } - - pub fn get_crypto_decipher_context_error( - e: &DecipherContextError, - ) -> &'static str { - match e { - DecipherContextError::ContextInUse => "TypeError", - DecipherContextError::Decipher(e) => get_crypto_decipher_error(e), - DecipherContextError::Resource(e) => { - get_error_class_name(e).unwrap_or("Error") - } - } - } - - pub fn get_crypto_decipher_error(e: &DecipherError) -> &'static str { - match e { - DecipherError::InvalidIvLength => "TypeError", - DecipherError::InvalidKeyLength => "RangeError", - DecipherError::InvalidInitializationVector => "TypeError", - DecipherError::CannotUnpadInputData => "TypeError", - DecipherError::DataAuthenticationFailed => "TypeError", - DecipherError::SetAutoPaddingFalseAes128GcmUnsupported => "TypeError", - DecipherError::SetAutoPaddingFalseAes256GcmUnsupported => "TypeError", - DecipherError::UnknownCipher(_) => "TypeError", - } - } - - pub fn get_x509_error(_: &X509Error) -> &'static str { - "Error" - } - - pub fn get_crypto_key_object_handle_prehashed_sign_and_verify_error( - e: &KeyObjectHandlePrehashedSignAndVerifyError, - ) -> &'static str { - match e { - KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignatureEncoding => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPrivate => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaSignature(_) => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsa => "Error", - KeyObjectHandlePrehashedSignAndVerifyError::DigestNotAllowedForRsaPssSignature(_) => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithRsaPss => "Error", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigestWithDsa => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::RsaPssHashAlgorithmUnsupported => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::PrivateKeyDisallowsUsage { .. } => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::FailedToSignDigest => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForSigning => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::KeyIsNotPublicOrPrivate => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::InvalidDsaSignature => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::X25519KeyCannotBeUsedForVerification => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::Ed25519KeyCannotBeUsedForPrehashedVerification => "TypeError", - KeyObjectHandlePrehashedSignAndVerifyError::DhKeyCannotBeUsedForVerification => "TypeError", - } - } - - pub fn get_crypto_hash_error(_: &HashError) -> &'static str { - "Error" - } - - pub fn get_asymmetric_public_key_jwk_error( - e: &AsymmetricPublicKeyJwkError, - ) -> &'static str { - match e { - AsymmetricPublicKeyJwkError::UnsupportedJwkEcCurveP224 => "TypeError", - AsymmetricPublicKeyJwkError::JwkExportNotImplementedForKeyType => { - "TypeError" - } - AsymmetricPublicKeyJwkError::KeyIsNotAsymmetricPublicKey => "TypeError", - } - } - - pub fn get_generate_rsa_pss_error(_: &GenerateRsaPssError) -> &'static str { - "TypeError" - } - - pub fn get_asymmetric_private_key_der_error( - e: &AsymmetricPrivateKeyDerError, - ) -> &'static str { - match e { - AsymmetricPrivateKeyDerError::KeyIsNotAsymmetricPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidRsaPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonRsaPrivateKeyAsPkcs1Unsupported => "TypeError", - AsymmetricPrivateKeyDerError::InvalidEcPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonEcPrivateKeyAsSec1Unsupported => "TypeError", - AsymmetricPrivateKeyDerError::ExportingNonRsaPssPrivateKeyAsPkcs8Unsupported => "Error", - AsymmetricPrivateKeyDerError::InvalidDsaPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidX25519PrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidEd25519PrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::InvalidDhPrivateKey => "TypeError", - AsymmetricPrivateKeyDerError::UnsupportedKeyType(_) => "TypeError", - } - } - - pub fn get_asymmetric_public_key_der_error( - _: &AsymmetricPublicKeyDerError, - ) -> &'static str { - "TypeError" - } - - pub fn get_export_public_key_pem_error( - e: &ExportPublicKeyPemError, - ) -> &'static str { - match e { - ExportPublicKeyPemError::AsymmetricPublicKeyDer(e) => { - get_asymmetric_public_key_der_error(e) - } - ExportPublicKeyPemError::VeryLargeData => "TypeError", - ExportPublicKeyPemError::Der(_) => "Error", - } - } - - pub fn get_export_private_key_pem_error( - e: &ExportPrivateKeyPemError, - ) -> &'static str { - match e { - ExportPrivateKeyPemError::AsymmetricPublicKeyDer(e) => { - get_asymmetric_private_key_der_error(e) - } - ExportPrivateKeyPemError::VeryLargeData => "TypeError", - ExportPrivateKeyPemError::Der(_) => "Error", - } - } - - pub fn get_x509_public_key_error(e: &X509PublicKeyError) -> &'static str { - match e { - X509PublicKeyError::X509(_) => "Error", - X509PublicKeyError::Rsa(_) => "Error", - X509PublicKeyError::Asn1(_) => "Error", - X509PublicKeyError::Ec(_) => "Error", - X509PublicKeyError::UnsupportedEcNamedCurve => "TypeError", - X509PublicKeyError::MissingEcParameters => "TypeError", - X509PublicKeyError::MalformedDssPublicKey => "TypeError", - X509PublicKeyError::UnsupportedX509KeyType => "TypeError", - } - } - - pub fn get_rsa_jwk_error(e: &RsaJwkError) -> &'static str { - match e { - RsaJwkError::Base64(_) => "Error", - RsaJwkError::Rsa(_) => "Error", - RsaJwkError::MissingRsaPrivateComponent => "TypeError", - } - } - - pub fn get_ec_jwk_error(e: &EcJwkError) -> &'static str { - match e { - EcJwkError::Ec(_) => "Error", - EcJwkError::UnsupportedCurve(_) => "TypeError", - } - } - - pub fn get_ed_raw_error(e: &EdRawError) -> &'static str { - match e { - EdRawError::Ed25519Signature(_) => "Error", - EdRawError::InvalidEd25519Key => "TypeError", - EdRawError::UnsupportedCurve => "TypeError", - } - } - - pub fn get_pbkdf2_error(e: &Pbkdf2Error) -> &'static str { - match e { - Pbkdf2Error::UnsupportedDigest(_) => "TypeError", - Pbkdf2Error::Join(_) => "Error", - } - } - - pub fn get_scrypt_async_error(e: &ScryptAsyncError) -> &'static str { - match e { - ScryptAsyncError::Join(_) => "Error", - ScryptAsyncError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } - } - - pub fn get_hkdf_error_error(e: &HkdfError) -> &'static str { - match e { - HkdfError::ExpectedSecretKey => "TypeError", - HkdfError::HkdfExpandFailed => "TypeError", - HkdfError::UnsupportedDigest(_) => "TypeError", - HkdfError::Join(_) => "Error", - } - } - - pub fn get_rsa_pss_params_parse_error( - _: &RsaPssParamsParseError, - ) -> &'static str { - "TypeError" - } - - pub fn get_asymmetric_private_key_error( - e: &AsymmetricPrivateKeyError, - ) -> &'static str { - match e { - AsymmetricPrivateKeyError::InvalidPemPrivateKeyInvalidUtf8(_) => "TypeError", - AsymmetricPrivateKeyError::InvalidEncryptedPemPrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidPemPrivateKey => "TypeError", - AsymmetricPrivateKeyError::EncryptedPrivateKeyRequiresPassphraseToDecrypt => "TypeError", - AsymmetricPrivateKeyError::InvalidPkcs1PrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidSec1PrivateKey => "TypeError", - AsymmetricPrivateKeyError::UnsupportedPemLabel(_) => "TypeError", - AsymmetricPrivateKeyError::RsaPssParamsParse(e) => get_rsa_pss_params_parse_error(e), - AsymmetricPrivateKeyError::InvalidEncryptedPkcs8PrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidPkcs8PrivateKey => "TypeError", - AsymmetricPrivateKeyError::Pkcs1PrivateKeyDoesNotSupportEncryptionWithPassphrase => "TypeError", - AsymmetricPrivateKeyError::Sec1PrivateKeyDoesNotSupportEncryptionWithPassphrase => "TypeError", - AsymmetricPrivateKeyError::UnsupportedEcNamedCurve => "TypeError", - AsymmetricPrivateKeyError::InvalidPrivateKey => "TypeError", - AsymmetricPrivateKeyError::InvalidDsaPrivateKey => "TypeError", - AsymmetricPrivateKeyError::MalformedOrMissingNamedCurveInEcParameters => "TypeError", - AsymmetricPrivateKeyError::UnsupportedKeyType(_) => "TypeError", - AsymmetricPrivateKeyError::UnsupportedKeyFormat(_) => "TypeError", - AsymmetricPrivateKeyError::InvalidX25519PrivateKey => "TypeError", - AsymmetricPrivateKeyError::X25519PrivateKeyIsWrongLength => "TypeError", - AsymmetricPrivateKeyError::InvalidEd25519PrivateKey => "TypeError", - AsymmetricPrivateKeyError::MissingDhParameters => "TypeError", - AsymmetricPrivateKeyError::UnsupportedPrivateKeyOid => "TypeError", - } - } - - pub fn get_asymmetric_public_key_error( - e: &AsymmetricPublicKeyError, - ) -> &'static str { - match e { - AsymmetricPublicKeyError::InvalidPemPrivateKeyInvalidUtf8(_) => { - "TypeError" - } - AsymmetricPublicKeyError::InvalidPemPublicKey => "TypeError", - AsymmetricPublicKeyError::InvalidPkcs1PublicKey => "TypeError", - AsymmetricPublicKeyError::AsymmetricPrivateKey(e) => { - get_asymmetric_private_key_error(e) - } - AsymmetricPublicKeyError::InvalidX509Certificate => "TypeError", - AsymmetricPublicKeyError::X509(_) => "Error", - AsymmetricPublicKeyError::X509PublicKey(e) => { - get_x509_public_key_error(e) - } - AsymmetricPublicKeyError::UnsupportedPemLabel(_) => "TypeError", - AsymmetricPublicKeyError::InvalidSpkiPublicKey => "TypeError", - AsymmetricPublicKeyError::UnsupportedKeyType(_) => "TypeError", - AsymmetricPublicKeyError::UnsupportedKeyFormat(_) => "TypeError", - AsymmetricPublicKeyError::Spki(_) => "Error", - AsymmetricPublicKeyError::Pkcs1(_) => "Error", - AsymmetricPublicKeyError::RsaPssParamsParse(_) => "TypeError", - AsymmetricPublicKeyError::MalformedDssPublicKey => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingNamedCurveInEcParameters => { - "TypeError" - } - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInEcSpki => { - "TypeError" - } - AsymmetricPublicKeyError::Ec(_) => "Error", - AsymmetricPublicKeyError::UnsupportedEcNamedCurve => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInX25519Spki => { - "TypeError" - } - AsymmetricPublicKeyError::X25519PublicKeyIsTooShort => "TypeError", - AsymmetricPublicKeyError::InvalidEd25519PublicKey => "TypeError", - AsymmetricPublicKeyError::MissingDhParameters => "TypeError", - AsymmetricPublicKeyError::MalformedDhParameters => "TypeError", - AsymmetricPublicKeyError::MalformedOrMissingPublicKeyInDhSpki => { - "TypeError" - } - AsymmetricPublicKeyError::UnsupportedPrivateKeyOid => "TypeError", - } - } - - pub fn get_private_encrypt_decrypt_error( - e: &PrivateEncryptDecryptError, - ) -> &'static str { - match e { - PrivateEncryptDecryptError::Pkcs8(_) => "Error", - PrivateEncryptDecryptError::Spki(_) => "Error", - PrivateEncryptDecryptError::Utf8(_) => "Error", - PrivateEncryptDecryptError::Rsa(_) => "Error", - PrivateEncryptDecryptError::UnknownPadding => "TypeError", - } - } - - pub fn get_ecdh_encode_pub_key_error(e: &EcdhEncodePubKey) -> &'static str { - match e { - EcdhEncodePubKey::InvalidPublicKey => "TypeError", - EcdhEncodePubKey::UnsupportedCurve => "TypeError", - EcdhEncodePubKey::Sec1(_) => "Error", - } - } - - pub fn get_diffie_hellman_error(_: &DiffieHellmanError) -> &'static str { - "TypeError" - } - - pub fn get_sign_ed25519_error(_: &SignEd25519Error) -> &'static str { - "TypeError" - } - - pub fn get_verify_ed25519_error(_: &VerifyEd25519Error) -> &'static str { - "TypeError" - } -} - -fn get_os_error(error: &OsError) -> &'static str { - match error { - OsError::Permission(e) => get_permission_check_error_class(e), - OsError::InvalidUtf8(_) => "InvalidData", - OsError::EnvEmptyKey => "TypeError", - OsError::EnvInvalidKey(_) => "TypeError", - OsError::EnvInvalidValue(_) => "TypeError", - OsError::Io(e) => get_io_error_class(e), - OsError::Var(e) => get_env_var_error_class(e), - } -} - -fn get_sync_fetch_error(error: &SyncFetchError) -> &'static str { - match error { - SyncFetchError::BlobUrlsNotSupportedInContext => "TypeError", - SyncFetchError::Io(e) => get_io_error_class(e), - SyncFetchError::InvalidScriptUrl => "TypeError", - SyncFetchError::InvalidStatusCode(_) => "TypeError", - SyncFetchError::ClassicScriptSchemeUnsupportedInWorkers(_) => "TypeError", - SyncFetchError::InvalidUri(_) => "Error", - SyncFetchError::InvalidMimeType(_) => "DOMExceptionNetworkError", - SyncFetchError::MissingMimeType => "DOMExceptionNetworkError", - SyncFetchError::Fetch(e) => get_fetch_error(e), - SyncFetchError::Join(_) => "Error", - SyncFetchError::Other(e) => get_error_class_name(e).unwrap_or("Error"), - } -} - -pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> { - deno_core::error::get_custom_error_class(e) - .or_else(|| { - e.downcast_ref::() - .map(get_child_permission_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_permission_check_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_permission_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_fs_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_blocklist_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_fs_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_idna_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ipc_json_stream_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_ipc_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_worker_threads_filename_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_require_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_http2_error) - }) - .or_else(|| e.downcast_ref::().map(node::get_os_error)) - .or_else(|| { - e.downcast_ref::() - .map(node::get_brotli_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_mode_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_zlib_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_cipher_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_cipher_context_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_decipher_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_decipher_context_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_x509_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_key_object_handle_prehashed_sign_and_verify_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_crypto_hash_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_generate_rsa_pss_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_private_key_der_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_der_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_export_public_key_pem_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_export_private_key_pem_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_rsa_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ec_jwk_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ed_raw_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_pbkdf2_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_scrypt_async_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_hkdf_error_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_rsa_pss_params_parse_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_private_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_asymmetric_public_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_private_encrypt_decrypt_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_ecdh_encode_pub_key_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_diffie_hellman_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_sign_ed25519_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(node::get_verify_ed25519_error) - }) - .or_else(|| e.downcast_ref::().map(get_napi_error_class)) - .or_else(|| e.downcast_ref::().map(get_web_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_create_worker_error) - }) - .or_else(|| e.downcast_ref::().map(get_tty_error)) - .or_else(|| e.downcast_ref::().map(get_readline_error)) - .or_else(|| e.downcast_ref::().map(get_signal_error)) - .or_else(|| e.downcast_ref::().map(get_fs_events_error)) - .or_else(|| e.downcast_ref::().map(get_http_start_error)) - .or_else(|| e.downcast_ref::().map(get_process_error)) - .or_else(|| e.downcast_ref::().map(get_os_error)) - .or_else(|| e.downcast_ref::().map(get_sync_fetch_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_web_compression_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_web_message_port_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_web_stream_resource_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_web_blob_error_class)) - .or_else(|| e.downcast_ref::().map(|_| "TypeError")) - .or_else(|| e.downcast_ref::().map(get_ffi_repr_error_class)) - .or_else(|| e.downcast_ref::().map(get_http_error)) - .or_else(|| e.downcast_ref::().map(get_http_next_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_websocket_upgrade_error) - }) - .or_else(|| e.downcast_ref::().map(get_fs_ops_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_dlfcn_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_static_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_ffi_callback_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_ffi_call_error_class)) - .or_else(|| e.downcast_ref::().map(get_tls_error_class)) - .or_else(|| e.downcast_ref::().map(get_cron_error_class)) - .or_else(|| e.downcast_ref::().map(get_canvas_error)) - .or_else(|| e.downcast_ref::().map(get_cache_error)) - .or_else(|| e.downcast_ref::().map(get_websocket_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_websocket_handshake_error) - }) - .or_else(|| e.downcast_ref::().map(get_kv_error)) - .or_else(|| e.downcast_ref::().map(get_fetch_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_http_client_create_error) - }) - .or_else(|| e.downcast_ref::().map(get_net_error)) - .or_else(|| { - e.downcast_ref::() - .map(get_net_map_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_broadcast_channel_error) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_buffer_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_bundle_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_byow_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_render_pass_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webgpu_surface_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_decrypt_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_encrypt_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_shared_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_ed25519_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_export_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_generate_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_import_key_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_x448_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_x25519_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_crypto_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_webstorage_class_name) - }) - .or_else(|| { - e.downcast_ref::() - .map(|_| "TypeError") - }) - .or_else(|| { - e.downcast_ref::() - .map(get_dlopen_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_hyper_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_hyper_util_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_hyper_v014_error_class) - }) - .or_else(|| { - e.downcast_ref::>() - .map(|e| get_hyper_v014_error_class(e)) - }) - .or_else(|| { - e.downcast_ref::().map(|e| { - let io_err: io::Error = e.to_owned().into(); - get_io_error_class(&io_err) - }) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_env_var_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_io_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_module_resolution_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_notify_error_class) - }) - .or_else(|| e.downcast_ref::().map(get_regex_error_class)) - .or_else(|| { - e.downcast_ref::() - .map(get_serde_json_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(get_url_parse_error_class) - }) - .or_else(|| { - e.downcast_ref::() - .map(|_| "TypeError") - }) - .or_else(|| { - #[cfg(unix)] - let maybe_get_nix_error_class = - || e.downcast_ref::().map(get_nix_error_class); - #[cfg(not(unix))] - let maybe_get_nix_error_class = || Option::<&'static str>::None; - (maybe_get_nix_error_class)() - }) -} diff --git a/runtime/lib.rs b/runtime/lib.rs index f0b1129ce3cf50..62c5865fea36aa 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -27,7 +27,6 @@ pub use deno_websocket; pub use deno_webstorage; pub mod code_cache; -pub mod errors; pub mod fmt_errors; pub mod fs_util; pub mod inspector_server; diff --git a/runtime/ops/fs_events.rs b/runtime/ops/fs_events.rs index c8e0228bc04199..b238b8d783c288 100644 --- a/runtime/ops/fs_events.rs +++ b/runtime/ops/fs_events.rs @@ -27,6 +27,7 @@ use std::path::Path; use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; +use deno_core::error::GENERIC_ERROR; use tokio::sync::mpsc; deno_core::extension!( @@ -109,16 +110,31 @@ fn starts_with_canonicalized(path: &Path, prefix: &str) -> bool { } } -#[derive(Debug, thiserror::Error)] +deno_core::js_error_wrapper!(NotifyError, JsNotifyError, |err| { + match &err.kind { + notify::ErrorKind::Generic(_) => GENERIC_ERROR, + notify::ErrorKind::Io(e) => e.get_class(), + notify::ErrorKind::PathNotFound => "NotFound", + notify::ErrorKind::WatchNotFound => "NotFound", + notify::ErrorKind::InvalidConfig(_) => "InvalidData", + notify::ErrorKind::MaxFilesWatch => GENERIC_ERROR, + } +}); + +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum FsEventsError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - Notify(#[from] NotifyError), + Notify(#[inherit] JsNotifyError), + #[class(inherit)] #[error(transparent)] - Canceled(#[from] deno_core::Canceled), + Canceled(#[from] #[inherit] deno_core::Canceled), } fn start_watcher( @@ -136,7 +152,7 @@ fn start_watcher( let sender_clone = senders.clone(); let watcher: RecommendedWatcher = Watcher::new( move |res: Result| { - let res2 = res.map(FsEvent::from).map_err(FsEventsError::Notify); + let res2 = res.map(FsEvent::from).map_err(|e| FsEventsError::Notify(JsNotifyError(e))); for (paths, sender) in sender_clone.lock().iter() { // Ignore result, if send failed it means that watcher was already closed, // but not all messages have been flushed. @@ -155,7 +171,7 @@ fn start_watcher( } }, Default::default(), - )?; + ).map_err(|e| FsEventsError::Notify(JsNotifyError(e)))?; state.put::(WatcherState { watcher, senders }); @@ -184,7 +200,7 @@ fn op_fs_events_open( .check_read(path, "Deno.watchFs()")?; let watcher = state.borrow_mut::(); - watcher.watcher.watch(&path, recursive_mode)?; + watcher.watcher.watch(&path, recursive_mode).map_err(|e| FsEventsError::Notify(JsNotifyError(e)))?; } let resource = FsEventsResource { receiver: AsyncRefCell::new(receiver), @@ -203,14 +219,13 @@ async fn op_fs_events_poll( let resource = state .borrow() .resource_table - .get::(rid) - .map_err(FsEventsError::Resource)?; + .get::(rid)?; let mut receiver = RcRef::map(&resource, |r| &r.receiver).borrow_mut().await; let cancel = RcRef::map(resource, |r| &r.cancel); let maybe_result = receiver.recv().or_cancel(cancel).await?; match maybe_result { Some(Ok(value)) => Ok(Some(value)), - Some(Err(err)) => Err(FsEventsError::Notify(err)), + Some(Err(err)) => Err(FsEventsError::Notify(JsNotifyError(err))), None => Ok(None), } } diff --git a/runtime/ops/http.rs b/runtime/ops/http.rs index 6e315766866f04..f6dd6de39ca559 100644 --- a/runtime/ops/http.rs +++ b/runtime/ops/http.rs @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use std::rc::Rc; - +use deno_core::error::ResourceError; use deno_core::op2; use deno_core::OpState; use deno_core::ResourceId; @@ -13,23 +13,30 @@ pub const UNSTABLE_FEATURE_NAME: &str = "http"; deno_core::extension!(deno_http_runtime, ops = [op_http_start],); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum HttpStartError { + #[class("Busy")] #[error("TCP stream is currently in use")] TcpStreamInUse, + #[class("Busy")] #[error("TLS stream is currently in use")] TlsStreamInUse, + #[class("Busy")] #[error("Unix socket is currently in use")] UnixSocketInUse, + #[class(GENERIC)] #[error(transparent)] ReuniteTcp(#[from] tokio::net::tcp::ReuniteError), #[cfg(unix)] + #[class(GENERIC)] #[error(transparent)] ReuniteUnix(#[from] tokio::net::unix::ReuniteError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Resource(#[inherit] ResourceError), } #[op2(fast)] @@ -89,5 +96,5 @@ fn op_http_start( )); } - Err(HttpStartError::Other(deno_core::error::bad_resource_id())) + Err(HttpStartError::Resource(ResourceError::BadResourceId)) } diff --git a/runtime/ops/os/mod.rs b/runtime/ops/os/mod.rs index 9bee9d82349d24..49eeb9d228f686 100644 --- a/runtime/ops/os/mod.rs +++ b/runtime/ops/os/mod.rs @@ -6,7 +6,7 @@ use deno_core::v8; use deno_core::OpState; use deno_node::NODE_ENV_VAR_ALLOWLIST; use deno_path_util::normalize_path; -use deno_permissions::PermissionsContainer; +use deno_permissions::{PermissionCheckError, PermissionsContainer}; use serde::Serialize; use std::collections::HashMap; use std::env; @@ -70,22 +70,29 @@ deno_core::extension!( }, ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum OsError { + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] PermissionCheckError), + #[class("InvalidData")] #[error("File name or path {0:?} is not valid UTF-8")] InvalidUtf8(std::ffi::OsString), + #[class(TYPE)] #[error("Key is an empty string.")] EnvEmptyKey, + #[class(TYPE)] #[error("Key contains invalid characters: {0:?}")] EnvInvalidKey(String), + #[class(TYPE)] #[error("Value contains invalid characters: {0:?}")] EnvInvalidValue(String), + #[class(inherit)] #[error(transparent)] - Var(#[from] env::VarError), + Var(#[from] #[inherit] env::VarError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), } #[op2] @@ -128,7 +135,7 @@ fn op_set_env( #[serde] fn op_env( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state.borrow_mut::().check_env_all()?; Ok(env::vars().collect()) } @@ -194,7 +201,7 @@ fn op_exit(state: &mut OpState) { #[serde] fn op_loadavg( state: &mut OpState, -) -> Result<(f64, f64, f64), deno_core::error::AnyError> { +) -> Result<(f64, f64, f64), PermissionCheckError> { state .borrow_mut::() .check_sys("loadavg", "Deno.loadavg()")?; @@ -205,7 +212,7 @@ fn op_loadavg( #[string] fn op_hostname( state: &mut OpState, -) -> Result { +) -> Result { state .borrow_mut::() .check_sys("hostname", "Deno.hostname()")?; @@ -216,7 +223,7 @@ fn op_hostname( #[string] fn op_os_release( state: &mut OpState, -) -> Result { +) -> Result { state .borrow_mut::() .check_sys("osRelease", "Deno.osRelease()")?; @@ -279,7 +286,7 @@ impl From for NetworkInterface { #[serde] fn op_system_memory_info( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("systemMemoryInfo", "Deno.systemMemoryInfo()")?; @@ -291,7 +298,7 @@ fn op_system_memory_info( #[smi] fn op_gid( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("gid", "Deno.gid()")?; @@ -307,7 +314,7 @@ fn op_gid( #[smi] fn op_gid( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("gid", "Deno.gid()")?; @@ -319,7 +326,7 @@ fn op_gid( #[smi] fn op_uid( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("uid", "Deno.uid()")?; @@ -335,7 +342,7 @@ fn op_uid( #[smi] fn op_uid( state: &mut OpState, -) -> Result, deno_core::error::AnyError> { +) -> Result, PermissionCheckError> { state .borrow_mut::() .check_sys("uid", "Deno.uid()")?; @@ -513,7 +520,7 @@ fn rss() -> usize { } } -fn os_uptime(state: &mut OpState) -> Result { +fn os_uptime(state: &mut OpState) -> Result { state .borrow_mut::() .check_sys("osUptime", "Deno.osUptime()")?; @@ -524,6 +531,6 @@ fn os_uptime(state: &mut OpState) -> Result { #[number] fn op_os_uptime( state: &mut OpState, -) -> Result { +) -> Result { os_uptime(state) } diff --git a/runtime/ops/permissions.rs b/runtime/ops/permissions.rs index 9ad963f3bc1aa4..c9529641ecfa14 100644 --- a/runtime/ops/permissions.rs +++ b/runtime/ops/permissions.rs @@ -45,18 +45,23 @@ impl From for PermissionStatus { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum PermissionError { + #[class("ReferenceError")] #[error("No such permission name: {0}")] InvalidPermissionName(String), + #[class(inherit)] #[error("{0}")] - PathResolve(#[from] ::deno_permissions::PathResolveError), + PathResolve(#[from] #[inherit] ::deno_permissions::PathResolveError), + #[class(URI)] #[error("{0}")] NetDescriptorParse(#[from] ::deno_permissions::NetDescriptorParseError), + #[class(inherit)] #[error("{0}")] - SysDescriptorParse(#[from] ::deno_permissions::SysDescriptorParseError), + SysDescriptorParse(#[from] #[inherit] ::deno_permissions::SysDescriptorParseError), + #[class(inherit)] #[error("{0}")] - RunDescriptorParse(#[from] ::deno_permissions::RunDescriptorParseError), + RunDescriptorParse(#[from] #[inherit] ::deno_permissions::RunDescriptorParseError), } #[op2] diff --git a/runtime/ops/process.rs b/runtime/ops/process.rs index de3141f1f933dd..928c8c2746407e 100644 --- a/runtime/ops/process.rs +++ b/runtime/ops/process.rs @@ -37,6 +37,7 @@ use crate::ops::signal::SignalError; use std::os::unix::prelude::ExitStatusExt; #[cfg(unix)] use std::os::unix::process::CommandExt; +use deno_core::error::JsNativeError; pub const UNSTABLE_FEATURE_NAME: &str = "process"; @@ -107,8 +108,7 @@ impl StdioOrRid { match &self { StdioOrRid::Stdio(val) => Ok(val.as_stdio()), StdioOrRid::Rid(rid) => { - FileResource::with_file(state, *rid, |file| Ok(file.as_stdio()?)) - .map_err(ProcessError::Resource) + Ok(FileResource::with_file(state, *rid, |file| Ok(file.as_stdio().map_err(JsNativeError::from_err)?))?) } } } @@ -190,37 +190,72 @@ pub struct SpawnArgs { needs_npm_process_state: bool, } -#[derive(Debug, thiserror::Error)] +#[cfg(unix)] +deno_core::js_error_wrapper!(nix::Error, JsNixError, |err| { + match err { + nix::Error::ECHILD => "NotFound", + nix::Error::EINVAL => "TypeError", + nix::Error::ENOENT => "NotFound", + nix::Error::ENOTTY => "BadResource", + nix::Error::EPERM => "PermissionDenied", + nix::Error::ESRCH => "NotFound", + nix::Error::ELOOP => "FilesystemLoop", + nix::Error::ENOTDIR => "NotADirectory", + nix::Error::ENETUNREACH => "NetworkUnreachable", + nix::Error::EISDIR => "IsADirectory", + nix::Error::UnknownErrno => "Error", + &nix::Error::ENOTSUP => unreachable!(), + _ => "Error", + } +}); + +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ProcessError { + #[class(inherit)] #[error("Failed to spawn '{command}': {error}")] SpawnFailed { command: String, - #[source] + #[source] #[inherit] error: Box, }, + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), #[cfg(unix)] + #[class(inherit)] #[error(transparent)] - Nix(nix::Error), + Nix(#[inherit] JsNixError), + #[class(inherit)] #[error("failed resolving cwd: {0}")] - FailedResolvingCwd(#[source] std::io::Error), + FailedResolvingCwd(#[source] #[inherit] std::io::Error), + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error(transparent)] - RunPermission(#[from] CheckRunPermissionError), + RunPermission(#[from] #[inherit] CheckRunPermissionError), + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[inherit] deno_core::error::ResourceError), + #[class(GENERIC)] #[error(transparent)] BorrowMut(std::cell::BorrowMutError), + #[class(GENERIC)] #[error(transparent)] Which(which::Error), + #[class(TYPE)] #[error("Child process has already terminated.")] ChildProcessAlreadyTerminated, + #[class(TYPE)] #[error("Invalid pid")] InvalidPid, + #[class(inherit)] + #[error(transparent)] + Signal(#[from] #[inherit] SignalError), + #[class(inherit)] #[error(transparent)] - Signal(#[from] SignalError), + Other(#[from] #[inherit] JsNativeError), + #[class(TYPE)] #[error("Missing cmd")] MissingCmd, // only for Deno.run } @@ -735,12 +770,14 @@ fn resolve_path(path: &str, cwd: &Path) -> PathBuf { deno_path_util::normalize_path(cwd.join(path)) } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CheckRunPermissionError { + #[class(inherit)] #[error(transparent)] - Permission(#[from] deno_permissions::PermissionCheckError), + Permission(#[from] #[inherit] deno_permissions::PermissionCheckError), + #[class(inherit)] #[error("{0}")] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } fn check_run_permission( @@ -756,7 +793,7 @@ 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(JsNativeError::new( "NotCapable", format!( "Requires --allow-all permissions to spawn subprocess with {} environment variable{}.", @@ -1077,8 +1114,8 @@ mod deprecated { use nix::sys::signal::kill as unix_kill; use nix::sys::signal::Signal; use nix::unistd::Pid; - let sig = Signal::try_from(signo).map_err(ProcessError::Nix)?; - unix_kill(Pid::from_raw(pid), Some(sig)).map_err(ProcessError::Nix) + let sig = Signal::try_from(signo).map_err(|e | ProcessError::Nix(JsNixError(e)))?; + unix_kill(Pid::from_raw(pid), Some(sig)).map_err(|e | ProcessError::Nix(JsNixError(e))) } #[cfg(not(unix))] diff --git a/runtime/ops/signal.rs b/runtime/ops/signal.rs index e1e4ab68bcf86f..570cccd65c0272 100644 --- a/runtime/ops/signal.rs +++ b/runtime/ops/signal.rs @@ -17,7 +17,7 @@ use std::rc::Rc; use std::sync::atomic::AtomicBool; #[cfg(unix)] use std::sync::Arc; - +use deno_core::error::ResourceError; #[cfg(unix)] use tokio::signal::unix::signal; #[cfg(unix)] @@ -44,7 +44,7 @@ deno_core::extension!( } ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum SignalError { #[cfg(any( target_os = "android", @@ -55,6 +55,7 @@ pub enum SignalError { target_os = "solaris", target_os = "illumos" ))] + #[class(TYPE)] #[error("Invalid signal: {0}")] InvalidSignalStr(String), #[cfg(any( @@ -66,18 +67,23 @@ pub enum SignalError { target_os = "solaris", target_os = "illumos" ))] + #[class(TYPE)] #[error("Invalid signal: {0}")] InvalidSignalInt(libc::c_int), #[cfg(target_os = "windows")] + #[class(TYPE)] #[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] InvalidSignalStr(String), #[cfg(target_os = "windows")] + #[class(TYPE)] #[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")] InvalidSignalInt(libc::c_int), + #[class(TYPE)] #[error("Binding to signal '{0}' is not allowed")] SignalNotAllowed(String), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), } #[cfg(unix)] @@ -460,7 +466,7 @@ fn op_signal_bind( async fn op_signal_poll( state: Rc>, #[smi] rid: ResourceId, -) -> Result { +) -> Result { let resource = state .borrow_mut() .resource_table @@ -479,7 +485,7 @@ async fn op_signal_poll( pub fn op_signal_unbind( state: &mut OpState, #[smi] rid: ResourceId, -) -> Result<(), deno_core::error::AnyError> { +) -> Result<(), ResourceError> { let resource = state.resource_table.take::(rid)?; #[cfg(unix)] diff --git a/runtime/ops/tty.rs b/runtime/ops/tty.rs index 7849185faaeaf8..8d5147742c796d 100644 --- a/runtime/ops/tty.rs +++ b/runtime/ops/tty.rs @@ -27,6 +27,7 @@ use nix::sys::termios; use std::cell::RefCell; #[cfg(unix)] use std::collections::HashMap; +use deno_core::error::{JsNativeError, GENERIC_ERROR}; #[cfg(unix)] #[derive(Default, Clone)] @@ -53,6 +54,7 @@ impl TtyModeStore { use winapi::shared::minwindef::DWORD; #[cfg(windows)] use winapi::um::wincon; +use crate::ops::process::JsNixError; deno_core::extension!( deno_tty, @@ -63,17 +65,21 @@ deno_core::extension!( }, ); -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum TtyError { + #[class(inherit)] #[error(transparent)] - Resource(deno_core::error::AnyError), + Resource(#[from] #[inherit] deno_core::error::ResourceError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] Error), #[cfg(unix)] + #[class(inherit)] #[error(transparent)] - Nix(nix::Error), + Nix(#[inherit] JsNixError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] JsNativeError), } // ref: @@ -106,7 +112,7 @@ fn op_set_raw( let handle_or_fd = state .resource_table .get_fd(rid) - .map_err(TtyError::Resource)?; + ?; // From https://github.com/kkawakam/rustyline/blob/master/src/tty/windows.rs // and https://github.com/kkawakam/rustyline/blob/master/src/tty/unix.rs @@ -116,13 +122,14 @@ fn op_set_raw( #[cfg(windows)] { use winapi::shared::minwindef::FALSE; + use deno_core::error::JsNativeError; use winapi::um::consoleapi; let handle = handle_or_fd; if cbreak { - return Err(TtyError::Other(deno_core::error::not_supported())); + return Err(TtyError::Other(JsNativeError::not_supported())); } let mut original_mode: DWORD = 0; @@ -268,7 +275,7 @@ fn op_set_raw( None => { // Save original mode. let original_mode = - termios::tcgetattr(raw_fd).map_err(TtyError::Nix)?; + termios::tcgetattr(raw_fd).map_err(|e| TtyError::Nix(JsNixError(e)))?; tty_mode_store.set(rid, original_mode.clone()); original_mode } @@ -291,12 +298,12 @@ fn op_set_raw( raw.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; raw.control_chars[termios::SpecialCharacterIndices::VTIME as usize] = 0; termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &raw) - .map_err(TtyError::Nix)?; + .map_err(|e| TtyError::Nix(JsNixError(e)))?; } else { // Try restore saved mode. if let Some(mode) = tty_mode_store.take(rid) { termios::tcsetattr(raw_fd, termios::SetArg::TCSADRAIN, &mode) - .map_err(TtyError::Nix)?; + .map_err(|e| TtyError::Nix(JsNixError(e)))?; } } @@ -317,7 +324,7 @@ fn op_console_size( let fd = state .resource_table .get_fd(rid) - .map_err(TtyError::Resource)?; + ?; let size = console_size_from_fd(fd)?; result[0] = size.cols; result[1] = size.rows; @@ -435,12 +442,28 @@ mod tests { } } +deno_core::js_error_wrapper!(ReadlineError, JsReadlineError, |err| { + match err { + ReadlineError::Io(e) => e.get_class(), + ReadlineError::Eof => GENERIC_ERROR, + ReadlineError::Interrupted => GENERIC_ERROR, + #[cfg(unix)] + ReadlineError::Errno(e) => JsNixError(e.clone()).get_class(), + ReadlineError::WindowResized => GENERIC_ERROR, + #[cfg(windows)] + ReadlineError::Decode(_) => GENERIC_ERROR, + #[cfg(windows)] + ReadlineError::SystemError(_) => GENERIC_ERROR, + _ => GENERIC_ERROR, + } +}); + #[op2] #[string] pub fn op_read_line_prompt( #[string] prompt_text: &str, #[string] default_value: &str, -) -> Result, ReadlineError> { +) -> Result, JsReadlineError> { let mut editor = Editor::<(), rustyline::history::DefaultHistory>::new() .expect("Failed to create editor."); @@ -460,6 +483,6 @@ pub fn op_read_line_prompt( Ok(None) } Err(ReadlineError::Eof) => Ok(None), - Err(err) => Err(err), + Err(err) => Err(JsReadlineError(err)), } } diff --git a/runtime/ops/web_worker/sync_fetch.rs b/runtime/ops/web_worker/sync_fetch.rs index d1f133d3d22e66..574d42102879e2 100644 --- a/runtime/ops/web_worker/sync_fetch.rs +++ b/runtime/ops/web_worker/sync_fetch.rs @@ -25,30 +25,41 @@ fn mime_type_essence(mime_type: &str) -> String { essence.trim().to_ascii_lowercase() } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum SyncFetchError { + #[class(TYPE)] #[error("Blob URLs are not supported in this context.")] BlobUrlsNotSupportedInContext, + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), + #[class(TYPE)] #[error("Invalid script URL")] InvalidScriptUrl, + #[class(TYPE)] #[error("http status error: {0}")] InvalidStatusCode(http::StatusCode), + #[class(TYPE)] #[error("Classic scripts with scheme {0}: are not supported in workers")] ClassicScriptSchemeUnsupportedInWorkers(String), + #[class(GENERIC)] #[error("{0}")] InvalidUri(#[from] http::uri::InvalidUri), + #[class("DOMExceptionNetworkError")] #[error("Invalid MIME type {0:?}.")] InvalidMimeType(String), + #[class("DOMExceptionNetworkError")] #[error("Missing MIME type.")] MissingMimeType, + #[class(inherit)] #[error(transparent)] - Fetch(#[from] FetchError), + Fetch(#[from] #[inherit] FetchError), + #[class(inherit)] #[error(transparent)] - Join(#[from] tokio::task::JoinError), + Join(#[from] #[inherit] tokio::task::JoinError), + #[class(inherit)] #[error(transparent)] - Other(deno_core::error::AnyError), + Other(#[inherit] deno_core::error::JsNativeError), } #[derive(Serialize, Deserialize)] diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index 521284a6a065b2..545da6a26bd057 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -118,18 +118,23 @@ pub struct CreateWorkerArgs { close_on_idle: bool, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum CreateWorkerError { + #[class("DOMExceptionNotSupportedError")] #[error("Classic workers are not supported.")] ClassicWorkers, + #[class(inherit)] #[error(transparent)] - Permission(deno_permissions::ChildPermissionError), + Permission(#[inherit] deno_permissions::ChildPermissionError), + #[class(inherit)] #[error(transparent)] - ModuleResolution(#[from] deno_core::ModuleResolutionError), + ModuleResolution(#[from] #[inherit] deno_core::ModuleResolutionError), + #[class(inherit)] #[error(transparent)] - MessagePort(#[from] MessagePortError), + MessagePort(#[from] #[inherit] MessagePortError), + #[class(inherit)] #[error("{0}")] - Io(#[from] std::io::Error), + Io(#[from] #[inherit] std::io::Error), } /// Create worker as the host diff --git a/runtime/permissions/lib.rs b/runtime/permissions/lib.rs index 6480f4bf586094..29791524c7e62f 100644 --- a/runtime/permissions/lib.rs +++ b/runtime/permissions/lib.rs @@ -805,7 +805,8 @@ pub enum Host { Ip(IpAddr), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] +#[class(URI)] pub enum HostParseError { #[error("invalid IPv6 address: '{0}'")] InvalidIpv6(String), @@ -940,12 +941,14 @@ pub enum NetDescriptorParseError { Host(#[from] HostParseError), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum NetDescriptorFromUrlParseError { + #[class(TYPE)] #[error("Missing host in url: '{0}'")] MissingHost(Url), + #[class(inherit)] #[error("{0}")] - Host(#[from] HostParseError), + Host(#[from] #[inherit] HostParseError), } impl NetDescriptor { @@ -1197,10 +1200,12 @@ pub enum RunQueryDescriptor { Name(String), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum PathResolveError { + #[class(inherit)] #[error("failed resolving cwd: {0}")] - CwdResolve(#[source] std::io::Error), + CwdResolve(#[source] #[inherit] std::io::Error), + #[class(GENERIC)] #[error("Empty path is not allowed")] EmptyPath, } @@ -1357,12 +1362,15 @@ pub enum AllowRunDescriptorParseResult { Descriptor(AllowRunDescriptor), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum RunDescriptorParseError { + #[class(GENERIC)] #[error("{0}")] Which(#[from] which::Error), + #[class(inherit)] #[error("{0}")] - PathResolve(#[from] PathResolveError), + PathResolve(#[from] #[inherit] PathResolveError), + #[class(GENERIC)] #[error("Empty run query is not allowed")] EmptyRunQuery, } @@ -1447,10 +1455,12 @@ fn denies_run_name(name: &str, cmd_path: &Path) -> bool { suffix.is_empty() || suffix.starts_with('.') } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum SysDescriptorParseError { + #[class(TYPE)] #[error("unknown system info kind \"{0}\"")] - InvalidKind(String), // TypeError + InvalidKind(String), + #[class(GENERIC)] #[error("Empty sys not allowed")] Empty, // Error } @@ -2175,34 +2185,46 @@ pub enum CheckSpecifierKind { Dynamic, } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum ChildPermissionError { + #[class("NotCapable")] #[error("Can't escalate parent thread permissions")] Escalation, + #[class(inherit)] #[error("{0}")] - PathResolve(#[from] PathResolveError), + PathResolve(#[from] #[inherit] PathResolveError), + #[class(URI)] #[error("{0}")] NetDescriptorParse(#[from] NetDescriptorParseError), + #[class(GENERIC)] #[error("{0}")] EnvDescriptorParse(#[from] EnvDescriptorParseError), + #[class(inherit)] #[error("{0}")] - SysDescriptorParse(#[from] SysDescriptorParseError), + SysDescriptorParse(#[from] #[inherit] SysDescriptorParseError), + #[class(inherit)] #[error("{0}")] - RunDescriptorParse(#[from] RunDescriptorParseError), + RunDescriptorParse(#[from] #[inherit] RunDescriptorParseError), } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, deno_core::JsError)] pub enum PermissionCheckError { + #[class("NotCapable")] #[error(transparent)] PermissionDenied(#[from] PermissionDeniedError), + #[class(URI)] #[error("Invalid file path.\n Specifier: {0}")] InvalidFilePath(Url), + #[class(inherit)] #[error(transparent)] - NetDescriptorForUrlParse(#[from] NetDescriptorFromUrlParseError), + NetDescriptorForUrlParse(#[from] #[inherit] NetDescriptorFromUrlParseError), + #[class(inherit)] #[error(transparent)] - SysDescriptorParse(#[from] SysDescriptorParseError), + SysDescriptorParse(#[from] #[inherit] SysDescriptorParseError), + #[class(inherit)] #[error(transparent)] - PathResolve(#[from] PathResolveError), + PathResolve(#[from] #[inherit] PathResolveError), + #[class(URI)] #[error(transparent)] HostParse(#[from] HostParseError), } diff --git a/runtime/shared.rs b/runtime/shared.rs index f7d76f67a760da..807f91f104f5be 100644 --- a/runtime/shared.rs +++ b/runtime/shared.rs @@ -4,7 +4,7 @@ use deno_ast::MediaType; use deno_ast::ParseParams; use deno_ast::SourceMapOption; -use deno_core::error::AnyError; +use deno_core::error::JsNativeError; use deno_core::extension; use deno_core::Extension; use deno_core::ModuleCodeString; @@ -63,10 +63,13 @@ extension!(runtime, } ); +deno_core::js_error_wrapper!(deno_ast::ParseDiagnostic, JsParseDiagnostic, "Error"); +deno_core::js_error_wrapper!(deno_ast::TranspileError, JsTranspileError, "Error"); + pub fn maybe_transpile_source( name: ModuleName, source: ModuleCodeString, -) -> Result<(ModuleCodeString, Option), AnyError> { +) -> Result<(ModuleCodeString, Option), JsNativeError> { // Always transpile `node:` built-in modules, since they might be TypeScript. let media_type = if name.starts_with("node:") { MediaType::TypeScript @@ -91,7 +94,7 @@ pub fn maybe_transpile_source( capture_tokens: false, scope_analysis: false, maybe_syntax: None, - })?; + }).map_err(|e| JsNativeError::from_err(JsParseDiagnostic(e)))?; let transpiled_source = parsed .transpile( &deno_ast::TranspileOptions { @@ -107,7 +110,7 @@ pub fn maybe_transpile_source( }, ..Default::default() }, - )? + ).map_err(|e| JsNativeError::from_err(JsTranspileError(e)))? .into_source(); let maybe_source_map: Option = transpiled_source diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index 61e5c770299285..e36f830ec8aff9 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -3,8 +3,7 @@ use deno_broadcast_channel::InMemoryBroadcastChannel; use deno_cache::CreateCache; use deno_cache::SqliteBackedCache; -use deno_core::error::AnyError; -use deno_core::error::JsError; +use deno_core::error::{CoreError}; use deno_core::futures::channel::mpsc; use deno_core::futures::future::poll_fn; use deno_core::futures::stream::StreamExt; @@ -19,7 +18,6 @@ use deno_core::CompiledWasmModuleStore; use deno_core::DetachedBuffer; use deno_core::Extension; use deno_core::FeatureChecker; -use deno_core::GetErrorClassFn; use deno_core::JsRuntime; use deno_core::ModuleCodeString; use deno_core::ModuleId; @@ -104,8 +102,7 @@ pub enum WebWorkerType { /// Events that are sent to host from child /// worker. pub enum WorkerControlEvent { - Error(AnyError), - TerminalError(AnyError), + TerminalError(CoreError), Close, } @@ -118,15 +115,13 @@ impl Serialize for WorkerControlEvent { { let type_id = match &self { WorkerControlEvent::TerminalError(_) => 1_i32, - WorkerControlEvent::Error(_) => 2_i32, WorkerControlEvent::Close => 3_i32, }; match self { - WorkerControlEvent::TerminalError(error) - | WorkerControlEvent::Error(error) => { - let value = match error.downcast_ref::() { - Some(js_error) => { + WorkerControlEvent::TerminalError(error) => { + let value = match error { + CoreError::Js(js_error) => { let frame = js_error.frames.iter().find(|f| match &f.file_name { Some(s) => !s.trim_start_matches('[').starts_with("ext:"), None => false, @@ -138,7 +133,7 @@ impl Serialize for WorkerControlEvent { "columnNumber": frame.map(|f| f.column_number.as_ref()), }) } - None => json!({ + _ => json!({ "message": error.to_string(), }), }; @@ -365,7 +360,6 @@ pub struct WebWorkerOptions { pub create_web_worker_cb: Arc, pub format_js_error_fn: Option>, pub worker_type: WebWorkerType, - pub get_error_class_fn: Option, pub cache_storage_dir: Option, pub stdio: Stdio, pub strace_ops: Option>, @@ -555,7 +549,6 @@ impl WebWorker { let mut js_runtime = JsRuntime::new(RuntimeOptions { module_loader: Some(services.module_loader), startup_snapshot: options.startup_snapshot, - get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: services.shared_array_buffer_store, compiled_wasm_module_store: services.compiled_wasm_module_store, extensions, @@ -717,7 +710,7 @@ impl WebWorker { &mut self, name: &'static str, source_code: ModuleCodeString, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self.js_runtime.execute_script(name, source_code)?; Ok(()) } @@ -726,7 +719,7 @@ impl WebWorker { pub async fn preload_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_main_es_module(module_specifier).await } @@ -734,7 +727,7 @@ impl WebWorker { pub async fn preload_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_side_es_module(module_specifier).await } @@ -745,7 +738,7 @@ impl WebWorker { pub async fn execute_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_side_module(module_specifier).await?; let mut receiver = self.js_runtime.mod_evaluate(id); tokio::select! { @@ -769,7 +762,7 @@ impl WebWorker { pub async fn execute_main_module( &mut self, id: ModuleId, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let mut receiver = self.js_runtime.mod_evaluate(id); let poll_options = PollEventLoopOptions::default(); @@ -796,7 +789,7 @@ impl WebWorker { &mut self, cx: &mut Context, poll_options: PollEventLoopOptions, - ) -> Poll> { + ) -> Poll> { // If awakened because we are terminating, just return Ok if self.internal_handle.terminate_if_needed() { return Poll::Ready(Ok(())); @@ -853,7 +846,7 @@ impl WebWorker { pub async fn run_event_loop( &mut self, poll_options: PollEventLoopOptions, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { poll_fn(|cx| self.poll_event_loop(cx, poll_options)).await } @@ -897,14 +890,14 @@ impl WebWorker { #[allow(clippy::print_stderr)] fn print_worker_error( - error: &AnyError, + error: &CoreError, name: &str, format_js_error_fn: Option<&FormatJsErrorFn>, ) { let error_str = match format_js_error_fn { - Some(format_js_error_fn) => match error.downcast_ref::() { - Some(js_error) => format_js_error_fn(js_error), - None => error.to_string(), + Some(format_js_error_fn) => match error { + CoreError::Js(js_error) => format_js_error_fn(js_error), + _ => error.to_string(), }, None => error.to_string(), }; @@ -923,7 +916,7 @@ pub fn run_web_worker( specifier: ModuleSpecifier, mut maybe_source_code: Option, format_js_error_fn: Option>, -) -> Result<(), AnyError> { +) -> Result<(), CoreError> { let name = worker.name.to_string(); // TODO(bartlomieju): run following block using "select!" diff --git a/runtime/worker.rs b/runtime/worker.rs index 88a61fa9389801..65972cd01f416a 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -12,14 +12,13 @@ use std::time::Instant; use deno_broadcast_channel::InMemoryBroadcastChannel; use deno_cache::CreateCache; use deno_cache::SqliteBackedCache; -use deno_core::error::AnyError; +use deno_core::error::{AnyError, CoreError}; use deno_core::error::JsError; use deno_core::merge_op_metrics; use deno_core::v8; use deno_core::CompiledWasmModuleStore; use deno_core::Extension; use deno_core::FeatureChecker; -use deno_core::GetErrorClassFn; use deno_core::InspectorSessionKind; use deno_core::InspectorSessionOptions; use deno_core::JsRuntime; @@ -58,10 +57,10 @@ use crate::BootstrapOptions; pub type FormatJsErrorFn = dyn Fn(&JsError) -> String + Sync + Send; pub fn import_meta_resolve_callback( - loader: &dyn deno_core::ModuleLoader, + loader: &dyn ModuleLoader, specifier: String, referrer: String, -) -> Result { +) -> Result { loader.resolve( &specifier, &referrer, @@ -200,9 +199,6 @@ pub struct WorkerOptions { /// If Some, print a low-level trace output for ops matching the given patterns. pub strace_ops: Option>, - /// Allows to map error type to a string "class" used to represent - /// error in JavaScript. - pub get_error_class_fn: Option, pub cache_storage_dir: Option, pub origin_storage_dir: Option, pub stdio: Stdio, @@ -222,7 +218,6 @@ impl Default for WorkerOptions { strace_ops: Default::default(), maybe_inspector_server: Default::default(), format_js_error_fn: Default::default(), - get_error_class_fn: Default::default(), origin_storage_dir: Default::default(), cache_storage_dir: Default::default(), extensions: Default::default(), @@ -481,7 +476,6 @@ impl MainWorker { startup_snapshot: options.startup_snapshot, create_params: options.create_params, skip_op_registration: options.skip_op_registration, - get_error_class_fn: options.get_error_class_fn, shared_array_buffer_store: services.shared_array_buffer_store.clone(), compiled_wasm_module_store: services.compiled_wasm_module_store.clone(), extensions, @@ -695,7 +689,7 @@ impl MainWorker { &mut self, script_name: &'static str, source_code: ModuleCodeString, - ) -> Result, AnyError> { + ) -> Result, CoreError> { self.js_runtime.execute_script(script_name, source_code) } @@ -703,7 +697,7 @@ impl MainWorker { pub async fn preload_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_main_es_module(module_specifier).await } @@ -711,7 +705,7 @@ impl MainWorker { pub async fn preload_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result { + ) -> Result { self.js_runtime.load_side_es_module(module_specifier).await } @@ -719,7 +713,7 @@ impl MainWorker { pub async fn evaluate_module( &mut self, id: ModuleId, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self.wait_for_inspector_session(); let mut receiver = self.js_runtime.mod_evaluate(id); tokio::select! { @@ -744,7 +738,7 @@ impl MainWorker { pub async fn run_up_to_duration( &mut self, duration: Duration, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { match tokio::time::timeout( duration, self @@ -763,7 +757,7 @@ impl MainWorker { pub async fn execute_side_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_side_module(module_specifier).await?; self.evaluate_module(id).await } @@ -774,7 +768,7 @@ impl MainWorker { pub async fn execute_main_module( &mut self, module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { let id = self.preload_main_module(module_specifier).await?; self.evaluate_module(id).await } @@ -805,10 +799,10 @@ impl MainWorker { pub async fn run_event_loop( &mut self, wait_for_inspector: bool, - ) -> Result<(), AnyError> { + ) -> Result<(), CoreError> { self .js_runtime - .run_event_loop(deno_core::PollEventLoopOptions { + .run_event_loop(PollEventLoopOptions { wait_for_inspector, ..Default::default() })