@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.
@@ -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":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,YAAY,EAA0C,MAAM,oBAAoB,CAAC;AAoB1F,MAAM,OAAO,cAAc;IACzB;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,OAAoB;QAC3C,MAAM,YAAY,GAAgB,EAAE,CAAC;QACrC,MAAM,cAAc,GAAkD,EAAE,CAAC;QAEzE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAErD,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;gBACrB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;QACvC,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC;QAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;QAElC,MAAM,OAAO,GAAG,GAAG,UAAU,IAAI,UAAU,uBAAuB,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAEnH,OAAO;YACL,YAAY;YACZ,cAAc;YACd,UAAU;YACV,UAAU;YACV,YAAY;YACZ,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,2BAA2B,CAAC,WAAmB;QAKpD,IAAI,CAAC;YACH,4BAA4B;YAC5B,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YAEtD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,0BAA0B;gBAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;gBAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAO;wBACL,KAAK,EAAE,IAAI;wBACX,UAAU,EAAE,IAAI;wBAChB,KAAK,EAAE,qCAAqC;qBAC7C,CAAC;gBACJ,CAAC;gBAED,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;YACzC,CAAC;YAED,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACrD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,IAAI;gBACX,UAAU,EAAE,IAAI;gBAChB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB;aACxE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAC3B,OAAoB,EACpB,UAII,EAAE;QAEN,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,uBAAuB,EAAE,GAAG,OAAO,CAAC;QACpF,MAAM,OAAO,GAA2B,EAAE,CAAC;QAE3C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,UAAU,GAAgC,IAAI,CAAC;YAEnD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;gBACpD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,+EAA+E;oBAC/E,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBACzE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBAE5C,MAAM,MAAM,GAAyB;wBACnC,KAAK;wBACL,YAAY;wBACZ,OAAO,EAAE,UAAU,CAAC,OAAO;wBAC3B,QAAQ,EAAE,UAAU,CAAC,QAAQ;wBAC7B,cAAc,EAAE,UAAU,CAAC,cAAc;qBAC1C,CAAC;oBAEF,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;wBACrF,UAAU,GAAG,MAAM,CAAC;oBACtB,CAAC;oBAED,IAAI,MAAM,CAAC,OAAO;wBAAE,MAAM,CAAC,2BAA2B;gBACxD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,UAAU,GAAG;wBACX,KAAK;wBACL,YAAY,EAAE,OAAO;wBACrB,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa;qBAC9D,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,oCAAoC;QACpC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC3B,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,yBAAyB,CAC9B,gBAA2C,EAC3C,gBAAyC;QAEzC,IAAI,MAAM,GAAG,4BAA4B,CAAC;QAC1C,MAAM,IAAI,sBAAsB,gBAAgB,CAAC,UAAU,IAAI,CAAC;QAChE,MAAM,IAAI,cAAc,gBAAgB,CAAC,UAAU,IAAI,CAAC;QACxD,MAAM,IAAI,gBAAgB,gBAAgB,CAAC,YAAY,IAAI,CAAC;QAC5D,MAAM,IAAI,qBAAqB,CAAC,CAAC,gBAAgB,CAAC,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAErH,IAAI,gBAAgB,CAAC,YAAY,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,0BAA0B,gBAAgB,CAAC,YAAY,OAAO,CAAC;YACzE,gBAAgB,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;gBACzD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5B,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,aAAa,KAAK,CAAC;gBACrF,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;oBAC7B,MAAM,IAAI,QAAQ,KAAK,IAAI,CAAC;gBAC9B,CAAC,CAAC,CAAC;gBACH,MAAM,IAAI,IAAI,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,gCAAgC,CAAC;YAC3C,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC/D,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAE/D,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,wBAAwB,cAAc,CAAC,MAAM,UAAU,CAAC;gBAClE,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;oBACpD,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,QAAQ,MAAM,CAAC,YAAY,IAAI,CAAC;oBACnG,IAAI,MAAM,CAAC,QAAQ;wBAAE,MAAM,IAAI,KAAK,MAAM,CAAC,QAAQ,GAAG,CAAC;oBACvD,IAAI,MAAM,CAAC,cAAc;wBAAE,MAAM,IAAI,KAAK,MAAM,CAAC,cAAc,GAAG,CAAC;oBACnE,MAAM,IAAI,IAAI,CAAC;gBACjB,CAAC,CAAC,CAAC;gBACH,MAAM,IAAI,IAAI,CAAC;YACjB,CAAC;YAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,uBAAuB,aAAa,CAAC,MAAM,UAAU,CAAC;gBAChE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;oBAClD,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,QAAQ,MAAM,CAAC,KAAK,IAAI,CAAC;gBAC9F,CAAC,CAAC,CAAC;gBACH,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC7B,MAAM,IAAI,WAAW,aAAa,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAAC,OAA8D;QAK3F,MAAM,eAAe,GAAG;YACtB,YAAY,EAAE;gBACZ,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACpC,QAAQ,EAAE;oBACR,WAAW,EAAE,QAAiB;oBAC9B,MAAM,EAAE,MAAe;oBACvB,YAAY,EAAE,QAAiB;iBAChC;gBACD,IAAI,EAAE;oBACJ,kDAAkD;oBAClD,8CAA8C;oBAC9C,+CAA+C;oBAC/C,sCAAsC;iBACvC;aACF;YACD,SAAS,EAAE;gBACT,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;gBACnC,QAAQ,EAAE;oBACR,WAAW,EAAE,QAAiB;oBAC9B,MAAM,EAAE,MAAe;oBACvB,YAAY,EAAE,WAAoB;iBACnC;gBACD,IAAI,EAAE;oBACJ,4CAA4C;oBAC5C,+CAA+C;oBAC/C,6CAA6C;oBAC7C,6CAA6C;iBAC9C;aACF;YACD,QAAQ,EAAE;gBACR,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACpC,QAAQ,EAAE;oBACR,WAAW,EAAE,QAAiB;oBAC9B,MAAM,EAAE,MAAe;oBACvB,YAAY,EAAE,UAAmB;iBAClC;gBACD,IAAI,EAAE;oBACJ,4BAA4B;oBAC5B,mCAAmC;oBACnC,yBAAyB;oBACzB,+CAA+C;iBAChD;aACF;YACD,OAAO,EAAE;gBACP,gBAAgB,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;gBACpC,QAAQ,EAAE;oBACR,WAAW,EAAE,QAAiB;oBAC9B,MAAM,EAAE,MAAe;oBACvB,YAAY,EAAE,QAAiB;iBAChC;gBACD,IAAI,EAAE;oBACJ,kCAAkC;oBAClC,qCAAqC;oBACrC,+BAA+B;oBAC/B,iCAAiC;iBAClC;aACF;SACF,CAAC;QAEF,OAAO,eAAe,CAAC,OAAO,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC;IAC7D,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,uBAAuB,CAAC,WAAmB;QACxD,sCAAsC;QACtC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC;YAC/C,OAAO;gBACL,WAAW,EAAE,QAAQ;gBACrB,aAAa,EAAE,MAAM;gBACrB,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,MAAM;gBACd,IAAI;gBACJ,IAAI;gBACJ,aAAa,EAAE,QAAQ;gBACvB,aAAa,EAAE,QAAQ;aACxB,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,iBAAiB,CACpC,KAAgB,EAChB,OAAe,EACf,OAAe;QAMf,4CAA4C;QAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC;QAE9E,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QAED,yBAAyB;QACzB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAExE,gEAAgE;QAChE,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;QAC/D,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACxC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;QAE1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,oBAAoB;YAC9B,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;SAChD,CAAC;IACJ,CAAC;CACF"}
@@ -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