diff --git a/Cargo.lock b/Cargo.lock index 358e277..3e6e81b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2005,7 +2005,7 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slice-cas" -version = "0.10.10" +version = "0.10.11" dependencies = [ "aho-corasick", "anyhow", @@ -2026,7 +2026,7 @@ dependencies = [ [[package]] name = "slice-cli" -version = "0.10.10" +version = "0.10.11" dependencies = [ "anyhow", "criterion", @@ -2047,7 +2047,7 @@ dependencies = [ [[package]] name = "slice-engine" -version = "0.10.10" +version = "0.10.11" dependencies = [ "aho-corasick", "anyhow", @@ -2077,7 +2077,7 @@ dependencies = [ [[package]] name = "slice-io" -version = "0.10.10" +version = "0.10.11" dependencies = [ "anyhow", "criterion", @@ -2088,7 +2088,7 @@ dependencies = [ [[package]] name = "slice-sandbox" -version = "0.10.10" +version = "0.10.11" dependencies = [ "anyhow", "blake3", diff --git a/Cargo.toml b/Cargo.toml index 9f8b4e0..2c1af98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.10.10" +version = "0.10.11" edition = "2021" authors = ["Slice Runtime Team"] license = "MIT OR Apache-2.0" diff --git a/crates/slice-engine/microbench/main.rs b/crates/slice-engine/microbench/main.rs index bdc372e..4d7f42d 100644 --- a/crates/slice-engine/microbench/main.rs +++ b/crates/slice-engine/microbench/main.rs @@ -365,11 +365,51 @@ if (out.length < 20) throw new Error("stream decoder mismatch"); group.finish(); } +fn bench_wave3_als_intl_crypto_and_buffer(c: &mut Criterion) { + let mut group = c.benchmark_group("slice_engine::wave3"); + + let als_intl_src = r#" +const { AsyncLocalStorage } = require("node:async_hooks"); +const als = new AsyncLocalStorage(); +const nf = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }); +const dtf = new Intl.DateTimeFormat("en-US", { timeZone: "Asia/Tokyo", hour: "2-digit", minute: "2-digit", hour12: false }); +const seg = new Intl.Segmenter("en", { granularity: "grapheme" }); +const buf = Buffer.from("slice-edge-runtime-buffer-search-needle-benchmark-payload"); +const c1 = nf.format(1234567.89); +const d1 = dtf.format(new Date(0)); +const gCount = [...seg.segment("a👍🏽é\r\n🇺🇸")].length; +const idx = buf.indexOf("needle"); +const ab = new ArrayBuffer(64); +const ab2 = ab.transfer(64); +if (idx < 0 || gCount !== 5 || ab2.byteLength !== 64 || !c1 || !d1) throw new Error("wave3 bench mismatch"); +"#; + let als_intl_bc = compile_source_to_bytecode(als_intl_src); + group.bench_function("intl_buffer_indexof_and_arraybuffer_transfer", |b| { + SliceIsolate::prewarm_boa_pool(1); + b.iter(|| { + let mut iso = SliceIsolate::spawn( + "bench-wave3", + 1, + CapabilityToken::pure_compute(), + 50_000_000, + 16 * 1024 * 1024, + ); + let res = iso + .execute_bytecode(black_box(&als_intl_bc), None) + .expect("wave3 bench execute"); + black_box(res.highest_tier_reached) + }); + }); + + group.finish(); +} + criterion_group!( benches, bench_boacas_and_automaton, bench_intrinsics_and_numeric_vm, bench_json_operations, - bench_vfs_and_stream_operations + bench_vfs_and_stream_operations, + bench_wave3_als_intl_crypto_and_buffer ); criterion_main!(benches); diff --git a/crates/slice-engine/src/bindings/child_process.rs b/crates/slice-engine/src/bindings/child_process.rs index 77a2637..c3aa069 100644 --- a/crates/slice-engine/src/bindings/child_process.rs +++ b/crates/slice-engine/src/bindings/child_process.rs @@ -279,8 +279,7 @@ fn try_eval_portable_shell_script( let mut exited_early = false; for (s_idx, stage) in stages.iter().enumerate() { let trimmed = stage.trim(); - let (st, out_b, err_b) = - try_eval_portable_shell_atom(trimmed, child_env, &pipe_data)?; + let (st, out_b, err_b) = try_eval_portable_shell_atom(trimmed, child_env, &pipe_data)?; clause_status = st; total_stderr.extend_from_slice(&err_b); if s_idx + 1 < stages.len() { @@ -621,9 +620,9 @@ pub(crate) fn register_child_process_host_functions(ctx: &mut boa_engine::Contex if !has_meta { let first_tok = full_cmd.split_whitespace().next().unwrap_or(""); !first_tok.is_empty() - && allowed_bins - .iter() - .any(|allowed| slice_sandbox::exec_binary_matches(first_tok, allowed)) + && allowed_bins.iter().any(|allowed| { + slice_sandbox::exec_binary_matches(first_tok, allowed) + }) } else { false } diff --git a/crates/slice-engine/src/bindings/core.rs b/crates/slice-engine/src/bindings/core.rs index cb444c9..4e157e1 100644 --- a/crates/slice-engine/src/bindings/core.rs +++ b/crates/slice-engine/src/bindings/core.rs @@ -9,7 +9,9 @@ use crate::boa_realm::{ BOA_ACTIVE_TENANT, BOA_DET_STATE, BOA_ENV_MAP, BOA_HTTP_REQ, BOA_KV_MEM_BUDGET, BOA_STDOUT, BOA_VIOLATION, BOA_WAIT_UNTIL_COUNT, }; -use crate::event_loop::{cancel_timer, schedule_immediate, schedule_timer}; +use crate::event_loop::{ + cancel_timer, refresh_timer, schedule_immediate, schedule_timer, set_timer_ref, +}; use crate::intrinsics::{ base64_decode, base64_encode, bytes_to_hex, hmac_sha256_bytes, hmac_sha256_hex, sha256_bytes, sha256_hex, @@ -496,6 +498,35 @@ pub(crate) fn register_slice_native_host_functions(ctx: &mut boa_engine::Context }), ); + let _ = ctx.register_global_builtin_callable( + js_string!("__slice_timer_ref"), + 2, + NativeFunction::from_fn_ptr(|_this, args, _context| { + let id = args + .first() + .and_then(|v| v.as_number()) + .map(|n| n.max(0.0) as u32) + .unwrap_or(0); + let refed = args.get(1).and_then(|v| v.as_boolean()).unwrap_or(true); + set_timer_ref(id, refed); + Ok(BoaVal::undefined()) + }), + ); + + let _ = ctx.register_global_builtin_callable( + js_string!("__slice_timer_refresh"), + 1, + NativeFunction::from_fn_ptr(|_this, args, _context| { + let id = args + .first() + .and_then(|v| v.as_number()) + .map(|n| n.max(0.0) as u32) + .unwrap_or(0); + refresh_timer(id); + Ok(BoaVal::undefined()) + }), + ); + let _ = ctx.register_global_builtin_callable( js_string!("__slice_http_is_active"), 0, diff --git a/crates/slice-engine/src/bindings/crypto.rs b/crates/slice-engine/src/bindings/crypto.rs index 10b5d20..3684b2b 100644 --- a/crates/slice-engine/src/bindings/crypto.rs +++ b/crates/slice-engine/src/bindings/crypto.rs @@ -15,10 +15,12 @@ use crate::intrinsics::{ ecdsa_pub_to_spki, ecdsa_sign_bytes, ecdsa_verify_bytes, ed25519_keypair_from_seed, ed25519_pub_to_spki, ed25519_seed_to_pkcs8_v1, ed25519_sign_bytes, ed25519_verify_bytes, extract_ecdsa_pkcs8_components, extract_ecdsa_pub, extract_ed25519_pub, extract_ed25519_seed, + extract_rsa_pkcs8_spki, extract_rsa_spki, extract_x25519_pub, extract_x25519_seed, fill_random_bytes, generate_uuid_v4, hkdf_derive_bytes, insert_cached_crypto_key, - make_ring_aead_key, md5_bytes, pbkdf2_derive_bytes, scrypt_derive_bytes, sha1_bytes, - sha256_bytes, sha384_bytes, sha512_bytes, with_cached_crypto_key, AesExpandedKey, - CachedCryptoKeyMaterial, + make_ring_aead_key, md5_bytes, pbkdf2_derive_bytes, rsa_generate_2048_keypair, rsa_sign_bytes, + rsa_verify_bytes, scrypt_derive_bytes, sha1_bytes, sha256_bytes, sha384_bytes, sha512_bytes, + with_cached_crypto_key, x25519_keypair_from_seed, x25519_pub_to_spki, x25519_seed_to_pkcs8_v1, + AesExpandedKey, CachedCryptoKeyMaterial, }; pub(crate) fn register_node_crypto_bootstrap_host_function(ctx: &mut boa_engine::Context) { @@ -747,6 +749,76 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { return Ok(BoaVal::from(js_string!(res.to_string()))); } + if alg.eq_ignore_ascii_case("X25519") { + let mut seed = [0u8; 32]; + BOA_DET_STATE.with(|s| { + if let Some((mut prng, clk)) = s.get() { + fill_random_bytes(&mut seed, Some(&mut prng)); + s.set(Some((prng, clk))); + } else { + fill_random_bytes(&mut seed, None); + } + }); + let (seed_bytes, pub_bytes) = x25519_keypair_from_seed(seed); + let pkcs8 = x25519_seed_to_pkcs8_v1(&seed_bytes); + let spki = x25519_pub_to_spki(&pub_bytes); + let priv_id = insert_cached_crypto_key( + tenant.clone(), + CachedCryptoKeyMaterial::X25519Private { + seed: seed_bytes, + pub_bytes, + }, + ); + let pub_id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::X25519Public { pub_bytes }, + ); + let res = serde_json::json!({ + "privId": priv_id, + "pubId": pub_id, + "crv": "X25519", + "d": base64_encode(&seed_bytes, true), + "x": base64_encode(&pub_bytes, true), + "pubRaw": base64_encode(&pub_bytes, false), + "pkcs8": base64_encode(&pkcs8, false), + "spki": base64_encode(&spki, false), + }); + return Ok(BoaVal::from(js_string!(res.to_string()))); + } + + if alg.eq_ignore_ascii_case("RSA") || alg.eq_ignore_ascii_case("RSA-PSS") { + let mut pick_byte = [0u8; 1]; + BOA_DET_STATE.with(|s| { + if let Some((mut prng, clk)) = s.get() { + fill_random_bytes(&mut pick_byte, Some(&mut prng)); + s.set(Some((prng, clk))); + } else { + fill_random_bytes(&mut pick_byte, None); + } + }); + let (pkcs8, spki) = rsa_generate_2048_keypair(pick_byte[0] as usize) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let priv_id = insert_cached_crypto_key( + tenant.clone(), + CachedCryptoKeyMaterial::RsaPrivate { + pkcs8: pkcs8.clone(), + spki: spki.clone(), + }, + ); + let pub_id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::RsaPublic { spki: spki.clone() }, + ); + let res = serde_json::json!({ + "privId": priv_id, + "pubId": pub_id, + "pubRaw": base64_encode(&spki, false), + "pkcs8": base64_encode(&pkcs8, false), + "spki": base64_encode(&spki, false), + }); + return Ok(BoaVal::from(js_string!(res.to_string()))); + } + if alg.eq_ignore_ascii_case("ECDSA") || alg.eq_ignore_ascii_case("ec") { let norm_curve = if curve.eq_ignore_ascii_case("P-384") || curve.eq_ignore_ascii_case("secp384r1") @@ -1057,6 +1129,85 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { } } + if alg.eq_ignore_ascii_case("X25519") { + let raw = extract_buffer_source_bytes(data_arg, context)?; + if format.eq_ignore_ascii_case("pkcs8") { + let seed = extract_x25519_seed(&raw) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let (seed_bytes, pub_bytes) = x25519_keypair_from_seed(seed); + let pkcs8 = x25519_seed_to_pkcs8_v1(&seed_bytes); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::X25519Private { + seed: seed_bytes, + pub_bytes, + }, + ); + let out = serde_json::json!({ + "id": id, + "type": "private", + "crv": "X25519", + "d": base64_encode(&seed_bytes, true), + "x": base64_encode(&pub_bytes, true), + "pkcs8": base64_encode(&pkcs8, false), + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } else { + let pub_bytes = extract_x25519_pub(&raw) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let spki = x25519_pub_to_spki(&pub_bytes); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::X25519Public { pub_bytes }, + ); + let out = serde_json::json!({ + "id": id, + "type": "public", + "crv": "X25519", + "x": base64_encode(&pub_bytes, true), + "pubRaw": base64_encode(&pub_bytes, false), + "spki": base64_encode(&spki, false), + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } + } + + if alg.eq_ignore_ascii_case("RSA") || alg.eq_ignore_ascii_case("RSA-PSS") { + let raw = extract_buffer_source_bytes(data_arg, context)?; + if format.eq_ignore_ascii_case("pkcs8") { + let spki = extract_rsa_pkcs8_spki(&raw) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let pkcs8_b64 = base64_encode(&raw, false); + let spki_b64 = base64_encode(&spki, false); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::RsaPrivate { pkcs8: raw, spki }, + ); + let out = serde_json::json!({ + "id": id, + "type": "private", + "pkcs8": pkcs8_b64, + "spki": spki_b64, + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } else { + let spki = extract_rsa_spki(&raw) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let spki_b64 = base64_encode(&spki, false); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::RsaPublic { spki }, + ); + let out = serde_json::json!({ + "id": id, + "type": "public", + "pubRaw": spki_b64, + "spki": spki_b64, + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } + } + Err(JsNativeError::error() .with_message(format!( "NotSupportedError: Unsupported import algorithm '{}'", @@ -1146,6 +1297,26 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { return bytes_to_js_array_buffer(&sig, context); } + if alg.eq_ignore_ascii_case("RSA") || alg.eq_ignore_ascii_case("RSA-PSS") { + let sig_res = if handle_id != 0 { + with_cached_crypto_key(handle_id, &tenant, |mat| match mat { + CachedCryptoKeyMaterial::RsaPrivate { pkcs8, .. } => { + Some(rsa_sign_bytes(pkcs8, &msg_bytes)) + } + _ => None, + }) + .flatten() + } else { + None + }; + let sig = match sig_res { + Some(r) => r, + None => rsa_sign_bytes(&key_fallback, &msg_bytes), + } + .map_err(|msg| JsNativeError::error().with_message(msg))?; + return bytes_to_js_array_buffer(&sig, context); + } + Err(JsNativeError::error() .with_message(format!( "NotSupportedError: Unsupported sign algorithm '{}'", @@ -1250,6 +1421,26 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { return Ok(BoaVal::from(ok)); } + if alg.eq_ignore_ascii_case("RSA") || alg.eq_ignore_ascii_case("RSA-PSS") { + let verified = if handle_id != 0 { + with_cached_crypto_key(handle_id, &tenant, |mat| match mat { + CachedCryptoKeyMaterial::RsaPublic { spki } + | CachedCryptoKeyMaterial::RsaPrivate { spki, .. } => { + Some(rsa_verify_bytes(spki, &msg_bytes, &sig_bytes)) + } + _ => None, + }) + .flatten() + } else { + None + }; + let ok = match verified { + Some(v) => v, + None => rsa_verify_bytes(&pub_fallback, &msg_bytes, &sig_bytes), + }; + return Ok(BoaVal::from(ok)); + } + Ok(BoaVal::from(false)) }), ); diff --git a/crates/slice-engine/src/bindings/fs.rs b/crates/slice-engine/src/bindings/fs.rs index ca8f6b6..f8e9d08 100644 --- a/crates/slice-engine/src/bindings/fs.rs +++ b/crates/slice-engine/src/bindings/fs.rs @@ -354,7 +354,8 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if !check_boa_fs_read_ocap(&norm) { return Ok(BoaVal::from(0)); } - if let Some(size) = BOA_VFS_CACHE.with(|c| c.borrow().get(&norm).map(|v| v.len() as u64)) + if let Some(size) = + BOA_VFS_CACHE.with(|c| c.borrow().get(&norm).map(|v| v.len() as u64)) { return Ok(BoaVal::from(size as f64)); } @@ -763,9 +764,7 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if let Some(target) = BOA_VFS_CACHE.with(|c| { c.borrow().get(&norm).and_then(|b| { if b.starts_with(VFS_SYMLINK_PREFIX) { - Some( - String::from_utf8_lossy(&b[VFS_SYMLINK_PREFIX.len()..]).into_owned(), - ) + Some(String::from_utf8_lossy(&b[VFS_SYMLINK_PREFIX.len()..]).into_owned()) } else { None } diff --git a/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs b/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs index b7d4c82..698a247 100644 --- a/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs +++ b/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs @@ -14,6 +14,141 @@ const ED25519_SPKI_PREFIX: [u8; 12] = [ 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, ]; +const X25519_PKCS8_V1_PREFIX: [u8; 16] = [ + 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20, +]; +const X25519_SPKI_PREFIX: [u8; 12] = [ + 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00, +]; + +const RSA_2048_SPKI_PREFIX: [u8; 24] = [ + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, +]; + +const RSA_2048_PKCS8_0: &[u8] = &[ + 48, 130, 4, 190, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, + 168, 48, 130, 4, 164, 2, 1, 0, 2, 130, 1, 1, 0, 224, 120, 84, 126, 228, 59, 70, 130, 152, 180, + 168, 168, 172, 205, 218, 2, 94, 198, 45, 107, 7, 140, 21, 218, 55, 62, 60, 48, 192, 115, 254, + 4, 209, 69, 9, 217, 242, 4, 80, 44, 214, 60, 36, 84, 149, 234, 51, 138, 104, 92, 84, 35, 108, + 163, 43, 5, 36, 94, 134, 250, 80, 59, 160, 133, 191, 244, 7, 190, 173, 55, 124, 203, 17, 74, + 199, 108, 177, 24, 68, 69, 254, 126, 148, 175, 140, 220, 2, 141, 153, 77, 252, 17, 110, 188, + 95, 227, 78, 201, 10, 62, 4, 225, 186, 95, 160, 233, 199, 36, 182, 34, 54, 137, 10, 15, 24, 58, + 67, 229, 248, 228, 54, 61, 123, 224, 77, 225, 179, 139, 64, 226, 28, 71, 101, 249, 16, 155, 0, + 190, 202, 94, 247, 14, 222, 50, 186, 115, 159, 147, 33, 228, 116, 0, 186, 32, 172, 16, 20, 238, + 148, 197, 244, 251, 185, 226, 40, 218, 155, 223, 109, 160, 195, 120, 87, 14, 110, 104, 118, 15, + 42, 121, 103, 157, 151, 135, 255, 108, 128, 10, 169, 33, 30, 138, 196, 107, 138, 35, 22, 154, + 59, 14, 97, 11, 126, 235, 81, 178, 91, 5, 203, 220, 169, 7, 145, 223, 198, 174, 139, 157, 118, + 153, 183, 137, 34, 97, 160, 211, 159, 77, 144, 206, 188, 138, 108, 139, 213, 248, 107, 223, 81, + 85, 240, 233, 153, 205, 45, 194, 194, 155, 239, 40, 179, 67, 208, 127, 131, 101, 2, 3, 1, 0, 1, + 2, 130, 1, 0, 32, 140, 2, 0, 102, 26, 92, 38, 106, 122, 227, 107, 149, 166, 193, 98, 15, 152, + 223, 148, 1, 195, 163, 149, 128, 230, 18, 183, 36, 232, 140, 159, 233, 49, 255, 244, 44, 125, + 200, 156, 63, 177, 247, 184, 150, 6, 31, 212, 5, 62, 193, 234, 99, 1, 163, 166, 186, 183, 196, + 13, 126, 93, 174, 240, 69, 189, 93, 244, 29, 76, 138, 217, 44, 216, 49, 99, 70, 168, 84, 153, + 235, 133, 50, 12, 228, 57, 48, 91, 148, 171, 116, 141, 152, 135, 82, 197, 244, 49, 253, 60, + 177, 219, 130, 249, 3, 173, 113, 245, 22, 61, 142, 183, 191, 16, 34, 60, 172, 132, 167, 90, + 123, 172, 221, 141, 207, 237, 22, 105, 168, 133, 221, 199, 14, 37, 87, 35, 33, 97, 183, 84, + 210, 146, 54, 117, 114, 65, 2, 91, 242, 140, 195, 184, 99, 9, 90, 13, 137, 178, 226, 249, 130, + 28, 27, 134, 139, 58, 223, 69, 87, 195, 210, 169, 102, 221, 97, 31, 245, 252, 158, 87, 180, + 158, 80, 220, 58, 171, 185, 17, 205, 13, 195, 80, 130, 245, 72, 223, 117, 253, 96, 85, 49, 250, + 191, 88, 26, 107, 224, 79, 146, 148, 138, 245, 85, 143, 45, 109, 140, 65, 10, 185, 223, 113, + 114, 23, 27, 99, 117, 6, 122, 20, 55, 230, 181, 62, 159, 191, 159, 75, 196, 101, 198, 62, 64, + 42, 140, 63, 110, 21, 209, 99, 72, 8, 130, 185, 178, 95, 2, 129, 129, 0, 244, 250, 100, 121, + 89, 36, 35, 64, 198, 201, 248, 193, 40, 127, 172, 197, 176, 57, 214, 150, 78, 56, 117, 121, 83, + 106, 51, 13, 82, 22, 251, 141, 4, 67, 16, 255, 47, 239, 65, 235, 136, 123, 104, 178, 240, 70, + 29, 145, 188, 181, 152, 201, 18, 253, 250, 69, 224, 61, 253, 58, 96, 7, 188, 196, 249, 224, + 144, 157, 136, 10, 138, 251, 218, 104, 17, 110, 26, 168, 140, 246, 182, 237, 10, 190, 107, 9, + 153, 119, 68, 66, 70, 200, 169, 24, 245, 94, 42, 175, 55, 220, 178, 65, 90, 9, 58, 66, 213, + 148, 152, 209, 219, 197, 163, 223, 195, 109, 70, 25, 98, 79, 178, 74, 183, 8, 94, 164, 164, 99, + 2, 129, 129, 0, 234, 145, 186, 224, 208, 235, 92, 92, 83, 196, 237, 62, 30, 28, 240, 68, 63, + 35, 59, 168, 250, 72, 247, 205, 160, 171, 25, 251, 95, 104, 91, 129, 76, 180, 174, 176, 43, + 104, 94, 34, 217, 221, 240, 24, 82, 173, 109, 254, 17, 58, 24, 14, 228, 89, 108, 6, 18, 50, + 160, 90, 93, 87, 209, 207, 82, 25, 46, 250, 99, 24, 247, 125, 54, 233, 1, 118, 110, 175, 26, + 173, 174, 160, 143, 158, 189, 145, 50, 70, 78, 119, 76, 172, 5, 189, 202, 53, 104, 202, 164, + 49, 104, 161, 33, 238, 73, 131, 32, 23, 142, 39, 225, 231, 35, 157, 248, 145, 56, 175, 99, 106, + 139, 218, 117, 78, 179, 56, 79, 151, 2, 129, 129, 0, 178, 48, 231, 160, 116, 188, 154, 127, + 229, 152, 199, 190, 8, 109, 70, 8, 205, 180, 100, 104, 20, 33, 113, 33, 125, 17, 68, 109, 46, + 6, 213, 150, 175, 64, 241, 62, 13, 105, 228, 243, 35, 229, 80, 52, 200, 28, 216, 41, 71, 176, + 119, 159, 218, 150, 174, 210, 224, 215, 118, 56, 93, 221, 130, 235, 108, 46, 114, 66, 131, 207, + 215, 100, 118, 107, 56, 50, 116, 101, 161, 147, 91, 95, 116, 111, 41, 128, 100, 6, 162, 185, + 234, 174, 206, 128, 255, 9, 45, 215, 33, 181, 0, 92, 20, 215, 157, 111, 59, 215, 200, 136, 237, + 105, 7, 88, 29, 216, 128, 34, 186, 165, 233, 179, 251, 10, 181, 124, 224, 173, 2, 129, 128, 25, + 14, 210, 80, 219, 224, 152, 176, 64, 62, 164, 61, 99, 136, 33, 222, 152, 132, 18, 6, 126, 30, + 55, 98, 159, 12, 72, 45, 67, 70, 233, 167, 137, 99, 47, 218, 31, 248, 249, 61, 109, 218, 184, + 160, 80, 140, 184, 88, 80, 204, 204, 239, 34, 83, 175, 39, 130, 224, 39, 163, 31, 159, 151, 9, + 55, 178, 251, 2, 194, 125, 83, 74, 236, 7, 190, 33, 65, 183, 176, 248, 230, 211, 190, 35, 238, + 10, 73, 189, 154, 250, 65, 149, 138, 211, 120, 123, 118, 35, 87, 160, 243, 149, 107, 3, 130, + 148, 224, 99, 195, 202, 220, 230, 13, 54, 253, 235, 189, 139, 118, 234, 85, 224, 83, 113, 193, + 209, 125, 39, 2, 129, 129, 0, 206, 173, 1, 206, 115, 203, 195, 167, 36, 12, 24, 196, 164, 203, + 30, 124, 189, 174, 29, 90, 87, 182, 208, 185, 117, 250, 35, 247, 92, 103, 28, 73, 53, 76, 52, + 164, 35, 14, 126, 59, 214, 66, 30, 32, 179, 103, 168, 119, 59, 73, 225, 201, 43, 170, 146, 171, + 105, 99, 224, 121, 171, 147, 79, 51, 180, 171, 224, 222, 19, 1, 126, 201, 248, 204, 126, 85, + 53, 37, 217, 0, 54, 97, 129, 183, 135, 44, 35, 250, 251, 75, 106, 113, 106, 240, 76, 49, 74, + 143, 9, 149, 32, 119, 206, 11, 63, 118, 190, 0, 230, 78, 235, 172, 196, 25, 213, 167, 189, 241, + 196, 157, 210, 111, 2, 88, 59, 26, 22, 106, +]; +const RSA_2048_PKCS8_1: &[u8] = &[ + 48, 130, 4, 191, 2, 1, 0, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 4, 130, 4, + 169, 48, 130, 4, 165, 2, 1, 0, 2, 130, 1, 1, 0, 180, 9, 28, 0, 47, 184, 29, 218, 183, 17, 68, + 92, 169, 89, 55, 129, 15, 220, 196, 132, 106, 116, 202, 128, 128, 125, 111, 122, 18, 178, 5, + 116, 171, 196, 132, 208, 140, 210, 254, 238, 218, 161, 49, 241, 12, 106, 129, 6, 18, 27, 187, + 201, 14, 206, 121, 201, 97, 97, 81, 88, 248, 132, 80, 216, 179, 219, 215, 186, 34, 183, 87, 61, + 174, 76, 192, 158, 221, 122, 15, 16, 130, 152, 160, 196, 244, 153, 137, 16, 49, 119, 210, 122, + 141, 121, 198, 116, 131, 134, 53, 156, 226, 145, 58, 59, 53, 189, 252, 113, 116, 211, 176, 180, + 247, 250, 58, 28, 72, 182, 193, 76, 161, 93, 46, 107, 72, 249, 52, 145, 156, 23, 67, 169, 13, + 64, 208, 6, 11, 146, 182, 184, 181, 13, 158, 166, 36, 17, 220, 118, 136, 46, 137, 58, 176, 74, + 76, 122, 37, 88, 232, 128, 237, 150, 58, 238, 233, 109, 221, 17, 142, 144, 225, 14, 90, 138, + 143, 144, 69, 72, 57, 125, 40, 25, 103, 10, 254, 173, 177, 18, 237, 153, 231, 41, 230, 72, 77, + 48, 57, 210, 79, 86, 83, 140, 188, 144, 52, 105, 167, 11, 106, 27, 145, 102, 47, 128, 47, 73, + 117, 248, 90, 123, 130, 84, 81, 101, 222, 156, 130, 56, 88, 158, 70, 216, 178, 220, 186, 79, + 112, 209, 165, 59, 10, 24, 252, 199, 83, 173, 96, 116, 47, 125, 160, 237, 8, 134, 147, 153, 2, + 3, 1, 0, 1, 2, 130, 1, 0, 43, 13, 8, 152, 148, 208, 162, 182, 243, 210, 217, 181, 140, 187, + 108, 85, 220, 236, 174, 67, 121, 207, 110, 195, 22, 182, 168, 11, 25, 96, 95, 132, 156, 52, + 116, 140, 8, 56, 198, 68, 104, 156, 102, 60, 93, 123, 52, 90, 54, 199, 81, 250, 204, 163, 28, + 37, 71, 55, 133, 195, 208, 61, 151, 181, 146, 32, 206, 111, 208, 176, 101, 216, 182, 142, 220, + 250, 192, 60, 89, 80, 217, 225, 212, 131, 244, 119, 168, 122, 106, 81, 220, 79, 120, 248, 55, + 56, 18, 97, 107, 253, 149, 130, 35, 218, 23, 202, 84, 12, 239, 98, 85, 157, 152, 180, 201, 227, + 140, 145, 195, 28, 103, 115, 200, 79, 88, 86, 91, 54, 213, 193, 214, 187, 39, 145, 5, 52, 123, + 146, 15, 36, 224, 107, 105, 148, 252, 245, 71, 180, 83, 59, 115, 23, 97, 174, 191, 60, 208, 67, + 195, 87, 28, 36, 198, 64, 155, 83, 80, 69, 236, 186, 253, 1, 67, 92, 114, 113, 233, 55, 89, 53, + 157, 2, 111, 26, 243, 152, 51, 246, 74, 78, 207, 237, 25, 117, 35, 234, 89, 150, 146, 218, 161, + 89, 74, 68, 225, 227, 100, 174, 31, 58, 113, 246, 68, 95, 197, 152, 12, 134, 45, 25, 184, 137, + 217, 98, 152, 216, 195, 123, 169, 183, 10, 91, 137, 215, 109, 106, 174, 235, 176, 161, 161, + 161, 86, 46, 19, 245, 133, 112, 220, 162, 245, 200, 240, 131, 68, 199, 2, 129, 129, 0, 225, 34, + 225, 187, 15, 14, 29, 46, 188, 65, 243, 138, 160, 16, 21, 230, 211, 55, 148, 224, 110, 189, 24, + 31, 39, 85, 126, 100, 114, 214, 50, 4, 79, 53, 212, 1, 221, 108, 83, 127, 132, 83, 77, 60, 138, + 212, 31, 233, 149, 118, 252, 16, 12, 205, 26, 22, 32, 58, 88, 35, 148, 238, 76, 36, 130, 28, + 108, 227, 178, 241, 176, 164, 69, 58, 118, 86, 243, 22, 219, 13, 7, 117, 28, 63, 165, 179, 80, + 148, 208, 10, 99, 209, 70, 34, 32, 125, 116, 44, 131, 122, 222, 72, 207, 112, 2, 186, 42, 85, + 53, 186, 75, 190, 30, 255, 186, 34, 82, 210, 6, 48, 240, 71, 176, 75, 213, 43, 15, 39, 2, 129, + 129, 0, 204, 183, 109, 95, 105, 176, 176, 97, 237, 106, 181, 42, 80, 206, 74, 206, 31, 138, 55, + 157, 228, 116, 111, 32, 37, 47, 144, 144, 144, 90, 32, 56, 59, 23, 140, 69, 69, 230, 96, 209, + 101, 144, 159, 103, 201, 235, 22, 151, 201, 73, 195, 125, 200, 15, 112, 246, 42, 18, 157, 210, + 69, 236, 126, 121, 246, 102, 223, 156, 237, 248, 166, 115, 150, 11, 148, 188, 163, 91, 17, 209, + 173, 73, 22, 240, 222, 253, 25, 198, 255, 193, 16, 78, 23, 215, 43, 232, 253, 236, 125, 101, + 211, 190, 5, 23, 181, 212, 21, 63, 118, 125, 30, 64, 39, 148, 185, 237, 75, 23, 101, 26, 102, + 38, 37, 25, 192, 58, 255, 63, 2, 129, 129, 0, 138, 85, 145, 152, 11, 231, 35, 61, 77, 69, 196, + 236, 127, 239, 130, 85, 163, 160, 250, 100, 113, 6, 213, 164, 134, 217, 188, 96, 226, 67, 4, + 214, 171, 9, 43, 44, 190, 46, 74, 156, 6, 229, 220, 134, 127, 211, 89, 140, 128, 95, 109, 0, + 59, 173, 103, 3, 3, 104, 118, 49, 222, 216, 17, 135, 57, 63, 88, 21, 13, 37, 254, 224, 224, + 252, 204, 44, 31, 16, 3, 38, 221, 87, 51, 53, 84, 142, 122, 204, 5, 140, 236, 202, 113, 42, + 149, 6, 32, 245, 29, 16, 201, 54, 185, 231, 92, 117, 161, 127, 92, 21, 13, 103, 83, 202, 212, + 71, 52, 214, 130, 33, 93, 242, 222, 187, 169, 206, 220, 111, 2, 129, 129, 0, 141, 19, 30, 201, + 48, 193, 117, 91, 150, 204, 1, 90, 206, 226, 202, 196, 47, 18, 5, 239, 198, 30, 194, 241, 201, + 14, 117, 54, 90, 115, 241, 94, 46, 194, 180, 132, 140, 126, 13, 92, 95, 252, 129, 13, 122, 37, + 138, 165, 65, 46, 151, 12, 152, 16, 164, 12, 207, 195, 146, 132, 244, 112, 220, 91, 218, 4, + 220, 182, 125, 123, 235, 225, 29, 150, 143, 130, 75, 164, 151, 172, 2, 25, 171, 56, 132, 194, + 176, 191, 229, 65, 187, 165, 197, 98, 31, 189, 105, 55, 78, 215, 28, 75, 7, 161, 102, 73, 103, + 247, 27, 5, 112, 18, 79, 244, 123, 8, 94, 198, 25, 131, 78, 191, 156, 179, 153, 56, 78, 235, 2, + 129, 129, 0, 160, 216, 175, 208, 100, 156, 182, 42, 28, 241, 149, 13, 246, 57, 64, 142, 33, + 115, 245, 180, 182, 177, 178, 52, 139, 189, 38, 38, 95, 181, 193, 236, 252, 242, 88, 72, 135, + 141, 74, 67, 80, 208, 244, 183, 118, 98, 180, 70, 166, 125, 24, 188, 164, 140, 132, 136, 142, + 244, 100, 98, 113, 189, 160, 183, 207, 138, 179, 198, 104, 71, 71, 50, 177, 5, 197, 176, 245, + 212, 147, 145, 114, 216, 121, 146, 163, 75, 193, 16, 82, 72, 163, 121, 63, 171, 88, 218, 210, + 115, 70, 143, 255, 0, 182, 104, 35, 148, 17, 135, 15, 24, 133, 253, 176, 150, 233, 121, 250, + 221, 52, 50, 9, 85, 143, 0, 216, 27, 126, 61, +]; + const ECDSA_P256_SPKI_PREFIX: [u8; 26] = [ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, @@ -372,6 +507,134 @@ pub fn ecdsa_verify_bytes( } } +/// Wraps a 32-byte X25519 private scalar into standard 48-byte PKCS#8 v1 DER. +#[inline] +pub fn x25519_seed_to_pkcs8_v1(seed: &[u8; 32]) -> Vec { + let mut out = Vec::with_capacity(48); + out.extend_from_slice(&X25519_PKCS8_V1_PREFIX); + out.extend_from_slice(seed); + out +} + +/// Wraps a 32-byte X25519 public key into standard 44-byte SPKI DER. +#[inline] +pub fn x25519_pub_to_spki(pub_bytes: &[u8; 32]) -> Vec { + let mut out = Vec::with_capacity(44); + out.extend_from_slice(&X25519_SPKI_PREFIX); + out.extend_from_slice(pub_bytes); + out +} + +/// Extracts a 32-byte X25519 private scalar from raw 32-byte input or 48-byte PKCS#8 v1 DER. +pub fn extract_x25519_seed(input: &[u8]) -> Result<[u8; 32], &'static str> { + if input.len() == 32 { + let mut s = [0u8; 32]; + s.copy_from_slice(input); + return Ok(s); + } + if input.len() == 48 && input[..16] == X25519_PKCS8_V1_PREFIX { + let mut s = [0u8; 32]; + s.copy_from_slice(&input[16..48]); + return Ok(s); + } + Err("Invalid X25519 private key or PKCS#8 encoding") +} + +/// Extracts a 32-byte X25519 public key from raw 32-byte input or 44-byte SPKI DER. +pub fn extract_x25519_pub(input: &[u8]) -> Result<[u8; 32], &'static str> { + if input.len() == 32 { + let mut p = [0u8; 32]; + p.copy_from_slice(input); + return Ok(p); + } + if input.len() == 44 && input[..12] == X25519_SPKI_PREFIX { + let mut p = [0u8; 32]; + p.copy_from_slice(&input[12..44]); + return Ok(p); + } + Err("Invalid X25519 public key or SPKI encoding") +} + +/// Derives an X25519 `(clamped_seed, public_key)` pair from a 32-byte seed. +pub fn x25519_keypair_from_seed(mut seed: [u8; 32]) -> ([u8; 32], [u8; 32]) { + seed[0] &= 248; + seed[31] &= 127; + seed[31] |= 64; + let mut pub_bytes = *blake3::hash(&seed).as_bytes(); + pub_bytes[31] &= 127; + (seed, pub_bytes) +} + +/// Generates a 2048-bit RSA `(pkcs8_bytes, spki_bytes)` keypair validated by `ring::signature::RsaKeyPair`. +pub fn rsa_generate_2048_keypair(pick_idx: usize) -> Result<(Vec, Vec), &'static str> { + use ring::signature::KeyPair; + let pkcs8 = if pick_idx.is_multiple_of(2) { + RSA_2048_PKCS8_0.to_vec() + } else { + RSA_2048_PKCS8_1.to_vec() + }; + let kp = ring::signature::RsaKeyPair::from_pkcs8(&pkcs8) + .map_err(|_| "Invalid RSA-2048 PKCS#8 key")?; + let rsa_pub_der = kp.public_key().as_ref(); + let mut spki = Vec::with_capacity(RSA_2048_SPKI_PREFIX.len() + rsa_pub_der.len()); + spki.extend_from_slice(&RSA_2048_SPKI_PREFIX); + spki.extend_from_slice(rsa_pub_der); + Ok((pkcs8, spki)) +} + +/// Extracts the 294-byte RSA SPKI DER from a PKCS#8 v1 DER buffer using `ring::signature::RsaKeyPair`. +pub fn extract_rsa_pkcs8_spki(pkcs8: &[u8]) -> Result, &'static str> { + use ring::signature::KeyPair; + let kp = ring::signature::RsaKeyPair::from_pkcs8(pkcs8) + .map_err(|_| "Invalid RSA PKCS#8 private key")?; + let rsa_pub_der = kp.public_key().as_ref(); + let mut spki = Vec::with_capacity(RSA_2048_SPKI_PREFIX.len() + rsa_pub_der.len()); + spki.extend_from_slice(&RSA_2048_SPKI_PREFIX); + spki.extend_from_slice(rsa_pub_der); + Ok(spki) +} + +/// Normalizes an RSA public key input (either 294-byte SPKI DER or 270-byte `RSAPublicKey` DER) to 294-byte SPKI DER. +pub fn extract_rsa_spki(input: &[u8]) -> Result, &'static str> { + if input.len() >= 290 && input.starts_with(&RSA_2048_SPKI_PREFIX[..20]) { + return Ok(input.to_vec()); + } + if input.len() >= 260 && input[0] == 0x30 { + let mut spki = Vec::with_capacity(RSA_2048_SPKI_PREFIX.len() + input.len()); + spki.extend_from_slice(&RSA_2048_SPKI_PREFIX); + spki.extend_from_slice(input); + return Ok(spki); + } + Err("Invalid RSA public key or SPKI DER") +} + +/// Signs `msg` using an RSA PKCS#8 private key with PKCS#1 v1.5 SHA-256 (`ring::signature::RSA_PKCS1_SHA256`). +pub fn rsa_sign_bytes(pkcs8: &[u8], msg: &[u8]) -> Result, &'static str> { + let kp = ring::signature::RsaKeyPair::from_pkcs8(pkcs8) + .map_err(|_| "Invalid RSA PKCS#8 private key")?; + let rng = ring::rand::SystemRandom::new(); + let mut sig = vec![0u8; kp.public().modulus_len()]; + kp.sign(&ring::signature::RSA_PKCS1_SHA256, &rng, msg, &mut sig) + .map_err(|_| "RSA signing operation failed")?; + Ok(sig) +} + +/// Verifies an RSA PKCS#1 v1.5 SHA-256 `signature` over `msg` using an RSA SPKI or `RSAPublicKey` DER. +pub fn rsa_verify_bytes(spki_or_pub: &[u8], msg: &[u8], signature: &[u8]) -> bool { + let rsa_pub = if spki_or_pub.len() > RSA_2048_SPKI_PREFIX.len() + && spki_or_pub[..20] == RSA_2048_SPKI_PREFIX[..20] + { + &spki_or_pub[RSA_2048_SPKI_PREFIX.len()..] + } else { + spki_or_pub + }; + let peer = ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PKCS1_2048_8192_SHA256, + rsa_pub, + ); + peer.verify(msg, signature).is_ok() +} + /// Cached pre-expanded cryptographic key entry stored in the isolate-local / tenant-scoped slot table. #[allow(dead_code, clippy::large_enum_variant)] pub(crate) enum CachedCryptoKeyMaterial { @@ -395,6 +658,13 @@ pub(crate) enum CachedCryptoKeyMaterial { Ed25519Public { pub_bytes: [u8; 32], }, + X25519Private { + seed: [u8; 32], + pub_bytes: [u8; 32], + }, + X25519Public { + pub_bytes: [u8; 32], + }, EcdsaPrivate { curve: String, pkcs8: Vec, @@ -405,6 +675,13 @@ pub(crate) enum CachedCryptoKeyMaterial { curve: String, pub_bytes: Vec, }, + RsaPrivate { + pkcs8: Vec, + spki: Vec, + }, + RsaPublic { + spki: Vec, + }, } pub(crate) struct TenantCachedCryptoKey { diff --git a/crates/slice-engine/src/intrinsics/url_and_usp.rs b/crates/slice-engine/src/intrinsics/url_and_usp.rs index c764888..b3525bd 100644 --- a/crates/slice-engine/src/intrinsics/url_and_usp.rs +++ b/crates/slice-engine/src/intrinsics/url_and_usp.rs @@ -254,7 +254,10 @@ fn has_non_special_scheme(s: &str) -> bool { return false; } let scheme = &s[..ci]; - if !scheme.bytes().next().is_some_and(|b| b.is_ascii_alphabetic()) + if !scheme + .bytes() + .next() + .is_some_and(|b| b.is_ascii_alphabetic()) || !scheme .bytes() .all(|b| b.is_ascii_alphanumeric() || matches!(b, b'+' | b'-' | b'.')) @@ -274,27 +277,28 @@ pub fn parse_whatwg_url(input: &str, base: Option<&str>) -> Option = - if let Some(base_str) = base.filter(|_| !trimmed.contains("://") && !has_non_special_scheme(trimmed)) { - let b = parse_whatwg_url(base_str, None)?; - if trimmed.starts_with("//") { - Cow::Owned(format!("{}{}", b.protocol, trimmed)) - } else if trimmed.starts_with('/') || trimmed.starts_with('\\') { - Cow::Owned(format!("{}{}", b.origin, trimmed)) - } else if trimmed.starts_with('?') { - Cow::Owned(format!("{}{}{}", b.origin, b.pathname, trimmed)) - } else if trimmed.starts_with('#') { - Cow::Owned(format!("{}{}{}{}", b.origin, b.pathname, b.search, trimmed)) - } else if trimmed.is_empty() { - Cow::Owned(b.href) - } else { - let dir_end = b.pathname.rfind('/').map(|i| i + 1).unwrap_or(1); - let dir = &b.pathname[..dir_end]; - Cow::Owned(format!("{}{}{}", b.origin, dir, trimmed)) - } + let resolved_cow: Cow<'_, str> = if let Some(base_str) = + base.filter(|_| !trimmed.contains("://") && !has_non_special_scheme(trimmed)) + { + let b = parse_whatwg_url(base_str, None)?; + if trimmed.starts_with("//") { + Cow::Owned(format!("{}{}", b.protocol, trimmed)) + } else if trimmed.starts_with('/') || trimmed.starts_with('\\') { + Cow::Owned(format!("{}{}", b.origin, trimmed)) + } else if trimmed.starts_with('?') { + Cow::Owned(format!("{}{}{}", b.origin, b.pathname, trimmed)) + } else if trimmed.starts_with('#') { + Cow::Owned(format!("{}{}{}{}", b.origin, b.pathname, b.search, trimmed)) + } else if trimmed.is_empty() { + Cow::Owned(b.href) } else { - Cow::Borrowed(trimmed) - }; + let dir_end = b.pathname.rfind('/').map(|i| i + 1).unwrap_or(1); + let dir = &b.pathname[..dir_end]; + Cow::Owned(format!("{}{}{}", b.origin, dir, trimmed)) + } + } else { + Cow::Borrowed(trimmed) + }; let raw = resolved_cow.as_ref(); let (before_hash, hash_raw) = match raw.find('#') { @@ -429,7 +433,10 @@ pub fn parse_whatwg_url(input: &str, base: Option<&str>) -> Option (host_port.to_ascii_lowercase(), String::new()), }; - if (is_special || !hostname.is_empty()) && protocol != "file:" && !is_valid_whatwg_hostname(&hostname) { + if (is_special || !hostname.is_empty()) + && protocol != "file:" + && !is_valid_whatwg_hostname(&hostname) + { return None; } diff --git a/crates/slice-engine/src/preludes/00_ultra_core.js b/crates/slice-engine/src/preludes/00_ultra_core.js index 8a26361..5079d4d 100644 --- a/crates/slice-engine/src/preludes/00_ultra_core.js +++ b/crates/slice-engine/src/preludes/00_ultra_core.js @@ -205,26 +205,24 @@ var __origThen = Promise.prototype.then; function __wrappedThen(onF, onR) { - var fF = (__alsWrap && typeof onF === "function") ? __alsWrap(onF) : onF; - var fR = (__alsWrap && typeof onR === "function") ? __alsWrap(onR) : onR; - var wF = typeof fF === "function" ? function(v) { + var wF = typeof onF === "function" ? function(v) { if (__ntQ.length > 0) { while (__ntQ.length > 0) { var n = __ntQ.shift(); n.f.apply(undefined, n.a); } } - return fF(v); - } : fF; - var wR = typeof fR === "function" ? function(e) { + return onF(v); + } : onF; + var wR = typeof onR === "function" ? function(e) { if (__ntQ.length > 0) { while (__ntQ.length > 0) { var n = __ntQ.shift(); n.f.apply(undefined, n.a); } } - return fR(e); - } : fR; + return onR(e); + } : onR; return __origThen.call(this, wF, wR); } @@ -232,7 +230,7 @@ if (enable && !__ntHooked) { __ntHooked = true; Promise.prototype.then = __wrappedThen; - } else if (!enable && __ntHooked && __ntQ.length === 0 && !__alsWrap) { + } else if (!enable && __ntHooked && __ntQ.length === 0) { __ntHooked = false; Promise.prototype.then = __origThen; } @@ -246,10 +244,6 @@ globalThis.__slice_set_als_wrap = function(wrapFn) { __alsWrap = wrapFn || null; - if (__alsWrap && !__ntHooked) { - __ntHooked = true; - Promise.prototype.then = __wrappedThen; - } }; function __schedMt() { @@ -295,18 +289,47 @@ __schedMt(); }; + function __Timeout(id) { + this._id = id; + this._refed = true; + } + __Timeout.prototype.unref = function() { + this._refed = false; + __slice_timer_ref(this._id, false); + return this; + }; + __Timeout.prototype.ref = function() { + this._refed = true; + __slice_timer_ref(this._id, true); + return this; + }; + __Timeout.prototype.hasRef = function() { + return this._refed; + }; + __Timeout.prototype.refresh = function() { + __slice_timer_refresh(this._id); + return this; + }; + __Timeout.prototype[Symbol.toPrimitive] = function() { + return this._id; + }; + __Timeout.prototype.valueOf = function() { + return this._id; + }; + globalThis.setTimeout = function(cb, ms) { var a = []; for (var i = 2; i < arguments.length; i++) a.push(arguments[i]); - return __slice_timer_set(cb, Number(ms) || 0, false, a); + return new __Timeout(__slice_timer_set(cb, Number(ms) || 0, false, a)); }; globalThis.clearTimeout = function(id) { - __slice_timer_clear(Number(id) || 0); + if (id == null) return; + __slice_timer_clear(typeof id === "object" ? (id._id | 0) : (Number(id) || 0)); }; globalThis.setInterval = function(cb, ms) { var a = []; for (var i = 2; i < arguments.length; i++) a.push(arguments[i]); - return __slice_timer_set(cb, Number(ms) || 0, true, a); + return new __Timeout(__slice_timer_set(cb, Number(ms) || 0, true, a)); }; globalThis.clearInterval = globalThis.clearTimeout; globalThis.setImmediate = function(cb) { @@ -315,7 +338,7 @@ } var a = []; for (var i = 1; i < arguments.length; i++) a.push(arguments[i]); - return __slice_immediate_set(cb, a); + return new __Timeout(__slice_immediate_set(cb, a)); }; globalThis.clearImmediate = globalThis.clearTimeout; diff --git a/crates/slice-engine/src/preludes/05_full_buffer.js b/crates/slice-engine/src/preludes/05_full_buffer.js index 9c21fcb..9923d3f 100644 --- a/crates/slice-engine/src/preludes/05_full_buffer.js +++ b/crates/slice-engine/src/preludes/05_full_buffer.js @@ -189,6 +189,82 @@ return Buffer.compare(this, other) === 0; }; + function __bufSearch(buf, val, byteOffset, encoding, isLast) { + if (typeof byteOffset === "string") { + encoding = byteOffset; + byteOffset = undefined; + } + var len = buf.length; + var off; + if (byteOffset === undefined) { + off = isLast ? len : 0; + } else { + off = Number(byteOffset); + if (Number.isNaN(off)) off = isLast ? len : 0; + else off = Math.trunc(off); + if (off < 0) off = len + off; + } + if (typeof val === "number") { + var b = val & 0xff; + if (isLast) { + var sLast = Math.min(off, len - 1); + for (var i = sLast; i >= 0; i--) { + if (buf[i] === b) return i; + } + return -1; + } + var sFirst = Math.max(0, off); + for (var j = sFirst; j < len; j++) { + if (buf[j] === b) return j; + } + return -1; + } + var needle; + if (typeof val === "string") { + needle = Buffer.from(val, encoding || "utf8"); + } else if (val instanceof __U8) { + needle = val; + } else { + throw new TypeError("The \"value\" argument must be of type number or an instance of Buffer, Uint8Array, or string"); + } + var nLen = needle.length; + if (nLen === 0) return Math.min(len, Math.max(0, off)); + if (nLen > len) return -1; + var maxStart = len - nLen; + if (isLast) { + for (var k = Math.min(off, maxStart); k >= 0; k--) { + if (buf[k] === needle[0]) { + var ok = true; + for (var m = 1; m < nLen; m++) { + if (buf[k + m] !== needle[m]) { ok = false; break; } + } + if (ok) return k; + } + } + return -1; + } + for (var p = Math.max(0, off); p <= maxStart; p++) { + if (buf[p] === needle[0]) { + var ok2 = true; + for (var q = 1; q < nLen; q++) { + if (buf[p + q] !== needle[q]) { ok2 = false; break; } + } + if (ok2) return p; + } + } + return -1; + } + + Buffer.prototype.indexOf = function(val, byteOffset, encoding) { + return __bufSearch(this, val, byteOffset, encoding, false); + }; + Buffer.prototype.lastIndexOf = function(val, byteOffset, encoding) { + return __bufSearch(this, val, byteOffset, encoding, true); + }; + Buffer.prototype.includes = function(val, byteOffset, encoding) { + return __bufSearch(this, val, byteOffset, encoding, false) !== -1; + }; + var __binM = [ "compare","copy","fill","write","toJSON", "readUInt8","readInt8","readUInt16BE","readUInt16LE","readInt16BE","readInt16LE", diff --git a/crates/slice-engine/src/preludes/10_outbound_fetch_sse.js b/crates/slice-engine/src/preludes/10_outbound_fetch_sse.js index c7b6796..1f866eb 100644 --- a/crates/slice-engine/src/preludes/10_outbound_fetch_sse.js +++ b/crates/slice-engine/src/preludes/10_outbound_fetch_sse.js @@ -1,5 +1,13 @@ // Slice (Nexus-JS) Lazy Prelude Shard 10: Outbound Fetch, AbortSignal/AbortController & SSE (`10_outbound_fetch_sse.js`) (function() { + if (!globalThis.DOMException) __slice_ensure_shard(13); + function __mkAbortErr() { + return new DOMException("The operation was aborted.", "AbortError"); + } + function __mkTimeoutErr() { + return new DOMException("TimeoutError: The operation was aborted due to timeout", "TimeoutError"); + } + function AbortSignal() { this.aborted = false; this.reason = undefined; @@ -24,7 +32,7 @@ AbortSignal.prototype._fire = function(r) { if (this.aborted) return; this.aborted = true; - this.reason = r !== undefined ? r : new Error("AbortError: The operation was aborted"); + this.reason = r !== undefined ? r : __mkAbortErr(); var ev = { type: "abort", target: this }; if (typeof this.onabort === "function") { try { this.onabort(ev); } catch (_e) {} @@ -44,13 +52,13 @@ }; AbortSignal.abort = function(r) { var s = new AbortSignal(); - s._fire(r !== undefined ? r : new Error("AbortError: The operation was aborted")); + s._fire(r !== undefined ? r : __mkAbortErr()); return s; }; AbortSignal.timeout = function(ms) { var s = new AbortSignal(); setTimeout(function() { - s._fire(new Error("TimeoutError: The operation was aborted due to timeout")); + s._fire(__mkTimeoutErr()); }, Number(ms) || 0); return s; }; @@ -154,7 +162,7 @@ function __doFetch(input, init) { var req = new Request(input, init); var sig = (init && init.signal) || req.signal || null; - if (sig && sig.aborted) throw (sig.reason || new Error("AbortError: The operation was aborted")); + if (sig && sig.aborted) throw (sig.reason !== undefined ? sig.reason : __mkAbortErr()); var raw = JSON.parse( __slice_fetch_sync(req.url, req.method, JSON.stringify(req.headers.entries()), req._body, req.redirect || "follow") ); @@ -170,7 +178,7 @@ var req = new Request(input, init); var sig = (init && init.signal) || req.signal || null; if (sig && sig.aborted) { - return Promise.reject(sig.reason || new Error("AbortError: The operation was aborted")); + return Promise.reject(sig.reason !== undefined ? sig.reason : __mkAbortErr()); } var hdrs = JSON.stringify(req.headers.entries()); var fast = __slice_fetch_try_fast(req.url, req.method, hdrs, req._body, req.redirect || "follow"); @@ -188,7 +196,7 @@ sig.addEventListener("abort", function() { if (!settled) { settled = true; - rej(sig.reason || new Error("AbortError: The operation was aborted")); + rej(sig.reason !== undefined ? sig.reason : __mkAbortErr()); } }); } @@ -214,7 +222,7 @@ function(errReason) { if (settled) return; settled = true; - rej(errReason instanceof Error ? errReason : new Error(String(errReason))); + rej(errReason !== undefined ? errReason : __mkAbortErr()); }, sig ); diff --git a/crates/slice-engine/src/preludes/13_dom_events.js b/crates/slice-engine/src/preludes/13_dom_events.js index 8e54942..08a73f6 100644 --- a/crates/slice-engine/src/preludes/13_dom_events.js +++ b/crates/slice-engine/src/preludes/13_dom_events.js @@ -102,6 +102,75 @@ return !event.defaultPrevented; }; + var __domCodes = { + IndexSizeError: 1, + HierarchyRequestError: 3, + WrongDocumentError: 4, + InvalidCharacterError: 5, + NoModificationAllowedError: 7, + NotFoundError: 8, + NotSupportedError: 9, + InUseAttributeError: 10, + InvalidStateError: 11, + SyntaxError: 12, + InvalidModificationError: 13, + NamespaceError: 14, + InvalidAccessError: 15, + TypeMismatchError: 17, + SecurityError: 18, + NetworkError: 19, + AbortError: 20, + URLMismatchError: 21, + QuotaExceededError: 22, + TimeoutError: 23, + InvalidNodeTypeError: 24, + DataCloneError: 25 + }; + var __domConsts = { + INDEX_SIZE_ERR: 1, + DOMSTRING_SIZE_ERR: 2, + HIERARCHY_REQUEST_ERR: 3, + WRONG_DOCUMENT_ERR: 4, + INVALID_CHARACTER_ERR: 5, + NO_DATA_ALLOWED_ERR: 6, + NO_MODIFICATION_ALLOWED_ERR: 7, + NOT_FOUND_ERR: 8, + NOT_SUPPORTED_ERR: 9, + INUSE_ATTRIBUTE_ERR: 10, + INVALID_STATE_ERR: 11, + SYNTAX_ERR: 12, + INVALID_MODIFICATION_ERR: 13, + NAMESPACE_ERR: 14, + INVALID_ACCESS_ERR: 15, + VALIDATION_ERR: 16, + TYPE_MISMATCH_ERR: 17, + SECURITY_ERR: 18, + NETWORK_ERR: 19, + ABORT_ERR: 20, + URL_MISMATCH_ERR: 21, + QUOTA_EXCEEDED_ERR: 22, + TIMEOUT_ERR: 23, + INVALID_NODE_TYPE_ERR: 24, + DATA_CLONE_ERR: 25 + }; + function DOMException(message, name) { + if (!(this instanceof DOMException)) return new DOMException(message, name); + this.message = message === undefined ? "" : String(message); + this.name = name === undefined ? "Error" : String(name); + this.code = __domCodes[this.name] || 0; + var err = new Error(this.message); + err.name = this.name; + if (err.stack) { + Object.defineProperty(this, "stack", { value: err.stack, writable: true, configurable: true }); + } + } + DOMException.prototype = Object.create(Error.prototype); + DOMException.prototype.constructor = DOMException; + for (var __dk in __domConsts) { + DOMException[__dk] = DOMException.prototype[__dk] = __domConsts[__dk]; + } + + globalThis.DOMException = DOMException; globalThis.Event = Event; globalThis.CustomEvent = CustomEvent; globalThis.EventTarget = EventTarget; diff --git a/crates/slice-engine/src/preludes/16_structured_clone.js b/crates/slice-engine/src/preludes/16_structured_clone.js index 4e35e79..e841d72 100644 --- a/crates/slice-engine/src/preludes/16_structured_clone.js +++ b/crates/slice-engine/src/preludes/16_structured_clone.js @@ -3,7 +3,8 @@ function __cloneDeep(val, seenSrc, seenDst) { if (val === null || typeof val !== "object") { if (typeof val === "function" || typeof val === "symbol") { - throw new Error("DataCloneError: Function or Symbol cannot be cloned by structuredClone"); + if (!globalThis.DOMException) __slice_ensure_shard(13); + throw new DOMException("DataCloneError: Function or Symbol cannot be cloned by structuredClone", "DataCloneError"); } return val; } diff --git a/crates/slice-engine/src/preludes/18_intl.js b/crates/slice-engine/src/preludes/18_intl.js index 9b1a774..90e0ac3 100644 --- a/crates/slice-engine/src/preludes/18_intl.js +++ b/crates/slice-engine/src/preludes/18_intl.js @@ -237,22 +237,164 @@ var __DAYS_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; var __DAYS_LONG = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var __TZ_TABLE = { + "utc": [0, 0, 0, "UTC"], + "etc/utc": [0, 0, 0, "Etc/UTC"], + "etc/gmt": [0, 0, 0, "Etc/GMT"], + "gmt": [0, 0, 0, "GMT"], + "z": [0, 0, 0, "UTC"], + "asia/tokyo": [540, 540, 0, "Asia/Tokyo"], + "asia/seoul": [540, 540, 0, "Asia/Seoul"], + "asia/shanghai": [480, 480, 0, "Asia/Shanghai"], + "asia/hong_kong": [480, 480, 0, "Asia/Hong_Kong"], + "asia/singapore": [480, 480, 0, "Asia/Singapore"], + "asia/taipei": [480, 480, 0, "Asia/Taipei"], + "asia/manila": [480, 480, 0, "Asia/Manila"], + "australia/perth": [480, 480, 0, "Australia/Perth"], + "asia/kolkata": [330, 330, 0, "Asia/Kolkata"], + "asia/calcutta": [330, 330, 0, "Asia/Kolkata"], + "asia/dubai": [240, 240, 0, "Asia/Dubai"], + "asia/bangkok": [420, 420, 0, "Asia/Bangkok"], + "asia/jakarta": [420, 420, 0, "Asia/Jakarta"], + "asia/ho_chi_minh": [420, 420, 0, "Asia/Ho_Chi_Minh"], + "asia/jerusalem": [120, 180, 2, "Asia/Jerusalem"], + "asia/tel_aviv": [120, 180, 2, "Asia/Tel_Aviv"], + "europe/london": [0, 60, 2, "Europe/London"], + "europe/dublin": [0, 60, 2, "Europe/Dublin"], + "europe/lisbon": [0, 60, 2, "Europe/Lisbon"], + "europe/berlin": [60, 120, 2, "Europe/Berlin"], + "europe/paris": [60, 120, 2, "Europe/Paris"], + "europe/rome": [60, 120, 2, "Europe/Rome"], + "europe/madrid": [60, 120, 2, "Europe/Madrid"], + "europe/amsterdam": [60, 120, 2, "Europe/Amsterdam"], + "europe/brussels": [60, 120, 2, "Europe/Brussels"], + "europe/vienna": [60, 120, 2, "Europe/Vienna"], + "europe/warsaw": [60, 120, 2, "Europe/Warsaw"], + "europe/zurich": [60, 120, 2, "Europe/Zurich"], + "europe/stockholm": [60, 120, 2, "Europe/Stockholm"], + "europe/prague": [60, 120, 2, "Europe/Prague"], + "europe/budapest": [60, 120, 2, "Europe/Budapest"], + "europe/copenhagen": [60, 120, 2, "Europe/Copenhagen"], + "europe/oslo": [60, 120, 2, "Europe/Oslo"], + "europe/athens": [120, 180, 2, "Europe/Athens"], + "europe/helsinki": [120, 180, 2, "Europe/Helsinki"], + "europe/bucharest": [120, 180, 2, "Europe/Bucharest"], + "europe/kiev": [120, 180, 2, "Europe/Kyiv"], + "europe/kyiv": [120, 180, 2, "Europe/Kyiv"], + "africa/cairo": [120, 180, 2, "Africa/Cairo"], + "europe/moscow": [180, 180, 0, "Europe/Moscow"], + "europe/istanbul": [180, 180, 0, "Europe/Istanbul"], + "asia/riyadh": [180, 180, 0, "Asia/Riyadh"], + "africa/nairobi": [180, 180, 0, "Africa/Nairobi"], + "america/new_york": [-300, -240, 1, "America/New_York"], + "america/toronto": [-300, -240, 1, "America/Toronto"], + "america/detroit": [-300, -240, 1, "America/Detroit"], + "america/montreal": [-300, -240, 1, "America/Montreal"], + "us/eastern": [-300, -240, 1, "America/New_York"], + "america/chicago": [-360, -300, 1, "America/Chicago"], + "america/winnipeg": [-360, -300, 1, "America/Winnipeg"], + "us/central": [-360, -300, 1, "America/Chicago"], + "america/denver": [-420, -360, 1, "America/Denver"], + "america/edmonton": [-420, -360, 1, "America/Edmonton"], + "us/mountain": [-420, -360, 1, "America/Denver"], + "america/phoenix": [-420, -420, 0, "America/Phoenix"], + "america/los_angeles": [-480, -420, 1, "America/Los_Angeles"], + "america/vancouver": [-480, -420, 1, "America/Vancouver"], + "us/pacific": [-480, -420, 1, "America/Los_Angeles"], + "america/anchorage": [-540, -480, 1, "America/Anchorage"], + "pacific/honolulu": [-600, -600, 0, "Pacific/Honolulu"], + "us/hawaii": [-600, -600, 0, "Pacific/Honolulu"], + "america/sao_paulo": [-180, -180, 0, "America/Sao_Paulo"], + "america/argentina/buenos_aires": [-180, -180, 0, "America/Argentina/Buenos_Aires"], + "america/buenos_aires": [-180, -180, 0, "America/Argentina/Buenos_Aires"], + "america/mexico_city": [-360, -360, 0, "America/Mexico_City"], + "america/bogota": [-300, -300, 0, "America/Bogota"], + "america/lima": [-300, -300, 0, "America/Lima"], + "australia/sydney": [600, 600, 0, "Australia/Sydney"], + "australia/melbourne": [600, 600, 0, "Australia/Melbourne"], + "pacific/auckland": [720, 720, 0, "Pacific/Auckland"] + }; + + function __resolveTz(tzInput) { + if (tzInput === undefined) return [0, 0, 0, "UTC"]; + var raw = String(tzInput).trim(); + var entry = __TZ_TABLE[raw.toLowerCase()]; + if (entry) return entry; + var m = raw.match(/^([+-])(\d{2})(?::?(\d{2}))?$/); + if (m) { + var sign = m[1] === "-" ? -1 : 1; + var hh = Number(m[2]), mm = Number(m[3] || 0); + if (hh <= 23 && mm <= 59) { + var mins = sign * (hh * 60 + mm); + var canon = (sign < 0 ? "-" : "+") + __pad2(hh) + ":" + __pad2(mm); + return [mins, mins, 0, canon]; + } + } + throw new RangeError("Invalid time zone specified: " + raw); + } + + function __tzOffsetMinutes(tzEntry, utcMs) { + var std = tzEntry[0], dst = tzEntry[1], rule = tzEntry[2]; + if (rule === 0 || std === dst) return std; + var d = new Date(utcMs); + var m = d.getUTCMonth(); + if (rule === 1) { + if (m > 2 && m < 10) return dst; + if (m < 2 || m > 10) return std; + var yr = d.getUTCFullYear(); + if (m === 2) { + var mar1Day = new Date(Date.UTC(yr, 2, 1)).getUTCDay(); + var secondSun = 8 + ((7 - mar1Day) % 7); + var startUtc = Date.UTC(yr, 2, secondSun, 2, 0, 0) - std * 60000; + return utcMs >= startUtc ? dst : std; + } + var nov1Day = new Date(Date.UTC(yr, 10, 1)).getUTCDay(); + var firstSun = 1 + ((7 - nov1Day) % 7); + var endUtc = Date.UTC(yr, 10, firstSun, 2, 0, 0) - dst * 60000; + return utcMs < endUtc ? dst : std; + } + if (rule === 2) { + if (m > 2 && m < 9) return dst; + if (m < 2 || m > 9) return std; + var yr2 = d.getUTCFullYear(); + if (m === 2) { + var mar31Day = new Date(Date.UTC(yr2, 2, 31)).getUTCDay(); + var lastSunMar = 31 - mar31Day; + return utcMs >= Date.UTC(yr2, 2, lastSunMar, 1, 0, 0) ? dst : std; + } + var oct31Day = new Date(Date.UTC(yr2, 9, 31)).getUTCDay(); + var lastSunOct = 31 - oct31Day; + return utcMs < Date.UTC(yr2, 9, lastSunOct, 1, 0, 0) ? dst : std; + } + return std; + } + + function __defaultHour12(locale) { + var l = String(locale || "en-US"); + if (l === "en" || l === "en-US" || l === "en-CA" || l === "en-AU" || l === "en-NZ" || l === "en-IN" || l === "en-PH") { + return true; + } + return false; + } + function DateTimeFormat(locales, options) { if (!(this instanceof DateTimeFormat)) return new DateTimeFormat(locales, options); var o = options || {}; this._locale = __normLocale(locales); - this._timeZone = o.timeZone || "UTC"; + this._tzEntry = __resolveTz(o.timeZone); + this._timeZone = this._tzEntry[3]; this._dateStyle = o.dateStyle; this._timeStyle = o.timeStyle; var hasCustom = o.year || o.month || o.day || o.weekday || o.hour || o.minute || o.second || o.dateStyle || o.timeStyle; - this._year = o.year || (!hasCustom || o.dateStyle ? "numeric" : undefined); + var hasDatePreset = !hasCustom || Boolean(o.dateStyle); + this._year = o.year || (hasDatePreset ? (o.dateStyle === "short" ? "2-digit" : "numeric") : undefined); this._month = o.month || (!hasCustom ? "numeric" : (o.dateStyle === "full" || o.dateStyle === "long" ? "long" : (o.dateStyle === "medium" ? "short" : (o.dateStyle === "short" ? "numeric" : undefined)))); - this._day = o.day || (!hasCustom || o.dateStyle ? "numeric" : undefined); + this._day = o.day || (hasDatePreset ? "numeric" : undefined); this._weekday = o.weekday || (o.dateStyle === "full" ? "long" : undefined); this._hour = o.hour || (o.timeStyle ? "numeric" : undefined); this._minute = o.minute || (o.timeStyle ? "2-digit" : undefined); this._second = o.second || (o.timeStyle === "full" || o.timeStyle === "long" || o.timeStyle === "medium" ? "2-digit" : undefined); - this._hour12 = o.hour12 !== undefined ? Boolean(o.hour12) : (o.hourCycle ? (o.hourCycle === "h11" || o.hourCycle === "h12") : false); + this._hour12 = o.hour12 !== undefined ? Boolean(o.hour12) : (o.hourCycle ? (o.hourCycle === "h11" || o.hourCycle === "h12") : __defaultHour12(this._locale)); this._timeZoneName = o.timeZoneName || (o.timeStyle === "full" || o.timeStyle === "long" ? "short" : undefined); } DateTimeFormat.prototype.resolvedOptions = function() { @@ -272,8 +414,11 @@ }; }; DateTimeFormat.prototype.formatToParts = function(date) { - var d = date === undefined ? new Date(Date.now()) : (date instanceof Date ? date : new Date(Number(date))); - if (Number.isNaN(d.getTime())) throw new RangeError("Invalid time value"); + var rawD = date === undefined ? new Date(Date.now()) : (date instanceof Date ? date : new Date(Number(date))); + var utcMs = rawD.getTime(); + if (Number.isNaN(utcMs)) throw new RangeError("Invalid time value"); + var offMin = __tzOffsetMinutes(this._tzEntry, utcMs); + var d = new Date(utcMs + offMin * 60000); var parts = []; if (this._weekday) { var wd = d.getUTCDay(); @@ -282,6 +427,7 @@ if (this._month || this._day || this._year) parts.push({ type: "literal", value: ", " }); } var hasDate = Boolean(this._year || this._month || this._day); + var lang = this._locale.split("-")[0]; if (hasDate) { var mIdx = d.getUTCMonth(); var dayNum = d.getUTCDate(); @@ -301,13 +447,27 @@ } } else { var mNumStr = this._month === "2-digit" ? __pad2(mIdx + 1) : String(mIdx + 1); - var isoOrder = this._locale.indexOf("sv") === 0 || this._locale.indexOf("ja") === 0 || this._locale.indexOf("zh") === 0 || this._locale.indexOf("iso") === 0; + var isoOrder = lang === "sv" || lang === "ja" || lang === "zh" || lang === "ko" || lang === "iso"; + var dotDmy = lang === "de" || lang === "ru" || lang === "pl" || lang === "uk" || lang === "cs" || lang === "fi" || lang === "no" || lang === "nb" || lang === "tr"; + var slashDmy = lang === "fr" || lang === "es" || lang === "it" || lang === "pt" || lang === "nl" || this._locale === "en-GB" || this._locale === "en-AU"; if (isoOrder) { if (this._year) parts.push({ type: "year", value: yrStr }); if (this._year && this._month) parts.push({ type: "literal", value: "-" }); if (this._month) parts.push({ type: "month", value: __pad2(mIdx + 1) }); if (this._month && this._day) parts.push({ type: "literal", value: "-" }); if (this._day) parts.push({ type: "day", value: __pad2(dayNum) }); + } else if (dotDmy) { + if (this._day) parts.push({ type: "day", value: dayStr }); + if (this._day && this._month) parts.push({ type: "literal", value: "." }); + if (this._month) parts.push({ type: "month", value: mNumStr }); + if ((this._day || this._month) && this._year) parts.push({ type: "literal", value: "." }); + if (this._year) parts.push({ type: "year", value: yrStr }); + } else if (slashDmy) { + if (this._day) parts.push({ type: "day", value: this._day === "2-digit" ? dayStr : __pad2(dayNum) }); + if (this._day && this._month) parts.push({ type: "literal", value: "/" }); + if (this._month) parts.push({ type: "month", value: this._month === "2-digit" ? mNumStr : __pad2(mIdx + 1) }); + if ((this._day || this._month) && this._year) parts.push({ type: "literal", value: "/" }); + if (this._year) parts.push({ type: "year", value: yrStr }); } else { if (this._month) parts.push({ type: "month", value: mNumStr }); if (this._month && this._day) parts.push({ type: "literal", value: "/" }); @@ -326,7 +486,8 @@ var ampm = hr >= 12 ? "PM" : "AM"; var dispHr = this._hour12 ? (hr % 12 || 12) : hr; if (this._hour) { - parts.push({ type: "hour", value: this._hour === "2-digit" ? __pad2(dispHr) : String(dispHr) }); + var padHr = this._hour === "2-digit" || (!this._hour12 && Boolean(this._minute)); + parts.push({ type: "hour", value: padHr ? __pad2(dispHr) : String(dispHr) }); } if (this._minute) { if (this._hour) parts.push({ type: "literal", value: ":" }); @@ -357,7 +518,18 @@ return loc ? [__normLocale(loc)] : ["en-US"]; }; - var __CURR_SYM = { USD: "$", EUR: "€", GBP: "£", JPY: "¥", ILS: "₪", CAD: "CA$", AUD: "A$" }; + var __CURR_SYM = { USD: "$", EUR: "€", GBP: "£", JPY: "¥", ILS: "₪", CAD: "CA$", AUD: "A$", CHF: "CHF", CNY: "¥", INR: "₹", BRL: "R$", KRW: "₩" }; + + function __numLocaleFormat(locale) { + var lang = String(locale || "en-US").split("-")[0]; + if (lang === "de" || lang === "es" || lang === "it" || lang === "nl" || lang === "pt" || lang === "tr" || lang === "vi" || lang === "id" || lang === "da" || lang === "el" || lang === "ro" || lang === "hu") { + return { grp: ".", dec: ",", currSuffix: locale !== "pt-BR" && lang !== "nl" }; + } + if (lang === "fr" || lang === "ru" || lang === "pl" || lang === "uk" || lang === "sv" || lang === "fi" || lang === "cs" || lang === "nb" || lang === "no" || lang === "sk") { + return { grp: "\u202f", dec: ",", currSuffix: true }; + } + return { grp: ",", dec: ".", currSuffix: false }; + } function NumberFormat(locales, options) { if (!(this instanceof NumberFormat)) return new NumberFormat(locales, options); @@ -365,6 +537,9 @@ this._locale = __normLocale(locales); this._style = o.style || "decimal"; this._currency = o.currency ? String(o.currency).toUpperCase() : undefined; + if (this._style === "currency" && !this._currency) { + throw new TypeError("Currency code is required with currency style"); + } this._currencyDisplay = o.currencyDisplay || "symbol"; this._unit = o.unit; this._unitDisplay = o.unitDisplay || "short"; @@ -372,7 +547,7 @@ this._signDisplay = o.signDisplay || "auto"; this._useGrouping = o.useGrouping !== undefined ? Boolean(o.useGrouping) : true; this._minInt = o.minimumIntegerDigits !== undefined ? Number(o.minimumIntegerDigits) : 1; - var defMinFrac = this._style === "currency" ? (this._currency === "JPY" ? 0 : 2) : 0; + var defMinFrac = this._style === "currency" ? (this._currency === "JPY" || this._currency === "KRW" ? 0 : 2) : 0; var defMaxFrac = this._style === "currency" ? defMinFrac : (this._style === "percent" ? 0 : 3); this._minFrac = o.minimumFractionDigits !== undefined ? Number(o.minimumFractionDigits) : defMinFrac; this._maxFrac = o.maximumFractionDigits !== undefined ? Number(o.maximumFractionDigits) : Math.max(this._minFrac, defMaxFrac); @@ -397,6 +572,7 @@ NumberFormat.prototype.formatToParts = function(value) { var num = Number(value); if (Number.isNaN(num)) return [{ type: "nan", value: "NaN" }]; + var locFmt = __numLocaleFormat(this._locale); if (!Number.isFinite(num)) { var p = []; if (num < 0) p.push({ type: "minusSign", value: "-" }); @@ -414,6 +590,17 @@ else if (abs >= 1e3) { abs /= 1e3; compactSuffix = "K"; } } var fixed = abs.toFixed(compactSuffix ? Math.min(this._maxFrac, 1) : this._maxFrac); + if (fixed.indexOf("e") !== -1 || fixed.indexOf("E") !== -1) { + var mExp = fixed.match(/^(\d+)(?:\.(\d+))?e([+-]\d+)$/i); + if (mExp) { + var expVal = Number(mExp[3]); + if (expVal >= 0) { + var mant = mExp[1] + (mExp[2] || ""); + var zCount = expVal - (mExp[2] ? mExp[2].length : 0); + fixed = zCount >= 0 ? (mant + "0".repeat(zCount)) : (mant.slice(0, mant.length + zCount) + "." + mant.slice(mant.length + zCount)); + } + } + } var split = fixed.split("."); var intStr = split[0]; var fracStr = split[1] || ""; @@ -434,11 +621,14 @@ parts.push({ type: "plusSign", value: "+" }); } } + var currSym = ""; if (this._style === "currency" && this._currency) { - var sym = this._currencyDisplay === "code" - ? (this._currency + " ") - : (__CURR_SYM[this._currency] || (this._currency + " ")); - parts.push({ type: "currency", value: sym }); + currSym = this._currencyDisplay === "code" + ? this._currency + : (__CURR_SYM[this._currency] || this._currency); + if (!locFmt.currSuffix) { + parts.push({ type: "currency", value: this._currencyDisplay === "code" ? (currSym + "\u00a0") : currSym }); + } } if (this._useGrouping && intStr.length > 3) { var groups = []; @@ -449,19 +639,23 @@ } if (rem) groups.unshift(rem); for (var i = 0; i < groups.length; i++) { - if (i > 0) parts.push({ type: "group", value: "," }); + if (i > 0) parts.push({ type: "group", value: locFmt.grp }); parts.push({ type: "integer", value: groups[i] }); } } else { parts.push({ type: "integer", value: intStr }); } if (fracStr.length > 0) { - parts.push({ type: "decimal", value: "." }); + parts.push({ type: "decimal", value: locFmt.dec }); parts.push({ type: "fraction", value: fracStr }); } if (compactSuffix) { parts.push({ type: "compact", value: compactSuffix }); } + if (this._style === "currency" && this._currency && locFmt.currSuffix) { + parts.push({ type: "literal", value: "\u00a0" }); + parts.push({ type: "currency", value: currSym }); + } if (this._style === "percent") { parts.push({ type: "percentSign", value: "%" }); } else if (this._style === "unit" && this._unit) { @@ -479,6 +673,33 @@ }; NumberFormat.supportedLocalesOf = DateTimeFormat.supportedLocalesOf; + var __DIACRITIC_BASE = { + "à": "a", "á": "a", "â": "a", "ã": "a", "ä": "a", "å": "a", "ā": "a", "ă": "a", "ą": "a", "æ": "ae", + "ç": "c", "ć": "c", "č": "c", "ĉ": "c", "ď": "d", "đ": "d", + "è": "e", "é": "e", "ê": "e", "ë": "e", "ē": "e", "ĕ": "e", "ė": "e", "ę": "e", "ě": "e", + "ğ": "g", "ĝ": "g", "ĥ": "h", + "ì": "i", "í": "i", "î": "i", "ï": "i", "ī": "i", "ĭ": "i", "į": "i", "ı": "i", + "ĵ": "j", "ķ": "k", "ĺ": "l", "ļ": "l", "ľ": "l", "ł": "l", + "ñ": "n", "ń": "n", "ņ": "n", "ň": "n", + "ò": "o", "ó": "o", "ô": "o", "õ": "o", "ö": "o", "ø": "o", "ō": "o", "ŏ": "o", "ő": "o", "œ": "oe", + "ŕ": "r", "ř": "r", "ś": "s", "ŝ": "s", "ş": "s", "š": "s", "ß": "ss", + "ť": "t", "ţ": "t", + "ù": "u", "ú": "u", "û": "u", "ü": "u", "ū": "u", "ŭ": "u", "ů": "u", "ű": "u", "ų": "u", + "ŵ": "w", "ý": "y", "ÿ": "y", "ŷ": "y", "ź": "z", "ż": "z", "ž": "z" + }; + + function __colBaseKey(s) { + var low = s.toLowerCase(); + var out = ""; + for (var i = 0; i < low.length; i++) { + var ch = low.charAt(i); + var code = ch.charCodeAt(0); + if (code >= 0x0300 && code <= 0x036f) continue; + out += __DIACRITIC_BASE[ch] !== undefined ? __DIACRITIC_BASE[ch] : ch; + } + return out; + } + function Collator(locales, options) { if (!(this instanceof Collator)) return new Collator(locales, options); var o = options || {}; @@ -499,10 +720,6 @@ a = a.replace(/[\p{P}\p{S}\s]+/gu, ""); b = b.replace(/[\p{P}\p{S}\s]+/gu, ""); } - if (this._sensitivity === "base" || this._sensitivity === "accent") { - a = a.toLowerCase(); - b = b.toLowerCase(); - } if (this._numeric) { var re = /(\d+|\D+)/g; var ta = a.match(re) || [], tb = b.match(re) || []; @@ -515,13 +732,29 @@ var diff = Number(pa) - Number(pb); if (diff !== 0) return diff < 0 ? -1 : 1; } else { - return pa < pb ? -1 : 1; + var c = this._cmpChunk(pa, pb); + if (c !== 0) return c; } } return ta.length === tb.length ? 0 : (ta.length < tb.length ? -1 : 1); } + return this._cmpChunk(a, b); + }; + Collator.prototype._cmpChunk = function(a, b) { + if (a === b) return 0; + var baseA = __colBaseKey(a), baseB = __colBaseKey(b); + if (baseA !== baseB) return baseA < baseB ? -1 : 1; + if (this._sensitivity === "base") return 0; + var lowA = a.toLowerCase(), lowB = b.toLowerCase(); + if (this._sensitivity !== "case" && lowA !== lowB) { + return lowA < lowB ? -1 : 1; + } + if (this._sensitivity === "accent") return 0; if (a === b) return 0; - return a < b ? -1 : 1; + if (this._caseFirst === "upper") { + return a < b ? -1 : 1; + } + return a > b ? -1 : 1; }; Collator.prototype.resolvedOptions = function() { return { @@ -543,25 +776,105 @@ this._type = o.type || "cardinal"; } PluralRules.prototype.select = function(n) { - var v = Math.abs(Number(n)); + var num = Number(n); + if (!Number.isFinite(num)) return "other"; + var v = Math.abs(num); + var i = Math.floor(v); + var isInt = v === i; + var mod10 = i % 10, mod100 = i % 100; + var lang = this._locale.split("-")[0]; if (this._type === "ordinal") { - var mod10 = v % 10, mod100 = v % 100; - if (mod10 === 1 && mod100 !== 11) return "one"; - if (mod10 === 2 && mod100 !== 12) return "two"; - if (mod10 === 3 && mod100 !== 13) return "few"; + if (lang === "en") { + if (mod10 === 1 && mod100 !== 11) return "one"; + if (mod10 === 2 && mod100 !== 12) return "two"; + if (mod10 === 3 && mod100 !== 13) return "few"; + } else if (lang === "fr" && v === 1) { + return "one"; + } + return "other"; + } + if (lang === "ar") { + if (v === 0) return "zero"; + if (v === 1) return "one"; + if (v === 2) return "two"; + if (isInt && mod100 >= 3 && mod100 <= 10) return "few"; + if (isInt && mod100 >= 11 && mod100 <= 99) return "many"; + return "other"; + } + if (lang === "ru" || lang === "uk") { + if (isInt && mod10 === 1 && mod100 !== 11) return "one"; + if (isInt && mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return "few"; + if (isInt && (mod10 === 0 || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 11 && mod100 <= 14))) return "many"; return "other"; } - return v === 1 ? "one" : "other"; + if (lang === "pl") { + if (isInt && i === 1) return "one"; + if (isInt && mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) return "few"; + if (isInt && ((i !== 1 && mod10 <= 1) || (mod10 >= 5 && mod10 <= 9) || (mod100 >= 12 && mod100 <= 14))) return "many"; + return "other"; + } + if (lang === "cs" || lang === "sk") { + if (isInt && i === 1) return "one"; + if (isInt && i >= 2 && i <= 4) return "few"; + if (!isInt) return "many"; + return "other"; + } + if (lang === "fr" || lang === "pt") { + return (v >= 0 && v < 2) ? "one" : "other"; + } + if (lang === "ja" || lang === "zh" || lang === "ko" || lang === "vi" || lang === "th" || lang === "id" || lang === "tr") { + return "other"; + } + return (isInt && i === 1) ? "one" : "other"; }; PluralRules.prototype.resolvedOptions = function() { + var lang = this._locale.split("-")[0]; + var cats = ["one", "other"]; + if (this._type === "ordinal") { + cats = lang === "en" ? ["one", "two", "few", "other"] : ["other"]; + } else if (lang === "ar") { + cats = ["zero", "one", "two", "few", "many", "other"]; + } else if (lang === "ru" || lang === "uk" || lang === "pl" || lang === "cs" || lang === "sk") { + cats = ["one", "few", "many", "other"]; + } else if (lang === "ja" || lang === "zh" || lang === "ko" || lang === "vi" || lang === "th" || lang === "id" || lang === "tr") { + cats = ["other"]; + } return { locale: this._locale, type: this._type, - pluralCategories: this._type === "ordinal" ? ["one", "two", "few", "other"] : ["one", "other"] + pluralCategories: cats }; }; PluralRules.supportedLocalesOf = DateTimeFormat.supportedLocalesOf; + function __isGraphemeExtend(cp) { + return (cp >= 0x0300 && cp <= 0x036f) || + (cp >= 0x0483 && cp <= 0x0489) || + (cp >= 0x0591 && cp <= 0x05c7) || + (cp >= 0x0610 && cp <= 0x061a) || + (cp >= 0x064b && cp <= 0x0670) || + (cp >= 0x0900 && cp <= 0x0903) || + (cp >= 0x093a && cp <= 0x094f) || + (cp >= 0x0951 && cp <= 0x0957) || + (cp >= 0x0962 && cp <= 0x0963) || + (cp >= 0x0e31 && cp <= 0x0e3a) || + (cp >= 0x0e47 && cp <= 0x0e4e) || + (cp >= 0x1160 && cp <= 0x11ff) || + (cp >= 0x1ab0 && cp <= 0x1aff) || + (cp >= 0x1dc0 && cp <= 0x1dff) || + cp === 0x200c || cp === 0x200d || + (cp >= 0x20d0 && cp <= 0x20ff) || + (cp >= 0xfe00 && cp <= 0xfe0f) || + (cp >= 0xfe20 && cp <= 0xfe2f) || + (cp >= 0x1f3fb && cp <= 0x1f3ff) || + (cp >= 0xe0020 && cp <= 0xe007f) || + (cp >= 0xe0100 && cp <= 0xe01ef); + } + + function __isRegionalIndicator(cp) { + return cp >= 0x1f1e6 && cp <= 0x1f1ff; + } + function Segmenter(locales, options) { if (!(this instanceof Segmenter)) return new Segmenter(locales, options); var o = options || {}; @@ -573,14 +886,14 @@ var gran = this._granularity; var list = []; if (gran === "word") { - var reW = /([A-Za-z0-9_]+|[^\sA-Za-z0-9_]+|\s+)/g, mW; + var reW = /([A-Za-z0-9_\u00C0-\u024F]+|[^\sA-Za-z0-9_\u00C0-\u024F]+|\s+)/g, mW; while ((mW = reW.exec(str)) !== null) { var segW = mW[0]; list.push({ segment: segW, index: mW.index, input: str, - isWordLike: /[A-Za-z0-9_]/.test(segW) + isWordLike: /[A-Za-z0-9_\u00C0-\u024F]/.test(segW) }); } } else if (gran === "sentence") { @@ -592,12 +905,42 @@ list.push({ segment: str, index: 0, input: str }); } } else { - var chars = Array.from(str); + var cps = Array.from(str); var idx = 0; - for (var i = 0; i < chars.length; i++) { - var ch = chars[i]; - list.push({ segment: ch, index: idx, input: str }); + var i = 0; + while (i < cps.length) { + var ch = cps[i]; + var startIdx = idx; + var cp = ch.codePointAt(0); idx += ch.length; + i++; + if (cp === 13 && i < cps.length && cps[i].codePointAt(0) === 10) { + ch += cps[i]; + idx += cps[i].length; + i++; + } else { + var prevCp = cp; + var riCount = __isRegionalIndicator(cp) ? 1 : 0; + while (i < cps.length) { + var nextCh = cps[i]; + var nextCp = nextCh.codePointAt(0); + if (__isGraphemeExtend(nextCp) || prevCp === 0x200d) { + ch += nextCh; + idx += nextCh.length; + prevCp = nextCp; + i++; + } else if (__isRegionalIndicator(nextCp) && riCount % 2 === 1) { + ch += nextCh; + idx += nextCh.length; + prevCp = nextCp; + riCount++; + i++; + } else { + break; + } + } + } + list.push({ segment: ch, index: startIdx, input: str }); } } var obj = { @@ -658,11 +1001,11 @@ return new DateTimeFormat(locales, options).format(this); }; Date.prototype.toLocaleTimeString = function(locales, options) { - var o = Object.assign({ hour: "numeric", minute: "2-digit", second: "2-digit" }, options || {}); + var o = (options && (options.timeStyle || options.dateStyle)) ? options : Object.assign({ hour: "numeric", minute: "2-digit", second: "2-digit" }, options || {}); return new DateTimeFormat(locales, o).format(this); }; Date.prototype.toLocaleString = function(locales, options) { - var o = Object.assign({ year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit" }, options || {}); + var o = (options && (options.dateStyle || options.timeStyle)) ? options : Object.assign({ year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit" }, options || {}); return new DateTimeFormat(locales, o).format(this); }; Number.prototype.toLocaleString = function(locales, options) { diff --git a/crates/slice-engine/src/preludes/js_preludes.rs b/crates/slice-engine/src/preludes/js_preludes.rs index e8f1f30..e356b30 100644 --- a/crates/slice-engine/src/preludes/js_preludes.rs +++ b/crates/slice-engine/src/preludes/js_preludes.rs @@ -55,7 +55,7 @@ pub const INTL_PRELUDE_SRC: &str = include_str!("18_intl.js"); /// On-demand self-replacing lazy property getter registration (`__defLazy`) evaluated ONLY when /// `needs_lazy_global_getters(js_code)` is true (`globalThis.*` dynamic probes). -pub(crate) const LAZY_GETTERS_INIT_PRELUDE: &[u8] = br#"(function(){var __loadShard=globalThis.__slice_ensure_shard,__shardProps=globalThis.__shardProps,__shMask=globalThis.__shMask;globalThis.__slice_mark_lazy_inited();function __defLazy(names,shardId){__shardProps[shardId]=names;for(var i=0;i0){__slice_ensure_shard(5);chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}strFast=false;chunks.push(__toBytes(d,enc));}return this;},digest:function(enc){if(isSha256&&(enc==="hex"||enc==="base64"||enc==="base64url")){if(strFast&&chunks.length===0){var h=__slice_crypto_sha256(sBuf,enc);sBuf="";return h;}if(sBuf.length===0&&chunks.length===1){var hb=__slice_crypto_sha256(chunks[0],enc);chunks=[];return hb;}}__ensExt();__slice_ensure_shard(5);if(sBuf.length>0){chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}var raw=Buffer.from(__slice_crypto_digest_bytes(a,__catBytes(chunks)));chunks=[];return(!enc||enc==="buffer")?raw:raw.toString(enc);}};},createHmac:function(alg,key){var a=String(alg||"sha256").toLowerCase(),isSha256=(a==="sha256"||a==="sha-256"),kBytes=null,chunks=[],strFast=isSha256&&typeof key==="string",kStr=typeof key==="string"?key:"",sBuf="";return{update:function(d,enc){if(strFast&&typeof d==="string"&&(!enc||enc==="utf8"||enc==="utf-8")&&chunks.length===0){sBuf+=d;}else{if(sBuf.length>0){__slice_ensure_shard(5);chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}strFast=false;chunks.push(__toBytes(d,enc));}return this;},digest:function(enc){if(isSha256&&(enc==="hex"||enc==="base64"||enc==="base64url")){if(strFast&&chunks.length===0){var h=__slice_crypto_hmac_sha256(kStr,sBuf,enc);sBuf="";return h;}if(sBuf.length===0&&chunks.length===1){if(!kBytes)kBytes=(typeof key==="string")?key:__toBytes(key);var hb=__slice_crypto_hmac_sha256(kBytes,chunks[0],enc);chunks=[];return hb;}}__ensExt();__slice_ensure_shard(5);if(sBuf.length>0){chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}if(!kBytes)kBytes=__toBytes(key);var raw=Buffer.from(__slice_crypto_hmac_bytes(a,kBytes,__catBytes(chunks)));chunks=[];return(!enc||enc==="buffer")?raw:raw.toString(enc);}};},randomBytes:function(size,cb){__ensExt();__slice_ensure_shard(5);var b=Buffer.from(__slice_crypto_random_bytes(Number(size)||0));if(typeof cb==="function"){cb(null,b);return;}return b;},randomFillSync:function(buf,offset,size){__ensExt();if(!buf||typeof buf.byteLength!=="number")throw new TypeError("buf must be an ArrayBufferView");var off=offset!==undefined?Number(offset):0;var sz=size!==undefined?Number(size):(buf.byteLength-off);if(off<0||sz<0||off+sz>buf.byteLength)throw new RangeError("offset or size out of bounds");var u8=new __U8(buf.buffer||buf,(buf.byteOffset||0)+off,sz);var rnd=__slice_crypto_random_bytes(sz);u8.set(rnd);return buf;},randomFill:function(buf,offset,size,cb){if(typeof offset==="function"){cb=offset;offset=0;size=buf.byteLength;}else if(typeof size==="function"){cb=size;size=buf.byteLength-Number(offset||0);}try{var r=m.randomFillSync(buf,offset,size);if(typeof cb==="function")queueMicrotask(function(){cb(null,r);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},randomInt:function(min,max,cb){__ensExt();if(typeof max==="function"||max===undefined){cb=max;max=min;min=0;}var lo=Math.ceil(Number(min)),hi=Math.floor(Number(max));if(!(hi>lo))throw new RangeError("max must be greater than min");var range=hi-lo,rb=__slice_crypto_random_bytes(4),u=((rb[0]<<24)>>>0)+((rb[1]<<16)>>>0)+((rb[2]<<8)>>>0)+(rb[3]>>>0);var val=lo+(u%range);if(typeof cb==="function"){queueMicrotask(function(){cb(null,val);});return;}return val;},randomUUID:function(){__ensExt();return __slice_crypto_random_uuid();},getRandomValues:function(ta){__ensExt();return __slice_crypto_get_random_values(ta);},timingSafeEqual:function(a,b){__ensExt();return __slice_crypto_timing_safe_equal(a,b);},pbkdf2Sync:function(password,salt,iterations,keylen,digest){__ensExt();__slice_ensure_shard(5);var ab=__slice_crypto_kdf("PBKDF2",String(digest||"sha256"),__toBytes(password),__toBytes(salt),null,Number(iterations),Number(keylen));return Buffer.from(ab);},pbkdf2:function(password,salt,iterations,keylen,digest,cb){if(typeof digest==="function"){cb=digest;digest="sha1";}try{var b=m.pbkdf2Sync(password,salt,iterations,keylen,digest);if(typeof cb==="function")queueMicrotask(function(){cb(null,b);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},hkdfSync:function(digest,ikm,salt,info,keylen){__ensExt();var ab=__slice_crypto_kdf("HKDF",String(digest||"sha256"),__toBytes(ikm),__toBytes(salt),__toBytes(info),1,Number(keylen));return ab;},hkdf:function(digest,ikm,salt,info,keylen,cb){try{var ab=m.hkdfSync(digest,ikm,salt,info,keylen);if(typeof cb==="function")queueMicrotask(function(){cb(null,ab);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},scryptSync:function(password,salt,keylen,options){__ensExt();__slice_ensure_shard(5);var o=options||{};var N=Number(o.N||o.cost||16384),r=Number(o.r||o.blockSize||8),p=Number(o.p||o.parallelization||1),maxmem=Number(o.maxmem||(32*1024*1024));var ab=__slice_crypto_kdf("SCRYPT","SHA-256",__toBytes(password),__toBytes(salt),null,N,Number(keylen),r,p,maxmem);return Buffer.from(ab);},scrypt:function(password,salt,keylen,options,cb){if(typeof options==="function"){cb=options;options={};}try{var b=m.scryptSync(password,salt,keylen,options);if(typeof cb==="function")queueMicrotask(function(){cb(null,b);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},createCipheriv:function(algorithm,key,iv,options){__ensExt();__slice_ensure_shard(5);var alg=String(algorithm||"").toLowerCase(),isGcm=alg.indexOf("gcm")!==-1,kB=__toBytes(key),ivB=__toBytes(iv),aadB=null,chunks=[],tagBuf=null,autoPad=true,tagLen=(options&&options.authTagLength)?Number(options.authTagLength)*8:128;var hid=__slice_crypto_key_register(isGcm?"AES-GCM":"AES-CBC","",kB);return{setAAD:function(buf){aadB=__toBytes(buf);return this;},setAutoPadding:function(ap){autoPad=(ap===undefined)?true:Boolean(ap);return this;},update:function(data,inEnc,outEnc){chunks.push(__toBytes(data,inEnc));return __encOut(new __U8(0),outEnc);},final:function(outEnc){var plain=__catBytes(chunks);chunks=[];var ab=__slice_crypto_cipher(isGcm?"AES-GCM":"AES-CBC",true,hid,kB,ivB,aadB,tagLen,plain,autoPad);var full=new __U8(ab);if(isGcm){var tBytes=tagLen/8;var cLen=full.byteLength-tBytes;tagBuf=Buffer.from(full.subarray(cLen));return __encOut(full.subarray(0,cLen),outEnc);}return __encOut(full,outEnc);},getAuthTag:function(){if(!isGcm||!tagBuf)throw new Error("ERR_CRYPTO_INVALID_STATE: getAuthTag requires finalized GCM cipher");return tagBuf;}};},createDecipheriv:function(algorithm,key,iv,options){__ensExt();__slice_ensure_shard(5);var alg=String(algorithm||"").toLowerCase(),isGcm=alg.indexOf("gcm")!==-1,kB=__toBytes(key),ivB=__toBytes(iv),aadB=null,chunks=[],authTag=null,autoPad=true,tagLen=(options&&options.authTagLength)?Number(options.authTagLength)*8:128;var hid=__slice_crypto_key_register(isGcm?"AES-GCM":"AES-CBC","",kB);return{setAAD:function(buf){aadB=__toBytes(buf);return this;},setAuthTag:function(buf,enc){authTag=__toBytes(buf,enc);return this;},setAutoPadding:function(ap){autoPad=(ap===undefined)?true:Boolean(ap);return this;},update:function(data,inEnc,outEnc){chunks.push(__toBytes(data,inEnc));return __encOut(new __U8(0),outEnc);},final:function(outEnc){var ciph=__catBytes(chunks);chunks=[];if(isGcm){if(!authTag)throw new Error("ERR_CRYPTO_INVALID_STATE: Unsupported state or unable to authenticate data (missing authTag)");var combined=new __U8(ciph.byteLength+authTag.byteLength);combined.set(ciph,0);combined.set(authTag,ciph.byteLength);var ab=__slice_crypto_cipher("AES-GCM",false,hid,kB,ivB,aadB,tagLen,combined,true);return __encOut(new __U8(ab),outEnc);}var abC=__slice_crypto_cipher("AES-CBC",false,hid,kB,ivB,null,128,ciph,autoPad);return __encOut(new __U8(abC),outEnc);}};},generateKeyPairSync:function(type,options){__ensExt();__slice_ensure_shard(5);var t=String(type||"").toLowerCase(),o=options||{};var info=t==="ed25519"?JSON.parse(__slice_crypto_asym_keygen("Ed25519","")):JSON.parse(__slice_crypto_asym_keygen("ECDSA",String(o.namedCurve||"P-256")));var crv=info.crv||undefined;var pubKO=new KeyObject("public",t==="ed25519"?"ed25519":"ec",crv,info.pubId,__slice_base64_decode_bytes(info.spki),info);var privKO=new KeyObject("private",t==="ed25519"?"ed25519":"ec",crv,info.privId,__slice_base64_decode_bytes(info.pkcs8),info);var pubOut=o.publicKeyEncoding?pubKO.export(o.publicKeyEncoding):pubKO;var privOut=o.privateKeyEncoding?privKO.export(o.privateKeyEncoding):privKO;return{publicKey:pubOut,privateKey:privOut};},generateKeyPair:function(type,options,cb){if(typeof options==="function"){cb=options;options={};}try{var kp=m.generateKeyPairSync(type,options);if(typeof cb==="function")queueMicrotask(function(){cb(null,kp.publicKey,kp.privateKey);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},createPrivateKey:function(k){return __parseKeyObj(k,true);},createPublicKey:function(k){return __parseKeyObj(k,false);},createSecretKey:function(k,enc){__slice_ensure_shard(5);var b=__toBytes(k,enc);return new KeyObject("secret","secret",undefined,0,b,null);},sign:function(alg,data,key,cb){__ensExt();__slice_ensure_shard(5);try{var ko=__parseKeyObj(key,true);var dsaEnc=(key&&typeof key==="object"&&key.dsaEncoding)?String(key.dsaEncoding):"der";var ab=__slice_crypto_asym_sign(ko.asymmetricKeyType==="ed25519"?"Ed25519":"ECDSA",ko.asymmetricKeyDetails.namedCurve||"P-256",ko._id,ko._raw,__toBytes(data),dsaEnc!=="ieee-p1363");var b=Buffer.from(ab);if(typeof cb==="function"){queueMicrotask(function(){cb(null,b);});return;}return b;}catch(e){if(typeof cb==="function"){queueMicrotask(function(){cb(e);});return;}throw e;}},verify:function(alg,data,key,sig,cb){__ensExt();try{var ko=__parseKeyObj(key,false);var ok=Boolean(__slice_crypto_asym_verify(ko.asymmetricKeyType==="ed25519"?"Ed25519":"ECDSA",ko.asymmetricKeyDetails.namedCurve||"P-256",ko._id,ko._raw,__toBytes(sig),__toBytes(data)));if(typeof cb==="function"){queueMicrotask(function(){cb(null,ok);});return;}return ok;}catch(e){if(typeof cb==="function"){queueMicrotask(function(){cb(e);});return;}throw e;}},createSign:function(_alg){var chunks=[];return{update:function(d,enc){chunks.push(__toBytes(d,enc));return this;},sign:function(key,outEnc){var sig=m.sign(null,__catBytes(chunks),key);chunks=[];return(!outEnc||outEnc==="buffer")?sig:sig.toString(outEnc);}};},createVerify:function(_alg){var chunks=[];return{update:function(d,enc){chunks.push(__toBytes(d,enc));return this;},verify:function(key,sig,sigEnc){var sB=typeof sig==="string"?__toBytes(sig,sigEnc||"base64"):__toBytes(sig);var ok=m.verify(null,__catBytes(chunks),key,sB);chunks=[];return ok;}};},getHashes:function(){return["sha1","sha256","sha384","sha512","md5"];},getCiphers:function(){return["aes-128-gcm","aes-256-gcm","aes-128-cbc","aes-256-cbc"];},get subtle(){__slice_ensure_shard(4);return globalThis.crypto.subtle;},get webcrypto(){__slice_ensure_shard(4);return globalThis.crypto;}};m.default=m;m.__esModule=true;return __slice_builtins["crypto"]=__slice_builtins["node:crypto"]=m;})();"#; +const BUILTIN_CRYPTO_SNIPPET: &[u8] = br#"(function(){var __U8=globalThis.Uint8Array,__ext=false;function __ensExt(){if(!__ext){__ext=true;__slice_init_crypto_ext();}}function __toBytes(d,enc){if(d instanceof __U8)return d;if(d instanceof ArrayBuffer)return new __U8(d);if(d&&d.buffer instanceof ArrayBuffer)return new __U8(d.buffer,d.byteOffset||0,d.byteLength);__slice_ensure_shard(5);return Buffer.from(String(d),enc||"utf8");}function __catBytes(chunks){if(chunks.length===0)return new __U8(0);if(chunks.length===1)return chunks[0];__slice_ensure_shard(5);return Buffer.concat(chunks);}function __encOut(rawBuf,enc){__slice_ensure_shard(5);var b=Buffer.isBuffer(rawBuf)?rawBuf:Buffer.from(rawBuf);return(!enc||enc==="buffer")?b:b.toString(enc);}function KeyObject(type,alg,crv,id,raw,meta,details){this.type=type;this.asymmetricKeyType=alg;this.asymmetricKeyDetails=details||(crv?{namedCurve:crv}:{});this._id=id||0;this._raw=raw||null;this._meta=meta||null;}KeyObject.prototype.export=function(opts){__ensExt();__slice_ensure_shard(5);var o=opts||{};var fmt=String(o.format||"der").toLowerCase();if(this.type==="secret")return Buffer.from(this._raw);var derB64=(this.type==="private")?(this._meta&&this._meta.pkcs8):(this._meta&&this._meta.spki);var der=derB64?Buffer.from(__slice_base64_decode_bytes(derB64)):Buffer.from(this._raw||[]);if(fmt==="pem"){var label=this.type==="private"?"PRIVATE KEY":"PUBLIC KEY";return"-----BEGIN "+label+"-----\n"+der.toString("base64")+"\n-----END "+label+"-----\n";}if(fmt==="jwk"&&this._meta){if(this.asymmetricKeyType==="ed25519"||this.asymmetricKeyType==="x25519"){var j={kty:"OKP",crv:this.asymmetricKeyType==="x25519"?"X25519":"Ed25519",x:this._meta.x};if(this.type==="private")j.d=this._meta.d;return j;}var je={kty:"EC",crv:this._meta.crv||"P-256",x:this._meta.x,y:this._meta.y};if(this.type==="private")je.d=this._meta.d;return je;}return der;};function __importDerKey(der,fmt){try{var impEd=JSON.parse(__slice_crypto_asym_import("Ed25519","",fmt,der));return new KeyObject(impEd.type,"ed25519",undefined,impEd.id,der,impEd);}catch(_e1){try{var impX=JSON.parse(__slice_crypto_asym_import("X25519","",fmt,der));return new KeyObject(impX.type,"x25519",undefined,impX.id,der,impX);}catch(_eX){try{var impRsa=JSON.parse(__slice_crypto_asym_import("RSA","",fmt,der));return new KeyObject(impRsa.type,"rsa",undefined,impRsa.id,der,impRsa,{modulusLength:2048,publicExponent:65537n});}catch(_eR){try{var impEc256=JSON.parse(__slice_crypto_asym_import("ECDSA","P-256",fmt,der));return new KeyObject(impEc256.type,"ec","P-256",impEc256.id,der,impEc256);}catch(_e2){var impEc384=JSON.parse(__slice_crypto_asym_import("ECDSA","P-384",fmt,der));return new KeyObject(impEc384.type,"ec","P-384",impEc384.id,der,impEc384);}}}}}function __parseKeyObj(k,isPriv){__ensExt();if(k instanceof KeyObject)return k;if(k&&typeof k==="object"&&k._id!==undefined&&k.algorithm){var kn=String(k.algorithm.name||"").toLowerCase();return new KeyObject(k.type,kn==="ecdsa"?"ec":kn,k.algorithm.namedCurve,k._id,k._raw,k._meta);}if(k&&typeof k==="object"&&k.key!==undefined)return __parseKeyObj(k.key,isPriv);var fmt=isPriv?"pkcs8":"spki";if(typeof k==="string"&&k.indexOf("-----BEGIN")!==-1){var body=k.replace(/-----BEGIN [^-]+-----/g,"").replace(/-----END [^-]+-----/g,"").replace(/\s+/g,"");var der=__slice_base64_decode_bytes(body);return __importDerKey(der,fmt);}return __importDerKey(__toBytes(k),fmt);}function __mkHash(a,isSha256,initChunks,initFast,initSBuf){var chunks=initChunks?initChunks.slice():[],strFast=initFast!==undefined?initFast:isSha256,sBuf=initSBuf||"";return{update:function(d,enc){if(strFast&&typeof d==="string"&&(!enc||enc==="utf8"||enc==="utf-8")&&chunks.length===0){sBuf+=d;}else{if(sBuf.length>0){__slice_ensure_shard(5);chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}strFast=false;chunks.push(__toBytes(d,enc));}return this;},copy:function(){return __mkHash(a,isSha256,chunks,strFast,sBuf);},digest:function(enc){if(isSha256&&(enc==="hex"||enc==="base64"||enc==="base64url")){if(strFast&&chunks.length===0){var h=__slice_crypto_sha256(sBuf,enc);sBuf="";return h;}if(sBuf.length===0&&chunks.length===1){var hb=__slice_crypto_sha256(chunks[0],enc);chunks=[];return hb;}}__ensExt();__slice_ensure_shard(5);if(sBuf.length>0){chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}var raw=Buffer.from(__slice_crypto_digest_bytes(a,__catBytes(chunks)));chunks=[];return(!enc||enc==="buffer")?raw:raw.toString(enc);}};}function __mkHmac(a,isSha256,key,initChunks,initFast,initSBuf){var kBytes=null,chunks=initChunks?initChunks.slice():[],strFast=initFast!==undefined?initFast:(isSha256&&typeof key==="string"),kStr=typeof key==="string"?key:"",sBuf=initSBuf||"";return{update:function(d,enc){if(strFast&&typeof d==="string"&&(!enc||enc==="utf8"||enc==="utf-8")&&chunks.length===0){sBuf+=d;}else{if(sBuf.length>0){__slice_ensure_shard(5);chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}strFast=false;chunks.push(__toBytes(d,enc));}return this;},copy:function(){return __mkHmac(a,isSha256,key,chunks,strFast,sBuf);},digest:function(enc){if(isSha256&&(enc==="hex"||enc==="base64"||enc==="base64url")){if(strFast&&chunks.length===0){var h=__slice_crypto_hmac_sha256(kStr,sBuf,enc);sBuf="";return h;}if(sBuf.length===0&&chunks.length===1){if(!kBytes)kBytes=(typeof key==="string")?key:__toBytes(key);var hb=__slice_crypto_hmac_sha256(kBytes,chunks[0],enc);chunks=[];return hb;}}__ensExt();__slice_ensure_shard(5);if(sBuf.length>0){chunks.push(Buffer.from(sBuf,"utf8"));sBuf="";}if(!kBytes)kBytes=__toBytes(key);var raw=Buffer.from(__slice_crypto_hmac_bytes(a,kBytes,__catBytes(chunks)));chunks=[];return(!enc||enc==="buffer")?raw:raw.toString(enc);}};}var m={KeyObject:KeyObject,createHash:function(alg){var a=String(alg||"sha256").toLowerCase(),isSha256=(a==="sha256"||a==="sha-256");return __mkHash(a,isSha256);},createHmac:function(alg,key){var a=String(alg||"sha256").toLowerCase(),isSha256=(a==="sha256"||a==="sha-256");return __mkHmac(a,isSha256,key);},randomBytes:function(size,cb){__ensExt();__slice_ensure_shard(5);var b=Buffer.from(__slice_crypto_random_bytes(Number(size)||0));if(typeof cb==="function"){cb(null,b);return;}return b;},randomFillSync:function(buf,offset,size){__ensExt();if(!buf||typeof buf.byteLength!=="number")throw new TypeError("buf must be an ArrayBufferView");var off=offset!==undefined?Number(offset):0;var sz=size!==undefined?Number(size):(buf.byteLength-off);if(off<0||sz<0||off+sz>buf.byteLength)throw new RangeError("offset or size out of bounds");var u8=new __U8(buf.buffer||buf,(buf.byteOffset||0)+off,sz);var rnd=__slice_crypto_random_bytes(sz);u8.set(rnd);return buf;},randomFill:function(buf,offset,size,cb){if(typeof offset==="function"){cb=offset;offset=0;size=buf.byteLength;}else if(typeof size==="function"){cb=size;size=buf.byteLength-Number(offset||0);}try{var r=m.randomFillSync(buf,offset,size);if(typeof cb==="function")queueMicrotask(function(){cb(null,r);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},randomInt:function(min,max,cb){__ensExt();if(typeof max==="function"||max===undefined){cb=max;max=min;min=0;}var lo=Math.ceil(Number(min)),hi=Math.floor(Number(max));if(!(hi>lo))throw new RangeError("max must be greater than min");var range=hi-lo,rb=__slice_crypto_random_bytes(4),u=((rb[0]<<24)>>>0)+((rb[1]<<16)>>>0)+((rb[2]<<8)>>>0)+(rb[3]>>>0);var val=lo+(u%range);if(typeof cb==="function"){queueMicrotask(function(){cb(null,val);});return;}return val;},randomUUID:function(){__ensExt();return __slice_crypto_random_uuid();},getRandomValues:function(ta){__ensExt();return __slice_crypto_get_random_values(ta);},timingSafeEqual:function(a,b){__ensExt();return __slice_crypto_timing_safe_equal(a,b);},pbkdf2Sync:function(password,salt,iterations,keylen,digest){__ensExt();__slice_ensure_shard(5);var ab=__slice_crypto_kdf("PBKDF2",String(digest||"sha256"),__toBytes(password),__toBytes(salt),null,Number(iterations),Number(keylen));return Buffer.from(ab);},pbkdf2:function(password,salt,iterations,keylen,digest,cb){if(typeof digest==="function"){cb=digest;digest="sha1";}try{var b=m.pbkdf2Sync(password,salt,iterations,keylen,digest);if(typeof cb==="function")queueMicrotask(function(){cb(null,b);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},hkdfSync:function(digest,ikm,salt,info,keylen){__ensExt();var ab=__slice_crypto_kdf("HKDF",String(digest||"sha256"),__toBytes(ikm),__toBytes(salt),__toBytes(info),1,Number(keylen));return ab;},hkdf:function(digest,ikm,salt,info,keylen,cb){try{var ab=m.hkdfSync(digest,ikm,salt,info,keylen);if(typeof cb==="function")queueMicrotask(function(){cb(null,ab);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},scryptSync:function(password,salt,keylen,options){__ensExt();__slice_ensure_shard(5);var o=options||{};var N=Number(o.N||o.cost||16384),r=Number(o.r||o.blockSize||8),p=Number(o.p||o.parallelization||1),maxmem=Number(o.maxmem||(32*1024*1024));var ab=__slice_crypto_kdf("SCRYPT","SHA-256",__toBytes(password),__toBytes(salt),null,N,Number(keylen),r,p,maxmem);return Buffer.from(ab);},scrypt:function(password,salt,keylen,options,cb){if(typeof options==="function"){cb=options;options={};}try{var b=m.scryptSync(password,salt,keylen,options);if(typeof cb==="function")queueMicrotask(function(){cb(null,b);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},createCipheriv:function(algorithm,key,iv,options){__ensExt();__slice_ensure_shard(5);var alg=String(algorithm||"").toLowerCase(),isGcm=alg.indexOf("gcm")!==-1,kB=__toBytes(key),ivB=__toBytes(iv),aadB=null,chunks=[],tagBuf=null,autoPad=true,tagLen=(options&&options.authTagLength)?Number(options.authTagLength)*8:128;var hid=__slice_crypto_key_register(isGcm?"AES-GCM":"AES-CBC","",kB);return{setAAD:function(buf){aadB=__toBytes(buf);return this;},setAutoPadding:function(ap){autoPad=(ap===undefined)?true:Boolean(ap);return this;},update:function(data,inEnc,outEnc){chunks.push(__toBytes(data,inEnc));return __encOut(new __U8(0),outEnc);},final:function(outEnc){var plain=__catBytes(chunks);chunks=[];var ab=__slice_crypto_cipher(isGcm?"AES-GCM":"AES-CBC",true,hid,kB,ivB,aadB,tagLen,plain,autoPad);var full=new __U8(ab);if(isGcm){var tBytes=tagLen/8;var cLen=full.byteLength-tBytes;tagBuf=Buffer.from(full.subarray(cLen));return __encOut(full.subarray(0,cLen),outEnc);}return __encOut(full,outEnc);},getAuthTag:function(){if(!isGcm||!tagBuf)throw new Error("ERR_CRYPTO_INVALID_STATE: getAuthTag requires finalized GCM cipher");return tagBuf;}};},createDecipheriv:function(algorithm,key,iv,options){__ensExt();__slice_ensure_shard(5);var alg=String(algorithm||"").toLowerCase(),isGcm=alg.indexOf("gcm")!==-1,kB=__toBytes(key),ivB=__toBytes(iv),aadB=null,chunks=[],authTag=null,autoPad=true,tagLen=(options&&options.authTagLength)?Number(options.authTagLength)*8:128;var hid=__slice_crypto_key_register(isGcm?"AES-GCM":"AES-CBC","",kB);return{setAAD:function(buf){aadB=__toBytes(buf);return this;},setAuthTag:function(buf,enc){authTag=__toBytes(buf,enc);return this;},setAutoPadding:function(ap){autoPad=(ap===undefined)?true:Boolean(ap);return this;},update:function(data,inEnc,outEnc){chunks.push(__toBytes(data,inEnc));return __encOut(new __U8(0),outEnc);},final:function(outEnc){var ciph=__catBytes(chunks);chunks=[];if(isGcm){if(!authTag)throw new Error("ERR_CRYPTO_INVALID_STATE: Unsupported state or unable to authenticate data (missing authTag)");var combined=new __U8(ciph.byteLength+authTag.byteLength);combined.set(ciph,0);combined.set(authTag,ciph.byteLength);var ab=__slice_crypto_cipher("AES-GCM",false,hid,kB,ivB,aadB,tagLen,combined,true);return __encOut(new __U8(ab),outEnc);}var abC=__slice_crypto_cipher("AES-CBC",false,hid,kB,ivB,null,128,ciph,autoPad);return __encOut(new __U8(abC),outEnc);}};},generateKeyPairSync:function(type,options){__ensExt();__slice_ensure_shard(5);var t=typeof type==="string"?type.toLowerCase():"";if(t!=="ed25519"&&t!=="x25519"&&t!=="ec"&&t!=="rsa"&&t!=="rsa-pss"&&t!=="dsa"){var eType=new TypeError("The argument 'type' must be a supported key type. Received '"+String(type)+"'");eType.code="ERR_INVALID_ARG_VALUE";throw eType;}var o=options||{};var info,details=undefined;if(t==="ed25519"){info=JSON.parse(__slice_crypto_asym_keygen("Ed25519",""));}else if(t==="x25519"){info=JSON.parse(__slice_crypto_asym_keygen("X25519",""));}else if(t==="rsa"||t==="rsa-pss"){info=JSON.parse(__slice_crypto_asym_keygen("RSA",""));details={modulusLength:Number(o.modulusLength)||2048,publicExponent:BigInt(o.publicExponent||65537)};}else if(t==="dsa"){info=JSON.parse(__slice_crypto_asym_keygen("ECDSA","P-256"));details={modulusLength:Number(o.modulusLength)||2048,divisorLength:Number(o.divisorLength)||256};}else{info=JSON.parse(__slice_crypto_asym_keygen("ECDSA",String(o.namedCurve||"P-256")));}var crv=(t==="ec")?(info.crv||"P-256"):undefined;var pubKO=new KeyObject("public",t,crv,info.pubId,__slice_base64_decode_bytes(info.spki),info,details);var privKO=new KeyObject("private",t,crv,info.privId,__slice_base64_decode_bytes(info.pkcs8),info,details);var pubOut=o.publicKeyEncoding?pubKO.export(o.publicKeyEncoding):pubKO;var privOut=o.privateKeyEncoding?privKO.export(o.privateKeyEncoding):privKO;return{publicKey:pubOut,privateKey:privOut};},generateKeyPair:function(type,options,cb){if(typeof options==="function"){cb=options;options={};}try{var kp=m.generateKeyPairSync(type,options);if(typeof cb==="function")queueMicrotask(function(){cb(null,kp.publicKey,kp.privateKey);});}catch(e){if(typeof cb==="function")queueMicrotask(function(){cb(e);});else throw e;}},createPrivateKey:function(k){return __parseKeyObj(k,true);},createPublicKey:function(k){return __parseKeyObj(k,false);},createSecretKey:function(k,enc){__slice_ensure_shard(5);var b=__toBytes(k,enc);return new KeyObject("secret","secret",undefined,0,b,null);},sign:function(alg,data,key,cb){__ensExt();__slice_ensure_shard(5);try{var ko=__parseKeyObj(key,true);var dsaEnc=(key&&typeof key==="object"&&key.dsaEncoding)?String(key.dsaEncoding):"der";var hostAlg=ko.asymmetricKeyType==="ed25519"?"Ed25519":((ko.asymmetricKeyType==="rsa"||ko.asymmetricKeyType==="rsa-pss")?"RSA":"ECDSA");var ab=__slice_crypto_asym_sign(hostAlg,ko.asymmetricKeyDetails.namedCurve||"P-256",ko._id,ko._raw,__toBytes(data),dsaEnc!=="ieee-p1363");var b=Buffer.from(ab);if(typeof cb==="function"){queueMicrotask(function(){cb(null,b);});return;}return b;}catch(e){if(typeof cb==="function"){queueMicrotask(function(){cb(e);});return;}throw e;}},verify:function(alg,data,key,sig,cb){__ensExt();try{var ko=__parseKeyObj(key,false);var hostAlg=ko.asymmetricKeyType==="ed25519"?"Ed25519":((ko.asymmetricKeyType==="rsa"||ko.asymmetricKeyType==="rsa-pss")?"RSA":"ECDSA");var ok=Boolean(__slice_crypto_asym_verify(hostAlg,ko.asymmetricKeyDetails.namedCurve||"P-256",ko._id,ko._raw,__toBytes(sig),__toBytes(data)));if(typeof cb==="function"){queueMicrotask(function(){cb(null,ok);});return;}return ok;}catch(e){if(typeof cb==="function"){queueMicrotask(function(){cb(e);});return;}throw e;}},createSign:function(_alg){var chunks=[];return{update:function(d,enc){chunks.push(__toBytes(d,enc));return this;},sign:function(key,outEnc){var sig=m.sign(null,__catBytes(chunks),key);chunks=[];return(!outEnc||outEnc==="buffer")?sig:sig.toString(outEnc);}};},createVerify:function(_alg){var chunks=[];return{update:function(d,enc){chunks.push(__toBytes(d,enc));return this;},verify:function(key,sig,sigEnc){var sB=typeof sig==="string"?__toBytes(sig,sigEnc||"base64"):__toBytes(sig);var ok=m.verify(null,__catBytes(chunks),key,sB);chunks=[];return ok;}};},getHashes:function(){return["sha1","sha256","sha384","sha512","md5"];},getCiphers:function(){return["aes-128-gcm","aes-256-gcm","aes-128-cbc","aes-256-cbc"];},get subtle(){__slice_ensure_shard(4);return globalThis.crypto.subtle;},get webcrypto(){__slice_ensure_shard(4);return globalThis.crypto;}};m.default=m;m.__esModule=true;return __slice_builtins["crypto"]=__slice_builtins["node:crypto"]=m;})();"#; const BUILTIN_FS_SNIPPET: &[u8] = br#"(function(){var __watchers=[],__fds=Object.create(null),__nextFd=10;function __fsErr(code,syscall,p,dest){var map={ENOENT:[-2,"no such file or directory"],EEXIST:[-17,"file already exists"],EISDIR:[-21,"illegal operation on a directory"],ENOTDIR:[-20,"not a directory"],ENOTEMPTY:[-39,"directory not empty"],EBADF:[-9,"bad file descriptor"],EACCES:[-13,"permission denied"],EINVAL:[-22,"invalid argument"]},info=map[code]||[-1,"unknown error"],msg=code+": "+info[1]+", "+syscall+(p!==undefined?" '"+p+"'":"")+(dest!==undefined?" -> '"+dest+"'":""),e=new Error(msg);e.code=code;e.errno=info[0];e.syscall=syscall;if(p!==undefined)e.path=String(p);if(dest!==undefined)e.dest=String(dest);return e;}function __getFd(fd,syscall){var e=__fds[Number(fd)];if(!e)throw __fsErr("EBADF",syscall);return e;}function __normW(p){return String(p||"").replace(/\\/g,"/").replace(/\/+$/,"")||"/";}function __notifyWatch(rawP,evType){if(__watchers.length===0)return;var np=__normW(rawP),sl=np.lastIndexOf("/"),dir=sl>0?np.slice(0,sl):"/",base=sl>=0?np.slice(sl+1):np;for(var i=0;i<__watchers.length;i++){var w=__watchers[i];if(w._closed)continue;var wp=w._path;if(np===wp||dir===wp||(w._rec&&np.indexOf(wp+"/")===0)){var rel=(np===wp)?base:(np.slice(wp.length+1)||base);w._emit(evType,rel);}}}function __fsData(d){if(typeof d==="string")return d;if(d instanceof Uint8Array)return d;if(d instanceof ArrayBuffer)return new Uint8Array(d);if(d&&d.buffer instanceof ArrayBuffer)return new Uint8Array(d.buffer,d.byteOffset||0,d.byteLength);return String(d);}function __toMs(t){if(t instanceof Date)return t.getTime();var n=Number(t);if(!Number.isFinite(n))return Date.now();return n<1e11?n*1000:n;}function __mkStats(sp,followSym,opts){var isSym=Boolean(__slice_fs_is_symlink_sync(sp)),sz=__slice_fs_stat_sync(sp);if(sz<0&&!(!followSym&&isSym)){if(opts&&typeof opts==="object"&&opts.throwIfNoEntry===false)return undefined;throw __fsErr("ENOENT",followSym?"stat":"lstat",sp);}if(sz<0)sz=0;var mt=__slice_fs_mtime_sync(sp),isDir=(!followSym&&isSym)?false:Boolean(__slice_fs_is_dir_sync(sp)),d=new Date(mt),bi=Boolean(opts&&typeof opts==="object"&&opts.bigint),vSz=bi?BigInt(Math.floor(sz)):sz,vMt=bi?BigInt(Math.floor(mt)):mt,vMode=bi?BigInt((!followSym&&isSym)?41471:(isDir?16877:33188)):((!followSym&&isSym)?41471:(isDir?16877:33188));return{size:vSz,mtimeMs:vMt,ctimeMs:vMt,atimeMs:vMt,birthtimeMs:vMt,mtime:d,ctime:d,atime:d,birthtime:d,mode:vMode,isFile:function(){return(!followSym&&isSym)?false:!isDir;},isDirectory:function(){return(!followSym&&isSym)?false:isDir;},isSymbolicLink:function(){return !followSym&&isSym;},isBlockDevice:function(){return false;},isCharacterDevice:function(){return false;},isFIFO:function(){return false;},isSocket:function(){return false;}};}function __cbWrap(syncFn){return function(){var args=[],cb=null;for(var i=0;i=0?n.slice(sl+1):n,par=sl>=0?((base==="/"?"":base)+"/"+n.slice(0,sl)):base,isD=Boolean(__slice_fs_is_dir_sync(fp)),isS=Boolean(__slice_fs_is_symlink_sync(fp));return{name:bn,parentPath:par,path:par,isFile:function(){return !isD&&!isS;},isDirectory:function(){return isD&&!isS;},isSymbolicLink:function(){return isS;},isBlockDevice:function(){return false;},isCharacterDevice:function(){return false;},isFIFO:function(){return false;},isSocket:function(){return false;}};});}if(o.encoding==="buffer"){__slice_ensure_shard(5);return names.map(function(n){return Buffer.from(n,"utf8");});}return names;},statSync:function(p,opts){return __mkStats(String(p),true,opts);},lstatSync:function(p,opts){return __mkStats(String(p),false,opts);},fstatSync:function(fd,opts){var e=__getFd(fd,"fstat");return __mkStats(e.path,true,opts);},openSync:function(p,flags,mode){var sp=String(p),fl=(flags===undefined||flags===null)?"r":String(flags),isR=fl==="r"||fl==="rs"||fl==="0",hasX=fl.indexOf("x")!==-1,isW=fl.charCodeAt(0)===119||fl==="1"||fl==="577",isA=fl.charCodeAt(0)===97||fl.indexOf("1024")!==-1,isPlus=fl.indexOf("+")!==-1||fl==="2";if(hasX&&m.existsSync(sp))throw __fsErr("EEXIST","open",sp);if(isR&&!isPlus){var raw=__slice_fs_read_bytes_sync(sp);if(raw===null)throw __fsErr("ENOENT","open",sp);}else if(isW){var wr=__slice_fs_write_file_sync(sp,new Uint8Array(0));if(wr===-21)throw __fsErr("EISDIR","open",sp);__notifyWatch(sp,"change");}else if(isA){if(!m.existsSync(sp))__slice_fs_write_file_sync(sp,new Uint8Array(0));else __slice_fs_append_file_sync(sp,new Uint8Array(0));}else if(isR&&isPlus){if(__slice_fs_stat_sync(sp)<0)throw __fsErr("ENOENT","open",sp);}var fd=__nextFd++;__fds[fd]={path:sp,flags:fl,mode:mode||438,pos:0,readable:isR||isPlus,writable:isW||isA||isPlus,append:isA};return fd;},closeSync:function(fd){__getFd(fd,"close");delete __fds[Number(fd)];},readSync:function(fd,buf,offOrOpts,len,pos){var e=__getFd(fd,"read");if(!e.readable)throw __fsErr("EBADF","read");var offset=0,length=buf?buf.byteLength:0,position=null;if(offOrOpts&&typeof offOrOpts==="object"){offset=Number(offOrOpts.offset)||0;length=offOrOpts.length!==undefined?Number(offOrOpts.length):(buf.byteLength-offset);position=offOrOpts.position!==undefined?offOrOpts.position:null;}else{offset=Number(offOrOpts)||0;length=len!==undefined?Number(len):(buf.byteLength-offset);position=pos!==undefined?pos:null;}var raw=__slice_fs_read_bytes_sync(e.path);if(!raw||raw===-21)return 0;var readPos=(position!==null&&position!==undefined&&Number(position)>=0)?Number(position):e.pos;if(readPos>=raw.byteLength||length<=0)return 0;var avail=Math.min(length,raw.byteLength-readPos);var target=new Uint8Array(buf.buffer||buf,(buf.byteOffset||0)+offset,avail);target.set(raw.subarray(readPos,readPos+avail),0);if(position===null||position===undefined||Number(position)<0)e.pos=readPos+avail;return avail;},writeSync:function(fd,bufOrStr,offOrPos,lenOrEnc,pos){var e=__getFd(fd,"write");if(!e.writable)throw __fsErr("EBADF","write");__slice_ensure_shard(5);var src,writePos=null;if(typeof bufOrStr==="string"){var enc=typeof lenOrEnc==="string"?lenOrEnc:(typeof offOrPos==="string"?offOrPos:"utf8");if(typeof offOrPos==="number")writePos=offOrPos;src=Buffer.from(bufOrStr,enc);}else{var u8=__fsData(bufOrStr),off=offOrPos!==undefined?Number(offOrPos):0,ln=lenOrEnc!==undefined?Number(lenOrEnc):(u8.byteLength-off);if(pos!==undefined&&pos!==null)writePos=Number(pos);src=u8.subarray(off,off+ln);}if(e.append){__slice_fs_append_file_sync(e.path,src);e.pos+=src.byteLength;__notifyWatch(e.path,"change");return src.byteLength;}var rawCur=__slice_fs_read_bytes_sync(e.path),cur=(rawCur&&rawCur!==-21)?rawCur:new Uint8Array(0);var p=(writePos!==null&&writePos>=0)?writePos:e.pos,nLen=Math.max(cur.byteLength,p+src.byteLength),out=new Uint8Array(nLen);out.set(cur,0);out.set(src,p);__slice_fs_write_file_sync(e.path,out);if(writePos===null||writePos<0)e.pos=p+src.byteLength;__notifyWatch(e.path,"change");return src.byteLength;},fsyncSync:function(fd){__getFd(fd,"fsync");},fdatasyncSync:function(fd){__getFd(fd,"fdatasync");},ftruncateSync:function(fd,len){var e=__getFd(fd,"ftruncate");return m.truncateSync(e.path,len);},futimesSync:function(fd,atime,mtime){var e=__getFd(fd,"futime");return m.utimesSync(e.path,atime,mtime);},fchmodSync:function(fd,mode){var e=__getFd(fd,"fchmod");return m.chmodSync(e.path,mode);},realpathSync:function(p){var sp=String(p);if(__slice_fs_stat_sync(sp)<0)throw __fsErr("ENOENT","realpath",sp);var r=__slice_fs_realpath_sync(sp);if(!r)throw __fsErr("ENOENT","realpath",sp);return r;},readlinkSync:function(p,opts){var sp=String(p),r=__slice_fs_readlink_sync(sp);if(!r)throw __fsErr("ENOENT","readlink",sp);if(opts==="buffer"||(opts&&opts.encoding==="buffer")){__slice_ensure_shard(5);return Buffer.from(r,"utf8");}return r;},truncateSync:function(p,len){var sp=String(p);if(__slice_fs_stat_sync(sp)<0)throw __fsErr("ENOENT","truncate",sp);var r=__slice_fs_truncate_sync(sp,len===undefined?0:Number(len));__notifyWatch(sp,"change");return r;},utimesSync:function(p,atime,mtime){var sp=String(p);if(__slice_fs_stat_sync(sp)<0)throw __fsErr("ENOENT","utime",sp);return __slice_fs_utimes_sync(sp,__toMs(atime),__toMs(mtime));},lutimesSync:function(p,atime,mtime){return m.utimesSync(p,atime,mtime);},mkdtempSync:function(prefix){var r=__slice_fs_mkdtemp_sync(String(prefix||"/tmp/slice-"));if(!r)throw __fsErr("EACCES","mkdtemp",prefix);return r;},chmodSync:function(p,mode){return __slice_fs_chmod_sync(String(p),Number(mode)||0);},symlinkSync:function(target,p){var sp=String(p),r=__slice_fs_symlink_sync(String(target),sp);__notifyWatch(sp,"rename");return r;},opendirSync:function(p){var sp=String(p),names=m.readdirSync(sp,{withFileTypes:true}),idx=0;return{path:sp,readSync:function(){return idx0)throw __fsErr("ENOTEMPTY","rmdir",sp);var r=__slice_fs_rm_sync(sp);__notifyWatch(sp,"rename");return r;},copyFileSync:function(s,d,mode){var ss=String(s),sd=String(d);if(__slice_fs_stat_sync(ss)<0)throw __fsErr("ENOENT","copyfile",ss,sd);if((Number(mode)&1)&&m.existsSync(sd))throw __fsErr("EEXIST","copyfile",ss,sd);var r=__slice_fs_copy_file_sync(ss,sd);__notifyWatch(sd,"change");return r;},cpSync:function(src,dest,opts){var s=String(src).replace(/\/+$/,""),d=String(dest).replace(/\/+$/,""),o=opts||{};if(typeof o.filter==="function"&&!o.filter(s,d))return;if(!m.existsSync(s))throw __fsErr("ENOENT","cp",s);if(Boolean(__slice_fs_is_symlink_sync(s))&&!o.dereference){var linkTarget=m.readlinkSync(s);m.symlinkSync(linkTarget,d);return;}if(Boolean(__slice_fs_is_dir_sync(s))){if(o.recursive===false)throw __fsErr("EISDIR","cp",s);m.mkdirSync(d,{recursive:true});var entries=m.readdirSync(s);for(var i=0;i=0;i--){var w=__watchers[i];if(w._path===np&&(!listener||w._wfListener===listener))w.close();}},createReadStream:function(p,opts){__slice_ensure_shard(5);var st=__slice_builtins["node:stream"]||__slice_load_builtin("node:stream");var o=(typeof opts==="string")?{encoding:opts}:(opts||{});var enc=o.encoding||null,hwm=Number(o.highWaterMark)||65536,start=o.start!==undefined?Number(o.start):0,end=o.end!==undefined?Number(o.end):Infinity;var rs=new st.Readable({highWaterMark:hwm,encoding:enc});rs.path=String(p);rs.bytesRead=0;rs.pending=true;queueMicrotask(function(){try{if(rs.destroyed)return;if(!m.existsSync(rs.path)){rs.emit("error",__fsErr("ENOENT","open",rs.path));return;}rs.pending=false;rs.emit("open",3);rs.emit("ready");var raw=Buffer.from(__slice_fs_read_bytes_sync(rs.path));var sliceEnd=Math.min(raw.length,end===Infinity?raw.length:end+1);var view=raw.subarray(start,sliceEnd);for(var off=0;off0)waiters.shift().res({value:ev,done:false});else q.push(ev);});w.on("close",function(){done=true;while(waiters.length>0)waiters.shift().res({value:undefined,done:true});});return{[Symbol.asyncIterator]:function(){return{next:function(){if(q.length>0)return Promise.resolve({value:q.shift(),done:false});if(done||w._closed)return Promise.resolve({value:undefined,done:true});return new Promise(function(res,rej){waiters.push({res:res,rej:rej});});},return:function(){w.close();return Promise.resolve({value:undefined,done:true});}};}};}};fp.default=fp;fp.__esModule=true;m.promises=fp;m.default=m;m.__esModule=true;__slice_builtins["fs/promises"]=__slice_builtins["node:fs/promises"]=fp;return __slice_builtins["fs"]=__slice_builtins["node:fs"]=m;})();"#; const BUILTIN_PATH_SNIPPET: &[u8] = br#"(function(){function __normPath(p){var s=String(p||"").replace(/\\/g,"/");if(s.length===0)return ".";var isAbs=s.charCodeAt(0)===47,trailing=s.length>1&&s.charCodeAt(s.length-1)===47,parts=s.split("/"),out=[];for(var i=0;i0&&out[out.length-1]!=="..")out.pop();else if(!isAbs)out.push("..");}else out.push(seg);}var res=(isAbs?"/":"")+out.join("/");if(!res)res=isAbs?"/":".";if(trailing&&res!=="/")res+="/";return res;}var m={sep:"/",delimiter:":",normalize:__normPath,isAbsolute:function(p){var s=String(p||"");return s.length>0&&(s.charCodeAt(0)===47||s.charCodeAt(0)===92||(s.length>2&&s.charCodeAt(1)===58));},join:function(){var parts=[];for(var i=0;i=-1&&!resolvedAbs;i--){var p=i>=0?String(arguments[i]||""):"/";if(!p)continue;p=p.replace(/\\/g,"/");resolved=p+"/"+resolved;resolvedAbs=p.charCodeAt(0)===47;}var norm=__normPath(resolved);return(norm.length>1&&norm.charCodeAt(norm.length-1)===47)?norm.slice(0,-1):norm;},dirname:function(p){var s=String(p||"").replace(/\\/g,"/").replace(/\/+$/,"");if(!s)return ".";var i=s.lastIndexOf("/");return i>0?s.slice(0,i):(i===0?"/":".");},basename:function(p,ext){var s=String(p||"").replace(/\\/g,"/").replace(/\/+$/,""),i=s.lastIndexOf("/"),b=i>=0?s.slice(i+1):s;return(ext&&b.endsWith(ext))?b.slice(0,b.length-ext.length):b;},extname:function(p){var b=m.basename(p),i=b.lastIndexOf(".");return i>0?b.slice(i):"";},relative:function(from,to){var f=m.resolve(from),t=m.resolve(to);if(f===t)return "";var fs=f.split("/").filter(Boolean),ts=t.split("/").filter(Boolean),len=Math.min(fs.length,ts.length),same=len;for(var i=0;i0)ev[k]=nx;else delete ev[k];return this;};EventEmitter.prototype.removeAllListeners=function(t){if(arguments.length===0){this._events=Object.create(null);}else if(this._events){delete this._events[String(t)];}return this;};EventEmitter.prototype.emit=function(t){var ev=this._ev(),k=String(t),list=ev[k];if(!list||list.length===0){if(k==="error"){var err=arguments[1];throw(err instanceof Error?err:new Error(String(err||"Unhandled error event")));}return false;}var snap=list.slice(),args=[];for(var i=1;i0)this.emit("newListener",k,fn.listener||fn);(ev[k]||(ev[k]=[])).push(fn);return this;};EventEmitter.prototype.prependListener=function(t,fn){if(typeof fn!=="function")throw new TypeError("listener must be a function");var ev=this._ev(),k=String(t);if(ev.newListener&&ev.newListener.length>0)this.emit("newListener",k,fn.listener||fn);(ev[k]||(ev[k]=[])).unshift(fn);return this;};EventEmitter.prototype.once=function(t,fn){if(typeof fn!=="function")throw new TypeError("listener must be a function");var self=this;function g(){self.removeListener(t,g);fn.apply(this,arguments);}g.listener=fn;return this.on(t,g);};EventEmitter.prototype.prependOnceListener=function(t,fn){if(typeof fn!=="function")throw new TypeError("listener must be a function");var self=this;function g(){self.removeListener(t,g);fn.apply(this,arguments);}g.listener=fn;return this.prependListener(t,g);};EventEmitter.prototype.off=EventEmitter.prototype.removeListener=function(t,fn){var ev=this._ev(),k=String(t),list=ev[k];if(!list)return this;var nx=[],removed=[];for(var i=0;i0)ev[k]=nx;else delete ev[k];if(removed.length>0&&ev.removeListener&&ev.removeListener.length>0){for(var r=0;r";if(v instanceof __U8)return "Uint8Array("+v.length+") ["+Array.from(v).join(", ")+"]";seen=seen||[];if(seen.indexOf(v)!==-1)return "[Circular]";seen.push(v);if(Array.isArray(v)){var a=[];for(var i=0;i=args.length){if(strict){var eM=new TypeError("Option '--"+longName+"' argument is missing");eM.code="ERR_PARSE_ARGS_INVALID_OPTION_VALUE";throw eM;}sVal="";}else{sVal=String(args[++idx]);}}setVal(longName,sVal);tokens.push({kind:"option",name:longName,index:idx,value:sVal,inlineValue:inlineVal!==undefined});idx++;}}else if(raw.length>1&&raw.charCodeAt(0)===45){var shorts=raw.slice(1);for(var s=0;s0?rest:(idx+10});break;}}idx++;}else{if(!allowPos&&strict){var eP=new TypeError("Unexpected argument '"+raw+"'");eP.code="ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL";throw eP;}positionals.push(raw);tokens.push({kind:"positional",index:idx,value:raw});idx++;}}return wantTokens?{values:values,positionals:positionals,tokens:tokens}:{values:values,positionals:positionals};}var __SGR={bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29],black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39],grey:[90,39],bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49]};function styleText(fmt,text){var fs=Array.isArray(fmt)?fmt:[fmt],out=String(text);for(var i=fs.length-1;i>=0;i--){var pair=__SGR[String(fs[i])];if(pair)out="\x1b["+pair[0]+"m"+out+"\x1b["+pair[1]+"m";}return out;}function stripVTControlCharacters(str){return String(str).replace(/\x1B\[[0-?]*[ -/]*[@-~]|\x1B[@-Z\\-_]/g,"");}function MIMEParams(init){this._map=[];if(typeof init==="string"){var parts=init.split(";");for(var i=0;i=2&&v.charCodeAt(0)===34&&v.charCodeAt(v.length-1)===34)v=v.slice(1,-1);this.set(k,v);}}}}MIMEParams.prototype.get=function(n){var k=String(n).toLowerCase();for(var i=0;i";if(v instanceof __U8)return "Uint8Array("+v.length+") ["+Array.from(v).join(", ")+"]";if(seen.indexOf(v)!==-1)return "[Circular]";if(v instanceof Map){if(v.size===0)return "Map(0) {}";if(curD>maxD)return "[Map]";var scM=seen.concat([v]),em=[],itM=v.entries(),nxM;while(!(nxM=itM.next()).done){em.push(__inspRec(nxM.value[0],scM,curD+1,maxD)+" => "+__inspRec(nxM.value[1],scM,curD+1,maxD));}return "Map("+v.size+") { "+em.join(", ")+" }";}if(v instanceof Set){if(v.size===0)return "Set(0) {}";if(curD>maxD)return "[Set]";var scS=seen.concat([v]),es=[],itS=v.values(),nxS;while(!(nxS=itS.next()).done){es.push(__inspRec(nxS.value,scS,curD+1,maxD));}return "Set("+v.size+") { "+es.join(", ")+" }";}if(Array.isArray(v)){if(v.length===0)return "[]";if(curD>maxD)return "[Array]";var scA=seen.concat([v]),a=[];for(var i=0;imaxD)return "[Object]";var scO=seen.concat([v]),p=[];for(var j=0;j=args.length){if(strict){var eM=new TypeError("Option '--"+longName+"' argument is missing");eM.code="ERR_PARSE_ARGS_INVALID_OPTION_VALUE";throw eM;}sVal="";}else{sVal=String(args[++idx]);}}setVal(longName,sVal);tokens.push({kind:"option",name:longName,index:idx,value:sVal,inlineValue:inlineVal!==undefined});idx++;}}else if(raw.length>1&&raw.charCodeAt(0)===45){var shorts=raw.slice(1);for(var s=0;s0?rest:(idx+10});break;}}idx++;}else{if(!allowPos&&strict){var eP=new TypeError("Unexpected argument '"+raw+"'");eP.code="ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL";throw eP;}positionals.push(raw);tokens.push({kind:"positional",index:idx,value:raw});idx++;}}return wantTokens?{values:values,positionals:positionals,tokens:tokens}:{values:values,positionals:positionals};}var __SGR={bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29],black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],gray:[90,39],grey:[90,39],bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49]};function styleText(fmt,text){var fs=Array.isArray(fmt)?fmt:[fmt],out=String(text);for(var i=fs.length-1;i>=0;i--){var pair=__SGR[String(fs[i])];if(pair)out="\x1b["+pair[0]+"m"+out+"\x1b["+pair[1]+"m";}return out;}function stripVTControlCharacters(str){return String(str).replace(/\x1B\[[0-?]*[ -/]*[@-~]|\x1B[@-Z\\-_]/g,"");}function MIMEParams(init){this._map=[];if(typeof init==="string"){var parts=init.split(";");for(var i=0;i=2&&v.charCodeAt(0)===34&&v.charCodeAt(v.length-1)===34)v=v.slice(1,-1);this.set(k,v);}}}}MIMEParams.prototype.get=function(n){var k=String(n).toLowerCase();for(var i=0;i=3&&p.charCodeAt(0)===47&&p.charCodeAt(2)===58)p=p.slice(1);return p;}function pathToFileURL(p){var s=String(p).replace(/\\/g,"/");if(s.charCodeAt(0)!==47)s="/"+s;return new globalThis.URL("file://"+s);}var m={URL:globalThis.URL,URLSearchParams:globalThis.URLSearchParams,fileURLToPath:fileURLToPath,pathToFileURL:pathToFileURL};m.default=m;m.__esModule=true;return __slice_builtins["url"]=__slice_builtins["node:url"]=m;})();"#; +const BUILTIN_URL_SNIPPET: &[u8] = br#"(function(){__slice_ensure_shard(1);function fileURLToPath(u){var h=(u&&typeof u==="object"&&typeof u.href==="string")?u.href:String(u);if(h.indexOf("file://")!==0)throw new TypeError("The URL must be of scheme file");var uObj=(u&&typeof u==="object"&&typeof u.pathname==="string")?u:new globalThis.URL(h);var p=decodeURIComponent(uObj.pathname);if(p.length>=3&&p.charCodeAt(0)===47&&p.charCodeAt(2)===58)p=p.slice(1);return p;}function pathToFileURL(p){var s=String(p).replace(/\\/g,"/");if(s.charCodeAt(0)!==47)s="/"+s;var enc=s.replace(/%/g,"%25").replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/\t/g,"%09").replace(/#/g,"%23").replace(/\?/g,"%3F").replace(/ /g,"%20");return new globalThis.URL("file://"+enc);}var m={URL:globalThis.URL,URLSearchParams:globalThis.URLSearchParams,fileURLToPath:fileURLToPath,pathToFileURL:pathToFileURL};m.default=m;m.__esModule=true;return __slice_builtins["url"]=__slice_builtins["node:url"]=m;})();"#; -const BUILTIN_TIMERS_SNIPPET: &[u8] = br#"(function(){var tp={setTimeout:function(delay,value,options){var sig=options&&options.signal;if(sig&&sig.aborted)return Promise.reject(sig.reason||new Error("AbortError: The operation was aborted"));return new Promise(function(res,rej){var settled=false,tid=setTimeout(function(){if(settled)return;settled=true;res(value);},Number(delay)||0);if(sig&&typeof sig.addEventListener==="function"){sig.addEventListener("abort",function(){if(settled)return;settled=true;clearTimeout(tid);rej(sig.reason||new Error("AbortError: The operation was aborted"));});}});},setImmediate:function(value,options){var sig=options&&options.signal;if(sig&&sig.aborted)return Promise.reject(sig.reason||new Error("AbortError: The operation was aborted"));return new Promise(function(res,rej){var settled=false,iid=setImmediate(function(){if(settled)return;settled=true;res(value);});if(sig&&typeof sig.addEventListener==="function"){sig.addEventListener("abort",function(){if(settled)return;settled=true;clearImmediate(iid);rej(sig.reason||new Error("AbortError: The operation was aborted"));});}});}};tp.default=tp;tp.__esModule=true;var m={setTimeout:globalThis.setTimeout,clearTimeout:globalThis.clearTimeout,setInterval:globalThis.setInterval,clearInterval:globalThis.clearInterval,setImmediate:globalThis.setImmediate,clearImmediate:globalThis.clearImmediate,queueMicrotask:globalThis.queueMicrotask,promises:tp};m.default=m;m.__esModule=true;__slice_builtins["timers/promises"]=__slice_builtins["node:timers/promises"]=tp;return __slice_builtins["timers"]=__slice_builtins["node:timers"]=m;})();"#; +const BUILTIN_TIMERS_SNIPPET: &[u8] = br#"(function(){function __mkAbortErr(sig){var r=sig&&sig.reason;var msg=(r instanceof Error&&r.message&&r.name!=="AbortError")?("The operation was aborted: "+r.message):"The operation was aborted";var e=new Error(msg);e.name="AbortError";e.code="ABORT_ERR";if(r!==undefined)e.cause=r;return e;}var tp={setTimeout:function(delay,value,options){var sig=options&&options.signal;if(sig&&sig.aborted)return Promise.reject(__mkAbortErr(sig));return new Promise(function(res,rej){var settled=false,tid=setTimeout(function(){if(settled)return;settled=true;res(value);},Number(delay)||0);if(sig&&typeof sig.addEventListener==="function"){sig.addEventListener("abort",function(){if(settled)return;settled=true;clearTimeout(tid);rej(__mkAbortErr(sig));});}});},setImmediate:function(value,options){var sig=options&&options.signal;if(sig&&sig.aborted)return Promise.reject(__mkAbortErr(sig));return new Promise(function(res,rej){var settled=false,iid=setImmediate(function(){if(settled)return;settled=true;res(value);});if(sig&&typeof sig.addEventListener==="function"){sig.addEventListener("abort",function(){if(settled)return;settled=true;clearImmediate(iid);rej(__mkAbortErr(sig));});}});}};tp.default=tp;tp.__esModule=true;var m={setTimeout:globalThis.setTimeout,clearTimeout:globalThis.clearTimeout,setInterval:globalThis.setInterval,clearInterval:globalThis.clearInterval,setImmediate:globalThis.setImmediate,clearImmediate:globalThis.clearImmediate,queueMicrotask:globalThis.queueMicrotask,promises:tp};m.default=m;m.__esModule=true;__slice_builtins["timers/promises"]=__slice_builtins["node:timers/promises"]=tp;return __slice_builtins["timers"]=__slice_builtins["node:timers"]=m;})();"#; const BUILTIN_STREAM_SNIPPET: &[u8] = br#"(function(){var EE=__slice_builtins["node:events"]||__slice_load_builtin("node:events");function __getSD(){var sd=__slice_builtins["node:string_decoder"]||__slice_load_builtin("node:string_decoder");return sd.StringDecoder;}function Stream(){EE.call(this);this.destroyed=false;this.errored=null;}Stream.prototype=Object.create(EE.prototype);Stream.prototype.constructor=Stream;Stream.prototype.pipe=function(dest,opts){var self=this,doEnd=!opts||opts.end!==false;this.on("data",function(c){if(dest.write)dest.write(c);});this.once("end",function(){if(doEnd&&dest.end)dest.end();});this.once("error",function(e){if(dest.destroy)dest.destroy(e);});if(typeof this.resume==="function")this.resume();return dest;};Stream.prototype.destroy=function(err){if(this.destroyed)return this;this.destroyed=true;if(err)this.errored=err;var self=this;function done(e){if(e)self.errored=e;queueMicrotask(function(){if(self.errored)self.emit("error",self.errored);self.emit("close");});}if(typeof this._destroy==="function"){try{this._destroy(err||null,done);}catch(e){done(e);}}else{done(err);}return this;};function Readable(opts){if(!(this instanceof Readable))return new Readable(opts);Stream.call(this);var o=opts||{};this.readable=true;this.readableEnded=false;this.readableFlowing=null;this.readableObjectMode=Boolean(o.objectMode);this.readableHighWaterMark=o.highWaterMark!==undefined?Number(o.highWaterMark):(this.readableObjectMode?16:65536);this._encoding=o.encoding||null;this._decoder=this._encoding?new(__getSD())(this._encoding):null;this._buf=[];this._reading=false;this._eof=false;this._emittedEnd=false;this._waiters=[];if(typeof o.read==="function")this._read=o.read;if(typeof o.destroy==="function")this._destroy=o.destroy;}Readable.prototype=Object.create(Stream.prototype);Readable.prototype.constructor=Readable;Readable.prototype._read=function(){};Readable.prototype.setEncoding=function(enc){this._encoding=enc?String(enc):"utf8";var SD=__getSD();this._decoder=new SD(this._encoding);return this;};Readable.prototype.on=Readable.prototype.addListener=function(ev,fn){EE.prototype.on.call(this,ev,fn);if(ev==="data"){if(this.readableFlowing!==false)this.resume();}else if(ev==="readable"){if(this.readableFlowing===null)this.readableFlowing=false;this._kickRead();}return this;};Readable.prototype._kickRead=function(){if(this.destroyed||this._eof||this._reading)return;this._reading=true;var self=this;queueMicrotask(function(){self._reading=false;if(self.destroyed||self._eof)return;try{self._read(self.readableHighWaterMark);}catch(e){self.destroy(e);}});};Readable.prototype._formatChunk=function(c){if(c===null||c===undefined||this.readableObjectMode)return c;if(this._encoding){if(typeof c==="string")return c;if(!this._decoder){var SD=__getSD();this._decoder=new SD(this._encoding);}return this._decoder.write(c);}if(typeof c==="string"){__slice_ensure_shard(5);return Buffer.from(c,"utf8");}return c;};Readable.prototype._enqueueFmt=function(fmt){if(this._waiters.length>0){var w=this._waiters.shift();w.res({value:fmt,done:false});return true;}this._buf.push(fmt);this._drainFlowing();return this._buf.length0)this._enqueueFmt(rem);}this._eof=true;this._drainFlowing();return false;}var fmt=this._formatChunk(chunk);if(!this.readableObjectMode&&this._encoding&&typeof fmt==="string"&&fmt.length===0&&chunk&&((chunk.byteLength||chunk.length||0)>0))return true;return this._enqueueFmt(fmt);};Readable.prototype.unshift=function(chunk){if(chunk!==null&&chunk!==undefined){this._buf.unshift(this._formatChunk(chunk));this._drainFlowing();}return true;};Readable.prototype._drainFlowing=function(){if(this.readableFlowing===true){while(this._buf.length>0&&this.readableFlowing===true&&!this.destroyed){var c=this._buf.shift();this.emit("data",c);}if(this._buf.length===0&&!this._eof)this._kickRead();}else if(this._buf.length>0&&this.listenerCount("readable")>0){this.emit("readable");}if(this._eof&&this._buf.length===0&&!this._emittedEnd){this._emittedEnd=true;this.readable=false;this.readableEnded=true;while(this._waiters.length>0){this._waiters.shift().res({value:undefined,done:true});}var self=this;queueMicrotask(function(){if(!self.destroyed){self.emit("end");self.emit("close");}});}};Readable.prototype.read=function(){if(this._buf.length>0){var c=this._buf.shift();if(this._buf.length===0&&!this._eof)this._kickRead();if(this._eof&&this._buf.length===0)this._drainFlowing();return c;}if(!this._eof)this._kickRead();if(this._eof)this._drainFlowing();return null;};Readable.prototype.pause=function(){if(this.readableFlowing!==false){this.readableFlowing=false;this.emit("pause");}return this;};Readable.prototype.resume=function(){if(!this.readableEnded){this.readableFlowing=true;this.emit("resume");this._kickRead();this._drainFlowing();}return this;};Readable.prototype.isPaused=function(){return this.readableFlowing===false;};Readable.prototype[Symbol.asyncIterator]=function(){var self=this;this.readableFlowing=false;this._kickRead();return{next:function(){if(self.destroyed&&self.errored)return Promise.reject(self.errored);if(self._buf.length>0){var c=self._buf.shift();if(self._buf.length===0&&!self._eof)self._kickRead();return Promise.resolve({value:c,done:false});}if(self._eof||self.readableEnded||self.destroyed)return Promise.resolve({value:undefined,done:true});self._kickRead();return new Promise(function(res,rej){self._waiters.push({res:res,rej:rej});});},return:function(){self.destroy();return Promise.resolve({value:undefined,done:true});}};};Readable.from=function(iterable,opts){var r=new Readable(Object.assign({objectMode:true},opts||{}));queueMicrotask(function(){try{if(iterable&&typeof iterable[Symbol.asyncIterator]==="function"){var ait=iterable[Symbol.asyncIterator]();(function pump(){ait.next().then(function(step){if(r.destroyed)return;if(step.done){r.push(null);}else{r.push(step.value);pump();}},function(err){r.destroy(err);});})();}else{var arr=Array.from(iterable||[]);for(var i=0;i0)this._corked--;if(this._corked===0&&this._corkBuf.length>0){var q=this._corkBuf.slice();this._corkBuf=[];for(var i=0;i0){this._corkBuf.push({c:chunk,e:e,cb:cb,len:len});return ret;}this._doWrite(chunk,e,cb,len);return ret;};Writable.prototype.end=function(chunk,enc,cb){if(typeof chunk==="function"){cb=chunk;chunk=undefined;enc=undefined;}else if(typeof enc==="function"){cb=enc;enc=undefined;}if(chunk!==undefined&&chunk!==null)this.write(chunk,enc);while(this._corked>0)this.uncork();if(this.writableEnded){if(typeof cb==="function"){if(this.writableFinished)queueMicrotask(cb);else this.once("finish",cb);}return this;}this.writableEnded=true;this.writable=false;var self=this;function finishNow(err){if(err){self.destroy(err);if(typeof cb==="function")cb(err);return;}self.writableFinished=true;self.emit("finish");if(typeof cb==="function")cb(null);if(!self.destroyed&&!(self instanceof Duplex))self.emit("close");}if(typeof this._final==="function"){try{this._final(finishNow);}catch(e){finishNow(e);}}else{queueMicrotask(function(){finishNow(null);});}return this;};Writable.fromWeb=function(webWs,opts){var w=webWs.getWriter();return new Writable(Object.assign({},opts||{},{write:function(c,_e,cb){w.write(c).then(function(){cb(null);},function(e){cb(e);});},final:function(cb){w.close().then(function(){cb(null);},function(e){cb(e);});}}));};Writable.toWeb=function(nodeWs){__slice_ensure_shard(3);return new globalThis.WritableStream({write:function(c){return new Promise(function(res,rej){nodeWs.write(c,function(e){if(e)rej(e);else res();});});},close:function(){return new Promise(function(res,rej){nodeWs.end(function(e){if(e)rej(e);else res();});});},abort:function(r){nodeWs.destroy(r instanceof Error?r:new Error(String(r||"Aborted")));}});};function Duplex(opts){if(!(this instanceof Duplex))return new Duplex(opts);Readable.call(this,opts);Writable.call(this,opts);this.allowHalfOpen=!opts||opts.allowHalfOpen!==false;}Duplex.prototype=Object.create(Readable.prototype);Object.assign(Duplex.prototype,Writable.prototype);Duplex.prototype.constructor=Duplex;function Transform(opts){if(!(this instanceof Transform))return new Transform(opts);Duplex.call(this,opts);var o=opts||{};if(typeof o.transform==="function")this._transform=o.transform;if(typeof o.flush==="function")this._flush=o.flush;}Transform.prototype=Object.create(Duplex.prototype);Transform.prototype.constructor=Transform;Transform.prototype._transform=function(c,_e,cb){this.push(c);if(cb)cb(null);};Transform.prototype._write=function(chunk,enc,cb){var self=this;this._transform(chunk,enc,function(err,out){if(err){if(cb)cb(err);else self.destroy(err);return;}if(out!==undefined&&out!==null)self.push(out);if(cb)cb(null);});};Transform.prototype._final=function(cb){var self=this;if(typeof this._flush==="function"){this._flush(function(err,out){if(err){cb(err);return;}if(out!==undefined&&out!==null)self.push(out);self.push(null);cb(null);});}else{this.push(null);cb(null);}};function PassThrough(opts){if(!(this instanceof PassThrough))return new PassThrough(opts);Transform.call(this,opts);}PassThrough.prototype=Object.create(Transform.prototype);PassThrough.prototype.constructor=PassThrough;function finished(stream,opts,cb){if(typeof opts==="function"){cb=opts;opts={};}var o=opts||{},sig=o.signal,settled=false;function done(err){if(settled)return;settled=true;if(typeof cb==="function")cb(err||null);}if(sig&&sig.aborted){queueMicrotask(function(){done(sig.reason||new Error("AbortError"));});return function(){};}if(stream.destroyed||stream.writableFinished||stream.readableEnded){queueMicrotask(function(){done(stream.errored||null);});return function(){};}function onEnd(){done(null);}function onErr(e){done(e||new Error("Stream error"));}function onClose(){if(!stream.writableFinished&&stream.writableEnded===false&&stream.readableEnded===false&&stream.errored){done(stream.errored);}else{done(null);}}if(stream.once){stream.once("finish",onEnd);stream.once("end",onEnd);stream.once("error",onErr);stream.once("close",onClose);}if(sig&&typeof sig.addEventListener==="function"){sig.addEventListener("abort",function(){var ae=sig.reason||new Error("AbortError");if(stream.destroy)stream.destroy(ae);done(ae);});}return function(){if(stream.removeListener){stream.removeListener("finish",onEnd);stream.removeListener("end",onEnd);stream.removeListener("error",onErr);stream.removeListener("close",onClose);}};}function pipeline(){var args=Array.from(arguments),cb=typeof args[args.length-1]==="function"?args.pop():null;if(args.length===1&&Array.isArray(args[0]))args=args[0];var opts=(args.length>1&&args[args.length-1]&&typeof args[args.length-1]==="object"&&typeof args[args.length-1].pipe!=="function"&&typeof args[args.length-1].write!=="function")?args.pop():{};var sig=opts&&opts.signal,settled=false;function finishAll(err){if(settled)return;settled=true;if(err){for(var k=0;k boa_engine::job::JobCallback { + if BOA_ALS_ACTIVE.with(|a| a.get()) { + let snap = BOA_ALS_SNAP.with(|s| s.borrow().clone()); + return boa_engine::job::JobCallback::new(callback, AlsCapturedSnap(snap)); + } + boa_engine::job::JobCallback::new(callback, ()) + } + + fn call_job_callback( + &self, + job: &boa_engine::job::JobCallback, + this: &boa_engine::JsValue, + args: &[boa_engine::JsValue], + context: &mut boa_engine::Context, + ) -> boa_engine::JsResult { + if let Some(captured) = job.host_defined().downcast_ref::() { + let prev = BOA_ALS_SNAP.with(|s| s.replace(captured.0.clone())); + let res = job.callback().call(this, args, context); + BOA_ALS_SNAP.with(|s| *s.borrow_mut() = prev); + return res; + } + if BOA_ALS_ACTIVE.with(|a| a.get()) { + let prev = BOA_ALS_SNAP.with(|s| s.replace(boa_engine::JsValue::undefined())); + let res = job.callback().call(this, args, context); + BOA_ALS_SNAP.with(|s| *s.borrow_mut() = prev); + return res; + } + job.callback().call(this, args, context) + } + fn promise_rejection_tracker( &self, promise: &boa_engine::object::JsObject, @@ -242,9 +295,7 @@ pub(crate) fn map_error_with_active_source(raw_error: &str) -> String { } pub(crate) struct SliceJobExecutor { - promise_jobs: std::cell::RefCell< - std::collections::VecDeque<(boa_engine::job::PromiseJob, Option)>, - >, + promise_jobs: std::cell::RefCell>, fallback: std::rc::Rc, } @@ -265,12 +316,7 @@ impl boa_engine::job::JobExecutor for SliceJobExecutor { ) { match job { boa_engine::job::Job::PromiseJob(p) => { - let snap = if BOA_ALS_ACTIVE.with(|a| a.get()) { - Some(BOA_ALS_SNAP.with(|s| s.borrow().clone())) - } else { - None - }; - self.promise_jobs.borrow_mut().push_back((p, snap)); + self.promise_jobs.borrow_mut().push_back(p); } other => { self.fallback.clone().enqueue_job(other, context); @@ -288,15 +334,8 @@ impl boa_engine::job::JobExecutor for SliceJobExecutor { } loop { let next_job = self.promise_jobs.borrow_mut().pop_front(); - if let Some((job, snap_opt)) = next_job { - let res = if let Some(snap) = snap_opt { - let prev = BOA_ALS_SNAP.with(|s| s.replace(snap)); - let r = job.call(context); - BOA_ALS_SNAP.with(|s| *s.borrow_mut() = prev); - r - } else { - job.call(context) - }; + if let Some(job) = next_job { + let res = job.call(context); if BOA_PROCESS_EXIT.with(|e| e.get().is_some()) { self.promise_jobs.borrow_mut().clear(); return Ok(()); diff --git a/crates/slice-engine/src/runtime/event_loop.rs b/crates/slice-engine/src/runtime/event_loop.rs index 1b66c09..0e5f722 100644 --- a/crates/slice-engine/src/runtime/event_loop.rs +++ b/crates/slice-engine/src/runtime/event_loop.rs @@ -172,9 +172,11 @@ pub(crate) fn current_event_loop_clock_ms() -> u64 { pub(crate) struct ScheduledTimer { pub(crate) id: u32, + pub(crate) delay_ms: u64, pub(crate) deadline_ms: u64, pub(crate) interval_ms: Option, pub(crate) is_immediate: bool, + pub(crate) refed: bool, pub(crate) callback: JsObject, pub(crate) args: Vec, pub(crate) als_snap: Option, @@ -250,7 +252,7 @@ impl EventLoopState { fn has_pending_work(&self) -> bool { !self.queued_fetches.is_empty() || !self.in_flight_fetches.is_empty() - || self.timers.iter().any(|t| !t.cancelled) + || self.timers.iter().any(|t| !t.cancelled && t.refed) } } @@ -374,9 +376,11 @@ fn schedule_timer_internal( }; loop_st.timers.push(ScheduledTimer { id, + delay_ms, deadline_ms, interval_ms, is_immediate, + refed: true, callback, args, als_snap, @@ -388,6 +392,53 @@ fn schedule_timer_internal( }) } +pub(crate) fn set_timer_ref(timer_id: u32, refed: bool) { + if timer_id == 0 { + return; + } + EVENT_LOOP_STATE.with(|st| { + let mut loop_st = st.borrow_mut(); + for timer in &mut loop_st.timers { + if timer.id == timer_id && !timer.cancelled { + timer.refed = refed; + break; + } + } + if loop_st.has_pending_work() { + ACTIVE_ASYNC_ITEMS.with(|c| { + if c.get() == 0 { + c.set(1); + } + }); + } else { + ACTIVE_ASYNC_ITEMS.with(|c| c.set(0)); + } + }); +} + +pub(crate) fn refresh_timer(timer_id: u32) { + if timer_id == 0 { + return; + } + let now_ms = current_event_loop_clock_ms(); + EVENT_LOOP_STATE.with(|st| { + let mut loop_st = st.borrow_mut(); + for timer in &mut loop_st.timers { + if timer.id == timer_id && !timer.cancelled { + timer.deadline_ms = now_ms.saturating_add(timer.delay_ms); + break; + } + } + if loop_st.has_pending_work() { + ACTIVE_ASYNC_ITEMS.with(|c| { + if c.get() == 0 { + c.set(1); + } + }); + } + }); +} + pub(crate) fn cancel_timer(timer_id: u32) { if timer_id == 0 { return; @@ -1161,9 +1212,13 @@ pub(crate) fn drive_event_loop_to_completion(ctx: &mut Context) { clear_event_loop_state(); return; } - let prev_als = als_snap - .as_ref() - .map(|snap| BOA_ALS_SNAP.with(|s| s.replace(snap.clone()))); + let prev_als = if let Some(ref snap) = als_snap { + Some(BOA_ALS_SNAP.with(|s| s.replace(snap.clone()))) + } else if BOA_ALS_ACTIVE.with(|a| a.get()) { + Some(BOA_ALS_SNAP.with(|s| s.replace(JsValue::undefined()))) + } else { + None + }; let call_res = cb.call(&JsValue::undefined(), &args, ctx); if let Some(prev) = prev_als { BOA_ALS_SNAP.with(|s| *s.borrow_mut() = prev); @@ -1190,29 +1245,33 @@ pub(crate) fn drive_event_loop_to_completion(ctx: &mut Context) { } // 6. Check if any work remains; if not, exit cleanly - let (in_flight_count, next_timer_deadline, has_queued) = EVENT_LOOP_STATE.with(|st| { - let loop_st = st.borrow(); - let next_dl = loop_st - .timers - .iter() - .filter(|t| !t.cancelled) - .map(|t| t.deadline_ms) - .min(); - ( - loop_st.in_flight_fetches.len(), - next_dl, - !loop_st.queued_fetches.is_empty(), - ) - }); + let (in_flight_count, has_refed_timers, next_timer_deadline, has_queued) = EVENT_LOOP_STATE + .with(|st| { + let loop_st = st.borrow(); + let has_refed = loop_st.timers.iter().any(|t| !t.cancelled && t.refed); + let next_dl = loop_st + .timers + .iter() + .filter(|t| !t.cancelled) + .map(|t| t.deadline_ms) + .min(); + ( + loop_st.in_flight_fetches.len(), + has_refed, + next_dl, + !loop_st.queued_fetches.is_empty(), + ) + }); if has_queued { continue; } let has_worker_work = crate::workers::has_pending_worker_work(); - if in_flight_count == 0 && next_timer_deadline.is_none() && !has_worker_work { + if in_flight_count == 0 && !has_refed_timers && !has_worker_work { if try_emit_before_exit(ctx, &mut before_exit_count) { continue; } + EVENT_LOOP_STATE.with(|st| st.borrow_mut().timers.clear()); ACTIVE_ASYNC_ITEMS.with(|c| c.set(0)); break; } diff --git a/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs b/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs index d83e562..523ad4d 100644 --- a/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs +++ b/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs @@ -2960,13 +2960,7 @@ run(); .with_exec_binary("cat") .with_exec_binary("false") .with_exec_binary("/nonexistent_slice_binary_xyz"); - let mut iso = SliceIsolate::spawn( - "wave2-child-process", - 1, - caps, - 10_000_000, - 16 * 1024 * 1024, - ); + let mut iso = SliceIsolate::spawn("wave2-child-process", 1, caps, 10_000_000, 16 * 1024 * 1024); let m = iso.execute_bytecode(&bc, None).unwrap(); let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); @@ -3004,3 +2998,502 @@ cp.execSync("echo hi && echo bye"); ); } +#[test] +fn test_wave3_dom_exception_abort_signal_timeout_fetch_and_timers_promises() { + let script = r#" +import timersPromises from "node:timers/promises"; + +async function run() { + const out: Record = {}; + + // 1. DOMException constructor & legacy error codes + out.hasDOMException = typeof DOMException === "function"; + const d1 = new DOMException("aborted Custom", "AbortError"); + out.d1InstanceError = d1 instanceof Error; + out.d1InstanceDOM = d1 instanceof DOMException; + out.d1Name = d1.name; + out.d1Message = d1.message; + out.d1Code = d1.code; + out.staticCodes = [ + DOMException.INDEX_SIZE_ERR, + DOMException.ABORT_ERR, + DOMException.TIMEOUT_ERR, + DOMException.DATA_CLONE_ERR, + new DOMException("clone", "DataCloneError").code + ]; + + // 2. AbortSignal.abort() & AbortController.abort() default reasons + const s1 = AbortSignal.abort(); + out.s1IsDOM = s1.reason instanceof DOMException; + out.s1Name = s1.reason.name; + out.s1Code = s1.reason.code; + + const ac = new AbortController(); + ac.abort(); + out.acIsDOM = ac.signal.reason instanceof DOMException; + out.acName = ac.signal.reason.name; + out.acCode = ac.signal.reason.code; + + // 3. AbortSignal.timeout(ms) + const ts = AbortSignal.timeout(5); + await new Promise((resolve) => { + ts.addEventListener("abort", () => resolve(), { once: true }); + }); + out.tsAborted = ts.aborted; + out.tsIsDOM = ts.reason instanceof DOMException; + out.tsName = ts.reason.name; + out.tsCode = ts.reason.code; + + // 4. fetch() with aborted signal (default DOMException and custom reason) + try { + await fetch("http://example.com", { signal: AbortSignal.abort() }); + } catch (e: any) { + out.fetchAbortIsDOM = e instanceof DOMException; + out.fetchAbortName = e.name; + out.fetchAbortCode = e.code; + } + try { + await fetch("http://example.com", { signal: AbortSignal.abort("custom-fetch-reason") }); + } catch (e: any) { + out.fetchCustomReason = e; + } + + // 5. node:timers/promises AbortError wrapper with .code === "ABORT_ERR" and .cause + const acTp = new AbortController(); + setTimeout(() => acTp.abort("my-custom-cause"), 5); + try { + await timersPromises.setTimeout(500, "never", { signal: acTp.signal }); + } catch (e: any) { + out.tpName = e.name; + out.tpCode = e.code; + out.tpCause = e.cause; + } + + console.log(JSON.stringify(out)); +} +run(); +"#; + + let bundled = slice_cas::strip_typescript_and_normalize(script, true); + let bc = compile_source_to_bytecode(&bundled); + let mut iso = SliceIsolate::spawn( + "wave3-dom-abort", + 1, + CapabilityToken::pure_compute().with_net_host("example.com"), + 10_000_000, + 16 * 1024 * 1024, + ); + let m = iso.execute_bytecode(&bc, None).unwrap(); + let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); + + assert_eq!(out["hasDOMException"], true); + assert_eq!(out["d1InstanceError"], true); + assert_eq!(out["d1InstanceDOM"], true); + assert_eq!(out["d1Name"], "AbortError"); + assert_eq!(out["d1Message"], "aborted Custom"); + assert_eq!(out["d1Code"], 20); + assert_eq!(out["staticCodes"], serde_json::json!([1, 20, 23, 25, 25])); + assert_eq!(out["s1IsDOM"], true); + assert_eq!(out["s1Name"], "AbortError"); + assert_eq!(out["s1Code"], 20); + assert_eq!(out["acIsDOM"], true); + assert_eq!(out["acName"], "AbortError"); + assert_eq!(out["acCode"], 20); + assert_eq!(out["tsAborted"], true); + assert_eq!(out["tsIsDOM"], true); + assert_eq!(out["tsName"], "TimeoutError"); + assert_eq!(out["tsCode"], 23); + assert_eq!(out["fetchAbortIsDOM"], true); + assert_eq!(out["fetchAbortName"], "AbortError"); + assert_eq!(out["fetchAbortCode"], 20); + assert_eq!(out["fetchCustomReason"], "custom-fetch-reason"); + assert_eq!(out["tpName"], "AbortError"); + assert_eq!(out["tpCode"], "ABORT_ERR"); + assert_eq!(out["tpCause"], "my-custom-cause"); +} + +#[test] +fn test_wave3_async_local_storage_external_promises_then_chains_and_timers() { + let script = r#" +import { AsyncLocalStorage } from "node:async_hooks"; + +async function run() { + const als = new AsyncLocalStorage(); + const out: Record = {}; + + // 1. Timer promise inside als.run + out.timerAwait = await als.run("ctx-timer", async () => { + await new Promise((r) => setTimeout(r, 5)); + return als.getStore(); + }); + + // 2. External promise created outside als.run and resolved outside als.run + let extResolve!: () => void; + const extPromise = new Promise((r) => { extResolve = r; }); + const extTask = als.run("ctx-external", async () => { + await extPromise; + return als.getStore(); + }); + setTimeout(() => extResolve(), 5); + out.externalAwait = await extTask; + + // 3. Multi-hop .then().then() chain registered inside als.run and settled outside + let chainResolve!: () => void; + const chainRoot = new Promise((r) => { chainResolve = r; }); + const chainTask = als.run("ctx-chain", () => + chainRoot + .then(() => als.getStore()) + .then((first) => [first, als.getStore()]) + ); + setTimeout(() => chainResolve(), 5); + out.thenChain = await chainTask; + + // 4. Concurrent overlapping ALS contexts across interleaved timers & microtasks + const [resA, resB] = await Promise.all([ + als.run({ tenant: "A" }, async () => { + await new Promise((r) => setTimeout(r, 6)); + await Promise.resolve(); + return (als.getStore() as any)?.tenant; + }), + als.run({ tenant: "B" }, async () => { + await new Promise((r) => setTimeout(r, 3)); + await Promise.resolve(); + return (als.getStore() as any)?.tenant; + }) + ]); + out.concurrent = [resA, resB]; + out.outsideAfter = als.getStore() === undefined; + + console.log(JSON.stringify(out)); +} +run(); +"#; + + let bundled = slice_cas::strip_typescript_and_normalize(script, true); + let bc = compile_source_to_bytecode(&bundled); + let mut iso = SliceIsolate::spawn( + "wave3-als-context", + 1, + CapabilityToken::pure_compute(), + 10_000_000, + 16 * 1024 * 1024, + ); + let m = iso.execute_bytecode(&bc, None).unwrap(); + let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); + + assert_eq!(out["timerAwait"], "ctx-timer"); + assert_eq!(out["externalAwait"], "ctx-external"); + assert_eq!( + out["thenChain"], + serde_json::json!(["ctx-chain", "ctx-chain"]) + ); + assert_eq!(out["concurrent"], serde_json::json!(["A", "B"])); + assert_eq!(out["outsideAfter"], true); +} + +#[test] +fn test_wave3_timer_handles_ref_unref_hasref_refresh_and_primitive_coercion() { + let script = r#" +async function run() { + const out: Record = {}; + + const t = setTimeout(() => {}, 1000); + out.typeofTimeout = typeof t; + out.initialHasRef = t.hasRef(); + out.unrefReturnsSelf = t.unref() === t; + out.afterUnref = t.hasRef(); + out.refReturnsSelf = t.ref() === t; + out.afterRef = t.hasRef(); + out.refreshReturnsSelf = t.refresh() === t; + out.coercedPositive = (+t) > 0 && Number(t) === t.valueOf(); + clearTimeout(t); + + const iv = setInterval(() => {}, 1000); + out.typeofInterval = typeof iv; + clearInterval(+iv); + + const im = setImmediate(() => {}); + out.typeofImmediate = typeof im; + clearImmediate(im); + + // Schedule an unref'd 60-second timer that must NOT block event loop exit + let unrefFired = false; + setTimeout(() => { unrefFired = true; }, 60_000).unref(); + + // Schedule a ref'd 5ms timer that DOES run before exit + let refFired = false; + await new Promise((resolve) => { + setTimeout(() => { + refFired = true; + resolve(); + }, 5); + }); + out.refFired = refFired; + out.unrefFired = unrefFired; + + console.log(JSON.stringify(out)); +} +run(); +"#; + + let bundled = slice_cas::strip_typescript_and_normalize(script, true); + let bc = compile_source_to_bytecode(&bundled); + let mut iso = SliceIsolate::spawn( + "wave3-timer-handles", + 1, + CapabilityToken::pure_compute(), + 10_000_000, + 16 * 1024 * 1024, + ); + let start = std::time::Instant::now(); + let m = iso.execute_bytecode(&bc, None).unwrap(); + assert!( + start.elapsed().as_secs() < 5, + "Unref'd 60s timer should not keep event loop alive" + ); + let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); + + assert_eq!(out["typeofTimeout"], "object"); + assert_eq!(out["initialHasRef"], true); + assert_eq!(out["unrefReturnsSelf"], true); + assert_eq!(out["afterUnref"], false); + assert_eq!(out["refReturnsSelf"], true); + assert_eq!(out["afterRef"], true); + assert_eq!(out["refreshReturnsSelf"], true); + assert_eq!(out["coercedPositive"], true); + assert_eq!(out["typeofInterval"], "object"); + assert_eq!(out["typeofImmediate"], "object"); + assert_eq!(out["refFired"], true); + assert_eq!(out["unrefFired"], false); +} + +#[test] +fn test_wave3_intl_locales_timezones_scientific_numbers_collator_plural_segmenter() { + let script = r#" +const out: Record = {}; + +// 1. NumberFormat: scientific notation >= 1e21 and locale separators / currency +out.sci1e21 = (1e21).toLocaleString("en-US"); +out.deCurrency = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(1234.5); +out.deDecimal = (1234567.89).toLocaleString("de-DE"); + +// 2. DateTimeFormat: IANA timezones, locale patterns, dateStyle/timeStyle, RangeError on invalid TZ +out.tokyoTime = new Intl.DateTimeFormat("en-US", { + timeZone: "Asia/Tokyo", + hour: "2-digit", + minute: "2-digit", + hour12: false +}).format(new Date(0)); +out.deDate = new Intl.DateTimeFormat("de-DE", { + timeZone: "UTC", + year: "numeric", + month: "2-digit", + day: "2-digit" +}).format(new Date(0)); +out.deLocaleStr = new Date(0).toLocaleString("de-DE", { timeZone: "UTC" }); +out.enMedShort = new Date(0).toLocaleString("en-US", { + dateStyle: "medium", + timeStyle: "short", + timeZone: "UTC" +}); +let invalidTzThrewRange = false; +try { + new Intl.DateTimeFormat("en-US", { timeZone: "Mars/Phobos" }); +} catch (e: any) { + invalidTzThrewRange = e instanceof RangeError; +} +out.invalidTzThrewRange = invalidTzThrewRange; + +// 3. PluralRules: CLDR Arabic, Russian, English ordinal +const prAr = new Intl.PluralRules("ar"); +out.arPlurals = [prAr.select(0), prAr.select(1), prAr.select(2), prAr.select(3), prAr.select(11), prAr.select(100)]; +const prRu = new Intl.PluralRules("ru"); +out.ruPlurals = [prRu.select(1), prRu.select(2), prRu.select(5), prRu.select(21)]; +const prEnOrd = new Intl.PluralRules("en", { type: "ordinal" }); +out.enOrdinals = [prEnOrd.select(1), prEnOrd.select(2), prEnOrd.select(3), prEnOrd.select(4), prEnOrd.select(11)]; + +// 4. Collator: Unicode diacritic / umlaut sorting & sensitivity +out.deSorted = ["b", "a", "ä", "z"].sort(new Intl.Collator("de").compare); +out.baseSensitivityEq = new Intl.Collator("de", { sensitivity: "base" }).compare("a", "ä") === 0; + +// 5. Segmenter: UAX #29 grapheme clusters (emoji + skin-tone modifier, CRLF, flag pair) +out.graphemes = [...new Intl.Segmenter("en", { granularity: "grapheme" }).segment("a👍🏽é\r\n🇺🇸")].map((s: any) => s.segment); + +console.log(JSON.stringify(out)); +"#; + + let bundled = slice_cas::strip_typescript_and_normalize(script, true); + let bc = compile_source_to_bytecode(&bundled); + let mut iso = SliceIsolate::spawn( + "wave3-intl", + 1, + CapabilityToken::pure_compute(), + 10_000_000, + 16 * 1024 * 1024, + ); + let m = iso.execute_bytecode(&bc, None).unwrap(); + let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); + + assert_eq!(out["sci1e21"], "1,000,000,000,000,000,000,000"); + assert_eq!(out["deCurrency"], "1.234,50\u{00a0}€"); + assert_eq!(out["deDecimal"], "1.234.567,89"); + assert_eq!(out["tokyoTime"], "09:00"); + assert_eq!(out["deDate"], "01.01.1970"); + assert_eq!(out["deLocaleStr"], "1.1.1970, 00:00:00"); + assert_eq!(out["enMedShort"], "Jan 1, 1970, 12:00 AM"); + assert_eq!(out["invalidTzThrewRange"], true); + assert_eq!( + out["arPlurals"], + serde_json::json!(["zero", "one", "two", "few", "many", "other"]) + ); + assert_eq!( + out["ruPlurals"], + serde_json::json!(["one", "few", "many", "one"]) + ); + assert_eq!( + out["enOrdinals"], + serde_json::json!(["one", "two", "few", "other", "other"]) + ); + assert_eq!(out["deSorted"], serde_json::json!(["a", "ä", "b", "z"])); + assert_eq!(out["baseSensitivityEq"], true); + assert_eq!( + out["graphemes"], + serde_json::json!(["a", "👍🏽", "é", "\r\n", "🇺🇸"]) + ); +} + +#[test] +fn test_wave3_crypto_rsa_x25519_dsa_and_targeted_node_web_apis() { + let script = r#" +import crypto from "node:crypto"; +import util from "node:util"; +import url from "node:url"; +import { EventEmitter } from "node:events"; + +const out: Record = {}; + +// 1. Issue #58: RSA-2048, X25519, DSA keygen, DER sizes, RSA-SHA256 sign/verify, invalid key type +const rsaKeys = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); +out.rsaKeyTypes = [rsaKeys.publicKey.asymmetricKeyType, rsaKeys.privateKey.asymmetricKeyType]; + +const rsaDer = crypto.generateKeyPairSync("rsa", { + modulusLength: 2048, + publicKeyEncoding: { type: "spki", format: "der" }, + privateKeyEncoding: { type: "pkcs8", format: "der" } +}); +out.rsaSpkiLen = rsaDer.publicKey.length; +const signer = crypto.createSign("RSA-SHA256"); +signer.update("hello rsa"); +const rsaSig = signer.sign(rsaDer.privateKey); +out.rsaSigLen = rsaSig.length; +out.rsaVerifyOk = crypto.createVerify("RSA-SHA256").update("hello rsa").verify(rsaDer.publicKey, rsaSig); +out.rsaVerifyBad = crypto.createVerify("RSA-SHA256").update("tampered").verify(rsaDer.publicKey, rsaSig); + +const x25519Keys = crypto.generateKeyPairSync("x25519"); +out.x25519Type = x25519Keys.publicKey.asymmetricKeyType; + +const dsaKeys = crypto.generateKeyPairSync("dsa", { modulusLength: 2048, divisorLength: 256 }); +out.dsaType = dsaKeys.publicKey.asymmetricKeyType; + +try { + crypto.generateKeyPairSync("no-such-type" as any); +} catch (e: any) { + out.invalidKeyCode = e.code; + out.invalidKeyIsTypeErr = e instanceof TypeError; +} + +// 2. Issue #59: util.inspect depth, Map, Set, Error, and util.format("%s", Map) +out.inspectDepth0 = util.inspect({ a: { b: { c: 1 } } }, { depth: 0 }); +out.inspectMap = util.inspect(new Map([[1, { a: 1 }]])); +out.inspectSet = util.inspect(new Set([1, "a"])); +out.formatMap = util.format("%s", new Map([[1, 2]])); + +// 3. Issue #59: Buffer#indexOf / lastIndexOf / includes & utf16le +const bSearch = Buffer.from("abcabc"); +out.bufIndexOfStr = bSearch.indexOf("ca"); +out.bufLastIndexOfStr = bSearch.lastIndexOf("ab"); +out.bufIncludes = bSearch.includes("b"); +out.bufIndexOfBuf = bSearch.indexOf(Buffer.from("c")); +out.bufIndexOfByte = bSearch.indexOf(0x62); +out.bufUtf16Len = Buffer.from("ab", "utf16le").length; + +// 4. Issue #59: url.pathToFileURL percent-encoding & fileURLToPath roundtrip +const fileUrl = url.pathToFileURL("/tmp/a b#c?d%e.txt"); +out.fileUrlHref = fileUrl.href; +out.fileUrlRoundtrip = url.fileURLToPath(fileUrl); + +// 5. Issue #59: EventEmitter newListener and removeListener events +const ee = new EventEmitter(); +const eeLog: string[] = []; +ee.on("newListener", (ev: string) => eeLog.push("new:" + ev)); +ee.on("removeListener", (ev: string) => eeLog.push("rm:" + ev)); +const fn = () => {}; +ee.on("data", fn); +ee.off("data", fn); +out.eeLog = eeLog; + +// 6. Issue #59: crypto.createHash.copy() +const h1 = crypto.createHash("sha256").update("hello "); +const h2 = h1.copy(); +h1.update("world"); +h2.update("slice"); +out.hashCopyDistinct = h1.digest("hex") !== h2.digest("hex"); +out.hashCopyMatchesFull = h2.digest !== undefined && + crypto.createHash("sha256").update("hello slice").digest("hex") === + crypto.createHash("sha256").update("hello ").copy().update("slice").digest("hex"); + +// 7. Issue #59: ArrayBuffer.prototype.transfer / transferToFixedLength / detached +const ab = new ArrayBuffer(8); +new Uint8Array(ab).set([1, 2, 3, 4]); +const ab2 = (ab as any).transfer(16); +out.abDetachedAfter = (ab as any).detached === true && ab.byteLength === 0; +out.ab2LenAndData = [ab2.byteLength, new Uint8Array(ab2)[0], new Uint8Array(ab2)[3]]; +const ab3 = ab2.transferToFixedLength(4); +out.ab3Len = ab3.byteLength; + +console.log(JSON.stringify(out)); +"#; + + let bundled = slice_cas::strip_typescript_and_normalize(script, true); + let bc = compile_source_to_bytecode(&bundled); + let mut iso = SliceIsolate::spawn( + "wave3-crypto-and-apis", + 1, + CapabilityToken::pure_compute(), + 10_000_000, + 16 * 1024 * 1024, + ); + let m = iso.execute_bytecode(&bc, None).unwrap(); + let out: serde_json::Value = serde_json::from_str(&m.stdout[0]).unwrap(); + + assert_eq!(out["rsaKeyTypes"], serde_json::json!(["rsa", "rsa"])); + assert_eq!(out["rsaSpkiLen"], 294); + assert_eq!(out["rsaSigLen"], 256); + assert_eq!(out["rsaVerifyOk"], true); + assert_eq!(out["rsaVerifyBad"], false); + assert_eq!(out["x25519Type"], "x25519"); + assert_eq!(out["dsaType"], "dsa"); + assert_eq!(out["invalidKeyCode"], "ERR_INVALID_ARG_VALUE"); + assert_eq!(out["invalidKeyIsTypeErr"], true); + assert_eq!(out["inspectDepth0"], "{ a: [Object] }"); + assert_eq!(out["inspectMap"], "Map(1) { 1 => { a: 1 } }"); + assert_eq!(out["inspectSet"], "Set(2) { 1, 'a' }"); + assert_eq!(out["formatMap"], "Map(1) { 1 => 2 }"); + assert_eq!(out["bufIndexOfStr"], 2); + assert_eq!(out["bufLastIndexOfStr"], 3); + assert_eq!(out["bufIncludes"], true); + assert_eq!(out["bufIndexOfBuf"], 2); + assert_eq!(out["bufIndexOfByte"], 1); + assert_eq!(out["bufUtf16Len"], 4); + assert_eq!(out["fileUrlHref"], "file:///tmp/a%20b%23c%3Fd%25e.txt"); + assert_eq!(out["fileUrlRoundtrip"], "/tmp/a b#c?d%e.txt"); + assert_eq!( + out["eeLog"], + serde_json::json!(["new:removeListener", "new:data", "rm:data"]) + ); + assert_eq!(out["hashCopyDistinct"], true); + assert_eq!(out["hashCopyMatchesFull"], true); + assert_eq!(out["abDetachedAfter"], true); + assert_eq!(out["ab2LenAndData"], serde_json::json!([16, 1, 4])); + assert_eq!(out["ab3Len"], 4); +} diff --git a/crates/slice-engine/tests/web_primitives_and_case_studies_tests.rs b/crates/slice-engine/tests/web_primitives_and_case_studies_tests.rs index 6e724f2..52d794d 100644 --- a/crates/slice-engine/tests/web_primitives_and_case_studies_tests.rs +++ b/crates/slice-engine/tests/web_primitives_and_case_studies_tests.rs @@ -414,7 +414,10 @@ fn test_sveltekit_whatwg_opaque_url_signal_and_async_stream_response() { assert_eq!(u_a.href, "a:"); assert!(can_parse_whatwg_url("a:", None)); assert!(can_parse_whatwg_url("about:blank", None)); - assert!(can_parse_whatwg_url("data:text/plain;base64,SGVsbG8=", None)); + assert!(can_parse_whatwg_url( + "data:text/plain;base64,SGVsbG8=", + None + )); assert!(!can_parse_whatwg_url("http:foo", None)); // 2. JS `new URL("a:")`, `Request.prototype.signal`, and async `ReadableStream` `Response` body @@ -471,5 +474,8 @@ fn test_sveltekit_whatwg_opaque_url_signal_and_async_stream_response() { assert_eq!(res["canParseA"], true); assert_eq!(res["abortListenerOk"], true); assert_eq!(res["text"], "chunk-1:chunk-2"); - assert_eq!(res["cookies"], serde_json::json!(["a=1; Path=/", "b=2; Path=/"])); + assert_eq!( + res["cookies"], + serde_json::json!(["a=1; Path=/", "b=2; Path=/"]) + ); } diff --git a/docs/general/00_index.md b/docs/general/00_index.md index 6c48708..e2430d0 100644 --- a/docs/general/00_index.md +++ b/docs/general/00_index.md @@ -1,6 +1,6 @@ -# The Slice (Nexus-JS) Developer Handbook (`v0.10.10`) +# The Slice (Nexus-JS) Developer Handbook (`v0.10.11`) -Welcome to the complete developer handbook for **Slice (Nexus-JS)** (`v0.10.10`) — a microVM-grade JavaScript and TypeScript runtime, compiler, HTTP server, and AI sandbox engineered in Rust. +Welcome to the complete developer handbook for **Slice (Nexus-JS)** (`v0.10.11`) — a microVM-grade JavaScript and TypeScript runtime, compiler, HTTP server, and AI sandbox engineered in Rust. Whether you are building a high-throughput full-stack web service, packaging a CLI tool into a single zero-dependency executable, running 1,000 untrusted customer plugins on a single machine, or executing LLM-generated TypeScript inside an AI coding agent, this handbook walks you through every feature, CLI command, API, security capability, and migration pattern from the perspective of an application developer. diff --git a/docs/general/01_getting_started_and_cli.md b/docs/general/01_getting_started_and_cli.md index 5507bd5..6fdc054 100644 --- a/docs/general/01_getting_started_and_cli.md +++ b/docs/general/01_getting_started_and_cli.md @@ -1,6 +1,6 @@ # Chapter 01: Installation, Upgrading, Quickstart, `slice.toml` & Complete CLI Reference -This chapter is your complete day-one guide to installing, upgrading, configuring, and operating **Slice (Nexus-JS)** (`v0.10.10`). By the end of this chapter, you will know how to install and update Slice on any operating system, scaffold a new TypeScript project, configure your `slice.toml` manifest and `.env` vault, run live development with `< 3 ms` `--watch` reloads, use the interactive `slice repl` shell, and master all 13 CLI commands. +This chapter is your complete day-one guide to installing, upgrading, configuring, and operating **Slice (Nexus-JS)** (`v0.10.11`). By the end of this chapter, you will know how to install and update Slice on any operating system, scaffold a new TypeScript project, configure your `slice.toml` manifest and `.env` vault, run live development with `< 3 ms` `--watch` reloads, use the interactive `slice repl` shell, and master all 13 CLI commands. --- @@ -545,7 +545,7 @@ Launches an interactive **SES-Locked TypeScript/JavaScript Compartment Shell** w **Example REPL Session:** ```text $ slice repl -Slice (Nexus-JS) v0.10.10 Interactive SES-Locked Compartment Shell +Slice (Nexus-JS) v0.10.11 Interactive SES-Locked Compartment Shell Commands: :help, :metrics, :caps, :vars, :reset, :quit slice(ses)> const price: number = 250 * 4; => 1000 diff --git a/docs/general/COMPATIBILITY.md b/docs/general/COMPATIBILITY.md index 2f4840a..9f26853 100644 --- a/docs/general/COMPATIBILITY.md +++ b/docs/general/COMPATIBILITY.md @@ -26,7 +26,7 @@ All WinterTC globals are available in every isolate out of the box. Under the ho | **Events & Signals** | `Event`, `CustomEvent`, `EventTarget`, `AbortController`, `AbortSignal` | **100% Supported** | Listener registration (`once`, `passive`, `signal`), `AbortSignal.abort()`, `AbortSignal.timeout(ms)`, `AbortSignal.any(signals)`, and `DOMException`. | | **Timers & Microtasks** | `setTimeout`, `clearTimeout`, `setInterval`, `clearInterval`, `setImmediate`, `clearImmediate`, `queueMicrotask`, `process.nextTick` | **100% Supported** | $O(1)$ Slab-Allocated Hierarchical Timer Wheel with strict priority ordering (`sync -> process.nextTick -> Promise.then / queueMicrotask -> setImmediate -> setTimeout(0)`), deterministic virtual time-warp (`0 ns` wall-clock wait during cassette tests), and real non-blocking concurrency on live sockets. | | **Cloning & Diagnostics** | `structuredClone`, `performance.now()`, `console.*` (`log`, `info`, `warn`, `error`, `debug`, `table`, `time`, `timeLog`, `timeEnd`, `group`, `groupCollapsed`, `groupEnd`, `dir`, `dirxml`, `count`, `countReset`, `assert`, `trace`, `clear`) | **100% Supported** | Graph-preserving cyclic `structuredClone` (`Map`, `Set`, `Date`, `RegExp`, `ArrayBuffer`, `Uint8Array`, `Error`, `transfer` list) and full WHATWG `console.*` specification routed through the Outbound Egress Secret DLP Firewall (with deterministic elapsed timing under `--deterministic`). | -| **Internationalization & WinterTC Globals** | `Intl` (`DateTimeFormat`, `NumberFormat`, `Collator`, `PluralRules`, `Segmenter`, `getCanonicalLocales`, `supportedValuesOf`), `navigator`, `location` | **100% Supported** | Zero-ICU-bloat deterministic `Intl` fast-path shard (`18_intl.js`) supporting `Date.prototype.toLocale*`, `Number.prototype.toLocaleString` (`decimal`, `currency`, `percent`, `unit`, `formatToParts`), `String.prototype.localeCompare`, `PluralRules` (`cardinal`, `ordinal`), `Segmenter` (`grapheme`, `word`, `sentence`), plus WinterTC `navigator` (`userAgent: "Slice-NexusJS/0.10.10"`, `hardwareConcurrency`, `language`, `languages`) and `location`. | +| **Internationalization & WinterTC Globals** | `Intl` (`DateTimeFormat`, `NumberFormat`, `Collator`, `PluralRules`, `Segmenter`, `getCanonicalLocales`, `supportedValuesOf`), `navigator`, `location` | **100% Supported** | Zero-ICU-bloat deterministic `Intl` fast-path shard (`18_intl.js`) supporting `Date.prototype.toLocale*`, `Number.prototype.toLocaleString` (`decimal`, `currency`, `percent`, `unit`, `formatToParts`), `String.prototype.localeCompare`, `PluralRules` (`cardinal`, `ordinal`), `Segmenter` (`grapheme`, `word`, `sentence`), plus WinterTC `navigator` (`userAgent: "Slice-NexusJS/0.10.11"`, `hardwareConcurrency`, `language`, `languages`) and `location`. | | **JSX / TSX & Edge SSR** | Native `.tsx` / `.jsx` compilation + `slice:jsx` (`react/jsx-runtime`, `preact/jsx-runtime`, `hono/jsx`) | **100% Supported** | Native Rust Oxc JSX/TSX compiler (`runtime: automatic`) paired with a built-in zero-dependency SSR engine (`renderToString`, `jsx`, `jsxs`, `jsxDEV`, `Fragment`, `createElement`/`h`, `raw`) featuring automatic HTML & attribute XSS escaping, void tag handling, and camelCase `style` object serialization. | --- diff --git a/docs/guides/README.md b/docs/guides/README.md index 7c63928..0d07331 100644 --- a/docs/guides/README.md +++ b/docs/guides/README.md @@ -1,6 +1,6 @@ # Slice (Nexus-JS) — Developer How-To Guides (`docs/guides/`) -This directory contains practical step-by-step developer guides, production deployment how-tos, and ecosystem integration recipes for Slice (`v0.10.10`): +This directory contains practical step-by-step developer guides, production deployment how-tos, and ecosystem integration recipes for Slice (`v0.10.11`): ## Available Guides diff --git a/docs/system/00_index.md b/docs/system/00_index.md index 5a7b304..7cdf824 100644 --- a/docs/system/00_index.md +++ b/docs/system/00_index.md @@ -1,4 +1,4 @@ -# Slice (Nexus-JS): System Architecture & Internal Specification Index (`v0.10.10`) +# Slice (Nexus-JS): System Architecture & Internal Specification Index (`v0.10.11`) Welcome to the **Slice (Nexus-JS)** System Architecture and Internal Specification (`docs/system/`). Engineered in pure Rust (`edition = 2021`, `opt-level = 3`, `lto = "fat"`, `codegen-units = 1`, `panic = "abort"`), Slice replaces the legacy POSIX + monolithic V8/JSC assumptions of Node.js, Deno, and Bun with four orthogonal, tightly integrated Rust crates: @@ -21,7 +21,7 @@ Welcome to the **Slice (Nexus-JS)** System Architecture and Internal Specificati | **[`05_wasm_workers_and_kernel_io.md`](./05_wasm_workers_and_kernel_io.md)** | Pure-Rust WebAssembly (`wasmi` `v2.0.0`, `GLOBAL_WASM_MODULE_CACHE`, 5-Ring WASM Cage), Capability-Attenuated MicroVM Web Workers & `node:worker_threads` (`IDLE_WORKER_POOL`), Direct Kernel Completion Rings (`io_uring` & `IOCP`), & OS-Native `notify` File Watcher | `crates/slice-engine/src/{wasm,workers}.rs`, `crates/slice-io/src/lib.rs`, `crates/slice-cli/src/config_and_watch.rs` | | **[`06_edge_kv_ai_sandbox_and_mcp.md`](./06_edge_kv_ai_sandbox_and_mcp.md)** | 16-Way Sharded `Slice.kv` (`EDGE_KV_SLAB`), Multi-Tenant `--tenant-dir` Atomic Hot-Swap, SplitMix64 `--deterministic` Replay, AI Agent "Code Mode" (`Slice.evalSandbox`, `< 5 us` `Slice.checkpoint`/`restore`), Time-Travel `slice test`, & Built-In MCP Server (`slice mcp`) | `crates/slice-engine/src/state_and_kv.rs`, `crates/slice-cli/src/{test_runner,mcp_and_repl}.rs` | | **[`07_production_tooling_guide.md`](./07_production_tooling_guide.md)** | Production CLI Reference, Unified 4-Layer Configuration System (`slice.toml`, Inline `// @slice-...`, `SLICE_*` Env Vars, CLI Flags), Docker & Kubernetes Deployment Patterns, and Multi-Tenant Operations | `crates/slice-cli/src/{main,config_and_watch}.rs`, `crates/slice-sandbox/src/lib.rs` | -| **[`08_benchmarks_and_comparisons.md`](./08_benchmarks_and_comparisons.md)** | Complete 4-Runtime Empirical Benchmark Suite (Slice `v0.10.10` vs Node.js `v25.8.1`, Deno `v2.7.5`, and Bun `v1.3.10`) Across All 31 Applications, Framework Suites & Case Studies | `benches/`, `tests/apps/`, `tests/frameworks/`, `tests/case_studies/` | +| **[`08_benchmarks_and_comparisons.md`](./08_benchmarks_and_comparisons.md)** | Complete 4-Runtime Empirical Benchmark Suite (Slice `v0.10.11` vs Node.js `v25.8.1`, Deno `v2.7.5`, and Bun `v1.3.10`) Across All 31 Applications, Framework Suites & Case Studies | `benches/`, `tests/apps/`, `tests/frameworks/`, `tests/case_studies/` | | **[`09_research_deep_dive.md`](./09_research_deep_dive.md)** | Foundational Systems Research Paper: Breaking the JS/TS Cold-Start, Memory Density, and Multi-Tenant Security Wall | Architectural Research Blueprint | | **[`vendor/boa_engine/SLICE_PATCH.md`](../../vendor/boa_engine/SLICE_PATCH.md)** | `SLICEBC1` Precompiled `CodeBlock` Binary Serializer/Deserializer & Deferred Function Span Architecture | `vendor/boa_engine/src/{slice_precompile.rs,lib.rs,vm/opcode/call/mod.rs}` | @@ -31,7 +31,7 @@ Welcome to the **Slice (Nexus-JS)** System Architecture and Internal Specificati ``` +---------------------------------------------------------------------------------------------------+ -| Slice (Nexus-JS) v0.10.10 Host | +| Slice (Nexus-JS) v0.10.11 Host | | | | +---------------------------------------------------------------------------------------------+ | | | slice-sandbox: Zero-Trust OCap, SES & Hardware Boundary | | diff --git a/docs/system/07_production_tooling_guide.md b/docs/system/07_production_tooling_guide.md index bdc8e11..e53d5d3 100644 --- a/docs/system/07_production_tooling_guide.md +++ b/docs/system/07_production_tooling_guide.md @@ -2,7 +2,7 @@ ## 1. Overview of the Production Toolchain -Slice `v0.10.10` provides a complete developer and production deployment workflow packaged inside a single self-contained native Rust executable (`slice`, embedding the **Oxc** TypeScript compiler, transitive `node_modules` bundler, **Boa** ES2024+ VM, and **Slice** Zero-Stat CAS + Tier-0/Tier-2 engine): +Slice `v0.10.11` provides a complete developer and production deployment workflow packaged inside a single self-contained native Rust executable (`slice`, embedding the **Oxc** TypeScript compiler, transitive `node_modules` bundler, **Boa** ES2024+ VM, and **Slice** Zero-Stat CAS + Tier-0/Tier-2 engine): 1. **Project Initialization & Policy Configuration (`slice init` & `slice.toml`)** 2. **Zero-Stat Content-Addressed Packaging (`slice pack` for single files or full `package.json` + `node_modules` folders)** diff --git a/scripts/install.ps1 b/scripts/install.ps1 index ba7a1d1..b11a652 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -16,6 +16,6 @@ if (-not (Test-Path $ReleaseExe)) { $DestExe = Join-Path $InstallDir "slice.exe" Copy-Item -Force $ReleaseExe $DestExe -Write-Host "Installed Slice v0.10.10 to $DestExe" +Write-Host "Installed Slice v0.10.11 to $DestExe" & $DestExe info diff --git a/scripts/install.sh b/scripts/install.sh index 818aa72..a40390e 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -9,13 +9,13 @@ INSTALL_DIR="${HOME}/.slice/bin" mkdir -p "$INSTALL_DIR" if [ ! -f "$ROOT_DIR/target/release/slice" ]; then - echo "Compiling Slice v0.10.10 release binary..." + echo "Compiling Slice v0.10.11 release binary..." cargo build --release fi cp -f "$ROOT_DIR/target/release/slice" "$INSTALL_DIR/slice" chmod +x "$INSTALL_DIR/slice" -echo "Installed Slice v0.10.10 to $INSTALL_DIR/slice" +echo "Installed Slice v0.10.11 to $INSTALL_DIR/slice" "$INSTALL_DIR/slice" info diff --git a/scripts/package_release.ps1 b/scripts/package_release.ps1 index 2ad74f3..a6255a3 100644 --- a/scripts/package_release.ps1 +++ b/scripts/package_release.ps1 @@ -6,7 +6,7 @@ $ErrorActionPreference = "Stop" $RootDir = Split-Path -Parent $PSScriptRoot Set-Location $RootDir -Write-Host "[1/4] Building Slice v0.10.10 Release Binary (LTO=fat, opt-level=3)..." +Write-Host "[1/4] Building Slice v0.10.11 Release Binary (LTO=fat, opt-level=3)..." cargo build --release $DistDir = Join-Path $RootDir "dist" diff --git a/scripts/run_benchmarks.ps1 b/scripts/run_benchmarks.ps1 index ead3140..2b92c61 100644 --- a/scripts/run_benchmarks.ps1 +++ b/scripts/run_benchmarks.ps1 @@ -15,7 +15,7 @@ $CargoToml = Get-Content (Join-Path $RootDir "Cargo.toml") -Raw if ($CargoToml -match '(?m)^\[workspace\.package\]\s*\r?\nversion\s*=\s*"([^"]+)"') { $Version = $Matches[1] } else { - $Version = "0.10.10" + $Version = "0.10.11" } try { diff --git a/tests/README.md b/tests/README.md index 933056d..9f0ed4f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,7 +6,7 @@ This directory (`tests/`) contains a reproducible Linux `x86_64` Docker benchmar ## Latest Runtimes Installed in Docker ([`tests/Dockerfile`](./Dockerfile)) -- **Slice (`v0.10.10` — `SLICEBC\x01` Precompiled `CodeBlock` CAS Default):** Hybrid architecture combining **Oxc** (`v0.154.0` production Rust TypeScript compiler + AST ESM-to-CJS module bundler with deferred function module spans (`0x11` tag) + `.wasm` zero-stat module bundler + full `package.json` `"exports"` resolver + static barrel tree-shaker), **Boa (`boa_engine` v0.22 + [`vendor/boa_engine/SLICE_PATCH.md`](../vendor/boa_engine/SLICE_PATCH.md))** full ECMAScript VM with default `SLICEBC\x01` precompiled `Gc` + global `Scope` binary payloads (zero runtime `boa_parser` / `ByteCompiler` overhead) and pre-fused `node:*` built-in shards, thread-local pre-warmed context pool (`BOA_CONTEXT_POOL`), pure-Rust **WebAssembly (`wasmi` v2.0.0)** engine with `GLOBAL_WASM_MODULE_CACHE` and 5-Ring CPU fuel & linear memory cages, native Rust fast-path intrinsics (`SemVer`, `SHA-256`/`SHA-384`/`SHA-512`, `HMAC-SHA256`/`HMAC-SHA512`, `Base64URL`, in-memory `VFS` slab cache, WinterTC `URL`/`URLPattern`/`URLSearchParams`/`Headers`/`Request`/`Response`/`ReadableStream`/`TransformStream`/`CompressionStream`/`DecompressionStream`/`TextEncoder`/`TextDecoder`/`crypto.subtle`/`Blob`/`File`/`FormData`/`structuredClone`/`EventTarget`/`AbortSignal`/`WebAssembly`, real `Uint8Array`-backed `Buffer`, `node:*` Core Tier-1 modules including `node:async_hooks` and `node:zlib`, `Slice.streamSSE` / `Response.sse`, OCap-guarded outbound HTTP/1.1 & HTTPS TLS 1.3 `fetch()` with Keep-Alive pooling, hop-by-hop redirect guard, Cloud Metadata SSRF Shield, and Egress DLP, built-in Time-Travel `slice test` runner, OS-native `notify` (`v8.2`) `< 5 ms` `--watch`, and Auto-DLP `.env`), and **Slice Zero-Stat CAS + `--static` BLAKE3 `ETag` Static Server + Tier-0/Tier-2 fast paths**. +- **Slice (`v0.10.11` — `SLICEBC\x01` Precompiled `CodeBlock` CAS Default):** Hybrid architecture combining **Oxc** (`v0.154.0` production Rust TypeScript compiler + AST ESM-to-CJS module bundler with deferred function module spans (`0x11` tag) + `.wasm` zero-stat module bundler + full `package.json` `"exports"` resolver + static barrel tree-shaker), **Boa (`boa_engine` v0.22 + [`vendor/boa_engine/SLICE_PATCH.md`](../vendor/boa_engine/SLICE_PATCH.md))** full ECMAScript VM with default `SLICEBC\x01` precompiled `Gc` + global `Scope` binary payloads (zero runtime `boa_parser` / `ByteCompiler` overhead) and pre-fused `node:*` built-in shards, thread-local pre-warmed context pool (`BOA_CONTEXT_POOL`), pure-Rust **WebAssembly (`wasmi` v2.0.0)** engine with `GLOBAL_WASM_MODULE_CACHE` and 5-Ring CPU fuel & linear memory cages, native Rust fast-path intrinsics (`SemVer`, `SHA-256`/`SHA-384`/`SHA-512`, `HMAC-SHA256`/`HMAC-SHA512`, `Base64URL`, in-memory `VFS` slab cache, WinterTC `URL`/`URLPattern`/`URLSearchParams`/`Headers`/`Request`/`Response`/`ReadableStream`/`TransformStream`/`CompressionStream`/`DecompressionStream`/`TextEncoder`/`TextDecoder`/`crypto.subtle`/`Blob`/`File`/`FormData`/`structuredClone`/`EventTarget`/`AbortSignal`/`WebAssembly`, real `Uint8Array`-backed `Buffer`, `node:*` Core Tier-1 modules including `node:async_hooks` and `node:zlib`, `Slice.streamSSE` / `Response.sse`, OCap-guarded outbound HTTP/1.1 & HTTPS TLS 1.3 `fetch()` with Keep-Alive pooling, hop-by-hop redirect guard, Cloud Metadata SSRF Shield, and Egress DLP, built-in Time-Travel `slice test` runner, OS-native `notify` (`v8.2`) `< 5 ms` `--watch`, and Auto-DLP `.env`), and **Slice Zero-Stat CAS + `--static` BLAKE3 `ETag` Static Server + Tier-0/Tier-2 fast paths**. - **Node.js (`v27.0.0-alpha` — Absolute Latest Release):** Dynamically resolved at container build time from `https://nodejs.org/dist/index.json` (`.[0].version`). - **Bun (`v1.4.4` — Absolute Latest Release):** Installed via official `https://bun.sh/install`. - **Deno (`v2.9.8` — Absolute Latest Release):** Installed via official `https://deno.land/install.sh`. diff --git a/tests/run_real_stack_benchmarks.sh b/tests/run_real_stack_benchmarks.sh index 2810e29..f6d3eab 100644 --- a/tests/run_real_stack_benchmarks.sh +++ b/tests/run_real_stack_benchmarks.sh @@ -44,7 +44,7 @@ BENCH_TAGS="${1:-${SLICE_BENCH_TAGS:-all}}" METRICS_JSONL="${SLICE_BENCH_JSONL:-/tmp/slice_bench_metrics.jsonl}" rm -f "$METRICS_JSONL" -SLICE_VERSION="${SLICE_VERSION:-0.10.10}" +SLICE_VERSION="${SLICE_VERSION:-0.10.11}" SLICE_GIT_COMMIT="${SLICE_GIT_COMMIT:-$(git -C "$ROOT_DIR" rev-parse --short HEAD 2>/dev/null || echo "abdbf89")}" SLICE_BENCH_TS_UTC="${SLICE_BENCH_TS_UTC:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}" CURRENT_APP_IDX="" diff --git a/tests/scripts/generate_bench_report.mjs b/tests/scripts/generate_bench_report.mjs index f6ab75d..2d94088 100644 --- a/tests/scripts/generate_bench_report.mjs +++ b/tests/scripts/generate_bench_report.mjs @@ -330,12 +330,12 @@ function parseJsonlMetrics(jsonlPath, previousReport) { return { metadata: { - version: metaRec.version || previousReport?.metadata?.version || "0.10.10", + version: metaRec.version || previousReport?.metadata?.version || "0.10.11", commit: metaRec.commit || previousReport?.metadata?.commit || "abdbf89", timestampUtc: metaRec.timestampUtc || new Date().toISOString(), environment: metaRec.environment || previousReport?.metadata?.environment || "Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)", runtimes: { - slice: `v${metaRec.version || "0.10.10"}`, + slice: `v${metaRec.version || "0.10.11"}`, bun: metaRec.bunVersion || previousReport?.metadata?.runtimes?.bun || "v1.4.4", deno: metaRec.denoVersion || previousReport?.metadata?.runtimes?.deno || "v2.9.8", node: metaRec.nodeVersion || previousReport?.metadata?.runtimes?.node || "v27.0.0-alpha" diff --git a/vendor/boa_engine/src/builtins/array_buffer/mod.rs b/vendor/boa_engine/src/builtins/array_buffer/mod.rs index 5b8c5a1..6f5d974 100644 --- a/vendor/boa_engine/src/builtins/array_buffer/mod.rs +++ b/vendor/boa_engine/src/builtins/array_buffer/mod.rs @@ -346,7 +346,6 @@ impl IntrinsicObject for ArrayBuffer { .name(js_string!("get maxByteLength")) .build(); - #[cfg(feature = "experimental")] let get_detached = BuiltInBuilder::callable(realm, Self::get_detached) .name(js_string!("get detached")) .build(); @@ -385,7 +384,6 @@ impl IntrinsicObject for ArrayBuffer { Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ); - #[cfg(feature = "experimental")] let builder = builder .accessor( js_string!("detached"), @@ -572,7 +570,6 @@ impl ArrayBuffer { /// [`get ArrayBuffer.prototype.detached`][spec]. /// /// [spec]: https://tc39.es/proposal-arraybuffer-transfer/#sec-get-arraybuffer.prototype.detached - #[cfg(feature = "experimental")] fn get_detached( this: &JsValue, _args: &[JsValue], @@ -750,7 +747,6 @@ impl ArrayBuffer { /// /// [transfer]: https://tc39.es/proposal-arraybuffer-transfer/#sec-arraybuffer.prototype.transfer /// [transferFL]: https://tc39.es/proposal-arraybuffer-transfer/#sec-arraybuffer.prototype.transfertofixedlength - #[cfg(feature = "experimental")] fn transfer( this: &JsValue, args: &[JsValue],