dominusnode 1.0.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.
- dominusnode-1.0.0/LICENSE +21 -0
- dominusnode-1.0.0/PKG-INFO +12 -0
- dominusnode-1.0.0/README.md +440 -0
- dominusnode-1.0.0/dominusnode/__init__.py +151 -0
- dominusnode-1.0.0/dominusnode/admin.py +252 -0
- dominusnode-1.0.0/dominusnode/agent_wallet.py +240 -0
- dominusnode-1.0.0/dominusnode/auth.py +271 -0
- dominusnode-1.0.0/dominusnode/client.py +457 -0
- dominusnode-1.0.0/dominusnode/constants.py +18 -0
- dominusnode-1.0.0/dominusnode/errors.py +91 -0
- dominusnode-1.0.0/dominusnode/http_client.py +435 -0
- dominusnode-1.0.0/dominusnode/keys.py +88 -0
- dominusnode-1.0.0/dominusnode/plans.py +93 -0
- dominusnode-1.0.0/dominusnode/proxy.py +248 -0
- dominusnode-1.0.0/dominusnode/py.typed +0 -0
- dominusnode-1.0.0/dominusnode/sessions.py +55 -0
- dominusnode-1.0.0/dominusnode/slots.py +60 -0
- dominusnode-1.0.0/dominusnode/teams.py +339 -0
- dominusnode-1.0.0/dominusnode/token_manager.py +235 -0
- dominusnode-1.0.0/dominusnode/types.py +521 -0
- dominusnode-1.0.0/dominusnode/usage.py +230 -0
- dominusnode-1.0.0/dominusnode/wallet.py +189 -0
- dominusnode-1.0.0/dominusnode/wallet_auth.py +241 -0
- dominusnode-1.0.0/dominusnode/x402.py +88 -0
- dominusnode-1.0.0/dominusnode.egg-info/PKG-INFO +12 -0
- dominusnode-1.0.0/dominusnode.egg-info/SOURCES.txt +40 -0
- dominusnode-1.0.0/dominusnode.egg-info/dependency_links.txt +1 -0
- dominusnode-1.0.0/dominusnode.egg-info/requires.txt +6 -0
- dominusnode-1.0.0/dominusnode.egg-info/top_level.txt +1 -0
- dominusnode-1.0.0/pyproject.toml +20 -0
- dominusnode-1.0.0/setup.cfg +4 -0
- dominusnode-1.0.0/tests/test_admin.py +191 -0
- dominusnode-1.0.0/tests/test_auth.py +239 -0
- dominusnode-1.0.0/tests/test_client.py +267 -0
- dominusnode-1.0.0/tests/test_errors.py +127 -0
- dominusnode-1.0.0/tests/test_keys.py +98 -0
- dominusnode-1.0.0/tests/test_proxy.py +168 -0
- dominusnode-1.0.0/tests/test_token_manager.py +199 -0
- dominusnode-1.0.0/tests/test_usage.py +165 -0
- dominusnode-1.0.0/tests/test_wallet.py +155 -0
- dominusnode-1.0.0/tests/test_wallet_auth.py +202 -0
- dominusnode-1.0.0/tests/test_x402.py +61 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dominus Node
|
|
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,12 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dominusnode
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Dominus Node SDK for Python
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: httpx>=0.24.0
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
11
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
12
|
+
Requires-Dist: respx>=0.20; extra == "dev"
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
# dominusnode -- Official Dominus Node Python SDK
|
|
2
|
+
|
|
3
|
+
The official Python SDK for the [Dominus Node](https://dominusnode.com) rotating proxy-as-a-service platform. Manage proxy connections, API keys, wallet balances, usage tracking, and more.
|
|
4
|
+
|
|
5
|
+
- **Sync + Async clients** -- `DominusNodeClient` and `AsyncDominusNodeClient`
|
|
6
|
+
- **Single dependency** -- only requires [httpx](https://www.python-httpx.org/)
|
|
7
|
+
- **Full type hints** -- PEP 561 compliant, works with mypy and pyright
|
|
8
|
+
- **Auto token refresh** -- JWT expiry is handled transparently
|
|
9
|
+
- **Rate limit auto-retry** -- 429 responses are automatically retried
|
|
10
|
+
- **Typed error hierarchy** -- catch specific exception classes
|
|
11
|
+
- **Python 3.9+** compatible
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install dominusnode
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
poetry add dominusnode
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Requirements:** Python 3.9+ and httpx >= 0.24.0.
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### Synchronous
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from dominusnode import DominusNodeClient
|
|
31
|
+
|
|
32
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com") as client:
|
|
33
|
+
# Authenticate with API key
|
|
34
|
+
client.connect_with_key("dn_live_your_api_key")
|
|
35
|
+
|
|
36
|
+
# Check balance
|
|
37
|
+
balance = client.wallet.get_balance()
|
|
38
|
+
print(f"Balance: ${balance.balance_usd}")
|
|
39
|
+
|
|
40
|
+
# Build a proxy URL
|
|
41
|
+
from dominusnode import ProxyUrlOptions
|
|
42
|
+
proxy_url = client.proxy.build_url(ProxyUrlOptions(
|
|
43
|
+
protocol="http",
|
|
44
|
+
country="US",
|
|
45
|
+
state="california",
|
|
46
|
+
))
|
|
47
|
+
print(proxy_url)
|
|
48
|
+
# => http://country-US-state-california:dn_live_your_api_key@proxy.dominusnode.com:8080
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Asynchronous
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import asyncio
|
|
55
|
+
from dominusnode import AsyncDominusNodeClient
|
|
56
|
+
|
|
57
|
+
async def main():
|
|
58
|
+
async with AsyncDominusNodeClient(base_url="https://api.dominusnode.com") as client:
|
|
59
|
+
await client.connect_with_key("dn_live_your_api_key")
|
|
60
|
+
|
|
61
|
+
balance = await client.wallet.get_balance()
|
|
62
|
+
print(f"Balance: ${balance.balance_usd}")
|
|
63
|
+
|
|
64
|
+
keys = await client.keys.list()
|
|
65
|
+
for key in keys:
|
|
66
|
+
print(f" {key.prefix} - {key.label}")
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Authentication
|
|
72
|
+
|
|
73
|
+
Three ways to authenticate:
|
|
74
|
+
|
|
75
|
+
### 1. API Key (Recommended for Proxy Usage)
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com") as client:
|
|
79
|
+
client.connect_with_key("dn_live_your_api_key")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or pass it in the constructor for auto-connect:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
with DominusNodeClient(
|
|
86
|
+
base_url="https://api.dominusnode.com",
|
|
87
|
+
api_key="dn_live_your_api_key",
|
|
88
|
+
) as client:
|
|
89
|
+
# Already authenticated
|
|
90
|
+
balance = client.wallet.get_balance()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2. Email/Password
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com") as client:
|
|
97
|
+
result = client.connect_with_credentials("user@example.com", "SecurePass123!")
|
|
98
|
+
|
|
99
|
+
if result.mfa_required:
|
|
100
|
+
# MFA is enabled -- complete with TOTP code
|
|
101
|
+
code = input("Enter MFA code: ")
|
|
102
|
+
client.complete_mfa(code)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. Pre-existing Tokens
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
client = DominusNodeClient(
|
|
109
|
+
base_url="https://api.dominusnode.com",
|
|
110
|
+
access_token="eyJhbGci...",
|
|
111
|
+
refresh_token="eyJhbGci...",
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Resources
|
|
116
|
+
|
|
117
|
+
All API operations are organized into resource objects:
|
|
118
|
+
|
|
119
|
+
### Auth
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# Register a new account
|
|
123
|
+
result = client.auth.register("user@example.com", "SecurePass123!")
|
|
124
|
+
|
|
125
|
+
# Login
|
|
126
|
+
result = client.auth.login("user@example.com", "SecurePass123!")
|
|
127
|
+
|
|
128
|
+
# Change password
|
|
129
|
+
client.auth.change_password("OldPass123!", "NewPass456!")
|
|
130
|
+
|
|
131
|
+
# Logout (revokes all refresh tokens)
|
|
132
|
+
client.auth.logout()
|
|
133
|
+
|
|
134
|
+
# Get current user info
|
|
135
|
+
user = client.auth.me()
|
|
136
|
+
print(f"User: {user.email}, Admin: {user.is_admin}")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### MFA (Two-Factor Authentication)
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
# Setup MFA
|
|
143
|
+
setup = client.auth.mfa_setup()
|
|
144
|
+
print(f"Secret: {setup.secret}")
|
|
145
|
+
print(f"OTPAuth URI: {setup.otpauth_uri}")
|
|
146
|
+
print(f"Backup codes: {setup.backup_codes}") # Save these!
|
|
147
|
+
|
|
148
|
+
# Enable MFA (verify with a code from your authenticator app)
|
|
149
|
+
client.auth.mfa_enable("123456")
|
|
150
|
+
|
|
151
|
+
# Check MFA status
|
|
152
|
+
status = client.auth.mfa_status()
|
|
153
|
+
print(f"MFA enabled: {status.enabled}, Backup codes remaining: {status.backup_codes_remaining}")
|
|
154
|
+
|
|
155
|
+
# Disable MFA
|
|
156
|
+
client.auth.mfa_disable("SecurePass123!", "123456")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### API Keys
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
# Create a new API key (the raw key is only shown once)
|
|
163
|
+
created = client.keys.create("my-scraper")
|
|
164
|
+
print(f"Key: {created.key}") # dn_live_xxxx -- save this!
|
|
165
|
+
print(f"ID: {created.id}")
|
|
166
|
+
|
|
167
|
+
# List all keys
|
|
168
|
+
keys = client.keys.list()
|
|
169
|
+
for key in keys:
|
|
170
|
+
print(f" {key.prefix} ({key.label}) - created {key.created_at}")
|
|
171
|
+
|
|
172
|
+
# Revoke a key
|
|
173
|
+
client.keys.revoke("key-uuid-here")
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Wallet
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
# Get balance
|
|
180
|
+
balance = client.wallet.get_balance()
|
|
181
|
+
print(f"Balance: ${balance.balance_usd} ({balance.balance_cents} cents)")
|
|
182
|
+
|
|
183
|
+
# Get transaction history
|
|
184
|
+
transactions = client.wallet.get_transactions(limit=20, offset=0)
|
|
185
|
+
for tx in transactions:
|
|
186
|
+
print(f" {tx.type}: {tx.amount_cents} cents - {tx.description}")
|
|
187
|
+
|
|
188
|
+
# Top up with Stripe
|
|
189
|
+
checkout = client.wallet.topup_stripe(amount_cents=5000)
|
|
190
|
+
print(f"Checkout URL: {checkout.url}")
|
|
191
|
+
|
|
192
|
+
# Top up with crypto
|
|
193
|
+
invoice = client.wallet.topup_crypto(amount_cents=5000, currency="btc")
|
|
194
|
+
print(f"Payment URL: {invoice.payment_url}")
|
|
195
|
+
|
|
196
|
+
# Get usage forecast
|
|
197
|
+
forecast = client.wallet.get_forecast()
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Usage
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
# Get usage records
|
|
204
|
+
usage = client.usage.get(from_date="2026-01-01", to_date="2026-02-01", limit=50)
|
|
205
|
+
print(f"Total bytes: {usage.summary.total_bytes}")
|
|
206
|
+
print(f"Total cost: {usage.summary.total_cost_cents} cents")
|
|
207
|
+
|
|
208
|
+
# Daily breakdown
|
|
209
|
+
daily = client.usage.get_daily(from_date="2026-01-01", to_date="2026-02-01")
|
|
210
|
+
for day in daily:
|
|
211
|
+
print(f" {day.date}: {day.bytes_total} bytes, ${day.cost_cents/100:.2f}")
|
|
212
|
+
|
|
213
|
+
# Top target hosts
|
|
214
|
+
top_hosts = client.usage.get_top_hosts(limit=10)
|
|
215
|
+
for host in top_hosts:
|
|
216
|
+
print(f" {host.host}: {host.request_count} requests, {host.bytes_total} bytes")
|
|
217
|
+
|
|
218
|
+
# Export as CSV
|
|
219
|
+
csv_data = client.usage.export_csv(from_date="2026-01-01", to_date="2026-02-01")
|
|
220
|
+
with open("usage.csv", "w") as f:
|
|
221
|
+
f.write(csv_data)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Plans
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
# List available plans
|
|
228
|
+
plans = client.plans.list()
|
|
229
|
+
for plan in plans:
|
|
230
|
+
print(f" {plan.id}: {plan.name} - ${plan.price_per_gb_cents/100:.2f}/GB")
|
|
231
|
+
|
|
232
|
+
# Get current plan
|
|
233
|
+
current = client.plans.get_user_plan()
|
|
234
|
+
print(f"Current plan: {current.plan_id}")
|
|
235
|
+
|
|
236
|
+
# Change plan
|
|
237
|
+
client.plans.change("vol100")
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Sessions
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# List active proxy sessions
|
|
244
|
+
sessions = client.sessions.get_active()
|
|
245
|
+
for session in sessions:
|
|
246
|
+
print(f" Session {session.id}: {session.bytes_total} bytes, started {session.started_at}")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Proxy
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from dominusnode import ProxyUrlOptions
|
|
253
|
+
|
|
254
|
+
# Build an HTTP proxy URL
|
|
255
|
+
proxy_url = client.proxy.build_url()
|
|
256
|
+
print(proxy_url)
|
|
257
|
+
# => http://user:dn_live_xxxx@proxy.dominusnode.com:8080
|
|
258
|
+
|
|
259
|
+
# With geo-targeting
|
|
260
|
+
proxy_url = client.proxy.build_url(ProxyUrlOptions(
|
|
261
|
+
protocol="http",
|
|
262
|
+
country="US",
|
|
263
|
+
state="california",
|
|
264
|
+
city="losangeles",
|
|
265
|
+
))
|
|
266
|
+
|
|
267
|
+
# SOCKS5 proxy URL
|
|
268
|
+
socks_url = client.proxy.build_url(ProxyUrlOptions(
|
|
269
|
+
protocol="socks5",
|
|
270
|
+
country="DE",
|
|
271
|
+
))
|
|
272
|
+
|
|
273
|
+
# With sticky session
|
|
274
|
+
sticky_url = client.proxy.build_url(ProxyUrlOptions(
|
|
275
|
+
country="US",
|
|
276
|
+
session_id="my-session-123",
|
|
277
|
+
))
|
|
278
|
+
|
|
279
|
+
# Get proxy health (no auth required)
|
|
280
|
+
health = client.proxy.get_health()
|
|
281
|
+
print(f"Status: {health.status}, Active sessions: {health.active_sessions}")
|
|
282
|
+
|
|
283
|
+
# Get detailed proxy status
|
|
284
|
+
status = client.proxy.get_status()
|
|
285
|
+
for provider in status.providers:
|
|
286
|
+
print(f" {provider.name}: {provider.state}, latency: {provider.avg_latency_ms}ms")
|
|
287
|
+
|
|
288
|
+
# Get proxy configuration
|
|
289
|
+
config = client.proxy.get_config()
|
|
290
|
+
print(f"Geo-targeting: state={config.geo_targeting.state_support}, city={config.geo_targeting.city_support}")
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Admin (Requires Admin Privileges)
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
# List all users
|
|
297
|
+
users = client.admin.list_users(limit=50, offset=0)
|
|
298
|
+
for user in users.users:
|
|
299
|
+
print(f" {user.email}: {user.status}, balance: {user.balance_cents} cents")
|
|
300
|
+
|
|
301
|
+
# Get user details
|
|
302
|
+
user_detail = client.admin.get_user("user-uuid")
|
|
303
|
+
print(f"Total usage: {user_detail.total_usage_bytes} bytes")
|
|
304
|
+
|
|
305
|
+
# Suspend/activate user
|
|
306
|
+
client.admin.suspend_user("user-uuid")
|
|
307
|
+
client.admin.activate_user("user-uuid")
|
|
308
|
+
|
|
309
|
+
# Get revenue stats
|
|
310
|
+
revenue = client.admin.get_revenue()
|
|
311
|
+
print(f"Total revenue: ${revenue.total_revenue_cents/100:.2f}")
|
|
312
|
+
|
|
313
|
+
# Get system stats
|
|
314
|
+
stats = client.admin.get_stats()
|
|
315
|
+
print(f"Total users: {stats.total_users}, Active sessions: {stats.active_sessions}")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Using with requests/httpx
|
|
319
|
+
|
|
320
|
+
Build proxy URLs and use them with any HTTP client:
|
|
321
|
+
|
|
322
|
+
### With requests
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
import requests
|
|
326
|
+
from dominusnode import DominusNodeClient, ProxyUrlOptions
|
|
327
|
+
|
|
328
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com", api_key="dn_live_KEY") as client:
|
|
329
|
+
proxy_url = client.proxy.build_url(ProxyUrlOptions(country="US"))
|
|
330
|
+
|
|
331
|
+
proxies = {"http": proxy_url, "https": proxy_url}
|
|
332
|
+
response = requests.get("https://httpbin.org/ip", proxies=proxies)
|
|
333
|
+
print(response.json())
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### With httpx
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
import httpx
|
|
340
|
+
from dominusnode import DominusNodeClient, ProxyUrlOptions
|
|
341
|
+
|
|
342
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com", api_key="dn_live_KEY") as client:
|
|
343
|
+
proxy_url = client.proxy.build_url(ProxyUrlOptions(country="US"))
|
|
344
|
+
|
|
345
|
+
with httpx.Client(proxy=proxy_url) as http:
|
|
346
|
+
response = http.get("https://httpbin.org/ip")
|
|
347
|
+
print(response.json())
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### With aiohttp
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
import aiohttp
|
|
354
|
+
from dominusnode import AsyncDominusNodeClient, ProxyUrlOptions
|
|
355
|
+
|
|
356
|
+
async with AsyncDominusNodeClient(base_url="https://api.dominusnode.com", api_key="dn_live_KEY") as client:
|
|
357
|
+
proxy_url = client.proxy.build_url(ProxyUrlOptions(country="US"))
|
|
358
|
+
|
|
359
|
+
async with aiohttp.ClientSession() as session:
|
|
360
|
+
async with session.get("https://httpbin.org/ip", proxy=proxy_url) as resp:
|
|
361
|
+
print(await resp.json())
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Error Handling
|
|
365
|
+
|
|
366
|
+
All SDK errors inherit from `DominusNodeError`:
|
|
367
|
+
|
|
368
|
+
```python
|
|
369
|
+
from dominusnode import (
|
|
370
|
+
DominusNodeClient,
|
|
371
|
+
DominusNodeError,
|
|
372
|
+
AuthenticationError,
|
|
373
|
+
AuthorizationError,
|
|
374
|
+
InsufficientBalanceError,
|
|
375
|
+
RateLimitError,
|
|
376
|
+
ValidationError,
|
|
377
|
+
NotFoundError,
|
|
378
|
+
ConflictError,
|
|
379
|
+
ServerError,
|
|
380
|
+
NetworkError,
|
|
381
|
+
ProxyError,
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
with DominusNodeClient(base_url="https://api.dominusnode.com") as client:
|
|
385
|
+
try:
|
|
386
|
+
client.connect_with_key("dn_live_invalid")
|
|
387
|
+
except AuthenticationError:
|
|
388
|
+
print("Invalid API key")
|
|
389
|
+
except RateLimitError as e:
|
|
390
|
+
print(f"Rate limited. Retry after {e.retry_after_seconds}s")
|
|
391
|
+
except InsufficientBalanceError:
|
|
392
|
+
print("Not enough balance -- top up your wallet")
|
|
393
|
+
except DominusNodeError as e:
|
|
394
|
+
print(f"API error: {e}")
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
| Error Class | HTTP Status | When |
|
|
398
|
+
|-------------|-------------|------|
|
|
399
|
+
| `AuthenticationError` | 401 | Invalid credentials, expired token |
|
|
400
|
+
| `AuthorizationError` | 403 | Insufficient permissions (e.g., non-admin) |
|
|
401
|
+
| `InsufficientBalanceError` | 402 | Wallet balance too low |
|
|
402
|
+
| `RateLimitError` | 429 | Too many requests |
|
|
403
|
+
| `ValidationError` | 400 | Invalid input |
|
|
404
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
405
|
+
| `ConflictError` | 409 | Duplicate resource |
|
|
406
|
+
| `ServerError` | 500+ | Server-side error |
|
|
407
|
+
| `NetworkError` | -- | Connection failure, timeout |
|
|
408
|
+
| `ProxyError` | -- | Proxy URL building error |
|
|
409
|
+
|
|
410
|
+
## Configuration
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
client = DominusNodeClient(
|
|
414
|
+
base_url="https://api.dominusnode.com", # API server URL
|
|
415
|
+
proxy_host="proxy.dominusnode.com", # Proxy gateway hostname
|
|
416
|
+
http_proxy_port=8080, # HTTP proxy port
|
|
417
|
+
socks5_proxy_port=1080, # SOCKS5 proxy port
|
|
418
|
+
timeout=30.0, # HTTP request timeout (seconds)
|
|
419
|
+
)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Development
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Install dev dependencies
|
|
426
|
+
pip install -e ".[dev]"
|
|
427
|
+
|
|
428
|
+
# Run tests
|
|
429
|
+
pytest
|
|
430
|
+
|
|
431
|
+
# Run tests with async support
|
|
432
|
+
pytest --asyncio-mode=auto
|
|
433
|
+
|
|
434
|
+
# Type checking
|
|
435
|
+
mypy dominusnode/
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## License
|
|
439
|
+
|
|
440
|
+
MIT
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""Dominus Node Python SDK.
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the Dominus Node rotating proxy-as-a-service platform.
|
|
4
|
+
|
|
5
|
+
Provides both synchronous and asynchronous clients::
|
|
6
|
+
|
|
7
|
+
# Sync
|
|
8
|
+
from dominusnode import DominusNodeClient
|
|
9
|
+
|
|
10
|
+
with DominusNodeClient(base_url="http://localhost:3000") as client:
|
|
11
|
+
client.connect_with_credentials("user@example.com", "s3cret!Pass")
|
|
12
|
+
print(client.wallet.get_balance())
|
|
13
|
+
|
|
14
|
+
# Async
|
|
15
|
+
from dominusnode import AsyncDominusNodeClient
|
|
16
|
+
|
|
17
|
+
async with AsyncDominusNodeClient(base_url="http://localhost:3000") as client:
|
|
18
|
+
await client.connect_with_credentials("user@example.com", "s3cret!Pass")
|
|
19
|
+
print(await client.wallet.get_balance())
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from .client import AsyncDominusNodeClient, DominusNodeClient
|
|
23
|
+
from .constants import SDK_VERSION
|
|
24
|
+
from .errors import (
|
|
25
|
+
AuthenticationError,
|
|
26
|
+
AuthorizationError,
|
|
27
|
+
ConflictError,
|
|
28
|
+
DominusNodeError,
|
|
29
|
+
InsufficientBalanceError,
|
|
30
|
+
NetworkError,
|
|
31
|
+
NotFoundError,
|
|
32
|
+
ProxyError,
|
|
33
|
+
RateLimitError,
|
|
34
|
+
ServerError,
|
|
35
|
+
ValidationError,
|
|
36
|
+
)
|
|
37
|
+
from .x402 import X402Info, X402Facilitator, X402Pricing
|
|
38
|
+
from .wallet_auth import WalletChallenge, WalletVerifyResult, WalletLinkResult
|
|
39
|
+
from .types import (
|
|
40
|
+
ActiveSession,
|
|
41
|
+
AdminUser,
|
|
42
|
+
AdminUserDetail,
|
|
43
|
+
AdminUsersResponse,
|
|
44
|
+
ApiKey,
|
|
45
|
+
CreatedApiKey,
|
|
46
|
+
CryptoInvoice,
|
|
47
|
+
DailyRevenue,
|
|
48
|
+
DailyUsage,
|
|
49
|
+
GeoTargeting,
|
|
50
|
+
LoginResult,
|
|
51
|
+
MfaSetup,
|
|
52
|
+
MfaStatus,
|
|
53
|
+
Pagination,
|
|
54
|
+
Plan,
|
|
55
|
+
ProxyConfig,
|
|
56
|
+
ProxyEndpointConfig,
|
|
57
|
+
ProxyEndpoints,
|
|
58
|
+
ProxyHealth,
|
|
59
|
+
ProxyStatus,
|
|
60
|
+
ProxyUrlOptions,
|
|
61
|
+
ProviderStat,
|
|
62
|
+
RevenueStats,
|
|
63
|
+
StripeCheckout,
|
|
64
|
+
SlotsInfo,
|
|
65
|
+
SystemStats,
|
|
66
|
+
TopHost,
|
|
67
|
+
UsagePagination,
|
|
68
|
+
UsagePeriod,
|
|
69
|
+
UsageRecord,
|
|
70
|
+
UsageResponse,
|
|
71
|
+
UsageSummary,
|
|
72
|
+
User,
|
|
73
|
+
UserPlanInfo,
|
|
74
|
+
UserPlanUsage,
|
|
75
|
+
Wallet,
|
|
76
|
+
WaitlistCount,
|
|
77
|
+
WaitlistJoinResult,
|
|
78
|
+
WalletForecast,
|
|
79
|
+
WalletTransaction,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
__version__ = SDK_VERSION
|
|
83
|
+
|
|
84
|
+
__all__ = [
|
|
85
|
+
# Clients
|
|
86
|
+
"DominusNodeClient",
|
|
87
|
+
"AsyncDominusNodeClient",
|
|
88
|
+
# Errors
|
|
89
|
+
"DominusNodeError",
|
|
90
|
+
"AuthenticationError",
|
|
91
|
+
"AuthorizationError",
|
|
92
|
+
"RateLimitError",
|
|
93
|
+
"InsufficientBalanceError",
|
|
94
|
+
"ValidationError",
|
|
95
|
+
"NotFoundError",
|
|
96
|
+
"ConflictError",
|
|
97
|
+
"ServerError",
|
|
98
|
+
"NetworkError",
|
|
99
|
+
"ProxyError",
|
|
100
|
+
# Types
|
|
101
|
+
"User",
|
|
102
|
+
"LoginResult",
|
|
103
|
+
"MfaStatus",
|
|
104
|
+
"MfaSetup",
|
|
105
|
+
"ApiKey",
|
|
106
|
+
"CreatedApiKey",
|
|
107
|
+
"Wallet",
|
|
108
|
+
"WalletTransaction",
|
|
109
|
+
"WalletForecast",
|
|
110
|
+
"StripeCheckout",
|
|
111
|
+
"CryptoInvoice",
|
|
112
|
+
"UsageSummary",
|
|
113
|
+
"UsageRecord",
|
|
114
|
+
"UsagePagination",
|
|
115
|
+
"UsagePeriod",
|
|
116
|
+
"UsageResponse",
|
|
117
|
+
"DailyUsage",
|
|
118
|
+
"TopHost",
|
|
119
|
+
"Plan",
|
|
120
|
+
"UserPlanUsage",
|
|
121
|
+
"UserPlanInfo",
|
|
122
|
+
"ActiveSession",
|
|
123
|
+
"ProxyUrlOptions",
|
|
124
|
+
"ProxyHealth",
|
|
125
|
+
"ProviderStat",
|
|
126
|
+
"ProxyEndpoints",
|
|
127
|
+
"ProxyStatus",
|
|
128
|
+
"GeoTargeting",
|
|
129
|
+
"ProxyEndpointConfig",
|
|
130
|
+
"ProxyConfig",
|
|
131
|
+
"AdminUser",
|
|
132
|
+
"AdminUserDetail",
|
|
133
|
+
"Pagination",
|
|
134
|
+
"AdminUsersResponse",
|
|
135
|
+
"RevenueStats",
|
|
136
|
+
"DailyRevenue",
|
|
137
|
+
"SlotsInfo",
|
|
138
|
+
"WaitlistJoinResult",
|
|
139
|
+
"WaitlistCount",
|
|
140
|
+
"SystemStats",
|
|
141
|
+
# x402
|
|
142
|
+
"X402Info",
|
|
143
|
+
"X402Facilitator",
|
|
144
|
+
"X402Pricing",
|
|
145
|
+
# Wallet Auth
|
|
146
|
+
"WalletChallenge",
|
|
147
|
+
"WalletVerifyResult",
|
|
148
|
+
"WalletLinkResult",
|
|
149
|
+
# Constants
|
|
150
|
+
"SDK_VERSION",
|
|
151
|
+
]
|