ó
    ýÞ j·—  ã            	      óh  • S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKr	SSK
r
SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKJrJr  SSKJrJrJr  SSKJr  SSKJrJrJrJ r J!r!  SSK"r"\(       a  SSK#J$r$  \RJ                  " \&5      r'S	r(S
r)Sr*Sr+Sr,Sr-Sr.Sr/Sr0Sr1Sr2\" SS9r3\Rh                  " 5       S-  S-  r5\" SS9 " S S5      5       r6 " S S\75      r8\! " S S\ 5      5       r9SIS  jr:SJS! jr;SKS" jr<SLS# jr=SS$.     SMS% jjr>SNS& jr?SOS' jr@SPS( jrASQS) jrB\R†                  SRS* j5       rDSSS+ jrESTS, jrFSUS- jrGS.S/.       SVS0 jjrH\I" S1S215      rJS.S/.       SVS3 jjrKS.S/.       SVS4 jjrL\ " S5 S65      5       rMSWS7 jrN\2SS8.             SXS9 jjrO " S: S;\	R                   R¢                  5      rRSYS< jrSSYS= jrT          SZS> jrU          S[S? jrVS\S@ jrWS\(\/\0\1\2SSASB.                 S]SC jjrXS\(SDSESF.         S^SG jjrY/ SHQrZg)_aJ  ChatGPT OAuth helpers for `_ChatOpenAICodex`.

Implements OAuth 2.0 Authorization Code Flow with PKCE against the OpenAI
auth endpoints used by Codex/ChatGPT subscription auth, plus a small file-backed
token store and refresh logic.

These helpers exist to keep login and token management *separate* from model
invocation. `_ChatOpenAICodex` only consumes a `_ChatGPTOAuthTokenProvider`.

!!! warning

    This is provider-specific subscription auth and is independent from the
    standard OpenAI API-key flow used by `ChatOpenAI`. Refresh-token rotation
    against `~/.codex/auth.json` can break Codex CLI / VS Code sessions, so
    the default store lives at `~/.langchain/chatgpt-auth.json`.

!!! warning "Experimental and unofficial"

    These helpers are not an official OpenAI API integration. Use them only
    where your OpenAI account, workspace, plan, and applicable OpenAI terms
    permit ChatGPT-authenticated Codex access. You are responsible for ensuring
    your implementation complies with OpenAI's terms, usage policies, account
    restrictions, rate limits, and safeguards.
é    )ÚannotationsN)Ú	dataclassÚfield)ÚdatetimeÚ	timedeltaÚtimezone)ÚPath)ÚTYPE_CHECKINGÚAnyÚLiteralÚProtocolÚruntime_checkable)ÚIteratorÚapp_EMoamEEZ73f0CkXaXp7hrannz'https://auth.openai.com/oauth/authorizez#https://auth.openai.com/oauth/tokenz8https://auth.openai.com/api/accounts/deviceauth/usercodez5https://auth.openai.com/api/accounts/deviceauth/tokenz+https://auth.openai.com/deviceauth/callbackzhttps://api.openai.com/authÚ	localhosti¯  z/auth/callbackz#openid profile email offline_accessé   )Úminutesz
.langchainzchatgpt-auth.jsonT)Úfrozenc                  ó®   • \ rS rSr% Sr\" SS9rS\S'   \" SS9rS\S'   S\S	'   S
r	S\S'   S
r
S\S'   S
rS\S'   \" S
SS9rS\S'   SS jr\S.SS jjrSrg
)Ú_ChatGPTTokenéG   aj  A ChatGPT OAuth token bundle.

`expires_at` is timezone-aware. The JWT-derived optionals (`account_id`,
`plan_type`, `user_id`) are populated when decodable from the `id_token`;
`id_token` itself is the raw token, not derived from it. Secret-bearing
fields (`access_token`, `refresh_token`, `id_token`) are excluded from the
default `repr` so the token does not leak into logs or tracebacks.

Instances are frozen: the constructor invariants below hold for the life of
the object, which matters because providers cache and share a single token
and replace it wholesale on refresh rather than mutating fields in place.
F)ÚreprÚstrÚaccess_tokenÚrefresh_tokenr   Ú
expires_atNú
str | NoneÚ
account_idÚ	plan_typeÚuser_id)Údefaultr   Úid_tokenc                óÄ   • U R                   (       d  Sn[        U5      eU R                  (       d  Sn[        U5      eU R                  R                  c  Sn[        U5      eg)z;Validate non-empty secrets and timezone-aware `expires_at`.z*`access_token` must be a non-empty string.z+`refresh_token` must be a non-empty string.Nz*`expires_at` must be timezone-aware (UTC).)r   Ú
ValueErrorr   r   Útzinfo)ÚselfÚmsgs     ÚX/var/www/html/gaurav/venv/lib/python3.13/site-packages/langchain_openai/chatgpt_oauth.pyÚ__post_init__Ú_ChatGPTToken.__post_init__^   sV   € à× × Ø>ˆCÜ˜S“/Ð!Ø×!×!Ø?ˆCÜ˜S“/Ð!Ø�?‰?×!Ñ!Ñ)Ø>ˆCÜ˜S“/Ð!ð *ó    ©Úskewc               ój   • [         R                  " [        R                  5      U R                  U-
  :¬  $ )z@Return `True` if the token is past (or within `skew` of) expiry.)r   Únowr   Úutcr   )r&   r-   s     r(   Ú
is_expiredÚ_ChatGPTToken.is_expiredj   s#   € ä�|Š|œHŸL™LÓ)¨d¯o©oÀÑ.DÑEÐEr+   © ©ÚreturnÚNone)r-   r   r5   Úbool)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   r   Ú__annotations__r   r   r   r    r"   r)   ÚDEFAULT_REFRESH_SKEWr1   Ú__static_attributes__r3   r+   r(   r   r   G   ss   ‡ ññ  5Ñ)€L�#Ó)Ù EÑ*€M�3Ó*ØÓØ!€J�
Ó!Ø €IˆzÓ Ø€GˆZÓÙ ¨°EÑ:€HˆjÓ:ô
"ð /C÷ Fò Fr+   r   c                  ó   • \ rS rSrSrSrg)Ú_ChatGPTOAuthRefreshErroréo   zìRaised when a refresh-token grant fails irrecoverably.

Typically signals that the stored refresh token has been revoked or has
expired; the caller should re-run `login_chatgpt()` (or the device-code
equivalent) to obtain a new bundle.
r3   N)r8   r9   r:   r;   r<   r?   r3   r+   r(   rA   rA   o   s   † ôr+   rA   c                  ó@   • \ rS rSrSrS	S jrS	S jrS
S jrS
S jrSr	g)Ú_ChatGPTOAuthTokenProvideréx   z:Refresh-aware token source consumed by `_ChatOpenAICodex`.c                ó   • g)z0Return a current token, refreshing if necessary.Nr3   ©r&   s    r(   Ú	get_tokenÚ$_ChatGPTOAuthTokenProvider.get_token|   ó   € àr+   c              ƒ  ó   #   • g7f)z¥Async variant of `get_token`.

Implementations must offer the same locking and refresh guarantees
as `get_token`: concurrent callers must not race on token storage.
Nr3   rG   s    r(   Ú
aget_tokenÚ%_ChatGPTOAuthTokenProvider.aget_token€   s
   é € ð 	ùó   ‚c                ó   • g)z=Return only the access token string (sync callable for SDKs).Nr3   rG   s    r(   Úget_access_tokenÚ+_ChatGPTOAuthTokenProvider.get_access_tokenˆ   rJ   r+   c              ƒ  ó   #   • g7f)z>Return only the access token string (async callable for SDKs).Nr3   rG   s    r(   Úaget_access_tokenÚ,_ChatGPTOAuthTokenProvider.aget_access_tokenŒ   s   é € àùrN   r3   N©r5   r   ©r5   r   )
r8   r9   r:   r;   r<   rH   rL   rP   rS   r?   r3   r+   r(   rD   rD   x   s   † áDôôô÷r+   rD   c                óV   • S[        U 5      * S-  -  n[        R                  " X-   5      $ )z@Decode a single base64url JWT segment, handling missing padding.Ú=é   )ÚlenÚbase64Úurlsafe_b64decode)ÚsegmentÚpaddings     r(   Ú_b64url_decode_segmentr_   ‘   s+   € à”c˜'“l�] QÑ&Ñ'€GÜ×#Ò# GÑ$5Ó6Ð6r+   c                óö   • U (       a  U R                  S5      S:  a  0 $  U R                  SS5      u  pn[        R                  " [	        U5      5      $ ! [
        [        R                  [        4 a    0 s $ f = f)aQ  Decode a JWT's payload without signature verification.

!!! danger
    This is for *local claim extraction only*. Never use the returned
    claims for security or authorization decisions.

Args:
    token: A JWT (`header.payload.signature`).

Returns:
    Decoded payload as a dict. Returns an empty dict if the token is
    malformed.
Ú.é   )ÚcountÚsplitÚjsonÚloadsr_   r$   ÚJSONDecodeErrorÚUnicodeDecodeError)ÚtokenÚ_Úpayloads      r(   Údecode_jwt_claimsrl   —   sl   € ö �E—K‘K Ó$ qÓ(Øˆ	ðØŸ™ C¨Ó+‰ˆ�AÜ�zŠzÔ0°Ó9Ó:Ð:øÜœ×,Ñ,Ô.@ÐAó ØŠ	ðús    3A Á!A8Á7A8c                óN  • SSSS.nU (       d  U$ [        U 5      nUR                  [        5      =(       d    0 n[        U[        5      (       a<  UR                  S5      US'   UR                  S5      US'   UR                  S5      US'   US   c  [
        R                  S	5        U$ )
z>Pull the ChatGPT account/plan/user IDs out of an ID-token JWT.N)r   r   r    Úchatgpt_account_idr   Úchatgpt_plan_typer   Úchatgpt_user_idr    zsNo `chatgpt_account_id` claim extracted from the ChatGPT id_token; the `ChatGPT-Account-Id` header will be omitted.)rl   ÚgetÚCHATGPT_AUTH_CLAIMS_NAMESPACEÚ
isinstanceÚdictÚloggerÚdebug)r"   ÚoutÚclaimsÚauths       r(   Ú_extract_chatgpt_claimsrz   ®   sª   € ð ØØñ"€Cö
 Øˆ
Ü˜xÓ(€FØ�:‰:Ô3Ó4×:¸€DÜ�$œ×ÑØ ŸH™HÐ%9Ó:ˆˆLÑØŸ8™8Ð$7Ó8ˆˆKÑØŸ™Ð"3Ó4ˆˆI‰Ø
ˆ<ÑÑ ô 	�‰ðIô	
ð €Jr+   c                ó  • U R                  S5      n Ub  [        U5      OSnUS::  a  Sn[	        U5      e[
        R                  " [        R                  5      [        US9-   $ ! [        [        4 a  nSU< 3n[	        U5      UeS nAff = f)NÚ
expires_inr   z/OAuth token response had invalid `expires_in`: znOAuth token response had missing or non-positive `expires_in`; refusing to store an immediately-expired token.)Úseconds)
rq   ÚintÚ	TypeErrorr$   rA   r   r/   r   r0   r   )rk   Úrawr|   Úexcr'   s        r(   Ú_expires_at_from_responser‚   È   s‘   € Ø
�+‰+�lÓ
#€Cð6Ø!$¡”S˜”X°aˆ
ð �Qƒð>ð 	ô (¨Ó,Ð,Ü�<Š<œŸ™Ó%¬	¸*Ñ(EÑEÐEøô ”zÐ"ó 6Ø?À¹wÐGˆÜ'¨Ó,°#Ð5ûð6ús   “A$ Á$BÁ4BÂB©Úfallback_refresh_tokenc          
     ó$  • U R                  S5      (       d  Sn[        U5      eU R                  S5      n[        U5      nU R                  S5      =(       d    UnU(       d  Sn[        U5      e[        U S   U[	        U 5      US   US   US   US	9$ )
z>Build a `_ChatGPTToken` from an OAuth token-endpoint response.r   z7OAuth token response did not include an `access_token`.r"   r   zzOAuth token response did not include a `refresh_token` and no prior refresh token was available; re-run `login_chatgpt()`.r   r   r    ©r   r   r   r   r   r    r"   )rq   rA   rz   r   r‚   )rk   r„   r'   r"   rx   r   s         r(   Ú_token_from_responser‡   Ø   s¥   € ð �;‰;�~×&Ñ&ØGˆÜ'¨Ó,Ð,Ø�{‰{˜:Ó&€HÜ$ XÓ.€FØ—K‘K Ó0×JÐ4J€MÞðKð 	ô (¨Ó,Ð,ÜØ˜^Ñ,Ø#Ü,¨WÓ5Ø˜,Ñ'Ø˜Ñ%Ø�yÑ!Øñð r+   c                óø   • U R                   U R                  U R                  R                  [        R
                  5      R                  5       U R                  U R                  U R                  U R                  S.$ )Nr†   )r   r   r   Ú
astimezoner   r0   Ú	isoformatr   r   r    r"   )ri   s    r(   Ú_serialize_tokenr‹   õ   s]   € à×*Ñ*Ø×,Ñ,Ø×&Ñ&×1Ñ1´(·,±,Ó?×IÑIÓKØ×&Ñ&Ø—_‘_Ø—=‘=Ø—N‘Nñð r+   c                ó
  • U R                  S5      n[        U[        5      (       aA  [        R                  " U5      nUR
                  c  UR                  [        R                  S9nOL[        U[        [        45      (       a$  [        R                  " U[        R                  S9nOSn[        U5      e[        U S   U S   UU R                  S5      U R                  S5      U R                  S	5      U R                  S
5      S9$ )Nr   )r%   )Útzz%Stored token is missing `expires_at`.r   r   r   r   r    r"   r†   )rq   rs   r   r   Úfromisoformatr%   Úreplacer   r0   r~   ÚfloatÚfromtimestampr$   r   )ÚdataÚexpires_at_rawr   r'   s       r(   Ú_deserialize_tokenr”     s×   € Ø—X‘X˜lÓ+€NÜ�.¤#×&Ñ&Ü×+Ò+¨NÓ;ˆ
Ø×ÑÑ$Ø#×+Ñ+´8·<±<Ð+Ð@ˆJøÜ	�N¤S¬% L×	1Ñ	1Ü×+Ò+¨N¼x¿|¹|ÑL‰
à5ˆÜ˜‹oÐÜØ˜.Ñ)Ø˜?Ñ+ØØ—8‘8˜LÓ)Ø—(‘(˜;Ó'Ø—‘˜Ó#Ø—‘˜*Ó%ñð r+   c                óœ   •  [         R                  " X5        g! [        [        4 a"  n[        R                  SUU U5         SnAgSnAff = f)a  Best-effort `chmod` that logs (but does not raise) on failure.

On filesystems without POSIX perms (Windows, some FUSE/SMB mounts) the
file may end up world-readable. Logging surfaces that to operators so
they don't silently trust the "private perms" claim of the caller.
uk   Failed to set permissions %o on %s: %s â€” token store may not have private permissions on this filesystem.N)ÚosÚchmodÚOSErrorÚNotImplementedErrorru   Úwarning)ÚpathÚmoder�   s      r(   Ú_chmod_warnr�     sH   € ð	
Ü
�Š�ÕøÜÔ(Ð)ó 
Ü�‰ð;àØØ÷	
ñ 	
ûð
ús   ‚ ™A©AÁAc                ó²  • U R                   nUR                  SSS9  [        US5        U R                  U R                  S-   5      n[
        R                  " USSS9n[        R                  [        R                  -  [        R                  -  n[        R                  " X5S5      n [        R                  " USS	S
9 nUR                  U5        SSS5        UR'                  U 5        [        U S5        g! , (       d  f       N,= f! [         aF    [        R                   " ["        5         UR%                  5         SSS5        e ! , (       d  f       e = ff = f)zAWrite `data` as JSON to `path` with 0600 perms (where supported).T©ÚparentsÚexist_okiÀ  z.tmprb   )ÚindentÚ	sort_keysé€  Úwúutf-8©ÚencodingN)ÚparentÚmkdirr�   Úwith_suffixÚsuffixre   Údumpsr–   ÚO_WRONLYÚO_CREATÚO_TRUNCÚopenÚfdopenÚwriteÚ	ExceptionÚ
contextlibÚsuppressr˜   Úunlinkr�   )r›   r’   r©   Útmprk   ÚflagsÚfdÚfhs           r(   Ú_atomic_write_private_jsonr¼   *  sý   € à�[‰[€FØ
‡L�L˜¨€LÑ-Ü�˜ÔØ
×
Ñ
˜4Ÿ;™;¨Ñ/Ó
0€CÜ�jŠj˜ a°4Ñ8€GÜ�K‰Kœ"Ÿ*™*Ñ$¤r§z¡zÑ1€EÜ	�Š�˜UÓ	#€BðÜ�YŠY�r˜3¨Ò1°RØ�H‰H�WÔ÷ 2ð ‡K�K�ÔÜ��eÕ÷ 2Õ1ûäó Ü× Ò ¤Õ)Ø�J‰JŒL÷ *à÷ *Ô)àúðúsB   Â'D Â=C5ÃD Ã5
DÃ?D ÄD Ä$EÄ*EÄ;	EÅ
E	ÅEc              #  ó²  #   • U R                  U R                  S-   5      nUR                  R                  SSS9  [        R
                  " U[        R                  [        R                  -  S5      nSn  SSKn UR                  X$R                  5        SnSv •  U(       a    SSKnUR                  X$R                  5        [        R                   " U5        g! [         a!  n[        R                  SUU5         SnANhSnAff = f! [         a    [        R                  S	U 5         N’f = f! [        [        4 a   n[        R                  S
X5         SnAN–SnAff = f! U(       aT   SSKnUR                  X$R                  5        O3! [        [        4 a   n[        R                  S
X5         SnAOSnAff = f[        R                   " U5        f = f7f)a4  Best-effort cross-platform file lock around refresh + write.

On POSIX this acquires an exclusive `fcntl.flock` on a sibling
`.lock` file. On Windows (or any platform where `fcntl` is
unavailable) the lock degrades to a no-op and a warning is logged so
callers know that cross-process safety is best-effort.
z.lockTrŸ   r¤   Fr   NuZ   fcntl.flock failed on %s: %s â€” token store is not protected against cross-process races.znfcntl is unavailable on this platform; ChatGPT token store at %s is not protected against cross-process races.z%Failed to release file lock on %s: %s)r«   r¬   r©   rª   r–   r±   r¯   ÚO_RDWRÚfcntlÚflockÚLOCK_EXr˜   ru   rš   ÚImportErrorÚLOCK_UNÚclose)r›   Ú	lock_pathrº   Úlockedr¿   r�   s         r(   Ú
_file_lockrÇ   >  s�  é € ð × Ñ  §¡¨wÑ!6Ó7€IØ×Ñ×Ñ 4°$ÐÑ7Ü	�Š�œBŸJ™J¬¯©Ñ2°EÓ	:€BØ€Fðð	Ûð	Ø—‘˜B§¡Ô.Ø�ó 	æðXÛà—‘˜B§¡Ô.ô 	�Š��øô! ó Ü—‘ð=àØ÷	ñ ûðûô ó 	Ü�N‰NðFàöð	ûô0  ¤Ð)ó XÜ—‘ÐFÈ	×WÑWûðXûö ðXÛà—‘˜B§¡Õ.øÜ¤Ð)ó XÜ—‘ÐFÈ	×WÑWûðXúä
�Š��üs´   ‚A2GÁ6D Á;C ÂE! ÂGÂ$D. ÃGÃ
DÃ$D Ã;E! Ä DÄE! Ä D+Ä(E! Ä*D+Ä+E! Ä.EÄ>EÅGÅEÅGÅ!GÅ*F
Æ	GÆ
F:ÆF5Æ0GÆ5F:Æ:GÇGc                ó0   • U (       d  gS[        U 5       S3$ )Nz<empty>z<redacted len=Ú>)rZ   )Úvalues    r(   Ú_redactrË   k  s   € ÞØØœC ›J˜< qÐ)Ð)r+   c                ó¸  •  U R                  5       n[	        U[
        5      (       as  UR                  S5      nUR                  S5      =(       d    SnU SU 3R                  S5      =(       d    U R                  SS n[	        U[        5      (       a  X$4$ SU4$ SU R                  SS 4$ ! [        [         R                  4 a    SU R                  SS 4s $ f = f)zAReturn `(error_code, body_excerpt)` from an OAuth error response.Niô  ÚerrorÚerror_descriptionÚ ú: )	re   r$   rg   Útextrs   rt   rq   Ústripr   )Úresprk   rÍ   ÚdescriptionÚexcerpts        r(   Ú_parse_oauth_errorrÖ   q  sÒ   € ð%Ø—)‘)“+ˆô �'œ4× Ñ Ø—‘˜GÓ$ˆØ—k‘kÐ"5Ó6×<¸"ˆØ�G˜2˜k˜]Ð+×1Ñ1°$Ó7×J¸4¿9¹9ÀTÀc¸?ˆÜ# E¬3×/Ñ/�ÐCÐC°T¸GÐCÐCØ�—‘˜4˜C�Ð Ð øô œ×,Ñ,Ð-ó %Ø�T—Y‘Y˜t �_Ð$Ò$ð%ús   ‚B+ Â++CÃCc                ó¤   • UR                   S:  a  g [        U5      u  p#US:X  a  Sn[        U5      eSU  SUR                    SU 3n[        U5      e)Né�  Úinvalid_grantzkChatGPT refresh token is no longer valid (`invalid_grant`). Re-run `login_chatgpt()` to obtain a new token.zOAuth request to z failed with status rÐ   )Ústatus_coderÖ   rA   ÚRuntimeError)ÚurlrÓ   Ú
error_coderÕ   r'   s        r(   Ú_raise_for_oauth_responserÞ     sj   € Ø×Ñ˜#ÓØÜ,¨TÓ2Ñ€JØ�_Ó$ð>ð 	ô (¨Ó,Ð,Ø˜c˜UÐ"6°t×7GÑ7GÐ6HÈÈ7È)Ð
T€CÜ
�sÓ
Ðr+   ç      >@©Útimeoutc               ó¼   • [         R                  " US9 nUR                  U USS0S9nSSS5        [        U W5        UR	                  5       $ ! , (       d  f       N*= f)z4POST a form payload and return the parsed JSON body.rà   ÚAcceptúapplication/json©r’   ÚheadersN)ÚhttpxÚClientÚpostrÞ   re   ©rÜ   r’   rá   ÚclientrÓ   s        r(   Ú
_post_formrì   �  sZ   € ô 
�Š˜gÒ	&¨&Ø�{‰{ØØØÐ1Ð2ð ð 
ˆ÷ 
'ô ˜c 4Ô(Ø�9‰9‹;Ð÷ 
'Õ	&ús   •AÁ
AÚauthorization_pendingÚ	slow_downc               óH  • [         R                  " US9 nUR                  U USS0S9nSSS5        WR                  S:  a  UR	                  5       $ [        U5      u  pVU[        ;   a  UR	                  5       $ [        X5        UR	                  5       $ ! , (       d  f       Np= f)zCPOST a device-code poll and return expected pending error payloads.rà   rã   rä   rå   NrØ   )rç   rè   ré   rÚ   re   rÖ   Ú_DEVICE_POLL_PENDING_ERRORSrÞ   )rÜ   r’   rá   rë   rÓ   rÝ   rj   s          r(   Ú_post_device_poll_formrñ   ¡  s“   € ô 
�Š˜gÒ	&¨&Ø�{‰{ØØØÐ1Ð2ð ð 
ˆ÷ 
'ð ×Ñ˜#ÓØ�y‰y‹{ÐÜ& tÓ,�M€JØÔ0Ó0Ø�y‰y‹{ÐÜ˜cÔ(Ø�9‰9‹;Ð÷ 
'Õ	&ús   •BÂ
B!c             ƒ  ó  #   • [         R                  " US9 ISh  v•N nUR                  U USS0S9I Sh  v•N nSSS5      ISh  v•N   [        U W5        UR	                  5       $  NK N2 N$! , ISh  v•N  (       d  f       N9= f7f)zCPOST a form payload asynchronously and return the parsed JSON body.rà   Nrã   rä   rå   )rç   ÚAsyncClientré   rÞ   re   rê   s        r(   Ú_apost_formrô   ·  sy   é € ô × Ò ¨×1Ò1°VØ—[‘[ØØØÐ1Ð2ð !ð 
÷ 
ˆ÷ 2×1ô ˜c 4Ô(Ø�9‰9‹;Ðñ 2ñ
÷ 2×1×1Ð1üsS   ‚B›A'œBŸA-¶A)·A-»BÁA+Á!BÁ)A-Á+BÁ-BÁ3A6Á4BÂ Bc                  óT  • \ rS rSr% Sr\" S S9rS\S'   \r	S\S'   \
rS\S	'   \rS
\S'   SrS\S'   \" SSSS9rS\S'   \" \R"                  SSS9rS\S'   \S&S j5       rS'S jrS(S jrS(S jrS)S jr      S*S jrS+S jrS,S jrS,S jrS,S  jrS,S! jrS,S" jrS-S# jr S-S$ jr!S%r"g).Ú_FileChatGPTOAuthTokenProvideriÈ  aù  File-backed `_ChatGPTOAuthTokenProvider`.

Stores tokens at `path` (defaults to `DEFAULT_STORE_PATH`) with private
permissions and refreshes them on read when they are within
`refresh_skew` of expiry. Refresh token rotation is preserved across
writes: if the OAuth response omits `refresh_token`, the existing one is
reused.

!!! warning
    The default path is intentionally distinct from `~/.codex/auth.json`
    so that refresh-token rotation here does not invalidate Codex CLI /
    VS Code sessions.
c                 ó   • [         $ ©N)ÚDEFAULT_STORE_PATHr3   r+   r(   Ú<lambda>Ú'_FileChatGPTOAuthTokenProvider.<lambda>Ø  s   € Õ/Ar+   )Údefault_factoryr	   r›   r   Ú	client_idÚ	token_urlr   Úrefresh_skewrß   r�   rá   NF)r!   Úinitr   ú_ChatGPTToken | NoneÚ_cached)rü   r   r   zthreading.LockÚ_lockc                ó   • U " 5       $ )zëConstruct a provider with all defaults (path, client ID, etc.).

Equivalent to `_FileChatGPTOAuthTokenProvider()`; the alias exists as
a discoverable entry point for callers reading the default-path
contract from the module docstring.
r3   )Úclss    r(   Úfrom_default_storeÚ1_FileChatGPTOAuthTokenProvider.from_default_storeâ  s   € ñ ‹uˆr+   c                ó  • U R                   R                  5       (       d  g U R                   R                  SS9n [        R                  " U5      n [        U5      $ ! [        [        4 a$  nSU R                    SU S3n[        U5      UeSnAff = f! [        R                   a$  nSU R                    SU S	3n[        U5      UeSnAff = f! [        [        4 a$  nSU R                    S
U S3n[        U5      UeSnAff = f)u  Return the stored token, or `None` if no store exists.

Raises `RuntimeError` (rather than returning `None`) if the file
exists but cannot be parsed â€” that way the user is not told to
"re-login" when the actual fix is to repair or remove a corrupt
store at `self.path`.
Nr¦   r§   z&Failed to read ChatGPT token store at rÐ   zS. Repair file permissions/encoding or delete the file and re-run `login_chatgpt()`.zChatGPT token store at z is not valid JSON: z/. Delete the file and re-run `login_chatgpt()`.z is missing required fields (z0). Delete the file and re-run `login_chatgpt()`.)r›   ÚexistsÚ	read_textr˜   rh   rÛ   re   rf   rg   r”   ÚKeyErrorr$   )r&   Úraw_textr�   r'   r’   s        r(   Ú_read_from_diskÚ._FileChatGPTOAuthTokenProvider._read_from_diskì  s1  € ð �y‰y×Ñ×!Ñ!Øð	-Ø—y‘y×*Ñ*°GÐ*Ð<ˆHð	-Ü—:’:˜hÓ'ˆDð	-Ü% dÓ+Ð+øô! Ô+Ð,ó 	-à8¸¿¹¸À2ÀcÀUð K,ð ,ð ô
 ˜sÓ#¨Ð,ûð	-ûô ×#Ñ#ó 	-à)¨$¯)©)¨Ð4HØ�%ÐFðHð ô ˜sÓ#¨Ð,ûð	-ûô œ*Ð%ó 	-à)¨$¯)©)¨ð 5Ø˜%ð  %ð%ð ô
 ˜sÓ#¨Ð,ûð	-úsF   ¢A ¼B Á
C ÁBÁ.BÂBÂCÂ)CÃCÃDÃ C?Ã?Dc                óB   • [        U R                  [        U5      5        g rø   )r¼   r›   r‹   ©r&   ri   s     r(   Ú_write_to_diskÚ-_FileChatGPTOAuthTokenProvider._write_to_disk  s   € Ü" 4§9¡9Ô.>¸uÓ.EÕFr+   c                óÜ   • U R                      [        U R                  5         U R                  U5        Xl        SSS5        SSS5        g! , (       d  f       N= f! , (       d  f       g= f)z/Persist `token` to disk and cache it in memory.N)r  rÇ   r›   r  r  r  s     r(   ÚsaveÚ#_FileChatGPTOAuthTokenProvider.save  s<   € à�Z‹Zœ D§I¡IÕ.Ø×Ñ Ô&Ø ŒL÷ /�ZˆZ×.Õ.ú�Z�Zús!   �A£A»AÁ
A	ÁAÁ
A+c                ó"   • SUU R                   S.$ )Nr   )Ú
grant_typer   rý   )rý   )r&   r   s     r(   Ú_build_refresh_payloadÚ5_FileChatGPTOAuthTokenProvider._build_refresh_payload  s   € à)Ø*ØŸ™ñ
ð 	
r+   c                óF   • [        XS9nU R                  U5        X0l        U$ )Nrƒ   )r‡   r  r  )r&   ÚresponseÚprevious_refreshri   s       r(   Ú_apply_refresh_responseÚ6_FileChatGPTOAuthTokenProvider._apply_refresh_response!  s&   € ô % XÑWˆØ×Ñ˜EÔ"ØŒØˆr+   c                óú   • [         R                  S[        UR                  5      5        [	        U R
                  U R                  UR                  5      U R                  S9nU R                  X!R                  5      $ )Nz3Refreshing ChatGPT access token (refresh_token=%s).rà   )	ru   rv   rË   r   rì   rþ   r  rá   r  )r&   Úexistingr  s      r(   Ú_refresh_syncÚ,_FileChatGPTOAuthTokenProvider._refresh_sync)  sf   € Ü�‰ØAÜ�H×*Ñ*Ó+ô	
ô Ø�N‰NØ×'Ñ'¨×(>Ñ(>Ó?Ø—L‘Lñ
ˆð
 ×+Ñ+¨H×6LÑ6LÓMÐMr+   c                óˆ   • U R                   =(       d    U R                  5       nUc  SU R                   S3n[        U5      eU$ )Nz No ChatGPT OAuth token found at z=. Run `langchain_openai.chatgpt_oauth.login_chatgpt()` first.)r  r  r›   ÚFileNotFoundError)r&   r   r'   s      r(   Ú_load_existingÚ-_FileChatGPTOAuthTokenProvider._load_existing5  sM   € Ø—<‘<×9 4×#7Ñ#7Ó#9ˆØÑà2°4·9±9°+ð >Jð Jð ô $ CÓ(Ð(Øˆr+   c                óœ   • U R                  5       nUR                  U R                  S9(       d  U$ U R                  5       nUb  X l        U$ U$ ©Nr,   )r%  r1   rÿ   r  r  )r&   r   Ú
disk_tokens      r(   Ú_load_existing_before_refreshÚ<_FileChatGPTOAuthTokenProvider._load_existing_before_refresh?  sP   € Ø×&Ñ&Ó(ˆØ×"Ñ"¨×(9Ñ(9Ð"Ö:ØˆOØ×)Ñ)Ó+ˆ
ØÑ!Ø%ŒLØÐØˆr+   c                ót  • U R                      [        U R                  5         U R                  5       nUR	                  U R
                  S9(       d  Xl        UsSSS5        sSSS5        $ U R                  U5      sSSS5        sSSS5        $ ! , (       d  f       O= fSSS5        g! , (       d  f       g= f)a!  Return a fresh token, refreshing on disk if needed.

Raises:
    FileNotFoundError: No token store exists at `self.path`; run
        `login_chatgpt()` first.
    _ChatGPTOAuthRefreshError: The stored refresh token was rejected
        (e.g. revoked or expired); re-run `login_chatgpt()`.
r,   N©r  rÇ   r›   r*  r1   rÿ   r  r!  ©r&   r   s     r(   rH   Ú(_FileChatGPTOAuthTokenProvider.get_tokenI  sy   € ð �Z‹Zœ D§I¡IÕ.Ø×9Ñ9Ó;ˆHØ×&Ñ&¨D×,=Ñ,=Ð&Ö>Ø'”Ø÷	 /Ð.�Z‰Zð
 ×%Ñ% hÓ/÷ /Ð.�Z‰Z×.Õ.ú�Z�ZŽZúó.   �B)£6BÁ	B)Á,BÁ<	B)Â
B	ÂB)Â)
B7c              ƒ  ó^   #   • [         R                  " U R                  5      I Sh  v•N $  N7f)aœ  Async variant of `get_token` with the same locking guarantees.

The thread lock and cross-process file lock are acquired off the
event loop via `asyncio.to_thread` so concurrent async callers do
not race on `_cached` or on the on-disk token bundle. The HTTP
refresh runs synchronously inside that worker thread; this avoids
nesting event loops while still keeping the cross-process lock
held for the entire refresh + write window.

Raises:
    FileNotFoundError: No token store exists at `self.path`; run
        `login_chatgpt()` first.
    _ChatGPTOAuthRefreshError: The stored refresh token was rejected
        (e.g. revoked or expired); re-run `login_chatgpt()`.
N)ÚasyncioÚ	to_threadÚ_aget_token_locked_blockingrG   s    r(   rL   Ú)_FileChatGPTOAuthTokenProvider.aget_tokenY  s$   é € ô  ×&Ò& t×'GÑ'GÓH×HÐHÑHùs   ‚$-¦+§-c                ót  • U R                      [        U R                  5         U R                  5       nUR	                  U R
                  S9(       d  Xl        UsS S S 5        sS S S 5        $ U R                  U5      sS S S 5        sS S S 5        $ ! , (       d  f       O= fS S S 5        g ! , (       d  f       g = fr(  r-  r.  s     r(   r4  Ú:_FileChatGPTOAuthTokenProvider._aget_token_locked_blockingk  sw   € Ø�Z‹Zœ D§I¡IÕ.Ø×9Ñ9Ó;ˆHØ×&Ñ&¨D×,=Ñ,=Ð&Ö>Ø'”Ø÷	 /Ð.�Z‰Zð
 ×%Ñ% hÓ/÷ /Ð.�Z‰Z×.Õ.ú�Z�ZŽZúr0  c                ó6   • U R                  5       R                  $ )z$Return only the access-token string.)rH   r   rG   s    r(   rP   Ú/_FileChatGPTOAuthTokenProvider.get_access_tokens  s   € à�~‰~Ó×,Ñ,Ð,r+   c              ƒ  óV   #   • U R                  5       I Sh  v•N nUR                  $  N7f)z,Return only the access-token string (async).N)rL   r   r  s     r(   rS   Ú0_FileChatGPTOAuthTokenProvider.aget_access_tokenw  s%   é € à—o‘oÓ'×'ˆØ×!Ñ!Ð!ñ (ùs   ‚)–'—))r  )r5   rö   )r5   r  )ri   r   r5   r6   )r   r   r5   údict[str, str])r  údict[str, Any]r  r   r5   r   )r   r   r5   r   rU   rV   )#r8   r9   r:   r;   r<   r   r›   r=   ÚCHATGPT_CLIENT_IDrý   ÚCHATGPT_TOKEN_URLrþ   r>   rÿ   rá   r  Ú	threadingÚLockr  Úclassmethodr  r  r  r  r  r  r!  r%  r*  rH   rL   r4  rP   rS   r?   r3   r+   r(   rö   rö   È  sâ   ‡ ññ Ñ'AÑB€Dˆ$ÓBØ&€IˆsÓ&Ø&€IˆsÓ&Ø2€L�)Ó2Ø€GˆUÓÙ$)°$¸UÈÑ$O€GÐ!ÓOÙ!Ø!Ÿ™¨U¸ñ€Eˆ>ó ð óó ðô#-ôJGô!ô
ðØ&ðØ:=ðà	ôô
Nôôô0ô Iô$0ô-÷"r+   rö   c                 óf  • [         R                  " [        R                  " S5      5      R	                  S5      R                  S5      n [        R                  " U R                  S5      5      R                  5       n[         R                  " U5      R	                  S5      R                  S5      nX4$ )z;Return a `(code_verifier, code_challenge)` pair using S256.é@   ó   =Úascii)
r[   Úurlsafe_b64encodeÚsecretsÚtoken_bytesÚrstripÚdecodeÚhashlibÚsha256ÚencodeÚdigest)ÚverifierrO  Ú	challenges      r(   Ú_generate_pkce_pairrR  }  s‰   € ô 	× Ò ¤×!4Ò!4°RÓ!8Ó9×@Ñ@ÀÓF×MÑMÈgÓVð ô �^Š^˜HŸO™O¨GÓ4Ó5×<Ñ<Ó>€FÜ×(Ò(¨Ó0×7Ñ7¸Ó=×DÑDÀWÓM€IØÐÐr+   )ÚscopeÚextra_paramsc                ó–   • U SUUUSUS.nU(       a  UR                  U5        [         S[        R                  R	                  U5       3$ )NÚcodeÚS256)rý   Úresponse_typeÚredirect_urirS  Úcode_challengeÚcode_challenge_methodÚstateÚ?)ÚupdateÚCHATGPT_AUTHORIZE_URLÚurllibÚparseÚ	urlencode)rý   rY  r\  rZ  rS  rT  Úparamss          r(   Ú_build_authorize_urlrd  ‡  sS   € ð ØØ$ØØ(Ø!'Øñ€Fö Ø�‰�lÔ#Ü#Ð$ A¤f§l¡l×&<Ñ&<¸VÓ&DÐ%EÐFÐFr+   c                  óF   • \ rS rSr% 0 rS\S'   \rS\S'   S
S jrSS jr	Sr
g	)Ú_CallbackHandleriž  r<  Úserver_resultr   Úcallback_pathc                ó®  • [         R                  R                  U R                  5      nUR                  U R                  :w  aM  [
        R                  SUR                  U R                  5        U R                  S5        U R                  5         g [         R                  R                  UR                  5      nS H/  nUR                  U5      nU(       d  M  US   U R                  U'   M1     U R                  S5        U R                  SS5        U R                  5         U R                  R                  S5      nU(       a]  U R                  R                  S	5      n[
        R                  S
UU=(       d    S5        U(       a	  U SU S3nOSU S3n[        U5      nO[!        S5      nU R"                  R%                  UR'                  S5      5        g )Nz?Ignoring callback request for unexpected path %r (expected %r).i”  )rV  r\  rÍ   rÎ   r   éÈ   zContent-Typeztext/html; charset=utf-8rÍ   rÎ   z-ChatGPT OAuth callback returned error %r (%s)zno descriptionz	 (error: Ú)zChatGPT returned error 'z2'. Close this tab and try `login_chatgpt()` again.zUChatGPT sign-in complete. You can close this browser tab and return to your terminal.r¦   )r`  ra  Úurlparser›   rh  ru   rv   Úsend_responseÚend_headersÚparse_qsÚqueryrq   rg  Úsend_headerrÍ   Ú_oauth_error_htmlÚ_oauth_success_htmlÚwfiler³   rN  )	r&   Úparsedrp  ÚkeyrÊ   rÍ   rÎ   rÔ   Úbodys	            r(   Údo_GETÚ_CallbackHandler.do_GET¢  s–  € Ü—‘×&Ñ& t§y¡yÓ1ˆØ�;‰;˜$×,Ñ,Ó,ô
 �L‰LØQØ—‘Ø×"Ñ"ôð
 ×Ñ˜sÔ#Ø×ÑÔØÜ—‘×%Ñ% f§l¡lÓ3ˆÛBˆCØ—I‘I˜c“NˆEßˆuØ*/°©(�×"Ñ" 3Ó'ñ Cð 	×Ñ˜3ÔØ×Ñ˜Ð)CÔDØ×ÑÔØ×"Ñ"×&Ñ& wÓ/ˆÞØ $× 2Ñ 2× 6Ñ 6Ð7JÓ KÐÜ�L‰LØ?ØØ!×5Ð%5ôö
 !Ø!2Ð 3°9¸U¸GÀ1ÐE‘ð /¨u¨gð 63ð 3ð ô % [Ó1‰Dä&ð/óˆDð 	�
‰
×Ñ˜Ÿ™ WÓ-Õ.r+   c                ó   • g rø   r3   )r&   ÚformatÚargss      r(   Úlog_messageÚ_CallbackHandler.log_messageÐ  s   € àr+   r3   Nr4   )r{  r   r|  r   r5   r6   )r8   r9   r:   r;   rg  r=   ÚDEFAULT_REDIRECT_PATHrh  rx  r}  r?   r3   r+   r(   rf  rf  ž  s!   ‡ Ø$&€M�>Ó&Ø.€M�3Ó.ô,/÷\r+   rf  c                ó   • [        SSU SS9$ )NzChatGPT sign-in completezYou're signed inÚsuccess©ÚtitleÚheadingÚmessageÚstatus©Ú_oauth_result_html©r…  s    r(   rs  rs  Õ  s   € ÜØ(Ø"ØØñ	ð r+   c                ó   • [        SSU SS9$ )NzChatGPT sign-in failedzSign-in failedrÍ   r‚  r‡  r‰  s    r(   rr  rr  Þ  s   € ÜØ&Ø ØØñ	ð r+   c                óì   • US:X  a  SOSnUS:X  a  SOSnUS:X  a  SOSn[         R                  " U 5      n[         R                  " U5      n[         R                  " U5      n	SU S	U S
U SU SU SU	 S3$ )Nr�  z#137333z#b3261ez#eef7f0z#fceeeez&check;Ú!z†<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>aM  </title><style>body{margin:0;min-height:100vh;display:grid;place-items:center;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#f8faf9;color:#1f2328}.panel{width:min(480px,calc(100vw - 40px));box-sizing:border-box;padding:32px;border:1px solid #d8dee4;border-radius:8px;background:#fff;box-shadow:0 18px 45px rgba(31,35,40,.08)}.mark{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;margin-bottom:20px;font-weight:700;font-size:22px}h1{font-size:24px;line-height:1.2;margin:0 0 10px}p{font-size:15px;line-height:1.5;margin:0;color:#57606a}@media (prefers-color-scheme: dark){body{background:#0d1117;color:#e6edf3}.panel{background:#161b22;border-color:#30363d;box-shadow:0 18px 45px rgba(0,0,0,.4)}p{color:#9da7b3}}</style></head><body><main class="panel"><div class="mark" style="background:z;color:z">z
</div><h1>z</h1><p>z</p></main></body></html>)ÚhtmlÚescape)
rƒ  r„  r…  r†  ÚaccentÚ
backgroundÚmarkÚescaped_titleÚescaped_headingÚescaped_messages
             r(   rˆ  rˆ  ç  sœ   € ð ! IÓ-‰Y°9€FØ$¨	Ó1‘°y€JØ )Ó+‰9°€DÜ—K’K Ó&€MÜ—k’k 'Ó*€OÜ—k’k 'Ó*€Oð	à�ð !/ð& 0:¨l¸'À&ÀÈØˆ&ð ØÐ˜x¨Ð'8ð 9ð/	ðr+   c                óÆ  •  " S S[         5      nX$l         [        R                  R	                  X4U5      nSUl        [        R                  " 5       U-   n [        R                  " 5       U:  a�  UR                  5         UR                  R                  S5      (       d   UR                  R                  S	5      (       a%  [        UR                  5      UR                  5         $ [        R                  " 5       U:  a  M�  UR                  5         S
U  SU 3n[        U5      e! [
         a  nSU  SU SU S3n[        U5      UeS nAff = f! UR                  5         f = f)Nc                  ó$   • \ rS rSr% 0 rS\S'   Srg)Ú1_wait_for_callback.<locals>._BoundCallbackHandleri  r<  rg  r3   N)r8   r9   r:   r;   rg  r=   r?   r3   r+   r(   Ú_BoundCallbackHandlerr—    s   ‡ Ø(*ˆ�~Ö*r+   r˜  z7Could not bind ChatGPT OAuth callback server on http://Ú:rÐ   zI. Free the port or pass `port=` to `login_chatgpt()` with an unused port.g      ð?rV  rÍ   z7Timed out waiting for ChatGPT OAuth callback on http://)rf  rh  ÚhttpÚserverÚ
HTTPServerr˜   rÛ   rá   ÚtimeÚ	monotonicÚhandle_requestrg  rq   rt   Úserver_closeÚTimeoutError)	ÚhostÚportrh  rá   r˜  r›  r�   r'   Údeadlines	            r(   Ú_wait_for_callbackr¥    sN  € ô+Ô 0ô +ð +8Ô'ð)Ü—‘×'Ñ'¨¨Ð6KÓLˆð €F„NÜ�~Š~Ó 'Ñ)€HðÜ�nŠnÓ Ó)Ø×!Ñ!Ô#Ø$×2Ñ2×6Ñ6Ø÷ñ à&×4Ñ4×8Ñ8¸×AÑAÜÐ1×?Ñ?Ó@à×ÑÕô �nŠnÓ Õ)ð 	×ÑÔØCÀDÀ6ÈÈ4È&Ð
Q€CÜ
�sÓ
Ðøô' ó )ðØ�V˜1˜T˜F " S Eð *8ð8ð 	ô
 ˜3Ó SÐ(ûð)ûð" 	×ÑÕús*   —!D$ ÁA=E Ã&E Ä$
EÄ.EÅEÅE c                óª   • U S:X  a  g [         R                  " U 5      R                  nU(       d  SU < S3n[        U5      eg! [         a    Sn N(f = f)uÔ  Reject non-loopback callback hosts.

The callback server receives the OAuth authorization `code` in the request
URL. Binding it to a non-loopback interface (e.g. `0.0.0.0`) would expose
that code on the local network, so only loopback hosts are permitted â€”
RFC 8252 Â§8.3 expects a loopback redirect for native-app PKCE flows.

Args:
    host: The callback host passed to `login_chatgpt`.

Raises:
    ValueError: `host` is not `localhost` or a loopback IP address.
r   NFz`host=zâ` is not a loopback address. The OAuth callback server receives the authorization code in the request URL, so it must bind to a loopback interface (`localhost`, `127.0.0.1`, or `::1`) to avoid exposing the code on the network.)Ú	ipaddressÚ
ip_addressÚis_loopbackr$   )r¢  r©  r'   s      r(   Ú_validate_loopback_hostrª  5  sn   € ð ˆ{ÓØðÜ×*Ò*¨4Ó0×<Ñ<ˆö à�T‘Hð @ð @ð 	ô ˜‹oÐð øô ó àŠðús   ‰ A ÁAÁAg     Àr@)Ú
store_pathrý   r¢  r£  rh  rS  Úopen_browserrá   c           	     ó  • [        U5        SU SU U 3n[        R                  " S5      n	[        5       u  p«[	        UUU	UUS9n[        SU S35        [        R                  S[        5        U(       a   [        R                  " U5        [        X#XGS
9nUR                  S5      U	:w  a  Sn[        U5      eSU;   a(  UR                  SS5      nSUS    SU 3n[        U5      eUR                  S5      nU(       d  Sn[        U5      e[!        ["        SUUUU
S.5      n[%        U5      n['        U =(       d    [(        US9nUR+                  U5        U$ ! [        R                   a   n[        R                  SU5         S	nANùS	nAff = f)a  Run the ChatGPT OAuth 2.0 Authorization Code Flow with PKCE.

Starts a loopback callback server, optionally opens a browser to the
OpenAI authorize endpoint (when `open_browser=True`; the URL is always
printed as a fallback), exchanges the returned code for tokens, and
persists them via `_FileChatGPTOAuthTokenProvider`.

Args:
    store_path: Where to persist the token. Defaults to
        `DEFAULT_STORE_PATH`.
    client_id: OAuth client ID (defaults to Codex/ChatGPT client).
    host: Local callback host. Must be a loopback address.
    port: Local callback port.
    callback_path: Local callback path.
    scope: OAuth scope string.
    open_browser: Whether to launch the system browser.
    timeout: Seconds to wait for the callback.

Returns:
    A `_FileChatGPTOAuthTokenProvider` ready for use by
        `_ChatOpenAICodex`.

Raises:
    ValueError: `host` is not a loopback address.
    RuntimeError: The callback server could not bind, the `state` did not
        match (CSRF), the provider returned an OAuth error, or no
        authorization code was returned.
    TimeoutError: No callback was received within `timeout` seconds.

See Also:
    `login_chatgpt_device`: Headless fallback for environments without a
        browser or the ability to bind a localhost callback port.
zhttp://r™  é    )rý   rY  r\  rZ  rS  z9
ChatGPT sign-in: open the following URL in a browser:
  Ú
z"Opening ChatGPT sign-in flow at %sz;Could not launch a browser: %s. Copy the URL above instead.N)r¢  r£  rh  rá   r\  z&ChatGPT OAuth callback state mismatch.rÍ   rÎ   rÏ   z'ChatGPT OAuth callback returned error: Ú rV  z=ChatGPT OAuth callback did not include an authorization code.Úauthorization_code©r  rV  rY  rý   Úcode_verifier©r›   rý   )rª  rH  Útoken_urlsaferR  rd  Úprintru   Úinfor_  Ú
webbrowserr±   ÚErrorrš   r¥  rq   rÛ   rì   r?  r‡   rö   rù   r  )r«  rý   r¢  r£  rh  rS  r¬  rá   rY  r\  rP  rQ  Úauthorize_urlr�   Úresultr'   rÔ   rV  r  ri   Úproviders                        r(   Úlogin_chatgptr½  T  s©  € ôX ˜DÔ!Ø˜T˜F ! D 6¨-¨Ð9€LÜ×!Ò! "Ó%€EÜ-Ó/Ñ€HÜ(ØØ!ØØ Øñ€Mô 
Ø
EÀmÀ_ÐTVÐWôô ‡K�KÐ4Ô6KÔLÞð	Ü�OŠO˜MÔ*ô  Ø¨Mñ€Fð ‡z�z�'Ó˜eÓ#Ø6ˆÜ˜3ÓÐØ�&ÓØ—j‘jÐ!4°bÓ9ˆØ7¸¸w¹Ð7HÈÈ+ÈÐWˆÜ˜3ÓÐØ�:‰:�fÓ€DÞØMˆÜ˜3ÓÐäÜà.ØØ(Ø"Ø%ñ	
ó	€Hô ! Ó*€EÜ-Ø×-Ô-¸ñ€Hð ‡M�M�%ÔØ€OøôO ×Ñó 	Ü�N‰NØMØ÷ñ ûð	ús   Á6E ÅF
Å*FÆF
g      @g     À‚@)r«  rý   Úpoll_intervalrá   c           	     ó´  • [        5       u  pE[        [        U[        USS.5      nUR	                  S5      nUR	                  S5      nUR	                  S5      =(       d    UR	                  S5      n	U(       a  U(       a  U	(       d  Sn
[        U
5      e[        R                  SX˜5        [        R                  " 5       U-   nS	nUn[        R                  " 5       U:  a™  [        [        XS
.5      nUR	                  S5      (       a  US   nOkUR	                  S5      nUS:X  a  US-  nOU(       a  US:w  a  SU 3n
[        U
5      e[        R                  " U5        [        R                  " 5       U:  a  M™  U(       d  Sn
[        U
5      e[        [        SU[        UUS.5      n[!        U5      n[#        U =(       d    [$        US9nUR'                  U5        U$ )aª  Run the ChatGPT device-code OAuth flow.

This is the headless fallback for environments without a browser. The
function prints a verification URL and user code, polls for completion,
then exchanges the resulting code via the OAuth token endpoint using
`CHATGPT_DEVICE_REDIRECT_URI`.

Args:
    store_path: Where to persist the token. Defaults to
        `DEFAULT_STORE_PATH`.
    client_id: OAuth client ID (defaults to Codex/ChatGPT client).
    poll_interval: Seconds between polls.
    timeout: Total seconds to wait.

Returns:
    A configured `_FileChatGPTOAuthTokenProvider`.

Raises:
    RuntimeError: The device-code response was missing required fields, or
        device authorization failed with a terminal error.
    TimeoutError: Authorization was not completed within `timeout` seconds.

See Also:
    `login_chatgpt`: Browser-based loopback flow preferred when a local
        browser and free callback port are available.
rW  )rý   rS  rZ  r[  Údevice_codeÚ	user_codeÚverification_uriÚverification_uri_completez5ChatGPT device-code response missing required fields.z,Open %s in a browser and enter user code: %sN)rý   rÀ  r±  rÍ   rî   r   rí   zDevice authorization failed: z3Timed out waiting for ChatGPT device authorization.r²  r´  )rR  rì   ÚCHATGPT_DEVICE_CODE_URLÚDEFAULT_SCOPErq   rÛ   ru   r·  r�  rž  rñ   ÚCHATGPT_DEVICE_TOKEN_URLÚsleepr¡  r?  ÚCHATGPT_DEVICE_REDIRECT_URIr‡   rö   rù   r  )r«  rý   r¾  rá   Ú	_verifierrQ  ÚstartrÀ  rÁ  rÂ  r'   r¤  r±  Úcurrent_intervalÚpollrÍ   r  ri   r¼  s                      r(   Úlogin_chatgpt_devicerÍ  ¿  sÊ  € ôB /Ó0Ñ€IÜÜà"Ü"Ø'Ø%+ñ		
ó€Eð —)‘)˜MÓ*€KØ—	‘	˜+Ó&€IØ—y‘yÐ!3Ó4÷ ¸¿	¹	Ø#ó9Ðö žIÖ*:ØEˆÜ˜3ÓÐÜ
‡K�KØ6Ð8Hôô �~Š~Ó 'Ñ)€HØ%)ÐØ$ÐÜ
�.Š.Ó
˜XÓ
%Ü%Ü$Ø#Ñ@ó
ˆð �8‰8Ð(×)Ñ)Ø!%Ð&:Ñ!;ÐØØ—‘˜Ó!ˆØ�KÓð  Ñ!ÑÞ�uÐ 7Ó7Ø1°%°Ð9ˆCÜ˜sÓ#Ð#Ü�
Š
Ð#Ô$ô! �.Š.Ó
˜XÕ
%ö" ØCˆÜ˜3ÓÐäÜà.Ø&Ü7Ø"Ø&ñ	
ó	€Hô ! Ó*€EÜ-Ø×-Ô-¸ñ€Hð ‡M�M�%ÔØ€Or+   )r_  r>  r?  rl   r½  rÍ  )r]   r   r5   Úbytes)ri   r   r5   r=  )r"   r   r5   zdict[str, str | None])rk   r=  r5   r   )rk   r=  r„   r   r5   r   )ri   r   r5   r=  )r’   r=  r5   r   )r›   r	   rœ   r~   r5   r6   )r›   r	   r’   r=  r5   r6   )r›   r	   r5   zIterator[None])rÊ   r   r5   r   )rÓ   úhttpx.Responser5   ztuple[str | None, str])rÜ   r   rÓ   rÏ  r5   r6   )rÜ   r   r’   r<  rá   r�   r5   r=  )r5   ztuple[str, str])rý   r   rY  r   r\  r   rZ  r   rS  r   rT  zdict[str, str] | Noner5   r   )r…  r   r5   r   )
rƒ  r   r„  r   r…  r   r†  zLiteral['success', 'error']r5   r   )
r¢  r   r£  r~   rh  r   rá   r�   r5   r<  )r¢  r   r5   r6   )r«  úPath | Nonerý   r   r¢  r   r£  r~   rh  r   rS  r   r¬  r7   rá   r�   r5   rö   )
r«  rÐ  rý   r   r¾  r�   rá   r�   r5   rö   )[r<   Ú
__future__r   r2  r[   rµ   rL  r�  Úhttp.serverrš  r§  re   Úloggingr–   rH  r@  r�  Úurllib.parser`  r¸  Údataclassesr   r   r   r   r   Úpathlibr	   Útypingr
   r   r   r   r   rç   Úcollections.abcr   Ú	getLoggerr8   ru   r>  r_  r?  rÄ  rÆ  rÈ  rr   ÚDEFAULT_REDIRECT_HOSTÚDEFAULT_REDIRECT_PORTr  rÅ  r>   Úhomerù   r   rÛ   rA   rD   r_   rl   rz   r‚   r‡   r‹   r”   r�   r¼   ÚcontextmanagerrÇ   rË   rÖ   rÞ   rì   Ú	frozensetrð   rñ   rô   rö   rR  rd  r›  ÚBaseHTTPRequestHandlerrf  rs  rr  rˆ  r¥  rª  r½  rÍ  Ú__all__r3   r+   r(   Ú<module>rá     s  ðñõ2 #ã Û Û Û Û Û Û Û Û Û 	Û Û Û Û Û ß (ß 2Ñ 2Ý ß KÕ Kã æÝ(à	×	Ò	˜8Ó	$€ð 3Ð ØAÐ Ø9Ð ØTÐ ØRÐ ØKÐ Ø =Ð Ø#Ð ØÐ Ø(Ð Ø5€Ù ¨Ñ+Ð Ø—Y’Y“[ <Ñ/Ð2EÑEÐ ñ �$Ñ÷$Fð $Fó ð$FôN ô ð ô ó ó ðô07ôô.ô4Fð& *.ñØðð 'ðð õ	ô:	ôô,
ô&ð( ×Ñó)ó ð)ôX*ô!ôð$ ñ	Ø	ðà
ðð ð	ð
 õñ" (Ð)@À+Ð(NÓOÐ ð ñ	Ø	ðà
ðð ð	ð
 õð4 ñ	Ø	ðà
ðð ð	ð
 õð" ÷q"ð q"ó ðq"ôhð  Ø*.ñGàðGð ðGð ð	Gð
 ðGð ðGð (ðGð 	õGô.4�t—{‘{×9Ñ9ô 4ônôð(àð(ð ð(ð ð	(ð
 (ð(ð 	ô(ðV à
ð ð ð ð ð	 ð
 ð ð ô ôFðB #Ø&Ø%Ø%Ø.ØØØñhàðhð ðhð ð	hð
 ðhð ðhð ðhð ðhð ðhð $õhðZ #Ø&ØØñ^àð^ð ð^ð ð	^ð
 ð^ð $õ^òB�r+   