dominus-sdk-python 7.0.0__tar.gz → 7.1.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.
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/PKG-INFO +51 -3
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/README.md +50 -2
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/__init__.py +3 -2
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/__init__.py +2 -1
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/stash.py +325 -1
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/PKG-INFO +51 -3
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/SOURCES.txt +2 -0
- dominus_sdk_python-7.1.0/dominus_sdk_python.egg-info/dependency_links.txt +1 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/pyproject.toml +1 -1
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_namespace_barrel_exports.py +15 -0
- dominus_sdk_python-7.1.0/tests/test_stash_tables_namespace.py +294 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/config/endpoints.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/errors.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/console_capture.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/core.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/sse.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/helpers/trace.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/admin.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/ai.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/artifacts.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/authority.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/browser.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/coder.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/db.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/deployer.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/fastapi.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/jobs.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/platform.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/portal.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/processor.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/publisher.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/recipes.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/secrets.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/secure.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/sync.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/warden.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/namespaces/workflow.py +0 -0
- /dominus_sdk_python-7.0.0/dominus_sdk_python.egg-info/dependency_links.txt → /dominus_sdk_python-7.1.0/dominus/py.typed +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus/start.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/setup.cfg +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_auth.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_authority_public_vocabulary.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_browser_namespace.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_control_plane_namespaces.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_errors.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_flat_commands.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_health.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_logs.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_platform_coder_namespaces.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_provisioning_parity.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_public_exports.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_publisher_namespace.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_recipes_namespace.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_recipes_stash_routing.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_stash_artifact_facade.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_transport_compat.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_workflow_lifecycle.py +0 -0
- {dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.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: 7.
|
|
3
|
+
Version: 7.1.0
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -48,7 +48,7 @@ cleanup audit is `docs/janitor/2026-06-27-0849-agent-guide-cleanup-audit.md`.
|
|
|
48
48
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
49
49
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
50
50
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
51
|
-
- Current package version: `7.
|
|
51
|
+
- Current package version: `7.1.0`
|
|
52
52
|
|
|
53
53
|
## Install
|
|
54
54
|
|
|
@@ -141,6 +141,54 @@ buffer_cleanup = await dominus.logs.run_archive_buffer_maintenance(
|
|
|
141
141
|
schedules = await dominus.authority.list_schedules(all_scopes=True)
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Stash Managed Tables
|
|
145
|
+
|
|
146
|
+
`dominus.stash.tables` provides a typed client for small, scoped JSONB tables
|
|
147
|
+
without exposing SQL. Every call requires `env`, `scope` (`self` or `group`),
|
|
148
|
+
and `table`; self and group tables resolve to independent project and shared
|
|
149
|
+
databases.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
spec = await dominus.stash.tables.define(
|
|
153
|
+
env="production",
|
|
154
|
+
scope="self",
|
|
155
|
+
table="jobs",
|
|
156
|
+
if_revision=0,
|
|
157
|
+
primary_key={"field": "id", "generate": "uuid"},
|
|
158
|
+
fields={
|
|
159
|
+
"id": {"type": "uuid", "required": True},
|
|
160
|
+
"status": {"type": "string", "required": True},
|
|
161
|
+
"priority": {"type": "integer"},
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
row = await dominus.stash.tables.put_row(
|
|
166
|
+
env="production",
|
|
167
|
+
scope="self",
|
|
168
|
+
table="jobs",
|
|
169
|
+
if_revision=0,
|
|
170
|
+
row={"status": "queued", "priority": 5},
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
page = await dominus.stash.tables.select(
|
|
174
|
+
env="production",
|
|
175
|
+
scope="self",
|
|
176
|
+
table="jobs",
|
|
177
|
+
where={
|
|
178
|
+
"or": [
|
|
179
|
+
{"field": "status", "op": "eq", "value": "queued"},
|
|
180
|
+
{"field": "priority", "op": "gte", "value": 5},
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
page_size=50,
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Use `if_revision` for table definitions and single-row put/delete compare-and-
|
|
188
|
+
swap. `update_where` instead requires `if_spec_revision` and `max_affected`.
|
|
189
|
+
Cursors are opaque keyset tokens. `delete_row` is a hard delete and returns a
|
|
190
|
+
durable mutation receipt; there is no soft-delete or restore lifecycle.
|
|
191
|
+
|
|
144
192
|
## Browser Automation
|
|
145
193
|
|
|
146
194
|
`dominus.browser` exposes the first-class Dominus browser automation primitive through authenticated gateway routes under `/svc/browser/*`. SDK methods use `/api/browser/*` internally with gateway routing enabled; worker-local routes remain `/health` and `/runs/*`.
|
|
@@ -230,7 +278,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
230
278
|
| `platform` | Platform Worker | Group/repository policy decisions with actor attribution |
|
|
231
279
|
| `coder` | Coder Runtime | Policy-bound Coder run lifecycle with workflow/pipeline recipe launch sources |
|
|
232
280
|
| `publisher` | Publisher | Release/channel/signing build and artifact operations |
|
|
233
|
-
| `stash` | Stash |
|
|
281
|
+
| `stash` | Stash | Items, managed tables, kinds, bookmarks, watches, artifact facade |
|
|
234
282
|
| `recipes` | Recipe Worker | Recipe type registry, publish, validate, get/list |
|
|
235
283
|
| `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
|
|
236
284
|
|
|
@@ -15,7 +15,7 @@ cleanup audit is `docs/janitor/2026-06-27-0849-agent-guide-cleanup-audit.md`.
|
|
|
15
15
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
16
16
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
17
17
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
18
|
-
- Current package version: `7.
|
|
18
|
+
- Current package version: `7.1.0`
|
|
19
19
|
|
|
20
20
|
## Install
|
|
21
21
|
|
|
@@ -108,6 +108,54 @@ buffer_cleanup = await dominus.logs.run_archive_buffer_maintenance(
|
|
|
108
108
|
schedules = await dominus.authority.list_schedules(all_scopes=True)
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
## Stash Managed Tables
|
|
112
|
+
|
|
113
|
+
`dominus.stash.tables` provides a typed client for small, scoped JSONB tables
|
|
114
|
+
without exposing SQL. Every call requires `env`, `scope` (`self` or `group`),
|
|
115
|
+
and `table`; self and group tables resolve to independent project and shared
|
|
116
|
+
databases.
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
spec = await dominus.stash.tables.define(
|
|
120
|
+
env="production",
|
|
121
|
+
scope="self",
|
|
122
|
+
table="jobs",
|
|
123
|
+
if_revision=0,
|
|
124
|
+
primary_key={"field": "id", "generate": "uuid"},
|
|
125
|
+
fields={
|
|
126
|
+
"id": {"type": "uuid", "required": True},
|
|
127
|
+
"status": {"type": "string", "required": True},
|
|
128
|
+
"priority": {"type": "integer"},
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
row = await dominus.stash.tables.put_row(
|
|
133
|
+
env="production",
|
|
134
|
+
scope="self",
|
|
135
|
+
table="jobs",
|
|
136
|
+
if_revision=0,
|
|
137
|
+
row={"status": "queued", "priority": 5},
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
page = await dominus.stash.tables.select(
|
|
141
|
+
env="production",
|
|
142
|
+
scope="self",
|
|
143
|
+
table="jobs",
|
|
144
|
+
where={
|
|
145
|
+
"or": [
|
|
146
|
+
{"field": "status", "op": "eq", "value": "queued"},
|
|
147
|
+
{"field": "priority", "op": "gte", "value": 5},
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
page_size=50,
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use `if_revision` for table definitions and single-row put/delete compare-and-
|
|
155
|
+
swap. `update_where` instead requires `if_spec_revision` and `max_affected`.
|
|
156
|
+
Cursors are opaque keyset tokens. `delete_row` is a hard delete and returns a
|
|
157
|
+
durable mutation receipt; there is no soft-delete or restore lifecycle.
|
|
158
|
+
|
|
111
159
|
## Browser Automation
|
|
112
160
|
|
|
113
161
|
`dominus.browser` exposes the first-class Dominus browser automation primitive through authenticated gateway routes under `/svc/browser/*`. SDK methods use `/api/browser/*` internally with gateway routing enabled; worker-local routes remain `/health` and `/runs/*`.
|
|
@@ -197,7 +245,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
197
245
|
| `platform` | Platform Worker | Group/repository policy decisions with actor attribution |
|
|
198
246
|
| `coder` | Coder Runtime | Policy-bound Coder run lifecycle with workflow/pipeline recipe launch sources |
|
|
199
247
|
| `publisher` | Publisher | Release/channel/signing build and artifact operations |
|
|
200
|
-
| `stash` | Stash |
|
|
248
|
+
| `stash` | Stash | Items, managed tables, kinds, bookmarks, watches, artifact facade |
|
|
201
249
|
| `recipes` | Recipe Worker | Recipe type registry, publish, validate, get/list |
|
|
202
250
|
| `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
|
|
203
251
|
|
|
@@ -115,7 +115,7 @@ from .namespaces.warden import WardenNamespace
|
|
|
115
115
|
from .namespaces.platform import PlatformNamespace
|
|
116
116
|
from .namespaces.coder import CoderNamespace
|
|
117
117
|
from .namespaces.publisher import PublisherNamespace
|
|
118
|
-
from .namespaces.stash import StashNamespace
|
|
118
|
+
from .namespaces.stash import StashNamespace, StashTablesNamespace
|
|
119
119
|
|
|
120
120
|
# Export AI namespace for agent-runtime operations
|
|
121
121
|
from .namespaces.ai import (
|
|
@@ -173,7 +173,7 @@ from .errors import (
|
|
|
173
173
|
TimeoutError as DominusTimeoutError,
|
|
174
174
|
)
|
|
175
175
|
|
|
176
|
-
__version__ = "7.
|
|
176
|
+
__version__ = "7.1.0"
|
|
177
177
|
__all__ = [
|
|
178
178
|
# Main SDK instance
|
|
179
179
|
"dominus",
|
|
@@ -228,6 +228,7 @@ __all__ = [
|
|
|
228
228
|
"CoderNamespace",
|
|
229
229
|
"PublisherNamespace",
|
|
230
230
|
"StashNamespace",
|
|
231
|
+
"StashTablesNamespace",
|
|
231
232
|
# AI namespace for agent-runtime operations
|
|
232
233
|
"AiNamespace",
|
|
233
234
|
"RagSubNamespace",
|
|
@@ -22,7 +22,7 @@ from .warden import WardenNamespace
|
|
|
22
22
|
from .platform import PlatformNamespace
|
|
23
23
|
from .coder import CoderNamespace
|
|
24
24
|
from .publisher import PublisherNamespace
|
|
25
|
-
from .stash import StashNamespace
|
|
25
|
+
from .stash import StashNamespace, StashTablesNamespace
|
|
26
26
|
from .ai import (
|
|
27
27
|
AiNamespace,
|
|
28
28
|
RagSubNamespace,
|
|
@@ -56,6 +56,7 @@ __all__ = [
|
|
|
56
56
|
"CoderNamespace",
|
|
57
57
|
"PublisherNamespace",
|
|
58
58
|
"StashNamespace",
|
|
59
|
+
"StashTablesNamespace",
|
|
59
60
|
"AiNamespace",
|
|
60
61
|
"RagSubNamespace",
|
|
61
62
|
"ArtifactsSubNamespace",
|
|
@@ -5,7 +5,17 @@ Routes through ``/svc/stash/*`` on the Dominus gateway. The stash worker
|
|
|
5
5
|
stores items in each project's ``stash.*`` schema and transparently falls
|
|
6
6
|
back to a designated shared project on read.
|
|
7
7
|
"""
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import (
|
|
9
|
+
Any,
|
|
10
|
+
Dict,
|
|
11
|
+
List,
|
|
12
|
+
Literal,
|
|
13
|
+
Mapping,
|
|
14
|
+
Optional,
|
|
15
|
+
TYPE_CHECKING,
|
|
16
|
+
TypedDict,
|
|
17
|
+
Union,
|
|
18
|
+
)
|
|
9
19
|
from urllib.parse import urlencode
|
|
10
20
|
|
|
11
21
|
if TYPE_CHECKING:
|
|
@@ -14,11 +24,324 @@ if TYPE_CHECKING:
|
|
|
14
24
|
BookmarkRef = Dict[str, Any]
|
|
15
25
|
WatcherRef = Dict[str, Any]
|
|
16
26
|
|
|
27
|
+
ManagedTableEnv = Literal["development", "staging", "production"]
|
|
28
|
+
ManagedTableScope = Literal["self", "group"]
|
|
29
|
+
ManagedTableFieldType = Literal[
|
|
30
|
+
"string",
|
|
31
|
+
"uuid",
|
|
32
|
+
"number",
|
|
33
|
+
"integer",
|
|
34
|
+
"boolean",
|
|
35
|
+
"timestamp",
|
|
36
|
+
"json",
|
|
37
|
+
]
|
|
38
|
+
ManagedTablePrimaryKeyGeneration = Literal["none", "uuid"]
|
|
39
|
+
ManagedTableEnumValue = Union[str, int, float, bool]
|
|
40
|
+
ManagedTableOperator = Literal[
|
|
41
|
+
"eq",
|
|
42
|
+
"ne",
|
|
43
|
+
"in",
|
|
44
|
+
"prefix",
|
|
45
|
+
"contains",
|
|
46
|
+
"is_null",
|
|
47
|
+
"gt",
|
|
48
|
+
"gte",
|
|
49
|
+
"lt",
|
|
50
|
+
"lte",
|
|
51
|
+
"between",
|
|
52
|
+
"before",
|
|
53
|
+
"after",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class _ManagedTableFieldOptional(TypedDict, total=False):
|
|
58
|
+
required: bool
|
|
59
|
+
nullable: bool
|
|
60
|
+
enum: List[ManagedTableEnumValue]
|
|
61
|
+
min_length: int
|
|
62
|
+
max_length: int
|
|
63
|
+
min: Union[int, float]
|
|
64
|
+
max: Union[int, float]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ManagedTableField(_ManagedTableFieldOptional):
|
|
68
|
+
type: ManagedTableFieldType
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class ManagedTablePrimaryKey(TypedDict):
|
|
72
|
+
field: str
|
|
73
|
+
generate: ManagedTablePrimaryKeyGeneration
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ManagedTableSpec(TypedDict):
|
|
77
|
+
table: str
|
|
78
|
+
revision: int
|
|
79
|
+
primary_key: ManagedTablePrimaryKey
|
|
80
|
+
fields: Dict[str, ManagedTableField]
|
|
81
|
+
created_at: str
|
|
82
|
+
updated_at: str
|
|
83
|
+
scope: ManagedTableScope
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ManagedTableRowView(TypedDict):
|
|
87
|
+
row_key: str
|
|
88
|
+
data: Dict[str, Any]
|
|
89
|
+
revision: int
|
|
90
|
+
schema_revision: int
|
|
91
|
+
stale_schema: bool
|
|
92
|
+
created_at: str
|
|
93
|
+
updated_at: str
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ManagedTableRow(ManagedTableRowView):
|
|
97
|
+
table: str
|
|
98
|
+
scope: ManagedTableScope
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class _ManagedTablePredicateOptional(TypedDict, total=False):
|
|
102
|
+
value: Any
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class ManagedTablePredicate(_ManagedTablePredicateOptional):
|
|
106
|
+
field: str
|
|
107
|
+
op: ManagedTableOperator
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
ManagedTableLeafAndGroup = TypedDict(
|
|
111
|
+
"ManagedTableLeafAndGroup",
|
|
112
|
+
{"and": List[ManagedTablePredicate]},
|
|
113
|
+
)
|
|
114
|
+
ManagedTableLeafOrGroup = TypedDict(
|
|
115
|
+
"ManagedTableLeafOrGroup",
|
|
116
|
+
{"or": List[ManagedTablePredicate]},
|
|
117
|
+
)
|
|
118
|
+
ManagedTableLeafGroup = Union[ManagedTableLeafAndGroup, ManagedTableLeafOrGroup]
|
|
119
|
+
ManagedTableWhereClause = Union[ManagedTablePredicate, ManagedTableLeafGroup]
|
|
120
|
+
ManagedTableAndGroup = TypedDict(
|
|
121
|
+
"ManagedTableAndGroup",
|
|
122
|
+
{"and": List[ManagedTableWhereClause]},
|
|
123
|
+
)
|
|
124
|
+
ManagedTableOrGroup = TypedDict(
|
|
125
|
+
"ManagedTableOrGroup",
|
|
126
|
+
{"or": List[ManagedTableWhereClause]},
|
|
127
|
+
)
|
|
128
|
+
ManagedTableWhere = Union[
|
|
129
|
+
List[ManagedTableWhereClause],
|
|
130
|
+
ManagedTableAndGroup,
|
|
131
|
+
ManagedTableOrGroup,
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class ManagedTableOrderBy(TypedDict):
|
|
136
|
+
field: str
|
|
137
|
+
direction: Literal["asc", "desc"]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class ManagedTableSelectResult(TypedDict):
|
|
141
|
+
rows: List[ManagedTableRowView]
|
|
142
|
+
next_cursor: Optional[str]
|
|
143
|
+
spec_revision: int
|
|
144
|
+
table: str
|
|
145
|
+
scope: ManagedTableScope
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class ManagedTableMutationReceipt(TypedDict):
|
|
149
|
+
mutation_id: str
|
|
150
|
+
created_at: str
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class _ManagedTableMutationRowOptional(TypedDict, total=False):
|
|
154
|
+
updated_at: str
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class ManagedTableMutationRow(_ManagedTableMutationRowOptional):
|
|
158
|
+
row_key: str
|
|
159
|
+
revision: int
|
|
160
|
+
schema_revision: int
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class ManagedTableUpdateResult(TypedDict):
|
|
164
|
+
matched_count: int
|
|
165
|
+
affected_count: int
|
|
166
|
+
rows: List[ManagedTableMutationRow]
|
|
167
|
+
receipt: ManagedTableMutationReceipt
|
|
168
|
+
table: str
|
|
169
|
+
scope: ManagedTableScope
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class ManagedTableDeleteResult(TypedDict):
|
|
173
|
+
deleted: Literal[True]
|
|
174
|
+
row_key: str
|
|
175
|
+
revision: int
|
|
176
|
+
schema_revision: int
|
|
177
|
+
receipt: ManagedTableMutationReceipt
|
|
178
|
+
table: str
|
|
179
|
+
scope: ManagedTableScope
|
|
180
|
+
|
|
17
181
|
|
|
18
182
|
def _facade_query(*, env: str, kind: str, scope: str, key: str) -> str:
|
|
19
183
|
return urlencode({"env": env, "kind": kind, "scope": scope, "key": key})
|
|
20
184
|
|
|
21
185
|
|
|
186
|
+
class StashTablesNamespace:
|
|
187
|
+
"""Typed client for Stash-managed JSONB tables."""
|
|
188
|
+
|
|
189
|
+
def __init__(self, client: "Dominus"):
|
|
190
|
+
self._client = client
|
|
191
|
+
|
|
192
|
+
async def define(
|
|
193
|
+
self,
|
|
194
|
+
*,
|
|
195
|
+
env: ManagedTableEnv,
|
|
196
|
+
scope: ManagedTableScope,
|
|
197
|
+
table: str,
|
|
198
|
+
if_revision: int,
|
|
199
|
+
primary_key: ManagedTablePrimaryKey,
|
|
200
|
+
fields: Mapping[str, ManagedTableField],
|
|
201
|
+
) -> ManagedTableSpec:
|
|
202
|
+
"""Create or revision-guard a managed table definition."""
|
|
203
|
+
return await self._client._request(
|
|
204
|
+
endpoint="/svc/stash/tables/define",
|
|
205
|
+
method="POST",
|
|
206
|
+
body={
|
|
207
|
+
"env": env,
|
|
208
|
+
"scope": scope,
|
|
209
|
+
"table": table,
|
|
210
|
+
"if_revision": if_revision,
|
|
211
|
+
"primary_key": dict(primary_key),
|
|
212
|
+
"fields": dict(fields),
|
|
213
|
+
},
|
|
214
|
+
use_gateway=True,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
async def put_row(
|
|
218
|
+
self,
|
|
219
|
+
*,
|
|
220
|
+
env: ManagedTableEnv,
|
|
221
|
+
scope: ManagedTableScope,
|
|
222
|
+
table: str,
|
|
223
|
+
if_revision: int,
|
|
224
|
+
row: Mapping[str, Any],
|
|
225
|
+
) -> ManagedTableRow:
|
|
226
|
+
"""Create or fully replace one row under exact row revision CAS."""
|
|
227
|
+
return await self._client._request(
|
|
228
|
+
endpoint="/svc/stash/tables/put-row",
|
|
229
|
+
method="POST",
|
|
230
|
+
body={
|
|
231
|
+
"env": env,
|
|
232
|
+
"scope": scope,
|
|
233
|
+
"table": table,
|
|
234
|
+
"if_revision": if_revision,
|
|
235
|
+
"row": dict(row),
|
|
236
|
+
},
|
|
237
|
+
use_gateway=True,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
async def get_row(
|
|
241
|
+
self,
|
|
242
|
+
*,
|
|
243
|
+
env: ManagedTableEnv,
|
|
244
|
+
scope: ManagedTableScope,
|
|
245
|
+
table: str,
|
|
246
|
+
key: Union[str, int],
|
|
247
|
+
) -> ManagedTableRow:
|
|
248
|
+
"""Read one managed-table row by its declared primary key."""
|
|
249
|
+
return await self._client._request(
|
|
250
|
+
endpoint="/svc/stash/tables/get-row",
|
|
251
|
+
method="POST",
|
|
252
|
+
body={
|
|
253
|
+
"env": env,
|
|
254
|
+
"scope": scope,
|
|
255
|
+
"table": table,
|
|
256
|
+
"key": key,
|
|
257
|
+
},
|
|
258
|
+
use_gateway=True,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
async def select(
|
|
262
|
+
self,
|
|
263
|
+
*,
|
|
264
|
+
env: ManagedTableEnv,
|
|
265
|
+
scope: ManagedTableScope,
|
|
266
|
+
table: str,
|
|
267
|
+
where: Optional[ManagedTableWhere] = None,
|
|
268
|
+
order_by: Optional[ManagedTableOrderBy] = None,
|
|
269
|
+
page_size: Optional[int] = None,
|
|
270
|
+
cursor: Optional[str] = None,
|
|
271
|
+
) -> ManagedTableSelectResult:
|
|
272
|
+
"""Select one keyset page using the bounded managed-table grammar."""
|
|
273
|
+
body: Dict[str, Any] = {"env": env, "scope": scope, "table": table}
|
|
274
|
+
if where is not None:
|
|
275
|
+
body["where"] = where
|
|
276
|
+
if order_by is not None:
|
|
277
|
+
body["order_by"] = dict(order_by)
|
|
278
|
+
if page_size is not None:
|
|
279
|
+
body["page_size"] = page_size
|
|
280
|
+
if cursor is not None:
|
|
281
|
+
body["cursor"] = cursor
|
|
282
|
+
return await self._client._request(
|
|
283
|
+
endpoint="/svc/stash/tables/select",
|
|
284
|
+
method="POST",
|
|
285
|
+
body=body,
|
|
286
|
+
use_gateway=True,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
async def update_where(
|
|
290
|
+
self,
|
|
291
|
+
*,
|
|
292
|
+
env: ManagedTableEnv,
|
|
293
|
+
scope: ManagedTableScope,
|
|
294
|
+
table: str,
|
|
295
|
+
where: ManagedTableWhere,
|
|
296
|
+
if_spec_revision: int,
|
|
297
|
+
max_affected: int,
|
|
298
|
+
set: Optional[Mapping[str, Any]] = None,
|
|
299
|
+
remove: Optional[List[str]] = None,
|
|
300
|
+
) -> ManagedTableUpdateResult:
|
|
301
|
+
"""Patch a bounded match set under exact active-spec revision CAS."""
|
|
302
|
+
body: Dict[str, Any] = {
|
|
303
|
+
"env": env,
|
|
304
|
+
"scope": scope,
|
|
305
|
+
"table": table,
|
|
306
|
+
"where": where,
|
|
307
|
+
"if_spec_revision": if_spec_revision,
|
|
308
|
+
"max_affected": max_affected,
|
|
309
|
+
}
|
|
310
|
+
if set is not None:
|
|
311
|
+
body["set"] = dict(set)
|
|
312
|
+
if remove is not None:
|
|
313
|
+
body["remove"] = list(remove)
|
|
314
|
+
return await self._client._request(
|
|
315
|
+
endpoint="/svc/stash/tables/update-where",
|
|
316
|
+
method="POST",
|
|
317
|
+
body=body,
|
|
318
|
+
use_gateway=True,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
async def delete_row(
|
|
322
|
+
self,
|
|
323
|
+
*,
|
|
324
|
+
env: ManagedTableEnv,
|
|
325
|
+
scope: ManagedTableScope,
|
|
326
|
+
table: str,
|
|
327
|
+
key: Union[str, int],
|
|
328
|
+
if_revision: int,
|
|
329
|
+
) -> ManagedTableDeleteResult:
|
|
330
|
+
"""Hard-delete one row under exact row revision CAS."""
|
|
331
|
+
return await self._client._request(
|
|
332
|
+
endpoint="/svc/stash/tables/delete-row",
|
|
333
|
+
method="POST",
|
|
334
|
+
body={
|
|
335
|
+
"env": env,
|
|
336
|
+
"scope": scope,
|
|
337
|
+
"table": table,
|
|
338
|
+
"key": key,
|
|
339
|
+
"if_revision": if_revision,
|
|
340
|
+
},
|
|
341
|
+
use_gateway=True,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
22
345
|
class StashNamespace:
|
|
23
346
|
"""
|
|
24
347
|
Stash worker namespace.
|
|
@@ -34,6 +357,7 @@ class StashNamespace:
|
|
|
34
357
|
|
|
35
358
|
def __init__(self, client: "Dominus"):
|
|
36
359
|
self._client = client
|
|
360
|
+
self.tables = StashTablesNamespace(client)
|
|
37
361
|
|
|
38
362
|
async def upsert(
|
|
39
363
|
self,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dominus-sdk-python
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.1.0
|
|
4
4
|
Summary: Python SDK for the Dominus gateway-first platform
|
|
5
5
|
Author-email: CareBridge Systems <dev@carebridge.io>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -48,7 +48,7 @@ cleanup audit is `docs/janitor/2026-06-27-0849-agent-guide-cleanup-audit.md`.
|
|
|
48
48
|
- Gateway-scoped client mode for MCP and other user-JWT sessions
|
|
49
49
|
- Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
|
|
50
50
|
- Local helpers for JWT verification, trace propagation, retries, and console capture
|
|
51
|
-
- Current package version: `7.
|
|
51
|
+
- Current package version: `7.1.0`
|
|
52
52
|
|
|
53
53
|
## Install
|
|
54
54
|
|
|
@@ -141,6 +141,54 @@ buffer_cleanup = await dominus.logs.run_archive_buffer_maintenance(
|
|
|
141
141
|
schedules = await dominus.authority.list_schedules(all_scopes=True)
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Stash Managed Tables
|
|
145
|
+
|
|
146
|
+
`dominus.stash.tables` provides a typed client for small, scoped JSONB tables
|
|
147
|
+
without exposing SQL. Every call requires `env`, `scope` (`self` or `group`),
|
|
148
|
+
and `table`; self and group tables resolve to independent project and shared
|
|
149
|
+
databases.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
spec = await dominus.stash.tables.define(
|
|
153
|
+
env="production",
|
|
154
|
+
scope="self",
|
|
155
|
+
table="jobs",
|
|
156
|
+
if_revision=0,
|
|
157
|
+
primary_key={"field": "id", "generate": "uuid"},
|
|
158
|
+
fields={
|
|
159
|
+
"id": {"type": "uuid", "required": True},
|
|
160
|
+
"status": {"type": "string", "required": True},
|
|
161
|
+
"priority": {"type": "integer"},
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
row = await dominus.stash.tables.put_row(
|
|
166
|
+
env="production",
|
|
167
|
+
scope="self",
|
|
168
|
+
table="jobs",
|
|
169
|
+
if_revision=0,
|
|
170
|
+
row={"status": "queued", "priority": 5},
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
page = await dominus.stash.tables.select(
|
|
174
|
+
env="production",
|
|
175
|
+
scope="self",
|
|
176
|
+
table="jobs",
|
|
177
|
+
where={
|
|
178
|
+
"or": [
|
|
179
|
+
{"field": "status", "op": "eq", "value": "queued"},
|
|
180
|
+
{"field": "priority", "op": "gte", "value": 5},
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
page_size=50,
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Use `if_revision` for table definitions and single-row put/delete compare-and-
|
|
188
|
+
swap. `update_where` instead requires `if_spec_revision` and `max_affected`.
|
|
189
|
+
Cursors are opaque keyset tokens. `delete_row` is a hard delete and returns a
|
|
190
|
+
durable mutation receipt; there is no soft-delete or restore lifecycle.
|
|
191
|
+
|
|
144
192
|
## Browser Automation
|
|
145
193
|
|
|
146
194
|
`dominus.browser` exposes the first-class Dominus browser automation primitive through authenticated gateway routes under `/svc/browser/*`. SDK methods use `/api/browser/*` internally with gateway routing enabled; worker-local routes remain `/health` and `/runs/*`.
|
|
@@ -230,7 +278,7 @@ JWT and selected scope headers directly through Gateway.
|
|
|
230
278
|
| `platform` | Platform Worker | Group/repository policy decisions with actor attribution |
|
|
231
279
|
| `coder` | Coder Runtime | Policy-bound Coder run lifecycle with workflow/pipeline recipe launch sources |
|
|
232
280
|
| `publisher` | Publisher | Release/channel/signing build and artifact operations |
|
|
233
|
-
| `stash` | Stash |
|
|
281
|
+
| `stash` | Stash | Items, managed tables, kinds, bookmarks, watches, artifact facade |
|
|
234
282
|
| `recipes` | Recipe Worker | Recipe type registry, publish, validate, get/list |
|
|
235
283
|
| `fastapi` | Local decorators | `@jwt`, `@psk`, `@scopes(...)` |
|
|
236
284
|
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
@@ -2,6 +2,7 @@ README.md
|
|
|
2
2
|
pyproject.toml
|
|
3
3
|
dominus/__init__.py
|
|
4
4
|
dominus/errors.py
|
|
5
|
+
dominus/py.typed
|
|
5
6
|
dominus/start.py
|
|
6
7
|
dominus/config/__init__.py
|
|
7
8
|
dominus/config/endpoints.py
|
|
@@ -64,6 +65,7 @@ tests/test_publisher_namespace.py
|
|
|
64
65
|
tests/test_recipes_namespace.py
|
|
65
66
|
tests/test_recipes_stash_routing.py
|
|
66
67
|
tests/test_stash_artifact_facade.py
|
|
68
|
+
tests/test_stash_tables_namespace.py
|
|
67
69
|
tests/test_transport_compat.py
|
|
68
70
|
tests/test_workflow_lifecycle.py
|
|
69
71
|
tests/test_workflow_refs.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_namespace_barrel_exports.py
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
1
3
|
import dominus
|
|
2
4
|
import dominus.namespaces
|
|
3
5
|
|
|
@@ -24,3 +26,16 @@ def test_top_level_all_lists_stash_and_publisher():
|
|
|
24
26
|
def test_namespaces_all_lists_stash_and_publisher():
|
|
25
27
|
assert "StashNamespace" in dominus.namespaces.__all__
|
|
26
28
|
assert "PublisherNamespace" in dominus.namespaces.__all__
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_stash_tables_namespace_is_exported_from_both_barrels():
|
|
32
|
+
from dominus import StashTablesNamespace as TopLevelStashTablesNamespace
|
|
33
|
+
from dominus.namespaces import StashTablesNamespace as NamespaceStashTablesNamespace
|
|
34
|
+
|
|
35
|
+
assert TopLevelStashTablesNamespace is NamespaceStashTablesNamespace
|
|
36
|
+
assert "StashTablesNamespace" in dominus.__all__
|
|
37
|
+
assert "StashTablesNamespace" in dominus.namespaces.__all__
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_package_includes_declared_pep561_marker():
|
|
41
|
+
assert Path(dominus.__file__).with_name("py.typed").is_file()
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import dominus.start as start_module
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.fixture()
|
|
7
|
+
def sdk(monkeypatch):
|
|
8
|
+
monkeypatch.setattr(start_module, "_VALIDATION_ERROR", None)
|
|
9
|
+
monkeypatch.setattr(start_module, "_TOKEN", "a" * 64)
|
|
10
|
+
monkeypatch.setattr(start_module, "_VALIDATED", False)
|
|
11
|
+
monkeypatch.setattr(start_module, "_BASE_URL", "https://gateway.example")
|
|
12
|
+
monkeypatch.setattr(start_module, "_GATEWAY_URL", "https://gateway.example")
|
|
13
|
+
return start_module.Dominus()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.asyncio
|
|
17
|
+
async def test_define_managed_table_posts_exact_worker_body(monkeypatch, sdk):
|
|
18
|
+
calls = []
|
|
19
|
+
|
|
20
|
+
async def fake_request(**kwargs):
|
|
21
|
+
calls.append(kwargs)
|
|
22
|
+
return {"table": "jobs", "revision": 1, "scope": "self"}
|
|
23
|
+
|
|
24
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
25
|
+
|
|
26
|
+
result = await sdk.stash.tables.define(
|
|
27
|
+
env="production",
|
|
28
|
+
scope="self",
|
|
29
|
+
table="jobs",
|
|
30
|
+
if_revision=0,
|
|
31
|
+
primary_key={"field": "id", "generate": "uuid"},
|
|
32
|
+
fields={
|
|
33
|
+
"id": {"type": "uuid", "required": True},
|
|
34
|
+
"status": {"type": "string", "required": True},
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
assert result == {"table": "jobs", "revision": 1, "scope": "self"}
|
|
39
|
+
assert calls == [
|
|
40
|
+
{
|
|
41
|
+
"endpoint": "/svc/stash/tables/define",
|
|
42
|
+
"method": "POST",
|
|
43
|
+
"body": {
|
|
44
|
+
"env": "production",
|
|
45
|
+
"scope": "self",
|
|
46
|
+
"table": "jobs",
|
|
47
|
+
"if_revision": 0,
|
|
48
|
+
"primary_key": {"field": "id", "generate": "uuid"},
|
|
49
|
+
"fields": {
|
|
50
|
+
"id": {"type": "uuid", "required": True},
|
|
51
|
+
"status": {"type": "string", "required": True},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
"use_gateway": True,
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@pytest.mark.asyncio
|
|
60
|
+
async def test_put_row_uses_row_revision_cas(monkeypatch, sdk):
|
|
61
|
+
calls = []
|
|
62
|
+
|
|
63
|
+
async def fake_request(**kwargs):
|
|
64
|
+
calls.append(kwargs)
|
|
65
|
+
return {"row_key": "job-1", "revision": 3, "schema_revision": 2}
|
|
66
|
+
|
|
67
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
68
|
+
|
|
69
|
+
result = await sdk.stash.tables.put_row(
|
|
70
|
+
env="staging",
|
|
71
|
+
scope="group",
|
|
72
|
+
table="jobs",
|
|
73
|
+
if_revision=2,
|
|
74
|
+
row={"id": "job-1", "status": "ready"},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
assert result["revision"] == 3
|
|
78
|
+
assert calls == [
|
|
79
|
+
{
|
|
80
|
+
"endpoint": "/svc/stash/tables/put-row",
|
|
81
|
+
"method": "POST",
|
|
82
|
+
"body": {
|
|
83
|
+
"env": "staging",
|
|
84
|
+
"scope": "group",
|
|
85
|
+
"table": "jobs",
|
|
86
|
+
"if_revision": 2,
|
|
87
|
+
"row": {"id": "job-1", "status": "ready"},
|
|
88
|
+
},
|
|
89
|
+
"use_gateway": True,
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.mark.asyncio
|
|
95
|
+
async def test_get_row_posts_integer_key_without_revision(monkeypatch, sdk):
|
|
96
|
+
calls = []
|
|
97
|
+
|
|
98
|
+
async def fake_request(**kwargs):
|
|
99
|
+
calls.append(kwargs)
|
|
100
|
+
return {"row_key": "42", "data": {"id": 42}}
|
|
101
|
+
|
|
102
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
103
|
+
|
|
104
|
+
result = await sdk.stash.tables.get_row(
|
|
105
|
+
env="development",
|
|
106
|
+
scope="self",
|
|
107
|
+
table="jobs",
|
|
108
|
+
key=42,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
assert result["row_key"] == "42"
|
|
112
|
+
assert calls == [
|
|
113
|
+
{
|
|
114
|
+
"endpoint": "/svc/stash/tables/get-row",
|
|
115
|
+
"method": "POST",
|
|
116
|
+
"body": {
|
|
117
|
+
"env": "development",
|
|
118
|
+
"scope": "self",
|
|
119
|
+
"table": "jobs",
|
|
120
|
+
"key": 42,
|
|
121
|
+
},
|
|
122
|
+
"use_gateway": True,
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@pytest.mark.asyncio
|
|
128
|
+
async def test_select_omits_optional_query_fields_by_default(monkeypatch, sdk):
|
|
129
|
+
calls = []
|
|
130
|
+
|
|
131
|
+
async def fake_request(**kwargs):
|
|
132
|
+
calls.append(kwargs)
|
|
133
|
+
return {"rows": [], "next_cursor": None, "spec_revision": 1}
|
|
134
|
+
|
|
135
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
136
|
+
|
|
137
|
+
result = await sdk.stash.tables.select(
|
|
138
|
+
env="production",
|
|
139
|
+
scope="self",
|
|
140
|
+
table="jobs",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
assert result["next_cursor"] is None
|
|
144
|
+
assert calls == [
|
|
145
|
+
{
|
|
146
|
+
"endpoint": "/svc/stash/tables/select",
|
|
147
|
+
"method": "POST",
|
|
148
|
+
"body": {
|
|
149
|
+
"env": "production",
|
|
150
|
+
"scope": "self",
|
|
151
|
+
"table": "jobs",
|
|
152
|
+
},
|
|
153
|
+
"use_gateway": True,
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_select_passes_shallow_boolean_filter_and_opaque_cursor(monkeypatch, sdk):
|
|
160
|
+
calls = []
|
|
161
|
+
|
|
162
|
+
async def fake_request(**kwargs):
|
|
163
|
+
calls.append(kwargs)
|
|
164
|
+
return {"rows": [], "next_cursor": "next-token", "spec_revision": 4}
|
|
165
|
+
|
|
166
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
167
|
+
where = {
|
|
168
|
+
"or": [
|
|
169
|
+
{"field": "status", "op": "eq", "value": "ready"},
|
|
170
|
+
{
|
|
171
|
+
"and": [
|
|
172
|
+
{"field": "priority", "op": "gte", "value": 5},
|
|
173
|
+
{"field": "enabled", "op": "eq", "value": True},
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
result = await sdk.stash.tables.select(
|
|
180
|
+
env="production",
|
|
181
|
+
scope="group",
|
|
182
|
+
table="jobs",
|
|
183
|
+
where=where,
|
|
184
|
+
order_by={"field": "priority", "direction": "desc"},
|
|
185
|
+
page_size=25,
|
|
186
|
+
cursor="opaque-token",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
assert result["next_cursor"] == "next-token"
|
|
190
|
+
assert calls == [
|
|
191
|
+
{
|
|
192
|
+
"endpoint": "/svc/stash/tables/select",
|
|
193
|
+
"method": "POST",
|
|
194
|
+
"body": {
|
|
195
|
+
"env": "production",
|
|
196
|
+
"scope": "group",
|
|
197
|
+
"table": "jobs",
|
|
198
|
+
"where": where,
|
|
199
|
+
"order_by": {"field": "priority", "direction": "desc"},
|
|
200
|
+
"page_size": 25,
|
|
201
|
+
"cursor": "opaque-token",
|
|
202
|
+
},
|
|
203
|
+
"use_gateway": True,
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@pytest.mark.asyncio
|
|
209
|
+
async def test_update_where_uses_spec_revision_and_guard_limit(monkeypatch, sdk):
|
|
210
|
+
calls = []
|
|
211
|
+
|
|
212
|
+
async def fake_request(**kwargs):
|
|
213
|
+
calls.append(kwargs)
|
|
214
|
+
return {
|
|
215
|
+
"matched_count": 1,
|
|
216
|
+
"affected_count": 1,
|
|
217
|
+
"rows": [{"row_key": "job-1", "revision": 2, "schema_revision": 4}],
|
|
218
|
+
"receipt": {"mutation_id": "mutation-1", "created_at": "2026-07-15T12:00:00.000Z"},
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
222
|
+
where = [{"field": "status", "op": "eq", "value": "queued"}]
|
|
223
|
+
|
|
224
|
+
result = await sdk.stash.tables.update_where(
|
|
225
|
+
env="production",
|
|
226
|
+
scope="group",
|
|
227
|
+
table="jobs",
|
|
228
|
+
where=where,
|
|
229
|
+
set={"status": "ready"},
|
|
230
|
+
remove=["note"],
|
|
231
|
+
if_spec_revision=4,
|
|
232
|
+
max_affected=10,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
assert result["receipt"]["mutation_id"] == "mutation-1"
|
|
236
|
+
assert calls == [
|
|
237
|
+
{
|
|
238
|
+
"endpoint": "/svc/stash/tables/update-where",
|
|
239
|
+
"method": "POST",
|
|
240
|
+
"body": {
|
|
241
|
+
"env": "production",
|
|
242
|
+
"scope": "group",
|
|
243
|
+
"table": "jobs",
|
|
244
|
+
"where": where,
|
|
245
|
+
"set": {"status": "ready"},
|
|
246
|
+
"remove": ["note"],
|
|
247
|
+
"if_spec_revision": 4,
|
|
248
|
+
"max_affected": 10,
|
|
249
|
+
},
|
|
250
|
+
"use_gateway": True,
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@pytest.mark.asyncio
|
|
256
|
+
async def test_delete_row_uses_row_revision_and_returns_hard_delete_receipt(monkeypatch, sdk):
|
|
257
|
+
calls = []
|
|
258
|
+
|
|
259
|
+
async def fake_request(**kwargs):
|
|
260
|
+
calls.append(kwargs)
|
|
261
|
+
return {
|
|
262
|
+
"deleted": True,
|
|
263
|
+
"row_key": "job-1",
|
|
264
|
+
"revision": 3,
|
|
265
|
+
"schema_revision": 4,
|
|
266
|
+
"receipt": {"mutation_id": "delete-1", "created_at": "2026-07-15T12:00:00.000Z"},
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
270
|
+
|
|
271
|
+
result = await sdk.stash.tables.delete_row(
|
|
272
|
+
env="production",
|
|
273
|
+
scope="self",
|
|
274
|
+
table="jobs",
|
|
275
|
+
key="job-1",
|
|
276
|
+
if_revision=3,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
assert result["deleted"] is True
|
|
280
|
+
assert result["receipt"]["mutation_id"] == "delete-1"
|
|
281
|
+
assert calls == [
|
|
282
|
+
{
|
|
283
|
+
"endpoint": "/svc/stash/tables/delete-row",
|
|
284
|
+
"method": "POST",
|
|
285
|
+
"body": {
|
|
286
|
+
"env": "production",
|
|
287
|
+
"scope": "self",
|
|
288
|
+
"table": "jobs",
|
|
289
|
+
"key": "job-1",
|
|
290
|
+
"if_revision": 3,
|
|
291
|
+
},
|
|
292
|
+
"use_gateway": True,
|
|
293
|
+
}
|
|
294
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/dominus_sdk_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_authority_public_vocabulary.py
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_control_plane_namespaces.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-7.0.0 → dominus_sdk_python-7.1.0}/tests/test_platform_coder_namespaces.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|