pake-cli 2.1.1 โ†’ 2.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,162 +1,124 @@
1
- import ora from 'ora';
2
- import log from 'loglevel';
1
+ import chalk from 'chalk';
3
2
  import { InvalidArgumentError, program } from 'commander';
4
- import fsExtra from 'fs-extra';
3
+ import log from 'loglevel';
5
4
  import path from 'path';
6
- import axios from 'axios';
7
- import { dir } from 'tmp-promise';
8
- import { fileTypeFromBuffer } from 'file-type';
9
- import chalk from 'chalk';
10
- import { fileURLToPath } from 'url';
11
- import psl from 'psl';
12
- import isUrl from 'is-url';
13
- import crypto from 'crypto';
5
+ import fsExtra from 'fs-extra';
14
6
  import prompts from 'prompts';
15
7
  import shelljs from 'shelljs';
8
+ import crypto from 'crypto';
9
+ import ora from 'ora';
10
+ import { fileURLToPath } from 'url';
16
11
  import dns from 'dns';
17
12
  import http from 'http';
18
13
  import { promisify } from 'util';
19
14
  import updateNotifier from 'update-notifier';
15
+ import axios from 'axios';
16
+ import { dir } from 'tmp-promise';
17
+ import { fileTypeFromBuffer } from 'file-type';
18
+ import psl from 'psl';
19
+ import isUrl from 'is-url';
20
20
  import fs from 'fs';
21
21
 
22
- const logger = {
23
- info(...msg) {
24
- log.info(...msg.map((m) => chalk.blue.bold(m)));
25
- },
26
- debug(...msg) {
27
- log.debug(...msg);
28
- },
29
- error(...msg) {
30
- log.error(...msg.map((m) => chalk.red.bold(m)));
31
- },
32
- warn(...msg) {
33
- log.info(...msg.map((m) => chalk.yellow.bold(m)));
34
- },
35
- success(...msg) {
36
- log.info(...msg.map((m) => chalk.green.bold(m)));
37
- }
22
+ var name = "pake-cli";
23
+ var version = "2.1.7";
24
+ var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with Rust. ๐Ÿคฑ๐Ÿป ๅพˆ็ฎ€ๅ•็š„็”จ Rust ๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆๅพˆๅฐ็š„ๆกŒ้ข Appใ€‚";
25
+ var engines = {
26
+ node: ">=16.0.0"
27
+ };
28
+ var bin = {
29
+ pake: "./cli.js"
30
+ };
31
+ var repository = {
32
+ type: "git",
33
+ url: "https://github.com/tw93/pake.git"
34
+ };
35
+ var author = {
36
+ name: "Tw93",
37
+ email: "tw93@qq.com"
38
+ };
39
+ var keywords = [
40
+ "pake",
41
+ "pake-cli",
42
+ "rust",
43
+ "tauri",
44
+ "no-electron",
45
+ "productivity"
46
+ ];
47
+ var files = [
48
+ "dist",
49
+ "src-tauri",
50
+ "cli.js"
51
+ ];
52
+ var scripts = {
53
+ start: "npm run dev",
54
+ dev: "npm run tauri dev",
55
+ build: "npm run tauri build --release",
56
+ "build:mac": "npm run tauri build -- --target universal-apple-darwin",
57
+ "build:all-unix": "chmod +x ./script/build.sh && ./script/build.sh",
58
+ "build:all-windows": "pwsh ./script/build.ps1",
59
+ analyze: "cd src-tauri && cargo bloat --release --crates",
60
+ tauri: "tauri",
61
+ cli: "rollup -c rollup.config.js --watch",
62
+ "cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
63
+ prepublishOnly: "npm run cli:build"
64
+ };
65
+ var type = "module";
66
+ var exports = "./dist/pake.js";
67
+ var license = "MIT";
68
+ var dependencies = {
69
+ "@tauri-apps/api": "^1.4.0",
70
+ "@tauri-apps/cli": "^1.4.0",
71
+ axios: "^1.1.3",
72
+ chalk: "^5.1.2",
73
+ commander: "^11.0.0",
74
+ "file-type": "^18.0.0",
75
+ "fs-extra": "^11.1.0",
76
+ "is-url": "^1.2.4",
77
+ loglevel: "^1.8.1",
78
+ ora: "^6.1.2",
79
+ prompts: "^2.4.2",
80
+ psl: "^1.9.0",
81
+ shelljs: "^0.8.5",
82
+ "tmp-promise": "^3.0.3",
83
+ "update-notifier": "^6.0.2"
84
+ };
85
+ var devDependencies = {
86
+ "@rollup/plugin-alias": "^4.0.2",
87
+ "@rollup/plugin-commonjs": "^23.0.2",
88
+ "@rollup/plugin-json": "^5.0.2",
89
+ "@rollup/plugin-terser": "^0.1.0",
90
+ "@types/fs-extra": "^9.0.13",
91
+ "@types/is-url": "^1.2.30",
92
+ "@types/page-icon": "^0.3.4",
93
+ "@types/prompts": "^2.4.1",
94
+ "@types/psl": "^1.1.0",
95
+ "@types/shelljs": "^0.8.11",
96
+ "@types/tmp": "^0.2.3",
97
+ "@types/update-notifier": "^6.0.1",
98
+ "app-root-path": "^3.1.0",
99
+ "cross-env": "^7.0.3",
100
+ rollup: "^3.3.0",
101
+ "rollup-plugin-typescript2": "^0.34.1",
102
+ tslib: "^2.4.1",
103
+ typescript: "^4.9.3"
104
+ };
105
+ var packageJson = {
106
+ name: name,
107
+ version: version,
108
+ description: description,
109
+ engines: engines,
110
+ bin: bin,
111
+ repository: repository,
112
+ author: author,
113
+ keywords: keywords,
114
+ files: files,
115
+ scripts: scripts,
116
+ type: type,
117
+ exports: exports,
118
+ license: license,
119
+ dependencies: dependencies,
120
+ devDependencies: devDependencies
38
121
  };
39
-
40
- // Convert the current module URL to a file path
41
- const currentModulePath = fileURLToPath(import.meta.url);
42
- // Resolve the parent directory of the current module
43
- const npmDirectory = path.join(path.dirname(currentModulePath), '..');
44
-
45
- const { platform: platform$2 } = process;
46
- const IS_MAC = platform$2 === 'darwin';
47
- const IS_WIN = platform$2 === 'win32';
48
- const IS_LINUX = platform$2 === 'linux';
49
-
50
- async function handleIcon(options) {
51
- if (options.icon) {
52
- if (options.icon.startsWith('http')) {
53
- return downloadIcon(options.icon);
54
- }
55
- else {
56
- return path.resolve(options.icon);
57
- }
58
- }
59
- else {
60
- logger.info('No app icon provided, default icon used. Use --icon option to assign an icon.');
61
- const iconPath = IS_WIN ? 'src-tauri/png/icon_256.ico' : IS_LINUX ? 'src-tauri/png/icon_512.png' : 'src-tauri/icons/icon.icns';
62
- return path.join(npmDirectory, iconPath);
63
- }
64
- }
65
- async function downloadIcon(iconUrl) {
66
- try {
67
- const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' });
68
- const iconData = await iconResponse.data;
69
- if (!iconData) {
70
- return null;
71
- }
72
- const fileDetails = await fileTypeFromBuffer(iconData);
73
- if (!fileDetails) {
74
- return null;
75
- }
76
- const { path: tempPath } = await dir();
77
- const iconPath = `${tempPath}/icon.${fileDetails.ext}`;
78
- await fsExtra.outputFile(iconPath, iconData);
79
- return iconPath;
80
- }
81
- catch (error) {
82
- if (error.response && error.response.status === 404) {
83
- return null;
84
- }
85
- throw error;
86
- }
87
- }
88
-
89
- // Extracts the domain from a given URL.
90
- function getDomain(inputUrl) {
91
- try {
92
- const url = new URL(inputUrl);
93
- // Use PSL to parse domain names.
94
- const parsed = psl.parse(url.hostname);
95
- // If domain is available, split it and return the SLD.
96
- if ("domain" in parsed && parsed.domain) {
97
- return parsed.domain.split('.')[0];
98
- }
99
- else {
100
- return null;
101
- }
102
- }
103
- catch (error) {
104
- return null;
105
- }
106
- }
107
- // Appends 'https://' protocol to the URL if not present.
108
- function appendProtocol(inputUrl) {
109
- try {
110
- new URL(inputUrl);
111
- return inputUrl;
112
- }
113
- catch {
114
- return `https://${inputUrl}`;
115
- }
116
- }
117
- // Normalizes the URL by ensuring it has a protocol and is valid.
118
- function normalizeUrl(urlToNormalize) {
119
- const urlWithProtocol = appendProtocol(urlToNormalize);
120
- if (isUrl(urlWithProtocol)) {
121
- return urlWithProtocol;
122
- }
123
- else {
124
- throw new Error(`Your url "${urlWithProtocol}" is invalid`);
125
- }
126
- }
127
-
128
- // Generates an identifier based on the given URL.
129
- function getIdentifier(url) {
130
- const postFixHash = crypto.createHash('md5')
131
- .update(url)
132
- .digest('hex')
133
- .substring(0, 6);
134
- return `pake-${postFixHash}`;
135
- }
136
- async function promptText(message, initial) {
137
- const response = await prompts({
138
- type: 'text',
139
- name: 'content',
140
- message,
141
- initial,
142
- });
143
- return response.content;
144
- }
145
-
146
- async function handleOptions(options, url) {
147
- const appOptions = {
148
- ...options,
149
- identifier: getIdentifier(url),
150
- };
151
- let urlExists = await fsExtra.pathExists(url);
152
- if (!appOptions.name) {
153
- const defaultName = urlExists ? "" : getDomain(url);
154
- const promptMessage = 'Enter your application name';
155
- appOptions.name = await promptText(promptMessage, defaultName);
156
- }
157
- appOptions.icon = await handleIcon(appOptions);
158
- return appOptions;
159
- }
160
122
 
161
123
  var windows = [
162
124
  {
@@ -343,11 +305,11 @@ var LinuxConf = {
343
305
  const platformConfigs = {
344
306
  win32: WinConf,
345
307
  darwin: MacConf,
346
- linux: LinuxConf
308
+ linux: LinuxConf,
347
309
  };
348
- const { platform: platform$1 } = process;
310
+ const { platform: platform$2 } = process;
349
311
  // @ts-ignore
350
- const platformConfig = platformConfigs[platform$1];
312
+ const platformConfig = platformConfigs[platform$2];
351
313
  let tauriConfig = {
352
314
  tauri: {
353
315
  ...CommonConf.tauri,
@@ -355,42 +317,99 @@ let tauriConfig = {
355
317
  },
356
318
  package: CommonConf.package,
357
319
  build: CommonConf.build,
358
- pake: pakeConf
320
+ pake: pakeConf,
359
321
  };
360
322
 
361
- function shellExec(command) {
362
- return new Promise((resolve, reject) => {
363
- shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, (code) => {
364
- if (code === 0) {
365
- resolve(0);
366
- }
367
- else {
368
- reject(new Error(`${code}`));
369
- }
370
- });
371
- });
372
- }
373
-
374
- const resolve = promisify(dns.resolve);
375
- const ping = async (host) => {
376
- const lookup = promisify(dns.lookup);
323
+ // Generates an identifier based on the given URL.
324
+ function getIdentifier(url) {
325
+ const postFixHash = crypto.createHash('md5').update(url).digest('hex').substring(0, 6);
326
+ return `pake-${postFixHash}`;
327
+ }
328
+ async function promptText(message, initial) {
329
+ const response = await prompts({
330
+ type: 'text',
331
+ name: 'content',
332
+ message,
333
+ initial,
334
+ });
335
+ return response.content;
336
+ }
337
+ function capitalizeFirstLetter(string) {
338
+ return string.charAt(0).toUpperCase() + string.slice(1);
339
+ }
340
+ function getSpinner(text) {
341
+ const loadingType = {
342
+ interval: 80,
343
+ frames: ['โœฆ', 'โœถ', 'โœบ', 'โœต', 'โœธ', 'โœน', 'โœบ'],
344
+ };
345
+ return ora({
346
+ text: `${chalk.cyan(text)}\n`,
347
+ spinner: loadingType,
348
+ color: 'cyan',
349
+ }).start();
350
+ }
351
+
352
+ const { platform: platform$1 } = process;
353
+ const IS_MAC = platform$1 === 'darwin';
354
+ const IS_WIN = platform$1 === 'win32';
355
+ const IS_LINUX = platform$1 === 'linux';
356
+
357
+ // Convert the current module URL to a file path
358
+ const currentModulePath = fileURLToPath(import.meta.url);
359
+ // Resolve the parent directory of the current module
360
+ const npmDirectory = path.join(path.dirname(currentModulePath), '..');
361
+
362
+ function shellExec(command) {
363
+ return new Promise((resolve, reject) => {
364
+ shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, code => {
365
+ if (code === 0) {
366
+ resolve(0);
367
+ }
368
+ else {
369
+ reject(new Error(`${code}`));
370
+ }
371
+ });
372
+ });
373
+ }
374
+
375
+ const logger = {
376
+ info(...msg) {
377
+ log.info(...msg.map(m => chalk.white(m)));
378
+ },
379
+ debug(...msg) {
380
+ log.debug(...msg);
381
+ },
382
+ error(...msg) {
383
+ log.error(...msg.map(m => chalk.red(m)));
384
+ },
385
+ warn(...msg) {
386
+ log.info(...msg.map(m => chalk.yellow(m)));
387
+ },
388
+ success(...msg) {
389
+ log.info(...msg.map(m => chalk.green(m)));
390
+ },
391
+ };
392
+
393
+ const resolve = promisify(dns.resolve);
394
+ const ping = async (host) => {
395
+ const lookup = promisify(dns.lookup);
377
396
  const ip = await lookup(host);
378
397
  const start = new Date();
379
398
  // Prevent timeouts from affecting user experience.
380
399
  const requestPromise = new Promise((resolve, reject) => {
381
- const req = http.get(`http://${ip.address}`, (res) => {
400
+ const req = http.get(`http://${ip.address}`, res => {
382
401
  const delay = new Date().getTime() - start.getTime();
383
402
  res.resume();
384
403
  resolve(delay);
385
404
  });
386
- req.on('error', (err) => {
405
+ req.on('error', err => {
387
406
  reject(err);
388
407
  });
389
408
  });
390
409
  const timeoutPromise = new Promise((_, reject) => {
391
410
  setTimeout(() => {
392
411
  reject(new Error('Request timed out after 3 seconds'));
393
- }, 3000);
412
+ }, 1000);
394
413
  });
395
414
  return Promise.race([requestPromise, timeoutPromise]);
396
415
  };
@@ -401,36 +420,35 @@ async function isChinaDomain(domain) {
401
420
  }
402
421
  catch (error) {
403
422
  logger.debug(`${domain} can't be parse!`);
404
- return false;
423
+ return true;
405
424
  }
406
425
  }
407
426
  async function isChinaIP(ip, domain) {
408
427
  try {
409
428
  const delay = await ping(ip);
410
429
  logger.debug(`${domain} latency is ${delay} ms`);
411
- return delay > 500;
430
+ return delay > 1000;
412
431
  }
413
432
  catch (error) {
414
433
  logger.debug(`ping ${domain} failed!`);
415
- return false;
434
+ return true;
416
435
  }
417
436
  }
418
437
 
419
438
  async function installRust() {
420
- const isInChina = await isChinaDomain("sh.rustup.rs");
439
+ const isInChina = await isChinaDomain('sh.rustup.rs');
421
440
  const rustInstallScriptForMac = isInChina
422
441
  ? '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'
423
442
  : "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y";
424
443
  const rustInstallScriptForWindows = 'winget install --id Rustlang.Rustup';
425
- const spinner = ora('Downloading Rust').start();
444
+ const spinner = getSpinner('Downloading Rust...');
426
445
  try {
427
446
  await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac);
428
- spinner.succeed();
447
+ spinner.succeed(chalk.green('Rust installed successfully!'));
429
448
  }
430
449
  catch (error) {
431
450
  console.error('Error installing Rust:', error.message);
432
- spinner.fail();
433
- //@ts-ignore
451
+ spinner.fail(chalk.red('Rust installation failed!'));
434
452
  process.exit(1);
435
453
  }
436
454
  }
@@ -438,50 +456,8 @@ function checkRustInstalled() {
438
456
  return shelljs.exec('rustc --version', { silent: true }).code === 0;
439
457
  }
440
458
 
441
- class BaseBuilder {
442
- async prepare() {
443
- // Windows and Linux need to install necessary build tools.
444
- if (!IS_MAC) {
445
- logger.info('Install Rust and required build tools to build the app.');
446
- logger.info('See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing.');
447
- }
448
- if (checkRustInstalled()) {
449
- return;
450
- }
451
- const res = await prompts({
452
- type: 'confirm',
453
- message: 'Rust not detected. Install now?',
454
- name: 'value',
455
- });
456
- if (res.value) {
457
- await installRust();
458
- }
459
- else {
460
- logger.error('Error: Rust required to package your webapp!');
461
- process.exit(2);
462
- }
463
- }
464
- async runBuildCommand(directory, command) {
465
- const spinner = ora('Building...').start();
466
- setTimeout(() => spinner.succeed(), 5000);
467
- const isChina = await isChinaDomain("www.npmjs.com");
468
- if (isChina) {
469
- logger.info("Located in China, using npm/Rust CN mirror.");
470
- const rustProjectDir = path.join(directory, 'src-tauri', ".cargo");
471
- await fsExtra.ensureDir(rustProjectDir);
472
- const projectCnConf = path.join(directory, "src-tauri", "rust_proxy.toml");
473
- const projectConf = path.join(rustProjectDir, "config");
474
- await fsExtra.copy(projectCnConf, projectConf);
475
- await shellExec(`cd "${directory}" && npm install --registry=https://registry.npmmirror.com && ${command}`);
476
- }
477
- else {
478
- await shellExec(`cd "${directory}" && npm install && ${command}`);
479
- }
480
- }
481
- }
482
-
483
459
  async function mergeConfig(url, options, tauriConf) {
484
- const { width, height, fullscreen, transparent, resizable, userAgent, showMenu, showSystemTray, systemTrayIcon, iterCopyFile, identifier, name, } = options;
460
+ const { width, height, fullscreen, transparent, userAgent, showMenu, showSystemTray, systemTrayIcon, iterCopyFile, identifier, name, resizable = true, } = options;
485
461
  const { platform } = process;
486
462
  // Set Windows parameters.
487
463
  const tauriConfWindowOptions = {
@@ -492,28 +468,12 @@ async function mergeConfig(url, options, tauriConf) {
492
468
  resizable,
493
469
  };
494
470
  Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
495
- // Determine whether the package name is valid.
496
- // for Linux, package name must be a-z, 0-9 or "-", not allow to A-Z and other
497
- const platformRegexMapping = {
498
- linux: /[0-9]*[a-z]+[0-9]*\-?[0-9]*[a-z]*[0-9]*\-?[0-9]*[a-z]*[0-9]*/,
499
- default: /([0-9]*[a-zA-Z]+[0-9]*)+/,
500
- };
501
- const reg = platformRegexMapping[platform] || platformRegexMapping.default;
502
- const nameCheck = reg.test(name) && reg.exec(name)[0].length === name.length;
503
- if (!nameCheck) {
504
- const errorMsg = platform === 'linux'
505
- ? `Package name is invalid. It 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.`
506
- : `Package name is invalid. It should only include letters and numbers, and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead.`;
507
- logger.error(errorMsg);
508
- process.exit();
509
- }
510
471
  tauriConf.package.productName = name;
511
472
  tauriConf.tauri.bundle.identifier = identifier;
512
- // Judge the type of URL, whether it is a file or a website.
513
- // If it is a file and the recursive copy function is enabled then the file and all files in its parent folder need to be copied to the "src" directory. Otherwise, only the single file will be copied.
514
- const urlExists = await fsExtra.pathExists(url);
515
- if (urlExists) {
516
- logger.warn('Your input might be a local file.');
473
+ //Judge the type of URL, whether it is a file or a website.
474
+ const pathExists = await fsExtra.pathExists(url);
475
+ if (pathExists) {
476
+ logger.warn('โœผ Your input might be a local file.');
517
477
  tauriConf.pake.windows[0].url_type = 'local';
518
478
  const fileName = path.basename(url);
519
479
  const dirName = path.dirname(url);
@@ -527,7 +487,7 @@ async function mergeConfig(url, options, tauriConf) {
527
487
  fsExtra.moveSync(distDir, distBakDir, { overwrite: true });
528
488
  fsExtra.copySync(dirName, distDir, { overwrite: true });
529
489
  const filesToCopyBack = ['cli.js', 'about_pake.html'];
530
- await Promise.all(filesToCopyBack.map((file) => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
490
+ await Promise.all(filesToCopyBack.map(file => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
531
491
  }
532
492
  tauriConf.pake.windows[0].url = fileName;
533
493
  tauriConf.pake.windows[0].url_type = 'local';
@@ -535,8 +495,7 @@ async function mergeConfig(url, options, tauriConf) {
535
495
  else {
536
496
  tauriConf.pake.windows[0].url_type = 'web';
537
497
  // Set the secure domain for calling window.__TAURI__ to the application domain that has been set.
538
- tauriConf.tauri.security.dangerousRemoteDomainIpcAccess[0].domain =
539
- new URL(url).hostname;
498
+ tauriConf.tauri.security.dangerousRemoteDomainIpcAccess[0].domain = new URL(url).hostname;
540
499
  }
541
500
  const platformMap = {
542
501
  win32: 'windows',
@@ -554,10 +513,11 @@ async function mergeConfig(url, options, tauriConf) {
554
513
  delete tauriConf.tauri.bundle.deb.files;
555
514
  const validTargets = ['all', 'deb', 'appimage'];
556
515
  if (validTargets.includes(options.targets)) {
557
- tauriConf.tauri.bundle.targets = options.targets === 'all' ? ['deb', 'appimage'] : [options.targets];
516
+ tauriConf.tauri.bundle.targets =
517
+ options.targets === 'all' ? ['deb', 'appimage'] : [options.targets];
558
518
  }
559
519
  else {
560
- logger.warn(`The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
520
+ logger.warn(`โœผ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
561
521
  }
562
522
  }
563
523
  // Set icon.
@@ -578,7 +538,7 @@ async function mergeConfig(url, options, tauriConf) {
578
538
  fileExt: '.icns',
579
539
  path: `icons/${name.toLowerCase()}.icns`,
580
540
  defaultIcon: 'icons/icon.icns',
581
- message: 'MacOS icon must be .icns type.',
541
+ message: 'macOS icon must be .icns type.',
582
542
  },
583
543
  };
584
544
  const iconInfo = platformIconMap[platform];
@@ -588,7 +548,7 @@ async function mergeConfig(url, options, tauriConf) {
588
548
  let customIconExt = path.extname(options.icon).toLowerCase();
589
549
  if (customIconExt !== iconInfo.fileExt) {
590
550
  updateIconPath = false;
591
- logger.warn(`${iconInfo.message}, but you give ${customIconExt}`);
551
+ logger.warn(`โœผ ${iconInfo.message}, but you give ${customIconExt}`);
592
552
  tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
593
553
  }
594
554
  else {
@@ -600,11 +560,11 @@ async function mergeConfig(url, options, tauriConf) {
600
560
  tauriConf.tauri.bundle.icon = [options.icon];
601
561
  }
602
562
  else {
603
- logger.warn(`Icon will remain as default.`);
563
+ logger.warn(`โœผ Icon will remain as default.`);
604
564
  }
605
565
  }
606
566
  else {
607
- logger.warn('Custom icon path may be invalid. Default icon will be used instead.');
567
+ logger.warn('โœผ Custom icon path may be invalid, default icon will be used instead.');
608
568
  tauriConf.tauri.bundle.icon = [iconInfo.defaultIcon];
609
569
  }
610
570
  // Set tray icon path.
@@ -620,13 +580,13 @@ async function mergeConfig(url, options, tauriConf) {
620
580
  await fsExtra.copy(systemTrayIcon, trayIcoPath);
621
581
  }
622
582
  else {
623
- logger.warn(`System tray icon must be .ico or .png, but you provided ${iconExt}.`);
624
- logger.warn(`Default system tray icon will be used.`);
583
+ logger.warn(`โœผ System tray icon must be .ico or .png, but you provided ${iconExt}.`);
584
+ logger.warn(`โœผ Default system tray icon will be used.`);
625
585
  }
626
586
  }
627
587
  catch {
628
- logger.warn(`${systemTrayIcon} not exists!`);
629
- logger.warn(`Default system tray icon will remain unchanged.`);
588
+ logger.warn(`โœผ ${systemTrayIcon} not exists!`);
589
+ logger.warn(`โœผ Default system tray icon will remain unchanged.`);
630
590
  }
631
591
  }
632
592
  tauriConf.tauri.systemTray.iconPath = trayIconPath;
@@ -648,80 +608,141 @@ async function mergeConfig(url, options, tauriConf) {
648
608
  await fsExtra.writeJson(configJsonPath, tauriConf2, { spaces: 4 });
649
609
  }
650
610
 
651
- class MacBuilder extends BaseBuilder {
652
- async build(url, options) {
653
- const { name } = options;
654
- await mergeConfig(url, options, tauriConfig);
655
- let dmgName;
656
- if (options.multiArch) {
657
- await this.runBuildCommand(npmDirectory, 'npm run build:mac');
658
- dmgName = `${name}_${tauriConfig.package.version}_universal.dmg`;
611
+ class BaseBuilder {
612
+ constructor(options) {
613
+ this.options = options;
614
+ }
615
+ async prepare() {
616
+ if (!IS_MAC) {
617
+ logger.info('โœบ The first use requires installing system dependencies.');
618
+ logger.info('โœบ See more in https://tauri.app/v1/guides/getting-started/prerequisites.');
619
+ }
620
+ if (!checkRustInstalled()) {
621
+ const res = await prompts({
622
+ type: 'confirm',
623
+ message: 'Rust not detected. Install now?',
624
+ name: 'value',
625
+ });
626
+ if (res.value) {
627
+ await installRust();
628
+ }
629
+ else {
630
+ logger.error('โœ• Rust required to package your webapp.');
631
+ process.exit(0);
632
+ }
633
+ }
634
+ const isChina = await isChinaDomain('www.npmjs.com');
635
+ const spinner = getSpinner('Installing package...');
636
+ if (isChina) {
637
+ logger.info('โœบ Located in China, using npm/rsProxy CN mirror.');
638
+ const rustProjectDir = path.join(npmDirectory, 'src-tauri', '.cargo');
639
+ await fsExtra.ensureDir(rustProjectDir);
640
+ const projectCnConf = path.join(npmDirectory, 'src-tauri', 'rust_proxy.toml');
641
+ const projectConf = path.join(rustProjectDir, 'config');
642
+ await fsExtra.copy(projectCnConf, projectConf);
643
+ await shellExec(`cd "${npmDirectory}" && npm install --registry=https://registry.npmmirror.com`);
659
644
  }
660
645
  else {
661
- await this.runBuildCommand(npmDirectory, 'npm run build');
662
- let arch = process.arch === "arm64" ? "aarch64" : process.arch;
663
- dmgName = `${name}_${tauriConfig.package.version}_${arch}.dmg`;
646
+ await shellExec(`cd "${npmDirectory}" && npm install`);
664
647
  }
665
- const appPath = this.getBuildAppPath(npmDirectory, dmgName, options.multiArch);
666
- const distPath = path.resolve(`${name}.dmg`);
648
+ spinner.succeed(chalk.green('Package installed!'));
649
+ }
650
+ async build(url) {
651
+ await this.buildAndCopy(url, this.options.targets);
652
+ }
653
+ async buildAndCopy(url, target) {
654
+ const { name } = this.options;
655
+ await mergeConfig(url, this.options, tauriConfig);
656
+ // Build app
657
+ const spinner = getSpinner('Building app...');
658
+ setTimeout(() => spinner.stop(), 3000);
659
+ await shellExec(`cd ${npmDirectory} && ${this.getBuildCommand()}`);
660
+ // Copy app
661
+ const fileName = this.getFileName();
662
+ const fileType = this.getFileType(target);
663
+ const appPath = this.getBuildAppPath(npmDirectory, fileName, fileType);
664
+ const distPath = path.resolve(`${name}.${fileType}`);
667
665
  await fsExtra.copy(appPath, distPath);
668
666
  await fsExtra.remove(appPath);
669
- logger.success('Build success!');
670
- logger.success('App installer located in', distPath);
667
+ logger.success('โœ” Build success!');
668
+ logger.success('โœ” App installer located in', distPath);
669
+ }
670
+ getFileType(target) {
671
+ return target;
672
+ }
673
+ getBuildCommand() {
674
+ return 'npm run build';
675
+ }
676
+ getBasePath() {
677
+ return 'src-tauri/target/release/bundle/';
678
+ }
679
+ getBuildAppPath(npmDirectory, fileName, fileType) {
680
+ return path.join(npmDirectory, this.getBasePath(), fileType.toLowerCase(), `${fileName}.${fileType}`);
681
+ }
682
+ }
683
+
684
+ class MacBuilder extends BaseBuilder {
685
+ constructor(options) {
686
+ super(options);
687
+ this.options.targets = 'dmg';
688
+ }
689
+ getFileName() {
690
+ const { name } = this.options;
691
+ let arch;
692
+ if (this.options.multiArch) {
693
+ arch = 'universal';
694
+ }
695
+ else {
696
+ arch = process.arch === 'arm64' ? 'aarch64' : process.arch;
697
+ }
698
+ return `${name}_${tauriConfig.package.version}_${arch}`;
699
+ }
700
+ getBuildCommand() {
701
+ return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand();
671
702
  }
672
- getBuildAppPath(npmDirectory, dmgName, multiArch) {
673
- const dmgPath = multiArch ? 'src-tauri/target/universal-apple-darwin/release/bundle/dmg' : 'src-tauri/target/release/bundle/dmg';
674
- return path.join(npmDirectory, dmgPath, dmgName);
703
+ getBasePath() {
704
+ return this.options.multiArch
705
+ ? 'src-tauri/target/universal-apple-darwin/release/bundle'
706
+ : super.getBasePath();
675
707
  }
676
708
  }
677
709
 
678
710
  class WinBuilder extends BaseBuilder {
679
- async build(url, options) {
680
- const { name } = options;
681
- await mergeConfig(url, options, tauriConfig);
682
- await this.runBuildCommand(npmDirectory, 'npm run build');
683
- const language = tauriConfig.tauri.bundle.windows.wix.language[0];
684
- const arch = process.arch;
685
- const msiName = `${name}_${tauriConfig.package.version}_${arch}_${language}.msi`;
686
- const appPath = this.getBuildAppPath(npmDirectory, msiName);
687
- const distPath = path.resolve(`${name}.msi`);
688
- await fsExtra.copy(appPath, distPath);
689
- await fsExtra.remove(appPath);
690
- logger.success('Build success!');
691
- logger.success('App installer located in', distPath);
711
+ constructor(options) {
712
+ super(options);
713
+ this.options.targets = 'msi';
692
714
  }
693
- getBuildAppPath(npmDirectory, msiName) {
694
- return path.join(npmDirectory, 'src-tauri/target/release/bundle/msi', msiName);
715
+ getFileName() {
716
+ const { name } = this.options;
717
+ const { arch } = process;
718
+ const language = tauriConfig.tauri.bundle.windows.wix.language[0];
719
+ return `${name}_${tauriConfig.package.version}_${arch}_${language}`;
695
720
  }
696
721
  }
697
722
 
698
723
  class LinuxBuilder extends BaseBuilder {
699
- async build(url, options) {
700
- const { name } = options;
701
- await mergeConfig(url, options, tauriConfig);
702
- await this.runBuildCommand(npmDirectory, 'npm run build');
703
- const arch = process.arch === "x64" ? "amd64" : process.arch;
704
- if (options.targets === "deb" || options.targets === "all") {
705
- const debName = `${name}_${tauriConfig.package.version}_${arch}.deb`;
706
- const appPath = this.getBuildAppPath(npmDirectory, "deb", debName);
707
- const distPath = path.resolve(`${name}.deb`);
708
- await fsExtra.copy(appPath, distPath);
709
- await fsExtra.remove(appPath);
710
- logger.success('Build Deb success!');
711
- logger.success('Deb app installer located in', distPath);
712
- }
713
- if (options.targets === "appimage" || options.targets === "all") {
714
- const appImageName = `${name}_${tauriConfig.package.version}_${arch}.AppImage`;
715
- const appImagePath = this.getBuildAppPath(npmDirectory, "appimage", appImageName);
716
- const distAppPath = path.resolve(`${name}.AppImage`);
717
- await fsExtra.copy(appImagePath, distAppPath);
718
- await fsExtra.remove(appImagePath);
719
- logger.success('Build AppImage success!');
720
- logger.success('AppImage installer located in', distAppPath);
724
+ constructor(options) {
725
+ super(options);
726
+ }
727
+ getFileName() {
728
+ const { name } = this.options;
729
+ const arch = process.arch === 'x64' ? 'amd64' : process.arch;
730
+ return `${name}_${tauriConfig.package.version}_${arch}`;
731
+ }
732
+ // Customize it, considering that there are all targets.
733
+ async build(url) {
734
+ const targetTypes = ['deb', 'appimage'];
735
+ for (const target of targetTypes) {
736
+ if (this.options.targets === target || this.options.targets === 'all') {
737
+ await this.buildAndCopy(url, target);
738
+ }
721
739
  }
722
740
  }
723
- getBuildAppPath(npmDirectory, packageType, packageName) {
724
- return path.join(npmDirectory, 'src-tauri/target/release/bundle/', packageType, packageName);
741
+ getFileType(target) {
742
+ if (target === 'appimage') {
743
+ return 'AppImage';
744
+ }
745
+ return super.getFileType(target);
725
746
  }
726
747
  }
727
748
 
@@ -732,120 +753,166 @@ const buildersMap = {
732
753
  linux: LinuxBuilder,
733
754
  };
734
755
  class BuilderProvider {
735
- static create() {
756
+ static create(options) {
736
757
  const Builder = buildersMap[platform];
737
758
  if (!Builder) {
738
759
  throw new Error('The current system is not supported!');
739
760
  }
740
- return new Builder();
761
+ return new Builder(options);
741
762
  }
742
763
  }
743
764
 
744
- var name = "pake-cli";
745
- var version = "2.1.1";
746
- var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with Rust. ๐Ÿคฑ๐Ÿป ๅพˆ็ฎ€ๅ•็š„็”จ Rust ๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆๅพˆๅฐ็š„ๆกŒ้ข Appใ€‚";
747
- var engines = {
748
- node: ">=16.0.0"
749
- };
750
- var bin = {
751
- pake: "./cli.js"
752
- };
753
- var repository = {
754
- type: "git",
755
- url: "https://github.com/tw93/pake.git"
756
- };
757
- var author = {
758
- name: "Tw93",
759
- email: "tw93@qq.com"
760
- };
761
- var keywords = [
762
- "pake",
763
- "pake-cli",
764
- "rust",
765
- "tauri",
766
- "no-electron",
767
- "productivity"
768
- ];
769
- var files = [
770
- "dist",
771
- "src-tauri",
772
- "cli.js"
773
- ];
774
- var scripts = {
775
- start: "npm run dev",
776
- dev: "npm run tauri dev",
777
- build: "npm run tauri build --release",
778
- "build:mac": "npm run tauri build -- --target universal-apple-darwin",
779
- "build:all-unix": "chmod +x ./script/build.sh && ./script/build.sh",
780
- "build:all-windows": "pwsh ./script/build.ps1",
781
- analyze: "cd src-tauri && cargo bloat --release --crates",
782
- tauri: "tauri",
783
- cli: "rollup -c rollup.config.js --watch",
784
- "cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
785
- prepublishOnly: "npm run cli:build"
786
- };
787
- var type = "module";
788
- var exports = "./dist/pake.js";
789
- var license = "MIT";
790
- var dependencies = {
791
- "@tauri-apps/api": "^1.4.0",
792
- "@tauri-apps/cli": "^1.4.0",
793
- axios: "^1.1.3",
794
- chalk: "^5.1.2",
795
- commander: "^11.0.0",
796
- "file-type": "^18.0.0",
797
- "fs-extra": "^11.1.0",
798
- "is-url": "^1.2.4",
799
- loglevel: "^1.8.1",
800
- ora: "^6.1.2",
801
- prompts: "^2.4.2",
802
- psl: "^1.9.0",
803
- shelljs: "^0.8.5",
804
- "tmp-promise": "^3.0.3",
805
- "update-notifier": "^6.0.2"
806
- };
807
- var devDependencies = {
808
- "@rollup/plugin-alias": "^4.0.2",
809
- "@rollup/plugin-commonjs": "^23.0.2",
810
- "@rollup/plugin-json": "^5.0.2",
811
- "@rollup/plugin-terser": "^0.1.0",
812
- "@types/fs-extra": "^9.0.13",
813
- "@types/is-url": "^1.2.30",
814
- "@types/page-icon": "^0.3.4",
815
- "@types/prompts": "^2.4.1",
816
- "@types/psl": "^1.1.0",
817
- "@types/shelljs": "^0.8.11",
818
- "@types/tmp": "^0.2.3",
819
- "@types/update-notifier": "^6.0.1",
820
- "app-root-path": "^3.1.0",
821
- "cross-env": "^7.0.3",
822
- rollup: "^3.3.0",
823
- "rollup-plugin-typescript2": "^0.34.1",
824
- tslib: "^2.4.1",
825
- typescript: "^4.9.3"
826
- };
827
- var packageJson = {
828
- name: name,
829
- version: version,
830
- description: description,
831
- engines: engines,
832
- bin: bin,
833
- repository: repository,
834
- author: author,
835
- keywords: keywords,
836
- files: files,
837
- scripts: scripts,
838
- type: type,
839
- exports: exports,
840
- license: license,
841
- dependencies: dependencies,
842
- devDependencies: devDependencies
765
+ const DEFAULT_PAKE_OPTIONS = {
766
+ icon: '',
767
+ height: 780,
768
+ width: 1200,
769
+ fullscreen: false,
770
+ resizable: true,
771
+ transparent: false,
772
+ userAgent: '',
773
+ showMenu: false,
774
+ showSystemTray: false,
775
+ multiArch: false,
776
+ targets: 'deb',
777
+ iterCopyFile: false,
778
+ systemTrayIcon: '',
779
+ debug: false,
843
780
  };
844
781
 
845
782
  async function checkUpdateTips() {
846
783
  updateNotifier({ pkg: packageJson }).notify();
847
784
  }
848
785
 
786
+ async function handleIcon(options) {
787
+ if (options.icon) {
788
+ if (options.icon.startsWith('http')) {
789
+ return downloadIcon(options.icon);
790
+ }
791
+ else {
792
+ return path.resolve(options.icon);
793
+ }
794
+ }
795
+ else {
796
+ logger.warn('โœผ No icon given, default in use. For a custom icon, use --icon option.');
797
+ const iconPath = IS_WIN
798
+ ? 'src-tauri/png/icon_256.ico'
799
+ : IS_LINUX
800
+ ? 'src-tauri/png/icon_512.png'
801
+ : 'src-tauri/icons/icon.icns';
802
+ return path.join(npmDirectory, iconPath);
803
+ }
804
+ }
805
+ async function downloadIcon(iconUrl) {
806
+ const spinner = getSpinner('Downloading icon...');
807
+ try {
808
+ const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' });
809
+ const iconData = await iconResponse.data;
810
+ if (!iconData) {
811
+ return null;
812
+ }
813
+ const fileDetails = await fileTypeFromBuffer(iconData);
814
+ if (!fileDetails) {
815
+ return null;
816
+ }
817
+ const { path: tempPath } = await dir();
818
+ const iconPath = `${tempPath}/icon.${fileDetails.ext}`;
819
+ await fsExtra.outputFile(iconPath, iconData);
820
+ spinner.succeed(chalk.green('Icon downloaded successfully!'));
821
+ return iconPath;
822
+ }
823
+ catch (error) {
824
+ spinner.fail(chalk.red('Icon download failed!'));
825
+ if (error.response && error.response.status === 404) {
826
+ return null;
827
+ }
828
+ throw error;
829
+ }
830
+ }
831
+
832
+ // Extracts the domain from a given URL.
833
+ function getDomain(inputUrl) {
834
+ try {
835
+ const url = new URL(inputUrl);
836
+ // Use PSL to parse domain names.
837
+ const parsed = psl.parse(url.hostname);
838
+ // If domain is available, split it and return the SLD.
839
+ if ('domain' in parsed && parsed.domain) {
840
+ return parsed.domain.split('.')[0];
841
+ }
842
+ else {
843
+ return null;
844
+ }
845
+ }
846
+ catch (error) {
847
+ return null;
848
+ }
849
+ }
850
+ // Appends 'https://' protocol to the URL if not present.
851
+ function appendProtocol(inputUrl) {
852
+ try {
853
+ new URL(inputUrl);
854
+ return inputUrl;
855
+ }
856
+ catch {
857
+ return `https://${inputUrl}`;
858
+ }
859
+ }
860
+ // Normalizes the URL by ensuring it has a protocol and is valid.
861
+ function normalizeUrl(urlToNormalize) {
862
+ const urlWithProtocol = appendProtocol(urlToNormalize);
863
+ if (isUrl(urlWithProtocol)) {
864
+ return urlWithProtocol;
865
+ }
866
+ else {
867
+ throw new Error(`Your url "${urlWithProtocol}" is invalid`);
868
+ }
869
+ }
870
+
871
+ function resolveAppName(name, platform) {
872
+ const domain = getDomain(name) || 'pake';
873
+ return platform !== 'linux' ? capitalizeFirstLetter(domain) : domain;
874
+ }
875
+ function isValidName(name, platform) {
876
+ const platformRegexMapping = {
877
+ linux: /^[a-z0-9]+(-[a-z0-9]+)*$/,
878
+ default: /^[a-zA-Z0-9]+$/,
879
+ };
880
+ const reg = platformRegexMapping[platform] || platformRegexMapping.default;
881
+ return !!name && reg.test(name);
882
+ }
883
+ async function handleOptions(options, url) {
884
+ const { platform } = process;
885
+ const isActions = process.env.GITHUB_ACTIONS;
886
+ let name = options.name;
887
+ const pathExists = await fsExtra.pathExists(url);
888
+ if (!options.name) {
889
+ const defaultName = pathExists ? '' : resolveAppName(url, platform);
890
+ const promptMessage = 'Enter your application name';
891
+ const namePrompt = await promptText(promptMessage, defaultName);
892
+ name = namePrompt || defaultName;
893
+ }
894
+ if (!isValidName(name, platform)) {
895
+ 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.`;
896
+ 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.`;
897
+ const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
898
+ logger.error(errorMsg);
899
+ if (isActions) {
900
+ name = resolveAppName(url, platform);
901
+ logger.warn(`โœผ Inside github actions, use the default name: ${name}`);
902
+ }
903
+ else {
904
+ process.exit(1);
905
+ }
906
+ }
907
+ const appOptions = {
908
+ ...options,
909
+ name,
910
+ identifier: getIdentifier(url),
911
+ };
912
+ appOptions.icon = await handleIcon(appOptions);
913
+ return appOptions;
914
+ }
915
+
849
916
  function validateNumberInput(value) {
850
917
  const parsedValue = Number(value);
851
918
  if (isNaN(parsedValue)) {
@@ -866,61 +933,46 @@ function validateUrlInput(url) {
866
933
  return url;
867
934
  }
868
935
 
869
- const DEFAULT_PAKE_OPTIONS = {
870
- icon: '',
871
- height: 780,
872
- width: 1200,
873
- fullscreen: false,
874
- resizable: true,
875
- transparent: false,
876
- userAgent: '',
877
- showMenu: false,
878
- showSystemTray: false,
879
- multiArch: false,
880
- targets: 'deb',
881
- iterCopyFile: false,
882
- systemTrayIcon: '',
883
- debug: false,
884
- };
885
-
886
936
  program
887
- .version(packageJson.version)
888
- .description('A CLI that can turn any webpage into a desktop app with Rust.')
937
+ .description(chalk.green('Pake can turn any webpage into a desktop app with Rust.'))
938
+ .usage('[url] [options]')
889
939
  .showHelpAfterError();
890
940
  program
891
941
  .argument('[url]', 'The web URL you want to package', validateUrlInput)
892
942
  .option('--name <string>', 'Application name')
893
943
  .option('--icon <string>', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
894
- .option('--height <number>', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
895
944
  .option('--width <number>', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
896
- .option('--no-resizable', 'Whether the window can be resizable', DEFAULT_PAKE_OPTIONS.resizable)
897
- .option('--fullscreen', 'Start the packaged app in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
898
- .option('--transparent', 'Transparent title bar', DEFAULT_PAKE_OPTIONS.transparent)
945
+ .option('--height <number>', 'Window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height)
946
+ .option('--transparent', 'Only for Mac, hide title bar', DEFAULT_PAKE_OPTIONS.transparent)
947
+ .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
899
948
  .option('--user-agent <string>', 'Custom user agent', DEFAULT_PAKE_OPTIONS.userAgent)
900
949
  .option('--show-menu', 'Show menu in app', DEFAULT_PAKE_OPTIONS.showMenu)
901
950
  .option('--show-system-tray', 'Show system tray in app', DEFAULT_PAKE_OPTIONS.showSystemTray)
902
951
  .option('--system-tray-icon <string>', 'Custom system tray icon', DEFAULT_PAKE_OPTIONS.systemTrayIcon)
903
- .option('--iter-copy-file', 'Copy files to app when URL is a local file', DEFAULT_PAKE_OPTIONS.iterCopyFile)
904
- .option('--multi-arch', 'Available for Mac only, supports both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
905
- .option('--targets <string>', 'Only for Linux, option "deb", "appimage" or "all"', DEFAULT_PAKE_OPTIONS.targets)
952
+ .option('--iter-copy-file', 'Copy files when URL is a local file', DEFAULT_PAKE_OPTIONS.iterCopyFile)
953
+ .option('--multi-arch', 'Only for Mac, supports both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
954
+ .option('--targets <string>', 'Only for Linux, option "deb" or "appimage"', DEFAULT_PAKE_OPTIONS.targets)
906
955
  .option('--debug', 'Debug mode', DEFAULT_PAKE_OPTIONS.debug)
956
+ .version(packageJson.version, '-v, --version', 'Output the current version')
907
957
  .action(async (url, options) => {
908
- //Check for update prompt
909
958
  await checkUpdateTips();
910
- // If no URL is provided, display help information
911
959
  if (!url) {
912
- program.help();
960
+ program.outputHelp(str => {
961
+ return str
962
+ .split('\n')
963
+ .filter(line => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line))
964
+ .join('\n');
965
+ });
966
+ process.exit(0);
913
967
  }
914
968
  log.setDefaultLevel('info');
915
969
  if (options.debug) {
916
970
  log.setLevel('debug');
917
971
  }
918
- const spinner = ora('Preparing...').start();
919
- const builder = BuilderProvider.create();
920
- await builder.prepare();
921
972
  const appOptions = await handleOptions(options, url);
922
- spinner.succeed();
923
973
  log.debug('PakeAppOptions', appOptions);
924
- await builder.build(url, appOptions);
974
+ const builder = BuilderProvider.create(appOptions);
975
+ await builder.prepare();
976
+ await builder.build(url);
925
977
  });
926
978
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pake-cli",
3
- "version": "2.1.1",
3
+ "version": "2.1.7",
4
4
  "description": "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with Rust. ๐Ÿคฑ๐Ÿป ๅพˆ็ฎ€ๅ•็š„็”จ Rust ๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆๅพˆๅฐ็š„ๆกŒ้ข Appใ€‚",
5
5
  "engines": {
6
6
  "node": ">=16.0.0"
@@ -136,8 +136,7 @@ document.addEventListener('DOMContentLoaded', () => {
136
136
  document.body.appendChild(m);
137
137
  setTimeout(function () {
138
138
  const d = 0.5;
139
- m.style.transition =
140
- 'transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
139
+ m.style.transition = 'transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
141
140
  m.style.opacity = '0';
142
141
  setTimeout(function () {
143
142
  document.body.removeChild(m);
@@ -151,14 +150,14 @@ document.addEventListener('DOMContentLoaded', () => {
151
150
  if (window.location.hostname === 'chat.openai.com') {
152
151
  const originFetch = fetch;
153
152
  window.fetch = (url, options) => {
154
- return originFetch(url, options).then(async (response) => {
153
+ return originFetch(url, options).then(async response => {
155
154
  if (url.indexOf('/backend-api/models') === -1) {
156
155
  return response;
157
156
  }
158
157
  const responseClone = response.clone();
159
158
  let res = await responseClone.json();
160
- res.models = res.models.map((m) => {
161
- m.tags = m.tags.filter((t) => {
159
+ res.models = res.models.map(m => {
160
+ m.tags = m.tags.filter(t => {
162
161
  return t !== 'mobile';
163
162
  });
164
163
  if (m.slug === 'gpt-4-mobile') {
@@ -82,14 +82,14 @@ async function invoke(cmd, args) {
82
82
 
83
83
  // Judgment of file download.
84
84
  function isDownloadLink(url) {
85
- const fileExtensions = [
86
- '3gp', '7z', 'ai', 'apk', 'avi', 'bmp', 'csv', 'dmg', 'doc', 'docx', 'fla', 'flv', 'gif', 'gz', 'gzip',
87
- 'ico', 'iso', 'indd', 'jar', 'jpeg', 'jpg', 'm3u8', 'mov', 'mp3', 'mp4', 'mpa', 'mpg',
88
- 'mpeg', 'msi', 'odt', 'ogg', 'ogv', 'pdf', 'png', 'ppt', 'pptx', 'psd', 'rar', 'raw', 'rss', 'svg',
89
- 'swf', 'tar', 'tif', 'tiff', 'ts', 'txt', 'wav', 'webm', 'webp', 'wma', 'wmv', 'xls', 'xlsx', 'xml', 'zip'
90
- ];
91
- const downloadLinkPattern = new RegExp(`\\.(${fileExtensions.join('|')})$`, 'i');
92
- return downloadLinkPattern.test(url);
85
+ const fileExtensions = [
86
+ '3gp', '7z', 'ai', 'apk', 'avi', 'bmp', 'csv', 'dmg', 'doc', 'docx', 'fla', 'flv', 'gif', 'gz', 'gzip',
87
+ 'ico', 'iso', 'indd', 'jar', 'jpeg', 'jpg', 'm3u8', 'mov', 'mp3', 'mp4', 'mpa', 'mpg',
88
+ 'mpeg', 'msi', 'odt', 'ogg', 'ogv', 'pdf', 'png', 'ppt', 'pptx', 'psd', 'rar', 'raw', 'rss', 'svg',
89
+ 'swf', 'tar', 'tif', 'tiff', 'ts', 'txt', 'wav', 'webm', 'webp', 'wma', 'wmv', 'xls', 'xlsx', 'xml', 'zip',
90
+ ];
91
+ const downloadLinkPattern = new RegExp(`\\.(${fileExtensions.join('|')})$`, 'i');
92
+ return downloadLinkPattern.test(url);
93
93
  }
94
94
 
95
95
  // No need to go to the download link.
@@ -185,7 +185,7 @@ document.addEventListener('DOMContentLoaded', () => {
185
185
 
186
186
  // Rewrite the window.open function.
187
187
  const originalWindowOpen = window.open;
188
- window.open = function (url, name, specs) {
188
+ window.open = function(url, name, specs) {
189
189
  // Apple login and google login
190
190
  if (name === 'AppleAuthentication') {
191
191
  //do nothing
@@ -278,7 +278,7 @@ function downloadFromBlobUrl(blobUrl, filename) {
278
278
  function detectDownloadByCreateAnchor() {
279
279
  const createEle = document.createElement;
280
280
  document.createElement = (el) => {
281
- if (el !== "a") return createEle.call(document, el);
281
+ if (el !== 'a') return createEle.call(document, el);
282
282
  const anchorEle = createEle.call(document, el);
283
283
 
284
284
  // use addEventListener to avoid overriding the original click event.
@@ -290,5 +290,5 @@ function detectDownloadByCreateAnchor() {
290
290
  });
291
291
 
292
292
  return anchorEle;
293
- }
293
+ };
294
294
  }
@@ -1,4 +1,4 @@
1
- window.addEventListener('DOMContentLoaded', (_event) => {
1
+ window.addEventListener('DOMContentLoaded', _event => {
2
2
  const css = `
3
3
  #page #footer-wrapper,
4
4
  .drawing-board .toolbar .toolbar-action,
@@ -9,9 +9,7 @@
9
9
  "dangerousRemoteDomainIpcAccess": [
10
10
  {
11
11
  "domain": "weread.qq.com",
12
- "windows": [
13
- "pake"
14
- ],
12
+ "windows": ["pake"],
15
13
  "enableTauriAPI": true
16
14
  }
17
15
  ]
@@ -27,9 +25,7 @@
27
25
  "all": true,
28
26
  "fs": {
29
27
  "all": true,
30
- "scope": [
31
- "$DOWNLOAD/*"
32
- ]
28
+ "scope": ["$DOWNLOAD/*"]
33
29
  }
34
30
  }
35
31
  },
@@ -8,7 +8,9 @@
8
8
  "copyright": "",
9
9
  "deb": {
10
10
  "depends": ["curl", "wget"],
11
- "files": {"/usr/share/applications/com-tw93-weread.desktop": "assets/com-tw93-weread.desktop"}
11
+ "files": {
12
+ "/usr/share/applications/com-tw93-weread.desktop": "assets/com-tw93-weread.desktop"
13
+ }
12
14
  },
13
15
  "externalBin": [],
14
16
  "longDescription": "",