oblien 1.2.4 → 1.2.6
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 +11 -7
- package/browser.js +6 -0
- package/cdn.js +6 -0
- package/index.d.ts +300 -0
- package/index.js +6 -0
- package/package.json +13 -3
- package/src/browser/index.js +424 -0
- package/src/cdn/index.js +744 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Oblien Browser Module
|
|
3
|
+
* Browser automation with automatic token management
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class OblienBrowser {
|
|
7
|
+
constructor(client, config = {}) {
|
|
8
|
+
if (!client) throw new Error('Oblien client is required');
|
|
9
|
+
this.client = client;
|
|
10
|
+
this.browserURL = config.browserURL || 'https://browser.oblien.com';
|
|
11
|
+
|
|
12
|
+
// Token cache for reuse within expiration window
|
|
13
|
+
this._tokenCache = {
|
|
14
|
+
token: null,
|
|
15
|
+
expiresAt: null
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate a browser token
|
|
21
|
+
* Tokens expire in 1 minute for security
|
|
22
|
+
*
|
|
23
|
+
* @returns {Promise<Object>} Token response with token and expiration
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const tokenData = await browser.generateToken();
|
|
27
|
+
* // Returns:
|
|
28
|
+
* // {
|
|
29
|
+
* // success: true,
|
|
30
|
+
* // token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
31
|
+
* // expiresIn: '1m'
|
|
32
|
+
* // }
|
|
33
|
+
*/
|
|
34
|
+
async generateToken() {
|
|
35
|
+
const response = await this.client.post('browser/token');
|
|
36
|
+
|
|
37
|
+
// Cache token for reuse
|
|
38
|
+
if (response.success && response.token) {
|
|
39
|
+
this._tokenCache = {
|
|
40
|
+
token: response.token,
|
|
41
|
+
expiresAt: Date.now() + 50000 // 50 seconds (buffer before 1m expiry)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return response;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get a valid token
|
|
50
|
+
* Automatically generates new token if cache is empty or expired
|
|
51
|
+
* @private
|
|
52
|
+
*/
|
|
53
|
+
async _getToken() {
|
|
54
|
+
const cached = this._tokenCache;
|
|
55
|
+
|
|
56
|
+
// Use cached token if still valid
|
|
57
|
+
if (cached.token && cached.expiresAt > Date.now()) {
|
|
58
|
+
return cached.token;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Generate new token
|
|
62
|
+
const tokenData = await this.generateToken();
|
|
63
|
+
return tokenData.token;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get page content
|
|
68
|
+
* Opens a URL and extracts content
|
|
69
|
+
*
|
|
70
|
+
* @param {Object} options - Page content options
|
|
71
|
+
* @param {string} options.url - URL to visit (required)
|
|
72
|
+
* @param {string} options.token - Browser token (optional, auto-generates if not provided)
|
|
73
|
+
* @param {number} options.waitFor - Wait time in ms
|
|
74
|
+
* @param {string} options.selector - CSS selector to wait for
|
|
75
|
+
* @param {string} options.extract - Content to extract ('html', 'text', 'both')
|
|
76
|
+
* @param {boolean} options.waitForFullLoad - Wait for full page load
|
|
77
|
+
* @param {boolean} options.useProxy - Use proxy
|
|
78
|
+
* @returns {Promise<Object>} Page content result
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const result = await browser.getPageContent({
|
|
82
|
+
* url: 'https://example.com',
|
|
83
|
+
* extract: 'both'
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Returns:
|
|
87
|
+
* // {
|
|
88
|
+
* // success: true,
|
|
89
|
+
* // url: 'https://example.com',
|
|
90
|
+
* // html: '<html>...</html>',
|
|
91
|
+
* // text: 'Page text content...',
|
|
92
|
+
* // title: 'Example Domain'
|
|
93
|
+
* // }
|
|
94
|
+
*/
|
|
95
|
+
async getPageContent(options) {
|
|
96
|
+
const { url, token, ...restOptions } = options;
|
|
97
|
+
|
|
98
|
+
if (!url) {
|
|
99
|
+
throw new Error('URL is required');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Get token (use provided or generate new one)
|
|
103
|
+
const browserToken = token || await this._getToken();
|
|
104
|
+
|
|
105
|
+
const response = await fetch(`${this.browserURL}/page-content`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Authorization': `Bearer ${browserToken}`,
|
|
109
|
+
'Content-Type': 'application/json'
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({ url, ...restOptions })
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const error = await response.json().catch(() => ({}));
|
|
116
|
+
throw new Error(error.error || `Request failed: ${response.status}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return response.json();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Take a screenshot of a page
|
|
124
|
+
*
|
|
125
|
+
* @param {Object} options - Screenshot options
|
|
126
|
+
* @param {string} options.url - URL to screenshot (required)
|
|
127
|
+
* @param {string} options.token - Browser token (optional)
|
|
128
|
+
* @param {boolean} options.fullPage - Capture full page
|
|
129
|
+
* @param {string} options.format - Image format ('png' or 'jpeg')
|
|
130
|
+
* @param {number} options.quality - JPEG quality (0-100)
|
|
131
|
+
* @param {Object} options.viewport - Viewport size {width, height}
|
|
132
|
+
* @param {string} options.device - Device preset name
|
|
133
|
+
* @param {boolean} options.useProxy - Use proxy
|
|
134
|
+
* @returns {Promise<Object>} Screenshot result with base64 image
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* const result = await browser.screenshot({
|
|
138
|
+
* url: 'https://example.com',
|
|
139
|
+
* fullPage: true,
|
|
140
|
+
* format: 'png'
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* // Returns:
|
|
144
|
+
* // {
|
|
145
|
+
* // success: true,
|
|
146
|
+
* // screenshot: 'data:image/png;base64,iVBORw0KGgo...',
|
|
147
|
+
* // format: 'png',
|
|
148
|
+
* // width: 1920,
|
|
149
|
+
* // height: 1080
|
|
150
|
+
* // }
|
|
151
|
+
*/
|
|
152
|
+
async screenshot(options) {
|
|
153
|
+
const { url, token, ...restOptions } = options;
|
|
154
|
+
|
|
155
|
+
if (!url) {
|
|
156
|
+
throw new Error('URL is required');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const browserToken = token || await this._getToken();
|
|
160
|
+
|
|
161
|
+
const response = await fetch(`${this.browserURL}/screenshot`, {
|
|
162
|
+
method: 'POST',
|
|
163
|
+
headers: {
|
|
164
|
+
'Authorization': `Bearer ${browserToken}`,
|
|
165
|
+
'Content-Type': 'application/json'
|
|
166
|
+
},
|
|
167
|
+
body: JSON.stringify({ url, ...restOptions })
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
const error = await response.json().catch(() => ({}));
|
|
172
|
+
throw new Error(error.error || `Screenshot failed: ${response.status}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return response.json();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Generate PDF from a page
|
|
180
|
+
*
|
|
181
|
+
* @param {Object} options - PDF options
|
|
182
|
+
* @param {string} options.url - URL to convert to PDF (required)
|
|
183
|
+
* @param {string} options.token - Browser token (optional)
|
|
184
|
+
* @param {string} options.format - Paper format ('A4', 'Letter', etc.)
|
|
185
|
+
* @param {boolean} options.landscape - Landscape orientation
|
|
186
|
+
* @param {boolean} options.printBackground - Print background graphics
|
|
187
|
+
* @param {Object} options.margin - Page margins {top, right, bottom, left}
|
|
188
|
+
* @param {boolean} options.useProxy - Use proxy
|
|
189
|
+
* @returns {Promise<Object>} PDF result with base64 data
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* const result = await browser.pdf({
|
|
193
|
+
* url: 'https://example.com',
|
|
194
|
+
* format: 'A4',
|
|
195
|
+
* printBackground: true
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* // Returns:
|
|
199
|
+
* // {
|
|
200
|
+
* // success: true,
|
|
201
|
+
* // pdf: 'JVBERi0xLjQKJeLjz9MKMyAwIG9iago8P...',
|
|
202
|
+
* // format: 'A4',
|
|
203
|
+
* // pages: 5
|
|
204
|
+
* // }
|
|
205
|
+
*/
|
|
206
|
+
async pdf(options) {
|
|
207
|
+
const { url, token, ...restOptions } = options;
|
|
208
|
+
|
|
209
|
+
if (!url) {
|
|
210
|
+
throw new Error('URL is required');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const browserToken = token || await this._getToken();
|
|
214
|
+
|
|
215
|
+
const response = await fetch(`${this.browserURL}/pdf`, {
|
|
216
|
+
method: 'POST',
|
|
217
|
+
headers: {
|
|
218
|
+
'Authorization': `Bearer ${browserToken}`,
|
|
219
|
+
'Content-Type': 'application/json'
|
|
220
|
+
},
|
|
221
|
+
body: JSON.stringify({ url, ...restOptions })
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
if (!response.ok) {
|
|
225
|
+
const error = await response.json().catch(() => ({}));
|
|
226
|
+
throw new Error(error.error || `PDF generation failed: ${response.status}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return response.json();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Monitor network requests on a page
|
|
234
|
+
*
|
|
235
|
+
* @param {Object} options - Monitor options
|
|
236
|
+
* @param {string} options.url - URL to monitor (required)
|
|
237
|
+
* @param {string} options.token - Browser token (optional)
|
|
238
|
+
* @param {number} options.duration - Monitoring duration in ms
|
|
239
|
+
* @param {Array<string>} options.filterTypes - Filter request types
|
|
240
|
+
* @param {boolean} options.useProxy - Use proxy
|
|
241
|
+
* @returns {Promise<Object>} Network requests result
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* const result = await browser.monitorRequests({
|
|
245
|
+
* url: 'https://example.com',
|
|
246
|
+
* duration: 5000,
|
|
247
|
+
* filterTypes: ['xhr', 'fetch']
|
|
248
|
+
* });
|
|
249
|
+
*
|
|
250
|
+
* // Returns:
|
|
251
|
+
* // {
|
|
252
|
+
* // success: true,
|
|
253
|
+
* // requests: [
|
|
254
|
+
* // { url: 'https://api.example.com/data', method: 'GET', type: 'xhr', ... }
|
|
255
|
+
* // ],
|
|
256
|
+
* // count: 15
|
|
257
|
+
* // }
|
|
258
|
+
*/
|
|
259
|
+
async monitorRequests(options) {
|
|
260
|
+
const { url, token, ...restOptions } = options;
|
|
261
|
+
|
|
262
|
+
if (!url) {
|
|
263
|
+
throw new Error('URL is required');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const browserToken = token || await this._getToken();
|
|
267
|
+
|
|
268
|
+
const response = await fetch(`${this.browserURL}/monitor-requests`, {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
headers: {
|
|
271
|
+
'Authorization': `Bearer ${browserToken}`,
|
|
272
|
+
'Content-Type': 'application/json'
|
|
273
|
+
},
|
|
274
|
+
body: JSON.stringify({ url, ...restOptions })
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (!response.ok) {
|
|
278
|
+
const error = await response.json().catch(() => ({}));
|
|
279
|
+
throw new Error(error.error || `Request monitoring failed: ${response.status}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return response.json();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Get console logs from a page
|
|
287
|
+
*
|
|
288
|
+
* @param {Object} options - Console logs options
|
|
289
|
+
* @param {string} options.url - URL to monitor (required)
|
|
290
|
+
* @param {string} options.token - Browser token (optional)
|
|
291
|
+
* @param {number} options.duration - Monitoring duration in ms
|
|
292
|
+
* @param {boolean} options.useProxy - Use proxy
|
|
293
|
+
* @returns {Promise<Object>} Console logs result
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* const result = await browser.getConsoleLogs({
|
|
297
|
+
* url: 'https://example.com',
|
|
298
|
+
* duration: 3000
|
|
299
|
+
* });
|
|
300
|
+
*
|
|
301
|
+
* // Returns:
|
|
302
|
+
* // {
|
|
303
|
+
* // success: true,
|
|
304
|
+
* // logs: [
|
|
305
|
+
* // { type: 'log', text: 'Console message', timestamp: '...' }
|
|
306
|
+
* // ]
|
|
307
|
+
* // }
|
|
308
|
+
*/
|
|
309
|
+
async getConsoleLogs(options) {
|
|
310
|
+
const { url, token, ...restOptions } = options;
|
|
311
|
+
|
|
312
|
+
if (!url) {
|
|
313
|
+
throw new Error('URL is required');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const browserToken = token || await this._getToken();
|
|
317
|
+
|
|
318
|
+
const response = await fetch(`${this.browserURL}/console-logs`, {
|
|
319
|
+
method: 'POST',
|
|
320
|
+
headers: {
|
|
321
|
+
'Authorization': `Bearer ${browserToken}`,
|
|
322
|
+
'Content-Type': 'application/json'
|
|
323
|
+
},
|
|
324
|
+
body: JSON.stringify({ url, ...restOptions })
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
const error = await response.json().catch(() => ({}));
|
|
329
|
+
throw new Error(error.error || `Console logs retrieval failed: ${response.status}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return response.json();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get available device presets
|
|
337
|
+
*
|
|
338
|
+
* @param {Object} options - Options
|
|
339
|
+
* @param {string} options.token - Browser token (optional)
|
|
340
|
+
* @returns {Promise<Object>} Device presets
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* const devices = await browser.getDevicePresets();
|
|
344
|
+
*
|
|
345
|
+
* // Returns:
|
|
346
|
+
* // {
|
|
347
|
+
* // devices: {
|
|
348
|
+
* // 'iPhone 13': { width: 390, height: 844, ... },
|
|
349
|
+
* // 'iPad Pro': { width: 1024, height: 1366, ... }
|
|
350
|
+
* // }
|
|
351
|
+
* // }
|
|
352
|
+
*/
|
|
353
|
+
async getDevicePresets(options = {}) {
|
|
354
|
+
const { token } = options;
|
|
355
|
+
|
|
356
|
+
const browserToken = token || await this._getToken();
|
|
357
|
+
|
|
358
|
+
const response = await fetch(`${this.browserURL}/device-presets`, {
|
|
359
|
+
method: 'GET',
|
|
360
|
+
headers: {
|
|
361
|
+
'Authorization': `Bearer ${browserToken}`
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
if (!response.ok) {
|
|
366
|
+
const error = await response.json().catch(() => ({}));
|
|
367
|
+
throw new Error(error.error || `Failed to get device presets: ${response.status}`);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return response.json();
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get browser server status
|
|
375
|
+
*
|
|
376
|
+
* @param {Object} options - Options
|
|
377
|
+
* @param {string} options.token - Browser token (optional)
|
|
378
|
+
* @returns {Promise<Object>} Server status
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* const status = await browser.getStatus();
|
|
382
|
+
*
|
|
383
|
+
* // Returns:
|
|
384
|
+
* // {
|
|
385
|
+
* // status: 'running',
|
|
386
|
+
* // poolSize: 5,
|
|
387
|
+
* // activeBrowsers: 2
|
|
388
|
+
* // }
|
|
389
|
+
*/
|
|
390
|
+
async getStatus(options = {}) {
|
|
391
|
+
const { token } = options;
|
|
392
|
+
|
|
393
|
+
const browserToken = token || await this._getToken();
|
|
394
|
+
|
|
395
|
+
const response = await fetch(`${this.browserURL}/status`, {
|
|
396
|
+
method: 'GET',
|
|
397
|
+
headers: {
|
|
398
|
+
'Authorization': `Bearer ${browserToken}`
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
if (!response.ok) {
|
|
403
|
+
const error = await response.json().catch(() => ({}));
|
|
404
|
+
throw new Error(error.error || `Failed to get status: ${response.status}`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
return response.json();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Clear token cache
|
|
412
|
+
* Useful when you want to force fresh token generation
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* browser.clearTokenCache();
|
|
416
|
+
*/
|
|
417
|
+
clearTokenCache() {
|
|
418
|
+
this._tokenCache = {
|
|
419
|
+
token: null,
|
|
420
|
+
expiresAt: null
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|