browser_oxide 0.1.3

Stealth headless browser engine in Rust: real HTML/CSS/DOM/JS, V8 via deno_core, own BoringSSL TLS/JA4 fingerprint, no Chromium, no CDP — for anti-bot web scraping, archival, and AI agents
Documentation
//! Navigation-pending signal — fast cross-thread flag the JS bootstrap
//! flips when `__pendingNavigation` (or any equivalent setter) is set.
//!
//! Why this exists: the navigation pipeline in `Page::navigate` runs an
//! iteration loop where each iteration does `event_loop.run_until_idle(30s)`.
//! Without this signal, when a script sets `location.href = ...` the
//! iteration still runs to its 30-second ceiling before the retry GET
//! fires — too late for sites with strict navigation-timing windows
//! (some expect the follow-up GET within a few seconds of a prior request).
//!
//! This op flips an `Arc<AtomicBool>` shared with `BrowserEventLoop`. The
//! event loop checks the flag each tick and exits early (after a brief
//! microtask tail to let in-flight `fetch().then(setCookie)` land in the
//! jar before the retry).

use deno_core::op2;
use deno_core::OpState;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

/// State stored in OpState. Cloned by `BrowserJsRuntime::nav_pending_signal`
/// so the event loop can read the flag without going through V8.
#[derive(Clone, Default)]
pub struct NavSignal(pub Arc<AtomicBool>);

impl NavSignal {
    pub fn new() -> Self {
        Self(Arc::new(AtomicBool::new(false)))
    }

    pub fn raise(&self) {
        self.0.store(true, Ordering::Relaxed);
    }

    pub fn pending(&self) -> bool {
        self.0.load(Ordering::Relaxed)
    }

    pub fn reset(&self) {
        self.0.store(false, Ordering::Relaxed);
    }
}

#[op2(fast)]
pub fn op_set_pending_nav(s: &mut OpState) {
    let s = s.borrow::<NavSignal>();
    s.raise();
}

deno_core::extension!(nav_extension, ops = [op_set_pending_nav],);