@browserless.io/browserless 2.2.0 → 2.3.0-beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +2 -2
  2. package/bin/browserless.js +67 -27
  3. package/bin/scaffold/README.md +50 -0
  4. package/bin/scaffold/src/hello-world.http.ts +2 -1
  5. package/build/browserless.d.ts +3 -0
  6. package/build/browserless.js +43 -19
  7. package/build/browsers/chrome.cdp.js +1 -1
  8. package/build/browsers/chrome.playwright.js +1 -1
  9. package/build/browsers/index.d.ts +1 -0
  10. package/build/browsers/index.js +4 -1
  11. package/build/data/classes.json +1 -1
  12. package/build/data/selectors.json +1 -1
  13. package/build/exports.js +1 -2
  14. package/build/limiter.d.ts +2 -1
  15. package/build/limiter.js +6 -3
  16. package/build/routes/chrome/http/content.post.body.json +8 -8
  17. package/build/routes/chrome/http/content.post.d.ts +2 -1
  18. package/build/routes/chrome/http/content.post.js +3 -2
  19. package/build/routes/chrome/http/download.post.d.ts +2 -1
  20. package/build/routes/chrome/http/download.post.js +3 -2
  21. package/build/routes/chrome/http/function.post.d.ts +2 -1
  22. package/build/routes/chrome/http/function.post.js +3 -2
  23. package/build/routes/chrome/http/json-list.get.d.ts +5 -1
  24. package/build/routes/chrome/http/json-list.get.js +5 -1
  25. package/build/routes/chrome/http/json-new.put.d.ts +5 -1
  26. package/build/routes/chrome/http/json-new.put.js +5 -1
  27. package/build/routes/chrome/http/json-protocol.get.d.ts +5 -1
  28. package/build/routes/chrome/http/json-protocol.get.js +5 -1
  29. package/build/routes/chrome/http/json-version.get.d.ts +5 -1
  30. package/build/routes/chrome/http/json-version.get.js +5 -1
  31. package/build/routes/chrome/http/pdf.post.body.json +8 -8
  32. package/build/routes/chrome/http/pdf.post.d.ts +2 -1
  33. package/build/routes/chrome/http/pdf.post.js +3 -2
  34. package/build/routes/chrome/http/performance.post.d.ts +2 -1
  35. package/build/routes/chrome/http/performance.post.js +3 -2
  36. package/build/routes/chrome/http/scrape.post.body.json +8 -8
  37. package/build/routes/chrome/http/scrape.post.d.ts +2 -1
  38. package/build/routes/chrome/http/scrape.post.js +3 -2
  39. package/build/routes/chrome/http/screenshot.post.body.json +8 -8
  40. package/build/routes/chrome/http/screenshot.post.d.ts +2 -1
  41. package/build/routes/chrome/http/screenshot.post.js +3 -2
  42. package/build/routes/chrome/ws/browser.d.ts +2 -1
  43. package/build/routes/chrome/ws/browser.js +3 -2
  44. package/build/routes/chrome/ws/cdp.d.ts +2 -1
  45. package/build/routes/chrome/ws/cdp.js +3 -2
  46. package/build/routes/chrome/ws/page.d.ts +3 -2
  47. package/build/routes/chrome/ws/page.js +3 -2
  48. package/build/routes/chrome/ws/playwright.d.ts +1 -0
  49. package/build/routes/chrome/ws/playwright.js +2 -1
  50. package/build/routes/chromium/http/content.post.body.json +8 -8
  51. package/build/routes/chromium/http/pdf.post.body.json +8 -8
  52. package/build/routes/chromium/http/scrape.post.body.json +8 -8
  53. package/build/routes/chromium/http/screenshot.post.body.json +8 -8
  54. package/build/routes/firefox/ws/playwright.d.ts +7 -2
  55. package/build/routes/firefox/ws/playwright.js +3 -2
  56. package/build/routes/firefox/ws/playwright.query.json +29 -31
  57. package/build/routes/management/http/config.get.d.ts +1 -0
  58. package/build/routes/management/http/config.get.js +2 -1
  59. package/build/routes/management/http/metrics-total.get.d.ts +1 -0
  60. package/build/routes/management/http/metrics-total.get.js +2 -1
  61. package/build/routes/management/http/metrics.get.d.ts +1 -0
  62. package/build/routes/management/http/metrics.get.js +2 -1
  63. package/build/routes/management/http/sessions.get.d.ts +1 -0
  64. package/build/routes/management/http/sessions.get.js +2 -1
  65. package/build/routes/management/http/static.get.d.ts +1 -0
  66. package/build/routes/management/http/static.get.js +8 -7
  67. package/build/routes/webkit/ws/playwright.d.ts +2 -1
  68. package/build/routes/webkit/ws/playwright.js +3 -2
  69. package/build/shared/browser.ws.d.ts +2 -1
  70. package/build/shared/browser.ws.js +3 -2
  71. package/build/shared/chromium.playwright.ws.d.ts +2 -1
  72. package/build/shared/chromium.playwright.ws.js +3 -2
  73. package/build/shared/chromium.ws.d.ts +2 -1
  74. package/build/shared/chromium.ws.js +3 -2
  75. package/build/shared/content.http.d.ts +2 -1
  76. package/build/shared/content.http.js +3 -2
  77. package/build/shared/download.http.d.ts +2 -1
  78. package/build/shared/download.http.js +3 -2
  79. package/build/shared/function.http.d.ts +2 -1
  80. package/build/shared/function.http.js +3 -2
  81. package/build/shared/json-list.http.d.ts +2 -1
  82. package/build/shared/json-list.http.js +3 -2
  83. package/build/shared/json-new.http.d.ts +2 -1
  84. package/build/shared/json-new.http.js +3 -2
  85. package/build/shared/json-protocol.http.d.ts +2 -1
  86. package/build/shared/json-protocol.http.js +3 -2
  87. package/build/shared/json-version.http.d.ts +2 -1
  88. package/build/shared/json-version.http.js +3 -2
  89. package/build/shared/page.ws.d.ts +2 -1
  90. package/build/shared/page.ws.js +3 -2
  91. package/build/shared/pdf.http.d.ts +2 -1
  92. package/build/shared/pdf.http.js +3 -2
  93. package/build/shared/performance.http.d.ts +1 -0
  94. package/build/shared/performance.http.js +2 -1
  95. package/build/shared/scrape.http.d.ts +2 -1
  96. package/build/shared/scrape.http.js +3 -2
  97. package/build/shared/screenshot.http.d.ts +1 -0
  98. package/build/shared/screenshot.http.js +2 -1
  99. package/build/shared/utils/performance/main.js +1 -1
  100. package/build/types.d.ts +91 -0
  101. package/build/types.js +54 -0
  102. package/build/utils.d.ts +1 -1
  103. package/build/utils.js +11 -6
  104. package/docker/chromium/Dockerfile +1 -2
  105. package/docker/firefox/Dockerfile +1 -2
  106. package/docker/multi/Dockerfile +2 -4
  107. package/docker/webkit/Dockerfile +1 -2
  108. package/package.json +11 -11
  109. package/scripts/build-open-api.js +142 -124
  110. package/src/browserless.ts +60 -22
  111. package/src/browsers/chrome.cdp.ts +1 -1
  112. package/src/browsers/chrome.playwright.ts +1 -1
  113. package/src/browsers/index.ts +5 -1
  114. package/src/exports.ts +1 -3
  115. package/src/limiter.ts +7 -3
  116. package/src/router.ts +6 -2
  117. package/src/routes/chrome/http/content.post.ts +7 -2
  118. package/src/routes/chrome/http/download.post.ts +7 -2
  119. package/src/routes/chrome/http/function.post.ts +7 -2
  120. package/src/routes/chrome/http/json-list.get.ts +7 -1
  121. package/src/routes/chrome/http/json-new.put.ts +7 -1
  122. package/src/routes/chrome/http/json-protocol.get.ts +7 -1
  123. package/src/routes/chrome/http/json-version.get.ts +7 -1
  124. package/src/routes/chrome/http/pdf.post.ts +7 -2
  125. package/src/routes/chrome/http/performance.post.ts +7 -2
  126. package/src/routes/chrome/http/scrape.post.ts +7 -2
  127. package/src/routes/chrome/http/screenshot.post.ts +7 -2
  128. package/src/routes/chrome/ws/browser.ts +3 -2
  129. package/src/routes/chrome/ws/cdp.ts +7 -2
  130. package/src/routes/chrome/ws/page.ts +3 -2
  131. package/src/routes/chrome/ws/playwright.ts +6 -1
  132. package/src/routes/firefox/ws/playwright.ts +6 -2
  133. package/src/routes/management/http/config.get.ts +2 -0
  134. package/src/routes/management/http/metrics-total.get.ts +2 -0
  135. package/src/routes/management/http/metrics.get.ts +2 -0
  136. package/src/routes/management/http/sessions.get.ts +2 -0
  137. package/src/routes/management/http/static.get.ts +16 -9
  138. package/src/routes/webkit/ws/playwright.ts +3 -1
  139. package/src/shared/browser.ws.ts +3 -1
  140. package/src/shared/chromium.playwright.ws.ts +3 -1
  141. package/src/shared/chromium.ws.ts +3 -1
  142. package/src/shared/content.http.ts +3 -1
  143. package/src/shared/download.http.ts +3 -1
  144. package/src/shared/function.http.ts +3 -1
  145. package/src/shared/json-list.http.ts +3 -1
  146. package/src/shared/json-new.http.ts +3 -1
  147. package/src/shared/json-protocol.http.ts +3 -1
  148. package/src/shared/json-version.http.ts +3 -1
  149. package/src/shared/page.ws.ts +3 -1
  150. package/src/shared/pdf.http.ts +3 -1
  151. package/src/shared/performance.http.ts +2 -0
  152. package/src/shared/scrape.http.ts +3 -1
  153. package/src/shared/screenshot.http.ts +2 -0
  154. package/src/shared/utils/performance/main.ts +1 -2
  155. package/src/types.ts +66 -0
  156. package/src/utils.ts +13 -7
  157. package/static/docs/swagger.json +91 -49
  158. package/static/docs/swagger.min.json +6697 -0
  159. package/static/function/client.js +323 -323
@@ -11,6 +11,13 @@ import { marked } from 'marked';
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
  const moduleMain = import.meta.url.endsWith(process.argv[1]);
13
13
  const swaggerJSONPath = join(__dirname, '..', 'static', 'docs', 'swagger.json');
14
+ const swaggerJSONMinimal = join(
15
+ __dirname,
16
+ '..',
17
+ 'static',
18
+ 'docs',
19
+ 'swagger.min.json',
20
+ );
14
21
  const packageJSONPath = join(__dirname, '..', 'package.json');
15
22
 
16
23
  const readFileOrNull = async (path) => {
@@ -42,6 +49,7 @@ const sortSwaggerRequiredAlpha = (prop, otherProp) => {
42
49
  const buildOpenAPI = async (
43
50
  externalHTTPRoutes = [],
44
51
  externalWebSocketRoutes = [],
52
+ disabledRoutes = [],
45
53
  ) => {
46
54
  const [{ getRouteFiles }, { Config }, { errorCodes }, packageJSON] =
47
55
  await Promise.all([
@@ -62,8 +70,6 @@ const buildOpenAPI = async (
62
70
  customSiteTitle: 'Browserless Documentation',
63
71
  definitions: {},
64
72
  info: {
65
- // Concatenation necessary for Changelog to show up in sidebar
66
- description: readme + `\n# Changelog\n` + changelog,
67
73
  title: 'Browserless',
68
74
  version: JSON.parse(packageJSON.toString()).version,
69
75
  'x-logo': {
@@ -93,6 +99,11 @@ const buildOpenAPI = async (
93
99
  throw new Error(`Invalid route file to import docs ${routeModule}`);
94
100
  }
95
101
  const route = new Route();
102
+
103
+ if (disabledRoutes.includes(route.name)) {
104
+ return null;
105
+ }
106
+
96
107
  const { name } = parse(routeModule);
97
108
  const body = routeModule.replace('.js', '.body.json');
98
109
  const query = routeModule.replace('.js', '.query.json');
@@ -100,7 +111,7 @@ const buildOpenAPI = async (
100
111
  const isWebSocket = routeModule.includes('/ws/') || name.endsWith('ws');
101
112
  const path = Array.isArray(route.path)
102
113
  ? route.path.join(' ')
103
- : [route.path];
114
+ : route.path;
104
115
  const {
105
116
  tags,
106
117
  description,
@@ -130,145 +141,152 @@ const buildOpenAPI = async (
130
141
  }),
131
142
  );
132
143
 
133
- const paths = routeMetaData.reduce((accum, r) => {
134
- const swaggerRoute = {
135
- definitions: {},
136
- description: r.description,
137
- parameters: [],
138
- requestBody: {
139
- content: {},
140
- },
141
- responses: {
142
- ...errorCodes,
143
- },
144
- summary: r.path,
145
- tags: r.tags,
146
- };
144
+ const paths = routeMetaData
145
+ .filter((_) => !!_)
146
+ .reduce((accum, r) => {
147
+ const swaggerRoute = {
148
+ definitions: {},
149
+ description: r.description,
150
+ parameters: [],
151
+ requestBody: {
152
+ content: {},
153
+ },
154
+ responses: {
155
+ ...errorCodes,
156
+ },
157
+ summary: r.path,
158
+ tags: r.tags,
159
+ };
147
160
 
148
- r.method = r.isWebSocket ? 'get' : r.method;
161
+ r.method = r.isWebSocket ? 'get' : r.method;
149
162
 
150
- // Find all the swagger definitions and merge them into the
151
- // definitions object
152
- const allDefs = {
153
- ...(r?.body?.definitions || {}),
154
- ...(r?.query?.definitions || {}),
155
- ...(r?.response?.definitions || {}),
156
- };
163
+ // Find all the swagger definitions and merge them into the
164
+ // definitions object
165
+ const allDefs = {
166
+ ...(r?.body?.definitions || {}),
167
+ ...(r?.query?.definitions || {}),
168
+ ...(r?.response?.definitions || {}),
169
+ };
157
170
 
158
- Object.entries(allDefs).forEach(([defName, definition]) => {
159
- // @ts-ignore
160
- swaggerJSON.definitions[defName] =
171
+ Object.entries(allDefs).forEach(([defName, definition]) => {
161
172
  // @ts-ignore
162
- swaggerJSON.definitions[defName] ?? definition;
163
- });
164
-
165
- if (r.isWebSocket) {
166
- swaggerRoute.responses['101'] = {
167
- description: 'Indicates successful WebSocket upgrade.',
168
- };
169
- }
173
+ swaggerJSON.definitions[defName] =
174
+ // @ts-ignore
175
+ swaggerJSON.definitions[defName] ?? definition;
176
+ });
170
177
 
171
- // Does a best-attempt at configuring multiple response types
172
- // Won't figure out APIs that return mixed response types like
173
- // JSON and binary blobs
174
- if (r.response) {
175
- if (r.contentTypes.length === 1) {
176
- const [type] = r.contentTypes;
177
- swaggerRoute.responses['200'] = {
178
- content: {
179
- [type]: {
180
- schema: r.response,
181
- },
182
- },
183
- description: r.response.description,
178
+ if (r.isWebSocket) {
179
+ swaggerRoute.responses['101'] = {
180
+ description: 'Indicates successful WebSocket upgrade.',
184
181
  };
185
- } else {
186
- const okResponses = r.contentTypes.reduce(
187
- (accum, c) => {
188
- // @ts-ignore
189
- accum.content[c] = {
190
- schema: {
191
- type: 'text',
182
+ }
183
+
184
+ // Does a best-attempt at configuring multiple response types
185
+ // Won't figure out APIs that return mixed response types like
186
+ // JSON and binary blobs
187
+ if (r.response) {
188
+ if (r.contentTypes.length === 1) {
189
+ const [type] = r.contentTypes;
190
+ swaggerRoute.responses['200'] = {
191
+ content: {
192
+ [type]: {
193
+ schema: r.response,
192
194
  },
193
- };
194
- return accum;
195
- },
196
- {
197
- content: {},
195
+ },
198
196
  description: r.response.description,
199
- },
200
- );
201
- swaggerRoute.responses['200'] = okResponses;
197
+ };
198
+ } else {
199
+ const okResponses = r.contentTypes.reduce(
200
+ (accum, c) => {
201
+ // @ts-ignore
202
+ accum.content[c] = {
203
+ schema: {
204
+ type: 'text',
205
+ },
206
+ };
207
+ return accum;
208
+ },
209
+ {
210
+ content: {},
211
+ description: r.response.description,
212
+ },
213
+ );
214
+ swaggerRoute.responses['200'] = okResponses;
215
+ }
202
216
  }
203
- }
204
217
 
205
- // Does a best-attempt at configuring multiple body types and
206
- // ignores the "accepts" properties on routes since we can't
207
- // yet correlate the accepted types to the proper body
208
- if (r.body) {
209
- const { properties, type, anyOf } = r.body;
210
- if (anyOf) {
211
- // @ts-ignore
212
- anyOf.forEach((anyType) => {
213
- if (anyType.type === 'string') {
214
- const type = r.accepts.filter(
215
- // @ts-ignore
216
- (accept) => accept !== 'application/json',
217
- );
218
- swaggerRoute.requestBody.content[type] = {
219
- schema: {
220
- type: 'string',
221
- },
222
- };
223
- }
218
+ // Does a best-attempt at configuring multiple body types and
219
+ // ignores the "accepts" properties on routes since we can't
220
+ // yet correlate the accepted types to the proper body
221
+ if (r.body) {
222
+ const { properties, type, anyOf } = r.body;
223
+ if (anyOf) {
224
+ // @ts-ignore
225
+ anyOf.forEach((anyType) => {
226
+ if (anyType.type === 'string') {
227
+ const type = r.accepts.filter(
228
+ // @ts-ignore
229
+ (accept) => accept !== 'application/json',
230
+ );
231
+ swaggerRoute.requestBody.content[type] = {
232
+ schema: {
233
+ type: 'string',
234
+ },
235
+ };
236
+ }
224
237
 
225
- if (anyType['$ref']) {
226
- swaggerRoute.requestBody.content['application/json'] = {
227
- schema: {
228
- $ref: anyType['$ref'],
229
- },
230
- };
231
- }
232
- });
233
- }
238
+ if (anyType['$ref']) {
239
+ swaggerRoute.requestBody.content['application/json'] = {
240
+ schema: {
241
+ $ref: anyType['$ref'],
242
+ },
243
+ };
244
+ }
245
+ });
246
+ }
234
247
 
235
- // Handle JSON
236
- if (type === 'object') {
237
- swaggerRoute.requestBody.content['application/json'] = {
238
- schema: {
239
- properties,
240
- type: 'object',
241
- },
242
- };
248
+ // Handle JSON
249
+ if (type === 'object') {
250
+ swaggerRoute.requestBody.content['application/json'] = {
251
+ schema: {
252
+ properties,
253
+ type: 'object',
254
+ },
255
+ };
256
+ }
243
257
  }
244
- }
245
258
 
246
- // Queries are easy in comparison, but still have to be iterated
247
- // over and made open-api-able
248
- if (r.query) {
249
- const { properties, required } = r.query;
250
- const props = Object.keys(properties || {});
251
- if (props.length) {
252
- swaggerRoute.parameters = props
253
- .map((prop) => ({
254
- in: 'query',
255
- name: prop,
256
- required: required?.includes(prop),
257
- schema: properties[prop],
258
- }))
259
- .sort(sortSwaggerRequiredAlpha);
259
+ // Queries are easy in comparison, but still have to be iterated
260
+ // over and made open-api-able
261
+ if (r.query) {
262
+ const { properties, required } = r.query;
263
+ const props = Object.keys(properties || {});
264
+ if (props.length) {
265
+ swaggerRoute.parameters = props
266
+ .map((prop) => ({
267
+ in: 'query',
268
+ name: prop,
269
+ required: required?.includes(prop),
270
+ schema: properties[prop],
271
+ }))
272
+ .sort(sortSwaggerRequiredAlpha);
273
+ }
260
274
  }
261
- }
262
275
 
263
- // @ts-ignore
264
- accum[r.path] = accum[r.path] || {};
265
- // @ts-ignore
266
- accum[r.path][r.method] = swaggerRoute;
276
+ // @ts-ignore
277
+ accum[r.path] = accum[r.path] || {};
278
+ // @ts-ignore
279
+ accum[r.path][r.method] = swaggerRoute;
267
280
 
268
- return accum;
269
- }, {});
281
+ return accum;
282
+ }, {});
270
283
  swaggerJSON.paths = paths;
271
- fs.writeFile(swaggerJSONPath, JSON.stringify(swaggerJSON, null, ' '));
284
+ await fs.writeFile(
285
+ swaggerJSONMinimal,
286
+ JSON.stringify(swaggerJSON, null, ' '),
287
+ );
288
+ swaggerJSON.info.description = readme + `\n# Changelog\n` + changelog;
289
+ await fs.writeFile(swaggerJSONPath, JSON.stringify(swaggerJSON, null, ' '));
272
290
  };
273
291
 
274
292
  export default buildOpenAPI;
@@ -36,6 +36,12 @@ type Implements<T> = {
36
36
  new (...args: unknown[]): T;
37
37
  };
38
38
 
39
+ type routeInstances =
40
+ | HTTPRoute
41
+ | BrowserHTTPRoute
42
+ | WebSocketRoute
43
+ | BrowserWebsocketRoute;
44
+
39
45
  export class Browserless {
40
46
  protected debug: debug.Debugger = createLogger('index');
41
47
  protected browserManager: BrowserManager;
@@ -48,6 +54,7 @@ export class Browserless {
48
54
  protected token: Token;
49
55
  protected webhooks: WebHooks;
50
56
 
57
+ disabledRouteNames: string[] = [];
51
58
  webSocketRouteFiles: string[] = [];
52
59
  httpRouteFiles: string[] = [];
53
60
  server?: HTTPServer;
@@ -138,6 +145,14 @@ export class Browserless {
138
145
  );
139
146
  };
140
147
 
148
+ private routeIsDisabled(route: routeInstances) {
149
+ return this.disabledRouteNames.some((name) => name === route.name);
150
+ }
151
+
152
+ public disableRoutes(...routeNames: string[]) {
153
+ this.disabledRouteNames.push(...routeNames);
154
+ }
155
+
141
156
  public addHTTPRoute(httpRouteFilePath: string) {
142
157
  this.httpRouteFiles.push(httpRouteFilePath);
143
158
  }
@@ -171,7 +186,7 @@ export class Browserless {
171
186
  WebkitPlaywright,
172
187
  ];
173
188
 
174
- const [[httpRouteFiles, wsRouteFiles], installedBrowsers] =
189
+ const [[internalHttpRouteFiles, internalWsRouteFiles], installedBrowsers] =
175
190
  await Promise.all([getRouteFiles(this.config), availableBrowsers]);
176
191
 
177
192
  const docsLink = makeExternalURL(this.config.getExternalAddress(), '/docs');
@@ -180,7 +195,10 @@ export class Browserless {
180
195
  this.debug(`Running as user "${userInfo().username}"`);
181
196
  this.debug('Starting import of HTTP Routes');
182
197
 
183
- for (const httpRoute of [...httpRouteFiles, ...this.httpRouteFiles]) {
198
+ for (const httpRoute of [
199
+ ...internalHttpRouteFiles,
200
+ ...this.httpRouteFiles,
201
+ ]) {
184
202
  if (httpRoute.endsWith('js')) {
185
203
  const { name } = path.parse(httpRoute);
186
204
  const [bodySchema, querySchema] = await Promise.all(
@@ -209,20 +227,26 @@ export class Browserless {
209
227
  this.metrics,
210
228
  this.monitoring,
211
229
  );
212
- route.bodySchema = safeParse(bodySchema);
213
- route.querySchema = safeParse(querySchema);
214
- route.config = () => this.config;
215
- route.metrics = () => this.metrics;
216
- route.monitoring = () => this.monitoring;
217
- route.fileSystem = () => this.fileSystem;
218
- route.debug = () => logger;
219
-
220
- httpRoutes.push(route);
230
+
231
+ if (!this.routeIsDisabled(route)) {
232
+ route.bodySchema = safeParse(bodySchema);
233
+ route.querySchema = safeParse(querySchema);
234
+ route.config = () => this.config;
235
+ route.metrics = () => this.metrics;
236
+ route.monitoring = () => this.monitoring;
237
+ route.fileSystem = () => this.fileSystem;
238
+ route.debug = () => logger;
239
+
240
+ httpRoutes.push(route);
241
+ }
221
242
  }
222
243
  }
223
244
 
224
245
  this.debug('Starting import of WebSocket Routes');
225
- for (const wsRoute of [...wsRouteFiles, ...this.webSocketRouteFiles]) {
246
+ for (const wsRoute of [
247
+ ...internalWsRouteFiles,
248
+ ...this.webSocketRouteFiles,
249
+ ]) {
226
250
  if (wsRoute.endsWith('js')) {
227
251
  const { name } = path.parse(wsRoute);
228
252
  const [, querySchema] = await Promise.all(
@@ -246,7 +270,6 @@ export class Browserless {
246
270
  | Implements<WebSocketRoute>
247
271
  | Implements<BrowserWebsocketRoute>;
248
272
  } = await import(wsImport + `?cb=${Date.now()}`);
249
-
250
273
  const route = new Route(
251
274
  this.browserManager,
252
275
  this.config,
@@ -255,19 +278,23 @@ export class Browserless {
255
278
  this.metrics,
256
279
  this.monitoring,
257
280
  );
258
- route.querySchema = safeParse(querySchema);
259
- route.config = () => this.config;
260
- route.metrics = () => this.metrics;
261
- route.monitoring = () => this.monitoring;
262
- route.fileSystem = () => this.fileSystem;
263
- route.debug = () => logger;
264
-
265
- wsRoutes.push(route);
281
+
282
+ if (!this.routeIsDisabled(route)) {
283
+ route.querySchema = safeParse(querySchema);
284
+ route.config = () => this.config;
285
+ route.metrics = () => this.metrics;
286
+ route.monitoring = () => this.monitoring;
287
+ route.fileSystem = () => this.fileSystem;
288
+ route.debug = () => logger;
289
+
290
+ wsRoutes.push(route);
291
+ }
266
292
  }
267
293
  }
268
294
 
295
+ const allRoutes = [...httpRoutes, ...wsRoutes];
269
296
  // Validate that we have the browsers they are asking for
270
- [...httpRoutes, ...wsRoutes].forEach((route) => {
297
+ allRoutes.forEach((route) => {
271
298
  if (
272
299
  'browser' in route &&
273
300
  route.browser &&
@@ -280,6 +307,17 @@ export class Browserless {
280
307
  }
281
308
  });
282
309
 
310
+ const duplicateNamedRoutes = allRoutes
311
+ .filter((e, i, a) => a.findIndex((r) => r.name === e.name) !== i)
312
+ .map((r) => r.name);
313
+
314
+ if (duplicateNamedRoutes.length) {
315
+ this.debug(
316
+ `Found duplicate routing names. Route names must be unique:`,
317
+ duplicateNamedRoutes,
318
+ );
319
+ }
320
+
283
321
  httpRoutes.forEach((r) => this.router.registerHTTPRoute(r));
284
322
  wsRoutes.forEach((r) => this.router.registerWebSocketRoute(r));
285
323
 
@@ -5,6 +5,6 @@ import {
5
5
  import { ChromiumCDP } from './chromium.cdp.js';
6
6
 
7
7
  export class ChromeCDP extends ChromiumCDP {
8
- protected executablePath = chromeExecutablePath;
8
+ protected executablePath = chromeExecutablePath();
9
9
  protected debug = createLogger('browsers:chrome:cdp');
10
10
  }
@@ -5,6 +5,6 @@ import {
5
5
  import { ChromiumPlaywright } from './chromium.playwright.js';
6
6
 
7
7
  export class ChromePlaywright extends ChromiumPlaywright {
8
- protected executablePath = chromeExecutablePath;
8
+ protected executablePath = chromeExecutablePath();
9
9
  protected debug = createLogger('browsers:chrome:playwright');
10
10
  }
@@ -63,6 +63,10 @@ export class BrowserManager {
63
63
  }
64
64
  };
65
65
 
66
+ protected onNewPage = async (req: Request, page: unknown) => {
67
+ await pageHook({ meta: req.parsed, page });
68
+ };
69
+
66
70
  /**
67
71
  * Returns the /json/protocol API contents from Chromium or Chrome, whichever is installed,
68
72
  * and modifies URLs to set them to the appropriate addresses configured.
@@ -466,7 +470,7 @@ export class BrowserManager {
466
470
  await browserHook({ browser, meta: req.parsed });
467
471
 
468
472
  browser.on('newPage', async (page) => {
469
- await pageHook({ meta: req.parsed, page });
473
+ await this.onNewPage(req, page);
470
474
  (router.onNewPage || noop)(req.parsed || '', page);
471
475
  });
472
476
 
package/src/exports.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Main Files
1
+ // Export all them goods...
2
2
  export * from './browserless.js';
3
3
  export * from './config.js';
4
4
  export * from './constants.js';
@@ -16,8 +16,6 @@ export * from './token.js';
16
16
  export * from './types.js';
17
17
  export * from './utils.js';
18
18
  export * from './webhooks.js';
19
-
20
- // Browsers and Helpers
21
19
  export * from './browsers/index.js';
22
20
  export * from './browsers/chrome.cdp.js';
23
21
  export * from './browsers/chrome.playwright.js';
package/src/limiter.ts CHANGED
@@ -77,6 +77,10 @@ export class Limiter extends q {
77
77
  this.logQueue('All jobs complete.');
78
78
  }
79
79
 
80
+ protected jobEnd(jobInfo: AfterResponse) {
81
+ afterRequest(jobInfo);
82
+ }
83
+
80
84
  protected handleSuccess({ detail: { job } }: { detail: { job: Job } }) {
81
85
  const timeUsed = Date.now() - job.start;
82
86
  this.debug(
@@ -84,7 +88,7 @@ export class Limiter extends q {
84
88
  );
85
89
  this.metrics.addSuccessful(Date.now() - job.start);
86
90
  // @TODO Figure out a better argument handling for jobs
87
- afterRequest({
91
+ this.jobEnd({
88
92
  req: job.args[0],
89
93
  start: job.start,
90
94
  status: 'successful',
@@ -104,7 +108,7 @@ export class Limiter extends q {
104
108
  this.webhooks.callTimeoutAlertURL();
105
109
  this.debug(`Calling timeout handler`);
106
110
  job?.onTimeoutFn(job);
107
- afterRequest({
111
+ this.jobEnd({
108
112
  req: job.args[0],
109
113
  start: job.start,
110
114
  status: 'timedout',
@@ -121,7 +125,7 @@ export class Limiter extends q {
121
125
  this.debug(`Recording failed stat, cleaning up: "${error?.toString()}"`);
122
126
  this.metrics.addError(Date.now() - job.start);
123
127
  this.webhooks.callErrorAlertURL(error?.toString() ?? 'Unknown Error');
124
- afterRequest({
128
+ this.jobEnd({
125
129
  req: job.args[0],
126
130
  start: job.start,
127
131
  status: 'error',
package/src/router.ts CHANGED
@@ -166,7 +166,9 @@ export class Router {
166
166
  : wrapped;
167
167
  route.path = Array.isArray(route.path) ? route.path : [route.path];
168
168
  const registeredPaths = this.httpRoutes.map((r) => r.path).flat();
169
- const duplicatePaths = registeredPaths.filter((path) => route.path.includes(path));
169
+ const duplicatePaths = registeredPaths.filter((path) =>
170
+ route.path.includes(path),
171
+ );
170
172
 
171
173
  if (duplicatePaths.length) {
172
174
  this.log(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
@@ -194,7 +196,9 @@ export class Router {
194
196
  : wrapped;
195
197
  route.path = Array.isArray(route.path) ? route.path : [route.path];
196
198
  const registeredPaths = this.webSocketRoutes.map((r) => r.path).flat();
197
- const duplicatePaths = registeredPaths.filter((path) => route.path.includes(path));
199
+ const duplicatePaths = registeredPaths.filter((path) =>
200
+ route.path.includes(path),
201
+ );
198
202
 
199
203
  if (duplicatePaths.length) {
200
204
  this.log(`Found duplicate routes: ${duplicatePaths.join(', ')}`);
@@ -4,9 +4,14 @@ import {
4
4
  QuerySchema,
5
5
  ResponseSchema,
6
6
  } from '../../../shared/content.http.js';
7
- import { ChromeCDP, HTTPRoutes } from '@browserless.io/browserless';
7
+ import {
8
+ BrowserlessRoutes,
9
+ ChromeCDP,
10
+ HTTPRoutes,
11
+ } from '@browserless.io/browserless';
8
12
 
9
- export default class ChromeContentRoute extends Content {
13
+ export default class ChromeContentPostRoute extends Content {
14
+ name = BrowserlessRoutes.ChromeContentPostRoute;
10
15
  browser = ChromeCDP;
11
16
  path = [HTTPRoutes.chromeContent];
12
17
  }
@@ -4,9 +4,14 @@ import {
4
4
  QuerySchema,
5
5
  ResponseSchema,
6
6
  } from '../../../shared/download.http.js';
7
- import { ChromeCDP, HTTPRoutes } from '@browserless.io/browserless';
7
+ import {
8
+ BrowserlessRoutes,
9
+ ChromeCDP,
10
+ HTTPRoutes,
11
+ } from '@browserless.io/browserless';
8
12
 
9
- export default class ChromeDownloadRoute extends Download {
13
+ export default class ChromeDownloadPostRoute extends Download {
14
+ name = BrowserlessRoutes.ChromeDownloadPostRoute;
10
15
  browser = ChromeCDP;
11
16
  path = [HTTPRoutes.chromeDownload];
12
17
  }
@@ -4,9 +4,14 @@ import {
4
4
  QuerySchema,
5
5
  ResponseSchema,
6
6
  } from '../../../shared/function.http.js';
7
- import { ChromeCDP, HTTPRoutes } from '@browserless.io/browserless';
7
+ import {
8
+ BrowserlessRoutes,
9
+ ChromeCDP,
10
+ HTTPRoutes,
11
+ } from '@browserless.io/browserless';
8
12
 
9
- export default class ChromeFunctionRoute extends Function {
13
+ export default class ChromeFunctionPostRoute extends Function {
14
+ name = BrowserlessRoutes.ChromeFunctionPostRoute;
10
15
  browser = ChromeCDP;
11
16
  path = [HTTPRoutes.chromeFunction];
12
17
  }
@@ -1 +1,7 @@
1
- export { default, ResponseSchema } from '../../../shared/json-list.http.js';
1
+ import { BrowserlessRoutes } from '@browserless.io/browserless';
2
+ export { ResponseSchema } from '../../../shared/json-list.http.js';
3
+ import { default as ChromiumJSONListGetRoute } from '../../../shared/json-list.http.js';
4
+
5
+ export default class ChromeJSONListGetRoute extends ChromiumJSONListGetRoute {
6
+ name = BrowserlessRoutes.ChromeJSONListGetRoute;
7
+ }
@@ -1 +1,7 @@
1
- export { default, ResponseSchema } from '../../../shared/json-new.http.js';
1
+ import { BrowserlessRoutes } from '@browserless.io/browserless';
2
+ export { ResponseSchema } from '../../../shared/json-new.http.js';
3
+ import { default as ChromiumJSONNewPutRoute } from '../../../shared/json-new.http.js';
4
+
5
+ export default class ChromeJSONNewPutRoute extends ChromiumJSONNewPutRoute {
6
+ name = BrowserlessRoutes.ChromeJSONNewPutRoute;
7
+ }