Files
Pake/dist/cli.js
2023-06-22 14:36:02 +08:00

950 lines
30 KiB
JavaScript
Vendored
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import log from 'loglevel';
import { InvalidArgumentError, program } from 'commander';
import fs from 'fs/promises';
import psl from 'psl';
import isUrl from 'is-url';
import crypto from 'crypto';
import prompts from 'prompts';
import path from 'path';
import axios from 'axios';
import { dir } from 'tmp-promise';
import { fileTypeFromBuffer } from 'file-type';
import chalk from 'chalk';
import { fileURLToPath } from 'url';
import shelljs from 'shelljs';
import dns from 'dns';
import http from 'http';
import { promisify } from 'util';
import ora from 'ora';
import fs2 from 'fs-extra';
import updateNotifier from 'update-notifier';
import fs$1 from 'fs';
// 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`);
}
}
// Generates an identifier based on the given URL.
function getIdentifier(url) {
const postFixHash = crypto.createHash('md5')
.update(url)
.digest('hex')
.substring(0, 6);
return `pake-${postFixHash}`;
}
async function promptText(message, initial) {
const response = await prompts({
type: 'text',
name: 'content',
message,
initial,
});
return response.content;
}
function formatMessage(color, ...msg) {
return msg.map((m) => color(m));
}
const logger = {
info(...msg) {
log.info(...formatMessage(chalk.blue, ...msg));
},
debug(...msg) {
log.debug(...formatMessage(chalk.magenta, ...msg));
},
error(...msg) {
log.error(...formatMessage(chalk.red, ...msg));
},
warn(...msg) {
log.warn(...formatMessage(chalk.yellow, ...msg));
},
success(...msg) {
log.info(...formatMessage(chalk.green, ...msg));
}
};
// 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 { platform: platform$1 } = process;
const IS_MAC = platform$1 === 'darwin';
const IS_WIN = platform$1 === 'win32';
const IS_LINUX = platform$1 === 'linux';
async function handleIcon(options, url) {
if (options.icon) {
if (options.icon.startsWith('http')) {
return downloadIcon(options.icon);
}
else {
return path.resolve(options.icon);
}
}
else {
return getDefaultIcon();
}
}
async function getDefaultIcon() {
logger.info('You have not provided an app icon, use the default icon.(use --icon option to assign an icon)');
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) {
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();
const iconPath = `${tempPath}/icon.${fileDetails.ext}`;
await fs.writeFile(iconPath, iconData);
return iconPath;
}
catch (error) {
if (error.response && error.response.status === 404) {
return null;
}
throw error;
}
}
async function handleOptions(options, url) {
const appOptions = {
...options,
identifier: getIdentifier(url),
};
let urlExists = false;
try {
await fs.stat(url);
urlExists = true;
}
catch (error) {
// URL does not exist
}
if (!appOptions.name) {
const defaultName = urlExists ? "" : getDomain(url);
const promptMessage = 'Please input your application name';
appOptions.name = await promptText(promptMessage, defaultName);
}
appOptions.icon = await handleIcon(appOptions);
return appOptions;
}
var windows = [
{
url: "https://weread.qq.com/",
transparent: true,
fullscreen: false,
width: 1200,
height: 780,
resizable: true,
url_type: "web"
}
];
var user_agent = {
macos: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.1 Safari/605.1.15",
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
windows: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
};
var menu = {
macos: true,
linux: false,
windows: false
};
var system_tray = {
macos: false,
linux: true,
windows: true
};
var pakeConf = {
windows: windows,
user_agent: user_agent,
menu: menu,
system_tray: system_tray
};
var tauri$3 = {
security: {
csp: null,
dangerousRemoteDomainIpcAccess: [
{
domain: "weread.qq.com",
windows: [
"pake"
],
enableTauriAPI: true
}
]
},
updater: {
active: false
},
systemTray: {
iconPath: "png/weread_512.png",
iconAsTemplate: true
},
allowlist: {
all: true,
fs: {
all: true,
scope: [
"$DOWNLOAD/*"
]
}
}
};
var build = {
withGlobalTauri: true,
devPath: "../dist",
distDir: "../dist",
beforeBuildCommand: "",
beforeDevCommand: ""
};
var CommonConf = {
"package": {
productName: "WeRead",
version: "1.0.0"
},
tauri: tauri$3,
build: build
};
var tauri$2 = {
bundle: {
icon: [
"png/weread_256.ico",
"png/weread_32.ico"
],
identifier: "com.tw93.weread",
active: true,
category: "DeveloperTool",
copyright: "",
externalBin: [
],
longDescription: "",
resources: [
"png/weread_32.ico"
],
shortDescription: "",
targets: [
"msi"
],
windows: {
certificateThumbprint: null,
digestAlgorithm: "sha256",
timestampUrl: "",
wix: {
language: [
"en-US"
],
template: "assets/main.wxs"
}
}
}
};
var WinConf = {
tauri: tauri$2
};
var tauri$1 = {
bundle: {
icon: [
"icons/weread.icns"
],
identifier: "com.tw93.weread",
active: true,
category: "DeveloperTool",
copyright: "",
externalBin: [
],
longDescription: "",
macOS: {
entitlements: null,
exceptionDomain: "",
frameworks: [
],
providerShortName: null,
signingIdentity: null
},
resources: [
],
shortDescription: "",
targets: [
"dmg"
]
}
};
var MacConf = {
tauri: tauri$1
};
var tauri = {
bundle: {
icon: [
"png/weread_512.png"
],
identifier: "com.tw93.weread",
active: true,
category: "DeveloperTool",
copyright: "",
deb: {
depends: [
"curl",
"wget"
],
files: {
"/usr/share/applications/com-tw93-weread.desktop": "assets/com-tw93-weread.desktop"
}
},
externalBin: [
],
longDescription: "",
resources: [
],
shortDescription: "",
targets: [
"deb",
"appimage"
]
}
};
var LinuxConf = {
tauri: tauri
};
const platformConfigs = {
win32: WinConf,
darwin: MacConf,
linux: LinuxConf
};
const { platform } = process;
// @ts-ignore
const platformConfig = platformConfigs[platform];
let tauriConfig = {
tauri: {
...CommonConf.tauri,
bundle: platformConfig.tauri.bundle,
},
package: CommonConf.package,
build: CommonConf.build,
pake: pakeConf
};
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 resolve = promisify(dns.resolve);
const ping = async (host) => {
const lookup = promisify(dns.lookup);
const ip = await lookup(host);
const start = new Date();
return 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);
});
});
};
async function isChinaDomain(domain) {
try {
const [ip] = await resolve(domain);
return await isChinaIP(ip, domain);
}
catch (error) {
logger.info(`${domain} can't be parse!`);
return false;
}
}
async function isChinaIP(ip, domain) {
try {
const delay = await ping(ip);
logger.info(`${domain} latency is ${delay} ms`);
return delay > 500;
}
catch (error) {
logger.info(`ping ${domain} failed!`);
return false;
}
}
async function installRust() {
const isInChina = await isChinaDomain("sh.rustup.rs");
const rustInstallScriptForMac = isInChina
? '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 = ora('Downloading Rust').start();
try {
await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
spinner.succeed();
}
catch (error) {
console.error('Error installing Rust:', error.message);
spinner.fail();
//@ts-ignore
process.exit(1);
}
}
function checkRustInstalled() {
return shelljs.exec('rustc --version', { silent: true }).code === 0;
}
class BaseBuilder {
async prepare() {
// Windows and Linux need to install necessary build tools.
if (!IS_MAC) {
logger.info('To build the app, you need to install Rust and necessary build tools.');
logger.info('See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing.');
}
if (checkRustInstalled()) {
return;
}
const res = await prompts({
type: 'confirm',
message: 'We detected that you have not installed Rust. Install it now?',
name: 'value',
});
if (res.value) {
await installRust();
}
else {
logger.error('Error: Pake needs Rust to package your webapp!');
process.exit(2);
}
}
async runBuildCommand(directory, command) {
const isChina = await isChinaDomain("www.npmjs.com");
if (isChina) {
logger.info("it's in China, use npm/rust cn mirror");
logger.debug("pake npm directory: ", directory);
const rustProjectDir = path.join(directory, 'src-tauri', ".cargo");
try {
await fs.access(rustProjectDir);
}
catch (e) {
await fs.mkdir(rustProjectDir, { recursive: true });
}
const projectCnConf = path.join(directory, "src-tauri", "rust_proxy.toml");
const projectConf = path.join(rustProjectDir, "config");
await fs.copyFile(projectCnConf, projectConf);
await shellExec(`cd "${directory}" && npm install --registry=https://registry.npmmirror.com && ${command}`);
}
else {
await shellExec(`cd "${directory}" && npm install && ${command}`);
}
}
}
function setSecurityConfigWithUrl(tauriConfig, url) {
tauriConfig.tauri.security.dangerousRemoteDomainIpcAccess[0].domain =
new URL(url).hostname;
}
async function writeFileAsJson(filePath, data) {
await fs.writeFile(filePath, JSON.stringify(data, null, 4), 'utf-8');
}
async function mergeConfig(url, options, tauriConf) {
const { width, height, fullscreen, transparent, resizable, userAgent, showMenu, showSystemTray, systemTrayIcon, iterCopyFile, identifier, name, } = options;
const tauriConfWindowOptions = {
width,
height,
fullscreen,
transparent,
resizable,
};
// Package name is valid ?
// for Linux, package name must be a-z, 0-9 or "-", not allow to A-Z and other
const { platform } = process;
const platformRegexMapping = {
linux: /[0-9]*[a-z]+[0-9]*\-?[0-9]*[a-z]*[0-9]*\-?[0-9]*[a-z]*[0-9]*/,
default: /([0-9]*[a-zA-Z]+[0-9]*)+/,
};
const reg = platformRegexMapping[platform] || platformRegexMapping.default;
const nameCheck = reg.test(name) && reg.exec(name)[0].length === name.length;
if (!nameCheck) {
const errorMsg = platform === 'linux'
? `Package name is illegal. It must be lowercase letters, numbers, dashes, and it must contain the lowercase letters. E.g com-123-xxx, 123pan, pan123,weread, we-read`
: `Package name is illegal. It must be letters, numbers, and it must contain the letters. E.g 123pan,123Pan Pan123,weread, WeRead, WERead`;
logger.error(errorMsg);
process.exit();
}
Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
tauriConf.package.productName = name;
tauriConf.tauri.bundle.identifier = identifier;
// 判断一下url类型是文件还是网站
// 如果是文件并且开启了递归拷贝功能则需要将该文件以及所在文件夹下的所有文件拷贝到src目录下否则只拷贝单个文件。
const urlExists = await fs
.stat(url)
.then(() => true)
.catch(() => false);
if (urlExists) {
logger.warn('You input may 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 fs.copyFile(url, urlPath);
}
else {
fs2.moveSync(distDir, distBakDir, { overwrite: true });
fs2.copySync(dirName, distDir, { overwrite: true });
const filesToCopyBack = ['cli.js', 'about_pake.html'];
await Promise.all(filesToCopyBack.map((file) => fs.copyFile(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';
}
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;
// 处理targets 暂时只对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(`Targets must be one of ${validTargets.join(', ')}, we will use default 'all'`);
}
}
const platformIconMap = {
win32: {
fileExt: '.ico',
path: `png/${name.toLowerCase()}_32.ico`,
defaultIcon: 'png/icon_256.ico',
message: 'Icon file in Windows must be 256 * 256 pix with .ico type',
},
linux: {
fileExt: '.png',
path: `png/${name.toLowerCase()}_32.png`,
defaultIcon: 'png/icon_512.png',
message: 'Icon file in Linux must be 512 * 512 pix with .png type',
},
darwin: {
fileExt: '.icns',
path: `icons/${name.toLowerCase()}_32.icns`,
defaultIcon: 'icons/icon.icns',
message: 'Icon file in MacOS must be .icns type',
},
};
const exists = await fs
.stat(options.icon)
.then(() => true)
.catch(() => false);
const iconInfo = platformIconMap[platform];
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 fs.copyFile(options.icon, iconPath);
}
if (updateIconPath) {
tauriConf.tauri.bundle.icon = [options.icon];
}
else {
logger.warn(`Icon file will not change with default.`);
}
}
else {
logger.warn('The custom icon path may not exists. we will use default icon to replace it');
tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
}
// 设定默认托盘图标路径
let trayIconPath = platform === 'linux' || platform === 'win32'
? tauriConf.tauri.bundle.icon[0]
: 'png/icon_512.png';
if (systemTrayIcon.length > 0) {
try {
await fs.stat(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 fs.copyFile(systemTrayIcon, trayIcoPath);
}
else {
logger.warn(`File type for system tray icon mut be .ico or .png , but you give ${iconExt}`);
logger.warn(`System tray icon file will not change with default.`);
}
}
catch {
logger.warn(`${systemTrayIcon} not exists!`);
logger.warn(`System tray icon file will not change with default.`);
}
}
// 设定托盘图标
tauriConf.tauri.systemTray.iconPath = trayIconPath;
// 设置安全调用 window.__TAURI__ 的安全域名为设置的应用域名
setSecurityConfigWithUrl(tauriConf, url);
// 保存配置文件
const platformConfigPaths = {
win32: 'src-tauri/tauri.windows.conf.json',
darwin: 'src-tauri/tauri.macos.conf.json',
linux: 'src-tauri/tauri.linux.conf.json',
};
const configPath = path.join(npmDirectory, platformConfigPaths[platform]);
const bundleConf = { tauri: { bundle: tauriConf.tauri.bundle } };
await writeFileAsJson(configPath, bundleConf);
const pakeConfigPath = path.join(npmDirectory, 'src-tauri/pake.json');
await writeFileAsJson(pakeConfigPath, tauriConf.pake);
let tauriConf2 = JSON.parse(JSON.stringify(tauriConf));
delete tauriConf2.pake;
delete tauriConf2.tauri.bundle;
const configJsonPath = path.join(npmDirectory, 'src-tauri/tauri.conf.json');
await writeFileAsJson(configJsonPath, tauriConf2);
}
class MacBuilder extends BaseBuilder {
async build(url, options) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
let dmgName;
if (options.multiArch) {
await this.runBuildCommand(npmDirectory, 'npm run build:mac');
dmgName = `${name}_${tauriConfig.package.version}_universal.dmg`;
}
else {
await this.runBuildCommand(npmDirectory, 'npm run build');
let arch = process.arch === "arm64" ? "aarch64" : process.arch;
dmgName = `${name}_${tauriConfig.package.version}_${arch}.dmg`;
}
const appPath = this.getBuildAppPath(npmDirectory, dmgName, options.multiArch);
const distPath = path.resolve(`${name}.dmg`);
await fs.copyFile(appPath, distPath);
await fs.unlink(appPath);
logger.success('Build success!');
logger.success('You can find the app installer in', distPath);
}
getBuildAppPath(npmDirectory, dmgName, multiArch) {
const dmgPath = multiArch ? 'src-tauri/target/universal-apple-darwin/release/bundle/dmg' : 'src-tauri/target/release/bundle/dmg';
return path.join(npmDirectory, dmgPath, dmgName);
}
}
class WinBuilder extends BaseBuilder {
async build(url, options) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
await this.runBuildCommand(npmDirectory, 'npm run build');
const language = tauriConfig.tauri.bundle.windows.wix.language[0];
const arch = process.arch;
const msiName = `${name}_${tauriConfig.package.version}_${arch}_${language}.msi`;
const appPath = this.getBuildAppPath(npmDirectory, msiName);
const distPath = path.resolve(`${name}.msi`);
await fs.copyFile(appPath, distPath);
await fs.unlink(appPath);
logger.success('Build success!');
logger.success('You can find the app installer in', distPath);
}
getBuildAppPath(npmDirectory, msiName) {
return path.join(npmDirectory, 'src-tauri/target/release/bundle/msi', msiName);
}
}
class LinuxBuilder extends BaseBuilder {
async build(url, options) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
await this.runBuildCommand(npmDirectory, 'npm run build');
const arch = process.arch === "x64" ? "amd64" : process.arch;
if (options.targets === "deb" || options.targets === "all") {
const debName = `${name}_${tauriConfig.package.version}_${arch}.deb`;
const appPath = this.getBuildAppPath(npmDirectory, "deb", debName);
const distPath = path.resolve(`${name}.deb`);
await fs.copyFile(appPath, distPath);
await fs.unlink(appPath);
logger.success('Build Deb success!');
logger.success('You can find the deb app installer in', distPath);
}
if (options.targets === "appimage" || options.targets === "all") {
const appImageName = `${name}_${tauriConfig.package.version}_${arch}.AppImage`;
const appImagePath = this.getBuildAppPath(npmDirectory, "appimage", appImageName);
const distAppPath = path.resolve(`${name}.AppImage`);
await fs.copyFile(appImagePath, distAppPath);
await fs.unlink(appImagePath);
logger.success('Build AppImage success!');
logger.success('You can find the AppImage app installer in', distAppPath);
}
}
getBuildAppPath(npmDirectory, packageType, packageName) {
return path.join(npmDirectory, 'src-tauri/target/release/bundle/', packageType, packageName);
}
}
class BuilderProvider {
static create() {
if (IS_MAC) {
return new MacBuilder();
}
if (IS_WIN) {
return new WinBuilder();
}
if (IS_LINUX) {
return new LinuxBuilder();
}
throw new Error('The current system is not supported!');
}
}
var name = "pake-cli";
var version = "2.1.0-beta2";
var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 很简单的用 Rust 打包网页生成很小的桌面 App。";
var engines = {
node: ">=16.0.0"
};
var bin = {
pake: "./cli.js"
};
var repository = {
type: "git",
url: "https://github.com/tw93/pake.git"
};
var author = {
name: "Tw93",
email: "tw93@qq.com"
};
var keywords = [
"pake",
"pake-cli",
"rust",
"tauri",
"no-electron",
"productivity"
];
var files = [
"dist",
"src-tauri",
"cli.js"
];
var scripts = {
start: "npm run dev",
dev: "npm run tauri dev",
build: "npm run tauri build --release",
"build:mac": "npm run tauri build -- --target universal-apple-darwin",
"build:all-unix": "chmod +x ./script/build.sh && ./script/build.sh",
"build:all-windows": "pwsh ./script/build.ps1",
analyze: "cd src-tauri && cargo bloat --release --crates",
tauri: "tauri",
cli: "rollup -c rollup.config.js --watch",
"cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
prepublishOnly: "npm run cli:build"
};
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",
"is-url": "^1.2.4",
loglevel: "^1.8.1",
ora: "^6.1.2",
prompts: "^2.4.2",
psl: "^1.9.0",
shelljs: "^0.8.5",
"tmp-promise": "^3.0.3",
"update-notifier": "^6.0.2"
};
var devDependencies = {
"@rollup/plugin-alias": "^4.0.2",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-json": "^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",
"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"
};
var packageJson = {
name: name,
version: version,
description: description,
engines: engines,
bin: bin,
repository: repository,
author: author,
keywords: keywords,
files: files,
scripts: scripts,
type: type,
exports: exports,
license: license,
dependencies: dependencies,
devDependencies: devDependencies
};
async function checkUpdateTips() {
updateNotifier({ pkg: packageJson }).notify();
}
function validateNumberInput(value) {
const parsedValue = Number(value);
if (isNaN(parsedValue)) {
throw new InvalidArgumentError('Not a number.');
}
return parsedValue;
}
function validateUrlInput(url) {
const isFile = fs$1.existsSync(url);
if (!isFile) {
try {
return normalizeUrl(url);
}
catch (error) {
throw new InvalidArgumentError(error.message);
}
}
return url;
}
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,
};
program
.version(packageJson.version)
.description('A CLI that can turn any webpage into a desktop app with Rust.')
.showHelpAfterError();
program
.argument('[url]', 'The web URL you want to package', validateUrlInput)
.option('--name <string>', 'Application name')
.option('--icon <string>', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
.option('--height <number>', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
.option('--width <number>', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
.option('--no-resizable', 'Whether the window can be resizable', DEFAULT_PAKE_OPTIONS.resizable)
.option('--fullscreen', 'Start the packaged app in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
.option('--transparent', 'Transparent title bar', DEFAULT_PAKE_OPTIONS.transparent)
.option('--user-agent <string>', '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 <string>', 'Custom system tray icon', DEFAULT_PAKE_OPTIONS.systemTrayIcon)
.option('--iter-copy-file', 'Copy all static files to pake app when URL is a local file', DEFAULT_PAKE_OPTIONS.iterCopyFile)
.option('--multi-arch', 'Available for Mac only, supports both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
.option('--targets <string>', 'Only for Linux, option "deb", "appimage" or "all"', DEFAULT_PAKE_OPTIONS.targets)
.option('--debug', 'Debug mode', DEFAULT_PAKE_OPTIONS.debug)
.action(async (url, options) => {
//Check for update prompt
await checkUpdateTips();
// If no URL is provided, display help information
if (!url) {
program.help();
}
log.setDefaultLevel('info');
if (options.debug) {
log.setLevel('debug');
}
const builder = BuilderProvider.create();
await builder.prepare();
const appOptions = await handleOptions(options, url);
log.debug('PakeAppOptions', appOptions);
await builder.build(url, appOptions);
});
program.parse();