§
    ›Çj"‚  ã                  ó¾   — d Z ddlmZ ddlZddlZddlZddlmZmZ dZ	 ej
        e¦  «                             d¦  «        Z G d„ de¦  «        Z G d	„ d
¦  «        ZdS )un  The injected script, called from Python.

â›” THIS MODULE REIMPLEMENTS NOTHING, and the reason is that it could not:
selector engines and actionability work on the DOM, and Python is not in
the page. JavaScript stays JavaScript; this file only handles loading it
into the right world and calling it.

THE TWO WORLDS, which are the reason for this entire file. Firefox gives
automation a separate context that sees the same DOM **through an Xray**:
inside it `addEventListener`, `textContent` and `querySelector` are the
NATIVE ones, not the ones the site may have replaced. In the MAIN world
everything belongs to the site, and every read is accountable to whoever
wrapped the accessor. On 2026-08-27 two spots that used the wrong world
produced 13 listeners plus one `textContent` read for every
`bounding_box()`: see `31-client-fork.md` Â§3.9 and Â§3.10.

**Rule: this file ALWAYS works in the utility world.**

HOW IT IS CREATED. There is no "create a world" command: you send
`Page.setInitScripts` with an **empty** script and a `worldName`, and
Juggler announces the context with `Runtime.executionContextCreated`,
whose `auxData.name` carries that name. â›” The name is `__ctx_aux__` and
**is not the upstream one**: our fork renamed it because it used to
travel on the page's window (`31-client-fork.md` Â§3.5). Changing it here
without changing it there breaks the hookup silently.
é    )ÚannotationsN)ÚAnyÚOptionalÚ__ctx_aux__zinjected.jsc                  ó   — e Zd ZdZdS )ÚEvaluationErrorz9The JavaScript raised. Carries the PAGE's text and stack.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    úWC:\Projects\Historical\venv\Lib\site-packages\invisible_playwright/_juggler/injected.pyr   r   +   s   € € € € € ØCÐCÐCÐCr   r   c                  óR  — e Zd ZdZdMd„ZdNd„ZdOd„ZdPd„ZdOd„ZdOd„Z	dQd„Z
dQd„ZddœdRd„ZdSd„ZdddœdTd$„ZdddœdUd&„ZdVd'„Zd(d)œdWd,„ZdXd.„ZdddœdYd/„ZdZd1„Zd[d3„Zd\d4„Zd]d5„Zd^d7„Zd]d8„Zd9Zd_d;„Zd]d<„Zd]d=„Zd]d>„Zd`d@„ZdVdA„Z dVdB„Z!dadC„Z"dbdE„Z#dcdG„Z$dddHdIœdedK„Z%dfdL„Z&dHS )gÚInjectedScriptz5One `InjectedScript` per frame, in the utility world.ÚsessionÚstrc                ó€   — || _         || _        i | _        i | _        g | _        |                     | j        ¦  «         d S ©N)Úcr   ÚcontextsÚ_handleÚ_init_scriptsÚadd_listenerÚ_route)ÚselfÚ
connectionr   s      r   Ú__init__zInjectedScript.__init__2   sH   € ØˆŒØˆŒà ˆŒð&  ˆŒð $&ˆÔð 	×Ò ¤Ñ,Ô,Ð,Ð,Ð,r   ÚmethodÚparamsÚdictÚevent_sessionúOptional[str]ÚreturnÚNonec                óL   — || j         k    r|                      ||¦  «         d S d S r   )r   Ú	_on_event)r   r   r    r"   s       r   r   zInjectedScript._routeR   s1   € à˜DœLÒ(Ð(Ø�NŠN˜6 6Ñ*Ô*Ð*Ð*Ð*ð )Ð(r   c                óD   — | j                              | j        ¦  «         dS )z?Stop listening. Called when the page this belongs to goes away.N)r   Úremove_listenerr   ©r   s    r   ÚdetachzInjectedScript.detachW   s    € àŒ×Ò˜tœ{Ñ+Ô+Ð+Ð+Ð+r   Úpc                ó`  ‡— |dk    rS|                      d¦  «        pi }|d         | j        |                      d¦  «        |                      d¦  «        pdf<   d S |dk    rK|d         Šˆfd„| j                             ¦   «         D ¦   «         D ]}| j                             |d ¦  «         Œd S d S )	NzRuntime.executionContextCreatedÚauxDataÚexecutionContextIdÚframeIdÚnameÚ z!Runtime.executionContextDestroyedc                ó&   •— g | ]\  }}|‰k    ¯|‘ŒS r   r   )Ú.0ÚkÚvÚdeads      €r   ú
<listcomp>z,InjectedScript._on_event.<locals>.<listcomp>b   s"   ø€ ÐGÐGÐG™D˜A˜q¸QÀ$ºY¸Y�a¸Y¸Y¸Yr   )Úgetr   ÚitemsÚpop)r   r   r,   Úauxr5   r7   s        @r   r'   zInjectedScript._on_event[   sÕ   ø€ ØÐ6Ò6Ð6Ø—%’%˜	Ñ"Ô"Ð( bˆCàÐ&Ô'ð ŒM˜3Ÿ7š7 9Ñ-Ô-¨s¯wªw°v©¬Ð/DÀ"ÐEÑFÐFÐFàÐ:Ò:Ð:ØÐ)Ô*ˆDØGÐGÐGÐG D¤M×$7Ò$7Ñ$9Ô$9ÐGÑGÔGð +ð +�Ø”×!Ò! ! TÑ*Ô*Ð*Ð*ð ;Ð:ð+ð +r   c                ó.   — |                       ¦   «          dS )z¦Creates the utility world. An EMPTY script is enough: what
        matters is the `worldName`, which is the only thing that makes
        the context come into being.N)Ú_push_scriptsr*   s    r   ÚinstallzInjectedScript.installs   s   € ð 	×ÒÑÔÐÐÐr   c                óŒ   — dt           dœg}|d„ | j        D ¦   «         z  }| j                             dd|i| j        ¬¦  «         dS )u  Send the WHOLE list, because the command replaces it.

        â›” ONE PLACE OWNS THIS LIST. `Page.setInitScripts` takes the complete
        set and replaces whatever was there, so a second caller that sends only
        its own script deletes the utility world - and the utility world is
        what every selector, every actionability check and every evaluation in
        this package runs in. The failure would not look like a lost init
        script: it would look like the browser having no DOM.
        r2   )ÚscriptÚ	worldNamec                ó   — g | ]}d |i‘ŒS )rA   r   )r4   Úss     r   r8   z0InjectedScript._push_scripts.<locals>.<listcomp>„   s   € Ð>Ð>Ð> a�X˜q�MÐ>Ð>Ð>r   zPage.setInitScriptsÚscripts)r   N)ÚUTILITY_WORLDr   r   Úsendr   )r   rE   s     r   r>   zInjectedScript._push_scriptsy   sf   € ð !­}Ð=Ð=Ð>ˆØÐ>Ð>¨4Ô+=Ð>Ñ>Ô>Ñ>ˆØŒ�ŠÐ)¨I°wÐ+?Ø œLð 	ñ 	*ô 	*ð 	*ð 	*ð 	*r   Úsourcec                ób   — | j                              |¦  «         |                      ¦   «          dS )uZ  A script the caller wants run before anything on every document.

        â›” APPENDED, never replacing. Playwright's `add_init_script` is
        cumulative by contract - callers add a stub, then another - and the
        engine's command is not, so the accumulation has to live here.

        â›” IN THE MAIN WORLD, with no `worldName`. The point of a caller's
        init script is to be seen BY THE PAGE; putting it in the utility world
        would run it behind the Xray, where the page cannot see anything it
        defines, and the call would succeed while doing nothing observable.
        N)r   Úappendr>   ©r   rH   s     r   Úadd_init_scriptzInjectedScript.add_init_scriptˆ   s3   € ð 	Ô×!Ò! &Ñ)Ô)Ð)Ø×ÒÑÔÐÐÐr   c                óx   — || j         v r0| j                              |¦  «         |                      ¦   «          dS dS )uÉ   Undo one. Removes ONE occurrence, not every copy.

        â›” The same source added twice is two scripts by Playwright's
        contract, and disposing one handle must leave the other alive.
        N)r   Úremover>   rK   s     r   Úremove_init_scriptz!InjectedScript.remove_init_script—   sI   € ð �TÔ'Ð'Ð'ØÔ×%Ò% fÑ-Ô-Ð-Ø×ÒÑ Ô Ð Ð Ð ð (Ð'r   g      $@)ÚtimeoutÚframe_idrP   Úfloatc               óP  ‡— ‰t           f}t          j        ¦   «         |z   }|| j        vrqt          j        ¦   «         |k    r=t	          ˆfd„| j        D ¦   «         ¦  «        }t          dt           ‰||pdfz  ¦  «        ‚t          j        d¦  «         || j        v°q| j        |         S )Nc              3  ó.   •K  — | ]\  }}|‰k    ¯|V — Œd S r   r   ©r4   ÚfÚnrQ   s      €r   ú	<genexpr>z,InjectedScript.context_id.<locals>.<genexpr>¦   s+   øè è € ÐMÐM¡d a¨¸qÀHº}¸} ¸}¸}¸}¸}ÐMÐMr   zwthe utility world (%s) has not been born for frame %s in %.0fs. Worlds seen for that frame: %s. Did you call install()?Únoneç{®Gáz„?)rF   ÚtimeÚ	monotonicr   ÚsortedÚTimeoutErrorÚsleep)r   rQ   rP   ÚkeyÚdeadlineÚworldss    `    r   Ú
context_idzInjectedScript.context_id¡   sÈ   ø€ Ø�Ð'ˆÝ”>Ñ#Ô# gÑ-ˆØ˜œÐ&Ð&ÝŒ~ÑÔ (Ò*Ð*ÝÐMÐMÐMÐM¨d¬mÐMÑMÔMÑMÔM�Ý"ð*å-:¸HØ-4°fÐ6FÀð-HñHñIô Ið Iõ
 ŒJ�tÑÔÐð ˜œÐ&Ð&ð Œ}˜SÔ!Ð!r   Úresponsec                ó   — |pi                       d¦  «        }|r]t          |                      d¦  «        p|                      d¦  «        pd›|                      d¦  «        rd|d         z   nd›�¦  «        ‚|pi                       d¦  «        pi S )	uä   â›” An exception from the page does NOT arrive as a protocol
        error: it arrives as an `exceptionDetails` field inside a
        SUCCESSFUL response. Whoever only looks at the return code reads
        `None` and moves on.ÚexceptionDetailsÚtextÚvalueÚ	exceptionÚstackú
r2   Úresult)r9   r   )r   rd   Úexcs      r   Ú_resultzInjectedScript._result°   sª   € ð
 ˆ~˜2×"Ò"Ð#5Ñ6Ô6ˆØð 	NÝ!ØŸ'š' &™/œ/ÐL¨S¯WªW°WÑ-=Ô-=ÐLÀÐLØ36·7²7¸7Ñ3CÔ3CÐK˜4 # g¤,Ñ.Ð.ÈÐKðMñNô Nð Nð �˜B×#Ò# HÑ-Ô-Ð3°Ð3r   Tg      >@)Úby_valuerP   Ú
expressionro   Úboolr   c          	     óô   — |                       | j                             d|                      |¦  «        ||dœ| j        |¬¦  «        ¦  «        }|r|                     d¦  «        n|                     d¦  «        S )NúRuntime.evaluate©r/   rp   ÚreturnByValue©r   rP   rh   ÚobjectId)rn   r   rG   rc   r   r9   )r   rQ   rp   ro   rP   Úrs         r   ÚevaluatezInjectedScript.evaluate¼   s}   € à�LŠL˜œŸšØØ#'§?¢?°8Ñ#<Ô#<Ø%¸ðBð Bà”L¨'ð	 %ñ 3ô 3ñ 4ô 4ˆð
 "*Ð@ˆq�uŠu�W‰~Œ~ˆ~¨q¯uªu°ZÑ/@Ô/@Ð@r   Údeclarationc          
     óœ  — d|                       |¦  «        ig}|D ]8}|                     t          |t          ¦  «        r
d|v sd|v r|nd|i¦  «         Œ9|                      | j                             d|                      |¦  «        |||dœ| j        |¬¦  «        ¦  «        }|r| 	                    d¦  «        n| 	                    d¦  «        S )z~`declaration` is a JS declaration; the FIRST argument passed
        is always the InjectedScript, the way the driver does it.rw   rh   úRuntime.callFunction©r/   ÚfunctionDeclarationÚargsru   rv   )
ÚhandlerJ   Ú
isinstancer!   rn   r   rG   rc   r   r9   )	r   rQ   rz   ro   rP   Ú	argumentsr   Úarx   s	            r   ÚcallzInjectedScript.callÅ   sü   € ð ˜TŸ[š[¨Ñ2Ô2Ð3Ð4ˆØð 	Mð 	MˆAØ�KŠK�Z¨­4Ñ0Ô0ð LØ# q˜˜¨G°q¨L¨Lð ˜Ø@GÈ¸|ñMô Mð Mð Mà�LŠL˜œŸšØ"Ø#'§?¢?°8Ñ#<Ô#<Ø$/¸Ø&ð(ð (ð ”L¨'ð %ñ 3ô 3ñ 4ô 4ˆð "*Ð@ˆq�uŠu�W‰~Œ~ˆ~¨q¯uªu°ZÑ/@Ô/@Ð@r   c           	     ó¾  — | j                              |t          f¦  «        }| j                             |¦  «        }|�|�|d         |k    r|d         S dddddddg d	œ}t                               d
¬¦  «        }d|›dt          j        |¦  «        ›d�}|                      ||d¬¦  «        }|st          d¦  «        ‚|  
                    |¦  «        |f| j        |<   |S )u  The frame's InjectedScript, built once per world it lives in.

        â›” "Built only once" was the old sentence and it was the bug. Once per
        FRAME is wrong: the script is an object inside one execution context,
        and the frame outlives its contexts - every navigation replaces them,
        and so does a restore from the back forward cache. What this returns
        has to be the script of the world the frame has NOW.

        Asking `contexts` is the whole of the check, and it is decidable at any
        moment from state this client already keeps. The alternative, which is
        what stood here, was to keep the objectId and trust that some earlier
        event had removed it when it went stale; a restore is exactly where
        that trust is misplaced.
        Nr   é   FÚpythonzdata-testidÚfirefoxT)ÚisUnderTestÚsdkLanguageÚtestIdAttributeNameÚstableRafCountÚbrowserNameÚshouldPrependErrorPrefixÚisUtilityWorldÚcustomEngineszutf-8)Úencodingz(() => { const module = {};
z:
return new (module.exports.InjectedScript())(globalThis, z); })();©ro   zIthe InjectedScript did not return an object: is the source the right one?)r   r9   rF   r   Ú_SOURCEÚ	read_textÚjsonÚdumpsry   r   rc   )r   rQ   ÚcurrentÚcachedÚoptionsrH   rp   Úoids           r   r€   zInjectedScript.handleÕ   s  € ð ”-×#Ò# X­}Ð$=Ñ>Ô>ˆØ”×!Ò! (Ñ+Ô+ˆØÐ 'Ð"5¸&À¼)ÀwÒ:NÐ:NØ˜!”9Ðð !Ø#Ø#0ØØ$Ø(-ð #Øð!
ð 
ˆõ$ ×"Ò"¨GÐ"Ñ4Ô4ˆˆð  ˜˜¥¤¨GÑ!4Ô!4Ð!4Ð!4ð6ˆ
ð �mŠm˜H j¸5ˆmÑAÔAˆØð 	0Ý!ð/ñ0ô 0ð 0ð #'§/¢/°(Ñ";Ô";¸SÐ!AˆŒ�XÑØˆ
r   F)ÚstrictÚselectorr›   c               ó6   — |                       |d||d¬¦  «        S )z4The objectId of the first matching element, or None.zƒ(injected, sel, strict) => {  const p = injected.parseSelector(sel);  return injected.querySelector(p, document, strict) || null; }Fr’   ©r„   )r   rQ   rœ   r›   s       r   Úquery_selectorzInjectedScript.query_selector  s1   € ð �yŠyØðNð �f uð ñ .ô .ð 	.r   Úintc                ó0   — |                       |d|¦  «        S )NzZ(injected, sel) => injected.querySelectorAll(injected.parseSelector(sel), document).lengthrž   )r   rQ   rœ   s      r   ÚcountzInjectedScript.count  s#   € Ø�yŠyØð<àñ	ô ð 	r   c          	     óú  ‡— t          j        ¦   «         |z   }‰df}|| j        vrgt          j        ¦   «         |k    r3t          d‰›dt	          ˆfd„| j        D ¦   «         ¦  «        ›�¦  «        ‚t          j        d¦  «         || j        v°g|                      | j                             d| j        |         ||dœ| j	        |¬¦  «        ¦  «        }|r| 
                    d	¦  «        n| 
                    d
¦  «        S )uP  Evaluate in the PAGE's own world, deliberately and rarely.

        â›” THIS IS THE ONE PLACE THAT LEAVES THE XRAY, AND IT NEEDS A REASON
        EVERY TIME. Everything else in this module runs in the utility world
        precisely so a site cannot count our reads. Running here is visible to
        anything that has wrapped an accessor.

        The reason it exists at all is `set_content`, and it is not a
        preference: the utility world has an EXTENDED principal (a sandbox over
        the window, deliberately, so closed shadow roots are reachable), and
        Gecko requires `document.open()` to run under a principal EQUAL to the
        document's. From the utility world it answers `The operation is
        insecure` EVERY time - measured here on 2026-08-27, and the same defect
        was already fixed once inside the driver, where it shipped a broken
        `set_content` to users.

        â›” AND THE MAIN WORLD IS THE ONE WITH THE EMPTY NAME. `auxData.name` is
        absent for the page's own context, which is why the key is `""` and not
        a missing lookup.
        r2   z(the main world never appeared for frame z. Worlds seen: c              3  ó.   •K  — | ]\  }}|‰k    ¯|V — Œd S r   r   rU   s      €r   rX   z2InjectedScript.evaluate_in_main.<locals>.<genexpr>;  s8   øè è € ð -?ð -?±4°1°aØ01°X²°ð ./Ø0=°°°ð-?ð -?r   rZ   rs   rt   rv   rh   rw   )r[   r\   r   r^   r]   r_   rn   r   rG   r   r9   )r   rQ   rp   ro   rP   ra   r`   rx   s    `      r   Úevaluate_in_mainzInjectedScript.evaluate_in_main  s5  ø€ õ, ”>Ñ#Ô# gÑ-ˆØ˜ˆnˆØ˜œÐ&Ð&ÝŒ~ÑÔ (Ò*Ð*Ý"�là$˜H˜H¥fð -?ð -?ð -?ð -?¸4¼=ð -?ñ -?ô -?ñ '?ô '?ð '?ð@ñAô Að Aõ ŒJ�tÑÔÐð ˜œÐ&Ð&ð �LŠL˜œŸšØØ#'¤=°Ô#5Ø%¸ðBð Bà”L¨'ð	 %ñ 3ô 3ñ 4ô 4ˆð
 "*Ð@ˆq�uŠu�W‰~Œ~ˆ~¨q¯uªu°ZÑ/@Ô/@Ð@r   Úlistc                ó¼   — |                       ||¦  «        }g }t          |¦  «        D ]3}|                      |d||d¬¦  «        }|r|                     |¦  «         Œ4|S )uz  Every match, as a list of objectIds the caller must dispose.

        â›” IT RETURNS HANDLES, AND EACH ONE HOLDS A DOM NODE ALIVE. A page with
        a thousand matches leaves a thousand nodes uncollectable until they are
        disposed, which is a leak that grows with the page and not with the
        code. The caller owns them; there is no scope here that could.
        zY(injected, sel, i) => injected.querySelectorAll(injected.parseSelector(sel), document)[i]Fr’   )r¢   Úranger„   rJ   )r   rQ   rœ   r¢   ÚidsÚindexÚ	object_ids          r   Úquery_selector_allz!InjectedScript.query_selector_allE  sz   € ð —
’
˜8 XÑ.Ô.ˆØˆÝ˜5‘\”\ð 	&ð 	&ˆEØŸ	š	Øð<à˜%¨%ð	 "ñ 1ô 1ˆIð
 ð &Ø—
’
˜9Ñ%Ô%Ð%øØˆ
r   Úelementc                óN   — t          |                      |dd|i¦  «        ¦  «        S )uÊ  Bring the element into the viewport, and say whether it moved.

        â›” IT WAS MISSING, AND THAT IS WHY A CLICK BELOW THE FOLD FAILED. The
        retry loop asked whether the element was visible, stable and enabled -
        all true for something 3000 px down the page - then computed its point
        from `getContentQuads`, which answers in main-frame coordinates. The
        event was dispatched at a y outside the viewport, landed on nothing,
        and the hit-target check reported `<html>` several hundred times before
        the deadline. Playwright scrolls as part of actionability; we did not.

        â›” `scrollIntoView`, called FROM THE UTILITY WORLD. Scrolling is
        page-visible by construction - a real user scrolls - so there is
        nothing to hide here; what the world buys is that the call goes to the
        NATIVE method through the Xray rather than to whatever the site may
        have replaced it with.

        â›” `block: "center"` rather than the default `"start"`: an element
        flush against the top edge is a point that a sticky header covers on a
        great many pages, and the interceptor would then correctly report that
        the event lands elsewhere.
        zÖ(injected, el) => { const before = el.getBoundingClientRect().top; el.scrollIntoView({block: 'center', inline: 'center',                    behavior: 'instant'}); return el.getBoundingClientRect().top !== before; }rw   )rq   r„   ©r   rQ   r­   s      r   Úscroll_into_viewzInjectedScript.scroll_into_viewY  s9   € õ, �D—I’IØðCð
 ˜Ð!ñ#ô #ñ $ô $ð 	$r   c                ó.   — |                       |d¦  «        S )u±  Where this frame's content area starts, in SCREEN css pixels.

        â›” IT COMES FROM THE ENGINE, and that is the whole point. The hit
        point a caller has is in the MAIN frame's space, because that is what
        `Page.getContentQuads` answers and what `dispatchMouseEvent` wants. To
        check it inside a nested frame it has to be expressed in THAT frame's
        space, and the difference between the two origins is exactly the shift.
        Reading it from `mozInnerScreen*` keeps one source: this project already
        owns that value in C++ (`StealthDeclaredContentOrigin`), so a second
        arithmetic here would be the duplicate that rule 16 is about.
        z8({x: window.mozInnerScreenX, y: window.mozInnerScreenY})©ry   ©r   rQ   s     r   Úcontent_originzInjectedScript.content_originx  s#   € ð �}Š}ØØFñHô Hð 	Hr   c           
     ó„   — |                       |dd|it          |d         ¦  «        t          |d         ¦  «        ¦  «        S )u•  Does `point` still belong to `element`? `"done"`, or what is there.

        â›” A PURE READ, and it replaced an interceptor. The bundle used to
        install capture listeners on the page's window and validate each event
        as it ARRIVED, blocking the ones that landed elsewhere. That was the
        last thing this package put on the page, and the blocking was itself a
        tell: a real `mousedown` that disappears under `preventDefault` is not
        something an input stack produces.

        The caller runs this BEFORE the action and again AFTER, which turns a
        target that moved into a retry instead of into a blocked event.
        z;(injected, el, x, y) => injected.checkHitTarget(el, {x, y})rw   r   r†   )r„   rR   )r   rQ   r­   Úpoints       r   Úcheck_hit_targetzInjectedScript.check_hit_targetˆ  sC   € ð �yŠyØØIØ˜Ð!¥5¨¨q¬¡?¤?µE¸%À¼(±O´OñEô Eð 	Er   Ústatesc                ó6   — |                       |dd|i|¦  «        S )uÂ  Asks the injected script whether the element is actionable.

        Returns `{"ok": True}` or `{"ok": False, "missing": "<state>"}`.
        The states are Playwright's: `visible`, `stable`, `enabled`,
        `editable`. â›” `stable` is ASYNCHRONOUS (it waits two frames), so
        the function is `async` and the value must be awaited: without
        `await` you would get a Promise and every element would come out
        actionable.
        zöasync (injected, el, states) => {  const r = await injected.checkElementStates(el, states);  if (r === undefined) return { ok: true };  if (typeof r === 'string') return { ok: false, missing: r };  return { ok: false, missing: r.missingState }; }rw   rž   )r   rQ   r­   r¸   s       r   Úelement_stateszInjectedScript.element_statesš  s/   € ð �yŠyØðAð
 ˜Ð! 6ñ+ô +ð 	+r   c                ó4   — |                       |dd|i¦  «        S )u’   â›” Goes through the utility world, hence through the Xray: the
        same read done in the MAIN world would be accountable to the
        site.z&(injected, el) => el.textContent || ''rw   rž   r¯   s      r   Útext_contentzInjectedScript.text_content®  s(   € ð �yŠyØØ4Ø˜Ð!ñ#ô #ð 	#r   )ÚvisibleÚhiddenÚenabledÚdisabledÚeditableÚcheckedÚ	uncheckedÚindeterminateÚstatec                óì  — || j         vr.t          d|›dd                     | j         ¦  «        ›d�¦  «        ‚|                      |dd|i|¦  «        }t	          |t
          ¦  «        r€t	          |                     d¦  «        t          ¦  «        r6|d                              d¦  «        rt          d	|›d
|d         ›�¦  «        ‚t          |                     d¦  «        ¦  «        S t          |¦  «        S )z<`is_visible`, `is_enabled`, `is_checked` and their siblings.zunknown state: z (the real ones are z, ú)z1(injected, el, s) => injected.elementState(el, s)rw   Úreceivedzerror:zelementState(z): Úmatches)ÚKNOWN_STATESÚ
ValueErrorÚjoinr„   r�   r!   r9   r   Ú
startswithr   rq   )r   rQ   r­   rÅ   rx   s        r   Úelement_statezInjectedScript.element_stateÄ  s
  € à˜Ô)Ð)Ð)Ý�*Ø %   t§y¢y°Ô1BÑ'CÔ'CÐ'CÐ'CðEñ Fô Fð Fà�IŠIØØ?Ø˜Ð! 5ñ*ô *ˆõ �a�ÑÔð 	*Ý˜!Ÿ%š% 
Ñ+Ô+­SÑ1Ô1ð EØ�j”M×,Ò,¨XÑ6Ô6ðEå%�oØ.3¨e¨e°Q°z´]°]ÐCñEô Eð Eå˜Ÿš˜iÑ(Ô(Ñ)Ô)Ð)Ý�A‰wŒwˆr   c                ó4   — |                       |dd|i¦  «        S )Nz(injected, el) => el.innerTextrw   rž   r¯   s      r   Ú
inner_textzInjectedScript.inner_textÙ  ó%   € Ø�yŠy˜Ð#CØ$ gÐ.ñ0ô 0ð 	0r   c                ó4   — |                       |dd|i¦  «        S )Nz(injected, el) => el.innerHTMLrw   rž   r¯   s      r   Ú
inner_htmlzInjectedScript.inner_htmlÝ  rÑ   r   c                ó4   — |                       |dd|i¦  «        S )u’   `input_value`. â›” Only valid on input, textarea and select: on
        a div it would silently return `undefined`, so it REFUSES
        instead.a
  (injected, el) => {  const e = injected.retarget(el, 'follow-label');  const n = e && e.nodeName.toLowerCase();  if (n !== 'input' && n !== 'textarea' && n !== 'select')    throw new Error('Node is not an <input>, <textarea> or <select> element');  return e.value; }rw   rž   r¯   s      r   Úinput_valuezInjectedScript.input_valueá  s,   € ð �yŠyØð"ð ˜Ð!ñ#ô #ð 	#r   r1   c                ó6   — |                       |dd|i|¦  «        S )uö   â›” An ABSENT attribute must return `None`, not the empty
        string: `getAttribute` already returns `null` on its own, but an
        empty value and an absence are two different things and the
        reader must be able to tell them apart.z'(injected, el, n) => el.getAttribute(n)rw   rž   )r   rQ   r­   r1   s       r   Úget_attributezInjectedScript.get_attributeï  s*   € ð
 �yŠyØÐ?Ø˜Ð! 4ñ)ô )ð 	)r   c                ó.   — |                       |d¦  «        S )Nzdocument.titler²   r³   s     r   ÚtitlezInjectedScript.titleø  s   € Ø�}Š}˜XÐ'7Ñ8Ô8Ð8r   c                ó.   — |                       |d¦  «        S )u½  `page.content()`, INCLUDING shadow roots - open and closed.

        â›” THIS IS A DELIBERATE DIVERGENCE FROM UPSTREAM PLAYWRIGHT, and it is
        the whole point of owning the client. Upstream serialises with
        `documentElement.outerHTML`, which walks the light DOM only: every
        shadow root, open or closed, comes back as an empty host element. A
        `content()` that silently omits half the document is the defect, not
        the contract - and closed roots are exactly where the interesting parts
        of a hostile page live.

        **HOW, and every piece was measured on the shipped engine on
        2026-08-27:**

        - `Element.getHTML({serializableShadowRoots, shadowRoots})` exists here
          and serialises a root as `<template shadowrootmode="closed">`. It only
          serialises roots it is HANDED, or ones the page marked `serializable`,
          so the list has to be collected first.
        - Collecting them is possible because this runs in the UTILITY world,
          where `element.shadowRoot` answers for a closed root too. That is our
          C++ patch in `Element::GetShadowRootForBindings`, gated on the
          ExpandedPrincipal, so the PAGE still gets `null` and nothing about
          this is observable from content. Measured both ways in the same run.
        - The walk is recursive: a shadow root can contain hosts of its own,
          and stopping at depth one would produce a document that looks
          complete and is not.

        On the probe page: 508 characters against 433 for the `outerHTML` path,
        and the closed root's text is present in the first and absent in the
        second.

        â›” NO FALLBACK. If `getHTML` is missing the call raises, and that is
        correct: this package pins its own engine through the seal, so a
        missing `getHTML` means the engine is not the one we pinned, and
        quietly returning a document with holes in it would hide that.
        aÑ  (() => {  const roots = [];  const walk = (root) => {    for (const el of root.querySelectorAll('*')) {      const sr = el.shadowRoot;      if (sr) { roots.push(sr); walk(sr); }    }  };  walk(document);  const doctype = document.doctype    ? new XMLSerializer().serializeToString(document.doctype) : '';  if (!document.documentElement) return doctype;  return doctype + document.documentElement.getHTML(    {serializableShadowRoots: true, shadowRoots: roots});})()r²   r³   s     r   ÚcontentzInjectedScript.contentû  s#   € ðH �}Š}Øðñô ð 	r   c                ó‚  — | j                              d||dœ| j        d¬¦  «        pi }|                     d¦  «        pg }|sdS d„ |D ¦   «         }t	          d„ |D ¦   «         ¦  «        }t	          d	„ |D ¦   «         ¦  «        }t          d
„ |D ¦   «         ¦  «        }t          d„ |D ¦   «         ¦  «        }	||||z
  |	|z
  dœS )u   `bounding_box`: x, y, width, height from the quads, or None.

        â›” Goes through `Page.getContentQuads` and NOT through the
        page's `getBoundingClientRect`: that getter belongs to the
        site, and reading it would be accountable.
        zPage.getContentQuads)r0   rw   é
   rv   ÚquadsNc                óT   — g | ]%}|d          |d         |d         |d         fD ]}|‘ŒŒ&S )Úp1Úp2Úp3Úp4r   )r4   Úqr,   s      r   r8   z/InjectedScript.bounding_box.<locals>.<listcomp>>  s^   € ð Að Að A˜Ø˜dœG Q t¤W¨a°¬g°q¸´wÐ?ðAð AØð ð Að Að Að Ar   c              3  ó&   K  — | ]}|d          V — ŒdS ©ÚxNr   ©r4   r,   s     r   rX   z.InjectedScript.bounding_box.<locals>.<genexpr>@  ó&   è è € Ð(Ð(˜A��3”Ð(Ð(Ð(Ð(Ð(Ð(r   c              3  ó&   K  — | ]}|d          V — ŒdS ©ÚyNr   rè   s     r   rX   z.InjectedScript.bounding_box.<locals>.<genexpr>A  ré   r   c              3  ó&   K  — | ]}|d          V — ŒdS ræ   r   rè   s     r   rX   z.InjectedScript.bounding_box.<locals>.<genexpr>B  ré   r   c              3  ó&   K  — | ]}|d          V — ŒdS rë   r   rè   s     r   rX   z.InjectedScript.bounding_box.<locals>.<genexpr>C  ré   r   )rç   rì   ÚwidthÚheight)r   rG   r   r9   ÚminÚmax)
r   rQ   r­   rx   rÞ   ÚpointsÚx1Úy1Úx2Úy2s
             r   Úbounding_boxzInjectedScript.bounding_box1  s  € ð ŒF�KŠKÐ.Ø$,¸'ÐBÐBØ $¤°bð ñ :ô :ð @à=?ð 	
ð —’�g‘”Ð$ "ˆØð 	Ø�4ðAð A˜Uð Añ Aô AˆåÐ(Ð( Ð(Ñ(Ô(Ñ(Ô(ˆÝÐ(Ð( Ð(Ñ(Ô(Ñ(Ô(ˆÝÐ(Ð( Ð(Ñ(Ô(Ñ(Ô(ˆÝÐ(Ð( Ð(Ñ(Ô(Ñ(Ô(ˆØ˜b¨2°©7¸bÀ2¹gÐFÐFÐFr   rc   c                óx   — t          | j                             ¦   «         ¦  «        D ]\  \  }}}||k    r|c S ŒdS )u$  Which frame owns this execution context, or None.

        â›” The registry is keyed the other way round - (frame, world) to
        context - because that is the direction every other caller needs. This
        is the one caller that arrives holding a context id and nothing else:
        `Page.fileChooserOpened` names the context the input lives in and never
        names the frame, so without this inversion the element could only be
        assumed to be in the main frame, which is wrong the moment a form sits
        in an iframe.
        N)r¦   r   r:   )r   rc   rQ   Ú_worldrh   s        r   Úframe_of_contextzInjectedScript.frame_of_contextF  sQ   € õ *.¨d¬m×.AÒ.AÑ.CÔ.CÑ)DÔ)Dð 	 ð 	 Ñ%ÑˆX�v Ø˜
Ò"Ð"Ø���ð #àˆtr   Úworldc           
     ó  — ||dk    rdnt           f}| j                             |¦  «        }|€dS |                      | j                             d|dd|igddœ| j        d	¬
¦  «        ¦  «        }|                     d¦  «        S )u…  The value of an objectId, asked in the world it belongs to.

        â›” An objectId is resolved inside the context it is given, so a handle
        born in the page's own world cannot be read from the utility one. This
        is the only reader that takes the world as an argument, because
        `waitForFunction` is the only place that hands back a main-world
        handle.
        Úmainr2   Nr|   z(v) => vrw   Tr}   rÝ   rv   rh   )rF   r   r9   rn   r   rG   r   )r   rQ   rü   r­   r`   Úcontextrx   s          r   Újson_value_inzInjectedScript.json_value_inV  sŸ   € ð ˜u¨š˜˜˜µMÐBˆØ”-×#Ò# CÑ(Ô(ˆØˆ?Ø�4Ø�LŠL˜œŸšØ"Ø#*Ø$.Ø! 7Ð+Ð,Ø"ð$ð $ð ”L¨"ð %ñ .ô .ñ /ô /ˆð �uŠu�W‰~Œ~Ðr   N)Úintor  c               óæ   — ||                       |p|¦  «        dœ}|�||d<   | j                             d|| j        d¬¦  «        pi }|                     d¦  «        pi                      d¦  «        pdS )u�  Move an objectId from the page's own world into the utility world.

        â›” AN objectId IS NOT PORTABLE BETWEEN WORLDS. Every other method here
        talks to the utility world, so a handle that arrived from the MAIN
        world - which is where `Page.fileChooserOpened` hands the input element
        from - cannot simply be passed to them: Juggler resolves an objectId
        inside the context it is given and answers that it does not exist.
        `Page.adoptNode` is the crossing, and it is the same one Playwright's
        own Firefox backend makes for this event.

        With no `element` the engine adopts the frame's OWNER - the `<iframe>`
        that holds `frame_id` - and it has to land in the world of the frame
        that element lives in, the parent, which is what `into` names. That is
        `frame.frame_element()`, and upstream's Firefox backend asks for it the
        same way.
        )r0   r/   Nrw   zPage.adoptNoderÝ   rv   ÚremoteObject)rc   r   rG   r   r9   )r   rQ   r­   r  r    Úanswers         r   ÚadoptzInjectedScript.adoptl  s•   € ð$ &Ø(,¯ª¸Ð8HÀÑ(IÔ(IðKð KˆàÐØ!(ˆF�:ÑØ”—’Ð-¨vØ%)¤\¸2ð ñ ?ô ?ð EØBDð 	à—’˜NÑ+Ô+Ð1¨r×6Ò6°zÑBÔBÐKÀtÐKr   c                óœ   — 	 | j                              d|                      |¦  «        |dœ| j        d¬¦  «         dS # t          $ r Y dS w xY w)uì   A retained objectId keeps a page DOM node alive.

        â›” `Runtime.disposeObject` ALSO wants the `executionContextId`:
        an objectId alone identifies nothing, because the same number
        can exist in two contexts.
        zRuntime.disposeObject)r/   rw   é   rv   N)r   rG   rc   r   Ú	Exceptionr¯   s      r   ÚdisposezInjectedScript.dispose†  sx   € ð	ØŒF�KŠKÐ/Ø/3¯ª¸xÑ/HÔ/HØ%,ð.ð .à $¤°að ñ 9ô 9ð 9ð 9ð 9øõ ð 	ð 	ð 	ØˆDˆDð	øøøs   ‚9= ½
AÁ
A)r   r   )r   r   r    r!   r"   r#   r$   r%   )r$   r%   )r   r   r,   r!   r$   r%   )rH   r   r$   r%   )rQ   r   rP   rR   r$   r   )rd   r!   r$   r!   )
rQ   r   rp   r   ro   rq   rP   rR   r$   r   )
rQ   r   rz   r   ro   rq   rP   rR   r$   r   )rQ   r   r$   r   )rQ   r   rœ   r   r›   rq   r$   r#   )rQ   r   rœ   r   r$   r    )rQ   r   rp   r   ro   rq   rP   rR   )rQ   r   rœ   r   r$   r¦   )rQ   r   r­   r   r$   rq   )rQ   r   r$   r!   )rQ   r   r­   r   r$   r   )rQ   r   r­   r   r¸   r¦   r$   r!   )rQ   r   r­   r   rÅ   r   r$   rq   )rQ   r   r­   r   r1   r   )rQ   r   r­   r   )rc   r   )rQ   r   rü   r   r­   r   r   )rQ   r   r­   r#   r  r#   )rQ   r   r­   r   r$   r%   )'r	   r
   r   r   r   r   r+   r'   r?   r>   rL   rO   rc   rn   ry   r„   r€   rŸ   r¢   r¥   r¬   r°   r´   r·   rº   r¼   rÊ   rÎ   rÐ   rÓ   rÕ   r×   rÙ   rÛ   rø   rû   r   r  r	  r   r   r   r   r   /   sV  € € € € € Ø?Ð?ð-ð -ð -ð -ð@+ð +ð +ð +ð
,ð ,ð ,ð ,ð+ð +ð +ð +ð0ð ð ð ð*ð *ð *ð *ðð ð ð ð!ð !ð !ð !ð =Að "ð "ð "ð "ð "ð "ð
4ð 
4ð 
4ð 
4ð "&¸ðAð Að Að Að Að Að #°TðAð Að Að Að Að Að 6ð 6ð 6ð 6ðt */ð.ð .ð .ð .ð .ð .ðð ð ð ð +/Àð$Að $Að $Að $Að $Að $AðLð ð ð ð($ð $ð $ð $ð>Hð Hð Hð Hð Eð Eð Eð Eð$+ð +ð +ð +ð(#ð #ð #ð #ð&=€Lðð ð ð ð*0ð 0ð 0ð 0ð0ð 0ð 0ð 0ð#ð #ð #ð #ð)ð )ð )ð )ð9ð 9ð 9ð 9ð4ð 4ð 4ð 4ðlGð Gð Gð Gð*ð ð ð ð ð ð ð ð,LØ$(ðLð Lð Lð Lð Lð Lð4ð ð ð ð ð r   r   )r   Ú
__future__r   r•   Úpathlibr[   Útypingr   r   rF   ÚPathÚ__file__Ú	with_namer“   ÚRuntimeErrorr   r   r   r   r   ú<module>r     sê   ððð ð4 #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø €€€Ø  Ð  Ð  Ð  Ð  Ð  Ð  Ð  ð €à
ˆ'Œ,�xÑ
 Ô
 ×
*Ò
*¨=Ñ
9Ô
9€ðDð Dð Dð Dð D�lñ Dô Dð Dðd	ð d	ð d	ð d	ð d	ñ d	ô d	ð d	ð d	ð d	r   