
    kKjv              
           d Z ddlmZ ddlmZmZ  G d de      ZdZdZeefZ	de
d	z  d
e
de
de
de
f
dZde
defdZde
de
fdZde
d	z  de
fdZy	)u  Docket and Redis key encoding for background tasks.

The compound Docket task key embeds the auth boundary so that the parser can
reject cross-scope access without consulting Redis.  Authenticated and
anonymous tasks live in disjoint keyspaces:

    auth:{enc_scope}:{client_task_id}:{task_type}:{enc_identifier}
    anon:{client_task_id}:{task_type}:{enc_identifier}

The same `auth/anon` partition is used for the per-task Redis prefix
(``fastmcp:task:auth:{enc_scope}`` vs ``fastmcp:task:anon``) — see
``task_redis_prefix``.

``task_scope`` is the raw scope identifier (typically derived from
``client_id`` or ``client_id|sub``); encoding happens once, at the boundary,
in this module.
    )	TypedDict)quoteunquotec                   @    e Zd ZU dZedz  ed<   eed<   eed<   eed<   y)TaskKeyPartszDecoded segments of a Docket task key.

    ``task_scope`` is ``None`` for anonymous tasks, the raw scope string
    otherwise.
    N
task_scopeclient_task_id	task_typecomponent_identifier)__name__
__module____qualname____doc__str__annotations__     j/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/tasks/keys.pyr   r      s$     d
Nr   r   authanonr   Nr	   r
   r   returnc           	          t        |d      }| t         d| d| d| S t        | d      }t         d| d| d| d| 	S )az  Build Docket task key with embedded metadata.

    When ``task_scope`` is ``None`` the task is anonymous and lives in the
    ``anon`` keyspace.  Otherwise it lives under ``auth:{enc_scope}``.

    Args:
        task_scope: Raw authorization scope, or ``None`` for anonymous tasks
        client_task_id: Client-provided task ID
        task_type: Type of task ("tool", "prompt", "resource")
        component_identifier: Tool name, prompt name, or resource URI

    Returns:
        Encoded task key for Docket

    Examples:
        >>> build_task_key("client-a", "task456", "tool", "my_tool")
        'auth:client-a:task456:tool:my_tool'

        >>> build_task_key(None, "task456", "tool", "my_tool")
        'anon:task456:tool:my_tool'

        >>> build_task_key("client-a", "task456", "resource", "file://data.txt")
        'auth:client-a:task456:resource:file%3A%2F%2Fdata.txt'
     safe:)r   	_ANON_TAG	_AUTH_TAG)r   r	   r
   r   encoded_identifierencoded_scopes         r   build_task_keyr!   )   sl    < 3"=An-Qyk;M:NOO*2.M+Q}oQ~&6a	{!DVCWXr   task_keyc                    | j                  d      \  }}}|t        vs|st        d|  dt         d      |t        k(  rE|j	                  dd      }t        |      dk7  rt        d|  d      |\  }}}d	||t        |      d
S |j	                  dd      }t        |      dk7  rt        d|  d      |\  }}}}t        |      ||t        |      d
S )a  Parse Docket task key to extract metadata.

    Args:
        task_key: Encoded task key from Docket

    Returns:
        Dict with keys: ``task_scope`` (``str | None``), ``client_task_id``,
        ``task_type``, ``component_identifier``.

    Raises:
        ValueError: If the key has an unrecognized tag or wrong segment count.

    Examples:
        >>> parse_task_key("auth:client-a:task456:tool:my_tool")
        `{'task_scope': 'client-a', 'client_task_id': 'task456', 'task_type': 'tool', 'component_identifier': 'my_tool'}`

        >>> parse_task_key("anon:task456:tool:my_tool")
        `{'task_scope': None, 'client_task_id': 'task456', 'task_type': 'tool', 'component_identifier': 'my_tool'}`
    r   zInvalid task key format: z. Expected leading tag in .      zInvalid anonymous task key: zD. Expected: anon:{client_task_id}:{task_type}:{component_identifier}N)r   r	   r
   r      z Invalid authenticated task key: zP. Expected: auth:{enc_scope}:{client_task_id}:{task_type}:{component_identifier})	partition_VALID_TAGS
ValueErrorr   splitlenr   )	r"   tag_restpartsr	   r
   r   r    s	            r   parse_task_keyr1   P   s*   ( %%c*LCD
+T'z 2''2m16
 	

 i

3"u:?.xj 9[ \  9>5	#5,"$+,>$?	
 	
 JJsAE
5zQ.xj 9e f
 	
 DI@M>9.@m,( '(: ;	 r   c                     t        |       d   S )a]  Extract just the client task ID from a task key.

    Args:
        task_key: Full encoded task key

    Returns:
        Client-provided task ID

    Examples:
        >>> get_client_task_id_from_key("auth:client-a:task456:tool:my_tool")
        'task456'

        >>> get_client_task_id_from_key("anon:task456:tool:my_tool")
        'task456'
    r	   )r1   )r"   s    r   get_client_task_id_from_keyr3      s      (#$455r   c                 F    | 	dt          S dt         dt        | d       S )zReturn the Redis key prefix that owns a given scope.

    Authenticated tasks live under ``fastmcp:task:auth:{enc_scope}``;
    anonymous tasks live under ``fastmcp:task:anon``.  Callers append
    ``f":{task_id}:..."`` to compose the final key.
    zfastmcp:task:r   r   r   )r   r   r   )r   s    r   task_redis_prefixr5      s2     yk**9+QuZb'A&BCCr   )r   typingr   urllib.parser   r   r   r   r   r)   r   r!   r1   r3   r5   r   r   r   <module>r8      s   $  '
9 
 		)$$d
$$ $ 	$
 	$N6S 6\ 6r6# 6# 6&	D#* 	D 	Dr   