refactor: reorganize client transport and extension internals

- Split client, native, remote, serve, markdown, and SDK internals into focused packages with direct imports.
- Move local and remote transport framing/protocol helpers behind clearer module boundaries.
- Break up the extension injected DOM logic into a separate content dispatch bundle and dedicated content modules.
- Add explicit client handling for passive remote discovery without noisy PQ warnings.
- Keep behavior covered with updated unit, integration, and extension tests.
This commit is contained in:
2026-06-13 23:31:24 +02:00
parent fd5447cbb9
commit 076914e5b7
88 changed files with 7491 additions and 5228 deletions
+22 -13
View File
@@ -7,8 +7,13 @@ client targeting the browser it came from, so ``tab.close()`` routes correctly.
"""
from __future__ import annotations
from typing import Any, Protocol, cast
from browser_cli.models import Group, Tab
class _FactoryClient(Protocol):
_key: str | None
class FactoryMixin:
"""Turn raw response dicts into bound ``Tab``/``Group`` objects.
@@ -16,7 +21,7 @@ class FactoryMixin:
``_browser``/``_remote``/``_key`` and being constructible via ``type(self)``.
"""
def _make_tab(
def tab_from(
self,
data: dict,
*,
@@ -34,20 +39,22 @@ class FactoryMixin:
group_id=data.get("groupId") or None,
browser=browser_name,
)
tab._browser = self if browser_profile is None else type(self)(
client = cast(_FactoryClient, self)
tab._browser = self if browser_profile is None else cast(Any, type(self))(
browser=browser_profile,
remote=browser_remote,
key=self._key,
key=client._key,
_command_sender=getattr(self, "_command_sender", None),
)
return tab
def _require_tab(self, data, error: str) -> Tab:
def require_tab_response(self, data, error: str) -> Tab:
"""Build a bound Tab from a tab-shaped response, or raise ``RuntimeError(error)``."""
if not isinstance(data, dict) or "id" not in data:
raise RuntimeError(error)
return self._make_tab(data)
return self.tab_from(data)
def _make_group(
def group_from(
self,
data: dict,
*,
@@ -63,25 +70,27 @@ class FactoryMixin:
tab_count=data.get("tabCount", 0),
browser=browser_name,
)
group._browser = self if browser_profile is None else type(self)(
client = cast(_FactoryClient, self)
group._browser = self if browser_profile is None else cast(Any, type(self))(
browser=browser_profile,
remote=browser_remote,
key=self._key,
key=client._key,
_command_sender=getattr(self, "_command_sender", None),
)
return group
def _make_tab_for(self, data: dict, target) -> Tab:
def tab_from_target(self, data: dict, target) -> Tab:
"""Build a Tab, tagging it with *target* in multi-browser mode (``None`` = local)."""
return self._make_tab(
return self.tab_from(
data,
browser_profile=target.profile if target else None,
browser_name=target.display_name if target else None,
browser_remote=target.remote if target else None,
)
def _make_group_for(self, data: dict, target) -> Group:
def group_from_target(self, data: dict, target) -> Group:
"""Build a Group, tagging it with *target* in multi-browser mode (``None`` = local)."""
return self._make_group(
return self.group_from(
data,
browser_profile=target.profile if target else None,
browser_name=target.display_name if target else None,
@@ -89,6 +98,6 @@ class FactoryMixin:
)
@staticmethod
def _tag_browser(item: dict, target) -> dict:
def tag_browser(item: dict, target) -> dict:
"""Return *item* as-is locally, or with a ``browser`` key in multi-browser mode."""
return item if target is None else {**item, "browser": target.display_name}