/// Response for GetLibraries — list of registered component libraries (without component details)
/// Response for GetVirtualViewStates - lists all tracked VirtualViews and their internal state
/// Get layout of nodes inside a specific VirtualView's DOM (by nested dom_id or parent node_id)
/// Component arguments as typed JSON values, e.g. {"label": "Click", "disabled": true, "count": 42}.
/// The `AZ_DEBUG` environment variable should be set to a port number (e.g., `AZ_DEBUG=8765`).
pub fn handle_event_request(body: &str, request_tx: &Arc<Mutex<spmc::Sender<DebugRequest>>>) -> String {
fn fail_with(message: impl Into<String>, expected: impl Into<String>, actual: impl Into<String>) -> Self {
Self { passed: false, message: message.into(), actual: Some(actual), expected: Some(expected) }
format!("[E2E] assertion FAILED: {} (expected={:?}, actual={:?})", result.message, result.expected, result.actual),
if let Some(bad) = reject_unknown_params("assert_node_count", params, &["selector", "expected"]) {
None => return AssertionResult::fail("assert_node_count: missing or invalid 'expected' (number)"),
if let Some(bad) = reject_unknown_params("assert_window_state", params, &["property", "expected", "tolerance"]) {
if let Some(bad) = reject_unknown_params("assert_layout", params, &["selector", "property", "expected", "tolerance"]) {
if let Some(bad) = reject_unknown_params("assert_css", params, &["selector", "property", "expected"]) {
fn navigate_json_path<'a>(root: &'a serde_json::Value, path: &str) -> Option<&'a serde_json::Value> {
if let Some(bad) = reject_unknown_params("assert_scroll", params, &["selector", "x", "y", "tolerance"]) {
if let Some(bad) = reject_unknown_params("assert_screenshot", params, &["reference", "threshold", "max_diff_ratio", "save_actual"]) {
if let Some(bad) = reject_unknown_params("assert_changed", params, &["vs", "min_damage_rects", "threshold", "which", "frame"]) {
if let Some(bad) = reject_unknown_params("assert_damage_covers_changes", params, &["vs", "threshold", "slack_px", "which", "frame"]) {
if let Some(bad) = reject_unknown_params("assert_damage_incremental", params, &["max_area_ratio", "which", "frame"]) {
if let Some(bad) = reject_unknown_params("assert_idle_stable", params, &["vs", "threshold", "max_frames"]) {
if depth_cap && !params.get("allow_depth_cap").and_then(serde_json::Value::as_bool).unwrap_or(false) {
if lw.text_edit_manager.multi_cursor.is_none() && lw.text_edit_manager.blink.blink_timer_active {
if let Some(bad) = reject_unknown_params("assert_state_machines_idle", params, &["damage"]) {
"pure projection — `A11ySnapshot::build()` is called on demand from `LayoutWindow::build_a11y_snapshot(&self)` and the result is handed straight to the platform bridge; nothing is stored on the window between calls. There is no state that could latch, so there is no invariant to assert. The a11y state that CAN latch lives in `a11y_manager`, which is checked",
if let Some(bad) = reject_unknown_params("assert_manager_invariants", params, &["managers", "cross", "min_checked"]) {
if lw.gpu_state_manager.scrollbar_fade_active && lw.scroll_manager.state_keys().is_empty() {
if info.max_scroll_y > 0.0 && th <= vis_h + TOL && (ty < vis_y - TOL || ty + th > vis_y + vis_h + TOL)
if info.max_scroll_x > 0.0 && tw <= vis_w + TOL && (tx < vis_x - TOL || tx + tw > vis_x + vis_w + TOL)
"pure projection, rebuilt from the DOM on every call and never stored — see the matching entry in UNOBSERVABLE_MANAGERS. Fingerprinting it would hash a value that is recomputed rather than remembered, so it would report a change on every frame and mean nothing",
fn fp_gesture(m: &azul_layout::managers::gesture::GestureAndDragManager) -> ManagerFingerprint {
fn fp_text_edit(m: &azul_layout::managers::text_edit::TextEditManager) -> ManagerFingerprint {
fn fp_text_input(m: &azul_layout::managers::text_input::TextInputManager) -> ManagerFingerprint {
fn fp_undo_redo(m: &azul_layout::managers::undo_redo::UndoRedoManager) -> ManagerFingerprint {
fn fp_virtual_view(m: &azul_layout::managers::virtual_view::VirtualViewManager) -> ManagerFingerprint {
fn fp_gpu_state(m: &azul_layout::managers::gpu_state::GpuStateManager) -> ManagerFingerprint {
fn fp_permission(m: &azul_layout::managers::permission::PermissionManager) -> ManagerFingerprint {
fn fp_clipboard(m: &azul_layout::managers::clipboard::ClipboardManager) -> ManagerFingerprint {
fn fp_file_drop(m: &azul_layout::managers::file_drop::FileDropManager) -> ManagerFingerprint {
fn fp_biometric(m: &azul_layout::managers::biometric::BiometricManager) -> ManagerFingerprint {
if let Some(bad) = reject_unknown_params("assert_composition", params, &["expect", "fixpoint", "damage"]) {
if let Some(bad) = reject_unknown_params("assert_damage_sound", params, &["vs", "threshold", "slack_px", "max_overpaint_ratio", "forbid_full", "pixel_identity"]) {
} else if op == "commit_undo_snapshot" || op == "undo_app_state" || op == "redo_app_state" {
let steps_passed = cont.current_step_results.iter().filter(|s| s.status == "pass").count();
let steps_failed = cont.current_step_results.iter().filter(|s| s.status == "fail").count();
format!("[E2E] Resuming continuation: test {}, step {}", continuation.test_idx, continuation.step_idx),
fn build_component_registry(map_ref: &azul_core::xml::ComponentMap) -> ComponentRegistryResponse {
let universal_attributes: Vec<ComponentAttributeInfo> = if def.source == ComponentSource::Builtin {
fn styled_dom_to_render_tree(styled_dom: &azul_core::styled_dom::StyledDom) -> serde_json::Value {
/// Convert a single `serde_json::Value` to a `ComponentDefaultValue` given the expected type.
serde_json::Value::String(s) => Ok(ComponentDefaultValue::String(AzString::from(s.as_str()))),
serde_json::Value::String(s) => Ok(ComponentDefaultValue::String(AzString::from(s.as_str()))),
fn build_exported_code(language: &str, map_ref: &azul_core::xml::ComponentMap) -> Result<ExportedCodeResponse, String> {
warnings.push("No user-defined component libraries to export. Generated minimal scaffold.".to_string());
/// Convert a `ComponentFieldType` to a JSON-friendly string for the debug protocol (legacy flat format).
ComponentFieldType::Callback(signature) => format!("Callback({})", signature.return_type.as_str()),
ComponentFieldType::OptionType(inner) => format!("Option<{}>", field_type_to_string(inner.as_ref())),
ComponentFieldType::VecType(inner) => format!("Vec<{}>", field_type_to_string(inner.as_ref())),
ComponentFieldType::CssProperty => StructuredFieldType::Primitive { name: "CssProperty".to_string() },
ComponentFieldType::ImageRef => StructuredFieldType::Primitive { name: "ImageRef".to_string() },
ComponentFieldType::FontRef => StructuredFieldType::Primitive { name: "FontRef".to_string() },
ComponentFieldType::StyledDom => StructuredFieldType::Primitive { name: "StyledDom".to_string() },
fn default_value_to_opt_string(dv: &azul_core::xml::OptionComponentDefaultValue) -> Option<String> {
ComponentDefaultValue::ComponentInstance(ci) => format!("instance:{}", ci.component.as_str()),
fn parse_field_type_from_string(s: &str) -> Result<azul_core::xml::ComponentFieldType, String> {
use azul_core::xml::{ComponentFieldType, ComponentCallbackSignature, ComponentCallbackArgVec, ComponentFieldTypeBox};
.ok_or_else(|| format!("Invalid Option type syntax '{}', expected 'Option<InnerType>'", other))?;
/// Validate a field name: must be a valid identifier (alphanumeric + underscore, not starting with digit).
"Field name '{}' contains invalid characters (only alphanumeric, underscore, hyphen allowed)",
fn validate_exported_field(field: &ExportedDataField) -> Result<azul_core::xml::ComponentDataField, String> {
fn validate_exported_fields(fields: &[ExportedDataField]) -> Result<Vec<azul_core::xml::ComponentDataField>, String> {
component_structs.push_str(&format!("/// Data model for the {} component\n", comp.display_name));
layout_body.push_str(" .with_child(Dom::create_text_do_not_use_without_block_level_wrapper(\"Hello from Azul!\"))\n");
render_fns.push_str(&format!("AzDom render_{}(const {}Data* data) {{\n", comp.name, struct_name));
render_fns.push_str(&format!(" return AzDom_createDiv(); /* TODO: implement {} */\n", comp.display_name));
"AzUpdate {slot_name}(AzRefAny* data, AzCallbackInfo* info) {{\n /* TODO: implement {slot_name} */\n return AzUpdate_DoNothing;\n}}\n\n",
layout_body.push_str(" AzDom_addChild(&body, AzDom_createTextDoNotUseWithoutBlockLevelWrapper(AZ_STR(\"Hello from Azul!\")));\n");
layout_body.push_str(&format!(" AzDom_addChild(&body, render_{}(&{}_data));\n", comp.name, comp.name));
AzRefAny data = AzRefAny_newC((AzGlVoidPtrConst){{ .ptr = NULL }}, 0, 1, 0, data_type, NULL, 0, 0);
render_fns.push_str(&format!("Dom render_{}(const {}Data& data) {{\n", comp.name, struct_name));
layout_body.push_str(" body.add_child(Dom::create_text_do_not_use_without_block_level_wrapper(String(\"Hello from Azul!\")));\n");
layout_body.push_str(&format!(" body.add_child(render_{}({}Data{{}}));\n", comp.name, struct_name));
layout_body.push_str(" body = body.with_child(Dom.create_text_do_not_use_without_block_level_wrapper(\"Hello from Azul!\"))\n");
layout_body.push_str(&format!(" body = body.with_child(render_{}({}()))\n", comp.name, class_name));
"img" | "image" => vec![("src", "String"), ("alt", "String"), ("width", "String"), ("height", "String")],
"button" => vec![("type", "String"), ("name", "String"), ("value", "String"), ("disabled", "bool")],
"script" => vec![("src", "String"), ("type", "String"), ("defer", "bool"), ("async", "bool")],
"video" | "audio" => vec![("src", "String"), ("controls", "bool"), ("autoplay", "bool"), ("loop", "bool")],
"meter" => vec![("value", "String"), ("min", "String"), ("max", "String"), ("low", "String"), ("high", "String")],
.unwrap_or_else(|| node_id.map_or_else(|| "<nothing>".to_string(), |n| format!("node {n}")));
azul_layout::solver3::display_list::DisplayListItem::Text { glyphs, font_size_px, color, clip_rect, .. } => {
azul_layout::solver3::display_list::DisplayListItem::TextLayout { bounds, font_size_px, color, .. } => {
azul_layout::solver3::display_list::DisplayListItem::Border { bounds, colors, widths, .. } => {
azul_css::css::CssPropertyValue::Exact(c) => Some(format!("#{:02x}{:02x}{:02x}{:02x}", c.inner.r, c.inner.g, c.inner.b, c.inner.a)),
azul_css::css::CssPropertyValue::Exact(c) => Some(format!("#{:02x}{:02x}{:02x}{:02x}", c.inner.r, c.inner.g, c.inner.b, c.inner.a)),
azul_css::css::CssPropertyValue::Exact(c) => Some(format!("#{:02x}{:02x}{:02x}{:02x}", c.inner.r, c.inner.g, c.inner.b, c.inner.a)),
azul_css::css::CssPropertyValue::Exact(c) => Some(format!("#{:02x}{:02x}{:02x}{:02x}", c.inner.r, c.inner.g, c.inner.b, c.inner.a)),
azul_css::css::CssPropertyValue::Exact(c) => Some(c.inner.to_pixels_internal(0.0, 16.0, 16.0)),
azul_css::css::CssPropertyValue::Exact(c) => Some(c.inner.to_pixels_internal(0.0, 16.0, 16.0)),
azul_css::css::CssPropertyValue::Exact(c) => Some(c.inner.to_pixels_internal(0.0, 16.0, 16.0)),
azul_css::css::CssPropertyValue::Exact(c) => Some(c.inner.to_pixels_internal(0.0, 16.0, 16.0)),
azul_layout::solver3::display_list::DisplayListItem::ScrollBar { bounds, color, orientation, .. } => {
"track:({:.1},{:.1},{:.1}x{:.1}) thumb:({:.1},{:.1},{:.1}x{:.1}) track_color:#{:02x}{:02x}{:02x}{:02x} thumb_color:#{:02x}{:02x}{:02x}{:02x} opacity_key:{} transform_key:{}",
info.thumb_transform_key.as_ref().map(|k| format!("{}", k.id)).unwrap_or_else(|| "none".to_string()),
azul_layout::solver3::display_list::DisplayListItem::PushStackingContext { z_index, bounds } => {
use azul_core::events::{ScrollIntoViewBehavior, ScrollIntoViewOptions, ScrollLogicalPosition};
format!("Getting scrollbar info for node_id={:?}, selector={:?}, text={:?}, orientation={:?}",
"No virtualized view found: specify dom_id or node_id. Use get_virtual_view_states to list all virtualized views.",
let (is_dragging, drag_type, description) = if let Some(drag_ctx) = gesture_manager.get_drag_context() {
format!("Debug key down: {} (shift={}, ctrl={}, alt={})", key, modifiers.shift, modifiers.ctrl, modifiers.alt),
let mut pressed_keys: alloc::vec::Vec<VirtualKeyCode> = new_state.keyboard_state.pressed_virtual_keycodes.iter().copied().collect();
new_state.keyboard_state.pressed_virtual_keycodes = VirtualKeyCodeVec::from_vec(pressed_keys);
format!("Debug key up: {} (shift={}, ctrl={}, alt={})", key, modifiers.shift, modifiers.ctrl, modifiers.alt),
let mut pressed_keys: alloc::vec::Vec<VirtualKeyCode> = new_state.keyboard_state.pressed_virtual_keycodes.iter().copied().collect();
new_state.keyboard_state.pressed_virtual_keycodes = VirtualKeyCodeVec::from_vec(pressed_keys);
let response = if let (Some(cursor), Some(mc)) = (tem.get_primary_cursor(), tem.multi_cursor.as_ref()) {
send_err(request, format!("Parent node {} not found (total nodes: {})", parent_id, node_count));
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let was_update = if let Some(existing) = libs.iter_mut().find(|l| l.name.as_str() == lib_name) {
"Library '{}' not found or is not exportable (builtin/compiled libraries cannot be exported)", name
send_err(request, "No exportable component libraries found. Only user-defined libraries can be exported.");
use azul_core::xml::{ComponentLibrary, ComponentDefVec, ComponentLibraryVec, ComponentDataModelVec};
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
use azul_core::xml::{ComponentDef, ComponentId, ComponentSource, ComponentLibraryVec, ComponentDataModel, ComponentDataFieldVec};
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut comps = core::mem::replace(&mut lib.components, Vec::new().into()).into_library_owned_vec();
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut comps = core::mem::replace(&mut lib.components, Vec::new().into()).into_library_owned_vec();
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut comps = core::mem::replace(&mut lib.components, Vec::new().into()).into_library_owned_vec();
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut comps = core::mem::replace(&mut lib.components, Vec::new().into()).into_library_owned_vec();
let mut libs = core::mem::replace(&mut map_guard.libraries, empty_libs).into_library_owned_vec();
let mut comps = core::mem::replace(&mut lib.components, Vec::new().into()).into_library_owned_vec();