§
    ›Çj÷M  ã                  óZ  — U 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dl	m
Z
 ddlmZmZmZmZ ddlmZ dHd„ZdId„Zdddddddddddœ
Zded<   dJd„ZeZdddddd œdKd)„Z G d*„ d+e¦  «        ZdLd/„ZdMd1„ZdNd2„Zdd3lmZ dd4l m!Z! e G d5„ d6¦  «        ¦   «         Z"dd7d7ddddd8dd9œ	dOdG„Z#dS )PzÊDirect-launch helpers shared by the Playwright wrapper and the profile
manager: write a user.js from a prefs dict, and build the subprocess env the
patched binary reads at startup. No Playwright, no Qt.é    )ÚannotationsN)Ú	dataclassÚfield)ÚPath)ÚAnyÚDictÚListÚOptionalé   )ÚDESKTOP_ENVÚvr   ÚreturnÚstrc                ó–   — t          | t          ¦  «        r!t          j        t	          | ¦  «        ¦  «        S t          j        | ¦  «        S )aE  Serialize a pref value the way Firefox's prefs parser accepts it.

    Firefox prefs are int / bool / string only - there is no float pref type;
    a fractional value (e.g. device-pixel-ratio) is stored as a STRING and the
    float pref parses it back. ``json.dumps`` would emit a bare ``1.25``, which
    Firefox rejects with ``prefs parse error: unexpected character`` and which
    invalidates every ``user_pref`` line after it. (bool is a subclass of int
    but ``json.dumps`` already maps it to ``true``/``false``, so it is handled
    before the float check matters.)
    )Ú
isinstanceÚfloatÚjsonÚdumpsr   )r   s    úFC:\Projects\Historical\venv\Lib\site-packages\invisible_core/launch.pyÚ_pref_literalr      s:   € õ �!•UÑÔð "ÝŒz�#˜a™&œ&Ñ!Ô!Ð!ÝŒ:�a‰=Œ=Ðó    Úprofile_dirú'str | os.PathLike[str]'ÚprefsúDict[str, Any]r   c                óò   — t          | ¦  «        }|                     dd¬¦  «         |dz  }d„ |                     ¦   «         D ¦   «         }|                     d                     |¦  «        dz   d¬¦  «         |S )a5  Write ``prefs`` as ``user_pref(...)`` lines into ``<profile_dir>/user.js``.

    Creates ``profile_dir`` if missing; overwrites any existing ``user.js``.
    Values are serialized so Python ``True``/strings/ints/floats map to what
    Firefox expects (``true``/quoted-strings/numbers, floats as strings).
    T©ÚparentsÚexist_okzuser.jsc                ód   — g | ]-\  }}d t          j        |¦  «        › dt          |¦  «        › d�‘Œ.S )z
user_pref(z, z);)r   r   r   )Ú.0Úkr   s      r   ú
<listcomp>z!write_user_js.<locals>.<listcomp>*   s@   € ÐZÐZÐZÁDÀAÀqÐ?�$œ* Q™-œ-Ð?Ð?­=¸Ñ+;Ô+;Ð?Ð?Ð?ÐZÐZÐZr   ú
zutf-8)Úencoding)r   ÚmkdirÚitemsÚ
write_textÚjoin)r   r   ÚdÚoutÚliness        r   Úwrite_user_jsr-       sw   € õ 	ˆ[ÑÔ€AØ‡G‚G�D 4€GÑ(Ô(Ð(Ø
ˆi‰-€CØZÐZÈEÏKÊKÉMÌMÐZÑZÔZ€EØ‡N‚N�4—9’9˜UÑ#Ô# dÑ*°W€NÑ=Ô=Ð=Ø€Jr   ÚEST5EDTÚCST6CDTÚMST7MDTÚPST8PDTÚMST7Ú	AKST9AKDTÚHST10)
zAmerica/New_YorkzAmerica/DetroitzAmerica/Indiana/IndianapoliszAmerica/Kentucky/LouisvillezAmerica/ChicagozAmerica/DenverzAmerica/Los_AngeleszAmerica/PhoenixzAmerica/AnchoragezPacific/HonoluluúDict[str, str]Ú_IANA_TO_POSIX_TZÚtimezonec                ó8   — t                                | | ¦  «        S )a¹  The value to put in ``TZ`` for an IANA zone.

    PUBLIC since 18.5.0. It was private, so the wrapper kept its own byte-identical
    copy of both this and the table - and the core's own comment admitted the table
    was "copied verbatim from the wrapper". A private name is not a reason to
    duplicate ten entries whose Phoenix row exists because getting it wrong made an
    identification service deduce the wrong origin timezone.
    )r6   Úget)r7   s    r   Útz_envr:   ?   s   € õ × Ò  ¨8Ñ4Ô4Ð4r   )r7   Úsrflx_declaredÚmanifest_pathÚbase_envÚdisplay_envúOptional[str]r;   r<   ú"'Optional[str | os.PathLike[str]]'r=   úOptional[Dict[str, str]]r>   ú"Optional[Dict[str, Optional[str]]]c               ó¢  — t          |€t          j        n|¦  «        }|rt          |¦  «        |d<   |�#|                     dt          |¦  «        ¦  «         |                     d¦  «        p|}|r
||d<   d|d<   |                     t          d¦  «         |pi  	                    ¦   «         D ]#\  }}	|	€|                     |d¦  «         Œ|	||<   Œ$|S )a˜  Subprocess env for the patched binary - the ONE place that composes it.

    The wrapper's `_session.build_env` delegates here after verifying the font
    manifest against the executable; until 34.26.0 it was a twin of this body,
    and the hidden-surface half of the contract lived only in the twin, so a
    consumer on this builder could not express a removal at all.

    TZ tunes the libc clock. STEALTHFOX_WEBRTC_PUBLIC_IP feeds nICEr the proxy
    egress IP; an already-set value in base_env wins.

    STEALTHFOX_FONT_MANIFEST points the engine at the font manifest THIS package
    declares, and it has to be an env var rather than the pref of the same name:
    the font list is built during app startup, inside
    InitSharedFontListForPlatform, and on the Juggler path the caller's prefs
    never reach the profile at all - they travel over the wire and are applied
    by JS once the browser is already running. Measured 2026-08-08: removing a
    family from this package's copy changed nothing, because the pref read empty
    and the engine's own file won. An env var is set at process creation and
    inherited by every content process.

    It carries a PATH. The manifest is ~20 KB and an environment block is not
    the place for it. `manifest_path=None` writes no variable, which leaves the
    engine on its packaged copy - the floor a browser launched without this
    package still has to stand on.
    NÚTZÚSTEALTHFOX_FONT_MANIFESTÚSTEALTHFOX_WEBRTC_PUBLIC_IPÚ1ÚSTEALTHFOX_WEBRTC_DISABLE_IPV6)
ÚdictÚosÚenvironÚ_tz_envÚ
setdefaultr   r9   Úpopr   r'   )
r   r7   r;   r<   r=   r>   ÚenvÚ	webrtc_ipr"   r   s
             r   Úbuild_launch_envrQ   R   sö   € õ` ˜XÐ-�rŒzˆz°8Ñ
<Ô
<€CØð &Ý˜HÑ%Ô%ˆˆD‰	ØÐ ð 	�ŠÐ1µ3°}Ñ3EÔ3EÑFÔFÐFØ—’Ð5Ñ6Ô6ÐH¸.€IØð 4Ø-6ˆÐ)Ñ*ð 14ˆÐ,Ñ-Ø‡G‚G�K˜ÑÔÐØÐ" ×)Ò)Ñ+Ô+ð ð ‰ˆˆ1Øˆ9Ø�GŠG�A�tÑÔÐÐàˆC�‰FˆFØ€Jr   c                  ó   — e Zd ZdZdS )ÚFontManifestMismatchzDThe manifest this package declares describes faces the engine lacks.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r   r   rS   rS   œ   s   € € € € € ØNÐNÐNÐNr   rS   ÚmanifestÚbinaryú'Optional[List[str]]'c                óÊ  ‡— t          |¦  «        j        dz  }g }|                      ¦   «         D ]b}|                     d¦  «        rK|                     d¦  «        }t          |¦  «        dk    r#|d         r|                     |d         ¦  «         Œc|sg S |                     ¦   «         sdS d„ |                     ¦   «         D ¦   «         Št          ˆfd„|D ¦   «         ¦  «        S )a©  Face files `manifest` names that the engine lacks, or None if unchecked.

    THREE outcomes, not two, and collapsing the last two is the trap:
      * `[]`   - checked, every face is present. Safe.
      * `[...]`- checked, these are missing. The caller should refuse.
      * `None` - could NOT check: the engine has no `fonts/` directory beside
                 it, so it is not a bundle-only layout this can inspect.

    `None` is not a pass and must not be treated as `[]`. It is returned rather
    than an empty list for the same reason `download.py` prints "an absent
    check is not a passed check" when an asset carries no omni.ja digest. What
    the caller may reasonably do with it is proceed anyway: an engine with no
    bundled fonts of its own cannot be made worse by a manifest it will read
    against files it does not have either way, and refusing would break every
    layout that is not ours - including every test fixture, which is how this
    distinction got written.

    This is the check that makes handing our manifest to the engine safe, and
    it deliberately is NOT "the two manifests are equal". They are supposed to
    diverge: the whole point of carrying one here is that this package can move
    ahead of a published engine. What must hold is narrower and is the thing
    that fails silently - every `f|` record gives vertical metrics for a named
    FILE, and metrics for a file the engine does not have are not an error, they
    are text laid out a few pixels wrong on a page nobody is measuring.

    Empty result means safe. The caller decides what a non-empty one costs: at
    launch it is worth refusing over, because the alternative is shipping a
    wrong layout to every session, whereas a browser that will not start is at
    least loud.

    An engine with no fonts directory at all returns every file as missing
    rather than an empty list - an absent check must never read like a passed
    one.
    Úfontszf|ú|r   Nc                ó   — h | ]	}|j         ’Œ
S rX   )Úname)r!   Úps     r   ú	<setcomp>z'verify_font_manifest.<locals>.<setcomp>Ï   s   € Ð0Ð0Ð0�qˆAŒFÐ0Ð0Ð0r   c                ó   •— h | ]}|‰v¯|’Œ	S rX   rX   )r!   ÚfÚhaves     €r   rb   z'verify_font_manifest.<locals>.<setcomp>Ð   s   ø€ Ð:Ð:Ð:˜¨A°T¨M¨M�1¨M¨M¨Mr   )
r   ÚparentÚ
splitlinesÚ
startswithÚsplitÚlenÚappendÚis_dirÚiterdirÚsorted)rY   rZ   Ú	fonts_dirÚ
referencedÚlineÚpartsre   s         @r   Úverify_font_manifestrs       sô   ø€ õH �V‘”Ô# gÑ-€IØ€JØ×#Ò#Ñ%Ô%ð ,ð ,ˆØ�?Š?˜4Ñ Ô ð 	,Ø—J’J˜s‘O”OˆEÝ�5‰zŒz˜AŠ~ˆ~ %¨¤(ˆ~Ø×!Ò! %¨¤(Ñ+Ô+Ð+øØð Øˆ	Ø×ÒÑÔð ØˆtØ0Ð0˜I×-Ò-Ñ/Ô/Ð0Ñ0Ô0€DÝÐ:Ð:Ð:Ð:˜jÐ:Ñ:Ô:Ñ;Ô;Ð;r   ú'Path | None'c                óT  — | sdS |                       d¦  «        }t          j        |¦  «                             ¦   «         dd…         }t	          ¦   «         dz  }|                     dd¬¦  «         |d|› d�z  }|                     ¦   «         r*|                     ¦   «         j        t          |¦  «        k    rqt          d	d
g¦  «        |vs
J d¦   «         ‚|                     dt          j        ¦   «         › d�¦  «        }|                     |¦  «         t          j        ||¦  «         |S )aó  Materialise `manifest` somewhere the engine can read it, once per content.

    The Playwright path does not own the profile directory - Playwright creates
    it - so the file cannot simply live beside the profile. Addressing it by the
    sha256 of its own bytes gives a stable path per manifest: launching a
    thousand sessions with the same core writes one file, and a session with a
    pinned manifest gets its own without disturbing the others. Nothing has to
    be cleaned up on teardown, which is the failure mode a per-session temp dir
    would introduce.

    Returns None for an empty manifest: the engine reads that as "use my own
    copy", and writing an empty file would say the same thing while looking
    like a configured one.
    NÚasciié   r]   Tr   zbundle-fonts-z.listé   é
   ú il manifest ha terminazioni CRLFú.z.tmp)ÚencodeÚhashlibÚsha256Ú	hexdigestÚ
cache_rootr&   Úis_fileÚstatÚst_sizerj   ÚbytesÚwith_suffixrJ   ÚgetpidÚwrite_bytesÚreplace)rY   ÚrawÚdigestr*   r+   Útmps         r   Úcached_font_manifest_pathrŒ   Ó   s  € ð ð ØˆtØ
�/Š/˜'Ñ
"Ô
"€CÝŒ^˜CÑ Ô ×*Ò*Ñ,Ô,¨S¨b¨SÔ1€FÝ‰Œ�wÑ€AØ‡G‚G�D 4€GÑ(Ô(Ð(Ø
Ð+˜fÐ+Ð+Ð+Ñ
+€CØ�;Š;‰=Œ=ð ˜CŸHšH™JœJÔ.µ#°c±(´(Ò:Ð:Ý�b˜"�X‰Œ cÐ)Ð)Ð)Ð+MÑ)Ô)Ð)ð �oŠoÐ3¥"¤)¡+¤+Ð3Ð3Ð3Ñ4Ô4ˆØ�Š˜ÑÔÐÝ
Œ
�3˜ÑÔÐØ€Jr   c                óò   — |sdS t          | ¦  «        }|                     dd¬¦  «         |dz  }|                     d¦  «        }t          ddg¦  «        |vs
J d¦   «         ‚|                     |¦  «         |S )	aœ  Write `manifest` beside the profile and return its path, or None.

    Returns None for an empty manifest rather than writing an empty file: the
    engine treats an unreadable or empty source as "use my own copy", and an
    empty file would be an indistinguishable way of saying the same thing while
    looking like a configured one.

    Written as BYTES with an explicit ascii encode. `write_text` on Windows
    translates every newline to CRLF, and this project has already shipped a
    30k-star repository a commit that was 48 additions and 48 deletions for a
    one-line change because of exactly that. The engine's parser splits on a
    bare newline.
    NTr   zbundle-fonts.listrv   rx   ry   rz   )r   r&   r|   r„   r‡   )r   rY   r*   r+   r‰   s        r   Úwrite_font_manifestrŽ   ó   s�   € ð ð ØˆtÝˆ[ÑÔ€AØ‡G‚G�D 4€GÑ(Ô(Ð(Ø
Ð!Ñ
!€CØ
�/Š/˜'Ñ
"Ô
"€Cõ �"�b�‰?Œ? #Ð%Ð%Ð%Ð'IÑ%Ô%Ð%Ø‡O‚O�CÑÔÐØ€Jr   )r€   )ÚSessionTokenc                  ó^   — e Zd ZU dZded<   ded<   ded<   ded	<    ee¬
¦  «        Zded<   dS )Ú
LaunchPlanz@Everything needed to spawn the patched Firefox for one identity.r   rZ   r   r   z	List[str]Úargvr5   rO   )Údefault_factoryr�   Úsession_tokenN)rT   rU   rV   rW   Ú__annotations__r   r�   r”   rX   r   r   r‘   r‘     sb   € € € € € € àJÐJØ€K€K�KØÐÐÑØ€O€O�OØÐÐÑð #( %¸Ð"EÑ"EÔ"E€MÐEÐEÐEÑEÐEÐEr   r‘   ÚautoÚ )	Úproxyr7   ÚlocaleÚpinÚ
binary_verÚbinary_pathÚ
extra_argsÚurlÚshow_cursorÚseedÚintr˜   r™   rš   úOptional[Dict[str, Any]]r›   rœ   r�   úOptional[List[str]]rž   rŸ   úOptional[bool]c       
        ó2  — ddl m} ddlm} ddlm} ddlm} |rL|                     d¦  «        pd 	                    ¦   «          
                    ¦   «         dvrt          d	¦  «        ‚|rt          |¦  «        }n$t          |r ||¦  «        n	 |¦   «         ¦  «        } ||||¦  «        } || |¬
¦  «        } |||j        |j        |d|
¬¦  «        j        }t          |¦  «        }t!          ||¦  «         t#          ||j        pd|                     ¦   «         ¬¦  «        }|ddt          |¦  «        g}|t'          |pg ¦  «        z  }|	r|                     |	¦  «         t+          j        ¦   «         }t/          ||||                     |¦  «        |¬¦  «        S )aÙ  The single direct-launch entry point (no Playwright, no Qt).

    Give it a ``seed`` and a ``profile_dir`` (plus optionally a concrete
    ``proxy`` dict, ``timezone``/``locale`` - both default to ``"auto"`` and are
    resolved from the proxy egress - a ``pin`` and a ``binary_ver``); it resolves
    geo, generates the fingerprint profile, translates it to prefs, writes
    ``user.js`` into ``profile_dir``, and returns the binary path + argv + env.
    Any direct-launch consumer uses this so the session-setup logic lives in
    one place (mirrors the wrapper's __aenter__) - the profile manager did,
    until its 2026-08-18 deletion.
    ``proxy`` must already be a concrete endpoint dict (SOCKS/HTTP), not an intent.
    r   )Úensure_binary)Úgenerate_profile)Úprepare_session_geo)Úcompose_session_prefsÚserverr—   )r—   z	direct://aB  build_launch_plan() cannot take a proxy: it starts the binary directly, so there is no protocol connection to send the engine's proxy command on, and a browser launched without the proxy it was given announces one country and connects from another. Drive the proxy through invisible_playwright, which holds the connection.)r    rš   T)r™   r7   r˜   Úsurvive_hard_killrŸ   N)r7   r;   z
-no-remotez-profile)rZ   r   r’   rO   r”   )Údownloadr¦   Ú_fpforger§   Ú_geor¨   r   r©   r9   ÚstripÚlowerÚ
ValueErrorr   r™   r7   r   r-   rQ   Úsrflx_to_declareÚlistrk   r�   Úmintr‘   Ústamp)r    r   r˜   r7   r™   rš   r›   rœ   r�   rž   rŸ   r¦   r§   r¨   r©   rZ   ÚgeoÚfpr   ÚpdirrO   r’   Útokens                          r   Úbuild_launch_planrº   '  s  € ðh (Ð'Ð'Ð'Ð'Ð'Ø*Ð*Ð*Ð*Ð*Ð*Ø)Ð)Ð)Ð)Ð)Ð)Ø,Ð,Ð,Ð,Ð,Ð,ð ð O�%—)’)˜HÑ%Ô%Ð+¨×2Ò2Ñ4Ô4×:Ò:Ñ<Ô<ÐDUÐUÐUÝðNñOô Oð 	Oð ð SÝ�[Ñ!Ô!ˆˆå°*ÐQ�]�] :Ñ.Ô.Ð.À-À-Á/Ä/ÑRÔRˆð
 Ð
˜h¨¨vÑ
6Ô
6€CØ	Ð	˜t¨Ð	-Ñ	-Ô	-€Bð "Ð!Ø
�3”:¨¬Ø tØðñ ô ô ð	 
õ
 �ÑÔ€DÝ�$˜ÑÔÐÝ
˜5¨3¬<Ð+?¸4Ø*-×*>Ò*>Ñ*@Ô*@ðBñ Bô B€Cà�L *­c°$©i¬iÐ8€DØ�D�Ð!˜rÑ"Ô"Ñ"€DØ
ð Ø�Š�CÑÔÐõ ÔÑÔ€EÝ˜V°¸DØŸ+š+ cÑ*Ô*¸%ðAñ Aô Að Ar   )r   r   r   r   )r   r   r   r   r   r   )r7   r   r   r   )r   r   r7   r?   r;   r?   r<   r@   r=   rA   r>   rB   r   r5   )rY   r   rZ   r   r   r[   )rY   r   r   rt   )r   r   rY   r   r   rt   )r    r¡   r   r   r˜   rA   r7   r   r™   r   rš   r¢   r›   r?   rœ   r?   r�   r£   rž   r   rŸ   r¤   r   r‘   )$rW   Ú
__future__r   r   r}   rJ   Údataclassesr   r   Úpathlibr   Útypingr   r   r	   r
   Ú	_headlessr   r   r-   r6   r•   r:   rL   rQ   ÚRuntimeErrorrS   rs   rŒ   rŽ   r¬   r€   Úprocessr�   r‘   rº   rX   r   r   ú<module>rÂ      s�  ðð:ð :ð :ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à "Ð "Ð "Ð "Ð "Ð "ðð ð ð ð ð ð ð ð$ %.Ø$-Ø$-Ø$-Ø$-Ø$-Ø$-Ø$*Ø$/Ø$+ð%ð %Ð ð ð ð ñ ð	5ð 	5ð 	5ð 	5ð  €ð #ð %)Ø8<Ø)-ð 7;ð+Fð Fð Fð Fð Fð FðTOð Oð Oð Oð O˜<ñ Oô Oð Oð0<ð 0<ð 0<ð 0<ðfð ð ð ð@ð ð ð ð@ !Ð  Ð  Ð  Ð  Ð  à !Ð !Ð !Ð !Ð !Ð !ð ðFð Fð Fð Fð Fñ Fô Fñ „ðFð$ '+ØØØ$(Ø $ð "&Ø&*ð ð #'ðIoAð oAð oAð oAð oAð oAð oAð oAr   