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 +1 -1
- package/compile.sh +5 -5
- package/deno.json +3 -3
- package/deno.lock +14 -14
- package/lib/browser.js +7 -2
- package/lib/cdp-client.js +18 -9
- package/lib/deno-polyfill.js +19 -2
- package/lib/single-file-bundle.js +1 -1
- package/lib/version.js +1 -1
- package/options.js +192 -94
- package/package.json +5 -5
- package/single-file-cli-api.js +39 -19
- package/single-file-launcher.js +5 -93
- package/test/e2e/errors-file.test.js +31 -0
- package/test/e2e/frame-gate.test.js +2 -1
- package/test/e2e/timeouts.test.js +70 -0
- package/test/e2e/urls-file.test.js +37 -0
- package/test/unit/cli-usage.test.js +56 -0
- package/test/unit/options.test.js +136 -0
- package/test/unit/write-file.test.js +37 -0
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.
|
|
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.
|
|
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.
|
|
10
|
-
"path": "jsr:@std/path@^1.1.
|
|
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.
|
|
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.
|
|
7
|
-
"npm:@eslint/js@^9.39.
|
|
8
|
-
"npm:esbuild@~0.27.
|
|
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.
|
|
10
|
+
"npm:simple-cdp@^1.10.1": "1.10.1"
|
|
11
11
|
},
|
|
12
12
|
"jsr": {
|
|
13
|
-
"@simple-cdp/simple-cdp@1.10.
|
|
14
|
-
"integrity": "
|
|
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.
|
|
531
|
-
"integrity": "sha512-
|
|
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.
|
|
562
|
-
"jsr:@std/path@^1.1.
|
|
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.
|
|
567
|
-
"npm:esbuild@~0.27.
|
|
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.
|
|
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
|
|
84
|
-
|
|
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
|
}
|
package/lib/deno-polyfill.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|