dominus-sdk-python-dev 2.1.8__py3-none-any.whl → 2.2.0__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.
@@ -0,0 +1,256 @@
1
+ """
2
+ Secure Namespace - Audit-logged data access for sensitive tables.
3
+
4
+ Provides CRUD operations with mandatory reason/actor parameters for compliance.
5
+ """
6
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from ..start import Dominus
10
+
11
+
12
+ class SecureAccessContext:
13
+ """Access context for secure table operations."""
14
+
15
+ def __init__(self, reason: str, actor: str):
16
+ self.reason = reason
17
+ self.actor = actor
18
+
19
+
20
+ class SecureNamespace:
21
+ """
22
+ Secure data access namespace.
23
+
24
+ All operations require a SecureAccessContext with reason and actor
25
+ for HIPAA/compliance audit logging.
26
+
27
+ Usage:
28
+ context = SecureAccessContext(
29
+ reason="Viewing patient chart for appointment #123",
30
+ actor="user:abc123"
31
+ )
32
+
33
+ # List secure tables
34
+ tables = await dominus.secure.tables(schema="tenant_acme")
35
+
36
+ # Query with audit context
37
+ patients = await dominus.secure.query(
38
+ "patients",
39
+ context,
40
+ filters={"active": True}
41
+ )
42
+
43
+ # Insert with audit context
44
+ await dominus.secure.insert(
45
+ "patients",
46
+ {"mrn": "12345", "name": "John Doe"},
47
+ context
48
+ )
49
+ """
50
+
51
+ def __init__(self, client: "Dominus"):
52
+ self._client = client
53
+
54
+ async def tables(self, schema: str = "public") -> List[Dict[str, Any]]:
55
+ """
56
+ List tables in a schema (secure view).
57
+
58
+ Args:
59
+ schema: Schema name (default: "public")
60
+
61
+ Returns:
62
+ List of table metadata
63
+ """
64
+ result = await self._client._request(
65
+ endpoint=f"/api/scribe/data/{schema}/tables",
66
+ method="GET"
67
+ )
68
+ return result.get("tables", result) if isinstance(result, dict) else result
69
+
70
+ async def columns(self, table: str, schema: str = "public") -> List[Dict[str, Any]]:
71
+ """
72
+ List columns in a table (secure view).
73
+
74
+ Args:
75
+ table: Table name
76
+ schema: Schema name (default: "public")
77
+
78
+ Returns:
79
+ List of column metadata with is_primary_key
80
+ """
81
+ result = await self._client._request(
82
+ endpoint=f"/api/scribe/data/{schema}/{table}/columns",
83
+ method="GET"
84
+ )
85
+ return result.get("columns", result) if isinstance(result, dict) else result
86
+
87
+ async def query(
88
+ self,
89
+ table: str,
90
+ context: SecureAccessContext,
91
+ schema: str = "public",
92
+ filters: Optional[Dict[str, Any]] = None,
93
+ sort_by: Optional[str] = None,
94
+ sort_order: str = "ASC",
95
+ limit: int = 100,
96
+ offset: int = 0
97
+ ) -> Dict[str, Any]:
98
+ """
99
+ Query table data with mandatory audit context.
100
+
101
+ Args:
102
+ table: Table name
103
+ context: SecureAccessContext with reason and actor
104
+ schema: Schema name (default: "public")
105
+ filters: Column:value filter dictionary
106
+ sort_by: Column to sort by
107
+ sort_order: "ASC" or "DESC"
108
+ limit: Maximum rows to return (default: 100)
109
+ offset: Rows to skip (default: 0)
110
+
111
+ Returns:
112
+ Dict with "rows" and "total" keys
113
+ """
114
+ body = {
115
+ "filters": filters,
116
+ "sort_by": sort_by,
117
+ "sort_order": sort_order,
118
+ "limit": limit,
119
+ "offset": offset,
120
+ "reason": context.reason,
121
+ "actor": context.actor
122
+ }
123
+
124
+ result = await self._client._request(
125
+ endpoint=f"/api/scribe/data/{schema}/{table}/query",
126
+ body=body
127
+ )
128
+
129
+ # Normalize response
130
+ return {
131
+ "rows": result.get("items", result.get("rows", [])),
132
+ "total": result.get("total", 0)
133
+ }
134
+
135
+ async def insert(
136
+ self,
137
+ table: str,
138
+ data: Dict[str, Any],
139
+ context: SecureAccessContext,
140
+ schema: str = "public"
141
+ ) -> Dict[str, Any]:
142
+ """
143
+ Insert a row with mandatory audit context.
144
+
145
+ Args:
146
+ table: Table name
147
+ data: Column:value dictionary
148
+ context: SecureAccessContext with reason and actor
149
+ schema: Schema name (default: "public")
150
+
151
+ Returns:
152
+ Inserted row data
153
+ """
154
+ body = {
155
+ "data": data,
156
+ "reason": context.reason,
157
+ "actor": context.actor
158
+ }
159
+
160
+ return await self._client._request(
161
+ endpoint=f"/api/scribe/data/{schema}/{table}/insert",
162
+ body=body
163
+ )
164
+
165
+ async def update(
166
+ self,
167
+ table: str,
168
+ data: Dict[str, Any],
169
+ filters: Dict[str, Any],
170
+ context: SecureAccessContext,
171
+ schema: str = "public"
172
+ ) -> Dict[str, Any]:
173
+ """
174
+ Update rows with mandatory audit context.
175
+
176
+ Args:
177
+ table: Table name
178
+ data: Column:value dictionary of updates
179
+ filters: Column:value dictionary for WHERE clause
180
+ context: SecureAccessContext with reason and actor
181
+ schema: Schema name (default: "public")
182
+
183
+ Returns:
184
+ Dict with "affected_rows" count
185
+ """
186
+ body = {
187
+ "data": data,
188
+ "filters": filters,
189
+ "reason": context.reason,
190
+ "actor": context.actor
191
+ }
192
+
193
+ return await self._client._request(
194
+ endpoint=f"/api/scribe/data/{schema}/{table}/update",
195
+ body=body
196
+ )
197
+
198
+ async def delete(
199
+ self,
200
+ table: str,
201
+ filters: Dict[str, Any],
202
+ context: SecureAccessContext,
203
+ schema: str = "public"
204
+ ) -> Dict[str, Any]:
205
+ """
206
+ Delete rows with mandatory audit context.
207
+
208
+ Args:
209
+ table: Table name
210
+ filters: Column:value dictionary for WHERE clause
211
+ context: SecureAccessContext with reason and actor
212
+ schema: Schema name (default: "public")
213
+
214
+ Returns:
215
+ Dict with "affected_rows" count
216
+ """
217
+ body = {
218
+ "filters": filters,
219
+ "reason": context.reason,
220
+ "actor": context.actor
221
+ }
222
+
223
+ return await self._client._request(
224
+ endpoint=f"/api/scribe/data/{schema}/{table}/delete",
225
+ body=body
226
+ )
227
+
228
+ async def bulk_insert(
229
+ self,
230
+ table: str,
231
+ rows: List[Dict[str, Any]],
232
+ context: SecureAccessContext,
233
+ schema: str = "public"
234
+ ) -> Dict[str, Any]:
235
+ """
236
+ Insert multiple rows with mandatory audit context.
237
+
238
+ Args:
239
+ table: Table name
240
+ rows: List of column:value dictionaries
241
+ context: SecureAccessContext with reason and actor
242
+ schema: Schema name (default: "public")
243
+
244
+ Returns:
245
+ Dict with "inserted_count" and optionally "rows"
246
+ """
247
+ body = {
248
+ "rows": rows,
249
+ "reason": context.reason,
250
+ "actor": context.actor
251
+ }
252
+
253
+ return await self._client._request(
254
+ endpoint=f"/api/scribe/data/{schema}/{table}/bulk-insert",
255
+ body=body
256
+ )
dominus/start.py CHANGED
@@ -333,6 +333,28 @@ class Dominus:
333
333
  from .namespaces.portal import PortalNamespace
334
334
  self.portal = PortalNamespace(self)
335
335
 
336
+ # Initialize FastAPI namespace (decorators for route auth)
337
+ from .namespaces.fastapi import FastAPINamespace
338
+ self.fastapi = FastAPINamespace(self)
339
+
340
+ # Initialize full namespaces (matching Node.js SDK pattern)
341
+ from .namespaces.db import DbNamespace
342
+ from .namespaces.auth import AuthNamespace
343
+ from .namespaces.ddl import DdlNamespace
344
+ from .namespaces.files import FilesNamespace
345
+ from .namespaces.admin import AdminNamespace
346
+ from .namespaces.secure import SecureNamespace as SecureNS
347
+
348
+ self.db = DbNamespace(self)
349
+ self.auth = AuthNamespace(self)
350
+ self.ddl = DdlNamespace(self)
351
+ self.files = FilesNamespace(self)
352
+ self.admin = AdminNamespace(self)
353
+
354
+ # Note: self.secure is already defined above as the flat API namespace
355
+ # The proper SecureNS namespace is available as dominus.db_secure for direct access
356
+ self.db_secure = SecureNS(self)
357
+
336
358
  # Cache for JWT public key
337
359
  self._public_key_cache = None
338
360