@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +13 -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 +19 -13
  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/http.d.ts +1 -0
  26. package/build/http.js +1 -0
  27. package/build/index.js +7 -7
  28. package/build/limiter.d.ts +2 -3
  29. package/build/limiter.js +11 -11
  30. package/build/logger.d.ts +16 -9
  31. package/build/logger.js +32 -16
  32. package/build/monitoring.d.ts +2 -3
  33. package/build/monitoring.js +4 -4
  34. package/build/router.d.ts +1 -3
  35. package/build/router.js +21 -22
  36. package/build/routes/chrome/http/content.post.body.json +8 -8
  37. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  38. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  39. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  40. package/build/routes/chromium/http/content.post.body.json +8 -8
  41. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  42. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  43. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  44. package/build/routes/management/http/pressure.get.d.ts +63 -0
  45. package/build/routes/management/http/pressure.get.js +56 -0
  46. package/build/routes/management/http/pressure.get.response.json +76 -0
  47. package/build/routes/management/http/static.get.js +3 -3
  48. package/build/routes/management/tests/management.spec.js +16 -0
  49. package/build/server.d.ts +1 -3
  50. package/build/server.js +33 -30
  51. package/build/shared/content.http.d.ts +1 -1
  52. package/build/shared/content.http.js +4 -1
  53. package/build/shared/download.http.js +9 -9
  54. package/build/shared/function.http.js +2 -2
  55. package/build/shared/json-protocol.http.d.ts +3 -3
  56. package/build/shared/json-protocol.http.js +2 -2
  57. package/build/shared/json-version.http.d.ts +3 -3
  58. package/build/shared/json-version.http.js +2 -2
  59. package/build/shared/pdf.http.d.ts +1 -1
  60. package/build/shared/pdf.http.js +6 -4
  61. package/build/shared/performance.http.js +1 -0
  62. package/build/shared/scrape.http.d.ts +1 -1
  63. package/build/shared/scrape.http.js +4 -1
  64. package/build/shared/screenshot.http.d.ts +1 -1
  65. package/build/shared/screenshot.http.js +4 -1
  66. package/build/shared/utils/function/handler.js +7 -7
  67. package/build/shared/utils/performance/child.js +4 -4
  68. package/build/shared/utils/performance/main.d.ts +1 -1
  69. package/build/shared/utils/performance/main.js +5 -7
  70. package/build/shared/utils/performance/types.d.ts +2 -1
  71. package/build/types.d.ts +10 -1
  72. package/build/types.js +10 -1
  73. package/build/utils.d.ts +1 -1
  74. package/build/utils.js +6 -2
  75. package/package.json +18 -15
  76. package/scripts/install-debugger.js +55 -15
  77. package/src/browserless.ts +25 -12
  78. package/src/browsers/chrome.cdp.ts +2 -5
  79. package/src/browsers/chrome.playwright.ts +2 -5
  80. package/src/browsers/chromium.cdp.ts +84 -35
  81. package/src/browsers/chromium.playwright.ts +26 -13
  82. package/src/browsers/firefox.playwright.ts +28 -13
  83. package/src/browsers/index.ts +24 -16
  84. package/src/browsers/webkit.playwright.ts +28 -13
  85. package/src/config.ts +4 -0
  86. package/src/file-system.ts +2 -7
  87. package/src/http.ts +1 -0
  88. package/src/index.ts +7 -7
  89. package/src/limiter.ts +13 -11
  90. package/src/logger.ts +39 -18
  91. package/src/monitoring.ts +6 -8
  92. package/src/router.ts +20 -20
  93. package/src/routes/management/http/pressure.get.ts +135 -0
  94. package/src/routes/management/http/static.get.ts +3 -5
  95. package/src/routes/management/tests/management.spec.ts +26 -0
  96. package/src/server.ts +43 -30
  97. package/src/shared/content.http.ts +5 -1
  98. package/src/shared/download.http.ts +9 -9
  99. package/src/shared/function.http.ts +2 -2
  100. package/src/shared/json-protocol.http.ts +8 -3
  101. package/src/shared/json-version.http.ts +8 -4
  102. package/src/shared/pdf.http.ts +6 -4
  103. package/src/shared/performance.http.ts +1 -0
  104. package/src/shared/scrape.http.ts +5 -1
  105. package/src/shared/screenshot.http.ts +4 -1
  106. package/src/shared/utils/function/handler.ts +7 -7
  107. package/src/shared/utils/performance/child.ts +4 -4
  108. package/src/shared/utils/performance/main.ts +5 -6
  109. package/src/shared/utils/performance/types.ts +2 -1
  110. package/src/types.ts +9 -0
  111. package/src/utils.ts +7 -2
  112. package/static/docs/swagger.json +138 -10
  113. package/static/docs/swagger.min.json +137 -9
  114. package/static/function/client.js +4290 -5542
  115. package/static/function/index.html +4290 -5542
@@ -24,11 +24,11 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
24
24
  handler = async (req, res, logger, browser) => new Promise(async (resolve, reject) => {
25
25
  const config = this.config();
26
26
  const downloadPath = path.join(await config.getDownloadsDir(), `.browserless.download.${id()}`);
27
- logger.log(`Generating a download directory at "${downloadPath}"`);
27
+ logger.info(`Generating a download directory at "${downloadPath}"`);
28
28
  await mkdir(downloadPath);
29
29
  const handler = functionHandler(config, logger, { downloadPath });
30
30
  const response = await handler(req, browser).catch((e) => {
31
- logger.log(`Error running download code handler: "${e}"`);
31
+ logger.error(`Error running download code handler: "${e}"`);
32
32
  reject(e);
33
33
  return null;
34
34
  });
@@ -36,10 +36,10 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
36
36
  return;
37
37
  }
38
38
  const { page } = response;
39
- logger.log(`Download function has returned, finding downloads...`);
39
+ logger.info(`Download function has returned, finding downloads...`);
40
40
  async function checkIfDownloadComplete() {
41
41
  if (res.headersSent) {
42
- logger.log(`Request headers have been sent, terminating download watch.`);
42
+ logger.trace(`Request headers have been sent, terminating download watch.`);
43
43
  return null;
44
44
  }
45
45
  const [fileName] = await readdir(downloadPath);
@@ -47,20 +47,20 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
47
47
  await sleep(500);
48
48
  return checkIfDownloadComplete();
49
49
  }
50
- logger.log(`All files have finished downloading`);
50
+ logger.info(`All files have finished downloading`);
51
51
  return path.join(downloadPath, fileName);
52
52
  }
53
53
  const filePath = await checkIfDownloadComplete();
54
- logger.log(`Closing pages.`);
54
+ logger.info(`Closing pages.`);
55
55
  page.close();
56
56
  page.removeAllListeners();
57
57
  const rmDownload = once(() => filePath &&
58
58
  deleteAsync(filePath, { force: true })
59
59
  .then(() => {
60
- logger.log(`Successfully deleted downloads from disk at "${filePath}"`);
60
+ logger.info(`Successfully deleted downloads from disk at "${filePath}"`);
61
61
  })
62
62
  .catch((err) => {
63
- logger.log(`Error cleaning up downloaded files: "${err}" at "${filePath}"`);
63
+ logger.error(`Error cleaning up downloaded files: "${err}" at "${filePath}"`);
64
64
  }));
65
65
  if (res.headersSent || !filePath) {
66
66
  rmDownload();
@@ -78,7 +78,7 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
78
78
  }
79
79
  })
80
80
  .on('end', () => {
81
- logger.log(`Downloads successfully sent`);
81
+ logger.info(`Downloads successfully sent`);
82
82
  rmDownload();
83
83
  return resolve();
84
84
  })
@@ -22,7 +22,7 @@ export default class ChromiumFunctionPostRoute extends BrowserHTTPRoute {
22
22
  const config = this.config();
23
23
  const handler = functionHandler(config, logger);
24
24
  const { contentType, payload, page } = await handler(req, browser);
25
- logger.log(`Got function response of "${contentType}"`);
25
+ logger.info(`Got function response of "${contentType}"`);
26
26
  page.close();
27
27
  page.removeAllListeners();
28
28
  if (contentType === 'uint8array') {
@@ -33,7 +33,7 @@ export default class ChromiumFunctionPostRoute extends BrowserHTTPRoute {
33
33
  throw new BadRequest(`Couldn't determine function's response type.`);
34
34
  }
35
35
  else {
36
- logger.log(`Sending file-type response of "${type}"`);
36
+ logger.info(`Sending file-type response of "${type}"`);
37
37
  const readStream = new Stream.PassThrough();
38
38
  readStream.end(response);
39
39
  res.setHeader('Content-Type', type);
@@ -1,7 +1,7 @@
1
- import { APITags, HTTPRoute, HTTPRoutes, Methods, Request, Response, contentTypes } from '@browserless.io/browserless';
1
+ import { APITags, HTTPRoute, HTTPRoutes, Logger, Methods, Request, Response, contentTypes } from '@browserless.io/browserless';
2
2
  export type ResponseSchema = object;
3
3
  export default class ChromiumJSONProtocolGetRoute extends HTTPRoute {
4
- private cachedProtocol;
4
+ protected cachedProtocol: object | undefined;
5
5
  name: string;
6
6
  accepts: contentTypes[];
7
7
  auth: boolean;
@@ -12,5 +12,5 @@ export default class ChromiumJSONProtocolGetRoute extends HTTPRoute {
12
12
  method: Methods;
13
13
  path: HTTPRoutes;
14
14
  tags: APITags[];
15
- handler: (_req: Request, res: Response) => Promise<void>;
15
+ handler: (_req: Request, res: Response, logger: Logger) => Promise<void>;
16
16
  }
@@ -11,10 +11,10 @@ export default class ChromiumJSONProtocolGetRoute extends HTTPRoute {
11
11
  method = Methods.get;
12
12
  path = HTTPRoutes.jsonProtocol;
13
13
  tags = [APITags.browserAPI];
14
- handler = async (_req, res) => {
14
+ handler = async (_req, res, logger) => {
15
15
  const browserManager = this.browserManager();
16
16
  if (!this.cachedProtocol) {
17
- this.cachedProtocol = await browserManager.getProtocolJSON();
17
+ this.cachedProtocol = await browserManager.getProtocolJSON(logger);
18
18
  }
19
19
  return jsonResponse(res, 200, this.cachedProtocol);
20
20
  };
@@ -1,7 +1,7 @@
1
- import { APITags, BrowserManager, HTTPRoute, HTTPRoutes, Methods, Request, Response, UnwrapPromise, contentTypes } from '@browserless.io/browserless';
1
+ import { APITags, BrowserManager, HTTPRoute, HTTPRoutes, Logger, Methods, Request, Response, UnwrapPromise, contentTypes } from '@browserless.io/browserless';
2
2
  export type ResponseSchema = UnwrapPromise<ReturnType<BrowserManager['getVersionJSON']>>;
3
3
  export default class ChromiumJSONVersionGetRoute extends HTTPRoute {
4
- private cachedJSON;
4
+ protected cachedJSON: ResponseSchema | undefined;
5
5
  name: string;
6
6
  accepts: contentTypes[];
7
7
  auth: boolean;
@@ -12,5 +12,5 @@ export default class ChromiumJSONVersionGetRoute extends HTTPRoute {
12
12
  method: Methods;
13
13
  path: HTTPRoutes;
14
14
  tags: APITags[];
15
- handler: (req: Request, res: Response) => Promise<void>;
15
+ handler: (req: Request, res: Response, logger: Logger) => Promise<void>;
16
16
  }
@@ -11,14 +11,14 @@ export default class ChromiumJSONVersionGetRoute extends HTTPRoute {
11
11
  method = Methods.get;
12
12
  path = HTTPRoutes.jsonVersion;
13
13
  tags = [APITags.browserAPI];
14
- handler = async (req, res) => {
14
+ handler = async (req, res, logger) => {
15
15
  const baseUrl = req.parsed.host;
16
16
  const protocol = req.parsed.protocol.includes('s') ? 'wss' : 'ws';
17
17
  try {
18
18
  if (!this.cachedJSON) {
19
19
  const browserManager = this.browserManager();
20
20
  this.cachedJSON = {
21
- ...(await browserManager.getVersionJSON()),
21
+ ...(await browserManager.getVersionJSON(logger)),
22
22
  webSocketDebuggerUrl: `${protocol}://${baseUrl}`,
23
23
  };
24
24
  }
@@ -43,5 +43,5 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
43
43
  method: Methods;
44
44
  path: HTTPRoutes[];
45
45
  tags: APITags[];
46
- handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
46
+ handler: (req: Request, res: ServerResponse, logger: Logger, browser: BrowserInstance) => Promise<void>;
47
47
  }
@@ -1,4 +1,4 @@
1
- import { APITags, BadRequest, BrowserHTTPRoute, BrowserlessRoutes, ChromiumCDP, HTTPRoutes, Methods, bestAttemptCatch, contentTypes, dedent, noop, sleep, waitForEvent as waitForEvt, waitForFunction as waitForFn, writeResponse, } from '@browserless.io/browserless';
1
+ import { APITags, BadRequest, BrowserHTTPRoute, BrowserlessRoutes, ChromiumCDP, HTTPRoutes, Methods, bestAttemptCatch, contentTypes, dedent, noop, sleep, waitForEvent as waitForEvt, waitForFunction as waitForFn, } from '@browserless.io/browserless';
2
2
  import { Stream } from 'stream';
3
3
  export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
4
4
  name = BrowserlessRoutes.ChromiumPDFPostRoute;
@@ -16,13 +16,13 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
16
16
  method = Methods.post;
17
17
  path = [HTTPRoutes.pdf, HTTPRoutes.chromiumPdf];
18
18
  tags = [APITags.browserAPI];
19
- handler = async (req, res, _logger, browser) => {
19
+ handler = async (req, res, logger, browser) => {
20
+ logger.info('PDF API invoked with body:', req.body);
20
21
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
21
22
  ? 'application/pdf'
22
23
  : req.headers.accept;
23
24
  if (!req.body) {
24
- writeResponse(res, 400, `Couldn't parse JSON body`);
25
- return;
25
+ throw new BadRequest(`Couldn't parse JSON body`);
26
26
  }
27
27
  res.setHeader('Content-Type', contentType);
28
28
  const { url, gotoOptions, authenticate, html, addScriptTag = [], addStyleTag = [], cookies = [], emulateMediaType, rejectRequestPattern = [], requestInterceptors = [], rejectResourceTypes = [], options, setExtraHTTPHeaders, setJavaScriptEnabled, userAgent, viewport, waitForEvent, waitForFunction, waitForSelector, waitForTimeout, bestAttempt = false, } = req.body;
@@ -60,6 +60,7 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
60
60
  page.on('request', (req) => {
61
61
  if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
62
62
  rejectResourceTypes.includes(req.resourceType())) {
63
+ logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
63
64
  return req.abort();
64
65
  }
65
66
  const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
@@ -112,5 +113,6 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
112
113
  readStream.end(pdfBuffer);
113
114
  await new Promise((r) => readStream.pipe(res).once('close', r));
114
115
  page.close().catch(noop);
116
+ logger.info('PDF API request completed');
115
117
  };
116
118
  }
@@ -16,6 +16,7 @@ export default class PerformancePost extends BrowserHTTPRoute {
16
16
  const response = await main({
17
17
  browser,
18
18
  context: req.body,
19
+ logger: _logger,
19
20
  timeout: config.getTimeout(),
20
21
  });
21
22
  return jsonResponse(res, 200, response);
@@ -115,5 +115,5 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
115
115
  method: Methods;
116
116
  path: HTTPRoutes[];
117
117
  tags: APITags[];
118
- handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
118
+ handler: (req: Request, res: ServerResponse, logger: Logger, browser: BrowserInstance) => Promise<void>;
119
119
  }
@@ -54,7 +54,8 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
54
54
  method = Methods.post;
55
55
  path = [HTTPRoutes.scrape, HTTPRoutes.chromiumScrape];
56
56
  tags = [APITags.browserAPI];
57
- handler = async (req, res, _logger, browser) => {
57
+ handler = async (req, res, logger, browser) => {
58
+ logger.info('Scrape API invoked with body:', req.body);
58
59
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
59
60
  ? contentTypes.html
60
61
  : req.headers.accept;
@@ -121,6 +122,7 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
121
122
  page.on('request', (req) => {
122
123
  if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
123
124
  rejectResourceTypes.includes(req.resourceType())) {
125
+ logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
124
126
  return req.abort();
125
127
  }
126
128
  const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
@@ -198,6 +200,7 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
198
200
  debug: debugData,
199
201
  };
200
202
  page.close().catch(noop);
203
+ logger.info('Scrape API request completed');
201
204
  return jsonResponse(res, 200, response, false);
202
205
  };
203
206
  }
@@ -46,5 +46,5 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
46
46
  method: Methods;
47
47
  path: HTTPRoutes[];
48
48
  tags: APITags[];
49
- handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
49
+ handler: (req: Request, res: ServerResponse, logger: Logger, browser: BrowserInstance) => Promise<void>;
50
50
  }
@@ -15,7 +15,8 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
15
15
  method = Methods.post;
16
16
  path = [HTTPRoutes.screenshot, HTTPRoutes.chromiumScreenshot];
17
17
  tags = [APITags.browserAPI];
18
- handler = async (req, res, _logger, browser) => {
18
+ handler = async (req, res, logger, browser) => {
19
+ logger.info('Screenshot API invoked with body:', req.body);
19
20
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
20
21
  ? 'image/png'
21
22
  : req.headers.accept;
@@ -61,6 +62,7 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
61
62
  page.on('request', (req) => {
62
63
  if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
63
64
  rejectResourceTypes.includes(req.resourceType())) {
65
+ logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
64
66
  return req.abort();
65
67
  }
66
68
  const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
@@ -122,5 +124,6 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
122
124
  readStream.end(buffer);
123
125
  await new Promise((r) => readStream.pipe(res).once('close', r));
124
126
  page.close().catch(noop);
127
+ logger.info('Screenshot API request completed');
125
128
  };
126
129
  }
@@ -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/types.d.ts CHANGED
@@ -54,7 +54,8 @@ declare abstract class Route {
54
54
  protected _metrics: Browserless['metrics'];
55
55
  protected _monitoring: Browserless['monitoring'];
56
56
  protected _staticSDKDir: Browserless['staticSDKDir'];
57
- constructor(_browserManager: Browserless['browserManager'], _config: Browserless['config'], _fileSystem: Browserless['fileSystem'], _metrics: Browserless['metrics'], _monitoring: Browserless['monitoring'], _staticSDKDir: Browserless['staticSDKDir']);
57
+ protected _limiter: Browserless['limiter'];
58
+ constructor(_browserManager: Browserless['browserManager'], _config: Browserless['config'], _fileSystem: Browserless['fileSystem'], _metrics: Browserless['metrics'], _monitoring: Browserless['monitoring'], _staticSDKDir: Browserless['staticSDKDir'], _limiter: Browserless['limiter']);
58
59
  /**
59
60
  * A unique name to identify this route. Used in downstream
60
61
  * SDKs to potentially remove or disable.
@@ -133,6 +134,12 @@ declare abstract class Route {
133
134
  * @returns {string | null} The full path location of the SDK's static directory
134
135
  */
135
136
  staticSDKDir: () => string | null;
137
+ /**
138
+ * Helper function that loads the limiter module into the router's
139
+ * handler scope.
140
+ * @returns Limiter
141
+ */
142
+ limiter: () => import("@browserless.io/browserless").Limiter;
136
143
  /**
137
144
  * The HTTP path that this route handles, eg '/my-route' OR an
138
145
  * array of paths that this route can handle.
@@ -510,6 +517,7 @@ export declare const BrowserlessManagementRoutes: {
510
517
  ConfigGetRoute: string;
511
518
  MetricsGetRoute: string;
512
519
  MetricsTotalGetRoute: string;
520
+ PressureGetRoute: string;
513
521
  SessionsGetRoute: string;
514
522
  StaticGetRoute: string;
515
523
  };
@@ -518,6 +526,7 @@ export declare const BrowserlessRoutes: {
518
526
  ConfigGetRoute: string;
519
527
  MetricsGetRoute: string;
520
528
  MetricsTotalGetRoute: string;
529
+ PressureGetRoute: string;
521
530
  SessionsGetRoute: string;
522
531
  StaticGetRoute: string;
523
532
  WebKitPlaywrightWebSocketRoute: string;
package/build/types.js CHANGED
@@ -5,13 +5,15 @@ class Route {
5
5
  _metrics;
6
6
  _monitoring;
7
7
  _staticSDKDir;
8
- constructor(_browserManager, _config, _fileSystem, _metrics, _monitoring, _staticSDKDir) {
8
+ _limiter;
9
+ constructor(_browserManager, _config, _fileSystem, _metrics, _monitoring, _staticSDKDir, _limiter) {
9
10
  this._browserManager = _browserManager;
10
11
  this._config = _config;
11
12
  this._fileSystem = _fileSystem;
12
13
  this._metrics = _metrics;
13
14
  this._monitoring = _monitoring;
14
15
  this._staticSDKDir = _staticSDKDir;
16
+ this._limiter = _limiter;
15
17
  }
16
18
  /**
17
19
  * A boolean, or a function that returns a boolean, on
@@ -86,6 +88,12 @@ class Route {
86
88
  * @returns {string | null} The full path location of the SDK's static directory
87
89
  */
88
90
  staticSDKDir = () => this._staticSDKDir;
91
+ /**
92
+ * Helper function that loads the limiter module into the router's
93
+ * handler scope.
94
+ * @returns Limiter
95
+ */
96
+ limiter = () => this._limiter;
89
97
  }
90
98
  /**
91
99
  * A primitive HTTP-based route that doesn't require a
@@ -184,6 +192,7 @@ export const BrowserlessManagementRoutes = {
184
192
  ConfigGetRoute: 'ConfigGetRoute',
185
193
  MetricsGetRoute: 'MetricsGetRoute',
186
194
  MetricsTotalGetRoute: 'MetricsTotalGetRoute',
195
+ PressureGetRoute: 'PressureGetRoute',
187
196
  SessionsGetRoute: 'SessionsGetRoute',
188
197
  StaticGetRoute: 'StaticGetRoute',
189
198
  };
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.10.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.1",
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.9",
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.12",
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.9.0",
79
+ "@typescript-eslint/parser": "^7.9.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"