@browserless.io/browserless 2.8.0 → 2.9.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 +9 -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 +15 -11
- 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/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/static.get.js +3 -3
- package/build/routes/management/tests/management.spec.js +9 -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/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 +21 -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/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/static.get.ts +3 -5
- package/src/routes/management/tests/management.spec.ts +15 -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/utils.ts +7 -2
- package/static/docs/swagger.json +10 -10
- package/static/docs/swagger.min.json +9 -9
- package/static/function/client.js +1646 -2917
- package/static/function/index.html +1646 -2917
|
@@ -29,7 +29,7 @@ export default (config, logger, options = {}) => async (req, browser) => {
|
|
|
29
29
|
*/
|
|
30
30
|
page.on('request', async (request) => {
|
|
31
31
|
const requestUrl = request.url();
|
|
32
|
-
logger.
|
|
32
|
+
logger.info(`Outbound Page Request: "${requestUrl}"`);
|
|
33
33
|
if (requestUrl.startsWith(functionRequestPath)) {
|
|
34
34
|
const filename = path.basename(requestUrl);
|
|
35
35
|
if (filename === functionCodeJS) {
|
|
@@ -48,23 +48,23 @@ export default (config, logger, options = {}) => async (req, browser) => {
|
|
|
48
48
|
status: 200,
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
logger.
|
|
51
|
+
logger.warn(`Static asset request to "${requestUrl}" couldn't be found, 404-ing`);
|
|
52
52
|
return request.respond({
|
|
53
53
|
body: code,
|
|
54
54
|
contentType: `Couldn't locate this file "${filename}" request "${requestUrl}" in "${functionAssetLocation}"`,
|
|
55
55
|
status: 404,
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
logger.
|
|
58
|
+
logger.info(`Request: "${requestUrl}" no responder found, continuing...`);
|
|
59
59
|
return request.continue();
|
|
60
60
|
});
|
|
61
61
|
page.on('response', (res) => {
|
|
62
|
-
if (res.
|
|
63
|
-
logger.
|
|
62
|
+
if (!res.ok()) {
|
|
63
|
+
logger.warn(`Received a non-200 response for request "${res.url()}"`);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
page.on('console', (event) => {
|
|
67
|
-
logger.
|
|
67
|
+
logger.trace(`${event.type()}: ${event.text()}`);
|
|
68
68
|
});
|
|
69
69
|
await page.goto(functionIndexHTML);
|
|
70
70
|
const { contentType, payload } = await page
|
|
@@ -85,7 +85,7 @@ export default (config, logger, options = {}) => async (req, browser) => {
|
|
|
85
85
|
});
|
|
86
86
|
}, browserWSEndpoint, context, functionCodeJS, JSON.stringify(options))
|
|
87
87
|
.catch((e) => {
|
|
88
|
-
logger.
|
|
88
|
+
logger.error(`Error running code: ${e}`);
|
|
89
89
|
throw new BadRequest(e.message);
|
|
90
90
|
});
|
|
91
91
|
return {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Logger } from '@browserless.io/browserless';
|
|
2
2
|
import lighthouse from 'lighthouse';
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const logger = new Logger('http:performance:child');
|
|
4
|
+
logger.info(`Child init`);
|
|
5
5
|
const send = (msg) => process.send && process.send(msg);
|
|
6
6
|
const start = async ({ url, config, options }) => {
|
|
7
7
|
try {
|
|
8
|
-
|
|
8
|
+
logger.info(`Child got payload, starting lighthouse`);
|
|
9
9
|
const results = await lighthouse(url, options, config);
|
|
10
10
|
send({
|
|
11
11
|
data: results?.lhr,
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { createLogger } from '@browserless.io/browserless';
|
|
2
1
|
import { fork } from 'child_process';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
const DEFAULT_AUDIT_CONFIG = {
|
|
5
4
|
extends: 'lighthouse:default',
|
|
6
5
|
};
|
|
7
|
-
export default async ({ browser, context, timeout, }) => {
|
|
6
|
+
export default async ({ browser, context, logger, timeout, }) => {
|
|
8
7
|
return new Promise((resolve, reject) => {
|
|
9
|
-
const debug = createLogger('http:performance:main');
|
|
10
8
|
const childPath = path.join('./', 'build', 'shared', 'utils', 'performance', 'child.js');
|
|
11
|
-
|
|
9
|
+
logger.trace(`Starting up child at ${childPath}`);
|
|
12
10
|
const child = fork(childPath);
|
|
13
11
|
const port = new URL(browser.wsEndpoint() || '').port;
|
|
14
12
|
let closed = false;
|
|
@@ -34,13 +32,13 @@ export default async ({ browser, context, timeout, }) => {
|
|
|
34
32
|
port,
|
|
35
33
|
};
|
|
36
34
|
child.on('error', (err) => {
|
|
37
|
-
|
|
35
|
+
logger.error(`Error in child process`, err);
|
|
38
36
|
reject('Performance run error: ' + err.message);
|
|
39
37
|
close(child.pid);
|
|
40
38
|
});
|
|
41
39
|
child.on('message', (payload) => {
|
|
42
40
|
if (payload.event === 'created') {
|
|
43
|
-
|
|
41
|
+
logger.info(`Child process is up, sending performance request`);
|
|
44
42
|
return child.send({
|
|
45
43
|
config,
|
|
46
44
|
event: 'start',
|
|
@@ -49,7 +47,7 @@ export default async ({ browser, context, timeout, }) => {
|
|
|
49
47
|
});
|
|
50
48
|
}
|
|
51
49
|
if (payload.event === 'complete') {
|
|
52
|
-
|
|
50
|
+
logger.info(`Performance gathered, closing and resolving request`);
|
|
53
51
|
close(child.pid);
|
|
54
52
|
return resolve({
|
|
55
53
|
data: payload.data,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { BrowserInstance, Logger } from '@browserless.io/browserless';
|
|
1
2
|
import { Config, Flags } from 'lighthouse';
|
|
2
|
-
import { BrowserInstance } from '@browserless.io/browserless';
|
|
3
3
|
export interface Message {
|
|
4
4
|
data?: unknown;
|
|
5
5
|
error?: unknown;
|
|
@@ -12,6 +12,7 @@ export interface mainOptions {
|
|
|
12
12
|
config?: unknown;
|
|
13
13
|
url: string;
|
|
14
14
|
};
|
|
15
|
+
logger: Logger;
|
|
15
16
|
timeout: number;
|
|
16
17
|
}
|
|
17
18
|
export interface start {
|
package/build/utils.d.ts
CHANGED
|
@@ -120,6 +120,6 @@ interface RequestInitTimeout extends RequestInit {
|
|
|
120
120
|
}
|
|
121
121
|
export declare const fetchTimeout: (input: RequestInfo | URL, initWithTimeout?: RequestInitTimeout) => Promise<Response>;
|
|
122
122
|
export declare const untildify: (path: string) => string;
|
|
123
|
-
export declare const printLogo: (docsLink: string) => string;
|
|
123
|
+
export declare const printLogo: (docsLink: string, debugURL?: string | boolean) => string;
|
|
124
124
|
export declare const getCDPClient: (page: Page) => CDPSession;
|
|
125
125
|
export {};
|
package/build/utils.js
CHANGED
|
@@ -561,12 +561,16 @@ export const untildify = (path) => {
|
|
|
561
561
|
const homeDir = homedir();
|
|
562
562
|
return homeDir ? path.replace(/^~(?=$|\/|\\)/, homeDir) : path;
|
|
563
563
|
};
|
|
564
|
-
export const printLogo = (docsLink) => `
|
|
564
|
+
export const printLogo = (docsLink, debugURL) => `
|
|
565
565
|
---------------------------------------------------------
|
|
566
566
|
| browserless.io
|
|
567
567
|
| To read documentation and more, load in your browser:
|
|
568
568
|
|
|
|
569
|
-
| ${docsLink}
|
|
569
|
+
| OpenAPI: ${docsLink}
|
|
570
|
+
| Full Documentation: https://docs.browserless.io/ ${
|
|
571
|
+
/*prettier-ignore*/
|
|
572
|
+
debugURL ? `
|
|
573
|
+
| Debbuger: ${debugURL}` : ""}
|
|
570
574
|
---------------------------------------------------------
|
|
571
575
|
${gradient('#ff1a8c', '#ffea00')(`
|
|
572
576
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
"clean": "node scripts/clean.js",
|
|
26
26
|
"dev": "npm run build:dev && env-cmd -f .env node build",
|
|
27
27
|
"install:adblock": "node scripts/install-adblock.js",
|
|
28
|
+
"install:debugger": "node scripts/install-debugger.js",
|
|
28
29
|
"install:browsers": "npx --yes playwright install chromium firefox webkit chrome",
|
|
29
|
-
"install:dev": "npm run install:browsers",
|
|
30
|
+
"install:dev": "npm run install:browsers && npm run install:debugger",
|
|
30
31
|
"lint": "eslint . --ext .ts --fix",
|
|
31
32
|
"prepack": "npm run build:dev",
|
|
32
33
|
"prettier": "prettier '{src,functions,scripts,bin,external,.github}/**/*.{js,ts,json,yml,yaml,md}' --log-level error --write",
|
|
@@ -55,40 +56,42 @@
|
|
|
55
56
|
"get-port": "^7.1.0",
|
|
56
57
|
"gradient-string": "^2.0.0",
|
|
57
58
|
"http-proxy": "^1.18.1",
|
|
58
|
-
"lighthouse": "^
|
|
59
|
+
"lighthouse": "^12.0.0",
|
|
59
60
|
"micromatch": "^4.0.4",
|
|
60
|
-
"playwright-core": "1.
|
|
61
|
-
"puppeteer-core": "^22.
|
|
61
|
+
"playwright-core": "1.44.0",
|
|
62
|
+
"puppeteer-core": "^22.8.0",
|
|
62
63
|
"puppeteer-extra": "^3.3.6",
|
|
63
64
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
64
65
|
"queue": "^7.0.0",
|
|
65
|
-
"systeminformation": "^5.22.
|
|
66
|
+
"systeminformation": "^5.22.8",
|
|
67
|
+
"tar-fs": "^3.0.6"
|
|
66
68
|
},
|
|
67
69
|
"optionalDependencies": {
|
|
68
|
-
"@types/chai": "^4.3.
|
|
70
|
+
"@types/chai": "^4.3.16",
|
|
69
71
|
"@types/debug": "^4.1.12",
|
|
70
72
|
"@types/gradient-string": "^1.1.6",
|
|
71
73
|
"@types/http-proxy": "^1.17.14",
|
|
72
|
-
"@types/micromatch": "^4.0.
|
|
74
|
+
"@types/micromatch": "^4.0.7",
|
|
73
75
|
"@types/mocha": "^10.0.6",
|
|
74
|
-
"@types/node": "^20.12.
|
|
76
|
+
"@types/node": "^20.12.11",
|
|
75
77
|
"@types/sinon": "^17.0.3",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
77
|
-
"@typescript-eslint/parser": "^7.
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
|
79
|
+
"@typescript-eslint/parser": "^7.8.0",
|
|
78
80
|
"assert": "^2.0.0",
|
|
79
|
-
"chai": "^5.1.
|
|
81
|
+
"chai": "^5.1.1",
|
|
80
82
|
"cross-env": "^7.0.3",
|
|
81
83
|
"env-cmd": "^10.1.0",
|
|
82
|
-
"esbuild": "^0.
|
|
84
|
+
"esbuild": "^0.21.2",
|
|
83
85
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
84
86
|
"eslint": "^8.57.0",
|
|
85
87
|
"eslint-plugin-typescript-sort-keys": "^3.2.0",
|
|
86
88
|
"extract-zip": "^2.0.1",
|
|
87
|
-
"
|
|
89
|
+
"gunzip-maybe": "^1.4.2",
|
|
90
|
+
"marked": "^12.0.2",
|
|
88
91
|
"mocha": "^10.4.0",
|
|
89
92
|
"move-file": "^3.1.0",
|
|
90
93
|
"prettier": "^3.2.5",
|
|
91
|
-
"sinon": "^17.0.
|
|
94
|
+
"sinon": "^17.0.2",
|
|
92
95
|
"ts-node": "^10.9.2",
|
|
93
96
|
"typescript": "^5.4.5",
|
|
94
97
|
"typescript-json-schema": "^0.63.0"
|
|
@@ -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,
|
|
@@ -281,7 +288,7 @@ export class Browserless extends EventEmitter {
|
|
|
281
288
|
}
|
|
282
289
|
}
|
|
283
290
|
|
|
284
|
-
this.
|
|
291
|
+
this.logger.info('Starting import of WebSocket Routes');
|
|
285
292
|
for (const wsRoute of [
|
|
286
293
|
...this.webSocketRouteFiles,
|
|
287
294
|
...internalWsRouteFiles,
|
|
@@ -349,7 +356,7 @@ export class Browserless extends EventEmitter {
|
|
|
349
356
|
.map((r) => r.name);
|
|
350
357
|
|
|
351
358
|
if (duplicateNamedRoutes.length) {
|
|
352
|
-
this.
|
|
359
|
+
this.logger.warn(
|
|
353
360
|
`Found duplicate routing names. Route names must be unique:`,
|
|
354
361
|
duplicateNamedRoutes,
|
|
355
362
|
);
|
|
@@ -358,7 +365,9 @@ export class Browserless extends EventEmitter {
|
|
|
358
365
|
httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
|
|
359
366
|
wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
|
|
360
367
|
|
|
361
|
-
this.
|
|
368
|
+
this.logger.info(
|
|
369
|
+
`Imported and validated all route files, starting up server.`,
|
|
370
|
+
);
|
|
362
371
|
|
|
363
372
|
this.server = new HTTPServer(
|
|
364
373
|
this.config,
|
|
@@ -370,7 +379,7 @@ export class Browserless extends EventEmitter {
|
|
|
370
379
|
);
|
|
371
380
|
|
|
372
381
|
await this.server.start();
|
|
373
|
-
this.
|
|
382
|
+
this.logger.info(`Starting metrics collection.`);
|
|
374
383
|
this.metricsSaveIntervalID = setInterval(
|
|
375
384
|
() => this.saveMetrics(),
|
|
376
385
|
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
|
},
|