single-file-cli 2.0.69 → 2.0.71
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/build.sh +8 -3
- package/deno.json +3 -3
- package/deno.lock +27 -32
- package/lib/cdp-client.js +151 -34
- package/lib/constants.js +3 -1
- package/lib/single-file-bundle.js +1 -1
- package/lib/version.js +1 -1
- package/options.js +37 -22
- package/package.json +1 -1
- package/single-file-cli-api.js +14 -1
- package/single-file-launcher.js +1 -1
package/build.sh
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
mv package.json package.json.tmp
|
|
4
|
+
mv deno.json deno.json.tmp
|
|
5
|
+
mv deno.lock deno.lock.tmp
|
|
6
|
+
deno install --vendor --quiet "npm:single-file-core@1.5.41"
|
|
7
|
+
mv package.json.tmp package.json
|
|
8
|
+
mv deno.json.tmp deno.json
|
|
9
|
+
mv deno.lock.tmp deno.lock
|
|
4
10
|
|
|
5
11
|
echo "
|
|
6
12
|
import { build } from 'npm:esbuild';
|
|
@@ -82,5 +88,4 @@ const version = JSON.parse(await Deno.readTextFile('./deno.json')).version;
|
|
|
82
88
|
await Deno.writeTextFile('lib/version.js', 'export const version = ' + JSON.stringify(version) + ';');
|
|
83
89
|
" | deno run --allow-read --allow-write --allow-net --allow-run --allow-env --lock=node_modules/deno.lock.tmp -
|
|
84
90
|
|
|
85
|
-
rm -rf node_modules
|
|
86
|
-
rm -rf vendor
|
|
91
|
+
rm -rf node_modules
|
package/deno.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@single-file/single-file-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.71",
|
|
4
4
|
"description": "SingleFile CLI",
|
|
5
|
-
"nodeModulesDir":
|
|
5
|
+
"nodeModulesDir": "auto",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./single-file-cli-api.js"
|
|
8
8
|
},
|
|
9
9
|
"imports": {
|
|
10
10
|
"simple-cdp": "jsr:@simple-cdp/simple-cdp@^1.8.5",
|
|
11
|
-
"path": "jsr:@std/path@^0.
|
|
11
|
+
"path": "jsr:@std/path@^0.224.0"
|
|
12
12
|
}
|
|
13
13
|
}
|
package/deno.lock
CHANGED
|
@@ -1,43 +1,38 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
"version": "4",
|
|
3
|
+
"specifiers": {
|
|
4
|
+
"jsr:@simple-cdp/simple-cdp@^1.8.5": "1.8.5",
|
|
5
|
+
"jsr:@std/assert@0.224": "0.224.0",
|
|
6
|
+
"jsr:@std/path@0.224": "0.224.0",
|
|
7
|
+
"npm:simple-cdp@^1.8.5": "1.8.5",
|
|
8
|
+
"npm:ws@^8.16.0": "8.16.0"
|
|
9
|
+
},
|
|
10
|
+
"jsr": {
|
|
11
|
+
"@simple-cdp/simple-cdp@1.8.5": {
|
|
12
|
+
"integrity": "7386ca561cd6293bb3115eadf14b8c98d1c41c35a69c79774ea70e5101159413"
|
|
13
|
+
},
|
|
14
|
+
"@std/assert@0.224.0": {
|
|
15
|
+
"integrity": "8643233ec7aec38a940a8264a6e3eed9bfa44e7a71cc6b3c8874213ff401967f"
|
|
10
16
|
},
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"jsr:@std/assert@^0.220.1"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
17
|
+
"@std/path@0.224.0": {
|
|
18
|
+
"integrity": "55bca6361e5a6d158b9380e82d4981d82d338ec587de02951e2b7c3a24910ee6",
|
|
19
|
+
"dependencies": [
|
|
20
|
+
"jsr:@std/assert"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"npm": {
|
|
25
|
+
"simple-cdp@1.8.5": {
|
|
26
|
+
"integrity": "sha512-bpXoeCk0mwFrr+8C8vVkhCug5h4HO49GI+MZdnyLQcFVKzTlokrimTjEoc69X2Y2n7mtjzDHTriq6B/kgUeUcA=="
|
|
24
27
|
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"integrity": "sha512-bpXoeCk0mwFrr+8C8vVkhCug5h4HO49GI+MZdnyLQcFVKzTlokrimTjEoc69X2Y2n7mtjzDHTriq6B/kgUeUcA==",
|
|
28
|
-
"dependencies": {}
|
|
29
|
-
},
|
|
30
|
-
"ws@8.16.0": {
|
|
31
|
-
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
|
32
|
-
"dependencies": {}
|
|
33
|
-
}
|
|
28
|
+
"ws@8.16.0": {
|
|
29
|
+
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ=="
|
|
34
30
|
}
|
|
35
31
|
},
|
|
36
|
-
"remote": {},
|
|
37
32
|
"workspace": {
|
|
38
33
|
"dependencies": [
|
|
39
34
|
"jsr:@simple-cdp/simple-cdp@^1.8.5",
|
|
40
|
-
"jsr:@std/path
|
|
35
|
+
"jsr:@std/path@0.224"
|
|
41
36
|
],
|
|
42
37
|
"packageJson": {
|
|
43
38
|
"dependencies": [
|
package/lib/cdp-client.js
CHANGED
|
@@ -28,6 +28,7 @@ import { getScriptSource, getHookScriptSource } from "./single-file-script.js";
|
|
|
28
28
|
import { CDP, options } from "simple-cdp";
|
|
29
29
|
|
|
30
30
|
const LOAD_TIMEOUT_ERROR = "ERR_LOAD_TIMEOUT";
|
|
31
|
+
const CAPTURE_TIMEOUT_ERROR = "ERR_CAPTURE_TIMEOUT";
|
|
31
32
|
const NETWORK_STATES = ["InteractiveTime", "networkIdle", "networkAlmostIdle", "load", "DOMContentLoaded"];
|
|
32
33
|
const MINIMIZED_WINDOW_STATE = "minimized";
|
|
33
34
|
const SINGLE_FILE_WORLD_NAME = "singlefile";
|
|
@@ -50,12 +51,19 @@ async function initialize(singleFileOptions) {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
async function getPageData(options) {
|
|
54
|
+
const debugMessages = [];
|
|
53
55
|
let targetInfo;
|
|
54
56
|
try {
|
|
57
|
+
if (options.debugMessagesFile) {
|
|
58
|
+
debugMessages.push([Date.now(), ["Loading page", EMPTY_PAGE_URL]]);
|
|
59
|
+
}
|
|
55
60
|
targetInfo = await CDP.createTarget(EMPTY_PAGE_URL);
|
|
56
61
|
const consoleMessages = [];
|
|
57
62
|
const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger, Console } = new CDP(targetInfo);
|
|
58
63
|
if (options.consoleMessagesFile) {
|
|
64
|
+
if (options.debugMessagesFile) {
|
|
65
|
+
debugMessages.push([Date.now(), ["Enabling console messages"]]);
|
|
66
|
+
}
|
|
59
67
|
await Console.enable();
|
|
60
68
|
Console.addEventListener("messageAdded", ({ params }) => {
|
|
61
69
|
const { message } = params;
|
|
@@ -65,13 +73,22 @@ async function getPageData(options) {
|
|
|
65
73
|
if (options.browserStartMinimized) {
|
|
66
74
|
const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.id });
|
|
67
75
|
if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
|
|
76
|
+
if (options.debugMessagesFile) {
|
|
77
|
+
debugMessages.push([Date.now(), ["Minimizing window"]]);
|
|
78
|
+
}
|
|
68
79
|
await Browser.setWindowBounds({ windowId, bounds: { windowState: MINIMIZED_WINDOW_STATE } });
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
if (options.browserIgnoreHTTPSErrors !== undefined && options.browserIgnoreHTTPSErrors) {
|
|
83
|
+
if (options.debugMessagesFile) {
|
|
84
|
+
debugMessages.push([Date.now(), ["Ignoring HTTPS errors"]]);
|
|
85
|
+
}
|
|
72
86
|
await Security.setIgnoreCertificateErrors({ ignore: true });
|
|
73
87
|
}
|
|
74
88
|
if (options.browserByPassCSP === undefined || options.browserByPassCSP) {
|
|
89
|
+
if (options.debugMessagesFile) {
|
|
90
|
+
debugMessages.push([Date.now(), ["Bypassing CSP"]]);
|
|
91
|
+
}
|
|
75
92
|
await Page.setBypassCSP({ enabled: true });
|
|
76
93
|
}
|
|
77
94
|
if (options.browserMobileEmulation || options.browserDeviceWidth || options.browserDeviceHeight || options.browserDeviceScaleFactor || options.platform || options.acceptLanguage) {
|
|
@@ -91,12 +108,16 @@ async function getPageData(options) {
|
|
|
91
108
|
const { result } = await Runtime.evaluate({ expression: "window.devicePixelRatio" });
|
|
92
109
|
browserDeviceScaleFactor = result.value;
|
|
93
110
|
}
|
|
94
|
-
|
|
111
|
+
const deviceMetricsOptions = {
|
|
95
112
|
mobile: Boolean(options.browserMobileEmulation),
|
|
96
113
|
width: options.browserDeviceWidth || (options.browserMobileEmulation ? 360 : options.width || browserDeviceWidth),
|
|
97
114
|
height: options.browserDeviceHeight || (options.browserMobileEmulation ? 800 : options.height || browserDeviceHeight),
|
|
98
115
|
deviceScaleFactor: options.browserDeviceScaleFactor || (options.browserMobileEmulation ? 2 : browserDeviceScaleFactor)
|
|
99
|
-
}
|
|
116
|
+
};
|
|
117
|
+
if (options.debugMessagesFile) {
|
|
118
|
+
debugMessages.push([Date.now(), ["Emulating device metrics", JSON.stringify(deviceMetricsOptions)]]);
|
|
119
|
+
}
|
|
120
|
+
await Emulation.setDeviceMetricsOverride(deviceMetricsOptions);
|
|
100
121
|
}
|
|
101
122
|
if (options.browserMobileEmulation || options.platform || options.acceptLanguage) {
|
|
102
123
|
const { userAgent, product } = await Browser.getVersion();
|
|
@@ -109,21 +130,29 @@ async function getPageData(options) {
|
|
|
109
130
|
if (options.platform || options.browserMobileEmulation) {
|
|
110
131
|
agentOptions.platform = options.platform || "Android";
|
|
111
132
|
}
|
|
133
|
+
if (options.debugMessagesFile) {
|
|
134
|
+
debugMessages.push([Date.now(), ["Emulating user agent", JSON.stringify(agentOptions)]]);
|
|
135
|
+
}
|
|
112
136
|
await Emulation.setUserAgentOverride(agentOptions);
|
|
113
137
|
}
|
|
114
138
|
}
|
|
115
139
|
const handleAuthRequests = Boolean(options.httpProxyUsername);
|
|
116
|
-
const patterns = handleAuthRequests ? [{ requestStage: "Request" }, { requestStage: "Response"
|
|
140
|
+
const patterns = handleAuthRequests ? [{ requestStage: "Request" }, { requestStage: "Response" }] : [{ requestStage: "Response" }];
|
|
117
141
|
await Fetch.enable({ handleAuthRequests, patterns });
|
|
118
142
|
if (handleAuthRequests) {
|
|
119
|
-
Fetch.addEventListener("authRequired", ({ params }) =>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
response: "ProvideCredentials",
|
|
123
|
-
username: options.httpProxyUsername,
|
|
124
|
-
password: options.httpProxyPassword
|
|
143
|
+
Fetch.addEventListener("authRequired", async ({ params }) => {
|
|
144
|
+
if (options.debugMessagesFile) {
|
|
145
|
+
debugMessages.push([Date.now(), ["Authenticating"]]);
|
|
125
146
|
}
|
|
126
|
-
|
|
147
|
+
await Fetch.continueWithAuth({
|
|
148
|
+
requestId: params.requestId,
|
|
149
|
+
authChallengeResponse: {
|
|
150
|
+
response: "ProvideCredentials",
|
|
151
|
+
username: options.httpProxyUsername,
|
|
152
|
+
password: options.httpProxyPassword
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
127
156
|
}
|
|
128
157
|
let url = options.url;
|
|
129
158
|
let alternativeUrl = new URL(url);
|
|
@@ -134,12 +163,15 @@ async function getPageData(options) {
|
|
|
134
163
|
let httpInfo;
|
|
135
164
|
Fetch.addEventListener("requestPaused", async ({ params }) => {
|
|
136
165
|
const { requestId, request, resourceType, responseHeaders, responseStatusCode, responseStatusText } = params;
|
|
137
|
-
if (options.outputJson && !httpInfo && (request.url == url || request.url == alternativeUrl) && responseStatusCode !== undefined) {
|
|
166
|
+
if (resourceType == "Document" && (options.outputJson && !httpInfo && (request.url == url || request.url == alternativeUrl) && responseStatusCode !== undefined)) {
|
|
138
167
|
if (REDIRECT_STATUS_CODES.includes(responseStatusCode)) {
|
|
139
168
|
const redirect = responseHeaders.find(header => header.name.toLowerCase() == "location").value;
|
|
140
169
|
if (redirect) {
|
|
141
170
|
url = new URL(redirect, url).href;
|
|
142
171
|
}
|
|
172
|
+
if (options.debugMessagesFile) {
|
|
173
|
+
debugMessages.push([Date.now(), ["Redirecting", url]]);
|
|
174
|
+
}
|
|
143
175
|
} else {
|
|
144
176
|
httpInfo = {
|
|
145
177
|
request: {
|
|
@@ -156,6 +188,18 @@ async function getPageData(options) {
|
|
|
156
188
|
}
|
|
157
189
|
};
|
|
158
190
|
}
|
|
191
|
+
} else if (options.blockedURLPatterns && options.blockedURLPatterns.length) {
|
|
192
|
+
const blockedURL = options.blockedURLPatterns.find(blockedURL => new RegExp(blockedURL).test(request.url));
|
|
193
|
+
if (blockedURL) {
|
|
194
|
+
try {
|
|
195
|
+
if (options.debugMessagesFile) {
|
|
196
|
+
debugMessages.push([Date.now(), ["Blocking request", request.url]]);
|
|
197
|
+
}
|
|
198
|
+
await Fetch.failRequest({ requestId, errorReason: "Aborted" });
|
|
199
|
+
} catch {
|
|
200
|
+
// ignored
|
|
201
|
+
}
|
|
202
|
+
}
|
|
159
203
|
}
|
|
160
204
|
try {
|
|
161
205
|
await Fetch.continueRequest({ requestId });
|
|
@@ -164,10 +208,16 @@ async function getPageData(options) {
|
|
|
164
208
|
}
|
|
165
209
|
});
|
|
166
210
|
if (options.httpHeaders && options.httpHeaders.length) {
|
|
211
|
+
if (options.debugMessagesFile) {
|
|
212
|
+
debugMessages.push([Date.now(), ["Setting HTTP headers", JSON.stringify(options.httpHeaders)]]);
|
|
213
|
+
}
|
|
167
214
|
await Network.setExtraHTTPHeaders({ headers: options.httpHeaders });
|
|
168
215
|
}
|
|
169
216
|
if (options.emulateMediaFeatures) {
|
|
170
217
|
for (const mediaFeature of options.emulateMediaFeatures) {
|
|
218
|
+
if (options.debugMessagesFile) {
|
|
219
|
+
debugMessages.push([Date.now(), ["Emulating media feature", mediaFeature.name, mediaFeature.value]]);
|
|
220
|
+
}
|
|
171
221
|
await Emulation.setEmulatedMedia({
|
|
172
222
|
media: mediaFeature.name,
|
|
173
223
|
features: mediaFeature.value.split(",").map(feature => feature.trim())
|
|
@@ -175,6 +225,9 @@ async function getPageData(options) {
|
|
|
175
225
|
}
|
|
176
226
|
}
|
|
177
227
|
if (options.browserCookies && options.browserCookies.length) {
|
|
228
|
+
if (options.debugMessagesFile) {
|
|
229
|
+
debugMessages.push([Date.now(), ["Setting cookies", JSON.stringify(options.browserCookies)]]);
|
|
230
|
+
}
|
|
178
231
|
await Network.setCookies({ cookies: options.browserCookies });
|
|
179
232
|
}
|
|
180
233
|
await Browser.setDownloadBehavior({ behavior: "deny" });
|
|
@@ -188,7 +241,7 @@ async function getPageData(options) {
|
|
|
188
241
|
worldName: SINGLE_FILE_WORLD_NAME
|
|
189
242
|
});
|
|
190
243
|
const [contextId] = await Promise.all([
|
|
191
|
-
loadPage({ Page, Runtime }, options),
|
|
244
|
+
loadPage({ Page, Runtime }, options, debugMessages),
|
|
192
245
|
options.browserDebug ? waitForDebuggerReady({ Debugger }) : Promise.resolve()
|
|
193
246
|
]);
|
|
194
247
|
await Runtime.addBinding({ name: SET_PAGE_DATA_FUNCTION_NAME, executionContextId: contextId });
|
|
@@ -196,6 +249,9 @@ async function getPageData(options) {
|
|
|
196
249
|
await Runtime.addBinding({ name: CAPTURE_SCREENSHOT_FUNCTION_NAME, executionContextId: contextId });
|
|
197
250
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
198
251
|
if (params.name === CAPTURE_SCREENSHOT_FUNCTION_NAME) {
|
|
252
|
+
if (options.debugMessagesFile) {
|
|
253
|
+
debugMessages.push([Date.now(), ["Capturing screenshot"]]);
|
|
254
|
+
}
|
|
199
255
|
try {
|
|
200
256
|
let screenshotOptions = { captureBeyondViewport: true };
|
|
201
257
|
if (options.embedScreenshotOptions) {
|
|
@@ -218,6 +274,9 @@ async function getPageData(options) {
|
|
|
218
274
|
await Runtime.addBinding({ name: PRINT_TO_PDF_FUNCTION_NAME, executionContextId: contextId });
|
|
219
275
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
220
276
|
if (params.name === PRINT_TO_PDF_FUNCTION_NAME) {
|
|
277
|
+
if (options.debugMessagesFile) {
|
|
278
|
+
debugMessages.push([Date.now(), ["Printing to PDF", options.embedPdfOptions || ""]]);
|
|
279
|
+
}
|
|
221
280
|
let pdfOptions = {};
|
|
222
281
|
if (options.embedPdfOptions) {
|
|
223
282
|
try {
|
|
@@ -243,6 +302,9 @@ async function getPageData(options) {
|
|
|
243
302
|
if (payload.length) {
|
|
244
303
|
pageDataResponse += payload;
|
|
245
304
|
} else {
|
|
305
|
+
if (options.debugMessagesFile) {
|
|
306
|
+
debugMessages.push([Date.now(), ["Setting page data"]]);
|
|
307
|
+
}
|
|
246
308
|
const result = JSON.parse(pageDataResponse);
|
|
247
309
|
if (result.content instanceof Array) {
|
|
248
310
|
result.content = new Uint8Array(result.content);
|
|
@@ -253,36 +315,71 @@ async function getPageData(options) {
|
|
|
253
315
|
});
|
|
254
316
|
});
|
|
255
317
|
if (options.browserWaitDelay) {
|
|
318
|
+
if (options.debugMessagesFile) {
|
|
319
|
+
debugMessages.push([Date.now(), [`Waiting ${options.browserWaitDelay} ms`]]);
|
|
320
|
+
}
|
|
256
321
|
await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
|
|
257
322
|
}
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
323
|
+
const captureTimeoutAbortController = new AbortController();
|
|
324
|
+
const captureTimeoutAbortSignal = captureTimeoutAbortController.signal;
|
|
325
|
+
try {
|
|
326
|
+
if (options.debugMessagesFile) {
|
|
327
|
+
debugMessages.push([Date.now(), ["Capturing page"]]);
|
|
328
|
+
}
|
|
329
|
+
const { result } = await Promise.race([
|
|
330
|
+
Runtime.evaluate({
|
|
331
|
+
expression: `(${getPageDataScriptSource.toString()})(${JSON.stringify(options)},${JSON.stringify([SET_SCREENSHOT_FUNCTION_NAME, SET_PDF_FUNCTION_NAME, SET_PAGE_DATA_FUNCTION_NAME, CAPTURE_SCREENSHOT_FUNCTION_NAME, PRINT_TO_PDF_FUNCTION_NAME])})`,
|
|
332
|
+
awaitPromise: true,
|
|
333
|
+
returnByValue: true,
|
|
334
|
+
contextId
|
|
335
|
+
}),
|
|
336
|
+
waitForTimeout(captureTimeoutAbortSignal, options.browserCaptureMaxTime, "Capture timeout", CAPTURE_TIMEOUT_ERROR)
|
|
337
|
+
]);
|
|
338
|
+
const { subtype, description } = result;
|
|
339
|
+
if (subtype === "error") {
|
|
340
|
+
throw new Error(description);
|
|
341
|
+
}
|
|
342
|
+
} finally {
|
|
343
|
+
if (!captureTimeoutAbortSignal.aborted) {
|
|
344
|
+
captureTimeoutAbortController.abort();
|
|
345
|
+
}
|
|
346
|
+
await Runtime.disable();
|
|
347
|
+
await Page.disable();
|
|
267
348
|
}
|
|
268
349
|
const pageData = await pageDataPromise;
|
|
269
350
|
if (options.consoleMessagesFile) {
|
|
270
351
|
await Console.disable();
|
|
271
352
|
pageData.consoleMessages = consoleMessages;
|
|
272
353
|
}
|
|
354
|
+
if (options.debugMessagesFile) {
|
|
355
|
+
pageData.debugMessages = debugMessages;
|
|
356
|
+
debugMessages.push([Date.now(), ["Returning page data"]]);
|
|
357
|
+
}
|
|
273
358
|
Object.assign(pageData, httpInfo);
|
|
274
359
|
return pageData;
|
|
275
360
|
} catch (error) {
|
|
276
361
|
if (error.code === LOAD_TIMEOUT_ERROR && options.browserWaitUntilFallback && options.browserWaitUntil) {
|
|
277
362
|
const browserWaitUntil = NETWORK_STATES[(NETWORK_STATES.indexOf(options.browserWaitUntil) + 1)];
|
|
278
363
|
if (browserWaitUntil) {
|
|
364
|
+
if (options.debugMessagesFile) {
|
|
365
|
+
debugMessages.push([Date.now(), ["Retrying with waitUntil", browserWaitUntil]]);
|
|
366
|
+
}
|
|
279
367
|
options.browserWaitUntil = browserWaitUntil;
|
|
280
368
|
await closeTarget();
|
|
281
369
|
return await getPageData(options);
|
|
282
370
|
}
|
|
283
371
|
}
|
|
372
|
+
if (options.consoleMessagesFile) {
|
|
373
|
+
error.consoleMessages = consoleMessages;
|
|
374
|
+
}
|
|
375
|
+
if (options.debugMessagesFile) {
|
|
376
|
+
error.debugMessages = debugMessages;
|
|
377
|
+
}
|
|
284
378
|
throw error;
|
|
285
379
|
} finally {
|
|
380
|
+
if (options.debugMessagesFile) {
|
|
381
|
+
debugMessages.push([Date.now(), ["Closing page"]]);
|
|
382
|
+
}
|
|
286
383
|
await closeTarget();
|
|
287
384
|
}
|
|
288
385
|
|
|
@@ -335,15 +432,18 @@ function getPageDataScriptSource(options, [SET_SCREENSHOT_FUNCTION_NAME, SET_PDF
|
|
|
335
432
|
});
|
|
336
433
|
}
|
|
337
434
|
|
|
338
|
-
async function loadPage({ Page, Runtime }, options) {
|
|
435
|
+
async function loadPage({ Page, Runtime }, options, debugMessages) {
|
|
339
436
|
await Runtime.enable();
|
|
340
437
|
await Page.enable();
|
|
341
438
|
const loadTimeoutAbortController = new AbortController();
|
|
342
439
|
const loadTimeoutAbortSignal = loadTimeoutAbortController.signal;
|
|
343
440
|
try {
|
|
441
|
+
if (options.debugMessagesFile) {
|
|
442
|
+
debugMessages.push([Date.now(), ["Loading page", options.url]]);
|
|
443
|
+
}
|
|
344
444
|
const [contextId] = await Promise.race([
|
|
345
|
-
Promise.all([getTopFrameContextId({ Page, Runtime }, options), Page.navigate({ url: options.url })]),
|
|
346
|
-
|
|
445
|
+
Promise.all([getTopFrameContextId({ Page, Runtime }, options, debugMessages), Page.navigate({ url: options.url })]),
|
|
446
|
+
waitForTimeout(loadTimeoutAbortSignal, options.browserLoadMaxTime, "Load timeout", LOAD_TIMEOUT_ERROR)
|
|
347
447
|
]);
|
|
348
448
|
return contextId;
|
|
349
449
|
} finally {
|
|
@@ -355,13 +455,16 @@ async function loadPage({ Page, Runtime }, options) {
|
|
|
355
455
|
}
|
|
356
456
|
}
|
|
357
457
|
|
|
358
|
-
async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
458
|
+
async function getTopFrameContextId({ Page, Runtime }, options, debugMessages) {
|
|
359
459
|
const CONTEXT_CREATED_EVENT = "executionContextCreated";
|
|
360
460
|
const contextIds = [];
|
|
361
461
|
let topFrameId;
|
|
362
462
|
try {
|
|
363
463
|
Runtime.addEventListener(CONTEXT_CREATED_EVENT, onExecutionContextCreated);
|
|
364
464
|
await waitForPageReady({ Page }, options);
|
|
465
|
+
if (options.debugMessagesFile) {
|
|
466
|
+
debugMessages.push([Date.now(), ["Getting execution context"]]);
|
|
467
|
+
}
|
|
365
468
|
const contextId = await getContextId();
|
|
366
469
|
if (contextId === undefined) {
|
|
367
470
|
throw new Error("Execution context not found");
|
|
@@ -392,12 +495,23 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
392
495
|
|
|
393
496
|
function onLifecycleEvent({ params }) {
|
|
394
497
|
const { frameId, name } = params;
|
|
395
|
-
if (frameId === topFrameId
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
498
|
+
if (frameId === topFrameId) {
|
|
499
|
+
if (options.debugMessagesFile) {
|
|
500
|
+
debugMessages.push([Date.now(), ["Detecting lifecycle event", name]]);
|
|
501
|
+
}
|
|
502
|
+
if (name === options.browserWaitUntil || (resolveCallbackTimeout && NETWORK_STATES.indexOf(name) < NETWORK_STATES.indexOf(options.browserWaitUntil))) {
|
|
503
|
+
clearTimeout(resolveCallbackTimeout);
|
|
504
|
+
if (options.debugMessagesFile) {
|
|
505
|
+
debugMessages.push([Date.now(), [`Waiting ${options.browserWaitUntilDelay} ms`]]);
|
|
506
|
+
}
|
|
507
|
+
setTimeout(() => {
|
|
508
|
+
if (options.debugMessagesFile) {
|
|
509
|
+
debugMessages.push([Date.now(), ["Detecting page ready"]]);
|
|
510
|
+
}
|
|
511
|
+
removeListeners();
|
|
512
|
+
resolve();
|
|
513
|
+
}, options.browserWaitUntilDelay);
|
|
514
|
+
}
|
|
401
515
|
}
|
|
402
516
|
}
|
|
403
517
|
|
|
@@ -409,6 +523,9 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
409
523
|
removeListeners();
|
|
410
524
|
reject(new Error("Unreachable URL: " + frame.unreachableUrl));
|
|
411
525
|
} else {
|
|
526
|
+
if (options.debugMessagesFile) {
|
|
527
|
+
debugMessages.push([Date.now(), ["Detecting top frame ID"]]);
|
|
528
|
+
}
|
|
412
529
|
topFrameId = frame.id;
|
|
413
530
|
}
|
|
414
531
|
}
|
|
@@ -452,14 +569,14 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
452
569
|
}
|
|
453
570
|
}
|
|
454
571
|
|
|
455
|
-
function
|
|
572
|
+
function waitForTimeout(abortSignal, maxDelay, errorMessage, errorCode) {
|
|
456
573
|
return new Promise((resolve, reject) => {
|
|
457
574
|
const ABORT_EVENT = "abort";
|
|
458
575
|
abortSignal.addEventListener(ABORT_EVENT, onAbort);
|
|
459
576
|
const timeoutId = setTimeout(() => {
|
|
460
577
|
abortSignal.removeEventListener(ABORT_EVENT, onAbort);
|
|
461
|
-
const error = new Error(
|
|
462
|
-
error.code =
|
|
578
|
+
const error = new Error(errorMessage);
|
|
579
|
+
error.code = errorCode;
|
|
463
580
|
reject(error);
|
|
464
581
|
}, maxDelay);
|
|
465
582
|
|
package/lib/constants.js
CHANGED