* 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]>
* feat: cookie jar persistence + storage-dir + filtering fix (clean v4)
* fix: resolve build errors, add storage_dir param throughout server chain
* fix: storage_dir end-to-end, plus two test-literal field additions
Five issues found while testing PR 114 end-to-end.
Build fixes (two test literals out of sync with new struct fields):
- crates/obscura-net/src/cookies.rs: CookieInfo literal in
test_domain_matches_subdomain_without_leading_dot was missing the
same_site and expires fields added in #170.
- crates/obscura-cli/src/main.rs: Command::Fetch literal in
matcher_still_uses_fetch_variant was missing the new storage_dir
field. Without these cargo test --workspace would not compile.
run_fetch was branching between BrowserContext::with_storage (which
hardcodes proxy=None, stealth=false, user_agent=None) and
with_options (which has no storage_dir slot), so --storage-dir +
--proxy + --stealth silently dropped the proxy and stealth flags.
Same bug SGavrl flagged on dispatch.rs in the previous round, just on
the other code path. Switched to with_storage_full which carries all
four. Verified the fetch now errors out against an invalid proxy.
run_fetch --eval short-circuited the function before
context.save_cookies() ran, so cookies set during an eval session
were never persisted to {storage_dir}/cookies.json. Moved the save
above the return.
obscura serve loaded cookies on startup but never saved them
anywhere, so a session that set cookies via Network.setCookie or
navigation dropped them on shutdown. Subscribed to Ctrl-C once in
put a single save_cookies() after the loop so both the Ctrl-C path
and the channel-closed path persist cookies. Verified end-to-end.
---------
Co-authored-by: zhangyang-crazy-one <[email protected]>
Co-authored-by: SGavrl <[email protected]>
Addresses follow-up issues from PR #44 bot review:
- Add parentId field to AXNode (walk DOM ancestors to resolve AX parent)
- Omit optional fields when empty (name, value, properties, childIds)
instead of emitting null/empty arrays, per CDP spec
- Add ax_value_boolean() and ax_value_integer() helpers for consistent
AXValue construction across all property types
- Use typed helpers throughout compute_properties() instead of inline
JSON construction
CDP spec reference: Accessibility.AXNode requires parentId as AXNodeId,
and optional fields should be absent when not applicable.
Co-authored-by: zhangyang-crazy-one <[email protected]>