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}