vortex-python-sdk 0.0.1__tar.gz → 0.0.2__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.
Potentially problematic release.
This version of vortex-python-sdk might be problematic. Click here for more details.
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/CHANGELOG.md +31 -0
- {vortex_python_sdk-0.0.1/src/vortex_python_sdk.egg-info → vortex_python_sdk-0.0.2}/PKG-INFO +24 -7
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/README.md +23 -6
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/pyproject.toml +1 -1
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2/src/vortex_python_sdk.egg-info}/PKG-INFO +24 -7
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_sdk/__init__.py +5 -1
- vortex_python_sdk-0.0.2/src/vortex_sdk/types.py +102 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_sdk/vortex.py +7 -3
- vortex_python_sdk-0.0.1/src/vortex_sdk/types.py +0 -59
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/LICENSE +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/MANIFEST.in +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/setup.cfg +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/SOURCES.txt +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/dependency_links.txt +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/requires.txt +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/top_level.txt +0 -0
- {vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_sdk/py.typed +0 -0
|
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.2] - 2025-01-31
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **BREAKING FIX**: JWT payload format now matches TypeScript SDK
|
|
14
|
+
- `identifiers` changed from `Dict[str, str]` to `List[Dict]` with `type` and `value` fields
|
|
15
|
+
- `groups` structure now properly includes `type`, `id`/`groupId`, and `name` fields
|
|
16
|
+
- Added `IdentifierInput` type for type-safe identifier creation
|
|
17
|
+
- Updated `GroupInput` to support both `id` (legacy) and `groupId` (preferred) with proper camelCase serialization
|
|
18
|
+
- Updated documentation with correct JWT generation examples
|
|
19
|
+
|
|
20
|
+
### Migration Guide
|
|
21
|
+
If you're upgrading from 0.0.1, update your JWT generation code:
|
|
22
|
+
|
|
23
|
+
**Before (0.0.1):**
|
|
24
|
+
```python
|
|
25
|
+
jwt = vortex.generate_jwt({
|
|
26
|
+
"user_id": "user-123",
|
|
27
|
+
"identifiers": {"email": "user@example.com"}, # Dict
|
|
28
|
+
"groups": ["admin"], # List of strings
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**After (0.0.2):**
|
|
33
|
+
```python
|
|
34
|
+
jwt = vortex.generate_jwt({
|
|
35
|
+
"user_id": "user-123",
|
|
36
|
+
"identifiers": [{"type": "email", "value": "user@example.com"}], # List of dicts
|
|
37
|
+
"groups": [{"type": "team", "id": "team-1", "name": "Engineering"}], # List of objects
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
10
41
|
## [0.0.1] - 2024-10-10
|
|
11
42
|
|
|
12
43
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vortex-python-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
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
|
|
@@ -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": "
|
|
71
|
-
"identifiers":
|
|
72
|
-
"email": "user@example.com"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
@@ -29,16 +29,33 @@ vortex = Vortex(api_key="your-api-key", base_url="https://custom-api.example.com
|
|
|
29
29
|
```python
|
|
30
30
|
# Generate JWT for a user
|
|
31
31
|
jwt = vortex.generate_jwt({
|
|
32
|
-
"user_id": "
|
|
33
|
-
"identifiers":
|
|
34
|
-
"email": "user@example.com"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
"user_id": "user-123",
|
|
33
|
+
"identifiers": [
|
|
34
|
+
{"type": "email", "value": "user@example.com"}
|
|
35
|
+
],
|
|
36
|
+
"groups": [
|
|
37
|
+
{"type": "team", "id": "team-1", "name": "Engineering"}
|
|
38
|
+
],
|
|
38
39
|
"role": "admin"
|
|
39
40
|
})
|
|
40
41
|
|
|
41
42
|
print(f"JWT: {jwt}")
|
|
43
|
+
|
|
44
|
+
# Or using type-safe models
|
|
45
|
+
from vortex_sdk import JwtPayload, IdentifierInput, GroupInput
|
|
46
|
+
|
|
47
|
+
jwt = vortex.generate_jwt(
|
|
48
|
+
JwtPayload(
|
|
49
|
+
user_id="user-123",
|
|
50
|
+
identifiers=[
|
|
51
|
+
IdentifierInput(type="email", value="user@example.com")
|
|
52
|
+
],
|
|
53
|
+
groups=[
|
|
54
|
+
GroupInput(type="team", id="team-1", name="Engineering")
|
|
55
|
+
],
|
|
56
|
+
role="admin"
|
|
57
|
+
)
|
|
58
|
+
)
|
|
42
59
|
```
|
|
43
60
|
|
|
44
61
|
### Invitation Management
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vortex-python-sdk"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.2"
|
|
8
8
|
description = "Vortex Python SDK for invitation management and JWT generation"
|
|
9
9
|
authors = [{name = "TeamVortexSoftware", email = "support@vortexsoftware.com"}]
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vortex-python-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.2
|
|
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
|
|
@@ -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": "
|
|
71
|
-
"identifiers":
|
|
72
|
-
"email": "user@example.com"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
@@ -8,6 +8,8 @@ from .vortex import Vortex
|
|
|
8
8
|
from .types import (
|
|
9
9
|
AuthenticatedUser,
|
|
10
10
|
JwtPayload,
|
|
11
|
+
IdentifierInput,
|
|
12
|
+
GroupInput,
|
|
11
13
|
InvitationTarget,
|
|
12
14
|
Invitation,
|
|
13
15
|
CreateInvitationRequest,
|
|
@@ -16,7 +18,7 @@ from .types import (
|
|
|
16
18
|
VortexApiError
|
|
17
19
|
)
|
|
18
20
|
|
|
19
|
-
__version__ = "0.0.
|
|
21
|
+
__version__ = "0.0.2"
|
|
20
22
|
__author__ = "TeamVortexSoftware"
|
|
21
23
|
__email__ = "support@vortexsoftware.com"
|
|
22
24
|
|
|
@@ -24,6 +26,8 @@ __all__ = [
|
|
|
24
26
|
"Vortex",
|
|
25
27
|
"AuthenticatedUser",
|
|
26
28
|
"JwtPayload",
|
|
29
|
+
"IdentifierInput",
|
|
30
|
+
"GroupInput",
|
|
27
31
|
"InvitationTarget",
|
|
28
32
|
"Invitation",
|
|
29
33
|
"CreateInvitationRequest",
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from typing import Dict, List, Optional, Union, Literal
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class IdentifierInput(BaseModel):
|
|
6
|
+
"""Identifier structure for JWT generation"""
|
|
7
|
+
type: Literal["email", "sms"]
|
|
8
|
+
value: str
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GroupInput(BaseModel):
|
|
12
|
+
"""Group structure for JWT generation (input)"""
|
|
13
|
+
type: str
|
|
14
|
+
id: Optional[str] = None # Legacy field (deprecated, use groupId)
|
|
15
|
+
groupId: Optional[str] = Field(None, alias="group_id", serialization_alias="groupId") # Preferred: Customer's group ID
|
|
16
|
+
name: str
|
|
17
|
+
|
|
18
|
+
class Config:
|
|
19
|
+
populate_by_name = True
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class InvitationGroup(BaseModel):
|
|
23
|
+
"""
|
|
24
|
+
Invitation group from API responses
|
|
25
|
+
This matches the MemberGroups table structure from the API
|
|
26
|
+
"""
|
|
27
|
+
id: str # Vortex internal UUID
|
|
28
|
+
account_id: str # Vortex account ID (camelCase in JSON: accountId)
|
|
29
|
+
group_id: str # Customer's group ID (camelCase in JSON: groupId)
|
|
30
|
+
type: str # Group type (e.g., "workspace", "team")
|
|
31
|
+
name: str # Group name
|
|
32
|
+
created_at: str # ISO 8601 timestamp (camelCase in JSON: createdAt)
|
|
33
|
+
|
|
34
|
+
class Config:
|
|
35
|
+
# Allow both snake_case (Python) and camelCase (JSON) field names
|
|
36
|
+
populate_by_name = True
|
|
37
|
+
json_schema_extra = {
|
|
38
|
+
"example": {
|
|
39
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
40
|
+
"accountId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
|
41
|
+
"groupId": "workspace-123",
|
|
42
|
+
"type": "workspace",
|
|
43
|
+
"name": "My Workspace",
|
|
44
|
+
"createdAt": "2025-01-27T12:00:00.000Z"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AuthenticatedUser(BaseModel):
|
|
50
|
+
user_id: str
|
|
51
|
+
identifiers: List[IdentifierInput]
|
|
52
|
+
groups: Optional[List[GroupInput]] = None
|
|
53
|
+
role: Optional[str] = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class JwtPayload(BaseModel):
|
|
57
|
+
user_id: str
|
|
58
|
+
identifiers: List[IdentifierInput]
|
|
59
|
+
groups: Optional[List[GroupInput]] = None
|
|
60
|
+
role: Optional[str] = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class InvitationTarget(BaseModel):
|
|
64
|
+
type: Literal["email", "username", "phoneNumber"]
|
|
65
|
+
value: str
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class Invitation(BaseModel):
|
|
69
|
+
id: str
|
|
70
|
+
target: InvitationTarget
|
|
71
|
+
groups: Optional[List[InvitationGroup]] = None # Full group information
|
|
72
|
+
status: str
|
|
73
|
+
created_at: str
|
|
74
|
+
updated_at: Optional[str] = None
|
|
75
|
+
expires_at: Optional[str] = None
|
|
76
|
+
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class CreateInvitationRequest(BaseModel):
|
|
80
|
+
target: InvitationTarget
|
|
81
|
+
group_type: Optional[str] = None
|
|
82
|
+
group_id: Optional[str] = None
|
|
83
|
+
expires_at: Optional[str] = None
|
|
84
|
+
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class AcceptInvitationsRequest(BaseModel):
|
|
88
|
+
invitation_ids: List[str]
|
|
89
|
+
target: InvitationTarget
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ApiResponse(BaseModel):
|
|
93
|
+
data: Optional[Dict] = None
|
|
94
|
+
error: Optional[str] = None
|
|
95
|
+
status_code: int = 200
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class VortexApiError(Exception):
|
|
99
|
+
def __init__(self, message: str, status_code: int = 500):
|
|
100
|
+
self.message = message
|
|
101
|
+
self.status_code = status_code
|
|
102
|
+
super().__init__(message)
|
|
@@ -49,14 +49,18 @@ class Vortex:
|
|
|
49
49
|
"typ": "JWT"
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
# JWT Payload
|
|
52
|
+
# JWT Payload - serialize identifiers and groups to dicts
|
|
53
53
|
jwt_payload = {
|
|
54
54
|
"userId": payload.user_id,
|
|
55
|
-
"identifiers": payload.identifiers,
|
|
55
|
+
"identifiers": [{"type": id.type, "value": id.value} for id in payload.identifiers],
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
if payload.groups is not None:
|
|
59
|
-
|
|
59
|
+
# Serialize groups, using model_dump to handle camelCase conversion
|
|
60
|
+
jwt_payload["groups"] = [
|
|
61
|
+
{k: v for k, v in group.model_dump(by_alias=True, exclude_none=True).items()}
|
|
62
|
+
for group in payload.groups
|
|
63
|
+
]
|
|
60
64
|
if payload.role is not None:
|
|
61
65
|
jwt_payload["role"] = payload.role
|
|
62
66
|
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
from typing import Dict, List, Optional, Union, Literal
|
|
2
|
-
from pydantic import BaseModel
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class AuthenticatedUser(BaseModel):
|
|
6
|
-
user_id: str
|
|
7
|
-
identifiers: Dict[str, str]
|
|
8
|
-
groups: Optional[List[str]] = None
|
|
9
|
-
role: Optional[str] = None
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class JwtPayload(BaseModel):
|
|
13
|
-
user_id: str
|
|
14
|
-
identifiers: Dict[str, str]
|
|
15
|
-
groups: Optional[List[str]] = None
|
|
16
|
-
role: Optional[str] = None
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class InvitationTarget(BaseModel):
|
|
20
|
-
type: Literal["email", "username", "phoneNumber"]
|
|
21
|
-
value: str
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Invitation(BaseModel):
|
|
25
|
-
id: str
|
|
26
|
-
target: InvitationTarget
|
|
27
|
-
group_type: Optional[str] = None
|
|
28
|
-
group_id: Optional[str] = None
|
|
29
|
-
status: str
|
|
30
|
-
created_at: str
|
|
31
|
-
updated_at: Optional[str] = None
|
|
32
|
-
expires_at: Optional[str] = None
|
|
33
|
-
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class CreateInvitationRequest(BaseModel):
|
|
37
|
-
target: InvitationTarget
|
|
38
|
-
group_type: Optional[str] = None
|
|
39
|
-
group_id: Optional[str] = None
|
|
40
|
-
expires_at: Optional[str] = None
|
|
41
|
-
metadata: Optional[Dict[str, Union[str, int, bool]]] = None
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class AcceptInvitationsRequest(BaseModel):
|
|
45
|
-
invitation_ids: List[str]
|
|
46
|
-
target: InvitationTarget
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class ApiResponse(BaseModel):
|
|
50
|
-
data: Optional[Dict] = None
|
|
51
|
-
error: Optional[str] = None
|
|
52
|
-
status_code: int = 200
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
class VortexApiError(Exception):
|
|
56
|
-
def __init__(self, message: str, status_code: int = 500):
|
|
57
|
-
self.message = message
|
|
58
|
-
self.status_code = status_code
|
|
59
|
-
super().__init__(message)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/requires.txt
RENAMED
|
File without changes
|
{vortex_python_sdk-0.0.1 → vortex_python_sdk-0.0.2}/src/vortex_python_sdk.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|