Skip to main content

bao/
lib.rs

1//! # Bao — unified library
2//!
3//! Single consumer-facing package. Full stack is **always linked**:
4//! SpiderMonkey (`bao_engine`) + servo browser (`bao_browser`) + Node/Bun API
5//! (`bun_runtime`) + CDP (`bao_cdp` / `bao_cdp_client`) + Stealth (`bao_stealth`).
6//!
7//! There are **no** Cargo product features that disable browser, CDP, stealth,
8//! or Node API. Runtime knobs (e.g. [`StealthProfile`], permissions) select
9//! behaviour without changing the link set.
10//!
11//! ## Quick start
12//!
13//! ```no_run
14//! use bao::{BaoConfig, BaoRuntime, PageConfig, StealthProfile};
15//!
16//! fn main() -> Result<(), bao::BrowserError> {
17//!     let runtime = BaoRuntime::new(BaoConfig::default())?;
18//!     let _pool = runtime.page_pool();
19//!     let _ = StealthProfile::firefox_default();
20//!     let _ = PageConfig::default();
21//!     Ok(())
22//! }
23//! ```
24//!
25//! ## CDP (Playwright-style)
26//!
27//! ```no_run
28//! use bao::Browser;
29//!
30//! fn main() -> Result<(), bao::ConnectError> {
31//!     let browser = Browser::connect("memory://bao")?;
32//!     let _ = browser;
33//!     Ok(())
34//! }
35//! ```
36//!
37//! @trace REQ-LIB-001 [level:library]
38//! @trace REQ-LIB-003 [level:library]
39//! @trace REQ-BRW-003 [level:library]
40
41#![allow(unused_imports)]
42
43// @trace STUB-INVENTORY: product never depends on or force-links bao_native_stubs
44// Residual symbols: product_process_exit / product_buffered_reader /
45// product_native_symbols / bun_* true owners — never reintroduce link_noop.
46
47// ── Namespaced full surfaces (always available) ───────────────────────────
48
49/// Browser runtime, PagePool, PageHandle, permissions, screenshots.
50pub mod browser {
51    pub use bao_browser::*;
52}
53
54/// SpiderMonkey engine surface (via `bao_engine` re-exports).
55pub mod engine {
56    pub use bao_engine::*;
57}
58
59/// Node.js / Bun API compatibility runtime (`bun_runtime` crate).
60///
61/// Note: this module also defines a `BaoRuntime` type that is **not** the same
62/// as the top-level [`crate::BaoRuntime`] (browser coordinator). Prefer the
63/// top-level name for embedding; use `bao::runtime::` for Node/Bun host setup.
64pub mod runtime {
65    pub use bun_runtime::*;
66}
67
68/// CDP server / router / WS codec surface.
69pub mod cdp {
70    pub use bao_cdp::*;
71}
72
73/// Playwright-style CDP client (`Browser::connect`, Page, …).
74pub mod cdp_client {
75    pub use bao_cdp_client::*;
76}
77
78/// Anti-fingerprint profiles and engine (runtime configuration).
79pub mod stealth {
80    pub use bao_stealth::*;
81}
82
83/// Event loop (epoll tick shared with FilePoll).
84pub mod uloop {
85    pub use bao_uloop::*;
86}
87
88// ── Stable top-level re-exports (consumer happy path) ─────────────────────
89// Prefer these over depending on internal crate paths.
90
91// Browser embedding (primary BaoRuntime)
92pub use bao_browser::{
93    BaoConfig, BaoRuntime, BrowserConfig, BrowserError, PageConfig, PageHandle, PagePool,
94    PageState, Permission, PermissionDenied, PermissionGuard, ScreenshotFormat, encode_image,
95    run_browser,
96};
97
98// Stealth (always linked; enable via profile at runtime)
99pub use bao_stealth::{
100    AudioProfile, BehaviorConfig, BehaviorSimulator, CanvasNoise, FontConfig, Http2Fingerprint,
101    NavigatorProfile, ScreenProfile, StealthEngine, StealthHooks, StealthProfile,
102    StealthTlsWireConfig, TlsFingerprint, WebGLProfile,
103};
104
105// CDP client entry
106pub use bao_cdp_client::{
107    Browser, CdpError, ConnectError, Connection, ConnectionConfig, Cookie, DeviceDescriptor,
108    Viewport, WaitUntilState,
109};
110
111// CDP server types commonly needed alongside the client
112pub use bao_cdp::{BackendKind, CdpRouter, CdpServer, CdpSession};
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    /// Packaging contract: the public crate always declares the full stack.
119    /// This drives the shipped `Cargo.toml`, not a hard-coded shadow list alone —
120    /// every required dep name must appear in the real manifest text.
121    #[test]
122    fn cargo_toml_always_depends_on_full_stack() {
123        let manifest = include_str!("../Cargo.toml");
124        let required = [
125            "bao_browser",
126            "bao_engine",
127            "bun_runtime",
128            "bao_cdp",
129            "bao_cdp_client",
130            "bao_stealth",
131            "bao_uloop",
132        ];
133        for dep in required {
134            assert!(
135                manifest.contains(dep),
136                "public package must always depend on {dep} (unified full stack)"
137            );
138        }
139        // Product must never depend on or feature-gate stubs (ignore comment lines).
140        let code_lines = || {
141            manifest.lines().filter(|l| {
142                let t = l.trim_start();
143                !t.is_empty() && !t.starts_with('#')
144            })
145        };
146        assert!(
147            code_lines().all(|l| !l.contains("native-stubs")),
148            "native-stubs feature must be removed (product never force-links stubs)"
149        );
150        assert!(
151            code_lines().all(|l| !l.contains("bao_native_stubs")),
152            "bao must not declare dep on bao_native_stubs (even optional)"
153        );
154        assert!(
155            manifest.contains("default = []"),
156            "product has no capability features; default remains empty"
157        );
158    }
159
160    /// Real API path: Stealth is linked and constructs a default profile.
161    #[test]
162    fn stealth_profile_firefox_default_is_available() {
163        let profile = StealthProfile::firefox_default();
164        let engine = StealthEngine::new(profile);
165        // Touch fields that exist on the real shipped type.
166        let _tls = engine.tls_config();
167        let _nav = engine.navigator();
168        assert!(std::mem::size_of_val(engine.profile()) > 0);
169    }
170
171    /// Real API path: browser config types are constructible without spinning servo
172    /// (full Servo init is env-heavy; config path still exercises shipped constructors).
173    #[test]
174    fn browser_config_defaults_construct() {
175        let cfg = BaoConfig::default();
176        let page = PageConfig::default();
177        let _ = (cfg, page, ScreenshotFormat::Png);
178        // Type identity: top-level BaoRuntime is the browser coordinator.
179        let _name = std::any::type_name::<BaoRuntime>();
180        assert!(_name.contains("BaoRuntime"));
181    }
182
183    /// CDP client Browser type is part of the public surface (connect needs runtime).
184    #[test]
185    fn cdp_browser_type_is_reexported() {
186        let name = std::any::type_name::<Browser>();
187        assert!(name.contains("Browser"));
188        let _ = std::any::type_name::<ConnectError>();
189        let _ = std::any::type_name::<CdpRouter>();
190        let _ = std::any::type_name::<CdpServer>();
191    }
192
193    /// Namespaced modules expose the same always-on crates.
194    #[test]
195    fn namespaced_modules_resolve_core_types() {
196        let _ = std::any::type_name::<browser::PagePool>();
197        let _ = std::any::type_name::<stealth::StealthEngine>();
198        let _ = std::any::type_name::<cdp_client::Browser>();
199        let _ = std::any::type_name::<cdp::CdpRouter>();
200    }
201}