@browserless.io/browserless 2.12.0-beta-2 → 2.12.0-beta-4

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.
Files changed (102) hide show
  1. package/build/browserless.d.ts +1 -0
  2. package/build/browserless.js +6 -0
  3. package/build/browsers/chromium.cdp.d.ts +1 -1
  4. package/build/browsers/chromium.cdp.js +2 -2
  5. package/build/browsers/chromium.playwright.d.ts +2 -2
  6. package/build/browsers/chromium.playwright.js +7 -5
  7. package/build/browsers/firefox.playwright.d.ts +2 -2
  8. package/build/browsers/firefox.playwright.js +7 -5
  9. package/build/browsers/index.d.ts +3 -2
  10. package/build/browsers/index.js +40 -16
  11. package/build/browsers/webkit.playwright.d.ts +2 -2
  12. package/build/browsers/webkit.playwright.js +7 -5
  13. package/build/config.d.ts +11 -0
  14. package/build/config.js +16 -0
  15. package/build/routes/chrome/http/content.post.body.json +8 -8
  16. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  17. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  18. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  19. package/build/routes/chrome/tests/websocket.spec.js +18 -3
  20. package/build/routes/chromium/http/content.post.body.json +8 -8
  21. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  22. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  23. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  24. package/build/routes/chromium/tests/websocket.spec.js +18 -0
  25. package/build/routes/firefox/tests/websocket.spec.js +18 -1
  26. package/build/routes/webkit/tests/websocket.spec.js +18 -0
  27. package/build/types.d.ts +1 -1
  28. package/build/utils.d.ts +9 -0
  29. package/build/utils.js +9 -0
  30. package/docker/chromium/Dockerfile +2 -1
  31. package/docker/firefox/Dockerfile +2 -1
  32. package/docker/multi/Dockerfile +1 -1
  33. package/docker/webkit/Dockerfile +2 -1
  34. package/extensions/ublock/_locales/eu/messages.json +4 -4
  35. package/extensions/ublock/_locales/hi/messages.json +5 -5
  36. package/extensions/ublock/_locales/kn/messages.json +11 -11
  37. package/extensions/ublock/_locales/nb/messages.json +2 -2
  38. package/extensions/ublock/_locales/no/messages.json +2 -2
  39. package/extensions/ublock/_locales/ro/messages.json +1 -1
  40. package/extensions/ublock/_locales/sv/messages.json +1 -1
  41. package/extensions/ublock/_locales/zh_CN/messages.json +2 -2
  42. package/extensions/ublock/assets/assets.json +3 -8
  43. package/extensions/ublock/assets/resources/scriptlets.js +128 -31
  44. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +4870 -3560
  45. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +662 -173
  46. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +10 -42
  47. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +241 -80
  48. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +2093 -1224
  49. package/extensions/ublock/assets/ublock/badlists.txt +2 -0
  50. package/extensions/ublock/assets/ublock/badware.min.txt +408 -287
  51. package/extensions/ublock/assets/ublock/filters.min.txt +947 -645
  52. package/extensions/ublock/assets/ublock/privacy.min.txt +43 -8
  53. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +55 -93
  54. package/extensions/ublock/assets/ublock/unbreak.min.txt +52 -19
  55. package/extensions/ublock/css/1p-filters.css +2 -0
  56. package/extensions/ublock/css/codemirror.css +2 -2
  57. package/extensions/ublock/css/dashboard.css +2 -5
  58. package/extensions/ublock/css/epicker-ui.css +3 -3
  59. package/extensions/ublock/css/fa-icons.css +3 -0
  60. package/extensions/ublock/css/logger-ui-inspector.css +1 -0
  61. package/extensions/ublock/css/logger-ui.css +44 -32
  62. package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +1 -0
  63. package/extensions/ublock/js/3p-filters.js +4 -5
  64. package/extensions/ublock/js/biditrie.js +16 -11
  65. package/extensions/ublock/js/cachestorage.js +37 -37
  66. package/extensions/ublock/js/contentscript-extra.js +0 -2
  67. package/extensions/ublock/js/contentscript.js +1 -6
  68. package/extensions/ublock/js/epicker-ui.js +28 -36
  69. package/extensions/ublock/js/fa-icons.js +1 -0
  70. package/extensions/ublock/js/hntrie.js +19 -13
  71. package/extensions/ublock/js/logger-ui-inspector.js +6 -13
  72. package/extensions/ublock/js/logger-ui.js +264 -264
  73. package/extensions/ublock/js/s14e-serializer.js +267 -264
  74. package/extensions/ublock/js/scriptlet-filtering.js +12 -18
  75. package/extensions/ublock/js/scriptlets/dom-inspector.js +1 -5
  76. package/extensions/ublock/js/scriptlets/epicker.js +53 -59
  77. package/extensions/ublock/js/start.js +0 -8
  78. package/extensions/ublock/js/storage.js +2 -9
  79. package/extensions/ublock/js/vapi-background.js +19 -20
  80. package/extensions/ublock/js/vapi-common.js +2 -7
  81. package/extensions/ublock/js/vapi.js +0 -4
  82. package/extensions/ublock/js/webext.js +23 -15
  83. package/extensions/ublock/logger-ui.html +24 -15
  84. package/extensions/ublock/manifest.json +2 -3
  85. package/package.json +18 -6
  86. package/src/browserless.ts +11 -0
  87. package/src/browsers/chromium.cdp.ts +2 -2
  88. package/src/browsers/chromium.playwright.ts +8 -4
  89. package/src/browsers/firefox.playwright.ts +8 -5
  90. package/src/browsers/index.ts +53 -18
  91. package/src/browsers/webkit.playwright.ts +8 -4
  92. package/src/config.ts +20 -0
  93. package/src/routes/chrome/tests/websocket.spec.ts +25 -4
  94. package/src/routes/chromium/tests/websocket.spec.ts +25 -0
  95. package/src/routes/firefox/tests/websocket.spec.ts +25 -1
  96. package/src/routes/webkit/tests/websocket.spec.ts +25 -0
  97. package/src/types.ts +1 -1
  98. package/src/utils.ts +9 -0
  99. package/static/docs/swagger.json +9 -9
  100. package/static/docs/swagger.min.json +9 -9
  101. package/static/function/client.js +95 -136
  102. package/static/function/index.html +95 -136
@@ -43,8 +43,8 @@ export class ChromiumPlaywright extends EventEmitter {
43
43
  this.removeAllListeners();
44
44
  }
45
45
 
46
- public keepAlive() {
47
- return false;
46
+ public keepUntil() {
47
+ return 0;
48
48
  }
49
49
 
50
50
  public isRunning = (): boolean => this.running;
@@ -89,10 +89,11 @@ export class ChromiumPlaywright extends EventEmitter {
89
89
 
90
90
  public launch = async (
91
91
  options: BrowserServerOptions = {},
92
+ version?: string,
92
93
  ): Promise<playwright.BrowserServer> => {
93
94
  this.logger.info(`Launching ${this.constructor.name} Handler`);
94
95
 
95
- this.browser = await playwright.chromium.launchServer({
96
+ const opts = {
96
97
  ...options,
97
98
  args: [
98
99
  `--no-sandbox`,
@@ -100,8 +101,11 @@ export class ChromiumPlaywright extends EventEmitter {
100
101
  this.userDataDir ? `--user-data-dir=${this.userDataDir}` : '',
101
102
  ],
102
103
  executablePath: this.executablePath,
103
- });
104
+ };
105
+
106
+ const versionedPw = await this.config.loadPwVersion(version!);
104
107
 
108
+ this.browser = await versionedPw.chromium.launchServer(opts);
105
109
  const browserWSEndpoint = this.browser.wsEndpoint();
106
110
 
107
111
  this.logger.info(
@@ -42,8 +42,8 @@ export class FirefoxPlaywright extends EventEmitter {
42
42
  this.removeAllListeners();
43
43
  }
44
44
 
45
- public keepAlive() {
46
- return false;
45
+ public keepUntil() {
46
+ return 0;
47
47
  }
48
48
 
49
49
  public isRunning = (): boolean => this.running;
@@ -84,18 +84,21 @@ export class FirefoxPlaywright extends EventEmitter {
84
84
 
85
85
  public launch = async (
86
86
  options: BrowserServerOptions = {},
87
+ version?: string,
87
88
  ): Promise<playwright.BrowserServer> => {
88
89
  this.logger.info(`Launching ${this.constructor.name} Handler`);
89
-
90
- this.browser = await playwright.firefox.launchServer({
90
+ const opts = {
91
91
  ...options,
92
92
  args: [
93
93
  ...(options.args || []),
94
94
  this.userDataDir ? `-profile=${this.userDataDir}` : '',
95
95
  ],
96
96
  executablePath: playwright.firefox.executablePath(),
97
- });
97
+ };
98
+
99
+ const versionedPw = await this.config.loadPwVersion(version!);
98
100
 
101
+ this.browser = await versionedPw.firefox.launchServer(opts);
99
102
  const browserWSEndpoint = this.browser.wsEndpoint();
100
103
 
101
104
  this.logger.info(
@@ -29,6 +29,7 @@ import {
29
29
  makeExternalURL,
30
30
  noop,
31
31
  parseBooleanParam,
32
+ pwVersionRegex,
32
33
  } from '@browserless.io/browserless';
33
34
  import { Page } from 'puppeteer-core';
34
35
  import { deleteAsync } from 'del';
@@ -36,7 +37,7 @@ import path from 'path';
36
37
 
37
38
  export class BrowserManager {
38
39
  protected browsers: Map<BrowserInstance, BrowserlessSession> = new Map();
39
- protected timers: Map<string, number> = new Map();
40
+ protected timers: Map<string, NodeJS.Timeout> = new Map();
40
41
  protected log = new Logger('browser-manager');
41
42
  protected chromeBrowsers = [ChromiumCDP, ChromeCDP];
42
43
  protected playwrightBrowserNames = [
@@ -225,7 +226,7 @@ export class BrowserManager {
225
226
  {
226
227
  ...session,
227
228
  browser: browser.constructor.name,
228
- browserId: browser.wsEndpoint()?.split('/').pop() as string,
229
+ browserId: session.id,
229
230
  initialConnectURL: new URL(session.initialConnectURL, serverAddress)
230
231
  .href,
231
232
  killURL: session.id
@@ -267,26 +268,54 @@ export class BrowserManager {
267
268
  browser: BrowserInstance,
268
269
  session: BrowserlessSession,
269
270
  ): Promise<void> => {
271
+ const now = Date.now();
272
+ const keepUntil = browser.keepUntil();
273
+ const connected = session.numbConnected;
274
+ const hasKeepUntil = keepUntil > now;
275
+ const keepOpen = connected > 0 || hasKeepUntil;
270
276
  const cleanupACtions: Array<() => Promise<void>> = [];
271
- this.log.info(`${session.numbConnected} Client(s) are currently connected`);
277
+ const priorTimer = this.timers.get(session.id);
272
278
 
273
- // Don't close if there's clients still connected
274
- if (session.numbConnected > 0 || browser.keepAlive()) {
275
- return;
279
+ if (priorTimer) {
280
+ this.log.info(`Deleting prior keep-until timer for "${session.id}"`);
281
+ global.clearTimeout(priorTimer);
276
282
  }
277
283
 
278
- this.log.info(`Closing browser session`);
279
- cleanupACtions.push(() => browser.close());
284
+ this.log.info(
285
+ `${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}`,
286
+ );
280
287
 
281
- if (session.isTempDataDir) {
282
- this.log.info(
283
- `Deleting "${session.userDataDir}" user-data-dir and session from memory`,
288
+ if (hasKeepUntil) {
289
+ const timeout = keepUntil - now;
290
+ this.log.trace(
291
+ `Setting timer ${timeout.toLocaleString()} for "${session.id}"`,
292
+ );
293
+ this.timers.set(
294
+ session.id,
295
+ global.setTimeout(() => {
296
+ const session = this.browsers.get(browser);
297
+ if (session) {
298
+ this.log.trace(`Timer hit for "${session.id}"`),
299
+ this.close(browser, session);
300
+ }
301
+ }, timeout),
284
302
  );
285
- this.browsers.delete(browser);
286
- cleanupACtions.push(() => this.removeUserDataDir(session.userDataDir));
287
303
  }
288
304
 
289
- await Promise.all(cleanupACtions.map((a) => a()));
305
+ if (!keepOpen) {
306
+ this.log.info(`Closing browser session`);
307
+ cleanupACtions.push(() => browser.close());
308
+
309
+ if (session.isTempDataDir) {
310
+ this.log.info(
311
+ `Deleting "${session.userDataDir}" user-data-dir and session from memory`,
312
+ );
313
+ this.browsers.delete(browser);
314
+ cleanupACtions.push(() => this.removeUserDataDir(session.userDataDir));
315
+ }
316
+
317
+ await Promise.all(cleanupACtions.map((a) => a()));
318
+ }
290
319
  };
291
320
 
292
321
  public getAllSessions = async (): Promise<BrowserlessSessionJSON[]> => {
@@ -436,6 +465,9 @@ export class BrowserManager {
436
465
  arg.includes('--proxy-server='),
437
466
  );
438
467
 
468
+ /**
469
+ * If it is a playwright request
470
+ */
439
471
  if (
440
472
  launchOptions.args &&
441
473
  proxyServerArg &&
@@ -455,8 +487,14 @@ export class BrowserManager {
455
487
  userDataDir,
456
488
  });
457
489
 
490
+ const match = (req.headers['user-agent'] || '').match(pwVersionRegex);
491
+ const pwVersion = match ? match[1] : 'default';
492
+
493
+ await browser.launch(launchOptions as object, pwVersion);
494
+ await this.hooks.browser({ browser, meta: req.parsed });
495
+
458
496
  const session: BrowserlessSession = {
459
- id: null,
497
+ id: browser.wsEndpoint()?.split('/').pop() as string,
460
498
  initialConnectURL:
461
499
  path.join(req.parsed.pathname, req.parsed.search) || '',
462
500
  isTempDataDir: !manualUserDataDir,
@@ -471,9 +509,6 @@ export class BrowserManager {
471
509
 
472
510
  this.browsers.set(browser, session);
473
511
 
474
- await browser.launch(launchOptions as object);
475
- await this.hooks.browser({ browser, meta: req.parsed });
476
-
477
512
  browser.on('newPage', async (page) => {
478
513
  await this.onNewPage(req, page);
479
514
  (router.onNewPage || noop)(req.parsed || '', page);
@@ -42,8 +42,8 @@ export class WebkitPlaywright extends EventEmitter {
42
42
  this.removeAllListeners();
43
43
  }
44
44
 
45
- public keepAlive() {
46
- return false;
45
+ public keepUntil() {
46
+ return 0;
47
47
  }
48
48
 
49
49
  public isRunning = (): boolean => this.running;
@@ -84,18 +84,22 @@ export class WebkitPlaywright extends EventEmitter {
84
84
 
85
85
  public launch = async (
86
86
  options: BrowserServerOptions = {},
87
+ version?: string,
87
88
  ): Promise<playwright.BrowserServer> => {
88
89
  this.logger.info(`Launching ${this.constructor.name} Handler`);
89
90
 
90
- this.browser = await playwright.webkit.launchServer({
91
+ const opts = {
91
92
  ...options,
92
93
  args: [
93
94
  ...(options.args || []),
94
95
  this.userDataDir ? `-profile=${this.userDataDir}` : '',
95
96
  ],
96
97
  executablePath: playwright.webkit.executablePath(),
97
- });
98
+ };
99
+
100
+ const versionedPw = await this.config.loadPwVersion(version!);
98
101
 
102
+ this.browser = await versionedPw.webkit.launchServer(opts);
99
103
  const browserWSEndpoint = this.browser.wsEndpoint();
100
104
 
101
105
  this.logger.info(
package/src/config.ts CHANGED
@@ -4,6 +4,7 @@ import debug from 'debug';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { mkdir } from 'fs/promises';
6
6
  import path from 'path';
7
+ import playwright from 'playwright-core';
7
8
  import { tmpdir } from 'os';
8
9
 
9
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -165,6 +166,7 @@ export class Config extends EventEmitter {
165
166
  protected rejectAlertURL = process.env.REJECT_ALERT_URL ?? null;
166
167
  protected timeoutAlertURL = process.env.TIMEOUT_ALERT_URL ?? null;
167
168
  protected errorAlertURL = process.env.ERROR_ALERT_URL ?? null;
169
+ protected pwVersions: { [key: string]: string } = {};
168
170
 
169
171
  public getRoutes = (): string => this.routes;
170
172
  public getHost = (): string => this.host;
@@ -172,6 +174,7 @@ export class Config extends EventEmitter {
172
174
  public getIsWin = (): boolean => this.isWin;
173
175
  public getToken = (): string | null => this.token;
174
176
  public getDebug = (): string => this.debug;
177
+ public getPwVersions = () => this.pwVersions;
175
178
 
176
179
  /**
177
180
  * The maximum number of concurrent sessions allowed. Set
@@ -261,6 +264,23 @@ export class Config extends EventEmitter {
261
264
 
262
265
  public getMetricsJSONPath = () => this.metricsJSONPath;
263
266
 
267
+ public setPwVersions = (versions: { [key: string]: string }) => {
268
+ this.pwVersions = versions;
269
+ };
270
+
271
+ public loadPwVersion = async (
272
+ version: string,
273
+ ): Promise<typeof playwright> => {
274
+ const versions = this.getPwVersions();
275
+
276
+ try {
277
+ return await import(versions[version] || versions['default']);
278
+ } catch (err) {
279
+ debug.log('Error importing Playwright. Using default version', err);
280
+ return playwright;
281
+ }
282
+ };
283
+
264
284
  public setDataDir = async (newDataDir: string): Promise<string> => {
265
285
  if (!(await exists(newDataDir))) {
266
286
  throw new Error(
@@ -13,10 +13,6 @@ import { expect } from 'chai';
13
13
  import puppeteer from 'puppeteer-core';
14
14
 
15
15
  describe('Chrome WebSocket API', function () {
16
- // Server shutdown can take a few seconds
17
- // and so can these tests :/
18
- this.timeout(10000);
19
-
20
16
  let browserless: Browserless;
21
17
 
22
18
  const start = ({
@@ -461,6 +457,31 @@ describe('Chrome WebSocket API', function () {
461
457
  expect(results.queued).to.equal(0);
462
458
  });
463
459
 
460
+ it('runs multiple versions of playwright', async () => {
461
+ const config = new Config();
462
+ config.setToken('browserless');
463
+ const metrics = new Metrics();
464
+ await start({ config, metrics });
465
+
466
+ const pwVersions = Object.keys(config.getPwVersions());
467
+
468
+ for (const version of pwVersions) {
469
+ const pw = await import(config.getPwVersions()[version]);
470
+ const browser = await pw.chromium.connect(
471
+ `ws://localhost:3000/chrome/playwright?token=browserless`,
472
+ );
473
+
474
+ await browser.close();
475
+ await sleep(100);
476
+ }
477
+
478
+ const results = metrics.get();
479
+ expect(results.timedout).to.equal(0);
480
+ expect(results.successful).to.equal(pwVersions.length);
481
+ expect(results.rejected).to.equal(0);
482
+ expect(results.queued).to.equal(0);
483
+ });
484
+
464
485
  it('rejects playwright without tokens', async () => {
465
486
  const config = new Config();
466
487
  config.setToken('browserless');
@@ -461,6 +461,31 @@ describe('Chromium WebSocket API', function () {
461
461
  expect(results.queued).to.equal(0);
462
462
  });
463
463
 
464
+ it('runs multiple versions of playwright', async () => {
465
+ const config = new Config();
466
+ config.setToken('browserless');
467
+ const metrics = new Metrics();
468
+ await start({ config, metrics });
469
+
470
+ const pwVersions = Object.keys(config.getPwVersions());
471
+
472
+ for (const version of pwVersions) {
473
+ const pw = await import(config.getPwVersions()[version]);
474
+ const browser = await pw.chromium.connect(
475
+ `ws://localhost:3000/playwright/chromium?token=browserless`,
476
+ );
477
+
478
+ await browser.close();
479
+ await sleep(100);
480
+ }
481
+
482
+ const results = metrics.get();
483
+ expect(results.timedout).to.equal(0);
484
+ expect(results.successful).to.equal(pwVersions.length);
485
+ expect(results.rejected).to.equal(0);
486
+ expect(results.queued).to.equal(0);
487
+ });
488
+
464
489
  it('rejects playwright without tokens', async () => {
465
490
  const config = new Config();
466
491
  config.setToken('browserless');
@@ -10,7 +10,6 @@ import { firefox } from 'playwright-core';
10
10
  describe('Firefox Websocket API', function () {
11
11
  // Server shutdown can take a few seconds
12
12
  // and so can these tests :/
13
- this.timeout(5000);
14
13
 
15
14
  let browserless: Browserless;
16
15
 
@@ -39,6 +38,31 @@ describe('Firefox Websocket API', function () {
39
38
  await browser.close();
40
39
  });
41
40
 
41
+ it('runs multiple versions of playwright', async () => {
42
+ const config = new Config();
43
+ config.setToken('browserless');
44
+ const metrics = new Metrics();
45
+ await start({ config, metrics });
46
+
47
+ const pwVersions = Object.keys(config.getPwVersions());
48
+
49
+ for (const version of pwVersions) {
50
+ const pw = await import(config.getPwVersions()[version]);
51
+ const browser = await pw.firefox.connect(
52
+ `ws://localhost:3000/playwright/firefox?token=browserless`,
53
+ );
54
+
55
+ await browser.close();
56
+ await sleep(100);
57
+ }
58
+
59
+ const results = metrics.get();
60
+ expect(results.timedout).to.equal(0);
61
+ expect(results.successful).to.equal(pwVersions.length);
62
+ expect(results.rejected).to.equal(0);
63
+ expect(results.queued).to.equal(0);
64
+ });
65
+
42
66
  it('rejects playwright requests', async () => {
43
67
  const config = new Config();
44
68
  config.setToken('browserless');
@@ -39,6 +39,31 @@ describe('Webkit Websocket API', function () {
39
39
  await browser.close();
40
40
  });
41
41
 
42
+ it('runs multiple versions of playwright', async () => {
43
+ const config = new Config();
44
+ config.setToken('browserless');
45
+ const metrics = new Metrics();
46
+ await start({ config, metrics });
47
+
48
+ const pwVersions = Object.keys(config.getPwVersions());
49
+
50
+ for (const version of pwVersions) {
51
+ const pw = await import(config.getPwVersions()[version]);
52
+ const browser = await pw.webkit.connect(
53
+ `ws://localhost:3000/playwright/webkit?token=browserless`,
54
+ );
55
+
56
+ await browser.close();
57
+ await sleep(100);
58
+ }
59
+
60
+ const results = metrics.get();
61
+ expect(results.timedout).to.equal(0);
62
+ expect(results.successful).to.equal(pwVersions.length);
63
+ expect(results.rejected).to.equal(0);
64
+ expect(results.queued).to.equal(0);
65
+ });
66
+
42
67
  it('rejects playwright requests', async () => {
43
68
  const config = new Config();
44
69
  config.setToken('browserless');
package/src/types.ts CHANGED
@@ -377,7 +377,7 @@ export interface BrowserServerOptions {
377
377
  }
378
378
 
379
379
  export interface BrowserlessSession {
380
- id: string | null;
380
+ id: string;
381
381
  initialConnectURL: string;
382
382
  isTempDataDir: boolean;
383
383
  launchOptions: CDPLaunchOptions | BrowserServerOptions;
package/src/utils.ts CHANGED
@@ -48,6 +48,15 @@ const getAuthHeaderToken = (header: string) => {
48
48
  return null;
49
49
  };
50
50
 
51
+ /**
52
+ * RegEx to match the Playwright version from the innitial request header.
53
+ *
54
+ * @example
55
+ * const userAgent = "Playwright/1.43.1 (x64; windows 10.0) node/20.11";
56
+ * userAgent.match(pwVersionRegex);
57
+ * // ["Playwright/1.43", "1.43"]
58
+ */
59
+ export const pwVersionRegex = /Playwright\/(\d+\.\d+)/;
51
60
  export const buildDir: string = path.join(path.resolve(), 'build');
52
61
  export const tsExtension = '.d.ts';
53
62
  export const jsonExtension = '.json';
@@ -225,14 +225,14 @@
225
225
  "length": {
226
226
  "type": "number"
227
227
  },
228
- "__@toStringTag@10952": {
228
+ "__@toStringTag@11009": {
229
229
  "type": "string",
230
230
  "const": "Uint8Array"
231
231
  }
232
232
  },
233
233
  "required": [
234
234
  "BYTES_PER_ELEMENT",
235
- "__@toStringTag@10952",
235
+ "__@toStringTag@11009",
236
236
  "buffer",
237
237
  "byteLength",
238
238
  "byteOffset",
@@ -267,13 +267,13 @@
267
267
  "byteLength": {
268
268
  "type": "number"
269
269
  },
270
- "__@toStringTag@10952": {
270
+ "__@toStringTag@11009": {
271
271
  "type": "string"
272
272
  }
273
273
  },
274
274
  "additionalProperties": false,
275
275
  "required": [
276
- "__@toStringTag@10952",
276
+ "__@toStringTag@11009",
277
277
  "byteLength"
278
278
  ]
279
279
  },
@@ -283,18 +283,18 @@
283
283
  "byteLength": {
284
284
  "type": "number"
285
285
  },
286
- "__@species@11053": {
286
+ "__@species@11110": {
287
287
  "$ref": "#/definitions/SharedArrayBuffer"
288
288
  },
289
- "__@toStringTag@10952": {
289
+ "__@toStringTag@11009": {
290
290
  "type": "string",
291
291
  "const": "SharedArrayBuffer"
292
292
  }
293
293
  },
294
294
  "additionalProperties": false,
295
295
  "required": [
296
- "__@species@11053",
297
- "__@toStringTag@10952",
296
+ "__@species@11110",
297
+ "__@toStringTag@11009",
298
298
  "byteLength"
299
299
  ]
300
300
  },
@@ -1098,7 +1098,7 @@
1098
1098
  },
1099
1099
  "info": {
1100
1100
  "title": "Browserless",
1101
- "version": "2.12.0-beta-2",
1101
+ "version": "2.12.0-beta-4",
1102
1102
  "x-logo": {
1103
1103
  "altText": "browserless logo",
1104
1104
  "url": "./docs/browserless-logo-inline.svg"
@@ -225,14 +225,14 @@
225
225
  "length": {
226
226
  "type": "number"
227
227
  },
228
- "__@toStringTag@10952": {
228
+ "__@toStringTag@11009": {
229
229
  "type": "string",
230
230
  "const": "Uint8Array"
231
231
  }
232
232
  },
233
233
  "required": [
234
234
  "BYTES_PER_ELEMENT",
235
- "__@toStringTag@10952",
235
+ "__@toStringTag@11009",
236
236
  "buffer",
237
237
  "byteLength",
238
238
  "byteOffset",
@@ -267,13 +267,13 @@
267
267
  "byteLength": {
268
268
  "type": "number"
269
269
  },
270
- "__@toStringTag@10952": {
270
+ "__@toStringTag@11009": {
271
271
  "type": "string"
272
272
  }
273
273
  },
274
274
  "additionalProperties": false,
275
275
  "required": [
276
- "__@toStringTag@10952",
276
+ "__@toStringTag@11009",
277
277
  "byteLength"
278
278
  ]
279
279
  },
@@ -283,18 +283,18 @@
283
283
  "byteLength": {
284
284
  "type": "number"
285
285
  },
286
- "__@species@11053": {
286
+ "__@species@11110": {
287
287
  "$ref": "#/definitions/SharedArrayBuffer"
288
288
  },
289
- "__@toStringTag@10952": {
289
+ "__@toStringTag@11009": {
290
290
  "type": "string",
291
291
  "const": "SharedArrayBuffer"
292
292
  }
293
293
  },
294
294
  "additionalProperties": false,
295
295
  "required": [
296
- "__@species@11053",
297
- "__@toStringTag@10952",
296
+ "__@species@11110",
297
+ "__@toStringTag@11009",
298
298
  "byteLength"
299
299
  ]
300
300
  },
@@ -1098,7 +1098,7 @@
1098
1098
  },
1099
1099
  "info": {
1100
1100
  "title": "Browserless",
1101
- "version": "2.12.0-beta-2",
1101
+ "version": "2.12.0-beta-4",
1102
1102
  "x-logo": {
1103
1103
  "altText": "browserless logo",
1104
1104
  "url": "./docs/browserless-logo-inline.svg"