@browserless.io/browserless 2.7.0 → 2.8.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 (84) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/bin/browserless.js +8 -4
  3. package/bin/scaffold/README.md +6 -4
  4. package/bin/scaffold/src/hello-world.http.ts +6 -1
  5. package/build/browserless.d.ts +4 -2
  6. package/build/browserless.js +9 -12
  7. package/build/exports.d.ts +1 -0
  8. package/build/exports.js +1 -0
  9. package/build/logger.d.ts +12 -0
  10. package/build/logger.js +27 -0
  11. package/build/router.d.ts +3 -2
  12. package/build/router.js +10 -6
  13. package/build/routes/chrome/http/content.post.body.json +8 -8
  14. package/build/routes/chrome/http/pdf.post.body.json +9 -9
  15. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  16. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  17. package/build/routes/chromium/http/content.post.body.json +8 -8
  18. package/build/routes/chromium/http/pdf.post.body.json +9 -9
  19. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  20. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  21. package/build/routes/firefox/ws/playwright.d.ts +2 -2
  22. package/build/routes/firefox/ws/playwright.js +1 -1
  23. package/build/routes/management/http/static.get.d.ts +2 -2
  24. package/build/routes/management/http/static.get.js +8 -10
  25. package/build/routes/webkit/ws/playwright.d.ts +2 -2
  26. package/build/routes/webkit/ws/playwright.js +1 -1
  27. package/build/sdk-utils.js +23 -10
  28. package/build/server.d.ts +3 -2
  29. package/build/server.js +5 -3
  30. package/build/shared/browser.ws.d.ts +2 -2
  31. package/build/shared/browser.ws.js +1 -1
  32. package/build/shared/chromium.playwright.ws.d.ts +2 -2
  33. package/build/shared/chromium.playwright.ws.js +1 -1
  34. package/build/shared/chromium.ws.d.ts +2 -2
  35. package/build/shared/chromium.ws.js +1 -1
  36. package/build/shared/content.http.d.ts +2 -2
  37. package/build/shared/content.http.js +1 -1
  38. package/build/shared/download.http.d.ts +2 -2
  39. package/build/shared/download.http.js +11 -12
  40. package/build/shared/function.http.d.ts +2 -2
  41. package/build/shared/function.http.js +4 -5
  42. package/build/shared/page.ws.d.ts +2 -2
  43. package/build/shared/page.ws.js +1 -1
  44. package/build/shared/pdf.http.d.ts +2 -2
  45. package/build/shared/pdf.http.js +1 -1
  46. package/build/shared/performance.http.d.ts +2 -2
  47. package/build/shared/performance.http.js +1 -1
  48. package/build/shared/scrape.http.d.ts +2 -2
  49. package/build/shared/scrape.http.js +1 -1
  50. package/build/shared/screenshot.http.d.ts +2 -2
  51. package/build/shared/screenshot.http.js +1 -1
  52. package/build/shared/utils/function/handler.d.ts +2 -3
  53. package/build/shared/utils/function/handler.js +7 -7
  54. package/build/types.d.ts +6 -15
  55. package/build/types.js +1 -10
  56. package/package.json +3 -3
  57. package/scripts/start.sh +2 -1
  58. package/scripts/test.sh +7 -4
  59. package/src/browserless.ts +8 -9
  60. package/src/exports.ts +1 -0
  61. package/src/logger.ts +31 -0
  62. package/src/router.ts +9 -7
  63. package/src/routes/firefox/ws/playwright.ts +2 -0
  64. package/src/routes/management/http/static.get.ts +15 -10
  65. package/src/routes/webkit/ws/playwright.ts +2 -0
  66. package/src/sdk-utils.ts +20 -2
  67. package/src/server.ts +4 -2
  68. package/src/shared/browser.ws.ts +2 -0
  69. package/src/shared/chromium.playwright.ws.ts +2 -0
  70. package/src/shared/chromium.ws.ts +2 -0
  71. package/src/shared/content.http.ts +2 -0
  72. package/src/shared/download.http.ts +14 -11
  73. package/src/shared/function.http.ts +5 -4
  74. package/src/shared/page.ws.ts +2 -0
  75. package/src/shared/pdf.http.ts +2 -0
  76. package/src/shared/performance.http.ts +2 -0
  77. package/src/shared/scrape.http.ts +2 -0
  78. package/src/shared/screenshot.http.ts +2 -0
  79. package/src/shared/utils/function/handler.ts +8 -12
  80. package/src/types.ts +5 -9
  81. package/static/docs/swagger.json +11 -11
  82. package/static/docs/swagger.min.json +10 -10
  83. package/static/function/client.js +20 -9
  84. package/static/function/index.html +20 -9
@@ -21,15 +21,14 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
21
21
  method = Methods.post;
22
22
  path = [HTTPRoutes.download, HTTPRoutes.chromiumDownload];
23
23
  tags = [APITags.browserAPI];
24
- handler = async (req, res, browser) => new Promise(async (resolve, reject) => {
25
- const debug = this.debug();
24
+ handler = async (req, res, logger, browser) => new Promise(async (resolve, reject) => {
26
25
  const config = this.config();
27
26
  const downloadPath = path.join(await config.getDownloadsDir(), `.browserless.download.${id()}`);
28
- debug(`Generating a download directory at "${downloadPath}"`);
27
+ logger.log(`Generating a download directory at "${downloadPath}"`);
29
28
  await mkdir(downloadPath);
30
- const handler = functionHandler(config, debug, { downloadPath });
29
+ const handler = functionHandler(config, logger, { downloadPath });
31
30
  const response = await handler(req, browser).catch((e) => {
32
- debug(`Error running download code handler: "${e}"`);
31
+ logger.log(`Error running download code handler: "${e}"`);
33
32
  reject(e);
34
33
  return null;
35
34
  });
@@ -37,10 +36,10 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
37
36
  return;
38
37
  }
39
38
  const { page } = response;
40
- debug(`Download function has returned, finding downloads...`);
39
+ logger.log(`Download function has returned, finding downloads...`);
41
40
  async function checkIfDownloadComplete() {
42
41
  if (res.headersSent) {
43
- debug(`Request headers have been sent, terminating download watch.`);
42
+ logger.log(`Request headers have been sent, terminating download watch.`);
44
43
  return null;
45
44
  }
46
45
  const [fileName] = await readdir(downloadPath);
@@ -48,20 +47,20 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
48
47
  await sleep(500);
49
48
  return checkIfDownloadComplete();
50
49
  }
51
- debug(`All files have finished downloading`);
50
+ logger.log(`All files have finished downloading`);
52
51
  return path.join(downloadPath, fileName);
53
52
  }
54
53
  const filePath = await checkIfDownloadComplete();
55
- debug(`Closing pages.`);
54
+ logger.log(`Closing pages.`);
56
55
  page.close();
57
56
  page.removeAllListeners();
58
57
  const rmDownload = once(() => filePath &&
59
58
  deleteAsync(filePath, { force: true })
60
59
  .then(() => {
61
- debug(`Successfully deleted downloads from disk at "${filePath}"`);
60
+ logger.log(`Successfully deleted downloads from disk at "${filePath}"`);
62
61
  })
63
62
  .catch((err) => {
64
- debug(`Error cleaning up downloaded files: "${err}" at "${filePath}"`);
63
+ logger.log(`Error cleaning up downloaded files: "${err}" at "${filePath}"`);
65
64
  }));
66
65
  if (res.headersSent || !filePath) {
67
66
  rmDownload();
@@ -79,7 +78,7 @@ export default class ChromiumDownloadPostRoute extends BrowserHTTPRoute {
79
78
  }
80
79
  })
81
80
  .on('end', () => {
82
- debug(`Downloads successfully sent`);
81
+ logger.log(`Downloads successfully sent`);
83
82
  rmDownload();
84
83
  return resolve();
85
84
  })
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Methods, Request, SystemQueryParameters, contentTypes } from '@browserless.io/browserless';
2
+ import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Logger, Methods, Request, SystemQueryParameters, contentTypes } from '@browserless.io/browserless';
3
3
  import { ServerResponse } from 'http';
4
4
  interface JSONSchema {
5
5
  code: string;
@@ -27,6 +27,6 @@ export default class ChromiumFunctionPostRoute extends BrowserHTTPRoute {
27
27
  method: Methods;
28
28
  path: HTTPRoutes[];
29
29
  tags: APITags[];
30
- handler: (req: Request, res: ServerResponse, browser: BrowserInstance) => Promise<void>;
30
+ handler: (req: Request, res: ServerResponse, logger: Logger, browser: BrowserInstance) => Promise<void>;
31
31
  }
32
32
  export {};
@@ -18,12 +18,11 @@ export default class ChromiumFunctionPostRoute extends BrowserHTTPRoute {
18
18
  method = Methods.post;
19
19
  path = [HTTPRoutes.function, HTTPRoutes.chromiumFunction];
20
20
  tags = [APITags.browserAPI];
21
- handler = async (req, res, browser) => {
22
- const debug = this.debug();
21
+ handler = async (req, res, logger, browser) => {
23
22
  const config = this.config();
24
- const handler = functionHandler(config, debug);
23
+ const handler = functionHandler(config, logger);
25
24
  const { contentType, payload, page } = await handler(req, browser);
26
- debug(`Got function response of "${contentType}"`);
25
+ logger.log(`Got function response of "${contentType}"`);
27
26
  page.close();
28
27
  page.removeAllListeners();
29
28
  if (contentType === 'uint8array') {
@@ -34,7 +33,7 @@ export default class ChromiumFunctionPostRoute extends BrowserHTTPRoute {
34
33
  throw new BadRequest(`Couldn't determine function's response type.`);
35
34
  }
36
35
  else {
37
- debug(`Sending file-type response of "${type}"`);
36
+ logger.log(`Sending file-type response of "${type}"`);
38
37
  const readStream = new Stream.PassThrough();
39
38
  readStream.end(response);
40
39
  res.setHeader('Content-Type', type);
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { APITags, BrowserWebsocketRoute, CDPLaunchOptions, ChromiumCDP, Request, SystemQueryParameters, WebsocketRoutes } from '@browserless.io/browserless';
3
+ import { APITags, BrowserWebsocketRoute, CDPLaunchOptions, ChromiumCDP, Logger, Request, SystemQueryParameters, WebsocketRoutes } from '@browserless.io/browserless';
4
4
  import { Duplex } from 'stream';
5
5
  export interface QuerySchema extends SystemQueryParameters {
6
6
  launch?: CDPLaunchOptions | string;
@@ -13,5 +13,5 @@ export default class ChromiumPageWebSocketRoute extends BrowserWebsocketRoute {
13
13
  description: string;
14
14
  path: WebsocketRoutes;
15
15
  tags: APITags[];
16
- handler: (req: Request, socket: Duplex, head: Buffer, browser: ChromiumCDP) => Promise<void>;
16
+ handler: (req: Request, socket: Duplex, head: Buffer, _logger: Logger, browser: ChromiumCDP) => Promise<void>;
17
17
  }
@@ -10,5 +10,5 @@ export default class ChromiumPageWebSocketRoute extends BrowserWebsocketRoute {
10
10
  or by finding the page's unique ID from your library of choice.`);
11
11
  path = WebsocketRoutes.page;
12
12
  tags = [APITags.browserWS];
13
- handler = async (req, socket, head, browser) => browser.proxyPageWebSocket(req, socket, head);
13
+ handler = async (req, socket, head, _logger, browser) => browser.proxyPageWebSocket(req, socket, head);
14
14
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Methods, Request, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
2
+ import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Logger, Methods, Request, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
3
3
  import { Page } from 'puppeteer-core';
4
4
  import { ServerResponse } from 'http';
5
5
  export interface BodySchema {
@@ -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, browser: BrowserInstance) => Promise<void>;
46
+ handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
47
47
  }
@@ -16,7 +16,7 @@ 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, browser) => {
19
+ handler = async (req, res, _logger, browser) => {
20
20
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
21
21
  ? 'application/pdf'
22
22
  : req.headers.accept;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Methods, Request, SystemQueryParameters, contentTypes } from '@browserless.io/browserless';
2
+ import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Logger, Methods, Request, SystemQueryParameters, contentTypes } from '@browserless.io/browserless';
3
3
  import { ServerResponse } from 'http';
4
4
  export interface BodySchema {
5
5
  budgets?: Array<object>;
@@ -26,5 +26,5 @@ export default class PerformancePost extends BrowserHTTPRoute {
26
26
  method: Methods;
27
27
  path: HTTPRoutes[];
28
28
  tags: APITags[];
29
- handler: (req: Request, res: ServerResponse, browser: BrowserInstance) => Promise<void>;
29
+ handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
30
30
  }
@@ -11,7 +11,7 @@ export default class PerformancePost extends BrowserHTTPRoute {
11
11
  method = Methods.post;
12
12
  path = [HTTPRoutes.performance, HTTPRoutes.chromiumPerformance];
13
13
  tags = [APITags.browserAPI];
14
- handler = async (req, res, browser) => {
14
+ handler = async (req, res, _logger, browser) => {
15
15
  const config = this.config();
16
16
  const response = await main({
17
17
  browser,
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, InBoundRequest, Methods, OutBoundRequest, Request, ScrapeDebugOptions, ScrapeElementSelector, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
2
+ import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, InBoundRequest, Logger, Methods, OutBoundRequest, Request, ScrapeDebugOptions, ScrapeElementSelector, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
3
3
  import { Cookie, Page } from 'puppeteer-core';
4
4
  import { ServerResponse } from 'http';
5
5
  export interface BodySchema {
@@ -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, browser: BrowserInstance) => Promise<void>;
118
+ handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
119
119
  }
@@ -54,7 +54,7 @@ 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, browser) => {
57
+ handler = async (req, res, _logger, browser) => {
58
58
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
59
59
  ? contentTypes.html
60
60
  : req.headers.accept;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Methods, Request, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
2
+ import { APITags, BrowserHTTPRoute, BrowserInstance, CDPLaunchOptions, ChromiumCDP, HTTPRoutes, Logger, Methods, Request, SystemQueryParameters, WaitForEventOptions, WaitForFunctionOptions, WaitForSelectorOptions, bestAttempt, contentTypes, rejectRequestPattern, rejectResourceTypes, requestInterceptors } from '@browserless.io/browserless';
3
3
  import { Page } from 'puppeteer-core';
4
4
  import { ServerResponse } from 'http';
5
5
  export interface QuerySchema extends SystemQueryParameters {
@@ -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, browser: BrowserInstance) => Promise<void>;
49
+ handler: (req: Request, res: ServerResponse, _logger: Logger, browser: BrowserInstance) => Promise<void>;
50
50
  }
@@ -15,7 +15,7 @@ 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, browser) => {
18
+ handler = async (req, res, _logger, browser) => {
19
19
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
20
20
  ? 'image/png'
21
21
  : req.headers.accept;
@@ -1,7 +1,6 @@
1
- import { BrowserInstance, Config, Request } from '@browserless.io/browserless';
1
+ import { BrowserInstance, Config, Logger, Request } from '@browserless.io/browserless';
2
2
  import { FunctionRunner } from './client.js';
3
3
  import { Page } from 'puppeteer-core';
4
- import debug from 'debug';
5
4
  declare global {
6
5
  interface Window {
7
6
  BrowserlessFunctionRunner: typeof FunctionRunner;
@@ -10,7 +9,7 @@ declare global {
10
9
  interface HandlerOptions {
11
10
  downloadPath?: string;
12
11
  }
13
- declare const _default: (config: Config, debug: debug.Debugger, options?: HandlerOptions) => (req: Request, browser: BrowserInstance) => Promise<{
12
+ declare const _default: (config: Config, logger: Logger, options?: HandlerOptions) => (req: Request, browser: BrowserInstance) => Promise<{
14
13
  contentType: string;
15
14
  page: Page;
16
15
  payload: unknown;
@@ -1,7 +1,7 @@
1
1
  import { BadRequest, HTTPRoutes, contentTypes, convertIfBase64, exists, getTokenFromRequest, id, makeExternalURL, mimeTypes, } from '@browserless.io/browserless';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- export default (config, debug, options = {}) => async (req, browser) => {
4
+ export default (config, logger, options = {}) => async (req, browser) => {
5
5
  const isJson = req.headers['content-type']?.includes('json');
6
6
  const functionAssetLocation = path.join(config.getStatic(), 'function');
7
7
  const functionRequestPath = makeExternalURL(config.getExternalAddress(), HTTPRoutes.function);
@@ -29,7 +29,7 @@ export default (config, debug, options = {}) => async (req, browser) => {
29
29
  */
30
30
  page.on('request', async (request) => {
31
31
  const requestUrl = request.url();
32
- debug(`Outbound Page Request: "${requestUrl}"`);
32
+ logger.log(`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, debug, options = {}) => async (req, browser) => {
48
48
  status: 200,
49
49
  });
50
50
  }
51
- debug(`Static asset request to "${requestUrl}" couldn't be found, 404-ing`);
51
+ logger.log(`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
- debug(`Request: "${requestUrl}" no responder found, continuing...`);
58
+ logger.log(`Request: "${requestUrl}" no responder found, continuing...`);
59
59
  return request.continue();
60
60
  });
61
61
  page.on('response', (res) => {
62
62
  if (res.status() !== 200) {
63
- debug(`Received a non-200 response for request "${res.url()}"`);
63
+ logger.log(`Received a non-200 response for request "${res.url()}"`);
64
64
  }
65
65
  });
66
66
  page.on('console', (event) => {
67
- debug(`${event.type()}: ${event.text()}`);
67
+ logger.log(`${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, debug, options = {}) => async (req, browser) => {
85
85
  });
86
86
  }, browserWSEndpoint, context, functionCodeJS, JSON.stringify(options))
87
87
  .catch((e) => {
88
- debug(`Error running code: ${e}`);
88
+ logger.log(`Error running code: ${e}`);
89
89
  throw new BadRequest(e.message);
90
90
  });
91
91
  return {
package/build/types.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  /// <reference types="node" />
4
- /// <reference types="debug" />
5
4
  import * as http from 'http';
6
5
  import * as stream from 'stream';
7
- import { APITags, Browserless, ChromiumCDP, ChromiumPlaywright, Config, FirefoxPlaywright, HTTPManagementRoutes, HTTPRoutes, Methods, Metrics, Request, WebkitPlaywright, WebsocketRoutes, contentTypes } from '@browserless.io/browserless';
6
+ import { APITags, Browserless, ChromiumCDP, ChromiumPlaywright, Config, FirefoxPlaywright, HTTPManagementRoutes, HTTPRoutes, Logger, Methods, Metrics, Request, WebkitPlaywright, WebsocketRoutes, contentTypes } from '@browserless.io/browserless';
8
7
  import { HTTPRequest, Page, ResponseForRequest, ScreenshotOptions } from 'puppeteer-core';
9
8
  export type PathTypes = HTTPRoutes | WebsocketRoutes | HTTPManagementRoutes | string;
10
9
  export interface BeforeRequest {
@@ -52,11 +51,10 @@ declare abstract class Route {
52
51
  protected _browserManager: Browserless['browserManager'];
53
52
  protected _config: Browserless['config'];
54
53
  protected _fileSystem: Browserless['fileSystem'];
55
- protected _debug: Browserless['debug'];
56
54
  protected _metrics: Browserless['metrics'];
57
55
  protected _monitoring: Browserless['monitoring'];
58
56
  protected _staticSDKDir: Browserless['staticSDKDir'];
59
- constructor(_browserManager: Browserless['browserManager'], _config: Browserless['config'], _fileSystem: Browserless['fileSystem'], _debug: Browserless['debug'], _metrics: Browserless['metrics'], _monitoring: Browserless['monitoring'], _staticSDKDir: Browserless['staticSDKDir']);
57
+ constructor(_browserManager: Browserless['browserManager'], _config: Browserless['config'], _fileSystem: Browserless['fileSystem'], _metrics: Browserless['metrics'], _monitoring: Browserless['monitoring'], _staticSDKDir: Browserless['staticSDKDir']);
60
58
  /**
61
59
  * A unique name to identify this route. Used in downstream
62
60
  * SDKs to potentially remove or disable.
@@ -107,13 +105,6 @@ declare abstract class Route {
107
105
  * @returns Config
108
106
  */
109
107
  config: () => Config;
110
- /**
111
- * Helper function that loads the debug module, useful
112
- * for logging messages scoped to the routes path. Defined
113
- * and injected by browserless after initialization.
114
- * @returns Debug
115
- */
116
- debug: () => import("debug").Debugger;
117
108
  /**
118
109
  * Helper function that loads the file-system module
119
110
  * for interacting with file-systems. Defined and injected by
@@ -184,7 +175,7 @@ export declare abstract class HTTPRoute extends BasicHTTPRoute {
184
175
  /**
185
176
  * Handles an inbound HTTP request, and supplies the Request and Response objects from node's HTTP request event
186
177
  */
187
- abstract handler: (req: Request, res: http.ServerResponse) => Promise<unknown>;
178
+ abstract handler: (req: Request, res: http.ServerResponse, logger: Logger) => Promise<unknown>;
188
179
  }
189
180
  /**
190
181
  * A HTTP-based route, with a handler, that can fulfill requests but
@@ -198,7 +189,7 @@ export declare abstract class BrowserHTTPRoute extends BasicHTTPRoute {
198
189
  * Handles an inbound HTTP request with a 3rd param of the predefined
199
190
  * browser used for the route -- only Chrome CDP is support currently.
200
191
  */
201
- abstract handler: (req: Request, res: http.ServerResponse, browser: BrowserInstance) => Promise<unknown>;
192
+ abstract handler: (req: Request, res: http.ServerResponse, logger: Logger, browser: BrowserInstance) => Promise<unknown>;
202
193
  /**
203
194
  * An optional function to automatically set up or handle new page
204
195
  * creation. Useful for injecting behaviors or other functionality.
@@ -214,7 +205,7 @@ export declare abstract class WebSocketRoute extends Route {
214
205
  /**
215
206
  * Handles an inbound Websocket request, and handles the connection
216
207
  */
217
- abstract handler: (req: Request, socket: stream.Duplex, head: Buffer) => Promise<unknown>;
208
+ abstract handler: (req: Request, socket: stream.Duplex, head: Buffer, logger: Logger) => Promise<unknown>;
218
209
  }
219
210
  /**
220
211
  * A WebSocket-based route, with a handler, that can fulfill requests
@@ -228,7 +219,7 @@ export declare abstract class BrowserWebsocketRoute extends Route {
228
219
  * Handles an inbound Websocket request, and handles the connection
229
220
  * with the prior set browser being injected.
230
221
  */
231
- abstract handler(req: Request, socket: stream.Duplex, head: Buffer, browser: BrowserInstance): Promise<unknown>;
222
+ abstract handler(req: Request, socket: stream.Duplex, head: Buffer, logger: Logger, browser: BrowserInstance): Promise<unknown>;
232
223
  /**
233
224
  * An optional function to automatically set up or handle new page
234
225
  * creation. Useful for injecting behaviors or other functionality.
package/build/types.js CHANGED
@@ -2,15 +2,13 @@ class Route {
2
2
  _browserManager;
3
3
  _config;
4
4
  _fileSystem;
5
- _debug;
6
5
  _metrics;
7
6
  _monitoring;
8
7
  _staticSDKDir;
9
- constructor(_browserManager, _config, _fileSystem, _debug, _metrics, _monitoring, _staticSDKDir) {
8
+ constructor(_browserManager, _config, _fileSystem, _metrics, _monitoring, _staticSDKDir) {
10
9
  this._browserManager = _browserManager;
11
10
  this._config = _config;
12
11
  this._fileSystem = _fileSystem;
13
- this._debug = _debug;
14
12
  this._metrics = _metrics;
15
13
  this._monitoring = _monitoring;
16
14
  this._staticSDKDir = _staticSDKDir;
@@ -60,13 +58,6 @@ class Route {
60
58
  * @returns Config
61
59
  */
62
60
  config = () => this._config;
63
- /**
64
- * Helper function that loads the debug module, useful
65
- * for logging messages scoped to the routes path. Defined
66
- * and injected by browserless after initialization.
67
- * @returns Debug
68
- */
69
- debug = () => this._debug;
70
61
  /**
71
62
  * Helper function that loads the file-system module
72
63
  * for interacting with file-systems. Defined and injected by
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserless.io/browserless",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "license": "SSPL",
5
5
  "description": "The browserless platform",
6
6
  "author": "browserless.io",
@@ -58,7 +58,7 @@
58
58
  "lighthouse": "^11.1.0",
59
59
  "micromatch": "^4.0.4",
60
60
  "playwright-core": "1.43.0",
61
- "puppeteer-core": "^22.6.3",
61
+ "puppeteer-core": "^22.6.4",
62
62
  "puppeteer-extra": "^3.3.6",
63
63
  "puppeteer-extra-plugin-stealth": "^2.11.2",
64
64
  "queue": "^7.0.0",
@@ -90,7 +90,7 @@
90
90
  "prettier": "^3.2.5",
91
91
  "sinon": "^17.0.1",
92
92
  "ts-node": "^10.9.2",
93
- "typescript": "^5.4.4",
93
+ "typescript": "^5.4.5",
94
94
  "typescript-json-schema": "^0.63.0"
95
95
  },
96
96
  "eslintConfig": {
package/scripts/start.sh CHANGED
@@ -13,7 +13,8 @@ _kill_procs() {
13
13
  # Relay quit commands to processes
14
14
  trap _kill_procs SIGTERM SIGINT
15
15
 
16
- if [ -z "$DISPLAY" ] then
16
+ if [ -z "$DISPLAY" ]
17
+ then
17
18
  Xvfb :99 -screen 0 1024x768x16 -nolisten tcp -nolisten unix &
18
19
  xvfb=$!
19
20
  export DISPLAY=:99
package/scripts/test.sh CHANGED
@@ -4,14 +4,17 @@ set -e
4
4
  # Install all dependencies for tests
5
5
  npm i --production=false
6
6
 
7
- # Setup env variables
8
- export DISPLAY=:1
7
+ # Setup Env Variables
9
8
  export DEBUG=-*
10
9
  export PUPPETEER_DISABLE_HEADLESS_WARNING=true
11
10
  export NODE_OPTIONS="--loader ts-node/esm"
12
11
 
13
- Xvfb :1 -screen 0 1024x768x16 -nolisten tcp -nolisten unix &
14
- xvfb=$!
12
+ if [ -z "$DISPLAY" ]
13
+ then
14
+ Xvfb :99 -screen 0 1024x768x16 -nolisten tcp -nolisten unix &
15
+ xvfb=$!
16
+ export DISPLAY=:99
17
+ fi
15
18
 
16
19
  # Run the tests
17
20
  ./node_modules/.bin/_mocha --timeout 30000 --slow 10000 --exit $@ && kill -TERM $xvfb
@@ -1,5 +1,6 @@
1
1
  import * as path from 'path';
2
2
  import {
3
+ Logger as BlessLogger,
3
4
  BrowserHTTPRoute,
4
5
  BrowserManager,
5
6
  BrowserWebsocketRoute,
@@ -51,6 +52,7 @@ export class Browserless extends EventEmitter {
51
52
  protected fileSystem: FileSystem;
52
53
  protected hooks: Hooks;
53
54
  protected limiter: Limiter;
55
+ protected Logger: typeof BlessLogger;
54
56
  protected metrics: Metrics;
55
57
  protected monitoring: Monitoring;
56
58
  protected router: Router;
@@ -71,12 +73,14 @@ export class Browserless extends EventEmitter {
71
73
  fileSystem,
72
74
  hooks,
73
75
  limiter,
76
+ Logger: LoggerOverride,
74
77
  metrics,
75
78
  monitoring,
76
79
  router,
77
80
  token,
78
81
  webhooks,
79
82
  }: {
83
+ Logger?: Browserless['Logger'];
80
84
  browserManager?: Browserless['browserManager'];
81
85
  config?: Browserless['config'];
82
86
  fileSystem?: Browserless['fileSystem'];
@@ -89,6 +93,7 @@ export class Browserless extends EventEmitter {
89
93
  webhooks?: Browserless['webhooks'];
90
94
  } = {}) {
91
95
  super();
96
+ this.Logger = LoggerOverride ?? BlessLogger;
92
97
  this.config = config || new Config();
93
98
  this.metrics = metrics || new Metrics();
94
99
  this.token = token || new Token(this.config);
@@ -108,7 +113,8 @@ export class Browserless extends EventEmitter {
108
113
  this.hooks,
109
114
  );
110
115
  this.router =
111
- router || new Router(this.config, this.browserManager, this.limiter);
116
+ router ||
117
+ new Router(this.config, this.browserManager, this.limiter, this.Logger);
112
118
  }
113
119
 
114
120
  protected saveMetrics = async (): Promise<void> => {
@@ -235,7 +241,6 @@ export class Browserless extends EventEmitter {
235
241
  ...internalHttpRouteFiles,
236
242
  ]) {
237
243
  if (httpRoute.endsWith('js')) {
238
- const { name } = path.parse(httpRoute);
239
244
  const [bodySchema, querySchema] = await Promise.all(
240
245
  routeSchemas.map(async (schemaType) => {
241
246
  const schemaPath = path.parse(httpRoute);
@@ -249,7 +254,6 @@ export class Browserless extends EventEmitter {
249
254
  const routeImport = `${
250
255
  this.config.getIsWin() ? 'file:///' : ''
251
256
  }${httpRoute}`;
252
- const logger = createLogger(`http:${name}`);
253
257
  const {
254
258
  default: Route,
255
259
  }: { default: Implements<HTTPRoute> | Implements<BrowserHTTPRoute> } =
@@ -258,7 +262,6 @@ export class Browserless extends EventEmitter {
258
262
  this.browserManager,
259
263
  this.config,
260
264
  this.fileSystem,
261
- logger,
262
265
  this.metrics,
263
266
  this.monitoring,
264
267
  this.staticSDKDir,
@@ -271,7 +274,6 @@ export class Browserless extends EventEmitter {
271
274
  route.metrics = () => this.metrics;
272
275
  route.monitoring = () => this.monitoring;
273
276
  route.fileSystem = () => this.fileSystem;
274
- route.debug = () => logger;
275
277
  route.staticSDKDir = () => this.staticSDKDir;
276
278
 
277
279
  httpRoutes.push(route);
@@ -285,7 +287,6 @@ export class Browserless extends EventEmitter {
285
287
  ...internalWsRouteFiles,
286
288
  ]) {
287
289
  if (wsRoute.endsWith('js')) {
288
- const { name } = path.parse(wsRoute);
289
290
  const [, querySchema] = await Promise.all(
290
291
  routeSchemas.map(async (schemaType) => {
291
292
  const schemaPath = path.parse(wsRoute);
@@ -299,7 +300,6 @@ export class Browserless extends EventEmitter {
299
300
  const wsImport = `${
300
301
  this.config.getIsWin() ? 'file:///' : ''
301
302
  }${wsRoute}`;
302
- const logger = createLogger(`ws:${name}`);
303
303
  const {
304
304
  default: Route,
305
305
  }: {
@@ -311,7 +311,6 @@ export class Browserless extends EventEmitter {
311
311
  this.browserManager,
312
312
  this.config,
313
313
  this.fileSystem,
314
- logger,
315
314
  this.metrics,
316
315
  this.monitoring,
317
316
  this.staticSDKDir,
@@ -323,7 +322,6 @@ export class Browserless extends EventEmitter {
323
322
  route.metrics = () => this.metrics;
324
323
  route.monitoring = () => this.monitoring;
325
324
  route.fileSystem = () => this.fileSystem;
326
- route.debug = () => logger;
327
325
  route.staticSDKDir = () => this.staticSDKDir;
328
326
 
329
327
  wsRoutes.push(route);
@@ -368,6 +366,7 @@ export class Browserless extends EventEmitter {
368
366
  this.token,
369
367
  this.router,
370
368
  this.hooks,
369
+ this.Logger,
371
370
  );
372
371
 
373
372
  await this.server.start();
package/src/exports.ts CHANGED
@@ -6,6 +6,7 @@ export * from './file-system.js';
6
6
  export * from './hooks.js';
7
7
  export * from './http.js';
8
8
  export * from './limiter.js';
9
+ export * from './logger.js';
9
10
  export * from './metrics.js';
10
11
  export * from './mime-types.js';
11
12
  export * from './monitoring.js';
package/src/logger.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { Request, createLogger } from '@browserless.io/browserless';
2
+
3
+ export class Logger {
4
+ protected _log: ReturnType<typeof createLogger>;
5
+ protected _verbose: ReturnType<typeof createLogger>;
6
+ protected _error: ReturnType<typeof createLogger>;
7
+
8
+ constructor(
9
+ protected prefix: string,
10
+ protected request: Request,
11
+ ) {
12
+ this._log = createLogger(prefix);
13
+ this._verbose = this._log.extend('verbose');
14
+ this._error = this._log.extend('error');
15
+ }
16
+
17
+ public verbose(...messages: string[]) {
18
+ const ip = this.request.socket.remoteAddress ?? 'Unknown';
19
+ this._verbose(ip, ...messages);
20
+ }
21
+
22
+ public log(...messages: string[]) {
23
+ const ip = this.request.socket.remoteAddress ?? 'Unknown';
24
+ this._log(ip, ...messages);
25
+ }
26
+
27
+ public error(...messages: string[]) {
28
+ const ip = this.request.socket.remoteAddress ?? 'Unknown';
29
+ this._error(ip, ...messages);
30
+ }
31
+ }