single-file-cli 2.0.68 → 2.0.70
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/README.MD +1 -1
- package/build.sh +8 -3
- package/deno.json +2 -2
- package/lib/browser.js +2 -2
- package/lib/cdp-client.js +140 -25
- package/lib/constants.js +3 -1
- package/lib/deno-polyfill.js +3 -1
- package/lib/single-file-bundle.js +1 -1
- package/lib/single-file-script.js +1 -1
- package/lib/version.js +1 -1
- package/options.js +86 -43
- package/package.json +1 -1
- package/single-file-cli-api.js +30 -7
- package/single-file-launcher.js +56 -3
package/README.MD
CHANGED
|
@@ -65,7 +65,7 @@ Make sure Chrome or a Chromium-based browser is installed in the default folder.
|
|
|
65
65
|
|
|
66
66
|
- There are 3 ways to download the code of SingleFile, choose the one you prefer:
|
|
67
67
|
|
|
68
|
-
- Install with `npm` (`npm`
|
|
68
|
+
- Install with `npm` and run `single-file` via `npx` (`npm` and `npx` are installed with Node.js)
|
|
69
69
|
|
|
70
70
|
```sh
|
|
71
71
|
npm install "single-file-cli"
|
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.40"
|
|
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
package/lib/browser.js
CHANGED
|
@@ -92,7 +92,7 @@ async function launchBrowser(options = {}, indexPath = 0) {
|
|
|
92
92
|
async function getDebugPort(port = getRandomDebugPort(), usedPorts = []) {
|
|
93
93
|
try {
|
|
94
94
|
await fetch("http://localhost:" + port + "/json/version");
|
|
95
|
-
} catch
|
|
95
|
+
} catch {
|
|
96
96
|
return port;
|
|
97
97
|
}
|
|
98
98
|
if (usedPorts.length < DEBUG_PORT_RANGE) {
|
|
@@ -121,7 +121,7 @@ async function closeBrowser() {
|
|
|
121
121
|
try {
|
|
122
122
|
await remove(profilePath, { recursive: true });
|
|
123
123
|
profilePath = undefined;
|
|
124
|
-
} catch
|
|
124
|
+
} catch {
|
|
125
125
|
console.log("Warning: failed to remove profile directory: " + profilePath); // eslint-disable-line no-console
|
|
126
126
|
}
|
|
127
127
|
}
|
package/lib/cdp-client.js
CHANGED
|
@@ -50,12 +50,19 @@ async function initialize(singleFileOptions) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
async function getPageData(options) {
|
|
53
|
+
const debugMessages = [];
|
|
53
54
|
let targetInfo;
|
|
54
55
|
try {
|
|
56
|
+
if (options.debugMessagesFile) {
|
|
57
|
+
debugMessages.push([Date.now(), ["Loading page", EMPTY_PAGE_URL]]);
|
|
58
|
+
}
|
|
55
59
|
targetInfo = await CDP.createTarget(EMPTY_PAGE_URL);
|
|
56
60
|
const consoleMessages = [];
|
|
57
61
|
const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger, Console } = new CDP(targetInfo);
|
|
58
62
|
if (options.consoleMessagesFile) {
|
|
63
|
+
if (options.debugMessagesFile) {
|
|
64
|
+
debugMessages.push([Date.now(), ["Enabling console messages"]]);
|
|
65
|
+
}
|
|
59
66
|
await Console.enable();
|
|
60
67
|
Console.addEventListener("messageAdded", ({ params }) => {
|
|
61
68
|
const { message } = params;
|
|
@@ -65,13 +72,22 @@ async function getPageData(options) {
|
|
|
65
72
|
if (options.browserStartMinimized) {
|
|
66
73
|
const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.id });
|
|
67
74
|
if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
|
|
75
|
+
if (options.debugMessagesFile) {
|
|
76
|
+
debugMessages.push([Date.now(), ["Minimizing window"]]);
|
|
77
|
+
}
|
|
68
78
|
await Browser.setWindowBounds({ windowId, bounds: { windowState: MINIMIZED_WINDOW_STATE } });
|
|
69
79
|
}
|
|
70
80
|
}
|
|
71
81
|
if (options.browserIgnoreHTTPSErrors !== undefined && options.browserIgnoreHTTPSErrors) {
|
|
82
|
+
if (options.debugMessagesFile) {
|
|
83
|
+
debugMessages.push([Date.now(), ["Ignoring HTTPS errors"]]);
|
|
84
|
+
}
|
|
72
85
|
await Security.setIgnoreCertificateErrors({ ignore: true });
|
|
73
86
|
}
|
|
74
87
|
if (options.browserByPassCSP === undefined || options.browserByPassCSP) {
|
|
88
|
+
if (options.debugMessagesFile) {
|
|
89
|
+
debugMessages.push([Date.now(), ["Bypassing CSP"]]);
|
|
90
|
+
}
|
|
75
91
|
await Page.setBypassCSP({ enabled: true });
|
|
76
92
|
}
|
|
77
93
|
if (options.browserMobileEmulation || options.browserDeviceWidth || options.browserDeviceHeight || options.browserDeviceScaleFactor || options.platform || options.acceptLanguage) {
|
|
@@ -91,12 +107,16 @@ async function getPageData(options) {
|
|
|
91
107
|
const { result } = await Runtime.evaluate({ expression: "window.devicePixelRatio" });
|
|
92
108
|
browserDeviceScaleFactor = result.value;
|
|
93
109
|
}
|
|
94
|
-
|
|
110
|
+
const deviceMetricsOptions = {
|
|
95
111
|
mobile: Boolean(options.browserMobileEmulation),
|
|
96
112
|
width: options.browserDeviceWidth || (options.browserMobileEmulation ? 360 : options.width || browserDeviceWidth),
|
|
97
113
|
height: options.browserDeviceHeight || (options.browserMobileEmulation ? 800 : options.height || browserDeviceHeight),
|
|
98
114
|
deviceScaleFactor: options.browserDeviceScaleFactor || (options.browserMobileEmulation ? 2 : browserDeviceScaleFactor)
|
|
99
|
-
}
|
|
115
|
+
};
|
|
116
|
+
if (options.debugMessagesFile) {
|
|
117
|
+
debugMessages.push([Date.now(), ["Emulating device metrics", JSON.stringify(deviceMetricsOptions)]]);
|
|
118
|
+
}
|
|
119
|
+
await Emulation.setDeviceMetricsOverride(deviceMetricsOptions);
|
|
100
120
|
}
|
|
101
121
|
if (options.browserMobileEmulation || options.platform || options.acceptLanguage) {
|
|
102
122
|
const { userAgent, product } = await Browser.getVersion();
|
|
@@ -109,21 +129,29 @@ async function getPageData(options) {
|
|
|
109
129
|
if (options.platform || options.browserMobileEmulation) {
|
|
110
130
|
agentOptions.platform = options.platform || "Android";
|
|
111
131
|
}
|
|
132
|
+
if (options.debugMessagesFile) {
|
|
133
|
+
debugMessages.push([Date.now(), ["Emulating user agent", JSON.stringify(agentOptions)]]);
|
|
134
|
+
}
|
|
112
135
|
await Emulation.setUserAgentOverride(agentOptions);
|
|
113
136
|
}
|
|
114
137
|
}
|
|
115
138
|
const handleAuthRequests = Boolean(options.httpProxyUsername);
|
|
116
|
-
const patterns = handleAuthRequests ? [{ requestStage: "Request" }, { requestStage: "Response"
|
|
139
|
+
const patterns = handleAuthRequests ? [{ requestStage: "Request" }, { requestStage: "Response" }] : [{ requestStage: "Response" }];
|
|
117
140
|
await Fetch.enable({ handleAuthRequests, patterns });
|
|
118
141
|
if (handleAuthRequests) {
|
|
119
|
-
Fetch.addEventListener("authRequired", ({ params }) =>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
response: "ProvideCredentials",
|
|
123
|
-
username: options.httpProxyUsername,
|
|
124
|
-
password: options.httpProxyPassword
|
|
142
|
+
Fetch.addEventListener("authRequired", async ({ params }) => {
|
|
143
|
+
if (options.debugMessagesFile) {
|
|
144
|
+
debugMessages.push([Date.now(), ["Authenticating"]]);
|
|
125
145
|
}
|
|
126
|
-
|
|
146
|
+
await Fetch.continueWithAuth({
|
|
147
|
+
requestId: params.requestId,
|
|
148
|
+
authChallengeResponse: {
|
|
149
|
+
response: "ProvideCredentials",
|
|
150
|
+
username: options.httpProxyUsername,
|
|
151
|
+
password: options.httpProxyPassword
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
127
155
|
}
|
|
128
156
|
let url = options.url;
|
|
129
157
|
let alternativeUrl = new URL(url);
|
|
@@ -134,12 +162,15 @@ async function getPageData(options) {
|
|
|
134
162
|
let httpInfo;
|
|
135
163
|
Fetch.addEventListener("requestPaused", async ({ params }) => {
|
|
136
164
|
const { requestId, request, resourceType, responseHeaders, responseStatusCode, responseStatusText } = params;
|
|
137
|
-
if (options.outputJson && !httpInfo && (request.url == url || request.url == alternativeUrl) && responseStatusCode !== undefined) {
|
|
165
|
+
if (resourceType == "Document" && (options.outputJson && !httpInfo && (request.url == url || request.url == alternativeUrl) && responseStatusCode !== undefined)) {
|
|
138
166
|
if (REDIRECT_STATUS_CODES.includes(responseStatusCode)) {
|
|
139
167
|
const redirect = responseHeaders.find(header => header.name.toLowerCase() == "location").value;
|
|
140
168
|
if (redirect) {
|
|
141
169
|
url = new URL(redirect, url).href;
|
|
142
170
|
}
|
|
171
|
+
if (options.debugMessagesFile) {
|
|
172
|
+
debugMessages.push([Date.now(), ["Redirecting", url]]);
|
|
173
|
+
}
|
|
143
174
|
} else {
|
|
144
175
|
httpInfo = {
|
|
145
176
|
request: {
|
|
@@ -156,18 +187,36 @@ async function getPageData(options) {
|
|
|
156
187
|
}
|
|
157
188
|
};
|
|
158
189
|
}
|
|
190
|
+
} else if (options.blockedURLPatterns && options.blockedURLPatterns.length) {
|
|
191
|
+
const blockedURL = options.blockedURLPatterns.find(blockedURL => new RegExp(blockedURL).test(request.url));
|
|
192
|
+
if (blockedURL) {
|
|
193
|
+
try {
|
|
194
|
+
if (options.debugMessagesFile) {
|
|
195
|
+
debugMessages.push([Date.now(), ["Blocking request", request.url]]);
|
|
196
|
+
}
|
|
197
|
+
await Fetch.failRequest({ requestId, errorReason: "Aborted" });
|
|
198
|
+
} catch {
|
|
199
|
+
// ignored
|
|
200
|
+
}
|
|
201
|
+
}
|
|
159
202
|
}
|
|
160
203
|
try {
|
|
161
204
|
await Fetch.continueRequest({ requestId });
|
|
162
|
-
} catch
|
|
205
|
+
} catch {
|
|
163
206
|
// ignored
|
|
164
207
|
}
|
|
165
208
|
});
|
|
166
209
|
if (options.httpHeaders && options.httpHeaders.length) {
|
|
210
|
+
if (options.debugMessagesFile) {
|
|
211
|
+
debugMessages.push([Date.now(), ["Setting HTTP headers", JSON.stringify(options.httpHeaders)]]);
|
|
212
|
+
}
|
|
167
213
|
await Network.setExtraHTTPHeaders({ headers: options.httpHeaders });
|
|
168
214
|
}
|
|
169
215
|
if (options.emulateMediaFeatures) {
|
|
170
216
|
for (const mediaFeature of options.emulateMediaFeatures) {
|
|
217
|
+
if (options.debugMessagesFile) {
|
|
218
|
+
debugMessages.push([Date.now(), ["Emulating media feature", mediaFeature.name, mediaFeature.value]]);
|
|
219
|
+
}
|
|
171
220
|
await Emulation.setEmulatedMedia({
|
|
172
221
|
media: mediaFeature.name,
|
|
173
222
|
features: mediaFeature.value.split(",").map(feature => feature.trim())
|
|
@@ -175,8 +224,12 @@ async function getPageData(options) {
|
|
|
175
224
|
}
|
|
176
225
|
}
|
|
177
226
|
if (options.browserCookies && options.browserCookies.length) {
|
|
227
|
+
if (options.debugMessagesFile) {
|
|
228
|
+
debugMessages.push([Date.now(), ["Setting cookies", JSON.stringify(options.browserCookies)]]);
|
|
229
|
+
}
|
|
178
230
|
await Network.setCookies({ cookies: options.browserCookies });
|
|
179
231
|
}
|
|
232
|
+
await Browser.setDownloadBehavior({ behavior: "deny" });
|
|
180
233
|
await Page.addScriptToEvaluateOnNewDocument({
|
|
181
234
|
source: getHookScriptSource(),
|
|
182
235
|
runImmediately: true
|
|
@@ -187,7 +240,7 @@ async function getPageData(options) {
|
|
|
187
240
|
worldName: SINGLE_FILE_WORLD_NAME
|
|
188
241
|
});
|
|
189
242
|
const [contextId] = await Promise.all([
|
|
190
|
-
loadPage({ Page, Runtime }, options),
|
|
243
|
+
loadPage({ Page, Runtime }, options, debugMessages),
|
|
191
244
|
options.browserDebug ? waitForDebuggerReady({ Debugger }) : Promise.resolve()
|
|
192
245
|
]);
|
|
193
246
|
await Runtime.addBinding({ name: SET_PAGE_DATA_FUNCTION_NAME, executionContextId: contextId });
|
|
@@ -195,19 +248,22 @@ async function getPageData(options) {
|
|
|
195
248
|
await Runtime.addBinding({ name: CAPTURE_SCREENSHOT_FUNCTION_NAME, executionContextId: contextId });
|
|
196
249
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
197
250
|
if (params.name === CAPTURE_SCREENSHOT_FUNCTION_NAME) {
|
|
251
|
+
if (options.debugMessagesFile) {
|
|
252
|
+
debugMessages.push([Date.now(), ["Capturing screenshot"]]);
|
|
253
|
+
}
|
|
198
254
|
try {
|
|
199
255
|
let screenshotOptions = { captureBeyondViewport: true };
|
|
200
256
|
if (options.embedScreenshotOptions) {
|
|
201
257
|
try {
|
|
202
258
|
screenshotOptions = JSON.parse(options.embedScreenshotOptions);
|
|
203
|
-
} catch
|
|
259
|
+
} catch {
|
|
204
260
|
// ignored
|
|
205
261
|
}
|
|
206
262
|
}
|
|
207
263
|
screenshotOptions.format = "png";
|
|
208
264
|
const { data } = await Page.captureScreenshot(screenshotOptions);
|
|
209
265
|
await Runtime.evaluate({ expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify(data)})`, contextId });
|
|
210
|
-
} catch
|
|
266
|
+
} catch {
|
|
211
267
|
await Runtime.evaluate({ expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify("")})`, contextId });
|
|
212
268
|
}
|
|
213
269
|
}
|
|
@@ -217,18 +273,21 @@ async function getPageData(options) {
|
|
|
217
273
|
await Runtime.addBinding({ name: PRINT_TO_PDF_FUNCTION_NAME, executionContextId: contextId });
|
|
218
274
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
219
275
|
if (params.name === PRINT_TO_PDF_FUNCTION_NAME) {
|
|
276
|
+
if (options.debugMessagesFile) {
|
|
277
|
+
debugMessages.push([Date.now(), ["Printing to PDF", options.embedPdfOptions || ""]]);
|
|
278
|
+
}
|
|
220
279
|
let pdfOptions = {};
|
|
221
280
|
if (options.embedPdfOptions) {
|
|
222
281
|
try {
|
|
223
282
|
pdfOptions = JSON.parse(options.embedPdfOptions);
|
|
224
|
-
} catch
|
|
283
|
+
} catch {
|
|
225
284
|
// ignored
|
|
226
285
|
}
|
|
227
286
|
}
|
|
228
287
|
try {
|
|
229
288
|
const { data } = await Page.printToPDF(pdfOptions);
|
|
230
289
|
await Runtime.evaluate({ expression: `globalThis.${SET_PDF_FUNCTION_NAME}(${JSON.stringify(data)})`, contextId });
|
|
231
|
-
} catch
|
|
290
|
+
} catch {
|
|
232
291
|
await Runtime.evaluate({ expression: `globalThis.${SET_PDF_FUNCTION_NAME}(${JSON.stringify("")})`, contextId });
|
|
233
292
|
}
|
|
234
293
|
}
|
|
@@ -236,12 +295,15 @@ async function getPageData(options) {
|
|
|
236
295
|
}
|
|
237
296
|
const pageDataPromise = new Promise(resolve => {
|
|
238
297
|
let pageDataResponse = "";
|
|
239
|
-
Runtime.addEventListener("bindingCalled",
|
|
298
|
+
Runtime.addEventListener("bindingCalled", ({ params }) => {
|
|
240
299
|
if (params.name === SET_PAGE_DATA_FUNCTION_NAME) {
|
|
241
300
|
const { payload } = params;
|
|
242
301
|
if (payload.length) {
|
|
243
302
|
pageDataResponse += payload;
|
|
244
303
|
} else {
|
|
304
|
+
if (options.debugMessagesFile) {
|
|
305
|
+
debugMessages.push([Date.now(), ["Setting page data"]]);
|
|
306
|
+
}
|
|
245
307
|
const result = JSON.parse(pageDataResponse);
|
|
246
308
|
if (result.content instanceof Array) {
|
|
247
309
|
result.content = new Uint8Array(result.content);
|
|
@@ -252,8 +314,14 @@ async function getPageData(options) {
|
|
|
252
314
|
});
|
|
253
315
|
});
|
|
254
316
|
if (options.browserWaitDelay) {
|
|
317
|
+
if (options.debugMessagesFile) {
|
|
318
|
+
debugMessages.push([Date.now(), [`Waiting ${options.browserWaitDelay} ms`]]);
|
|
319
|
+
}
|
|
255
320
|
await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
|
|
256
321
|
}
|
|
322
|
+
if (options.debugMessagesFile) {
|
|
323
|
+
debugMessages.push([Date.now(), ["Capturing page"]]);
|
|
324
|
+
}
|
|
257
325
|
const { result } = await Runtime.evaluate({
|
|
258
326
|
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])})`,
|
|
259
327
|
awaitPromise: true,
|
|
@@ -269,20 +337,42 @@ async function getPageData(options) {
|
|
|
269
337
|
await Console.disable();
|
|
270
338
|
pageData.consoleMessages = consoleMessages;
|
|
271
339
|
}
|
|
340
|
+
if (options.debugMessagesFile) {
|
|
341
|
+
pageData.debugMessages = debugMessages;
|
|
342
|
+
debugMessages.push([Date.now(), ["Returning page data"]]);
|
|
343
|
+
}
|
|
272
344
|
Object.assign(pageData, httpInfo);
|
|
273
345
|
return pageData;
|
|
274
346
|
} catch (error) {
|
|
275
347
|
if (error.code === LOAD_TIMEOUT_ERROR && options.browserWaitUntilFallback && options.browserWaitUntil) {
|
|
276
348
|
const browserWaitUntil = NETWORK_STATES[(NETWORK_STATES.indexOf(options.browserWaitUntil) + 1)];
|
|
277
349
|
if (browserWaitUntil) {
|
|
350
|
+
if (options.debugMessagesFile) {
|
|
351
|
+
debugMessages.push([Date.now(), ["Retrying with waitUntil", browserWaitUntil]]);
|
|
352
|
+
}
|
|
278
353
|
options.browserWaitUntil = browserWaitUntil;
|
|
354
|
+
await closeTarget();
|
|
279
355
|
return await getPageData(options);
|
|
280
356
|
}
|
|
281
357
|
}
|
|
358
|
+
if (options.consoleMessagesFile) {
|
|
359
|
+
error.consoleMessages = consoleMessages;
|
|
360
|
+
}
|
|
361
|
+
if (options.debugMessagesFile) {
|
|
362
|
+
error.debugMessages = debugMessages;
|
|
363
|
+
}
|
|
282
364
|
throw error;
|
|
283
365
|
} finally {
|
|
366
|
+
if (options.debugMessagesFile) {
|
|
367
|
+
debugMessages.push([Date.now(), ["Closing page"]]);
|
|
368
|
+
}
|
|
369
|
+
await closeTarget();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function closeTarget() {
|
|
284
373
|
if (targetInfo && !options.browserDebug) {
|
|
285
374
|
await CDP.closeTarget(targetInfo.id);
|
|
375
|
+
targetInfo = null;
|
|
286
376
|
}
|
|
287
377
|
}
|
|
288
378
|
}
|
|
@@ -328,14 +418,17 @@ function getPageDataScriptSource(options, [SET_SCREENSHOT_FUNCTION_NAME, SET_PDF
|
|
|
328
418
|
});
|
|
329
419
|
}
|
|
330
420
|
|
|
331
|
-
async function loadPage({ Page, Runtime }, options) {
|
|
421
|
+
async function loadPage({ Page, Runtime }, options, debugMessages) {
|
|
332
422
|
await Runtime.enable();
|
|
333
423
|
await Page.enable();
|
|
334
424
|
const loadTimeoutAbortController = new AbortController();
|
|
335
425
|
const loadTimeoutAbortSignal = loadTimeoutAbortController.signal;
|
|
336
426
|
try {
|
|
427
|
+
if (options.debugMessagesFile) {
|
|
428
|
+
debugMessages.push([Date.now(), ["Loading page", options.url]]);
|
|
429
|
+
}
|
|
337
430
|
const [contextId] = await Promise.race([
|
|
338
|
-
Promise.all([getTopFrameContextId({ Page, Runtime }, options), Page.navigate({ url: options.url })]),
|
|
431
|
+
Promise.all([getTopFrameContextId({ Page, Runtime }, options, debugMessages), Page.navigate({ url: options.url })]),
|
|
339
432
|
waitForLoadTimeout(loadTimeoutAbortSignal, options.browserLoadMaxTime)
|
|
340
433
|
]);
|
|
341
434
|
return contextId;
|
|
@@ -348,13 +441,16 @@ async function loadPage({ Page, Runtime }, options) {
|
|
|
348
441
|
}
|
|
349
442
|
}
|
|
350
443
|
|
|
351
|
-
async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
444
|
+
async function getTopFrameContextId({ Page, Runtime }, options, debugMessages) {
|
|
352
445
|
const CONTEXT_CREATED_EVENT = "executionContextCreated";
|
|
353
446
|
const contextIds = [];
|
|
354
447
|
let topFrameId;
|
|
355
448
|
try {
|
|
356
449
|
Runtime.addEventListener(CONTEXT_CREATED_EVENT, onExecutionContextCreated);
|
|
357
450
|
await waitForPageReady({ Page }, options);
|
|
451
|
+
if (options.debugMessagesFile) {
|
|
452
|
+
debugMessages.push([Date.now(), ["Getting execution context"]]);
|
|
453
|
+
}
|
|
358
454
|
const contextId = await getContextId();
|
|
359
455
|
if (contextId === undefined) {
|
|
360
456
|
throw new Error("Execution context not found");
|
|
@@ -374,6 +470,7 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
374
470
|
}
|
|
375
471
|
|
|
376
472
|
async function waitForPageReady({ Page }, options) {
|
|
473
|
+
let resolveCallbackTimeout;
|
|
377
474
|
await Page.setLifecycleEventsEnabled({ enabled: true });
|
|
378
475
|
try {
|
|
379
476
|
await new Promise((resolve, reject) => {
|
|
@@ -384,9 +481,23 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
384
481
|
|
|
385
482
|
function onLifecycleEvent({ params }) {
|
|
386
483
|
const { frameId, name } = params;
|
|
387
|
-
if (frameId === topFrameId
|
|
388
|
-
|
|
389
|
-
|
|
484
|
+
if (frameId === topFrameId) {
|
|
485
|
+
if (options.debugMessagesFile) {
|
|
486
|
+
debugMessages.push([Date.now(), ["Detecting lifecycle event", name]]);
|
|
487
|
+
}
|
|
488
|
+
if (name === options.browserWaitUntil || (resolveCallbackTimeout && NETWORK_STATES.indexOf(name) < NETWORK_STATES.indexOf(options.browserWaitUntil))) {
|
|
489
|
+
clearTimeout(resolveCallbackTimeout);
|
|
490
|
+
if (options.debugMessagesFile) {
|
|
491
|
+
debugMessages.push([Date.now(), [`Waiting ${options.browserWaitUntilDelay} ms`]]);
|
|
492
|
+
}
|
|
493
|
+
setTimeout(() => {
|
|
494
|
+
if (options.debugMessagesFile) {
|
|
495
|
+
debugMessages.push([Date.now(), ["Detecting page ready"]]);
|
|
496
|
+
}
|
|
497
|
+
removeListeners();
|
|
498
|
+
resolve();
|
|
499
|
+
}, options.browserWaitUntilDelay);
|
|
500
|
+
}
|
|
390
501
|
}
|
|
391
502
|
}
|
|
392
503
|
|
|
@@ -394,9 +505,13 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
394
505
|
const { frame } = params;
|
|
395
506
|
if (!frame.parentId) {
|
|
396
507
|
if (frame.unreachableUrl) {
|
|
508
|
+
clearTimeout(resolveCallbackTimeout);
|
|
397
509
|
removeListeners();
|
|
398
510
|
reject(new Error("Unreachable URL: " + frame.unreachableUrl));
|
|
399
511
|
} else {
|
|
512
|
+
if (options.debugMessagesFile) {
|
|
513
|
+
debugMessages.push([Date.now(), ["Detecting top frame ID"]]);
|
|
514
|
+
}
|
|
400
515
|
topFrameId = frame.id;
|
|
401
516
|
}
|
|
402
517
|
}
|
|
@@ -433,7 +548,7 @@ async function getTopFrameContextId({ Page, Runtime }, options) {
|
|
|
433
548
|
contextId
|
|
434
549
|
});
|
|
435
550
|
return result.value === true;
|
|
436
|
-
} catch
|
|
551
|
+
} catch {
|
|
437
552
|
// ignored
|
|
438
553
|
}
|
|
439
554
|
return false;
|
package/lib/constants.js
CHANGED
package/lib/deno-polyfill.js
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
* Source.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
// deno-lint-ignore-file no-node-globals
|
|
25
|
+
|
|
24
26
|
/* global globalThis, URL, Deno, process */
|
|
25
27
|
|
|
26
28
|
import * as path from "path";
|
|
@@ -244,7 +246,7 @@ async function cwd() {
|
|
|
244
246
|
}
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
|
|
249
|
+
function dirname(filePath) {
|
|
248
250
|
return path.dirname(filePath);
|
|
249
251
|
}
|
|
250
252
|
|