@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
@@ -441,14 +441,14 @@
441
441
  "length": {
442
442
  "type": "number"
443
443
  },
444
- "__@toStringTag@229203": {
444
+ "__@toStringTag@208093": {
445
445
  "type": "string",
446
446
  "const": "Uint8Array"
447
447
  }
448
448
  },
449
449
  "required": [
450
450
  "BYTES_PER_ELEMENT",
451
- "__@toStringTag@229203",
451
+ "__@toStringTag@208093",
452
452
  "buffer",
453
453
  "byteLength",
454
454
  "byteOffset",
@@ -483,13 +483,13 @@
483
483
  "byteLength": {
484
484
  "type": "number"
485
485
  },
486
- "__@toStringTag@229203": {
486
+ "__@toStringTag@208093": {
487
487
  "type": "string"
488
488
  }
489
489
  },
490
490
  "additionalProperties": false,
491
491
  "required": [
492
- "__@toStringTag@229203",
492
+ "__@toStringTag@208093",
493
493
  "byteLength"
494
494
  ]
495
495
  },
@@ -499,18 +499,18 @@
499
499
  "byteLength": {
500
500
  "type": "number"
501
501
  },
502
- "__@species@229304": {
502
+ "__@species@208194": {
503
503
  "$ref": "#/definitions/SharedArrayBuffer"
504
504
  },
505
- "__@toStringTag@229203": {
505
+ "__@toStringTag@208093": {
506
506
  "type": "string",
507
507
  "const": "SharedArrayBuffer"
508
508
  }
509
509
  },
510
510
  "additionalProperties": false,
511
511
  "required": [
512
- "__@species@229304",
513
- "__@toStringTag@229203",
512
+ "__@species@208194",
513
+ "__@toStringTag@208093",
514
514
  "byteLength"
515
515
  ]
516
516
  },
@@ -484,14 +484,14 @@
484
484
  "length": {
485
485
  "type": "number"
486
486
  },
487
- "__@toStringTag@240378": {
487
+ "__@toStringTag@241336": {
488
488
  "type": "string",
489
489
  "const": "Uint8Array"
490
490
  }
491
491
  },
492
492
  "required": [
493
493
  "BYTES_PER_ELEMENT",
494
- "__@toStringTag@240378",
494
+ "__@toStringTag@241336",
495
495
  "buffer",
496
496
  "byteLength",
497
497
  "byteOffset",
@@ -526,13 +526,13 @@
526
526
  "byteLength": {
527
527
  "type": "number"
528
528
  },
529
- "__@toStringTag@240378": {
529
+ "__@toStringTag@241336": {
530
530
  "type": "string"
531
531
  }
532
532
  },
533
533
  "additionalProperties": false,
534
534
  "required": [
535
- "__@toStringTag@240378",
535
+ "__@toStringTag@241336",
536
536
  "byteLength"
537
537
  ]
538
538
  },
@@ -542,18 +542,18 @@
542
542
  "byteLength": {
543
543
  "type": "number"
544
544
  },
545
- "__@species@240479": {
545
+ "__@species@241437": {
546
546
  "$ref": "#/definitions/SharedArrayBuffer"
547
547
  },
548
- "__@toStringTag@240378": {
548
+ "__@toStringTag@241336": {
549
549
  "type": "string",
550
550
  "const": "SharedArrayBuffer"
551
551
  }
552
552
  },
553
553
  "additionalProperties": false,
554
554
  "required": [
555
- "__@species@240479",
556
- "__@toStringTag@240378",
555
+ "__@species@241437",
556
+ "__@toStringTag@241336",
557
557
  "byteLength"
558
558
  ]
559
559
  },
@@ -0,0 +1,63 @@
1
+ /// <reference types="node" />
2
+ import { APITags, HTTPManagementRoutes, HTTPRoute, Methods, Request, contentTypes } from '@browserless.io/browserless';
3
+ import { ServerResponse } from 'http';
4
+ export type ResponseSchema = {
5
+ /**
6
+ * An integer representing the percentage of CPU being used. For instance 92 means 92%
7
+ */
8
+ cpu: number | null;
9
+ /**
10
+ * A number of milliseconds since epoch, or "Date.now()" equivalent.
11
+ */
12
+ date: number;
13
+ /**
14
+ * Whether or not a session can be connected and immediately ran on a health instance.
15
+ */
16
+ isAvailable: boolean;
17
+ /**
18
+ * The maximum amount of browsers that can be ran at a single time.
19
+ */
20
+ maxConcurrent: number;
21
+ /**
22
+ * The maximum amount of queued connections allowed at a single time.
23
+ */
24
+ maxQueued: number;
25
+ /**
26
+ * An integer representing the percentage of Memory being used. For instance 95 means 95%
27
+ */
28
+ memory: number | null;
29
+ /**
30
+ * A human-readable message as the overall status of the instance.
31
+ */
32
+ message: string;
33
+ /**
34
+ * The current number of connect or API calls pending to run.
35
+ */
36
+ queued: number;
37
+ /**
38
+ * A simple single-word reason as to why an instance may or may not be available.
39
+ */
40
+ reason: 'full' | 'cpu' | 'memory' | '';
41
+ /**
42
+ * The number of recent connections that were rejected due to the queue and concurrency
43
+ * limits having been filled.
44
+ */
45
+ recentlyRejected: number;
46
+ /**
47
+ * The current number of running connections or API calls.
48
+ */
49
+ running: number;
50
+ };
51
+ export default class PressureGetRoute extends HTTPRoute {
52
+ name: string;
53
+ accepts: contentTypes[];
54
+ auth: boolean;
55
+ browser: null;
56
+ concurrency: boolean;
57
+ contentTypes: contentTypes[];
58
+ description: string;
59
+ method: Methods;
60
+ path: HTTPManagementRoutes;
61
+ tags: APITags[];
62
+ handler: (_req: Request, res: ServerResponse) => Promise<void>;
63
+ }
@@ -0,0 +1,56 @@
1
+ import { APITags, BrowserlessRoutes, HTTPManagementRoutes, HTTPRoute, Methods, contentTypes, jsonResponse, } from '@browserless.io/browserless';
2
+ export default class PressureGetRoute extends HTTPRoute {
3
+ name = BrowserlessRoutes.PressureGetRoute;
4
+ accepts = [contentTypes.any];
5
+ auth = true;
6
+ browser = null;
7
+ concurrency = false;
8
+ contentTypes = [contentTypes.json];
9
+ description = `Returns a JSON body of stats related to the pressure being created on the instance.`;
10
+ method = Methods.get;
11
+ path = HTTPManagementRoutes.pressure;
12
+ tags = [APITags.management];
13
+ handler = async (_req, res) => {
14
+ const monitoring = this.monitoring();
15
+ const config = this.config();
16
+ const limiter = this.limiter();
17
+ const metrics = this.metrics();
18
+ const { cpuInt: cpu, memoryInt: memory, cpuOverloaded, memoryOverloaded, } = await monitoring.overloaded();
19
+ const date = Date.now();
20
+ const hasCapacity = limiter.hasCapacity;
21
+ const queued = limiter.waiting;
22
+ const isAvailable = hasCapacity && !cpuOverloaded && !memoryOverloaded;
23
+ const running = limiter.executing;
24
+ const recentlyRejected = metrics.get().rejected;
25
+ const maxConcurrent = config.getConcurrent();
26
+ const maxQueued = config.getQueued();
27
+ const reason = !hasCapacity
28
+ ? 'full'
29
+ : cpuOverloaded
30
+ ? 'cpu'
31
+ : memoryOverloaded
32
+ ? 'memory'
33
+ : '';
34
+ const message = !hasCapacity
35
+ ? 'Concurrency and queue are full'
36
+ : cpuOverloaded
37
+ ? 'CPU is over the configured maximum for cpu percent'
38
+ : memoryOverloaded
39
+ ? 'Memory is over the configured maximum for memory percent'
40
+ : '';
41
+ const response = {
42
+ cpu,
43
+ date,
44
+ isAvailable,
45
+ maxConcurrent,
46
+ maxQueued,
47
+ memory,
48
+ message,
49
+ queued,
50
+ reason,
51
+ recentlyRejected,
52
+ running,
53
+ };
54
+ return jsonResponse(res, 200, response);
55
+ };
56
+ }
@@ -0,0 +1,76 @@
1
+ {
2
+ "type": "object",
3
+ "properties": {
4
+ "cpu": {
5
+ "description": "An integer representing the percentage of CPU being used. For instance 92 means 92%",
6
+ "type": [
7
+ "null",
8
+ "number"
9
+ ]
10
+ },
11
+ "date": {
12
+ "description": "A number of milliseconds since epoch, or \"Date.now()\" equivalent.",
13
+ "type": "number"
14
+ },
15
+ "isAvailable": {
16
+ "description": "Whether or not a session can be connected and immediately ran on a health instance.",
17
+ "type": "boolean"
18
+ },
19
+ "maxConcurrent": {
20
+ "description": "The maximum amount of browsers that can be ran at a single time.",
21
+ "type": "number"
22
+ },
23
+ "maxQueued": {
24
+ "description": "The maximum amount of queued connections allowed at a single time.",
25
+ "type": "number"
26
+ },
27
+ "memory": {
28
+ "description": "An integer representing the percentage of Memory being used. For instance 95 means 95%",
29
+ "type": [
30
+ "null",
31
+ "number"
32
+ ]
33
+ },
34
+ "message": {
35
+ "description": "A human-readable message as the overall status of the instance.",
36
+ "type": "string"
37
+ },
38
+ "queued": {
39
+ "description": "The current number of connect or API calls pending to run.",
40
+ "type": "number"
41
+ },
42
+ "reason": {
43
+ "description": "A simple single-word reason as to why an instance may or may not be available.",
44
+ "enum": [
45
+ "",
46
+ "cpu",
47
+ "full",
48
+ "memory"
49
+ ],
50
+ "type": "string"
51
+ },
52
+ "recentlyRejected": {
53
+ "description": "The number of recent connections that were rejected due to the queue and concurrency\nlimits having been filled.",
54
+ "type": "number"
55
+ },
56
+ "running": {
57
+ "description": "The current number of running connections or API calls.",
58
+ "type": "number"
59
+ }
60
+ },
61
+ "additionalProperties": false,
62
+ "required": [
63
+ "cpu",
64
+ "date",
65
+ "isAvailable",
66
+ "maxConcurrent",
67
+ "maxQueued",
68
+ "memory",
69
+ "message",
70
+ "queued",
71
+ "reason",
72
+ "recentlyRejected",
73
+ "running"
74
+ ],
75
+ "$schema": "http://json-schema.org/draft-07/schema#"
76
+ }
@@ -4,7 +4,7 @@ import path from 'path';
4
4
  const pathMap = new Map();
5
5
  const streamFile = (logger, res, file, contentType) => new Promise((resolve, reject) => {
6
6
  if (contentType) {
7
- logger.log(`Setting content-type ${contentType}`);
7
+ logger.debug(`Setting content-type ${contentType}`);
8
8
  res.setHeader('Content-Type', contentType);
9
9
  }
10
10
  return createReadStream(file)
@@ -49,10 +49,10 @@ export default class StaticGetRoute extends HTTPRoute {
49
49
  throw new NotFound(`No route or file found for resource ${req.method}: ${pathname}`);
50
50
  }
51
51
  if (foundFilePaths.length > 1) {
52
- logger.log(`Multiple files found for request to "${pathname}". Only the first file is served, so please name your files uniquely.`);
52
+ logger.warn(`Multiple files found for request to "${pathname}". Only the first file is served, so please name your files uniquely.`);
53
53
  }
54
54
  const [foundFilePath] = foundFilePaths;
55
- logger.verbose(`Found new file "${foundFilePath}", caching path and serving`);
55
+ logger.info(`Found new file "${foundFilePath}", caching path and serving`);
56
56
  const contentType = mimeTypes.get(path.extname(foundFilePath));
57
57
  if (contentType) {
58
58
  res.setHeader('Content-Type', contentType);
@@ -31,6 +31,13 @@ describe('Management APIs', function () {
31
31
  expect(res.status).to.equal(200);
32
32
  });
33
33
  });
34
+ it('allows requests to /pressure', async () => {
35
+ await start();
36
+ await fetch('http://localhost:3000/pressure?token=6R0W53R135510').then(async (res) => {
37
+ expect(res.headers.get('content-type')).to.equal('application/json; charset=UTF-8');
38
+ expect(res.status).to.equal(200);
39
+ });
40
+ });
34
41
  it('allows requests to /sessions', async () => {
35
42
  await start();
36
43
  await fetch('http://localhost:3000/sessions?token=6R0W53R135510').then(async (res) => {
@@ -45,4 +52,13 @@ describe('Management APIs', function () {
45
52
  expect(res.status).to.equal(204);
46
53
  });
47
54
  });
55
+ it('allows HEAD requests to /active', async () => {
56
+ await start();
57
+ await fetch('http://localhost:3000/active?token=6R0W53R135510', {
58
+ method: 'HEAD',
59
+ }).then(async (res) => {
60
+ expect(res.headers.get('content-type')).to.equal('text/plain; charset=UTF-8');
61
+ expect(res.status).to.equal(204);
62
+ });
63
+ });
48
64
  });
package/build/server.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
- /// <reference types="debug" />
3
2
  /// <reference types="node" />
4
3
  /// <reference types="node" />
5
4
  /// <reference types="node" />
@@ -24,8 +23,7 @@ export declare class HTTPServer extends EventEmitter {
24
23
  protected server: http.Server;
25
24
  protected port: number;
26
25
  protected host?: string;
27
- protected log: import("debug").Debugger;
28
- protected verbose: import("debug").Debugger;
26
+ protected logger: BlessLogger;
29
27
  constructor(config: Config, metrics: Metrics, token: Token, router: Router, hooks: Hooks, Logger: typeof BlessLogger);
30
28
  protected onHTTPUnauthorized: (_req: Request, res: Response) => void;
31
29
  protected onWebsocketUnauthorized: (_req: Request, socket: stream.Duplex) => void;
package/build/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as http from 'http';
2
- import { BadRequest, NotFound, Timeout, TooManyRequests, Unauthorized, contentTypes, convertPathToURL, createLogger, queryParamsToObject, readBody, shimLegacyRequests, writeResponse, } from '@browserless.io/browserless';
2
+ import { BadRequest, Logger as BlessLogger, NotFound, Timeout, TooManyRequests, Unauthorized, contentTypes, convertPathToURL, queryParamsToObject, readBody, shimLegacyRequests, writeResponse, } from '@browserless.io/browserless';
3
3
  import { EventEmitter } from 'events';
4
4
  // @ts-ignore
5
5
  import Enjoi from 'enjoi';
@@ -13,8 +13,7 @@ export class HTTPServer extends EventEmitter {
13
13
  server = http.createServer();
14
14
  port;
15
15
  host;
16
- log = createLogger('server');
17
- verbose = createLogger('server:verbose');
16
+ logger = new BlessLogger('server');
18
17
  constructor(config, metrics, token, router, hooks, Logger) {
19
18
  super();
20
19
  this.config = config;
@@ -25,20 +24,20 @@ export class HTTPServer extends EventEmitter {
25
24
  this.Logger = Logger;
26
25
  this.host = config.getHost();
27
26
  this.port = config.getPort();
28
- this.log(`Server instantiated with host "${this.host}" on port "${this.port}" using token "${this.config.getToken()}"`);
27
+ this.logger.info(`Server instantiated with host "${this.host}" on port "${this.port}" using token "${this.config.getToken()}"`);
29
28
  }
30
29
  onHTTPUnauthorized = (_req, res) => {
31
- this.log(`HTTP request is not properly authorized, responding with 401`);
30
+ this.logger.error(`HTTP request is not properly authorized, responding with 401`);
32
31
  this.metrics.addUnauthorized();
33
32
  return writeResponse(res, 401, 'Bad or missing authentication.');
34
33
  };
35
34
  onWebsocketUnauthorized = (_req, socket) => {
36
- this.log(`Websocket request is not properly authorized, responding with 401`);
35
+ this.logger.error(`Websocket request is not properly authorized, responding with 401`);
37
36
  this.metrics.addUnauthorized();
38
37
  return writeResponse(socket, 401, 'Bad or missing authentication.');
39
38
  };
40
39
  async start() {
41
- this.log(`HTTP Server is starting`);
40
+ this.logger.info(`HTTP Server is starting`);
42
41
  this.server.on('request', this.handleRequest);
43
42
  this.server.on('upgrade', this.handleWebSocket);
44
43
  const listenMessage = [
@@ -50,13 +49,13 @@ export class HTTPServer extends EventEmitter {
50
49
  host: this.host,
51
50
  port: this.port,
52
51
  }, undefined, () => {
53
- this.log(listenMessage);
52
+ this.logger.info(listenMessage);
54
53
  r(undefined);
55
54
  });
56
55
  });
57
56
  }
58
57
  handleRequest = async (request, res) => {
59
- this.verbose(`Handling inbound HTTP request on "${request.method}: ${request.url}"`);
58
+ this.logger.trace(`Handling inbound HTTP request on "${request.method}: ${request.url}"`);
60
59
  const req = request;
61
60
  const proceed = await this.hooks.before({ req, res });
62
61
  req.parsed = convertPathToURL(request.url || '', this.config);
@@ -70,6 +69,10 @@ export class HTTPServer extends EventEmitter {
70
69
  return res.end();
71
70
  }
72
71
  }
72
+ if (req.method?.toLowerCase() === 'head') {
73
+ this.logger.debug(`Inbound HEAD request, setting to GET`);
74
+ req.method = 'GET';
75
+ }
73
76
  if (this.config.getAllowGetCalls() &&
74
77
  req.method === 'GET' &&
75
78
  req.parsed.searchParams.has('body')) {
@@ -80,13 +83,13 @@ export class HTTPServer extends EventEmitter {
80
83
  }
81
84
  const route = await this.router.getRouteForHTTPRequest(req);
82
85
  if (!route) {
83
- this.log(`No matching HTTP route handler for "${req.method}: ${req.parsed.href}"`);
86
+ this.logger.error(`No matching HTTP route handler for "${req.method}: ${req.parsed.href}"`);
84
87
  writeResponse(res, 404, 'Not Found');
85
88
  return Promise.resolve();
86
89
  }
87
- this.verbose(`Found matching HTTP route handler "${route.path}"`);
90
+ this.logger.trace(`Found matching HTTP route handler "${route.path}"`);
88
91
  if (route?.auth) {
89
- this.verbose(`Authorizing HTTP request to "${request.url}"`);
92
+ this.logger.trace(`Authorizing HTTP request to "${request.url}"`);
90
93
  const isPermitted = await this.token.isAuthorized(req, route);
91
94
  if (!isPermitted) {
92
95
  return this.onHTTPUnauthorized(req, res);
@@ -104,7 +107,7 @@ export class HTTPServer extends EventEmitter {
104
107
  return Promise.resolve();
105
108
  }
106
109
  if (route.querySchema) {
107
- this.verbose(`Validating route query-params with QUERY schema`);
110
+ this.logger.trace(`Validating route query-params with QUERY schema`);
108
111
  try {
109
112
  const schema = Enjoi.schema(route.querySchema);
110
113
  const valid = schema.validate(req.queryParams, {
@@ -114,19 +117,19 @@ export class HTTPServer extends EventEmitter {
114
117
  const errorDetails = valid.error.details
115
118
  .map(({ message, context, }) => context?.message || message)
116
119
  .join('\n');
117
- this.log(`HTTP query-params contain errors sending 400:${errorDetails}`);
120
+ this.logger.error(`HTTP query-params contain errors sending 400:${errorDetails}`);
118
121
  writeResponse(res, 400, `Query-parameter validation failed: ${errorDetails}`, contentTypes.text);
119
122
  return Promise.resolve();
120
123
  }
121
124
  }
122
125
  catch (e) {
123
- this.log(`Error parsing body schema`, e);
126
+ this.logger.error(`Error parsing body schema`, e);
124
127
  writeResponse(res, 500, 'There was an error handling your request', contentTypes.text);
125
128
  return Promise.resolve();
126
129
  }
127
130
  }
128
131
  if (route.bodySchema) {
129
- this.verbose(`Validating route payload with BODY schema`);
132
+ this.logger.trace(`Validating route payload with BODY schema`);
130
133
  try {
131
134
  const schema = Enjoi.schema(route.bodySchema);
132
135
  const valid = schema.validate(body, { abortEarly: false });
@@ -134,13 +137,13 @@ export class HTTPServer extends EventEmitter {
134
137
  const errorDetails = valid.error.details
135
138
  .map(({ message, context, }) => context?.message || message)
136
139
  .join('\n');
137
- this.log(`HTTP body contain errors sending 400:${errorDetails}`);
140
+ this.logger.error(`HTTP body contain errors sending 400:${errorDetails}`);
138
141
  writeResponse(res, 400, `POST Body validation failed: ${errorDetails}`, contentTypes.text);
139
142
  return Promise.resolve();
140
143
  }
141
144
  }
142
145
  catch (e) {
143
- this.log(`Error parsing body schema`, e);
146
+ this.logger.error(`Error parsing body schema`, e);
144
147
  writeResponse(res, 500, 'There was an error handling your request', contentTypes.text);
145
148
  return Promise.resolve();
146
149
  }
@@ -148,7 +151,7 @@ export class HTTPServer extends EventEmitter {
148
151
  return route
149
152
  .handler(req, res, new this.Logger(route.name, req))
150
153
  .then(() => {
151
- this.verbose('HTTP connection complete');
154
+ this.logger.trace('HTTP connection complete');
152
155
  })
153
156
  .catch((e) => {
154
157
  if (e instanceof BadRequest) {
@@ -170,7 +173,7 @@ export class HTTPServer extends EventEmitter {
170
173
  });
171
174
  };
172
175
  handleWebSocket = async (request, socket, head) => {
173
- this.verbose(`Handling inbound WebSocket request on "${request.url}"`);
176
+ this.logger.trace(`Handling inbound WebSocket request on "${request.url}"`);
174
177
  const req = request;
175
178
  const proceed = await this.hooks.before({ head, req, socket });
176
179
  req.parsed = convertPathToURL(request.url || '', this.config);
@@ -180,16 +183,16 @@ export class HTTPServer extends EventEmitter {
180
183
  req.queryParams = queryParamsToObject(req.parsed.searchParams);
181
184
  const route = await this.router.getRouteForWebSocketRequest(req);
182
185
  if (route) {
183
- this.verbose(`Found matching WebSocket route handler "${route.path}"`);
186
+ this.logger.trace(`Found matching WebSocket route handler "${route.path}"`);
184
187
  if (route?.auth) {
185
- this.verbose(`Authorizing WebSocket request to "${req.parsed.href}"`);
188
+ this.logger.trace(`Authorizing WebSocket request to "${req.parsed.href}"`);
186
189
  const isPermitted = await this.token.isAuthorized(req, route);
187
190
  if (!isPermitted) {
188
191
  return this.onWebsocketUnauthorized(req, socket);
189
192
  }
190
193
  }
191
194
  if (route.querySchema) {
192
- this.verbose(`Validating route query-params with QUERY schema`);
195
+ this.logger.trace(`Validating route query-params with QUERY schema`);
193
196
  try {
194
197
  const schema = Enjoi.schema(route.querySchema);
195
198
  const valid = schema.validate(req.queryParams, {
@@ -199,13 +202,13 @@ export class HTTPServer extends EventEmitter {
199
202
  const errorDetails = valid.error.details
200
203
  .map(({ message, context, }) => context?.message || message)
201
204
  .join('\n');
202
- this.log(`WebSocket query-params contain errors sending 400:${errorDetails}`);
205
+ this.logger.error(`WebSocket query-params contain errors sending 400:${errorDetails}`);
203
206
  writeResponse(socket, 400, `Query-parameter validation failed: ${errorDetails}`, contentTypes.text);
204
207
  return Promise.resolve();
205
208
  }
206
209
  }
207
210
  catch (e) {
208
- this.log(`Error parsing query-params schema`, e);
211
+ this.logger.error(`Error parsing query-params schema`, e);
209
212
  writeResponse(socket, 500, 'There was an error handling your request', contentTypes.text);
210
213
  return Promise.resolve();
211
214
  }
@@ -213,7 +216,7 @@ export class HTTPServer extends EventEmitter {
213
216
  return route
214
217
  .handler(req, socket, head, new this.Logger(route.name, req))
215
218
  .then(() => {
216
- this.verbose('Websocket connection complete');
219
+ this.logger.trace('Websocket connection complete');
217
220
  })
218
221
  .catch((e) => {
219
222
  if (e instanceof BadRequest) {
@@ -228,20 +231,20 @@ export class HTTPServer extends EventEmitter {
228
231
  if (e instanceof TooManyRequests) {
229
232
  return writeResponse(socket, 429, e.message);
230
233
  }
231
- this.log(`Error handling request at "${route.path}": ${e}\n${e.stack}`);
234
+ this.logger.error(`Error handling request at "${route.path}": ${e}\n${e.stack}`);
232
235
  return writeResponse(socket, 500, e.message);
233
236
  });
234
237
  }
235
- this.log(`No matching WebSocket route handler for "${req.parsed.href}"`);
238
+ this.logger.error(`No matching WebSocket route handler for "${req.parsed.href}"`);
236
239
  return writeResponse(socket, 404, 'Not Found');
237
240
  };
238
241
  async shutdown() {
239
- this.log(`HTTP Server is shutting down`);
242
+ this.logger.info(`HTTP Server is shutting down`);
240
243
  await new Promise((r) => this.server.close(r));
241
244
  this.server && this.server.removeAllListeners();
242
245
  // @ts-ignore garbage collect this reference
243
246
  this.server = null;
244
- this.log(`HTTP Server shutdown complete`);
247
+ this.logger.info(`HTTP Server shutdown complete`);
245
248
  }
246
249
  /**
247
250
  * Left blank for downstream SDK modules to optionally implement.
@@ -43,5 +43,5 @@ export default class ChromiumContentPostRoute 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
  }
@@ -10,7 +10,8 @@ export default class ChromiumContentPostRoute extends BrowserHTTPRoute {
10
10
  method = Methods.post;
11
11
  path = [HTTPRoutes.content, HTTPRoutes.chromiumContent];
12
12
  tags = [APITags.browserAPI];
13
- handler = async (req, res, _logger, browser) => {
13
+ handler = async (req, res, logger, browser) => {
14
+ logger.info('Content API invoked with body:', req.body);
14
15
  const contentType = !req.headers.accept || req.headers.accept?.includes('*')
15
16
  ? contentTypes.html
16
17
  : req.headers.accept;
@@ -53,6 +54,7 @@ export default class ChromiumContentPostRoute extends BrowserHTTPRoute {
53
54
  page.on('request', (req) => {
54
55
  if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
55
56
  rejectResourceTypes.includes(req.resourceType())) {
57
+ logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
56
58
  return req.abort();
57
59
  }
58
60
  const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
@@ -102,6 +104,7 @@ export default class ChromiumContentPostRoute extends BrowserHTTPRoute {
102
104
  }
103
105
  const markup = await page.content();
104
106
  page.close().catch(noop);
107
+ logger.info('Content API request completed');
105
108
  return writeResponse(res, 200, markup, contentTypes.html);
106
109
  };
107
110
  }