@browserless.io/browserless 2.1.0 → 2.1.1
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 -2
- package/bin/browserless.js +49 -13
- package/build/browserless.js +9 -2
- package/build/browsers/cdp-chromium.d.ts +1 -1
- package/build/browsers/cdp-chromium.js +3 -3
- package/build/browsers/index.d.ts +1 -0
- package/build/browsers/index.js +20 -0
- package/build/browsers/playwright-chromium.d.ts +1 -1
- package/build/browsers/playwright-firefox.d.ts +1 -1
- package/build/browsers/playwright-webkit.d.ts +1 -1
- package/build/constants.d.ts +1 -0
- package/build/constants.js +1 -0
- package/build/data/classes.json +1 -1
- package/build/data/selectors.json +1 -1
- package/build/http.d.ts +3 -0
- package/build/http.js +3 -0
- package/build/routes/chromium/http/content-post.body.json +8 -8
- package/build/routes/chromium/http/json-list.d.ts +15 -0
- package/build/routes/chromium/http/json-list.js +23 -0
- package/build/routes/chromium/http/json-list.response.json +52 -0
- package/build/routes/chromium/http/json-new.d.ts +15 -0
- package/build/routes/chromium/http/json-new.js +23 -0
- package/build/routes/chromium/http/json-new.response.json +44 -0
- package/build/routes/chromium/http/json-protocol-get.d.ts +15 -0
- package/build/routes/chromium/http/json-protocol-get.js +20 -0
- package/build/routes/chromium/http/json-protocol-get.response.json +6 -0
- package/build/routes/chromium/http/json-version-get.d.ts +1 -1
- package/build/routes/chromium/http/json-version-get.js +1 -1
- package/build/routes/chromium/http/pdf-post.body.json +12 -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/chromium/utils/cdp.d.ts +2 -0
- package/build/routes/chromium/utils/cdp.js +14 -0
- package/build/types.d.ts +31 -0
- package/build/utils.d.ts +9 -0
- package/build/utils.js +17 -2
- package/package.json +11 -13
- package/src/browserless.ts +12 -1
- package/src/browsers/cdp-chromium.ts +5 -7
- package/src/browsers/index.ts +25 -0
- package/src/browsers/playwright-chromium.ts +1 -1
- package/src/browsers/playwright-firefox.ts +1 -1
- package/src/browsers/playwright-webkit.ts +1 -1
- package/src/constants.ts +1 -0
- package/src/http.ts +3 -0
- package/src/routes/chromium/http/json-list.ts +50 -0
- package/src/routes/chromium/http/json-new.ts +50 -0
- package/src/routes/chromium/http/json-protocol-get.ts +38 -0
- package/src/routes/chromium/http/json-version-get.ts +1 -1
- package/src/routes/chromium/utils/cdp.ts +19 -0
- package/src/types.ts +38 -0
- package/src/utils.ts +26 -4
- package/static/docs/swagger.json +315 -10
- package/static/function/client.js +2328 -1975
- package/browser.json +0 -7
- package/scripts/install-cdp-json.js +0 -37
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
|
-
# [Latest](https://github.com/browserless/chrome/compare/v2.
|
|
2
|
-
- Dependency updates.
|
|
1
|
+
# [Latest](https://github.com/browserless/chrome/compare/v2.1.0...main)
|
|
2
|
+
- Dependency updates.
|
|
3
|
+
- Add `clean` command to `@browserless.io/browserless` CLI.
|
|
4
|
+
- Adds support for `/json/list`, `/json/new` and `json/protocol` APIs (Chrome only).
|
|
5
|
+
- Removes legacy `browser.json` files since browserless now generates those and caches when requested.
|
|
6
|
+
- Only verify that internally managed browsers are installed when starting.
|
|
7
|
+
|
|
8
|
+
# [v2.1.0](https://github.com/browserless/browserless/compare/v2.0.0-beta-1...v2.1.0)
|
|
9
|
+
- Dependency updates.
|
|
10
|
+
- Name is now `@browserless.io/browserless` to reflect our npm package.
|
|
11
|
+
- NEW: SDK is now live here: https://www.npmjs.com/package/@browserless.io/browserless.
|
|
12
|
+
- Drops gulp and other gulp utilities in favor of our own. Move to modules in `scripts` dir.
|
|
13
|
+
- Many private class properties now use `protected` so they can be referenced in SDK extensions.
|
|
14
|
+
- Adds a `/json/version` route for older libraries that use it.
|
|
15
|
+
- Merge startup/test scripts into `scripts` dir.
|
|
16
|
+
- Moves installed browsers to `/usr/local/bin/playwright-browsers`.
|
|
17
|
+
- Merge root files into package.json where possible.
|
|
18
|
+
- README updates and fixes.
|
|
19
|
+
- Numerous link and copyright fixes.
|
|
3
20
|
|
|
4
21
|
# [v2.0.0](https://github.com/browserless/chrome/compare/master...feat/browserless-2.0)
|
|
5
22
|
browserless 2.0.0 represents the best body of work after running browserless for over 5 years. It contains mostly the same functionality and more, and is rebuilt to be more modular and offer a NodeJS SDK. It's also much lighter and faster than prior versions and includes a lot of semantic changes.
|
package/bin/browserless.js
CHANGED
|
@@ -14,7 +14,9 @@ import fs from 'fs/promises';
|
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { spawn } from 'child_process';
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
if (typeof process.env.DEBUG === 'undefined') {
|
|
18
|
+
debug.enable('browserless*');
|
|
19
|
+
}
|
|
18
20
|
|
|
19
21
|
const log = debug('browserless.io:sdk:log');
|
|
20
22
|
const promptLog = debug('browserless.io:prompt');
|
|
@@ -22,9 +24,17 @@ const promptLog = debug('browserless.io:prompt');
|
|
|
22
24
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
23
25
|
const cmd = process.argv[2];
|
|
24
26
|
const subCMD = process.argv[3];
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
const allowedCMDs = [
|
|
28
|
+
'build',
|
|
29
|
+
'dev',
|
|
30
|
+
'docker',
|
|
31
|
+
'start',
|
|
32
|
+
'create',
|
|
33
|
+
'help',
|
|
34
|
+
'clean',
|
|
35
|
+
];
|
|
36
|
+
const projectDir = process.cwd();
|
|
37
|
+
const compiledDir = path.join(projectDir, 'build');
|
|
28
38
|
const packageJSON = readFile(path.join(__dirname, '..', 'package.json')).then(
|
|
29
39
|
(r) => JSON.parse(r.toString()),
|
|
30
40
|
);
|
|
@@ -59,7 +69,7 @@ const importClassOverride = async (files, className) => {
|
|
|
59
69
|
return;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
const classModuleFullFilePath = path.join(
|
|
72
|
+
const classModuleFullFilePath = path.join(compiledDir, classModuleFile);
|
|
63
73
|
|
|
64
74
|
if (!classModuleFile) {
|
|
65
75
|
return;
|
|
@@ -68,6 +78,12 @@ const importClassOverride = async (files, className) => {
|
|
|
68
78
|
return (await import(classModuleFullFilePath)).default;
|
|
69
79
|
};
|
|
70
80
|
|
|
81
|
+
const clean = async () =>
|
|
82
|
+
fs.rm(path.join(compiledDir), {
|
|
83
|
+
force: true,
|
|
84
|
+
recursive: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
71
87
|
const installDependencies = async (workingDirectory) =>
|
|
72
88
|
new Promise((resolve, reject) => {
|
|
73
89
|
spawn('npm', ['i'], {
|
|
@@ -88,7 +104,7 @@ const buildDockerImage = async (cmd) => {
|
|
|
88
104
|
new Promise((resolve, reject) => {
|
|
89
105
|
const [docker, ...args] = cmd.split(' ');
|
|
90
106
|
spawn(docker, args, {
|
|
91
|
-
cwd,
|
|
107
|
+
cwd: projectDir,
|
|
92
108
|
stdio: 'inherit',
|
|
93
109
|
}).once('close', (code) => {
|
|
94
110
|
if (code === 0) {
|
|
@@ -105,7 +121,7 @@ const buildDockerImage = async (cmd) => {
|
|
|
105
121
|
const buildTypeScript = async () =>
|
|
106
122
|
new Promise((resolve, reject) => {
|
|
107
123
|
spawn('npx', ['tsc', '--outDir', 'build'], {
|
|
108
|
-
cwd,
|
|
124
|
+
cwd: projectDir,
|
|
109
125
|
stdio: 'inherit',
|
|
110
126
|
}).once('close', (code) => {
|
|
111
127
|
if (code === 0) {
|
|
@@ -118,16 +134,16 @@ const buildTypeScript = async () =>
|
|
|
118
134
|
});
|
|
119
135
|
|
|
120
136
|
const getSourceFiles = async () => {
|
|
121
|
-
const files = await fs.readdir(
|
|
137
|
+
const files = await fs.readdir(compiledDir, { recursive: true });
|
|
122
138
|
const [httpRoutes, webSocketRoutes] = files.reduce(
|
|
123
139
|
([httpRoutes, webSocketRoutes], file) => {
|
|
124
140
|
const parsed = path.parse(file);
|
|
125
141
|
if (parsed.name.endsWith('http')) {
|
|
126
|
-
httpRoutes.push(path.join(
|
|
142
|
+
httpRoutes.push(path.join(compiledDir, file));
|
|
127
143
|
}
|
|
128
144
|
|
|
129
145
|
if (parsed.name.endsWith('ws')) {
|
|
130
|
-
webSocketRoutes.push(path.join(
|
|
146
|
+
webSocketRoutes.push(path.join(compiledDir, file));
|
|
131
147
|
}
|
|
132
148
|
|
|
133
149
|
return [httpRoutes, webSocketRoutes];
|
|
@@ -177,6 +193,9 @@ const getArgSwitches = () => {
|
|
|
177
193
|
* and validation. Doesn't start the HTTP server.
|
|
178
194
|
*/
|
|
179
195
|
const build = async () => {
|
|
196
|
+
log(`Cleaning build directory`);
|
|
197
|
+
await clean();
|
|
198
|
+
|
|
180
199
|
log(`Compiling TypeScript`);
|
|
181
200
|
await buildTypeScript();
|
|
182
201
|
|
|
@@ -309,7 +328,7 @@ const start = async (dev = false) => {
|
|
|
309
328
|
};
|
|
310
329
|
|
|
311
330
|
const buildDocker = async () => {
|
|
312
|
-
const finalDockerPath = path.join(
|
|
331
|
+
const finalDockerPath = path.join(projectDir, 'build', 'Dockerfile');
|
|
313
332
|
const argSwitches = getArgSwitches();
|
|
314
333
|
|
|
315
334
|
await build();
|
|
@@ -320,7 +339,10 @@ const buildDocker = async () => {
|
|
|
320
339
|
|
|
321
340
|
log(`Generating Dockerfile at "${finalDockerPath}"`);
|
|
322
341
|
|
|
323
|
-
await fs.writeFile(
|
|
342
|
+
await fs.writeFile(
|
|
343
|
+
path.join(projectDir, 'build', 'Dockerfile'),
|
|
344
|
+
dockerContents,
|
|
345
|
+
);
|
|
324
346
|
|
|
325
347
|
const from =
|
|
326
348
|
argSwitches.from ||
|
|
@@ -391,7 +413,7 @@ const create = async () => {
|
|
|
391
413
|
throw new Error(`Name must not include special characters.`);
|
|
392
414
|
}
|
|
393
415
|
|
|
394
|
-
const installPath = path.join(
|
|
416
|
+
const installPath = path.join(projectDir, directory);
|
|
395
417
|
log(`Creating folder "${installPath}"...`);
|
|
396
418
|
await fs.mkdir(installPath);
|
|
397
419
|
|
|
@@ -440,6 +462,15 @@ const help = () => {
|
|
|
440
462
|
`);
|
|
441
463
|
break;
|
|
442
464
|
|
|
465
|
+
case 'clean':
|
|
466
|
+
console.log(dedent`
|
|
467
|
+
Usage: npx @browserless.io/browserless clean
|
|
468
|
+
|
|
469
|
+
Description: Cleans the TypeScript generated JavaScript found
|
|
470
|
+
in the "build" directory and any other temporary assets.
|
|
471
|
+
`);
|
|
472
|
+
break;
|
|
473
|
+
|
|
443
474
|
case 'dev':
|
|
444
475
|
console.log(dedent`
|
|
445
476
|
Usage: npx @browserless.io/browserless dev
|
|
@@ -492,6 +523,7 @@ const help = () => {
|
|
|
492
523
|
Usage: npx @browserless.io/browserless [command] [arguments]
|
|
493
524
|
|
|
494
525
|
Options:
|
|
526
|
+
clean Removes build artifacts and other temporary directories.
|
|
495
527
|
create Creates a new scaffold project, installs dependencies, and exits.
|
|
496
528
|
dev Compiles TypeScript, generates build assets and starts the server.
|
|
497
529
|
build Compiles TypeScript, generates build assets and exits.
|
|
@@ -501,6 +533,10 @@ const help = () => {
|
|
|
501
533
|
};
|
|
502
534
|
|
|
503
535
|
switch (cmd) {
|
|
536
|
+
case 'clean':
|
|
537
|
+
clean();
|
|
538
|
+
break;
|
|
539
|
+
|
|
504
540
|
case 'start':
|
|
505
541
|
start(false);
|
|
506
542
|
break;
|
package/build/browserless.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { BrowserManager, Config, FileSystem, HTTPServer, Limiter, Metrics, Monitoring, Router, Token, WebHooks, availableBrowsers, createLogger, getRouteFiles, makeExternalURL, printLogo, safeParse, } from '@browserless.io/browserless';
|
|
2
|
+
import { BrowserManager, CDPChromium, Config, FileSystem, HTTPServer, Limiter, Metrics, Monitoring, PlaywrightChromium, PlaywrightFirefox, PlaywrightWebkit, Router, Token, WebHooks, availableBrowsers, createLogger, getRouteFiles, makeExternalURL, printLogo, safeParse, } from '@browserless.io/browserless';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
import { userInfo } from 'os';
|
|
5
5
|
const routeSchemas = ['body', 'query'];
|
|
@@ -88,6 +88,12 @@ export class Browserless {
|
|
|
88
88
|
async start() {
|
|
89
89
|
const httpRoutes = [];
|
|
90
90
|
const wsRoutes = [];
|
|
91
|
+
const internalBrowsers = [
|
|
92
|
+
CDPChromium,
|
|
93
|
+
PlaywrightFirefox,
|
|
94
|
+
PlaywrightChromium,
|
|
95
|
+
PlaywrightWebkit,
|
|
96
|
+
];
|
|
91
97
|
const [[httpRouteFiles, wsRouteFiles], installedBrowsers] = await Promise.all([getRouteFiles(this.config), availableBrowsers]);
|
|
92
98
|
const docsLink = makeExternalURL(this.config.getExternalAddress(), '/docs');
|
|
93
99
|
this.debug(printLogo(docsLink));
|
|
@@ -137,10 +143,11 @@ export class Browserless {
|
|
|
137
143
|
wsRoutes.push(route);
|
|
138
144
|
}
|
|
139
145
|
}
|
|
140
|
-
// Validate that
|
|
146
|
+
// Validate that we have the browsers they are asking for
|
|
141
147
|
[...httpRoutes, ...wsRoutes].forEach((route) => {
|
|
142
148
|
if ('browser' in route &&
|
|
143
149
|
route.browser &&
|
|
150
|
+
internalBrowsers.includes(route.browser) &&
|
|
144
151
|
!installedBrowsers.some((b) => b.name === route.browser?.name)) {
|
|
145
152
|
throw new Error(`Couldn't load route "${route.path}" due to missing browser of "${route.browser?.name}"`);
|
|
146
153
|
}
|
|
@@ -38,7 +38,7 @@ export declare class CDPChromium extends EventEmitter {
|
|
|
38
38
|
process: () => import("child_process").ChildProcess | null;
|
|
39
39
|
launch: (options?: CDPLaunchOptions) => Promise<Browser>;
|
|
40
40
|
wsEndpoint: () => string | null;
|
|
41
|
-
publicWSEndpoint: (token: string) => string | null;
|
|
41
|
+
publicWSEndpoint: (token: string | null) => string | null;
|
|
42
42
|
proxyPageWebSocket: (req: Request, socket: Duplex, head: Buffer) => Promise<void>;
|
|
43
43
|
proxyWebSocket: (req: Request, socket: Duplex, head: Buffer) => Promise<void>;
|
|
44
44
|
}
|
|
@@ -243,14 +243,14 @@ export class CDPChromium extends EventEmitter {
|
|
|
243
243
|
throw new ServerError(`No browserWSEndpoint found, did you launch first?`);
|
|
244
244
|
}
|
|
245
245
|
socket.once('close', resolve);
|
|
246
|
-
this.debug(`Proxying ${req.parsed.href} to browser ${this.browserWSEndpoint}`);
|
|
247
246
|
const [page] = await this.browser.pages();
|
|
248
247
|
const pageLocation = `/devtools/page/${this.getPageId(page)}`;
|
|
249
248
|
this.debug(`Proxying ${req.parsed.href} to page "${pageLocation}"`);
|
|
250
|
-
|
|
249
|
+
const target = new URL(pageLocation, this.browserWSEndpoint).href;
|
|
250
|
+
req.url = '';
|
|
251
251
|
this.proxy.ws(req, socket, head, {
|
|
252
252
|
changeOrigin: true,
|
|
253
|
-
target
|
|
253
|
+
target,
|
|
254
254
|
}, (error) => {
|
|
255
255
|
this.debug(`Error proxying session: ${error}`);
|
|
256
256
|
this.close();
|
|
@@ -18,6 +18,7 @@ export declare class BrowserManager {
|
|
|
18
18
|
* @returns Promise<string> of the fully-qualified path of the directory
|
|
19
19
|
*/
|
|
20
20
|
protected generateDataDir: (sessionId?: string) => Promise<string>;
|
|
21
|
+
getProtocolJSON: () => Promise<object>;
|
|
21
22
|
getVersionJSON: () => Promise<{
|
|
22
23
|
Browser: string;
|
|
23
24
|
'Debugger-Version': string;
|
package/build/browsers/index.js
CHANGED
|
@@ -41,7 +41,27 @@ export class BrowserManager {
|
|
|
41
41
|
});
|
|
42
42
|
return dataDirPath;
|
|
43
43
|
};
|
|
44
|
+
getProtocolJSON = async () => {
|
|
45
|
+
this.debug(`Launching Chrome to generate /json/protocol results`);
|
|
46
|
+
const browser = new CDPChromium({
|
|
47
|
+
blockAds: false,
|
|
48
|
+
config: this.config,
|
|
49
|
+
record: false,
|
|
50
|
+
userDataDir: null,
|
|
51
|
+
});
|
|
52
|
+
await browser.launch();
|
|
53
|
+
const wsEndpoint = browser.wsEndpoint();
|
|
54
|
+
if (!wsEndpoint) {
|
|
55
|
+
throw new Error('There was an error launching the browser');
|
|
56
|
+
}
|
|
57
|
+
const { port } = new URL(wsEndpoint);
|
|
58
|
+
const res = await fetch(`http://127.0.0.1:${port}/json/protocol`);
|
|
59
|
+
const protocolJSON = await res.json();
|
|
60
|
+
browser.close();
|
|
61
|
+
return protocolJSON;
|
|
62
|
+
};
|
|
44
63
|
getVersionJSON = async () => {
|
|
64
|
+
this.debug(`Launching Chrome to generate /json/version results`);
|
|
45
65
|
const browser = new CDPChromium({
|
|
46
66
|
blockAds: false,
|
|
47
67
|
config: this.config,
|
|
@@ -31,7 +31,7 @@ export declare class PlaywrightChromium extends EventEmitter {
|
|
|
31
31
|
newPage: () => Promise<Page>;
|
|
32
32
|
launch: (options?: BrowserServerOptions) => Promise<playwright.BrowserServer>;
|
|
33
33
|
wsEndpoint: () => string | null;
|
|
34
|
-
publicWSEndpoint: (token: string) => string | null;
|
|
34
|
+
publicWSEndpoint: (token: string | null) => string | null;
|
|
35
35
|
proxyPageWebSocket: () => Promise<void>;
|
|
36
36
|
proxyWebSocket: (req: Request, socket: Duplex, head: Buffer) => Promise<void>;
|
|
37
37
|
}
|
|
@@ -31,7 +31,7 @@ export declare class PlaywrightFirefox extends EventEmitter {
|
|
|
31
31
|
newPage: () => Promise<Page>;
|
|
32
32
|
launch: (options?: BrowserServerOptions) => Promise<playwright.BrowserServer>;
|
|
33
33
|
wsEndpoint: () => string | null;
|
|
34
|
-
publicWSEndpoint: (token: string) => string | null;
|
|
34
|
+
publicWSEndpoint: (token: string | null) => string | null;
|
|
35
35
|
proxyPageWebSocket: () => Promise<void>;
|
|
36
36
|
proxyWebSocket: (req: Request, socket: Duplex, head: Buffer) => Promise<void>;
|
|
37
37
|
}
|
|
@@ -31,7 +31,7 @@ export declare class PlaywrightWebkit extends EventEmitter {
|
|
|
31
31
|
newPage: () => Promise<Page>;
|
|
32
32
|
launch: (options?: BrowserServerOptions) => Promise<playwright.BrowserServer>;
|
|
33
33
|
wsEndpoint: () => string | null;
|
|
34
|
-
publicWSEndpoint: (token: string) => string | null;
|
|
34
|
+
publicWSEndpoint: (token: string | null) => string | null;
|
|
35
35
|
proxyPageWebSocket: () => Promise<void>;
|
|
36
36
|
proxyWebSocket: (req: Request, socket: Duplex, head: Buffer) => Promise<void>;
|
|
37
37
|
}
|
package/build/constants.d.ts
CHANGED
package/build/constants.js
CHANGED
package/build/data/classes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
["b-modal-banner--disabled","blocked","bodyBlocked","c24-cc-visible","cbar","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","modal--is-open","modal-open","no_scroll","no-scroll","shopee-no-scroll","show-cookie-policy-info","sp-message-open","ta-cc-modal-open","touchevents-false","wt-cli-eu-country","wt-cli-geoip-on"]
|
|
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"]
|