@browserless/function 10.9.18 → 10.10.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@browserless/function",
3
3
  "description": "Execute arbitrary JavaScript code in a secure browser sandbox with access to page DOM and network.",
4
4
  "homepage": "https://browserless.js.org",
5
- "version": "10.9.18",
5
+ "version": "10.10.2",
6
6
  "main": "src/index.js",
7
7
  "author": {
8
8
  "email": "hello@microlink.io",
@@ -31,7 +31,7 @@
31
31
  "isolate"
32
32
  ],
33
33
  "dependencies": {
34
- "@browserless/errors": "^10.9.18",
34
+ "@browserless/errors": "^10.10.1",
35
35
  "isolated-function": "~0.1.48",
36
36
  "require-one-of": "~1.0.24"
37
37
  },
@@ -57,5 +57,5 @@
57
57
  "timeout": "2m",
58
58
  "workerThreads": false
59
59
  },
60
- "gitHead": "f5e8cd0788e4bad3b3ad9b007943754f96653817"
60
+ "gitHead": "ec6a614923a1a692bd717ecc8e6f1b09417801d9"
61
61
  }
package/src/function.js CHANGED
@@ -5,10 +5,17 @@ const template = require('./template')
5
5
 
6
6
  const [nodeMajor] = process.version.slice(1).split('.').map(Number)
7
7
 
8
- module.exports = async ({ url, code, vmOpts, browserWSEndpoint, ...opts }) => {
9
- const needsNetwork = template.isUsingPage(code)
8
+ module.exports = async ({
9
+ url,
10
+ code,
11
+ vmOpts,
12
+ browserWSEndpoint,
13
+ needsNetwork = template.isUsingPage(code),
14
+ source = template(code, needsNetwork),
15
+ ...opts
16
+ }) => {
10
17
  const permissions = needsNetwork && nodeMajor >= 25 ? ['net'] : []
11
- const [fn, teardown] = isolatedFunction(template(code), {
18
+ const [fn, teardown] = isolatedFunction(source, {
12
19
  ...vmOpts,
13
20
  allow: { permissions },
14
21
  throwError: false
@@ -17,3 +24,6 @@ module.exports = async ({ url, code, vmOpts, browserWSEndpoint, ...opts }) => {
17
24
  await teardown()
18
25
  return result
19
26
  }
27
+
28
+ module.exports.isUsingPage = template.isUsingPage
29
+ module.exports.buildTemplate = template
package/src/index.js CHANGED
@@ -6,40 +6,68 @@ const runFunction = require('./function')
6
6
 
7
7
  const stringify = fn => fn.toString().trim().replace(/;$/, '')
8
8
 
9
- module.exports =
10
- (
11
- fn,
12
- {
13
- getBrowserless = requireOneOf(['browserless']),
14
- retry = 2,
15
- timeout = 30000,
16
- gotoOpts,
17
- ...opts
18
- } = {}
19
- ) =>
20
- async (url, fnOpts = {}) => {
21
- const browserlessPromise = getBrowserless()
22
- const browser = await browserlessPromise
23
- const browserless = await browser.createContext()
24
-
25
- return browserless.withPage((page, goto) => async () => {
26
- const { device } = await goto(page, { url, timeout, ...gotoOpts })
27
-
28
- const browserWSEndpoint = (await browserless.browser()).wsEndpoint()
29
- if (!browserWSEndpoint) throw new Error('Browser WebSocket endpoint not found')
9
+ module.exports = (
10
+ fn,
11
+ {
12
+ getBrowserless = requireOneOf(['browserless']),
13
+ retry = 2,
14
+ timeout = 30000,
15
+ gotoOpts,
16
+ ...opts
17
+ } = {}
18
+ ) => {
19
+ const code = stringify(fn)
20
+ const needsNetwork = runFunction.isUsingPage(code)
21
+ const source = runFunction.buildTemplate(code, needsNetwork)
22
+ let browserPromise
30
23
 
31
- const result = await runFunction({
32
- url,
33
- code: stringify(fn),
34
- browserWSEndpoint: (await browserless.browser()).wsEndpoint(),
35
- device,
36
- ...opts,
37
- ...fnOpts
38
- })
39
-
40
- if (result.isFulfilled) return result
41
- const error = ensureError(result.value)
42
- if (isBrowserlessError(error)) throw error
43
- return result
44
- })()
24
+ const getBrowser = async () => {
25
+ if (!browserPromise) {
26
+ browserPromise = Promise.resolve(getBrowserless()).catch(error => {
27
+ browserPromise = undefined
28
+ throw error
29
+ })
45
30
  }
31
+ return browserPromise
32
+ }
33
+
34
+ return async (url, fnOpts = {}) => {
35
+ const browser = await getBrowser()
36
+ const browserless = await browser.createContext()
37
+
38
+ return browserless.withPage((page, goto) => async () => {
39
+ const { device } = await goto(page, { url, timeout, ...gotoOpts })
40
+
41
+ const runFunctionOpts = {
42
+ url,
43
+ code,
44
+ device,
45
+ ...opts,
46
+ ...fnOpts
47
+ }
48
+
49
+ if (runFunctionOpts.code === code) {
50
+ runFunctionOpts.needsNetwork = needsNetwork
51
+ runFunctionOpts.source = source
52
+ }
53
+
54
+ if (runFunctionOpts.needsNetwork !== false) {
55
+ const browserFromPage = typeof page.browser === 'function' ? page.browser() : undefined
56
+ const browserWSEndpoint =
57
+ browserFromPage && typeof browserFromPage.wsEndpoint === 'function'
58
+ ? browserFromPage.wsEndpoint()
59
+ : undefined
60
+
61
+ if (!browserWSEndpoint) throw new Error('Browser WebSocket endpoint not found')
62
+ runFunctionOpts.browserWSEndpoint = browserWSEndpoint
63
+ }
64
+
65
+ const result = await runFunction(runFunctionOpts)
66
+
67
+ if (result.isFulfilled) return result
68
+ const error = ensureError(result.value)
69
+ if (isBrowserlessError(error)) throw error
70
+ return result
71
+ })()
72
+ }
73
+ }
package/src/template.js CHANGED
@@ -29,8 +29,8 @@ const isUsingPage = code => {
29
29
  return result
30
30
  }
31
31
 
32
- const template = code => {
33
- if (!isUsingPage(code)) return `async (url, _, opts) => (${code})(opts)`
32
+ const template = (code, usesPage = isUsingPage(code)) => {
33
+ if (!usesPage) return `async (url, _, opts) => (${code})(opts)`
34
34
  return `
35
35
  async (url, browserWSEndpoint, opts) => {
36
36
  const puppeteer = require('@cloudflare/puppeteer')