vortex-python-sdk 0.1.3__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.
@@ -0,0 +1,144 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.3] - 2025-01-29
11
+
12
+ ### Added
13
+ - **AcceptUser Type**: New preferred format for accepting invitations with `email`, `phone`, and `name` fields
14
+ - Enhanced `accept_invitations` and `accept_invitations_sync` methods to support both new User format and legacy target format
15
+
16
+ ### Changed
17
+ - **DEPRECATED**: Legacy `InvitationTarget` format for `accept_invitations` - use `AcceptUser` instead
18
+ - Internal API calls now always use User format for consistency
19
+ - Added deprecation logging when legacy target format is used
20
+
21
+ ### Fixed
22
+ - Maintained 100% backward compatibility - existing code using legacy target format continues to work
23
+
24
+ ## [0.1.2] - Previous
25
+
26
+ ### Changed
27
+
28
+ - **JWT Payload Simplification**: Updated JWT structure to use simplified fields (backward compatible)
29
+ - **NEW (Preferred)**: Use `User` object with `id`, `email`, and `admin_scopes` for cleaner, more maintainable code
30
+ - `id` (string): User's ID in your system
31
+ - `email` (string): User's email address - replaces the `identifiers` array
32
+ - `admin_scopes` (list): List of admin scopes (e.g., `['autojoin']` for autojoin admin privileges)
33
+ - **DEPRECATED (Still Supported)**: `identifiers`, `groups`, and `role` fields maintained for backward compatibility
34
+ - Supports additional properties via Pydantic's `extra="allow"` configuration
35
+ - All existing integrations will continue to work without changes
36
+
37
+ ### Migration Guide (Optional - Backward Compatible)
38
+
39
+ The old format still works, but we recommend migrating to the simpler structure:
40
+
41
+ **New simplified format (recommended):**
42
+
43
+ ```python
44
+ user = {
45
+ "id": "user-123",
46
+ "email": "user@example.com",
47
+ "admin_scopes": ["autojoin"] # optional: grants autojoin admin privileges
48
+ }
49
+ jwt = vortex.generate_jwt(user=user)
50
+ ```
51
+
52
+ **Old format (still supported):**
53
+
54
+ ```python
55
+ jwt = vortex.generate_jwt({
56
+ "user_id": "user-123",
57
+ "identifiers": [{"type": "email", "value": "user@example.com"}],
58
+ "groups": [{"type": "team", "id": "team-1", "name": "Engineering"}],
59
+ "role": "admin"
60
+ })
61
+ ```
62
+
63
+ ## [0.0.5] - 2025-11-06
64
+
65
+ ### Fixed
66
+
67
+ - **CRITICAL FIX**: Updated api url & auth headers
68
+
69
+ ## [0.0.3] - 2025-01-31
70
+
71
+ ### Fixed
72
+
73
+ - **CRITICAL FIX**: JWT generation now matches Node.js SDK implementation exactly
74
+ - Improved JWT signing algorithm to match Node.js SDK
75
+ - Added `iat` (issued at) and `expires` timestamp fields to JWT
76
+ - Added `attributes` field support in JwtPayload for custom user attributes
77
+ - Fixed base64url encoding
78
+ - Added comprehensive tests verifying JWT output matches Node.js SDK byte-for-byte
79
+
80
+ ### Breaking Changes
81
+
82
+ - JWT structure changed significantly - tokens from 0.0.2 are incompatible with 0.0.3
83
+ - JWTs now include `iat` and `expires` fields for proper token lifecycle management
84
+
85
+ ## [0.0.2] - 2025-01-31
86
+
87
+ ### Fixed
88
+
89
+ - **BREAKING FIX**: JWT payload format now matches TypeScript SDK
90
+ - `identifiers` changed from `Dict[str, str]` to `List[Dict]` with `type` and `value` fields
91
+ - `groups` structure now properly includes `type`, `id`/`groupId`, and `name` fields
92
+ - Added `IdentifierInput` type for type-safe identifier creation
93
+ - Updated `GroupInput` to support both `id` (legacy) and `groupId` (preferred) with proper camelCase serialization
94
+ - Updated documentation with correct JWT generation examples
95
+
96
+ ### Migration Guide
97
+
98
+ If you're upgrading from 0.0.1, update your JWT generation code:
99
+
100
+ **Before (0.0.1):**
101
+
102
+ ```python
103
+ jwt = vortex.generate_jwt({
104
+ "user_id": "user-123",
105
+ "identifiers": {"email": "user@example.com"}, # Dict
106
+ "groups": ["admin"], # List of strings
107
+ })
108
+ ```
109
+
110
+ **After (0.0.2):**
111
+
112
+ ```python
113
+ jwt = vortex.generate_jwt({
114
+ "user_id": "user-123",
115
+ "identifiers": [{"type": "email", "value": "user@example.com"}], # List of dicts
116
+ "groups": [{"type": "team", "id": "team-1", "name": "Engineering"}], # List of objects
117
+ })
118
+ ```
119
+
120
+ ## [0.0.1] - 2024-10-10
121
+
122
+ ### Added
123
+
124
+ - Initial release of Vortex Python SDK
125
+ - JWT generation with HMAC-SHA256 signing
126
+ - Complete invitation management API
127
+ - Async and sync HTTP client methods
128
+ - Type safety with Pydantic models
129
+ - Context manager support for resource cleanup
130
+ - Comprehensive error handling with VortexApiError
131
+ - Full compatibility with Node.js SDK API
132
+
133
+ ### Features
134
+
135
+ - `generate_jwt()` - Generate Vortex JWT tokens
136
+ - `get_invitations_by_target()` - Get invitations by email/username/phone
137
+ - `accept_invitations()` - Accept multiple invitations
138
+ - `get_invitation()` - Get specific invitation by ID
139
+ - `revoke_invitation()` - Revoke invitation
140
+ - `get_invitations_by_group()` - Get invitations for a group
141
+ - `delete_invitations_by_group()` - Delete all group invitations
142
+ - `reinvite()` - Reinvite functionality
143
+ - Both async and sync versions of all methods
144
+ - Python 3.8+ support
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 TeamVortexSoftware
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ recursive-include src/vortex_sdk *.py
5
+ recursive-include src/vortex_sdk py.typed
6
+ exclude tests/
7
+ exclude .github/
8
+ exclude *.pyc
9
+ exclude __pycache__/
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: vortex-python-sdk
3
+ Version: 0.1.3
4
+ Summary: Vortex Python SDK for invitation management and JWT generation
5
+ Author-email: TeamVortexSoftware <support@vortexsoftware.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/teamvortexsoftware/vortex-python-sdk
8
+ Project-URL: Repository, https://github.com/teamvortexsoftware/vortex-python-sdk.git
9
+ Project-URL: Documentation, https://docs.vortexsoftware.com/python-sdk
10
+ Project-URL: Changelog, https://github.com/teamvortexsoftware/vortex-python-sdk/blob/main/CHANGELOG.md
11
+ Keywords: vortex,invitations,jwt,api,sdk
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: pydantic>=2.8.0
28
+ Requires-Dist: typing-extensions>=4.8.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
31
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
32
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
33
+ Requires-Dist: black>=23.0.0; extra == "dev"
34
+ Requires-Dist: isort>=5.12.0; extra == "dev"
35
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
36
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # Vortex Python SDK
40
+
41
+ A Python SDK for Vortex invitation management and JWT generation.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install vortex-python-sdk
47
+ ```
48
+
49
+ > **Note**: The package will be available on PyPI once published. See [PUBLISHING.md](PUBLISHING.md) for publishing instructions.
50
+
51
+ ## Usage
52
+
53
+ ### Basic Setup
54
+
55
+ ```python
56
+ from vortex_sdk import Vortex
57
+
58
+ # Initialize the client with your Vortex API key
59
+ vortex = Vortex(api_key="your-vortex-api-key")
60
+
61
+ # Or with custom base URL
62
+ vortex = Vortex(api_key="your-vortex-api-key", base_url="https://custom-api.example.com")
63
+ ```
64
+
65
+ ### JWT Generation
66
+
67
+ ```python
68
+ # Generate JWT for a user
69
+ user = {
70
+ "id": "user-123",
71
+ "email": "user@example.com",
72
+ "admin_scopes": ["autojoin"] # Optional - included as adminScopes array in JWT
73
+ }
74
+
75
+ jwt = vortex.generate_jwt(user=user)
76
+ print(f"JWT: {jwt}")
77
+
78
+ # With additional properties
79
+ jwt = vortex.generate_jwt(
80
+ user=user,
81
+ role="admin",
82
+ department="Engineering"
83
+ )
84
+
85
+ # Or using type-safe models
86
+ from vortex_sdk import User
87
+
88
+ user = User(
89
+ id="user-123",
90
+ email="user@example.com",
91
+ admin_scopes=["autojoin"]
92
+ )
93
+
94
+ jwt = vortex.generate_jwt(user=user)
95
+ ```
96
+
97
+ ### Invitation Management
98
+
99
+ #### Get Invitations by Target
100
+
101
+ ```python
102
+ import asyncio
103
+
104
+ async def get_user_invitations():
105
+ # Async version
106
+ invitations = await vortex.get_invitations_by_target("email", "user@example.com")
107
+ for invitation in invitations:
108
+ print(f"Invitation ID: {invitation.id}, Status: {invitation.status}")
109
+
110
+ # Sync version
111
+ invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
112
+ ```
113
+
114
+ #### Accept Invitations
115
+
116
+ ```python
117
+ async def accept_user_invitations():
118
+ # Async version
119
+ result = await vortex.accept_invitations(
120
+ invitation_ids=["inv1", "inv2"],
121
+ target={"type": "email", "value": "user@example.com"}
122
+ )
123
+ print(f"Result: {result}")
124
+
125
+ # Sync version
126
+ result = vortex.accept_invitations_sync(
127
+ invitation_ids=["inv1", "inv2"],
128
+ target={"type": "email", "value": "user@example.com"}
129
+ )
130
+ ```
131
+
132
+ #### Get Specific Invitation
133
+
134
+ ```python
135
+ async def get_invitation():
136
+ # Async version
137
+ invitation = await vortex.get_invitation("invitation-id")
138
+ print(f"Invitation: {invitation.id}")
139
+
140
+ # Sync version
141
+ invitation = vortex.get_invitation_sync("invitation-id")
142
+ ```
143
+
144
+ #### Revoke Invitation
145
+
146
+ ```python
147
+ async def revoke_invitation():
148
+ # Async version
149
+ result = await vortex.revoke_invitation("invitation-id")
150
+ print(f"Revoked: {result}")
151
+
152
+ # Sync version
153
+ result = vortex.revoke_invitation_sync("invitation-id")
154
+ ```
155
+
156
+ ### Group Operations
157
+
158
+ #### Get Invitations by Group
159
+
160
+ ```python
161
+ async def get_group_invitations():
162
+ # Async version
163
+ invitations = await vortex.get_invitations_by_group("organization", "org123")
164
+ print(f"Found {len(invitations)} invitations")
165
+
166
+ # Sync version
167
+ invitations = vortex.get_invitations_by_group_sync("organization", "org123")
168
+ ```
169
+
170
+ #### Delete Invitations by Group
171
+
172
+ ```python
173
+ async def delete_group_invitations():
174
+ # Async version
175
+ result = await vortex.delete_invitations_by_group("organization", "org123")
176
+ print(f"Deleted: {result}")
177
+
178
+ # Sync version
179
+ result = vortex.delete_invitations_by_group_sync("organization", "org123")
180
+ ```
181
+
182
+ #### Reinvite
183
+
184
+ ```python
185
+ async def reinvite_user():
186
+ # Async version
187
+ invitation = await vortex.reinvite("invitation-id")
188
+ print(f"Reinvited: {invitation.id}")
189
+
190
+ # Sync version
191
+ invitation = vortex.reinvite_sync("invitation-id")
192
+ ```
193
+
194
+ ### Context Manager Usage
195
+
196
+ ```python
197
+ # Async context manager
198
+ async with Vortex(api_key="your-api-key") as vortex:
199
+ invitations = await vortex.get_invitations_by_target("email", "user@example.com")
200
+
201
+ # Sync context manager
202
+ with Vortex(api_key="your-api-key") as vortex:
203
+ invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
204
+ ```
205
+
206
+ ### Error Handling
207
+
208
+ ```python
209
+ from vortex_sdk import VortexApiError
210
+
211
+ try:
212
+ invitation = vortex.get_invitation_sync("invalid-id")
213
+ except VortexApiError as e:
214
+ print(f"API Error: {e.message} (Status: {e.status_code})")
215
+ except Exception as e:
216
+ print(f"Unexpected error: {e}")
217
+ ```
218
+
219
+ ## Development
220
+
221
+ ### Installation
222
+
223
+ ```bash
224
+ # Install development dependencies
225
+ pip install -e ".[dev]"
226
+ ```
227
+
228
+ ### Running Tests
229
+
230
+ ```bash
231
+ pytest
232
+ ```
233
+
234
+ ### Code Formatting
235
+
236
+ ```bash
237
+ # Format code
238
+ black src/ tests/
239
+ isort src/ tests/
240
+
241
+ # Lint code
242
+ ruff check src/ tests/
243
+ mypy src/
244
+ ```
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,210 @@
1
+ # Vortex Python SDK
2
+
3
+ A Python SDK for Vortex invitation management and JWT generation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install vortex-python-sdk
9
+ ```
10
+
11
+ > **Note**: The package will be available on PyPI once published. See [PUBLISHING.md](PUBLISHING.md) for publishing instructions.
12
+
13
+ ## Usage
14
+
15
+ ### Basic Setup
16
+
17
+ ```python
18
+ from vortex_sdk import Vortex
19
+
20
+ # Initialize the client with your Vortex API key
21
+ vortex = Vortex(api_key="your-vortex-api-key")
22
+
23
+ # Or with custom base URL
24
+ vortex = Vortex(api_key="your-vortex-api-key", base_url="https://custom-api.example.com")
25
+ ```
26
+
27
+ ### JWT Generation
28
+
29
+ ```python
30
+ # Generate JWT for a user
31
+ user = {
32
+ "id": "user-123",
33
+ "email": "user@example.com",
34
+ "admin_scopes": ["autojoin"] # Optional - included as adminScopes array in JWT
35
+ }
36
+
37
+ jwt = vortex.generate_jwt(user=user)
38
+ print(f"JWT: {jwt}")
39
+
40
+ # With additional properties
41
+ jwt = vortex.generate_jwt(
42
+ user=user,
43
+ role="admin",
44
+ department="Engineering"
45
+ )
46
+
47
+ # Or using type-safe models
48
+ from vortex_sdk import User
49
+
50
+ user = User(
51
+ id="user-123",
52
+ email="user@example.com",
53
+ admin_scopes=["autojoin"]
54
+ )
55
+
56
+ jwt = vortex.generate_jwt(user=user)
57
+ ```
58
+
59
+ ### Invitation Management
60
+
61
+ #### Get Invitations by Target
62
+
63
+ ```python
64
+ import asyncio
65
+
66
+ async def get_user_invitations():
67
+ # Async version
68
+ invitations = await vortex.get_invitations_by_target("email", "user@example.com")
69
+ for invitation in invitations:
70
+ print(f"Invitation ID: {invitation.id}, Status: {invitation.status}")
71
+
72
+ # Sync version
73
+ invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
74
+ ```
75
+
76
+ #### Accept Invitations
77
+
78
+ ```python
79
+ async def accept_user_invitations():
80
+ # Async version
81
+ result = await vortex.accept_invitations(
82
+ invitation_ids=["inv1", "inv2"],
83
+ target={"type": "email", "value": "user@example.com"}
84
+ )
85
+ print(f"Result: {result}")
86
+
87
+ # Sync version
88
+ result = vortex.accept_invitations_sync(
89
+ invitation_ids=["inv1", "inv2"],
90
+ target={"type": "email", "value": "user@example.com"}
91
+ )
92
+ ```
93
+
94
+ #### Get Specific Invitation
95
+
96
+ ```python
97
+ async def get_invitation():
98
+ # Async version
99
+ invitation = await vortex.get_invitation("invitation-id")
100
+ print(f"Invitation: {invitation.id}")
101
+
102
+ # Sync version
103
+ invitation = vortex.get_invitation_sync("invitation-id")
104
+ ```
105
+
106
+ #### Revoke Invitation
107
+
108
+ ```python
109
+ async def revoke_invitation():
110
+ # Async version
111
+ result = await vortex.revoke_invitation("invitation-id")
112
+ print(f"Revoked: {result}")
113
+
114
+ # Sync version
115
+ result = vortex.revoke_invitation_sync("invitation-id")
116
+ ```
117
+
118
+ ### Group Operations
119
+
120
+ #### Get Invitations by Group
121
+
122
+ ```python
123
+ async def get_group_invitations():
124
+ # Async version
125
+ invitations = await vortex.get_invitations_by_group("organization", "org123")
126
+ print(f"Found {len(invitations)} invitations")
127
+
128
+ # Sync version
129
+ invitations = vortex.get_invitations_by_group_sync("organization", "org123")
130
+ ```
131
+
132
+ #### Delete Invitations by Group
133
+
134
+ ```python
135
+ async def delete_group_invitations():
136
+ # Async version
137
+ result = await vortex.delete_invitations_by_group("organization", "org123")
138
+ print(f"Deleted: {result}")
139
+
140
+ # Sync version
141
+ result = vortex.delete_invitations_by_group_sync("organization", "org123")
142
+ ```
143
+
144
+ #### Reinvite
145
+
146
+ ```python
147
+ async def reinvite_user():
148
+ # Async version
149
+ invitation = await vortex.reinvite("invitation-id")
150
+ print(f"Reinvited: {invitation.id}")
151
+
152
+ # Sync version
153
+ invitation = vortex.reinvite_sync("invitation-id")
154
+ ```
155
+
156
+ ### Context Manager Usage
157
+
158
+ ```python
159
+ # Async context manager
160
+ async with Vortex(api_key="your-api-key") as vortex:
161
+ invitations = await vortex.get_invitations_by_target("email", "user@example.com")
162
+
163
+ # Sync context manager
164
+ with Vortex(api_key="your-api-key") as vortex:
165
+ invitations = vortex.get_invitations_by_target_sync("email", "user@example.com")
166
+ ```
167
+
168
+ ### Error Handling
169
+
170
+ ```python
171
+ from vortex_sdk import VortexApiError
172
+
173
+ try:
174
+ invitation = vortex.get_invitation_sync("invalid-id")
175
+ except VortexApiError as e:
176
+ print(f"API Error: {e.message} (Status: {e.status_code})")
177
+ except Exception as e:
178
+ print(f"Unexpected error: {e}")
179
+ ```
180
+
181
+ ## Development
182
+
183
+ ### Installation
184
+
185
+ ```bash
186
+ # Install development dependencies
187
+ pip install -e ".[dev]"
188
+ ```
189
+
190
+ ### Running Tests
191
+
192
+ ```bash
193
+ pytest
194
+ ```
195
+
196
+ ### Code Formatting
197
+
198
+ ```bash
199
+ # Format code
200
+ black src/ tests/
201
+ isort src/ tests/
202
+
203
+ # Lint code
204
+ ruff check src/ tests/
205
+ mypy src/
206
+ ```
207
+
208
+ ## License
209
+
210
+ MIT