@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.
Files changed (105) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/README.md +41 -3
  3. package/assets/debugger.png +0 -0
  4. package/bin/scaffold/src/hello-world.http.ts +3 -2
  5. package/build/browserless.d.ts +5 -4
  6. package/build/browserless.js +15 -11
  7. package/build/browsers/chrome.cdp.d.ts +2 -2
  8. package/build/browsers/chrome.cdp.js +2 -2
  9. package/build/browsers/chrome.playwright.d.ts +2 -2
  10. package/build/browsers/chrome.playwright.js +2 -2
  11. package/build/browsers/chromium.cdp.d.ts +4 -4
  12. package/build/browsers/chromium.cdp.js +49 -32
  13. package/build/browsers/chromium.playwright.d.ts +4 -4
  14. package/build/browsers/chromium.playwright.js +14 -13
  15. package/build/browsers/firefox.playwright.d.ts +4 -4
  16. package/build/browsers/firefox.playwright.js +14 -13
  17. package/build/browsers/index.d.ts +24 -8
  18. package/build/browsers/index.js +20 -15
  19. package/build/browsers/webkit.playwright.d.ts +4 -4
  20. package/build/browsers/webkit.playwright.js +14 -13
  21. package/build/config.d.ts +3 -0
  22. package/build/config.js +3 -0
  23. package/build/file-system.d.ts +2 -3
  24. package/build/file-system.js +2 -2
  25. package/build/index.js +7 -7
  26. package/build/limiter.d.ts +2 -3
  27. package/build/limiter.js +11 -11
  28. package/build/logger.d.ts +16 -9
  29. package/build/logger.js +32 -16
  30. package/build/monitoring.d.ts +2 -3
  31. package/build/monitoring.js +4 -4
  32. package/build/router.d.ts +1 -3
  33. package/build/router.js +21 -22
  34. package/build/routes/chrome/http/content.post.body.json +8 -8
  35. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  36. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  37. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  38. package/build/routes/chromium/http/content.post.body.json +8 -8
  39. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  40. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  41. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  42. package/build/routes/management/http/static.get.js +3 -3
  43. package/build/routes/management/tests/management.spec.js +9 -0
  44. package/build/server.d.ts +1 -3
  45. package/build/server.js +33 -30
  46. package/build/shared/content.http.d.ts +1 -1
  47. package/build/shared/content.http.js +4 -1
  48. package/build/shared/download.http.js +9 -9
  49. package/build/shared/function.http.js +2 -2
  50. package/build/shared/json-protocol.http.d.ts +3 -3
  51. package/build/shared/json-protocol.http.js +2 -2
  52. package/build/shared/json-version.http.d.ts +3 -3
  53. package/build/shared/json-version.http.js +2 -2
  54. package/build/shared/pdf.http.d.ts +1 -1
  55. package/build/shared/pdf.http.js +6 -4
  56. package/build/shared/performance.http.js +1 -0
  57. package/build/shared/scrape.http.d.ts +1 -1
  58. package/build/shared/scrape.http.js +4 -1
  59. package/build/shared/screenshot.http.d.ts +1 -1
  60. package/build/shared/screenshot.http.js +4 -1
  61. package/build/shared/utils/function/handler.js +7 -7
  62. package/build/shared/utils/performance/child.js +4 -4
  63. package/build/shared/utils/performance/main.d.ts +1 -1
  64. package/build/shared/utils/performance/main.js +5 -7
  65. package/build/shared/utils/performance/types.d.ts +2 -1
  66. package/build/utils.d.ts +1 -1
  67. package/build/utils.js +6 -2
  68. package/package.json +18 -15
  69. package/scripts/install-debugger.js +55 -15
  70. package/src/browserless.ts +21 -12
  71. package/src/browsers/chrome.cdp.ts +2 -5
  72. package/src/browsers/chrome.playwright.ts +2 -5
  73. package/src/browsers/chromium.cdp.ts +84 -35
  74. package/src/browsers/chromium.playwright.ts +26 -13
  75. package/src/browsers/firefox.playwright.ts +28 -13
  76. package/src/browsers/index.ts +24 -16
  77. package/src/browsers/webkit.playwright.ts +28 -13
  78. package/src/config.ts +4 -0
  79. package/src/file-system.ts +2 -7
  80. package/src/index.ts +7 -7
  81. package/src/limiter.ts +13 -11
  82. package/src/logger.ts +39 -18
  83. package/src/monitoring.ts +6 -8
  84. package/src/router.ts +20 -20
  85. package/src/routes/management/http/static.get.ts +3 -5
  86. package/src/routes/management/tests/management.spec.ts +15 -0
  87. package/src/server.ts +43 -30
  88. package/src/shared/content.http.ts +5 -1
  89. package/src/shared/download.http.ts +9 -9
  90. package/src/shared/function.http.ts +2 -2
  91. package/src/shared/json-protocol.http.ts +8 -3
  92. package/src/shared/json-version.http.ts +8 -4
  93. package/src/shared/pdf.http.ts +6 -4
  94. package/src/shared/performance.http.ts +1 -0
  95. package/src/shared/scrape.http.ts +5 -1
  96. package/src/shared/screenshot.http.ts +4 -1
  97. package/src/shared/utils/function/handler.ts +7 -7
  98. package/src/shared/utils/performance/child.ts +4 -4
  99. package/src/shared/utils/performance/main.ts +5 -6
  100. package/src/shared/utils/performance/types.ts +2 -1
  101. package/src/utils.ts +7 -2
  102. package/static/docs/swagger.json +10 -10
  103. package/static/docs/swagger.min.json +9 -9
  104. package/static/function/client.js +1646 -2917
  105. 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.log(`Outbound Page Request: "${requestUrl}"`);
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.log(`Static asset request to "${requestUrl}" couldn't be found, 404-ing`);
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.log(`Request: "${requestUrl}" no responder found, continuing...`);
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.status() !== 200) {
63
- logger.log(`Received a non-200 response for request "${res.url()}"`);
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.log(`${event.type()}: ${event.text()}`);
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.log(`Error running code: ${e}`);
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 { createLogger } from '@browserless.io/browserless';
1
+ import { Logger } from '@browserless.io/browserless';
2
2
  import lighthouse from 'lighthouse';
3
- const debug = createLogger('http:performance:child');
4
- debug(`Child init`);
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
- debug(`Child got payload, starting lighthouse`);
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,3 +1,3 @@
1
1
  import { mainOptions } from './types.js';
2
- declare const _default: ({ browser, context, timeout, }: mainOptions) => Promise<unknown>;
2
+ declare const _default: ({ browser, context, logger, timeout, }: mainOptions) => Promise<unknown>;
3
3
  export default _default;
@@ -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
- debug(`Starting up child at ${childPath}`);
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
- debug(`Error in child process`, err);
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
- debug(`Child process is up, sending performance request`);
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
- debug(`Performance gathered, closing and resolving request`);
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.8.0",
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": "^11.1.0",
59
+ "lighthouse": "^12.0.0",
59
60
  "micromatch": "^4.0.4",
60
- "playwright-core": "1.43.0",
61
- "puppeteer-core": "^22.6.4",
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.7"
66
+ "systeminformation": "^5.22.8",
67
+ "tar-fs": "^3.0.6"
66
68
  },
67
69
  "optionalDependencies": {
68
- "@types/chai": "^4.3.14",
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.6",
74
+ "@types/micromatch": "^4.0.7",
73
75
  "@types/mocha": "^10.0.6",
74
- "@types/node": "^20.12.7",
76
+ "@types/node": "^20.12.11",
75
77
  "@types/sinon": "^17.0.3",
76
- "@typescript-eslint/eslint-plugin": "^7.6.0",
77
- "@typescript-eslint/parser": "^7.6.0",
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.0",
81
+ "chai": "^5.1.1",
80
82
  "cross-env": "^7.0.3",
81
83
  "env-cmd": "^10.1.0",
82
- "esbuild": "^0.20.2",
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
- "marked": "^12.0.1",
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.1",
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
- import { cp } from 'fs/promises';
2
- import { fileURLToPath } from 'url';
3
- import path from 'path';
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
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
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 from = path.join(
8
- __dirname,
9
- '..',
10
- 'node_modules',
11
- 'browserless-debugger',
12
- 'static',
13
- );
14
- const to = path.join(__dirname, '..', 'static', 'debugger');
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
- await cp(from, to, {
18
- recursive: true,
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
+ });
@@ -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 debug: debug.Debugger = createLogger('index');
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.debug(
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.debug(`Saving metrics to "${metricsPath}"`);
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
- private routeIsDisabled(route: routeInstances) {
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.debug(printLogo(docsLink));
236
- this.debug(`Running as user "${userInfo().username}"`);
237
- this.debug('Starting import of HTTP Routes');
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.debug('Starting import of WebSocket Routes');
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.debug(
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.debug(`Imported and validated all route files, starting up server.`);
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.debug(`Starting metrics collection.`);
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 debug = createLogger('browsers:chrome:cdp');
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 debug = createLogger('browsers:chrome:playwright');
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 debug = createLogger('browsers:chromium:cdp');
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.debug(`Starting new browser instance`);
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.debug(`Error in new page ${e}`);
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
- if (!this.config.getAllowFileProtocol()) {
72
- this.debug(`Setting up file:// protocol request rejection`);
73
- page.on('request', async (request) => {
74
- if (request.url().startsWith('file://')) {
75
- this.debug(`File protocol request found in request, terminating`);
76
- page.close().catch(noop);
77
- this.close();
78
- }
79
- });
80
-
81
- page.on('response', async (response) => {
82
- if (response.url().startsWith('file://')) {
83
- this.debug(
84
- `File protocol request found in response, terminating`,
85
- );
86
- page.close().catch(noop);
87
- this.close();
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(`Browser hasn't been launched yet!`);
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.debug(`Closing browser process and all listeners`);
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.debug(`Got open port ${this.port}`);
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.debug(finalOptions, `Launching CDP Handler`);
161
- // @ts-ignore mis-matched types from stealth...
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.debug(`Browser is running on ${this.browserWSEndpoint}`);
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.debug(`Proxying ${req.parsed.href}`);
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.debug(`Error proxying session: ${error}`);
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.debug(
257
- `Proxying ${req.parsed.href} to browser ${this.browserWSEndpoint}`,
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.debug(`Error proxying session: ${error}`);
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
  },