miso-client 0.1.0__py3-none-any.whl → 3.7.2__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.
Files changed (69) hide show
  1. miso_client/__init__.py +523 -130
  2. miso_client/api/__init__.py +35 -0
  3. miso_client/api/auth_api.py +367 -0
  4. miso_client/api/logs_api.py +91 -0
  5. miso_client/api/permissions_api.py +88 -0
  6. miso_client/api/roles_api.py +88 -0
  7. miso_client/api/types/__init__.py +75 -0
  8. miso_client/api/types/auth_types.py +183 -0
  9. miso_client/api/types/logs_types.py +71 -0
  10. miso_client/api/types/permissions_types.py +31 -0
  11. miso_client/api/types/roles_types.py +31 -0
  12. miso_client/errors.py +30 -4
  13. miso_client/models/__init__.py +4 -0
  14. miso_client/models/config.py +275 -72
  15. miso_client/models/error_response.py +39 -0
  16. miso_client/models/filter.py +255 -0
  17. miso_client/models/pagination.py +44 -0
  18. miso_client/models/sort.py +25 -0
  19. miso_client/services/__init__.py +6 -5
  20. miso_client/services/auth.py +496 -87
  21. miso_client/services/cache.py +42 -41
  22. miso_client/services/encryption.py +18 -17
  23. miso_client/services/logger.py +467 -328
  24. miso_client/services/logger_chain.py +288 -0
  25. miso_client/services/permission.py +130 -67
  26. miso_client/services/redis.py +28 -23
  27. miso_client/services/role.py +145 -62
  28. miso_client/utils/__init__.py +3 -3
  29. miso_client/utils/audit_log_queue.py +222 -0
  30. miso_client/utils/auth_strategy.py +88 -0
  31. miso_client/utils/auth_utils.py +65 -0
  32. miso_client/utils/circuit_breaker.py +125 -0
  33. miso_client/utils/client_token_manager.py +244 -0
  34. miso_client/utils/config_loader.py +88 -17
  35. miso_client/utils/controller_url_resolver.py +80 -0
  36. miso_client/utils/data_masker.py +104 -33
  37. miso_client/utils/environment_token.py +126 -0
  38. miso_client/utils/error_utils.py +216 -0
  39. miso_client/utils/fastapi_endpoints.py +166 -0
  40. miso_client/utils/filter.py +364 -0
  41. miso_client/utils/filter_applier.py +143 -0
  42. miso_client/utils/filter_parser.py +110 -0
  43. miso_client/utils/flask_endpoints.py +169 -0
  44. miso_client/utils/http_client.py +494 -262
  45. miso_client/utils/http_client_logging.py +352 -0
  46. miso_client/utils/http_client_logging_helpers.py +197 -0
  47. miso_client/utils/http_client_query_helpers.py +138 -0
  48. miso_client/utils/http_error_handler.py +92 -0
  49. miso_client/utils/http_log_formatter.py +115 -0
  50. miso_client/utils/http_log_masker.py +203 -0
  51. miso_client/utils/internal_http_client.py +435 -0
  52. miso_client/utils/jwt_tools.py +125 -16
  53. miso_client/utils/logger_helpers.py +206 -0
  54. miso_client/utils/logging_helpers.py +70 -0
  55. miso_client/utils/origin_validator.py +128 -0
  56. miso_client/utils/pagination.py +275 -0
  57. miso_client/utils/request_context.py +285 -0
  58. miso_client/utils/sensitive_fields_loader.py +116 -0
  59. miso_client/utils/sort.py +116 -0
  60. miso_client/utils/token_utils.py +114 -0
  61. miso_client/utils/url_validator.py +66 -0
  62. miso_client/utils/user_token_refresh.py +245 -0
  63. miso_client-3.7.2.dist-info/METADATA +1021 -0
  64. miso_client-3.7.2.dist-info/RECORD +68 -0
  65. miso_client-0.1.0.dist-info/METADATA +0 -551
  66. miso_client-0.1.0.dist-info/RECORD +0 -23
  67. {miso_client-0.1.0.dist-info → miso_client-3.7.2.dist-info}/WHEEL +0 -0
  68. {miso_client-0.1.0.dist-info → miso_client-3.7.2.dist-info}/licenses/LICENSE +0 -0
  69. {miso_client-0.1.0.dist-info → miso_client-3.7.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,35 @@
1
+ """
2
+ Centralized API layer with typed interfaces.
3
+
4
+ Provides typed interfaces for all controller API calls, organized by domain.
5
+ """
6
+
7
+ from ..utils.http_client import HttpClient
8
+ from .auth_api import AuthApi
9
+ from .logs_api import LogsApi
10
+ from .permissions_api import PermissionsApi
11
+ from .roles_api import RolesApi
12
+
13
+
14
+ class ApiClient:
15
+ """
16
+ Centralized API client for Miso Controller communication.
17
+
18
+ Wraps HttpClient and provides typed interfaces organized by domain.
19
+ """
20
+
21
+ def __init__(self, http_client: HttpClient):
22
+ """
23
+ Initialize API client.
24
+
25
+ Args:
26
+ http_client: HttpClient instance
27
+ """
28
+ self.http_client = http_client
29
+ self.auth = AuthApi(http_client)
30
+ self.roles = RolesApi(http_client)
31
+ self.permissions = PermissionsApi(http_client)
32
+ self.logs = LogsApi(http_client)
33
+
34
+
35
+ __all__ = ["ApiClient", "AuthApi", "RolesApi", "PermissionsApi", "LogsApi"]
@@ -0,0 +1,367 @@
1
+ """
2
+ Auth API implementation.
3
+
4
+ Provides typed interfaces for authentication endpoints.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from ..models.config import AuthStrategy
10
+ from ..utils.http_client import HttpClient
11
+ from .types.auth_types import (
12
+ DeviceCodeRequest,
13
+ DeviceCodeResponseWrapper,
14
+ DeviceCodeTokenPollRequest,
15
+ DeviceCodeTokenPollResponse,
16
+ DeviceCodeTokenResponse,
17
+ GetPermissionsResponse,
18
+ GetRolesResponse,
19
+ GetUserResponse,
20
+ LoginResponse,
21
+ LogoutResponse,
22
+ RefreshPermissionsResponse,
23
+ RefreshRolesResponse,
24
+ RefreshTokenRequest,
25
+ RefreshTokenResponse,
26
+ ValidateTokenRequest,
27
+ ValidateTokenResponse,
28
+ )
29
+
30
+
31
+ class AuthApi:
32
+ """Auth API client for authentication endpoints."""
33
+
34
+ # Endpoint constants
35
+ LOGIN_ENDPOINT = "/api/v1/auth/login"
36
+ VALIDATE_ENDPOINT = "/api/v1/auth/validate"
37
+ USER_ENDPOINT = "/api/v1/auth/user"
38
+ LOGOUT_ENDPOINT = "/api/v1/auth/logout"
39
+ REFRESH_ENDPOINT = "/api/v1/auth/refresh"
40
+ DEVICE_CODE_ENDPOINT = "/api/v1/auth/login"
41
+ DEVICE_CODE_TOKEN_ENDPOINT = "/api/v1/auth/login/device/token"
42
+ DEVICE_CODE_REFRESH_ENDPOINT = "/api/v1/auth/login/device/refresh"
43
+ ROLES_ENDPOINT = "/api/v1/auth/roles"
44
+ ROLES_REFRESH_ENDPOINT = "/api/v1/auth/roles/refresh"
45
+ PERMISSIONS_ENDPOINT = "/api/v1/auth/permissions"
46
+ PERMISSIONS_REFRESH_ENDPOINT = "/api/v1/auth/permissions/refresh"
47
+
48
+ def __init__(self, http_client: HttpClient):
49
+ """
50
+ Initialize Auth API client.
51
+
52
+ Args:
53
+ http_client: HttpClient instance
54
+ """
55
+ self.http_client = http_client
56
+
57
+ async def login(self, redirect: str, state: Optional[str] = None) -> LoginResponse:
58
+ """
59
+ Initiate login flow (GET with query params).
60
+
61
+ Args:
62
+ redirect: Redirect URI for OAuth2 callback
63
+ state: Optional state parameter for CSRF protection
64
+
65
+ Returns:
66
+ LoginResponse with login URL
67
+
68
+ Raises:
69
+ MisoClientError: If request fails
70
+ """
71
+ params = {"redirect": redirect}
72
+ if state:
73
+ params["state"] = state
74
+
75
+ response = await self.http_client.get(self.LOGIN_ENDPOINT, params=params)
76
+ return LoginResponse(**response)
77
+
78
+ async def validate_token(
79
+ self,
80
+ token: str,
81
+ environment: Optional[str] = None,
82
+ application: Optional[str] = None,
83
+ auth_strategy: Optional[AuthStrategy] = None,
84
+ ) -> ValidateTokenResponse:
85
+ """
86
+ Validate authentication token (POST).
87
+
88
+ Uses authenticated_request to send the token as Bearer token for authentication,
89
+ while also including it in the request body for validation.
90
+
91
+ Args:
92
+ token: JWT token to validate
93
+ environment: Optional environment key
94
+ application: Optional application key
95
+ auth_strategy: Optional authentication strategy
96
+
97
+ Returns:
98
+ ValidateTokenResponse with validation result
99
+
100
+ Raises:
101
+ MisoClientError: If request fails
102
+ """
103
+ request_data = ValidateTokenRequest(
104
+ token=token, environment=environment, application=application
105
+ )
106
+ response = await self.http_client.authenticated_request(
107
+ "POST",
108
+ self.VALIDATE_ENDPOINT,
109
+ token,
110
+ data=request_data.model_dump(exclude_none=True),
111
+ auth_strategy=auth_strategy,
112
+ )
113
+ return ValidateTokenResponse(**response)
114
+
115
+ async def get_user(
116
+ self, token: Optional[str] = None, auth_strategy: Optional[AuthStrategy] = None
117
+ ) -> GetUserResponse:
118
+ """
119
+ Get current user information (GET).
120
+
121
+ Token is optional - can use x-client-token header instead.
122
+
123
+ Args:
124
+ token: Optional user token (if not provided, uses x-client-token)
125
+ auth_strategy: Optional authentication strategy
126
+
127
+ Returns:
128
+ GetUserResponse with user information
129
+
130
+ Raises:
131
+ MisoClientError: If request fails
132
+ """
133
+ if token:
134
+ response = await self.http_client.authenticated_request(
135
+ "GET", self.USER_ENDPOINT, token, auth_strategy=auth_strategy
136
+ )
137
+ else:
138
+ response = await self.http_client.get(self.USER_ENDPOINT)
139
+ return GetUserResponse(**response)
140
+
141
+ async def logout(self, token: Optional[str] = None) -> LogoutResponse:
142
+ """
143
+ Logout user (POST).
144
+
145
+ If token is provided, sends it in the request body for server-side invalidation.
146
+ Otherwise, uses client credentials authentication.
147
+
148
+ Args:
149
+ token: Optional user token to invalidate (sent in request body if provided)
150
+
151
+ Returns:
152
+ LogoutResponse with logout message
153
+
154
+ Raises:
155
+ MisoClientError: If request fails
156
+ """
157
+ if token:
158
+ # Send token in body for server-side invalidation
159
+ response = await self.http_client.authenticated_request(
160
+ "POST", self.LOGOUT_ENDPOINT, token, data={"token": token}
161
+ )
162
+ else:
163
+ # Use client credentials (no user token)
164
+ response = await self.http_client.post(self.LOGOUT_ENDPOINT)
165
+ return LogoutResponse(**response)
166
+
167
+ async def refresh_token(self, refresh_token: str) -> RefreshTokenResponse:
168
+ """
169
+ Refresh user access token (POST).
170
+
171
+ Args:
172
+ refresh_token: Refresh token
173
+
174
+ Returns:
175
+ RefreshTokenResponse with new tokens
176
+
177
+ Raises:
178
+ MisoClientError: If request fails
179
+ """
180
+ request_data = RefreshTokenRequest(refreshToken=refresh_token)
181
+ response = await self.http_client.post(
182
+ self.REFRESH_ENDPOINT, data=request_data.model_dump()
183
+ )
184
+ return RefreshTokenResponse(**response)
185
+
186
+ async def initiate_device_code(
187
+ self, environment: Optional[str] = None, scope: Optional[str] = None
188
+ ) -> DeviceCodeResponseWrapper:
189
+ """
190
+ Initiate device code flow (POST).
191
+
192
+ Args:
193
+ environment: Optional environment key
194
+ scope: Optional OAuth2 scope string
195
+
196
+ Returns:
197
+ DeviceCodeResponseWrapper with device code information
198
+
199
+ Raises:
200
+ MisoClientError: If request fails
201
+ """
202
+ request_data = DeviceCodeRequest(environment=environment, scope=scope)
203
+ response = await self.http_client.post(
204
+ self.DEVICE_CODE_ENDPOINT, data=request_data.model_dump(exclude_none=True)
205
+ )
206
+ return DeviceCodeResponseWrapper(**response)
207
+
208
+ async def poll_device_code_token(self, device_code: str) -> DeviceCodeTokenPollResponse:
209
+ """
210
+ Poll for device code token (POST).
211
+
212
+ Returns 202 while authorization is pending.
213
+
214
+ Args:
215
+ device_code: Device code from initiation
216
+
217
+ Returns:
218
+ DeviceCodeTokenPollResponse with token or pending status
219
+
220
+ Raises:
221
+ MisoClientError: If request fails
222
+ """
223
+ request_data = DeviceCodeTokenPollRequest(deviceCode=device_code)
224
+ response = await self.http_client.post(
225
+ self.DEVICE_CODE_TOKEN_ENDPOINT, data=request_data.model_dump()
226
+ )
227
+ return DeviceCodeTokenPollResponse(**response)
228
+
229
+ async def refresh_device_code_token(self, refresh_token: str) -> DeviceCodeTokenResponse:
230
+ """
231
+ Refresh device code access token (POST).
232
+
233
+ Args:
234
+ refresh_token: Refresh token from device code flow
235
+
236
+ Returns:
237
+ DeviceCodeTokenResponse with new tokens
238
+
239
+ Raises:
240
+ MisoClientError: If request fails
241
+ """
242
+ request_data = RefreshTokenRequest(refreshToken=refresh_token)
243
+ response = await self.http_client.post(
244
+ self.DEVICE_CODE_REFRESH_ENDPOINT, data=request_data.model_dump()
245
+ )
246
+ response_data = response.get("data", {})
247
+ return DeviceCodeTokenResponse(**response_data)
248
+
249
+ async def get_roles(
250
+ self,
251
+ token: Optional[str] = None,
252
+ environment: Optional[str] = None,
253
+ application: Optional[str] = None,
254
+ auth_strategy: Optional[AuthStrategy] = None,
255
+ ) -> GetRolesResponse:
256
+ """
257
+ Get user roles (GET).
258
+
259
+ Args:
260
+ token: Optional user token (if not provided, uses x-client-token)
261
+ environment: Optional environment key filter
262
+ application: Optional application key filter
263
+ auth_strategy: Optional authentication strategy
264
+
265
+ Returns:
266
+ GetRolesResponse with user roles
267
+
268
+ Raises:
269
+ MisoClientError: If request fails
270
+ """
271
+ params = {}
272
+ if environment:
273
+ params["environment"] = environment
274
+ if application:
275
+ params["application"] = application
276
+
277
+ if token:
278
+ response = await self.http_client.authenticated_request(
279
+ "GET", self.ROLES_ENDPOINT, token, params=params, auth_strategy=auth_strategy
280
+ )
281
+ else:
282
+ response = await self.http_client.get(self.ROLES_ENDPOINT, params=params)
283
+ return GetRolesResponse(**response)
284
+
285
+ async def refresh_roles(
286
+ self, token: Optional[str] = None, auth_strategy: Optional[AuthStrategy] = None
287
+ ) -> RefreshRolesResponse:
288
+ """
289
+ Refresh user roles (GET).
290
+
291
+ Args:
292
+ token: Optional user token (if not provided, uses x-client-token)
293
+ auth_strategy: Optional authentication strategy
294
+
295
+ Returns:
296
+ RefreshRolesResponse with refreshed roles
297
+
298
+ Raises:
299
+ MisoClientError: If request fails
300
+ """
301
+ if token:
302
+ response = await self.http_client.authenticated_request(
303
+ "GET", self.ROLES_REFRESH_ENDPOINT, token, auth_strategy=auth_strategy
304
+ )
305
+ else:
306
+ response = await self.http_client.get(self.ROLES_REFRESH_ENDPOINT)
307
+ return RefreshRolesResponse(**response)
308
+
309
+ async def get_permissions(
310
+ self,
311
+ token: Optional[str] = None,
312
+ environment: Optional[str] = None,
313
+ application: Optional[str] = None,
314
+ auth_strategy: Optional[AuthStrategy] = None,
315
+ ) -> GetPermissionsResponse:
316
+ """
317
+ Get user permissions (GET).
318
+
319
+ Args:
320
+ token: Optional user token (if not provided, uses x-client-token)
321
+ environment: Optional environment key filter
322
+ application: Optional application key filter
323
+ auth_strategy: Optional authentication strategy
324
+
325
+ Returns:
326
+ GetPermissionsResponse with user permissions
327
+
328
+ Raises:
329
+ MisoClientError: If request fails
330
+ """
331
+ params = {}
332
+ if environment:
333
+ params["environment"] = environment
334
+ if application:
335
+ params["application"] = application
336
+
337
+ if token:
338
+ response = await self.http_client.authenticated_request(
339
+ "GET", self.PERMISSIONS_ENDPOINT, token, params=params, auth_strategy=auth_strategy
340
+ )
341
+ else:
342
+ response = await self.http_client.get(self.PERMISSIONS_ENDPOINT, params=params)
343
+ return GetPermissionsResponse(**response)
344
+
345
+ async def refresh_permissions(
346
+ self, token: Optional[str] = None, auth_strategy: Optional[AuthStrategy] = None
347
+ ) -> RefreshPermissionsResponse:
348
+ """
349
+ Refresh user permissions (GET).
350
+
351
+ Args:
352
+ token: Optional user token (if not provided, uses x-client-token)
353
+ auth_strategy: Optional authentication strategy
354
+
355
+ Returns:
356
+ RefreshPermissionsResponse with refreshed permissions
357
+
358
+ Raises:
359
+ MisoClientError: If request fails
360
+ """
361
+ if token:
362
+ response = await self.http_client.authenticated_request(
363
+ "GET", self.PERMISSIONS_REFRESH_ENDPOINT, token, auth_strategy=auth_strategy
364
+ )
365
+ else:
366
+ response = await self.http_client.get(self.PERMISSIONS_REFRESH_ENDPOINT)
367
+ return RefreshPermissionsResponse(**response)
@@ -0,0 +1,91 @@
1
+ """
2
+ Logs API implementation.
3
+
4
+ Provides typed interfaces for logging endpoints.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from ..models.config import LogEntry
10
+ from ..utils.http_client import HttpClient
11
+ from .types.logs_types import BatchLogRequest, BatchLogResponse, LogRequest, LogResponse
12
+
13
+
14
+ class LogsApi:
15
+ """Logs API client for logging endpoints."""
16
+
17
+ # Endpoint constants
18
+ LOGS_ENDPOINT = "/api/v1/logs"
19
+ LOGS_BATCH_ENDPOINT = "/api/v1/logs/batch"
20
+
21
+ def __init__(self, http_client: HttpClient):
22
+ """
23
+ Initialize Logs API client.
24
+
25
+ Args:
26
+ http_client: HttpClient instance
27
+ """
28
+ self.http_client = http_client
29
+
30
+ async def send_log(self, log_entry: LogRequest, token: Optional[str] = None) -> LogResponse:
31
+ """
32
+ Send log entry (POST).
33
+
34
+ Supports Bearer token, x-client-token, or client credentials authentication.
35
+ If token is provided, uses authenticated_request. Otherwise uses client credentials (automatic).
36
+
37
+ Args:
38
+ log_entry: LogRequest with type and data
39
+ token: Optional user token (if not provided, uses x-client-token/client credentials)
40
+
41
+ Returns:
42
+ LogResponse with success status
43
+
44
+ Raises:
45
+ MisoClientError: If request fails
46
+ """
47
+ if token:
48
+ response = await self.http_client.authenticated_request(
49
+ "POST",
50
+ self.LOGS_ENDPOINT,
51
+ token,
52
+ data=log_entry.model_dump(exclude_none=True),
53
+ )
54
+ else:
55
+ response = await self.http_client.post(
56
+ self.LOGS_ENDPOINT, data=log_entry.model_dump(exclude_none=True)
57
+ )
58
+ return LogResponse(**response)
59
+
60
+ async def send_batch_logs(
61
+ self, logs: list[LogEntry], token: Optional[str] = None
62
+ ) -> BatchLogResponse:
63
+ """
64
+ Send multiple log entries in batch (POST).
65
+
66
+ Supports Bearer token, x-client-token, or client credentials authentication.
67
+ If token is provided, uses authenticated_request. Otherwise uses client credentials (automatic).
68
+
69
+ Args:
70
+ logs: List of LogEntry objects
71
+ token: Optional user token (if not provided, uses x-client-token/client credentials)
72
+
73
+ Returns:
74
+ BatchLogResponse with processing results
75
+
76
+ Raises:
77
+ MisoClientError: If request fails
78
+ """
79
+ request_data = BatchLogRequest(logs=logs)
80
+ if token:
81
+ response = await self.http_client.authenticated_request(
82
+ "POST",
83
+ self.LOGS_BATCH_ENDPOINT,
84
+ token,
85
+ data=request_data.model_dump(exclude_none=True),
86
+ )
87
+ else:
88
+ response = await self.http_client.post(
89
+ self.LOGS_BATCH_ENDPOINT, data=request_data.model_dump(exclude_none=True)
90
+ )
91
+ return BatchLogResponse(**response)
@@ -0,0 +1,88 @@
1
+ """
2
+ Permissions API implementation.
3
+
4
+ Provides typed interfaces for permissions endpoints.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from ..models.config import AuthStrategy
10
+ from ..utils.http_client import HttpClient
11
+ from .types.permissions_types import GetPermissionsResponse, RefreshPermissionsResponse
12
+
13
+
14
+ class PermissionsApi:
15
+ """Permissions API client for permission endpoints."""
16
+
17
+ # Endpoint constants
18
+ PERMISSIONS_ENDPOINT = "/api/v1/auth/permissions"
19
+ PERMISSIONS_REFRESH_ENDPOINT = "/api/v1/auth/permissions/refresh"
20
+
21
+ def __init__(self, http_client: HttpClient):
22
+ """
23
+ Initialize Permissions API client.
24
+
25
+ Args:
26
+ http_client: HttpClient instance
27
+ """
28
+ self.http_client = http_client
29
+
30
+ async def get_permissions(
31
+ self,
32
+ token: Optional[str] = None,
33
+ environment: Optional[str] = None,
34
+ application: Optional[str] = None,
35
+ auth_strategy: Optional[AuthStrategy] = None,
36
+ ) -> GetPermissionsResponse:
37
+ """
38
+ Get user permissions (GET).
39
+
40
+ Args:
41
+ token: Optional user token (if not provided, uses x-client-token)
42
+ environment: Optional environment key filter
43
+ application: Optional application key filter
44
+ auth_strategy: Optional authentication strategy
45
+
46
+ Returns:
47
+ GetPermissionsResponse with user permissions
48
+
49
+ Raises:
50
+ MisoClientError: If request fails
51
+ """
52
+ params = {}
53
+ if environment:
54
+ params["environment"] = environment
55
+ if application:
56
+ params["application"] = application
57
+
58
+ if token:
59
+ response = await self.http_client.authenticated_request(
60
+ "GET", self.PERMISSIONS_ENDPOINT, token, params=params, auth_strategy=auth_strategy
61
+ )
62
+ else:
63
+ response = await self.http_client.get(self.PERMISSIONS_ENDPOINT, params=params)
64
+ return GetPermissionsResponse(**response)
65
+
66
+ async def refresh_permissions(
67
+ self, token: Optional[str] = None, auth_strategy: Optional[AuthStrategy] = None
68
+ ) -> RefreshPermissionsResponse:
69
+ """
70
+ Refresh user permissions (GET).
71
+
72
+ Args:
73
+ token: Optional user token (if not provided, uses x-client-token)
74
+ auth_strategy: Optional authentication strategy
75
+
76
+ Returns:
77
+ RefreshPermissionsResponse with refreshed permissions
78
+
79
+ Raises:
80
+ MisoClientError: If request fails
81
+ """
82
+ if token:
83
+ response = await self.http_client.authenticated_request(
84
+ "GET", self.PERMISSIONS_REFRESH_ENDPOINT, token, auth_strategy=auth_strategy
85
+ )
86
+ else:
87
+ response = await self.http_client.get(self.PERMISSIONS_REFRESH_ENDPOINT)
88
+ return RefreshPermissionsResponse(**response)
@@ -0,0 +1,88 @@
1
+ """
2
+ Roles API implementation.
3
+
4
+ Provides typed interfaces for roles endpoints.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from ..models.config import AuthStrategy
10
+ from ..utils.http_client import HttpClient
11
+ from .types.roles_types import GetRolesResponse, RefreshRolesResponse
12
+
13
+
14
+ class RolesApi:
15
+ """Roles API client for role endpoints."""
16
+
17
+ # Endpoint constants
18
+ ROLES_ENDPOINT = "/api/v1/auth/roles"
19
+ ROLES_REFRESH_ENDPOINT = "/api/v1/auth/roles/refresh"
20
+
21
+ def __init__(self, http_client: HttpClient):
22
+ """
23
+ Initialize Roles API client.
24
+
25
+ Args:
26
+ http_client: HttpClient instance
27
+ """
28
+ self.http_client = http_client
29
+
30
+ async def get_roles(
31
+ self,
32
+ token: Optional[str] = None,
33
+ environment: Optional[str] = None,
34
+ application: Optional[str] = None,
35
+ auth_strategy: Optional[AuthStrategy] = None,
36
+ ) -> GetRolesResponse:
37
+ """
38
+ Get user roles (GET).
39
+
40
+ Args:
41
+ token: Optional user token (if not provided, uses x-client-token)
42
+ environment: Optional environment key filter
43
+ application: Optional application key filter
44
+ auth_strategy: Optional authentication strategy
45
+
46
+ Returns:
47
+ GetRolesResponse with user roles
48
+
49
+ Raises:
50
+ MisoClientError: If request fails
51
+ """
52
+ params = {}
53
+ if environment:
54
+ params["environment"] = environment
55
+ if application:
56
+ params["application"] = application
57
+
58
+ if token:
59
+ response = await self.http_client.authenticated_request(
60
+ "GET", self.ROLES_ENDPOINT, token, params=params, auth_strategy=auth_strategy
61
+ )
62
+ else:
63
+ response = await self.http_client.get(self.ROLES_ENDPOINT, params=params)
64
+ return GetRolesResponse(**response)
65
+
66
+ async def refresh_roles(
67
+ self, token: Optional[str] = None, auth_strategy: Optional[AuthStrategy] = None
68
+ ) -> RefreshRolesResponse:
69
+ """
70
+ Refresh user roles (GET).
71
+
72
+ Args:
73
+ token: Optional user token (if not provided, uses x-client-token)
74
+ auth_strategy: Optional authentication strategy
75
+
76
+ Returns:
77
+ RefreshRolesResponse with refreshed roles
78
+
79
+ Raises:
80
+ MisoClientError: If request fails
81
+ """
82
+ if token:
83
+ response = await self.http_client.authenticated_request(
84
+ "GET", self.ROLES_REFRESH_ENDPOINT, token, auth_strategy=auth_strategy
85
+ )
86
+ else:
87
+ response = await self.http_client.get(self.ROLES_REFRESH_ENDPOINT)
88
+ return RefreshRolesResponse(**response)