feat(api): add obscura-api crate with Browser + Page + Element + CookieStore (#191)

* feat(api): add obscura-api crate with Browser + Page API

Adds a Rust library crate exposing Obscura as a programmable browser:
- Browser: build with config (proxy, stealth, UA, storage_dir)
- Page: goto, url, evaluate, content
- BrowserBuilder with fluent API
- examples/basic.rs

Part of #169

* feat(api): add Element API + CookieStore + wait_for_selector

- Element: text(), attribute(), click() via JS evaluation
- CookieStore: set/get_all/get_for_url/save_to_file/load_from_file
- Page::wait_for_selector with 100ms polling
- Page::query_selector for single element lookup
- Updated examples/basic.rs with full interaction demo

Part of #169

* feat(api): add Browser::cookies() method

* refactor(api): move to obscura crate with feature flag

- Renamed obscura-api → obscura (per maintainer feedback #169)
- API enabled by default via 'api' feature flag
- Usage: cargo add obscura (default=api) or cargo add obscura --features api
- Removed separate obscura-api crate

* chore: exclude docker workflow from fork

* fix(api): make the obscura crate build, run, and document install correctly

- examples/basic.rs and the lib.rs doctest imported `obscura_api`, but the crate
  is named `obscura`, so both failed to compile. Use the real crate name.
- wait_for_selector / query_selector read the node id with `Value::as_u64`, but
  `evaluate` returns JS numbers as f64, so it was always None and every
  wait_for_selector timed out. Accept an integer or a non-negative finite float.
- restore .github/workflows/docker.yml, which the PR removed (a fork-specific
  change that should not land upstream).
- add crates/obscura/README.md with honest install instructions: the crate is not
  on crates.io, so depend on it via git (and it builds the embedded V8 from
  source). The `cargo add obscura` form does not work yet.

Verified: workspace + example build, the lib doctest passes, the example runs end
to end (goto, wait_for_selector, text, attribute), and the integration suite is
28/28 with no regressions.

---------

Co-authored-by: zhangyang-crazy-one <[email protected]>
Co-authored-by: SGavrl <[email protected]>
This commit is contained in:
authored and GitHub committed 2026-06-04 18:20:51 +00:00
1 parent a703b7ac30
commit 2e731a2ab9
12 files changed
+781 -140

No files matched your search

+8 -2
View File
@@ -167,7 +167,10 @@ pub async fn handle(
"removeNode" => Ok(json!({})),
"getBoxModel" => {
let page = ctx.get_session_page_mut(session_id).ok_or("No page")?;
let node_id = resolve_node_id(page, params)?;
let node_id = match resolve_node_id(page, params) {
Ok(nid) => nid,
Err(_) => return Ok(json!(null)),
};
let code = format!(
"(function() {{\
var el = globalThis._wrap && globalThis._wrap({0});\
@@ -202,7 +205,10 @@ pub async fn handle(
}
"getContentQuads" => {
let page = ctx.get_session_page_mut(session_id).ok_or("No page")?;
let node_id = resolve_node_id(page, params)?;
let node_id = match resolve_node_id(page, params) {
Ok(nid) => nid,
Err(_) => return Ok(json!(null)),
};
let code = format!(
"(function() {{\
var el = globalThis._wrap && globalThis._wrap({0});\