@browserless.io/browserless 2.2.0 → 2.3.0-beta-2
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/README.md +2 -2
- package/bin/browserless.js +67 -27
- package/bin/scaffold/README.md +50 -0
- package/bin/scaffold/src/hello-world.http.ts +2 -1
- package/build/browserless.d.ts +3 -0
- package/build/browserless.js +43 -19
- package/build/browsers/chrome.cdp.js +1 -1
- package/build/browsers/chrome.playwright.js +1 -1
- package/build/browsers/index.d.ts +1 -0
- package/build/browsers/index.js +4 -1
- package/build/data/classes.json +1 -1
- package/build/data/selectors.json +1 -1
- package/build/exports.js +1 -2
- package/build/limiter.d.ts +2 -1
- package/build/limiter.js +6 -3
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/content.post.d.ts +2 -1
- package/build/routes/chrome/http/content.post.js +3 -2
- package/build/routes/chrome/http/download.post.d.ts +2 -1
- package/build/routes/chrome/http/download.post.js +3 -2
- package/build/routes/chrome/http/function.post.d.ts +2 -1
- package/build/routes/chrome/http/function.post.js +3 -2
- package/build/routes/chrome/http/json-list.get.d.ts +5 -1
- package/build/routes/chrome/http/json-list.get.js +5 -1
- package/build/routes/chrome/http/json-new.put.d.ts +5 -1
- package/build/routes/chrome/http/json-new.put.js +5 -1
- package/build/routes/chrome/http/json-protocol.get.d.ts +5 -1
- package/build/routes/chrome/http/json-protocol.get.js +5 -1
- package/build/routes/chrome/http/json-version.get.d.ts +5 -1
- package/build/routes/chrome/http/json-version.get.js +5 -1
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.d.ts +2 -1
- package/build/routes/chrome/http/pdf.post.js +3 -2
- package/build/routes/chrome/http/performance.post.d.ts +2 -1
- package/build/routes/chrome/http/performance.post.js +3 -2
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.d.ts +2 -1
- package/build/routes/chrome/http/scrape.post.js +3 -2
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.d.ts +2 -1
- package/build/routes/chrome/http/screenshot.post.js +3 -2
- package/build/routes/chrome/ws/browser.d.ts +2 -1
- package/build/routes/chrome/ws/browser.js +3 -2
- package/build/routes/chrome/ws/cdp.d.ts +2 -1
- package/build/routes/chrome/ws/cdp.js +3 -2
- package/build/routes/chrome/ws/page.d.ts +3 -2
- package/build/routes/chrome/ws/page.js +3 -2
- package/build/routes/chrome/ws/playwright.d.ts +1 -0
- package/build/routes/chrome/ws/playwright.js +2 -1
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- 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 +7 -2
- package/build/routes/firefox/ws/playwright.js +3 -2
- package/build/routes/firefox/ws/playwright.query.json +29 -31
- package/build/routes/management/http/config.get.d.ts +1 -0
- package/build/routes/management/http/config.get.js +2 -1
- package/build/routes/management/http/metrics-total.get.d.ts +1 -0
- package/build/routes/management/http/metrics-total.get.js +2 -1
- package/build/routes/management/http/metrics.get.d.ts +1 -0
- package/build/routes/management/http/metrics.get.js +2 -1
- package/build/routes/management/http/sessions.get.d.ts +1 -0
- package/build/routes/management/http/sessions.get.js +2 -1
- package/build/routes/management/http/static.get.d.ts +1 -0
- package/build/routes/management/http/static.get.js +8 -7
- package/build/routes/webkit/ws/playwright.d.ts +2 -1
- package/build/routes/webkit/ws/playwright.js +3 -2
- package/build/shared/browser.ws.d.ts +2 -1
- package/build/shared/browser.ws.js +3 -2
- package/build/shared/chromium.playwright.ws.d.ts +2 -1
- package/build/shared/chromium.playwright.ws.js +3 -2
- package/build/shared/chromium.ws.d.ts +2 -1
- package/build/shared/chromium.ws.js +3 -2
- package/build/shared/content.http.d.ts +2 -1
- package/build/shared/content.http.js +3 -2
- package/build/shared/download.http.d.ts +2 -1
- package/build/shared/download.http.js +3 -2
- package/build/shared/function.http.d.ts +2 -1
- package/build/shared/function.http.js +3 -2
- package/build/shared/json-list.http.d.ts +2 -1
- package/build/shared/json-list.http.js +3 -2
- package/build/shared/json-new.http.d.ts +2 -1
- package/build/shared/json-new.http.js +3 -2
- package/build/shared/json-protocol.http.d.ts +2 -1
- package/build/shared/json-protocol.http.js +3 -2
- package/build/shared/json-version.http.d.ts +2 -1
- package/build/shared/json-version.http.js +3 -2
- package/build/shared/page.ws.d.ts +2 -1
- package/build/shared/page.ws.js +3 -2
- package/build/shared/pdf.http.d.ts +2 -1
- package/build/shared/pdf.http.js +3 -2
- package/build/shared/performance.http.d.ts +1 -0
- package/build/shared/performance.http.js +2 -1
- package/build/shared/scrape.http.d.ts +2 -1
- package/build/shared/scrape.http.js +3 -2
- package/build/shared/screenshot.http.d.ts +1 -0
- package/build/shared/screenshot.http.js +2 -1
- package/build/shared/utils/performance/main.js +1 -1
- package/build/types.d.ts +91 -0
- package/build/types.js +54 -0
- package/build/utils.d.ts +1 -1
- package/build/utils.js +11 -6
- package/docker/chromium/Dockerfile +1 -2
- package/docker/firefox/Dockerfile +1 -2
- package/docker/multi/Dockerfile +2 -4
- package/docker/webkit/Dockerfile +1 -2
- package/package.json +11 -11
- package/scripts/build-open-api.js +142 -124
- package/src/browserless.ts +60 -22
- package/src/browsers/chrome.cdp.ts +1 -1
- package/src/browsers/chrome.playwright.ts +1 -1
- package/src/browsers/index.ts +5 -1
- package/src/exports.ts +1 -3
- package/src/limiter.ts +7 -3
- package/src/router.ts +6 -2
- package/src/routes/chrome/http/content.post.ts +7 -2
- package/src/routes/chrome/http/download.post.ts +7 -2
- package/src/routes/chrome/http/function.post.ts +7 -2
- package/src/routes/chrome/http/json-list.get.ts +7 -1
- package/src/routes/chrome/http/json-new.put.ts +7 -1
- package/src/routes/chrome/http/json-protocol.get.ts +7 -1
- package/src/routes/chrome/http/json-version.get.ts +7 -1
- package/src/routes/chrome/http/pdf.post.ts +7 -2
- package/src/routes/chrome/http/performance.post.ts +7 -2
- package/src/routes/chrome/http/scrape.post.ts +7 -2
- package/src/routes/chrome/http/screenshot.post.ts +7 -2
- package/src/routes/chrome/ws/browser.ts +3 -2
- package/src/routes/chrome/ws/cdp.ts +7 -2
- package/src/routes/chrome/ws/page.ts +3 -2
- package/src/routes/chrome/ws/playwright.ts +6 -1
- package/src/routes/firefox/ws/playwright.ts +6 -2
- package/src/routes/management/http/config.get.ts +2 -0
- package/src/routes/management/http/metrics-total.get.ts +2 -0
- package/src/routes/management/http/metrics.get.ts +2 -0
- package/src/routes/management/http/sessions.get.ts +2 -0
- package/src/routes/management/http/static.get.ts +16 -9
- package/src/routes/webkit/ws/playwright.ts +3 -1
- package/src/shared/browser.ws.ts +3 -1
- package/src/shared/chromium.playwright.ws.ts +3 -1
- package/src/shared/chromium.ws.ts +3 -1
- package/src/shared/content.http.ts +3 -1
- package/src/shared/download.http.ts +3 -1
- package/src/shared/function.http.ts +3 -1
- package/src/shared/json-list.http.ts +3 -1
- package/src/shared/json-new.http.ts +3 -1
- package/src/shared/json-protocol.http.ts +3 -1
- package/src/shared/json-version.http.ts +3 -1
- package/src/shared/page.ws.ts +3 -1
- package/src/shared/pdf.http.ts +3 -1
- package/src/shared/performance.http.ts +2 -0
- package/src/shared/scrape.http.ts +3 -1
- package/src/shared/screenshot.http.ts +2 -0
- package/src/shared/utils/performance/main.ts +1 -2
- package/src/types.ts +66 -0
- package/src/utils.ts +13 -7
- package/static/docs/swagger.json +91 -49
- package/static/docs/swagger.min.json +6697 -0
- package/static/function/client.js +323 -323
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ If you've been struggling to deploy headless browsers without running into issue
|
|
|
23
23
|
4. [Hosting](#hosting-providers)
|
|
24
24
|
5. [Puppeteer](#puppeteer)
|
|
25
25
|
6. [Playwright](#playwright)
|
|
26
|
-
7. [Extending with NodeJS SDK](#extending-nodejs-
|
|
26
|
+
7. [Extending with NodeJS SDK](#extending-nodejs-sdk)
|
|
27
27
|
8. [Licensing](#licensing)
|
|
28
28
|
9. [Changelog](https://github.com/browserless/chrome/blob/master/CHANGELOG.md)
|
|
29
29
|
|
|
@@ -102,7 +102,7 @@ const browser = await pw.chromium.connectOverCDP('ws://localhost:3000');
|
|
|
102
102
|
|
|
103
103
|
After that, the rest of your code remains the same with no other changes required.
|
|
104
104
|
|
|
105
|
-
# Extending (NodeJS
|
|
105
|
+
# Extending (NodeJS SDK)
|
|
106
106
|
|
|
107
107
|
Browserless comes with built-in extension capabilities, and allows for extending nearly any aspect of the system (for Version 2+). For more details on how to write your own routes, build docker images, and more, [see our SDK README.md](/bin/scaffold/README.md) or simply run "npx @browserless.io/browserless create" in a terminal and follow the onscreen prompts.
|
|
108
108
|
|
package/bin/browserless.js
CHANGED
|
@@ -33,11 +33,6 @@ const allowedCMDs = [
|
|
|
33
33
|
'help',
|
|
34
34
|
'clean',
|
|
35
35
|
];
|
|
36
|
-
const projectDir = process.cwd();
|
|
37
|
-
const compiledDir = path.join(projectDir, 'build');
|
|
38
|
-
const packageJSON = readFile(path.join(__dirname, '..', 'package.json')).then(
|
|
39
|
-
(r) => JSON.parse(r.toString()),
|
|
40
|
-
);
|
|
41
36
|
|
|
42
37
|
if (!allowedCMDs.includes(cmd)) {
|
|
43
38
|
throw new Error(
|
|
@@ -45,6 +40,21 @@ if (!allowedCMDs.includes(cmd)) {
|
|
|
45
40
|
);
|
|
46
41
|
}
|
|
47
42
|
|
|
43
|
+
const projectDir = process.cwd();
|
|
44
|
+
const buildDir = 'build';
|
|
45
|
+
const srcDir = 'src';
|
|
46
|
+
const compiledDir = path.join(projectDir, buildDir);
|
|
47
|
+
|
|
48
|
+
const projectPackageJSON = readFile(path.join(projectDir, 'package.json'))
|
|
49
|
+
.then((r) => JSON.parse(r.toString()))
|
|
50
|
+
.catch(() => null);
|
|
51
|
+
|
|
52
|
+
const browserlessPackageJSON = readFile(
|
|
53
|
+
path.join(__dirname, '..', 'package.json'),
|
|
54
|
+
).then((r) => JSON.parse(r.toString()));
|
|
55
|
+
|
|
56
|
+
const camelCase = (str) => str.replace(/-([a-z])/g, (_, w) => w.toUpperCase());
|
|
57
|
+
|
|
48
58
|
const prompt = async (question) => {
|
|
49
59
|
const rl = createInterface({
|
|
50
60
|
input: process.stdin,
|
|
@@ -60,22 +70,43 @@ const prompt = async (question) => {
|
|
|
60
70
|
});
|
|
61
71
|
};
|
|
62
72
|
|
|
63
|
-
const
|
|
73
|
+
const translateSrcToBuild = (directory) => {
|
|
74
|
+
const srcToBuild = directory.replace(srcDir, '');
|
|
75
|
+
const pathParsed = path.parse(srcToBuild);
|
|
76
|
+
return path.format({ ...pathParsed, base: '', ext: '.js' });
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const importDefault = async (files, fileName) => {
|
|
80
|
+
const pJSON = await projectPackageJSON;
|
|
81
|
+
// Check first if overrides are manually specified in the project's package.json
|
|
82
|
+
if (pJSON && pJSON.browserless && typeof pJSON.browserless === 'object') {
|
|
83
|
+
const camelCaseFileName = camelCase(fileName);
|
|
84
|
+
const relativePath = pJSON.browserless[camelCaseFileName];
|
|
85
|
+
if (relativePath) {
|
|
86
|
+
const fullFilePath = path.join(
|
|
87
|
+
compiledDir,
|
|
88
|
+
translateSrcToBuild(relativePath),
|
|
89
|
+
);
|
|
90
|
+
log(`Importing module from package.json: "${fullFilePath}"`);
|
|
91
|
+
return (await import(fullFilePath)).default;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
const classModuleFile = files.find((f) =>
|
|
65
|
-
path.parse(f).name.endsWith(
|
|
96
|
+
path.parse(f).name.endsWith(fileName),
|
|
66
97
|
);
|
|
67
98
|
|
|
68
99
|
if (!classModuleFile) {
|
|
69
100
|
return;
|
|
70
101
|
}
|
|
71
102
|
|
|
72
|
-
const
|
|
103
|
+
const fullFilePath = path.join(compiledDir, classModuleFile);
|
|
73
104
|
|
|
74
105
|
if (!classModuleFile) {
|
|
75
106
|
return;
|
|
76
107
|
}
|
|
77
|
-
log(`Importing module
|
|
78
|
-
return (await import(
|
|
108
|
+
log(`Importing module from found files: "${fullFilePath}"`);
|
|
109
|
+
return (await import(fullFilePath)).default;
|
|
79
110
|
};
|
|
80
111
|
|
|
81
112
|
const clean = async () =>
|
|
@@ -120,7 +151,7 @@ const buildDockerImage = async (cmd) => {
|
|
|
120
151
|
|
|
121
152
|
const buildTypeScript = async () =>
|
|
122
153
|
new Promise((resolve, reject) => {
|
|
123
|
-
spawn('npx', ['tsc', '--outDir',
|
|
154
|
+
spawn('npx', ['tsc', '--outDir', buildDir], {
|
|
124
155
|
cwd: projectDir,
|
|
125
156
|
stdio: 'inherit',
|
|
126
157
|
}).once('close', (code) => {
|
|
@@ -209,7 +240,8 @@ const build = async () => {
|
|
|
209
240
|
);
|
|
210
241
|
|
|
211
242
|
log(`Generating OpenAPI JSON file`);
|
|
212
|
-
await
|
|
243
|
+
const disabledRoutes = await importDefault(files, 'disabled-routes');
|
|
244
|
+
await buildOpenAPI(httpRoutes, webSocketRoutes, disabledRoutes);
|
|
213
245
|
|
|
214
246
|
log(`All built assets complete`);
|
|
215
247
|
|
|
@@ -239,16 +271,18 @@ const start = async (dev = false) => {
|
|
|
239
271
|
Router,
|
|
240
272
|
Token,
|
|
241
273
|
Webhooks,
|
|
274
|
+
disabledRoutes,
|
|
242
275
|
] = await Promise.all([
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
276
|
+
importDefault(files, 'browser-manager'),
|
|
277
|
+
importDefault(files, 'config'),
|
|
278
|
+
importDefault(files, 'file-system'),
|
|
279
|
+
importDefault(files, 'limiter'),
|
|
280
|
+
importDefault(files, 'metrics'),
|
|
281
|
+
importDefault(files, 'monitoring'),
|
|
282
|
+
importDefault(files, 'router'),
|
|
283
|
+
importDefault(files, 'token'),
|
|
284
|
+
importDefault(files, 'webhooks'),
|
|
285
|
+
importDefault(files, 'disabled-routes'),
|
|
252
286
|
]);
|
|
253
287
|
|
|
254
288
|
log(`Starting Browserless`);
|
|
@@ -285,6 +319,15 @@ const start = async (dev = false) => {
|
|
|
285
319
|
webhooks,
|
|
286
320
|
});
|
|
287
321
|
|
|
322
|
+
if (disabledRoutes !== undefined) {
|
|
323
|
+
if (!Array.isArray(disabledRoutes)) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`The "disabled-routes.ts" default export should be an array of Route classes.`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
browserless.disableRoutes(...disabledRoutes);
|
|
329
|
+
}
|
|
330
|
+
|
|
288
331
|
httpRoutes.forEach((r) => browserless.addHTTPRoute(r));
|
|
289
332
|
webSocketRoutes.forEach((r) => browserless.addWebSocketRoute(r));
|
|
290
333
|
|
|
@@ -328,7 +371,7 @@ const start = async (dev = false) => {
|
|
|
328
371
|
};
|
|
329
372
|
|
|
330
373
|
const buildDocker = async () => {
|
|
331
|
-
const finalDockerPath = path.join(
|
|
374
|
+
const finalDockerPath = path.join(compiledDir, 'Dockerfile');
|
|
332
375
|
const argSwitches = getArgSwitches();
|
|
333
376
|
|
|
334
377
|
await build();
|
|
@@ -339,10 +382,7 @@ const buildDocker = async () => {
|
|
|
339
382
|
|
|
340
383
|
log(`Generating Dockerfile at "${finalDockerPath}"`);
|
|
341
384
|
|
|
342
|
-
await fs.writeFile(
|
|
343
|
-
path.join(projectDir, 'build', 'Dockerfile'),
|
|
344
|
-
dockerContents,
|
|
345
|
-
);
|
|
385
|
+
await fs.writeFile(compiledDir, dockerContents);
|
|
346
386
|
|
|
347
387
|
const from =
|
|
348
388
|
argSwitches.from ||
|
|
@@ -424,7 +464,7 @@ const create = async () => {
|
|
|
424
464
|
const to = path.join(installPath, sdkFile);
|
|
425
465
|
if (sdkFile === 'package.json') {
|
|
426
466
|
const sdkPackageJSONTemplate = (await readFile(from)).toString();
|
|
427
|
-
const { version } = await
|
|
467
|
+
const { version } = await browserlessPackageJSON;
|
|
428
468
|
const sdkPackageJSON = sdkPackageJSONTemplate.replace(
|
|
429
469
|
'${BROWSERLESS_VERSION}',
|
|
430
470
|
version,
|
package/bin/scaffold/README.md
CHANGED
|
@@ -13,6 +13,7 @@ Finally, this SDK and Browserless.io are built to support businesses and enterpr
|
|
|
13
13
|
- [Routing](#routing)
|
|
14
14
|
- [Utilities](#utilities)
|
|
15
15
|
- [Extending Modules](#extending-modules)
|
|
16
|
+
- [Disabling Routes](#dis)
|
|
16
17
|
- [Running in Development](#running-in-development)
|
|
17
18
|
- [Building for Production](#building-for-production)
|
|
18
19
|
- [Running without Building](#running-without-building)
|
|
@@ -133,6 +134,9 @@ export type ResponseSchema = string;
|
|
|
133
134
|
|
|
134
135
|
// Similar to React and other ecosystems, extend our basic HTTPRoute
|
|
135
136
|
export default class HelloWorldRoute extends HTTPRoute {
|
|
137
|
+
// Must have a unique name for things like disabling to work if desired
|
|
138
|
+
name = 'PDFToS3Route';
|
|
139
|
+
|
|
136
140
|
// Detail any content-types that this route should except. "contentTypes.any" here means any content-type.
|
|
137
141
|
// If the content-type does not match then a 404 will be sent back
|
|
138
142
|
accepts = [contentTypes.any];
|
|
@@ -192,6 +196,9 @@ export interface QuerySchema extends SystemQueryParameters {
|
|
|
192
196
|
}
|
|
193
197
|
|
|
194
198
|
export default class ChromiumWebSocketRoute extends BrowserWebsocketRoute {
|
|
199
|
+
// Must have a unique name for things like disabling to work if desired
|
|
200
|
+
name = 'ChromiumWebSocketRoute';
|
|
201
|
+
|
|
195
202
|
// This route requires a valid authorization token.
|
|
196
203
|
auth = true;
|
|
197
204
|
|
|
@@ -297,6 +304,9 @@ export interface BodySchema {
|
|
|
297
304
|
}
|
|
298
305
|
|
|
299
306
|
export default class PDFToS3Route extends BrowserHTTPRoute {
|
|
307
|
+
// Must have a unique name for things like disabling to work if desired
|
|
308
|
+
name = 'PDFToS3Route';
|
|
309
|
+
|
|
300
310
|
// Our route only accepts JSON content-types, and the rest 404
|
|
301
311
|
accepts = [contentTypes.json];
|
|
302
312
|
|
|
@@ -347,6 +357,46 @@ export default class PDFToS3Route extends BrowserHTTPRoute {
|
|
|
347
357
|
|
|
348
358
|
With this approach you can effectively write, extend and author your own workflows within browserless!
|
|
349
359
|
|
|
360
|
+
## Disabling Routes
|
|
361
|
+
|
|
362
|
+
You can disable access to core routes by specifying the route names you want to disable in a file named `disabled-routes.ts`. Browserless will scan all directories for a file named as such, and disable the named classes exported by this file. The alternative is to create a `browserless` property in your package.json file that contains a `disabledRoutes` string pointing to the relative path of your disabled routes file.
|
|
363
|
+
|
|
364
|
+
For example, if you want to disable all metrics, config, and session information your `src/disabled-routes.ts` file would look like this:
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
import { BrowserlessRoutes } from '@browserless.io/browserless';
|
|
368
|
+
|
|
369
|
+
export default [
|
|
370
|
+
BrowserlessRoutes.ConfigGetRoute,
|
|
371
|
+
BrowserlessRoutes.SessionsGetGetRoute,
|
|
372
|
+
BrowserlessRoutes.MetricsGetRoute,
|
|
373
|
+
BrowserlessRoutes.MetricsTotalGetRoute,
|
|
374
|
+
];
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
And in the package.json file, it'd look like this:
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{
|
|
381
|
+
// ... lots of package.json stuff
|
|
382
|
+
"browserless": {
|
|
383
|
+
"disabledRoutes": "./src/disabled-routes.ts"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
In order for route-disabling to work, you must have a `default` export that's an array of names. Browserless exports every route name it builds and runs internally, meaning you simply need to pass them through this `disabled-routes.ts` file after importing them.
|
|
389
|
+
|
|
390
|
+
Disabling a route will do several things:
|
|
391
|
+
|
|
392
|
+
- Return a `404` HTTP response when trying to call any of these routes.
|
|
393
|
+
- Remove them from the embedded documentation site that is auto-generated.
|
|
394
|
+
- Removes them from the OpenAPI JSON Schematic.
|
|
395
|
+
- Prevents their type information from being converted from TypeScript to runtime validation.
|
|
396
|
+
- It doesn't, however, remove them from Node's Module cache.
|
|
397
|
+
|
|
398
|
+
All of Browserless' internal routes are side-effect free, meaning their largely state-less and don't do exhibit kind of behavior aside from route handling and metrics reporting. Having them in Node's module cache is fine since they're never mounted in the router and set up as a potential route.
|
|
399
|
+
|
|
350
400
|
## Running in Development
|
|
351
401
|
|
|
352
402
|
After the project has been set up, you can use npm commands to build and run your code. The most important of these is the `npm run dev` command, which will do the following:
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
export type ResponseSchema = string;
|
|
12
12
|
|
|
13
|
-
export default class
|
|
13
|
+
export default class HelloWorldHTTPRoute extends HTTPRoute {
|
|
14
|
+
name = 'HelloWorldHTTPRoute';
|
|
14
15
|
accepts = [contentTypes.any];
|
|
15
16
|
auth = true;
|
|
16
17
|
browser = null;
|
package/build/browserless.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class Browserless {
|
|
|
12
12
|
protected router: Router;
|
|
13
13
|
protected token: Token;
|
|
14
14
|
protected webhooks: WebHooks;
|
|
15
|
+
disabledRouteNames: string[];
|
|
15
16
|
webSocketRouteFiles: string[];
|
|
16
17
|
httpRouteFiles: string[];
|
|
17
18
|
server?: HTTPServer;
|
|
@@ -30,6 +31,8 @@ export declare class Browserless {
|
|
|
30
31
|
});
|
|
31
32
|
protected saveMetrics: () => Promise<void>;
|
|
32
33
|
setMetricsSaveInterval: (interval: number) => void;
|
|
34
|
+
private routeIsDisabled;
|
|
35
|
+
disableRoutes(...routeNames: string[]): void;
|
|
33
36
|
addHTTPRoute(httpRouteFilePath: string): void;
|
|
34
37
|
addWebSocketRoute(webSocketRouteFilePath: string): void;
|
|
35
38
|
setPort(port: number): void;
|
package/build/browserless.js
CHANGED
|
@@ -14,6 +14,7 @@ export class Browserless {
|
|
|
14
14
|
router;
|
|
15
15
|
token;
|
|
16
16
|
webhooks;
|
|
17
|
+
disabledRouteNames = [];
|
|
17
18
|
webSocketRouteFiles = [];
|
|
18
19
|
httpRouteFiles = [];
|
|
19
20
|
server;
|
|
@@ -69,6 +70,12 @@ export class Browserless {
|
|
|
69
70
|
this.metricsSaveInterval = interval;
|
|
70
71
|
this.metricsSaveIntervalID = setInterval(this.saveMetrics, this.metricsSaveInterval);
|
|
71
72
|
};
|
|
73
|
+
routeIsDisabled(route) {
|
|
74
|
+
return this.disabledRouteNames.some((name) => name === route.name);
|
|
75
|
+
}
|
|
76
|
+
disableRoutes(...routeNames) {
|
|
77
|
+
this.disabledRouteNames.push(...routeNames);
|
|
78
|
+
}
|
|
72
79
|
addHTTPRoute(httpRouteFilePath) {
|
|
73
80
|
this.httpRouteFiles.push(httpRouteFilePath);
|
|
74
81
|
}
|
|
@@ -95,12 +102,15 @@ export class Browserless {
|
|
|
95
102
|
ChromiumPlaywright,
|
|
96
103
|
WebkitPlaywright,
|
|
97
104
|
];
|
|
98
|
-
const [[
|
|
105
|
+
const [[internalHttpRouteFiles, internalWsRouteFiles], installedBrowsers] = await Promise.all([getRouteFiles(this.config), availableBrowsers]);
|
|
99
106
|
const docsLink = makeExternalURL(this.config.getExternalAddress(), '/docs');
|
|
100
107
|
this.debug(printLogo(docsLink));
|
|
101
108
|
this.debug(`Running as user "${userInfo().username}"`);
|
|
102
109
|
this.debug('Starting import of HTTP Routes');
|
|
103
|
-
for (const httpRoute of [
|
|
110
|
+
for (const httpRoute of [
|
|
111
|
+
...internalHttpRouteFiles,
|
|
112
|
+
...this.httpRouteFiles,
|
|
113
|
+
]) {
|
|
104
114
|
if (httpRoute.endsWith('js')) {
|
|
105
115
|
const { name } = path.parse(httpRoute);
|
|
106
116
|
const [bodySchema, querySchema] = await Promise.all(routeSchemas.map(async (schemaType) => {
|
|
@@ -112,18 +122,23 @@ export class Browserless {
|
|
|
112
122
|
const logger = createLogger(`http:${name}`);
|
|
113
123
|
const { default: Route, } = await import(routeImport + `?cb=${Date.now()}`);
|
|
114
124
|
const route = new Route(this.browserManager, this.config, this.fileSystem, logger, this.metrics, this.monitoring);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
if (!this.routeIsDisabled(route)) {
|
|
126
|
+
route.bodySchema = safeParse(bodySchema);
|
|
127
|
+
route.querySchema = safeParse(querySchema);
|
|
128
|
+
route.config = () => this.config;
|
|
129
|
+
route.metrics = () => this.metrics;
|
|
130
|
+
route.monitoring = () => this.monitoring;
|
|
131
|
+
route.fileSystem = () => this.fileSystem;
|
|
132
|
+
route.debug = () => logger;
|
|
133
|
+
httpRoutes.push(route);
|
|
134
|
+
}
|
|
123
135
|
}
|
|
124
136
|
}
|
|
125
137
|
this.debug('Starting import of WebSocket Routes');
|
|
126
|
-
for (const wsRoute of [
|
|
138
|
+
for (const wsRoute of [
|
|
139
|
+
...internalWsRouteFiles,
|
|
140
|
+
...this.webSocketRouteFiles,
|
|
141
|
+
]) {
|
|
127
142
|
if (wsRoute.endsWith('js')) {
|
|
128
143
|
const { name } = path.parse(wsRoute);
|
|
129
144
|
const [, querySchema] = await Promise.all(routeSchemas.map(async (schemaType) => {
|
|
@@ -135,17 +150,20 @@ export class Browserless {
|
|
|
135
150
|
const logger = createLogger(`ws:${name}`);
|
|
136
151
|
const { default: Route, } = await import(wsImport + `?cb=${Date.now()}`);
|
|
137
152
|
const route = new Route(this.browserManager, this.config, this.fileSystem, logger, this.metrics, this.monitoring);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
if (!this.routeIsDisabled(route)) {
|
|
154
|
+
route.querySchema = safeParse(querySchema);
|
|
155
|
+
route.config = () => this.config;
|
|
156
|
+
route.metrics = () => this.metrics;
|
|
157
|
+
route.monitoring = () => this.monitoring;
|
|
158
|
+
route.fileSystem = () => this.fileSystem;
|
|
159
|
+
route.debug = () => logger;
|
|
160
|
+
wsRoutes.push(route);
|
|
161
|
+
}
|
|
145
162
|
}
|
|
146
163
|
}
|
|
164
|
+
const allRoutes = [...httpRoutes, ...wsRoutes];
|
|
147
165
|
// Validate that we have the browsers they are asking for
|
|
148
|
-
|
|
166
|
+
allRoutes.forEach((route) => {
|
|
149
167
|
if ('browser' in route &&
|
|
150
168
|
route.browser &&
|
|
151
169
|
internalBrowsers.includes(route.browser) &&
|
|
@@ -153,6 +171,12 @@ export class Browserless {
|
|
|
153
171
|
throw new Error(`Couldn't load route "${route.path}" due to missing browser binary for "${route.browser?.name}"`);
|
|
154
172
|
}
|
|
155
173
|
});
|
|
174
|
+
const duplicateNamedRoutes = allRoutes
|
|
175
|
+
.filter((e, i, a) => a.findIndex((r) => r.name === e.name) !== i)
|
|
176
|
+
.map((r) => r.name);
|
|
177
|
+
if (duplicateNamedRoutes.length) {
|
|
178
|
+
this.debug(`Found duplicate routing names. Route names must be unique:`, duplicateNamedRoutes);
|
|
179
|
+
}
|
|
156
180
|
httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
|
|
157
181
|
wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
|
|
158
182
|
this.debug(`Imported and validated all route files, starting up server.`);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { chromeExecutablePath, createLogger, } from '@browserless.io/browserless';
|
|
2
2
|
import { ChromiumCDP } from './chromium.cdp.js';
|
|
3
3
|
export class ChromeCDP extends ChromiumCDP {
|
|
4
|
-
executablePath = chromeExecutablePath;
|
|
4
|
+
executablePath = chromeExecutablePath();
|
|
5
5
|
debug = createLogger('browsers:chrome:cdp');
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { chromeExecutablePath, createLogger, } from '@browserless.io/browserless';
|
|
2
2
|
import { ChromiumPlaywright } from './chromium.playwright.js';
|
|
3
3
|
export class ChromePlaywright extends ChromiumPlaywright {
|
|
4
|
-
executablePath = chromeExecutablePath;
|
|
4
|
+
executablePath = chromeExecutablePath();
|
|
5
5
|
debug = createLogger('browsers:chrome:playwright');
|
|
6
6
|
}
|
|
@@ -11,6 +11,7 @@ export declare class BrowserManager {
|
|
|
11
11
|
constructor(config: Config);
|
|
12
12
|
private browserIsChrome;
|
|
13
13
|
protected removeUserDataDir: (userDataDir: string | null) => Promise<void>;
|
|
14
|
+
protected onNewPage: (req: Request, page: unknown) => Promise<void>;
|
|
14
15
|
/**
|
|
15
16
|
* Returns the /json/protocol API contents from Chromium or Chrome, whichever is installed,
|
|
16
17
|
* and modifies URLs to set them to the appropriate addresses configured.
|
package/build/browsers/index.js
CHANGED
|
@@ -26,6 +26,9 @@ export class BrowserManager {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
+
onNewPage = async (req, page) => {
|
|
30
|
+
await pageHook({ meta: req.parsed, page });
|
|
31
|
+
};
|
|
29
32
|
/**
|
|
30
33
|
* Returns the /json/protocol API contents from Chromium or Chrome, whichever is installed,
|
|
31
34
|
* and modifies URLs to set them to the appropriate addresses configured.
|
|
@@ -316,7 +319,7 @@ export class BrowserManager {
|
|
|
316
319
|
await browser.launch(launchOptions);
|
|
317
320
|
await browserHook({ browser, meta: req.parsed });
|
|
318
321
|
browser.on('newPage', async (page) => {
|
|
319
|
-
await
|
|
322
|
+
await this.onNewPage(req, page);
|
|
320
323
|
(router.onNewPage || noop)(req.parsed || '', page);
|
|
321
324
|
});
|
|
322
325
|
return browser;
|
package/build/data/classes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
["b-modal-banner--disabled","blocked","bodyBlocked","c24-cc-visible","cbar","ccm-blocked","cmp-open","consent-modal-open","consent-modal-overflow","CookiePolicy--show","cookies","cu_k_cookie_consent_modal_open","gcdc-locked","gdpr-infobar-visible","gdprbanner_consent_gdpr_consent","gdprCookieBanner-acceptedAll","hasCookieBanner","ibeugdpr-disabled","idxrcookies-block-user-nav","modal--is-open","modal-open","no_scroll","no-scroll","noScroll","popin-gdpr-no-scroll","shopee-no-scroll","show-cookie-policy-info","sp-message-open","start-cookies","ta-cc-modal-open","touchevents-false","wt-cli-eu-country","wt-cli-geoip-on"]
|
|
1
|
+
["appconsent_noscroll","b-modal-banner--disabled","blocked","bodyBlocked","c24-cc-visible","cbar","ccm-blocked","cmp-open","consent-modal-open","consent-modal-overflow","cookie_consent","CookiePolicy--show","cookies","cu_k_cookie_consent_modal_open","didomi-popup-open","gcdc-locked","gdpr-infobar-visible","gdprbanner_consent_gdpr_consent","gdprCookieBanner-acceptedAll","hasCookieBanner","ibeugdpr-disabled","idxrcookies-block-user-nav","modal--is-open","modal-open","no_scroll","no-scroll","noScroll","popin-gdpr-no-scroll","shopee-no-scroll","show-cookie-policy-info","sp-message-open","start-cookies","ta-cc-modal-open","touchevents-false","wt-cli-eu-country","wt-cli-geoip-on"]
|