dominus-sdk-python 4.4.0__tar.gz → 4.6.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 (61) hide show
  1. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/PKG-INFO +1 -1
  2. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/__init__.py +1 -1
  3. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/browser.py +10 -1
  4. dominus_sdk_python-4.6.0/dominus/namespaces/stash.py +275 -0
  5. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/start.py +4 -0
  6. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus_sdk_python.egg-info/PKG-INFO +1 -1
  7. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus_sdk_python.egg-info/SOURCES.txt +1 -0
  8. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/pyproject.toml +1 -1
  9. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/README.md +0 -0
  10. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/config/__init__.py +0 -0
  11. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/config/endpoints.py +0 -0
  12. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/errors.py +0 -0
  13. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/__init__.py +0 -0
  14. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/auth.py +0 -0
  15. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/cache.py +0 -0
  16. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/console_capture.py +0 -0
  17. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/core.py +0 -0
  18. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/crypto.py +0 -0
  19. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/sse.py +0 -0
  20. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/helpers/trace.py +0 -0
  21. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/__init__.py +0 -0
  22. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/admin.py +0 -0
  23. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/ai.py +0 -0
  24. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/artifacts.py +0 -0
  25. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/auth.py +0 -0
  26. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/authority.py +0 -0
  27. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/courier.py +0 -0
  28. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/db.py +0 -0
  29. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/ddl.py +0 -0
  30. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/deployer.py +0 -0
  31. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/fastapi.py +0 -0
  32. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/files.py +0 -0
  33. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/health.py +0 -0
  34. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/jobs.py +0 -0
  35. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/logs.py +0 -0
  36. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/portal.py +0 -0
  37. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/processor.py +0 -0
  38. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/redis.py +0 -0
  39. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/secrets.py +0 -0
  40. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/secure.py +0 -0
  41. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/sync.py +0 -0
  42. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/warden.py +0 -0
  43. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/namespaces/workflow.py +0 -0
  44. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus/services/__init__.py +0 -0
  45. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
  46. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
  47. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
  48. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/setup.cfg +0 -0
  49. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_auth.py +0 -0
  50. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_authority_public_vocabulary.py +0 -0
  51. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_browser_namespace.py +0 -0
  52. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_control_plane_namespaces.py +0 -0
  53. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_errors.py +0 -0
  54. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_flat_commands.py +0 -0
  55. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_health.py +0 -0
  56. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_logs.py +0 -0
  57. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_provisioning_parity.py +0 -0
  58. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_public_exports.py +0 -0
  59. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_transport_compat.py +0 -0
  60. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_workflow_lifecycle.py +0 -0
  61. {dominus_sdk_python-4.4.0 → dominus_sdk_python-4.6.0}/tests/test_workflow_refs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 4.4.0
3
+ Version: 4.6.0
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -164,7 +164,7 @@ from .errors import (
164
164
  TimeoutError as DominusTimeoutError,
165
165
  )
166
166
 
167
- __version__ = "4.4.0"
167
+ __version__ = "4.6.0"
168
168
  __all__ = [
169
169
  # Main SDK instance
170
170
  "dominus",
@@ -98,7 +98,16 @@ class BrowserNamespace:
98
98
  Ensure a browser run. ``POST /api/browser/runs/ensure``.
99
99
 
100
100
  Browser run metadata remains browser-worker runtime state. Artifact V2
101
- is only used by the worker for sanitized result/capture payloads.
101
+ is used for sanitized `browser-run` result payloads and, when opted-in
102
+ via ``capture_policy["storage_state"] = "always"`` plus
103
+ ``auth_ref["session_slot_id"]``, for captured Playwright storage_state
104
+ in the separate ``browser-session`` category. Captured values are
105
+ never returned inline; only the artifact ref appears on the result
106
+ envelope as ``result_summary.captured_session_artifact_ref``.
107
+
108
+ Reuse a captured session by passing the same ``session_slot_id`` (slot
109
+ lookup, returns no storage_state on first call) or an explicit
110
+ ``session_artifact_ref`` (hard-error if the ref does not exist).
102
111
  """
103
112
  if not target:
104
113
  raise ValueError("target is required")
@@ -0,0 +1,275 @@
1
+ """
2
+ Stash Namespace - per-scope durable items (credentials + configs).
3
+
4
+ Routes through ``/svc/stash/*`` on the Dominus gateway. The stash worker
5
+ stores items in each project's ``stash.*`` schema and transparently falls
6
+ back to a designated shared project on read.
7
+ """
8
+ from typing import Any, Dict, List, Optional, TYPE_CHECKING
9
+
10
+ if TYPE_CHECKING:
11
+ from ..start import Dominus
12
+
13
+
14
+ class StashNamespace:
15
+ """
16
+ Stash worker namespace.
17
+
18
+ Usage:
19
+ item = await dominus.stash.resolve(
20
+ kind="credential.vendor.fuji_synapse",
21
+ scope={"user_id": user_id, "organization_code": "piedmont"},
22
+ purpose="extraction",
23
+ )
24
+ await dominus.stash.mark_verified(id=item["id"], purpose="extraction")
25
+ """
26
+
27
+ def __init__(self, client: "Dominus"):
28
+ self._client = client
29
+
30
+ async def upsert(
31
+ self,
32
+ *,
33
+ kind: str,
34
+ scope: Dict[str, Any],
35
+ value: Dict[str, Any],
36
+ id: Optional[str] = None,
37
+ target: Optional[str] = None,
38
+ item_key: Optional[str] = None,
39
+ role: Optional[str] = None,
40
+ priority: Optional[int] = None,
41
+ is_sensitive: Optional[bool] = None,
42
+ rotation_interval_days: Optional[int] = None,
43
+ expires_at: Optional[str] = None,
44
+ purpose: Optional[str] = None,
45
+ ) -> Dict[str, Any]:
46
+ """Insert or update a stash item."""
47
+ body: Dict[str, Any] = {"kind": kind, "scope": scope, "value": value}
48
+ if id is not None:
49
+ body["id"] = id
50
+ if target is not None:
51
+ body["target"] = target
52
+ if item_key is not None:
53
+ body["item_key"] = item_key
54
+ if role is not None:
55
+ body["role"] = role
56
+ if priority is not None:
57
+ body["priority"] = priority
58
+ if is_sensitive is not None:
59
+ body["is_sensitive"] = is_sensitive
60
+ if rotation_interval_days is not None:
61
+ body["rotation_interval_days"] = rotation_interval_days
62
+ if expires_at is not None:
63
+ body["expires_at"] = expires_at
64
+ if purpose is not None:
65
+ body["purpose"] = purpose
66
+ return await self._client._request(
67
+ endpoint="/svc/stash/items/upsert",
68
+ body=body,
69
+ use_gateway=True,
70
+ )
71
+
72
+ async def get(
73
+ self,
74
+ id: str,
75
+ *,
76
+ purpose: Optional[str] = None,
77
+ include_shared: Optional[bool] = None,
78
+ ) -> Optional[Dict[str, Any]]:
79
+ """Fetch a single item by id; decrypts sensitive values."""
80
+ body: Dict[str, Any] = {"id": id}
81
+ if purpose is not None:
82
+ body["purpose"] = purpose
83
+ if include_shared is not None:
84
+ body["include_shared"] = include_shared
85
+ result = await self._client._request(
86
+ endpoint="/svc/stash/items/get",
87
+ body=body,
88
+ use_gateway=True,
89
+ )
90
+ return result.get("item") if isinstance(result, dict) else None
91
+
92
+ async def resolve(
93
+ self,
94
+ *,
95
+ kind: str,
96
+ scope: Dict[str, Any],
97
+ purpose: str,
98
+ fallback_roles: Optional[List[str]] = None,
99
+ health_status_in: Optional[List[str]] = None,
100
+ machine_id: Optional[str] = None,
101
+ include_shared: Optional[bool] = None,
102
+ ) -> Optional[Dict[str, Any]]:
103
+ """Resolve the best-priority match by (kind, scope) with fallback walk."""
104
+ body: Dict[str, Any] = {"kind": kind, "scope": scope, "purpose": purpose}
105
+ if fallback_roles is not None:
106
+ body["fallback_roles"] = fallback_roles
107
+ if health_status_in is not None:
108
+ body["health_status_in"] = health_status_in
109
+ if machine_id is not None:
110
+ body["machine_id"] = machine_id
111
+ if include_shared is not None:
112
+ body["include_shared"] = include_shared
113
+ result = await self._client._request(
114
+ endpoint="/svc/stash/items/resolve",
115
+ body=body,
116
+ use_gateway=True,
117
+ )
118
+ return result.get("item") if isinstance(result, dict) else None
119
+
120
+ async def list(
121
+ self,
122
+ *,
123
+ kind: Optional[str] = None,
124
+ scope: Optional[Dict[str, Any]] = None,
125
+ role: Optional[str] = None,
126
+ health_status: Optional[Any] = None,
127
+ scope_origin: Optional[str] = None,
128
+ include_deleted: Optional[bool] = None,
129
+ limit: Optional[int] = None,
130
+ offset: Optional[int] = None,
131
+ ) -> Dict[str, Any]:
132
+ """List items by (kind, partial scope, role, health). Metadata only."""
133
+ body: Dict[str, Any] = {}
134
+ if kind is not None:
135
+ body["kind"] = kind
136
+ if scope is not None:
137
+ body["scope"] = scope
138
+ if role is not None:
139
+ body["role"] = role
140
+ if health_status is not None:
141
+ body["health_status"] = health_status
142
+ if scope_origin is not None:
143
+ body["scope_origin"] = scope_origin
144
+ if include_deleted is not None:
145
+ body["include_deleted"] = include_deleted
146
+ if limit is not None:
147
+ body["limit"] = limit
148
+ if offset is not None:
149
+ body["offset"] = offset
150
+ return await self._client._request(
151
+ endpoint="/svc/stash/items/list",
152
+ body=body,
153
+ use_gateway=True,
154
+ )
155
+
156
+ async def mark_verified(
157
+ self, *, id: str, purpose: str, detail: Optional[str] = None
158
+ ) -> Optional[Dict[str, Any]]:
159
+ """Mark an item as verified after a successful use; resets failure_count."""
160
+ body: Dict[str, Any] = {"id": id, "purpose": purpose}
161
+ if detail is not None:
162
+ body["detail"] = detail
163
+ result = await self._client._request(
164
+ endpoint="/svc/stash/items/mark-verified",
165
+ body=body,
166
+ use_gateway=True,
167
+ )
168
+ return result.get("item") if isinstance(result, dict) else None
169
+
170
+ async def mark_failed(
171
+ self,
172
+ *,
173
+ id: str,
174
+ purpose: str,
175
+ failure_reason: Optional[str] = None,
176
+ detail: Optional[str] = None,
177
+ ) -> Optional[Dict[str, Any]]:
178
+ """Mark an item as failed; increments failure_count, sets last_failed_at."""
179
+ body: Dict[str, Any] = {"id": id, "purpose": purpose}
180
+ if failure_reason is not None:
181
+ body["failure_reason"] = failure_reason
182
+ if detail is not None:
183
+ body["detail"] = detail
184
+ result = await self._client._request(
185
+ endpoint="/svc/stash/items/mark-failed",
186
+ body=body,
187
+ use_gateway=True,
188
+ )
189
+ return result.get("item") if isinstance(result, dict) else None
190
+
191
+ async def delete(self, id: str, *, purpose: Optional[str] = None) -> bool:
192
+ """Soft-delete an item (sets deleted_at)."""
193
+ body: Dict[str, Any] = {"id": id}
194
+ if purpose is not None:
195
+ body["purpose"] = purpose
196
+ result = await self._client._request(
197
+ endpoint="/svc/stash/items/delete",
198
+ body=body,
199
+ use_gateway=True,
200
+ )
201
+ return bool(result.get("deleted")) if isinstance(result, dict) else False
202
+
203
+ async def register_kind(
204
+ self,
205
+ *,
206
+ kind: str,
207
+ is_sensitive: Optional[bool] = None,
208
+ value_schema: Optional[Dict[str, Any]] = None,
209
+ default_rotation_days: Optional[int] = None,
210
+ verification_probe_ref: Optional[str] = None,
211
+ description: Optional[str] = None,
212
+ ) -> Dict[str, Any]:
213
+ """Register or update a kind in stash.kind_registry. Admin-scoped."""
214
+ body: Dict[str, Any] = {"kind": kind}
215
+ if is_sensitive is not None:
216
+ body["is_sensitive"] = is_sensitive
217
+ if value_schema is not None:
218
+ body["value_schema"] = value_schema
219
+ if default_rotation_days is not None:
220
+ body["default_rotation_days"] = default_rotation_days
221
+ if verification_probe_ref is not None:
222
+ body["verification_probe_ref"] = verification_probe_ref
223
+ if description is not None:
224
+ body["description"] = description
225
+ result = await self._client._request(
226
+ endpoint="/svc/stash/kinds/register",
227
+ body=body,
228
+ use_gateway=True,
229
+ )
230
+ return result.get("kind", {}) if isinstance(result, dict) else {}
231
+
232
+ async def list_kinds(self) -> List[Dict[str, Any]]:
233
+ """List registered kinds (own + shared merged)."""
234
+ result = await self._client._request(
235
+ endpoint="/svc/stash/kinds/list",
236
+ body={},
237
+ use_gateway=True,
238
+ )
239
+ return result.get("kinds", []) if isinstance(result, dict) else []
240
+
241
+ async def query_audit(
242
+ self,
243
+ *,
244
+ item_id: Optional[str] = None,
245
+ kind: Optional[str] = None,
246
+ caller_id: Optional[str] = None,
247
+ action: Optional[str] = None,
248
+ occurred_after: Optional[str] = None,
249
+ occurred_before: Optional[str] = None,
250
+ limit: Optional[int] = None,
251
+ offset: Optional[int] = None,
252
+ ) -> Dict[str, Any]:
253
+ """Query the append-only audit log. Hashes only — never plaintext."""
254
+ body: Dict[str, Any] = {}
255
+ if item_id is not None:
256
+ body["item_id"] = item_id
257
+ if kind is not None:
258
+ body["kind"] = kind
259
+ if caller_id is not None:
260
+ body["caller_id"] = caller_id
261
+ if action is not None:
262
+ body["action"] = action
263
+ if occurred_after is not None:
264
+ body["occurred_after"] = occurred_after
265
+ if occurred_before is not None:
266
+ body["occurred_before"] = occurred_before
267
+ if limit is not None:
268
+ body["limit"] = limit
269
+ if offset is not None:
270
+ body["offset"] = offset
271
+ return await self._client._request(
272
+ endpoint="/svc/stash/audit/query",
273
+ body=body,
274
+ use_gateway=True,
275
+ )
@@ -182,6 +182,10 @@ class Dominus:
182
182
  self.deployer = DeployerNamespace(self)
183
183
  self.warden = WardenNamespace(self)
184
184
 
185
+ # Stash worker (per-scope durable items: credentials + configs)
186
+ from .namespaces.stash import StashNamespace
187
+ self.stash = StashNamespace(self)
188
+
185
189
  # Cache for JWT public key
186
190
  self._public_key_cache = None
187
191
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 4.4.0
3
+ Version: 4.6.0
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -34,6 +34,7 @@ dominus/namespaces/processor.py
34
34
  dominus/namespaces/redis.py
35
35
  dominus/namespaces/secrets.py
36
36
  dominus/namespaces/secure.py
37
+ dominus/namespaces/stash.py
37
38
  dominus/namespaces/sync.py
38
39
  dominus/namespaces/warden.py
39
40
  dominus/namespaces/workflow.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dominus-sdk-python"
7
- version = "4.4.0"
7
+ version = "4.6.0"
8
8
  description = "Python SDK for the Dominus gateway-first platform"
9
9
  readme = "README.md"
10
10
  license = {text = "Proprietary"}