@browserless/function 10.10.1 → 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 +2 -2
- package/src/function.js +13 -3
- package/src/index.js +63 -35
- package/src/template.js +2 -2
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.10.
|
|
5
|
+
"version": "10.10.2",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"author": {
|
|
8
8
|
"email": "hello@microlink.io",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"timeout": "2m",
|
|
58
58
|
"workerThreads": false
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
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 ({
|
|
9
|
-
|
|
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(
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 (!
|
|
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')
|