casfa-client 0.1.0__tar.gz
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.
- casfa_client-0.1.0/PKG-INFO +166 -0
- casfa_client-0.1.0/README.md +141 -0
- casfa_client-0.1.0/casfa/__init__.py +227 -0
- casfa_client-0.1.0/casfa/api/__init__.py +21 -0
- casfa_client-0.1.0/casfa/api/admin.py +81 -0
- casfa_client-0.1.0/casfa/api/auth.py +230 -0
- casfa_client-0.1.0/casfa/api/depots.py +207 -0
- casfa_client-0.1.0/casfa/api/mcp.py +90 -0
- casfa_client-0.1.0/casfa/api/nodes.py +147 -0
- casfa_client-0.1.0/casfa/api/oauth.py +156 -0
- casfa_client-0.1.0/casfa/api/realm.py +58 -0
- casfa_client-0.1.0/casfa/api/tickets.py +184 -0
- casfa_client-0.1.0/casfa/auth/__init__.py +37 -0
- casfa_client-0.1.0/casfa/auth/p256.py +177 -0
- casfa_client-0.1.0/casfa/auth/permissions.py +158 -0
- casfa_client-0.1.0/casfa/auth/ticket.py +95 -0
- casfa_client-0.1.0/casfa/auth/token.py +36 -0
- casfa_client-0.1.0/casfa/auth/user.py +181 -0
- casfa_client-0.1.0/casfa/client.py +191 -0
- casfa_client-0.1.0/casfa/types/__init__.py +118 -0
- casfa_client-0.1.0/casfa/types/api.py +314 -0
- casfa_client-0.1.0/casfa/types/auth.py +160 -0
- casfa_client-0.1.0/casfa/types/providers.py +60 -0
- casfa_client-0.1.0/casfa/utils/__init__.py +37 -0
- casfa_client-0.1.0/casfa/utils/errors.py +83 -0
- casfa_client-0.1.0/casfa/utils/fetch.py +259 -0
- casfa_client-0.1.0/casfa_client.egg-info/PKG-INFO +166 -0
- casfa_client-0.1.0/casfa_client.egg-info/SOURCES.txt +34 -0
- casfa_client-0.1.0/casfa_client.egg-info/dependency_links.txt +1 -0
- casfa_client-0.1.0/casfa_client.egg-info/requires.txt +10 -0
- casfa_client-0.1.0/casfa_client.egg-info/top_level.txt +1 -0
- casfa_client-0.1.0/pyproject.toml +53 -0
- casfa_client-0.1.0/setup.cfg +4 -0
- casfa_client-0.1.0/tests/test_auth.py +180 -0
- casfa_client-0.1.0/tests/test_client.py +108 -0
- casfa_client-0.1.0/tests/test_types.py +167 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: casfa-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CASFA (Content-Addressable Storage for Agents) Python SDK
|
|
5
|
+
Author: Mitsein Team
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: casfa,cas,content-addressable,storage,agents
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Typing :: Typed
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: httpx>=0.27.0
|
|
17
|
+
Requires-Dist: pydantic>=2.0.0
|
|
18
|
+
Requires-Dist: cryptography>=42.0.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-httpx>=0.30.0; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# CASFA Python SDK
|
|
27
|
+
|
|
28
|
+
Python client for CASFA (Content-Addressable Storage for Agents).
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install casfa-client
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### Agent Token Authentication
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import asyncio
|
|
42
|
+
from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
|
|
43
|
+
|
|
44
|
+
async def main():
|
|
45
|
+
# Create client with agent token
|
|
46
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
47
|
+
base_url="https://casfa.example.com",
|
|
48
|
+
auth=TokenAuthConfig(type="token", token="casfa_xxx"),
|
|
49
|
+
realm_id="user:ABC123",
|
|
50
|
+
))
|
|
51
|
+
|
|
52
|
+
# Get realm usage
|
|
53
|
+
result = await client.realm.get_usage()
|
|
54
|
+
if result.ok:
|
|
55
|
+
print(f"Nodes: {result.data.node_count}")
|
|
56
|
+
print(f"Bytes: {result.data.total_bytes}")
|
|
57
|
+
else:
|
|
58
|
+
print(f"Error: {result.error.message}")
|
|
59
|
+
|
|
60
|
+
# List depots
|
|
61
|
+
result = await client.depots.list()
|
|
62
|
+
if result.ok:
|
|
63
|
+
for depot in result.data.items:
|
|
64
|
+
print(f"Depot: {depot.title} (v{depot.version})")
|
|
65
|
+
|
|
66
|
+
await client.close()
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Ticket Authentication
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from casfa import create_casfa_client, CasfaClientConfig, TicketAuthConfig
|
|
75
|
+
|
|
76
|
+
async def process_with_ticket(ticket_id: str):
|
|
77
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
78
|
+
base_url="https://casfa.example.com",
|
|
79
|
+
auth=TicketAuthConfig(type="ticket", ticket_id=ticket_id),
|
|
80
|
+
))
|
|
81
|
+
|
|
82
|
+
# Read nodes allowed by ticket scope
|
|
83
|
+
result = await client.nodes.get(key="node:abc123...")
|
|
84
|
+
if result.ok:
|
|
85
|
+
data = result.data # bytes
|
|
86
|
+
# Process data...
|
|
87
|
+
|
|
88
|
+
# Commit output
|
|
89
|
+
result = await client.tickets.commit(
|
|
90
|
+
ticket_id=ticket_id,
|
|
91
|
+
output="node:result123...",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
await client.close()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
### Client Creation
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from casfa import create_casfa_client, CasfaClientConfig
|
|
103
|
+
|
|
104
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
105
|
+
base_url="https://casfa.example.com",
|
|
106
|
+
auth=auth_config, # TokenAuthConfig, TicketAuthConfig, etc.
|
|
107
|
+
realm_id="user:ABC123", # Optional
|
|
108
|
+
))
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### API Namespaces
|
|
112
|
+
|
|
113
|
+
| Namespace | Description |
|
|
114
|
+
|-----------|-------------|
|
|
115
|
+
| `client.oauth` | OAuth/Cognito authentication |
|
|
116
|
+
| `client.auth` | AWP clients and Agent tokens |
|
|
117
|
+
| `client.admin` | Admin user management |
|
|
118
|
+
| `client.mcp` | MCP JSON-RPC tool calls |
|
|
119
|
+
| `client.realm` | Realm info and usage |
|
|
120
|
+
| `client.tickets` | Ticket management |
|
|
121
|
+
| `client.depots` | Depot management |
|
|
122
|
+
| `client.nodes` | Node storage operations |
|
|
123
|
+
|
|
124
|
+
### Result Pattern
|
|
125
|
+
|
|
126
|
+
All API methods return `FetchResult[T]`:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
result = await client.tickets.create(...)
|
|
130
|
+
|
|
131
|
+
if result.ok:
|
|
132
|
+
ticket = result.data # TicketInfo
|
|
133
|
+
print(ticket.ticket_id)
|
|
134
|
+
else:
|
|
135
|
+
error = result.error # CasfaError
|
|
136
|
+
print(f"Error: {error.code} - {error.message}")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Authentication Types
|
|
140
|
+
|
|
141
|
+
| Type | Config | Header |
|
|
142
|
+
|------|--------|--------|
|
|
143
|
+
| Agent Token | `TokenAuthConfig` | `AgentToken {token}` |
|
|
144
|
+
| Ticket | `TicketAuthConfig` | `Ticket {ticketId}` |
|
|
145
|
+
| User OAuth | `UserAuthConfig` | `Bearer {accessToken}` |
|
|
146
|
+
| P256 (AWP) | `P256AuthConfig` | `X-AWP-*` headers |
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Install dev dependencies
|
|
152
|
+
pip install -e ".[dev]"
|
|
153
|
+
|
|
154
|
+
# Run tests
|
|
155
|
+
pytest
|
|
156
|
+
|
|
157
|
+
# Type check
|
|
158
|
+
mypy casfa
|
|
159
|
+
|
|
160
|
+
# Lint
|
|
161
|
+
ruff check casfa
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# CASFA Python SDK
|
|
2
|
+
|
|
3
|
+
Python client for CASFA (Content-Addressable Storage for Agents).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install casfa-client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Agent Token Authentication
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
import asyncio
|
|
17
|
+
from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
|
|
18
|
+
|
|
19
|
+
async def main():
|
|
20
|
+
# Create client with agent token
|
|
21
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
22
|
+
base_url="https://casfa.example.com",
|
|
23
|
+
auth=TokenAuthConfig(type="token", token="casfa_xxx"),
|
|
24
|
+
realm_id="user:ABC123",
|
|
25
|
+
))
|
|
26
|
+
|
|
27
|
+
# Get realm usage
|
|
28
|
+
result = await client.realm.get_usage()
|
|
29
|
+
if result.ok:
|
|
30
|
+
print(f"Nodes: {result.data.node_count}")
|
|
31
|
+
print(f"Bytes: {result.data.total_bytes}")
|
|
32
|
+
else:
|
|
33
|
+
print(f"Error: {result.error.message}")
|
|
34
|
+
|
|
35
|
+
# List depots
|
|
36
|
+
result = await client.depots.list()
|
|
37
|
+
if result.ok:
|
|
38
|
+
for depot in result.data.items:
|
|
39
|
+
print(f"Depot: {depot.title} (v{depot.version})")
|
|
40
|
+
|
|
41
|
+
await client.close()
|
|
42
|
+
|
|
43
|
+
asyncio.run(main())
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Ticket Authentication
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from casfa import create_casfa_client, CasfaClientConfig, TicketAuthConfig
|
|
50
|
+
|
|
51
|
+
async def process_with_ticket(ticket_id: str):
|
|
52
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
53
|
+
base_url="https://casfa.example.com",
|
|
54
|
+
auth=TicketAuthConfig(type="ticket", ticket_id=ticket_id),
|
|
55
|
+
))
|
|
56
|
+
|
|
57
|
+
# Read nodes allowed by ticket scope
|
|
58
|
+
result = await client.nodes.get(key="node:abc123...")
|
|
59
|
+
if result.ok:
|
|
60
|
+
data = result.data # bytes
|
|
61
|
+
# Process data...
|
|
62
|
+
|
|
63
|
+
# Commit output
|
|
64
|
+
result = await client.tickets.commit(
|
|
65
|
+
ticket_id=ticket_id,
|
|
66
|
+
output="node:result123...",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
await client.close()
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API Reference
|
|
73
|
+
|
|
74
|
+
### Client Creation
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from casfa import create_casfa_client, CasfaClientConfig
|
|
78
|
+
|
|
79
|
+
client = create_casfa_client(CasfaClientConfig(
|
|
80
|
+
base_url="https://casfa.example.com",
|
|
81
|
+
auth=auth_config, # TokenAuthConfig, TicketAuthConfig, etc.
|
|
82
|
+
realm_id="user:ABC123", # Optional
|
|
83
|
+
))
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### API Namespaces
|
|
87
|
+
|
|
88
|
+
| Namespace | Description |
|
|
89
|
+
|-----------|-------------|
|
|
90
|
+
| `client.oauth` | OAuth/Cognito authentication |
|
|
91
|
+
| `client.auth` | AWP clients and Agent tokens |
|
|
92
|
+
| `client.admin` | Admin user management |
|
|
93
|
+
| `client.mcp` | MCP JSON-RPC tool calls |
|
|
94
|
+
| `client.realm` | Realm info and usage |
|
|
95
|
+
| `client.tickets` | Ticket management |
|
|
96
|
+
| `client.depots` | Depot management |
|
|
97
|
+
| `client.nodes` | Node storage operations |
|
|
98
|
+
|
|
99
|
+
### Result Pattern
|
|
100
|
+
|
|
101
|
+
All API methods return `FetchResult[T]`:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
result = await client.tickets.create(...)
|
|
105
|
+
|
|
106
|
+
if result.ok:
|
|
107
|
+
ticket = result.data # TicketInfo
|
|
108
|
+
print(ticket.ticket_id)
|
|
109
|
+
else:
|
|
110
|
+
error = result.error # CasfaError
|
|
111
|
+
print(f"Error: {error.code} - {error.message}")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Authentication Types
|
|
115
|
+
|
|
116
|
+
| Type | Config | Header |
|
|
117
|
+
|------|--------|--------|
|
|
118
|
+
| Agent Token | `TokenAuthConfig` | `AgentToken {token}` |
|
|
119
|
+
| Ticket | `TicketAuthConfig` | `Ticket {ticketId}` |
|
|
120
|
+
| User OAuth | `UserAuthConfig` | `Bearer {accessToken}` |
|
|
121
|
+
| P256 (AWP) | `P256AuthConfig` | `X-AWP-*` headers |
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Install dev dependencies
|
|
127
|
+
pip install -e ".[dev]"
|
|
128
|
+
|
|
129
|
+
# Run tests
|
|
130
|
+
pytest
|
|
131
|
+
|
|
132
|
+
# Type check
|
|
133
|
+
mypy casfa
|
|
134
|
+
|
|
135
|
+
# Lint
|
|
136
|
+
ruff check casfa
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""CASFA Python SDK - Content-Addressable Storage for Agents.
|
|
2
|
+
|
|
3
|
+
This SDK provides a Python client for interacting with the CASFA API,
|
|
4
|
+
mirroring the TypeScript Client V2 (`@agent-web-portal/casfa-client-v2`).
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
>>> from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
|
|
8
|
+
>>>
|
|
9
|
+
>>> client = create_casfa_client(CasfaClientConfig(
|
|
10
|
+
... base_url="https://casfa.example.com",
|
|
11
|
+
... auth=TokenAuthConfig(type="token", token="casfa_xxx"),
|
|
12
|
+
... realm_id="user:ABC123",
|
|
13
|
+
... ))
|
|
14
|
+
>>>
|
|
15
|
+
>>> # Get realm usage
|
|
16
|
+
>>> result = await client.realm.get_usage()
|
|
17
|
+
>>> if result.ok:
|
|
18
|
+
... print(f"Nodes: {result.data.node_count}")
|
|
19
|
+
...
|
|
20
|
+
>>> # Create a ticket
|
|
21
|
+
>>> result = await client.tickets.create(
|
|
22
|
+
... input=["node:abc123..."],
|
|
23
|
+
... purpose="Process data",
|
|
24
|
+
... )
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# Main Client
|
|
29
|
+
# =============================================================================
|
|
30
|
+
|
|
31
|
+
from casfa.auth.p256 import P256Auth, create_p256_auth
|
|
32
|
+
from casfa.auth.permissions import (
|
|
33
|
+
API_PERMISSIONS,
|
|
34
|
+
ApiName,
|
|
35
|
+
PermissionCheckResult,
|
|
36
|
+
assert_access,
|
|
37
|
+
can_access,
|
|
38
|
+
check_permission,
|
|
39
|
+
get_required_auth,
|
|
40
|
+
is_public_api,
|
|
41
|
+
)
|
|
42
|
+
from casfa.auth.ticket import TicketAuth, create_ticket_auth
|
|
43
|
+
from casfa.auth.token import TokenAuth, create_token_auth
|
|
44
|
+
|
|
45
|
+
# =============================================================================
|
|
46
|
+
# Auth Strategies
|
|
47
|
+
# =============================================================================
|
|
48
|
+
from casfa.auth.user import UserAuth, create_user_auth
|
|
49
|
+
from casfa.client import CasfaClient, CasfaClientConfig, create_casfa_client
|
|
50
|
+
|
|
51
|
+
# =============================================================================
|
|
52
|
+
# Types - API
|
|
53
|
+
# =============================================================================
|
|
54
|
+
from casfa.types.api import (
|
|
55
|
+
# Agent Token
|
|
56
|
+
AgentTokenInfo,
|
|
57
|
+
# AWP Client
|
|
58
|
+
AwpAuthInitResponse,
|
|
59
|
+
AwpAuthPollResponse,
|
|
60
|
+
AwpClientInfo,
|
|
61
|
+
# OAuth
|
|
62
|
+
CognitoConfig,
|
|
63
|
+
CreateAgentTokenResponse,
|
|
64
|
+
DepotDetail,
|
|
65
|
+
DepotHistoryEntry,
|
|
66
|
+
# Depot
|
|
67
|
+
DepotInfo,
|
|
68
|
+
DictNodeMetadata,
|
|
69
|
+
FileNodeMetadata,
|
|
70
|
+
McpError,
|
|
71
|
+
# MCP
|
|
72
|
+
McpRequest,
|
|
73
|
+
McpResponse,
|
|
74
|
+
NodeKind,
|
|
75
|
+
# Node
|
|
76
|
+
NodeMetadata,
|
|
77
|
+
# Pagination
|
|
78
|
+
PaginatedResponse,
|
|
79
|
+
PrepareNodesResult,
|
|
80
|
+
# Realm
|
|
81
|
+
RealmInfo,
|
|
82
|
+
RealmUsage,
|
|
83
|
+
SuccessorNodeMetadata,
|
|
84
|
+
# Ticket
|
|
85
|
+
TicketInfo,
|
|
86
|
+
TicketListItem,
|
|
87
|
+
TokenResponse,
|
|
88
|
+
UserInfo,
|
|
89
|
+
# Admin
|
|
90
|
+
UserListItem,
|
|
91
|
+
WritableConfig,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# =============================================================================
|
|
95
|
+
# Types - Auth
|
|
96
|
+
# =============================================================================
|
|
97
|
+
from casfa.types.auth import (
|
|
98
|
+
AuthConfig,
|
|
99
|
+
AuthState,
|
|
100
|
+
AuthType,
|
|
101
|
+
# P256
|
|
102
|
+
P256AuthCallbacks,
|
|
103
|
+
P256AuthConfig,
|
|
104
|
+
P256AuthState,
|
|
105
|
+
P256PollStatus,
|
|
106
|
+
TicketAuthConfig,
|
|
107
|
+
# Ticket
|
|
108
|
+
TicketAuthState,
|
|
109
|
+
TokenAuthConfig,
|
|
110
|
+
# Token
|
|
111
|
+
TokenAuthState,
|
|
112
|
+
# User
|
|
113
|
+
UserAuthCallbacks,
|
|
114
|
+
UserAuthConfig,
|
|
115
|
+
UserAuthState,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# Types - Providers
|
|
120
|
+
# =============================================================================
|
|
121
|
+
from casfa.types.providers import (
|
|
122
|
+
HashProvider,
|
|
123
|
+
KeyPairProvider,
|
|
124
|
+
P256KeyPair,
|
|
125
|
+
StorageProvider,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# =============================================================================
|
|
129
|
+
# Utils
|
|
130
|
+
# =============================================================================
|
|
131
|
+
from casfa.utils.errors import (
|
|
132
|
+
CasfaError,
|
|
133
|
+
CasfaErrorCode,
|
|
134
|
+
create_error,
|
|
135
|
+
is_casfa_error,
|
|
136
|
+
)
|
|
137
|
+
from casfa.utils.fetch import FetchResult, FetchResultErr, FetchResultOk
|
|
138
|
+
|
|
139
|
+
# =============================================================================
|
|
140
|
+
# Version
|
|
141
|
+
# =============================================================================
|
|
142
|
+
|
|
143
|
+
__version__ = "0.1.0"
|
|
144
|
+
|
|
145
|
+
__all__ = [
|
|
146
|
+
# Client
|
|
147
|
+
"CasfaClient",
|
|
148
|
+
"CasfaClientConfig",
|
|
149
|
+
"create_casfa_client",
|
|
150
|
+
# API Types
|
|
151
|
+
"CognitoConfig",
|
|
152
|
+
"TokenResponse",
|
|
153
|
+
"UserInfo",
|
|
154
|
+
"AwpAuthInitResponse",
|
|
155
|
+
"AwpAuthPollResponse",
|
|
156
|
+
"AwpClientInfo",
|
|
157
|
+
"AgentTokenInfo",
|
|
158
|
+
"CreateAgentTokenResponse",
|
|
159
|
+
"UserListItem",
|
|
160
|
+
"RealmInfo",
|
|
161
|
+
"RealmUsage",
|
|
162
|
+
"TicketInfo",
|
|
163
|
+
"TicketListItem",
|
|
164
|
+
"WritableConfig",
|
|
165
|
+
"DepotInfo",
|
|
166
|
+
"DepotDetail",
|
|
167
|
+
"DepotHistoryEntry",
|
|
168
|
+
"NodeMetadata",
|
|
169
|
+
"DictNodeMetadata",
|
|
170
|
+
"FileNodeMetadata",
|
|
171
|
+
"SuccessorNodeMetadata",
|
|
172
|
+
"NodeKind",
|
|
173
|
+
"PrepareNodesResult",
|
|
174
|
+
"McpRequest",
|
|
175
|
+
"McpResponse",
|
|
176
|
+
"McpError",
|
|
177
|
+
"PaginatedResponse",
|
|
178
|
+
# Auth Types
|
|
179
|
+
"AuthConfig",
|
|
180
|
+
"AuthState",
|
|
181
|
+
"AuthType",
|
|
182
|
+
"UserAuthCallbacks",
|
|
183
|
+
"UserAuthState",
|
|
184
|
+
"UserAuthConfig",
|
|
185
|
+
"TokenAuthState",
|
|
186
|
+
"TokenAuthConfig",
|
|
187
|
+
"TicketAuthState",
|
|
188
|
+
"TicketAuthConfig",
|
|
189
|
+
"P256AuthCallbacks",
|
|
190
|
+
"P256AuthState",
|
|
191
|
+
"P256AuthConfig",
|
|
192
|
+
"P256PollStatus",
|
|
193
|
+
# Provider Types
|
|
194
|
+
"StorageProvider",
|
|
195
|
+
"HashProvider",
|
|
196
|
+
"KeyPairProvider",
|
|
197
|
+
"P256KeyPair",
|
|
198
|
+
# Auth Strategies
|
|
199
|
+
"UserAuth",
|
|
200
|
+
"create_user_auth",
|
|
201
|
+
"TokenAuth",
|
|
202
|
+
"create_token_auth",
|
|
203
|
+
"TicketAuth",
|
|
204
|
+
"create_ticket_auth",
|
|
205
|
+
"P256Auth",
|
|
206
|
+
"create_p256_auth",
|
|
207
|
+
# Permissions
|
|
208
|
+
"ApiName",
|
|
209
|
+
"API_PERMISSIONS",
|
|
210
|
+
"can_access",
|
|
211
|
+
"assert_access",
|
|
212
|
+
"get_required_auth",
|
|
213
|
+
"is_public_api",
|
|
214
|
+
"check_permission",
|
|
215
|
+
"PermissionCheckResult",
|
|
216
|
+
# Errors
|
|
217
|
+
"CasfaError",
|
|
218
|
+
"CasfaErrorCode",
|
|
219
|
+
"create_error",
|
|
220
|
+
"is_casfa_error",
|
|
221
|
+
# Fetch Result
|
|
222
|
+
"FetchResult",
|
|
223
|
+
"FetchResultOk",
|
|
224
|
+
"FetchResultErr",
|
|
225
|
+
# Version
|
|
226
|
+
"__version__",
|
|
227
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""CASFA API namespaces."""
|
|
2
|
+
|
|
3
|
+
from casfa.api.admin import AdminApi
|
|
4
|
+
from casfa.api.auth import AuthApi
|
|
5
|
+
from casfa.api.depots import DepotApi
|
|
6
|
+
from casfa.api.mcp import McpApi
|
|
7
|
+
from casfa.api.nodes import NodeApi
|
|
8
|
+
from casfa.api.oauth import OAuthApi
|
|
9
|
+
from casfa.api.realm import RealmApi
|
|
10
|
+
from casfa.api.tickets import TicketApi
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"OAuthApi",
|
|
14
|
+
"AuthApi",
|
|
15
|
+
"AdminApi",
|
|
16
|
+
"McpApi",
|
|
17
|
+
"RealmApi",
|
|
18
|
+
"TicketApi",
|
|
19
|
+
"DepotApi",
|
|
20
|
+
"NodeApi",
|
|
21
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Admin API - User management for admins."""
|
|
2
|
+
|
|
3
|
+
from casfa.types.api import PaginatedResponse, UserListItem
|
|
4
|
+
from casfa.utils.fetch import Fetcher, FetchResult, FetchResultOk, RequestOptions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AdminApi:
|
|
8
|
+
"""Admin API namespace for user management."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, fetcher: Fetcher) -> None:
|
|
11
|
+
self._fetcher = fetcher
|
|
12
|
+
|
|
13
|
+
async def list_users(
|
|
14
|
+
self,
|
|
15
|
+
*,
|
|
16
|
+
cursor: str | None = None,
|
|
17
|
+
limit: int | None = None,
|
|
18
|
+
) -> FetchResult[PaginatedResponse[UserListItem]]:
|
|
19
|
+
"""List all users (admin only)."""
|
|
20
|
+
params = []
|
|
21
|
+
if cursor:
|
|
22
|
+
params.append(f"cursor={cursor}")
|
|
23
|
+
if limit:
|
|
24
|
+
params.append(f"limit={limit}")
|
|
25
|
+
|
|
26
|
+
path = "/api/admin/users"
|
|
27
|
+
if params:
|
|
28
|
+
path += "?" + "&".join(params)
|
|
29
|
+
|
|
30
|
+
result = await self._fetcher.request(path)
|
|
31
|
+
if result.ok:
|
|
32
|
+
data = result.data
|
|
33
|
+
items = [
|
|
34
|
+
UserListItem(
|
|
35
|
+
user_id=item["user_id"],
|
|
36
|
+
email=item["email"],
|
|
37
|
+
role=item["role"],
|
|
38
|
+
created_at=item["created_at"],
|
|
39
|
+
realm_id=item.get("realm_id"),
|
|
40
|
+
)
|
|
41
|
+
for item in data.get("items", [])
|
|
42
|
+
]
|
|
43
|
+
return FetchResultOk(
|
|
44
|
+
ok=True,
|
|
45
|
+
data=PaginatedResponse(
|
|
46
|
+
items=items,
|
|
47
|
+
next_cursor=data.get("next_cursor"),
|
|
48
|
+
total=data.get("total"),
|
|
49
|
+
),
|
|
50
|
+
status=result.status,
|
|
51
|
+
)
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
async def update_user_role(
|
|
55
|
+
self,
|
|
56
|
+
*,
|
|
57
|
+
user_id: str,
|
|
58
|
+
role: str,
|
|
59
|
+
) -> FetchResult[UserListItem]:
|
|
60
|
+
"""Update a user's role (admin only)."""
|
|
61
|
+
result = await self._fetcher.request(
|
|
62
|
+
f"/api/admin/users/{user_id}/role",
|
|
63
|
+
RequestOptions(
|
|
64
|
+
method="PUT",
|
|
65
|
+
body={"role": role},
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
if result.ok:
|
|
69
|
+
data = result.data
|
|
70
|
+
return FetchResultOk(
|
|
71
|
+
ok=True,
|
|
72
|
+
data=UserListItem(
|
|
73
|
+
user_id=data["user_id"],
|
|
74
|
+
email=data["email"],
|
|
75
|
+
role=data["role"],
|
|
76
|
+
created_at=data["created_at"],
|
|
77
|
+
realm_id=data.get("realm_id"),
|
|
78
|
+
),
|
|
79
|
+
status=result.status,
|
|
80
|
+
)
|
|
81
|
+
return result
|