
    +j!                    $   d Z ddlmZ ddlZddlZddlmZ ddlmZmZ ddl	m
Z
mZ  G d de          Zd	Zd
ZdZ ed           G d d                      ZdZd-d.dZd-d/dZ	 d0d1d!Zd2d$Zd3d&Z ed'd(d(ej        )          Zd4d*Zd5d,ZdS )6u  Opaque keyset-pagination cursor for /api/assets.

Payload JSON uses short keys to keep the encoded length small:

    {"s": <sort_field>, "v": <value>, "id": <id>, "o": <order>}

The `o` key binds the cursor to the sort direction it was minted under,
so replaying a `desc` cursor against an `asc` request fails with
``INVALID_CURSOR`` rather than silently walking the wrong direction.
`o` is mandatory on every payload — a cursor without it is rejected as
malformed.

Encoding is base64url with no padding. Cursors are opaque tokens: the
payload format is internal to this server, and clients must treat a
cursor as a black box handed back via `next_cursor`. No byte-level
compatibility with any other implementation is required.

Time values are serialized as Unix microseconds (UTC) — microsecond
precision is sufficient to round-trip the timestamps stored by the
database without rounding rows in the same millisecond bucket.
    )annotationsN)	dataclass)datetimetimezone)IterableOptionalc                      e Zd ZdZdS )InvalidCursorErrorzRaised on a malformed, oversized, or unsupported-sort-field cursor.

    Map to a 400 response with code ``INVALID_CURSOR`` at the handler.
    N)__name__
__module____qualname____doc__     :/home/wildlama/comfy/ComfyUI/app/assets/services/cursor.pyr
   r
      s           r   r
   i    i      T)frozenc                  8    e Zd ZU ded<   ded<   ded<   ded<   dS )CursorPayloadstr
sort_fieldvalueidorderN)r   r   r   __annotations__r   r   r   r   r   :   s4         OOOJJJGGGJJJJJr   r   )ascdescr   r   r   r   r   r   returnc                   |t           vrt          dt            d|          |st          d          t          |          t          k    rt          d          t          |          t          k    rt          d          | |||d}t          j        |dd	          }t          j        |	                    d
                    
                    d                              d          S )a   Encode a cursor payload as a base64url (no-padding) string.

    `order` binds the cursor to the sort direction it was minted under so a
    later request with a flipped `order` query parameter is rejected with
    ``INVALID_CURSOR`` rather than silently walking the wrong direction.
    zorder must be one of z, got zid must be non-emptyid exceeds maximum lengthvalue exceeds maximum length)svr   o),:F)
separatorsensure_asciizutf-8   =ascii)_VALID_ORDERSr
   lenMAX_CURSOR_ID_LENGTHMAX_CURSOR_VALUE_LENGTHjsondumpsbase64urlsafe_b64encodeencoderstripdecode)r   r   r   r   payloadraws         r   encode_cursorr8   E   s     M!! !W!W!We!W!WXXX  9 !7888
2ww%%% !<===
5zz+++ !?@@@U"5AAG
*W%
H
H
HC #CJJw$7$788??EELLWUUUr   tr   c                    |j         t          d          t          |                    t          j                            }t          | t          |          ||          S )a  Encode a time-typed cursor at Unix microsecond precision.

    Accepts an aware datetime (any timezone) and normalizes to UTC. Naive
    datetimes are rejected so callers can't accidentally encode the local
    wall-clock value of a UTC-stored timestamp.
    Nz2encode_cursor_from_time requires an aware datetime)r   )tzinfo
ValueError_datetime_to_unix_micros
astimezoner   utcr8   r   )r   r9   r   r   micross        r   encode_cursor_from_timerA   _   sS     	xMNNN%all8<&@&@AAFS[["EBBBBr   cursorallowed_sort_fieldsIterable[str]expected_order
str | Nonec                   t          |           t          k    rt          d          	 dt          |            dz  z  }t          j        | |z             }n6# t
          t          j        j        f$ r}t          d|           |d}~ww xY w	 t          j	        |          }n1# t          j
        t          f$ r}t          d|           |d}~ww xY wt          |t                    st          d          |                    d          }|                    d	          }|                    d
          }	|                    d          }
t          |t                    r*t          |t                    rt          |	t                    st          d          |	dk    rt          d          t          |	          t           k    rt          d          t          |          t"          k    rt          d          ||vrt          d|          t          |
t                    st          d          |
t$          vrt          d|
          ||
|k    rt          d|
d|          t'          |||	|
          S )u0  Parse an opaque cursor.

    ``allowed_sort_fields`` is the endpoint's accepted sort-field list — a
    cursor carrying a field outside this set is rejected so a cursor minted
    for one column can't be replayed against another (e.g. a ``created_at``
    timestamp string compared against a ``name`` column).

    ``expected_order`` (``"asc"``/``"desc"``), when supplied, must match the
    payload's ``o`` field. ``o`` is required on every payload; a cursor
    missing it is rejected as malformed.

    Passing no allowed fields rejects every cursor.
    zcursor exceeds maximum length=   z
encoding: Nz	payload: zpayload: expected objectr"   r#   r   r$   z%payload: missing or non-string s/v/id z
missing idr    r!   zunsupported sort field zmissing or non-string ozunsupported order zcursor order z does not match request order )r   r   r   r   )r,   MAX_ENCODED_CURSOR_LENGTHr
   r1   urlsafe_b64decoder<   binasciiErrorr/   loadsJSONDecodeErrorUnicodeDecodeError
isinstancedictgetr   r-   r.   r+   r   )rB   rC   rE   paddingr7   edecodedr   r   r   r   s              r   decode_cursorrX   l   s   $ 6{{... !@AAA: #f++)*&v'788-. : : : !1a!1!1229:9*S// "45 9 9 9 Q11q89 gt$$ = !;<<<S!!JKKE	T		BKKEj#&& Jj.D.D JJWY[^L_L_ J !HIII	Rxx ...
2ww%%% !<===
5zz+++ !?@@@,,, !I:!I!IJJJeS!! < !:;;;M!! !?e!?!?@@@!e~&=&= UEUU>UU
 
 	
 Je%PPPPs/   -A B
2BB
B# #C9CCr6   Optional[CursorPayload]c                   | t          d          	 t          | j                  }n%# t          $ r}t          d|           |d}~ww xY w	 t	          |          S # t
          t          t          f$ r}t          d|           |d}~ww xY w)zDParse a time-typed cursor value as Unix microseconds, returning UTC.Nnil cursor payloadz value is not a valid timestamp: z%value is out of representable range: )r
   intr   r<   _unix_micros_to_datetimeOverflowErrorOSError)r6   r@   rV   s      r   decode_cursor_timer`      s     !5666PW]## P P P !GA!G!GHHaOPU'///7J/ U U U !!L!L!LMMSTTUs,   ( 
A
AA
A B4BBr\   c                    | t          d          	 t          | j                  S # t          $ r}t          d|           |d}~ww xY w)z*Parse a cursor value as a base-10 integer.Nr[   zvalue is not a valid integer: )r
   r\   r   r<   )r6   rV   s     r   decode_cursor_intrb      sh     !5666N7=!!! N N N !E!!E!EFFAMNs   ' 
A	AA	i     )r;   c                P    | t           z
  }|j        dz  |j        z   dz  |j        z   S )zBConvert an aware UTC datetime to Unix microseconds (integer math).iQ @B )_EPOCHdayssecondsmicroseconds)r9   deltas     r   r=   r=      s,    JEJ%-/9<u?QQQr   r@   c                    t          | d          \  }}t          j        |t          j                                      |          S )zBConvert Unix microseconds to a UTC datetime, preserving precision.re   )tz)microsecond)divmodr   fromtimestampr   r?   replace)r@   rh   micro_remainders      r   r]   r]      s@    %fi88G_!'hl;;;CCP_C```r   )r   )
r   r   r   r   r   r   r   r   r   r   )
r   r   r9   r   r   r   r   r   r   r   )N)rB   r   rC   rD   rE   rF   r   r   )r6   rY   r   r   )r6   rY   r   r\   )r9   r   r   r\   )r@   r\   r   r   )r   
__future__r   r1   r/   dataclassesr   r   r   typingr   r   r<   r
   rK   r.   r-   r   r+   r8   rA   rX   r`   rb   r?   rf   r=   r]   r   r   r   <module>ru      s   * # " " " " "   ! ! ! ! ! ! ' ' ' ' ' ' ' ' % % % % % % % %       , !    $         V V V V V4
C 
C 
C 
C 
C  "&@Q @Q @Q @Q @QFU U U U N N N N 
$1X\	2	2	2R R R Ra a a a a ar   