@browserless.io/browserless 2.7.1 → 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 (82) hide show
  1. package/CHANGELOG.md +11 -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 +2 -2
  57. package/src/browserless.ts +8 -9
  58. package/src/exports.ts +1 -0
  59. package/src/logger.ts +31 -0
  60. package/src/router.ts +9 -7
  61. package/src/routes/firefox/ws/playwright.ts +2 -0
  62. package/src/routes/management/http/static.get.ts +15 -10
  63. package/src/routes/webkit/ws/playwright.ts +2 -0
  64. package/src/sdk-utils.ts +20 -2
  65. package/src/server.ts +4 -2
  66. package/src/shared/browser.ws.ts +2 -0
  67. package/src/shared/chromium.playwright.ws.ts +2 -0
  68. package/src/shared/chromium.ws.ts +2 -0
  69. package/src/shared/content.http.ts +2 -0
  70. package/src/shared/download.http.ts +14 -11
  71. package/src/shared/function.http.ts +5 -4
  72. package/src/shared/page.ws.ts +2 -0
  73. package/src/shared/pdf.http.ts +2 -0
  74. package/src/shared/performance.http.ts +2 -0
  75. package/src/shared/scrape.http.ts +2 -0
  76. package/src/shared/screenshot.http.ts +2 -0
  77. package/src/shared/utils/function/handler.ts +8 -12
  78. package/src/types.ts +5 -9
  79. package/static/docs/swagger.json +11 -11
  80. package/static/docs/swagger.min.json +10 -10
  81. package/static/function/client.js +20 -9
  82. package/static/function/index.html +20 -9
@@ -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.1",
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",
@@ -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
+ }
package/src/router.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  HTTPManagementRoutes,
7
7
  HTTPRoute,
8
8
  Limiter,
9
+ Logger,
9
10
  Methods,
10
11
  PathTypes,
11
12
  Request,
@@ -30,6 +31,7 @@ export class Router extends EventEmitter {
30
31
  protected config: Config,
31
32
  protected browserManager: BrowserManager,
32
33
  protected limiter: Limiter,
34
+ protected logger: typeof Logger,
33
35
  ) {
34
36
  super();
35
37
  }
@@ -70,7 +72,7 @@ export class Router extends EventEmitter {
70
72
  this.log(`HTTP Request has closed prior to running`);
71
73
  return Promise.resolve();
72
74
  }
73
-
75
+ const logger = new this.logger(route.name, req);
74
76
  if ('browser' in route && route.browser) {
75
77
  const browser = await this.browserManager.getBrowserForRequest(
76
78
  req,
@@ -90,7 +92,7 @@ export class Router extends EventEmitter {
90
92
  try {
91
93
  this.verbose(`Running found HTTP handler.`);
92
94
  return await Promise.race([
93
- handler(req, res, browser),
95
+ handler(req, res, logger, browser),
94
96
  new Promise((resolve, reject) => {
95
97
  res.once('close', () => {
96
98
  if (!res.writableEnded) {
@@ -107,7 +109,7 @@ export class Router extends EventEmitter {
107
109
  }
108
110
  }
109
111
 
110
- return (handler as HTTPRoute['handler'])(req, res);
112
+ return (handler as HTTPRoute['handler'])(req, res, logger);
111
113
  };
112
114
 
113
115
  protected wrapWebSocketHandler =
@@ -120,7 +122,7 @@ export class Router extends EventEmitter {
120
122
  this.log(`WebSocket Request has closed prior to running`);
121
123
  return Promise.resolve();
122
124
  }
123
-
125
+ const logger = new this.logger(route.name, req);
124
126
  if ('browser' in route && route.browser) {
125
127
  const browser = await this.browserManager.getBrowserForRequest(
126
128
  req,
@@ -139,14 +141,14 @@ export class Router extends EventEmitter {
139
141
 
140
142
  try {
141
143
  this.verbose(`Running found WebSocket handler.`);
142
- await handler(req, socket, head, browser);
144
+ await handler(req, socket, head, logger, browser);
143
145
  } finally {
144
146
  this.verbose(`WebSocket Request handler has finished.`);
145
147
  this.browserManager.complete(browser);
146
148
  }
147
149
  return;
148
150
  }
149
- return (handler as WebSocketRoute['handler'])(req, socket, head);
151
+ return (handler as WebSocketRoute['handler'])(req, socket, head, logger);
150
152
  };
151
153
 
152
154
  public registerHTTPRoute(
@@ -230,7 +232,7 @@ export class Router extends EventEmitter {
230
232
  micromatch.isMatch(req.parsed.pathname, p),
231
233
  ) &&
232
234
  r.method === (req.method?.toLocaleLowerCase() as Methods) &&
233
- (accepts.some((a) => a.startsWith('*/*')) ||
235
+ (accepts.some((a) => a.includes('*/*')) ||
234
236
  r.contentTypes.some((contentType) =>
235
237
  accepts.includes(contentType),
236
238
  )) &&
@@ -5,6 +5,7 @@ import {
5
5
  BrowserWebsocketRoute,
6
6
  BrowserlessRoutes,
7
7
  FirefoxPlaywright,
8
+ Logger,
8
9
  Request,
9
10
  SystemQueryParameters,
10
11
  WebsocketRoutes,
@@ -29,6 +30,7 @@ export default class FirefoxPlaywrightWebSocketRoute extends BrowserWebsocketRou
29
30
  req: Request,
30
31
  socket: Duplex,
31
32
  head: Buffer,
33
+ _logger: Logger,
32
34
  browser: FirefoxPlaywright,
33
35
  ): Promise<void> => {
34
36
  const isPlaywright = req.headers['user-agent']