maeyr 0.2.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maeyr/__init__.py +57 -0
- maeyr/_constants.py +27 -0
- maeyr/client/__init__.py +42 -0
- maeyr/client/auth.py +346 -0
- maeyr/client/base.py +441 -0
- maeyr/client/builder.py +245 -0
- maeyr/client/chat.py +201 -0
- maeyr/client/config.py +30 -0
- maeyr/client/errors.py +254 -0
- maeyr/client/marketplace.py +114 -0
- maeyr/client/mcp.py +143 -0
- maeyr/client/pagination.py +88 -0
- maeyr/client/pulse.py +53 -0
- maeyr/client/scheduler.py +65 -0
- maeyr/client/sse.py +55 -0
- maeyr/client/transport.py +269 -0
- maeyr/client/webhook.py +89 -0
- maeyr/client/workflow.py +118 -0
- maeyr/devtools/__init__.py +13 -0
- maeyr/devtools/cli.py +38 -0
- maeyr/devtools/validate_agent.py +217 -0
- maeyr/devtools/validate_envelope.py +104 -0
- maeyr/mcp_bridge/__init__.py +13 -0
- maeyr/mcp_bridge/cli.py +110 -0
- maeyr/mcp_bridge/gateway.py +182 -0
- maeyr/models/__init__.py +71 -0
- maeyr/models/a2a.py +50 -0
- maeyr/models/agent.py +241 -0
- maeyr/models/auth.py +97 -0
- maeyr/models/executor.py +61 -0
- maeyr/py.typed +1 -0
- maeyr/runtime/__init__.py +28 -0
- maeyr/runtime/_canonical_maeyr.txt +188 -0
- maeyr/runtime/a2a.py +57 -0
- maeyr/runtime/auth.py +135 -0
- maeyr/runtime/endpoints.py +13 -0
- maeyr/runtime/inject.py +15 -0
- maeyr-0.2.8.dist-info/METADATA +774 -0
- maeyr-0.2.8.dist-info/RECORD +43 -0
- maeyr-0.2.8.dist-info/WHEEL +5 -0
- maeyr-0.2.8.dist-info/entry_points.txt +3 -0
- maeyr-0.2.8.dist-info/licenses/LICENSE +17 -0
- maeyr-0.2.8.dist-info/top_level.txt +1 -0
maeyr/__init__.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Maeyr platform SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
__version__ = "0.2.8"
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"MaeyrApiError",
|
|
9
|
+
"MaeyrAuthenticationError",
|
|
10
|
+
"MaeyrClient",
|
|
11
|
+
"MaeyrNotFoundError",
|
|
12
|
+
"MaeyrRateLimitError",
|
|
13
|
+
"MaeyrStreamError",
|
|
14
|
+
"MaeyrTransportError",
|
|
15
|
+
"MaeyrValidationError",
|
|
16
|
+
"WebhookClient",
|
|
17
|
+
"__version__",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def __getattr__(name: str) -> Any:
|
|
22
|
+
if name == "MaeyrClient":
|
|
23
|
+
from maeyr.client import MaeyrClient
|
|
24
|
+
|
|
25
|
+
return MaeyrClient
|
|
26
|
+
if name == "WebhookClient":
|
|
27
|
+
from maeyr.client import WebhookClient
|
|
28
|
+
|
|
29
|
+
return WebhookClient
|
|
30
|
+
for exc_name, exc_path in (
|
|
31
|
+
("MaeyrApiError", "MaeyrApiError"),
|
|
32
|
+
("MaeyrAuthenticationError", "MaeyrAuthenticationError"),
|
|
33
|
+
("MaeyrNotFoundError", "MaeyrNotFoundError"),
|
|
34
|
+
("MaeyrRateLimitError", "MaeyrRateLimitError"),
|
|
35
|
+
("MaeyrStreamError", "MaeyrStreamError"),
|
|
36
|
+
("MaeyrTransportError", "MaeyrTransportError"),
|
|
37
|
+
("MaeyrValidationError", "MaeyrValidationError"),
|
|
38
|
+
):
|
|
39
|
+
if name == exc_name:
|
|
40
|
+
from maeyr.client import errors as err
|
|
41
|
+
|
|
42
|
+
return getattr(err, exc_path)
|
|
43
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from maeyr.client import (
|
|
48
|
+
MaeyrApiError,
|
|
49
|
+
MaeyrAuthenticationError,
|
|
50
|
+
MaeyrClient,
|
|
51
|
+
MaeyrNotFoundError,
|
|
52
|
+
MaeyrRateLimitError,
|
|
53
|
+
MaeyrStreamError,
|
|
54
|
+
MaeyrTransportError,
|
|
55
|
+
MaeyrValidationError,
|
|
56
|
+
WebhookClient,
|
|
57
|
+
)
|
maeyr/_constants.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Platform API constants."""
|
|
2
|
+
|
|
3
|
+
DEFAULT_BASE_URL = "https://api.maeyr.com"
|
|
4
|
+
|
|
5
|
+
SERVICE_PATHS = {
|
|
6
|
+
"auth": "/auth",
|
|
7
|
+
"builder": "/builder",
|
|
8
|
+
"chat": "/chat",
|
|
9
|
+
"pulse": "/pulse",
|
|
10
|
+
"workflow": "/workflow",
|
|
11
|
+
"scheduler": "/scheduler",
|
|
12
|
+
"marketplace": "/marketplace/api/v1/marketplace",
|
|
13
|
+
"org": "/org",
|
|
14
|
+
"project": "/project",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ENV_ACCESS_TOKEN = "MAEYR_ACCESS_TOKEN"
|
|
18
|
+
ENV_API_KEY = "MAEYR_API_KEY"
|
|
19
|
+
ENV_EMAIL = "MAEYR_EMAIL"
|
|
20
|
+
ENV_PASSWORD = "MAEYR_PASSWORD"
|
|
21
|
+
ENV_REFRESH_TOKEN = "MAEYR_REFRESH_TOKEN"
|
|
22
|
+
ENV_ORG_ID = "MAEYR_ORG_ID"
|
|
23
|
+
ENV_PROJECT_ID = "MAEYR_PROJECT_ID"
|
|
24
|
+
ENV_BASE_URL = "MAEYR_BASE_URL"
|
|
25
|
+
ENV_AGENT_ALIAS = "MAEYR_AGENT_ALIAS"
|
|
26
|
+
ENV_MCP_TOKEN = "MAEYR_MCP_TOKEN"
|
|
27
|
+
ENV_MCP_GATEWAY_URL = "MAEYR_MCP_GATEWAY_URL"
|
maeyr/client/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from maeyr.client.base import MaeyrClient
|
|
2
|
+
from maeyr.client.config import ClientConfig, RetryConfig
|
|
3
|
+
from maeyr.client.errors import (
|
|
4
|
+
ErrorDetail,
|
|
5
|
+
MaeyrApiError,
|
|
6
|
+
MaeyrAuthenticationError,
|
|
7
|
+
MaeyrConflictError,
|
|
8
|
+
MaeyrError,
|
|
9
|
+
MaeyrNotFoundError,
|
|
10
|
+
MaeyrPermissionError,
|
|
11
|
+
MaeyrRateLimitError,
|
|
12
|
+
MaeyrServerError,
|
|
13
|
+
MaeyrStreamError,
|
|
14
|
+
MaeyrTransportError,
|
|
15
|
+
MaeyrValidationError,
|
|
16
|
+
parse_error_details,
|
|
17
|
+
raise_for_response,
|
|
18
|
+
)
|
|
19
|
+
from maeyr.client.mcp import McpClient
|
|
20
|
+
from maeyr.client.webhook import WebhookClient
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"ClientConfig",
|
|
24
|
+
"ErrorDetail",
|
|
25
|
+
"RetryConfig",
|
|
26
|
+
"MaeyrApiError",
|
|
27
|
+
"MaeyrAuthenticationError",
|
|
28
|
+
"McpClient",
|
|
29
|
+
"MaeyrClient",
|
|
30
|
+
"MaeyrConflictError",
|
|
31
|
+
"MaeyrError",
|
|
32
|
+
"MaeyrNotFoundError",
|
|
33
|
+
"MaeyrPermissionError",
|
|
34
|
+
"MaeyrRateLimitError",
|
|
35
|
+
"MaeyrServerError",
|
|
36
|
+
"MaeyrStreamError",
|
|
37
|
+
"MaeyrTransportError",
|
|
38
|
+
"MaeyrValidationError",
|
|
39
|
+
"WebhookClient",
|
|
40
|
+
"parse_error_details",
|
|
41
|
+
"raise_for_response",
|
|
42
|
+
]
|
maeyr/client/auth.py
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, Optional
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
|
|
7
|
+
from maeyr._constants import SERVICE_PATHS
|
|
8
|
+
from maeyr.models.auth import (
|
|
9
|
+
ApiKeyRequest,
|
|
10
|
+
KeyValidationRequest,
|
|
11
|
+
KeyValidationResponse,
|
|
12
|
+
LoginRequest,
|
|
13
|
+
RefreshRequest,
|
|
14
|
+
SwitchOrgRequest,
|
|
15
|
+
SwitchProjectRequest,
|
|
16
|
+
TokenResponse,
|
|
17
|
+
UserResponse,
|
|
18
|
+
WorkerKeyCreateRequest,
|
|
19
|
+
WorkerKeyRateLimit,
|
|
20
|
+
WorkerKeyScope,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from maeyr.client.base import MaeyrClient
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _OrgClient:
|
|
28
|
+
def __init__(self, auth: AuthClient) -> None:
|
|
29
|
+
self._auth = auth
|
|
30
|
+
self._prefix = SERVICE_PATHS["org"]
|
|
31
|
+
|
|
32
|
+
async def list(self) -> Any:
|
|
33
|
+
return await self._auth._client._arequest("GET", self._prefix, "/list")
|
|
34
|
+
|
|
35
|
+
async def create(self, body: Dict[str, Any]) -> Any:
|
|
36
|
+
return await self._auth._client._arequest("POST", self._prefix, "/create", json=body)
|
|
37
|
+
|
|
38
|
+
async def get(self, org_id: str) -> Any:
|
|
39
|
+
return await self._auth._client._arequest("GET", self._prefix, f"/{org_id}")
|
|
40
|
+
|
|
41
|
+
async def update(self, org_id: str, body: Dict[str, Any]) -> Any:
|
|
42
|
+
return await self._auth._client._arequest("PUT", self._prefix, f"/{org_id}", json=body)
|
|
43
|
+
|
|
44
|
+
async def delete(self, org_id: str) -> Any:
|
|
45
|
+
return await self._auth._client._arequest("DELETE", self._prefix, f"/{org_id}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class _ProjectClient:
|
|
49
|
+
def __init__(self, auth: AuthClient) -> None:
|
|
50
|
+
self._auth = auth
|
|
51
|
+
self._prefix = SERVICE_PATHS["project"]
|
|
52
|
+
|
|
53
|
+
async def create(self, body: Dict[str, Any]) -> Any:
|
|
54
|
+
return await self._auth._client._arequest("POST", self._prefix, "/create", json=body)
|
|
55
|
+
|
|
56
|
+
async def list(self, org_id: str) -> Any:
|
|
57
|
+
return await self._auth._client._arequest("GET", self._prefix, f"/list/{org_id}")
|
|
58
|
+
|
|
59
|
+
async def get(self, project_id: str) -> Any:
|
|
60
|
+
return await self._auth._client._arequest("GET", self._prefix, f"/{project_id}")
|
|
61
|
+
|
|
62
|
+
async def update(self, project_id: str, body: Dict[str, Any]) -> Any:
|
|
63
|
+
return await self._auth._client._arequest("PUT", self._prefix, f"/{project_id}", json=body)
|
|
64
|
+
|
|
65
|
+
async def delete(self, project_id: str) -> Any:
|
|
66
|
+
return await self._auth._client._arequest("DELETE", self._prefix, f"/{project_id}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class AuthClient:
|
|
70
|
+
def __init__(self, client: MaeyrClient) -> None:
|
|
71
|
+
self._client = client
|
|
72
|
+
self._prefix = SERVICE_PATHS["auth"]
|
|
73
|
+
self.orgs = _OrgClient(self)
|
|
74
|
+
self.projects = _ProjectClient(self)
|
|
75
|
+
|
|
76
|
+
async def login(self, email: str, password: str) -> TokenResponse:
|
|
77
|
+
data = await self._client._arequest(
|
|
78
|
+
"POST",
|
|
79
|
+
self._prefix,
|
|
80
|
+
"/individual/login",
|
|
81
|
+
json=LoginRequest(email=email, password=password).model_dump(),
|
|
82
|
+
)
|
|
83
|
+
tokens = TokenResponse.model_validate(data)
|
|
84
|
+
self._apply_tokens(tokens)
|
|
85
|
+
return tokens
|
|
86
|
+
|
|
87
|
+
def login_sync(self, email: str, password: str) -> TokenResponse:
|
|
88
|
+
data = self._client._request(
|
|
89
|
+
"POST",
|
|
90
|
+
self._prefix,
|
|
91
|
+
"/individual/login",
|
|
92
|
+
json=LoginRequest(email=email, password=password).model_dump(),
|
|
93
|
+
)
|
|
94
|
+
tokens = TokenResponse.model_validate(data)
|
|
95
|
+
self._apply_tokens(tokens)
|
|
96
|
+
return tokens
|
|
97
|
+
|
|
98
|
+
async def refresh(self) -> TokenResponse:
|
|
99
|
+
if not self._client.refresh_token:
|
|
100
|
+
raise ValueError("refresh_token is required to refresh")
|
|
101
|
+
data = await self._client._arequest(
|
|
102
|
+
"POST",
|
|
103
|
+
self._prefix,
|
|
104
|
+
"/refresh",
|
|
105
|
+
json=RefreshRequest(refresh_token=self._client.refresh_token).model_dump(),
|
|
106
|
+
)
|
|
107
|
+
tokens = TokenResponse.model_validate(data)
|
|
108
|
+
self._apply_tokens(tokens)
|
|
109
|
+
return tokens
|
|
110
|
+
|
|
111
|
+
def refresh_sync(self) -> TokenResponse:
|
|
112
|
+
if not self._client.refresh_token:
|
|
113
|
+
raise ValueError("refresh_token is required to refresh")
|
|
114
|
+
data = self._client._request(
|
|
115
|
+
"POST",
|
|
116
|
+
self._prefix,
|
|
117
|
+
"/refresh",
|
|
118
|
+
json=RefreshRequest(refresh_token=self._client.refresh_token).model_dump(),
|
|
119
|
+
)
|
|
120
|
+
tokens = TokenResponse.model_validate(data)
|
|
121
|
+
self._apply_tokens(tokens)
|
|
122
|
+
return tokens
|
|
123
|
+
|
|
124
|
+
async def logout(self) -> Any:
|
|
125
|
+
return await self._client._arequest("POST", self._prefix, "/logout")
|
|
126
|
+
|
|
127
|
+
async def logout_all(self) -> Any:
|
|
128
|
+
return await self._client._arequest("POST", self._prefix, "/logout-all")
|
|
129
|
+
|
|
130
|
+
async def me(self) -> UserResponse:
|
|
131
|
+
data = await self._client._arequest("GET", self._prefix, "/me")
|
|
132
|
+
return UserResponse.model_validate(data)
|
|
133
|
+
|
|
134
|
+
def me_sync(self) -> UserResponse:
|
|
135
|
+
data = self._client._request("GET", self._prefix, "/me")
|
|
136
|
+
return UserResponse.model_validate(data)
|
|
137
|
+
|
|
138
|
+
async def usage(self) -> Any:
|
|
139
|
+
return await self._client._arequest("GET", self._prefix, "/usage")
|
|
140
|
+
|
|
141
|
+
async def switch_org(self, org_id: str) -> TokenResponse:
|
|
142
|
+
data = await self._client._arequest(
|
|
143
|
+
"POST",
|
|
144
|
+
self._prefix,
|
|
145
|
+
"/switch-org",
|
|
146
|
+
json=SwitchOrgRequest(org_id=org_id).model_dump(),
|
|
147
|
+
)
|
|
148
|
+
tokens = TokenResponse.model_validate(data)
|
|
149
|
+
self._apply_tokens(tokens)
|
|
150
|
+
return tokens
|
|
151
|
+
|
|
152
|
+
async def switch_project(self, project_id: str) -> TokenResponse:
|
|
153
|
+
data = await self._client._arequest(
|
|
154
|
+
"POST",
|
|
155
|
+
self._prefix,
|
|
156
|
+
"/switch-project",
|
|
157
|
+
json=SwitchProjectRequest(project_id=project_id).model_dump(),
|
|
158
|
+
)
|
|
159
|
+
tokens = TokenResponse.model_validate(data)
|
|
160
|
+
self._apply_tokens(tokens)
|
|
161
|
+
return tokens
|
|
162
|
+
|
|
163
|
+
async def list_sessions(self) -> Any:
|
|
164
|
+
return await self._client._arequest("GET", self._prefix, "/sessions")
|
|
165
|
+
|
|
166
|
+
async def revoke_session(self, session_id: str) -> Any:
|
|
167
|
+
return await self._client._arequest("DELETE", self._prefix, f"/sessions/{session_id}")
|
|
168
|
+
|
|
169
|
+
async def revoke_all_sessions(self) -> Any:
|
|
170
|
+
return await self._client._arequest("DELETE", self._prefix, "/sessions")
|
|
171
|
+
|
|
172
|
+
async def validate_api_key(self, api_key: str) -> KeyValidationResponse:
|
|
173
|
+
"""Validate a project API key (no JWT required)."""
|
|
174
|
+
data = await self._client._arequest(
|
|
175
|
+
"POST",
|
|
176
|
+
self._prefix,
|
|
177
|
+
"/key/validate/api",
|
|
178
|
+
json=KeyValidationRequest(api_key=api_key).model_dump(),
|
|
179
|
+
)
|
|
180
|
+
return KeyValidationResponse.model_validate(data)
|
|
181
|
+
|
|
182
|
+
def validate_api_key_sync(self, api_key: str) -> KeyValidationResponse:
|
|
183
|
+
data = self._client._request(
|
|
184
|
+
"POST",
|
|
185
|
+
self._prefix,
|
|
186
|
+
"/key/validate/api",
|
|
187
|
+
json=KeyValidationRequest(api_key=api_key).model_dump(),
|
|
188
|
+
)
|
|
189
|
+
return KeyValidationResponse.model_validate(data)
|
|
190
|
+
|
|
191
|
+
async def create_api_key(self, name: str, description: Optional[str] = None) -> Any:
|
|
192
|
+
return await self._client._arequest(
|
|
193
|
+
"POST",
|
|
194
|
+
self._prefix,
|
|
195
|
+
"/key/api",
|
|
196
|
+
json=ApiKeyRequest(name=name, description=description).model_dump(),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
async def list_api_keys(self, *, skip: int = 0, limit: int = 50) -> Any:
|
|
200
|
+
return await self._client._arequest(
|
|
201
|
+
"GET",
|
|
202
|
+
self._prefix,
|
|
203
|
+
"/key/api",
|
|
204
|
+
params={"skip": skip, "limit": limit},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
async def revoke_api_key(self, key_id: str) -> Any:
|
|
208
|
+
return await self._client._arequest("POST", self._prefix, f"/key/api/{key_id}/revoke")
|
|
209
|
+
|
|
210
|
+
async def delete_api_key(self, key_id: str) -> Any:
|
|
211
|
+
return await self._client._arequest("DELETE", self._prefix, f"/key/api/{key_id}")
|
|
212
|
+
|
|
213
|
+
async def create_worker_key(
|
|
214
|
+
self,
|
|
215
|
+
name: str | WorkerKeyCreateRequest,
|
|
216
|
+
description: Optional[str] = None,
|
|
217
|
+
*,
|
|
218
|
+
project_id: Optional[str] = None,
|
|
219
|
+
scopes: Optional[Sequence[WorkerKeyScope]] = None,
|
|
220
|
+
expires_in_days: Optional[int] = None,
|
|
221
|
+
key_id: Optional[str] = None,
|
|
222
|
+
rate_limit: Optional[WorkerKeyRateLimit] = None,
|
|
223
|
+
) -> Any:
|
|
224
|
+
"""Create a project-scoped worker key using the current Auth contract.
|
|
225
|
+
|
|
226
|
+
Passing a string preserves the pre-0.2.8 call shape. ``description`` is
|
|
227
|
+
still accepted for source compatibility but is not sent because the
|
|
228
|
+
Auth worker-key request does not define that field. New callers may pass
|
|
229
|
+
a :class:`WorkerKeyCreateRequest` as the first argument.
|
|
230
|
+
"""
|
|
231
|
+
if isinstance(name, WorkerKeyCreateRequest):
|
|
232
|
+
if any(
|
|
233
|
+
value is not None
|
|
234
|
+
for value in (
|
|
235
|
+
description,
|
|
236
|
+
project_id,
|
|
237
|
+
scopes,
|
|
238
|
+
expires_in_days,
|
|
239
|
+
key_id,
|
|
240
|
+
rate_limit,
|
|
241
|
+
)
|
|
242
|
+
):
|
|
243
|
+
raise ValueError(
|
|
244
|
+
"worker-key request model cannot be combined with individual fields"
|
|
245
|
+
)
|
|
246
|
+
request = name
|
|
247
|
+
else:
|
|
248
|
+
request_fields: Dict[str, Any] = {
|
|
249
|
+
"name": name,
|
|
250
|
+
"key_type": "worker",
|
|
251
|
+
}
|
|
252
|
+
if project_id is not None:
|
|
253
|
+
request_fields["project_id"] = project_id
|
|
254
|
+
if scopes is not None:
|
|
255
|
+
request_fields["scopes"] = list(scopes)
|
|
256
|
+
if expires_in_days is not None:
|
|
257
|
+
request_fields["expires_in_days"] = expires_in_days
|
|
258
|
+
if key_id is not None:
|
|
259
|
+
request_fields["key_id"] = key_id
|
|
260
|
+
if rate_limit is not None:
|
|
261
|
+
request_fields["rate_limit"] = rate_limit
|
|
262
|
+
request = WorkerKeyCreateRequest.model_validate(request_fields)
|
|
263
|
+
return await self._client._arequest(
|
|
264
|
+
"POST",
|
|
265
|
+
self._prefix,
|
|
266
|
+
"/key/worker",
|
|
267
|
+
json=request.model_dump(exclude_none=True),
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
async def list_worker_keys(
|
|
271
|
+
self,
|
|
272
|
+
*,
|
|
273
|
+
project_id: Optional[str] = None,
|
|
274
|
+
include_revoked: bool = False,
|
|
275
|
+
skip: int = 0,
|
|
276
|
+
limit: int = 50,
|
|
277
|
+
search: Optional[str] = None,
|
|
278
|
+
) -> Any:
|
|
279
|
+
"""List worker keys using Auth's project and pagination filters."""
|
|
280
|
+
if skip < 0:
|
|
281
|
+
raise ValueError("skip must be non-negative")
|
|
282
|
+
if not 1 <= limit <= 500:
|
|
283
|
+
raise ValueError("limit must be between 1 and 500")
|
|
284
|
+
params: Dict[str, Any] = {
|
|
285
|
+
"include_revoked": include_revoked,
|
|
286
|
+
"skip": skip,
|
|
287
|
+
"limit": limit,
|
|
288
|
+
}
|
|
289
|
+
if project_id is not None:
|
|
290
|
+
params["project_id"] = project_id
|
|
291
|
+
if search is not None:
|
|
292
|
+
params["search"] = search
|
|
293
|
+
return await self._client._arequest(
|
|
294
|
+
"GET",
|
|
295
|
+
self._prefix,
|
|
296
|
+
"/key/worker",
|
|
297
|
+
params=params,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
async def revoke_worker_key(
|
|
301
|
+
self,
|
|
302
|
+
key_id: str,
|
|
303
|
+
*,
|
|
304
|
+
project_id: Optional[str] = None,
|
|
305
|
+
) -> Any:
|
|
306
|
+
"""Revoke a worker key without deleting its audit record."""
|
|
307
|
+
path = self._worker_key_path(key_id, suffix="/revoke")
|
|
308
|
+
params = {"project_id": project_id} if project_id is not None else None
|
|
309
|
+
return await self._client._arequest(
|
|
310
|
+
"POST",
|
|
311
|
+
self._prefix,
|
|
312
|
+
path,
|
|
313
|
+
params=params,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
async def delete_worker_key(
|
|
317
|
+
self,
|
|
318
|
+
key_id: str,
|
|
319
|
+
*,
|
|
320
|
+
project_id: Optional[str] = None,
|
|
321
|
+
) -> Any:
|
|
322
|
+
"""Permanently delete a worker key in the selected project."""
|
|
323
|
+
path = self._worker_key_path(key_id)
|
|
324
|
+
params = {"project_id": project_id} if project_id is not None else None
|
|
325
|
+
return await self._client._arequest(
|
|
326
|
+
"DELETE",
|
|
327
|
+
self._prefix,
|
|
328
|
+
path,
|
|
329
|
+
params=params,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
@staticmethod
|
|
333
|
+
def _worker_key_path(key_id: str, *, suffix: str = "") -> str:
|
|
334
|
+
key_id = key_id.strip()
|
|
335
|
+
if not key_id:
|
|
336
|
+
raise ValueError("key_id is required")
|
|
337
|
+
return f"/key/worker/{quote(key_id, safe='')}{suffix}"
|
|
338
|
+
|
|
339
|
+
def _apply_tokens(self, tokens: TokenResponse) -> None:
|
|
340
|
+
self._client.access_token = tokens.access_token
|
|
341
|
+
self._client.refresh_token = tokens.refresh_token
|
|
342
|
+
if tokens.org_id:
|
|
343
|
+
self._client.org_id = tokens.org_id
|
|
344
|
+
if tokens.project_id:
|
|
345
|
+
self._client.project_id = tokens.project_id
|
|
346
|
+
self._client._sync_headers()
|