single-file-cli 1.1.53 → 2.0.2

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.
Files changed (43) hide show
  1. package/{.eslintrc.js → .eslintrc.json} +5 -6
  2. package/Dockerfile +2 -1
  3. package/README.MD +56 -60
  4. package/args.js +252 -334
  5. package/back-ends/chromium-back-end.js +223 -0
  6. package/back-ends/chromium-browser.js +89 -0
  7. package/back-ends/chromium-constants.js +157 -0
  8. package/back-ends/{common/scripts.js → single-file-script.js} +21 -49
  9. package/build-lib-dev.sh +84 -0
  10. package/build-lib.sh +80 -3
  11. package/compile.sh +13 -0
  12. package/deno-polyfill.js +223 -0
  13. package/deno.json +13 -0
  14. package/deno.lock +49 -0
  15. package/lib/single-file-bundle.js +1 -0
  16. package/package.json +9 -33
  17. package/single-file +39 -14
  18. package/single-file-cli-api.js +32 -44
  19. package/back-ends/extensions/bypass-csp/index.js +0 -36
  20. package/back-ends/extensions/bypass-csp/manifest.json +0 -20
  21. package/back-ends/extensions/disable-web-security/index.js +0 -54
  22. package/back-ends/extensions/disable-web-security/manifest.json +0 -20
  23. package/back-ends/extensions/network-idle/bg.js +0 -61
  24. package/back-ends/extensions/network-idle/content.js +0 -29
  25. package/back-ends/extensions/network-idle/manifest.json +0 -31
  26. package/back-ends/extensions/signed/bypass_csp-0.0.3-an+fx.xpi +0 -0
  27. package/back-ends/extensions/signed/disable_web_security-0.0.3-an+fx.xpi +0 -0
  28. package/back-ends/extensions/signed/network_idle-0.0.2-an+fx.xpi +0 -0
  29. package/back-ends/jsdom.js +0 -159
  30. package/back-ends/playwright-chromium.js +0 -126
  31. package/back-ends/playwright-firefox.js +0 -115
  32. package/back-ends/playwright-webkit.js +0 -126
  33. package/back-ends/puppeteer-firefox.js +0 -172
  34. package/back-ends/puppeteer.js +0 -201
  35. package/back-ends/webdriver-chromium.js +0 -172
  36. package/back-ends/webdriver-gecko.js +0 -190
  37. package/lib/single-file-bootstrap.js +0 -1
  38. package/lib/single-file-frames.js +0 -1
  39. package/lib/single-file-hooks-frames.js +0 -1
  40. package/lib/single-file-zip.min.js +0 -1
  41. package/lib/single-file.js +0 -1
  42. package/rollup.config.dev.js +0 -57
  43. package/rollup.config.js +0 -58
@@ -0,0 +1,223 @@
1
+ /*
2
+ * Copyright 2010-2024 Gildas Lormeau
3
+ * contact : gildas.lormeau <at> gmail.com
4
+ *
5
+ * This file is part of SingleFile.
6
+ *
7
+ * The code in this file is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License
9
+ * (GNU AGPL) as published by the Free Software Foundation, either version 3
10
+ * of the License, or (at your option) any later version.
11
+ *
12
+ * The code in this file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * As additional permission under GNU AGPL version 3 section 7, you may
18
+ * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
19
+ * AGPL normally required by section 4, provided you include this license
20
+ * notice and a URL through which recipients can access the Corresponding
21
+ * Source.
22
+ */
23
+
24
+ /* global setTimeout, clearTimeout */
25
+
26
+ import { launchBrowser, closeBrowser } from "./chromium-browser.js";
27
+ import { getScriptSource, getHookScriptSource } from "./single-file-script.js";
28
+ import { getCDP } from "../deno-polyfill.js";
29
+
30
+ const LOAD_TIMEOUT_ERROR = "ERR_LOAD_TIMEOUT";
31
+ const NETWORK_IDLE_STATE = "networkIdle";
32
+ const NETWORK_STATES = ["networkAlmostIdle", "load", "DOMContentLoaded"];
33
+ const MINIMIZED_WINDOW_STATE = "minimized";
34
+ const SINGLE_FILE_WORLD_NAME = "singlefile";
35
+ const EMPTY_PAGE_URL = "about:blank";
36
+
37
+ export { initialize, getPageData, closeBrowser };
38
+
39
+ async function initialize(options) {
40
+ await launchBrowser(getBrowserOptions(options));
41
+ }
42
+
43
+ async function getPageData(options) {
44
+ let targetInfo;
45
+ const CDP = await getCDP();
46
+ try {
47
+ const targetInfo = await CDP.createTarget({ url: EMPTY_PAGE_URL });
48
+ const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger } = new CDP(targetInfo);
49
+ if (options.browserStartMinimized) {
50
+ const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.targetId });
51
+ if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
52
+ await Browser.setWindowBounds({ windowId, bounds: { windowState: MINIMIZED_WINDOW_STATE } });
53
+ }
54
+ }
55
+ if (options.browserIgnoreHTTPSErrors !== undefined && options.browserIgnoreHTTPSErrors) {
56
+ await Security.setIgnoreCertificateErrors({ ignore: true });
57
+ }
58
+ if (options.browserByPassCSP === undefined || options.browserByPassCSP) {
59
+ await Page.setBypassCSP({ enabled: true });
60
+ }
61
+ if (options.browserMobileEmulation) {
62
+ await Emulation.setDeviceMetricsOverride({ mobile: true });
63
+ }
64
+ if (options.httpProxyServer && options.httpProxyUsername) {
65
+ await Fetch.enable({ handleAuthRequests: true });
66
+ Fetch.addEventListener("authRequired", async ({ params }) => {
67
+ await Fetch.continueWithAuth({
68
+ requestId: params.requestId,
69
+ authChallengeResponse: {
70
+ response: "ProvideCredentials",
71
+ username: options.httpProxyUsername,
72
+ password: options.httpProxyPassword
73
+ }
74
+ });
75
+ });
76
+ Fetch.addEventListener("requestPaused", ({ params }) => Fetch.continueRequest({ requestId: params.requestId }));
77
+ }
78
+ if (options.httpHeaders && options.httpHeaders.length) {
79
+ await Network.setExtraHTTPHeaders({ headers: options.httpHeaders });
80
+ }
81
+ if (options.emulateMediaFeatures) {
82
+ for (const mediaFeature of options.emulateMediaFeatures) {
83
+ await Emulation.setEmulatedMedia({
84
+ media: mediaFeature.name,
85
+ features: mediaFeature.value.split(",").map(feature => feature.trim())
86
+ });
87
+ }
88
+ }
89
+ if (options.browserCookies && options.browserCookies.length) {
90
+ await Network.setCookies({ cookies: options.browserCookies });
91
+ }
92
+ let debuggerReady;
93
+ if (options.browserDebug) {
94
+ await Debugger.enable();
95
+ debuggerReady = new Promise(resolve => {
96
+ const SCRIPT_PARSED_EVENT = "scriptParsed";
97
+ const RESUMED_EVENT = "resumed";
98
+ Debugger.addEventListener(SCRIPT_PARSED_EVENT, onScriptParsed);
99
+
100
+ async function onScriptParsed() {
101
+ Debugger.removeEventListener(SCRIPT_PARSED_EVENT, onScriptParsed);
102
+ Debugger.addEventListener(RESUMED_EVENT, onResumed);
103
+ await Debugger.pause();
104
+ }
105
+
106
+ async function onResumed() {
107
+ Debugger.removeEventListener(RESUMED_EVENT, onResumed);
108
+ await Debugger.disable();
109
+ resolve();
110
+ }
111
+ });
112
+ }
113
+ await Page.addScriptToEvaluateOnNewDocument({
114
+ source: await getHookScriptSource(),
115
+ runImmediately: true
116
+ });
117
+ await Page.addScriptToEvaluateOnNewDocument({
118
+ source: await getScriptSource(options),
119
+ runImmediately: true,
120
+ worldName: SINGLE_FILE_WORLD_NAME
121
+ });
122
+ await Runtime.enable();
123
+ let topFrameId;
124
+ const executionContextIdPromise = new Promise(resolve => {
125
+ const CONTEXT_CREATED_EVENT = "executionContextCreated";
126
+ Runtime.addEventListener(CONTEXT_CREATED_EVENT, executionContextCreated);
127
+
128
+ async function executionContextCreated({ params }) {
129
+ const { context } = params;
130
+ if (context.auxData && context.auxData.isDefault && topFrameId === undefined) {
131
+ topFrameId = context.auxData.frameId;
132
+ } else if (context.name === SINGLE_FILE_WORLD_NAME && context.auxData && context.auxData.frameId === topFrameId) {
133
+ Runtime.removeEventListener(CONTEXT_CREATED_EVENT, executionContextCreated);
134
+ await Runtime.disable();
135
+ resolve(context.id);
136
+ }
137
+ }
138
+ });
139
+ await Page.enable();
140
+ await Page.setLifecycleEventsEnabled({ enabled: true });
141
+ const pageNavigated = Page.navigate({ url: options.url });
142
+ const pageReady = new Promise(resolve => {
143
+ const LIFE_CYCLE_EVENT = "lifecycleEvent";
144
+ let contentLoaded;
145
+ Page.addEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
146
+
147
+ async function onLifecycleEvent({ params }) {
148
+ const { name, frameId } = params;
149
+ if (topFrameId === undefined && frameId !== undefined) {
150
+ topFrameId = frameId;
151
+ }
152
+ if (name === "DOMContentLoaded" && topFrameId !== undefined && frameId === topFrameId) {
153
+ contentLoaded = true;
154
+ }
155
+ if (contentLoaded && name === (options.browserWaitUntil || NETWORK_IDLE_STATE) && frameId === topFrameId) {
156
+ if (options.browserWaitDelay) {
157
+ setTimeout(() => resolve, options.browserWaitDelay);
158
+ } else {
159
+ Page.removeEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
160
+ await Page.setLifecycleEventsEnabled({ enabled: false });
161
+ await Page.disable();
162
+ resolve();
163
+ }
164
+ }
165
+ }
166
+ });
167
+ let timeoutReady, timeoutId, resolveTimeoutReady;
168
+ if (options.browserLoadMaxTime) {
169
+ timeoutReady = new Promise((resolve, reject) => {
170
+ resolveTimeoutReady = resolve;
171
+ timeoutId = setTimeout(() => {
172
+ const error = new Error("Load timeout");
173
+ error.code = LOAD_TIMEOUT_ERROR;
174
+ reject(error);
175
+ }, options.browserLoadMaxTime);
176
+ });
177
+ }
178
+ await Promise.race([Promise.all([pageNavigated, pageReady, debuggerReady]), timeoutReady]);
179
+ if (timeoutId) {
180
+ clearTimeout(timeoutId);
181
+ resolveTimeoutReady();
182
+ }
183
+ const contextId = await executionContextIdPromise;
184
+ const { result } = await Runtime.evaluate({
185
+ expression: `singlefile.getPageData(${JSON.stringify(options)})`,
186
+ awaitPromise: true,
187
+ returnByValue: true,
188
+ contextId
189
+ });
190
+ const { value } = result;
191
+ if (options.compressContent) {
192
+ value.content = new Uint8Array(value.content);
193
+ }
194
+ return value;
195
+ } catch (error) {
196
+ if (error.code === LOAD_TIMEOUT_ERROR && options.browserWaitUntilFallback && options.browserWaitUntil) {
197
+ const browserWaitUntil = NETWORK_STATES[(NETWORK_STATES.indexOf(options.browserWaitUntil) + 1)];
198
+ if (browserWaitUntil) {
199
+ options.browserWaitUntil = browserWaitUntil;
200
+ return await getPageData(options);
201
+ }
202
+ }
203
+ throw error;
204
+ } finally {
205
+ if (targetInfo && !options.browserDebug) {
206
+ await CDP.closeTarget(targetInfo.targetId);
207
+ }
208
+ }
209
+ }
210
+
211
+ function getBrowserOptions(options) {
212
+ const browserOptions = {};
213
+ browserOptions.args = options.browserArgs ? JSON.parse(options.browserArgs) : [];
214
+ browserOptions.headless = options.browserHeadless && !options.browserDebug;
215
+ browserOptions.executablePath = options.browserExecutablePath;
216
+ browserOptions.browserDebug = options.browserDebug;
217
+ browserOptions.browserDisableWebSecurity = options.browserDisableWebSecurity === undefined || options.browserDisableWebSecurity;
218
+ browserOptions.browserWidth = options.browserWidth;
219
+ browserOptions.browserHeight = options.browserHeight;
220
+ browserOptions.userAgent = options.userAgent;
221
+ browserOptions.httpProxyServer = options.httpProxyServer;
222
+ return browserOptions;
223
+ }
@@ -0,0 +1,89 @@
1
+ /*
2
+ * Copyright 2010-2024 Gildas Lormeau
3
+ * contact : gildas.lormeau <at> gmail.com
4
+ *
5
+ * This file is part of SingleFile.
6
+ *
7
+ * The code in this file is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License
9
+ * (GNU AGPL) as published by the Free Software Foundation, either version 3
10
+ * of the License, or (at your option) any later version.
11
+ *
12
+ * The code in this file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * As additional permission under GNU AGPL version 3 section 7, you may
18
+ * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
19
+ * AGPL normally required by section 4, provided you include this license
20
+ * notice and a URL through which recipients can access the Corresponding
21
+ * Source.
22
+ */
23
+
24
+ import { BROWSER_PATHS, BROWSER_ARGS } from "./chromium-constants.js";
25
+ import { build, makeTempDir, Command, errors, remove } from "../deno-polyfill.js";
26
+
27
+ const PIPED_STD_CONFIG = "piped";
28
+
29
+ let child, profilePath;
30
+ export { launchBrowser, closeBrowser };
31
+
32
+ async function launchBrowser(options = {}, indexPath = 0) {
33
+ let path = BROWSER_PATHS[build.os][indexPath];
34
+ const args = Array.from(BROWSER_ARGS);
35
+ profilePath = await makeTempDir();
36
+ if (options.headless) {
37
+ args.push("--headless");
38
+ } else {
39
+ args.push("--start-maximized");
40
+ }
41
+ if (options.executablePath) {
42
+ path = options.executablePath;
43
+ }
44
+ if (options.browserDebug) {
45
+ args.push("--auto-open-devtools-for-tabs");
46
+ }
47
+ if (options.browserDisableWebSecurity) {
48
+ args.push("--disable-web-security");
49
+ }
50
+ if (options.browserWidth && options.browserHeight) {
51
+ args.push("--window-size=" + options.browserWidth + "," + options.browserHeight);
52
+ }
53
+ if (options.userAgent) {
54
+ args.push("--user-agent=" + options.userAgent);
55
+ }
56
+ if (options.httpProxyServer) {
57
+ args.push("--proxy-server=" + options.httpProxyServer);
58
+ }
59
+ if (options.args) {
60
+ args.push(...options.args);
61
+ }
62
+ args.push(`--user-data-dir=${profilePath}`);
63
+ const command = new Command(path, { args, stdout: PIPED_STD_CONFIG, stderr: PIPED_STD_CONFIG });
64
+ try {
65
+ child = await command.spawn();
66
+ } catch (error) {
67
+ if (error instanceof errors.NotFound) {
68
+ if (indexPath + 1 < BROWSER_PATHS[build.os].length) {
69
+ await launchBrowser(options, indexPath + 1);
70
+ } else {
71
+ throw error;
72
+ }
73
+ }
74
+ }
75
+ child.ref();
76
+ return child;
77
+ }
78
+
79
+ async function closeBrowser() {
80
+ if (child !== undefined) {
81
+ child.kill();
82
+ await child.status;
83
+ child = undefined;
84
+ }
85
+ if (profilePath !== undefined) {
86
+ await remove(profilePath, { recursive: true });
87
+ profilePath = undefined;
88
+ }
89
+ }
@@ -0,0 +1,157 @@
1
+ /*
2
+ * Copyright 2010-2024 Gildas Lormeau
3
+ * contact : gildas.lormeau <at> gmail.com
4
+ *
5
+ * This file is part of SingleFile.
6
+ *
7
+ * The code in this file is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License
9
+ * (GNU AGPL) as published by the Free Software Foundation, either version 3
10
+ * of the License, or (at your option) any later version.
11
+ *
12
+ * The code in this file is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * As additional permission under GNU AGPL version 3 section 7, you may
18
+ * distribute UNMODIFIED VERSIONS OF THIS file without the copy of the GNU
19
+ * AGPL normally required by section 4, provided you include this license
20
+ * notice and a URL through which recipients can access the Corresponding
21
+ * Source.
22
+ */
23
+
24
+ const BROWSER_ARGS = [
25
+ "--disable-field-trial-config",
26
+ "--disable-background-networking",
27
+ "--enable-features=NetworkService,NetworkServiceInProcess",
28
+ "--disable-background-timer-throttling",
29
+ "--disable-backgrounding-occluded-windows",
30
+ "--disable-back-forward-cache",
31
+ "--disable-breakpad",
32
+ "--disable-client-side-phishing-detection",
33
+ "--disable-component-extensions-with-background-pages",
34
+ "--disable-component-update",
35
+ "--no-default-browser-check",
36
+ "--disable-default-apps",
37
+ "--disable-dev-shm-usage",
38
+ "--disable-extensions",
39
+ "--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,HttpsUpgrades,PaintHolding",
40
+ "--allow-pre-commit-input",
41
+ "--disable-hang-monitor",
42
+ "--disable-ipc-flooding-protection",
43
+ "--disable-popup-blocking",
44
+ "--disable-prompt-on-repost",
45
+ "--disable-renderer-backgrounding",
46
+ "--force-color-profile=srgb",
47
+ "--metrics-recording-only",
48
+ "--no-first-run",
49
+ "--enable-automation",
50
+ "--password-store=basic",
51
+ "--use-mock-keychain",
52
+ "--no-service-autorun",
53
+ "--export-tagged-pdf",
54
+ "--disable-search-engine-choice-screen",
55
+ "--enable-use-zoom-for-dsf=false",
56
+ "--no-sandbox",
57
+ "--no-startup-window",
58
+ "--remote-debugging-port=9222",
59
+ "--bwsi"
60
+ ];
61
+ const BROWSER_PATHS = {
62
+ linux: [
63
+ "/usr/bin/chromium",
64
+ "/usr/bin/chromium-beta",
65
+ "/usr/bin/chromium-unstable",
66
+ "/usr/bin/chromium-dev",
67
+ "/usr/bin/chromium-browser",
68
+ "/usr/bin/chromium-browser-beta",
69
+ "/usr/bin/chromium-browser-unstable",
70
+ "/usr/bin/chromium-browser-dev",
71
+ "/opt/google/chrome/google-chrome",
72
+ "/opt/google/chrome-beta/google-chrome",
73
+ "/opt/google/chrome-unstable/google-chrome",
74
+ "/opt/google/chrome-dev/google-chrome",
75
+ "/usr/bin/google-chrome",
76
+ "/usr/bin/google-chrome-beta",
77
+ "/usr/bin/google-chrome-unstable",
78
+ "/usr/bin/google-chrome-dev",
79
+ "/usr/bin/brave-browser",
80
+ "/usr/bin/brave-browser-beta",
81
+ "/usr/bin/brave-browser-dev",
82
+ "/usr/bin/brave-browser-nightly",
83
+ "/usr/bin/brave",
84
+ "/usr/bin/brave-beta",
85
+ "/usr/bin/brave-dev",
86
+ "/usr/bin/brave-nightly",
87
+ "/usr/bin/microsoft-edge",
88
+ "/usr/bin/microsoft-edge-beta",
89
+ "/usr/bin/microsoft-edge-dev",
90
+ "/usr/bin/microsoft-edge-insider",
91
+ "/usr/bin/microsoft-edge-beta",
92
+ "/usr/bin/microsoft-edge-dev",
93
+ "/usr/bin/microsoft-edge-canary",
94
+ "/usr/bin/vivaldi",
95
+ "/usr/bin/vivaldi-stable",
96
+ "/usr/bin/vivaldi-snapshot",
97
+ "/usr/bin/vivaldi-beta",
98
+ "/usr/bin/opera",
99
+ "/usr/bin/opera-beta",
100
+ "/usr/bin/opera-developer",
101
+ "/usr/bin/opera-snapshot",
102
+ "/usr/bin/yandex-browser-beta",
103
+ "/usr/bin/yandex-browser-alpha",
104
+ "/usr/bin/yandex-browser",
105
+ "/usr/bin/yandex",
106
+ "/usr/bin/yandex-beta",
107
+ "/usr/bin/yandex-alpha"
108
+ ],
109
+ darwin: [
110
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
111
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
112
+ "/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev",
113
+ "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta",
114
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
115
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
116
+ "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
117
+ "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
118
+ "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary",
119
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
120
+ "/Applications/Vivaldi.app/Contents/MacOS/Vivaldi",
121
+ "/Applications/Opera.app/Contents/MacOS/Opera",
122
+ "/Applications/Yandex.app/Contents/MacOS/Yandex"
123
+ ],
124
+ windows: [
125
+ "C:\\Program Files\\Chromium\\Application\\chrome.exe",
126
+ "C:\\Program Files (x86)\\Chromium\\Application\\chrome.exe",
127
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
128
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
129
+ "C:\\Program Files\\Google\\Chrome Dev\\Application\\chrome.exe",
130
+ "C:\\Program Files (x86)\\Google\\Chrome Dev\\Application\\chrome.exe",
131
+ "C:\\Program Files\\Google\\Chrome Beta\\Application\\chrome.exe",
132
+ "C:\\Program Files (x86)\\Google\\Chrome Beta\\Application\\chrome.exe",
133
+ "C:\\Program Files\\Google\\Chrome SxS\\Application\\chrome.exe",
134
+ "C:\\Program Files (x86)\\Google\\Chrome SxS\\Application\\chrome.exe",
135
+ "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
136
+ "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
137
+ "C:\\Program Files\\Microsoft\\Edge Dev\\Application\\msedge.exe",
138
+ "C:\\Program Files (x86)\\Microsoft\\Edge Dev\\Application\\msedge.exe",
139
+ "C:\\Program Files\\Microsoft\\Edge Beta\\Application\\msedge.exe",
140
+ "C:\\Program Files (x86)\\Microsoft\\Edge Beta\\Application\\msedge.exe",
141
+ "C:\\Program Files\\Microsoft\\Edge SxS\\Application\\msedge.exe",
142
+ "C:\\Program Files (x86)\\Microsoft\\Edge SxS\\Application\\msedge.exe",
143
+ "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
144
+ "C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe",
145
+ "C:\\Program Files\\Vivaldi\\Application\\vivaldi.exe",
146
+ "C:\\Program Files (x86)\\Vivaldi\\Application\\vivaldi.exe",
147
+ "C:\\Program Files\\Opera\\launcher.exe",
148
+ "C:\\Program Files (x86)\\Opera\\launcher.exe",
149
+ "C:\\Program Files\\Yandex\\YandexBrowser\\Application\\browser.exe",
150
+ "C:\\Program Files (x86)\\Yandex\\YandexBrowser\\Application\\browser.exe"
151
+ ]
152
+ };
153
+
154
+ export {
155
+ BROWSER_ARGS,
156
+ BROWSER_PATHS
157
+ };
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2010-2020 Gildas Lormeau
2
+ * Copyright 2010-2024 Gildas Lormeau
3
3
  * contact : gildas.lormeau <at> gmail.com
4
4
  *
5
5
  * This file is part of SingleFile.
@@ -21,18 +21,12 @@
21
21
  * Source.
22
22
  */
23
23
 
24
- /* global require, exports, singlefile, XMLHttpRequest */
24
+ /* global singlefile, XMLHttpRequest */
25
25
 
26
- const fs = require("fs");
26
+ import { script, hookScript, zipScript } from "../lib/single-file-bundle.js";
27
+ import { readTextFile } from "../deno-polyfill.js";
27
28
 
28
- const SCRIPTS = [
29
- "lib/single-file.js",
30
- "lib/single-file-bootstrap.js",
31
- "lib/single-file-hooks-frames.js",
32
- "lib/single-file-zip.min.js"
33
- ];
34
-
35
- const basePath = "./../../";
29
+ export { getScriptSource, getHookScriptSource, getZipScriptSource };
36
30
 
37
31
  function initSingleFile() {
38
32
  singlefile.init({
@@ -64,47 +58,25 @@ function initSingleFile() {
64
58
  });
65
59
  }
66
60
 
67
- function browserFreezePrototypes() {
68
- Object.freeze(Object.prototype);
69
- Object.freeze(Function.prototype);
70
- Object.freeze(Array.prototype);
71
- Object.freeze(String.prototype);
72
- Object.freeze(Number.prototype);
73
- Object.freeze(Boolean.prototype);
74
- Object.freeze(Date.prototype);
75
- Object.freeze(RegExp.prototype);
76
- Object.freeze(Math.prototype);
77
- Object.freeze(Error.prototype);
78
- Object.freeze(JSON.prototype);
79
- }
80
-
81
- exports.get = async options => {
82
- let scripts = "let _singleFileDefine; if (typeof define !== 'undefined') { _singleFileDefine = define; define = null }";
83
- scripts += await readScriptFiles(SCRIPTS, basePath);
84
- scripts += await readScriptFiles(options && options.browserScripts ? options.browserScripts : [], "");
61
+ async function getScriptSource(options) {
62
+ let source = "";
63
+ source += script;
64
+ source += await readScriptFiles(options && options.browserScripts ? options.browserScripts : []);
85
65
  if (options.browserStylesheets && options.browserStylesheets.length) {
86
- scripts += "addEventListener(\"load\",()=>{const styleElement=document.createElement(\"style\");styleElement.textContent=" + JSON.stringify(await readScriptFiles(options.browserStylesheets, "")) + ";document.body.appendChild(styleElement);});";
66
+ source += "addEventListener(\"load\",()=>{const styleElement=document.createElement(\"style\");styleElement.textContent=" + JSON.stringify(await readScriptFiles(options.browserStylesheets)) + ";document.body.appendChild(styleElement);});";
87
67
  }
88
- if (options.browserFreezePrototypes) {
89
- scripts += "(" + browserFreezePrototypes.toString() + ")();";
90
- }
91
- scripts += "if (_singleFileDefine) { define = _singleFileDefine; _singleFileDefine = null }";
92
- scripts += "(" + initSingleFile.toString() + ")();";
93
- return scripts;
94
- };
68
+ source += "(" + initSingleFile.toString() + ")();";
69
+ return source;
70
+ }
95
71
 
96
- async function readScriptFiles(paths, basePath = "../../../") {
97
- return (await Promise.all(paths.map(path => readScriptFile(path, basePath)))).join("");
72
+ async function getHookScriptSource() {
73
+ return hookScript;
98
74
  }
99
75
 
100
- function readScriptFile(path, basePath) {
101
- return new Promise((resolve, reject) =>
102
- fs.readFile(basePath ? require.resolve(basePath + path) : path, (err, data) => {
103
- if (err) {
104
- reject(err);
105
- } else {
106
- resolve(data.toString() + "\n");
107
- }
108
- })
109
- );
76
+ async function getZipScriptSource() {
77
+ return zipScript;
78
+ }
79
+
80
+ async function readScriptFiles(paths) {
81
+ return (await Promise.all(paths.map(path => readTextFile(path)))).join("");
110
82
  }
@@ -0,0 +1,84 @@
1
+ #!/bin/sh
2
+
3
+ mkdir -p node_modules/single-file-core
4
+ cp -R ../single-file-core/* node_modules/single-file-core
5
+
6
+ echo "
7
+ import { build } from 'npm:esbuild';
8
+
9
+ await build({
10
+ entryPoints: [
11
+ 'node_modules/single-file-core/single-file.js'
12
+ ],
13
+ bundle: true,
14
+ globalName: 'singlefile',
15
+ outdir: 'lib/',
16
+ platform: 'browser',
17
+ sourcemap: false,
18
+ minify: false,
19
+ format: 'iife',
20
+ plugins: [],
21
+ });
22
+
23
+ await build({
24
+ entryPoints: [
25
+ 'node_modules/single-file-core/single-file-bootstrap.js'
26
+ ],
27
+ bundle: true,
28
+ globalName: 'singlefileBootstrap',
29
+ outdir: 'lib/',
30
+ platform: 'browser',
31
+ sourcemap: false,
32
+ minify: false,
33
+ format: 'iife',
34
+ plugins: [],
35
+ });
36
+
37
+ await build({
38
+ entryPoints: [
39
+ 'node_modules/single-file-core/single-file-hooks-frames.js'
40
+ ],
41
+ bundle: true,
42
+ outdir: 'lib/',
43
+ platform: 'browser',
44
+ sourcemap: false,
45
+ minify: false,
46
+ format: 'iife',
47
+ plugins: [],
48
+ });
49
+
50
+ await build({
51
+ entryPoints: [
52
+ 'node_modules/single-file-core/vendor/zip/zip.min.js'
53
+ ],
54
+ bundle: true,
55
+ globalName: 'zip',
56
+ outdir: 'lib/',
57
+ platform: 'browser',
58
+ sourcemap: false,
59
+ minify: false,
60
+ format: 'iife',
61
+ plugins: [],
62
+ });
63
+
64
+ const SCRIPTS = [
65
+ 'lib/single-file.js',
66
+ 'lib/single-file-bootstrap.js',
67
+ 'lib/zip.min.js'
68
+ ];
69
+
70
+ let script = '';
71
+ const scripts = SCRIPTS.map(script => Deno.readTextFile(script));
72
+ const sources = await Promise.all(scripts);
73
+ script += 'const script = ' + JSON.stringify(sources.join(';')) + ';';
74
+ const hookScript = await Deno.readTextFile('lib/single-file-hooks-frames.js');
75
+ script += 'const hookScript = ' + JSON.stringify(hookScript) + ';';
76
+ const zipScript = await Deno.readTextFile('lib/zip.min.js');
77
+ script += 'const zipScript = ' + JSON.stringify(zipScript) + ';';
78
+ script += 'export { script, zipScript, hookScript };';
79
+ await Deno.writeTextFile('lib/single-file-bundle.js', script)
80
+ await Promise.all(SCRIPTS.map(script => Deno.remove(script)));
81
+ await Deno.remove('lib/single-file-hooks-frames.js');
82
+ " | deno run --allow-read --allow-write --allow-net --allow-run --allow-env --lock=node_modules/deno.lock.tmp -
83
+
84
+ rm -rf node_modules