@roxybrowser/openapi 1.0.1
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/README.md +374 -0
- package/lib/browser/browser-creator.d.ts +58 -0
- package/lib/browser/browser-creator.d.ts.map +1 -0
- package/lib/browser/browser-creator.js +286 -0
- package/lib/browser/browser-creator.js.map +1 -0
- package/lib/browser/template-manager.d.ts +48 -0
- package/lib/browser/template-manager.d.ts.map +1 -0
- package/lib/browser/template-manager.js +324 -0
- package/lib/browser/template-manager.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +821 -0
- package/lib/index.js.map +1 -0
- package/lib/proxy/proxy-manager.d.ts +67 -0
- package/lib/proxy/proxy-manager.d.ts.map +1 -0
- package/lib/proxy/proxy-manager.js +278 -0
- package/lib/proxy/proxy-manager.js.map +1 -0
- package/lib/proxy/proxy-validator.d.ts +66 -0
- package/lib/proxy/proxy-validator.d.ts.map +1 -0
- package/lib/proxy/proxy-validator.js +273 -0
- package/lib/proxy/proxy-validator.js.map +1 -0
- package/lib/roxy-client.d.ts +83 -0
- package/lib/roxy-client.d.ts.map +1 -0
- package/lib/roxy-client.js +306 -0
- package/lib/roxy-client.js.map +1 -0
- package/lib/types.d.ts +371 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +36 -0
- package/lib/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Advanced proxy validation and testing tools for RoxyBrowser MCP
|
|
5
|
+
*/
|
|
6
|
+
import { ProxyManager } from './proxy-manager.js';
|
|
7
|
+
export class ProxyValidator {
|
|
8
|
+
/**
|
|
9
|
+
* Validate a list of proxies
|
|
10
|
+
*/
|
|
11
|
+
static validateProxyList(proxies) {
|
|
12
|
+
const validProxies = [];
|
|
13
|
+
const invalidProxies = [];
|
|
14
|
+
for (const proxy of proxies) {
|
|
15
|
+
const validation = ProxyManager.validateProxy(proxy);
|
|
16
|
+
if (validation.valid) {
|
|
17
|
+
validProxies.push(proxy);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
invalidProxies.push({ proxy, errors: validation.errors });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const validCount = validProxies.length;
|
|
24
|
+
const invalidCount = invalidProxies.length;
|
|
25
|
+
const totalCount = proxies.length;
|
|
26
|
+
const summary = `${validCount}/${totalCount} proxies are valid (${((validCount / totalCount) * 100).toFixed(1)}%)`;
|
|
27
|
+
return {
|
|
28
|
+
validProxies,
|
|
29
|
+
invalidProxies,
|
|
30
|
+
totalCount,
|
|
31
|
+
validCount,
|
|
32
|
+
invalidCount,
|
|
33
|
+
summary,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parse and validate proxy string in various formats
|
|
38
|
+
*/
|
|
39
|
+
static parseAndValidateProxyString(proxyString) {
|
|
40
|
+
try {
|
|
41
|
+
// Try to parse proxy string
|
|
42
|
+
const proxy = ProxyManager.parseProxyUrl(proxyString);
|
|
43
|
+
if (!proxy) {
|
|
44
|
+
// Try alternative formats
|
|
45
|
+
const altProxy = this.parseAlternativeFormats(proxyString);
|
|
46
|
+
if (!altProxy) {
|
|
47
|
+
return {
|
|
48
|
+
proxy: null,
|
|
49
|
+
validation: null,
|
|
50
|
+
error: 'Unable to parse proxy string format',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const validation = ProxyManager.validateProxy(altProxy);
|
|
54
|
+
return { proxy: altProxy, validation };
|
|
55
|
+
}
|
|
56
|
+
const validation = ProxyManager.validateProxy(proxy);
|
|
57
|
+
return { proxy, validation };
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
proxy: null,
|
|
62
|
+
validation: null,
|
|
63
|
+
error: error instanceof Error ? error.message : 'Unknown parsing error',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Test multiple proxies and rank by performance
|
|
69
|
+
*/
|
|
70
|
+
static async benchmarkProxies(proxies, options = {}) {
|
|
71
|
+
const { timeout = 10000, retries = 1, testUrl = 'http://httpbin.org/ip' } = options;
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const proxy of proxies) {
|
|
74
|
+
let bestResult = null;
|
|
75
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
76
|
+
const startTime = Date.now();
|
|
77
|
+
try {
|
|
78
|
+
// Simulate proxy test (in real implementation, you'd use actual HTTP requests)
|
|
79
|
+
const testResult = await this.simulateProxyTest(proxy, testUrl, timeout);
|
|
80
|
+
const responseTime = Date.now() - startTime;
|
|
81
|
+
const result = {
|
|
82
|
+
proxy,
|
|
83
|
+
responseTime,
|
|
84
|
+
success: testResult.success,
|
|
85
|
+
location: testResult.location,
|
|
86
|
+
anonymityLevel: testResult.anonymityLevel,
|
|
87
|
+
};
|
|
88
|
+
if (!bestResult || (result.success && result.responseTime < bestResult.responseTime)) {
|
|
89
|
+
bestResult = result;
|
|
90
|
+
}
|
|
91
|
+
if (result.success)
|
|
92
|
+
break; // Stop retrying on success
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
bestResult = {
|
|
96
|
+
proxy,
|
|
97
|
+
responseTime: timeout,
|
|
98
|
+
success: false,
|
|
99
|
+
error: error instanceof Error ? error.message : 'Test failed',
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (bestResult) {
|
|
104
|
+
results.push(bestResult);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Sort by success and response time
|
|
108
|
+
return results.sort((a, b) => {
|
|
109
|
+
if (a.success && !b.success)
|
|
110
|
+
return -1;
|
|
111
|
+
if (!a.success && b.success)
|
|
112
|
+
return 1;
|
|
113
|
+
return a.responseTime - b.responseTime;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generate proxy health report
|
|
118
|
+
*/
|
|
119
|
+
static generateProxyHealthReport(validationResult, benchmarkResults) {
|
|
120
|
+
let report = `## Proxy Health Report\n\n`;
|
|
121
|
+
report += `**Total Proxies:** ${validationResult.totalCount}\n`;
|
|
122
|
+
report += `**Valid:** ${validationResult.validCount}\n`;
|
|
123
|
+
report += `**Invalid:** ${validationResult.invalidCount}\n`;
|
|
124
|
+
report += `**Success Rate:** ${((validationResult.validCount / validationResult.totalCount) * 100).toFixed(1)}%\n\n`;
|
|
125
|
+
if (validationResult.invalidCount > 0) {
|
|
126
|
+
report += `### ❌ Invalid Proxies (${validationResult.invalidCount})\n\n`;
|
|
127
|
+
validationResult.invalidProxies.forEach((invalid, index) => {
|
|
128
|
+
const proxy = invalid.proxy;
|
|
129
|
+
report += `${index + 1}. **${proxy.host}:${proxy.port}** (${proxy.proxyCategory})\n`;
|
|
130
|
+
invalid.errors.forEach(error => {
|
|
131
|
+
report += ` • ${error}\n`;
|
|
132
|
+
});
|
|
133
|
+
report += '\n';
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (benchmarkResults && benchmarkResults.length > 0) {
|
|
137
|
+
report += `### 🚀 Performance Results\n\n`;
|
|
138
|
+
const workingProxies = benchmarkResults.filter(r => r.success);
|
|
139
|
+
const failedProxies = benchmarkResults.filter(r => !r.success);
|
|
140
|
+
if (workingProxies.length > 0) {
|
|
141
|
+
report += `**✅ Working Proxies (${workingProxies.length}):**\n\n`;
|
|
142
|
+
workingProxies.slice(0, 10).forEach((result, index) => {
|
|
143
|
+
report += `${index + 1}. **${result.proxy.host}:${result.proxy.port}** - ${result.responseTime}ms`;
|
|
144
|
+
if (result.location)
|
|
145
|
+
report += ` (${result.location})`;
|
|
146
|
+
if (result.anonymityLevel)
|
|
147
|
+
report += ` [${result.anonymityLevel}]`;
|
|
148
|
+
report += '\n';
|
|
149
|
+
});
|
|
150
|
+
report += '\n';
|
|
151
|
+
}
|
|
152
|
+
if (failedProxies.length > 0) {
|
|
153
|
+
report += `**❌ Failed Proxies (${failedProxies.length}):**\n\n`;
|
|
154
|
+
failedProxies.slice(0, 5).forEach((result, index) => {
|
|
155
|
+
report += `${index + 1}. **${result.proxy.host}:${result.proxy.port}** - ${result.error}\n`;
|
|
156
|
+
});
|
|
157
|
+
if (failedProxies.length > 5) {
|
|
158
|
+
report += `... and ${failedProxies.length - 5} more\n`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return report;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get proxy recommendations based on use case
|
|
166
|
+
*/
|
|
167
|
+
static getProxyRecommendations(useCase) {
|
|
168
|
+
const recommendations = {
|
|
169
|
+
social_media: {
|
|
170
|
+
recommendedTypes: ['SOCKS5', 'HTTP'],
|
|
171
|
+
settings: {
|
|
172
|
+
proxyMethod: 'custom',
|
|
173
|
+
ipType: 'IPV4',
|
|
174
|
+
checkChannel: 'IP-API',
|
|
175
|
+
},
|
|
176
|
+
tips: [
|
|
177
|
+
'Use residential proxies for better success rates',
|
|
178
|
+
'Rotate proxies frequently to avoid detection',
|
|
179
|
+
'Ensure proxy location matches target audience',
|
|
180
|
+
'Test proxy anonymity level regularly',
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
ecommerce: {
|
|
184
|
+
recommendedTypes: ['HTTP', 'HTTPS'],
|
|
185
|
+
settings: {
|
|
186
|
+
proxyMethod: 'custom',
|
|
187
|
+
ipType: 'IPV4',
|
|
188
|
+
checkChannel: 'IPRust.io',
|
|
189
|
+
},
|
|
190
|
+
tips: [
|
|
191
|
+
'Use dedicated proxies for account security',
|
|
192
|
+
'Prefer HTTPS proxies for sensitive operations',
|
|
193
|
+
'Test proxy stability before bulk operations',
|
|
194
|
+
'Keep proxy sessions long for shopping carts',
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
scraping: {
|
|
198
|
+
recommendedTypes: ['SOCKS5', 'HTTP'],
|
|
199
|
+
settings: {
|
|
200
|
+
proxyMethod: 'custom',
|
|
201
|
+
ipType: 'IPV4',
|
|
202
|
+
checkChannel: 'IP123.in',
|
|
203
|
+
},
|
|
204
|
+
tips: [
|
|
205
|
+
'Use high-anonymity proxies',
|
|
206
|
+
'Implement proxy rotation strategy',
|
|
207
|
+
'Monitor proxy ban rates',
|
|
208
|
+
'Use different proxy pools for different sites',
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
general: {
|
|
212
|
+
recommendedTypes: ['HTTP', 'SOCKS5'],
|
|
213
|
+
settings: {
|
|
214
|
+
proxyMethod: 'custom',
|
|
215
|
+
ipType: 'IPV4',
|
|
216
|
+
checkChannel: 'IP-API',
|
|
217
|
+
},
|
|
218
|
+
tips: [
|
|
219
|
+
'Test proxy speed and reliability',
|
|
220
|
+
'Use geographically relevant proxies',
|
|
221
|
+
'Keep backup proxies available',
|
|
222
|
+
'Monitor proxy uptime statistics',
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
return recommendations[useCase] || recommendations.general;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Private helper methods
|
|
230
|
+
*/
|
|
231
|
+
static parseAlternativeFormats(proxyString) {
|
|
232
|
+
// Format: host:port:username:password
|
|
233
|
+
const parts = proxyString.split(':');
|
|
234
|
+
if (parts.length >= 2) {
|
|
235
|
+
const [host, port, username, password] = parts;
|
|
236
|
+
return {
|
|
237
|
+
proxyMethod: 'custom',
|
|
238
|
+
proxyCategory: 'HTTP',
|
|
239
|
+
protocol: 'HTTP',
|
|
240
|
+
ipType: 'IPV4',
|
|
241
|
+
host,
|
|
242
|
+
port,
|
|
243
|
+
proxyUserName: username,
|
|
244
|
+
proxyPassword: password,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
static async simulateProxyTest(proxy, testUrl, timeout) {
|
|
250
|
+
// Simulate proxy test with basic validation
|
|
251
|
+
const isValid = proxy.host && proxy.port && proxy.proxyCategory !== 'noproxy';
|
|
252
|
+
if (!isValid) {
|
|
253
|
+
throw new Error('Invalid proxy configuration');
|
|
254
|
+
}
|
|
255
|
+
// Simulate network delay
|
|
256
|
+
await new Promise(resolve => setTimeout(resolve, Math.random() * 1000));
|
|
257
|
+
// Simulate success/failure based on proxy configuration quality
|
|
258
|
+
const hasAuth = !!(proxy.proxyUserName && proxy.proxyPassword);
|
|
259
|
+
const isGoodType = ['SOCKS5', 'HTTPS'].includes(proxy.proxyCategory || '');
|
|
260
|
+
const successRate = hasAuth ? 0.9 : 0.7;
|
|
261
|
+
const typeBonus = isGoodType ? 0.1 : 0;
|
|
262
|
+
const success = Math.random() < (successRate + typeBonus);
|
|
263
|
+
if (!success) {
|
|
264
|
+
throw new Error('Proxy connection failed');
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
success: true,
|
|
268
|
+
location: 'Simulated Location',
|
|
269
|
+
anonymityLevel: hasAuth ? 'elite' : 'anonymous',
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=proxy-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-validator.js","sourceRoot":"","sources":["../../src/proxy/proxy-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoxyBrowser API Client
|
|
3
|
+
*
|
|
4
|
+
* HTTP client for RoxyBrowser REST API with authentication and error handling
|
|
5
|
+
*/
|
|
6
|
+
import { RoxyClientConfig, WorkspaceListResponse, BrowserListResponse, BrowserListParams, BrowserOpenParams, BrowserOpenResult, BrowserCloseParams, BrowserCreateConfig, BrowserCreateBatchResult } from './types.js';
|
|
7
|
+
export declare class RoxyClient {
|
|
8
|
+
private readonly config;
|
|
9
|
+
constructor(config: RoxyClientConfig);
|
|
10
|
+
/**
|
|
11
|
+
* Make authenticated HTTP request to RoxyBrowser API
|
|
12
|
+
*/
|
|
13
|
+
private makeRequest;
|
|
14
|
+
/**
|
|
15
|
+
* Get list of workspaces and projects
|
|
16
|
+
*/
|
|
17
|
+
getWorkspaces(pageIndex?: number, pageSize?: number): Promise<WorkspaceListResponse>;
|
|
18
|
+
/**
|
|
19
|
+
* Get list of browsers in workspace/project
|
|
20
|
+
*/
|
|
21
|
+
getBrowsers(params: BrowserListParams): Promise<BrowserListResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Open a single browser
|
|
24
|
+
*/
|
|
25
|
+
openBrowser(params: BrowserOpenParams): Promise<BrowserOpenResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Open multiple browsers in batch
|
|
28
|
+
*/
|
|
29
|
+
openBrowsers(workspaceId: number, dirIds: string[], args?: string[]): Promise<BrowserOpenResult[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Close a single browser
|
|
32
|
+
*/
|
|
33
|
+
closeBrowser(params: BrowserCloseParams): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Close multiple browsers in batch
|
|
36
|
+
*/
|
|
37
|
+
closeBrowsers(dirIds: string[]): Promise<Array<{
|
|
38
|
+
dirId: string;
|
|
39
|
+
success: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
}>>;
|
|
42
|
+
/**
|
|
43
|
+
* Create a single browser
|
|
44
|
+
*/
|
|
45
|
+
createBrowser(config: BrowserCreateConfig): Promise<{
|
|
46
|
+
dirId: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Create multiple browsers in batch
|
|
50
|
+
*/
|
|
51
|
+
createBrowsers(configs: BrowserCreateConfig[]): Promise<BrowserCreateBatchResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Get browser details by ID
|
|
54
|
+
*/
|
|
55
|
+
getBrowserDetail(workspaceId: number, dirId: string): Promise<any>;
|
|
56
|
+
/**
|
|
57
|
+
* Update/modify existing browser
|
|
58
|
+
*/
|
|
59
|
+
updateBrowser(config: BrowserCreateConfig & {
|
|
60
|
+
dirId: string;
|
|
61
|
+
}): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Delete browsers
|
|
64
|
+
*/
|
|
65
|
+
deleteBrowsers(workspaceId: number, dirIds: string[]): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Random fingerprint for browser
|
|
68
|
+
*/
|
|
69
|
+
randomBrowserFingerprint(workspaceId: number, dirId: string): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Clear browser local cache
|
|
72
|
+
*/
|
|
73
|
+
clearBrowserLocalCache(dirIds: string[]): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Clear browser server cache
|
|
76
|
+
*/
|
|
77
|
+
clearBrowserServerCache(workspaceId: number, dirIds: string[]): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Test API connectivity
|
|
80
|
+
*/
|
|
81
|
+
testConnection(): Promise<boolean>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=roxy-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roxy-client.d.ts","sourceRoot":"","sources":["../src/roxy-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,gBAAgB,EAEhB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EAEnB,wBAAwB,EAIzB,MAAM,YAAY,CAAC;AAEpB,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,MAAM,EAAE,gBAAgB;IAiBpC;;OAEG;YACW,WAAW;IA4DzB;;OAEG;IACG,aAAa,CAAC,SAAS,SAAI,EAAE,QAAQ,SAAK,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAUjF;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiB1E;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAOxE;;OAEG;IACG,YAAY,CAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EAAE,EAChB,IAAI,CAAC,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAqC/B;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAoB1G;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAO5E;;OAEG;IACG,cAAc,CAClB,OAAO,EAAE,mBAAmB,EAAE,GAC7B,OAAO,CAAC,wBAAwB,CAAC;IAsDpC;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAUxE;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnF;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1E;;OAEG;IACG,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjF;;OAEG;IACG,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D;;OAEG;IACG,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnF;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CASzC"}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoxyBrowser API Client
|
|
3
|
+
*
|
|
4
|
+
* HTTP client for RoxyBrowser REST API with authentication and error handling
|
|
5
|
+
*/
|
|
6
|
+
import { RoxyApiError, ConfigError, } from './types.js';
|
|
7
|
+
export class RoxyClient {
|
|
8
|
+
config;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
// Validate required configuration
|
|
11
|
+
if (!config.apiKey?.trim()) {
|
|
12
|
+
throw new ConfigError('API key is required');
|
|
13
|
+
}
|
|
14
|
+
if (!config.apiHost?.trim()) {
|
|
15
|
+
throw new ConfigError('API host is required');
|
|
16
|
+
}
|
|
17
|
+
this.config = {
|
|
18
|
+
apiHost: config.apiHost.replace(/\/$/, ''), // Remove trailing slash
|
|
19
|
+
apiKey: config.apiKey,
|
|
20
|
+
timeout: config.timeout ?? 30000,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Make authenticated HTTP request to RoxyBrowser API
|
|
25
|
+
*/
|
|
26
|
+
async makeRequest(endpoint, options = {}) {
|
|
27
|
+
const url = `${this.config.apiHost}${endpoint}`;
|
|
28
|
+
const controller = new AbortController();
|
|
29
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
30
|
+
try {
|
|
31
|
+
const response = await fetch(url, {
|
|
32
|
+
...options,
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
'token': this.config.apiKey, // RoxyBrowser uses 'token' header
|
|
36
|
+
...options.headers,
|
|
37
|
+
},
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
});
|
|
40
|
+
clearTimeout(timeoutId);
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
throw new RoxyApiError(`HTTP ${response.status}: ${response.statusText}`, response.status, await response.text().catch(() => 'Unknown error'));
|
|
43
|
+
}
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
// Check API response code
|
|
46
|
+
if (data.code !== 0) {
|
|
47
|
+
throw new RoxyApiError(data.msg || 'API request failed', data.code, data);
|
|
48
|
+
}
|
|
49
|
+
return data.data;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
clearTimeout(timeoutId);
|
|
53
|
+
if (error instanceof RoxyApiError) {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
if (error instanceof Error) {
|
|
57
|
+
if (error.name === 'AbortError') {
|
|
58
|
+
throw new RoxyApiError(`Request timeout after ${this.config.timeout}ms`, 408);
|
|
59
|
+
}
|
|
60
|
+
throw new RoxyApiError(`Network error: ${error.message}`, 0, error);
|
|
61
|
+
}
|
|
62
|
+
throw new RoxyApiError('Unknown error occurred', 0, error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get list of workspaces and projects
|
|
67
|
+
*/
|
|
68
|
+
async getWorkspaces(pageIndex = 1, pageSize = 15) {
|
|
69
|
+
const params = new URLSearchParams({
|
|
70
|
+
page_index: pageIndex.toString(),
|
|
71
|
+
page_size: pageSize.toString(),
|
|
72
|
+
});
|
|
73
|
+
return this.makeRequest(`/browser/workspace?${params}`, {
|
|
74
|
+
method: 'GET',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get list of browsers in workspace/project
|
|
79
|
+
*/
|
|
80
|
+
async getBrowsers(params) {
|
|
81
|
+
const searchParams = new URLSearchParams();
|
|
82
|
+
searchParams.append('workspaceId', params.workspaceId.toString());
|
|
83
|
+
if (params.dirIds)
|
|
84
|
+
searchParams.append('dirIds', params.dirIds);
|
|
85
|
+
if (params.windowName)
|
|
86
|
+
searchParams.append('windowName', params.windowName);
|
|
87
|
+
if (params.sortNums)
|
|
88
|
+
searchParams.append('sortNums', params.sortNums);
|
|
89
|
+
if (params.os)
|
|
90
|
+
searchParams.append('os', params.os);
|
|
91
|
+
if (params.projectIds)
|
|
92
|
+
searchParams.append('projectIds', params.projectIds);
|
|
93
|
+
if (params.windowRemark)
|
|
94
|
+
searchParams.append('windowRemark', params.windowRemark);
|
|
95
|
+
if (params.page_index)
|
|
96
|
+
searchParams.append('page_index', params.page_index.toString());
|
|
97
|
+
if (params.page_size)
|
|
98
|
+
searchParams.append('page_size', params.page_size.toString());
|
|
99
|
+
return this.makeRequest(`/browser/list_v3?${searchParams}`, {
|
|
100
|
+
method: 'GET',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Open a single browser
|
|
105
|
+
*/
|
|
106
|
+
async openBrowser(params) {
|
|
107
|
+
return this.makeRequest('/browser/open', {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
body: JSON.stringify(params),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Open multiple browsers in batch
|
|
114
|
+
*/
|
|
115
|
+
async openBrowsers(workspaceId, dirIds, args) {
|
|
116
|
+
const results = [];
|
|
117
|
+
const errors = [];
|
|
118
|
+
// Open browsers in parallel with reasonable concurrency
|
|
119
|
+
const BATCH_SIZE = 5;
|
|
120
|
+
for (let i = 0; i < dirIds.length; i += BATCH_SIZE) {
|
|
121
|
+
const batch = dirIds.slice(i, i + BATCH_SIZE);
|
|
122
|
+
const batchPromises = batch.map(async (dirId) => {
|
|
123
|
+
try {
|
|
124
|
+
const result = await this.openBrowser({ workspaceId, dirId, args });
|
|
125
|
+
return { dirId, result };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
129
|
+
return { dirId, error: errorMsg };
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const batchResults = await Promise.all(batchPromises);
|
|
133
|
+
for (const item of batchResults) {
|
|
134
|
+
if ('result' in item && item.result) {
|
|
135
|
+
results.push(item.result);
|
|
136
|
+
}
|
|
137
|
+
else if ('error' in item) {
|
|
138
|
+
errors.push({ dirId: item.dirId, error: item.error });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (errors.length > 0) {
|
|
143
|
+
console.warn('Some browsers failed to open:', errors);
|
|
144
|
+
}
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Close a single browser
|
|
149
|
+
*/
|
|
150
|
+
async closeBrowser(params) {
|
|
151
|
+
await this.makeRequest('/browser/close', {
|
|
152
|
+
method: 'POST',
|
|
153
|
+
body: JSON.stringify(params),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Close multiple browsers in batch
|
|
158
|
+
*/
|
|
159
|
+
async closeBrowsers(dirIds) {
|
|
160
|
+
const results = [];
|
|
161
|
+
// Close browsers in parallel
|
|
162
|
+
const closePromises = dirIds.map(async (dirId) => {
|
|
163
|
+
try {
|
|
164
|
+
await this.closeBrowser({ dirId });
|
|
165
|
+
return { dirId, success: true };
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
169
|
+
return { dirId, success: false, error: errorMsg };
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const closeResults = await Promise.all(closePromises);
|
|
173
|
+
results.push(...closeResults);
|
|
174
|
+
return results;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Create a single browser
|
|
178
|
+
*/
|
|
179
|
+
async createBrowser(config) {
|
|
180
|
+
return this.makeRequest('/browser/create', {
|
|
181
|
+
method: 'POST',
|
|
182
|
+
body: JSON.stringify(config),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Create multiple browsers in batch
|
|
187
|
+
*/
|
|
188
|
+
async createBrowsers(configs) {
|
|
189
|
+
const results = [];
|
|
190
|
+
const errors = [];
|
|
191
|
+
// Create browsers in parallel with reasonable concurrency
|
|
192
|
+
const BATCH_SIZE = 3;
|
|
193
|
+
for (let i = 0; i < configs.length; i += BATCH_SIZE) {
|
|
194
|
+
const batch = configs.slice(i, i + BATCH_SIZE);
|
|
195
|
+
const batchPromises = batch.map(async (config, batchIndex) => {
|
|
196
|
+
try {
|
|
197
|
+
const result = await this.createBrowser(config);
|
|
198
|
+
return {
|
|
199
|
+
dirId: result.dirId,
|
|
200
|
+
windowName: config.windowName || `Browser-${i + batchIndex + 1}`,
|
|
201
|
+
success: true,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
206
|
+
errors.push({ config, error: errorMsg });
|
|
207
|
+
return {
|
|
208
|
+
dirId: '',
|
|
209
|
+
windowName: config.windowName || `Browser-${i + batchIndex + 1}`,
|
|
210
|
+
success: false,
|
|
211
|
+
error: errorMsg,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
const batchResults = await Promise.all(batchPromises);
|
|
216
|
+
results.push(...batchResults);
|
|
217
|
+
// Add small delay between batches to avoid overwhelming the API
|
|
218
|
+
if (i + BATCH_SIZE < configs.length) {
|
|
219
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const successCount = results.filter(r => r.success).length;
|
|
223
|
+
const failureCount = results.filter(r => !r.success).length;
|
|
224
|
+
// If there were errors and some successes, log warnings
|
|
225
|
+
if (errors.length > 0) {
|
|
226
|
+
console.warn(`${errors.length} browser creation(s) failed:`, errors);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
results,
|
|
230
|
+
successCount,
|
|
231
|
+
failureCount,
|
|
232
|
+
total: configs.length,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get browser details by ID
|
|
237
|
+
*/
|
|
238
|
+
async getBrowserDetail(workspaceId, dirId) {
|
|
239
|
+
const params = new URLSearchParams({
|
|
240
|
+
workspaceId: workspaceId.toString(),
|
|
241
|
+
dirId,
|
|
242
|
+
});
|
|
243
|
+
return this.makeRequest(`/browser/detail?${params}`, {
|
|
244
|
+
method: 'GET',
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Update/modify existing browser
|
|
249
|
+
*/
|
|
250
|
+
async updateBrowser(config) {
|
|
251
|
+
await this.makeRequest('/browser/mdf', {
|
|
252
|
+
method: 'POST',
|
|
253
|
+
body: JSON.stringify(config),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Delete browsers
|
|
258
|
+
*/
|
|
259
|
+
async deleteBrowsers(workspaceId, dirIds) {
|
|
260
|
+
await this.makeRequest('/browser/delete', {
|
|
261
|
+
method: 'POST',
|
|
262
|
+
body: JSON.stringify({ workspaceId, dirIds }),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Random fingerprint for browser
|
|
267
|
+
*/
|
|
268
|
+
async randomBrowserFingerprint(workspaceId, dirId) {
|
|
269
|
+
await this.makeRequest('/browser/random_env', {
|
|
270
|
+
method: 'POST',
|
|
271
|
+
body: JSON.stringify({ workspaceId, dirId }),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Clear browser local cache
|
|
276
|
+
*/
|
|
277
|
+
async clearBrowserLocalCache(dirIds) {
|
|
278
|
+
await this.makeRequest('/browser/clear_local_cache', {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
body: JSON.stringify({ dirIds }),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Clear browser server cache
|
|
285
|
+
*/
|
|
286
|
+
async clearBrowserServerCache(workspaceId, dirIds) {
|
|
287
|
+
await this.makeRequest('/browser/clear_server_cache', {
|
|
288
|
+
method: 'POST',
|
|
289
|
+
body: JSON.stringify({ workspaceId, dirIds }),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Test API connectivity
|
|
294
|
+
*/
|
|
295
|
+
async testConnection() {
|
|
296
|
+
try {
|
|
297
|
+
await this.makeRequest('/health');
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
console.error('Connection test failed:', error);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=roxy-client.js.map
|