@browserless.io/browserless 2.7.1 → 2.9.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 +19 -1
- package/README.md +41 -3
- package/assets/debugger.png +0 -0
- package/bin/browserless.js +8 -4
- package/bin/scaffold/README.md +6 -4
- package/bin/scaffold/src/hello-world.http.ts +7 -1
- package/build/browserless.d.ts +8 -5
- package/build/browserless.js +23 -22
- package/build/browsers/chrome.cdp.d.ts +2 -2
- package/build/browsers/chrome.cdp.js +2 -2
- package/build/browsers/chrome.playwright.d.ts +2 -2
- package/build/browsers/chrome.playwright.js +2 -2
- package/build/browsers/chromium.cdp.d.ts +4 -4
- package/build/browsers/chromium.cdp.js +49 -32
- package/build/browsers/chromium.playwright.d.ts +4 -4
- package/build/browsers/chromium.playwright.js +14 -13
- package/build/browsers/firefox.playwright.d.ts +4 -4
- package/build/browsers/firefox.playwright.js +14 -13
- package/build/browsers/index.d.ts +24 -8
- package/build/browsers/index.js +20 -15
- package/build/browsers/webkit.playwright.d.ts +4 -4
- package/build/browsers/webkit.playwright.js +14 -13
- package/build/config.d.ts +3 -0
- package/build/config.js +3 -0
- package/build/exports.d.ts +1 -0
- package/build/exports.js +1 -0
- package/build/file-system.d.ts +2 -3
- package/build/file-system.js +2 -2
- package/build/index.js +7 -7
- package/build/limiter.d.ts +2 -3
- package/build/limiter.js +11 -11
- package/build/logger.d.ts +19 -0
- package/build/logger.js +43 -0
- package/build/monitoring.d.ts +2 -3
- package/build/monitoring.js +4 -4
- package/build/router.d.ts +4 -5
- package/build/router.js +31 -28
- 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/management/tests/management.spec.js +9 -0
- 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 +4 -5
- package/build/server.js +38 -33
- 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 +4 -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/json-protocol.http.d.ts +3 -3
- package/build/shared/json-protocol.http.js +2 -2
- package/build/shared/json-version.http.d.ts +3 -3
- package/build/shared/json-version.http.js +2 -2
- 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 +6 -4
- package/build/shared/performance.http.d.ts +2 -2
- package/build/shared/performance.http.js +2 -1
- package/build/shared/scrape.http.d.ts +2 -2
- package/build/shared/scrape.http.js +4 -1
- package/build/shared/screenshot.http.d.ts +2 -2
- package/build/shared/screenshot.http.js +4 -1
- package/build/shared/utils/function/handler.d.ts +2 -3
- package/build/shared/utils/function/handler.js +8 -8
- package/build/shared/utils/performance/child.js +4 -4
- package/build/shared/utils/performance/main.d.ts +1 -1
- package/build/shared/utils/performance/main.js +5 -7
- package/build/shared/utils/performance/types.d.ts +2 -1
- package/build/types.d.ts +6 -15
- package/build/types.js +1 -10
- package/build/utils.d.ts +1 -1
- package/build/utils.js +6 -2
- package/package.json +18 -15
- package/scripts/install-debugger.js +55 -15
- package/src/browserless.ts +29 -21
- package/src/browsers/chrome.cdp.ts +2 -5
- package/src/browsers/chrome.playwright.ts +2 -5
- package/src/browsers/chromium.cdp.ts +84 -35
- package/src/browsers/chromium.playwright.ts +26 -13
- package/src/browsers/firefox.playwright.ts +28 -13
- package/src/browsers/index.ts +24 -16
- package/src/browsers/webkit.playwright.ts +28 -13
- package/src/config.ts +4 -0
- package/src/exports.ts +1 -0
- package/src/file-system.ts +2 -7
- package/src/index.ts +7 -7
- package/src/limiter.ts +13 -11
- package/src/logger.ts +52 -0
- package/src/monitoring.ts +6 -8
- package/src/router.ts +29 -27
- package/src/routes/firefox/ws/playwright.ts +2 -0
- package/src/routes/management/http/static.get.ts +13 -10
- package/src/routes/management/tests/management.spec.ts +15 -0
- package/src/routes/webkit/ws/playwright.ts +2 -0
- package/src/sdk-utils.ts +20 -2
- package/src/server.ts +47 -32
- 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 +6 -0
- package/src/shared/download.http.ts +14 -11
- package/src/shared/function.http.ts +5 -4
- package/src/shared/json-protocol.http.ts +8 -3
- package/src/shared/json-version.http.ts +8 -4
- package/src/shared/page.ws.ts +2 -0
- package/src/shared/pdf.http.ts +7 -3
- package/src/shared/performance.http.ts +3 -0
- package/src/shared/scrape.http.ts +6 -0
- package/src/shared/screenshot.http.ts +5 -0
- package/src/shared/utils/function/handler.ts +9 -13
- package/src/shared/utils/performance/child.ts +4 -4
- package/src/shared/utils/performance/main.ts +5 -6
- package/src/shared/utils/performance/types.ts +2 -1
- package/src/types.ts +5 -9
- package/src/utils.ts +7 -2
- package/static/docs/swagger.json +11 -11
- package/static/docs/swagger.min.json +10 -10
- package/static/function/client.js +1656 -2916
- package/static/function/index.html +1656 -2916
package/build/shared/pdf.http.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APITags, BadRequest, BrowserHTTPRoute, BrowserlessRoutes, ChromiumCDP, HTTPRoutes, Methods, bestAttemptCatch, contentTypes, dedent, noop, sleep, waitForEvent as waitForEvt, waitForFunction as waitForFn,
|
|
1
|
+
import { APITags, BadRequest, BrowserHTTPRoute, BrowserlessRoutes, ChromiumCDP, HTTPRoutes, Methods, bestAttemptCatch, contentTypes, dedent, noop, sleep, waitForEvent as waitForEvt, waitForFunction as waitForFn, } from '@browserless.io/browserless';
|
|
2
2
|
import { Stream } from 'stream';
|
|
3
3
|
export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
|
|
4
4
|
name = BrowserlessRoutes.ChromiumPDFPostRoute;
|
|
@@ -16,13 +16,13 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
|
|
|
16
16
|
method = Methods.post;
|
|
17
17
|
path = [HTTPRoutes.pdf, HTTPRoutes.chromiumPdf];
|
|
18
18
|
tags = [APITags.browserAPI];
|
|
19
|
-
handler = async (req, res, browser) => {
|
|
19
|
+
handler = async (req, res, logger, browser) => {
|
|
20
|
+
logger.info('PDF API invoked with body:', req.body);
|
|
20
21
|
const contentType = !req.headers.accept || req.headers.accept?.includes('*')
|
|
21
22
|
? 'application/pdf'
|
|
22
23
|
: req.headers.accept;
|
|
23
24
|
if (!req.body) {
|
|
24
|
-
|
|
25
|
-
return;
|
|
25
|
+
throw new BadRequest(`Couldn't parse JSON body`);
|
|
26
26
|
}
|
|
27
27
|
res.setHeader('Content-Type', contentType);
|
|
28
28
|
const { url, gotoOptions, authenticate, html, addScriptTag = [], addStyleTag = [], cookies = [], emulateMediaType, rejectRequestPattern = [], requestInterceptors = [], rejectResourceTypes = [], options, setExtraHTTPHeaders, setJavaScriptEnabled, userAgent, viewport, waitForEvent, waitForFunction, waitForSelector, waitForTimeout, bestAttempt = false, } = req.body;
|
|
@@ -60,6 +60,7 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
|
|
|
60
60
|
page.on('request', (req) => {
|
|
61
61
|
if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
|
|
62
62
|
rejectResourceTypes.includes(req.resourceType())) {
|
|
63
|
+
logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
|
|
63
64
|
return req.abort();
|
|
64
65
|
}
|
|
65
66
|
const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
|
|
@@ -112,5 +113,6 @@ export default class ChromiumPDFPostRoute extends BrowserHTTPRoute {
|
|
|
112
113
|
readStream.end(pdfBuffer);
|
|
113
114
|
await new Promise((r) => readStream.pipe(res).once('close', r));
|
|
114
115
|
page.close().catch(noop);
|
|
116
|
+
logger.info('PDF API request completed');
|
|
115
117
|
};
|
|
116
118
|
}
|
|
@@ -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,11 +11,12 @@ 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,
|
|
18
18
|
context: req.body,
|
|
19
|
+
logger: _logger,
|
|
19
20
|
timeout: config.getTimeout(),
|
|
20
21
|
});
|
|
21
22
|
return jsonResponse(res, 200, response);
|
|
@@ -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,8 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
|
|
|
54
54
|
method = Methods.post;
|
|
55
55
|
path = [HTTPRoutes.scrape, HTTPRoutes.chromiumScrape];
|
|
56
56
|
tags = [APITags.browserAPI];
|
|
57
|
-
handler = async (req, res, browser) => {
|
|
57
|
+
handler = async (req, res, logger, browser) => {
|
|
58
|
+
logger.info('Scrape API invoked with body:', req.body);
|
|
58
59
|
const contentType = !req.headers.accept || req.headers.accept?.includes('*')
|
|
59
60
|
? contentTypes.html
|
|
60
61
|
: req.headers.accept;
|
|
@@ -121,6 +122,7 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
|
|
|
121
122
|
page.on('request', (req) => {
|
|
122
123
|
if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
|
|
123
124
|
rejectResourceTypes.includes(req.resourceType())) {
|
|
125
|
+
logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
|
|
124
126
|
return req.abort();
|
|
125
127
|
}
|
|
126
128
|
const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
|
|
@@ -198,6 +200,7 @@ export default class ChromiumScrapePostRoute extends BrowserHTTPRoute {
|
|
|
198
200
|
debug: debugData,
|
|
199
201
|
};
|
|
200
202
|
page.close().catch(noop);
|
|
203
|
+
logger.info('Scrape API request completed');
|
|
201
204
|
return jsonResponse(res, 200, response, false);
|
|
202
205
|
};
|
|
203
206
|
}
|
|
@@ -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,8 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
|
|
|
15
15
|
method = Methods.post;
|
|
16
16
|
path = [HTTPRoutes.screenshot, HTTPRoutes.chromiumScreenshot];
|
|
17
17
|
tags = [APITags.browserAPI];
|
|
18
|
-
handler = async (req, res, browser) => {
|
|
18
|
+
handler = async (req, res, logger, browser) => {
|
|
19
|
+
logger.info('Screenshot API invoked with body:', req.body);
|
|
19
20
|
const contentType = !req.headers.accept || req.headers.accept?.includes('*')
|
|
20
21
|
? 'image/png'
|
|
21
22
|
: req.headers.accept;
|
|
@@ -61,6 +62,7 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
|
|
|
61
62
|
page.on('request', (req) => {
|
|
62
63
|
if (!!rejectRequestPattern.find((pattern) => req.url().match(pattern)) ||
|
|
63
64
|
rejectResourceTypes.includes(req.resourceType())) {
|
|
65
|
+
logger.debug(`Aborting request ${req.method()}: ${req.url()}`);
|
|
64
66
|
return req.abort();
|
|
65
67
|
}
|
|
66
68
|
const interceptor = requestInterceptors.find((r) => req.url().match(r.pattern));
|
|
@@ -122,5 +124,6 @@ export default class ScreenshotPost extends BrowserHTTPRoute {
|
|
|
122
124
|
readStream.end(buffer);
|
|
123
125
|
await new Promise((r) => readStream.pipe(res).once('close', r));
|
|
124
126
|
page.close().catch(noop);
|
|
127
|
+
logger.info('Screenshot API request completed');
|
|
125
128
|
};
|
|
126
129
|
}
|
|
@@ -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.info(`Outbound Page Request: "${requestUrl}"`);
|
|
33
33
|
if (requestUrl.startsWith(functionRequestPath)) {
|
|
34
34
|
const filename = path.basename(requestUrl);
|
|
35
35
|
if (filename === functionCodeJS) {
|
|
@@ -48,23 +48,23 @@ export default (config, debug, options = {}) => async (req, browser) => {
|
|
|
48
48
|
status: 200,
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
logger.warn(`Static asset request to "${requestUrl}" couldn't be found, 404-ing`);
|
|
52
52
|
return request.respond({
|
|
53
53
|
body: code,
|
|
54
54
|
contentType: `Couldn't locate this file "${filename}" request "${requestUrl}" in "${functionAssetLocation}"`,
|
|
55
55
|
status: 404,
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
logger.info(`Request: "${requestUrl}" no responder found, continuing...`);
|
|
59
59
|
return request.continue();
|
|
60
60
|
});
|
|
61
61
|
page.on('response', (res) => {
|
|
62
|
-
if (res.
|
|
63
|
-
|
|
62
|
+
if (!res.ok()) {
|
|
63
|
+
logger.warn(`Received a non-200 response for request "${res.url()}"`);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
page.on('console', (event) => {
|
|
67
|
-
|
|
67
|
+
logger.trace(`${event.type()}: ${event.text()}`);
|
|
68
68
|
});
|
|
69
69
|
await page.goto(functionIndexHTML);
|
|
70
70
|
const { contentType, payload } = await page
|
|
@@ -85,7 +85,7 @@ export default (config, debug, options = {}) => async (req, browser) => {
|
|
|
85
85
|
});
|
|
86
86
|
}, browserWSEndpoint, context, functionCodeJS, JSON.stringify(options))
|
|
87
87
|
.catch((e) => {
|
|
88
|
-
|
|
88
|
+
logger.error(`Error running code: ${e}`);
|
|
89
89
|
throw new BadRequest(e.message);
|
|
90
90
|
});
|
|
91
91
|
return {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Logger } from '@browserless.io/browserless';
|
|
2
2
|
import lighthouse from 'lighthouse';
|
|
3
|
-
const
|
|
4
|
-
|
|
3
|
+
const logger = new Logger('http:performance:child');
|
|
4
|
+
logger.info(`Child init`);
|
|
5
5
|
const send = (msg) => process.send && process.send(msg);
|
|
6
6
|
const start = async ({ url, config, options }) => {
|
|
7
7
|
try {
|
|
8
|
-
|
|
8
|
+
logger.info(`Child got payload, starting lighthouse`);
|
|
9
9
|
const results = await lighthouse(url, options, config);
|
|
10
10
|
send({
|
|
11
11
|
data: results?.lhr,
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { createLogger } from '@browserless.io/browserless';
|
|
2
1
|
import { fork } from 'child_process';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
const DEFAULT_AUDIT_CONFIG = {
|
|
5
4
|
extends: 'lighthouse:default',
|
|
6
5
|
};
|
|
7
|
-
export default async ({ browser, context, timeout, }) => {
|
|
6
|
+
export default async ({ browser, context, logger, timeout, }) => {
|
|
8
7
|
return new Promise((resolve, reject) => {
|
|
9
|
-
const debug = createLogger('http:performance:main');
|
|
10
8
|
const childPath = path.join('./', 'build', 'shared', 'utils', 'performance', 'child.js');
|
|
11
|
-
|
|
9
|
+
logger.trace(`Starting up child at ${childPath}`);
|
|
12
10
|
const child = fork(childPath);
|
|
13
11
|
const port = new URL(browser.wsEndpoint() || '').port;
|
|
14
12
|
let closed = false;
|
|
@@ -34,13 +32,13 @@ export default async ({ browser, context, timeout, }) => {
|
|
|
34
32
|
port,
|
|
35
33
|
};
|
|
36
34
|
child.on('error', (err) => {
|
|
37
|
-
|
|
35
|
+
logger.error(`Error in child process`, err);
|
|
38
36
|
reject('Performance run error: ' + err.message);
|
|
39
37
|
close(child.pid);
|
|
40
38
|
});
|
|
41
39
|
child.on('message', (payload) => {
|
|
42
40
|
if (payload.event === 'created') {
|
|
43
|
-
|
|
41
|
+
logger.info(`Child process is up, sending performance request`);
|
|
44
42
|
return child.send({
|
|
45
43
|
config,
|
|
46
44
|
event: 'start',
|
|
@@ -49,7 +47,7 @@ export default async ({ browser, context, timeout, }) => {
|
|
|
49
47
|
});
|
|
50
48
|
}
|
|
51
49
|
if (payload.event === 'complete') {
|
|
52
|
-
|
|
50
|
+
logger.info(`Performance gathered, closing and resolving request`);
|
|
53
51
|
close(child.pid);
|
|
54
52
|
return resolve({
|
|
55
53
|
data: payload.data,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { BrowserInstance, Logger } from '@browserless.io/browserless';
|
|
1
2
|
import { Config, Flags } from 'lighthouse';
|
|
2
|
-
import { BrowserInstance } from '@browserless.io/browserless';
|
|
3
3
|
export interface Message {
|
|
4
4
|
data?: unknown;
|
|
5
5
|
error?: unknown;
|
|
@@ -12,6 +12,7 @@ export interface mainOptions {
|
|
|
12
12
|
config?: unknown;
|
|
13
13
|
url: string;
|
|
14
14
|
};
|
|
15
|
+
logger: Logger;
|
|
15
16
|
timeout: number;
|
|
16
17
|
}
|
|
17
18
|
export interface start {
|
package/build/types.d.ts
CHANGED
|
@@ -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/build/utils.d.ts
CHANGED
|
@@ -120,6 +120,6 @@ interface RequestInitTimeout extends RequestInit {
|
|
|
120
120
|
}
|
|
121
121
|
export declare const fetchTimeout: (input: RequestInfo | URL, initWithTimeout?: RequestInitTimeout) => Promise<Response>;
|
|
122
122
|
export declare const untildify: (path: string) => string;
|
|
123
|
-
export declare const printLogo: (docsLink: string) => string;
|
|
123
|
+
export declare const printLogo: (docsLink: string, debugURL?: string | boolean) => string;
|
|
124
124
|
export declare const getCDPClient: (page: Page) => CDPSession;
|
|
125
125
|
export {};
|
package/build/utils.js
CHANGED
|
@@ -561,12 +561,16 @@ export const untildify = (path) => {
|
|
|
561
561
|
const homeDir = homedir();
|
|
562
562
|
return homeDir ? path.replace(/^~(?=$|\/|\\)/, homeDir) : path;
|
|
563
563
|
};
|
|
564
|
-
export const printLogo = (docsLink) => `
|
|
564
|
+
export const printLogo = (docsLink, debugURL) => `
|
|
565
565
|
---------------------------------------------------------
|
|
566
566
|
| browserless.io
|
|
567
567
|
| To read documentation and more, load in your browser:
|
|
568
568
|
|
|
|
569
|
-
| ${docsLink}
|
|
569
|
+
| OpenAPI: ${docsLink}
|
|
570
|
+
| Full Documentation: https://docs.browserless.io/ ${
|
|
571
|
+
/*prettier-ignore*/
|
|
572
|
+
debugURL ? `
|
|
573
|
+
| Debbuger: ${debugURL}` : ""}
|
|
570
574
|
---------------------------------------------------------
|
|
571
575
|
${gradient('#ff1a8c', '#ffea00')(`
|
|
572
576
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
"clean": "node scripts/clean.js",
|
|
26
26
|
"dev": "npm run build:dev && env-cmd -f .env node build",
|
|
27
27
|
"install:adblock": "node scripts/install-adblock.js",
|
|
28
|
+
"install:debugger": "node scripts/install-debugger.js",
|
|
28
29
|
"install:browsers": "npx --yes playwright install chromium firefox webkit chrome",
|
|
29
|
-
"install:dev": "npm run install:browsers",
|
|
30
|
+
"install:dev": "npm run install:browsers && npm run install:debugger",
|
|
30
31
|
"lint": "eslint . --ext .ts --fix",
|
|
31
32
|
"prepack": "npm run build:dev",
|
|
32
33
|
"prettier": "prettier '{src,functions,scripts,bin,external,.github}/**/*.{js,ts,json,yml,yaml,md}' --log-level error --write",
|
|
@@ -55,40 +56,42 @@
|
|
|
55
56
|
"get-port": "^7.1.0",
|
|
56
57
|
"gradient-string": "^2.0.0",
|
|
57
58
|
"http-proxy": "^1.18.1",
|
|
58
|
-
"lighthouse": "^
|
|
59
|
+
"lighthouse": "^12.0.0",
|
|
59
60
|
"micromatch": "^4.0.4",
|
|
60
|
-
"playwright-core": "1.
|
|
61
|
-
"puppeteer-core": "^22.
|
|
61
|
+
"playwright-core": "1.44.0",
|
|
62
|
+
"puppeteer-core": "^22.8.0",
|
|
62
63
|
"puppeteer-extra": "^3.3.6",
|
|
63
64
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
64
65
|
"queue": "^7.0.0",
|
|
65
|
-
"systeminformation": "^5.22.
|
|
66
|
+
"systeminformation": "^5.22.8",
|
|
67
|
+
"tar-fs": "^3.0.6"
|
|
66
68
|
},
|
|
67
69
|
"optionalDependencies": {
|
|
68
|
-
"@types/chai": "^4.3.
|
|
70
|
+
"@types/chai": "^4.3.16",
|
|
69
71
|
"@types/debug": "^4.1.12",
|
|
70
72
|
"@types/gradient-string": "^1.1.6",
|
|
71
73
|
"@types/http-proxy": "^1.17.14",
|
|
72
|
-
"@types/micromatch": "^4.0.
|
|
74
|
+
"@types/micromatch": "^4.0.7",
|
|
73
75
|
"@types/mocha": "^10.0.6",
|
|
74
|
-
"@types/node": "^20.12.
|
|
76
|
+
"@types/node": "^20.12.11",
|
|
75
77
|
"@types/sinon": "^17.0.3",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
77
|
-
"@typescript-eslint/parser": "^7.
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
|
79
|
+
"@typescript-eslint/parser": "^7.8.0",
|
|
78
80
|
"assert": "^2.0.0",
|
|
79
|
-
"chai": "^5.1.
|
|
81
|
+
"chai": "^5.1.1",
|
|
80
82
|
"cross-env": "^7.0.3",
|
|
81
83
|
"env-cmd": "^10.1.0",
|
|
82
|
-
"esbuild": "^0.
|
|
84
|
+
"esbuild": "^0.21.2",
|
|
83
85
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
84
86
|
"eslint": "^8.57.0",
|
|
85
87
|
"eslint-plugin-typescript-sort-keys": "^3.2.0",
|
|
86
88
|
"extract-zip": "^2.0.1",
|
|
87
|
-
"
|
|
89
|
+
"gunzip-maybe": "^1.4.2",
|
|
90
|
+
"marked": "^12.0.2",
|
|
88
91
|
"mocha": "^10.4.0",
|
|
89
92
|
"move-file": "^3.1.0",
|
|
90
93
|
"prettier": "^3.2.5",
|
|
91
|
-
"sinon": "^17.0.
|
|
94
|
+
"sinon": "^17.0.2",
|
|
92
95
|
"ts-node": "^10.9.2",
|
|
93
96
|
"typescript": "^5.4.5",
|
|
94
97
|
"typescript-json-schema": "^0.63.0"
|
|
@@ -1,20 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
/* global fetch, console, process */
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import os from 'os';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
import { deleteAsync } from 'del';
|
|
8
|
+
import gunzip from 'gunzip-maybe';
|
|
9
|
+
import { moveFile } from 'move-file';
|
|
10
|
+
import tar from 'tar-fs';
|
|
6
11
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
14
|
-
|
|
12
|
+
const registryURL = 'https://registry.npmjs.org/@browserless.io/debugger/';
|
|
13
|
+
const tmp = join(os.tmpdir(), 'browserless-debugger');
|
|
14
|
+
const untarDir = join(tmp, 'package', 'static');
|
|
15
|
+
const debuggerDir = join(process.cwd(), 'static', 'debugger');
|
|
16
|
+
|
|
17
|
+
const lastFromArr = (arr) => arr[arr.length - 1];
|
|
18
|
+
const dlAndExtract = (url) =>
|
|
19
|
+
fetch(url).then(
|
|
20
|
+
(response) =>
|
|
21
|
+
new Promise((resolve, reject) => {
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
Readable.fromWeb(response.body)
|
|
24
|
+
.pipe(gunzip())
|
|
25
|
+
.pipe(tar.extract(tmp))
|
|
26
|
+
.on('error', reject)
|
|
27
|
+
.on('finish', resolve);
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const getLatestVersion = async () => {
|
|
32
|
+
const response = await fetch(registryURL);
|
|
33
|
+
const json = await response.json();
|
|
34
|
+
const latest = lastFromArr(Object.keys(json.versions));
|
|
35
|
+
return json.versions[latest];
|
|
36
|
+
};
|
|
15
37
|
|
|
16
38
|
(async () => {
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
if (existsSync(debuggerDir)) {
|
|
40
|
+
await deleteAsync(debuggerDir);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const dist = await getLatestVersion()
|
|
44
|
+
.then((version) => version.dist.tarball)
|
|
45
|
+
.catch((error) => {
|
|
46
|
+
console.error(`Couldn't fetch latest debugger version: ${error.message}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await dlAndExtract(dist).catch((error) => {
|
|
51
|
+
console.error(`Couldn't download debugger: ${error.message}`);
|
|
52
|
+
process.exit(1);
|
|
19
53
|
});
|
|
20
|
-
|
|
54
|
+
|
|
55
|
+
await moveFile(untarDir, debuggerDir);
|
|
56
|
+
await deleteAsync(tmp, { force: true });
|
|
57
|
+
})().catch((error) => {
|
|
58
|
+
console.error(`An error occurred: ${error.message}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|