@browserless.io/browserless 2.0.0-beta-4 → 2.0.0-beta-6

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 (240) hide show
  1. package/LICENSE +2 -0
  2. package/README.md +11 -11
  3. package/bin/browserless.js +155 -11
  4. package/bin/scaffold/README.md +415 -0
  5. package/bin/scaffold/package.json +21 -0
  6. package/bin/scaffold/src/hello-world.http.ts +25 -0
  7. package/bin/scaffold/tsconfig.json +4 -0
  8. package/build/browserless.js +18 -15
  9. package/build/browsers/index.d.ts +2 -18
  10. package/build/browsers/index.js +43 -14
  11. package/build/http.d.ts +3 -3
  12. package/build/http.js +3 -3
  13. package/build/router.js +2 -4
  14. package/build/routes/chromium/http/content-post.body.json +8 -8
  15. package/build/routes/chromium/http/content-post.d.ts +15 -3
  16. package/build/routes/chromium/http/content-post.js +14 -15
  17. package/build/routes/chromium/http/download-post.d.ts +16 -3
  18. package/build/routes/chromium/http/download-post.js +17 -22
  19. package/build/routes/chromium/http/function-post.d.ts +16 -3
  20. package/build/routes/chromium/http/function-post.js +17 -22
  21. package/build/routes/chromium/http/pdf-post.body.json +8 -8
  22. package/build/routes/chromium/http/pdf-post.d.ts +15 -3
  23. package/build/routes/chromium/http/pdf-post.js +19 -15
  24. package/build/routes/chromium/http/performance.d.ts +15 -3
  25. package/build/routes/chromium/http/performance.js +15 -23
  26. package/build/routes/chromium/http/scrape-post.body.json +8 -8
  27. package/build/routes/chromium/http/scrape-post.d.ts +15 -3
  28. package/build/routes/chromium/http/scrape-post.js +15 -16
  29. package/build/routes/chromium/http/screenshot-post.body.json +8 -8
  30. package/build/routes/chromium/http/screenshot-post.d.ts +15 -3
  31. package/build/routes/chromium/http/screenshot-post.js +18 -15
  32. package/build/routes/chromium/tests/websocket.spec.js +20 -1
  33. package/build/routes/chromium/utils/function/handler.js +2 -2
  34. package/build/routes/chromium/ws/browser.d.ts +13 -3
  35. package/build/routes/chromium/ws/browser.js +10 -11
  36. package/build/routes/chromium/ws/cdp-chromium.d.ts +13 -3
  37. package/build/routes/chromium/ws/cdp-chromium.js +10 -11
  38. package/build/routes/chromium/ws/page.d.ts +13 -3
  39. package/build/routes/chromium/ws/page.js +10 -11
  40. package/build/routes/chromium/ws/playwright-chromium.d.ts +13 -3
  41. package/build/routes/chromium/ws/playwright-chromium.js +11 -12
  42. package/build/routes/firefox/ws/playwright-firefox.d.ts +13 -3
  43. package/build/routes/firefox/ws/playwright-firefox.js +11 -12
  44. package/build/routes/management/http/config-get.d.ts +15 -3
  45. package/build/routes/management/http/config-get.js +15 -20
  46. package/build/routes/management/http/metrics-get.d.ts +15 -3
  47. package/build/routes/management/http/metrics-get.js +16 -21
  48. package/build/routes/management/http/metrics-total-get.d.ts +15 -3
  49. package/build/routes/management/http/metrics-total-get.js +16 -21
  50. package/build/routes/management/http/sessions-get.d.ts +15 -3
  51. package/build/routes/management/http/sessions-get.js +16 -20
  52. package/build/routes/management/http/static-get.d.ts +15 -3
  53. package/build/routes/management/http/static-get.js +15 -20
  54. package/build/routes/webkit/ws/playwright-webkit.d.ts +13 -3
  55. package/build/routes/webkit/ws/playwright-webkit.js +11 -12
  56. package/build/server.js +0 -1
  57. package/build/types.d.ts +48 -38
  58. package/build/types.js +135 -0
  59. package/extensions/ublock/1p-filters.html +0 -1
  60. package/extensions/ublock/3p-filters.html +0 -2
  61. package/extensions/ublock/_locales/bg/messages.json +6 -6
  62. package/extensions/ublock/_locales/br_FR/messages.json +14 -14
  63. package/extensions/ublock/_locales/bs/messages.json +8 -8
  64. package/extensions/ublock/_locales/ca/messages.json +1 -1
  65. package/extensions/ublock/_locales/da/messages.json +5 -5
  66. package/extensions/ublock/_locales/fa/messages.json +1 -1
  67. package/extensions/ublock/_locales/fi/messages.json +6 -6
  68. package/extensions/ublock/_locales/hr/messages.json +4 -4
  69. package/extensions/ublock/_locales/nb/messages.json +1 -1
  70. package/extensions/ublock/_locales/no/messages.json +1 -1
  71. package/extensions/ublock/_locales/ro/messages.json +2 -2
  72. package/extensions/ublock/_locales/ru/messages.json +1 -1
  73. package/extensions/ublock/_locales/sk/messages.json +1 -1
  74. package/extensions/ublock/_locales/sv/messages.json +2 -2
  75. package/extensions/ublock/_locales/te/messages.json +17 -17
  76. package/extensions/ublock/_locales/vi/messages.json +12 -12
  77. package/extensions/ublock/_locales/zh_TW/messages.json +13 -13
  78. package/extensions/ublock/assets/assets.json +3 -3
  79. package/extensions/ublock/assets/resources/scriptlets.js +218 -97
  80. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +3010 -2056
  81. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +624 -433
  82. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +93 -24
  83. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +7 -15
  84. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +795 -777
  85. package/extensions/ublock/assets/ublock/badware.min.txt +138 -72
  86. package/extensions/ublock/assets/ublock/filters.min.txt +1929 -2735
  87. package/extensions/ublock/assets/ublock/privacy.min.txt +57 -26
  88. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +125 -74
  89. package/extensions/ublock/assets/ublock/unbreak.min.txt +46 -53
  90. package/extensions/ublock/css/codemirror.css +8 -7
  91. package/extensions/ublock/css/dom-inspector.css +40 -0
  92. package/extensions/ublock/css/logger-ui-inspector.css +7 -1
  93. package/extensions/ublock/css/logger-ui.css +12 -5
  94. package/extensions/ublock/css/popup-fenix.css +1 -1
  95. package/extensions/ublock/devtools.html +1 -0
  96. package/extensions/ublock/js/1p-filters.js +4 -3
  97. package/extensions/ublock/js/3p-filters.js +25 -31
  98. package/extensions/ublock/js/about.js +1 -1
  99. package/extensions/ublock/js/advanced-settings.js +1 -1
  100. package/extensions/ublock/js/asset-viewer.js +1 -1
  101. package/extensions/ublock/js/assets.js +74 -44
  102. package/extensions/ublock/js/background.js +9 -3
  103. package/extensions/ublock/js/base64-custom.js +1 -1
  104. package/extensions/ublock/js/benchmarks.js +1 -1
  105. package/extensions/ublock/js/biditrie.js +1 -1
  106. package/extensions/ublock/js/broadcast.js +75 -0
  107. package/extensions/ublock/js/cachestorage.js +68 -45
  108. package/extensions/ublock/js/click2load.js +1 -1
  109. package/extensions/ublock/js/cloud-ui.js +1 -1
  110. package/extensions/ublock/js/code-viewer.js +1 -1
  111. package/extensions/ublock/js/codemirror/search-thread.js +1 -1
  112. package/extensions/ublock/js/codemirror/search.js +1 -1
  113. package/extensions/ublock/js/codemirror/ubo-dynamic-filtering.js +1 -1
  114. package/extensions/ublock/js/codemirror/ubo-static-filtering.js +98 -24
  115. package/extensions/ublock/js/commands.js +1 -1
  116. package/extensions/ublock/js/console.js +1 -1
  117. package/extensions/ublock/js/contentscript-extra.js +1 -1
  118. package/extensions/ublock/js/contentscript.js +1 -3
  119. package/extensions/ublock/js/contextmenu.js +1 -1
  120. package/extensions/ublock/js/cosmetic-filtering.js +4 -4
  121. package/extensions/ublock/js/dashboard-common.js +1 -1
  122. package/extensions/ublock/js/dashboard.js +1 -1
  123. package/extensions/ublock/js/devtools.js +23 -15
  124. package/extensions/ublock/js/diff-updater.js +3 -3
  125. package/extensions/ublock/js/document-blocked.js +1 -1
  126. package/extensions/ublock/js/dom-inspector.js +68 -0
  127. package/extensions/ublock/js/dom.js +1 -1
  128. package/extensions/ublock/js/dyna-rules.js +1 -1
  129. package/extensions/ublock/js/dynamic-net-filtering.js +1 -1
  130. package/extensions/ublock/js/epicker-ui.js +35 -59
  131. package/extensions/ublock/js/fa-icons.js +1 -1
  132. package/extensions/ublock/js/filtering-context.js +1 -1
  133. package/extensions/ublock/js/filtering-engines.js +1 -1
  134. package/extensions/ublock/js/hnswitches.js +1 -1
  135. package/extensions/ublock/js/hntrie.js +1 -1
  136. package/extensions/ublock/js/html-filtering.js +1 -1
  137. package/extensions/ublock/js/httpheader-filtering.js +1 -1
  138. package/extensions/ublock/js/i18n.js +1 -1
  139. package/extensions/ublock/js/is-webrtc-supported.js +1 -1
  140. package/extensions/ublock/js/logger-ui-inspector.js +203 -145
  141. package/extensions/ublock/js/logger-ui.js +21 -5
  142. package/extensions/ublock/js/logger.js +6 -2
  143. package/extensions/ublock/js/lz4.js +2 -2
  144. package/extensions/ublock/js/messaging.js +266 -166
  145. package/extensions/ublock/js/mrucache.js +58 -0
  146. package/extensions/ublock/js/pagestore.js +1 -1
  147. package/extensions/ublock/js/popup-fenix.js +2 -1
  148. package/extensions/ublock/js/redirect-engine.js +1 -1
  149. package/extensions/ublock/js/redirect-resources.js +1 -12
  150. package/extensions/ublock/js/reverselookup-worker.js +1 -1
  151. package/extensions/ublock/js/reverselookup.js +1 -1
  152. package/extensions/ublock/js/scriptlet-filtering-core.js +300 -0
  153. package/extensions/ublock/js/scriptlet-filtering.js +122 -350
  154. package/extensions/ublock/js/scriptlets/cosmetic-logger.js +36 -47
  155. package/extensions/ublock/js/scriptlets/cosmetic-off.js +1 -1
  156. package/extensions/ublock/js/scriptlets/cosmetic-on.js +1 -1
  157. package/extensions/ublock/js/scriptlets/cosmetic-report.js +1 -1
  158. package/extensions/ublock/js/scriptlets/dom-inspector.js +341 -323
  159. package/extensions/ublock/js/scriptlets/dom-survey-elements.js +1 -1
  160. package/extensions/ublock/js/scriptlets/dom-survey-scripts.js +1 -1
  161. package/extensions/ublock/js/scriptlets/epicker.js +80 -89
  162. package/extensions/ublock/js/scriptlets/load-3p-css.js +1 -1
  163. package/extensions/ublock/js/scriptlets/load-large-media-all.js +1 -1
  164. package/extensions/ublock/js/scriptlets/load-large-media-interactive.js +1 -1
  165. package/extensions/ublock/js/scriptlets/noscript-spoof.js +1 -1
  166. package/extensions/ublock/js/scriptlets/should-inject-contentscript.js +1 -1
  167. package/extensions/ublock/js/scriptlets/subscriber.js +1 -1
  168. package/extensions/ublock/js/scriptlets/updater.js +20 -3
  169. package/extensions/ublock/js/settings.js +1 -1
  170. package/extensions/ublock/js/start.js +19 -20
  171. package/extensions/ublock/js/static-dnr-filtering.js +1 -1
  172. package/extensions/ublock/js/static-ext-filtering-db.js +1 -1
  173. package/extensions/ublock/js/static-ext-filtering.js +1 -1
  174. package/extensions/ublock/js/static-filtering-io.js +1 -1
  175. package/extensions/ublock/js/static-filtering-parser.js +5 -3
  176. package/extensions/ublock/js/static-net-filtering.js +57 -37
  177. package/extensions/ublock/js/storage.js +49 -29
  178. package/extensions/ublock/js/support.js +4 -4
  179. package/extensions/ublock/js/tab.js +1 -1
  180. package/extensions/ublock/js/tasks.js +1 -1
  181. package/extensions/ublock/js/text-encode.js +1 -1
  182. package/extensions/ublock/js/text-utils.js +1 -1
  183. package/extensions/ublock/js/theme.js +1 -1
  184. package/extensions/ublock/js/traffic.js +2 -1
  185. package/extensions/ublock/js/ublock.js +15 -11
  186. package/extensions/ublock/js/uri-utils.js +1 -1
  187. package/extensions/ublock/js/url-net-filtering.js +1 -1
  188. package/extensions/ublock/js/utils.js +1 -73
  189. package/extensions/ublock/js/vapi-background-ext.js +1 -1
  190. package/extensions/ublock/js/vapi-background.js +92 -83
  191. package/extensions/ublock/js/vapi-client.js +4 -33
  192. package/extensions/ublock/js/vapi-common.js +16 -30
  193. package/extensions/ublock/js/vapi.js +1 -1
  194. package/extensions/ublock/js/wasm/biditrie.wat +1 -1
  195. package/extensions/ublock/js/wasm/hntrie.wat +1 -1
  196. package/extensions/ublock/js/webext.js +1 -1
  197. package/extensions/ublock/js/whitelist.js +1 -1
  198. package/extensions/ublock/logger-ui.html +2 -2
  199. package/extensions/ublock/manifest.json +1 -1
  200. package/extensions/ublock/support.html +0 -1
  201. package/extensions/ublock/web_accessible_resources/dom-inspector.html +25 -0
  202. package/extensions/ublock/web_accessible_resources/epicker-ui.html +0 -1
  203. package/extensions/ublock/web_accessible_resources/googletagservices_gpt.js +1 -0
  204. package/package.json +10 -20
  205. package/scripts/build-open-api.js +7 -4
  206. package/src/browserless.ts +42 -18
  207. package/src/browsers/index.ts +48 -20
  208. package/src/http.ts +3 -3
  209. package/src/router.ts +2 -6
  210. package/src/routes/chromium/http/content-post.ts +13 -16
  211. package/src/routes/chromium/http/download-post.ts +16 -27
  212. package/src/routes/chromium/http/function-post.ts +16 -25
  213. package/src/routes/chromium/http/pdf-post.ts +19 -15
  214. package/src/routes/chromium/http/performance.ts +14 -26
  215. package/src/routes/chromium/http/scrape-post.ts +14 -16
  216. package/src/routes/chromium/http/screenshot-post.ts +18 -15
  217. package/src/routes/chromium/tests/websocket.spec.ts +28 -1
  218. package/src/routes/chromium/utils/function/handler.ts +2 -1
  219. package/src/routes/chromium/ws/browser.ts +10 -12
  220. package/src/routes/chromium/ws/cdp-chromium.ts +10 -12
  221. package/src/routes/chromium/ws/page.ts +10 -12
  222. package/src/routes/chromium/ws/playwright-chromium.ts +10 -12
  223. package/src/routes/firefox/ws/playwright-firefox.ts +10 -12
  224. package/src/routes/management/http/config-get.ts +14 -23
  225. package/src/routes/management/http/metrics-get.ts +15 -24
  226. package/src/routes/management/http/metrics-total-get.ts +15 -26
  227. package/src/routes/management/http/sessions-get.ts +15 -23
  228. package/src/routes/management/http/static-get.ts +14 -22
  229. package/src/routes/webkit/ws/playwright-webkit.ts +10 -12
  230. package/src/server.ts +0 -1
  231. package/src/types.ts +59 -45
  232. package/static/docs/browserless-logo-inline.svg +1 -0
  233. package/static/docs/index.html +27 -0
  234. package/static/docs/swagger.json +33 -33
  235. package/static/function/client.js +626 -78
  236. package/extensions/ublock/js/vapi-client-extra.js +0 -312
  237. package/extensions/ublock/web_accessible_resources/addthis_widget.js +0 -39
  238. package/extensions/ublock/web_accessible_resources/ligatus_angular-tag.js +0 -29
  239. package/extensions/ublock/web_accessible_resources/monkeybroker.js +0 -43
  240. package/extensions/ublock/web_accessible_resources/mxpnl_mixpanel.js +0 -51
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@browserless.io/browserless",
3
- "version": "2.0.0-beta-4",
3
+ "version": "2.0.0-beta-6",
4
4
  "license": "SSPL",
5
5
  "description": "The browserless platform",
6
6
  "author": "browserless.io",
7
7
  "type": "module",
8
8
  "types": "./src/exports.ts",
9
9
  "main": "./build/exports.js",
10
- "exports": "./build/exports.js",
10
+ "exports": {
11
+ ".": "./build/exports.js"
12
+ },
11
13
  "bin": {
12
14
  "browserless": "./bin/browserless.js"
13
15
  },
@@ -27,7 +29,7 @@
27
29
  "install:dev": "npm run install:browsers && npm run install:cdp-json",
28
30
  "lint": "eslint . --ext .ts --fix",
29
31
  "prepack": "npm run build:dev",
30
- "prettier": "prettier '{src,functions,scripts,bin,external}/**/*.{js,ts,json}' --log-level error --write",
32
+ "prettier": "prettier '{src,functions,scripts,bin,external,bin}/**/*.{js,ts,json}' --log-level error --write",
31
33
  "test": "cross-env DEBUG=quiet mocha"
32
34
  },
33
35
  "files": [
@@ -69,15 +71,15 @@
69
71
  "@types/http-proxy": "^1.17.14",
70
72
  "@types/micromatch": "^4.0.6",
71
73
  "@types/mocha": "^10.0.6",
72
- "@types/node": "^20.10.5",
74
+ "@types/node": "^20.10.8",
73
75
  "@types/sinon": "^17.0.2",
74
- "@typescript-eslint/eslint-plugin": "^6.15.0",
75
- "@typescript-eslint/parser": "^6.15.0",
76
+ "@typescript-eslint/eslint-plugin": "^6.18.1",
77
+ "@typescript-eslint/parser": "^6.18.1",
76
78
  "assert": "^2.0.0",
77
- "chai": "^4.3.6",
79
+ "chai": "^5.0.0",
78
80
  "cross-env": "^7.0.3",
79
81
  "env-cmd": "^10.1.0",
80
- "esbuild": "^0.19.10",
82
+ "esbuild": "^0.19.11",
81
83
  "esbuild-plugin-polyfill-node": "^0.3.0",
82
84
  "eslint": "^8.56.0",
83
85
  "eslint-plugin-import": "^2.29.1",
@@ -156,18 +158,6 @@
156
158
  "timeout": 30000,
157
159
  "slow": 5000
158
160
  },
159
- "nodemonConfig": {
160
- "ignoreRoot": [
161
- ".git",
162
- ".no-git"
163
- ],
164
- "watch": [
165
- "src"
166
- ],
167
- "exec": "npx tsc && node ./build/index.js",
168
- "ext": "ts json",
169
- "signal": "SIGTERM"
170
- },
171
161
  "prettier": {
172
162
  "semi": true,
173
163
  "trailingComma": "all",
@@ -56,17 +56,19 @@ const buildOpenAPI = async (
56
56
  const changelog = marked.parse(
57
57
  (await fs.readFile('CHANGELOG.md').catch(() => '')).toString(),
58
58
  );
59
+
59
60
  const [httpRoutes, wsRoutes] = await getRouteFiles(new Config());
60
61
  const swaggerJSON = {
61
62
  customSiteTitle: 'Browserless Documentation',
62
63
  definitions: {},
63
64
  info: {
64
- description: readme + changelog,
65
+ // Concatenation necessary for Changelog to show up in sidebar
66
+ description: readme + `\n# Changelog\n` + changelog,
65
67
  title: 'Browserless',
66
68
  version: JSON.parse(packageJSON.toString()).version,
67
69
  'x-logo': {
68
70
  altText: 'browserless logo',
69
- url: './docs/browserless-logo.png',
71
+ url: './docs/browserless-logo-inline.svg',
70
72
  },
71
73
  },
72
74
  openapi: '3.0.0',
@@ -86,10 +88,11 @@ const buildOpenAPI = async (
86
88
  .sort()
87
89
  .map(async (routeModule) => {
88
90
  const routeImport = `${isWin ? 'file:///' : ''}${routeModule}`;
89
- const { default: route } = await import(routeImport);
90
- if (!route) {
91
+ const { default: Route } = await import(routeImport);
92
+ if (!Route) {
91
93
  throw new Error(`Invalid route file to import docs ${routeModule}`);
92
94
  }
95
+ const route = new Route();
93
96
  const { name } = parse(routeModule);
94
97
  const body = routeModule.replace('.js', '.body.json');
95
98
  const query = routeModule.replace('.js', '.query.json');
@@ -27,6 +27,10 @@ import { userInfo } from 'os';
27
27
 
28
28
  const routeSchemas = ['body', 'query'];
29
29
 
30
+ type Implements<T> = {
31
+ new (...args: unknown[]): T;
32
+ };
33
+
30
34
  export class Browserless {
31
35
  protected debug: debug.Debugger = createLogger('index');
32
36
  protected browserManager: BrowserManager;
@@ -181,16 +185,25 @@ export class Browserless {
181
185
  this.config.getIsWin() ? 'file:///' : ''
182
186
  }${httpRoute}`;
183
187
  const logger = createLogger(`http:${name}`);
184
- const { default: route }: { default: HTTPRoute | BrowserHTTPRoute } =
188
+ const {
189
+ default: Route,
190
+ }: { default: Implements<HTTPRoute> | Implements<BrowserHTTPRoute> } =
185
191
  await import(routeImport + `?cb=${Date.now()}`);
186
-
192
+ const route = new Route(
193
+ this.browserManager,
194
+ this.config,
195
+ this.fileSystem,
196
+ logger,
197
+ this.metrics,
198
+ this.monitoring,
199
+ );
187
200
  route.bodySchema = safeParse(bodySchema);
188
201
  route.querySchema = safeParse(querySchema);
189
- route.getConfig = () => this.config;
190
- route.getMetrics = () => this.metrics;
191
- route.getMonitoring = () => this.monitoring;
192
- route.getFileSystem = () => this.fileSystem;
193
- route.getDebug = () => logger;
202
+ route.config = () => this.config;
203
+ route.metrics = () => this.metrics;
204
+ route.monitoring = () => this.monitoring;
205
+ route.fileSystem = () => this.fileSystem;
206
+ route.debug = () => logger;
194
207
 
195
208
  httpRoutes.push(route);
196
209
  }
@@ -215,17 +228,27 @@ export class Browserless {
215
228
  }${wsRoute}`;
216
229
  const logger = createLogger(`ws:${name}`);
217
230
  const {
218
- default: route,
219
- }: { default: WebSocketRoute | BrowserWebsocketRoute } = await import(
220
- wsImport + `?cb=${Date.now()}`
221
- );
231
+ default: Route,
232
+ }: {
233
+ default:
234
+ | Implements<WebSocketRoute>
235
+ | Implements<BrowserWebsocketRoute>;
236
+ } = await import(wsImport + `?cb=${Date.now()}`);
222
237
 
238
+ const route = new Route(
239
+ this.browserManager,
240
+ this.config,
241
+ this.fileSystem,
242
+ logger,
243
+ this.metrics,
244
+ this.monitoring,
245
+ );
223
246
  route.querySchema = safeParse(querySchema);
224
- route.getConfig = () => this.config;
225
- route.getMetrics = () => this.metrics;
226
- route.getMonitoring = () => this.monitoring;
227
- route.getFileSystem = () => this.fileSystem;
228
- route.getDebug = () => logger;
247
+ route.config = () => this.config;
248
+ route.metrics = () => this.metrics;
249
+ route.monitoring = () => this.monitoring;
250
+ route.fileSystem = () => this.fileSystem;
251
+ route.debug = () => logger;
229
252
 
230
253
  wsRoutes.push(route);
231
254
  }
@@ -234,11 +257,12 @@ export class Browserless {
234
257
  // Validate that browsers are installed and route paths are unique
235
258
  [...httpRoutes, ...wsRoutes].forEach((route) => {
236
259
  if (
260
+ 'browser' in route &&
237
261
  route.browser &&
238
- !installedBrowsers.some((b) => b.name === route.browser.name)
262
+ !installedBrowsers.some((b) => b.name === route.browser?.name)
239
263
  ) {
240
264
  throw new Error(
241
- `Couldn't load route "${route.path}" due to missing browser of "${route.browser.name}"`,
265
+ `Couldn't load route "${route.path}" due to missing browser of "${route.browser?.name}"`,
242
266
  );
243
267
  }
244
268
  });
@@ -82,27 +82,52 @@ export class BrowserManager {
82
82
  return dataDirPath;
83
83
  };
84
84
 
85
- protected generateSessionJson = (
85
+ private generateSessionJson = async (
86
86
  browser: BrowserInstance,
87
87
  session: BrowserlessSession,
88
88
  ) => {
89
89
  const serverAddress = this.config.getExternalAddress();
90
90
 
91
- return {
92
- ...session,
93
- browser: browser.constructor.name,
94
- browserId: browser.wsEndpoint()?.split('/').pop(),
95
- initialConnectURL: new URL(session.initialConnectURL, serverAddress).href,
96
- killURL: session.id
97
- ? makeExternalURL(
98
- serverAddress,
99
- HTTPManagementRoutes.sessions,
100
- session.id,
101
- )
102
- : null,
103
- running: browser.isRunning(),
104
- timeAliveMs: Date.now() - session.startedOn,
105
- };
91
+ const sessions = [
92
+ {
93
+ ...session,
94
+ browser: browser.constructor.name,
95
+ browserId: browser.wsEndpoint()?.split('/').pop(),
96
+ initialConnectURL: new URL(session.initialConnectURL, serverAddress)
97
+ .href,
98
+ killURL: session.id
99
+ ? makeExternalURL(
100
+ serverAddress,
101
+ HTTPManagementRoutes.sessions,
102
+ session.id,
103
+ )
104
+ : null,
105
+ running: browser.isRunning(),
106
+ timeAliveMs: Date.now() - session.startedOn,
107
+ type: 'browser',
108
+ },
109
+ ];
110
+
111
+ const wsEndpoint = browser.wsEndpoint();
112
+ if (browser.constructor.name === 'CDPChromium' && wsEndpoint) {
113
+ const port = new URL(wsEndpoint).port;
114
+ const response = await fetch(`http://127.0.0.1:${port}/json/list`, {
115
+ headers: {
116
+ Host: '127.0.0.1',
117
+ },
118
+ });
119
+ if (response.ok) {
120
+ const body = await response.json();
121
+ for (const page of body) {
122
+ sessions.push({
123
+ ...sessions[0],
124
+ ...page,
125
+ browserWSEndpoint: wsEndpoint,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ return sessions;
106
131
  };
107
132
 
108
133
  public close = async (
@@ -129,9 +154,12 @@ export class BrowserManager {
129
154
  public getAllSessions = async (): Promise<BrowserlessSessionJSON[]> => {
130
155
  const sessions = Array.from(this.browsers);
131
156
 
132
- return sessions.map(([browser, session]) =>
133
- this.generateSessionJson(browser, session),
134
- );
157
+ const formattedSessions: BrowserlessSessionJSON[] = [];
158
+ for (const [browser, session] of sessions) {
159
+ const formattedSession = await this.generateSessionJson(browser, session);
160
+ formattedSessions.push(...formattedSession);
161
+ }
162
+ return formattedSessions;
135
163
  };
136
164
 
137
165
  public complete = async (browser: BrowserInstance): Promise<void> => {
@@ -208,7 +236,7 @@ export class BrowserManager {
208
236
  const manualUserDataDir =
209
237
  launchOptions.args
210
238
  ?.find((arg) => arg.includes('--user-data-dir='))
211
- ?.split('=')[2] || (launchOptions as CDPLaunchOptions).userDataDir;
239
+ ?.split('=')[1] || (launchOptions as CDPLaunchOptions).userDataDir;
212
240
 
213
241
  // Always specify a user-data-dir since plugins can "inject" their own
214
242
  // unless it's playwright which takes care of its own data-dirs
package/src/http.ts CHANGED
@@ -107,9 +107,9 @@ export enum HTTPManagementRoutes {
107
107
  }
108
108
 
109
109
  export enum APITags {
110
- 'browserAPI' = 'Browser APIs',
111
- 'browserWS' = 'Browser WebSockets',
112
- 'management' = 'Management APIs',
110
+ 'browserAPI' = 'Browser REST APIs',
111
+ 'browserWS' = 'Browser WebSocket APIs',
112
+ 'management' = 'Management REST APIs',
113
113
  }
114
114
 
115
115
  export interface Request extends http.IncomingMessage {
package/src/router.ts CHANGED
@@ -67,7 +67,7 @@ export class Router {
67
67
  return Promise.resolve();
68
68
  }
69
69
 
70
- if (route.browser) {
70
+ if ('browser' in route && route.browser) {
71
71
  const browser = await this.browserManager.getBrowserForRequest(
72
72
  req,
73
73
  route,
@@ -111,7 +111,7 @@ export class Router {
111
111
  return Promise.resolve();
112
112
  }
113
113
 
114
- if (route.browser) {
114
+ if ('browser' in route && route.browser) {
115
115
  const browser = await this.browserManager.getBrowserForRequest(
116
116
  req,
117
117
  route,
@@ -146,8 +146,6 @@ export class Router {
146
146
  `Registering HTTP ${route.method.toUpperCase()} ${route.path}`,
147
147
  );
148
148
 
149
- route.getBrowserManager = () => this.browserManager;
150
-
151
149
  const bound = route.handler.bind(route);
152
150
  const wrapped = this.wrapHTTPHandler(route, bound);
153
151
 
@@ -170,8 +168,6 @@ export class Router {
170
168
  ): WebSocketRoute | BrowserWebsocketRoute {
171
169
  this.verbose(`Registering WebSocket "${route.path}"`);
172
170
 
173
- route.getBrowserManager = () => this.browserManager;
174
-
175
171
  const bound = route.handler.bind(route);
176
172
  const wrapped = this.wrapWebSocketHandler(route, bound);
177
173
 
@@ -61,15 +61,17 @@ export type QuerySchema = SystemQueryParameters & {
61
61
  launch?: CDPLaunchOptions | string;
62
62
  };
63
63
 
64
- const route: BrowserHTTPRoute = {
65
- accepts: [contentTypes.json],
66
- auth: true,
67
- browser: CDPChromium,
68
- concurrency: true,
69
- contentTypes: [contentTypes.html],
70
- description: `A JSON-based API. Given a "url" or "html" field, runs and returns HTML content after the page has loaded and JavaScript has parsed.`,
71
-
72
- handler: async (
64
+ export default class ContentPostRoute extends BrowserHTTPRoute {
65
+ accepts = [contentTypes.json];
66
+ auth = true;
67
+ browser = CDPChromium;
68
+ concurrency = true;
69
+ contentTypes = [contentTypes.html];
70
+ description = `A JSON-based API. Given a "url" or "html" field, runs and returns HTML content after the page has loaded and JavaScript has parsed.`;
71
+ method = Methods.post;
72
+ path = HTTPRoutes.content;
73
+ tags = [APITags.browserAPI];
74
+ handler = async (
73
75
  req: Request,
74
76
  res: ServerResponse,
75
77
  browser: BrowserInstance,
@@ -229,10 +231,5 @@ const route: BrowserHTTPRoute = {
229
231
  page.close().catch(noop);
230
232
 
231
233
  return writeResponse(res, 200, markup, contentTypes.html);
232
- },
233
- method: Methods.post,
234
- path: HTTPRoutes.content,
235
- tags: [APITags.browserAPI],
236
- };
237
-
238
- export default route;
234
+ };
235
+ }
@@ -8,7 +8,6 @@ import {
8
8
  Methods,
9
9
  NotFound,
10
10
  Request,
11
- ServerError,
12
11
  SystemQueryParameters,
13
12
  contentTypes,
14
13
  dedent,
@@ -41,35 +40,30 @@ export interface QuerySchema extends SystemQueryParameters {
41
40
  */
42
41
  export type ResponseSchema = unknown;
43
42
 
44
- const route: BrowserHTTPRoute = {
45
- accepts: [contentTypes.json, contentTypes.javascript],
46
- auth: true,
47
- browser: CDPChromium,
48
- concurrency: true,
49
- contentTypes: [contentTypes.any],
50
- description: dedent(`
43
+ export default class DownloadPost extends BrowserHTTPRoute {
44
+ accepts = [contentTypes.json, contentTypes.javascript];
45
+ auth = true;
46
+ browser = CDPChromium;
47
+ concurrency = true;
48
+ contentTypes = [contentTypes.any];
49
+ description = dedent(`
51
50
  A JSON or JavaScript content-type API for returning files Chrome has downloaded during
52
51
  the execution of puppeteer code, which is ran inside context of the browser.
53
52
  Browserless sets up a blank page, a fresh download directory, injects your puppeteer code, and then executes it.
54
53
  You can load external libraries via the "import" syntax, and import ESM-style modules
55
54
  that are written for execution inside of the browser. Once your script is finished, any
56
- downloaded files from Chromium are returned back with the appropriate content-type header.`),
57
- handler: async (
55
+ downloaded files from Chromium are returned back with the appropriate content-type header.`);
56
+ method = Methods.post;
57
+ path = HTTPRoutes.download;
58
+ tags = [APITags.browserAPI];
59
+ handler = async (
58
60
  req: Request,
59
61
  res: ServerResponse,
60
62
  browser: BrowserInstance,
61
63
  ): Promise<void> =>
62
64
  new Promise(async (resolve, reject) => {
63
- const { getConfig: getConfig, getDebug: getDebug } = route;
64
-
65
- if (!getConfig || !getDebug) {
66
- return reject(
67
- new ServerError(`Couldn't load configuration for request`),
68
- );
69
- }
70
-
71
- const debug = getDebug();
72
- const config = getConfig();
65
+ const debug = this.debug();
66
+ const config = this.config();
73
67
  const downloadPath = path.join(
74
68
  await config.getDownloadsDir(),
75
69
  `.browserless.download.${id()}`,
@@ -153,10 +147,5 @@ const route: BrowserHTTPRoute = {
153
147
  return resolve();
154
148
  })
155
149
  .pipe(res);
156
- }),
157
- method: Methods.post,
158
- path: HTTPRoutes.download,
159
- tags: [APITags.browserAPI],
160
- };
161
-
162
- export default route;
150
+ });
151
+ }
@@ -8,7 +8,6 @@ import {
8
8
  HTTPRoutes,
9
9
  Methods,
10
10
  Request,
11
- ServerError,
12
11
  SystemQueryParameters,
13
12
  contentTypes,
14
13
  dedent,
@@ -38,31 +37,28 @@ export interface QuerySchema extends SystemQueryParameters {
38
37
  */
39
38
  export type ResponseSchema = unknown;
40
39
 
41
- const route: BrowserHTTPRoute = {
42
- accepts: [contentTypes.json, contentTypes.javascript],
43
- auth: true,
44
- browser: CDPChromium,
45
- concurrency: true,
46
- contentTypes: [contentTypes.any],
47
- description: dedent(`
40
+ export default class FunctionPost extends BrowserHTTPRoute {
41
+ accepts = [contentTypes.json, contentTypes.javascript];
42
+ auth = true;
43
+ browser = CDPChromium;
44
+ concurrency = true;
45
+ contentTypes = [contentTypes.any];
46
+ description = dedent(`
48
47
  A JSON or JavaScript content-type API for running puppeteer code in the browser's context.
49
48
  Browserless sets up a blank page, injects your puppeteer code, and runs it.
50
49
  You can optionally load external libraries via the "import" module that are meant for browser usage.
51
50
  Values returned from the function are checked and an appropriate content-type and response is sent back
52
- to your HTTP call.`),
53
- handler: async (
51
+ to your HTTP call.`);
52
+ method = Methods.post;
53
+ path = HTTPRoutes.function;
54
+ tags = [APITags.browserAPI];
55
+ handler = async (
54
56
  req: Request,
55
57
  res: ServerResponse,
56
58
  browser: BrowserInstance,
57
59
  ): Promise<void> => {
58
- const { getConfig: getConfig, getDebug: getDebug } = route;
59
-
60
- if (!getConfig || !getDebug) {
61
- throw new ServerError(`Couldn't load configuration for request`);
62
- }
63
-
64
- const debug = getDebug();
65
- const config = getConfig();
60
+ const debug = this.debug();
61
+ const config = this.config();
66
62
  const handler = functionHandler(config, debug);
67
63
  const { contentType, payload, page } = await handler(req, browser);
68
64
 
@@ -89,10 +85,5 @@ const route: BrowserHTTPRoute = {
89
85
  }
90
86
 
91
87
  return;
92
- },
93
- method: Methods.post,
94
- path: HTTPRoutes.function,
95
- tags: [APITags.browserAPI],
96
- };
97
-
98
- export default route;
88
+ };
89
+ }
@@ -16,6 +16,7 @@ import {
16
16
  bestAttempt,
17
17
  bestAttemptCatch,
18
18
  contentTypes,
19
+ dedent,
19
20
  noop,
20
21
  rejectRequestPattern,
21
22
  rejectResourceTypes,
@@ -61,14 +62,22 @@ export interface QuerySchema extends SystemQueryParameters {
61
62
  */
62
63
  export type ResponseSchema = string;
63
64
 
64
- const route: BrowserHTTPRoute = {
65
- accepts: [contentTypes.json],
66
- auth: true,
67
- browser: CDPChromium,
68
- concurrency: true,
69
- contentTypes: [contentTypes.pdf],
70
- description: `A JSON-based API for getting a PDF binary from either a supplied "url" or "html" payload in your request.`,
71
- handler: async (
65
+ export default class PDFPost extends BrowserHTTPRoute {
66
+ accepts = [contentTypes.json];
67
+ auth = true;
68
+ browser = CDPChromium;
69
+ concurrency = true;
70
+ contentTypes = [contentTypes.pdf];
71
+ description = dedent(`
72
+ A JSON-based API for getting a PDF binary from either a supplied
73
+ "url" or "html" payload in your request. Many options exist for
74
+ injecting cookies, request interceptors, user-agents and waiting for
75
+ selectors, timers and more.
76
+ `);
77
+ method = Methods.post;
78
+ path = HTTPRoutes.pdf;
79
+ tags = [APITags.browserAPI];
80
+ handler = async (
72
81
  req: Request,
73
82
  res: ServerResponse,
74
83
  browser: BrowserInstance,
@@ -225,10 +234,5 @@ const route: BrowserHTTPRoute = {
225
234
  });
226
235
 
227
236
  page.close().catch(noop);
228
- },
229
- method: Methods.post,
230
- path: HTTPRoutes.pdf,
231
- tags: [APITags.browserAPI],
232
- };
233
-
234
- export default route;
237
+ };
238
+ }
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  APITags,
3
- BadRequest,
4
3
  BrowserHTTPRoute,
5
4
  BrowserInstance,
6
5
  CDPChromium,
@@ -8,7 +7,6 @@ import {
8
7
  HTTPRoutes,
9
8
  Methods,
10
9
  Request,
11
- ServerError,
12
10
  SystemQueryParameters,
13
11
  contentTypes,
14
12
  jsonResponse,
@@ -34,27 +32,22 @@ export interface QuerySchema extends SystemQueryParameters {
34
32
  */
35
33
  export type ResponseSchema = object;
36
34
 
37
- const route: BrowserHTTPRoute = {
38
- accepts: [contentTypes.json],
39
- auth: true,
40
- browser: CDPChromium,
41
- concurrency: true,
42
- contentTypes: [contentTypes.json],
43
- description: `Run lighthouse performance audits with a supplied "url" in your JSON payload.`,
44
- handler: async (
35
+ export default class PerformancePost extends BrowserHTTPRoute {
36
+ accepts = [contentTypes.json];
37
+ auth = true;
38
+ browser = CDPChromium;
39
+ concurrency = true;
40
+ contentTypes = [contentTypes.json];
41
+ description = `Run lighthouse performance audits with a supplied "url" in your JSON payload.`;
42
+ method = Methods.post;
43
+ path = HTTPRoutes.performance;
44
+ tags = [APITags.browserAPI];
45
+ handler = async (
45
46
  req: Request,
46
47
  res: ServerResponse,
47
48
  browser: BrowserInstance,
48
49
  ): Promise<void> => {
49
- const { getConfig: getConfig } = route;
50
- if (!req.body) {
51
- throw new BadRequest(`No JSON body present`);
52
- }
53
-
54
- if (!getConfig) {
55
- throw new ServerError(`Couldn't load configuration for timeouts`);
56
- }
57
- const config = getConfig();
50
+ const config = this.config();
58
51
  const response = await main({
59
52
  browser,
60
53
  context: req.body as BodySchema,
@@ -62,10 +55,5 @@ const route: BrowserHTTPRoute = {
62
55
  });
63
56
 
64
57
  return jsonResponse(res, 200, response);
65
- },
66
- method: Methods.post,
67
- path: HTTPRoutes.performance,
68
- tags: [APITags.browserAPI],
69
- };
70
-
71
- export default route;
58
+ };
59
+ }