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 +6 -6
- package/src/driver.js +14 -3
- package/src/index.js +25 -25
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.
|
|
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.
|
|
38
|
-
"@browserless/goto": "^10.10.
|
|
39
|
-
"@browserless/pdf": "^10.10.
|
|
40
|
-
"@browserless/screenshot": "^10.10.
|
|
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": "
|
|
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
|
-
|
|
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(
|
|
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
|
|
84
|
-
getBrowser(),
|
|
85
|
-
getBrowserContext()
|
|
86
|
-
])
|
|
83
|
+
const browserContext = await getBrowserContext()
|
|
87
84
|
const page = await browserContext.newPage()
|
|
88
|
-
|
|
89
|
-
|
|
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(
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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(() =>
|
|
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
|
-
|
|
144
|
-
|
|
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
|
}
|