@browserless.io/browserless 2.24.0-beta-5 → 2.24.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 +22 -1
- package/bin/browserless.js +1 -1
- package/build/browsers/browsers.playwright.d.ts +1 -0
- package/build/browsers/browsers.playwright.js +3 -0
- package/build/browsers/index.d.ts +2 -1
- package/build/browsers/index.js +28 -7
- package/build/http.d.ts +5 -0
- package/build/http.js +1 -0
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/content.post.query.json +4 -0
- package/build/routes/chrome/http/download.post.query.json +4 -0
- package/build/routes/chrome/http/function.post.query.json +4 -0
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.query.json +4 -0
- package/build/routes/chrome/http/performance.post.query.json +4 -0
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.query.json +4 -0
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.query.json +4 -0
- package/build/routes/chrome/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/chrome/tests/kill-sessions.spec.js +80 -0
- package/build/routes/chrome/ws/browser.query.json +4 -0
- package/build/routes/chrome/ws/cdp.query.json +4 -0
- package/build/routes/chrome/ws/page.query.json +4 -0
- package/build/routes/chrome/ws/playwright.query.json +4 -0
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/content.post.query.json +4 -0
- package/build/routes/chromium/http/download.post.query.json +4 -0
- package/build/routes/chromium/http/function.post.query.json +4 -0
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.query.json +4 -0
- package/build/routes/chromium/http/performance.post.query.json +4 -0
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.query.json +4 -0
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.query.json +4 -0
- package/build/routes/chromium/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/chromium/tests/kill-sessions.spec.js +80 -0
- package/build/routes/chromium/tests/websocket.spec.js +23 -0
- package/build/routes/chromium/ws/browser.query.json +4 -0
- package/build/routes/chromium/ws/cdp.query.json +4 -0
- package/build/routes/chromium/ws/page.query.json +4 -0
- package/build/routes/chromium/ws/playwright.query.json +4 -0
- package/build/routes/firefox/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/firefox/tests/kill-sessions.spec.js +72 -0
- package/build/routes/firefox/ws/playwright.query.json +4 -0
- package/build/routes/management/http/kill.get.d.ts +21 -0
- package/build/routes/management/http/kill.get.js +19 -0
- package/build/routes/management/http/kill.get.query.json +193 -0
- package/build/routes/management/http/meta.get.js +3 -2
- package/build/routes/management/http/sessions.get.query.json +1 -0
- package/build/routes/management/tests/management.spec.js +12 -0
- package/build/routes/webkit/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/webkit/tests/kill-sessions.spec.js +72 -0
- package/build/routes/webkit/ws/playwright.query.json +4 -0
- package/build/shared/utils/performance/main.js +2 -1
- package/build/types.d.ts +2 -0
- package/build/types.js +1 -0
- package/build/utils.d.ts +1 -1
- package/build/utils.js +1 -10
- package/package.json +13 -13
- package/src/browsers/browsers.playwright.ts +3 -0
- package/src/browsers/index.ts +33 -12
- package/src/http.ts +6 -0
- package/src/routes/chrome/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/chromium/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/chromium/tests/websocket.spec.ts +29 -0
- package/src/routes/firefox/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/management/http/kill.get.ts +40 -0
- package/src/routes/management/http/meta.get.ts +12 -10
- package/src/routes/management/tests/management.spec.ts +19 -0
- package/src/routes/webkit/tests/kill-sessions.spec.ts +99 -0
- package/src/shared/utils/performance/main.ts +2 -8
- package/src/types.ts +1 -0
- package/src/utils.ts +2 -11
- package/static/docs/swagger.json +297 -10
- package/static/docs/swagger.min.json +296 -9
- package/static/function/client.js +157 -42
- package/static/function/index.html +157 -42
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "object",
|
|
3
|
+
"properties": {
|
|
4
|
+
"token": {
|
|
5
|
+
"description": "The authorization token",
|
|
6
|
+
"type": "string"
|
|
7
|
+
},
|
|
8
|
+
"browserId": {
|
|
9
|
+
"type": "string"
|
|
10
|
+
},
|
|
11
|
+
"trackingId": {
|
|
12
|
+
"description": "Custom session identifier",
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"blockAds": {
|
|
16
|
+
"description": "Whether or nor to load ad-blocking extensions for the session.\nThis currently uses uBlock Origin and may cause certain sites\nto not load properly.",
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
},
|
|
19
|
+
"launch": {
|
|
20
|
+
"description": "Launch options, which can be either an object\nof puppeteer.launch options or playwright.launchServer\noptions, depending on the API. Must be either JSON\nobject, or a base64-encoded JSON object.",
|
|
21
|
+
"anyOf": [
|
|
22
|
+
{
|
|
23
|
+
"$ref": "#/definitions/CDPLaunchOptions"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"$ref": "#/definitions/BrowserServerOptions"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "string"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"timeout": {
|
|
34
|
+
"description": "Override the system-level timeout for this request.\nAccepts a value in milliseconds.",
|
|
35
|
+
"type": "number"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"required": [
|
|
40
|
+
"token"
|
|
41
|
+
],
|
|
42
|
+
"definitions": {
|
|
43
|
+
"CDPLaunchOptions": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
"args": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": "string"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"defaultViewport": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"properties": {
|
|
55
|
+
"deviceScaleFactor": {
|
|
56
|
+
"type": "number"
|
|
57
|
+
},
|
|
58
|
+
"hasTouch": {
|
|
59
|
+
"type": "boolean"
|
|
60
|
+
},
|
|
61
|
+
"height": {
|
|
62
|
+
"type": "number"
|
|
63
|
+
},
|
|
64
|
+
"isLandscape": {
|
|
65
|
+
"type": "boolean"
|
|
66
|
+
},
|
|
67
|
+
"isMobile": {
|
|
68
|
+
"type": "boolean"
|
|
69
|
+
},
|
|
70
|
+
"width": {
|
|
71
|
+
"type": "number"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"additionalProperties": false,
|
|
75
|
+
"required": [
|
|
76
|
+
"height",
|
|
77
|
+
"width"
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"devtools": {
|
|
81
|
+
"type": "boolean"
|
|
82
|
+
},
|
|
83
|
+
"dumpio": {
|
|
84
|
+
"type": "boolean"
|
|
85
|
+
},
|
|
86
|
+
"headless": {
|
|
87
|
+
"enum": [
|
|
88
|
+
false,
|
|
89
|
+
"shell",
|
|
90
|
+
true
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"ignoreDefaultArgs": {
|
|
94
|
+
"anyOf": [
|
|
95
|
+
{
|
|
96
|
+
"type": "array",
|
|
97
|
+
"items": {
|
|
98
|
+
"type": "string"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "boolean"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"ignoreHTTPSErrors": {
|
|
107
|
+
"type": "boolean"
|
|
108
|
+
},
|
|
109
|
+
"slowMo": {
|
|
110
|
+
"type": "number"
|
|
111
|
+
},
|
|
112
|
+
"stealth": {
|
|
113
|
+
"type": "boolean"
|
|
114
|
+
},
|
|
115
|
+
"timeout": {
|
|
116
|
+
"type": "number"
|
|
117
|
+
},
|
|
118
|
+
"userDataDir": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"waitForInitialPage": {
|
|
122
|
+
"type": "boolean"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"additionalProperties": false
|
|
126
|
+
},
|
|
127
|
+
"BrowserServerOptions": {
|
|
128
|
+
"type": "object",
|
|
129
|
+
"properties": {
|
|
130
|
+
"args": {
|
|
131
|
+
"type": "array",
|
|
132
|
+
"items": {
|
|
133
|
+
"type": "string"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"chromiumSandbox": {
|
|
137
|
+
"type": "boolean"
|
|
138
|
+
},
|
|
139
|
+
"devtools": {
|
|
140
|
+
"type": "boolean"
|
|
141
|
+
},
|
|
142
|
+
"downloadsPath": {
|
|
143
|
+
"type": "string"
|
|
144
|
+
},
|
|
145
|
+
"headless": {
|
|
146
|
+
"type": "boolean"
|
|
147
|
+
},
|
|
148
|
+
"ignoreDefaultArgs": {
|
|
149
|
+
"anyOf": [
|
|
150
|
+
{
|
|
151
|
+
"type": "array",
|
|
152
|
+
"items": {
|
|
153
|
+
"type": "string"
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "boolean"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
"proxy": {
|
|
162
|
+
"type": "object",
|
|
163
|
+
"properties": {
|
|
164
|
+
"bypass": {
|
|
165
|
+
"type": "string"
|
|
166
|
+
},
|
|
167
|
+
"password": {
|
|
168
|
+
"type": "string"
|
|
169
|
+
},
|
|
170
|
+
"server": {
|
|
171
|
+
"type": "string"
|
|
172
|
+
},
|
|
173
|
+
"username": {
|
|
174
|
+
"type": "string"
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"additionalProperties": false,
|
|
178
|
+
"required": [
|
|
179
|
+
"server"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"timeout": {
|
|
183
|
+
"type": "number"
|
|
184
|
+
},
|
|
185
|
+
"tracesDir": {
|
|
186
|
+
"type": "string"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"additionalProperties": false
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
193
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { APITags, BrowserlessRoutes, ChromiumCDP, FirefoxPlaywright, HTTPManagementRoutes, HTTPRoute, Methods, WebKitPlaywright, availableBrowsers, contentTypes, jsonResponse, } from '@browserless.io/browserless';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
const semverReg = /(\*|\^|>|=|<|~)/gi;
|
|
4
5
|
const require = createRequire(import.meta.url);
|
|
5
|
-
const blessPackageJSON = require('
|
|
6
|
-
const { browsers } = require('
|
|
6
|
+
const blessPackageJSON = require(path.join(process.cwd(), 'package.json'));
|
|
7
|
+
const { browsers } = require(path.join(process.cwd(), 'node_modules', 'playwright-core', 'browsers.json'));
|
|
7
8
|
const chromium = browsers.find((b) => b.name === 'chromium').browserVersion;
|
|
8
9
|
const firefox = browsers.find((b) => b.name === 'firefox').browserVersion;
|
|
9
10
|
const webkit = browsers.find((b) => b.name === 'webkit').browserVersion;
|
|
@@ -68,4 +68,16 @@ describe('Management APIs', function () {
|
|
|
68
68
|
expect(res.status).to.equal(204);
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
|
+
it('allows requests to /kill', async () => {
|
|
72
|
+
await start();
|
|
73
|
+
await fetch('http://localhost:3000/kill/all?token=6R0W53R135510').then(async (res) => {
|
|
74
|
+
expect(res.status).to.equal(204);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
it('Throws an error trying to kill invalid session', async () => {
|
|
78
|
+
await start();
|
|
79
|
+
await fetch(`http://localhost:3000/kill/invalid-session?token=6R0W53R135510`).then(async (res) => {
|
|
80
|
+
expect(res.status).to.equal(404);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
71
83
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Browserless, Config, Metrics } from '@browserless.io/browserless';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { webkit } from 'playwright-core';
|
|
4
|
+
describe('/kill API webkit', function () {
|
|
5
|
+
let browserless;
|
|
6
|
+
const start = ({ config = new Config(), metrics = new Metrics(), } = {}) => {
|
|
7
|
+
config.setToken('browserless');
|
|
8
|
+
browserless = new Browserless({ config, metrics });
|
|
9
|
+
return browserless.start();
|
|
10
|
+
};
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await browserless.stop();
|
|
13
|
+
});
|
|
14
|
+
it('Kill all sessions', async () => {
|
|
15
|
+
await start();
|
|
16
|
+
const browser1 = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-1`);
|
|
17
|
+
const browser2 = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-2`);
|
|
18
|
+
await fetch('http://localhost:3000/kill/all?token=browserless').then(async (res) => {
|
|
19
|
+
expect(res.status).to.equal(204);
|
|
20
|
+
});
|
|
21
|
+
let errorThrown1;
|
|
22
|
+
try {
|
|
23
|
+
await browser1.newPage();
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
errorThrown1 = e;
|
|
27
|
+
}
|
|
28
|
+
let errorThrown2;
|
|
29
|
+
try {
|
|
30
|
+
await browser2.newPage();
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
errorThrown2 = e;
|
|
34
|
+
}
|
|
35
|
+
expect(errorThrown1.message).contains('closed');
|
|
36
|
+
expect(errorThrown2.message).contains('closed');
|
|
37
|
+
});
|
|
38
|
+
it('Kill session by browserId', async () => {
|
|
39
|
+
await start();
|
|
40
|
+
const browser = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless`);
|
|
41
|
+
await fetch('http://localhost:3000/sessions?token=browserless').then(async (res) => {
|
|
42
|
+
const sessions = await res.json();
|
|
43
|
+
const browserId = sessions[0].browserId;
|
|
44
|
+
await fetch(`http://localhost:3000/kill/${browserId}?token=browserless`).then(async (res) => {
|
|
45
|
+
expect(res.status).to.equal(204);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
let errorThrown;
|
|
49
|
+
try {
|
|
50
|
+
await browser.newPage();
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
errorThrown = e;
|
|
54
|
+
}
|
|
55
|
+
expect(errorThrown.message).contains('closed');
|
|
56
|
+
});
|
|
57
|
+
it('Kill session by trackingId', async () => {
|
|
58
|
+
await start();
|
|
59
|
+
const browser = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-1`);
|
|
60
|
+
await fetch('http://localhost:3000/kill/session-1?token=browserless').then(async (res) => {
|
|
61
|
+
expect(res.status).to.equal(204);
|
|
62
|
+
});
|
|
63
|
+
let errorThrown;
|
|
64
|
+
try {
|
|
65
|
+
await browser.newPage();
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
errorThrown = e;
|
|
69
|
+
}
|
|
70
|
+
expect(errorThrown.message).contains('closed');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { fork } from 'child_process';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
const __dirname = import.meta.dirname;
|
|
3
4
|
const DEFAULT_AUDIT_CONFIG = {
|
|
4
5
|
extends: 'lighthouse:default',
|
|
5
6
|
};
|
|
6
7
|
export default async ({ browser, context, logger, timeout, }) => {
|
|
7
8
|
return new Promise((resolve, reject) => {
|
|
8
|
-
const childPath = path.join(
|
|
9
|
+
const childPath = path.join(__dirname, 'child.js');
|
|
9
10
|
logger.trace(`Starting up child at ${childPath}`);
|
|
10
11
|
const child = fork(childPath);
|
|
11
12
|
const port = new URL(browser.wsEndpoint() || '').port;
|
package/build/types.d.ts
CHANGED
|
@@ -520,6 +520,7 @@ export declare const BrowserlessWebKitRoutes: {
|
|
|
520
520
|
export declare const BrowserlessManagementRoutes: {
|
|
521
521
|
ActiveGetRoute: string;
|
|
522
522
|
ConfigGetRoute: string;
|
|
523
|
+
KillGetRoute: string;
|
|
523
524
|
MetaGetRoute: string;
|
|
524
525
|
MetricsGetRoute: string;
|
|
525
526
|
MetricsTotalGetRoute: string;
|
|
@@ -530,6 +531,7 @@ export declare const BrowserlessManagementRoutes: {
|
|
|
530
531
|
export declare const BrowserlessRoutes: {
|
|
531
532
|
ActiveGetRoute: string;
|
|
532
533
|
ConfigGetRoute: string;
|
|
534
|
+
KillGetRoute: string;
|
|
533
535
|
MetaGetRoute: string;
|
|
534
536
|
MetricsGetRoute: string;
|
|
535
537
|
MetricsTotalGetRoute: string;
|
package/build/types.js
CHANGED
|
@@ -190,6 +190,7 @@ export const BrowserlessWebKitRoutes = {
|
|
|
190
190
|
export const BrowserlessManagementRoutes = {
|
|
191
191
|
ActiveGetRoute: 'ActiveGetRoute',
|
|
192
192
|
ConfigGetRoute: 'ConfigGetRoute',
|
|
193
|
+
KillGetRoute: 'KillGetRoute',
|
|
193
194
|
MetaGetRoute: 'MetaGetRoute',
|
|
194
195
|
MetricsGetRoute: 'MetricsGetRoute',
|
|
195
196
|
MetricsTotalGetRoute: 'MetricsTotalGetRoute',
|
package/build/utils.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare class Timeout extends Error {
|
|
|
126
126
|
export declare const bestAttemptCatch: (bestAttempt: boolean) => (err: Error) => void;
|
|
127
127
|
export declare const parseBooleanParam: (params: URLSearchParams, name: string, defaultValue: boolean) => boolean;
|
|
128
128
|
export declare const parseNumberParam: (params: URLSearchParams, name: string, defaultValue: number) => number;
|
|
129
|
-
export declare const parseStringParam: (params: URLSearchParams, name: string, defaultValue: string) =>
|
|
129
|
+
export declare const parseStringParam: (params: URLSearchParams, name: string, defaultValue: string) => string;
|
|
130
130
|
export declare const encrypt: (text: string, secret: Buffer) => string;
|
|
131
131
|
export declare const decrypt: (encryptedText: string, secret: Buffer) => string;
|
|
132
132
|
interface RequestInitTimeout extends RequestInit {
|
package/build/utils.js
CHANGED
|
@@ -538,16 +538,7 @@ export const parseStringParam = (params, name, defaultValue) => {
|
|
|
538
538
|
if (value === null) {
|
|
539
539
|
return defaultValue;
|
|
540
540
|
}
|
|
541
|
-
|
|
542
|
-
if (value === '') {
|
|
543
|
-
return true;
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
return JSON.parse(value);
|
|
547
|
-
}
|
|
548
|
-
catch {
|
|
549
|
-
return value;
|
|
550
|
-
}
|
|
541
|
+
return value;
|
|
551
542
|
};
|
|
552
543
|
export const encrypt = (text, secret) => {
|
|
553
544
|
const iv = crypto.randomBytes(16);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.24.
|
|
3
|
+
"version": "2.24.1",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -48,25 +48,25 @@
|
|
|
48
48
|
"tsconfig.json"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"debug": "^4.
|
|
51
|
+
"debug": "^4.4.0",
|
|
52
52
|
"del": "^8.0.0",
|
|
53
53
|
"enjoi": "^9.0.1",
|
|
54
54
|
"file-type": "^19.6.0",
|
|
55
55
|
"get-port": "^7.1.0",
|
|
56
56
|
"gradient-string": "^3.0.0",
|
|
57
57
|
"http-proxy": "^1.18.1",
|
|
58
|
-
"lighthouse": "^12.
|
|
58
|
+
"lighthouse": "^12.3.0",
|
|
59
59
|
"micromatch": "^4.0.8",
|
|
60
60
|
"playwright-1.45": "npm:playwright-core@1.45.3",
|
|
61
61
|
"playwright-1.46": "npm:playwright-core@1.46.1",
|
|
62
62
|
"playwright-1.47": "npm:playwright-core@1.47.2",
|
|
63
63
|
"playwright-1.48": "npm:playwright-core@1.48.2",
|
|
64
|
-
"playwright-core": "^1.49.
|
|
65
|
-
"puppeteer-core": "^23.
|
|
64
|
+
"playwright-core": "^1.49.1",
|
|
65
|
+
"puppeteer-core": "^23.11.1",
|
|
66
66
|
"puppeteer-extra": "^3.3.6",
|
|
67
67
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
68
68
|
"queue": "^7.0.0",
|
|
69
|
-
"systeminformation": "^5.23.
|
|
69
|
+
"systeminformation": "^5.23.16",
|
|
70
70
|
"tar-fs": "^3.0.6"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
@@ -76,23 +76,23 @@
|
|
|
76
76
|
"@types/http-proxy": "^1.17.15",
|
|
77
77
|
"@types/micromatch": "^4.0.9",
|
|
78
78
|
"@types/mocha": "^10.0.10",
|
|
79
|
-
"@types/node": "^22.10.
|
|
79
|
+
"@types/node": "^22.10.2",
|
|
80
80
|
"@types/sinon": "^17.0.3",
|
|
81
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
82
|
-
"@typescript-eslint/parser": "^8.
|
|
81
|
+
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
82
|
+
"@typescript-eslint/parser": "^8.18.1",
|
|
83
83
|
"assert": "^2.0.0",
|
|
84
84
|
"chai": "^5.1.2",
|
|
85
85
|
"cross-env": "^7.0.3",
|
|
86
86
|
"env-cmd": "^10.1.0",
|
|
87
|
-
"esbuild": "^0.24.
|
|
87
|
+
"esbuild": "^0.24.2",
|
|
88
88
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
89
|
-
"eslint": "^9.
|
|
89
|
+
"eslint": "^9.17.0",
|
|
90
90
|
"extract-zip": "^2.0.1",
|
|
91
91
|
"gunzip-maybe": "^1.4.2",
|
|
92
|
-
"marked": "^15.0.
|
|
92
|
+
"marked": "^15.0.4",
|
|
93
93
|
"mocha": "^11.0.1",
|
|
94
94
|
"move-file": "^3.1.0",
|
|
95
|
-
"prettier": "^3.4.
|
|
95
|
+
"prettier": "^3.4.2",
|
|
96
96
|
"sinon": "^19.0.2",
|
|
97
97
|
"ts-node": "^10.9.2",
|
|
98
98
|
"typescript": "^5.7.2",
|
|
@@ -24,6 +24,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
24
24
|
protected userDataDir: string | null;
|
|
25
25
|
protected running = false;
|
|
26
26
|
protected logger: Logger;
|
|
27
|
+
protected socket: Duplex | null = null;
|
|
27
28
|
protected proxy = httpProxy.createProxyServer();
|
|
28
29
|
protected browser: playwright.BrowserServer | null = null;
|
|
29
30
|
protected browserWSEndpoint: string | null = null;
|
|
@@ -78,6 +79,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
78
79
|
this.logger.info(
|
|
79
80
|
`Closing ${this.constructor.name} process and all listeners`,
|
|
80
81
|
);
|
|
82
|
+
this.socket?.destroy();
|
|
81
83
|
this.emit('close');
|
|
82
84
|
this.cleanListeners();
|
|
83
85
|
this.browser.close();
|
|
@@ -167,6 +169,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
167
169
|
socket: Duplex,
|
|
168
170
|
head: Buffer,
|
|
169
171
|
): Promise<void> {
|
|
172
|
+
this.socket = socket;
|
|
170
173
|
return new Promise((resolve, reject) => {
|
|
171
174
|
if (!this.browserWSEndpoint) {
|
|
172
175
|
throw new ServerError(
|
package/src/browsers/index.ts
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
Config,
|
|
17
17
|
FileSystem,
|
|
18
18
|
FirefoxPlaywright,
|
|
19
|
-
HTTPManagementRoutes,
|
|
20
19
|
Hooks,
|
|
21
20
|
Logger,
|
|
22
21
|
NotFound,
|
|
@@ -35,6 +34,7 @@ import {
|
|
|
35
34
|
} from '@browserless.io/browserless';
|
|
36
35
|
import { Page } from 'puppeteer-core';
|
|
37
36
|
import { deleteAsync } from 'del';
|
|
37
|
+
import micromatch from 'micromatch';
|
|
38
38
|
import path from 'path';
|
|
39
39
|
|
|
40
40
|
export class BrowserManager {
|
|
@@ -236,11 +236,7 @@ export class BrowserManager {
|
|
|
236
236
|
initialConnectURL: new URL(session.initialConnectURL, serverAddress)
|
|
237
237
|
.href,
|
|
238
238
|
killURL: session.id
|
|
239
|
-
? makeExternalURL(
|
|
240
|
-
serverAddress,
|
|
241
|
-
HTTPManagementRoutes.sessions,
|
|
242
|
-
session.id,
|
|
243
|
-
)
|
|
239
|
+
? makeExternalURL(serverAddress, '/kill/', session.id)
|
|
244
240
|
: null,
|
|
245
241
|
running: browser.isRunning(),
|
|
246
242
|
timeAliveMs: Date.now() - session.startedOn,
|
|
@@ -277,12 +273,13 @@ export class BrowserManager {
|
|
|
277
273
|
public async close(
|
|
278
274
|
browser: BrowserInstance,
|
|
279
275
|
session: BrowserlessSession,
|
|
276
|
+
force = false,
|
|
280
277
|
): Promise<void> {
|
|
281
278
|
const now = Date.now();
|
|
282
279
|
const keepUntil = browser.keepUntil();
|
|
283
280
|
const connected = session.numbConnected;
|
|
284
281
|
const hasKeepUntil = keepUntil > now;
|
|
285
|
-
const keepOpen = connected > 0 || hasKeepUntil;
|
|
282
|
+
const keepOpen = (connected > 0 || hasKeepUntil) && !force;
|
|
286
283
|
const cleanupACtions: Array<() => Promise<void>> = [];
|
|
287
284
|
const priorTimer = this.timers.get(session.id);
|
|
288
285
|
|
|
@@ -292,10 +289,10 @@ export class BrowserManager {
|
|
|
292
289
|
}
|
|
293
290
|
|
|
294
291
|
this.log.info(
|
|
295
|
-
`${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}`,
|
|
292
|
+
`${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}, force: ${force}`,
|
|
296
293
|
);
|
|
297
294
|
|
|
298
|
-
if (hasKeepUntil) {
|
|
295
|
+
if (!force && hasKeepUntil) {
|
|
299
296
|
const timeout = keepUntil - now;
|
|
300
297
|
this.log.trace(
|
|
301
298
|
`Setting timer ${timeout.toLocaleString()} for "${session.id}"`,
|
|
@@ -328,6 +325,28 @@ export class BrowserManager {
|
|
|
328
325
|
}
|
|
329
326
|
}
|
|
330
327
|
|
|
328
|
+
public async killSessions(target: string): Promise<void> {
|
|
329
|
+
this.log.info(`killSessions invoked target: "${target}"`);
|
|
330
|
+
const sessions = Array.from(this.browsers);
|
|
331
|
+
let closed = 0;
|
|
332
|
+
for (const [browser, session] of sessions) {
|
|
333
|
+
if (
|
|
334
|
+
session.trackingId === target ||
|
|
335
|
+
session.id === target ||
|
|
336
|
+
target === 'all'
|
|
337
|
+
) {
|
|
338
|
+
this.log.info(
|
|
339
|
+
`Closing browser via killSessions BrowserId: "${session.id}", trackingId: "${session.trackingId}"`,
|
|
340
|
+
);
|
|
341
|
+
this.close(browser, session, true);
|
|
342
|
+
closed++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (closed === 0 && target !== 'all') {
|
|
346
|
+
throw new NotFound(`Couldn't locate session for id: "${target}"`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
331
350
|
public async getAllSessions(
|
|
332
351
|
trackingId?: string,
|
|
333
352
|
): Promise<BrowserlessSessionJSON[]> {
|
|
@@ -398,12 +417,14 @@ export class BrowserManager {
|
|
|
398
417
|
);
|
|
399
418
|
}
|
|
400
419
|
|
|
401
|
-
if (
|
|
402
|
-
['/', '.', '\\'].some((routeLike) => trackingId.includes(routeLike))
|
|
403
|
-
) {
|
|
420
|
+
if (!micromatch.isMatch(trackingId, '+([0-9a-zA-Z-_])')) {
|
|
404
421
|
throw new BadRequest(`trackingId contains invalid characters`);
|
|
405
422
|
}
|
|
406
423
|
|
|
424
|
+
if (trackingId === 'all') {
|
|
425
|
+
throw new BadRequest(`trackingId cannot be the reserved word "all"`);
|
|
426
|
+
}
|
|
427
|
+
|
|
407
428
|
this.log.info(`Assigning session trackingId "${trackingId}"`);
|
|
408
429
|
}
|
|
409
430
|
|
package/src/http.ts
CHANGED
|
@@ -126,6 +126,7 @@ export enum HTTPRoutes {
|
|
|
126
126
|
export enum HTTPManagementRoutes {
|
|
127
127
|
active = '/active?(/)',
|
|
128
128
|
config = '/config?(/)',
|
|
129
|
+
kill = '/kill/+([0-9a-zA-Z-_])?(/)',
|
|
129
130
|
meta = '/meta?(/)',
|
|
130
131
|
metrics = '/metrics?(/)',
|
|
131
132
|
metricsTotal = '/metrics/total?(/)',
|
|
@@ -174,4 +175,9 @@ export interface SystemQueryParameters {
|
|
|
174
175
|
* The authorization token
|
|
175
176
|
*/
|
|
176
177
|
token?: string;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Custom session identifier
|
|
181
|
+
*/
|
|
182
|
+
trackingId?: string;
|
|
177
183
|
}
|