diff --git a/README.md b/README.md
index 047c331..fef3e0f 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@
- 🎐 Nearly 20 times smaller than an Electron package (around 5M!)
- 🚀 With Rust Tauri, Pake is much more lightweight and faster than JS-based frameworks.
- 📦 Battery-included package — shortcut pass-through, immersive windows, and minimalist customization.
-- 👻 Pake is just a simple tool — replace the old bundle approach with Rust (though PWA is good enough).
+- 👻 Pake is just a simple tool — replace the old bundle approach with Tauri (though PWA is good enough).
## Popular Packages
@@ -60,8 +60,8 @@
-  |
-  |
+  |
+  |
| YouTube Music
@@ -76,7 +76,7 @@
|
-  |
+  |
 |
diff --git a/README_CN.md b/README_CN.md
index 5b892f5..1c5ee3f 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -25,7 +25,7 @@
- 🎐 相比传统的 Electron 套壳打包,要小将近 20 倍,5M 上下。
- 🚀 Pake 的底层使用的 Rust Tauri 框架,性能体验较 JS 框架要轻快不少,内存小很多。
- 📦 不是单纯打包,实现了快捷键的透传、沉浸式的窗口、拖动、样式改写、去广告、产品的极简风格定制。
-- 👻 只是一个很简单的小玩具,用 Rust 替代之前套壳网页打包的老思路,其实 PWA 也很好。
+- 👻 只是一个很简单的小玩具,用 Tauri 替代之前套壳网页打包的老思路,其实 PWA 也很好。
## 常用包下载
@@ -59,8 +59,8 @@
-  |
-  |
+  |
+  |
| YouTube Music
@@ -75,7 +75,7 @@
|
-  |
+  |
 |
@@ -223,13 +223,6 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
Tlntin
-
-
-
-
- Pan93412
-
- |
@@ -237,6 +230,13 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
Santree
|
+
+
+
+
+ Pan93412
+
+ |
@@ -309,6 +309,20 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
|
+
+
+
+
+ Abu Taher Siddik
+
+ |
+
+
+
+
+ An Li
+
+ |
@@ -343,7 +357,8 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
Po Chen
- |
+
+
@@ -357,8 +372,7 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
Null
- |
-
+
@@ -372,6 +386,13 @@ Pake 的发展离不开这些 Hacker 们,一起贡献了大量能力,也欢
Ranger
+ |
+
+
+
+
+ 贺天卓
+
|
diff --git a/dist/cli.js b/dist/cli.js
index fe24d02..7c430ac 100644
--- a/dist/cli.js
+++ b/dist/cli.js
@@ -20,7 +20,7 @@ import psl from 'psl';
import isUrl from 'is-url';
var name = "pake-cli";
-var version = "2.3.4";
+var version = "2.3.5";
var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
var engines = {
node: ">=16.0.0"
@@ -67,42 +67,42 @@ var type = "module";
var exports = "./dist/pake.js";
var license = "MIT";
var dependencies = {
- "@tauri-apps/api": "^1.4.0",
- "@tauri-apps/cli": "^1.4.0",
- axios: "^1.1.3",
- chalk: "^5.1.2",
- commander: "^11.0.0",
- "file-type": "^18.0.0",
- "fs-extra": "^11.1.0",
+ "@tauri-apps/api": "^1.5.1",
+ "@tauri-apps/cli": "^1.5.6",
+ axios: "^1.6.1",
+ chalk: "^5.3.0",
+ commander: "^11.1.0",
+ "file-type": "^18.6.0",
+ "fs-extra": "^11.1.1",
"is-url": "^1.2.4",
loglevel: "^1.8.1",
- ora: "^6.1.2",
+ ora: "^7.0.1",
prompts: "^2.4.2",
psl: "^1.9.0",
shelljs: "^0.8.5",
"tmp-promise": "^3.0.3",
- "update-notifier": "^6.0.2"
+ "update-notifier": "^7.0.0"
};
var devDependencies = {
- "@rollup/plugin-alias": "^4.0.2",
- "@rollup/plugin-commonjs": "^23.0.2",
- "@rollup/plugin-json": "^5.0.2",
- "@rollup/plugin-replace": "^5.0.2",
- "@rollup/plugin-terser": "^0.1.0",
- "@types/fs-extra": "^9.0.13",
- "@types/is-url": "^1.2.30",
- "@types/page-icon": "^0.3.4",
- "@types/prompts": "^2.4.1",
- "@types/psl": "^1.1.0",
- "@types/shelljs": "^0.8.11",
- "@types/tmp": "^0.2.3",
- "@types/update-notifier": "^6.0.1",
+ "@rollup/plugin-alias": "^5.0.1",
+ "@rollup/plugin-commonjs": "^25.0.7",
+ "@rollup/plugin-json": "^6.0.1",
+ "@rollup/plugin-replace": "^5.0.5",
+ "@rollup/plugin-terser": "^0.4.4",
+ "@types/fs-extra": "^11.0.4",
+ "@types/is-url": "^1.2.32",
+ "@types/page-icon": "^0.3.6",
+ "@types/prompts": "^2.4.8",
+ "@types/psl": "^1.1.3",
+ "@types/shelljs": "^0.8.15",
+ "@types/tmp": "^0.2.6",
+ "@types/update-notifier": "^6.0.7",
"app-root-path": "^3.1.0",
"cross-env": "^7.0.3",
- rollup: "^3.3.0",
- "rollup-plugin-typescript2": "^0.34.1",
- tslib: "^2.4.1",
- typescript: "^4.9.3"
+ rollup: "^4.3.0",
+ "rollup-plugin-typescript2": "^0.36.0",
+ tslib: "^2.6.2",
+ typescript: "^5.2.2"
};
var packageJson = {
name: name,
@@ -124,7 +124,7 @@ var packageJson = {
var windows = [
{
- url: "https://weread.qq.com/",
+ url: "https://weread.qq.com",
transparent: true,
fullscreen: false,
width: 1200,
@@ -307,752 +307,752 @@ var LinuxConf = {
tauri: tauri
};
-const platformConfigs = {
- win32: WinConf,
- darwin: MacConf,
- linux: LinuxConf,
-};
-const { platform: platform$2 } = process;
-// @ts-ignore
-const platformConfig = platformConfigs[platform$2];
-let tauriConfig = {
- tauri: {
- ...CommonConf.tauri,
- bundle: platformConfig.tauri.bundle,
- },
- package: CommonConf.package,
- build: CommonConf.build,
- pake: pakeConf,
+const platformConfigs = {
+ win32: WinConf,
+ darwin: MacConf,
+ linux: LinuxConf,
+};
+const { platform: platform$2 } = process;
+// @ts-ignore
+const platformConfig = platformConfigs[platform$2];
+let tauriConfig = {
+ tauri: {
+ ...CommonConf.tauri,
+ bundle: platformConfig.tauri.bundle,
+ },
+ package: CommonConf.package,
+ build: CommonConf.build,
+ pake: pakeConf,
};
-// Generates an identifier based on the given URL.
-function getIdentifier(url) {
- const postFixHash = crypto.createHash('md5').update(url).digest('hex').substring(0, 6);
- return `com.pake.${postFixHash}`;
-}
-async function promptText(message, initial) {
- const response = await prompts({
- type: 'text',
- name: 'content',
- message,
- initial,
- });
- return response.content;
-}
-function capitalizeFirstLetter(string) {
- return string.charAt(0).toUpperCase() + string.slice(1);
-}
-function getSpinner(text) {
- const loadingType = {
- interval: 80,
- frames: ['✦', '✶', '✺', '✵', '✸', '✹', '✺'],
- };
- return ora({
- text: `${chalk.cyan(text)}\n`,
- spinner: loadingType,
- color: 'cyan',
- }).start();
+// Generates an identifier based on the given URL.
+function getIdentifier(url) {
+ const postFixHash = crypto.createHash('md5').update(url).digest('hex').substring(0, 6);
+ return `com.pake.${postFixHash}`;
+}
+async function promptText(message, initial) {
+ const response = await prompts({
+ type: 'text',
+ name: 'content',
+ message,
+ initial,
+ });
+ return response.content;
+}
+function capitalizeFirstLetter(string) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+}
+function getSpinner(text) {
+ const loadingType = {
+ interval: 80,
+ frames: ['✦', '✶', '✺', '✵', '✸', '✹', '✺'],
+ };
+ return ora({
+ text: `${chalk.cyan(text)}\n`,
+ spinner: loadingType,
+ color: 'cyan',
+ }).start();
}
-const { platform: platform$1 } = process;
-const IS_MAC = platform$1 === 'darwin';
-const IS_WIN = platform$1 === 'win32';
+const { platform: platform$1 } = process;
+const IS_MAC = platform$1 === 'darwin';
+const IS_WIN = platform$1 === 'win32';
const IS_LINUX = platform$1 === 'linux';
-// Convert the current module URL to a file path
-const currentModulePath = fileURLToPath(import.meta.url);
-// Resolve the parent directory of the current module
-const npmDirectory = path.join(path.dirname(currentModulePath), '..');
+// Convert the current module URL to a file path
+const currentModulePath = fileURLToPath(import.meta.url);
+// Resolve the parent directory of the current module
+const npmDirectory = path.join(path.dirname(currentModulePath), '..');
const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri');
-function shellExec(command) {
- return new Promise((resolve, reject) => {
- shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, code => {
- if (code === 0) {
- resolve(0);
- }
- else {
- reject(new Error(`${code}`));
- }
- });
- });
+function shellExec(command) {
+ return new Promise((resolve, reject) => {
+ shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, code => {
+ if (code === 0) {
+ resolve(0);
+ }
+ else {
+ reject(new Error(`${code}`));
+ }
+ });
+ });
}
-const logger = {
- info(...msg) {
- log.info(...msg.map(m => chalk.white(m)));
- },
- debug(...msg) {
- log.debug(...msg);
- },
- error(...msg) {
- log.error(...msg.map(m => chalk.red(m)));
- },
- warn(...msg) {
- log.info(...msg.map(m => chalk.yellow(m)));
- },
- success(...msg) {
- log.info(...msg.map(m => chalk.green(m)));
- },
+const logger = {
+ info(...msg) {
+ log.info(...msg.map(m => chalk.white(m)));
+ },
+ debug(...msg) {
+ log.debug(...msg);
+ },
+ error(...msg) {
+ log.error(...msg.map(m => chalk.red(m)));
+ },
+ warn(...msg) {
+ log.info(...msg.map(m => chalk.yellow(m)));
+ },
+ success(...msg) {
+ log.info(...msg.map(m => chalk.green(m)));
+ },
};
-const resolve = promisify(dns.resolve);
-const ping = async (host) => {
- const lookup = promisify(dns.lookup);
- const ip = await lookup(host);
- const start = new Date();
- // Prevent timeouts from affecting user experience.
- const requestPromise = new Promise((resolve, reject) => {
- const req = http.get(`http://${ip.address}`, res => {
- const delay = new Date().getTime() - start.getTime();
- res.resume();
- resolve(delay);
- });
- req.on('error', err => {
- reject(err);
- });
- });
- const timeoutPromise = new Promise((_, reject) => {
- setTimeout(() => {
- reject(new Error('Request timed out after 3 seconds'));
- }, 1000);
- });
- return Promise.race([requestPromise, timeoutPromise]);
-};
-async function isChinaDomain(domain) {
- try {
- const [ip] = await resolve(domain);
- return await isChinaIP(ip, domain);
- }
- catch (error) {
- logger.debug(`${domain} can't be parse!`);
- return true;
- }
-}
-async function isChinaIP(ip, domain) {
- try {
- const delay = await ping(ip);
- logger.debug(`${domain} latency is ${delay} ms`);
- return delay > 1000;
- }
- catch (error) {
- logger.debug(`ping ${domain} failed!`);
- return true;
- }
+const resolve = promisify(dns.resolve);
+const ping = async (host) => {
+ const lookup = promisify(dns.lookup);
+ const ip = await lookup(host);
+ const start = new Date();
+ // Prevent timeouts from affecting user experience.
+ const requestPromise = new Promise((resolve, reject) => {
+ const req = http.get(`http://${ip.address}`, res => {
+ const delay = new Date().getTime() - start.getTime();
+ res.resume();
+ resolve(delay);
+ });
+ req.on('error', err => {
+ reject(err);
+ });
+ });
+ const timeoutPromise = new Promise((_, reject) => {
+ setTimeout(() => {
+ reject(new Error('Request timed out after 3 seconds'));
+ }, 1000);
+ });
+ return Promise.race([requestPromise, timeoutPromise]);
+};
+async function isChinaDomain(domain) {
+ try {
+ const [ip] = await resolve(domain);
+ return await isChinaIP(ip, domain);
+ }
+ catch (error) {
+ logger.debug(`${domain} can't be parse!`);
+ return true;
+ }
+}
+async function isChinaIP(ip, domain) {
+ try {
+ const delay = await ping(ip);
+ logger.debug(`${domain} latency is ${delay} ms`);
+ return delay > 1000;
+ }
+ catch (error) {
+ logger.debug(`ping ${domain} failed!`);
+ return true;
+ }
}
-async function installRust() {
- const isActions = process.env.GITHUB_ACTIONS;
- const isInChina = await isChinaDomain('sh.rustup.rs');
- const rustInstallScriptForMac = isInChina && !isActions
- ? 'export RUSTUP_DIST_SERVER="https://rsproxy.cn" && export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup" && curl --proto "=https" --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | sh'
- : "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y";
- const rustInstallScriptForWindows = 'winget install --id Rustlang.Rustup';
- const spinner = getSpinner('Downloading Rust...');
- try {
- await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
- spinner.succeed(chalk.green('Rust installed successfully!'));
- }
- catch (error) {
- console.error('Error installing Rust:', error.message);
- spinner.fail(chalk.red('Rust installation failed!'));
- process.exit(1);
- }
-}
-function checkRustInstalled() {
- return shelljs.exec('rustc --version', { silent: true }).code === 0;
+async function installRust() {
+ const isActions = process.env.GITHUB_ACTIONS;
+ const isInChina = await isChinaDomain('sh.rustup.rs');
+ const rustInstallScriptForMac = isInChina && !isActions
+ ? 'export RUSTUP_DIST_SERVER="https://rsproxy.cn" && export RUSTUP_UPDATE_ROOT="https://rsproxy.cn/rustup" && curl --proto "=https" --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | sh'
+ : "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y";
+ const rustInstallScriptForWindows = 'winget install --id Rustlang.Rustup';
+ const spinner = getSpinner('Downloading Rust...');
+ try {
+ await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
+ spinner.succeed(chalk.green('Rust installed successfully!'));
+ }
+ catch (error) {
+ console.error('Error installing Rust:', error.message);
+ spinner.fail(chalk.red('Rust installation failed!'));
+ process.exit(1);
+ }
+}
+function checkRustInstalled() {
+ return shelljs.exec('rustc --version', { silent: true }).code === 0;
}
-async function combineFiles(files, output) {
- const contents = files.map(file => {
- const fileContent = fs.readFileSync(file);
- if (file.endsWith('.css')) {
- return "window.addEventListener('DOMContentLoaded', (_event) => { const css = `" + fileContent + "`; const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); });";
- }
- return "window.addEventListener('DOMContentLoaded', (_event) => { " + fileContent + " });";
- });
- fs.writeFileSync(output, contents.join('\n'));
- return files;
+async function combineFiles(files, output) {
+ const contents = files.map(file => {
+ const fileContent = fs.readFileSync(file);
+ if (file.endsWith('.css')) {
+ return "window.addEventListener('DOMContentLoaded', (_event) => { const css = `" + fileContent + "`; const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); });";
+ }
+ return "window.addEventListener('DOMContentLoaded', (_event) => { " + fileContent + " });";
+ });
+ fs.writeFileSync(output, contents.join('\n'));
+ return files;
}
-async function mergeConfig(url, options, tauriConf) {
- const { width, height, fullscreen, transparent, userAgent, showMenu, showSystemTray, systemTrayIcon, iterCopyFile, identifier, name, resizable = true, inject, safeDomain, } = options;
- const { platform } = process;
- // Set Windows parameters.
- const tauriConfWindowOptions = {
- width,
- height,
- fullscreen,
- transparent,
- resizable,
- };
- Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
- tauriConf.package.productName = name;
- tauriConf.tauri.bundle.identifier = identifier;
- //Judge the type of URL, whether it is a file or a website.
- const pathExists = await fsExtra.pathExists(url);
- if (pathExists) {
- logger.warn('✼ Your input might be a local file.');
- tauriConf.pake.windows[0].url_type = 'local';
- const fileName = path.basename(url);
- const dirName = path.dirname(url);
- const distDir = path.join(npmDirectory, 'dist');
- const distBakDir = path.join(npmDirectory, 'dist_bak');
- if (!iterCopyFile) {
- const urlPath = path.join(distDir, fileName);
- await fsExtra.copy(url, urlPath);
- }
- else {
- fsExtra.moveSync(distDir, distBakDir, { overwrite: true });
- fsExtra.copySync(dirName, distDir, { overwrite: true });
- // ignore it, because about_pake.html have be erased.
- // const filesToCopyBack = ['cli.js', 'about_pake.html'];
- const filesToCopyBack = ['cli.js'];
- await Promise.all(filesToCopyBack.map(file => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
- }
- tauriConf.pake.windows[0].url = fileName;
- tauriConf.pake.windows[0].url_type = 'local';
- }
- else {
- tauriConf.pake.windows[0].url_type = 'web';
- // Set the secure domain for calling window.__TAURI__ to the application domain that has been set.
- tauriConf.tauri.security.dangerousRemoteDomainIpcAccess = [
- {
- domain: new URL(url).hostname,
- windows: ['pake'],
- enableTauriAPI: true,
- },
- ];
- }
- if (safeDomain.length > 0) {
- tauriConf.tauri.security.dangerousRemoteDomainIpcAccess = [
- ...tauriConf.tauri.security.dangerousRemoteDomainIpcAccess,
- ...safeDomain.map(domain => ({
- domain,
- windows: ['pake'],
- enableTauriAPI: true,
- })),
- ];
- }
- const platformMap = {
- win32: 'windows',
- linux: 'linux',
- darwin: 'macos',
- };
- const currentPlatform = platformMap[platform];
- if (userAgent.length > 0) {
- tauriConf.pake.user_agent[currentPlatform] = userAgent;
- }
- tauriConf.pake.menu[currentPlatform] = showMenu;
- tauriConf.pake.system_tray[currentPlatform] = showSystemTray;
- // Processing targets are currently only open to Linux.
- if (platform === 'linux') {
- delete tauriConf.tauri.bundle.deb.files;
- const validTargets = ['all', 'deb', 'appimage'];
- if (validTargets.includes(options.targets)) {
- tauriConf.tauri.bundle.targets = options.targets === 'all' ? ['deb', 'appimage'] : [options.targets];
- }
- else {
- logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
- }
- }
- // Set icon.
- const platformIconMap = {
- win32: {
- fileExt: '.ico',
- path: `png/${name.toLowerCase()}_256.ico`,
- defaultIcon: 'png/icon_256.ico',
- message: 'Windows icon must be .ico and 256x256px.',
- },
- linux: {
- fileExt: '.png',
- path: `png/${name.toLowerCase()}_512.png`,
- defaultIcon: 'png/icon_512.png',
- message: 'Linux icon must be .png and 512x512px.',
- },
- darwin: {
- fileExt: '.icns',
- path: `icons/${name.toLowerCase()}.icns`,
- defaultIcon: 'icons/icon.icns',
- message: 'macOS icon must be .icns type.',
- },
- };
- const iconInfo = platformIconMap[platform];
- const exists = await fsExtra.pathExists(options.icon);
- if (exists) {
- let updateIconPath = true;
- let customIconExt = path.extname(options.icon).toLowerCase();
- if (customIconExt !== iconInfo.fileExt) {
- updateIconPath = false;
- logger.warn(`✼ ${iconInfo.message}, but you give ${customIconExt}`);
- tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
- }
- else {
- const iconPath = path.join(npmDirectory, 'src-tauri/', iconInfo.path);
- tauriConf.tauri.bundle.resources = [iconInfo.path];
- await fsExtra.copy(options.icon, iconPath);
- }
- if (updateIconPath) {
- tauriConf.tauri.bundle.icon = [options.icon];
- }
- else {
- logger.warn(`✼ Icon will remain as default.`);
- }
- }
- else {
- logger.warn('✼ Custom icon path may be invalid, default icon will be used instead.');
- tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
- }
- // Set tray icon path.
- let trayIconPath = platform === 'darwin' ? 'png/icon_512.png' : tauriConf.tauri.bundle.icon[0];
- if (systemTrayIcon.length > 0) {
- try {
- await fsExtra.pathExists(systemTrayIcon);
- // 需要判断图标格式,默认只支持ico和png两种
- let iconExt = path.extname(systemTrayIcon).toLowerCase();
- if (iconExt == '.png' || iconExt == '.ico') {
- const trayIcoPath = path.join(npmDirectory, `src-tauri/png/${name.toLowerCase()}${iconExt}`);
- trayIconPath = `png/${name.toLowerCase()}${iconExt}`;
- await fsExtra.copy(systemTrayIcon, trayIcoPath);
- }
- else {
- logger.warn(`✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`);
- logger.warn(`✼ Default system tray icon will be used.`);
- }
- }
- catch {
- logger.warn(`✼ ${systemTrayIcon} not exists!`);
- logger.warn(`✼ Default system tray icon will remain unchanged.`);
- }
- }
- tauriConf.tauri.systemTray.iconPath = trayIconPath;
- const injectFilePath = path.join(npmDirectory, `src-tauri/src/inject/custom.js`);
- // inject js or css files
- if (inject?.length > 0) {
- if (!inject.every(item => item.endsWith('.css') || item.endsWith('.js'))) {
- logger.error('The injected file must be in either CSS or JS format.');
- return;
- }
- const files = inject.map(filepath => path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath));
- tauriConf.pake.inject = files;
- await combineFiles(files, injectFilePath);
- }
- else {
- tauriConf.pake.inject = [];
- await fsExtra.writeFile(injectFilePath, '');
- }
- // Save config file.
- const platformConfigPaths = {
- win32: 'tauri.windows.conf.json',
- darwin: 'tauri.macos.conf.json',
- linux: 'tauri.linux.conf.json',
- };
- const configPath = path.join(tauriConfigDirectory, platformConfigPaths[platform]);
- const bundleConf = { tauri: { bundle: tauriConf.tauri.bundle } };
- await fsExtra.outputJSON(configPath, bundleConf, { spaces: 4 });
- const pakeConfigPath = path.join(tauriConfigDirectory, 'pake.json');
- await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
- let tauriConf2 = JSON.parse(JSON.stringify(tauriConf));
- delete tauriConf2.pake;
- delete tauriConf2.tauri.bundle;
- const configJsonPath = path.join(tauriConfigDirectory, 'tauri.conf.json');
- await fsExtra.outputJSON(configJsonPath, tauriConf2, { spaces: 4 });
+async function mergeConfig(url, options, tauriConf) {
+ const { width, height, fullscreen, transparent, userAgent, showMenu, showSystemTray, systemTrayIcon, iterCopyFile, identifier, name, resizable = true, inject, safeDomain, } = options;
+ const { platform } = process;
+ // Set Windows parameters.
+ const tauriConfWindowOptions = {
+ width,
+ height,
+ fullscreen,
+ transparent,
+ resizable,
+ };
+ Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
+ tauriConf.package.productName = name;
+ tauriConf.tauri.bundle.identifier = identifier;
+ //Judge the type of URL, whether it is a file or a website.
+ const pathExists = await fsExtra.pathExists(url);
+ if (pathExists) {
+ logger.warn('✼ Your input might be a local file.');
+ tauriConf.pake.windows[0].url_type = 'local';
+ const fileName = path.basename(url);
+ const dirName = path.dirname(url);
+ const distDir = path.join(npmDirectory, 'dist');
+ const distBakDir = path.join(npmDirectory, 'dist_bak');
+ if (!iterCopyFile) {
+ const urlPath = path.join(distDir, fileName);
+ await fsExtra.copy(url, urlPath);
+ }
+ else {
+ fsExtra.moveSync(distDir, distBakDir, { overwrite: true });
+ fsExtra.copySync(dirName, distDir, { overwrite: true });
+ // ignore it, because about_pake.html have be erased.
+ // const filesToCopyBack = ['cli.js', 'about_pake.html'];
+ const filesToCopyBack = ['cli.js'];
+ await Promise.all(filesToCopyBack.map(file => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
+ }
+ tauriConf.pake.windows[0].url = fileName;
+ tauriConf.pake.windows[0].url_type = 'local';
+ }
+ else {
+ tauriConf.pake.windows[0].url_type = 'web';
+ // Set the secure domain for calling window.__TAURI__ to the application domain that has been set.
+ tauriConf.tauri.security.dangerousRemoteDomainIpcAccess = [
+ {
+ domain: new URL(url).hostname,
+ windows: ['pake'],
+ enableTauriAPI: true,
+ },
+ ];
+ }
+ if (safeDomain.length > 0) {
+ tauriConf.tauri.security.dangerousRemoteDomainIpcAccess = [
+ ...tauriConf.tauri.security.dangerousRemoteDomainIpcAccess,
+ ...safeDomain.map(domain => ({
+ domain,
+ windows: ['pake'],
+ enableTauriAPI: true,
+ })),
+ ];
+ }
+ const platformMap = {
+ win32: 'windows',
+ linux: 'linux',
+ darwin: 'macos',
+ };
+ const currentPlatform = platformMap[platform];
+ if (userAgent.length > 0) {
+ tauriConf.pake.user_agent[currentPlatform] = userAgent;
+ }
+ tauriConf.pake.menu[currentPlatform] = showMenu;
+ tauriConf.pake.system_tray[currentPlatform] = showSystemTray;
+ // Processing targets are currently only open to Linux.
+ if (platform === 'linux') {
+ delete tauriConf.tauri.bundle.deb.files;
+ const validTargets = ['all', 'deb', 'appimage'];
+ if (validTargets.includes(options.targets)) {
+ tauriConf.tauri.bundle.targets = options.targets === 'all' ? ['deb', 'appimage'] : [options.targets];
+ }
+ else {
+ logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
+ }
+ }
+ // Set icon.
+ const platformIconMap = {
+ win32: {
+ fileExt: '.ico',
+ path: `png/${name.toLowerCase()}_256.ico`,
+ defaultIcon: 'png/icon_256.ico',
+ message: 'Windows icon must be .ico and 256x256px.',
+ },
+ linux: {
+ fileExt: '.png',
+ path: `png/${name.toLowerCase()}_512.png`,
+ defaultIcon: 'png/icon_512.png',
+ message: 'Linux icon must be .png and 512x512px.',
+ },
+ darwin: {
+ fileExt: '.icns',
+ path: `icons/${name.toLowerCase()}.icns`,
+ defaultIcon: 'icons/icon.icns',
+ message: 'macOS icon must be .icns type.',
+ },
+ };
+ const iconInfo = platformIconMap[platform];
+ const exists = await fsExtra.pathExists(options.icon);
+ if (exists) {
+ let updateIconPath = true;
+ let customIconExt = path.extname(options.icon).toLowerCase();
+ if (customIconExt !== iconInfo.fileExt) {
+ updateIconPath = false;
+ logger.warn(`✼ ${iconInfo.message}, but you give ${customIconExt}`);
+ tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
+ }
+ else {
+ const iconPath = path.join(npmDirectory, 'src-tauri/', iconInfo.path);
+ tauriConf.tauri.bundle.resources = [iconInfo.path];
+ await fsExtra.copy(options.icon, iconPath);
+ }
+ if (updateIconPath) {
+ tauriConf.tauri.bundle.icon = [options.icon];
+ }
+ else {
+ logger.warn(`✼ Icon will remain as default.`);
+ }
+ }
+ else {
+ logger.warn('✼ Custom icon path may be invalid, default icon will be used instead.');
+ tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
+ }
+ // Set tray icon path.
+ let trayIconPath = platform === 'darwin' ? 'png/icon_512.png' : tauriConf.tauri.bundle.icon[0];
+ if (systemTrayIcon.length > 0) {
+ try {
+ await fsExtra.pathExists(systemTrayIcon);
+ // 需要判断图标格式,默认只支持ico和png两种
+ let iconExt = path.extname(systemTrayIcon).toLowerCase();
+ if (iconExt == '.png' || iconExt == '.ico') {
+ const trayIcoPath = path.join(npmDirectory, `src-tauri/png/${name.toLowerCase()}${iconExt}`);
+ trayIconPath = `png/${name.toLowerCase()}${iconExt}`;
+ await fsExtra.copy(systemTrayIcon, trayIcoPath);
+ }
+ else {
+ logger.warn(`✼ System tray icon must be .ico or .png, but you provided ${iconExt}.`);
+ logger.warn(`✼ Default system tray icon will be used.`);
+ }
+ }
+ catch {
+ logger.warn(`✼ ${systemTrayIcon} not exists!`);
+ logger.warn(`✼ Default system tray icon will remain unchanged.`);
+ }
+ }
+ tauriConf.tauri.systemTray.iconPath = trayIconPath;
+ const injectFilePath = path.join(npmDirectory, `src-tauri/src/inject/custom.js`);
+ // inject js or css files
+ if (inject?.length > 0) {
+ if (!inject.every(item => item.endsWith('.css') || item.endsWith('.js'))) {
+ logger.error('The injected file must be in either CSS or JS format.');
+ return;
+ }
+ const files = inject.map(filepath => path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath));
+ tauriConf.pake.inject = files;
+ await combineFiles(files, injectFilePath);
+ }
+ else {
+ tauriConf.pake.inject = [];
+ await fsExtra.writeFile(injectFilePath, '');
+ }
+ // Save config file.
+ const platformConfigPaths = {
+ win32: 'tauri.windows.conf.json',
+ darwin: 'tauri.macos.conf.json',
+ linux: 'tauri.linux.conf.json',
+ };
+ const configPath = path.join(tauriConfigDirectory, platformConfigPaths[platform]);
+ const bundleConf = { tauri: { bundle: tauriConf.tauri.bundle } };
+ await fsExtra.outputJSON(configPath, bundleConf, { spaces: 4 });
+ const pakeConfigPath = path.join(tauriConfigDirectory, 'pake.json');
+ await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
+ let tauriConf2 = JSON.parse(JSON.stringify(tauriConf));
+ delete tauriConf2.pake;
+ delete tauriConf2.tauri.bundle;
+ const configJsonPath = path.join(tauriConfigDirectory, 'tauri.conf.json');
+ await fsExtra.outputJSON(configJsonPath, tauriConf2, { spaces: 4 });
}
-class BaseBuilder {
- constructor(options) {
- this.options = options;
- }
- async prepare() {
- const tauriSrcPath = path.join(npmDirectory, 'src-tauri');
- const tauriTargetPath = path.join(tauriSrcPath, 'target');
- const tauriTargetPathExists = await fsExtra.pathExists(tauriTargetPath);
- if (!IS_MAC && !tauriTargetPathExists) {
- logger.warn('✼ The first use requires installing system dependencies.');
- logger.warn('✼ See more in https://tauri.app/v1/guides/getting-started/prerequisites.');
- }
- if (!checkRustInstalled()) {
- const res = await prompts({
- type: 'confirm',
- message: 'Rust not detected. Install now?',
- name: 'value',
- });
- if (res.value) {
- await installRust();
- }
- else {
- logger.error('✕ Rust required to package your webapp.');
- process.exit(0);
- }
- }
- const isChina = await isChinaDomain('www.npmjs.com');
- const spinner = getSpinner('Installing package...');
- const rustProjectDir = path.join(tauriSrcPath, '.cargo');
- const projectConf = path.join(rustProjectDir, 'config');
- await fsExtra.ensureDir(rustProjectDir);
- if (isChina) {
- logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
- const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
- await fsExtra.copy(projectCnConf, projectConf);
- await shellExec(`cd "${npmDirectory}" && npm install --registry=https://registry.npmmirror.com`);
- }
- else {
- await shellExec(`cd "${npmDirectory}" && npm install`);
- }
- spinner.succeed(chalk.green('Package installed!'));
- if (!tauriTargetPathExists) {
- logger.warn('✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.');
- }
- }
- async build(url) {
- await this.buildAndCopy(url, this.options.targets);
- }
- async start(url) {
- await mergeConfig(url, this.options, tauriConfig);
- }
- async buildAndCopy(url, target) {
- const { name } = this.options;
- await mergeConfig(url, this.options, tauriConfig);
- // Build app
- const spinner = getSpinner('Building app...');
- setTimeout(() => spinner.stop(), 3000);
- await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`);
- // Copy app
- const fileName = this.getFileName();
- const fileType = this.getFileType(target);
- const appPath = this.getBuildAppPath(npmDirectory, fileName, fileType);
- const distPath = path.resolve(`${name}.${fileType}`);
- await fsExtra.copy(appPath, distPath);
- await fsExtra.remove(appPath);
- logger.success('✔ Build success!');
- logger.success('✔ App installer located in', distPath);
- }
- getFileType(target) {
- return target;
- }
- getBuildCommand() {
- // the debug option should support `--debug` and `--release`
- return this.options.debug ? 'npm run build:debug' : 'npm run build';
- }
- getBasePath() {
- return 'src-tauri/target/release/bundle/';
- }
- getBuildAppPath(npmDirectory, fileName, fileType) {
- return path.join(npmDirectory, this.getBasePath(), fileType.toLowerCase(), `${fileName}.${fileType}`);
- }
+class BaseBuilder {
+ constructor(options) {
+ this.options = options;
+ }
+ async prepare() {
+ const tauriSrcPath = path.join(npmDirectory, 'src-tauri');
+ const tauriTargetPath = path.join(tauriSrcPath, 'target');
+ const tauriTargetPathExists = await fsExtra.pathExists(tauriTargetPath);
+ if (!IS_MAC && !tauriTargetPathExists) {
+ logger.warn('✼ The first use requires installing system dependencies.');
+ logger.warn('✼ See more in https://tauri.app/v1/guides/getting-started/prerequisites.');
+ }
+ if (!checkRustInstalled()) {
+ const res = await prompts({
+ type: 'confirm',
+ message: 'Rust not detected. Install now?',
+ name: 'value',
+ });
+ if (res.value) {
+ await installRust();
+ }
+ else {
+ logger.error('✕ Rust required to package your webapp.');
+ process.exit(0);
+ }
+ }
+ const isChina = await isChinaDomain('www.npmjs.com');
+ const spinner = getSpinner('Installing package...');
+ const rustProjectDir = path.join(tauriSrcPath, '.cargo');
+ const projectConf = path.join(rustProjectDir, 'config');
+ await fsExtra.ensureDir(rustProjectDir);
+ if (isChina) {
+ logger.info('✺ Located in China, using npm/rsProxy CN mirror.');
+ const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml');
+ await fsExtra.copy(projectCnConf, projectConf);
+ await shellExec(`cd "${npmDirectory}" && npm install --registry=https://registry.npmmirror.com`);
+ }
+ else {
+ await shellExec(`cd "${npmDirectory}" && npm install`);
+ }
+ spinner.succeed(chalk.green('Package installed!'));
+ if (!tauriTargetPathExists) {
+ logger.warn('✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.');
+ }
+ }
+ async build(url) {
+ await this.buildAndCopy(url, this.options.targets);
+ }
+ async start(url) {
+ await mergeConfig(url, this.options, tauriConfig);
+ }
+ async buildAndCopy(url, target) {
+ const { name } = this.options;
+ await mergeConfig(url, this.options, tauriConfig);
+ // Build app
+ const spinner = getSpinner('Building app...');
+ setTimeout(() => spinner.stop(), 3000);
+ await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand()}`);
+ // Copy app
+ const fileName = this.getFileName();
+ const fileType = this.getFileType(target);
+ const appPath = this.getBuildAppPath(npmDirectory, fileName, fileType);
+ const distPath = path.resolve(`${name}.${fileType}`);
+ await fsExtra.copy(appPath, distPath);
+ await fsExtra.remove(appPath);
+ logger.success('✔ Build success!');
+ logger.success('✔ App installer located in', distPath);
+ }
+ getFileType(target) {
+ return target;
+ }
+ getBuildCommand() {
+ // the debug option should support `--debug` and `--release`
+ return this.options.debug ? 'npm run build:debug' : 'npm run build';
+ }
+ getBasePath() {
+ return 'src-tauri/target/release/bundle/';
+ }
+ getBuildAppPath(npmDirectory, fileName, fileType) {
+ return path.join(npmDirectory, this.getBasePath(), fileType.toLowerCase(), `${fileName}.${fileType}`);
+ }
}
-class MacBuilder extends BaseBuilder {
- constructor(options) {
- super(options);
- this.options.targets = 'dmg';
- }
- getFileName() {
- const { name } = this.options;
- let arch;
- if (this.options.multiArch) {
- arch = 'universal';
- }
- else {
- arch = process.arch === 'arm64' ? 'aarch64' : process.arch;
- }
- return `${name}_${tauriConfig.package.version}_${arch}`;
- }
- getBuildCommand() {
- return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand();
- }
- getBasePath() {
- return this.options.multiArch
- ? 'src-tauri/target/universal-apple-darwin/release/bundle'
- : super.getBasePath();
- }
+class MacBuilder extends BaseBuilder {
+ constructor(options) {
+ super(options);
+ this.options.targets = 'dmg';
+ }
+ getFileName() {
+ const { name } = this.options;
+ let arch;
+ if (this.options.multiArch) {
+ arch = 'universal';
+ }
+ else {
+ arch = process.arch === 'arm64' ? 'aarch64' : process.arch;
+ }
+ return `${name}_${tauriConfig.package.version}_${arch}`;
+ }
+ getBuildCommand() {
+ return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand();
+ }
+ getBasePath() {
+ return this.options.multiArch
+ ? 'src-tauri/target/universal-apple-darwin/release/bundle'
+ : super.getBasePath();
+ }
}
-class WinBuilder extends BaseBuilder {
- constructor(options) {
- super(options);
- this.options.targets = 'msi';
- }
- getFileName() {
- const { name } = this.options;
- const { arch } = process;
- const language = tauriConfig.tauri.bundle.windows.wix.language[0];
- return `${name}_${tauriConfig.package.version}_${arch}_${language}`;
- }
+class WinBuilder extends BaseBuilder {
+ constructor(options) {
+ super(options);
+ this.options.targets = 'msi';
+ }
+ getFileName() {
+ const { name } = this.options;
+ const { arch } = process;
+ const language = tauriConfig.tauri.bundle.windows.wix.language[0];
+ return `${name}_${tauriConfig.package.version}_${arch}_${language}`;
+ }
}
-class LinuxBuilder extends BaseBuilder {
- constructor(options) {
- super(options);
- }
- getFileName() {
- const { name } = this.options;
- const arch = process.arch === 'x64' ? 'amd64' : process.arch;
- return `${name}_${tauriConfig.package.version}_${arch}`;
- }
- // Customize it, considering that there are all targets.
- async build(url) {
- const targetTypes = ['deb', 'appimage'];
- for (const target of targetTypes) {
- if (this.options.targets === target || this.options.targets === 'all') {
- await this.buildAndCopy(url, target);
- }
- }
- }
- getFileType(target) {
- if (target === 'appimage') {
- return 'AppImage';
- }
- return super.getFileType(target);
- }
+class LinuxBuilder extends BaseBuilder {
+ constructor(options) {
+ super(options);
+ }
+ getFileName() {
+ const { name } = this.options;
+ const arch = process.arch === 'x64' ? 'amd64' : process.arch;
+ return `${name}_${tauriConfig.package.version}_${arch}`;
+ }
+ // Customize it, considering that there are all targets.
+ async build(url) {
+ const targetTypes = ['deb', 'appimage'];
+ for (const target of targetTypes) {
+ if (this.options.targets === target || this.options.targets === 'all') {
+ await this.buildAndCopy(url, target);
+ }
+ }
+ }
+ getFileType(target) {
+ if (target === 'appimage') {
+ return 'AppImage';
+ }
+ return super.getFileType(target);
+ }
}
-const { platform } = process;
-const buildersMap = {
- darwin: MacBuilder,
- win32: WinBuilder,
- linux: LinuxBuilder,
-};
-class BuilderProvider {
- static create(options) {
- const Builder = buildersMap[platform];
- if (!Builder) {
- throw new Error('The current system is not supported!');
- }
- return new Builder(options);
- }
+const { platform } = process;
+const buildersMap = {
+ darwin: MacBuilder,
+ win32: WinBuilder,
+ linux: LinuxBuilder,
+};
+class BuilderProvider {
+ static create(options) {
+ const Builder = buildersMap[platform];
+ if (!Builder) {
+ throw new Error('The current system is not supported!');
+ }
+ return new Builder(options);
+ }
}
-const DEFAULT_PAKE_OPTIONS = {
- icon: '',
- height: 780,
- width: 1200,
- fullscreen: false,
- resizable: true,
- transparent: false,
- userAgent: '',
- showMenu: false,
- showSystemTray: false,
- multiArch: false,
- targets: 'deb',
- iterCopyFile: false,
- systemTrayIcon: '',
- debug: false,
- inject: [],
- safeDomain: [],
+const DEFAULT_PAKE_OPTIONS = {
+ icon: '',
+ height: 780,
+ width: 1200,
+ fullscreen: false,
+ resizable: true,
+ transparent: false,
+ userAgent: '',
+ showMenu: false,
+ showSystemTray: false,
+ multiArch: false,
+ targets: 'deb',
+ iterCopyFile: false,
+ systemTrayIcon: '',
+ debug: false,
+ inject: [],
+ safeDomain: [],
};
-async function checkUpdateTips() {
- updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({ isGlobal: true });
+async function checkUpdateTips() {
+ updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({ isGlobal: true });
}
-async function handleIcon(options) {
- if (options.icon) {
- if (options.icon.startsWith('http')) {
- return downloadIcon(options.icon);
- }
- else {
- return path.resolve(options.icon);
- }
- }
- else {
- logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.');
- const iconPath = IS_WIN
- ? 'src-tauri/png/icon_256.ico'
- : IS_LINUX
- ? 'src-tauri/png/icon_512.png'
- : 'src-tauri/icons/icon.icns';
- return path.join(npmDirectory, iconPath);
- }
-}
-async function downloadIcon(iconUrl) {
- const spinner = getSpinner('Downloading icon...');
- try {
- const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' });
- const iconData = await iconResponse.data;
- if (!iconData) {
- return null;
- }
- const fileDetails = await fileTypeFromBuffer(iconData);
- if (!fileDetails) {
- return null;
- }
- const { path: tempPath } = await dir();
- let iconPath = `${tempPath}/icon.${fileDetails.ext}`;
- // Fix this for linux
- if (IS_LINUX) {
- iconPath = 'png/linux_temp.png';
- await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, iconData);
- }
- else {
- await fsExtra.outputFile(iconPath, iconData);
- }
- await fsExtra.outputFile(iconPath, iconData);
- spinner.succeed(chalk.green('Icon downloaded successfully!'));
- return iconPath;
- }
- catch (error) {
- spinner.fail(chalk.red('Icon download failed!'));
- if (error.response && error.response.status === 404) {
- return null;
- }
- throw error;
- }
+async function handleIcon(options) {
+ if (options.icon) {
+ if (options.icon.startsWith('http')) {
+ return downloadIcon(options.icon);
+ }
+ else {
+ return path.resolve(options.icon);
+ }
+ }
+ else {
+ logger.warn('✼ No icon given, default in use. For a custom icon, use --icon option.');
+ const iconPath = IS_WIN
+ ? 'src-tauri/png/icon_256.ico'
+ : IS_LINUX
+ ? 'src-tauri/png/icon_512.png'
+ : 'src-tauri/icons/icon.icns';
+ return path.join(npmDirectory, iconPath);
+ }
+}
+async function downloadIcon(iconUrl) {
+ const spinner = getSpinner('Downloading icon...');
+ try {
+ const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' });
+ const iconData = await iconResponse.data;
+ if (!iconData) {
+ return null;
+ }
+ const fileDetails = await fileTypeFromBuffer(iconData);
+ if (!fileDetails) {
+ return null;
+ }
+ const { path: tempPath } = await dir();
+ let iconPath = `${tempPath}/icon.${fileDetails.ext}`;
+ // Fix this for linux
+ if (IS_LINUX) {
+ iconPath = 'png/linux_temp.png';
+ await fsExtra.outputFile(`${npmDirectory}/src-tauri/${iconPath}`, iconData);
+ }
+ else {
+ await fsExtra.outputFile(iconPath, iconData);
+ }
+ await fsExtra.outputFile(iconPath, iconData);
+ spinner.succeed(chalk.green('Icon downloaded successfully!'));
+ return iconPath;
+ }
+ catch (error) {
+ spinner.fail(chalk.red('Icon download failed!'));
+ if (error.response && error.response.status === 404) {
+ return null;
+ }
+ throw error;
+ }
}
-// Extracts the domain from a given URL.
-function getDomain(inputUrl) {
- try {
- const url = new URL(inputUrl);
- // Use PSL to parse domain names.
- const parsed = psl.parse(url.hostname);
- // If domain is available, split it and return the SLD.
- if ('domain' in parsed && parsed.domain) {
- return parsed.domain.split('.')[0];
- }
- else {
- return null;
- }
- }
- catch (error) {
- return null;
- }
-}
-// Appends 'https://' protocol to the URL if not present.
-function appendProtocol(inputUrl) {
- try {
- new URL(inputUrl);
- return inputUrl;
- }
- catch {
- return `https://${inputUrl}`;
- }
-}
-// Normalizes the URL by ensuring it has a protocol and is valid.
-function normalizeUrl(urlToNormalize) {
- const urlWithProtocol = appendProtocol(urlToNormalize);
- if (isUrl(urlWithProtocol)) {
- return urlWithProtocol;
- }
- else {
- throw new Error(`Your url "${urlWithProtocol}" is invalid`);
- }
+// Extracts the domain from a given URL.
+function getDomain(inputUrl) {
+ try {
+ const url = new URL(inputUrl);
+ // Use PSL to parse domain names.
+ const parsed = psl.parse(url.hostname);
+ // If domain is available, split it and return the SLD.
+ if ('domain' in parsed && parsed.domain) {
+ return parsed.domain.split('.')[0];
+ }
+ else {
+ return null;
+ }
+ }
+ catch (error) {
+ return null;
+ }
+}
+// Appends 'https://' protocol to the URL if not present.
+function appendProtocol(inputUrl) {
+ try {
+ new URL(inputUrl);
+ return inputUrl;
+ }
+ catch {
+ return `https://${inputUrl}`;
+ }
+}
+// Normalizes the URL by ensuring it has a protocol and is valid.
+function normalizeUrl(urlToNormalize) {
+ const urlWithProtocol = appendProtocol(urlToNormalize);
+ if (isUrl(urlWithProtocol)) {
+ return urlWithProtocol;
+ }
+ else {
+ throw new Error(`Your url "${urlWithProtocol}" is invalid`);
+ }
}
-function resolveAppName(name, platform) {
- const domain = getDomain(name) || 'pake';
- return platform !== 'linux' ? capitalizeFirstLetter(domain) : domain;
-}
-function isValidName(name, platform) {
- const platformRegexMapping = {
- linux: /^[a-z0-9]+(-[a-z0-9]+)*$/,
- default: /^[a-zA-Z0-9]+$/,
- };
- const reg = platformRegexMapping[platform] || platformRegexMapping.default;
- return !!name && reg.test(name);
-}
-async function handleOptions(options, url) {
- const { platform } = process;
- const isActions = process.env.GITHUB_ACTIONS;
- let name = options.name;
- const pathExists = await fsExtra.pathExists(url);
- if (!options.name) {
- const defaultName = pathExists ? '' : resolveAppName(url, platform);
- const promptMessage = 'Enter your application name';
- const namePrompt = await promptText(promptMessage, defaultName);
- name = namePrompt || defaultName;
- }
- if (!isValidName(name, platform)) {
- const LINUX_NAME_ERROR = `✕ name should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`;
- const DEFAULT_NAME_ERROR = `✕ Name should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`;
- const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
- logger.error(errorMsg);
- if (isActions) {
- name = resolveAppName(url, platform);
- logger.warn(`✼ Inside github actions, use the default name: ${name}`);
- }
- else {
- process.exit(1);
- }
- }
- const appOptions = {
- ...options,
- name,
- identifier: getIdentifier(url),
- };
- appOptions.icon = await handleIcon(appOptions);
- return appOptions;
+function resolveAppName(name, platform) {
+ const domain = getDomain(name) || 'pake';
+ return platform !== 'linux' ? capitalizeFirstLetter(domain) : domain;
+}
+function isValidName(name, platform) {
+ const platformRegexMapping = {
+ linux: /^[a-z0-9]+(-[a-z0-9]+)*$/,
+ default: /^[a-zA-Z0-9]+$/,
+ };
+ const reg = platformRegexMapping[platform] || platformRegexMapping.default;
+ return !!name && reg.test(name);
+}
+async function handleOptions(options, url) {
+ const { platform } = process;
+ const isActions = process.env.GITHUB_ACTIONS;
+ let name = options.name;
+ const pathExists = await fsExtra.pathExists(url);
+ if (!options.name) {
+ const defaultName = pathExists ? '' : resolveAppName(url, platform);
+ const promptMessage = 'Enter your application name';
+ const namePrompt = await promptText(promptMessage, defaultName);
+ name = namePrompt || defaultName;
+ }
+ if (!isValidName(name, platform)) {
+ const LINUX_NAME_ERROR = `✕ name should only include lowercase letters, numbers, and dashes, and must contain at least one lowercase letter. Examples: com-123-xxx, 123pan, pan123, weread, we-read.`;
+ const DEFAULT_NAME_ERROR = `✕ Name should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`;
+ const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
+ logger.error(errorMsg);
+ if (isActions) {
+ name = resolveAppName(url, platform);
+ logger.warn(`✼ Inside github actions, use the default name: ${name}`);
+ }
+ else {
+ process.exit(1);
+ }
+ }
+ const appOptions = {
+ ...options,
+ name,
+ identifier: getIdentifier(url),
+ };
+ appOptions.icon = await handleIcon(appOptions);
+ return appOptions;
}
-function validateNumberInput(value) {
- const parsedValue = Number(value);
- if (isNaN(parsedValue)) {
- throw new InvalidArgumentError('Not a number.');
- }
- return parsedValue;
-}
-function validateUrlInput(url) {
- const isFile = fs.existsSync(url);
- if (!isFile) {
- try {
- return normalizeUrl(url);
- }
- catch (error) {
- throw new InvalidArgumentError(error.message);
- }
- }
- return url;
+function validateNumberInput(value) {
+ const parsedValue = Number(value);
+ if (isNaN(parsedValue)) {
+ throw new InvalidArgumentError('Not a number.');
+ }
+ return parsedValue;
+}
+function validateUrlInput(url) {
+ const isFile = fs.existsSync(url);
+ if (!isFile) {
+ try {
+ return normalizeUrl(url);
+ }
+ catch (error) {
+ throw new InvalidArgumentError(error.message);
+ }
+ }
+ return url;
}
-const { green, yellow } = chalk;
+const { green, yellow } = chalk;
const logo = `${chalk.green(' ____ _')}
${green('| _ \\ __ _| | _____')}
${green('| |_) / _` | |/ / _ \\')}
${green('| __/ (_| | < __/')} ${yellow('https://github.com/tw93/pake')}
${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with Rust.')}
-`;
-program
- .addHelpText('beforeAll', logo)
- .usage(`[url] [options]`)
- .showHelpAfterError();
-program
- .argument('[url]', 'The web URL you want to package', validateUrlInput)
- .option('--name ', 'Application name')
- .option('--icon ', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
- .option('--width ', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
- .option('--height ', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
- .option('--transparent', 'Only for Mac, hide title bar', DEFAULT_PAKE_OPTIONS.transparent)
- .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
- .option('--user-agent ', 'Custom user agent', DEFAULT_PAKE_OPTIONS.userAgent)
- .option('--show-menu', 'Show menu in app', DEFAULT_PAKE_OPTIONS.showMenu)
- .option('--show-system-tray', 'Show system tray in app', DEFAULT_PAKE_OPTIONS.showSystemTray)
- .option('--system-tray-icon ', 'Custom system tray icon', DEFAULT_PAKE_OPTIONS.systemTrayIcon)
- .option('--iter-copy-file', 'Copy files when URL is a local file', DEFAULT_PAKE_OPTIONS.iterCopyFile)
- .option('--multi-arch', 'Only for Mac, supports both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
- .option('--targets ', 'Only for Linux, option "deb" or "appimage"', DEFAULT_PAKE_OPTIONS.targets)
- .option('--inject [injects...]', 'Injection of .js or .css Files', DEFAULT_PAKE_OPTIONS.inject)
- .option('--safe-domain [domains...]', 'Domains that Require Security Configuration"', DEFAULT_PAKE_OPTIONS.safeDomain)
- .option('--debug', 'Debug mode', DEFAULT_PAKE_OPTIONS.debug)
- .version(packageJson.version, '-v, --version', 'Output the current version')
- .action(async (url, options) => {
- await checkUpdateTips();
- if (!url) {
- program.outputHelp(str => {
- return str
- .split('\n')
- .filter(line => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line))
- .join('\n');
- });
- process.exit(0);
- }
- log.setDefaultLevel('info');
- if (options.debug) {
- log.setLevel('debug');
- }
- const appOptions = await handleOptions(options, url);
- log.debug('PakeAppOptions', appOptions);
- const builder = BuilderProvider.create(appOptions);
- await builder.prepare();
- await builder.build(url);
-});
+`;
+program
+ .addHelpText('beforeAll', logo)
+ .usage(`[url] [options]`)
+ .showHelpAfterError();
+program
+ .argument('[url]', 'The web URL you want to package', validateUrlInput)
+ .option('--name ', 'Application name')
+ .option('--icon ', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
+ .option('--width ', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
+ .option('--height ', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
+ .option('--transparent', 'Only for Mac, hide title bar', DEFAULT_PAKE_OPTIONS.transparent)
+ .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
+ .option('--user-agent ', 'Custom user agent', DEFAULT_PAKE_OPTIONS.userAgent)
+ .option('--show-menu', 'Show menu in app', DEFAULT_PAKE_OPTIONS.showMenu)
+ .option('--show-system-tray', 'Show system tray in app', DEFAULT_PAKE_OPTIONS.showSystemTray)
+ .option('--system-tray-icon ', 'Custom system tray icon', DEFAULT_PAKE_OPTIONS.systemTrayIcon)
+ .option('--iter-copy-file', 'Copy files when URL is a local file', DEFAULT_PAKE_OPTIONS.iterCopyFile)
+ .option('--multi-arch', 'Only for Mac, supports both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
+ .option('--targets ', 'Only for Linux, option "deb" or "appimage"', DEFAULT_PAKE_OPTIONS.targets)
+ .option('--inject [injects...]', 'Injection of .js or .css Files', DEFAULT_PAKE_OPTIONS.inject)
+ .option('--safe-domain [domains...]', 'Domains that Require Security Configuration"', DEFAULT_PAKE_OPTIONS.safeDomain)
+ .option('--debug', 'Debug mode', DEFAULT_PAKE_OPTIONS.debug)
+ .version(packageJson.version, '-v, --version', 'Output the current version')
+ .action(async (url, options) => {
+ await checkUpdateTips();
+ if (!url) {
+ program.outputHelp(str => {
+ return str
+ .split('\n')
+ .filter(line => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line))
+ .join('\n');
+ });
+ process.exit(0);
+ }
+ log.setDefaultLevel('info');
+ if (options.debug) {
+ log.setLevel('debug');
+ }
+ const appOptions = await handleOptions(options, url);
+ log.debug('PakeAppOptions', appOptions);
+ const builder = BuilderProvider.create(appOptions);
+ await builder.prepare();
+ await builder.build(url);
+});
program.parse();
diff --git a/package.json b/package.json
index fa26c1e..8662b9f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "pake-cli",
- "version": "2.3.4",
+ "version": "2.3.5",
"description": "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。",
"engines": {
"node": ">=16.0.0"
@@ -47,41 +47,41 @@
"exports": "./dist/pake.js",
"license": "MIT",
"dependencies": {
- "@tauri-apps/api": "^1.4.0",
- "@tauri-apps/cli": "^1.4.0",
- "axios": "^1.1.3",
- "chalk": "^5.1.2",
- "commander": "^11.0.0",
- "file-type": "^18.0.0",
- "fs-extra": "^11.1.0",
+ "@tauri-apps/api": "^1.5.1",
+ "@tauri-apps/cli": "^1.5.6",
+ "axios": "^1.6.1",
+ "chalk": "^5.3.0",
+ "commander": "^11.1.0",
+ "file-type": "^18.6.0",
+ "fs-extra": "^11.1.1",
"is-url": "^1.2.4",
"loglevel": "^1.8.1",
- "ora": "^6.1.2",
+ "ora": "^7.0.1",
"prompts": "^2.4.2",
"psl": "^1.9.0",
"shelljs": "^0.8.5",
"tmp-promise": "^3.0.3",
- "update-notifier": "^6.0.2"
+ "update-notifier": "^7.0.0"
},
"devDependencies": {
- "@rollup/plugin-alias": "^4.0.2",
- "@rollup/plugin-commonjs": "^23.0.2",
- "@rollup/plugin-json": "^5.0.2",
- "@rollup/plugin-replace": "^5.0.2",
- "@rollup/plugin-terser": "^0.1.0",
- "@types/fs-extra": "^9.0.13",
- "@types/is-url": "^1.2.30",
- "@types/page-icon": "^0.3.4",
- "@types/prompts": "^2.4.1",
- "@types/psl": "^1.1.0",
- "@types/shelljs": "^0.8.11",
- "@types/tmp": "^0.2.3",
- "@types/update-notifier": "^6.0.1",
+ "@rollup/plugin-alias": "^5.0.1",
+ "@rollup/plugin-commonjs": "^25.0.7",
+ "@rollup/plugin-json": "^6.0.1",
+ "@rollup/plugin-replace": "^5.0.5",
+ "@rollup/plugin-terser": "^0.4.4",
+ "@types/fs-extra": "^11.0.4",
+ "@types/is-url": "^1.2.32",
+ "@types/page-icon": "^0.3.6",
+ "@types/prompts": "^2.4.8",
+ "@types/psl": "^1.1.3",
+ "@types/shelljs": "^0.8.15",
+ "@types/tmp": "^0.2.6",
+ "@types/update-notifier": "^6.0.7",
"app-root-path": "^3.1.0",
"cross-env": "^7.0.3",
- "rollup": "^3.3.0",
- "rollup-plugin-typescript2": "^0.34.1",
- "tslib": "^2.4.1",
- "typescript": "^4.9.3"
+ "rollup": "^4.3.0",
+ "rollup-plugin-typescript2": "^0.36.0",
+ "tslib": "^2.6.2",
+ "typescript": "^5.2.2"
}
}
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index b582e9a..c0b85d2 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -176,7 +176,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -193,7 +193,7 @@ checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -658,7 +658,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -692,7 +692,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -703,7 +703,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -834,7 +834,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -1021,7 +1021,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -1425,7 +1425,21 @@ checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148"
dependencies = [
"log",
"mac",
- "markup5ever",
+ "markup5ever 0.10.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "html5ever"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
+dependencies = [
+ "log",
+ "mac",
+ "markup5ever 0.11.0",
"proc-macro2",
"quote",
"syn 1.0.109",
@@ -1732,7 +1746,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358"
dependencies = [
"cssparser",
- "html5ever",
+ "html5ever 0.25.2",
+ "matches",
+ "selectors",
+]
+
+[[package]]
+name = "kuchikiki"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
+dependencies = [
+ "cssparser",
+ "html5ever 0.26.0",
+ "indexmap 1.9.3",
"matches",
"selectors",
]
@@ -1810,9 +1837,9 @@ dependencies = [
[[package]]
name = "log"
-version = "0.4.19"
+version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "loom"
@@ -1865,7 +1892,21 @@ checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
dependencies = [
"log",
"phf 0.8.0",
- "phf_codegen",
+ "phf_codegen 0.8.0",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
+[[package]]
+name = "markup5ever"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
+dependencies = [
+ "log",
+ "phf 0.10.1",
+ "phf_codegen 0.10.0",
"string_cache",
"string_cache_codegen",
"tendril",
@@ -2194,7 +2235,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -2361,6 +2402,16 @@ dependencies = [
"phf_shared 0.8.0",
]
+[[package]]
+name = "phf_codegen"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
+dependencies = [
+ "phf_generator 0.10.0",
+ "phf_shared 0.10.0",
+]
+
[[package]]
name = "phf_generator"
version = "0.8.0"
@@ -2924,7 +2975,7 @@ dependencies = [
"log",
"matches",
"phf 0.8.0",
- "phf_codegen",
+ "phf_codegen 0.8.0",
"precomputed-hash",
"servo_arc",
"smallvec",
@@ -2942,29 +2993,29 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.171"
+version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9"
+checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.171"
+version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682"
+checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
name = "serde_json"
-version = "1.0.103"
+version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa 1.0.9",
"ryu",
@@ -2979,7 +3030,7 @@ checksum = "1d89a8107374290037607734c0b73a85db7ed80cae314b3c5791f192a496e731"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -3028,7 +3079,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -3254,9 +3305,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.26"
+version = "2.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970"
+checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
dependencies = [
"proc-macro2",
"quote",
@@ -3381,9 +3432,9 @@ checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e"
[[package]]
name = "tauri"
-version = "1.4.1"
+version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fbe522898e35407a8e60dc3870f7579fea2fc262a6a6072eccdd37ae1e1d91e"
+checksum = "9bfe673cf125ef364d6f56b15e8ce7537d9ca7e4dae1cf6fbbdeed2e024db3d9"
dependencies = [
"anyhow",
"bytes",
@@ -3436,12 +3487,13 @@ dependencies = [
[[package]]
name = "tauri-build"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d2edd6a259b5591c8efdeb9d5702cb53515b82a6affebd55c7fd6d3a27b7d1b"
+checksum = "defbfc551bd38ab997e5f8e458f87396d2559d05ce32095076ad6c30f7fc5f9c"
dependencies = [
"anyhow",
"cargo_toml",
+ "dirs-next",
"heck 0.4.1",
"json-patch",
"semver",
@@ -3449,13 +3501,14 @@ dependencies = [
"serde_json",
"tauri-utils",
"tauri-winres",
+ "walkdir",
]
[[package]]
name = "tauri-codegen"
-version = "1.4.0"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54ad2d49fdeab4a08717f5b49a163bdc72efc3b1950b6758245fcde79b645e1a"
+checksum = "7b3475e55acec0b4a50fb96435f19631fb58cbcd31923e1a213de5c382536bbb"
dependencies = [
"base64 0.21.2",
"brotli",
@@ -3479,9 +3532,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
-version = "1.4.0"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eb12a2454e747896929338d93b0642144bb51e0dddbb36e579035731f0d76b7"
+checksum = "613740228de92d9196b795ac455091d3a5fbdac2654abb8bb07d010b62ab43af"
dependencies = [
"heck 0.4.1",
"proc-macro2",
@@ -3507,9 +3560,9 @@ dependencies = [
[[package]]
name = "tauri-runtime"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "108683199cb18f96d2d4134187bb789964143c845d2d154848dda209191fd769"
+checksum = "07f8e9e53e00e9f41212c115749e87d5cd2a9eebccafca77a19722eeecd56d43"
dependencies = [
"gtk",
"http",
@@ -3528,9 +3581,9 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7aa256a1407a3a091b5d843eccc1a5042289baf0a43d1179d9f0fcfea37c1b"
+checksum = "8141d72b6b65f2008911e9ef5b98a68d1e3413b7a1464e8f85eb3673bb19a895"
dependencies = [
"cocoa",
"gtk",
@@ -3548,19 +3601,20 @@ dependencies = [
[[package]]
name = "tauri-utils"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03fc02bb6072bb397e1d473c6f76c953cda48b4a2d0cce605df284aa74a12e84"
+checksum = "34d55e185904a84a419308d523c2c6891d5e2dbcee740c4997eb42e75a7b0f46"
dependencies = [
"brotli",
"ctor",
"dunce",
"glob",
"heck 0.4.1",
- "html5ever",
+ "html5ever 0.26.0",
"infer",
"json-patch",
- "kuchiki",
+ "kuchikiki",
+ "log",
"memchr",
"phf 0.10.1",
"proc-macro2",
@@ -3653,7 +3707,7 @@ checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -3818,7 +3872,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
]
[[package]]
@@ -4059,7 +4113,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
"wasm-bindgen-shared",
]
@@ -4093,7 +4147,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.26",
+ "syn 2.0.32",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -4548,9 +4602,9 @@ dependencies = [
[[package]]
name = "wry"
-version = "0.24.3"
+version = "0.24.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33748f35413c8a98d45f7a08832d848c0c5915501803d1faade5a4ebcd258cea"
+checksum = "88ef04bdad49eba2e01f06e53688c8413bd6a87b0bc14b72284465cf96e3578e"
dependencies = [
"base64 0.13.1",
"block",
@@ -4562,7 +4616,7 @@ dependencies = [
"gio",
"glib",
"gtk",
- "html5ever",
+ "html5ever 0.25.2",
"http",
"kuchiki",
"libc",
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index aaee0d6..7e62f90 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -12,12 +12,12 @@ rust-version = "1.63.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
-tauri-build = { version = "1.4.0", features = [] }
+tauri-build = { version = "1.5.0", features = [] }
[dependencies]
-serde_json = "1.0.96"
-serde = { version = "1.0.163", features = ["derive"] }
-tauri = { version = "1.4.1", features = ["api-all", "system-tray"] }
+serde_json = "1.0.108"
+serde = { version = "1.0.192", features = ["derive"] }
+tauri = { version = "1.5.2", features = ["api-all", "system-tray"] }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
[dev-dependencies]
diff --git a/src-tauri/pake.json b/src-tauri/pake.json
index 31f5d56..46ef062 100644
--- a/src-tauri/pake.json
+++ b/src-tauri/pake.json
@@ -1,7 +1,7 @@
{
"windows": [
{
- "url": "https://weread.qq.com/",
+ "url": "https://weread.qq.com",
"transparent": true,
"fullscreen": false,
"width": 1200,
diff --git a/src-tauri/src/app/menu.rs b/src-tauri/src/app/menu.rs
index 4bee1cb..a845465 100644
--- a/src-tauri/src/app/menu.rs
+++ b/src-tauri/src/app/menu.rs
@@ -3,7 +3,7 @@ use tauri::MenuItem;
use tauri::{CustomMenuItem, Menu, Submenu, WindowMenuEvent};
#[cfg(any(target_os = "linux", target_os = "windows"))]
-use tauri::{Manager, SystemTray, SystemTrayEvent, SystemTrayMenu };
+use tauri::{Manager, SystemTray, SystemTrayEvent, SystemTrayMenu};
#[cfg(any(target_os = "linux", target_os = "windows"))]
use tauri_plugin_window_state::{AppHandleExt, StateFlags};
diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs
index 24aed37..64c5db9 100644
--- a/src-tauri/src/app/window.rs
+++ b/src-tauri/src/app/window.rs
@@ -33,6 +33,12 @@ pub fn get_window(app: &mut App, config: PakeConfig, _data_dir: PathBuf) -> Wind
//This is necessary to allow for file injection by external developers for customization purposes.
.initialization_script(include_str!("../inject/custom.js"));
+ // For dynamic display of header styles
+ if window_config.transparent {
+ let transparent_script = "window.pakeWindowTitleTransparent = true;";
+ window_builder = window_builder.initialization_script(transparent_script);
+ }
+
#[cfg(target_os = "macos")]
{
let title_bar_style = if window_config.transparent {
@@ -48,5 +54,5 @@ pub fn get_window(app: &mut App, config: PakeConfig, _data_dir: PathBuf) -> Wind
window_builder = window_builder.data_directory(_data_dir);
}
- window_builder.build().unwrap()
+ window_builder.build().expect("Failed to build window")
}
diff --git a/src-tauri/src/inject/event.js b/src-tauri/src/inject/event.js
index 56e8e21..051b1a5 100644
--- a/src-tauri/src/inject/event.js
+++ b/src-tauri/src/inject/event.js
@@ -58,10 +58,6 @@ function externalTargetLink() {
return ['zbook.lol'].indexOf(location.hostname) > -1;
}
-function externalSelfLink() {
- return ['chat.openai.com'].indexOf(location.hostname) > -1;
-}
-
document.addEventListener('DOMContentLoaded', () => {
const tauri = window.__TAURI__;
const appWindow = tauri.window.appWindow;
@@ -170,7 +166,7 @@ document.addEventListener('DOMContentLoaded', () => {
// case: download from dataURL -> convert dataURL ->
} else if (url.startsWith('data:')) {
downloadFromDataUri(url, filename);
- } else if (isDownloadLink(url)) {
+ } else if (isDownloadLink(url) || anchorEle.hostname !== window.location.host) {
handleExternalLink(e, url);
}
}, true);
diff --git a/src-tauri/src/inject/style.js b/src-tauri/src/inject/style.js
index 5baccf8..418700d 100644
--- a/src-tauri/src/inject/style.js
+++ b/src-tauri/src/inject/style.js
@@ -1,5 +1,6 @@
window.addEventListener('DOMContentLoaded', _event => {
- const css = `
+ // Customize and transform existing functions
+ const contentCSS = `
#page #footer-wrapper,
.drawing-board .toolbar .toolbar-action,
.c-swiper-container,
@@ -33,29 +34,14 @@ window.addEventListener('DOMContentLoaded', _event => {
opacity: 1;
}
- #layout > ytmusic-nav-bar{
- padding: 6px 16px 0 72px;
- }
-
html::-webkit-scrollbar {
display: none !important;
}
- #__next header.HeaderBar_header__jn5ju{
- padding-top: 16px;
- }
-
#__next .ChatPageSidebar_menuFooter__E1KTY,#__next > div.PageWithSidebarLayout_centeringDiv___L9br > div > aside > div > menu > section:nth-child(6) {
display: none;
}
- #page .main_header, .cb-layout-basic--navbar,
- #app .splitpanes.splitpanes--horizontal.no-splitter header,
- .fui-FluentProvider .fui-Button[data-testid="HomeButton"],
- #__next > div.PageWithSidebarLayout_centeringDiv___L9br > aside .ChatPageSidebar_logo__9PIXq {
- padding-top: 20px;
- }
-
#__next > div.overflow-hidden.w-full.h-full .min-h-\\[20px\\].items-start.gap-4.whitespace-pre-wrap.break-words {
word-break: break-all;
}
@@ -88,61 +74,24 @@ window.addEventListener('DOMContentLoaded', _event => {
display: none;
}
- #__next .overflow-hidden>.overflow-x-hidden .scrollbar-trigger > nav {
- padding-top: 30px;
- }
-
#__next .absolute .px-3.pt-2.pb-3.text-center {
visibility: hidden;
padding-bottom: 4px;
}
+ #__next .h-full.w-full .text-center.text-xs.text-gray-600>span {
+ visibility: hidden;
+ height: 15px;
+ }
+
#__next > div.overflow-hidden.w-full.h-full.relative.flex > div.dark.hidden.flex-shrink-0.bg-gray-900.md\\:flex.md\\:w-\\[260px\\].md\\:flex-col > div > div > nav {
width: 100%;
}
- #tabs-sidebar--tabpanel-0 > div.tw-flex.tw-items-center.tw-mb-\\[12px\\].tw-mt-\\[14px\\].tw-px-4 {
- padding-top: 15px;
- }
-
- #tabs-sidebar--tabpanel-1 > div > div.tw-p-\\[16px\\].tw-flex.tw-flex-col.tw-gap-1\\.5{
- padding-top: 30px;
- }
-
- #tabs-sidebar--tabpanel-2 > div > h2 {
- padding-top: 20px;
- height: 70px;
- }
-
- .lark > .dashboard-sidebar, .lark > .dashboard-sidebar > .sidebar-user-info , .lark > .dashboard-sidebar .index-module_wrapper_F-Wbq{
- padding-top:15px;
- }
-
- .lark > .main-wrapper [data-testid="aside"] {
- top: 15px;
- }
-
.panel.give_me .nav_view {
top: 164px !important;
}
- .columns .column #header,
- .main > div > div.panel.give_me > div.header {
- padding-top: 30px;
- }
-
- ytd-masthead>#container.style-scope.ytd-masthead {
- padding-top: 12px;
- }
-
- #background.ytd-masthead {
- height: 68px;
- }
-
- .wrap.h1body-exist.max-container > div.menu-tocs > div.menu-btn{
- top: 28px;
- }
-
#Wrapper{
background-color: #F8F8F8 !important;
background-image:none !important;
@@ -152,20 +101,14 @@ window.addEventListener('DOMContentLoaded', _event => {
border-bottom: none;
}
- .container-with-note #home, .container-with-note #switcher{
- top: 30px;
+ #global > div.header-container.showSearchBoxOrHeaderFixed > header > div.right > div > div.dropdown-nav{
+ display: none;
}
- .geist-page nav.dashboard_nav__PRmJv,
- #app > div.layout > div.header-container.showSearchBoxOrHeaderFixed > header > a {
- padding-top:10px;
+ #__next > div.AnnouncementWrapper_container__Z51yh > div > aside > div > div > menu > section:nth-child(4) > section, #__next > div.AnnouncementWrapper_container__Z51yh > div > aside > div > div > menu > section:nth-child(4){
+ display: none;
}
- .geist-page .submenu button{
- margin-top:24px;
- }
-
-
#react-root [data-testid="placementTracking"] article,
#react-root a[href*="quick_promote_web"],
#react-root [data-testid="AppTabBar_Explore_Link"],
@@ -321,43 +264,114 @@ window.addEventListener('DOMContentLoaded', _event => {
}
}
- @media (min-width:1024px){
- #__next .text-base.lg\\:max-w-xl, #__next form.stretch.lg\\:max-w-2xl,
- #__next > .w-full.h-full .lg\\:max-w-\\[38rem\\] {
- max-width: 44rem;
- }
- }
-
@media (min-width:1280px){
#__next .text-base.xl\\:max-w-3xl, #__next form.stretch.xl\\:max-w-3xl {
max-width: 48rem;
}
}
- @media (max-width:767px){
- #__next .overflow-hidden.w-full .max-w-full>.sticky.top-0 {
- padding-top: 20px;
- }
-
- #__next .overflow-hidden.w-full main.relative.h-full.w-full.flex-1{
- padding-bottom: 82px;
- }
-
- #__next > div.overflow-hidden.w-full.h-full main.relative.h-full.w-full.flex-1 > .flex-1.overflow-hidden .h-32.md\\:h-48.flex-shrink-0{
- height: 0px;
- }
- }
-
- @media (max-width:565px){
- #__next .overflow-hidden.w-full main.relative.h-full.w-full.flex-1{
- padding-bottom: 98px;
- }
- }
-
#__next .prose ol li p {
margin: 0;
display: inline;
}
+ `;
+ const contentStyleElement = document.createElement('style');
+ contentStyleElement.innerHTML = contentCSS;
+ document.head.appendChild(contentStyleElement);
+
+ // Top spacing adapts to head-hiding scenarios
+ const topPaddingCSS = `
+ #layout > ytmusic-nav-bar{
+ padding-top: 20px;
+ }
+
+ .columns .column #header,
+ .main > div > div.panel.give_me > div.header {
+ padding-top: 30px;
+ }
+
+ ytd-masthead>#container.style-scope.ytd-masthead {
+ padding-top: 12px;
+ }
+
+ #__next header.HeaderBar_header__jn5ju{
+ padding-top: 16px;
+ }
+
+ .geist-page nav.dashboard_nav__PRmJv,
+ #app > div.layout > div.header-container.showSearchBoxOrHeaderFixed > header > a {
+ padding-top:10px;
+ }
+
+ .geist-page .submenu button{
+ margin-top:24px;
+ }
+
+ .container-with-note #home, .container-with-note #switcher{
+ top: 30px;
+ }
+
+ #__next .overflow-hidden>.overflow-x-hidden .scrollbar-trigger > nav {
+ padding-top: 30px;
+ }
+
+ #__next > div.relative.z-0.flex.h-full.w-full.overflow-hidden > div.relative.flex.h-full.max-w-full.flex-1.flex-col.overflow-hidden > main > div.flex.h-full.flex-col > div.flex-1.overflow-hidden > div > div.absolute.left-0.right-0 > div > div.flex.items-center.gap-2 > button{
+ margin-left: 60px;
+ margin-right: -10px;
+ }
+
+ #__next>div>div>.flex.h-screen.w-full.flex-col.items-center {
+ padding-top: 20px;
+ }
+
+ #__next .sticky.left-0.right-0.top-0.z-20.bg-black{
+ padding-top: 0px;
+ }
+
+ #header-area > div > .css-gtiexd > div:nth-child(1) > div, #header-area .logoIcon .user-info{
+ padding-top: 20px;
+ }
+
+ #__next > div.AnnouncementWrapper_container__Z51yh > div > aside.SidebarLayout_sidebar__SXeDJ.SidebarLayout_left__k163a > div > div > header{
+ padding-left: 84px;
+ padding-top: 10px;
+ }
+
+ #page .main_header, .cb-layout-basic--navbar,
+ #app .splitpanes.splitpanes--horizontal.no-splitter header,
+ .fui-FluentProvider .fui-Button[data-testid="HomeButton"],
+ #__next > div.PageWithSidebarLayout_centeringDiv___L9br > aside .ChatPageSidebar_logo__9PIXq {
+ padding-top: 20px;
+ }
+
+ #tabs-sidebar--tabpanel-0 > div.tw-flex.tw-items-center.tw-mb-\\[12px\\].tw-mt-\\[14px\\].tw-px-4 {
+ padding-top: 15px;
+ }
+
+ #tabs-sidebar--tabpanel-1 > div > div.tw-p-\\[16px\\].tw-flex.tw-flex-col.tw-gap-1\\.5{
+ padding-top: 30px;
+ }
+
+ #tabs-sidebar--tabpanel-2 > div > h2 {
+ padding-top: 20px;
+ height: 70px;
+ }
+
+ .lark > .dashboard-sidebar, .lark > .dashboard-sidebar > .sidebar-user-info , .lark > .dashboard-sidebar .index-module_wrapper_F-Wbq{
+ padding-top:15px;
+ }
+
+ .lark > .main-wrapper [data-testid="aside"] {
+ top: 15px;
+ }
+
+ #background.ytd-masthead {
+ height: 68px;
+ }
+
+ .wrap.h1body-exist.max-container > div.menu-tocs > div.menu-btn{
+ top: 28px;
+ }
#pack-top-dom:active {
cursor: grabbing;
@@ -376,8 +390,21 @@ window.addEventListener('DOMContentLoaded', _event => {
-webkit-user-select: none;
z-index: 90000;
}
+
+ @media (max-width:767px){
+ #__next .overflow-hidden.w-full .max-w-full>.sticky.top-0 {
+ padding-top: 20px;
+ }
+
+ #__next > div.overflow-hidden.w-full.h-full main.relative.h-full.w-full.flex-1 > .flex-1.overflow-hidden .h-32.md\\:h-48.flex-shrink-0{
+ height: 0px;
+ }
+ }
`;
- const styleElement = document.createElement('style');
- styleElement.innerHTML = css;
- document.head.appendChild(styleElement);
+ const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
+ if (window.pakeWindowTitleTransparent && isMac) {
+ const topPaddingStyleElement = document.createElement('style');
+ topPaddingStyleElement.innerHTML = topPaddingCSS;
+ document.head.appendChild(topPaddingStyleElement);
+ }
});