From a5c4e8b6fd5308defb7d960fe3dde4a77476824d Mon Sep 17 00:00:00 2001 From: ldm0 Date: Thu, 10 Sep 2026 11:59:17 +0800 Subject: [PATCH] fix: construct native navigation events in their target realm Use intrinsic constructors in the Navigation or history entry target realm for navigate, currententrychange, navigatesuccess, navigateerror and dispose. Create history entries in their owning window even when methods are borrowed from another window. Preserve native navigate event trust and construct navigation abort controllers and trusted abort events through intrinsics. Add three Browser integration tests covering 14 cross-window, joint-history and cross-document flows, including throwing public constructor getters. The same fixture matches Chrome in all 14 flows. Validation: cargo fmt --all; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo nextest run --no-fail-fast (17918 passed, 13 skipped). The 334-case WPT comparison gains two passing cases and two subtests without regressions; passed ledger is 9107. --- .../wpt-cross-current/failed-cases.txt | 1 - .../wpt-cross-current/passed-cases.txt | 2 + .../runtime/navigation_event_realms.html | 143 ++++++++++++++++++ moli-core/tests/history_event_realms.rs | 95 ++++++++++++ .../src/context_bootstrap/history_mutation.rs | 2 + .../navigation_activation.rs | 1 + .../src/context_bootstrap/navigation_entry.rs | 6 + .../context_bootstrap/navigation_events.rs | 107 +++++++------ .../navigation_mutation/local.rs | 2 + .../navigation_mutation/same_document.rs | 4 + .../context_bootstrap/navigation_restore.rs | 2 + .../src/context_bootstrap/navigation_seed.rs | 3 + .../src/native_bridge/abort/event.rs | 21 +-- 13 files changed, 319 insertions(+), 70 deletions(-) create mode 100644 moli-core/tests/fixtures/runtime/navigation_event_realms.html create mode 100644 moli-core/tests/history_event_realms.rs diff --git a/moli-benchmark/wpt-cross-current/failed-cases.txt b/moli-benchmark/wpt-cross-current/failed-cases.txt index 61cbcd52d7..903cd39062 100644 --- a/moli-benchmark/wpt-cross-current/failed-cases.txt +++ b/moli-benchmark/wpt-cross-current/failed-cases.txt @@ -2993,7 +2993,6 @@ navigation-api/focus-reset/autofocus.html?delayed-checkpoint navigation-api/focus-reset/autofocus.html?same-checkpoint navigation-api/navigate-event/defer/tentative/defer-same-document.html navigation-api/navigate-event/intercept-detach-multiple.html -navigation-api/navigate-event/navigation-traverseTo-in-iframe-same-document-preventDefault.html navigation-api/navigate-event/traverseTo-detach.html navigation-api/navigation-methods/reload-service-worker-fetch-event.html navigation-api/navigation-methods/return-value/back-204-205-download.html diff --git a/moli-benchmark/wpt-cross-current/passed-cases.txt b/moli-benchmark/wpt-cross-current/passed-cases.txt index 3b105623fb..9007a92eef 100644 --- a/moli-benchmark/wpt-cross-current/passed-cases.txt +++ b/moli-benchmark/wpt-cross-current/passed-cases.txt @@ -3758,6 +3758,7 @@ dom/abort/abort-signal-any-crash.html dom/abort/abort-signal-timeout.html dom/abort/crashtests/any-on-abort.html dom/abort/crashtests/timeout-close.html +dom/abort/event.any.js?moli-wpt-any=window dom/abort/reason-constructor.html dom/attributes-are-nodes.html dom/collections/HTMLCollection-as-prototype.html @@ -7891,6 +7892,7 @@ navigation-api/navigate-event/navigate-window-open.html navigation-api/navigate-event/navigatesuccess-cross-document.html navigation-api/navigate-event/navigatesuccess-same-document.html navigation-api/navigate-event/navigation-back-same-document-preventDefault.html +navigation-api/navigate-event/navigation-traverseTo-in-iframe-same-document-preventDefault.html navigation-api/navigate-event/navigation-traverseTo-same-document-preventDefault-multiple-windows.html navigation-api/navigate-event/navigation-traverseTo-top-cancels-cross-document-child.html navigation-api/navigate-event/replaceState-inside-back-handler.html diff --git a/moli-core/tests/fixtures/runtime/navigation_event_realms.html b/moli-core/tests/fixtures/runtime/navigation_event_realms.html new file mode 100644 index 0000000000..bde4dc6763 --- /dev/null +++ b/moli-core/tests/fixtures/runtime/navigation_event_realms.html @@ -0,0 +1,143 @@ + diff --git a/moli-core/tests/history_event_realms.rs b/moli-core/tests/history_event_realms.rs new file mode 100644 index 0000000000..28a75f2a0b --- /dev/null +++ b/moli-core/tests/history_event_realms.rs @@ -0,0 +1,95 @@ +use anyhow::Result; +use moli_core::runtime::{Browser, BrowserConfig}; +use moli_test_support::FixtureServer; +use serde_json::{Value, json}; +use tokio::time::Duration; +use url::Url; + +async fn navigation_events(scenario: &str, target: &str, constructors: &str) -> Result { + let markup = include_str!("fixtures/runtime/navigation_event_realms.html") + .replace("__SCENARIO__", &serde_json::to_string(scenario)?) + .replace("__TARGET__", &serde_json::to_string(target)?) + .replace("__CONSTRUCTORS__", &serde_json::to_string(constructors)?); + let server = FixtureServer::spawn().await?; + let browser = Browser::new(BrowserConfig::default())?; + let mut url = Url::parse(&server.url("/compat/child-dynamic-markup-document"))?; + url.query_pairs_mut().append_pair("markup", &markup); + let result = tokio::time::timeout(Duration::from_secs(10), async { + let mut page = browser.fetch(url.as_str()).await?; + page.evaluate_runtime_expression_with_await_async( + "finished.then(value => JSON.stringify(value))", + true, + ) + .await + }) + .await??; + let result = serde_json::from_str(result["value"].as_str().unwrap())?; + server.shutdown().await; + Ok(result) +} + +#[tokio::test(flavor = "multi_thread")] +async fn cross_window_navigation_events_use_the_target_realm_and_native_constructors() -> Result<()> +{ + for constructors in ["original", "overwritten"] { + for target in ["top", "child"] { + for scenario in ["success", "reject"] { + let events = if scenario == "success" { + json!([ + "navigate", + "currententrychange", + "navigatesuccess", + "navigate", + "currententrychange", + "dispose", + "navigatesuccess", + "currententrychange", + "navigate", + "currententrychange", + "navigatesuccess" + ]) + } else { + json!(["navigate", "currententrychange", "abort", "navigateerror"]) + }; + assert_eq!( + navigation_events(scenario, target, constructors).await?, + json!({"errors": [], "reads": 0, "events": events}), + "{scenario}/{target}/{constructors}" + ); + } + } + } + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn child_joint_history_events_use_the_parent_event_target_realm() -> Result<()> { + for constructors in ["original", "overwritten"] { + for scenario in ["joint-cancel", "joint-prune"] { + let events = if scenario == "joint-cancel" { + json!(["navigate", "abort", "navigateerror"]) + } else { + json!(["dispose", "dispose"]) + }; + assert_eq!( + navigation_events(scenario, "top", constructors).await?, + json!({"errors": [], "reads": 0, "events": events}), + "{scenario}/{constructors}" + ); + } + } + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn parent_initiated_child_navigation_constructs_events_in_the_retiring_child_realm() +-> Result<()> { + for constructors in ["original", "overwritten"] { + assert_eq!( + navigation_events("cross-document", "child", constructors).await?, + json!({"errors": [], "reads": 0, "events": ["navigate"]}), + "{constructors}" + ); + } + Ok(()) +} diff --git a/moli-renderer-v8/src/context_bootstrap/history_mutation.rs b/moli-renderer-v8/src/context_bootstrap/history_mutation.rs index e78ff9c29c..6697702f61 100644 --- a/moli-renderer-v8/src/context_bootstrap/history_mutation.rs +++ b/moli-renderer-v8/src/context_bootstrap/history_mutation.rs @@ -194,6 +194,7 @@ fn mutate_history_object<'s>( let next_navigation_index = current_navigation_index + 1; let entry = create_navigation_entry( scope, + owner, url.as_str(), state_json.as_deref(), None, @@ -218,6 +219,7 @@ fn mutate_history_object<'s>( .unwrap_or_else(|| new_navigation_entry_key().as_str().to_owned()); let entry = create_navigation_entry( scope, + owner, url.as_str(), state_json.as_deref(), None, diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_activation.rs b/moli-renderer-v8/src/context_bootstrap/navigation_activation.rs index 4346907dc5..6f5f6c4574 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_activation.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_activation.rs @@ -138,6 +138,7 @@ pub(super) fn navigation_entry_object_from_snapshot<'s>( } let entry = create_navigation_entry( scope, + owner, &snapshot.url, snapshot.history_state_json.as_deref(), snapshot.navigation_state_json.as_deref(), diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_entry.rs b/moli-renderer-v8/src/context_bootstrap/navigation_entry.rs index f97711eca3..91a368969a 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_entry.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_entry.rs @@ -172,6 +172,7 @@ pub(super) fn restore_current_navigation_entry_scroll_position<'s>( pub(super) fn create_navigation_entry<'s>( scope: &mut v8::PinScope<'s, '_>, + owner: v8::Local<'s, v8::Object>, url: &str, history_state_json: Option<&str>, navigation_state_json: Option<&str>, @@ -180,6 +181,11 @@ pub(super) fn create_navigation_entry<'s>( id: &str, key: &str, ) -> v8::Local<'s, v8::Object> { + // Borrowed cross-window methods still create entries in the owner realm. + let context = owner + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); let history_snapshot = super::navigation_serialize::parse_history_entry_state(scope, history_state_json); let navigation_snapshot = diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_events.rs b/moli-renderer-v8/src/context_bootstrap/navigation_events.rs index a939a7cd7d..05956fd945 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_events.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_events.rs @@ -726,14 +726,14 @@ pub(super) fn dispatch_navigation_currententrychange<'s>( from: Option>, navigation_type: Option<&str>, ) { - let global = scope.get_current_context().global(scope); - let Some(event_ctor) = global - .get( - scope, - v8str(scope, "NavigationCurrentEntryChangeEvent").into(), - ) - .and_then(|value| v8::Local::::try_from(value).ok()) - else { + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); + let Ok(event_ctor) = super::exposed_interfaces::ensure_intrinsic_interface_constructor( + scope, + "NavigationCurrentEntryChangeEvent", + ) else { return; }; let init = NavigationCurrentEntryChangeEventInitDeclaration { @@ -767,17 +767,13 @@ pub(super) fn dispatch_navigation_entry_dispose<'s>( scope: &mut v8::PinScope<'s, '_>, entry: v8::Local<'s, v8::Object>, ) { - let global = scope.get_current_context().global(scope); - let Some(event_ctor) = global - .get(scope, v8str(scope, "Event").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - else { + let context = entry + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); + let Some(event) = construct_original_event(scope, "dispose") else { return; }; - let Some(event) = event_ctor.new_instance(scope, &[v8str(scope, "dispose").into()]) else { - return; - }; - mark_event_trusted(scope, event); let _ = dispatch_simple_event_target_event( scope, entry, @@ -791,18 +787,13 @@ pub(super) fn dispatch_navigation_success<'s>( scope: &mut v8::PinScope<'s, '_>, navigation: v8::Local<'s, v8::Object>, ) { - let global = scope.get_current_context().global(scope); - let Some(event_ctor) = global - .get(scope, v8str(scope, "Event").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - else { + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); + let Some(event) = construct_original_event(scope, "navigatesuccess") else { return; }; - let Some(event) = event_ctor.new_instance(scope, &[v8str(scope, "navigatesuccess").into()]) - else { - return; - }; - mark_event_trusted(scope, event); let _ = dispatch_simple_event_target_event( scope, navigation, @@ -818,7 +809,15 @@ pub(super) fn dispatch_navigation_error<'s>( error: v8::Local<'s, v8::Value>, filename: &str, ) { - let global = scope.get_current_context().global(scope); + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); + let Ok(event_ctor) = + super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "ErrorEvent") + else { + return; + }; let message = error .to_string(scope) .map(|value| value.to_rust_string_lossy(scope)) @@ -833,10 +832,7 @@ pub(super) fn dispatch_navigation_error<'s>( .bind(scope) .expect("NavigationErrorEvent init declaration should bind"); let event_type = v8str(scope, "navigateerror"); - let event = global - .get(scope, v8str(scope, "ErrorEvent").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - .and_then(|ctor| ctor.new_instance(scope, &[event_type.into(), init.into()])); + let event = event_ctor.new_instance(scope, &[event_type.into(), init.into()]); let Some(event) = event else { return; }; @@ -899,12 +895,14 @@ pub(super) fn dispatch_navigation_navigate_event_with_form_data_and_outcome<'s>( form_data: Option>, source_element: Option>, ) -> NavigationDispatchOutcome<'s> { - let global = scope.get_current_context().global(scope); + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); let focus_reset_epoch = context_host_ptr_from_global_bridge(scope) .map(|host_ptr| unsafe { &*host_ptr }.focus_change_epoch()); - let Some(event_ctor) = global - .get(scope, v8str(scope, "NavigateEvent").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) + let Ok(event_ctor) = + super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "NavigateEvent") else { return NavigationDispatchOutcome::proceed(); }; @@ -938,6 +936,7 @@ pub(super) fn dispatch_navigation_navigate_event_with_form_data_and_outcome<'s>( else { return NavigationDispatchOutcome::proceed(); }; + mark_event_trusted(scope, event); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_SYNTHETIC_SLOT, false); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_FOCUS_RESET_SLOT, true); set_navigate_event_private_bool( @@ -1124,21 +1123,17 @@ fn dispatch_cross_document_navigation_navigate_event_for_window_with_type_form_d let Some(navigation) = window_navigation_for_holder(scope, owner) else { return true; }; + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); if download_request.is_some() { let _ = cancel_active_navigation_event(scope, navigation); cancel_active_intercepted_same_document_navigation(scope, navigation); } - let event_ctor = owner - .get(scope, v8str(scope, "NavigateEvent").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - .or_else(|| { - scope - .get_current_context() - .global(scope) - .get(scope, v8str(scope, "NavigateEvent").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - }); - let Some(event_ctor) = event_ctor else { + let Ok(event_ctor) = + super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "NavigateEvent") + else { return true; }; let current_href = window_location_for_holder(scope, owner) @@ -1184,6 +1179,7 @@ fn dispatch_cross_document_navigation_navigate_event_for_window_with_type_form_d else { return true; }; + mark_event_trusted(scope, event); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_SYNTHETIC_SLOT, false); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_FOCUS_RESET_SLOT, true); set_navigate_event_private_bool( @@ -1235,12 +1231,14 @@ pub(super) fn dispatch_navigation_traverse_event_with_outcome<'s>( target_index: u32, info: Option>, ) -> NavigationDispatchOutcome<'s> { - let global = scope.get_current_context().global(scope); + let context = navigation + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); let focus_reset_epoch = context_host_ptr_from_global_bridge(scope) .map(|host_ptr| unsafe { &*host_ptr }.focus_change_epoch()); - let Some(event_ctor) = global - .get(scope, v8str(scope, "NavigateEvent").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) + let Ok(event_ctor) = + super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "NavigateEvent") else { return NavigationDispatchOutcome::proceed(); }; @@ -1289,6 +1287,7 @@ pub(super) fn dispatch_navigation_traverse_event_with_outcome<'s>( else { return NavigationDispatchOutcome::proceed(); }; + mark_event_trusted(scope, event); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_SYNTHETIC_SLOT, false); set_navigate_event_private_bool(scope, event, NAVIGATE_EVENT_FOCUS_RESET_SLOT, true); set_navigate_event_private_bool( @@ -1560,10 +1559,8 @@ fn navigation_destination_entry_string_property<'s>( fn create_navigation_abort_signal<'s>( scope: &mut v8::PinScope<'s, '_>, ) -> v8::Local<'s, v8::Value> { - let global = scope.get_current_context().global(scope); - let Some(controller_ctor) = global - .get(scope, v8str(scope, "AbortController").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) + let Ok(controller_ctor) = + super::exposed_interfaces::ensure_intrinsic_interface_constructor(scope, "AbortController") else { return v8::null(scope).into(); }; diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_mutation/local.rs b/moli-renderer-v8/src/context_bootstrap/navigation_mutation/local.rs index c8cfbf2af3..788088a6ee 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_mutation/local.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_mutation/local.rs @@ -30,6 +30,7 @@ pub(crate) fn apply_local_window_location_navigation<'s>( let state = v8::null(scope).into(); let next_entry = create_navigation_entry( scope, + owner, resolved.as_str(), None, None, @@ -60,6 +61,7 @@ pub(crate) fn apply_local_window_location_navigation<'s>( .unwrap_or_else(|| new_navigation_entry_key().as_str().to_owned()); let entry = create_navigation_entry( scope, + owner, resolved.as_str(), None, None, diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_mutation/same_document.rs b/moli-renderer-v8/src/context_bootstrap/navigation_mutation/same_document.rs index 524ee9da20..44ecdaa892 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_mutation/same_document.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_mutation/same_document.rs @@ -43,6 +43,7 @@ pub(in crate::context_bootstrap) fn update_navigation_current_entry_for_same_doc set_child_joint_top_index_for_entry(scope, owner, Some(current_entry)); let next_entry = create_navigation_entry( scope, + owner, href, history_state_json.as_deref(), navigation_state_json.as_deref(), @@ -71,6 +72,7 @@ pub(in crate::context_bootstrap) fn update_navigation_current_entry_for_same_doc .unwrap_or_else(|| new_navigation_entry_key().as_str().to_owned()); let entry = create_navigation_entry( scope, + owner, href, history_state_json.as_deref(), navigation_state_json.as_deref(), @@ -135,6 +137,7 @@ pub(in crate::context_bootstrap) fn apply_navigation_navigate_same_document<'s>( } let next_entry = create_navigation_entry( scope, + owner, href, None, None, @@ -170,6 +173,7 @@ pub(in crate::context_bootstrap) fn apply_navigation_navigate_same_document<'s>( .unwrap_or_else(|| new_navigation_entry_key().as_str().to_owned()); let entry = create_navigation_entry( scope, + owner, href, None, None, diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_restore.rs b/moli-renderer-v8/src/context_bootstrap/navigation_restore.rs index 0461e1d9a4..74282f1d8b 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_restore.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_restore.rs @@ -40,6 +40,7 @@ pub(crate) fn install_navigation_bootstrap_entry_for_holder<'s>( for snapshot in &entry_seed.entries { let entry = create_navigation_entry( scope, + owner, &snapshot.url, snapshot.history_state_json.as_deref(), snapshot.navigation_state_json.as_deref(), @@ -64,6 +65,7 @@ pub(crate) fn install_navigation_bootstrap_entry_for_holder<'s>( let entry_key = NavigationHistoryEntryKey::allocate(); let entry = create_navigation_entry( scope, + owner, "about:blank", None, None, diff --git a/moli-renderer-v8/src/context_bootstrap/navigation_seed.rs b/moli-renderer-v8/src/context_bootstrap/navigation_seed.rs index 97cb9edd6f..e8253743c5 100644 --- a/moli-renderer-v8/src/context_bootstrap/navigation_seed.rs +++ b/moli-renderer-v8/src/context_bootstrap/navigation_seed.rs @@ -37,6 +37,7 @@ pub(super) fn build_history_entries_array_from_seed<'s>( for snapshot in &seed.entries { let entry = create_navigation_entry( scope, + owner, &snapshot.url, snapshot.history_state_json.as_deref(), snapshot.navigation_state_json.as_deref(), @@ -68,6 +69,7 @@ pub(super) fn build_current_navigation_entry_from_seed<'s>( let entry_key = NavigationHistoryEntryKey::allocate(); let entry = create_navigation_entry( scope, + owner, "about:blank", fallback_state_json.as_deref(), fallback_state_json.as_deref(), @@ -83,6 +85,7 @@ pub(super) fn build_current_navigation_entry_from_seed<'s>( }; let entry = create_navigation_entry( scope, + owner, &snapshot.url, snapshot.history_state_json.as_deref(), snapshot.navigation_state_json.as_deref(), diff --git a/moli-renderer-v8/src/native_bridge/abort/event.rs b/moli-renderer-v8/src/native_bridge/abort/event.rs index 097834e34f..2672363767 100644 --- a/moli-renderer-v8/src/native_bridge/abort/event.rs +++ b/moli-renderer-v8/src/native_bridge/abort/event.rs @@ -1,12 +1,11 @@ use super::{AbortDispatchSnapshot, AbortStore}; use crate::context_bootstrap::{ - EVENT_PASSIVE_SLOT, EVENT_STOP_IMMEDIATE_PROPAGATION_SLOT, event_internal_bool_flag, - set_event_internal_flag, + EVENT_PASSIVE_SLOT, EVENT_STOP_IMMEDIATE_PROPAGATION_SLOT, construct_original_event, + event_internal_bool_flag, set_event_internal_flag, }; use crate::exception_reporting::invoke_callback; use crate::host::invoke_prepared_event_callback_on_object; use crate::native_bridge::JsContextHost; -use crate::util::{v8_string, v8str}; pub(super) fn invoke_abort_algorithms<'s>( scope: &mut v8::PinScope<'s, '_>, @@ -41,17 +40,11 @@ pub(super) fn dispatch_abort<'s>( // front so listeners and `onabort` retain local `TryCatch`, structured // stderr, and no stdout pollution. let signal = local_object_in_scope(scope, signal); - let global = scope.get_current_context().global(scope); - let Some(event_ctor) = global - .get(scope, v8str(scope, "Event").into()) - .and_then(|value| v8::Local::::try_from(value).ok()) - else { - return; - }; - let Some(event_type) = v8_string(scope, "abort") else { - return; - }; - let Some(event) = event_ctor.new_instance(scope, &[event_type.into()]) else { + let context = signal + .get_creation_context(scope) + .unwrap_or_else(|| scope.get_current_context()); + let scope = &mut v8::ContextScope::new(scope, context); + let Some(event) = construct_original_event(scope, "abort") else { return; }; AbortStore::define_hidden_value(scope, event, "target", signal.into());