Deprecate legacy login/register methods with warnings

- Add DeprecationWarning to login() and register() static methods
- Update docstrings with .. deprecated:: notices
- Sync types with backend changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-25 00:48:33 -04:00
1 parent 024ea8ee97
commit 47a8038e8d
4 files changed
+329 -9

No files matched your search

+44
View File
@@ -18,17 +18,32 @@ from .types import (
EAR,
Agent,
AgentKey,
AgentAssignment,
AdminEvent,
EpochAnchor,
MemberEntry,
Operation,
Receipt,
Epoch,
Export,
Organization,
User,
WebhookEntry,
AdminAction,
AgentStatus,
ExportStatus,
IntegrationType,
KeyStatus,
RbacRole,
RegisterAgentRequest,
RegisterAgentResponse,
UpdateAgentRequest,
UpdateAgentResponse,
GetAgentResponse,
ListAgentsResponse,
DeleteAgentResponse,
FreezeAgentResponse,
UnfreezeAgentResponse,
SubmitOperationResponse,
GetOperationResponse,
VerifyOperationResponse,
@@ -38,6 +53,10 @@ from .types import (
CreateExportResponse,
GetExportResponse,
ListExportsResponse,
ListWebhooksResponse,
RegisterWebhookResponse,
ListMembersResponse,
ListAdminEventsResponse,
JWKSResponse,
AuthRegisterResponse,
AuthLoginResponse,
@@ -47,6 +66,7 @@ from .types import (
IssueTokenResponse,
RotateTokenResponse,
HealthResponse,
DeepHealthResponse,
)
__version__ = "1.2.0"
@@ -66,21 +86,40 @@ __all__ = [
"base64url_decode",
"generate_nonce",
"generate_uuidv7",
# Literal type aliases
"AdminAction",
"AgentStatus",
"ExportStatus",
"IntegrationType",
"KeyStatus",
"RbacRole",
# Entity types
"EOR",
"EAR",
"Agent",
"AgentAssignment",
"AgentKey",
"AdminEvent",
"EpochAnchor",
"MemberEntry",
"Operation",
"Receipt",
"Epoch",
"Export",
"Organization",
"User",
"WebhookEntry",
# Request types
"RegisterAgentRequest",
"UpdateAgentRequest",
# Response types
"RegisterAgentResponse",
"UpdateAgentResponse",
"GetAgentResponse",
"ListAgentsResponse",
"DeleteAgentResponse",
"FreezeAgentResponse",
"UnfreezeAgentResponse",
"SubmitOperationResponse",
"GetOperationResponse",
"VerifyOperationResponse",
@@ -90,6 +129,10 @@ __all__ = [
"CreateExportResponse",
"GetExportResponse",
"ListExportsResponse",
"ListWebhooksResponse",
"RegisterWebhookResponse",
"ListMembersResponse",
"ListAdminEventsResponse",
"JWKSResponse",
"AuthRegisterResponse",
"AuthLoginResponse",
@@ -99,4 +142,5 @@ __all__ = [
"IssueTokenResponse",
"RotateTokenResponse",
"HealthResponse",
"DeepHealthResponse",
]
+77 -4
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import time
import asyncio
import warnings
from typing import Any, Dict, List, Optional, Union
import aiohttp
@@ -15,8 +16,10 @@ from .types import (
AuthLoginResponse,
AuthRegisterResponse,
CreateExportResponse,
DeepHealthResponse,
DeleteAgentResponse,
EOR,
FreezeAgentResponse,
GetAgentResponse,
GetEpochResponse,
GetExportResponse,
@@ -24,6 +27,9 @@ from .types import (
GetOperationResponse,
HealthResponse,
IssueApiTokenResponse,
ListAdminEventsResponse,
ListMembersResponse,
ListWebhooksResponse,
RotateApiTokenResponse,
JWKSResponse,
ListAgentsResponse,
@@ -31,7 +37,10 @@ from .types import (
ListExportsResponse,
RegisterAgentRequest,
RegisterAgentResponse,
RegisterWebhookResponse,
SubmitOperationResponse,
UnfreezeAgentResponse,
UpdateAgentResponse,
VerifyOperationResponse,
)
from .utils import generate_nonce, generate_uuidv7
@@ -172,7 +181,16 @@ class AsyncElydoraClient:
display_name: Optional[str] = None,
org_name: Optional[str] = None,
) -> AuthRegisterResponse:
"""Register a new user and organization."""
"""Register a new user and organization.
.. deprecated::
Use Better Auth endpoints directly. See docs.
"""
warnings.warn(
"AsyncElydoraClient.register() is deprecated. Use Better Auth endpoints directly. See docs.",
DeprecationWarning,
stacklevel=2,
)
url = f"{base_url.rstrip('/')}/v1/auth/register"
body: Dict[str, Any] = {"email": email, "password": password}
if display_name is not None:
@@ -187,7 +205,16 @@ class AsyncElydoraClient:
@staticmethod
async def login(base_url: str, email: str, password: str) -> AuthLoginResponse:
"""Authenticate and receive a session token."""
"""Authenticate and receive a session token.
.. deprecated::
Use Better Auth endpoints directly. See docs.
"""
warnings.warn(
"AsyncElydoraClient.login() is deprecated. Use Better Auth endpoints directly. See docs.",
DeprecationWarning,
stacklevel=2,
)
url = f"{base_url.rstrip('/')}/v1/auth/login"
body = {"email": email, "password": password}
async with aiohttp.ClientSession() as session:
@@ -235,9 +262,13 @@ class AsyncElydoraClient:
"""List all agents for the organization."""
return await self._request("GET", "/v1/agents")
async def unfreeze_agent(self, agent_id: str, reason: str) -> None:
async def unfreeze_agent(self, agent_id: str, reason: str) -> UnfreezeAgentResponse:
"""Unfreeze an agent."""
await self._request("POST", f"/v1/agents/{agent_id}/unfreeze", json_body={"reason": reason})
return await self._request("POST", f"/v1/agents/{agent_id}/unfreeze", json_body={"reason": reason})
async def update_agent(self, agent_id: str, integration_type: str) -> UpdateAgentResponse:
"""Update an agent's integration type."""
return await self._request("PATCH", f"/v1/agents/{agent_id}", json_body={"integration_type": integration_type})
async def delete_agent(self, agent_id: str) -> DeleteAgentResponse:
"""Delete an agent."""
@@ -399,6 +430,41 @@ class AsyncElydoraClient:
await self._handle_response(resp)
return await resp.read()
# -----------------------------------------------------------------
# Webhooks
# -----------------------------------------------------------------
async def list_webhooks(self) -> ListWebhooksResponse:
"""List all webhooks for the organization."""
return await self._request("GET", "/v1/webhooks")
async def register_webhook(self, endpoint_url: str, events: list, secret: str) -> RegisterWebhookResponse:
"""Register a new webhook."""
return await self._request("POST", "/v1/webhooks", json_body={"endpoint_url": endpoint_url, "events": events, "secret": secret})
async def delete_webhook(self, webhook_id: str) -> None:
"""Delete a webhook."""
await self._request("DELETE", f"/v1/webhooks/{webhook_id}")
# -----------------------------------------------------------------
# Members
# -----------------------------------------------------------------
async def list_members(self) -> ListMembersResponse:
"""List all members in the organization."""
return await self._request("GET", "/v1/members")
# -----------------------------------------------------------------
# Admin events
# -----------------------------------------------------------------
async def list_admin_events(self, limit: Optional[int] = None) -> ListAdminEventsResponse:
"""List recent admin events."""
params: Dict[str, str] = {}
if limit is not None:
params["limit"] = str(limit)
return await self._request("GET", "/v1/admin/events", params=params)
# -----------------------------------------------------------------
# JWKS
# -----------------------------------------------------------------
@@ -420,3 +486,10 @@ class AsyncElydoraClient:
session = await self._get_session()
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as resp:
return await self._handle_response(resp)
async def deep_health(self) -> DeepHealthResponse:
"""Check API deep health (public, no auth required)."""
url = f"{self.base_url}/v1/health/deep"
session = await self._get_session()
async with session.get(url, timeout=aiohttp.ClientTimeout(total=30)) as resp:
return await self._handle_response(resp)
+76 -4
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import time
import warnings
from typing import Any, Dict, List, Optional, Union
import requests
@@ -14,8 +15,10 @@ from .types import (
AuthLoginResponse,
AuthRegisterResponse,
CreateExportResponse,
DeepHealthResponse,
DeleteAgentResponse,
EOR,
FreezeAgentResponse,
GetAgentResponse,
GetEpochResponse,
GetExportResponse,
@@ -23,6 +26,9 @@ from .types import (
GetOperationResponse,
HealthResponse,
IssueApiTokenResponse,
ListAdminEventsResponse,
ListMembersResponse,
ListWebhooksResponse,
RotateApiTokenResponse,
JWKSResponse,
ListAgentsResponse,
@@ -30,7 +36,10 @@ from .types import (
ListExportsResponse,
RegisterAgentRequest,
RegisterAgentResponse,
RegisterWebhookResponse,
SubmitOperationResponse,
UnfreezeAgentResponse,
UpdateAgentResponse,
VerifyOperationResponse,
)
from .utils import generate_nonce, generate_uuidv7
@@ -169,7 +178,16 @@ class ElydoraClient:
display_name: Optional[str] = None,
org_name: Optional[str] = None,
) -> AuthRegisterResponse:
"""Register a new user and organization."""
"""Register a new user and organization.
.. deprecated::
Use Better Auth endpoints directly. See docs.
"""
warnings.warn(
"ElydoraClient.register() is deprecated. Use Better Auth endpoints directly. See docs.",
DeprecationWarning,
stacklevel=2,
)
url = f"{base_url.rstrip('/')}/v1/auth/register"
body: Dict[str, Any] = {"email": email, "password": password}
if display_name is not None:
@@ -181,7 +199,16 @@ class ElydoraClient:
@staticmethod
def login(base_url: str, email: str, password: str) -> AuthLoginResponse:
"""Authenticate and receive a session token."""
"""Authenticate and receive a session token.
.. deprecated::
Use Better Auth endpoints directly. See docs.
"""
warnings.warn(
"ElydoraClient.login() is deprecated. Use Better Auth endpoints directly. See docs.",
DeprecationWarning,
stacklevel=2,
)
url = f"{base_url.rstrip('/')}/v1/auth/login"
body = {"email": email, "password": password}
resp = requests.post(url, json=body, headers={"Content-Type": "application/json"}, timeout=30)
@@ -226,9 +253,13 @@ class ElydoraClient:
"""List all agents for the organization."""
return self._request("GET", "/v1/agents")
def unfreeze_agent(self, agent_id: str, reason: str) -> None:
def unfreeze_agent(self, agent_id: str, reason: str) -> UnfreezeAgentResponse:
"""Unfreeze an agent."""
self._request("POST", f"/v1/agents/{agent_id}/unfreeze", json_body={"reason": reason})
return self._request("POST", f"/v1/agents/{agent_id}/unfreeze", json_body={"reason": reason})
def update_agent(self, agent_id: str, integration_type: str) -> UpdateAgentResponse:
"""Update an agent's integration type."""
return self._request("PATCH", f"/v1/agents/{agent_id}", json_body={"integration_type": integration_type})
def delete_agent(self, agent_id: str) -> DeleteAgentResponse:
"""Delete an agent."""
@@ -389,6 +420,41 @@ class ElydoraClient:
self._handle_response(resp)
return resp.content
# -----------------------------------------------------------------
# Webhooks
# -----------------------------------------------------------------
def list_webhooks(self) -> ListWebhooksResponse:
"""List all webhooks for the organization."""
return self._request("GET", "/v1/webhooks")
def register_webhook(self, endpoint_url: str, events: list, secret: str) -> RegisterWebhookResponse:
"""Register a new webhook."""
return self._request("POST", "/v1/webhooks", json_body={"endpoint_url": endpoint_url, "events": events, "secret": secret})
def delete_webhook(self, webhook_id: str) -> None:
"""Delete a webhook."""
self._request("DELETE", f"/v1/webhooks/{webhook_id}")
# -----------------------------------------------------------------
# Members
# -----------------------------------------------------------------
def list_members(self) -> ListMembersResponse:
"""List all members in the organization."""
return self._request("GET", "/v1/members")
# -----------------------------------------------------------------
# Admin events
# -----------------------------------------------------------------
def list_admin_events(self, limit: Optional[int] = None) -> ListAdminEventsResponse:
"""List recent admin events."""
params: Dict[str, str] = {}
if limit is not None:
params["limit"] = str(limit)
return self._request("GET", "/v1/admin/events", params=params)
# -----------------------------------------------------------------
# JWKS
# -----------------------------------------------------------------
@@ -408,3 +474,9 @@ class ElydoraClient:
url = f"{self.base_url}/v1/health"
resp = self._session.get(url, timeout=30)
return self._handle_response(resp)
def deep_health(self) -> DeepHealthResponse:
"""Check API deep health (public, no auth required)."""
url = f"{self.base_url}/v1/health/deep"
resp = self._session.get(url, timeout=30)
return self._handle_response(resp)
+132 -1
View File
@@ -28,6 +28,28 @@ RbacRole = Literal[
"readonly_investigator",
"integration_engineer",
]
IntegrationType = Literal[
"openai",
"anthropic",
"gemini",
"langchain",
"llamaindex",
"autogen",
"crewai",
"custom",
]
AdminAction = Literal[
"agent.freeze",
"agent.unfreeze",
"agent.revoke_key",
"agent.delete",
"member.invite",
"member.remove",
"member.role_change",
"webhook.register",
"webhook.delete",
"org.update",
]
ErrorCode = Literal[
"INVALID_SIGNATURE",
"UNKNOWN_AGENT",
@@ -56,6 +78,7 @@ class Agent(TypedDict):
display_name: str
responsible_entity: str
status: AgentStatus
integration_type: str
created_at: int
updated_at: int
@@ -111,6 +134,8 @@ class Epoch(TypedDict):
class Organization(TypedDict):
org_id: str
name: str
description: Optional[str]
ba_org_id: Optional[str]
created_at: int
updated_at: int
@@ -247,9 +272,16 @@ class AuditQueryResponse(TypedDict):
total_count: int
class EpochAnchor(TypedDict, total=False):
tsa_url: str
anchored_at: int
tsa_token: str
root_hash: str
class GetEpochResponse(TypedDict, total=False):
epoch: Epoch
anchor: Dict[str, Any]
anchor: EpochAnchor
class ListEpochsResponse(TypedDict):
@@ -327,3 +359,102 @@ class HealthResponse(TypedDict):
version: str
protocol_version: str
timestamp: int
# ---------------------------------------------------------------------------
# Additional entity types
# ---------------------------------------------------------------------------
class AdminEvent(TypedDict):
event_id: str
org_id: str
actor_user_id: str
action: str
target_type: str
target_id: str
metadata: Optional[Dict[str, Any]]
created_at: int
class AgentAssignment(TypedDict):
assignment_id: str
agent_id: str
org_id: str
assigned_to: str
assigned_by: str
created_at: int
class WebhookEntry(TypedDict):
webhook_id: str
org_id: str
endpoint_url: str
events: List[str]
created_at: int
updated_at: int
class MemberEntry(TypedDict):
user_id: str
org_id: str
email: str
display_name: str
role: RbacRole
status: Literal["active", "suspended"]
created_at: int
# ---------------------------------------------------------------------------
# Additional request types
# ---------------------------------------------------------------------------
class UpdateAgentRequest(TypedDict, total=False):
integration_type: str
# ---------------------------------------------------------------------------
# Additional response types
# ---------------------------------------------------------------------------
class UpdateAgentResponse(TypedDict):
agent: Agent
class FreezeAgentResponse(TypedDict):
agent_id: str
previous_status: AgentStatus
status: AgentStatus
class UnfreezeAgentResponse(TypedDict):
agent_id: str
previous_status: AgentStatus
status: AgentStatus
class ListWebhooksResponse(TypedDict):
webhooks: List[WebhookEntry]
class RegisterWebhookResponse(TypedDict):
webhook: WebhookEntry
class ListMembersResponse(TypedDict):
members: List[MemberEntry]
class ListAdminEventsResponse(TypedDict):
events: List[AdminEvent]
cursor: Optional[str]
class DeepHealthResponse(TypedDict, total=False):
status: str
version: str
protocol_version: str
timestamp: int
checks: Dict[str, Any]