@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/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,
|
|
@@ -22,7 +23,6 @@ import {
|
|
|
22
23
|
WebSocketRoute,
|
|
23
24
|
WebkitPlaywright,
|
|
24
25
|
availableBrowsers,
|
|
25
|
-
createLogger,
|
|
26
26
|
getRouteFiles,
|
|
27
27
|
makeExternalURL,
|
|
28
28
|
printLogo,
|
|
@@ -45,12 +45,13 @@ type routeInstances =
|
|
|
45
45
|
| BrowserWebsocketRoute;
|
|
46
46
|
|
|
47
47
|
export class Browserless extends EventEmitter {
|
|
48
|
-
protected
|
|
48
|
+
protected logger: BlessLogger;
|
|
49
49
|
protected browserManager: BrowserManager;
|
|
50
50
|
protected config: Config;
|
|
51
51
|
protected fileSystem: FileSystem;
|
|
52
52
|
protected hooks: Hooks;
|
|
53
53
|
protected limiter: Limiter;
|
|
54
|
+
protected Logger: typeof BlessLogger;
|
|
54
55
|
protected metrics: Metrics;
|
|
55
56
|
protected monitoring: Monitoring;
|
|
56
57
|
protected router: Router;
|
|
@@ -71,12 +72,14 @@ export class Browserless extends EventEmitter {
|
|
|
71
72
|
fileSystem,
|
|
72
73
|
hooks,
|
|
73
74
|
limiter,
|
|
75
|
+
Logger: LoggerOverride,
|
|
74
76
|
metrics,
|
|
75
77
|
monitoring,
|
|
76
78
|
router,
|
|
77
79
|
token,
|
|
78
80
|
webhooks,
|
|
79
81
|
}: {
|
|
82
|
+
Logger?: Browserless['Logger'];
|
|
80
83
|
browserManager?: Browserless['browserManager'];
|
|
81
84
|
config?: Browserless['config'];
|
|
82
85
|
fileSystem?: Browserless['fileSystem'];
|
|
@@ -89,6 +92,8 @@ export class Browserless extends EventEmitter {
|
|
|
89
92
|
webhooks?: Browserless['webhooks'];
|
|
90
93
|
} = {}) {
|
|
91
94
|
super();
|
|
95
|
+
this.Logger = LoggerOverride ?? BlessLogger;
|
|
96
|
+
this.logger = new this.Logger('index');
|
|
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> => {
|
|
@@ -123,7 +129,7 @@ export class Browserless extends EventEmitter {
|
|
|
123
129
|
|
|
124
130
|
this.metrics.reset();
|
|
125
131
|
|
|
126
|
-
this.
|
|
132
|
+
this.logger.info(
|
|
127
133
|
`Current period usage: ${JSON.stringify({
|
|
128
134
|
date: aggregatedStats.date,
|
|
129
135
|
error: aggregatedStats.error,
|
|
@@ -140,7 +146,7 @@ export class Browserless extends EventEmitter {
|
|
|
140
146
|
);
|
|
141
147
|
|
|
142
148
|
if (metricsPath) {
|
|
143
|
-
this.
|
|
149
|
+
this.logger.info(`Saving metrics to "${metricsPath}"`);
|
|
144
150
|
this.fileSystem.append(
|
|
145
151
|
metricsPath,
|
|
146
152
|
JSON.stringify(aggregatedStats),
|
|
@@ -164,7 +170,7 @@ export class Browserless extends EventEmitter {
|
|
|
164
170
|
);
|
|
165
171
|
};
|
|
166
172
|
|
|
167
|
-
|
|
173
|
+
protected routeIsDisabled(route: routeInstances) {
|
|
168
174
|
return this.disabledRouteNames.some((name) => name === route.name);
|
|
169
175
|
}
|
|
170
176
|
|
|
@@ -224,18 +230,24 @@ export class Browserless extends EventEmitter {
|
|
|
224
230
|
const [[internalHttpRouteFiles, internalWsRouteFiles], installedBrowsers] =
|
|
225
231
|
await Promise.all([getRouteFiles(this.config), availableBrowsers]);
|
|
226
232
|
|
|
233
|
+
const hasDebugger = await this.config.hasDebugger();
|
|
234
|
+
const debuggerURL =
|
|
235
|
+
hasDebugger &&
|
|
236
|
+
makeExternalURL(
|
|
237
|
+
this.config.getExternalAddress(),
|
|
238
|
+
`/debugger/?token=${this.config.getToken()}`,
|
|
239
|
+
);
|
|
227
240
|
const docsLink = makeExternalURL(this.config.getExternalAddress(), '/docs');
|
|
228
241
|
|
|
229
|
-
this.
|
|
230
|
-
this.
|
|
231
|
-
this.
|
|
242
|
+
this.logger.info(printLogo(docsLink, debuggerURL));
|
|
243
|
+
this.logger.info(`Running as user "${userInfo().username}"`);
|
|
244
|
+
this.logger.info('Starting import of HTTP Routes');
|
|
232
245
|
|
|
233
246
|
for (const httpRoute of [
|
|
234
247
|
...this.httpRouteFiles,
|
|
235
248
|
...internalHttpRouteFiles,
|
|
236
249
|
]) {
|
|
237
250
|
if (httpRoute.endsWith('js')) {
|
|
238
|
-
const { name } = path.parse(httpRoute);
|
|
239
251
|
const [bodySchema, querySchema] = await Promise.all(
|
|
240
252
|
routeSchemas.map(async (schemaType) => {
|
|
241
253
|
const schemaPath = path.parse(httpRoute);
|
|
@@ -249,7 +261,6 @@ export class Browserless extends EventEmitter {
|
|
|
249
261
|
const routeImport = `${
|
|
250
262
|
this.config.getIsWin() ? 'file:///' : ''
|
|
251
263
|
}${httpRoute}`;
|
|
252
|
-
const logger = createLogger(`http:${name}`);
|
|
253
264
|
const {
|
|
254
265
|
default: Route,
|
|
255
266
|
}: { default: Implements<HTTPRoute> | Implements<BrowserHTTPRoute> } =
|
|
@@ -258,7 +269,6 @@ export class Browserless extends EventEmitter {
|
|
|
258
269
|
this.browserManager,
|
|
259
270
|
this.config,
|
|
260
271
|
this.fileSystem,
|
|
261
|
-
logger,
|
|
262
272
|
this.metrics,
|
|
263
273
|
this.monitoring,
|
|
264
274
|
this.staticSDKDir,
|
|
@@ -271,7 +281,6 @@ export class Browserless extends EventEmitter {
|
|
|
271
281
|
route.metrics = () => this.metrics;
|
|
272
282
|
route.monitoring = () => this.monitoring;
|
|
273
283
|
route.fileSystem = () => this.fileSystem;
|
|
274
|
-
route.debug = () => logger;
|
|
275
284
|
route.staticSDKDir = () => this.staticSDKDir;
|
|
276
285
|
|
|
277
286
|
httpRoutes.push(route);
|
|
@@ -279,13 +288,12 @@ export class Browserless extends EventEmitter {
|
|
|
279
288
|
}
|
|
280
289
|
}
|
|
281
290
|
|
|
282
|
-
this.
|
|
291
|
+
this.logger.info('Starting import of WebSocket Routes');
|
|
283
292
|
for (const wsRoute of [
|
|
284
293
|
...this.webSocketRouteFiles,
|
|
285
294
|
...internalWsRouteFiles,
|
|
286
295
|
]) {
|
|
287
296
|
if (wsRoute.endsWith('js')) {
|
|
288
|
-
const { name } = path.parse(wsRoute);
|
|
289
297
|
const [, querySchema] = await Promise.all(
|
|
290
298
|
routeSchemas.map(async (schemaType) => {
|
|
291
299
|
const schemaPath = path.parse(wsRoute);
|
|
@@ -299,7 +307,6 @@ export class Browserless extends EventEmitter {
|
|
|
299
307
|
const wsImport = `${
|
|
300
308
|
this.config.getIsWin() ? 'file:///' : ''
|
|
301
309
|
}${wsRoute}`;
|
|
302
|
-
const logger = createLogger(`ws:${name}`);
|
|
303
310
|
const {
|
|
304
311
|
default: Route,
|
|
305
312
|
}: {
|
|
@@ -311,7 +318,6 @@ export class Browserless extends EventEmitter {
|
|
|
311
318
|
this.browserManager,
|
|
312
319
|
this.config,
|
|
313
320
|
this.fileSystem,
|
|
314
|
-
logger,
|
|
315
321
|
this.metrics,
|
|
316
322
|
this.monitoring,
|
|
317
323
|
this.staticSDKDir,
|
|
@@ -323,7 +329,6 @@ export class Browserless extends EventEmitter {
|
|
|
323
329
|
route.metrics = () => this.metrics;
|
|
324
330
|
route.monitoring = () => this.monitoring;
|
|
325
331
|
route.fileSystem = () => this.fileSystem;
|
|
326
|
-
route.debug = () => logger;
|
|
327
332
|
route.staticSDKDir = () => this.staticSDKDir;
|
|
328
333
|
|
|
329
334
|
wsRoutes.push(route);
|
|
@@ -351,7 +356,7 @@ export class Browserless extends EventEmitter {
|
|
|
351
356
|
.map((r) => r.name);
|
|
352
357
|
|
|
353
358
|
if (duplicateNamedRoutes.length) {
|
|
354
|
-
this.
|
|
359
|
+
this.logger.warn(
|
|
355
360
|
`Found duplicate routing names. Route names must be unique:`,
|
|
356
361
|
duplicateNamedRoutes,
|
|
357
362
|
);
|
|
@@ -360,7 +365,9 @@ export class Browserless extends EventEmitter {
|
|
|
360
365
|
httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
|
|
361
366
|
wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
|
|
362
367
|
|
|
363
|
-
this.
|
|
368
|
+
this.logger.info(
|
|
369
|
+
`Imported and validated all route files, starting up server.`,
|
|
370
|
+
);
|
|
364
371
|
|
|
365
372
|
this.server = new HTTPServer(
|
|
366
373
|
this.config,
|
|
@@ -368,10 +375,11 @@ export class Browserless extends EventEmitter {
|
|
|
368
375
|
this.token,
|
|
369
376
|
this.router,
|
|
370
377
|
this.hooks,
|
|
378
|
+
this.Logger,
|
|
371
379
|
);
|
|
372
380
|
|
|
373
381
|
await this.server.start();
|
|
374
|
-
this.
|
|
382
|
+
this.logger.info(`Starting metrics collection.`);
|
|
375
383
|
this.metricsSaveIntervalID = setInterval(
|
|
376
384
|
() => this.saveMetrics(),
|
|
377
385
|
this.metricsSaveInterval,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
chromeExecutablePath,
|
|
3
|
-
createLogger,
|
|
4
|
-
} from '@browserless.io/browserless';
|
|
1
|
+
import { Logger, chromeExecutablePath } from '@browserless.io/browserless';
|
|
5
2
|
import { ChromiumCDP } from './chromium.cdp.js';
|
|
6
3
|
|
|
7
4
|
export class ChromeCDP extends ChromiumCDP {
|
|
8
5
|
protected executablePath = chromeExecutablePath();
|
|
9
|
-
protected
|
|
6
|
+
protected logger = new Logger('browsers:chrome:cdp');
|
|
10
7
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
chromeExecutablePath,
|
|
3
|
-
createLogger,
|
|
4
|
-
} from '@browserless.io/browserless';
|
|
1
|
+
import { Logger, chromeExecutablePath } from '@browserless.io/browserless';
|
|
5
2
|
import { ChromiumPlaywright } from './chromium.playwright.js';
|
|
6
3
|
|
|
7
4
|
export class ChromePlaywright extends ChromiumPlaywright {
|
|
8
5
|
protected executablePath = chromeExecutablePath();
|
|
9
|
-
protected
|
|
6
|
+
protected logger = new Logger('browsers:chrome:playwright');
|
|
10
7
|
}
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
BLESS_PAGE_IDENTIFIER,
|
|
3
3
|
CDPLaunchOptions,
|
|
4
4
|
Config,
|
|
5
|
+
Logger,
|
|
5
6
|
Request,
|
|
6
7
|
ServerError,
|
|
7
|
-
createLogger,
|
|
8
8
|
noop,
|
|
9
9
|
once,
|
|
10
10
|
} from '@browserless.io/browserless';
|
|
@@ -29,7 +29,7 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
29
29
|
protected browser: Browser | null = null;
|
|
30
30
|
protected browserWSEndpoint: string | null = null;
|
|
31
31
|
protected port?: number;
|
|
32
|
-
protected
|
|
32
|
+
protected logger: Logger;
|
|
33
33
|
protected proxy = httpProxy.createProxyServer();
|
|
34
34
|
protected executablePath = playwright.chromium.executablePath();
|
|
35
35
|
|
|
@@ -37,9 +37,11 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
37
37
|
blockAds,
|
|
38
38
|
config,
|
|
39
39
|
userDataDir,
|
|
40
|
+
logger,
|
|
40
41
|
}: {
|
|
41
42
|
blockAds: boolean;
|
|
42
43
|
config: Config;
|
|
44
|
+
logger: Logger;
|
|
43
45
|
userDataDir: ChromiumCDP['userDataDir'];
|
|
44
46
|
}) {
|
|
45
47
|
super();
|
|
@@ -47,7 +49,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
47
49
|
this.userDataDir = userDataDir;
|
|
48
50
|
this.config = config;
|
|
49
51
|
this.blockAds = blockAds;
|
|
50
|
-
this.
|
|
52
|
+
this.logger = logger;
|
|
53
|
+
|
|
54
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
protected cleanListeners() {
|
|
@@ -63,31 +67,62 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
63
67
|
protected onTargetCreated = async (target: Target) => {
|
|
64
68
|
if (target.type() === 'page') {
|
|
65
69
|
const page = await target.page().catch((e) => {
|
|
66
|
-
this.
|
|
70
|
+
this.logger.error(`Error in ${this.constructor.name} new page ${e}`);
|
|
67
71
|
return null;
|
|
68
72
|
});
|
|
69
73
|
|
|
70
74
|
if (page) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
75
|
+
this.logger.trace(`Setting up file:// protocol request rejection`);
|
|
76
|
+
|
|
77
|
+
page.on('error', (err) => {
|
|
78
|
+
this.logger.error(err);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
page.on('pageerror', (err) => {
|
|
82
|
+
this.logger.warn(err);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
page.on('framenavigated', (frame) => {
|
|
86
|
+
this.logger.trace(`Navigation to ${frame.url()}`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
page.on('console', (message) => {
|
|
90
|
+
this.logger.trace(`${message.type()}: ${message.text()}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
page.on('requestfailed', (req) => {
|
|
94
|
+
this.logger.warn(`"${req.failure()?.errorText}": ${req.url()}`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
page.on('request', async (request) => {
|
|
98
|
+
this.logger.trace(`${request.method()}: ${request.url()}`);
|
|
99
|
+
if (
|
|
100
|
+
!this.config.getAllowFileProtocol() &&
|
|
101
|
+
request.url().startsWith('file://')
|
|
102
|
+
) {
|
|
103
|
+
this.logger.error(
|
|
104
|
+
`File protocol request found in request to ${this.constructor.name}, terminating`,
|
|
105
|
+
);
|
|
106
|
+
page.close().catch(noop);
|
|
107
|
+
this.close();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
page.on('response', async (response) => {
|
|
112
|
+
this.logger.trace(`${response.status()}: ${response.url()}`);
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
!this.config.getAllowFileProtocol() &&
|
|
116
|
+
response.url().startsWith('file://')
|
|
117
|
+
) {
|
|
118
|
+
this.logger.error(
|
|
119
|
+
`File protocol request found in response to ${this.constructor.name}, terminating`,
|
|
120
|
+
);
|
|
121
|
+
page.close().catch(noop);
|
|
122
|
+
this.close();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
91
126
|
this.emit('newPage', page);
|
|
92
127
|
}
|
|
93
128
|
}
|
|
@@ -97,7 +132,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
97
132
|
|
|
98
133
|
public newPage = async (): Promise<Page> => {
|
|
99
134
|
if (!this.browser) {
|
|
100
|
-
throw new ServerError(
|
|
135
|
+
throw new ServerError(
|
|
136
|
+
`${this.constructor.name} hasn't been launched yet!`,
|
|
137
|
+
);
|
|
101
138
|
}
|
|
102
139
|
|
|
103
140
|
return this.browser.newPage();
|
|
@@ -105,7 +142,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
105
142
|
|
|
106
143
|
public close = async (): Promise<void> => {
|
|
107
144
|
if (this.browser) {
|
|
108
|
-
this.
|
|
145
|
+
this.logger.info(
|
|
146
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
147
|
+
);
|
|
109
148
|
this.emit('close');
|
|
110
149
|
this.cleanListeners();
|
|
111
150
|
this.browser.removeAllListeners();
|
|
@@ -122,7 +161,7 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
122
161
|
|
|
123
162
|
public launch = async (options: CDPLaunchOptions = {}): Promise<Browser> => {
|
|
124
163
|
this.port = await getPort();
|
|
125
|
-
this.
|
|
164
|
+
this.logger.info(`${this.constructor.name} got open port ${this.port}`);
|
|
126
165
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
127
166
|
const finalOptions = {
|
|
128
167
|
...options,
|
|
@@ -157,13 +196,17 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
157
196
|
? puppeteerStealth.launch.bind(puppeteerStealth)
|
|
158
197
|
: puppeteer.launch.bind(puppeteer);
|
|
159
198
|
|
|
160
|
-
this.
|
|
161
|
-
|
|
199
|
+
this.logger.info(
|
|
200
|
+
finalOptions,
|
|
201
|
+
`Launching ${this.constructor.name} Handler`,
|
|
202
|
+
);
|
|
162
203
|
this.browser = (await launch(finalOptions)) as Browser;
|
|
163
204
|
this.browser.on('targetcreated', this.onTargetCreated);
|
|
164
205
|
this.running = true;
|
|
165
206
|
this.browserWSEndpoint = this.browser.wsEndpoint();
|
|
166
|
-
this.
|
|
207
|
+
this.logger.info(
|
|
208
|
+
`${this.constructor.name} is running on ${this.browserWSEndpoint}`,
|
|
209
|
+
);
|
|
167
210
|
|
|
168
211
|
return this.browser;
|
|
169
212
|
};
|
|
@@ -199,7 +242,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
199
242
|
);
|
|
200
243
|
}
|
|
201
244
|
socket.once('close', resolve);
|
|
202
|
-
this.
|
|
245
|
+
this.logger.info(
|
|
246
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name}`,
|
|
247
|
+
);
|
|
203
248
|
|
|
204
249
|
const shouldMakePage = req.parsed.pathname.includes(
|
|
205
250
|
BLESS_PAGE_IDENTIFIER,
|
|
@@ -223,7 +268,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
223
268
|
target,
|
|
224
269
|
},
|
|
225
270
|
(error) => {
|
|
226
|
-
this.
|
|
271
|
+
this.logger.error(
|
|
272
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
273
|
+
);
|
|
227
274
|
this.close();
|
|
228
275
|
return reject(error);
|
|
229
276
|
},
|
|
@@ -253,8 +300,8 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
253
300
|
this.browser?.process()?.once('close', close);
|
|
254
301
|
socket.once('close', close);
|
|
255
302
|
|
|
256
|
-
this.
|
|
257
|
-
`Proxying ${req.parsed.href} to
|
|
303
|
+
this.logger.info(
|
|
304
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
258
305
|
);
|
|
259
306
|
|
|
260
307
|
req.url = '';
|
|
@@ -271,7 +318,9 @@ export class ChromiumCDP extends EventEmitter {
|
|
|
271
318
|
target: this.browserWSEndpoint,
|
|
272
319
|
},
|
|
273
320
|
(error) => {
|
|
274
|
-
this.
|
|
321
|
+
this.logger.error(
|
|
322
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
323
|
+
);
|
|
275
324
|
this.close();
|
|
276
325
|
return reject(error);
|
|
277
326
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BrowserServerOptions,
|
|
3
3
|
Config,
|
|
4
|
+
Logger,
|
|
4
5
|
Request,
|
|
5
6
|
ServerError,
|
|
6
|
-
createLogger,
|
|
7
7
|
} from '@browserless.io/browserless';
|
|
8
8
|
import playwright, { Page } from 'playwright-core';
|
|
9
9
|
import { Duplex } from 'stream';
|
|
@@ -15,25 +15,28 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
15
15
|
protected config: Config;
|
|
16
16
|
protected userDataDir: string | null;
|
|
17
17
|
protected running = false;
|
|
18
|
+
protected logger: Logger;
|
|
18
19
|
protected proxy = httpProxy.createProxyServer();
|
|
19
20
|
protected browser: playwright.BrowserServer | null = null;
|
|
20
21
|
protected browserWSEndpoint: string | null = null;
|
|
21
|
-
protected debug = createLogger('browsers:chromium:playwright');
|
|
22
22
|
protected executablePath = playwright.chromium.executablePath();
|
|
23
23
|
|
|
24
24
|
constructor({
|
|
25
25
|
config,
|
|
26
26
|
userDataDir,
|
|
27
|
+
logger,
|
|
27
28
|
}: {
|
|
28
29
|
config: Config;
|
|
30
|
+
logger: Logger;
|
|
29
31
|
userDataDir: ChromiumPlaywright['userDataDir'];
|
|
30
32
|
}) {
|
|
31
33
|
super();
|
|
32
34
|
|
|
33
35
|
this.userDataDir = userDataDir;
|
|
34
36
|
this.config = config;
|
|
37
|
+
this.logger = logger;
|
|
35
38
|
|
|
36
|
-
this.
|
|
39
|
+
this.logger.info(`Starting new ${this.constructor.name} instance`);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
protected cleanListeners() {
|
|
@@ -44,7 +47,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
44
47
|
|
|
45
48
|
public close = async (): Promise<void> => {
|
|
46
49
|
if (this.browser) {
|
|
47
|
-
this.
|
|
50
|
+
this.logger.info(
|
|
51
|
+
`Closing ${this.constructor.name} process and all listeners`,
|
|
52
|
+
);
|
|
48
53
|
this.emit('close');
|
|
49
54
|
this.cleanListeners();
|
|
50
55
|
this.browser.close();
|
|
@@ -57,18 +62,22 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
57
62
|
public pages = async (): Promise<[]> => [];
|
|
58
63
|
|
|
59
64
|
public getPageId = (): string => {
|
|
60
|
-
throw new ServerError(
|
|
65
|
+
throw new ServerError(
|
|
66
|
+
`#getPageId is not yet supported with ${this.constructor.name}.`,
|
|
67
|
+
);
|
|
61
68
|
};
|
|
62
69
|
|
|
63
70
|
public makeLiveURL = (): void => {
|
|
64
71
|
throw new ServerError(
|
|
65
|
-
`Live URLs are not yet supported with this
|
|
72
|
+
`Live URLs are not yet supported with ${this.constructor.name}. In the future this will be at "${this.config.getExternalAddress()}"`,
|
|
66
73
|
);
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
public newPage = async (): Promise<Page> => {
|
|
70
77
|
if (!this.browser || !this.browserWSEndpoint) {
|
|
71
|
-
throw new ServerError(
|
|
78
|
+
throw new ServerError(
|
|
79
|
+
`${this.constructor.name} hasn't been launched yet!`,
|
|
80
|
+
);
|
|
72
81
|
}
|
|
73
82
|
const browser = await playwright.chromium.connect(this.browserWSEndpoint);
|
|
74
83
|
return await browser.newPage();
|
|
@@ -77,7 +86,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
77
86
|
public launch = async (
|
|
78
87
|
options: BrowserServerOptions = {},
|
|
79
88
|
): Promise<playwright.BrowserServer> => {
|
|
80
|
-
this.
|
|
89
|
+
this.logger.info(`Launching ${this.constructor.name} Handler`);
|
|
81
90
|
|
|
82
91
|
this.browser = await playwright.chromium.launchServer({
|
|
83
92
|
...options,
|
|
@@ -91,7 +100,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
91
100
|
|
|
92
101
|
const browserWSEndpoint = this.browser.wsEndpoint();
|
|
93
102
|
|
|
94
|
-
this.
|
|
103
|
+
this.logger.info(
|
|
104
|
+
`${this.constructor.name} is running on ${browserWSEndpoint}`,
|
|
105
|
+
);
|
|
95
106
|
this.running = true;
|
|
96
107
|
this.browserWSEndpoint = browserWSEndpoint;
|
|
97
108
|
|
|
@@ -118,7 +129,7 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
118
129
|
};
|
|
119
130
|
|
|
120
131
|
public proxyPageWebSocket = async () => {
|
|
121
|
-
|
|
132
|
+
this.logger.warn(`${this.constructor.name} Not yet implemented`);
|
|
122
133
|
};
|
|
123
134
|
|
|
124
135
|
public proxyWebSocket = async (
|
|
@@ -134,8 +145,8 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
134
145
|
}
|
|
135
146
|
socket.once('close', resolve);
|
|
136
147
|
|
|
137
|
-
this.
|
|
138
|
-
`Proxying ${req.parsed.href} to
|
|
148
|
+
this.logger.info(
|
|
149
|
+
`Proxying ${req.parsed.href} to ${this.constructor.name} ${this.browserWSEndpoint}`,
|
|
139
150
|
);
|
|
140
151
|
|
|
141
152
|
// Delete headers known to cause issues
|
|
@@ -152,7 +163,9 @@ export class ChromiumPlaywright extends EventEmitter {
|
|
|
152
163
|
target: this.browserWSEndpoint,
|
|
153
164
|
},
|
|
154
165
|
(error) => {
|
|
155
|
-
this.
|
|
166
|
+
this.logger.error(
|
|
167
|
+
`Error proxying session to ${this.constructor.name}: ${error}`,
|
|
168
|
+
);
|
|
156
169
|
this.close();
|
|
157
170
|
return reject(error);
|
|
158
171
|
},
|