Metadata-Version: 2.2
Name: angdh-v8
Version: 1.0.6
Summary: Python V8 runtime with a lightweight browser DOM
License: MIT
Requires-Python: <4,>=3.9
Description-Content-Type: text/markdown

# angdh_v8

Python V8 runtime with a lightweight browser DOM.

## Install

```bash
python -m pip install angdh_v8 -i https://pypi.org/simple
```

## Public Python API

`JSContext` is keyword-only and requires `license_hash`. The maintained API
guide, handler schemas, capability configuration, and examples live in
[`docs/api/PYTHON_API.md`](docs/api/PYTHON_API.md).

`timeout` 限制最外层 V8 Task，但不能抢占同步 Python 回调；超时只能在
回调返回后报告。回调永不返回时，同一 Context 上等待的操作也不会返回，且
回调后的 JavaScript 是否继续执行不可依赖。

`add_resource()` / `load_page()` 的最终 HTTP `status` 只接受非 `bool` 的
Python `int`，范围为 `200..599`。`opaque=True` 时 JavaScript 看到的 `0` 是
Fetch 过滤结果，不是可传入的资源状态。`load_page(error=...)` 与显式
`status=...` 互斥，并在任何 ResourceBundle 或 Realm 变更前失败。

`worker_limits` 可配置 per-context/global Worker、预留 memory 与消息队列
item/serialized/transferable byte 上限；超额的 Worker constructor 或
`postMessage()` 抛出 `QuotaExceededError`。余额与峰值通过
`worker_resource_statistics()` 读取，完整字段和默认值见 API 文档。

`native_resource_limits` 为 DOM/DOMParser 及后续 native-backed 子系统提供
per-context/global byte budget、DOM node/attribute/text/input/depth 上限。超额操作在
提交对象变更前抛出 `QuotaExceededError`；`native_resource_statistics()` 返回分类账本，
`resource_statistics()` 统一返回 V8/native/Worker/host bytes 与 Realm、iframe、Worker、
socket、host callback、EventLoop 的 current/peak/created/released 生命周期余额。
WebSocket/WebSocketStream 连接按 owner Realm 隔离；导航、iframe 移除和 Context
关闭会取消旧 Realm 事件并对仍连接的 transport 恰好关闭一次。socket 快照还包含
queued/stale-drop/delegate-close-error 与 close-latency 指标。
`VideoFrame` 的 coded dimension、pixel 与单帧 RGBA bytes 分别限制为 **16384**、
**67108864**、**268435456**；持有帧及 structured-clone/encoder 临时快照进入同一
`video_frame` ledger，默认聚合上限 **536870912 bytes** 且还受 context/global cap 约束；
clone 共享 reservation，`close()`、wrapper GC 和 Context teardown 释放额度。
内存型 File System Access/OPFS 也使用有限 per-file/per-origin/per-context/global
quota；所有 truncate/seek-write/append/sync-access 扩容先预留再分配，失败不改变
bytes/cursor/mtime/usage。committed/pending native bytes 进入 `file_system` ledger，
`navigator.storage.estimate()` 返回同一 committed usage 和有效 per-origin quota。

<!-- README_PYTHON_API_CONSTRUCTOR_PARAMETERS_START -->
- `license_hash`
- `timezone`
- `width`
- `height`
- `timeout`
- `memory_limit`
- `mode`
- `dialog_handler`
- `fetch_handler`
- `file_picker_handler`
- `image_decode_handler`
- `audio_codec_handler`
- `video_codec_handler`
- `push_handler`
- `remote_playback_handler`
- `speech_synthesis_handler`
- `presentation_handler`
- `device_access_handler`
- `xr_handler`
- `gpu_handler`
- `ink_handler`
- `shared_storage_handler`
- `websocket_handler`
- `webrtc_handler`
- `browser_capabilities`
- `fetch_executor_limits`
- `worker_limits`
- `native_resource_limits`
<!-- README_PYTHON_API_CONSTRUCTOR_PARAMETERS_END -->

<!-- README_PYTHON_API_METHODS_START -->
- `dispatch_input_event(selector, event_type, options=None)`
- `dispatch_input_click(selector)`
- `navigate()`
- `set_dialog_handler(handler)`
- `set_fetch_handler(handler)`
- `dispatch_websocket_event(connection_id, event)`
- `dispatch_webrtc_event(peer_id, event)`
- `dispatch_media_session_action(action, details=None)`
- `dispatch_remote_playback_event(remote_id, event)`
- `dispatch_speech_synthesis_event(utterance_id, event)`
- `dispatch_presentation_event(connection_id, event)`
- `set_file_picker_handler(handler)`
- `set_image_decode_handler(handler)`
- `expose(callable, name=None)`
- `set_permission_state(name, state)`
- `with_devtools(port=9229, *, break_on_start=True, log_path='out.log', debugger_name=None, trace_scope='js')`
- `close()`
- `heap_statistics()`
- `worker_resource_statistics()`
- `native_resource_statistics()`
- `resource_statistics()`
- `lifecycle_profile()`
- `load_html_profile()`
- `network_log()`
- `add_network_diagnostic_entry(entry)`
- `resource_snapshot()`
- `navigation_requests()`
- `frame_document_snapshot()`
- `frame_window_snapshot()`
- `add_resource(url, body='', *, status=None, headers=None, error=None, redirect_url=None, opaque=False, delay=0)`
- `load_html(html, *, base_url='about:blank')`
- `load_page(snapshot=None, *, html=None, base_url=None, resources=None, headers=None, status=None, error=None, delay=None, parser_timer_checkpoint=None)`
- `tick(milliseconds)`
- `tick_profile(milliseconds)`
- `drain()`
- `eval(code, *, to_py=True, filename='<eval>', line_offset=0, column_offset=0)`
<!-- README_PYTHON_API_METHODS_END -->
