diff --git a/packages/function/package.json b/packages/function/package.json index d03d765d5..8d6218423 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -30,7 +30,7 @@ ], "dependencies": { "@browserless/errors": "^10.9.7", - "isolated-function": "~0.1.39", + "isolated-function": "~0.1.46", "require-one-of": "~1.0.24" }, "devDependencies": { diff --git a/packages/function/src/function.js b/packages/function/src/function.js index 8e223e008..57f361569 100644 --- a/packages/function/src/function.js +++ b/packages/function/src/function.js @@ -3,8 +3,12 @@ const isolatedFunction = require('isolated-function') const template = require('./template') +const [nodeMajor] = process.version.slice(1).split('.').map(Number) + module.exports = async ({ url, code, vmOpts, browserWSEndpoint, ...opts }) => { - const [fn, teardown] = isolatedFunction(template(code), { ...vmOpts, throwError: false }) + const needsNetwork = template.isUsingPage(code) + const allow = needsNetwork && nodeMajor >= 25 ? ['net'] : [] + const [fn, teardown] = isolatedFunction(template(code), { ...vmOpts, allow, throwError: false }) const result = await fn(url, browserWSEndpoint, opts) await teardown() return result diff --git a/packages/function/src/index.js b/packages/function/src/index.js index 3e9948942..d1cd07475 100644 --- a/packages/function/src/index.js +++ b/packages/function/src/index.js @@ -24,6 +24,10 @@ module.exports = return browserless.withPage((page, goto) => async () => { const { device } = await goto(page, { url, timeout, ...gotoOpts }) + + const browserWSEndpoint = (await browserless.browser()).wsEndpoint() + if (!browserWSEndpoint) throw new Error('Browser WebSocket endpoint not found') + const result = await runFunction({ url, code: stringify(fn), diff --git a/packages/function/src/template.js b/packages/function/src/template.js index da81adad6..253fcaf04 100644 --- a/packages/function/src/template.js +++ b/packages/function/src/template.js @@ -3,30 +3,34 @@ const walk = require('acorn-walk') const acorn = require('acorn') -module.exports = code => { +const isUsingPage = code => { const ast = acorn.parse(code, { ecmaVersion: 2023, sourceType: 'module' }) - let isUsingPage = false + let result = false walk.simple(ast, { ObjectPattern (node) { node.properties.forEach(prop => { if (prop.type === 'Property' && prop.key.name === 'page') { - isUsingPage = true + result = true } if (prop.type === 'RestElement' && prop.argument.name === 'page') { - isUsingPage = true + result = true } }) }, MemberExpression (node) { if (node.property.name === 'page' || node.property.value === 'page') { - isUsingPage = true + result = true } } }) - if (!isUsingPage) return `async (url, _, opts) => (${code})(opts)` + return result +} + +const template = code => { + if (!isUsingPage(code)) return `async (url, _, opts) => (${code})(opts)` return ` async (url, browserWSEndpoint, opts) => { const puppeteer = require('@cloudflare/puppeteer') @@ -40,3 +44,6 @@ module.exports = code => { } }` } + +module.exports = template +module.exports.isUsingPage = isUsingPage diff --git a/packages/function/test/index.js b/packages/function/test/index.js index fa01dd7f7..a82ab0156 100644 --- a/packages/function/test/index.js +++ b/packages/function/test/index.js @@ -267,3 +267,17 @@ test('interact with npm modules', async t => { t.true(!!profiling) t.true(!!logging) }) + +test('throws error when browser is launched with pipe mode', async t => { + const createTestUtil = require('@browserless/test/util/create') + const { getBrowser } = createTestUtil({ pipe: true }) + + const code = ({ page }) => page.title() + + const myFn = browserlessFunction(code, { + getBrowserless: () => getBrowser() + }) + + const error = await t.throwsAsync(myFn(fileUrl)) + t.is(error.message, 'Browser WebSocket endpoint not found') +})