@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
@@ -0,0 +1,415 @@
1
+ # Your Browserless.io SDK Project
2
+
3
+ Welcome to your browserless.io SDK project! This readme will help you get started and running as quickly as possible. Below is a handy Table of Contents in order to find what you're looking for fastest.
4
+
5
+ Please note that, as of right now, breaking changes aren't yet reflected in our semantic versioning. You can think of this SDK as still in beta for the time being, and we'll carefully document any major or breaking changes in future releases of Browserless.
6
+
7
+ Finally, this SDK and Browserless.io are built to support businesses and enterprise clients. If you're looking to use our code and modules in a production environment, [please contact us to get appropriately licensed](https://www.browserless.io/contact).
8
+
9
+ ## Table of Contents
10
+ - [Quick Start](#quick-start)
11
+ - [About](#about)
12
+ - [The CLI](#the-cli)
13
+ - [Routing](#routing)
14
+ - [Utilities](#utilities)
15
+ - [Extending Modules](#extending-modules)
16
+ - [Running in Development](#running-in-development)
17
+ - [Building for Production](#building-for-production)
18
+ - [Running without Building](#running-without-building)
19
+ - [Docker](#docker)
20
+ - [Licensing](#licensing)
21
+
22
+ ## Quick Start
23
+
24
+ To start a new project, simply run this command in a folder of your choosing and follow the prompts:
25
+
26
+ ```sh
27
+ npx @browserless.io/browserless create
28
+ ```
29
+
30
+ browserless will install a scaffolded project, install dependencies, and establish a simple "hello-world" REST API route. There's a lot you can do within this framework, so be sure to dive into all the details below!
31
+
32
+ ## About
33
+
34
+ The Browserless.io SDK and accompanying CLI were written with intention that developers can add and enhance functionality into Browserless for your needs. This way you can get results into a database, third-party uploads, work within your enterprises requirements, all while using your favorite modern libraries. The Browserless platform simply ensure system stability, authorization, and the best developer experience.
35
+
36
+ When creating a new project, the scaffold will ask a series of questions and generate the project for you. Once complete, a list of files it created for you. Here's the list so far:
37
+
38
+ ```
39
+ ├── node_modules
40
+ ├── build
41
+ ├── src
42
+ │ └── hello-world.http.ts
43
+ ├── .gitignore
44
+ ├── package.json
45
+ ├── package-lock.json
46
+ ├── README.md
47
+ └── tsconfig.json
48
+ ```
49
+
50
+ These are the files included and what they do:
51
+
52
+ - `node_modules` The projects underlying dependencies. Feel free to add whatever you'd want.
53
+ - `build` The built project after TypeScript has run and produced a NodeJS compatible project.
54
+ - `src` Routes, modules, and other files need to go here in order for them to be included.
55
+ - `src/hello-world.http.ts` An example "Hello World" HTTP-based route.
56
+ - `.gitignore` Files to ignore from git (node_modules and build for example).
57
+ - `package.json` Your project's package.json file.
58
+ - `package-lock.json` Your projects locked dependency manifest file.
59
+ - `README.md` This README file.
60
+ - `tsconfig.json` The TypeScript configuration JSON file. Extends browserless' own.
61
+
62
+ Aside form scaffolding the project, Browserless also looks for the following:
63
+
64
+ - `*.http.ts` Files with this name convention are treated as HTTP routes.
65
+ - `*.websocket.ts` Files with this naming convention are treated as WebSocket routes.
66
+ - `config.ts` Loads the default export here as a config override.
67
+ - `file-system.ts` Loads the default export here as a file-system override.
68
+ - `limiter.ts` Loads the default export here as a limiter override (concurrency).
69
+ - `metrics.ts` Loads the default export as a metrics override.
70
+ - `monitoring.ts` Loads the default export as a monitoring override.
71
+ - `router.ts` Loads the default export as a routing override.
72
+ - `token.ts` Loads the default export as a token override.
73
+ - `webhooks.ts` Loads the default export as a WebHook override.
74
+
75
+ When enhancing overrides it's highly recommended to extend the existing implementation versus re-implementing the entire module. You can either default export a Class or an instance of a class and Browserless will handle it appropriately for you. This is useful if your enhancements require new constructor arguments or other features. See below for more details.
76
+
77
+ Once you're satisfied with your work, you can run `npm start` and Browserless will compile your TypeScript, generate runtime validation, generate the embedded documentation site, and start the development server.
78
+
79
+ Finally, once you're ready to build the docker image, simply execute `npm run docker` and follow the steps to build your docker image.
80
+
81
+ With these components and enhancements you can extend practically any part of Browserless: add new browsers, support multiple token authentication, save things to a file-system or external platform, push things to S3 buckets, and way more!
82
+
83
+ ## The CLI
84
+
85
+ Alongside the SDK that Browserless ships with, you'll also get a handy CLI that can help with all aspects of extending Browserless. Most of the CLI commands are ran as `npm run *` commands as is common in NodeJS projects. These are listed in the package.json "scripts" property for your reference.
86
+
87
+ Similarly, you can simply run these commands by doing:
88
+
89
+ ```sh
90
+ $ npx @browserless.io/browserless $COMMAND
91
+ ```
92
+
93
+ For instance, to print the help text, simply execute:
94
+
95
+ ```sh
96
+ $ npx @browserless.io/browserless help
97
+ ```
98
+
99
+ For help with a specific command, you can also run:
100
+
101
+ ```sh
102
+ $ npx npx @browserless.io/browserless help start
103
+ ```
104
+
105
+ By default most commands are non-interactive, such as the `build` and `dev` commands. Others, like the `docker` commands, can operate in a interactive or non-interactive mode when the correct switches are applied.
106
+
107
+ ## Routing
108
+
109
+ Routing is, simply, a plain-old JavaScript object with certain expected properties. Many of the features of Browserless are exposed as options on routes so you can define many types of functionality with just a route definition.
110
+
111
+ Browserless has 4 different types of routes:
112
+
113
+ - HTTP Routes that don't need a browser to run.
114
+ - HTTP Routes that do need a browser to run.
115
+ - WebSocket routes that don't a browser.
116
+ - WebSockets that need a browser.
117
+
118
+ We use this same semantic in our own codebase, so feel free to see how those work in our open-source projects. All routes are TypeScript and all our modules are documented, so you should be able to effectively write routes and modules with your code editor and not necessarily need these examples open. Below are a few examples:
119
+
120
+ ### Basic HTTP Route
121
+ ```ts
122
+ import {
123
+ APITags,
124
+ HTTPRoute,
125
+ Methods,
126
+ contentTypes,
127
+ writeResponse,
128
+ } from '@browserless.io/browserless';
129
+
130
+ // Response schemas must be typed "ResponseSchema" and are documented for you and
131
+ // shown in the built-in documentation site.
132
+ export type ResponseSchema = string;
133
+
134
+ // Similar to React and other ecosystems, extend our basic HTTPRoute
135
+ export default class HelloWorldRoute extends HTTPRoute {
136
+ // Detail any content-types that this route should except. "contentTypes.any" here means any content-type.
137
+ // If the content-type does not match then a 404 will be sent back
138
+ accepts = [contentTypes.any];
139
+
140
+ // A boolean to indicate if authorization (token auth) is required to access this route. Can also be a function
141
+ // that returns a boolean with the request object being the only argument.
142
+ auth = true;
143
+
144
+ // If this route requires a browser. `null` indicates no browser needed.
145
+ browser = null;
146
+
147
+ // Does this route need to be limited by the global concurrency limit? Set to "true" if so
148
+ concurrency = false;
149
+
150
+ // The returned content-type of this route. Shown in the documentation site.
151
+ contentTypes = [contentTypes.text];
152
+
153
+ // A description for this route and what it does. Gets displayed inside the documentation site.
154
+ description = `Returns a simple "Hello World!" response.`;
155
+
156
+ // Define what method that this route will listen for. Other methods will 404.
157
+ method = Methods.get;
158
+
159
+ // The path that this route will listen on requests for.
160
+ path = '/hello';
161
+
162
+ // A list of arbitrary tags to group similar APIs with in the documentation site.
163
+ tags = [APITags.management];
164
+
165
+ // Handler is a function, getting the request and response objects, and is where you'll write the
166
+ // core logic behind this route. Use utilities like writeResponse or writeJSONResponse to help
167
+ // return the appropriate response.
168
+ handler = async (_req, res): Promise<void> => {
169
+ const response: ResponseSchema = 'Hello World!';
170
+ return writeResponse(res, 200, ResponseSchema, contentTypes.text);
171
+ };
172
+ }
173
+ ```
174
+
175
+ ### Chromium WebSocket Route
176
+ ```ts
177
+ import {
178
+ APITags,
179
+ BrowserWebsocketRoute,
180
+ CDPChromium,
181
+ CDPLaunchOptions,
182
+ Request,
183
+ SystemQueryParameters,
184
+ WebsocketRoutes,
185
+ } from '@browserless.io/browserless';
186
+ import { Duplex } from 'stream';
187
+
188
+ // Use "QuerySchema" here to define what query-parameters are allowed
189
+ // which get parsed into the documentation site.
190
+ export interface QuerySchema extends SystemQueryParameters {
191
+ launch?: CDPLaunchOptions | string;
192
+ }
193
+
194
+ export default class ChromiumWebSocketRoute extends BrowserWebsocketRoute {
195
+ // This route requires a valid authorization token.
196
+ auth = true;
197
+
198
+ // This route uses the built-in CDPChromium class (Chromium)
199
+ browser = CDPChromium;
200
+
201
+ // This route is limited by the global concurrency limiter
202
+ concurrency = true;
203
+
204
+ // Short description of the route and what it does shown on the documentation site
205
+ description = `Launch and connect to Chromium with a library like puppeteer or others that work over chrome-devtools-protocol.`;
206
+
207
+ // This route is available on the '/' route
208
+ path = WebsocketRoutes['/'];
209
+
210
+ // This is a browser-based WebSocket route so we tag it as such
211
+ tags = [APITags.browserWS];
212
+
213
+ // Routes with a browser type get a browser argument of the Browser instance, otherwise
214
+ // request, socket, and head are the other 3 arguments. Here we pass them through
215
+ // and proxy the request into Chromium to handle.
216
+ handler = async (
217
+ req,
218
+ socket,
219
+ head,
220
+ chromium,
221
+ ): Promise<void> => chromium.proxyWebSocket(req, socket, head);
222
+ }
223
+ ```
224
+
225
+ Many more examples can be seen in `src/routes` as we use this same routing semantic internally.
226
+
227
+ ## Utilities
228
+
229
+ Browserless comes out-of-the-box with many utilities and functions to help with extending. Below are a few that we think are helpful and you may wish to use. All exports, including types, in browserless happen in the `@browserless.io/browserless` dependency, so simply require them from that path.
230
+
231
+ - `id()` Function that generates a random UUID string.
232
+ - `createLogger(domain: string)` Creates a debug instance with `browserless:` prepended to the name of the message.
233
+ - `dedent(message)` Useful for backtick strings, which this function cleans up white space
234
+ - `isConnected(res)` Checks if the underlying connection is still there. Useful for exiting early if a request disconnects.
235
+ - `writeResponse(res, code, message, contentType)` Function that writes a basic response, excepting the Response object, the HTTP Code, the message and the content type.
236
+ - `jsonResponse(res, code, object)` Function that writes JSON responses back with the appropriate headers.
237
+ - `getTokenFromRequest(req)` Gets the token from the request, whether it be a token parameter Basic/Bearer Authorization header. Token query-parameter is checked first.
238
+ - `readBody(req)` Parses the request's body and returns the result as a string or object for JSON content-types.
239
+ - `safeParse(JSON)` Attempts to parse the input from JSON to object, returning null if it fails.
240
+ - `sleep(milliseconds)` Sleeps or waits for the number of milliseconds passed. Async.
241
+ - `exists(filePath)` Checks if the file-path exists, returning a boolean. Async.
242
+ - `fileExists(filePath)` Checks if a file-path exists and is a file (not a directory). Async.
243
+ - `availableBrowsers` Returns an array of installed browsers on the image or system. Async and cached after the first call.
244
+ - `noop` A function that does... nothing. Do you do something?
245
+ - `once(func)` Wraps a function so it is only called one time.
246
+ - `encrypt(plainText, secret)` Encrypts the text with a secret, using Node's `createCipheriv` and `randomBytes(16)`.
247
+ - `decrypt(encryptedText, secret)` Attempts to decrypt the encrypted-text using the provided secret.
248
+ - `untildify(path)` Remove `~` characters from a path and returns the full filepath.
249
+
250
+ ### Error helpers:
251
+ - `BadRequest` An error that will cause browserless to return a `400` response with the error text being the message.
252
+ - `TooManyRequests` When thrown causes browserless to return a `429` with the error as the message.
253
+ - `ServerError` Returns a `500` code and shows the corresponding message.
254
+ - `Unauthorized` Returns a `401` error code and shows the corresponding message.
255
+ - `NotFound` When thrown causes a `404` to show with the error message.
256
+ - `Timeout` When thrown causes a `408` to be returned with the error message.
257
+
258
+ ## Extending Modules
259
+
260
+ Browserless comes with a batteries-loaded approach, and includes core modules for you to use or extend. Extending is generally recommended as it allows you to add features you care about without re-implementing the entirety of the module.
261
+
262
+ Module extension is only recommended for core cases where things like routing don't already work. Keep in mind: the more you extend the more you "opt-in" to ongoing maintenance and changes! With that in mind, you can freely look at the modules in our open-source project to get an idea for how they work and run. Otherwise, feel to keep reading!
263
+
264
+ **Extending Config**
265
+
266
+ The easiest module to extend is the Configuration module, as it's usage is pretty simple and straightforward. Here, we're going to add another property that we'll use later in a route. Doing this makes properties available in all routes, and makes a more pleasant route authoring experience. Routes can load modules, look at process variables and more, so it's up to you to decide where you'd like to place things like configuration.
267
+
268
+ ```ts
269
+ // src/config.ts
270
+ import { Config } from '@browserless.io/browserless';
271
+
272
+ // Your config class must be the default export
273
+ // and you can export the Class or an instance of it.
274
+ export default class MyConfig extends Config {
275
+ public getS3Bucket = (): string => {
276
+ // Load from environment variables or default to some other named bucket.
277
+ return process.env.S3_BUCKET ?? 'my-fun-s3-bucket';
278
+ };
279
+ };
280
+ ```
281
+
282
+ Then, later, in your route you can define some functionality and load the config object. Let's make a PDF route that generates a PDF from a URL and then saves the result to this S3 bucket.
283
+
284
+ ```ts
285
+ // src/pdf.http.ts
286
+ import { BrowserHTTPRoute } from '@browserless.io/browserless';
287
+ import MyConfig from './config';
288
+
289
+ // Export the BodySchema for documentation site to parse, plus
290
+ // browserless creates runtime validation with this as well!
291
+ export interface BodySchema {
292
+ /**
293
+ * The URL of the PDF you want to generate. Comments of this style get
294
+ * converted into descriptions in the documentation site.
295
+ */
296
+ url: string;
297
+ }
298
+
299
+ export default class PDFToS3Route extends BrowserHTTPRoute {
300
+ // Our route only accepts JSON content-types, and the rest 404
301
+ accepts = [contentTypes.json];
302
+
303
+ // Since we're launching a browser and saving something to S3
304
+ // we should have this route under authentication
305
+ auth = true;
306
+
307
+ // This route uses Chromium to process the PDF.
308
+ browser = CDPChromium;
309
+
310
+ // Generally, we recommend limiting concurrency when using
311
+ // browser routing
312
+ concurrency = true;
313
+
314
+ // This defines our content-type response when processed properly.
315
+ // We'll return a simple "ok" response if everything goes well.
316
+ contentTypes = [contentTypes.text];
317
+
318
+ // This description gets generated into the built-in documentation site.
319
+ description = `Produces a PDF from a supplied "url" parameter and loads it to the configured S3 Bucket`;
320
+
321
+ // We only accept POST'd payloads, else we 404
322
+ method = Methods.post;
323
+
324
+ // This route exists on the '/pdf-to-s3' route
325
+ path = '/pdf-to-s3';
326
+
327
+ // This a browser-based API so we tag it as such for documentation handling
328
+ tags = [APITags.browserAPI];
329
+
330
+ // Handler's are where we embed the logic that facilitates this route.
331
+ handler = async (
332
+ req,
333
+ res,
334
+ browser,
335
+ ): Promise<void> => {
336
+ // Modules like Config are injected via this internal methods.
337
+ // Use them to load core modules within the platform.
338
+ const config = this.config() as MyConfig;
339
+ const s3Bucket = config.getS3Bucket();
340
+ const page = await browser.newPage();
341
+
342
+ // ...Handle the rest!
343
+ };
344
+ }
345
+ ```
346
+
347
+ With this approach you can effectively write, extend and author your own workflows within browserless!
348
+
349
+ ## Running in Development
350
+
351
+ After the project has been set up, you can use npm commands to build and run your code. The most important of these is the `npm run dev` command, which will do the following:
352
+
353
+ - Compile your TypeScript files into a NodeJS compatible `build` directory.
354
+ - Load your authored routes and generate runtime validations for them.
355
+ - Generate an OpenAPI JSON manifest for the documentation site.
356
+ - Finally, it will start the service, binding to port `3000` and `localhost`.
357
+
358
+ This process may take up to a few seconds depending on the number of routes you've created. Browserless prioritizes, in order: deterministic behavior, completion and then speed.
359
+
360
+ Once these are done you'll notice some friendly logs in your terminal, as well as a link to the documentation site that comes for free with your route definitions!
361
+
362
+ ## Building for Production
363
+
364
+ While the end-goal is a docker image being built, you can simply do a complete build for CI or other purposes by simply running:
365
+
366
+ ```sh
367
+ $ npm run build
368
+ ```
369
+
370
+ Similar to development builds, this will compile all assets, generate OpenAPI JSON, and build out the runtime validation files, but *won't start the http server*.
371
+
372
+ If you wish to simply run the server without having to rebuild assets, then read more below.
373
+
374
+ ## Running without Building
375
+
376
+ If you wish to simply run the project without building, then simply run:
377
+
378
+ ```sh
379
+ $ npm start
380
+ ```
381
+
382
+ This will skip all the building phases required to normally start the server. Useful if you're simply restarting due to an error or want to just re-use the last made build.
383
+
384
+ ## Docker
385
+
386
+ Browserless comes with a CLI utility to help with building your docker image. It takes care of things like platforms, correctly setting up the production bundle, logging, and more. To get started with the docker build simply run:
387
+
388
+ ```sh
389
+ $ npm run docker
390
+ ```
391
+
392
+ Without any argument switches (those fun `--some-argument` bits), Browserless will prompt for input in a interactive way. To see a list of all options to input at once, run:
393
+
394
+ ```sh
395
+ $ npm run docker help
396
+ ```
397
+
398
+ This will print out all the available options so you can run a build in a continuous integration environment.
399
+
400
+ Based upon answers to either these switches or prompts, this utility will pull a respective GitHub container from the Browserless organization, insert your code, then build and execute it.
401
+
402
+ ## Licensing
403
+
404
+ SPDX-License-Identifier: SSPL-1.0 OR Browserless Commercial License.
405
+
406
+ If you want to use Browserless to build commercial sites, applications, or in a continuous-integration system that's closed-source then you'll need to purchase a commercial license. This allows you to keep your software proprietary whilst still using Browserless. [You can purchase a commercial license here](https://www.browserless.io/contact). A commercial license grants you:
407
+
408
+ - Priority support on issues and features.
409
+ - On-premise running as well as running on public cloud providers for commercial/CI purposes for proprietary systems.
410
+ - Ability to modify the source (forking) for your own purposes.
411
+ - This SDK and accompanying software it produces.
412
+
413
+ Not only does it grant you a license to run such a critical piece of infrastructure, but you are also supporting further innovation in this space and our ability to contribute to it.
414
+
415
+ If you are creating an open source application under a license compatible with the Server Side License 1.0, you may use Browserless under those terms.
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "",
3
+ "version": "1.0.0",
4
+ "description": "A browserless.io extension project!",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build": "DEBUG=browserless* browserless build",
10
+ "docker": "DEBUG=browserless* browserless docker",
11
+ "clean": "rm -r build",
12
+ "dev": "DEBUG=browserless*,-**:verbose browserless dev",
13
+ "start": "DEBUG=browserless*,-**:verbose browserless start",
14
+ "prettier": "prettier 'src/**.{js,ts,json}' --log-level error --write"
15
+ },
16
+ "author": "",
17
+ "license": "",
18
+ "dependencies": {
19
+ "@browserless.io/browserless": "^2.0.0-beta-5"
20
+ }
21
+ }
@@ -0,0 +1,25 @@
1
+ import {
2
+ APITags,
3
+ HTTPRoute,
4
+ Methods,
5
+ contentTypes,
6
+ writeResponse,
7
+ } from '@browserless.io/browserless';
8
+
9
+ export type ResponseSchema = string;
10
+
11
+ export default class HelloWorldRoute extends HTTPRoute {
12
+ accepts = [contentTypes.any];
13
+ auth = true;
14
+ browser = null;
15
+ concurrency = false;
16
+ contentTypes = [contentTypes.text];
17
+ description = `Returns a simple "Hello World!" response. Useful for testing.`;
18
+ method = Methods.get;
19
+ path = '/hello';
20
+ tags = [APITags.management];
21
+ handler = async (_req, res): Promise<void> => {
22
+ const response: ResponseSchema = 'Hello World!';
23
+ return writeResponse(res, 200, response, contentTypes.text);
24
+ };
25
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./node_modules/@browserless.io/browserless/tsconfig.json",
3
+ "include": ["./src/**/*"]
4
+ }
@@ -103,14 +103,15 @@ export class Browserless {
103
103
  }));
104
104
  const routeImport = `${this.config.getIsWin() ? 'file:///' : ''}${httpRoute}`;
105
105
  const logger = createLogger(`http:${name}`);
106
- const { default: route } = await import(routeImport + `?cb=${Date.now()}`);
106
+ const { default: Route, } = await import(routeImport + `?cb=${Date.now()}`);
107
+ const route = new Route(this.browserManager, this.config, this.fileSystem, logger, this.metrics, this.monitoring);
107
108
  route.bodySchema = safeParse(bodySchema);
108
109
  route.querySchema = safeParse(querySchema);
109
- route.getConfig = () => this.config;
110
- route.getMetrics = () => this.metrics;
111
- route.getMonitoring = () => this.monitoring;
112
- route.getFileSystem = () => this.fileSystem;
113
- route.getDebug = () => logger;
110
+ route.config = () => this.config;
111
+ route.metrics = () => this.metrics;
112
+ route.monitoring = () => this.monitoring;
113
+ route.fileSystem = () => this.fileSystem;
114
+ route.debug = () => logger;
114
115
  httpRoutes.push(route);
115
116
  }
116
117
  }
@@ -125,21 +126,23 @@ export class Browserless {
125
126
  }));
126
127
  const wsImport = `${this.config.getIsWin() ? 'file:///' : ''}${wsRoute}`;
127
128
  const logger = createLogger(`ws:${name}`);
128
- const { default: route, } = await import(wsImport + `?cb=${Date.now()}`);
129
+ const { default: Route, } = await import(wsImport + `?cb=${Date.now()}`);
130
+ const route = new Route(this.browserManager, this.config, this.fileSystem, logger, this.metrics, this.monitoring);
129
131
  route.querySchema = safeParse(querySchema);
130
- route.getConfig = () => this.config;
131
- route.getMetrics = () => this.metrics;
132
- route.getMonitoring = () => this.monitoring;
133
- route.getFileSystem = () => this.fileSystem;
134
- route.getDebug = () => logger;
132
+ route.config = () => this.config;
133
+ route.metrics = () => this.metrics;
134
+ route.monitoring = () => this.monitoring;
135
+ route.fileSystem = () => this.fileSystem;
136
+ route.debug = () => logger;
135
137
  wsRoutes.push(route);
136
138
  }
137
139
  }
138
140
  // Validate that browsers are installed and route paths are unique
139
141
  [...httpRoutes, ...wsRoutes].forEach((route) => {
140
- if (route.browser &&
141
- !installedBrowsers.some((b) => b.name === route.browser.name)) {
142
- throw new Error(`Couldn't load route "${route.path}" due to missing browser of "${route.browser.name}"`);
142
+ if ('browser' in route &&
143
+ route.browser &&
144
+ !installedBrowsers.some((b) => b.name === route.browser?.name)) {
145
+ throw new Error(`Couldn't load route "${route.path}" due to missing browser of "${route.browser?.name}"`);
143
146
  }
144
147
  });
145
148
  httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
@@ -1,5 +1,5 @@
1
1
  /// <reference types="debug" />
2
- import { BrowserHTTPRoute, BrowserInstance, BrowserServerOptions, BrowserWebsocketRoute, BrowserlessSession, BrowserlessSessionJSON, CDPLaunchOptions, Config, Request } from '@browserless.io/browserless';
2
+ import { BrowserHTTPRoute, BrowserInstance, BrowserWebsocketRoute, BrowserlessSession, BrowserlessSessionJSON, Config, Request } from '@browserless.io/browserless';
3
3
  export declare class BrowserManager {
4
4
  protected config: Config;
5
5
  protected browsers: Map<BrowserInstance, BrowserlessSession>;
@@ -18,23 +18,7 @@ export declare class BrowserManager {
18
18
  * @returns Promise<string> of the fully-qualified path of the directory
19
19
  */
20
20
  protected generateDataDir: (sessionId?: string) => Promise<string>;
21
- protected generateSessionJson: (browser: BrowserInstance, session: BrowserlessSession) => {
22
- browser: string;
23
- browserId: string | undefined;
24
- initialConnectURL: string;
25
- killURL: string | null;
26
- running: boolean;
27
- timeAliveMs: number;
28
- id: string | null;
29
- isTempDataDir: boolean;
30
- launchOptions: CDPLaunchOptions | BrowserServerOptions;
31
- numbConnected: number;
32
- resolver: (val: unknown) => void;
33
- routePath: string;
34
- startedOn: number;
35
- ttl: number;
36
- userDataDir: string | null;
37
- };
21
+ private generateSessionJson;
38
22
  close: (browser: BrowserInstance, session: BrowserlessSession) => Promise<void>;
39
23
  getAllSessions: () => Promise<BrowserlessSessionJSON[]>;
40
24
  complete: (browser: BrowserInstance) => Promise<void>;
@@ -41,19 +41,43 @@ export class BrowserManager {
41
41
  });
42
42
  return dataDirPath;
43
43
  };
44
- generateSessionJson = (browser, session) => {
44
+ generateSessionJson = async (browser, session) => {
45
45
  const serverAddress = this.config.getExternalAddress();
46
- return {
47
- ...session,
48
- browser: browser.constructor.name,
49
- browserId: browser.wsEndpoint()?.split('/').pop(),
50
- initialConnectURL: new URL(session.initialConnectURL, serverAddress).href,
51
- killURL: session.id
52
- ? makeExternalURL(serverAddress, HTTPManagementRoutes.sessions, session.id)
53
- : null,
54
- running: browser.isRunning(),
55
- timeAliveMs: Date.now() - session.startedOn,
56
- };
46
+ const sessions = [
47
+ {
48
+ ...session,
49
+ browser: browser.constructor.name,
50
+ browserId: browser.wsEndpoint()?.split('/').pop(),
51
+ initialConnectURL: new URL(session.initialConnectURL, serverAddress)
52
+ .href,
53
+ killURL: session.id
54
+ ? makeExternalURL(serverAddress, HTTPManagementRoutes.sessions, session.id)
55
+ : null,
56
+ running: browser.isRunning(),
57
+ timeAliveMs: Date.now() - session.startedOn,
58
+ type: 'browser',
59
+ },
60
+ ];
61
+ const wsEndpoint = browser.wsEndpoint();
62
+ if (browser.constructor.name === 'CDPChromium' && wsEndpoint) {
63
+ const port = new URL(wsEndpoint).port;
64
+ const response = await fetch(`http://127.0.0.1:${port}/json/list`, {
65
+ headers: {
66
+ Host: '127.0.0.1',
67
+ },
68
+ });
69
+ if (response.ok) {
70
+ const body = await response.json();
71
+ for (const page of body) {
72
+ sessions.push({
73
+ ...sessions[0],
74
+ ...page,
75
+ browserWSEndpoint: wsEndpoint,
76
+ });
77
+ }
78
+ }
79
+ }
80
+ return sessions;
57
81
  };
58
82
  close = async (browser, session) => {
59
83
  const cleanupACtions = [];
@@ -69,7 +93,12 @@ export class BrowserManager {
69
93
  };
70
94
  getAllSessions = async () => {
71
95
  const sessions = Array.from(this.browsers);
72
- return sessions.map(([browser, session]) => this.generateSessionJson(browser, session));
96
+ const formattedSessions = [];
97
+ for (const [browser, session] of sessions) {
98
+ const formattedSession = await this.generateSessionJson(browser, session);
99
+ formattedSessions.push(...formattedSession);
100
+ }
101
+ return formattedSessions;
73
102
  };
74
103
  complete = async (browser) => {
75
104
  const session = this.browsers.get(browser);
@@ -117,7 +146,7 @@ export class BrowserManager {
117
146
  };
118
147
  const manualUserDataDir = launchOptions.args
119
148
  ?.find((arg) => arg.includes('--user-data-dir='))
120
- ?.split('=')[2] || launchOptions.userDataDir;
149
+ ?.split('=')[1] || launchOptions.userDataDir;
121
150
  // Always specify a user-data-dir since plugins can "inject" their own
122
151
  // unless it's playwright which takes care of its own data-dirs
123
152
  const userDataDir = manualUserDataDir ||
package/build/http.d.ts CHANGED
@@ -132,9 +132,9 @@ export declare enum HTTPManagementRoutes {
132
132
  static = "/"
133
133
  }
134
134
  export declare enum APITags {
135
- 'browserAPI' = "Browser APIs",
136
- 'browserWS' = "Browser WebSockets",
137
- 'management' = "Management APIs"
135
+ 'browserAPI' = "Browser REST APIs",
136
+ 'browserWS' = "Browser WebSocket APIs",
137
+ 'management' = "Management REST APIs"
138
138
  }
139
139
  export interface Request extends http.IncomingMessage {
140
140
  body: unknown;
package/build/http.js CHANGED
@@ -98,7 +98,7 @@ export var HTTPManagementRoutes;
98
98
  })(HTTPManagementRoutes || (HTTPManagementRoutes = {}));
99
99
  export var APITags;
100
100
  (function (APITags) {
101
- APITags["browserAPI"] = "Browser APIs";
102
- APITags["browserWS"] = "Browser WebSockets";
103
- APITags["management"] = "Management APIs";
101
+ APITags["browserAPI"] = "Browser REST APIs";
102
+ APITags["browserWS"] = "Browser WebSocket APIs";
103
+ APITags["management"] = "Management REST APIs";
104
104
  })(APITags || (APITags = {}));