@dominusnode/sdk 1.0.0

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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +679 -0
  3. package/dist/cjs/admin.d.ts +71 -0
  4. package/dist/cjs/admin.js +60 -0
  5. package/dist/cjs/auth.d.ts +47 -0
  6. package/dist/cjs/auth.js +46 -0
  7. package/dist/cjs/client.d.ts +56 -0
  8. package/dist/cjs/client.js +109 -0
  9. package/dist/cjs/constants.d.ts +8 -0
  10. package/dist/cjs/constants.js +11 -0
  11. package/dist/cjs/errors.d.ts +36 -0
  12. package/dist/cjs/errors.js +86 -0
  13. package/dist/cjs/http.d.ts +19 -0
  14. package/dist/cjs/http.js +195 -0
  15. package/dist/cjs/index.d.ts +30 -0
  16. package/dist/cjs/index.js +58 -0
  17. package/dist/cjs/keys.d.ts +27 -0
  18. package/dist/cjs/keys.js +22 -0
  19. package/dist/cjs/plans.d.ts +37 -0
  20. package/dist/cjs/plans.js +22 -0
  21. package/dist/cjs/proxy.d.ts +62 -0
  22. package/dist/cjs/proxy.js +71 -0
  23. package/dist/cjs/resources/agent-wallet.d.ts +52 -0
  24. package/dist/cjs/resources/agent-wallet.js +64 -0
  25. package/dist/cjs/resources/teams.d.ts +93 -0
  26. package/dist/cjs/resources/teams.js +82 -0
  27. package/dist/cjs/resources/wallet-auth.d.ts +66 -0
  28. package/dist/cjs/resources/wallet-auth.js +105 -0
  29. package/dist/cjs/resources/x402.d.ts +39 -0
  30. package/dist/cjs/resources/x402.js +25 -0
  31. package/dist/cjs/sessions.d.ts +15 -0
  32. package/dist/cjs/sessions.js +14 -0
  33. package/dist/cjs/slots.d.ts +9 -0
  34. package/dist/cjs/slots.js +19 -0
  35. package/dist/cjs/token-manager.d.ts +21 -0
  36. package/dist/cjs/token-manager.js +105 -0
  37. package/dist/cjs/types.d.ts +154 -0
  38. package/dist/cjs/types.js +2 -0
  39. package/dist/cjs/usage.d.ts +80 -0
  40. package/dist/cjs/usage.js +56 -0
  41. package/dist/cjs/wallet.d.ts +59 -0
  42. package/dist/cjs/wallet.js +56 -0
  43. package/dist/esm/admin.d.ts +71 -0
  44. package/dist/esm/admin.js +56 -0
  45. package/dist/esm/auth.d.ts +47 -0
  46. package/dist/esm/auth.js +42 -0
  47. package/dist/esm/client.d.ts +56 -0
  48. package/dist/esm/client.js +105 -0
  49. package/dist/esm/constants.d.ts +8 -0
  50. package/dist/esm/constants.js +8 -0
  51. package/dist/esm/errors.d.ts +36 -0
  52. package/dist/esm/errors.js +72 -0
  53. package/dist/esm/http.d.ts +19 -0
  54. package/dist/esm/http.js +191 -0
  55. package/dist/esm/index.d.ts +30 -0
  56. package/dist/esm/index.js +23 -0
  57. package/dist/esm/keys.d.ts +27 -0
  58. package/dist/esm/keys.js +18 -0
  59. package/dist/esm/plans.d.ts +37 -0
  60. package/dist/esm/plans.js +18 -0
  61. package/dist/esm/proxy.d.ts +62 -0
  62. package/dist/esm/proxy.js +67 -0
  63. package/dist/esm/resources/agent-wallet.d.ts +52 -0
  64. package/dist/esm/resources/agent-wallet.js +60 -0
  65. package/dist/esm/resources/teams.d.ts +93 -0
  66. package/dist/esm/resources/teams.js +78 -0
  67. package/dist/esm/resources/wallet-auth.d.ts +66 -0
  68. package/dist/esm/resources/wallet-auth.js +101 -0
  69. package/dist/esm/resources/x402.d.ts +39 -0
  70. package/dist/esm/resources/x402.js +21 -0
  71. package/dist/esm/sessions.d.ts +15 -0
  72. package/dist/esm/sessions.js +10 -0
  73. package/dist/esm/slots.d.ts +9 -0
  74. package/dist/esm/slots.js +15 -0
  75. package/dist/esm/token-manager.d.ts +21 -0
  76. package/dist/esm/token-manager.js +101 -0
  77. package/dist/esm/types.d.ts +154 -0
  78. package/dist/esm/types.js +1 -0
  79. package/dist/esm/usage.d.ts +80 -0
  80. package/dist/esm/usage.js +52 -0
  81. package/dist/esm/wallet.d.ts +59 -0
  82. package/dist/esm/wallet.js +52 -0
  83. package/dist/tsconfig.tsbuildinfo +1 -0
  84. package/package.json +31 -0
package/LICENSE ADDED
@@ -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.
package/README.md ADDED
@@ -0,0 +1,679 @@
1
+ # @dominusnode/sdk -- Official Dominus Node Node.js SDK
2
+
3
+ The official Node.js/TypeScript 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 -- all from a single, strongly-typed client.
4
+
5
+ - **Zero dependencies** -- uses the Node.js 18+ built-in `fetch` API
6
+ - **Dual CJS + ESM output** -- works with `require()` and `import` out of the box
7
+ - **Full TypeScript support** -- every request and response is fully typed
8
+ - **Auto token refresh** -- JWT expiry is handled transparently via base64 decode (no crypto dependency)
9
+ - **Rate limit auto-retry** -- 429 responses are automatically retried after the server-specified delay
10
+ - **Typed error hierarchy** -- catch specific error classes instead of parsing status codes
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @dominusnode/sdk
16
+ ```
17
+
18
+ ```bash
19
+ yarn add @dominusnode/sdk
20
+ ```
21
+
22
+ ```bash
23
+ pnpm add @dominusnode/sdk
24
+ ```
25
+
26
+ **Requirements:** Node.js 18.0.0 or later (uses built-in `fetch`).
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import { DominusNodeClient } from '@dominusnode/sdk';
32
+
33
+ // Connect with API key
34
+ const client = new DominusNodeClient({ baseUrl: 'https://api.dominusnode.com' });
35
+ await client.connectWithKey('dn_live_your_api_key');
36
+
37
+ // Check balance
38
+ const balance = await client.wallet.getBalance();
39
+ console.log(`Balance: $${balance.balanceUsd}`);
40
+
41
+ // Build proxy URL
42
+ const proxyUrl = client.proxy.buildUrl('dn_live_your_key', {
43
+ protocol: 'http',
44
+ country: 'US',
45
+ state: 'california',
46
+ city: 'losangeles',
47
+ });
48
+ console.log(proxyUrl);
49
+ // => http://user-country_US-state_california-city_losangeles:dn_live_your_key@proxy.dominusnode.com:8080
50
+ ```
51
+
52
+ ## Authentication
53
+
54
+ The SDK supports three authentication modes. All authenticated requests automatically include a Bearer token, and expired tokens are refreshed transparently.
55
+
56
+ ### API Key
57
+
58
+ Best for server-side scripts and backend integrations. The key is exchanged for a JWT token pair on the first call.
59
+
60
+ ```typescript
61
+ const client = new DominusNodeClient({ baseUrl: 'https://api.dominusnode.com' });
62
+ await client.connectWithKey('dn_live_your_api_key');
63
+ ```
64
+
65
+ ### Email + Password
66
+
67
+ Best for interactive applications where the user logs in with credentials. Supports MFA (TOTP or backup codes).
68
+
69
+ ```typescript
70
+ const client = new DominusNodeClient({ baseUrl: 'https://api.dominusnode.com' });
71
+ const result = await client.connectWithCredentials('user@example.com', 'SecurePass123!');
72
+
73
+ if (result.mfaRequired) {
74
+ // User has 2FA enabled -- need TOTP code
75
+ await client.completeMfa('123456');
76
+ }
77
+ ```
78
+
79
+ ### Pre-authenticated
80
+
81
+ Use when you already have valid JWT tokens (e.g., stored from a previous session).
82
+
83
+ ```typescript
84
+ const client = new DominusNodeClient({
85
+ baseUrl: 'https://api.dominusnode.com',
86
+ accessToken: 'existing_jwt',
87
+ refreshToken: 'existing_refresh_token',
88
+ });
89
+ ```
90
+
91
+ ### Disconnecting
92
+
93
+ Clear all stored tokens locally. Call `client.auth.logout()` first if you also want to revoke refresh tokens server-side.
94
+
95
+ ```typescript
96
+ await client.auth.logout(); // Revoke server-side refresh tokens
97
+ client.disconnect(); // Clear local token state
98
+ ```
99
+
100
+ ## Configuration
101
+
102
+ ```typescript
103
+ interface DominusNodeConfig {
104
+ baseUrl?: string; // Default: 'https://api.dominusnode.com'
105
+ accessToken?: string; // Pre-existing access token
106
+ refreshToken?: string; // Pre-existing refresh token
107
+ proxyHost?: string; // Default: 'proxy.dominusnode.com'
108
+ httpProxyPort?: number; // Default: 8080
109
+ socks5ProxyPort?: number; // Default: 1080
110
+ }
111
+ ```
112
+
113
+ All fields are optional. The defaults point to the Dominus Node production endpoints.
114
+
115
+ ## Resources
116
+
117
+ The `DominusNodeClient` exposes eight resource modules, each grouping related API operations.
118
+
119
+ ### Auth
120
+
121
+ Registration, login, MFA management, password changes, and session introspection.
122
+
123
+ ```typescript
124
+ // Register a new account
125
+ const { user } = await client.auth.register('user@example.com', 'SecurePass123!');
126
+
127
+ // Login (returns token + user, or mfaRequired flag)
128
+ const result = await client.auth.login('user@example.com', 'SecurePass123!');
129
+
130
+ // MFA verify with TOTP code
131
+ await client.auth.verifyMfa('123456');
132
+
133
+ // MFA verify with backup code
134
+ await client.auth.verifyMfa('12345678', { isBackupCode: true });
135
+
136
+ // MFA setup -- returns secret, otpauthUri, and backup codes
137
+ const setup = await client.auth.mfaSetup();
138
+ // setup.secret, setup.otpauthUri, setup.backupCodes
139
+
140
+ // MFA enable (confirm with a valid TOTP code)
141
+ await client.auth.mfaEnable('123456');
142
+
143
+ // MFA disable (requires current password + TOTP code)
144
+ await client.auth.mfaDisable('password', '123456');
145
+
146
+ // MFA status
147
+ const status = await client.auth.mfaStatus();
148
+ // status.enabled, status.backupCodesRemaining
149
+
150
+ // Change password
151
+ await client.auth.changePassword('oldpass', 'newpass');
152
+
153
+ // Logout (revokes refresh tokens server-side)
154
+ await client.auth.logout();
155
+
156
+ // Session info (get current user from the JWT)
157
+ const me = await client.auth.me();
158
+ // me.user.id, me.user.email, me.user.is_admin
159
+ ```
160
+
161
+ ### Keys
162
+
163
+ Create, list, and revoke API keys. API keys use the `dn_live_` prefix and are authenticated via SHA-256 hash for fast O(1) lookup.
164
+
165
+ ```typescript
166
+ // Create a new API key
167
+ const key = await client.keys.create('my-scraper');
168
+ // key.key is the full API key (dn_live_xxx) -- shown only once, save it!
169
+ // key.id, key.prefix, key.label, key.created_at
170
+
171
+ // List all API keys (raw key is never returned after creation)
172
+ const keys = await client.keys.list();
173
+ // keys.keys[0].id, .prefix, .label, .created_at, .revoked_at
174
+
175
+ // Revoke an API key by ID
176
+ await client.keys.revoke('key-id');
177
+ ```
178
+
179
+ ### Wallet
180
+
181
+ Check balances, view transaction history, top up via Stripe or cryptocurrency, and get spending forecasts.
182
+
183
+ ```typescript
184
+ // Get current balance
185
+ const balance = await client.wallet.getBalance();
186
+ // balance.balanceCents -- integer cents (e.g., 1050)
187
+ // balance.balanceUsd -- decimal USD (e.g., 10.50)
188
+ // balance.currency -- "USD"
189
+ // balance.lastToppedUp -- ISO timestamp or null
190
+
191
+ // Transaction history (paginated)
192
+ const txs = await client.wallet.getTransactions({ limit: 50, offset: 0 });
193
+ // txs.transactions[0].type -- "topup" | "debit" | "refund"
194
+ // txs.transactions[0].amountCents -- integer cents
195
+ // txs.transactions[0].amountUsd -- decimal USD
196
+ // txs.transactions[0].description
197
+ // txs.transactions[0].createdAt
198
+
199
+ // Top up with Stripe (amount in cents)
200
+ const checkout = await client.wallet.topUpStripe(1000); // $10.00
201
+ // checkout.url -- redirect user to this Stripe Checkout URL
202
+ // checkout.sessionId -- Stripe session ID
203
+
204
+ // Top up with crypto (amount in cents, currency code)
205
+ const invoice = await client.wallet.topUpCrypto(1000, 'btc');
206
+ // invoice.invoiceId -- NOWPayments invoice ID
207
+ // invoice.invoiceUrl -- redirect user to pay
208
+ // invoice.payCurrency -- e.g., "btc"
209
+ // invoice.priceAmount -- amount in USD
210
+
211
+ // Spending forecast
212
+ const forecast = await client.wallet.getForecast();
213
+ // forecast.dailyAvgCents -- average daily spend
214
+ // forecast.daysRemaining -- estimated days until balance runs out (null if no usage)
215
+ // forecast.trend -- "up" | "down" | "stable"
216
+ // forecast.trendPct -- percentage change
217
+ ```
218
+
219
+ ### Usage
220
+
221
+ Query usage records, daily breakdowns, top hosts, and export data as CSV.
222
+
223
+ ```typescript
224
+ // Usage records with summary (paginated, filterable by date)
225
+ const usage = await client.usage.get({ from: '2024-01-01', to: '2024-01-31', limit: 100 });
226
+ // usage.summary.totalBytes, .totalCostCents, .requestCount, .totalGB, .totalCostUsd
227
+ // usage.records[0].bytesIn, .bytesOut, .totalBytes, .costCents, .targetHost, .createdAt
228
+ // usage.pagination.limit, .offset, .total
229
+ // usage.period.since, .until
230
+
231
+ // Daily breakdown (for charts)
232
+ const daily = await client.usage.getDaily({ from: '2024-01-01', to: '2024-01-31' });
233
+ // daily.days[0].date, .totalBytes, .totalGB, .totalCostCents, .totalCostUsd, .requestCount
234
+
235
+ // Top target hosts by bandwidth
236
+ const hosts = await client.usage.getTopHosts({ limit: 10 });
237
+ // hosts.hosts[0].targetHost, .totalBytes, .totalGB, .requestCount
238
+
239
+ // CSV export
240
+ const csv = await client.usage.exportCsv({ from: '2024-01-01', to: '2024-01-31' });
241
+ // csv is a raw CSV string
242
+ ```
243
+
244
+ ### Plans
245
+
246
+ List available pricing plans, view the current user's plan, and change plans.
247
+
248
+ ```typescript
249
+ // List all available plans (no auth required)
250
+ const plans = await client.plans.list();
251
+ // plans.plans[0].id, .name, .pricePerGbCents, .pricePerGbUsd,
252
+ // .monthlyBandwidthBytes, .monthlyBandwidthGB, .isDefault
253
+
254
+ // Get the current user's plan and monthly usage
255
+ const plan = await client.plans.getUserPlan();
256
+ // plan.plan -- the PlanEntry object
257
+ // plan.usage.monthlyUsageBytes, .monthlyUsageGB, .limitBytes, .limitGB, .percentUsed
258
+
259
+ // Change plan
260
+ const result = await client.plans.changePlan('vol100');
261
+ // result.message, result.plan
262
+ ```
263
+
264
+ ### Sessions
265
+
266
+ View active proxy sessions for the authenticated user.
267
+
268
+ ```typescript
269
+ // Get all active proxy sessions
270
+ const sessions = await client.sessions.getActive();
271
+ // sessions.sessions[0].id, .startedAt, .status
272
+ ```
273
+
274
+ ### Proxy
275
+
276
+ Build proxy URLs for direct use with HTTP clients, and query proxy health/status/config.
277
+
278
+ ```typescript
279
+ // Build a basic HTTP proxy URL (no network call -- pure string construction)
280
+ const httpUrl = client.proxy.buildUrl('dn_live_key');
281
+ // => http://user:dn_live_key@proxy.dominusnode.com:8080
282
+
283
+ // Build a SOCKS5 proxy URL
284
+ const socksUrl = client.proxy.buildUrl('dn_live_key', { protocol: 'socks5' });
285
+ // => socks5://user:dn_live_key@proxy.dominusnode.com:1080
286
+
287
+ // Geo-targeted with sticky session
288
+ const geoUrl = client.proxy.buildUrl('dn_live_key', {
289
+ country: 'US',
290
+ state: 'california',
291
+ city: 'losangeles',
292
+ sessionId: 'sticky123',
293
+ });
294
+ // => http://user-country_US-state_california-city_losangeles-session_sticky123:dn_live_key@proxy.dominusnode.com:8080
295
+
296
+ // ASN targeting
297
+ const asnUrl = client.proxy.buildUrl('dn_live_key', { asn: 7922 });
298
+ // => http://user-asn_7922:dn_live_key@proxy.dominusnode.com:8080
299
+
300
+ // Proxy health (no auth required)
301
+ const health = await client.proxy.getHealth();
302
+ // health.status, .activeSessions, .uptimeSeconds
303
+
304
+ // Proxy status (auth required -- includes provider info)
305
+ const status = await client.proxy.getStatus();
306
+ // status.providers[0].name, .state, .consecutiveFailures, .avgLatencyMs
307
+ // status.endpoints.http, .endpoints.socks5
308
+ // status.supportedCountries
309
+
310
+ // Proxy config (auth required)
311
+ const config = await client.proxy.getConfig();
312
+ // config.httpProxy, .socks5Proxy, .supportedCountries, .blockedCountries, .geoTargeting
313
+ ```
314
+
315
+ ### Admin (requires admin privileges)
316
+
317
+ User management, revenue analytics, and system statistics. All endpoints require the authenticated user to have `is_admin: true`.
318
+
319
+ ```typescript
320
+ // List users (paginated)
321
+ const users = await client.admin.listUsers({ page: 1, limit: 25 });
322
+ // users.users[0].id, .email, .status, .is_admin, .created_at, .balance_cents
323
+ // users.pagination.page, .limit, .total, .totalPages
324
+
325
+ // Get a specific user
326
+ const user = await client.admin.getUser('user-id');
327
+ // user.user.id, .email, .status, ...
328
+
329
+ // Suspend a user account
330
+ await client.admin.suspendUser('user-id');
331
+
332
+ // Reactivate a suspended user
333
+ await client.admin.activateUser('user-id');
334
+
335
+ // Soft-delete a user account
336
+ await client.admin.deleteUser('user-id');
337
+
338
+ // Revenue statistics (filterable by date range)
339
+ const revenue = await client.admin.getRevenue({ since: '2024-01-01', until: '2024-01-31' });
340
+ // revenue.totalRevenueCents, .totalRevenueUsd, .avgTransactionCents, .transactionCount
341
+
342
+ // Daily revenue breakdown
343
+ const daily = await client.admin.getDailyRevenue({ since: '2024-01-01', until: '2024-01-31' });
344
+ // daily.days[0].date, .revenueCents, .revenueUsd
345
+
346
+ // System-wide statistics
347
+ const stats = await client.admin.getStats();
348
+ // stats.active_sessions, .total_users, .total_bandwidth_bytes
349
+ ```
350
+
351
+ ## Error Handling
352
+
353
+ The SDK throws typed error classes instead of generic errors. Every error extends `DominusNodeError`, which itself extends the built-in `Error` class.
354
+
355
+ ```typescript
356
+ import {
357
+ DominusNodeClient,
358
+ AuthenticationError,
359
+ InsufficientBalanceError,
360
+ RateLimitError,
361
+ ValidationError,
362
+ NotFoundError,
363
+ } from '@dominusnode/sdk';
364
+
365
+ try {
366
+ await client.wallet.getBalance();
367
+ } catch (err) {
368
+ if (err instanceof AuthenticationError) {
369
+ // 401 -- not authenticated or token refresh failed
370
+ console.error('Not authenticated -- login or provide API key');
371
+ } else if (err instanceof InsufficientBalanceError) {
372
+ // 402 -- wallet balance too low
373
+ console.error('Wallet balance too low -- top up first');
374
+ } else if (err instanceof RateLimitError) {
375
+ // 429 -- rate limited (SDK already retried once automatically)
376
+ console.error(`Rate limited -- retry after ${err.retryAfterSeconds}s`);
377
+ } else if (err instanceof ValidationError) {
378
+ // 400 -- invalid request parameters
379
+ console.error(`Invalid input: ${err.message}`);
380
+ } else if (err instanceof NotFoundError) {
381
+ // 404 -- resource not found
382
+ console.error(`Not found: ${err.message}`);
383
+ }
384
+ }
385
+ ```
386
+
387
+ ### Error Hierarchy
388
+
389
+ All errors include a `statusCode` property (when applicable) and a descriptive `message`.
390
+
391
+ | Error Class | HTTP Status | Description |
392
+ |---|---|---|
393
+ | `DominusNodeError` | (varies) | Base class for all SDK errors |
394
+ | `AuthenticationError` | 401 | Invalid credentials or expired/revoked tokens |
395
+ | `AuthorizationError` | 403 | Insufficient permissions (e.g., non-admin accessing admin routes) |
396
+ | `InsufficientBalanceError` | 402 | Wallet balance too low for the operation |
397
+ | `RateLimitError` | 429 | Too many requests -- has `retryAfterSeconds` property |
398
+ | `ValidationError` | 400 | Invalid request parameters |
399
+ | `NotFoundError` | 404 | Requested resource does not exist |
400
+ | `ConflictError` | 409 | Resource conflict (e.g., duplicate email registration) |
401
+ | `ServerError` | 500+ | Server-side error |
402
+ | `NetworkError` | -- | Connection failure, DNS resolution error, or timeout |
403
+ | `ProxyError` | -- | Proxy-specific error -- has optional `proxyErrorCode` property |
404
+
405
+ ## Using the Proxy URL
406
+
407
+ The `proxy.buildUrl()` method returns a standard proxy URL string that works with any HTTP client that supports proxy configuration.
408
+
409
+ ### With undici (ProxyAgent)
410
+
411
+ ```typescript
412
+ import { DominusNodeClient } from '@dominusnode/sdk';
413
+ import { ProxyAgent } from 'undici';
414
+
415
+ const client = new DominusNodeClient({ baseUrl: 'https://api.dominusnode.com' });
416
+ await client.connectWithKey('dn_live_key');
417
+
418
+ const proxyUrl = client.proxy.buildUrl('dn_live_key', { country: 'US' });
419
+ const agent = new ProxyAgent(proxyUrl);
420
+
421
+ const response = await fetch('http://httpbin.org/ip', { dispatcher: agent });
422
+ const data = await response.json();
423
+ console.log(data.origin); // US IP address
424
+ ```
425
+
426
+ ### With curl (command line)
427
+
428
+ ```bash
429
+ curl -x http://user:dn_live_your_key@proxy.dominusnode.com:8080 http://httpbin.org/ip
430
+ curl -x http://user:dn_live_your_key@proxy.dominusnode.com:8080 https://httpbin.org/ip
431
+ ```
432
+
433
+ ### With axios
434
+
435
+ ```typescript
436
+ import axios from 'axios';
437
+ import { HttpsProxyAgent } from 'https-proxy-agent';
438
+
439
+ const proxyUrl = client.proxy.buildUrl('dn_live_key', { country: 'DE' });
440
+ const agent = new HttpsProxyAgent(proxyUrl);
441
+
442
+ const { data } = await axios.get('https://httpbin.org/ip', { httpsAgent: agent });
443
+ console.log(data.origin); // German IP address
444
+ ```
445
+
446
+ ### Geo-Targeting Options
447
+
448
+ The proxy URL username field encodes geo-targeting and session parameters using the format `user-param_value-param_value`:
449
+
450
+ | Option | Type | Description | Example |
451
+ |---|---|---|---|
452
+ | `protocol` | `"http"` or `"socks5"` | Proxy protocol (default: `"http"`) | `{ protocol: 'socks5' }` |
453
+ | `country` | `string` | ISO 3166-1 alpha-2 country code | `{ country: 'US' }` |
454
+ | `state` | `string` | State or region name | `{ state: 'california' }` |
455
+ | `city` | `string` | City name (no spaces) | `{ city: 'losangeles' }` |
456
+ | `asn` | `number` | Autonomous System Number | `{ asn: 7922 }` |
457
+ | `sessionId` | `string` | Sticky session identifier | `{ sessionId: 'abc123' }` |
458
+
459
+ ## Auto Token Refresh
460
+
461
+ The SDK automatically manages JWT token lifecycle. You do not need to handle token refresh manually.
462
+
463
+ The token refresh flow works as follows:
464
+
465
+ 1. Before each request, the SDK checks the access token's `exp` claim (decoded from base64, no crypto library needed).
466
+ 2. If the token expires within 60 seconds, the SDK proactively refreshes it using the stored refresh token.
467
+ 3. If a request returns 401, the SDK force-refreshes the token and retries the request once.
468
+ 4. Concurrent requests that trigger refresh are deduplicated -- only one refresh call is made.
469
+ 5. If the refresh token itself is expired or revoked, an `AuthenticationError` is thrown and all stored tokens are cleared.
470
+
471
+ ## TypeScript Support
472
+
473
+ All types are exported from the package. Use `import type` for type-only imports:
474
+
475
+ ```typescript
476
+ import type {
477
+ // Core types
478
+ User,
479
+ ApiKey,
480
+ Wallet,
481
+ WalletTransaction,
482
+ UsageRecord,
483
+ TopHost,
484
+ Plan,
485
+ ActiveSession,
486
+ ProxyUrlOptions,
487
+ ProxyHealth,
488
+ ProxyConfig,
489
+ StripeCheckout,
490
+ CryptoInvoice,
491
+ AdminUser,
492
+ RevenueStats,
493
+ DailyRevenue,
494
+ SystemStats,
495
+ MfaStatus,
496
+ MfaSetup,
497
+ LoginResult,
498
+ TokenPair,
499
+
500
+ // Config
501
+ DominusNodeConfig,
502
+
503
+ // Response types
504
+ WalletBalanceResponse,
505
+ TransactionsResponse,
506
+ StripeCheckoutResponse,
507
+ CryptoInvoiceResponse,
508
+ ForecastResponse,
509
+ UsageSummary,
510
+ UsageResponse,
511
+ DailyUsageDay,
512
+ DailyUsageResponse,
513
+ TopHostEntry,
514
+ TopHostsResponse,
515
+ PlanEntry,
516
+ ListPlansResponse,
517
+ UserPlanResponse,
518
+ ChangePlanResponse,
519
+ ActiveSessionEntry,
520
+ ActiveSessionsResponse,
521
+ CreateKeyResponse,
522
+ ListKeysResponse,
523
+ ProxyHealthResponse,
524
+ ProxyStatusResponse,
525
+ ListUsersResponse,
526
+ GetUserResponse,
527
+ RevenueResponse,
528
+ DailyRevenueEntry,
529
+ DailyRevenueResponse,
530
+ } from '@dominusnode/sdk';
531
+ ```
532
+
533
+ ## CommonJS Usage
534
+
535
+ The SDK ships dual CJS + ESM builds. CommonJS usage works with `require()`:
536
+
537
+ ```javascript
538
+ const { DominusNodeClient } = require('@dominusnode/sdk');
539
+
540
+ async function main() {
541
+ const client = new DominusNodeClient({ baseUrl: 'https://api.dominusnode.com' });
542
+ await client.connectWithKey('dn_live_your_key');
543
+
544
+ const balance = await client.wallet.getBalance();
545
+ console.log(`Balance: $${balance.balanceUsd}`);
546
+ }
547
+
548
+ main().catch(console.error);
549
+ ```
550
+
551
+ ## Complete Example
552
+
553
+ ```typescript
554
+ import { DominusNodeClient, AuthenticationError, InsufficientBalanceError } from '@dominusnode/sdk';
555
+
556
+ async function main() {
557
+ // Initialize client
558
+ const client = new DominusNodeClient({
559
+ baseUrl: 'https://api.dominusnode.com',
560
+ proxyHost: 'proxy.dominusnode.com',
561
+ httpProxyPort: 8080,
562
+ socks5ProxyPort: 1080,
563
+ });
564
+
565
+ try {
566
+ // Authenticate
567
+ await client.connectWithKey('dn_live_your_api_key');
568
+
569
+ // Check who we are
570
+ const { user } = await client.auth.me();
571
+ console.log(`Logged in as: ${user.email}`);
572
+
573
+ // Check balance
574
+ const balance = await client.wallet.getBalance();
575
+ console.log(`Balance: $${balance.balanceUsd} (${balance.balanceCents} cents)`);
576
+
577
+ // If balance is low, create a Stripe checkout
578
+ if (balance.balanceCents < 500) {
579
+ const checkout = await client.wallet.topUpStripe(2000); // $20.00
580
+ console.log(`Top up here: ${checkout.url}`);
581
+ }
582
+
583
+ // List API keys
584
+ const { keys } = await client.keys.list();
585
+ console.log(`You have ${keys.length} API key(s)`);
586
+
587
+ // Check current plan
588
+ const plan = await client.plans.getUserPlan();
589
+ console.log(`Plan: ${plan.plan.name} ($${plan.plan.pricePerGbUsd}/GB)`);
590
+ if (plan.usage.percentUsed !== null) {
591
+ console.log(`Monthly usage: ${plan.usage.percentUsed.toFixed(1)}%`);
592
+ }
593
+
594
+ // Get usage stats for this month
595
+ const now = new Date();
596
+ const firstOfMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01`;
597
+ const usage = await client.usage.get({ from: firstOfMonth });
598
+ console.log(`This month: ${usage.summary.totalGB.toFixed(2)} GB, $${usage.summary.totalCostUsd}`);
599
+
600
+ // Build a geo-targeted proxy URL
601
+ const proxyUrl = client.proxy.buildUrl('dn_live_your_api_key', {
602
+ country: 'US',
603
+ state: 'california',
604
+ });
605
+ console.log(`Proxy URL: ${proxyUrl}`);
606
+
607
+ // Check active sessions
608
+ const sessions = await client.sessions.getActive();
609
+ console.log(`Active sessions: ${sessions.sessions.length}`);
610
+
611
+ } catch (err) {
612
+ if (err instanceof AuthenticationError) {
613
+ console.error('Authentication failed:', err.message);
614
+ } else if (err instanceof InsufficientBalanceError) {
615
+ console.error('Insufficient balance:', err.message);
616
+ } else {
617
+ throw err;
618
+ }
619
+ } finally {
620
+ client.disconnect();
621
+ }
622
+ }
623
+
624
+ main();
625
+ ```
626
+
627
+ ## API Reference Summary
628
+
629
+ | Resource | Method | Description |
630
+ |---|---|---|
631
+ | `auth` | `register(email, password)` | Create a new account |
632
+ | `auth` | `login(email, password)` | Login with credentials |
633
+ | `auth` | `verifyMfa(code, opts?)` | Complete MFA verification |
634
+ | `auth` | `mfaSetup()` | Begin MFA setup (returns secret + backup codes) |
635
+ | `auth` | `mfaEnable(code)` | Confirm and enable MFA |
636
+ | `auth` | `mfaDisable(password, code)` | Disable MFA |
637
+ | `auth` | `mfaStatus()` | Check MFA status |
638
+ | `auth` | `changePassword(current, new)` | Change password |
639
+ | `auth` | `logout()` | Revoke refresh tokens server-side |
640
+ | `auth` | `me()` | Get current user info |
641
+ | `auth` | `verifyKey(apiKey)` | Exchange API key for JWT tokens |
642
+ | `auth` | `refresh(refreshToken)` | Refresh access token (used internally) |
643
+ | `keys` | `create(label?)` | Create a new API key |
644
+ | `keys` | `list()` | List all API keys |
645
+ | `keys` | `revoke(id)` | Revoke an API key |
646
+ | `wallet` | `getBalance()` | Get current balance |
647
+ | `wallet` | `getTransactions(opts?)` | Transaction history (paginated) |
648
+ | `wallet` | `topUpStripe(amountCents)` | Create Stripe checkout session |
649
+ | `wallet` | `topUpCrypto(amountCents, currency)` | Create crypto invoice |
650
+ | `wallet` | `getForecast()` | Spending forecast |
651
+ | `usage` | `get(opts?)` | Usage records with summary |
652
+ | `usage` | `getDaily(opts?)` | Daily usage aggregation |
653
+ | `usage` | `getTopHosts(opts?)` | Top target hosts by bandwidth |
654
+ | `usage` | `exportCsv(opts?)` | Export usage as CSV |
655
+ | `plans` | `list()` | List available plans |
656
+ | `plans` | `getUserPlan()` | Get current user's plan |
657
+ | `plans` | `changePlan(planId)` | Change plan |
658
+ | `sessions` | `getActive()` | Get active proxy sessions |
659
+ | `proxy` | `buildUrl(apiKey, opts?)` | Build proxy URL string (no network call) |
660
+ | `proxy` | `getHealth()` | Proxy health (no auth) |
661
+ | `proxy` | `getStatus()` | Proxy status with provider info |
662
+ | `proxy` | `getConfig()` | Proxy configuration |
663
+ | `admin` | `listUsers(opts?)` | List all users (paginated) |
664
+ | `admin` | `getUser(id)` | Get user details |
665
+ | `admin` | `suspendUser(id)` | Suspend a user |
666
+ | `admin` | `activateUser(id)` | Reactivate a user |
667
+ | `admin` | `deleteUser(id)` | Soft-delete a user |
668
+ | `admin` | `getRevenue(opts?)` | Revenue statistics |
669
+ | `admin` | `getDailyRevenue(opts?)` | Daily revenue breakdown |
670
+ | `admin` | `getStats()` | System-wide statistics |
671
+
672
+ ## Requirements
673
+
674
+ - **Node.js 18+** (uses built-in `fetch` -- no polyfill needed)
675
+ - **No external dependencies** -- the SDK has zero production dependencies
676
+
677
+ ## License
678
+
679
+ MIT