single-file-cli 2.1.1 → 2.1.3

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  mv package.json package.json.tmp
4
4
  mv deno.json deno.json.tmp
5
5
  mv deno.lock deno.lock.tmp
6
- deno install --vendor --quiet --minimum-dependency-age=0 "npm:single-file-core@1.5.85"
6
+ deno install --vendor --quiet --minimum-dependency-age=0 "npm:single-file-core@1.5.86"
7
7
  mv package.json.tmp package.json
8
8
  mv deno.json.tmp deno.json
9
9
  mv deno.lock.tmp deno.lock
package/compile.sh CHANGED
@@ -12,11 +12,11 @@ cp -R ./resources "$stage_dir/resources"
12
12
  mkdir -p "$dist_dir"
13
13
  cd "$stage_dir"
14
14
 
15
- deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-aarch64-apple-darwin" --target=aarch64-apple-darwin ./single-file
16
- deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-x86_64-apple-darwin" --target=x86_64-apple-darwin ./single-file
17
- deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-x86_64-linux" --target=x86_64-unknown-linux-gnu ./single-file
18
- deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-aarch64-linux" --target=aarch64-unknown-linux-gnu ./single-file
19
- deno compile --allow-all --ext=js --output="$dist_dir/single-file.exe" --target=x86_64-pc-windows-msvc --icon=./resources/single-file.ico ./single-file
15
+ deno compile --minimum-dependency-age=0 --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-aarch64-apple-darwin" --target=aarch64-apple-darwin ./single-file
16
+ deno compile --minimum-dependency-age=0 --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-x86_64-apple-darwin" --target=x86_64-apple-darwin ./single-file
17
+ deno compile --minimum-dependency-age=0 --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-x86_64-linux" --target=x86_64-unknown-linux-gnu ./single-file
18
+ deno compile --minimum-dependency-age=0 --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output="$dist_dir/single-file-aarch64-linux" --target=aarch64-unknown-linux-gnu ./single-file
19
+ deno compile --minimum-dependency-age=0 --allow-all --ext=js --output="$dist_dir/single-file.exe" --target=x86_64-pc-windows-msvc --icon=./resources/single-file.ico ./single-file
20
20
 
21
21
  cd - > /dev/null
22
22
 
package/deno.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@single-file/single-file-cli",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "SingleFile CLI",
5
5
  "exports": {
6
6
  ".": "./single-file-cli-api.js"
7
7
  },
8
8
  "imports": {
9
- "simple-cdp": "jsr:@simple-cdp/simple-cdp@^1.10.0",
10
- "path": "jsr:@std/path@^1.1.2"
9
+ "simple-cdp": "jsr:@simple-cdp/simple-cdp@^1.10.1",
10
+ "path": "jsr:@std/path@^1.1.6"
11
11
  }
12
12
  }
package/deno.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "version": "5",
3
3
  "specifiers": {
4
- "jsr:@simple-cdp/simple-cdp@^1.10.0": "1.10.0",
4
+ "jsr:@simple-cdp/simple-cdp@^1.10.1": "1.10.1",
5
5
  "jsr:@std/internal@^1.0.14": "1.0.14",
6
- "jsr:@std/path@^1.1.2": "1.1.6",
7
- "npm:@eslint/js@^9.39.1": "9.39.5",
8
- "npm:esbuild@~0.27.4": "0.27.7",
6
+ "jsr:@std/path@^1.1.6": "1.1.6",
7
+ "npm:@eslint/js@^9.39.5": "9.39.5",
8
+ "npm:esbuild@~0.27.7": "0.27.7",
9
9
  "npm:eslint@^10.8.1": "10.8.1",
10
- "npm:simple-cdp@^1.10.0": "1.10.0"
10
+ "npm:simple-cdp@^1.10.1": "1.10.1"
11
11
  },
12
12
  "jsr": {
13
- "@simple-cdp/simple-cdp@1.10.0": {
14
- "integrity": "3f8c91e22598c3e15a680f14ee3d2aa174c21b9b528caad5ec8552e3df0c3897"
13
+ "@simple-cdp/simple-cdp@1.10.1": {
14
+ "integrity": "33c686242e812a53d13ba7fcebd18ed81b4685fb02da37c2ee6ed9a5123f9b8c"
15
15
  },
16
16
  "@std/internal@1.0.14": {
17
17
  "integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7"
@@ -527,8 +527,8 @@
527
527
  "shebang-regex@3.0.0": {
528
528
  "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
529
529
  },
530
- "simple-cdp@1.10.0": {
531
- "integrity": "sha512-UXDAaiges1GqNKtBy39po+CD4hXDJxQEDtR1GF9bK2J9MNN0epTo2GpoSmEc8o5ofW8dutpHafBjowEchSNgig=="
530
+ "simple-cdp@1.10.1": {
531
+ "integrity": "sha512-svGX76zc2MY2ErGAWGb9NWP9aF5XQgDyx00iqAGCgRi1qQd5MQjtBwuC7mcktliFH263gpHdnHicfsB+n7Vnyg=="
532
532
  },
533
533
  "type-check@0.4.0": {
534
534
  "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
@@ -558,15 +558,15 @@
558
558
  },
559
559
  "workspace": {
560
560
  "dependencies": [
561
- "jsr:@simple-cdp/simple-cdp@^1.10.0",
562
- "jsr:@std/path@^1.1.2"
561
+ "jsr:@simple-cdp/simple-cdp@^1.10.1",
562
+ "jsr:@std/path@^1.1.6"
563
563
  ],
564
564
  "packageJson": {
565
565
  "dependencies": [
566
- "npm:@eslint/js@^9.39.1",
567
- "npm:esbuild@~0.27.4",
566
+ "npm:@eslint/js@^9.39.5",
567
+ "npm:esbuild@~0.27.7",
568
568
  "npm:eslint@^10.8.1",
569
- "npm:simple-cdp@^1.10.0"
569
+ "npm:simple-cdp@^1.10.1"
570
570
  ]
571
571
  }
572
572
  }
package/lib/browser.js CHANGED
@@ -80,8 +80,13 @@ async function launchBrowser(options = {}, indexPath = 0) {
80
80
  } catch (error) {
81
81
  await remove(profilePath, { recursive: true }).catch(() => { });
82
82
  profilePath = undefined;
83
- if (error instanceof errors.NotFound && indexPath + 1 < BROWSER_PATHS[build.os].length) {
84
- return launchBrowser(options, indexPath + 1);
83
+ if (error instanceof errors.NotFound) {
84
+ if (!options.executablePath && indexPath + 1 < BROWSER_PATHS[build.os].length) {
85
+ return launchBrowser(options, indexPath + 1);
86
+ }
87
+ throw new Error(options.executablePath ?
88
+ `The browser executable was not found at ${JSON.stringify(executablePath)}` :
89
+ "The browser executable was not found, use --browser-executable-path to set its location");
85
90
  }
86
91
  throw error;
87
92
  }
package/lib/cdp-client.js CHANGED
@@ -102,7 +102,7 @@ function relaunchBrowser() {
102
102
 
103
103
  async function getPageData(options) {
104
104
  const EMPTY_PAGE_URL = "about:blank";
105
- const pageContext = { options, consoleMessages: [], debugMessages: [], httpInfo: {} };
105
+ const pageContext = { options, consoleMessages: [], debugMessages: [], httpInfo: {}, fetchAbortController: new AbortController() };
106
106
  let targetInfo, cdp;
107
107
  try {
108
108
  logData(["Loading page", EMPTY_PAGE_URL], pageContext);
@@ -131,6 +131,7 @@ async function getPageData(options) {
131
131
  throw error;
132
132
  } finally {
133
133
  logData(["Closing page"], pageContext);
134
+ pageContext.fetchAbortController.abort();
134
135
  await closeTarget();
135
136
  logData(["Finishing"], pageContext);
136
137
  }
@@ -454,14 +455,16 @@ async function loadPage({ Page, Runtime }, { options, debugMessages }) {
454
455
  ]),
455
456
  waitForTimeout(loadTimeoutAbortSignal, options.browserLoadMaxTime, LOAD_TIMEOUT_ERROR_MESSAGE, LOAD_TIMEOUT_ERROR)
456
457
  ]);
458
+ // only called when the page loaded, these calls can hang forever on an
459
+ // unresponsive page and would mask the load timeout error
460
+ await Page.setLifecycleEventsEnabled({ enabled: false });
461
+ await Runtime.disable();
462
+ await Page.disable();
457
463
  return contextId;
458
464
  } finally {
459
465
  if (!loadTimeoutAbortSignal.aborted) {
460
466
  loadTimeoutAbortController.abort();
461
467
  }
462
- await Page.setLifecycleEventsEnabled({ enabled: false });
463
- await Runtime.disable();
464
- await Page.disable();
465
468
  }
466
469
  }
467
470
 
@@ -571,7 +574,7 @@ function setupPageDataCapture({ Runtime }, _contextId, { options, debugMessages
571
574
  });
572
575
  }
573
576
 
574
- async function setupBindings({ Page, Runtime }, contextId, { options, debugMessages }) {
577
+ async function setupBindings({ Page, Runtime }, contextId, { options, debugMessages, fetchAbortController }) {
575
578
  await Runtime.addBinding({ name: SET_PAGE_DATA_FUNCTION_NAME, executionContextId: contextId });
576
579
  if (options.embedScreenshot && options.compressContent) {
577
580
  await setupScreenshotCapture({ Page, Runtime }, contextId, { options, debugMessages });
@@ -582,7 +585,7 @@ async function setupBindings({ Page, Runtime }, contextId, { options, debugMessa
582
585
  await Runtime.addBinding({ name: FETCH_FUNCTION_NAME, executionContextId: contextId });
583
586
  Runtime.addEventListener(BINDING_CALLED_EVENT_TYPE, ignoringErrors(async ({ params }) => {
584
587
  if (params.name === FETCH_FUNCTION_NAME) {
585
- await handleFetchRequest({ Runtime }, params, contextId, { options, debugMessages });
588
+ await handleFetchRequest({ Runtime }, params, contextId, { options, debugMessages, fetchAbortController });
586
589
  }
587
590
  }, { options, debugMessages }));
588
591
  }
@@ -645,12 +648,12 @@ async function setupPdfCapture({ Page, Runtime }, contextId, { options, debugMes
645
648
  }
646
649
  }
647
650
 
648
- async function handleFetchRequest({ Runtime }, params, contextId, { options, debugMessages }) {
651
+ async function handleFetchRequest({ Runtime }, params, contextId, { options, debugMessages, fetchAbortController }) {
649
652
  const { payload } = params;
650
653
  const { requestId, url, options: fetchOptions } = JSON.parse(payload);
651
654
  logData(["Fetching URL", url], { options, debugMessages });
652
655
  try {
653
- const response = await fetch(url, fetchOptions);
656
+ const response = await fetch(url, Object.assign({}, fetchOptions, { signal: fetchAbortController.signal }));
654
657
  const arrayBuffer = await response.arrayBuffer();
655
658
  const base64Data = arrayBufferToBase64(arrayBuffer);
656
659
  const result = {
@@ -694,7 +697,7 @@ async function capturePageData({ Runtime }, contextId, { options, debugMessages
694
697
  CAPTURE_SCREENSHOT_FUNCTION_NAME,
695
698
  PRINT_TO_PDF_FUNCTION_NAME
696
699
  ])})`;
697
- const { result } = await Promise.race([
700
+ const { result, exceptionDetails } = await Promise.race([
698
701
  Runtime.evaluate({
699
702
  expression: captureScript,
700
703
  awaitPromise: true,
@@ -703,6 +706,12 @@ async function capturePageData({ Runtime }, contextId, { options, debugMessages
703
706
  }),
704
707
  waitForTimeout(captureTimeoutAbortSignal, options.browserCaptureMaxTime, CAPTURE_TIMEOUT_ERROR_MESSAGE, CAPTURE_TIMEOUT_ERROR)
705
708
  ]);
709
+ // `returnByValue` serializes the rejection value to an empty object, so
710
+ // the error is only readable in `exceptionDetails`
711
+ if (exceptionDetails) {
712
+ const { exception, text } = exceptionDetails;
713
+ throw new Error(exception && exception.description ? exception.description : text);
714
+ }
706
715
  if (result.subtype === ERROR_SUBTYPE) {
707
716
  throw new Error(result.description);
708
717
  }
@@ -53,6 +53,12 @@ const errors = {
53
53
  super(message);
54
54
  this.name = "NotFound";
55
55
  }
56
+ },
57
+ AlreadyExists: DENO_RUNTIME_DETECTED ? Deno.errors.AlreadyExists : class AlreadyExists extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = "AlreadyExists";
61
+ }
56
62
  }
57
63
  };
58
64
 
@@ -157,7 +163,7 @@ async function writeTextFile(path, data, options = {}) {
157
163
  if (options.append) {
158
164
  return fsPromise.appendFile(path, data, options);
159
165
  } else {
160
- return fsPromise.writeFile(path, data, options);
166
+ return nodeWriteFile(fsPromise, path, data, options);
161
167
  }
162
168
  }
163
169
  }
@@ -167,7 +173,18 @@ async function writeFile(path, data, options = {}) {
167
173
  return Deno.writeFile(path, data, options);
168
174
  } else {
169
175
  const fsPromise = await import(NODE_MODULES["fs"]);
170
- return fsPromise.writeFile(path, data, options);
176
+ return nodeWriteFile(fsPromise, path, data, options);
177
+ }
178
+ }
179
+
180
+ async function nodeWriteFile(fsPromise, path, data, options) {
181
+ if (options.createNew) {
182
+ options.flag = "wx";
183
+ }
184
+ try {
185
+ return await fsPromise.writeFile(path, data, options);
186
+ } catch (error) {
187
+ throw error.code == "EEXIST" ? new errors.AlreadyExists(error.message) : error;
171
188
  }
172
189
  }
173
190