@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.
- package/CHANGELOG.md +16 -1
- package/bin/browserless.js +8 -4
- package/bin/scaffold/README.md +6 -4
- package/bin/scaffold/src/hello-world.http.ts +6 -1
- package/build/browserless.d.ts +4 -2
- package/build/browserless.js +9 -12
- package/build/exports.d.ts +1 -0
- package/build/exports.js +1 -0
- package/build/logger.d.ts +12 -0
- package/build/logger.js +27 -0
- package/build/router.d.ts +3 -2
- package/build/router.js +10 -6
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +9 -9
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +9 -9
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/firefox/ws/playwright.d.ts +2 -2
- package/build/routes/firefox/ws/playwright.js +1 -1
- package/build/routes/management/http/static.get.d.ts +2 -2
- package/build/routes/management/http/static.get.js +8 -10
- package/build/routes/webkit/ws/playwright.d.ts +2 -2
- package/build/routes/webkit/ws/playwright.js +1 -1
- package/build/sdk-utils.js +23 -10
- package/build/server.d.ts +3 -2
- package/build/server.js +5 -3
- package/build/shared/browser.ws.d.ts +2 -2
- package/build/shared/browser.ws.js +1 -1
- package/build/shared/chromium.playwright.ws.d.ts +2 -2
- package/build/shared/chromium.playwright.ws.js +1 -1
- package/build/shared/chromium.ws.d.ts +2 -2
- package/build/shared/chromium.ws.js +1 -1
- package/build/shared/content.http.d.ts +2 -2
- package/build/shared/content.http.js +1 -1
- package/build/shared/download.http.d.ts +2 -2
- package/build/shared/download.http.js +11 -12
- package/build/shared/function.http.d.ts +2 -2
- package/build/shared/function.http.js +4 -5
- package/build/shared/page.ws.d.ts +2 -2
- package/build/shared/page.ws.js +1 -1
- package/build/shared/pdf.http.d.ts +2 -2
- package/build/shared/pdf.http.js +1 -1
- package/build/shared/performance.http.d.ts +2 -2
- package/build/shared/performance.http.js +1 -1
- package/build/shared/scrape.http.d.ts +2 -2
- package/build/shared/scrape.http.js +1 -1
- package/build/shared/screenshot.http.d.ts +2 -2
- package/build/shared/screenshot.http.js +1 -1
- package/build/shared/utils/function/handler.d.ts +2 -3
- package/build/shared/utils/function/handler.js +7 -7
- package/build/types.d.ts +6 -15
- package/build/types.js +1 -10
- package/package.json +3 -3
- package/scripts/start.sh +2 -1
- package/scripts/test.sh +7 -4
- package/src/browserless.ts +8 -9
- package/src/exports.ts +1 -0
- package/src/logger.ts +31 -0
- package/src/router.ts +9 -7
- package/src/routes/firefox/ws/playwright.ts +2 -0
- package/src/routes/management/http/static.get.ts +15 -10
- package/src/routes/webkit/ws/playwright.ts +2 -0
- package/src/sdk-utils.ts +20 -2
- package/src/server.ts +4 -2
- package/src/shared/browser.ws.ts +2 -0
- package/src/shared/chromium.playwright.ws.ts +2 -0
- package/src/shared/chromium.ws.ts +2 -0
- package/src/shared/content.http.ts +2 -0
- package/src/shared/download.http.ts +14 -11
- package/src/shared/function.http.ts +5 -4
- package/src/shared/page.ws.ts +2 -0
- package/src/shared/pdf.http.ts +2 -0
- package/src/shared/performance.http.ts +2 -0
- package/src/shared/scrape.http.ts +2 -0
- package/src/shared/screenshot.http.ts +2 -0
- package/src/shared/utils/function/handler.ts +8 -12
- package/src/types.ts +5 -9
- package/static/docs/swagger.json +11 -11
- package/static/docs/swagger.min.json +10 -10
- package/static/function/client.js +20 -9
- 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
|
-
|
|
27
|
+
logger.log(`Generating a download directory at "${downloadPath}"`);
|
|
29
28
|
await mkdir(downloadPath);
|
|
30
|
-
const handler = functionHandler(config,
|
|
29
|
+
const handler = functionHandler(config, logger, { downloadPath });
|
|
31
30
|
const response = await handler(req, browser).catch((e) => {
|
|
32
|
-
|
|
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
|
-
|
|
39
|
+
logger.log(`Download function has returned, finding downloads...`);
|
|
41
40
|
async function checkIfDownloadComplete() {
|
|
42
41
|
if (res.headersSent) {
|
|
43
|
-
|
|
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
|
-
|
|
50
|
+
logger.log(`All files have finished downloading`);
|
|
52
51
|
return path.join(downloadPath, fileName);
|
|
53
52
|
}
|
|
54
53
|
const filePath = await checkIfDownloadComplete();
|
|
55
|
-
|
|
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
|
-
|
|
60
|
+
logger.log(`Successfully deleted downloads from disk at "${filePath}"`);
|
|
62
61
|
})
|
|
63
62
|
.catch((err) => {
|
|
64
|
-
|
|
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
|
-
|
|
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,
|
|
23
|
+
const handler = functionHandler(config, logger);
|
|
25
24
|
const { contentType, payload, page } = await handler(req, browser);
|
|
26
|
-
|
|
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
|
-
|
|
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
|
}
|
package/build/shared/page.ws.js
CHANGED
|
@@ -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
|
}
|
package/build/shared/pdf.http.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
+
logger.log(`Received a non-200 response for request "${res.url()}"`);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
page.on('console', (event) => {
|
|
67
|
-
|
|
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
|
-
|
|
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'],
|
|
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,
|
|
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.
|
|
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.
|
|
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.
|
|
93
|
+
"typescript": "^5.4.5",
|
|
94
94
|
"typescript-json-schema": "^0.63.0"
|
|
95
95
|
},
|
|
96
96
|
"eslintConfig": {
|
package/scripts/start.sh
CHANGED
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
|
|
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
|
-
|
|
14
|
-
|
|
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
|
package/src/browserless.ts
CHANGED
|
@@ -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 ||
|
|
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
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
|
+
}
|