@browserless.io/browserless 2.8.0 → 2.10.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/CHANGELOG.md +13 -1
- package/README.md +41 -3
- package/assets/debugger.png +0 -0
- package/bin/scaffold/src/hello-world.http.ts +3 -2
- package/build/browserless.d.ts +5 -4
- package/build/browserless.js +19 -13
- package/build/browsers/chrome.cdp.d.ts +2 -2
- package/build/browsers/chrome.cdp.js +2 -2
- package/build/browsers/chrome.playwright.d.ts +2 -2
- package/build/browsers/chrome.playwright.js +2 -2
- package/build/browsers/chromium.cdp.d.ts +4 -4
- package/build/browsers/chromium.cdp.js +49 -32
- package/build/browsers/chromium.playwright.d.ts +4 -4
- package/build/browsers/chromium.playwright.js +14 -13
- package/build/browsers/firefox.playwright.d.ts +4 -4
- package/build/browsers/firefox.playwright.js +14 -13
- package/build/browsers/index.d.ts +24 -8
- package/build/browsers/index.js +20 -15
- package/build/browsers/webkit.playwright.d.ts +4 -4
- package/build/browsers/webkit.playwright.js +14 -13
- package/build/config.d.ts +3 -0
- package/build/config.js +3 -0
- package/build/file-system.d.ts +2 -3
- package/build/file-system.js +2 -2
- package/build/http.d.ts +1 -0
- package/build/http.js +1 -0
- package/build/index.js +7 -7
- package/build/limiter.d.ts +2 -3
- package/build/limiter.js +11 -11
- package/build/logger.d.ts +16 -9
- package/build/logger.js +32 -16
- package/build/monitoring.d.ts +2 -3
- package/build/monitoring.js +4 -4
- package/build/router.d.ts +1 -3
- package/build/router.js +21 -22
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/management/http/pressure.get.d.ts +63 -0
- package/build/routes/management/http/pressure.get.js +56 -0
- package/build/routes/management/http/pressure.get.response.json +76 -0
- package/build/routes/management/http/static.get.js +3 -3
- package/build/routes/management/tests/management.spec.js +16 -0
- package/build/server.d.ts +1 -3
- package/build/server.js +33 -30
- package/build/shared/content.http.d.ts +1 -1
- package/build/shared/content.http.js +4 -1
- package/build/shared/download.http.js +9 -9
- package/build/shared/function.http.js +2 -2
- package/build/shared/json-protocol.http.d.ts +3 -3
- package/build/shared/json-protocol.http.js +2 -2
- package/build/shared/json-version.http.d.ts +3 -3
- package/build/shared/json-version.http.js +2 -2
- package/build/shared/pdf.http.d.ts +1 -1
- package/build/shared/pdf.http.js +6 -4
- package/build/shared/performance.http.js +1 -0
- package/build/shared/scrape.http.d.ts +1 -1
- package/build/shared/scrape.http.js +4 -1
- package/build/shared/screenshot.http.d.ts +1 -1
- package/build/shared/screenshot.http.js +4 -1
- package/build/shared/utils/function/handler.js +7 -7
- package/build/shared/utils/performance/child.js +4 -4
- package/build/shared/utils/performance/main.d.ts +1 -1
- package/build/shared/utils/performance/main.js +5 -7
- package/build/shared/utils/performance/types.d.ts +2 -1
- package/build/types.d.ts +10 -1
- package/build/types.js +10 -1
- package/build/utils.d.ts +1 -1
- package/build/utils.js +6 -2
- package/package.json +18 -15
- package/scripts/install-debugger.js +55 -15
- package/src/browserless.ts +25 -12
- package/src/browsers/chrome.cdp.ts +2 -5
- package/src/browsers/chrome.playwright.ts +2 -5
- package/src/browsers/chromium.cdp.ts +84 -35
- package/src/browsers/chromium.playwright.ts +26 -13
- package/src/browsers/firefox.playwright.ts +28 -13
- package/src/browsers/index.ts +24 -16
- package/src/browsers/webkit.playwright.ts +28 -13
- package/src/config.ts +4 -0
- package/src/file-system.ts +2 -7
- package/src/http.ts +1 -0
- package/src/index.ts +7 -7
- package/src/limiter.ts +13 -11
- package/src/logger.ts +39 -18
- package/src/monitoring.ts +6 -8
- package/src/router.ts +20 -20
- package/src/routes/management/http/pressure.get.ts +135 -0
- package/src/routes/management/http/static.get.ts +3 -5
- package/src/routes/management/tests/management.spec.ts +26 -0
- package/src/server.ts +43 -30
- package/src/shared/content.http.ts +5 -1
- package/src/shared/download.http.ts +9 -9
- package/src/shared/function.http.ts +2 -2
- package/src/shared/json-protocol.http.ts +8 -3
- package/src/shared/json-version.http.ts +8 -4
- package/src/shared/pdf.http.ts +6 -4
- package/src/shared/performance.http.ts +1 -0
- package/src/shared/scrape.http.ts +5 -1
- package/src/shared/screenshot.http.ts +4 -1
- package/src/shared/utils/function/handler.ts +7 -7
- package/src/shared/utils/performance/child.ts +4 -4
- package/src/shared/utils/performance/main.ts +5 -6
- package/src/shared/utils/performance/types.ts +2 -1
- package/src/types.ts +9 -0
- package/src/utils.ts +7 -2
- package/static/docs/swagger.json +138 -10
- package/static/docs/swagger.min.json +137 -9
- package/static/function/client.js +4290 -5542
- package/static/function/index.html +4290 -5542
|
@@ -1,20 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
/* global fetch, console, process */
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import os from 'os';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
import { deleteAsync } from 'del';
|
|
8
|
+
import gunzip from 'gunzip-maybe';
|
|
9
|
+
import { moveFile } from 'move-file';
|
|
10
|
+
import tar from 'tar-fs';
|
|
6
11
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
14
|
-
|
|
12
|
+
const registryURL = 'https://registry.npmjs.org/@browserless.io/debugger/';
|
|
13
|
+
const tmp = join(os.tmpdir(), 'browserless-debugger');
|
|
14
|
+
const untarDir = join(tmp, 'package', 'static');
|
|
15
|
+
const debuggerDir = join(process.cwd(), 'static', 'debugger');
|
|
16
|
+
|
|
17
|
+
const lastFromArr = (arr) => arr[arr.length - 1];
|
|
18
|
+
const dlAndExtract = (url) =>
|
|
19
|
+
fetch(url).then(
|
|
20
|
+
(response) =>
|
|
21
|
+
new Promise((resolve, reject) => {
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
Readable.fromWeb(response.body)
|
|
24
|
+
.pipe(gunzip())
|
|
25
|
+
.pipe(tar.extract(tmp))
|
|
26
|
+
.on('error', reject)
|
|
27
|
+
.on('finish', resolve);
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const getLatestVersion = async () => {
|
|
32
|
+
const response = await fetch(registryURL);
|
|
33
|
+
const json = await response.json();
|
|
34
|
+
const latest = lastFromArr(Object.keys(json.versions));
|
|
35
|
+
return json.versions[latest];
|
|
36
|
+
};
|
|
15
37
|
|
|
16
38
|
(async () => {
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
if (existsSync(debuggerDir)) {
|
|
40
|
+
await deleteAsync(debuggerDir);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const dist = await getLatestVersion()
|
|
44
|
+
.then((version) => version.dist.tarball)
|
|
45
|
+
.catch((error) => {
|
|
46
|
+
console.error(`Couldn't fetch latest debugger version: ${error.message}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await dlAndExtract(dist).catch((error) => {
|
|
51
|
+
console.error(`Couldn't download debugger: ${error.message}`);
|
|
52
|
+
process.exit(1);
|
|
19
53
|
});
|
|
20
|
-
|
|
54
|
+
|
|
55
|
+
await moveFile(untarDir, debuggerDir);
|
|
56
|
+
await deleteAsync(tmp, { force: true });
|
|
57
|
+
})().catch((error) => {
|
|
58
|
+
console.error(`An error occurred: ${error.message}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|
package/src/browserless.ts
CHANGED
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
WebSocketRoute,
|
|
24
24
|
WebkitPlaywright,
|
|
25
25
|
availableBrowsers,
|
|
26
|
-
createLogger,
|
|
27
26
|
getRouteFiles,
|
|
28
27
|
makeExternalURL,
|
|
29
28
|
printLogo,
|
|
@@ -46,7 +45,7 @@ type routeInstances =
|
|
|
46
45
|
| BrowserWebsocketRoute;
|
|
47
46
|
|
|
48
47
|
export class Browserless extends EventEmitter {
|
|
49
|
-
protected
|
|
48
|
+
protected logger: BlessLogger;
|
|
50
49
|
protected browserManager: BrowserManager;
|
|
51
50
|
protected config: Config;
|
|
52
51
|
protected fileSystem: FileSystem;
|
|
@@ -94,6 +93,7 @@ export class Browserless extends EventEmitter {
|
|
|
94
93
|
} = {}) {
|
|
95
94
|
super();
|
|
96
95
|
this.Logger = LoggerOverride ?? BlessLogger;
|
|
96
|
+
this.logger = new this.Logger('index');
|
|
97
97
|
this.config = config || new Config();
|
|
98
98
|
this.metrics = metrics || new Metrics();
|
|
99
99
|
this.token = token || new Token(this.config);
|
|
@@ -129,7 +129,7 @@ export class Browserless extends EventEmitter {
|
|
|
129
129
|
|
|
130
130
|
this.metrics.reset();
|
|
131
131
|
|
|
132
|
-
this.
|
|
132
|
+
this.logger.info(
|
|
133
133
|
`Current period usage: ${JSON.stringify({
|
|
134
134
|
date: aggregatedStats.date,
|
|
135
135
|
error: aggregatedStats.error,
|
|
@@ -146,7 +146,7 @@ export class Browserless extends EventEmitter {
|
|
|
146
146
|
);
|
|
147
147
|
|
|
148
148
|
if (metricsPath) {
|
|
149
|
-
this.
|
|
149
|
+
this.logger.info(`Saving metrics to "${metricsPath}"`);
|
|
150
150
|
this.fileSystem.append(
|
|
151
151
|
metricsPath,
|
|
152
152
|
JSON.stringify(aggregatedStats),
|
|
@@ -170,7 +170,7 @@ export class Browserless extends EventEmitter {
|
|
|
170
170
|
);
|
|
171
171
|
};
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
protected routeIsDisabled(route: routeInstances) {
|
|
174
174
|
return this.disabledRouteNames.some((name) => name === route.name);
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -230,11 +230,18 @@ export class Browserless extends EventEmitter {
|
|
|
230
230
|
const [[internalHttpRouteFiles, internalWsRouteFiles], installedBrowsers] =
|
|
231
231
|
await Promise.all([getRouteFiles(this.config), availableBrowsers]);
|
|
232
232
|
|
|
233
|
+
const hasDebugger = await this.config.hasDebugger();
|
|
234
|
+
const debuggerURL =
|
|
235
|
+
hasDebugger &&
|
|
236
|
+
makeExternalURL(
|
|
237
|
+
this.config.getExternalAddress(),
|
|
238
|
+
`/debugger/?token=${this.config.getToken()}`,
|
|
239
|
+
);
|
|
233
240
|
const docsLink = makeExternalURL(this.config.getExternalAddress(), '/docs');
|
|
234
241
|
|
|
235
|
-
this.
|
|
236
|
-
this.
|
|
237
|
-
this.
|
|
242
|
+
this.logger.info(printLogo(docsLink, debuggerURL));
|
|
243
|
+
this.logger.info(`Running as user "${userInfo().username}"`);
|
|
244
|
+
this.logger.info('Starting import of HTTP Routes');
|
|
238
245
|
|
|
239
246
|
for (const httpRoute of [
|
|
240
247
|
...this.httpRouteFiles,
|
|
@@ -265,12 +272,14 @@ export class Browserless extends EventEmitter {
|
|
|
265
272
|
this.metrics,
|
|
266
273
|
this.monitoring,
|
|
267
274
|
this.staticSDKDir,
|
|
275
|
+
this.limiter,
|
|
268
276
|
);
|
|
269
277
|
|
|
270
278
|
if (!this.routeIsDisabled(route)) {
|
|
271
279
|
route.bodySchema = safeParse(bodySchema);
|
|
272
280
|
route.querySchema = safeParse(querySchema);
|
|
273
281
|
route.config = () => this.config;
|
|
282
|
+
route.limiter = () => this.limiter;
|
|
274
283
|
route.metrics = () => this.metrics;
|
|
275
284
|
route.monitoring = () => this.monitoring;
|
|
276
285
|
route.fileSystem = () => this.fileSystem;
|
|
@@ -281,7 +290,7 @@ export class Browserless extends EventEmitter {
|
|
|
281
290
|
}
|
|
282
291
|
}
|
|
283
292
|
|
|
284
|
-
this.
|
|
293
|
+
this.logger.info('Starting import of WebSocket Routes');
|
|
285
294
|
for (const wsRoute of [
|
|
286
295
|
...this.webSocketRouteFiles,
|
|
287
296
|
...internalWsRouteFiles,
|
|
@@ -314,11 +323,13 @@ export class Browserless extends EventEmitter {
|
|
|
314
323
|
this.metrics,
|
|
315
324
|
this.monitoring,
|
|
316
325
|
this.staticSDKDir,
|
|
326
|
+
this.limiter,
|
|
317
327
|
);
|
|
318
328
|
|
|
319
329
|
if (!this.routeIsDisabled(route)) {
|
|
320
330
|
route.querySchema = safeParse(querySchema);
|
|
321
331
|
route.config = () => this.config;
|
|
332
|
+
route.limiter = () => this.limiter;
|
|
322
333
|
route.metrics = () => this.metrics;
|
|
323
334
|
route.monitoring = () => this.monitoring;
|
|
324
335
|
route.fileSystem = () => this.fileSystem;
|
|
@@ -349,7 +360,7 @@ export class Browserless extends EventEmitter {
|
|
|
349
360
|
.map((r) => r.name);
|
|
350
361
|
|
|
351
362
|
if (duplicateNamedRoutes.length) {
|
|
352
|
-
this.
|
|
363
|
+
this.logger.warn(
|
|
353
364
|
`Found duplicate routing names. Route names must be unique:`,
|
|
354
365
|
duplicateNamedRoutes,
|
|
355
366
|
);
|
|
@@ -358,7 +369,9 @@ export class Browserless extends EventEmitter {
|
|
|
358
369
|
httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
|
|
359
370
|
wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
|
|
360
371
|
|
|
361
|
-
this.
|
|
372
|
+
this.logger.info(
|
|
373
|
+
`Imported and validated all route files, starting up server.`,
|
|
374
|
+
);
|
|
362
375
|
|
|
363
376
|
this.server = new HTTPServer(
|
|
364
377
|
this.config,
|
|
@@ -370,7 +383,7 @@ export class Browserless extends EventEmitter {
|
|
|
370
383
|
);
|
|
371
384
|
|
|
372
385
|
await this.server.start();
|
|
373
|
-
this.
|
|
386
|
+
this.logger.info(`Starting metrics collection.`);
|
|
374
387
|
this.metricsSaveIntervalID = setInterval(
|
|
375
388
|
() => this.saveMetrics(),
|
|
376
389
|
this.metricsSaveInterval,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
chromeExecutablePath,
|
|
3
|
-
createLogger,
|
|
4
|
-
} from '@browserless.io/browserless';
|
|
1
|
+
import { Logger, chromeExecutablePath } from '@browserless.io/browserless';
|
|
5
2
|
import { ChromiumCDP } from './chromium.cdp.js';
|
|
6
3
|
|
|
7
4
|
export class ChromeCDP extends ChromiumCDP {
|
|
8
5
|
protected executablePath = chromeExecutablePath();
|
|
9
|
-
protected
|
|
6
|
+
protected logger = new Logger('browsers:chrome:cdp');
|
|
10
7
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
chromeExecutablePath,
|
|
3
|
-
createLogger,
|
|
4
|
-
} from '@browserless.io/browserless';
|
|
1
|
+
import { Logger, chromeExecutablePath } from '@browserless.io/browserless';
|
|
5
2
|
import { ChromiumPlaywright } from './chromium.playwright.js';
|
|
6
3
|
|
|
7
4
|
export class ChromePlaywright extends ChromiumPlaywright {
|
|
8
5
|
protected executablePath = chromeExecutablePath();
|
|
9
|
-
protected
|
|
6
|
+
protected logger = new Logger('browsers:chrome:playwright');
|
|
10
7
|
}
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
BLESS_PAGE_IDENTIFIER,
|
|
3
3
|
CDPLaunchOptions,
|
|
4
4
|
Config,
|
|
5
|
+
Logger,
|
|
5
6
|
Request,
|
|
6
7
|
ServerError,
|
|
7
|
-
createLogger,
|
|
8
8
|
noop,
|
|
9
9
|
once,
|
|
10
10
|
} from '@browserless.io/browserless';
|
|
@@ -29,7 +29,7 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
29
29
|
protected browser: Browser | null = null;
|
|
30
30
|
protected browserWSEndpoint: string | null = null;
|
|
31
31
|
protected port?: number;
|
|
32
|
-
protected
|
|
32
|
+
protected logger: Logger;
|
|
33
33
|
protected proxy = httpProxy.createProxyServer();
|
|
34
34
|
protected executablePath = playwright.chromium.executablePath();
|
|
35
35
|
|
|
@@ -37,9 +37,11 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
37
37
|
blockAds,
|
|
38
38
|
config,
|
|
39
39
|
userDataDir,
|
|
40
|
+
logger,
|
|
40
41
|
}: {
|
|
41
42
|
blockAds: boolean;
|
|
42
43
|
config: Config;
|
|
44
|
+
logger: Logger;
|
|
43
45
|
userDataDir: ChromiumCDP['userDataDir'];
|
|
44
46
|
}) {
|
|
45
47
|
super();
|
|
@@ -47,7 +49,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
47
49
|
this.userDataDir = userDataDir;
|
|
48
50
|
this.config = config;
|
|
49
51
|
this.blockAds = blockAds;
|
|
50
|
-
this.
|
|
52
|
+
this.logger = logger;
|
|
53
|
+
|
|
54
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
protected cleanListeners() {
|
|
@@ -63,31 +67,62 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
63
67
|
protected onTargetCreated = async (target: Target) => {
|
|
64
68
|
if (target.type() === 'page') {
|
|
65
69
|
const page = await target.page().catch((e) => {
|
|
66
|
-
this.
|
|
70
|
+
this.logger.error(`Error in ${this.constructor.name} new page ${e}`);
|
|
67
71
|
return null;
|
|
68
72
|
});
|
|
69
73
|
|
|
70
74
|
if (page) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
75
|
+
this.logger.trace(`Setting up file:// protocol request rejection`);
|
|
76
|
+
|
|
77
|
+
page.on('error', (err) => {
|
|
78
|
+
this.logger.error(err);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
page.on('pageerror', (err) => {
|
|
82
|
+
this.logger.warn(err);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
page.on('framenavigated', (frame) => {
|
|
86
|
+
this.logger.trace(`Navigation to ${frame.url()}`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
page.on('console', (message) => {
|
|
90
|
+
this.logger.trace(`${message.type()}: ${message.text()}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
page.on('requestfailed', (req) => {
|
|
94
|
+
this.logger.warn(`"${req.failure()?.errorText}": ${req.url()}`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
page.on('request', async (request) => {
|
|
98
|
+
this.logger.trace(`${request.method()}: ${request.url()}`);
|
|
99
|
+
if (
|
|
100
|
+
!this.config.getAllowFileProtocol() &&
|
|
101
|
+
request.url().startsWith('file://')
|
|
102
|
+
) {
|
|
103
|
+
this.logger.error(
|
|
104
|
+
`File protocol request found in request to ${this.constructor.name}, terminating`,
|
|
105
|
+
);
|
|
106
|
+
page.close().catch(noop);
|
|
107
|
+
this.close();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
page.on('response', async (response) => {
|
|
112
|
+
this.logger.trace(`${response.status()}: ${response.url()}`);
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
!this.config.getAllowFileProtocol() &&
|
|
116
|
+
response.url().startsWith('file://')
|
|
117
|
+
) {
|
|
118
|
+
this.logger.error(
|
|
119
|
+
`File protocol request found in response to ${this.constructor.name}, terminating`,
|
|
120
|
+
);
|
|
121
|
+
page.close().catch(noop);
|
|
122
|
+
this.close();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
91
126
|
this.emit('newPage', page);
|
|
92
127
|
}
|
|
93
128
|
}
|
|
@@ -97,7 +132,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
97
132
|
|
|
98
133
|
public newPage = async (): Promise<Page> => {
|
|
99
134
|
if (!this.browser) {
|
|
100
|
-
throw new ServerError(
|
|
135
|
+
throw new ServerError(
|
|
136
|
+
`${this.constructor.name} hasn't been launched yet!`,
|
|
137
|
+
);
|
|
101
138
|
}
|
|
102
139
|
|
|
103
140
|
return this.browser.newPage();
|
|
@@ -105,7 +142,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
105
142
|
|
|
106
143
|
public close = async (): Promise<void> => {
|
|
107
144
|
if (this.browser) {
|
|
108
|
-
this.
|
|
145
|
+
this.logger.info(
|
|
146
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
147
|
+
);
|
|
109
148
|
this.emit('close');
|
|
110
149
|
this.cleanListeners();
|
|
111
150
|
this.browser.removeAllListeners();
|
|
@@ -122,7 +161,7 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
122
161
|
|
|
123
162
|
public launch = async (options: CDPLaunchOptions = {}): Promise<Browser> => {
|
|
124
163
|
this.port = await getPort();
|
|
125
|
-
this.
|
|
164
|
+
this.logger.info(`${this.constructor.name} got open port ${this.port}`);
|
|
126
165
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
127
166
|
const finalOptions = {
|
|
128
167
|
...options,
|
|
@@ -157,13 +196,17 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
157
196
|
? puppeteerStealth.launch.bind(puppeteerStealth)
|
|
158
197
|
: puppeteer.launch.bind(puppeteer);
|
|
159
198
|
|
|
160
|
-
this.
|
|
161
|
-
|
|
199
|
+
this.logger.info(
|
|
200
|
+
finalOptions,
|
|
201
|
+
`Launching ${this.constructor.name} Handler`,
|
|
202
|
+
);
|
|
162
203
|
this.browser = (await launch(finalOptions)) as Browser;
|
|
163
204
|
this.browser.on('targetcreated', this.onTargetCreated);
|
|
164
205
|
this.running = true;
|
|
165
206
|
this.browserWSEndpoint = this.browser.wsEndpoint();
|
|
166
|
-
this.
|
|
207
|
+
this.logger.info(
|
|
208
|
+
`${this.constructor.name} is running on ${this.browserWSEndpoint}`,
|
|
209
|
+
);
|
|
167
210
|
|
|
168
211
|
return this.browser;
|
|
169
212
|
};
|
|
@@ -199,7 +242,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
199
242
|
);
|
|
200
243
|
}
|
|
201
244
|
socket.once('close', resolve);
|
|
202
|
-
this.
|
|
245
|
+
this.logger.info(
|
|
246
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name}`,
|
|
247
|
+
);
|
|
203
248
|
|
|
204
249
|
const shouldMakePage = req.parsed.pathname.includes(
|
|
205
250
|
BLESS_PAGE_IDENTIFIER,
|
|
@@ -223,7 +268,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
223
268
|
target,
|
|
224
269
|
},
|
|
225
270
|
(error) => {
|
|
226
|
-
this.
|
|
271
|
+
this.logger.error(
|
|
272
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
273
|
+
);
|
|
227
274
|
this.close();
|
|
228
275
|
return reject(error);
|
|
229
276
|
},
|
|
@@ -253,8 +300,8 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
253
300
|
this.browser?.process()?.once('close', close);
|
|
254
301
|
socket.once('close', close);
|
|
255
302
|
|
|
256
|
-
this.
|
|
257
|
-
`Proxying ${req.parsed.href} to
|
|
303
|
+
this.logger.info(
|
|
304
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
258
305
|
);
|
|
259
306
|
|
|
260
307
|
req.url = '';
|
|
@@ -271,7 +318,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
271
318
|
target: this.browserWSEndpoint,
|
|
272
319
|
},
|
|
273
320
|
(error) => {
|
|
274
|
-
this.
|
|
321
|
+
this.logger.error(
|
|
322
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
323
|
+
);
|
|
275
324
|
this.close();
|
|
276
325
|
return reject(error);
|
|
277
326
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserServerOptions,
|
|
3
3
|
Config,
|
|
4
|
+
Logger,
|
|
4
5
|
Request,
|
|
5
6
|
ServerError,
|
|
6
|
-
createLogger,
|
|
7
7
|
} from '@browserless.io/browserless';
|
|
8
8
|
import playwright, { Page } from 'playwright-core';
|
|
9
9
|
import { Duplex } from 'stream';
|
|
@@ -15,25 +15,28 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
15
15
|
protected config: Config;
|
|
16
16
|
protected userDataDir: string | null;
|
|
17
17
|
protected running = false;
|
|
18
|
+
protected logger: Logger;
|
|
18
19
|
protected proxy = httpProxy.createProxyServer();
|
|
19
20
|
protected browser: playwright.BrowserServer | null = null;
|
|
20
21
|
protected browserWSEndpoint: string | null = null;
|
|
21
|
-
protected debug = createLogger('browsers:chromium:playwright');
|
|
22
22
|
protected executablePath = playwright.chromium.executablePath();
|
|
23
23
|
|
|
24
24
|
constructor({
|
|
25
25
|
config,
|
|
26
26
|
userDataDir,
|
|
27
|
+
logger,
|
|
27
28
|
}: {
|
|
28
29
|
config: Config;
|
|
30
|
+
logger: Logger;
|
|
29
31
|
userDataDir: ChromiumPlaywright['userDataDir'];
|
|
30
32
|
}) {
|
|
31
33
|
super();
|
|
32
34
|
|
|
33
35
|
this.userDataDir = userDataDir;
|
|
34
36
|
this.config = config;
|
|
37
|
+
this.logger = logger;
|
|
35
38
|
|
|
36
|
-
this.
|
|
39
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
protected cleanListeners() {
|
|
@@ -44,7 +47,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
44
47
|
|
|
45
48
|
public close = async (): Promise<void> => {
|
|
46
49
|
if (this.browser) {
|
|
47
|
-
this.
|
|
50
|
+
this.logger.info(
|
|
51
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
52
|
+
);
|
|
48
53
|
this.emit('close');
|
|
49
54
|
this.cleanListeners();
|
|
50
55
|
this.browser.close();
|
|
@@ -57,18 +62,22 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
57
62
|
public pages = async (): Promise<[]> => [];
|
|
58
63
|
|
|
59
64
|
public getPageId = (): string => {
|
|
60
|
-
throw new ServerError(
|
|
65
|
+
throw new ServerError(
|
|
66
|
+
`#getPageId is not yet supported with ${this.constructor.name}.`,
|
|
67
|
+
);
|
|
61
68
|
};
|
|
62
69
|
|
|
63
70
|
public makeLiveURL = (): void => {
|
|
64
71
|
throw new ServerError(
|
|
65
|
-
`Live URLs are not yet supported with this
|
|
72
|
+
`Live URLs are not yet supported with ${this.constructor.name}. In the future this will be at "${this.config.getExternalAddress()}"`,
|
|
66
73
|
);
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
public newPage = async (): Promise<Page> => {
|
|
70
77
|
if (!this.browser || !this.browserWSEndpoint) {
|
|
71
|
-
throw new ServerError(
|
|
78
|
+
throw new ServerError(
|
|
79
|
+
`${this.constructor.name} hasn't been launched yet!`,
|
|
80
|
+
);
|
|
72
81
|
}
|
|
73
82
|
const browser = await playwright.chromium.connect(this.browserWSEndpoint);
|
|
74
83
|
return await browser.newPage();
|
|
@@ -77,7 +86,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
77
86
|
public launch = async (
|
|
78
87
|
options: BrowserServerOptions = {},
|
|
79
88
|
): Promise<playwright.BrowserServer> => {
|
|
80
|
-
this.
|
|
89
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
81
90
|
|
|
82
91
|
this.browser = await playwright.chromium.launchServer({
|
|
83
92
|
...options,
|
|
@@ -91,7 +100,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
91
100
|
|
|
92
101
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
93
102
|
|
|
94
|
-
this.
|
|
103
|
+
this.logger.info(
|
|
104
|
+
`${this.constructor.name} is running on ${browserWSEndpoint}`,
|
|
105
|
+
);
|
|
95
106
|
this.running = true;
|
|
96
107
|
this.browserWSEndpoint = browserWSEndpoint;
|
|
97
108
|
|
|
@@ -118,7 +129,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
118
129
|
};
|
|
119
130
|
|
|
120
131
|
public proxyPageWebSocket = async () => {
|
|
121
|
-
|
|
132
|
+
this.logger.warn(`${this.constructor.name} Not yet implemented`);
|
|
122
133
|
};
|
|
123
134
|
|
|
124
135
|
public proxyWebSocket = async (
|
|
@@ -134,8 +145,8 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
134
145
|
}
|
|
135
146
|
socket.once('close', resolve);
|
|
136
147
|
|
|
137
|
-
this.
|
|
138
|
-
`Proxying ${req.parsed.href} to
|
|
148
|
+
this.logger.info(
|
|
149
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
139
150
|
);
|
|
140
151
|
|
|
141
152
|
// Delete headers known to cause issues
|
|
@@ -152,7 +163,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
152
163
|
target: this.browserWSEndpoint,
|
|
153
164
|
},
|
|
154
165
|
(error) => {
|
|
155
|
-
this.
|
|
166
|
+
this.logger.error(
|
|
167
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
168
|
+
);
|
|
156
169
|
this.close();
|
|
157
170
|
return reject(error);
|
|
158
171
|
},
|