foundrydb-sdk 0.5.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.
- foundrydb_sdk-0.5.0/.github/workflows/publish.yml +55 -0
- foundrydb_sdk-0.5.0/.gitignore +11 -0
- foundrydb_sdk-0.5.0/LICENSE +21 -0
- foundrydb_sdk-0.5.0/PKG-INFO +433 -0
- foundrydb_sdk-0.5.0/README.md +403 -0
- foundrydb_sdk-0.5.0/RELEASING.md +31 -0
- foundrydb_sdk-0.5.0/foundrydb/__init__.py +280 -0
- foundrydb_sdk-0.5.0/foundrydb/ai_actions.py +242 -0
- foundrydb_sdk-0.5.0/foundrydb/app_jobs.py +494 -0
- foundrydb_sdk-0.5.0/foundrydb/app_services.py +606 -0
- foundrydb_sdk-0.5.0/foundrydb/backups.py +43 -0
- foundrydb_sdk-0.5.0/foundrydb/client.py +354 -0
- foundrydb_sdk-0.5.0/foundrydb/data_pipelines.py +155 -0
- foundrydb_sdk-0.5.0/foundrydb/edge.py +166 -0
- foundrydb_sdk-0.5.0/foundrydb/embedding_pipelines.py +415 -0
- foundrydb_sdk-0.5.0/foundrydb/file_services.py +333 -0
- foundrydb_sdk-0.5.0/foundrydb/inference.py +325 -0
- foundrydb_sdk-0.5.0/foundrydb/monitoring.py +117 -0
- foundrydb_sdk-0.5.0/foundrydb/organizations.py +76 -0
- foundrydb_sdk-0.5.0/foundrydb/queues.py +242 -0
- foundrydb_sdk-0.5.0/foundrydb/services.py +286 -0
- foundrydb_sdk-0.5.0/foundrydb/types.py +2297 -0
- foundrydb_sdk-0.5.0/foundrydb/users.py +47 -0
- foundrydb_sdk-0.5.0/foundrydb/vector_search.py +141 -0
- foundrydb_sdk-0.5.0/foundrydb/webhooks.py +239 -0
- foundrydb_sdk-0.5.0/pyproject.toml +47 -0
- foundrydb_sdk-0.5.0/test_live.py +209 -0
- foundrydb_sdk-0.5.0/tests/__init__.py +0 -0
- foundrydb_sdk-0.5.0/tests/conftest.py +12 -0
- foundrydb_sdk-0.5.0/tests/test_app_services.py +429 -0
- foundrydb_sdk-0.5.0/tests/test_backups.py +298 -0
- foundrydb_sdk-0.5.0/tests/test_client.py +428 -0
- foundrydb_sdk-0.5.0/tests/test_edge.py +435 -0
- foundrydb_sdk-0.5.0/tests/test_monitoring.py +349 -0
- foundrydb_sdk-0.5.0/tests/test_organizations.py +197 -0
- foundrydb_sdk-0.5.0/tests/test_services.py +420 -0
- foundrydb_sdk-0.5.0/tests/test_users.py +237 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*.*.*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag:
|
|
10
|
+
description: 'Version tag to publish (e.g. v1.2.3)'
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
name: Build and publish foundrydb
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.11'
|
|
26
|
+
|
|
27
|
+
- name: Derive version from tag
|
|
28
|
+
run: |
|
|
29
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
30
|
+
TAG="${{ github.event.inputs.tag }}"
|
|
31
|
+
else
|
|
32
|
+
TAG="${GITHUB_REF_NAME}"
|
|
33
|
+
fi
|
|
34
|
+
VERSION="${TAG#v}"
|
|
35
|
+
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
|
36
|
+
echo "Publishing version: $VERSION"
|
|
37
|
+
|
|
38
|
+
- name: Patch pyproject.toml version (ephemeral, in CI only)
|
|
39
|
+
# Replaces the hard-coded version line so the built wheel/sdist carries
|
|
40
|
+
# the tag version. The change is never committed.
|
|
41
|
+
run: |
|
|
42
|
+
sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
|
|
43
|
+
grep "^version" pyproject.toml
|
|
44
|
+
|
|
45
|
+
- name: Install build tools
|
|
46
|
+
run: pip install build twine
|
|
47
|
+
|
|
48
|
+
- name: Build distributions
|
|
49
|
+
run: python -m build
|
|
50
|
+
|
|
51
|
+
- name: Publish to PyPI
|
|
52
|
+
run: twine upload dist/*
|
|
53
|
+
env:
|
|
54
|
+
TWINE_USERNAME: __token__
|
|
55
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anorph
|
|
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,433 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: foundrydb-sdk
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Python SDK for the FoundryDB managed database platform
|
|
5
|
+
Project-URL: Homepage, https://foundrydb.com
|
|
6
|
+
Project-URL: Repository, https://github.com/anorph/foundrydb-sdk-python
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/anorph/foundrydb-sdk-python/issues
|
|
8
|
+
Author: Anorph
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: foundrydb,kafka,managed-database,mongodb,mssql,mysql,opensearch,postgresql,valkey
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Database
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Requires-Dist: httpx>=0.24.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: hatchling; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# foundrydb
|
|
32
|
+
|
|
33
|
+
Official Python SDK for the [FoundryDB](https://foundrydb.com) managed database platform.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install foundrydb-sdk
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The distribution is published as `foundrydb-sdk`; the import package is `foundrydb`:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import foundrydb
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Requirements
|
|
48
|
+
|
|
49
|
+
- Python 3.9+
|
|
50
|
+
- [`httpx`](https://www.python-httpx.org/) (automatically installed)
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from foundrydb import FoundryDB
|
|
56
|
+
|
|
57
|
+
client = FoundryDB(
|
|
58
|
+
api_url="https://api.foundrydb.com",
|
|
59
|
+
username="admin",
|
|
60
|
+
password="admin",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
services = client.services.list()
|
|
64
|
+
for svc in services:
|
|
65
|
+
print(svc.id, svc.name, svc.status)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Organizations
|
|
69
|
+
|
|
70
|
+
FoundryDB supports personal and team organizations. You can list all organizations
|
|
71
|
+
your account belongs to, and scope a client (or individual service creation requests)
|
|
72
|
+
to a specific organization.
|
|
73
|
+
|
|
74
|
+
### List organizations
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
orgs = client.organizations.list()
|
|
78
|
+
for org in orgs:
|
|
79
|
+
print(org.id, org.name, org.slug, "personal=" + str(org.is_personal))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Each entry is an `Organization` dataclass with fields: `id`, `name`, `slug`, `is_personal`.
|
|
83
|
+
|
|
84
|
+
### Scope client to an organization
|
|
85
|
+
|
|
86
|
+
Pass `organization_id` when constructing the client. Every request will then include
|
|
87
|
+
the `X-Active-Org-ID` header automatically.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
client = FoundryDB(
|
|
91
|
+
api_url="https://api.foundrydb.com",
|
|
92
|
+
username="admin",
|
|
93
|
+
password="admin",
|
|
94
|
+
organization_id="org_abc123",
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Override organization per request
|
|
99
|
+
|
|
100
|
+
You can also pass `organization_id` directly to `services.create()` to override the
|
|
101
|
+
client-level setting for a single call:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
service = client.services.create(
|
|
105
|
+
name="team-pg",
|
|
106
|
+
database_type="postgresql",
|
|
107
|
+
version="17",
|
|
108
|
+
plan_name="tier-2",
|
|
109
|
+
zone="se-sto1",
|
|
110
|
+
storage_size_gb=50,
|
|
111
|
+
storage_tier="maxiops",
|
|
112
|
+
organization_id="org_team456",
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Supported Database Types
|
|
117
|
+
|
|
118
|
+
| Type | Versions |
|
|
119
|
+
|------|----------|
|
|
120
|
+
| `postgresql` | 14, 15, 16, 17, 18 |
|
|
121
|
+
| `mysql` | 8.4 |
|
|
122
|
+
| `mongodb` | 6.0, 7.0, 8.0 |
|
|
123
|
+
| `valkey` | 7.2, 8.0, 8.1, 9.0 |
|
|
124
|
+
| `kafka` | 3.6, 3.7, 3.8, 3.9, 4.0 |
|
|
125
|
+
| `opensearch: 2 |
|
|
126
|
+
| `mssql` | 4.8 |
|
|
127
|
+
|
|
128
|
+
## Usage
|
|
129
|
+
|
|
130
|
+
### Services
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# List all managed services
|
|
134
|
+
services = client.services.list()
|
|
135
|
+
|
|
136
|
+
# Create a single-node PostgreSQL 17 service
|
|
137
|
+
service = client.services.create(
|
|
138
|
+
name="my-pg",
|
|
139
|
+
database_type="postgresql",
|
|
140
|
+
version="17",
|
|
141
|
+
plan_name="tier-2",
|
|
142
|
+
zone="se-sto1",
|
|
143
|
+
storage_size_gb=50,
|
|
144
|
+
storage_tier="maxiops",
|
|
145
|
+
)
|
|
146
|
+
print("Created:", service.id, service.status)
|
|
147
|
+
|
|
148
|
+
# Create a 3-node HA PostgreSQL cluster with auto-failover
|
|
149
|
+
ha_service = client.services.create(
|
|
150
|
+
name="my-pg-ha",
|
|
151
|
+
database_type="postgresql",
|
|
152
|
+
version="17",
|
|
153
|
+
plan_name="tier-2",
|
|
154
|
+
zone="se-sto1",
|
|
155
|
+
storage_size_gb=100,
|
|
156
|
+
storage_tier="maxiops",
|
|
157
|
+
node_count=3,
|
|
158
|
+
auto_failover_enabled=True,
|
|
159
|
+
replication_mode="async",
|
|
160
|
+
encryption_enabled=True,
|
|
161
|
+
allowed_cidrs=["203.0.113.0/24"],
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Create an OpenSearch service
|
|
165
|
+
search_svc = client.services.create(
|
|
166
|
+
name="my-search",
|
|
167
|
+
database_type="opensearch",
|
|
168
|
+
version="2",
|
|
169
|
+
plan_name="tier-2",
|
|
170
|
+
zone="se-sto1",
|
|
171
|
+
storage_size_gb=50,
|
|
172
|
+
storage_tier="maxiops",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Create a Kafka cluster
|
|
176
|
+
kafka_svc = client.services.create(
|
|
177
|
+
name="my-kafka",
|
|
178
|
+
database_type="kafka",
|
|
179
|
+
version="4.0",
|
|
180
|
+
plan_name="tier-2",
|
|
181
|
+
zone="se-sto1",
|
|
182
|
+
storage_size_gb=100,
|
|
183
|
+
storage_tier="maxiops",
|
|
184
|
+
node_count=3,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Get a service by ID
|
|
188
|
+
svc = client.services.get(service.id)
|
|
189
|
+
|
|
190
|
+
# Update a service (e.g. change allowed CIDRs)
|
|
191
|
+
client.services.update(service.id, allowed_cidrs=["203.0.113.0/24"])
|
|
192
|
+
|
|
193
|
+
# Delete a service
|
|
194
|
+
client.services.delete(service.id)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### `create()` parameters
|
|
198
|
+
|
|
199
|
+
| Parameter | Type | Required | Description |
|
|
200
|
+
|-----------|------|----------|-------------|
|
|
201
|
+
| `name` | str | yes | Display name |
|
|
202
|
+
| `database_type` | DatabaseType | yes | Engine (see table above) |
|
|
203
|
+
| `version` | str | yes | Engine version string |
|
|
204
|
+
| `plan_name` | str | yes | Compute plan (e.g. `"tier-2"`) |
|
|
205
|
+
| `zone` | str | yes | Deployment zone (e.g. `"se-sto1"`) |
|
|
206
|
+
| `storage_size_gb` | int | yes | Data disk size in GB |
|
|
207
|
+
| `storage_tier` | str | yes | `"standard"` or `"maxiops"` |
|
|
208
|
+
| `organization_id` | str | no | Override active org for this request |
|
|
209
|
+
| `node_count` | int | no | Number of nodes (default 1) |
|
|
210
|
+
| `auto_failover_enabled` | bool | no | Enable automatic failover |
|
|
211
|
+
| `replication_mode` | str | no | `"async"` or `"sync"` |
|
|
212
|
+
| `encryption_enabled` | bool | no | At-rest encryption |
|
|
213
|
+
| `allowed_cidrs` | list[str] | no | Allowed source CIDRs |
|
|
214
|
+
| `maintenance_window` | str | no | Preferred maintenance window |
|
|
215
|
+
|
|
216
|
+
### Database Users and Credentials
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
# List users
|
|
220
|
+
users = client.users.list(service_id)
|
|
221
|
+
for user in users:
|
|
222
|
+
print(user.username)
|
|
223
|
+
|
|
224
|
+
# Reveal password and connection string
|
|
225
|
+
creds = client.users.reveal_password(service_id, "admin")
|
|
226
|
+
print(creds.connection_string)
|
|
227
|
+
# postgresql://admin:s3cret@my-pg.foundrydb.com:5432/defaultdb?sslmode=require
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Backups
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# List backups
|
|
234
|
+
backups = client.backups.list(service_id)
|
|
235
|
+
for b in backups:
|
|
236
|
+
print(b.id, b.status, b.backup_type)
|
|
237
|
+
|
|
238
|
+
# Trigger an on-demand backup
|
|
239
|
+
result = client.backups.trigger(service_id)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Monitoring
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# Get current metrics
|
|
246
|
+
metrics = client.monitoring.get_metrics(service_id)
|
|
247
|
+
print(f"CPU: {metrics.cpu_usage_percent}%")
|
|
248
|
+
print(f"Memory: {metrics.memory_usage_percent}%")
|
|
249
|
+
|
|
250
|
+
# Request logs and poll manually
|
|
251
|
+
task = client.monitoring.request_logs(service_id, lines=200)
|
|
252
|
+
result = client.monitoring.get_logs(service_id, task.task_id)
|
|
253
|
+
print(result.logs)
|
|
254
|
+
|
|
255
|
+
# Or use the convenience wrapper (auto-polls until done)
|
|
256
|
+
logs = client.monitoring.fetch_logs(service_id, lines=500)
|
|
257
|
+
print(logs)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Edge Gateway
|
|
261
|
+
|
|
262
|
+
The edge gateway sits in front of app services and provides custom domains with automated TLS, path-based caching, a token-bucket rate limiter, and a WAF. All methods are on `client.edge`:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
from foundrydb import EdgeCacheRule, EdgeRateLimit
|
|
266
|
+
|
|
267
|
+
# Add a custom domain (starts in pending_verification; platform verifies CNAME and issues TLS)
|
|
268
|
+
domain = client.edge.create_domain(app.id, "shop.acme.com")
|
|
269
|
+
print(domain.cname_target) # "edge.foundrydb.com" -- point your CNAME here
|
|
270
|
+
|
|
271
|
+
# Trigger an immediate verification pass instead of waiting for the background worker
|
|
272
|
+
domain = client.edge.verify_domain(app.id, domain.id)
|
|
273
|
+
|
|
274
|
+
# List all domains attached to the app
|
|
275
|
+
domains = client.edge.list_domains(app.id)
|
|
276
|
+
for d in domains:
|
|
277
|
+
print(d.domain, d.status)
|
|
278
|
+
|
|
279
|
+
# Remove a domain (idempotent: 404 is treated as success)
|
|
280
|
+
client.edge.delete_domain(app.id, domain.id)
|
|
281
|
+
|
|
282
|
+
# Inspect the edge overview: enabled flag, home PoP, CNAME target, per-PoP convergence
|
|
283
|
+
status = client.edge.get_status(app.id)
|
|
284
|
+
print(status.edge_enabled, status.home_pop, status.config_version)
|
|
285
|
+
for pop in status.applications:
|
|
286
|
+
print(pop.zone, pop.status, pop.applied_version)
|
|
287
|
+
|
|
288
|
+
# Update customer-tunable edge settings (cache rules, rate limit, WAF mode)
|
|
289
|
+
settings = client.edge.update_settings(
|
|
290
|
+
app.id,
|
|
291
|
+
cache_rules=[EdgeCacheRule(path_prefix="/static/", ttl_seconds=86400)],
|
|
292
|
+
rate_limit=EdgeRateLimit(requests_per_second=100, burst=200, key="ip"),
|
|
293
|
+
waf_mode="detect",
|
|
294
|
+
)
|
|
295
|
+
print(settings.config_version) # version the fleet will converge on
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
#### `update_settings()` parameters
|
|
299
|
+
|
|
300
|
+
| Parameter | Type | Description |
|
|
301
|
+
|-----------|------|-------------|
|
|
302
|
+
| `cache_rules` | `list[EdgeCacheRule]` or `None` | Path-prefix cache rules. Pass `[]` to clear. |
|
|
303
|
+
| `rate_limit` | `EdgeRateLimit` or `None` | Token-bucket rate limit. |
|
|
304
|
+
| `waf_mode` | `str` or `None` | `"off"` or `"detect"`. |
|
|
305
|
+
|
|
306
|
+
#### Edge models
|
|
307
|
+
|
|
308
|
+
| Model | Fields |
|
|
309
|
+
|-------|--------|
|
|
310
|
+
| `EdgeDomain` | `id`, `service_id`, `user_id`, `domain`, `status`, `cname_target`, `certificate_id`, `verification_checked_at`, `error_message`, `created_at`, `updated_at` |
|
|
311
|
+
| `EdgeStatus` | `edge_enabled`, `home_pop`, `cname_target`, `config_version`, `applications` |
|
|
312
|
+
| `EdgeAppApplication` | `zone`, `applied_version`, `status`, `error_message` |
|
|
313
|
+
| `EdgeSettings` | `waf_mode`, `config_version`, `cache_rules`, `rate_limit` |
|
|
314
|
+
| `EdgeCacheRule` | `path_prefix`, `ttl_seconds` |
|
|
315
|
+
| `EdgeRateLimit` | `requests_per_second`, `burst`, `key` |
|
|
316
|
+
|
|
317
|
+
`EdgeDomainStatus` values: `pending_verification`, `verifying`, `issuing_certificate`, `propagating`, `active`, `failed`, `deleting`.
|
|
318
|
+
|
|
319
|
+
## Async Client
|
|
320
|
+
|
|
321
|
+
All methods have async equivalents. Use `AsyncFoundryDB` as an async context manager:
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
import asyncio
|
|
325
|
+
from foundrydb import AsyncFoundryDB
|
|
326
|
+
|
|
327
|
+
async def main():
|
|
328
|
+
async with AsyncFoundryDB(
|
|
329
|
+
api_url="https://api.foundrydb.com",
|
|
330
|
+
username="admin",
|
|
331
|
+
password="admin",
|
|
332
|
+
organization_id="org_abc123", # optional org scoping
|
|
333
|
+
) as client:
|
|
334
|
+
# List organizations
|
|
335
|
+
orgs = await client.organizations.list()
|
|
336
|
+
|
|
337
|
+
# Create a service
|
|
338
|
+
service = await client.services.create(
|
|
339
|
+
name="async-pg",
|
|
340
|
+
database_type="postgresql",
|
|
341
|
+
version="17",
|
|
342
|
+
plan_name="tier-2",
|
|
343
|
+
zone="se-sto1",
|
|
344
|
+
storage_size_gb=50,
|
|
345
|
+
storage_tier="maxiops",
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
creds = await client.users.reveal_password(service.id, "admin")
|
|
349
|
+
print(creds.connection_string)
|
|
350
|
+
|
|
351
|
+
logs = await client.monitoring.fetch_logs(service.id)
|
|
352
|
+
print(logs)
|
|
353
|
+
|
|
354
|
+
asyncio.run(main())
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Error Handling
|
|
358
|
+
|
|
359
|
+
API errors raise `FoundryDBError` with `status_code` and `body` attributes:
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
from foundrydb import FoundryDB, FoundryDBError
|
|
363
|
+
|
|
364
|
+
try:
|
|
365
|
+
client.services.get("non-existent-id")
|
|
366
|
+
except FoundryDBError as e:
|
|
367
|
+
print(f"API error {e.status_code}: {e}")
|
|
368
|
+
print(e.body) # raw dict from the API
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Configuration
|
|
372
|
+
|
|
373
|
+
```python
|
|
374
|
+
client = FoundryDB(
|
|
375
|
+
api_url="https://api.foundrydb.com", # required
|
|
376
|
+
username="admin", # required
|
|
377
|
+
password="admin", # required
|
|
378
|
+
timeout=30.0, # optional, default 30s
|
|
379
|
+
organization_id="org_abc123", # optional, scopes all requests
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Typed Models
|
|
384
|
+
|
|
385
|
+
All responses are typed dataclasses:
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from foundrydb import (
|
|
389
|
+
Organization,
|
|
390
|
+
Service,
|
|
391
|
+
DatabaseUser,
|
|
392
|
+
Backup,
|
|
393
|
+
ServiceMetrics,
|
|
394
|
+
CreateServiceRequest,
|
|
395
|
+
)
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Each model also exposes `.raw` for direct access to the full JSON response dict.
|
|
399
|
+
|
|
400
|
+
### `Organization`
|
|
401
|
+
|
|
402
|
+
| Field | Type | Description |
|
|
403
|
+
|-------|------|-------------|
|
|
404
|
+
| `id` | str | Unique organization ID |
|
|
405
|
+
| `name` | str | Display name |
|
|
406
|
+
| `slug` | str | URL-safe identifier |
|
|
407
|
+
| `is_personal` | bool | True for a user's personal org |
|
|
408
|
+
|
|
409
|
+
### `CreateServiceRequest`
|
|
410
|
+
|
|
411
|
+
A dataclass that mirrors the `create()` keyword arguments. You can construct it
|
|
412
|
+
directly and call `.to_dict()` to get the request payload:
|
|
413
|
+
|
|
414
|
+
```python
|
|
415
|
+
from foundrydb import CreateServiceRequest
|
|
416
|
+
|
|
417
|
+
req = CreateServiceRequest(
|
|
418
|
+
name="my-valkey",
|
|
419
|
+
database_type="valkey",
|
|
420
|
+
version="8.1",
|
|
421
|
+
plan_name="tier-2",
|
|
422
|
+
zone="se-sto1",
|
|
423
|
+
storage_size_gb=20,
|
|
424
|
+
storage_tier="maxiops",
|
|
425
|
+
node_count=3,
|
|
426
|
+
auto_failover_enabled=True,
|
|
427
|
+
)
|
|
428
|
+
print(req.to_dict())
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## License
|
|
432
|
+
|
|
433
|
+
MIT
|