@browserless.io/browserless 2.19.0 → 2.20.0-beta-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/build/utils.js CHANGED
@@ -36,7 +36,22 @@ export const buildDir = path.join(path.resolve(), 'build');
36
36
  export const tsExtension = '.d.ts';
37
37
  export const jsonExtension = '.json';
38
38
  export const jsExtension = '.js';
39
+ export const isWin = process.platform === 'win32';
39
40
  export const id = () => crypto.randomUUID();
41
+ /**
42
+ * Normalizes a full-path by adding the `file://` protocol if needed.
43
+ *
44
+ * @param filepath - The file path to normalize.
45
+ * @returns The normalized file path.
46
+ */
47
+ export const normalizeFileProtocol = (filepath) => {
48
+ if (isWin) {
49
+ if (filepath.startsWith('file:///'))
50
+ return filepath;
51
+ return 'file:///' + filepath;
52
+ }
53
+ return filepath;
54
+ };
40
55
  /**
41
56
  * Generates a random, Chromium-compliant page ID with "BLESS"
42
57
  * prepended. This prepended text signals to other parts of the
@@ -26,8 +26,9 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
26
26
  fonts-ubuntu \
27
27
  fonts-wqy-zenhei
28
28
 
29
- RUN npx --yes playwright install chrome &&\
30
- npx --yes playwright install-deps chrome &&\
29
+ # NOTE it's important to not use npx playwright-core here since it'll likely install
30
+ # a more recent version than we potentially have in our own package.json
31
+ RUN ./node_modules/playwright-core/cli.js install --with-deps chrome &&\
31
32
  npm run build &&\
32
33
  npm run build:function &&\
33
34
  npm prune production &&\
@@ -26,8 +26,9 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
26
26
  fonts-ubuntu \
27
27
  fonts-wqy-zenhei
28
28
 
29
- RUN npx --yes playwright install chromium &&\
30
- npx --yes playwright install-deps chromium &&\
29
+ # NOTE it's important to not use npx playwright-core here since it'll likely install
30
+ # a more recent version than we potentially have in our own package.json
31
+ RUN ./node_modules/playwright-core/cli.js install --with-deps chromium &&\
31
32
  npm run build &&\
32
33
  npm run build:function &&\
33
34
  npm prune production &&\
@@ -26,8 +26,9 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
26
26
  fonts-ubuntu \
27
27
  fonts-wqy-zenhei
28
28
 
29
- RUN npx --yes playwright install firefox &&\
30
- npx --yes playwright install-deps firefox &&\
29
+ # NOTE it's important to not use npx playwright-core here since it'll likely install
30
+ # a more recent version than we potentially have in our own package.json
31
+ RUN ./node_modules/playwright-core/cli.js install --with-deps firefox &&\
31
32
  npm run build &&\
32
33
  npm prune production &&\
33
34
  chown -R blessuser:blessuser $APP_DIR &&\
@@ -29,12 +29,14 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
29
29
  # Chrome stable is only supported on non-ARM builds
30
30
  # so it's installation is conditional on whether or not amd64
31
31
  RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
32
- ./node_modules/.bin/playwright-core install --with-deps chrome; \
32
+ ./node_modules/playwright-core/cli.js install --with-deps chrome; \
33
33
  else \
34
34
  rm -rf ./src/routes/chrome; \
35
35
  fi
36
36
 
37
- RUN npx --yes playwright install --with-deps chromium firefox webkit &&\
37
+ # NOTE it's important to not use npx playwright-core here since it'll likely install
38
+ # a more recent version than we potentially have in our own package.json
39
+ RUN ./node_modules/playwright-core/cli.js install --with-deps chromium firefox webkit &&\
38
40
  npm run build &&\
39
41
  npm run build:function &&\
40
42
  npm prune production &&\
@@ -27,8 +27,9 @@ RUN echo "ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula sele
27
27
  fonts-ubuntu \
28
28
  fonts-wqy-zenhei
29
29
 
30
- RUN npx --yes playwright install webkit &&\
31
- npx --yes playwright install-deps webkit &&\
30
+ # NOTE it's important to not use npx playwright-core here since it'll likely install
31
+ # a more recent version than we potentially have in our own package.json
32
+ RUN ./node_modules/playwright-core/cli.js install --with-deps webkit &&\
32
33
  npm run build &&\
33
34
  npm prune production &&\
34
35
  chown -R blessuser:blessuser $APP_DIR &&\
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserless.io/browserless",
3
- "version": "2.19.0",
3
+ "version": "2.20.0-beta-1",
4
4
  "license": "SSPL",
5
5
  "description": "The browserless platform",
6
6
  "author": "browserless.io",
@@ -25,9 +25,9 @@
25
25
  "dev": "npm run build:dev && env-cmd -f .env node build",
26
26
  "install:adblock": "node scripts/install-adblock.js",
27
27
  "install:debugger": "node scripts/install-debugger.js",
28
- "install:browsers": "npx --yes playwright install chromium firefox webkit chrome",
28
+ "install:browsers": "npx --no playwright-core install chromium firefox webkit",
29
29
  "install:dev": "npm run install:browsers && npm run install:debugger",
30
- "lint": "eslint . --ext .ts --fix",
30
+ "lint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --ext .ts --fix",
31
31
  "prepack": "npm run build:dev",
32
32
  "prettier": "prettier '{src,functions,scripts,bin,external,.github}/**/*.{js,ts,json,yml,yaml,md}' --log-level error --write",
33
33
  "test": "cross-env DEBUG=quiet mocha",
@@ -48,21 +48,21 @@
48
48
  "tsconfig.json"
49
49
  ],
50
50
  "dependencies": {
51
- "debug": "^4.3.6",
51
+ "debug": "^4.3.7",
52
52
  "del": "^7.0.0",
53
53
  "enjoi": "^9.0.1",
54
- "file-type": "^19.4.1",
54
+ "file-type": "^19.5.0",
55
55
  "get-port": "^7.1.0",
56
56
  "gradient-string": "^2.0.0",
57
57
  "http-proxy": "^1.18.1",
58
- "lighthouse": "^12.2.0",
58
+ "lighthouse": "^12.2.1",
59
59
  "micromatch": "^4.0.8",
60
60
  "playwright-1.41": "npm:playwright-core@1.41.2",
61
61
  "playwright-1.42": "npm:playwright-core@1.42.1",
62
62
  "playwright-1.43": "npm:playwright-core@1.43.1",
63
63
  "playwright-1.44": "npm:playwright-core@1.44.1",
64
- "playwright-core": "^1.46.1",
65
- "puppeteer-core": "^23.2.1",
64
+ "playwright-core": "^1.47.0",
65
+ "puppeteer-core": "^23.3.0",
66
66
  "puppeteer-extra": "^3.3.6",
67
67
  "puppeteer-extra-plugin-stealth": "^2.11.2",
68
68
  "queue": "^7.0.0",
@@ -76,26 +76,26 @@
76
76
  "@types/http-proxy": "^1.17.15",
77
77
  "@types/micromatch": "^4.0.9",
78
78
  "@types/mocha": "^10.0.7",
79
- "@types/node": "^22.5.2",
79
+ "@types/node": "^22.5.4",
80
80
  "@types/sinon": "^17.0.3",
81
- "@typescript-eslint/eslint-plugin": "^8.4.0",
82
- "@typescript-eslint/parser": "^8.4.0",
81
+ "@typescript-eslint/eslint-plugin": "^8.5.0",
82
+ "@typescript-eslint/parser": "^8.5.0",
83
83
  "assert": "^2.0.0",
84
84
  "chai": "^5.1.1",
85
85
  "cross-env": "^7.0.3",
86
86
  "env-cmd": "^10.1.0",
87
87
  "esbuild": "^0.23.1",
88
88
  "esbuild-plugin-polyfill-node": "^0.3.0",
89
- "eslint": "^8.57.0",
89
+ "eslint": "^9.10.0",
90
90
  "extract-zip": "^2.0.1",
91
91
  "gunzip-maybe": "^1.4.2",
92
- "marked": "^14.1.0",
92
+ "marked": "^14.1.2",
93
93
  "mocha": "^10.7.3",
94
94
  "move-file": "^3.1.0",
95
95
  "prettier": "^3.3.3",
96
96
  "sinon": "^18.0.0",
97
97
  "ts-node": "^10.9.2",
98
- "typescript": "^5.5.4",
98
+ "typescript": "^5.6.2",
99
99
  "typescript-json-schema": "^0.65.1"
100
100
  },
101
101
  "playwrightVersions": {
@@ -25,8 +25,10 @@ import {
25
25
  WebKitPlaywright,
26
26
  WebSocketRoute,
27
27
  availableBrowsers,
28
+ dedent,
28
29
  getRouteFiles,
29
30
  makeExternalURL,
31
+ normalizeFileProtocol,
30
32
  printLogo,
31
33
  safeParse,
32
34
  } from '@browserless.io/browserless';
@@ -313,9 +315,7 @@ export class Browserless extends EventEmitter {
313
315
  }),
314
316
  );
315
317
 
316
- const wsImport = `${
317
- this.config.getIsWin() ? 'file:///' : ''
318
- }${wsRoute}`;
318
+ const wsImport = normalizeFileProtocol(wsRoute);
319
319
  const {
320
320
  default: Route,
321
321
  }: {
@@ -357,7 +357,8 @@ export class Browserless extends EventEmitter {
357
357
  !installedBrowsers.some((b) => b.name === route.browser?.name)
358
358
  ) {
359
359
  throw new Error(
360
- `Couldn't load route "${route.path}" due to missing browser binary for "${route.browser?.name}"`,
360
+ dedent(`Couldn't load route "${route.path}" due to missing browser binary for "${route.browser?.name}".
361
+ Installed Browsers: ${installedBrowsers.join(', ')}`),
361
362
  );
362
363
  }
363
364
  });
package/src/config.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { exists, keyLength, untildify } from '@browserless.io/browserless';
1
+ import { exists, isWin as isWindows, keyLength, untildify } from '@browserless.io/browserless';
2
2
  import { EventEmitter } from 'events';
3
3
  import debug from 'debug';
4
4
  import { fileURLToPath } from 'url';
@@ -112,8 +112,8 @@ const getDebug = () => {
112
112
  export class Config extends EventEmitter {
113
113
  protected readonly debug = getDebug();
114
114
  protected readonly host = process.env.HOST ?? 'localhost';
115
+ protected readonly isWin = isWindows;
115
116
  protected external = process.env.PROXY_URL ?? process.env.EXTERNAL;
116
- protected readonly isWin = process.platform === 'win32';
117
117
 
118
118
  protected port = +(process.env.PORT ?? '3000');
119
119
 
package/src/sdk-utils.ts CHANGED
@@ -2,7 +2,24 @@ import { createInterface } from 'readline';
2
2
  import debug from 'debug';
3
3
  import fs from 'fs/promises';
4
4
  import path from 'path';
5
- import { spawn } from 'child_process';
5
+ import { promisify } from 'util';
6
+
7
+ import { exec } from 'child_process';
8
+
9
+ const execAsync = promisify(exec);
10
+
11
+ const waitForCommand = async (cmd: string, workingDirectory: string) =>
12
+ new Promise<void>((resolve, reject) =>
13
+ execAsync(cmd, { cwd: workingDirectory }).then(({ stderr }) => {
14
+ if (stderr) {
15
+ return reject(
16
+ `Error running ${cmd}. See output for more details: \n${stderr}`,
17
+ );
18
+ }
19
+
20
+ return resolve();
21
+ }),
22
+ );
6
23
 
7
24
  export const getArgSwitches = () => {
8
25
  return process.argv.reduce(
@@ -41,7 +58,13 @@ export const getSourceFiles = async (cwd: string) => {
41
58
  const files = await fs.readdir(buildDir, { recursive: true });
42
59
  const [httpRoutes, webSocketRoutes] = files.reduce(
43
60
  ([httpRoutes, webSocketRoutes], file) => {
61
+ const isInRootDir = !file.includes(path.sep);
44
62
  const parsed = path.parse(file);
63
+
64
+ if (isInRootDir) {
65
+ return [httpRoutes, webSocketRoutes];
66
+ }
67
+
45
68
  if (parsed.name.endsWith('http')) {
46
69
  httpRoutes.push(path.join(buildDir, file));
47
70
  }
@@ -81,74 +104,23 @@ export const prompt = async (question: string) => {
81
104
  });
82
105
  };
83
106
 
107
+ // Exceptions are not caught, since any error would result in a crash regardless
84
108
  export const installDependencies = async (
85
109
  workingDirectory: string,
86
110
  ): Promise<void> => {
87
- await new Promise<void>((resolve, reject) => {
88
- spawn('npm', ['i'], {
89
- cwd: workingDirectory,
90
- stdio: 'inherit',
91
- }).once('close', (code) => {
92
- if (code === 0) {
93
- return resolve();
94
- }
95
- return reject(
96
- `Error when installing dependencies, see output for more details`,
97
- );
98
- });
99
- });
100
- await new Promise<void>((resolve, reject) => {
101
- spawn(
102
- 'npx',
103
- 'playwright-core install --with-deps chromium firefox webkit'.split(' '),
104
- {
105
- cwd: workingDirectory,
106
- stdio: 'inherit',
107
- },
108
- ).once('close', (code) => {
109
- if (code === 0) {
110
- return resolve();
111
- }
112
- return reject(
113
- `Error when installing dependencies, see output for more details`,
114
- );
115
- });
116
- });
111
+ await waitForCommand('npm install', workingDirectory);
112
+ await waitForCommand(
113
+ 'npx playwright-core install --with-deps chromium firefox webkit',
114
+ workingDirectory,
115
+ );
117
116
  };
118
117
 
119
118
  export const buildDockerImage = async (
120
119
  cmd: string,
121
120
  projectDir: string,
122
- ): Promise<void> =>
123
- new Promise((resolve, reject) => {
124
- const [docker, ...args] = cmd.split(' ');
125
- spawn(docker, args, {
126
- cwd: projectDir,
127
- stdio: 'inherit',
128
- }).once('close', (code) => {
129
- if (code === 0) {
130
- return resolve();
131
- }
132
- return reject(
133
- `Error when building Docker image, see output for more details`,
134
- );
135
- });
136
- });
121
+ ): Promise<void> => waitForCommand(cmd, projectDir);
137
122
 
138
123
  export const buildTypeScript = async (
139
124
  buildDir: string,
140
125
  projectDir: string,
141
- ): Promise<void> =>
142
- new Promise((resolve, reject) => {
143
- spawn('npx', ['tsc', '--outDir', buildDir], {
144
- cwd: projectDir,
145
- stdio: 'inherit',
146
- }).once('close', (code) => {
147
- if (code === 0) {
148
- return resolve();
149
- }
150
- return reject(
151
- `Error in building TypeScript, see output for more details`,
152
- );
153
- });
154
- });
126
+ ): Promise<void> => waitForCommand(`npx tsc --outDir ${buildDir}`, projectDir);
package/src/utils.ts CHANGED
@@ -64,9 +64,26 @@ export const buildDir: string = path.join(path.resolve(), 'build');
64
64
  export const tsExtension = '.d.ts';
65
65
  export const jsonExtension = '.json';
66
66
  export const jsExtension = '.js';
67
+ export const isWin = process.platform === 'win32';
67
68
 
68
69
  export const id = (): string => crypto.randomUUID();
69
70
 
71
+ /**
72
+ * Normalizes a full-path by adding the `file://` protocol if needed.
73
+ *
74
+ * @param filepath - The file path to normalize.
75
+ * @returns The normalized file path.
76
+ */
77
+ export const normalizeFileProtocol = (filepath: string) => {
78
+ if (isWin) {
79
+ if (filepath.startsWith('file:///')) return filepath;
80
+
81
+ return 'file:///' + filepath;
82
+ }
83
+
84
+ return filepath;
85
+ };
86
+
70
87
  /**
71
88
  * Generates a random, Chromium-compliant page ID with "BLESS"
72
89
  * prepended. This prepended text signals to other parts of the