vortex-python-sdk 0.0.1__py3-none-any.whl → 0.0.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortex-python-sdk
3
- Version: 0.0.1
3
+ Version: 0.0.5
4
4
  Summary: Vortex Python SDK for invitation management and JWT generation
5
5
  Author-email: TeamVortexSoftware <support@vortexsoftware.com>
6
6
  License-Expression: MIT
@@ -55,11 +55,11 @@ pip install vortex-python-sdk
55
55
  ```python
56
56
  from vortex_sdk import Vortex
57
57
 
58
- # Initialize the client
59
- vortex = Vortex(api_key="your-api-key")
58
+ # Initialize the client with your Vortex API key
59
+ vortex = Vortex(api_key="your-vortex-api-key")
60
60
 
61
61
  # Or with custom base URL
62
- vortex = Vortex(api_key="your-api-key", base_url="https://custom-api.example.com")
62
+ vortex = Vortex(api_key="your-vortex-api-key", base_url="https://custom-api.example.com")
63
63
  ```
64
64
 
65
65
  ### JWT Generation
@@ -67,16 +67,33 @@ vortex = Vortex(api_key="your-api-key", base_url="https://custom-api.example.com
67
67
  ```python
68
68
  # Generate JWT for a user
69
69
  jwt = vortex.generate_jwt({
70
- "user_id": "user123",
71
- "identifiers": {
72
- "email": "user@example.com",
73
- "username": "johndoe"
74
- },
75
- "groups": ["admin", "users"],
70
+ "user_id": "user-123",
71
+ "identifiers": [
72
+ {"type": "email", "value": "user@example.com"}
73
+ ],
74
+ "groups": [
75
+ {"type": "team", "id": "team-1", "name": "Engineering"}
76
+ ],
76
77
  "role": "admin"
77
78
  })
78
79
 
79
80
  print(f"JWT: {jwt}")
81
+
82
+ # Or using type-safe models
83
+ from vortex_sdk import JwtPayload, IdentifierInput, GroupInput
84
+
85
+ jwt = vortex.generate_jwt(
86
+ JwtPayload(
87
+ user_id="user-123",
88
+ identifiers=[
89
+ IdentifierInput(type="email", value="user@example.com")
90
+ ],
91
+ groups=[
92
+ GroupInput(type="team", id="team-1", name="Engineering")
93
+ ],
94
+ role="admin"
95
+ )
96
+ )
80
97
  ```
81
98
 
82
99
  ### Invitation Management
@@ -0,0 +1,9 @@
1
+ vortex_python_sdk-0.0.5.dist-info/licenses/LICENSE,sha256=VndlWxbL4-w3YDf2yE5gJscj4zVXF0qlSq0LDtay3lo,1074
2
+ vortex_sdk/__init__.py,sha256=_39nOXzridOgUJS7MrGv6jt097egE44yVCm6ZkDbFMs,711
3
+ vortex_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ vortex_sdk/types.py,sha256=2YAqEjR5ttZjB1_JfOQWJuPekbc0F-vGlqu8t-jIeho,3344
5
+ vortex_sdk/vortex.py,sha256=qvKWMcd1ISePtV3q8N8-BwBxRdbLQ7sG34nCnLtbpKc,15033
6
+ vortex_python_sdk-0.0.5.dist-info/METADATA,sha256=k_glnwxag_W43RzWI6BJ6wU8NhpjR8GsLcXaK48wutk,6237
7
+ vortex_python_sdk-0.0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ vortex_python_sdk-0.0.5.dist-info/top_level.txt,sha256=xFDlEcXIIi_sBhkse0YfMnSdg2IlaYUd0oP2UCDc_Y0,11
9
+ vortex_python_sdk-0.0.5.dist-info/RECORD,,
vortex_sdk/__init__.py CHANGED
@@ -4,19 +4,21 @@ Vortex Python SDK
4
4
  A Python SDK for Vortex invitation management and JWT generation.
5
5
  """
6
6
 
7
- from .vortex import Vortex
8
7
  from .types import (
9
- AuthenticatedUser,
10
- JwtPayload,
11
- InvitationTarget,
12
- Invitation,
13
- CreateInvitationRequest,
14
8
  AcceptInvitationsRequest,
15
9
  ApiResponse,
16
- VortexApiError
10
+ AuthenticatedUser,
11
+ CreateInvitationRequest,
12
+ GroupInput,
13
+ IdentifierInput,
14
+ Invitation,
15
+ InvitationTarget,
16
+ JwtPayload,
17
+ VortexApiError,
17
18
  )
19
+ from .vortex import Vortex
18
20
 
19
- __version__ = "0.0.1"
21
+ __version__ = "0.0.5"
20
22
  __author__ = "TeamVortexSoftware"
21
23
  __email__ = "support@vortexsoftware.com"
22
24
 
@@ -24,10 +26,12 @@ __all__ = [
24
26
  "Vortex",
25
27
  "AuthenticatedUser",
26
28
  "JwtPayload",
29
+ "IdentifierInput",
30
+ "GroupInput",
27
31
  "InvitationTarget",
28
32
  "Invitation",
29
33
  "CreateInvitationRequest",
30
34
  "AcceptInvitationsRequest",
31
35
  "ApiResponse",
32
36
  "VortexApiError",
33
- ]
37
+ ]
vortex_sdk/types.py CHANGED
@@ -1,19 +1,70 @@
1
- from typing import Dict, List, Optional, Union, Literal
2
- from pydantic import BaseModel
1
+ from typing import Any, Dict, List, Literal, Optional, Union
2
+
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ class IdentifierInput(BaseModel):
7
+ """Identifier structure for JWT generation"""
8
+
9
+ type: Literal["email", "sms"]
10
+ value: str
11
+
12
+
13
+ class GroupInput(BaseModel):
14
+ """Group structure for JWT generation (input)"""
15
+
16
+ type: str
17
+ id: Optional[str] = None # Legacy field (deprecated, use groupId)
18
+ groupId: Optional[str] = Field(
19
+ None, alias="group_id", serialization_alias="groupId"
20
+ ) # Preferred: Customer's group ID
21
+ name: str
22
+
23
+ class Config:
24
+ populate_by_name = True
25
+
26
+
27
+ class InvitationGroup(BaseModel):
28
+ """
29
+ Invitation group from API responses
30
+ This matches the MemberGroups table structure from the API
31
+ """
32
+
33
+ id: str # Vortex internal UUID
34
+ account_id: str = Field(alias="accountId") # Vortex account ID
35
+ group_id: str = Field(alias="groupId") # Customer's group ID
36
+ type: str # Group type (e.g., "workspace", "team")
37
+ name: str # Group name
38
+ created_at: str = Field(alias="createdAt") # ISO 8601 timestamp
39
+
40
+ class Config:
41
+ # Allow both snake_case (Python) and camelCase (JSON) field names
42
+ populate_by_name = True
43
+ json_schema_extra = {
44
+ "example": {
45
+ "id": "550e8400-e29b-41d4-a716-446655440000",
46
+ "accountId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
47
+ "groupId": "workspace-123",
48
+ "type": "workspace",
49
+ "name": "My Workspace",
50
+ "createdAt": "2025-01-27T12:00:00.000Z",
51
+ }
52
+ }
3
53
 
4
54
 
5
55
  class AuthenticatedUser(BaseModel):
6
56
  user_id: str
7
- identifiers: Dict[str, str]
8
- groups: Optional[List[str]] = None
57
+ identifiers: List[IdentifierInput]
58
+ groups: Optional[List[GroupInput]] = None
9
59
  role: Optional[str] = None
10
60
 
11
61
 
12
62
  class JwtPayload(BaseModel):
13
63
  user_id: str
14
- identifiers: Dict[str, str]
15
- groups: Optional[List[str]] = None
64
+ identifiers: List[IdentifierInput]
65
+ groups: Optional[List[GroupInput]] = None
16
66
  role: Optional[str] = None
67
+ attributes: Optional[Dict[str, Any]] = None
17
68
 
18
69
 
19
70
  class InvitationTarget(BaseModel):
@@ -23,15 +74,17 @@ class InvitationTarget(BaseModel):
23
74
 
24
75
  class Invitation(BaseModel):
25
76
  id: str
26
- target: InvitationTarget
27
- group_type: Optional[str] = None
28
- group_id: Optional[str] = None
77
+ target: Union[InvitationTarget, List[InvitationTarget]] # API returns list or single
78
+ groups: Optional[List[Optional[InvitationGroup]]] = None # Full group information, can contain None
29
79
  status: str
30
- created_at: str
31
- updated_at: Optional[str] = None
32
- expires_at: Optional[str] = None
80
+ created_at: Optional[str] = Field(None, alias="createdAt") # API uses camelCase
81
+ updated_at: Optional[str] = Field(None, alias="updatedAt")
82
+ expires_at: Optional[str] = Field(None, alias="expiresAt")
33
83
  metadata: Optional[Dict[str, Union[str, int, bool]]] = None
34
84
 
85
+ class Config:
86
+ populate_by_name = True
87
+
35
88
 
36
89
  class CreateInvitationRequest(BaseModel):
37
90
  target: InvitationTarget
@@ -56,4 +109,4 @@ class VortexApiError(Exception):
56
109
  def __init__(self, message: str, status_code: int = 500):
57
110
  self.message = message
58
111
  self.status_code = status_code
59
- super().__init__(message)
112
+ super().__init__(message)
vortex_sdk/vortex.py CHANGED
@@ -1,92 +1,155 @@
1
- import json
2
- import hmac
3
- import hashlib
4
1
  import base64
5
- from typing import Dict, List, Optional, Union, Literal
2
+ import hashlib
3
+ import hmac
4
+ import json
5
+ import time
6
+ import uuid
7
+ from typing import Dict, List, Literal, Optional, Union
6
8
  from urllib.parse import urlencode
9
+
7
10
  import httpx
11
+
8
12
  from .types import (
9
- JwtPayload,
10
- InvitationTarget,
11
- Invitation,
12
- CreateInvitationRequest,
13
13
  AcceptInvitationsRequest,
14
14
  ApiResponse,
15
- VortexApiError
15
+ CreateInvitationRequest,
16
+ Invitation,
17
+ InvitationTarget,
18
+ JwtPayload,
19
+ VortexApiError,
16
20
  )
17
21
 
18
22
 
23
+ def _get_version():
24
+ """Lazy import of version to avoid circular import"""
25
+ from . import __version__
26
+ return __version__
27
+
28
+
19
29
  class Vortex:
20
- def __init__(self, api_key: str, base_url: str = "https://api.vortexsoftware.com"):
30
+ def __init__(
31
+ self, api_key: str, base_url: str = "https://api.vortexsoftware.com/api/v1"
32
+ ):
21
33
  """
22
34
  Initialize Vortex client
23
35
 
24
36
  Args:
25
37
  api_key: Your Vortex API key
26
- base_url: Base URL for Vortex API (default: https://api.vortexsoftware.com)
38
+ base_url: Base URL for Vortex API (default: https://api.vortexsoftware.com/api/v1)
27
39
  """
28
40
  self.api_key = api_key
29
- self.base_url = base_url.rstrip('/')
41
+ self.base_url = base_url.rstrip("/")
30
42
  self._client = httpx.AsyncClient()
31
43
  self._sync_client = httpx.Client()
32
44
 
33
45
  def generate_jwt(self, payload: Union[JwtPayload, Dict]) -> str:
34
46
  """
35
- Generate a JWT token for the given payload
47
+ Generate a JWT token for the given payload matching Node.js SDK implementation
36
48
 
37
49
  Args:
38
50
  payload: JWT payload containing user_id, identifiers, groups, and role
39
51
 
40
52
  Returns:
41
53
  JWT token string
54
+
55
+ Raises:
56
+ ValueError: If API key format is invalid
42
57
  """
43
58
  if isinstance(payload, dict):
44
59
  payload = JwtPayload(**payload)
45
60
 
46
- # JWT Header
61
+ # Parse API key (format: VRTX.base64url(uuid).key)
62
+ parts = self.api_key.split(".")
63
+ if len(parts) != 3:
64
+ raise ValueError("Invalid API key format. Expected: VRTX.{encodedId}.{key}")
65
+
66
+ prefix, encoded_id, key = parts
67
+
68
+ if prefix != "VRTX":
69
+ raise ValueError("Invalid API key prefix. Expected: VRTX")
70
+
71
+ # Decode UUID from base64url
72
+ # Add padding if needed
73
+ padding = 4 - len(encoded_id) % 4
74
+ if padding != 4:
75
+ encoded_id_padded = encoded_id + ("=" * padding)
76
+ else:
77
+ encoded_id_padded = encoded_id
78
+
79
+ try:
80
+ uuid_bytes = base64.urlsafe_b64decode(encoded_id_padded)
81
+ kid = str(uuid.UUID(bytes=uuid_bytes))
82
+ except Exception as e:
83
+ raise ValueError(f"Invalid UUID in API key: {e}")
84
+
85
+ # Generate timestamps
86
+ iat = int(time.time())
87
+ expires = iat + 3600
88
+
89
+ # Step 1: Derive signing key from API key + UUID
90
+ signing_key = hmac.new(key.encode(), kid.encode(), hashlib.sha256).digest()
91
+
92
+ # Step 2: Build header + payload
47
93
  header = {
94
+ "iat": iat,
48
95
  "alg": "HS256",
49
- "typ": "JWT"
96
+ "typ": "JWT",
97
+ "kid": kid,
50
98
  }
51
99
 
52
- # JWT Payload
100
+ # Serialize identifiers
101
+ identifiers_list = [
102
+ {"type": id.type, "value": id.value} for id in payload.identifiers
103
+ ]
104
+
105
+ # Serialize groups
106
+ groups_list = None
107
+ if payload.groups is not None:
108
+ groups_list = [
109
+ {
110
+ k: v
111
+ for k, v in group.model_dump(
112
+ by_alias=True, exclude_none=True
113
+ ).items()
114
+ }
115
+ for group in payload.groups
116
+ ]
117
+
53
118
  jwt_payload = {
54
119
  "userId": payload.user_id,
55
- "identifiers": payload.identifiers,
120
+ "groups": groups_list,
121
+ "role": payload.role,
122
+ "expires": expires,
123
+ "identifiers": identifiers_list,
56
124
  }
57
125
 
58
- if payload.groups is not None:
59
- jwt_payload["groups"] = payload.groups
60
- if payload.role is not None:
61
- jwt_payload["role"] = payload.role
126
+ # Add attributes if provided
127
+ if hasattr(payload, "attributes") and payload.attributes:
128
+ jwt_payload["attributes"] = payload.attributes
62
129
 
63
- # Encode header and payload
64
- header_encoded = base64.urlsafe_b64encode(
65
- json.dumps(header, separators=(',', ':')).encode()
66
- ).decode().rstrip('=')
130
+ # Step 3: Base64URL encode (without padding)
131
+ header_json = json.dumps(header, separators=(",", ":"))
132
+ payload_json = json.dumps(jwt_payload, separators=(",", ":"))
67
133
 
68
- payload_encoded = base64.urlsafe_b64encode(
69
- json.dumps(jwt_payload, separators=(',', ':')).encode()
70
- ).decode().rstrip('=')
134
+ header_b64 = base64.urlsafe_b64encode(header_json.encode()).decode().rstrip("=")
135
+ payload_b64 = (
136
+ base64.urlsafe_b64encode(payload_json.encode()).decode().rstrip("=")
137
+ )
71
138
 
72
- # Create signature
73
- message = f"{header_encoded}.{payload_encoded}"
74
- signature = hmac.new(
75
- self.api_key.encode(),
76
- message.encode(),
77
- hashlib.sha256
78
- ).digest()
139
+ # Step 4: Sign
140
+ to_sign = f"{header_b64}.{payload_b64}"
141
+ signature = hmac.new(signing_key, to_sign.encode(), hashlib.sha256).digest()
79
142
 
80
- signature_encoded = base64.urlsafe_b64encode(signature).decode().rstrip('=')
143
+ signature_b64 = base64.urlsafe_b64encode(signature).decode().rstrip("=")
81
144
 
82
- return f"{message}.{signature_encoded}"
145
+ return f"{to_sign}.{signature_b64}"
83
146
 
84
147
  async def _vortex_api_request(
85
148
  self,
86
149
  method: str,
87
150
  endpoint: str,
88
151
  data: Optional[Dict] = None,
89
- params: Optional[Dict] = None
152
+ params: Optional[Dict] = None,
90
153
  ) -> Dict:
91
154
  """
92
155
  Make an API request to Vortex
@@ -105,26 +168,27 @@ class Vortex:
105
168
  """
106
169
  url = f"{self.base_url}{endpoint}"
107
170
  headers = {
108
- "Authorization": f"Bearer {self.api_key}",
171
+ "x-api-key": f"{self.api_key}",
109
172
  "Content-Type": "application/json",
110
- "User-Agent": "vortex-python-sdk/0.0.1"
173
+ "User-Agent": f"vortex-python-sdk/{_get_version()}",
111
174
  }
112
175
 
113
176
  try:
114
177
  response = await self._client.request(
115
- method=method,
116
- url=url,
117
- json=data,
118
- params=params,
119
- headers=headers
178
+ method=method, url=url, json=data, params=params, headers=headers
120
179
  )
121
180
 
122
181
  if response.status_code >= 400:
123
182
  try:
124
183
  error_data = response.json()
125
- error_message = error_data.get('error', f'API request failed with status {response.status_code}')
184
+ error_message = error_data.get(
185
+ "error",
186
+ f"API request failed with status {response.status_code}",
187
+ )
126
188
  except:
127
- error_message = f'API request failed with status {response.status_code}'
189
+ error_message = (
190
+ f"API request failed with status {response.status_code}"
191
+ )
128
192
 
129
193
  raise VortexApiError(error_message, response.status_code)
130
194
 
@@ -138,7 +202,7 @@ class Vortex:
138
202
  method: str,
139
203
  endpoint: str,
140
204
  data: Optional[Dict] = None,
141
- params: Optional[Dict] = None
205
+ params: Optional[Dict] = None,
142
206
  ) -> Dict:
143
207
  """
144
208
  Make a synchronous API request to Vortex
@@ -157,26 +221,27 @@ class Vortex:
157
221
  """
158
222
  url = f"{self.base_url}{endpoint}"
159
223
  headers = {
160
- "Authorization": f"Bearer {self.api_key}",
224
+ "x-api-key": f"{self.api_key}",
161
225
  "Content-Type": "application/json",
162
- "User-Agent": "vortex-python-sdk/0.0.1"
226
+ "User-Agent": f"vortex-python-sdk/{_get_version()}",
163
227
  }
164
228
 
165
229
  try:
166
230
  response = self._sync_client.request(
167
- method=method,
168
- url=url,
169
- json=data,
170
- params=params,
171
- headers=headers
231
+ method=method, url=url, json=data, params=params, headers=headers
172
232
  )
173
233
 
174
234
  if response.status_code >= 400:
175
235
  try:
176
236
  error_data = response.json()
177
- error_message = error_data.get('error', f'API request failed with status {response.status_code}')
237
+ error_message = error_data.get(
238
+ "error",
239
+ f"API request failed with status {response.status_code}",
240
+ )
178
241
  except:
179
- error_message = f'API request failed with status {response.status_code}'
242
+ error_message = (
243
+ f"API request failed with status {response.status_code}"
244
+ )
180
245
 
181
246
  raise VortexApiError(error_message, response.status_code)
182
247
 
@@ -188,7 +253,7 @@ class Vortex:
188
253
  async def get_invitations_by_target(
189
254
  self,
190
255
  target_type: Literal["email", "username", "phoneNumber"],
191
- target_value: str
256
+ target_value: str,
192
257
  ) -> List[Invitation]:
193
258
  """
194
259
  Get invitations for a specific target
@@ -200,18 +265,17 @@ class Vortex:
200
265
  Returns:
201
266
  List of invitations
202
267
  """
203
- params = {
204
- "targetType": target_type,
205
- "targetValue": target_value
206
- }
268
+ params = {"targetType": target_type, "targetValue": target_value}
207
269
 
208
- response = await self._vortex_api_request("GET", "/invitations/by-target", params=params)
270
+ response = await self._vortex_api_request(
271
+ "GET", "/invitations/by-target", params=params
272
+ )
209
273
  return [Invitation(**inv) for inv in response.get("invitations", [])]
210
274
 
211
275
  def get_invitations_by_target_sync(
212
276
  self,
213
277
  target_type: Literal["email", "username", "phoneNumber"],
214
- target_value: str
278
+ target_value: str,
215
279
  ) -> List[Invitation]:
216
280
  """
217
281
  Get invitations for a specific target (synchronous)
@@ -223,12 +287,11 @@ class Vortex:
223
287
  Returns:
224
288
  List of invitations
225
289
  """
226
- params = {
227
- "targetType": target_type,
228
- "targetValue": target_value
229
- }
290
+ params = {"targetType": target_type, "targetValue": target_value}
230
291
 
231
- response = self._vortex_api_request_sync("GET", "/invitations/by-target", params=params)
292
+ response = self._vortex_api_request_sync(
293
+ "GET", "/invitations/by-target", params=params
294
+ )
232
295
  return [Invitation(**inv) for inv in response.get("invitations", [])]
233
296
 
234
297
  async def get_invitation(self, invitation_id: str) -> Invitation:
@@ -241,7 +304,9 @@ class Vortex:
241
304
  Returns:
242
305
  Invitation object
243
306
  """
244
- response = await self._vortex_api_request("GET", f"/invitations/{invitation_id}")
307
+ response = await self._vortex_api_request(
308
+ "GET", f"/invitations/{invitation_id}"
309
+ )
245
310
  return Invitation(**response)
246
311
 
247
312
  def get_invitation_sync(self, invitation_id: str) -> Invitation:
@@ -258,9 +323,7 @@ class Vortex:
258
323
  return Invitation(**response)
259
324
 
260
325
  async def accept_invitations(
261
- self,
262
- invitation_ids: List[str],
263
- target: Union[InvitationTarget, Dict[str, str]]
326
+ self, invitation_ids: List[str], target: Union[InvitationTarget, Dict[str, str]]
264
327
  ) -> Dict:
265
328
  """
266
329
  Accept multiple invitations
@@ -275,17 +338,12 @@ class Vortex:
275
338
  if isinstance(target, dict):
276
339
  target = InvitationTarget(**target)
277
340
 
278
- data = {
279
- "invitationIds": invitation_ids,
280
- "target": target.model_dump()
281
- }
341
+ data = {"invitationIds": invitation_ids, "target": target.model_dump()}
282
342
 
283
343
  return await self._vortex_api_request("POST", "/invitations/accept", data=data)
284
344
 
285
345
  def accept_invitations_sync(
286
- self,
287
- invitation_ids: List[str],
288
- target: Union[InvitationTarget, Dict[str, str]]
346
+ self, invitation_ids: List[str], target: Union[InvitationTarget, Dict[str, str]]
289
347
  ) -> Dict:
290
348
  """
291
349
  Accept multiple invitations (synchronous)
@@ -300,10 +358,7 @@ class Vortex:
300
358
  if isinstance(target, dict):
301
359
  target = InvitationTarget(**target)
302
360
 
303
- data = {
304
- "invitationIds": invitation_ids,
305
- "target": target.model_dump()
306
- }
361
+ data = {"invitationIds": invitation_ids, "target": target.model_dump()}
307
362
 
308
363
  return self._vortex_api_request_sync("POST", "/invitations/accept", data=data)
309
364
 
@@ -332,9 +387,7 @@ class Vortex:
332
387
  return self._vortex_api_request_sync("DELETE", f"/invitations/{invitation_id}")
333
388
 
334
389
  async def get_invitations_by_group(
335
- self,
336
- group_type: str,
337
- group_id: str
390
+ self, group_type: str, group_id: str
338
391
  ) -> List[Invitation]:
339
392
  """
340
393
  Get invitations for a specific group
@@ -346,13 +399,13 @@ class Vortex:
346
399
  Returns:
347
400
  List of invitations
348
401
  """
349
- response = await self._vortex_api_request("GET", f"/invitations/by-group/{group_type}/{group_id}")
402
+ response = await self._vortex_api_request(
403
+ "GET", f"/invitations/by-group/{group_type}/{group_id}"
404
+ )
350
405
  return [Invitation(**inv) for inv in response.get("invitations", [])]
351
406
 
352
407
  def get_invitations_by_group_sync(
353
- self,
354
- group_type: str,
355
- group_id: str
408
+ self, group_type: str, group_id: str
356
409
  ) -> List[Invitation]:
357
410
  """
358
411
  Get invitations for a specific group (synchronous)
@@ -364,14 +417,12 @@ class Vortex:
364
417
  Returns:
365
418
  List of invitations
366
419
  """
367
- response = self._vortex_api_request_sync("GET", f"/invitations/by-group/{group_type}/{group_id}")
420
+ response = self._vortex_api_request_sync(
421
+ "GET", f"/invitations/by-group/{group_type}/{group_id}"
422
+ )
368
423
  return [Invitation(**inv) for inv in response.get("invitations", [])]
369
424
 
370
- async def delete_invitations_by_group(
371
- self,
372
- group_type: str,
373
- group_id: str
374
- ) -> Dict:
425
+ async def delete_invitations_by_group(self, group_type: str, group_id: str) -> Dict:
375
426
  """
376
427
  Delete all invitations for a specific group
377
428
 
@@ -382,13 +433,11 @@ class Vortex:
382
433
  Returns:
383
434
  API response
384
435
  """
385
- return await self._vortex_api_request("DELETE", f"/invitations/by-group/{group_type}/{group_id}")
436
+ return await self._vortex_api_request(
437
+ "DELETE", f"/invitations/by-group/{group_type}/{group_id}"
438
+ )
386
439
 
387
- def delete_invitations_by_group_sync(
388
- self,
389
- group_type: str,
390
- group_id: str
391
- ) -> Dict:
440
+ def delete_invitations_by_group_sync(self, group_type: str, group_id: str) -> Dict:
392
441
  """
393
442
  Delete all invitations for a specific group (synchronous)
394
443
 
@@ -399,7 +448,9 @@ class Vortex:
399
448
  Returns:
400
449
  API response
401
450
  """
402
- return self._vortex_api_request_sync("DELETE", f"/invitations/by-group/{group_type}/{group_id}")
451
+ return self._vortex_api_request_sync(
452
+ "DELETE", f"/invitations/by-group/{group_type}/{group_id}"
453
+ )
403
454
 
404
455
  async def reinvite(self, invitation_id: str) -> Invitation:
405
456
  """
@@ -411,7 +462,9 @@ class Vortex:
411
462
  Returns:
412
463
  Updated invitation object
413
464
  """
414
- response = await self._vortex_api_request("POST", f"/invitations/{invitation_id}/reinvite")
465
+ response = await self._vortex_api_request(
466
+ "POST", f"/invitations/{invitation_id}/reinvite"
467
+ )
415
468
  return Invitation(**response)
416
469
 
417
470
  def reinvite_sync(self, invitation_id: str) -> Invitation:
@@ -424,7 +477,9 @@ class Vortex:
424
477
  Returns:
425
478
  Updated invitation object
426
479
  """
427
- response = self._vortex_api_request_sync("POST", f"/invitations/{invitation_id}/reinvite")
480
+ response = self._vortex_api_request_sync(
481
+ "POST", f"/invitations/{invitation_id}/reinvite"
482
+ )
428
483
  return Invitation(**response)
429
484
 
430
485
  async def close(self):
@@ -449,4 +504,4 @@ class Vortex:
449
504
 
450
505
  def __exit__(self, exc_type, exc_val, exc_tb):
451
506
  """Context manager exit"""
452
- self.close_sync()
507
+ self.close_sync()
@@ -1,9 +0,0 @@
1
- vortex_python_sdk-0.0.1.dist-info/licenses/LICENSE,sha256=VndlWxbL4-w3YDf2yE5gJscj4zVXF0qlSq0LDtay3lo,1074
2
- vortex_sdk/__init__.py,sha256=mFLcyV2i5W7xuj25cThFWYBm6S0HpeOGtUIHDenzhBc,631
3
- vortex_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- vortex_sdk/types.py,sha256=whBfV7yVcrmk5K7ex1s4FCs92V9_bj-7KUsCRi5fmgk,1491
5
- vortex_sdk/vortex.py,sha256=_Ov62rzGdLecbID6LVQLMZgDc96xw7jY5qNqsfUjV3o,12963
6
- vortex_python_sdk-0.0.1.dist-info/METADATA,sha256=BH1AkI5SMi_mhRtttqLa5w1o2gk8ymwdzX3emM6U5iQ,5765
7
- vortex_python_sdk-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- vortex_python_sdk-0.0.1.dist-info/top_level.txt,sha256=xFDlEcXIIi_sBhkse0YfMnSdg2IlaYUd0oP2UCDc_Y0,11
9
- vortex_python_sdk-0.0.1.dist-info/RECORD,,