@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.
- package/LICENSE +21 -0
- package/README.md +679 -0
- package/dist/cjs/admin.d.ts +71 -0
- package/dist/cjs/admin.js +60 -0
- package/dist/cjs/auth.d.ts +47 -0
- package/dist/cjs/auth.js +46 -0
- package/dist/cjs/client.d.ts +56 -0
- package/dist/cjs/client.js +109 -0
- package/dist/cjs/constants.d.ts +8 -0
- package/dist/cjs/constants.js +11 -0
- package/dist/cjs/errors.d.ts +36 -0
- package/dist/cjs/errors.js +86 -0
- package/dist/cjs/http.d.ts +19 -0
- package/dist/cjs/http.js +195 -0
- package/dist/cjs/index.d.ts +30 -0
- package/dist/cjs/index.js +58 -0
- package/dist/cjs/keys.d.ts +27 -0
- package/dist/cjs/keys.js +22 -0
- package/dist/cjs/plans.d.ts +37 -0
- package/dist/cjs/plans.js +22 -0
- package/dist/cjs/proxy.d.ts +62 -0
- package/dist/cjs/proxy.js +71 -0
- package/dist/cjs/resources/agent-wallet.d.ts +52 -0
- package/dist/cjs/resources/agent-wallet.js +64 -0
- package/dist/cjs/resources/teams.d.ts +93 -0
- package/dist/cjs/resources/teams.js +82 -0
- package/dist/cjs/resources/wallet-auth.d.ts +66 -0
- package/dist/cjs/resources/wallet-auth.js +105 -0
- package/dist/cjs/resources/x402.d.ts +39 -0
- package/dist/cjs/resources/x402.js +25 -0
- package/dist/cjs/sessions.d.ts +15 -0
- package/dist/cjs/sessions.js +14 -0
- package/dist/cjs/slots.d.ts +9 -0
- package/dist/cjs/slots.js +19 -0
- package/dist/cjs/token-manager.d.ts +21 -0
- package/dist/cjs/token-manager.js +105 -0
- package/dist/cjs/types.d.ts +154 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/usage.d.ts +80 -0
- package/dist/cjs/usage.js +56 -0
- package/dist/cjs/wallet.d.ts +59 -0
- package/dist/cjs/wallet.js +56 -0
- package/dist/esm/admin.d.ts +71 -0
- package/dist/esm/admin.js +56 -0
- package/dist/esm/auth.d.ts +47 -0
- package/dist/esm/auth.js +42 -0
- package/dist/esm/client.d.ts +56 -0
- package/dist/esm/client.js +105 -0
- package/dist/esm/constants.d.ts +8 -0
- package/dist/esm/constants.js +8 -0
- package/dist/esm/errors.d.ts +36 -0
- package/dist/esm/errors.js +72 -0
- package/dist/esm/http.d.ts +19 -0
- package/dist/esm/http.js +191 -0
- package/dist/esm/index.d.ts +30 -0
- package/dist/esm/index.js +23 -0
- package/dist/esm/keys.d.ts +27 -0
- package/dist/esm/keys.js +18 -0
- package/dist/esm/plans.d.ts +37 -0
- package/dist/esm/plans.js +18 -0
- package/dist/esm/proxy.d.ts +62 -0
- package/dist/esm/proxy.js +67 -0
- package/dist/esm/resources/agent-wallet.d.ts +52 -0
- package/dist/esm/resources/agent-wallet.js +60 -0
- package/dist/esm/resources/teams.d.ts +93 -0
- package/dist/esm/resources/teams.js +78 -0
- package/dist/esm/resources/wallet-auth.d.ts +66 -0
- package/dist/esm/resources/wallet-auth.js +101 -0
- package/dist/esm/resources/x402.d.ts +39 -0
- package/dist/esm/resources/x402.js +21 -0
- package/dist/esm/sessions.d.ts +15 -0
- package/dist/esm/sessions.js +10 -0
- package/dist/esm/slots.d.ts +9 -0
- package/dist/esm/slots.js +15 -0
- package/dist/esm/token-manager.d.ts +21 -0
- package/dist/esm/token-manager.js +101 -0
- package/dist/esm/types.d.ts +154 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/usage.d.ts +80 -0
- package/dist/esm/usage.js +52 -0
- package/dist/esm/wallet.d.ts +59 -0
- package/dist/esm/wallet.js +52 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { TokenManager } from "./token-manager.js";
|
|
2
|
+
import { HttpClient } from "./http.js";
|
|
3
|
+
import { AuthResource } from "./auth.js";
|
|
4
|
+
import { KeysResource } from "./keys.js";
|
|
5
|
+
import { WalletResource } from "./wallet.js";
|
|
6
|
+
import { UsageResource } from "./usage.js";
|
|
7
|
+
import { PlansResource } from "./plans.js";
|
|
8
|
+
import { SessionsResource } from "./sessions.js";
|
|
9
|
+
import { ProxyResource } from "./proxy.js";
|
|
10
|
+
import { AdminResource } from "./admin.js";
|
|
11
|
+
import { SlotsResource } from "./slots.js";
|
|
12
|
+
import { AgenticWalletResource } from "./resources/agent-wallet.js";
|
|
13
|
+
import { TeamsResource } from "./resources/teams.js";
|
|
14
|
+
import { X402Resource } from "./resources/x402.js";
|
|
15
|
+
import { WalletAuthResource } from "./resources/wallet-auth.js";
|
|
16
|
+
import { DEFAULT_BASE_URL } from "./constants.js";
|
|
17
|
+
export class DominusNodeClient {
|
|
18
|
+
auth;
|
|
19
|
+
keys;
|
|
20
|
+
wallet;
|
|
21
|
+
usage;
|
|
22
|
+
plans;
|
|
23
|
+
sessions;
|
|
24
|
+
proxy;
|
|
25
|
+
admin;
|
|
26
|
+
slots;
|
|
27
|
+
agenticWallets;
|
|
28
|
+
teams;
|
|
29
|
+
x402;
|
|
30
|
+
walletAuth;
|
|
31
|
+
tokenManager;
|
|
32
|
+
http;
|
|
33
|
+
apiKey = null;
|
|
34
|
+
constructor(config = {}) {
|
|
35
|
+
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
36
|
+
this.tokenManager = new TokenManager();
|
|
37
|
+
this.http = new HttpClient(baseUrl, this.tokenManager);
|
|
38
|
+
// Initialize all resource modules BEFORE setting refresh function
|
|
39
|
+
// this.auth must exist before refresh function can be invoked
|
|
40
|
+
this.auth = new AuthResource(this.http);
|
|
41
|
+
this.keys = new KeysResource(this.http);
|
|
42
|
+
this.wallet = new WalletResource(this.http);
|
|
43
|
+
this.usage = new UsageResource(this.http);
|
|
44
|
+
this.plans = new PlansResource(this.http);
|
|
45
|
+
this.sessions = new SessionsResource(this.http);
|
|
46
|
+
this.proxy = new ProxyResource(this.http, config);
|
|
47
|
+
this.admin = new AdminResource(this.http);
|
|
48
|
+
this.slots = new SlotsResource(this.http);
|
|
49
|
+
this.agenticWallets = new AgenticWalletResource(this.http);
|
|
50
|
+
this.teams = new TeamsResource(this.http);
|
|
51
|
+
this.x402 = new X402Resource(this.http);
|
|
52
|
+
this.walletAuth = new WalletAuthResource(this.http, this.tokenManager);
|
|
53
|
+
// Set refresh function AFTER auth is initialized
|
|
54
|
+
this.tokenManager.setRefreshFunction(async (rt) => {
|
|
55
|
+
const res = await this.auth.refresh(rt);
|
|
56
|
+
return { accessToken: res.token, refreshToken: res.refreshToken };
|
|
57
|
+
});
|
|
58
|
+
// Auto-authenticate if tokens were provided in config
|
|
59
|
+
if (config.accessToken) {
|
|
60
|
+
this.tokenManager.setTokens(config.accessToken, config.refreshToken);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Authenticate with an API key.
|
|
65
|
+
* Verifies the key against the server and stores the resulting JWT tokens
|
|
66
|
+
* for subsequent authenticated requests.
|
|
67
|
+
*/
|
|
68
|
+
async connectWithKey(apiKey) {
|
|
69
|
+
const res = await this.auth.verifyKey(apiKey);
|
|
70
|
+
this.apiKey = apiKey;
|
|
71
|
+
this.tokenManager.setTokens(res.token, res.refreshToken);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Authenticate with email and password.
|
|
75
|
+
* If MFA is required, the returned result will have `mfaRequired: true`.
|
|
76
|
+
* Call `completeMfa()` to finish authentication in that case.
|
|
77
|
+
*/
|
|
78
|
+
async connectWithCredentials(email, password) {
|
|
79
|
+
const res = await this.auth.login(email, password);
|
|
80
|
+
if (res.token) {
|
|
81
|
+
this.tokenManager.setTokens(res.token, res.refreshToken);
|
|
82
|
+
}
|
|
83
|
+
return { user: res.user, mfaRequired: res.mfaRequired };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Complete MFA verification after a login that returned `mfaRequired: true`.
|
|
87
|
+
*/
|
|
88
|
+
async completeMfa(code, opts) {
|
|
89
|
+
const res = await this.auth.verifyMfa(code, opts);
|
|
90
|
+
this.tokenManager.setTokens(res.token, res.refreshToken);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Disconnect: revoke refresh tokens server-side (best-effort) and clear all stored tokens.
|
|
94
|
+
*/
|
|
95
|
+
async disconnect() {
|
|
96
|
+
try {
|
|
97
|
+
await this.auth.logout();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Best-effort — server may be unreachable
|
|
101
|
+
}
|
|
102
|
+
this.apiKey = null;
|
|
103
|
+
this.tokenManager.clear();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const SDK_VERSION = "1.0.0";
|
|
2
|
+
export declare const USER_AGENT = "dominusnode-sdk-node/1.0.0";
|
|
3
|
+
export declare const DEFAULT_BASE_URL = "https://api.dominusnode.com";
|
|
4
|
+
export declare const DEFAULT_PROXY_HOST = "proxy.dominusnode.com";
|
|
5
|
+
export declare const DEFAULT_HTTP_PROXY_PORT = 8080;
|
|
6
|
+
export declare const DEFAULT_SOCKS5_PROXY_PORT = 1080;
|
|
7
|
+
export declare const TOKEN_REFRESH_BUFFER_MS = 60000;
|
|
8
|
+
export declare const MAX_RATE_LIMIT_RETRIES = 1;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const SDK_VERSION = "1.0.0";
|
|
2
|
+
export const USER_AGENT = `dominusnode-sdk-node/${SDK_VERSION}`;
|
|
3
|
+
export const DEFAULT_BASE_URL = "https://api.dominusnode.com";
|
|
4
|
+
export const DEFAULT_PROXY_HOST = "proxy.dominusnode.com";
|
|
5
|
+
export const DEFAULT_HTTP_PROXY_PORT = 8080;
|
|
6
|
+
export const DEFAULT_SOCKS5_PROXY_PORT = 1080;
|
|
7
|
+
export const TOKEN_REFRESH_BUFFER_MS = 60_000; // Refresh 60s before expiry
|
|
8
|
+
export const MAX_RATE_LIMIT_RETRIES = 1;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export declare class DominusNodeError extends Error {
|
|
2
|
+
readonly statusCode?: number | undefined;
|
|
3
|
+
constructor(message: string, statusCode?: number | undefined);
|
|
4
|
+
}
|
|
5
|
+
export declare class AuthenticationError extends DominusNodeError {
|
|
6
|
+
constructor(message?: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class AuthorizationError extends DominusNodeError {
|
|
9
|
+
constructor(message?: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class RateLimitError extends DominusNodeError {
|
|
12
|
+
readonly retryAfterSeconds: number;
|
|
13
|
+
constructor(message?: string, retryAfter?: number);
|
|
14
|
+
}
|
|
15
|
+
export declare class InsufficientBalanceError extends DominusNodeError {
|
|
16
|
+
constructor(message?: string);
|
|
17
|
+
}
|
|
18
|
+
export declare class ValidationError extends DominusNodeError {
|
|
19
|
+
constructor(message?: string);
|
|
20
|
+
}
|
|
21
|
+
export declare class NotFoundError extends DominusNodeError {
|
|
22
|
+
constructor(message?: string);
|
|
23
|
+
}
|
|
24
|
+
export declare class ConflictError extends DominusNodeError {
|
|
25
|
+
constructor(message?: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class ServerError extends DominusNodeError {
|
|
28
|
+
constructor(message?: string);
|
|
29
|
+
}
|
|
30
|
+
export declare class NetworkError extends DominusNodeError {
|
|
31
|
+
constructor(message?: string);
|
|
32
|
+
}
|
|
33
|
+
export declare class ProxyError extends DominusNodeError {
|
|
34
|
+
readonly proxyErrorCode?: string;
|
|
35
|
+
constructor(message: string, proxyErrorCode?: string);
|
|
36
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export class DominusNodeError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
constructor(message, statusCode) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.statusCode = statusCode;
|
|
6
|
+
this.name = "DominusNodeError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class AuthenticationError extends DominusNodeError {
|
|
10
|
+
constructor(message = "Authentication failed") {
|
|
11
|
+
super(message, 401);
|
|
12
|
+
this.name = "AuthenticationError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class AuthorizationError extends DominusNodeError {
|
|
16
|
+
constructor(message = "Access denied") {
|
|
17
|
+
super(message, 403);
|
|
18
|
+
this.name = "AuthorizationError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class RateLimitError extends DominusNodeError {
|
|
22
|
+
retryAfterSeconds;
|
|
23
|
+
constructor(message = "Rate limit exceeded", retryAfter = 60) {
|
|
24
|
+
super(message, 429);
|
|
25
|
+
this.name = "RateLimitError";
|
|
26
|
+
this.retryAfterSeconds = retryAfter;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class InsufficientBalanceError extends DominusNodeError {
|
|
30
|
+
constructor(message = "Insufficient balance") {
|
|
31
|
+
super(message, 402);
|
|
32
|
+
this.name = "InsufficientBalanceError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class ValidationError extends DominusNodeError {
|
|
36
|
+
constructor(message = "Validation failed") {
|
|
37
|
+
super(message, 400);
|
|
38
|
+
this.name = "ValidationError";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class NotFoundError extends DominusNodeError {
|
|
42
|
+
constructor(message = "Resource not found") {
|
|
43
|
+
super(message, 404);
|
|
44
|
+
this.name = "NotFoundError";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class ConflictError extends DominusNodeError {
|
|
48
|
+
constructor(message = "Resource conflict") {
|
|
49
|
+
super(message, 409);
|
|
50
|
+
this.name = "ConflictError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export class ServerError extends DominusNodeError {
|
|
54
|
+
constructor(message = "Server error") {
|
|
55
|
+
super(message, 500);
|
|
56
|
+
this.name = "ServerError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class NetworkError extends DominusNodeError {
|
|
60
|
+
constructor(message = "Network error") {
|
|
61
|
+
super(message);
|
|
62
|
+
this.name = "NetworkError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export class ProxyError extends DominusNodeError {
|
|
66
|
+
proxyErrorCode;
|
|
67
|
+
constructor(message, proxyErrorCode) {
|
|
68
|
+
super(message);
|
|
69
|
+
this.name = "ProxyError";
|
|
70
|
+
this.proxyErrorCode = proxyErrorCode;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TokenManager } from "./token-manager.js";
|
|
2
|
+
export interface HttpOptions {
|
|
3
|
+
method: string;
|
|
4
|
+
path: string;
|
|
5
|
+
body?: unknown;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
requiresAuth?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class HttpClient {
|
|
10
|
+
private baseUrl;
|
|
11
|
+
private tokenManager;
|
|
12
|
+
constructor(baseUrl: string, tokenManager: TokenManager);
|
|
13
|
+
request<T>(opts: HttpOptions): Promise<T>;
|
|
14
|
+
get<T>(path: string, requiresAuth?: boolean): Promise<T>;
|
|
15
|
+
post<T>(path: string, body?: unknown, requiresAuth?: boolean): Promise<T>;
|
|
16
|
+
put<T>(path: string, body?: unknown): Promise<T>;
|
|
17
|
+
patch<T>(path: string, body?: unknown): Promise<T>;
|
|
18
|
+
delete<T>(path: string): Promise<T>;
|
|
19
|
+
}
|
package/dist/esm/http.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { USER_AGENT } from "./constants.js";
|
|
2
|
+
import { DominusNodeError, AuthenticationError, AuthorizationError, RateLimitError, InsufficientBalanceError, ValidationError, NotFoundError, ConflictError, ServerError, NetworkError, } from "./errors.js";
|
|
3
|
+
// Sanitize parsed JSON to prevent prototype pollution from untrusted API responses
|
|
4
|
+
// Recursive prototype pollution stripping (covers nested objects too)
|
|
5
|
+
const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
6
|
+
// Depth limit prevents stack overflow on deeply nested JSON
|
|
7
|
+
function stripDangerousKeys(obj, depth = 0) {
|
|
8
|
+
if (depth > 50 || !obj || typeof obj !== "object")
|
|
9
|
+
return;
|
|
10
|
+
if (Array.isArray(obj)) {
|
|
11
|
+
for (const item of obj)
|
|
12
|
+
stripDangerousKeys(item, depth + 1);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const record = obj;
|
|
16
|
+
for (const key of Object.keys(record)) {
|
|
17
|
+
if (DANGEROUS_KEYS.has(key)) {
|
|
18
|
+
delete record[key];
|
|
19
|
+
}
|
|
20
|
+
else if (record[key] && typeof record[key] === "object") {
|
|
21
|
+
stripDangerousKeys(record[key], depth + 1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function safeJsonParse(text) {
|
|
26
|
+
const parsed = JSON.parse(text);
|
|
27
|
+
stripDangerousKeys(parsed);
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
// Add jitter to retry delays to prevent thundering-herd on rate-limited endpoints
|
|
31
|
+
function addJitter(ms) {
|
|
32
|
+
const jitter = ms * 0.2 * (Math.random() - 0.5); // ±10% jitter
|
|
33
|
+
return Math.max(100, Math.round(ms + jitter));
|
|
34
|
+
}
|
|
35
|
+
function throwForStatus(status, body, headers) {
|
|
36
|
+
let message;
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(body);
|
|
39
|
+
message = parsed.error ?? parsed.message ?? body;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
message = body;
|
|
43
|
+
}
|
|
44
|
+
// Truncate error message to prevent unbounded body in exception strings
|
|
45
|
+
if (message.length > 500)
|
|
46
|
+
message = message.slice(0, 500) + "... [truncated]";
|
|
47
|
+
switch (status) {
|
|
48
|
+
case 400: throw new ValidationError(message);
|
|
49
|
+
case 401: throw new AuthenticationError(message);
|
|
50
|
+
case 402: throw new InsufficientBalanceError(message);
|
|
51
|
+
case 403: throw new AuthorizationError(message);
|
|
52
|
+
case 404: throw new NotFoundError(message);
|
|
53
|
+
case 409: throw new ConflictError(message);
|
|
54
|
+
case 429: {
|
|
55
|
+
const parsed = parseInt(headers.get("retry-after") ?? "60", 10);
|
|
56
|
+
const retryAfter = Number.isFinite(parsed) ? parsed : 60; // NaN guard
|
|
57
|
+
throw new RateLimitError(message, retryAfter);
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
if (status >= 500)
|
|
61
|
+
throw new ServerError(message);
|
|
62
|
+
throw new DominusNodeError(message, status);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Max response body size to prevent OOM from malicious/large API responses
|
|
66
|
+
const MAX_RESPONSE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
67
|
+
export class HttpClient {
|
|
68
|
+
baseUrl;
|
|
69
|
+
tokenManager;
|
|
70
|
+
constructor(baseUrl, tokenManager) {
|
|
71
|
+
this.baseUrl = baseUrl;
|
|
72
|
+
this.tokenManager = tokenManager;
|
|
73
|
+
}
|
|
74
|
+
async request(opts) {
|
|
75
|
+
const headers = {
|
|
76
|
+
"User-Agent": USER_AGENT,
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
...opts.headers,
|
|
79
|
+
};
|
|
80
|
+
if (opts.requiresAuth !== false) {
|
|
81
|
+
const token = await this.tokenManager.getValidToken();
|
|
82
|
+
// Guard against null/empty token to prevent "Bearer " header
|
|
83
|
+
if (!token) {
|
|
84
|
+
throw new Error("No valid token available. Call connectWithKey() or login() first.");
|
|
85
|
+
}
|
|
86
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
87
|
+
}
|
|
88
|
+
const url = `${this.baseUrl}${opts.path}`;
|
|
89
|
+
let response;
|
|
90
|
+
const timeoutMs = 30_000; // 30s request timeout
|
|
91
|
+
try {
|
|
92
|
+
response = await fetch(url, {
|
|
93
|
+
method: opts.method,
|
|
94
|
+
headers,
|
|
95
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
96
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
97
|
+
redirect: "error", // Reject redirects — prevents HTTPS→HTTP credential leakage
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
throw new NetworkError(err instanceof Error ? err.message : "Network request failed");
|
|
102
|
+
}
|
|
103
|
+
if (response.status === 429) {
|
|
104
|
+
// Auto-retry once on rate limit (cap wait at 10s to avoid client-side DoS)
|
|
105
|
+
const parsed = parseInt(response.headers.get("retry-after") ?? "5", 10);
|
|
106
|
+
const retryAfter = Number.isFinite(parsed) ? parsed : 5; // NaN guard
|
|
107
|
+
// Cancel body stream instead of buffering — prevents OOM from large 429 responses
|
|
108
|
+
await response.body?.cancel();
|
|
109
|
+
await new Promise((resolve) => setTimeout(resolve, addJitter(Math.min(retryAfter * 1000, 10_000))));
|
|
110
|
+
// Refresh token before retry in case it expired during the wait
|
|
111
|
+
if (opts.requiresAuth !== false) {
|
|
112
|
+
const freshToken = await this.tokenManager.getValidToken();
|
|
113
|
+
headers["Authorization"] = `Bearer ${freshToken}`;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
response = await fetch(url, {
|
|
117
|
+
method: opts.method,
|
|
118
|
+
headers,
|
|
119
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
120
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
121
|
+
redirect: "error",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
throw new NetworkError(err instanceof Error ? err.message : "Network request failed");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (response.status === 401 && opts.requiresAuth !== false) {
|
|
129
|
+
// Cancel body stream before retry to prevent memory leak from unconsumed response
|
|
130
|
+
await response.body?.cancel();
|
|
131
|
+
// Force a token refresh (don't reuse the rejected token) and retry once
|
|
132
|
+
try {
|
|
133
|
+
const newToken = await this.tokenManager.forceRefresh();
|
|
134
|
+
headers["Authorization"] = `Bearer ${newToken}`;
|
|
135
|
+
const retry = await fetch(url, {
|
|
136
|
+
method: opts.method,
|
|
137
|
+
headers,
|
|
138
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
139
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
140
|
+
redirect: "error",
|
|
141
|
+
});
|
|
142
|
+
// Apply response size limit to 401 retry path too
|
|
143
|
+
const retryContentLength = parseInt(retry.headers.get("content-length") ?? "0", 10);
|
|
144
|
+
if (retryContentLength > MAX_RESPONSE_BYTES) {
|
|
145
|
+
throw new ServerError("Response body too large");
|
|
146
|
+
}
|
|
147
|
+
const retryText = await retry.text();
|
|
148
|
+
if (retryText.length > MAX_RESPONSE_BYTES) {
|
|
149
|
+
throw new ServerError("Response body exceeds size limit");
|
|
150
|
+
}
|
|
151
|
+
if (retry.ok) {
|
|
152
|
+
return retryText ? safeJsonParse(retryText) : {};
|
|
153
|
+
}
|
|
154
|
+
throwForStatus(retry.status, retryText, retry.headers);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
if (err instanceof DominusNodeError)
|
|
158
|
+
throw err;
|
|
159
|
+
// Refresh failed — fall through to original 401 handling
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Enforce response body size limit to prevent OOM
|
|
163
|
+
const contentLength = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
164
|
+
if (contentLength > MAX_RESPONSE_BYTES) {
|
|
165
|
+
throw new ServerError("Response body too large");
|
|
166
|
+
}
|
|
167
|
+
const responseText = await response.text();
|
|
168
|
+
if (responseText.length > MAX_RESPONSE_BYTES) {
|
|
169
|
+
throw new ServerError("Response body exceeds size limit");
|
|
170
|
+
}
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
throwForStatus(response.status, responseText, response.headers);
|
|
173
|
+
}
|
|
174
|
+
return responseText ? safeJsonParse(responseText) : {};
|
|
175
|
+
}
|
|
176
|
+
async get(path, requiresAuth = true) {
|
|
177
|
+
return this.request({ method: "GET", path, requiresAuth });
|
|
178
|
+
}
|
|
179
|
+
async post(path, body, requiresAuth = true) {
|
|
180
|
+
return this.request({ method: "POST", path, body, requiresAuth });
|
|
181
|
+
}
|
|
182
|
+
async put(path, body) {
|
|
183
|
+
return this.request({ method: "PUT", path, body });
|
|
184
|
+
}
|
|
185
|
+
async patch(path, body) {
|
|
186
|
+
return this.request({ method: "PATCH", path, body });
|
|
187
|
+
}
|
|
188
|
+
async delete(path) {
|
|
189
|
+
return this.request({ method: "DELETE", path });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { DominusNodeClient } from "./client.js";
|
|
2
|
+
export { AuthResource } from "./auth.js";
|
|
3
|
+
export { KeysResource } from "./keys.js";
|
|
4
|
+
export type { CreateKeyResponse, ListKeysResponse } from "./keys.js";
|
|
5
|
+
export { WalletResource } from "./wallet.js";
|
|
6
|
+
export type { WalletBalanceResponse, TransactionsResponse, StripeCheckoutResponse, CryptoInvoiceResponse, ForecastResponse, } from "./wallet.js";
|
|
7
|
+
export { UsageResource } from "./usage.js";
|
|
8
|
+
export type { DateRangeOptions as UsageDateRangeOptions, UsageSummary, UsageResponse, DailyUsageDay, DailyUsageResponse, TopHostEntry, TopHostsResponse, } from "./usage.js";
|
|
9
|
+
export { PlansResource } from "./plans.js";
|
|
10
|
+
export type { PlanEntry, ListPlansResponse, UserPlanResponse, ChangePlanResponse, } from "./plans.js";
|
|
11
|
+
export { SessionsResource } from "./sessions.js";
|
|
12
|
+
export type { ActiveSessionEntry, ActiveSessionsResponse } from "./sessions.js";
|
|
13
|
+
export { ProxyResource } from "./proxy.js";
|
|
14
|
+
export type { ProxyHealthResponse, ProxyStatusResponse } from "./proxy.js";
|
|
15
|
+
export { AdminResource } from "./admin.js";
|
|
16
|
+
export { SlotsResource } from "./slots.js";
|
|
17
|
+
export { AgenticWalletResource } from "./resources/agent-wallet.js";
|
|
18
|
+
export type { AgenticWallet, AgenticWalletTransaction, AgenticWalletListResponse, AgenticWalletFundResponse, AgenticWalletTransactionsResponse, AgenticWalletDeleteResponse, } from "./resources/agent-wallet.js";
|
|
19
|
+
export { TeamsResource } from "./resources/teams.js";
|
|
20
|
+
export type { Team, TeamMember, TeamInvite, TeamListResponse, TeamMembersResponse, TeamInvitesResponse, TeamKeysResponse, TeamKeyCreateResponse, TeamDeleteResponse, TeamFundResponse, TeamTransactionsResponse, } from "./resources/teams.js";
|
|
21
|
+
export { X402Resource } from "./resources/x402.js";
|
|
22
|
+
export type { X402Info, X402Facilitator, X402Pricing, } from "./resources/x402.js";
|
|
23
|
+
export { WalletAuthResource } from "./resources/wallet-auth.js";
|
|
24
|
+
export type { WalletChallenge, WalletVerifyResult, WalletLinkResult, } from "./resources/wallet-auth.js";
|
|
25
|
+
export type { DateRangeOptions as AdminDateRangeOptions, ListUsersResponse, GetUserResponse, RevenueResponse, DailyRevenueEntry, DailyRevenueResponse, } from "./admin.js";
|
|
26
|
+
export { HttpClient } from "./http.js";
|
|
27
|
+
export type { HttpOptions } from "./http.js";
|
|
28
|
+
export { DominusNodeError, AuthenticationError, AuthorizationError, RateLimitError, InsufficientBalanceError, ValidationError, NotFoundError, ConflictError, ServerError, NetworkError, ProxyError, } from "./errors.js";
|
|
29
|
+
export type { DominusNodeConfig, User, ApiKey, Wallet, WalletTransaction, UsageRecord, TopHost, Plan, ActiveSession, ProxyUrlOptions, ProxyHealth, ProxyConfig, StripeCheckout, CryptoInvoice, AdminUser, RevenueStats, DailyRevenue, SystemStats, MfaStatus, MfaSetup, LoginResult, TokenPair, SlotsInfo, WaitlistJoinResult, WaitlistCount, } from "./types.js";
|
|
30
|
+
export { SDK_VERSION, USER_AGENT, DEFAULT_BASE_URL, DEFAULT_PROXY_HOST, DEFAULT_HTTP_PROXY_PORT, DEFAULT_SOCKS5_PROXY_PORT, } from "./constants.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Main client
|
|
2
|
+
export { DominusNodeClient } from "./client.js";
|
|
3
|
+
// Resource modules
|
|
4
|
+
export { AuthResource } from "./auth.js";
|
|
5
|
+
export { KeysResource } from "./keys.js";
|
|
6
|
+
export { WalletResource } from "./wallet.js";
|
|
7
|
+
export { UsageResource } from "./usage.js";
|
|
8
|
+
export { PlansResource } from "./plans.js";
|
|
9
|
+
export { SessionsResource } from "./sessions.js";
|
|
10
|
+
export { ProxyResource } from "./proxy.js";
|
|
11
|
+
export { AdminResource } from "./admin.js";
|
|
12
|
+
export { SlotsResource } from "./slots.js";
|
|
13
|
+
export { AgenticWalletResource } from "./resources/agent-wallet.js";
|
|
14
|
+
export { TeamsResource } from "./resources/teams.js";
|
|
15
|
+
export { X402Resource } from "./resources/x402.js";
|
|
16
|
+
export { WalletAuthResource } from "./resources/wallet-auth.js";
|
|
17
|
+
// Infrastructure (HttpClient for advanced custom integrations)
|
|
18
|
+
export { HttpClient } from "./http.js";
|
|
19
|
+
// TokenManager is internal — not exported to prevent misuse of token lifecycle
|
|
20
|
+
// Errors
|
|
21
|
+
export { DominusNodeError, AuthenticationError, AuthorizationError, RateLimitError, InsufficientBalanceError, ValidationError, NotFoundError, ConflictError, ServerError, NetworkError, ProxyError, } from "./errors.js";
|
|
22
|
+
// Constants
|
|
23
|
+
export { SDK_VERSION, USER_AGENT, DEFAULT_BASE_URL, DEFAULT_PROXY_HOST, DEFAULT_HTTP_PROXY_PORT, DEFAULT_SOCKS5_PROXY_PORT, } from "./constants.js";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HttpClient } from "./http.js";
|
|
2
|
+
export interface CreateKeyResponse {
|
|
3
|
+
key: string;
|
|
4
|
+
id: string;
|
|
5
|
+
prefix: string;
|
|
6
|
+
label: string;
|
|
7
|
+
created_at: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ListKeysResponse {
|
|
10
|
+
keys: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
prefix: string;
|
|
13
|
+
label: string;
|
|
14
|
+
created_at: string;
|
|
15
|
+
revoked_at: string | null;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export declare class KeysResource {
|
|
19
|
+
private http;
|
|
20
|
+
constructor(http: HttpClient);
|
|
21
|
+
/** Create a new API key. The raw key is returned only once. */
|
|
22
|
+
create(label?: string): Promise<CreateKeyResponse>;
|
|
23
|
+
/** List all API keys for the authenticated user. */
|
|
24
|
+
list(): Promise<ListKeysResponse>;
|
|
25
|
+
/** Revoke an API key by its ID. */
|
|
26
|
+
revoke(id: string): Promise<void>;
|
|
27
|
+
}
|
package/dist/esm/keys.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class KeysResource {
|
|
2
|
+
http;
|
|
3
|
+
constructor(http) {
|
|
4
|
+
this.http = http;
|
|
5
|
+
}
|
|
6
|
+
/** Create a new API key. The raw key is returned only once. */
|
|
7
|
+
async create(label) {
|
|
8
|
+
return this.http.post("/api/keys", { label: label ?? "Default" });
|
|
9
|
+
}
|
|
10
|
+
/** List all API keys for the authenticated user. */
|
|
11
|
+
async list() {
|
|
12
|
+
return this.http.get("/api/keys");
|
|
13
|
+
}
|
|
14
|
+
/** Revoke an API key by its ID. */
|
|
15
|
+
async revoke(id) {
|
|
16
|
+
await this.http.delete(`/api/keys/${encodeURIComponent(id)}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HttpClient } from "./http.js";
|
|
2
|
+
export interface PlanEntry {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
pricePerGbCents: number;
|
|
6
|
+
pricePerGbUsd: number;
|
|
7
|
+
monthlyBandwidthBytes: number;
|
|
8
|
+
monthlyBandwidthGB: number | null;
|
|
9
|
+
isDefault: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ListPlansResponse {
|
|
12
|
+
plans: PlanEntry[];
|
|
13
|
+
}
|
|
14
|
+
export interface UserPlanResponse {
|
|
15
|
+
plan: PlanEntry;
|
|
16
|
+
usage: {
|
|
17
|
+
monthlyUsageBytes: number;
|
|
18
|
+
monthlyUsageGB: number;
|
|
19
|
+
limitBytes: number;
|
|
20
|
+
limitGB: number | null;
|
|
21
|
+
percentUsed: number | null;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface ChangePlanResponse {
|
|
25
|
+
message: string;
|
|
26
|
+
plan: PlanEntry;
|
|
27
|
+
}
|
|
28
|
+
export declare class PlansResource {
|
|
29
|
+
private http;
|
|
30
|
+
constructor(http: HttpClient);
|
|
31
|
+
/** List all available plans (does not require authentication). */
|
|
32
|
+
list(): Promise<ListPlansResponse>;
|
|
33
|
+
/** Get the current user's plan and monthly usage. */
|
|
34
|
+
getUserPlan(): Promise<UserPlanResponse>;
|
|
35
|
+
/** Change the current user's plan. */
|
|
36
|
+
changePlan(planId: string): Promise<ChangePlanResponse>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class PlansResource {
|
|
2
|
+
http;
|
|
3
|
+
constructor(http) {
|
|
4
|
+
this.http = http;
|
|
5
|
+
}
|
|
6
|
+
/** List all available plans (does not require authentication). */
|
|
7
|
+
async list() {
|
|
8
|
+
return this.http.get("/api/plans", false);
|
|
9
|
+
}
|
|
10
|
+
/** Get the current user's plan and monthly usage. */
|
|
11
|
+
async getUserPlan() {
|
|
12
|
+
return this.http.get("/api/plans/user/plan");
|
|
13
|
+
}
|
|
14
|
+
/** Change the current user's plan. */
|
|
15
|
+
async changePlan(planId) {
|
|
16
|
+
return this.http.put("/api/plans/user/plan", { planId });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { HttpClient } from "./http.js";
|
|
2
|
+
import type { ProxyUrlOptions, ProxyConfig, DominusNodeConfig } from "./types.js";
|
|
3
|
+
export interface ProxyHealthResponse {
|
|
4
|
+
status: string;
|
|
5
|
+
activeSessions: number;
|
|
6
|
+
uptimeSeconds: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ProxyStatusResponse {
|
|
9
|
+
status: string;
|
|
10
|
+
activeSessions: number;
|
|
11
|
+
userActiveSessions: number;
|
|
12
|
+
avgLatencyMs: number;
|
|
13
|
+
providers: Array<{
|
|
14
|
+
name: string;
|
|
15
|
+
state: string;
|
|
16
|
+
consecutiveFailures: number;
|
|
17
|
+
totalRequests: number;
|
|
18
|
+
totalErrors: number;
|
|
19
|
+
avgLatencyMs: number;
|
|
20
|
+
fallbackOnly: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
endpoints: {
|
|
23
|
+
http: string;
|
|
24
|
+
socks5: string;
|
|
25
|
+
};
|
|
26
|
+
supportedCountries: string[];
|
|
27
|
+
uptimeSeconds: number;
|
|
28
|
+
}
|
|
29
|
+
export declare class ProxyResource {
|
|
30
|
+
private http;
|
|
31
|
+
private proxyHost;
|
|
32
|
+
private httpPort;
|
|
33
|
+
private socks5Port;
|
|
34
|
+
constructor(http: HttpClient, config: DominusNodeConfig);
|
|
35
|
+
/**
|
|
36
|
+
* Build a proxy URL string for use with HTTP clients.
|
|
37
|
+
*
|
|
38
|
+
* The returned URL includes authentication via the username field.
|
|
39
|
+
* Geo-targeting and sticky sessions are encoded in the username portion
|
|
40
|
+
* following Dominus Node proxy conventions.
|
|
41
|
+
*
|
|
42
|
+
* @param apiKey - The API key to authenticate proxy requests.
|
|
43
|
+
* @param opts - Optional targeting parameters (protocol, country, etc.).
|
|
44
|
+
* @returns A fully-formed proxy URL string.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const url = client.proxy.buildUrl("dn_live_abc123");
|
|
49
|
+
* // => "http://user:dn_live_abc123@proxy.dominusnode.com:8080"
|
|
50
|
+
*
|
|
51
|
+
* const socksUrl = client.proxy.buildUrl("dn_live_abc123", { protocol: "socks5", country: "US" });
|
|
52
|
+
* // => "socks5://user-country-US:dn_live_abc123@proxy.dominusnode.com:1080"
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
buildUrl(apiKey: string, opts?: ProxyUrlOptions): string;
|
|
56
|
+
/** Get public proxy health status (does not require authentication). */
|
|
57
|
+
getHealth(): Promise<ProxyHealthResponse>;
|
|
58
|
+
/** Get detailed proxy status including provider info (requires authentication). */
|
|
59
|
+
getStatus(): Promise<ProxyStatusResponse>;
|
|
60
|
+
/** Get proxy server configuration (requires authentication). */
|
|
61
|
+
getConfig(): Promise<ProxyConfig>;
|
|
62
|
+
}
|