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.
@@ -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
+