"""The Juggler client: the one copy every invisible_ wrapper drives the engine with.

| module | what it does |
|---|---|
| `protocol.py` | GENERATED by `python -m invisible_core.juggler._gen_protocol` from the `Protocol.js` inside the shipped binary. It is tied to the engine like the seal, which is why it lives in the same package: a new engine moves both in one release. The wrapper's e2e runs `--check` against the pinned engine |
| `connection.py` | the pipe to Juggler. JSON delimited by a zero byte; fd 3/4 on POSIX, inheritable HANDLEs on Windows |
| `lifecycle.py` | frame tree, navigations, the four load states |
| `injected.py` | loads `injected.js` into the UTILITY world and calls it: selectors and actionability; and, for `execute_script`, the crossings into the page's own world |
| `injected.js` | extracted from the Playwright bundle with `scripts/gen_injected_source.py`. It is not upstream: it carries the fork's stealth fixes |
| `actions.py` | the retry loop and every input action. `engine_approach` says who draws the pointer's approach: the client's cursor (Playwright) or this side (Selenium, Puppeteer) |
| `keyboard.py`, `keylayout.py` | from a key name to the four fields `Page.dispatchKeyEvent` demands |
| `_behaviour.py`, `_motion.py`, `_pacing.py` | the human rhythm: personas, paths, and the discipline every movement is delivered under, on the client's cursor and here alike |

⛔ ONE COPY, AND THAT IS THE WHOLE POINT (80-decision-log.md [D85]). Until
38.34.0 this folder lived in invisible-playwright, invisible-selenium and
invisible-puppeteer, about 13,000 lines each, and a fix reached one client and
not the others: the wrapper had five remedies the other two never got, and the
selenium copy had the one guard the wrapper lacked. What each client does its
own way is an OPTION here, not a fork: `Actions(engine_approach=...)` and
`glide_to`. (The `Actions.dialog_opened` hook and `Connection.send(abort=...)`
were options too until firefox-39, for a click whose `alert()` held the page:
the engine ends that wait itself now, inside the dispatch. [B230])

⛔ No Playwright here: the client speaks Juggler, the engine's own protocol,
and Selenium and Puppeteer use it without Playwright installed.

WHAT A CONSUMER IMPORTS, it imports from HERE or from a public module above.
`_behaviour`, `_motion`, `_pacing` and `_profile` keep their underscore - they
are this package's to rearrange - and the names the wrappers load from them are
re-exported below, which is the list `tests/test_consumer_contract.py` freezes.
"""
from . import actions, connection, injected, keyboard, keylayout, lifecycle, protocol
from ._behaviour import (
    PageActs, PointerPersona, Step, initial_pointer, landing_point,
    plan_aimless_move, plan_approach, plan_idle, plan_scroll, popup_number,
    steps_from_waypoints, tail_within,
)
from ._motion import CursorMotion
from ._pacing import (
    DONE, MIN_EVENT_INTERVAL_MS, SLEEP, Ev, Pacer, clamp_to_viewport,
    fine_timer, fit_timeline,
)
from ._profile import domain_matches, host_of, only_set, read_version, remove_profile

__all__ = [
    "actions", "connection", "injected", "keyboard", "keylayout", "lifecycle",
    "protocol",
    "PageActs", "PointerPersona", "Step", "initial_pointer", "landing_point",
    "plan_aimless_move", "plan_approach", "plan_idle", "plan_scroll",
    "popup_number", "steps_from_waypoints", "tail_within",
    "CursorMotion",
    "DONE", "MIN_EVENT_INTERVAL_MS", "SLEEP", "Ev", "Pacer",
    "clamp_to_viewport", "fine_timer", "fit_timeline",
    "domain_matches", "host_of", "only_set", "read_version", "remove_profile",
]
