@browserless.io/browserless 2.0.0-beta-1 → 2.0.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/bin/browserless.js +128 -8
- package/build/browserless.d.ts +23 -18
- package/build/browserless.js +24 -17
- package/build/browsers/cdp-chromium.d.ts +17 -14
- package/build/browsers/index.d.ts +27 -10
- package/build/browsers/index.js +2 -12
- package/build/browsers/playwright-chromium.d.ts +12 -9
- package/build/browsers/playwright-firefox.d.ts +12 -9
- package/build/browsers/playwright-webkit.d.ts +12 -9
- package/build/config.d.ts +31 -31
- package/build/exports.d.ts +2 -0
- package/build/exports.js +2 -0
- package/build/file-system.d.ts +2 -2
- package/build/limiter.d.ts +34 -11
- package/build/metrics.d.ts +17 -11
- package/build/monitoring.d.ts +3 -2
- package/build/router.d.ts +28 -0
- package/build/router.js +138 -0
- package/build/routes/chromium/http/content-post.body.json +8 -8
- package/build/routes/chromium/http/download-post.js +1 -1
- package/build/routes/chromium/http/function-post.js +1 -1
- package/build/routes/chromium/http/pdf-post.body.json +8 -8
- package/build/routes/chromium/http/performance.js +1 -1
- 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/function/client.d.ts +3 -3
- package/build/routes/management/http/config-get.js +1 -1
- package/build/routes/management/http/metrics-get.js +1 -1
- package/build/routes/management/http/metrics-total-get.js +1 -1
- package/build/routes/management/http/sessions-get.js +3 -3
- package/build/routes/management/http/static-get.js +1 -1
- package/build/server.d.ts +22 -27
- package/build/server.js +29 -149
- package/build/token.d.ts +6 -0
- package/build/token.js +21 -0
- package/build/types.d.ts +85 -14
- package/build/utils.d.ts +1 -2
- package/build/utils.js +0 -13
- package/build/webhooks.d.ts +2 -2
- package/docker/sdk/Dockerfile +2 -6
- package/package.json +4 -4
- package/src/browserless.ts +44 -32
- package/src/browsers/cdp-chromium.ts +13 -13
- package/src/browsers/index.ts +9 -24
- package/src/browsers/playwright-chromium.ts +9 -9
- package/src/browsers/playwright-firefox.ts +9 -9
- package/src/browsers/playwright-webkit.ts +9 -9
- package/src/config.ts +32 -31
- package/src/exports.ts +2 -0
- package/src/file-system.ts +2 -2
- package/src/limiter.ts +11 -11
- package/src/metrics.ts +11 -11
- package/src/monitoring.ts +2 -2
- package/src/router.ts +234 -0
- package/src/routes/chromium/http/download-post.ts +1 -1
- package/src/routes/chromium/http/function-post.ts +1 -1
- package/src/routes/chromium/http/performance.ts +1 -1
- package/src/routes/chromium/utils/function/client.ts +2 -2
- package/src/routes/management/http/config-get.ts +1 -1
- package/src/routes/management/http/metrics-get.ts +1 -1
- package/src/routes/management/http/metrics-total-get.ts +1 -1
- package/src/routes/management/http/sessions-get.ts +3 -3
- package/src/routes/management/http/static-get.ts +1 -1
- package/src/server.ts +43 -238
- package/src/token.ts +40 -0
- package/src/types.ts +92 -17
- package/src/utils.ts +0 -25
- package/src/webhooks.ts +2 -2
- package/static/docs/swagger.json +9 -9
package/docker/sdk/Dockerfile
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
ARG FROM=ghcr.io/browserless/multi
|
|
2
|
-
ARG VERSION=latest
|
|
1
|
+
ARG FROM=ghcr.io/browserless/multi:latest
|
|
3
2
|
|
|
4
|
-
FROM ${FROM}
|
|
3
|
+
FROM ${FROM}
|
|
5
4
|
|
|
6
5
|
# Change to root for install
|
|
7
6
|
USER root
|
|
@@ -17,9 +16,6 @@ COPY src src
|
|
|
17
16
|
COPY package.json .
|
|
18
17
|
COPY package-lock.json .
|
|
19
18
|
COPY tsconfig.json .
|
|
20
|
-
|
|
21
|
-
# Optional files that might not always be there
|
|
22
|
-
COPY *browserless.io-browserless-*.tgz .
|
|
23
19
|
COPY *README.md .
|
|
24
20
|
|
|
25
21
|
# Install dependencies
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.0.0-beta-
|
|
3
|
+
"version": "2.0.0-beta-2",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -71,13 +71,13 @@
|
|
|
71
71
|
"@types/mocha": "^10.0.6",
|
|
72
72
|
"@types/node": "^20.10.5",
|
|
73
73
|
"@types/sinon": "^17.0.2",
|
|
74
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
75
|
-
"@typescript-eslint/parser": "^6.
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
75
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
76
76
|
"assert": "^2.0.0",
|
|
77
77
|
"chai": "^4.3.6",
|
|
78
78
|
"cross-env": "^7.0.3",
|
|
79
79
|
"env-cmd": "^10.1.0",
|
|
80
|
-
"esbuild": "^0.19.
|
|
80
|
+
"esbuild": "^0.19.10",
|
|
81
81
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
82
82
|
"eslint": "^8.56.0",
|
|
83
83
|
"eslint-plugin-import": "^2.29.1",
|
package/src/browserless.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
Limiter,
|
|
12
12
|
Metrics,
|
|
13
13
|
Monitoring,
|
|
14
|
+
Router,
|
|
15
|
+
Token,
|
|
14
16
|
WebHooks,
|
|
15
17
|
WebSocketRoute,
|
|
16
18
|
availableBrowsers,
|
|
@@ -26,14 +28,16 @@ import { userInfo } from 'os';
|
|
|
26
28
|
const routeSchemas = ['body', 'query'];
|
|
27
29
|
|
|
28
30
|
export class Browserless {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
protected debug: debug.Debugger = createLogger('index');
|
|
32
|
+
protected browserManager: BrowserManager;
|
|
33
|
+
protected config: Config;
|
|
34
|
+
protected fileSystem: FileSystem;
|
|
35
|
+
protected limiter: Limiter;
|
|
36
|
+
protected metrics: Metrics;
|
|
37
|
+
protected monitoring: Monitoring;
|
|
38
|
+
protected router: Router;
|
|
39
|
+
protected token: Token;
|
|
40
|
+
protected webhooks: WebHooks;
|
|
37
41
|
|
|
38
42
|
webSocketRouteFiles: string[] = [];
|
|
39
43
|
httpRouteFiles: string[] = [];
|
|
@@ -44,22 +48,27 @@ export class Browserless {
|
|
|
44
48
|
constructor({
|
|
45
49
|
browserManager,
|
|
46
50
|
config,
|
|
47
|
-
|
|
51
|
+
fileSystem,
|
|
48
52
|
limiter,
|
|
49
53
|
metrics,
|
|
50
|
-
|
|
54
|
+
monitoring,
|
|
55
|
+
router,
|
|
56
|
+
token,
|
|
51
57
|
webhooks,
|
|
52
58
|
}: {
|
|
53
|
-
browserManager?:
|
|
54
|
-
config?:
|
|
55
|
-
fileSystem?:
|
|
56
|
-
limiter?:
|
|
57
|
-
metrics?:
|
|
58
|
-
monitoring?:
|
|
59
|
-
|
|
59
|
+
browserManager?: Browserless['browserManager'];
|
|
60
|
+
config?: Browserless['config'];
|
|
61
|
+
fileSystem?: Browserless['fileSystem'];
|
|
62
|
+
limiter?: Browserless['limiter'];
|
|
63
|
+
metrics?: Browserless['metrics'];
|
|
64
|
+
monitoring?: Browserless['monitoring'];
|
|
65
|
+
router?: Browserless['router'];
|
|
66
|
+
token?: Browserless['token'];
|
|
67
|
+
webhooks?: Browserless['webhooks'];
|
|
60
68
|
} = {}) {
|
|
61
69
|
this.config = config || new Config();
|
|
62
70
|
this.metrics = metrics || new Metrics();
|
|
71
|
+
this.token = token || new Token(this.config);
|
|
63
72
|
this.webhooks = webhooks || new WebHooks(this.config);
|
|
64
73
|
this.browserManager = browserManager || new BrowserManager(this.config);
|
|
65
74
|
this.monitoring = monitoring || new Monitoring(this.config);
|
|
@@ -67,9 +76,11 @@ export class Browserless {
|
|
|
67
76
|
this.limiter =
|
|
68
77
|
limiter ||
|
|
69
78
|
new Limiter(this.config, this.metrics, this.monitoring, this.webhooks);
|
|
79
|
+
this.router =
|
|
80
|
+
router || new Router(this.config, this.browserManager, this.limiter);
|
|
70
81
|
}
|
|
71
82
|
|
|
72
|
-
|
|
83
|
+
protected saveMetrics = async (): Promise<void> => {
|
|
73
84
|
const metricsPath = this.config.getMetricsJSONPath();
|
|
74
85
|
const { cpu, memory } = await this.monitoring.getMachineStats();
|
|
75
86
|
const metrics = await this.metrics.get();
|
|
@@ -175,11 +186,11 @@ export class Browserless {
|
|
|
175
186
|
|
|
176
187
|
route.bodySchema = safeParse(bodySchema);
|
|
177
188
|
route.querySchema = safeParse(querySchema);
|
|
178
|
-
route.
|
|
179
|
-
route.
|
|
180
|
-
route.
|
|
181
|
-
route.
|
|
182
|
-
route.
|
|
189
|
+
route.getConfig = () => this.config;
|
|
190
|
+
route.getMetrics = () => this.metrics;
|
|
191
|
+
route.getMonitoring = () => this.monitoring;
|
|
192
|
+
route.getFileSystem = () => this.fileSystem;
|
|
193
|
+
route.getDebug = () => logger;
|
|
183
194
|
|
|
184
195
|
httpRoutes.push(route);
|
|
185
196
|
}
|
|
@@ -210,11 +221,11 @@ export class Browserless {
|
|
|
210
221
|
);
|
|
211
222
|
|
|
212
223
|
route.querySchema = safeParse(querySchema);
|
|
213
|
-
route.
|
|
214
|
-
route.
|
|
215
|
-
route.
|
|
216
|
-
route.
|
|
217
|
-
route.
|
|
224
|
+
route.getConfig = () => this.config;
|
|
225
|
+
route.getMetrics = () => this.metrics;
|
|
226
|
+
route.getMonitoring = () => this.monitoring;
|
|
227
|
+
route.getFileSystem = () => this.fileSystem;
|
|
228
|
+
route.getDebug = () => logger;
|
|
218
229
|
|
|
219
230
|
wsRoutes.push(route);
|
|
220
231
|
}
|
|
@@ -232,15 +243,16 @@ export class Browserless {
|
|
|
232
243
|
}
|
|
233
244
|
});
|
|
234
245
|
|
|
246
|
+
httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
|
|
247
|
+
wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
|
|
248
|
+
|
|
235
249
|
this.debug(`Imported and validated all route files, starting up server.`);
|
|
236
250
|
|
|
237
251
|
this.server = new HTTPServer(
|
|
238
252
|
this.config,
|
|
239
253
|
this.metrics,
|
|
240
|
-
this.
|
|
241
|
-
this.
|
|
242
|
-
httpRoutes,
|
|
243
|
-
wsRoutes,
|
|
254
|
+
this.token,
|
|
255
|
+
this.router,
|
|
244
256
|
);
|
|
245
257
|
|
|
246
258
|
await this.server.start();
|
|
@@ -24,16 +24,16 @@ import puppeteerStealth from 'puppeteer-extra';
|
|
|
24
24
|
puppeteerStealth.use(StealthPlugin());
|
|
25
25
|
|
|
26
26
|
export class CDPChromium extends EventEmitter {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
protected config: Config;
|
|
28
|
+
protected userDataDir: string | null;
|
|
29
|
+
protected record: boolean;
|
|
30
|
+
protected blockAds: boolean;
|
|
31
|
+
protected running = false;
|
|
32
|
+
protected browser: Browser | null = null;
|
|
33
|
+
protected browserWSEndpoint: string | null = null;
|
|
34
|
+
protected port?: number;
|
|
35
|
+
protected debug = createLogger('browsers:cdp:chromium');
|
|
36
|
+
protected proxy = httpProxy.createProxyServer();
|
|
37
37
|
|
|
38
38
|
constructor({
|
|
39
39
|
userDataDir,
|
|
@@ -55,12 +55,12 @@ export class CDPChromium extends EventEmitter {
|
|
|
55
55
|
this.debug(`Starting new browser instance`);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
protected cleanListeners() {
|
|
59
59
|
this.browser?.removeAllListeners();
|
|
60
60
|
this.removeAllListeners();
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
protected setUpEmbeddedAPI = async (
|
|
64
64
|
page: Page,
|
|
65
65
|
id: string,
|
|
66
66
|
record: boolean,
|
|
@@ -189,7 +189,7 @@ export class CDPChromium extends EventEmitter {
|
|
|
189
189
|
return makeExternalURL(serverAddress, 'live', query);
|
|
190
190
|
};
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
protected onTargetCreated = async (target: Target) => {
|
|
193
193
|
if (target.type() === 'page') {
|
|
194
194
|
const page = await target.page().catch((e) => {
|
|
195
195
|
this.debug(`Error in new page ${e}`);
|
package/src/browsers/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
convertIfBase64,
|
|
18
18
|
createLogger,
|
|
19
19
|
exists,
|
|
20
|
-
getTokenFromRequest,
|
|
21
20
|
id,
|
|
22
21
|
makeExternalURL,
|
|
23
22
|
noop,
|
|
@@ -29,14 +28,14 @@ import { deleteAsync } from 'del';
|
|
|
29
28
|
import { mkdir } from 'fs/promises';
|
|
30
29
|
|
|
31
30
|
export class BrowserManager {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
protected browsers: Map<BrowserInstance, BrowserlessSession> = new Map();
|
|
32
|
+
protected launching: Map<string, Promise<unknown>> = new Map();
|
|
33
|
+
protected timers: Map<string, number> = new Map();
|
|
34
|
+
protected debug = createLogger('browser-manager');
|
|
36
35
|
|
|
37
|
-
constructor(
|
|
36
|
+
constructor(protected config: Config) {}
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
protected removeUserDataDir = async (userDataDir: string | null) => {
|
|
40
39
|
if (userDataDir && (await exists(userDataDir))) {
|
|
41
40
|
this.debug(`Deleting data directory "${userDataDir}"`);
|
|
42
41
|
await deleteAsync(userDataDir, { force: true }).catch((err) => {
|
|
@@ -56,7 +55,7 @@ export class BrowserManager {
|
|
|
56
55
|
* @param sessionId The ID of the session
|
|
57
56
|
* @returns Promise<string> of the fully-qualified path of the directory
|
|
58
57
|
*/
|
|
59
|
-
|
|
58
|
+
protected generateDataDir = async (
|
|
60
59
|
sessionId: string = id(),
|
|
61
60
|
): Promise<string> => {
|
|
62
61
|
const baseDirectory = await this.config.getDataDir();
|
|
@@ -83,7 +82,7 @@ export class BrowserManager {
|
|
|
83
82
|
return dataDirPath;
|
|
84
83
|
};
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
protected generateSessionJson = (
|
|
87
86
|
browser: BrowserInstance,
|
|
88
87
|
session: BrowserlessSession,
|
|
89
88
|
) => {
|
|
@@ -127,17 +126,9 @@ export class BrowserManager {
|
|
|
127
126
|
await Promise.all(cleanupACtions.map((a) => a()));
|
|
128
127
|
};
|
|
129
128
|
|
|
130
|
-
public getAllSessions = async (
|
|
131
|
-
req: Request,
|
|
132
|
-
): Promise<BrowserlessSessionJSON[]> => {
|
|
129
|
+
public getAllSessions = async (): Promise<BrowserlessSessionJSON[]> => {
|
|
133
130
|
const sessions = Array.from(this.browsers);
|
|
134
131
|
|
|
135
|
-
const requestToken = getTokenFromRequest(req);
|
|
136
|
-
const token = this.config.getToken();
|
|
137
|
-
if (token && !requestToken) {
|
|
138
|
-
throw new BadRequest(`Couldn't locate your API token`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
132
|
return sessions.map(([browser, session]) =>
|
|
142
133
|
this.generateSessionJson(browser, session),
|
|
143
134
|
);
|
|
@@ -203,12 +194,6 @@ export class BrowserManager {
|
|
|
203
194
|
`Error parsing launch-options: ${err}. Launch options must be a JSON or base64-encoded JSON object`,
|
|
204
195
|
);
|
|
205
196
|
}
|
|
206
|
-
const requestToken = getTokenFromRequest(req);
|
|
207
|
-
const token = this.config.getToken();
|
|
208
|
-
|
|
209
|
-
if (token && !requestToken) {
|
|
210
|
-
throw new ServerError(`Error locating authorization token`);
|
|
211
|
-
}
|
|
212
197
|
|
|
213
198
|
const routerOptions =
|
|
214
199
|
typeof router.defaultLaunchOptions === 'function'
|
|
@@ -11,14 +11,14 @@ import { EventEmitter } from 'events';
|
|
|
11
11
|
import httpProxy from 'http-proxy';
|
|
12
12
|
|
|
13
13
|
export class PlaywrightChromium extends EventEmitter {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
protected config: Config;
|
|
15
|
+
protected userDataDir: string | null;
|
|
16
|
+
protected record: boolean;
|
|
17
|
+
protected running = false;
|
|
18
|
+
protected proxy = httpProxy.createProxyServer();
|
|
19
|
+
protected browser: playwright.BrowserServer | null = null;
|
|
20
|
+
protected browserWSEndpoint: string | null = null;
|
|
21
|
+
protected debug = createLogger('browsers:playwright:chromium');
|
|
22
22
|
|
|
23
23
|
constructor({
|
|
24
24
|
config,
|
|
@@ -38,7 +38,7 @@ export class PlaywrightChromium extends EventEmitter {
|
|
|
38
38
|
this.debug(`Starting new browser instance`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
protected cleanListeners() {
|
|
42
42
|
this.removeAllListeners();
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -11,14 +11,14 @@ import { EventEmitter } from 'events';
|
|
|
11
11
|
import httpProxy from 'http-proxy';
|
|
12
12
|
|
|
13
13
|
export class PlaywrightFirefox extends EventEmitter {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
protected config: Config;
|
|
15
|
+
protected userDataDir: string | null;
|
|
16
|
+
protected record: boolean;
|
|
17
|
+
protected running = false;
|
|
18
|
+
protected proxy = httpProxy.createProxyServer();
|
|
19
|
+
protected browser: playwright.BrowserServer | null = null;
|
|
20
|
+
protected browserWSEndpoint: string | null = null;
|
|
21
|
+
protected debug = createLogger('browsers:playwright:firefox');
|
|
22
22
|
|
|
23
23
|
constructor({
|
|
24
24
|
config,
|
|
@@ -38,7 +38,7 @@ export class PlaywrightFirefox extends EventEmitter {
|
|
|
38
38
|
this.debug(`Starting new browser instance`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
protected cleanListeners() {
|
|
42
42
|
this.removeAllListeners();
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -11,14 +11,14 @@ import { EventEmitter } from 'events';
|
|
|
11
11
|
import httpProxy from 'http-proxy';
|
|
12
12
|
|
|
13
13
|
export class PlaywrightWebkit extends EventEmitter {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
protected config: Config;
|
|
15
|
+
protected userDataDir: string | null;
|
|
16
|
+
protected record: boolean;
|
|
17
|
+
protected running = false;
|
|
18
|
+
protected proxy = httpProxy.createProxyServer();
|
|
19
|
+
protected browser: playwright.BrowserServer | null = null;
|
|
20
|
+
protected browserWSEndpoint: string | null = null;
|
|
21
|
+
protected debug = createLogger('browsers:playwright:webkit');
|
|
22
22
|
|
|
23
23
|
constructor({
|
|
24
24
|
config,
|
|
@@ -38,7 +38,7 @@ export class PlaywrightWebkit extends EventEmitter {
|
|
|
38
38
|
this.debug(`Starting new browser instance`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
protected cleanListeners() {
|
|
42
42
|
this.removeAllListeners();
|
|
43
43
|
}
|
|
44
44
|
|
package/src/config.ts
CHANGED
|
@@ -109,60 +109,61 @@ const getDebug = () => {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
export class Config extends EventEmitter {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
protected readonly debug = getDebug();
|
|
113
|
+
protected readonly host = process.env.HOST ?? 'localhost';
|
|
114
|
+
protected readonly external = process.env.PROXY_URL ?? process.env.EXTERNAL;
|
|
115
|
+
protected readonly isWin = process.platform === 'win32';
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
protected port = +(process.env.PORT ?? '3000');
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
protected downloadsDir = process.env.DOWNLOAD_DIR
|
|
120
120
|
? untildify(process.env.DOWNLOAD_DIR)
|
|
121
121
|
: path.join(tmpdir(), 'browserless-download-dirs');
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
protected dataDir = process.env.DATA_DIR
|
|
124
124
|
? untildify(process.env.DATA_DIR)
|
|
125
125
|
: path.join(tmpdir(), 'browserless-data-dirs');
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
protected metricsJSONPath = process.env.METRICS_JSON_PATH
|
|
128
128
|
? untildify(process.env.METRICS_JSON_PATH)
|
|
129
129
|
: path.join(tmpdir(), 'browserless-metrics.json');
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
protected createDataDir = !process.env.DATA_DIR;
|
|
132
|
+
protected createDownloadsDir = !process.env.DOWNLOAD_DIR;
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
protected routes = process.env.ROUTES
|
|
135
135
|
? untildify(process.env.ROUTES)
|
|
136
136
|
: path.join(__dirname, '..', 'build', 'routes');
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
protected token = process.env.TOKEN || null;
|
|
139
|
+
protected concurrent = +(
|
|
140
140
|
process.env.CONCURRENT ??
|
|
141
141
|
process.env.MAX_CONCURRENT_SESSIONS ??
|
|
142
142
|
'10'
|
|
143
143
|
);
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
protected queued = +(process.env.QUEUE_LENGTH ?? process.env.QUEUED ?? '10');
|
|
145
|
+
protected timeout = +(
|
|
146
146
|
process.env.TIMEOUT ??
|
|
147
147
|
process.env.CONNECTION_TIMEOUT ??
|
|
148
148
|
'30000'
|
|
149
149
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
150
|
+
protected static = process.env.STATIC ?? path.join(__dirname, '..', 'static');
|
|
151
|
+
protected retries = +(process.env.RETRIES ?? '5');
|
|
152
|
+
protected allowFileProtocol = !!parseEnvVars(false, 'ALLOW_FILE_PROTOCOL');
|
|
153
|
+
protected allowGet = !!parseEnvVars(false, 'ALLOW_GET', 'ENABLE_API_GET');
|
|
154
|
+
protected allowCors = !!parseEnvVars(false, 'CORS', 'ENABLE_CORS');
|
|
155
|
+
protected corsMethods =
|
|
156
|
+
process.env.CORS_ALLOW_METHODS ?? 'OPTIONS, POST, GET';
|
|
157
|
+
protected corsOrigin = process.env.CORS_ALLOW_ORIGIN ?? '*';
|
|
158
|
+
protected corsMaxAge = +(process.env.CORS_MAX_AGE ?? '2592000');
|
|
159
|
+
protected maxCpu = +(process.env.MAX_CPU_PERCENT ?? '99');
|
|
160
|
+
protected maxMemory = +(process.env.MAX_MEMORY_PERCENT ?? '99');
|
|
161
|
+
protected healthCheck = !!parseEnvVars(false, 'HEALTH');
|
|
162
|
+
protected failedHealthURL = process.env.FAILED_HEALTH_URL ?? null;
|
|
163
|
+
protected queueAlertURL = process.env.QUEUE_ALERT_URL ?? null;
|
|
164
|
+
protected rejectAlertURL = process.env.REJECT_ALERT_URL ?? null;
|
|
165
|
+
protected timeoutAlertURL = process.env.TIMEOUT_ALERT_URL ?? null;
|
|
166
|
+
protected errorAlertURL = process.env.ERROR_ALERT_URL ?? null;
|
|
166
167
|
|
|
167
168
|
public getRoutes = (): string => this.routes;
|
|
168
169
|
public getHost = (): string => this.host;
|
package/src/exports.ts
CHANGED
|
@@ -9,8 +9,10 @@ export * from './limiter.js';
|
|
|
9
9
|
export * from './metrics.js';
|
|
10
10
|
export * from './mime-types.js';
|
|
11
11
|
export * from './monitoring.js';
|
|
12
|
+
export * from './router.js';
|
|
12
13
|
export * from './server.js';
|
|
13
14
|
export * from './shim.js';
|
|
15
|
+
export * from './token.js';
|
|
14
16
|
export * from './types.js';
|
|
15
17
|
export * from './utils.js';
|
|
16
18
|
export * from './webhooks.js';
|
package/src/file-system.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { Config, decrypt, encrypt } from '@browserless.io/browserless';
|
|
|
2
2
|
import { readFile, writeFile } from 'fs/promises';
|
|
3
3
|
|
|
4
4
|
export class FileSystem {
|
|
5
|
-
|
|
5
|
+
protected fsMap: Map<string, string[]> = new Map();
|
|
6
6
|
|
|
7
|
-
constructor(
|
|
7
|
+
constructor(protected config: Config) {}
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Appends contents to a file-path for persistance. File contents are
|
package/src/limiter.ts
CHANGED
|
@@ -25,14 +25,14 @@ interface Job {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export class Limiter extends q {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
protected queued: number;
|
|
29
|
+
protected debug = createLogger('limiter');
|
|
30
30
|
|
|
31
31
|
constructor(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
protected config: Config,
|
|
33
|
+
protected metrics: Metrics,
|
|
34
|
+
protected monitor: Monitoring,
|
|
35
|
+
protected webhooks: WebHooks,
|
|
36
36
|
) {
|
|
37
37
|
super({
|
|
38
38
|
autostart: true,
|
|
@@ -73,11 +73,11 @@ export class Limiter extends q {
|
|
|
73
73
|
this.addEventListener('end', this.handleEnd);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
protected handleEnd() {
|
|
77
77
|
this.logQueue('All jobs complete.');
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
protected handleSuccess({ detail: { job } }: { detail: { job: Job } }) {
|
|
81
81
|
const timeUsed = Date.now() - job.start;
|
|
82
82
|
this.debug(
|
|
83
83
|
`Job has succeeded after ${timeUsed.toLocaleString()}ms of activity.`,
|
|
@@ -91,7 +91,7 @@ export class Limiter extends q {
|
|
|
91
91
|
} as AfterResponse);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
protected handleJobTimeout({
|
|
95
95
|
detail: { next, job },
|
|
96
96
|
}: {
|
|
97
97
|
detail: { job: Job; next: Job };
|
|
@@ -113,7 +113,7 @@ export class Limiter extends q {
|
|
|
113
113
|
next();
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
protected handleFail({
|
|
117
117
|
detail: { error, job },
|
|
118
118
|
}: {
|
|
119
119
|
detail: { error: unknown; job: Job };
|
|
@@ -128,7 +128,7 @@ export class Limiter extends q {
|
|
|
128
128
|
} as AfterResponse);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
protected logQueue(message: string) {
|
|
132
132
|
this.debug(
|
|
133
133
|
`(Running: ${this.executing}, Pending: ${this.waiting}) ${message} `,
|
|
134
134
|
);
|
package/src/metrics.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { IBrowserlessStats } from '@browserless.io/browserless';
|
|
2
2
|
|
|
3
3
|
export class Metrics {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
protected sessionTimes: number[] = [];
|
|
5
|
+
protected successful = 0;
|
|
6
|
+
protected queued = 0;
|
|
7
|
+
protected rejected = 0;
|
|
8
|
+
protected unauthorized = 0;
|
|
9
|
+
protected concurrent = 0;
|
|
10
|
+
protected timedout = 0;
|
|
11
|
+
protected running = 0;
|
|
12
|
+
protected unhealthy = 0;
|
|
13
|
+
protected error = 0;
|
|
14
14
|
|
|
15
15
|
addSuccessful = (sessionTime: number): number => {
|
|
16
16
|
--this.running;
|
|
@@ -90,7 +90,7 @@ export class Metrics {
|
|
|
90
90
|
this.sessionTimes = [];
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
protected calculateStats(sessionTimes: number[]) {
|
|
94
94
|
return {
|
|
95
95
|
maxTime: Math.max(...sessionTimes) || 0,
|
|
96
96
|
meanTime: sessionTimes.reduce(
|
package/src/monitoring.ts
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
import si from 'systeminformation';
|
|
7
7
|
|
|
8
8
|
export class Monitoring {
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
9
|
+
protected log = createLogger('hardware');
|
|
10
|
+
constructor(protected config: Config) {}
|
|
11
11
|
|
|
12
12
|
public getMachineStats = async (): Promise<IResourceLoad> => {
|
|
13
13
|
const [cpuLoad, memLoad] = await Promise.all([
|