dominus-sdk-python 2.1.7__tar.gz → 2.2.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.
Files changed (40) hide show
  1. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/PKG-INFO +215 -28
  2. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/README.md +214 -27
  3. dominus_sdk_python-2.2.0/dominus/__init__.py +108 -0
  4. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/config/__init__.py +4 -4
  5. dominus_sdk_python-2.2.0/dominus/namespaces/admin.py +58 -0
  6. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/auth.py +539 -10
  7. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/db.py +26 -1
  8. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/ddl.py +206 -0
  9. dominus_sdk_python-2.2.0/dominus/namespaces/fastapi.py +252 -0
  10. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/files.py +180 -0
  11. dominus_sdk_python-2.2.0/dominus/namespaces/secure.py +256 -0
  12. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/start.py +22 -0
  13. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus_sdk_python.egg-info/PKG-INFO +215 -28
  14. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus_sdk_python.egg-info/SOURCES.txt +3 -0
  15. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/pyproject.toml +1 -1
  16. dominus_sdk_python-2.1.7/dominus/__init__.py +0 -47
  17. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/config/endpoints.py +0 -0
  18. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/errors.py +0 -0
  19. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/helpers/__init__.py +0 -0
  20. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/helpers/auth.py +0 -0
  21. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/helpers/cache.py +0 -0
  22. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/helpers/core.py +0 -0
  23. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/helpers/crypto.py +0 -0
  24. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/__init__.py +0 -0
  25. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/_deprecated_crossover.py +0 -0
  26. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/_deprecated_sql.py +0 -0
  27. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/courier.py +0 -0
  28. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/health.py +0 -0
  29. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/logs.py +0 -0
  30. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/open.py +0 -0
  31. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/portal.py +0 -0
  32. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/redis.py +0 -0
  33. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/namespaces/secrets.py +0 -0
  34. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/services/__init__.py +0 -0
  35. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/services/_deprecated_architect.py +0 -0
  36. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus/services/_deprecated_sovereign.py +0 -0
  37. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
  38. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
  39. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
  40. {dominus_sdk_python-2.1.7 → dominus_sdk_python-2.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 2.1.7
3
+ Version: 2.2.0
4
4
  Summary: Python SDK for the Dominus Orchestrator Platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -29,31 +29,31 @@ Provides-Extra: dev
29
29
  Requires-Dist: pytest>=7.0.0; extra == "dev"
30
30
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
31
31
 
32
- # CB Dominus SDK
32
+ # CB Dominus SDK for Python
33
33
 
34
- **Python SDK for the Dominus Orchestrator Platform**
34
+ **Async Python SDK for the Dominus Orchestrator Platform**
35
35
 
36
36
  A unified, async-first Python SDK providing seamless access to all Dominus backend services including secrets management, database operations, caching, file storage, authentication, schema management, and structured logging.
37
37
 
38
38
  ## Features
39
39
 
40
40
  - **Namespace-based API** - Intuitive access via `dominus.db`, `dominus.redis`, `dominus.files`, etc.
41
- - **Async/Await** - Built for modern async Python applications
41
+ - **Async/Await** - Built for modern async Python applications (asyncio)
42
42
  - **Automatic JWT Management** - Token minting, caching, and refresh handled transparently
43
43
  - **Resilience Built-in** - Circuit breaker, exponential backoff, and retry logic
44
- - **Typed Errors** - Specific error classes for different failure modes
44
+ - **Cold Start Handling** - Special retry logic for orchestrator cold starts
45
+ - **Typed Errors** - 9 specific error classes for different failure modes
45
46
  - **Secure by Default** - Client-side password hashing, encrypted cache, audit trail support
46
47
 
47
48
  ## Quick Start
48
49
 
49
50
  ```python
50
51
  from dominus import dominus
52
+ import os
51
53
 
52
54
  # Set your token (or use DOMINUS_TOKEN environment variable)
53
- import os
54
55
  os.environ["DOMINUS_TOKEN"] = "your-psk-token"
55
56
 
56
- # Start using the SDK
57
57
  async def main():
58
58
  # Secrets
59
59
  db_url = await dominus.get("DATABASE_URL")
@@ -81,18 +81,32 @@ git clone https://github.com/carebridgesystems/cb-dominus-sdk.git
81
81
  pip install httpx bcrypt cryptography
82
82
  ```
83
83
 
84
+ Or install via pip (when published):
85
+
86
+ ```bash
87
+ pip install dominus-sdk-python
88
+ ```
89
+
90
+ ## Requirements
91
+
92
+ - Python 3.9+
93
+ - `httpx` - Async HTTP client
94
+ - `bcrypt` - Password hashing
95
+ - `cryptography` - Cache encryption
96
+
84
97
  ## Namespaces
85
98
 
86
99
  | Namespace | Service | Purpose |
87
100
  |-----------|---------|---------|
88
101
  | `dominus.secrets` | Warden | Secrets management |
89
102
  | `dominus.db` | Scribe | Database CRUD operations |
90
- | `dominus.redis` | Whisperer | Redis caching |
91
- | `dominus.files` | Archivist | Object storage (B2) |
92
- | `dominus.auth` | Guardian | Authentication & authorization |
103
+ | `dominus.secure` | Scribe | Secure table access with audit logging |
104
+ | `dominus.redis` | Whisperer | Redis caching & distributed locks |
105
+ | `dominus.files` | Archivist | Object storage (Backblaze B2) |
106
+ | `dominus.auth` | Guardian | Users, roles, scopes, tenants, pages, navigation |
93
107
  | `dominus.ddl` | Smith | Schema DDL & migrations |
94
- | `dominus.logs` | Herald | Structured logging |
95
- | `dominus.portal` | Portal | User auth & sessions |
108
+ | `dominus.logs` | Herald | Structured logging (BetterStack) |
109
+ | `dominus.portal` | Portal | User auth, sessions, profiles, navigation |
96
110
  | `dominus.courier` | Courier | Email delivery (Postmark) |
97
111
  | `dominus.open` | Scribe | Direct database access |
98
112
  | `dominus.health` | Health | Service health checks |
@@ -114,6 +128,10 @@ await dominus.secrets.delete("OLD_KEY")
114
128
  ### Database Operations
115
129
 
116
130
  ```python
131
+ # List tables
132
+ tables = await dominus.db.tables()
133
+ tenant_tables = await dominus.db.tables(schema="tenant_acme")
134
+
117
135
  # Query with filters and pagination
118
136
  users = await dominus.db.query(
119
137
  "users",
@@ -133,6 +151,15 @@ user = await dominus.db.insert("users", {
133
151
  # Update
134
152
  await dominus.db.update("users", {"status": "inactive"}, filters={"id": user_id})
135
153
 
154
+ # Delete
155
+ await dominus.db.delete("users", filters={"id": user_id})
156
+
157
+ # Bulk insert
158
+ await dominus.db.bulk_insert("events", [
159
+ {"type": "login", "user_id": "123"},
160
+ {"type": "login", "user_id": "456"}
161
+ ])
162
+
136
163
  # Secure table access (requires audit reason)
137
164
  patients = await dominus.db.query(
138
165
  "patients",
@@ -145,9 +172,10 @@ patients = await dominus.db.query(
145
172
  ### Redis Caching
146
173
 
147
174
  ```python
148
- # Key-value operations
175
+ # Key-value operations (TTL: min 60s, max 24h)
149
176
  await dominus.redis.set("user:123", {"name": "John"}, ttl=3600)
150
177
  value = await dominus.redis.get("user:123")
178
+ await dominus.redis.delete("user:123")
151
179
 
152
180
  # Distributed locks
153
181
  if await dominus.redis.setnx("lock:job", "worker-1", ttl=60):
@@ -162,6 +190,7 @@ await dominus.redis.incr("page:views", delta=1)
162
190
 
163
191
  # Hash operations
164
192
  await dominus.redis.hset("user:123", "email", "john@example.com", ttl=3600)
193
+ email = await dominus.redis.hget("user:123", "email")
165
194
  ```
166
195
 
167
196
  ### File Storage
@@ -181,6 +210,9 @@ url = download["download_url"]
181
210
 
182
211
  # List files
183
212
  files = await dominus.files.list(category="reports", prefix="2025/")
213
+
214
+ # Delete file
215
+ await dominus.files.delete(file_id=result["id"])
184
216
  ```
185
217
 
186
218
  ### Structured Logging
@@ -190,38 +222,67 @@ files = await dominus.files.list(category="reports", prefix="2025/")
190
222
  await dominus.logs.info("User logged in", {"user_id": "123"})
191
223
  await dominus.logs.error("Payment failed", {"order_id": "456"})
192
224
 
225
+ # All log levels
226
+ await dominus.logs.debug("Debug message", {"data": "..."})
227
+ await dominus.logs.notice("Important notice", {})
228
+ await dominus.logs.warn("Warning message", {})
229
+ await dominus.logs.critical("Critical error", {})
230
+
231
+ # With category
232
+ await dominus.logs.info("Cache hit", {"key": "user:123"}, category="cache")
233
+
193
234
  # With exception context
194
235
  try:
195
236
  risky_operation()
196
237
  except Exception as e:
197
- await dominus.logs.error("Operation failed", exception=e)
238
+ await dominus.logs.error("Operation failed", {}, exception=e)
239
+
240
+ # Batch logging
241
+ await dominus.logs.batch([
242
+ {"level": "info", "message": "Step 1 complete", "data": {}},
243
+ {"level": "info", "message": "Step 2 complete", "data": {}}
244
+ ])
198
245
 
199
246
  # Query logs
200
247
  errors = await dominus.logs.query(level="error", limit=100)
201
248
  ```
202
249
 
203
- ### Authentication
250
+ ### Authentication & Authorization (Guardian)
204
251
 
205
252
  ```python
206
253
  # User management
207
- user = await dominus.auth.add_user(
254
+ users = await dominus.auth.list_users()
255
+ user = await dominus.auth.get_user(user_id="uuid")
256
+
257
+ new_user = await dominus.auth.add_user(
208
258
  username="john",
209
259
  password="secure-password",
210
260
  email="john@example.com"
211
261
  )
212
262
 
263
+ await dominus.auth.update_user("uuid", status="active")
264
+ await dominus.auth.delete_user("uuid")
265
+
213
266
  # Role management
267
+ roles = await dominus.auth.list_roles()
214
268
  role = await dominus.auth.add_role(
215
269
  name="Editor",
216
270
  scope_slugs=["read", "write", "publish"]
217
271
  )
218
272
 
273
+ # Scope management
274
+ scopes = await dominus.auth.list_scopes()
275
+
276
+ # Tenant management
277
+ tenants = await dominus.auth.list_tenants()
278
+ categories = await dominus.auth.list_tenant_categories()
279
+
219
280
  # JWT operations
220
281
  jwt = await dominus.auth.mint_jwt(user_id=user["id"], expires_in=900)
221
282
  claims = await dominus.auth.validate_jwt(token)
222
283
  ```
223
284
 
224
- ### Schema Management
285
+ ### Schema Management (DDL)
225
286
 
226
287
  ```python
227
288
  # Create table
@@ -232,29 +293,60 @@ await dominus.ddl.add_table("orders", [
232
293
  {"name": "created_at", "type": "TIMESTAMPTZ", "default": "NOW()"}
233
294
  ])
234
295
 
235
- # Provision tenant schema
296
+ # Add column
297
+ await dominus.ddl.add_column("orders", "status", "VARCHAR(50)", default="'pending'")
298
+
299
+ # Provision tenant schema from category template
236
300
  await dominus.ddl.provision_tenant("customer_acme", category_slug="healthcare")
237
301
  ```
238
302
 
239
303
  ### User Authentication (Portal)
240
304
 
241
305
  ```python
242
- # User login
306
+ # User login (tenant_id is optional)
243
307
  session = await dominus.portal.login(
244
308
  username="john@example.com",
245
309
  password="secret123",
246
- tenant_id="tenant-uuid"
310
+ tenant_id="tenant-uuid" # optional
247
311
  )
248
312
 
313
+ # Client login with PSK (for service-to-service)
314
+ client_session = await dominus.portal.login_client(psk="psk-token")
315
+
249
316
  # Get current user
250
317
  me = await dominus.portal.me()
251
318
 
252
- # Get navigation (access-filtered)
319
+ # Get navigation (access-filtered for current user)
253
320
  nav = await dominus.portal.get_navigation()
254
321
 
322
+ # Check page access
323
+ has_access = await dominus.portal.check_page_access("/dashboard/admin/users")
324
+
325
+ # Switch tenant
326
+ await dominus.portal.switch_tenant("other-tenant-uuid")
327
+
255
328
  # Profile & preferences
329
+ profile = await dominus.portal.get_profile()
330
+ await dominus.portal.update_profile(display_name="John Doe")
331
+
332
+ prefs = await dominus.portal.get_preferences()
256
333
  await dominus.portal.update_preferences(theme="dark", timezone="America/New_York")
257
334
 
335
+ # Password management
336
+ await dominus.portal.change_password("old-password", "new-password")
337
+ await dominus.portal.request_password_reset("john@example.com")
338
+ await dominus.portal.confirm_password_reset("reset-token", "new-password")
339
+
340
+ # Session management
341
+ sessions = await dominus.portal.list_sessions()
342
+ await dominus.portal.revoke_session("session-id")
343
+ await dominus.portal.revoke_all_sessions()
344
+
345
+ # Registration & email verification
346
+ await dominus.portal.register("newuser", "new@example.com", "password", "tenant-id")
347
+ await dominus.portal.verify_email("verification-token")
348
+ await dominus.portal.resend_verification("new@example.com")
349
+
258
350
  # Logout
259
351
  await dominus.portal.logout()
260
352
  ```
@@ -271,6 +363,14 @@ result = await dominus.courier.send(
271
363
  )
272
364
 
273
365
  # Convenience methods
366
+ await dominus.courier.send_welcome(
367
+ to="user@example.com",
368
+ from_email="noreply@myapp.com",
369
+ name="John",
370
+ action_url="https://myapp.com/start",
371
+ product_name="My App"
372
+ )
373
+
274
374
  await dominus.courier.send_password_reset(
275
375
  to="user@example.com",
276
376
  from_email="noreply@myapp.com",
@@ -278,6 +378,30 @@ await dominus.courier.send_password_reset(
278
378
  reset_url="https://myapp.com/reset?token=abc",
279
379
  product_name="My App"
280
380
  )
381
+
382
+ await dominus.courier.send_email_verification(
383
+ to="user@example.com",
384
+ from_email="noreply@myapp.com",
385
+ name="John",
386
+ verify_url="https://myapp.com/verify?token=xyz",
387
+ product_name="My App"
388
+ )
389
+
390
+ await dominus.courier.send_invitation(
391
+ to="invited@example.com",
392
+ from_email="noreply@myapp.com",
393
+ name="Invited User",
394
+ invite_url="https://myapp.com/invite?token=abc",
395
+ inviter_name="John",
396
+ product_name="My App"
397
+ )
398
+ ```
399
+
400
+ ### Health Checks
401
+
402
+ ```python
403
+ # Basic health check
404
+ status = await dominus.health.check()
281
405
  ```
282
406
 
283
407
  ## Error Handling
@@ -290,7 +414,11 @@ from dominus import (
290
414
  AuthorizationError,
291
415
  NotFoundError,
292
416
  ValidationError,
417
+ ConflictError,
418
+ ServiceError,
293
419
  SecureTableError,
420
+ ConnectionError,
421
+ TimeoutError,
294
422
  )
295
423
 
296
424
  try:
@@ -299,6 +427,14 @@ except NotFoundError as e:
299
427
  print(f"User not found: {e.message}")
300
428
  except SecureTableError as e:
301
429
  print("Secure table requires 'reason' and 'actor' parameters")
430
+ except AuthenticationError as e:
431
+ print("Invalid or expired token")
432
+ except AuthorizationError as e:
433
+ print("Insufficient permissions")
434
+ except ValidationError as e:
435
+ print(f"Invalid request: {e.message}")
436
+ except TimeoutError as e:
437
+ print("Request timed out")
302
438
  except DominusError as e:
303
439
  print(f"Error {e.status_code}: {e.message}")
304
440
  if e.details:
@@ -326,13 +462,17 @@ except DominusError as e:
326
462
  ```bash
327
463
  # Required: PSK token for authentication
328
464
  export DOMINUS_TOKEN="your-psk-token"
465
+
466
+ # Optional: Project configuration
467
+ export CB_PROJECT_SLUG="my-project"
468
+ export CB_ENVIRONMENT="production"
329
469
  ```
330
470
 
331
471
  ### Token Resolution
332
472
 
333
473
  The SDK resolves the authentication token in this order:
334
474
  1. `DOMINUS_TOKEN` environment variable
335
- 2. Hardcoded fallback in `dominus/start.py`
475
+ 2. Hardcoded fallback in `dominus/start.py` (development only)
336
476
 
337
477
  ## Architecture
338
478
 
@@ -356,16 +496,53 @@ The SDK resolves the authentication token in this order:
356
496
  │ ┌─────────┬─────────┬────────┐ │
357
497
  │ │ Warden │Guardian │Archivist│ │
358
498
  │ │ Scribe │ Smith │Whisperer│ │
359
- │ │ Herald │ Portal │ Courier│ │
499
+ │ │ Herald │ Portal │ Courier │ │
360
500
  │ └─────────┴─────────┴────────┘ │
361
501
  └─────────────────────────────────┘
362
502
  ```
363
503
 
364
- ## Dependencies
504
+ ## FastAPI Integration
365
505
 
366
- - `httpx` - Async HTTP client
367
- - `bcrypt` - Password hashing
368
- - `cryptography` - Cache encryption
506
+ ```python
507
+ from fastapi import FastAPI, HTTPException
508
+ from dominus import dominus, NotFoundError
509
+
510
+ app = FastAPI()
511
+
512
+ @app.get("/users")
513
+ async def list_users():
514
+ try:
515
+ users = await dominus.db.query("users", filters={"status": "active"}, limit=50)
516
+ return users
517
+ except NotFoundError:
518
+ raise HTTPException(status_code=404, detail="Not found")
519
+ except Exception as e:
520
+ raise HTTPException(status_code=500, detail=str(e))
521
+
522
+ @app.get("/users/{user_id}")
523
+ async def get_user(user_id: str):
524
+ try:
525
+ user = await dominus.auth.get_user(user_id)
526
+ return user
527
+ except NotFoundError:
528
+ raise HTTPException(status_code=404, detail="User not found")
529
+ ```
530
+
531
+ ## Pagination Pattern
532
+
533
+ ```python
534
+ async def get_all_users(page_size: int = 100):
535
+ offset = 0
536
+ all_users = []
537
+ while True:
538
+ result = await dominus.db.query("users", limit=page_size, offset=offset)
539
+ rows = result.get("rows", [])
540
+ all_users.extend(rows)
541
+ if len(rows) < page_size:
542
+ break
543
+ offset += page_size
544
+ return all_users
545
+ ```
369
546
 
370
547
  ## Documentation
371
548
 
@@ -374,7 +551,17 @@ The SDK resolves the authentication token in this order:
374
551
 
375
552
  ## Version
376
553
 
377
- **v2.0.0** - Namespace-based API with unified orchestrator backend
554
+ **v2.1.6** - Latest release with navigation routes and page scope methods
555
+
556
+ ### Changelog
557
+
558
+ - **v2.1.6** - Fix navigation routes and add page scope methods
559
+ - **v2.1.5** - Add PSK-only client login
560
+ - **v2.1.4** - Make `tenant_id` optional in login methods
561
+ - **v2.1.2** - Remove `/verify` endpoint call, keep health warmup
562
+ - **v2.1.1** - Fix hardcoded orchestrator base URL
563
+ - **v2.1.0** - Fix SDK routes and remove hardcoded token support
564
+ - **v2.0.0** - Complete namespace-based API rewrite
378
565
 
379
566
  ## License
380
567