browserless 10.10.0 → 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",
3
3
  "description": "The headless Chrome/Chromium driver on top of Puppeteer. Take screenshots, generate PDFs, extract text and HTML with a production-ready API.",
4
4
  "homepage": "https://browserless.js.org",
5
- "version": "10.10.0",
5
+ "version": "10.10.2",
6
6
  "main": "src/index.js",
7
7
  "author": {
8
8
  "email": "hello@microlink.io",
@@ -34,10 +34,10 @@
34
34
  "javascript"
35
35
  ],
36
36
  "dependencies": {
37
- "@browserless/errors": "^10.9.18",
38
- "@browserless/goto": "^10.10.0",
39
- "@browserless/pdf": "^10.10.0",
40
- "@browserless/screenshot": "^10.10.0",
37
+ "@browserless/errors": "^10.10.1",
38
+ "@browserless/goto": "^10.10.2",
39
+ "@browserless/pdf": "^10.10.2",
40
+ "@browserless/screenshot": "^10.10.2",
41
41
  "debug-logfmt": "~1.4.7",
42
42
  "kill-process-group": "~1.0.13",
43
43
  "p-reflect": "~2.1.0",
@@ -67,5 +67,5 @@
67
67
  "timeout": "2m",
68
68
  "workerThreads": false
69
69
  },
70
- "gitHead": "9b80e677418f2defb804d39043680fe65e3e277b"
70
+ "gitHead": "ec6a614923a1a692bd717ecc8e6f1b09417801d9"
71
71
  }
package/src/driver.js CHANGED
@@ -71,16 +71,27 @@ const getPid = subprocess => {
71
71
 
72
72
  const close = async (subprocess, { signal = 'SIGKILL', ...debugOpts } = {}) => {
73
73
  const pid = getPid(subprocess)
74
- if (pid === undefined) return
74
+ const hasDisconnect = subprocess && typeof subprocess.disconnect === 'function'
75
+ const hasClose = subprocess && typeof subprocess.close === 'function'
76
+
77
+ if (pid === undefined && !hasDisconnect && !hasClose) return
75
78
 
76
79
  // It's necessary to call `browser.close` for removing temporal files associated
77
80
  // and remove listeners attached to the main process; check
78
81
  // - https://github.com/puppeteer/puppeteer/blob/778ac92469d66c542c3c12fe0aa23703dd6315c2/src/node/BrowserRunner.ts#L146
79
82
  // - https://github.com/puppeteer/puppeteer/blob/69d85e874416d62de6e821bef30e5cebcfd42f15/src/node/BrowserRunner.ts#L189
80
- await pReflect('close' in subprocess ? subprocess.close() : killProcessGroup(subprocess, signal))
83
+ await pReflect(
84
+ pid === undefined
85
+ ? hasDisconnect
86
+ ? subprocess.disconnect()
87
+ : subprocess.close()
88
+ : hasClose
89
+ ? subprocess.close()
90
+ : killProcessGroup(subprocess, signal)
91
+ )
81
92
 
82
93
  debug('close', { pid, signal, ...debugOpts })
83
- return { pid }
94
+ return pid === undefined ? {} : { pid }
84
95
  }
85
96
 
86
97
  module.exports = { spawn, pid: getPid, close, defaultArgs }
package/src/index.js CHANGED
@@ -14,9 +14,8 @@ const { AbortError } = pRetry
14
14
 
15
15
  const driver = require('./driver')
16
16
 
17
- const lock = withLock()
18
-
19
17
  module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
18
+ const lock = withLock()
20
19
  const goto = createGoto({ timeout: globalTimeout, ...launchOpts })
21
20
  const { defaultViewport } = goto
22
21
 
@@ -75,22 +74,22 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
75
74
  const createContext = async ({ retry = 2, timeout: contextTimeout, ...contextOpts } = {}) => {
76
75
  let _contextPromise = createBrowserContext(contextOpts)
77
76
  let isDestroyedForced = false
77
+ const pageMetadata = new WeakMap()
78
78
 
79
79
  const getBrowserContext = () => _contextPromise
80
80
 
81
81
  const createPage = async name => {
82
82
  const duration = debug.duration('createPage')
83
- const [browserProcess, browserContext] = await Promise.all([
84
- getBrowser(),
85
- getBrowserContext()
86
- ])
83
+ const browserContext = await getBrowserContext()
87
84
  const page = await browserContext.newPage()
88
- duration({
89
- name,
85
+ const browser = typeof page.browser === 'function' ? page.browser() : undefined
86
+ const metadata = {
90
87
  id: page._client().id(),
91
88
  contextId: browserContext.id,
92
- browserPid: driver.pid(browserProcess)
93
- })
89
+ browserPid: browser ? driver.pid(browser) : undefined
90
+ }
91
+ pageMetadata.set(page, metadata)
92
+ duration({ name, ...metadata })
94
93
  return page
95
94
  }
96
95
 
@@ -98,17 +97,9 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
98
97
  if (page && !page.isClosed()) {
99
98
  const duration = debug.duration('closePage')
100
99
  if (page.disableAdblock) page.disableAdblock()
101
- const [browserProcess, browserContext] = await Promise.all([
102
- getBrowser(),
103
- getBrowserContext(),
104
- pReflect(page.close())
105
- ])
106
- duration({
107
- name,
108
- id: page._client().id(),
109
- contextId: browserContext.id,
110
- browserPid: driver.pid(browserProcess)
111
- })
100
+ await pReflect(page.close())
101
+ duration({ name, ...(pageMetadata.get(page) || {}) })
102
+ pageMetadata.delete(page)
112
103
  }
113
104
  }
114
105
 
@@ -120,16 +111,25 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
120
111
 
121
112
  async function run () {
122
113
  let page
114
+ let closePageTimeout
123
115
 
124
116
  try {
125
117
  page = await createPage(name)
126
- setTimeout(() => closePage(page, name), timeout).unref()
118
+ closePageTimeout = setTimeout(() => {
119
+ closePage(page, name).catch(error => {
120
+ const { message, code, name } = ensureError(error)
121
+ debug('closePage:timeout:error', { message, code, name })
122
+ })
123
+ }, timeout)
124
+ if (typeof closePageTimeout.unref === 'function') closePageTimeout.unref()
127
125
  const value = await fn(page, goto)(...args)
128
126
  await closePage(page, `${name}:success`)
129
127
  return value
130
128
  } catch (error) {
131
129
  await closePage(page, `${name}:error`)
132
130
  if (!isRejected) throw ensureError(error)
131
+ } finally {
132
+ if (closePageTimeout) clearTimeout(closePageTimeout)
133
133
  }
134
134
  }
135
135
 
@@ -140,9 +140,9 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
140
140
  debug('onFailedAttempt', { name: error.name, code: error.code, isRejected })
141
141
  if (error.name === 'AbortError') throw error
142
142
  if (isRejected || isDestroyedForced) throw new AbortError()
143
- if (error.code === 'EBRWSRCONTEXTCONNRESET') {
144
- _contextPromise = createBrowserContext(contextOpts)
145
- }
143
+ const isRetryable = error.code === 'EBRWSRCONTEXTCONNRESET'
144
+ if (!isRetryable) throw error
145
+ _contextPromise = createBrowserContext(contextOpts)
146
146
  const { message, attemptNumber, retriesLeft } = error
147
147
  debug('retry', { attemptNumber, retriesLeft, message })
148
148
  }