single-file-cli 2.0.21 → 2.0.23

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 CHANGED
@@ -69,7 +69,7 @@ Make sure Chrome or a Chromium-based browser is installed in the default folder.
69
69
 
70
70
  ```sh
71
71
  npm install "single-file-cli"
72
- cd single-file-cli-master
72
+ cd node_modules/single-file-cli
73
73
  ```
74
74
 
75
75
  You can also install SingleFile globally with `-g` when running `npm install`.
package/deno.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@single-file/single-file-cli",
3
- "version": "2.0.21",
3
+ "version": "2.0.23",
4
4
  "description": "SingleFile CLI",
5
5
  "nodeModulesDir": true,
6
6
  "exports": {
7
7
  ".": "./single-file-cli-api.js"
8
8
  },
9
9
  "imports": {
10
- "simple-cdp": "jsr:@simple-cdp/simple-cdp@^1.8.4",
10
+ "simple-cdp": "jsr:@simple-cdp/simple-cdp@^1.8.5",
11
11
  "path": "jsr:@std/path@^0.220.1"
12
12
  }
13
13
  }
package/deno.lock CHANGED
@@ -2,15 +2,15 @@
2
2
  "version": "3",
3
3
  "packages": {
4
4
  "specifiers": {
5
- "jsr:@simple-cdp/simple-cdp@^1.8.4": "jsr:@simple-cdp/simple-cdp@1.8.4",
5
+ "jsr:@simple-cdp/simple-cdp@^1.8.5": "jsr:@simple-cdp/simple-cdp@1.8.5",
6
6
  "jsr:@std/assert@^0.220.1": "jsr:@std/assert@0.220.1",
7
7
  "jsr:@std/path@^0.220.1": "jsr:@std/path@0.220.1",
8
- "npm:simple-cdp@^1.8.4": "npm:simple-cdp@1.8.4",
8
+ "npm:simple-cdp@^1.8.5": "npm:simple-cdp@1.8.5",
9
9
  "npm:ws@^8.16.0": "npm:ws@8.16.0"
10
10
  },
11
11
  "jsr": {
12
- "@simple-cdp/simple-cdp@1.8.4": {
13
- "integrity": "5e31ab90a552f9f1cf84e6cf0454d21c5b9dc1d89f9c1f9a750772b47bad9a4e"
12
+ "@simple-cdp/simple-cdp@1.8.5": {
13
+ "integrity": "7386ca561cd6293bb3115eadf14b8c98d1c41c35a69c79774ea70e5101159413"
14
14
  },
15
15
  "@std/assert@0.220.1": {
16
16
  "integrity": "88710d54f3afdd7a5761e7805abba1f56cd14e4b212feffeb3e73a9f77482425"
@@ -23,8 +23,8 @@
23
23
  }
24
24
  },
25
25
  "npm": {
26
- "simple-cdp@1.8.4": {
27
- "integrity": "sha512-fsvMUyz13vzX8nxSPwJfdxdROGxRDdTAFX7XitVpRsKwClowsyL3NZ6kR4vR5tZfxbz31p3uoM14eFUvhaWisA==",
26
+ "simple-cdp@1.8.5": {
27
+ "integrity": "sha512-bpXoeCk0mwFrr+8C8vVkhCug5h4HO49GI+MZdnyLQcFVKzTlokrimTjEoc69X2Y2n7mtjzDHTriq6B/kgUeUcA==",
28
28
  "dependencies": {}
29
29
  },
30
30
  "ws@8.16.0": {
@@ -36,12 +36,12 @@
36
36
  "remote": {},
37
37
  "workspace": {
38
38
  "dependencies": [
39
- "jsr:@simple-cdp/simple-cdp@^1.8.4",
39
+ "jsr:@simple-cdp/simple-cdp@^1.8.5",
40
40
  "jsr:@std/path@^0.220.1"
41
41
  ],
42
42
  "packageJson": {
43
43
  "dependencies": [
44
- "npm:simple-cdp@^1.8.4",
44
+ "npm:simple-cdp@^1.8.5",
45
45
  "npm:ws@^8.16.0"
46
46
  ]
47
47
  }
package/lib/cdp-client.js CHANGED
@@ -28,7 +28,7 @@ import { getScriptSource, getHookScriptSource } from "./single-file-script.js";
28
28
  import { CDP } from "simple-cdp";
29
29
 
30
30
  const LOAD_TIMEOUT_ERROR = "ERR_LOAD_TIMEOUT";
31
- const INTERACTIVE_TIME_STATE = "InteractiveTime";
31
+ const DEFAULT_NETWORK_STATE = "networkIdle";
32
32
  const NETWORK_STATES = ["InteractiveTime", "networkIdle", "networkAlmostIdle", "load", "DOMContentLoaded"];
33
33
  const MINIMIZED_WINDOW_STATE = "minimized";
34
34
  const SINGLE_FILE_WORLD_NAME = "singlefile";
@@ -37,10 +37,10 @@ const EMPTY_PAGE_URL = "about:blank";
37
37
  export { initialize, getPageData, closeBrowser };
38
38
 
39
39
  async function initialize(options) {
40
- if (!options.browserRemoteDebuggingUrl) {
41
- await launchBrowser(getBrowserOptions(options));
40
+ if (options.browserRemoteDebuggingURL) {
41
+ CDP.remoteDebuggingUrl = options.browserRemoteDebuggingURL;
42
42
  } else {
43
- CDP.remoteDebuggingUrl = options.browserRemoteDebuggingUrl;
43
+ await launchBrowser(getBrowserOptions(options));
44
44
  }
45
45
  }
46
46
 
@@ -50,7 +50,7 @@ async function getPageData(options) {
50
50
  targetInfo = await CDP.createTarget(EMPTY_PAGE_URL);
51
51
  const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger } = new CDP(targetInfo);
52
52
  if (options.browserStartMinimized) {
53
- const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.targetId });
53
+ const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.id });
54
54
  if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
55
55
  await Browser.setWindowBounds({ windowId, bounds: { windowState: MINIMIZED_WINDOW_STATE } });
56
56
  }
@@ -64,7 +64,7 @@ async function getPageData(options) {
64
64
  if (options.browserMobileEmulation) {
65
65
  await Emulation.setDeviceMetricsOverride({ mobile: true });
66
66
  }
67
- if (options.httpProxyServer && options.httpProxyUsername) {
67
+ if (options.httpProxyUsername) {
68
68
  await Fetch.enable({ handleAuthRequests: true });
69
69
  Fetch.addEventListener("authRequired", ({ params }) => Fetch.continueWithAuth({
70
70
  requestId: params.requestId,
@@ -194,12 +194,14 @@ function getTopFrameContextId({ Page, Runtime }, options) {
194
194
  contextId = contextIds[contextIdIndex];
195
195
  }
196
196
  contextIdIndex++;
197
- } while (contextId === undefined && contextIdIndex < contextIds.length);
197
+ } while (contextId === undefined && contextIdIndex < contextIds.length && !navigationSignal.aborted);
198
198
  }
199
- if (contextId === undefined) {
200
- reject(new Error("Execution context not found"));
201
- } else {
202
- resolve(contextId);
199
+ if (!navigationSignal.aborted) {
200
+ if (contextId === undefined) {
201
+ reject(new Error("Execution context not found"));
202
+ } else {
203
+ resolve(contextId);
204
+ }
203
205
  }
204
206
  }
205
207
  }
@@ -219,20 +221,20 @@ function getTopFrameContextId({ Page, Runtime }, options) {
219
221
  contextIds.splice(index, 1);
220
222
  }
221
223
  }
224
+ });
222
225
 
223
- async function testExecutionContext(contextId) {
224
- try {
225
- const { result } = await Runtime.evaluate({
226
- expression: "singlefile !== undefined",
227
- contextId
228
- });
229
- return result.value === true;
230
- } catch (error) {
231
- // ignored
232
- }
233
- return false;
226
+ async function testExecutionContext(contextId) {
227
+ try {
228
+ const { result } = await Runtime.evaluate({
229
+ expression: "singlefile !== undefined",
230
+ contextId
231
+ });
232
+ return result.value === true;
233
+ } catch (error) {
234
+ // ignored
234
235
  }
235
- });
236
+ return false;
237
+ }
236
238
  }
237
239
 
238
240
  function waitForLoadTimeout(abortSignal, maxDelay) {
@@ -262,11 +264,9 @@ async function waitForPageReady({ Page }, topFrameId, options, navigationSignal)
262
264
 
263
265
  function onLifecycleEvent({ params }) {
264
266
  const { name, frameId } = params;
265
- if (frameId === topFrameId) {
266
- if (name === options.browserWaitUntil || name === INTERACTIVE_TIME_STATE || navigationSignal.aborted) {
267
- Page.removeEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
268
- resolve();
269
- }
267
+ if (frameId === topFrameId && (name === options.browserWaitUntil || name === DEFAULT_NETWORK_STATE || navigationSignal.aborted)) {
268
+ Page.removeEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
269
+ resolve();
270
270
  }
271
271
  }
272
272
  });
@@ -114,7 +114,6 @@ const DenoAPI = {
114
114
  };
115
115
 
116
116
  const pathAPI = {
117
- toFileUrl,
118
117
  dirname
119
118
  };
120
119
 
@@ -208,15 +207,6 @@ function exit(code) {
208
207
  }
209
208
  }
210
209
 
211
- async function toFileUrl(filePath) {
212
- if (DENO_RUNTIME_DETECTED) {
213
- return path.toFileUrl(filePath);
214
- } else {
215
- const url = await import(NODE_MODULES["url"]);
216
- return new URL(url.pathToFileURL(filePath));
217
- }
218
- }
219
-
220
210
  async function dirname(filePath) {
221
211
  return path.dirname(filePath);
222
212
  }
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "2.0.21";
1
+ export const version = "2.0.23";
package/options.js CHANGED
@@ -60,7 +60,7 @@ const OPTIONS_INFO = {
60
60
  "browser-cookie": { description: "Ordered list of cookie parameters separated by a comma (name,value,domain,path,expires,httpOnly,secure,sameSite,url)", type: "string[]" },
61
61
  "browser-cookies-file": { description: "Path of the cookies file formatted as a JSON file or a Netscape text file", type: "string" },
62
62
  "browser-ignore-insecure-certs": { description: "Ignore HTTPs errors", type: "boolean" },
63
- "browser-remote-debugging-url": { description: "Remote debugging URL", type: "string" },
63
+ "browser-remote-debugging-URL": { description: "Remote debugging URL", type: "string" },
64
64
  "compress-content": { description: "Compress the output file into a ZIP file", type: "boolean" },
65
65
  "compress-CSS": { description: "Compress CSS stylesheets", type: "boolean" },
66
66
  "compress-HTML": { description: "Compress HTML content", type: "boolean", defaultValue: true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-cli",
3
- "version": "2.0.21",
3
+ "version": "2.0.23",
4
4
  "description": "SingleFile CLI",
5
5
  "author": "Gildas Lormeau",
6
6
  "engines": {
@@ -13,7 +13,7 @@
13
13
  "single-file": "./single-file-node.js"
14
14
  },
15
15
  "dependencies": {
16
- "simple-cdp": "^1.8.4",
16
+ "simple-cdp": "^1.8.5",
17
17
  "ws": "^8.16.0"
18
18
  }
19
19
  }
@@ -79,7 +79,7 @@ const STATE_PROCESSED = "processed";
79
79
  const { readTextFile, writeTextFile, writeFile, stdout, mkdir, stat, errors } = Deno;
80
80
  let tasks = [], maxParallelWorkers, sessionFilename;
81
81
 
82
- export { DEFAULT_OPTIONS, VALID_URL_TEST, initialize };
82
+ export { initialize };
83
83
 
84
84
  async function initialize(options) {
85
85
  options = Object.assign({}, DEFAULT_OPTIONS, options);
@@ -203,21 +203,28 @@ function testMaxDepth(task) {
203
203
 
204
204
  function createTask(url, options, parentTask, rootTask) {
205
205
  url = parentTask ? rewriteURL(url, options.crawlRemoveURLFragment, options.crawlRewriteRules) : url;
206
- if (VALID_URL_TEST.test(url)) {
207
- const isInnerLink = rootTask && url.startsWith(getHostURL(rootTask.url));
208
- const rootBaseURIMatch = rootTask && rootTask.url.match(/(.*?)[^/]*$/);
209
- const isChild = isInnerLink && rootBaseURIMatch && rootBaseURIMatch[1] && url.startsWith(rootBaseURIMatch[1]);
210
- return {
211
- url,
212
- isInnerLink,
213
- isChild,
214
- originalUrl: url,
215
- rootBaseURI: rootBaseURIMatch && rootBaseURIMatch[1],
216
- depth: parentTask ? parentTask.depth + 1 : 0,
217
- externalLinkDepth: isInnerLink ? -1 : parentTask ? parentTask.externalLinkDepth + 1 : -1,
218
- options
219
- };
206
+ if (!VALID_URL_TEST.test(url)) {
207
+ try {
208
+ url = url.replace(/\\/g, "/");
209
+ url = url.replace(/#/g, "%23");
210
+ url = new URL(url, import.meta.url).href;
211
+ } catch (error) {
212
+ throw new Error("Invalid URL or file path: " + url);
213
+ }
220
214
  }
215
+ const isInnerLink = rootTask && url.startsWith(getHostURL(rootTask.url));
216
+ const rootBaseURIMatch = rootTask && rootTask.url.match(/(.*?)[^/]*$/);
217
+ const isChild = isInnerLink && rootBaseURIMatch && rootBaseURIMatch[1] && url.startsWith(rootBaseURIMatch[1]);
218
+ return {
219
+ url,
220
+ isInnerLink,
221
+ isChild,
222
+ originalUrl: url,
223
+ rootBaseURI: rootBaseURIMatch && rootBaseURIMatch[1],
224
+ depth: parentTask ? parentTask.depth + 1 : 0,
225
+ externalLinkDepth: isInnerLink ? -1 : parentTask ? parentTask.externalLinkDepth + 1 : -1,
226
+ options
227
+ };
221
228
  }
222
229
 
223
230
  async function saveTasks() {
@@ -23,21 +23,17 @@
23
23
 
24
24
  /* global URL */
25
25
 
26
- import { VALID_URL_TEST, initialize } from "./single-file-cli-api.js";
27
- import { Deno, path } from "./lib/deno-polyfill.js";
26
+ import { initialize } from "./single-file-cli-api.js";
27
+ import { Deno } from "./lib/deno-polyfill.js";
28
28
  import options from "./options.js";
29
29
 
30
30
  const { readTextFile, exit } = Deno;
31
- const { toFileUrl } = path;
32
31
 
33
32
  export { run };
34
33
 
35
34
  async function run() {
36
35
  try {
37
36
  let urls;
38
- if (options.url && !VALID_URL_TEST.test(options.url)) {
39
- options.url = (await toFileUrl(new URL(options.url, import.meta.url).pathname)).href;
40
- }
41
37
  if (options.urlsFile) {
42
38
  urls = (await readTextFile(options.urlsFile)).split("\n");
43
39
  } else {
package/single-file.bat CHANGED
@@ -1,2 +1,2 @@
1
1
  @echo off
2
- node "%~dp0\single-file" %*
2
+ deno run --allow-read --allow-write --allow-net --allow-env --allow-run "%~dp0\single-file" %*