pake-cli 3.1.0 → 3.2.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +82 -25
  2. package/dist/cli.js +160 -88
  3. package/dist/dev.js +39 -20
  4. package/dist/dev.js.map +1 -1
  5. package/package.json +15 -17
  6. package/src-tauri/.cargo/config.toml +5 -0
  7. package/src-tauri/Cargo.lock +1392 -1154
  8. package/src-tauri/Cargo.toml +12 -12
  9. package/src-tauri/assets/{com-tw93-weread.desktop → com-tw93-weekly.desktop} +4 -4
  10. package/src-tauri/gen/schemas/acl-manifests.json +1 -1
  11. package/src-tauri/gen/schemas/desktop-schema.json +946 -411
  12. package/src-tauri/gen/schemas/macOS-schema.json +946 -411
  13. package/src-tauri/icons/deepseek.icns +0 -0
  14. package/src-tauri/icons/grok.icns +0 -0
  15. package/src-tauri/icons/weekly.icns +0 -0
  16. package/src-tauri/pake.json +3 -2
  17. package/src-tauri/png/chatgpt_256.ico +0 -0
  18. package/src-tauri/png/chatgpt_32.ico +0 -0
  19. package/src-tauri/png/chatgpt_512.png +0 -0
  20. package/src-tauri/png/deepseek_256.ico +0 -0
  21. package/src-tauri/png/deepseek_32.ico +0 -0
  22. package/src-tauri/png/deepseek_512.png +0 -0
  23. package/src-tauri/png/excalidraw_256.ico +0 -0
  24. package/src-tauri/png/excalidraw_32.ico +0 -0
  25. package/src-tauri/png/excalidraw_512.png +0 -0
  26. package/src-tauri/png/flomo_256.ico +0 -0
  27. package/src-tauri/png/flomo_32.ico +0 -0
  28. package/src-tauri/png/flomo_512.png +0 -0
  29. package/src-tauri/png/gemini_256.ico +0 -0
  30. package/src-tauri/png/gemini_32.ico +0 -0
  31. package/src-tauri/png/gemini_512.png +0 -0
  32. package/src-tauri/png/grok_256.ico +0 -0
  33. package/src-tauri/png/grok_32.ico +0 -0
  34. package/src-tauri/png/grok_512.png +0 -0
  35. package/src-tauri/png/icon_256.ico +0 -0
  36. package/src-tauri/png/icon_32.ico +0 -0
  37. package/src-tauri/png/icon_512.png +0 -0
  38. package/src-tauri/png/lizhi_256.ico +0 -0
  39. package/src-tauri/png/lizhi_32.ico +0 -0
  40. package/src-tauri/png/lizhi_512.png +0 -0
  41. package/src-tauri/png/programmusic_256.ico +0 -0
  42. package/src-tauri/png/programmusic_32.ico +0 -0
  43. package/src-tauri/png/programmusic_512.png +0 -0
  44. package/src-tauri/png/qwerty_256.ico +0 -0
  45. package/src-tauri/png/qwerty_32.ico +0 -0
  46. package/src-tauri/png/qwerty_512.png +0 -0
  47. package/src-tauri/png/twitter_256.ico +0 -0
  48. package/src-tauri/png/twitter_32.ico +0 -0
  49. package/src-tauri/png/twitter_512.png +0 -0
  50. package/src-tauri/png/wechat_256.ico +0 -0
  51. package/src-tauri/png/wechat_32.ico +0 -0
  52. package/src-tauri/png/wechat_512.png +0 -0
  53. package/src-tauri/png/weekly_256.ico +0 -0
  54. package/src-tauri/png/weekly_32.ico +0 -0
  55. package/src-tauri/png/weekly_512.png +0 -0
  56. package/src-tauri/png/weread_256.ico +0 -0
  57. package/src-tauri/png/weread_32.ico +0 -0
  58. package/src-tauri/png/weread_512.png +0 -0
  59. package/src-tauri/png/xiaohongshu_256.ico +0 -0
  60. package/src-tauri/png/xiaohongshu_32.ico +0 -0
  61. package/src-tauri/png/xiaohongshu_512.png +0 -0
  62. package/src-tauri/png/youtube_256.ico +0 -0
  63. package/src-tauri/png/youtube_32.ico +0 -0
  64. package/src-tauri/png/youtube_512.png +0 -0
  65. package/src-tauri/png/youtubemusic_256.ico +0 -0
  66. package/src-tauri/png/youtubemusic_32.ico +0 -0
  67. package/src-tauri/png/youtubemusic_512.png +0 -0
  68. package/src-tauri/src/app/config.rs +1 -0
  69. package/src-tauri/src/app/setup.rs +3 -1
  70. package/src-tauri/src/app/window.rs +25 -3
  71. package/src-tauri/src/inject/component.js +6 -5
  72. package/src-tauri/src/inject/event.js +143 -62
  73. package/src-tauri/src/inject/style.js +29 -8
  74. package/src-tauri/src/lib.rs +22 -13
  75. package/src-tauri/src/util.rs +4 -4
  76. package/src-tauri/tauri.conf.json +3 -3
  77. package/src-tauri/tauri.linux.conf.json +4 -2
  78. package/src-tauri/tauri.macos.conf.json +1 -1
  79. package/src-tauri/tauri.windows.conf.json +2 -2
  80. package/src-tauri/.pake/pake.json +0 -30
  81. package/src-tauri/.pake/tauri.conf.json +0 -24
  82. package/src-tauri/.pake/tauri.macos.conf.json +0 -15
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import log from 'loglevel';
4
4
  import path from 'path';
5
5
  import fsExtra from 'fs-extra';
6
6
  import prompts from 'prompts';
7
- import shelljs from 'shelljs';
7
+ import { execa, execaSync } from 'execa';
8
8
  import crypto from 'crypto';
9
9
  import ora from 'ora';
10
10
  import { fileURLToPath } from 'url';
@@ -17,10 +17,9 @@ import axios from 'axios';
17
17
  import { dir } from 'tmp-promise';
18
18
  import { fileTypeFromBuffer } from 'file-type';
19
19
  import * as psl from 'psl';
20
- import isUrl from 'is-url';
21
20
 
22
21
  var name = "pake-cli";
23
- var version$1 = "3.1.0";
22
+ var version$1 = "3.2.0-beta";
24
23
  var description = "🤱🏻 Turn any webpage into a desktop app with Rust. 🤱🏻 利用 Rust 轻松构建轻量级多端桌面应用。";
25
24
  var engines = {
26
25
  node: ">=16.0.0"
@@ -61,49 +60,47 @@ var scripts = {
61
60
  cli: "rollup -c rollup.config.js --watch",
62
61
  "cli:dev": "cross-env NODE_ENV=development rollup -c rollup.config.js -w",
63
62
  "cli:build": "cross-env NODE_ENV=production rollup -c rollup.config.js",
63
+ format: "npx prettier --write . --ignore-unknown && cd src-tauri && cargo fmt --verbose",
64
64
  prepublishOnly: "npm run cli:build"
65
65
  };
66
66
  var type = "module";
67
67
  var exports = "./dist/pake.js";
68
68
  var license = "MIT";
69
69
  var dependencies = {
70
- "@tauri-apps/api": "^1.6.0",
71
- "@tauri-apps/cli": "^2.1.0",
72
- axios: "^1.7.9",
73
- chalk: "^5.4.1",
70
+ "@tauri-apps/api": "^2.7.0",
71
+ "@tauri-apps/cli": "^2.7.1",
72
+ axios: "^1.11.0",
73
+ chalk: "^5.5.0",
74
74
  commander: "^11.1.0",
75
+ execa: "^9.6.0",
75
76
  "file-type": "^18.7.0",
76
- "fs-extra": "^11.2.0",
77
- "is-url": "^1.2.4",
77
+ "fs-extra": "^11.3.1",
78
78
  loglevel: "^1.9.2",
79
- ora: "^7.0.1",
79
+ ora: "^8.2.0",
80
80
  prompts: "^2.4.2",
81
81
  psl: "^1.15.0",
82
- shelljs: "^0.8.5",
83
82
  "tmp-promise": "^3.0.3",
84
83
  "update-notifier": "^7.3.1"
85
84
  };
86
85
  var devDependencies = {
87
86
  "@rollup/plugin-alias": "^5.1.1",
88
- "@rollup/plugin-commonjs": "^25.0.8",
87
+ "@rollup/plugin-commonjs": "^28.0.6",
89
88
  "@rollup/plugin-json": "^6.1.0",
90
- "@rollup/plugin-replace": "^5.0.7",
89
+ "@rollup/plugin-replace": "^6.0.2",
91
90
  "@rollup/plugin-terser": "^0.4.4",
92
91
  "@types/fs-extra": "^11.0.4",
93
- "@types/is-url": "^1.2.32",
94
- "@types/node": "^20.17.10",
92
+ "@types/node": "^20.19.10",
95
93
  "@types/page-icon": "^0.3.6",
96
94
  "@types/prompts": "^2.4.9",
97
- "@types/psl": "^1.1.3",
98
- "@types/shelljs": "^0.8.15",
95
+ "@types/psl": "^1.11.0",
99
96
  "@types/tmp": "^0.2.6",
100
97
  "@types/update-notifier": "^6.0.8",
101
98
  "app-root-path": "^3.1.0",
102
99
  "cross-env": "^7.0.3",
103
- rollup: "^4.29.1",
100
+ rollup: "^4.46.2",
104
101
  "rollup-plugin-typescript2": "^0.36.0",
105
102
  tslib: "^2.8.1",
106
- typescript: "^5.7.2"
103
+ typescript: "^5.9.2"
107
104
  };
108
105
  var packageJson = {
109
106
  name: name,
@@ -125,7 +122,7 @@ var packageJson = {
125
122
 
126
123
  var windows = [
127
124
  {
128
- url: "https://weread.qq.com",
125
+ url: "https://weekly.tw93.fun/",
129
126
  url_type: "web",
130
127
  hide_title_bar: true,
131
128
  fullscreen: false,
@@ -135,7 +132,8 @@ var windows = [
135
132
  always_on_top: false,
136
133
  dark_mode: false,
137
134
  activation_shortcut: "",
138
- disabled_web_shortcuts: false
135
+ disabled_web_shortcuts: false,
136
+ hide_on_close: true
139
137
  }
140
138
  ];
141
139
  var user_agent = {
@@ -161,13 +159,13 @@ var pakeConf = {
161
159
  proxy_url: proxy_url
162
160
  };
163
161
 
164
- var productName$1 = "WeRead";
165
- var identifier = "com.pake.weread";
162
+ var productName$1 = "Weekly";
163
+ var identifier = "com.pake.weekly";
166
164
  var version = "1.0.0";
167
165
  var app = {
168
166
  withGlobalTauri: true,
169
167
  trayIcon: {
170
- iconPath: "png/weread_512.png",
168
+ iconPath: "png/weekly_512.png",
171
169
  iconAsTemplate: false,
172
170
  id: "pake-tray"
173
171
  }
@@ -185,12 +183,12 @@ var CommonConf = {
185
183
 
186
184
  var bundle$2 = {
187
185
  icon: [
188
- "png/weread_256.ico",
189
- "png/weread_32.ico"
186
+ "png/weekly_256.ico",
187
+ "png/weekly_32.ico"
190
188
  ],
191
189
  active: true,
192
190
  resources: [
193
- "png/weread_32.ico"
191
+ "png/weekly_32.ico"
194
192
  ],
195
193
  targets: [
196
194
  "msi"
@@ -211,7 +209,7 @@ var WinConf = {
211
209
 
212
210
  var bundle$1 = {
213
211
  icon: [
214
- "icons/weread.icns"
212
+ "icons/weekly.icns"
215
213
  ],
216
214
  active: true,
217
215
  macOS: {
@@ -227,7 +225,7 @@ var MacConf = {
227
225
  var productName = "we-read";
228
226
  var bundle = {
229
227
  icon: [
230
- "png/weread_512.png"
228
+ "png/weekly.png"
231
229
  ],
232
230
  active: true,
233
231
  linux: {
@@ -237,7 +235,7 @@ var bundle = {
237
235
  "wget"
238
236
  ],
239
237
  files: {
240
- "/usr/share/applications/com-pake-weread.desktop": "assets/com-pake-weread.desktop"
238
+ "/usr/share/applications/com-pake-weekly.desktop": "assets/com-pake-weekly.desktop"
241
239
  }
242
240
  }
243
241
  },
@@ -274,7 +272,11 @@ let tauriConfig = {
274
272
 
275
273
  // Generates an identifier based on the given URL.
276
274
  function getIdentifier(url) {
277
- const postFixHash = crypto.createHash('md5').update(url).digest('hex').substring(0, 6);
275
+ const postFixHash = crypto
276
+ .createHash('md5')
277
+ .update(url)
278
+ .digest('hex')
279
+ .substring(0, 6);
278
280
  return `com.pake.${postFixHash}`;
279
281
  }
280
282
  async function promptText(message, initial) {
@@ -312,34 +314,34 @@ const currentModulePath = fileURLToPath(import.meta.url);
312
314
  const npmDirectory = path.join(path.dirname(currentModulePath), '..');
313
315
  const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri');
314
316
 
315
- function shellExec(command) {
316
- return new Promise((resolve, reject) => {
317
- shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, code => {
318
- if (code === 0) {
319
- resolve(0);
320
- }
321
- else {
322
- reject(new Error(`Error occurred while executing command "${command}". Exit code: ${code}`));
323
- }
317
+ async function shellExec(command) {
318
+ try {
319
+ const { exitCode } = await execa(command, {
320
+ cwd: npmDirectory,
321
+ stdio: 'inherit',
324
322
  });
325
- });
323
+ return exitCode;
324
+ }
325
+ catch (error) {
326
+ throw new Error(`Error occurred while executing command "${command}". Exit code: ${error.exitCode}`);
327
+ }
326
328
  }
327
329
 
328
330
  const logger = {
329
331
  info(...msg) {
330
- log.info(...msg.map(m => chalk.white(m)));
332
+ log.info(...msg.map((m) => chalk.white(m)));
331
333
  },
332
334
  debug(...msg) {
333
335
  log.debug(...msg);
334
336
  },
335
337
  error(...msg) {
336
- log.error(...msg.map(m => chalk.red(m)));
338
+ log.error(...msg.map((m) => chalk.red(m)));
337
339
  },
338
340
  warn(...msg) {
339
- log.info(...msg.map(m => chalk.yellow(m)));
341
+ log.info(...msg.map((m) => chalk.yellow(m)));
340
342
  },
341
343
  success(...msg) {
342
- log.info(...msg.map(m => chalk.green(m)));
344
+ log.info(...msg.map((m) => chalk.green(m)));
343
345
  },
344
346
  };
345
347
 
@@ -350,12 +352,12 @@ const ping = async (host) => {
350
352
  const start = new Date();
351
353
  // Prevent timeouts from affecting user experience.
352
354
  const requestPromise = new Promise((resolve, reject) => {
353
- const req = http.get(`http://${ip.address}`, res => {
355
+ const req = http.get(`http://${ip.address}`, (res) => {
354
356
  const delay = new Date().getTime() - start.getTime();
355
357
  res.resume();
356
358
  resolve(delay);
357
359
  });
358
- req.on('error', err => {
360
+ req.on('error', (err) => {
359
361
  reject(err);
360
362
  });
361
363
  });
@@ -407,25 +409,33 @@ async function installRust() {
407
409
  }
408
410
  }
409
411
  function checkRustInstalled() {
410
- return shelljs.exec('rustc --version', { silent: true }).code === 0;
412
+ try {
413
+ execaSync('rustc', ['--version']);
414
+ return true;
415
+ }
416
+ catch {
417
+ return false;
418
+ }
411
419
  }
412
420
 
413
421
  async function combineFiles(files, output) {
414
- const contents = files.map(file => {
422
+ const contents = files.map((file) => {
415
423
  const fileContent = fs.readFileSync(file);
416
424
  if (file.endsWith('.css')) {
417
425
  return ("window.addEventListener('DOMContentLoaded', (_event) => { const css = `" +
418
426
  fileContent +
419
427
  "`; const style = document.createElement('style'); style.innerHTML = css; document.head.appendChild(style); });");
420
428
  }
421
- return "window.addEventListener('DOMContentLoaded', (_event) => { " + fileContent + ' });';
429
+ return ("window.addEventListener('DOMContentLoaded', (_event) => { " +
430
+ fileContent +
431
+ ' });');
422
432
  });
423
433
  fs.writeFileSync(output, contents.join('\n'));
424
434
  return files;
425
435
  }
426
436
 
427
437
  async function mergeConfig(url, options, tauriConf) {
428
- const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, } = options;
438
+ const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, } = options;
429
439
  const { platform } = process;
430
440
  // Set Windows parameters.
431
441
  const tauriConfWindowOptions = {
@@ -438,6 +448,7 @@ async function mergeConfig(url, options, tauriConf) {
438
448
  always_on_top: alwaysOnTop,
439
449
  dark_mode: darkMode,
440
450
  disabled_web_shortcuts: disabledWebShortcuts,
451
+ hide_on_close: hideOnClose,
441
452
  };
442
453
  Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions });
443
454
  tauriConf.productName = name;
@@ -465,7 +476,7 @@ async function mergeConfig(url, options, tauriConf) {
465
476
  // ignore it, because about_pake.html have be erased.
466
477
  // const filesToCopyBack = ['cli.js', 'about_pake.html'];
467
478
  const filesToCopyBack = ['cli.js'];
468
- await Promise.all(filesToCopyBack.map(file => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
479
+ await Promise.all(filesToCopyBack.map((file) => fsExtra.copy(path.join(distBakDir, file), path.join(distDir, file))));
469
480
  }
470
481
  tauriConf.pake.windows[0].url = fileName;
471
482
  tauriConf.pake.windows[0].url_type = 'local';
@@ -486,9 +497,9 @@ async function mergeConfig(url, options, tauriConf) {
486
497
  // Processing targets are currently only open to Linux.
487
498
  if (platform === 'linux') {
488
499
  delete tauriConf.bundle.linux.deb.files;
489
- const validTargets = ['all', 'deb', 'appimage', 'rpm'];
500
+ const validTargets = ['deb', 'appimage', 'rpm'];
490
501
  if (validTargets.includes(options.targets)) {
491
- tauriConf.bundle.targets = options.targets === 'all' ? ['deb', 'appimage', 'rpm'] : [options.targets];
502
+ tauriConf.bundle.targets = [options.targets];
492
503
  }
493
504
  else {
494
505
  logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
@@ -569,11 +580,11 @@ async function mergeConfig(url, options, tauriConf) {
569
580
  const injectFilePath = path.join(npmDirectory, `src-tauri/src/inject/custom.js`);
570
581
  // inject js or css files
571
582
  if (inject?.length > 0) {
572
- if (!inject.every(item => item.endsWith('.css') || item.endsWith('.js'))) {
583
+ if (!inject.every((item) => item.endsWith('.css') || item.endsWith('.js'))) {
573
584
  logger.error('The injected file must be in either CSS or JS format.');
574
585
  return;
575
586
  }
576
- const files = inject.map(filepath => (path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath)));
587
+ const files = inject.map((filepath) => path.isAbsolute(filepath) ? filepath : path.join(process.cwd(), filepath));
577
588
  tauriConf.pake.inject = files;
578
589
  await combineFiles(files, injectFilePath);
579
590
  }
@@ -701,7 +712,9 @@ class MacBuilder extends BaseBuilder {
701
712
  return `${name}_${tauriConfig.version}_${arch}`;
702
713
  }
703
714
  getBuildCommand() {
704
- return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand();
715
+ return this.options.multiArch
716
+ ? 'npm run build:mac'
717
+ : super.getBuildCommand();
705
718
  }
706
719
  getBasePath() {
707
720
  return this.options.multiArch
@@ -728,15 +741,23 @@ class LinuxBuilder extends BaseBuilder {
728
741
  super(options);
729
742
  }
730
743
  getFileName() {
731
- const { name } = this.options;
732
- const arch = process.arch === 'x64' ? 'amd64' : process.arch;
733
- return `${name}_${tauriConfig.version}_${arch}`;
744
+ const { name, targets } = this.options;
745
+ const version = tauriConfig.version;
746
+ let arch = process.arch === 'x64' ? 'amd64' : process.arch;
747
+ if (arch === 'arm64' && (targets === 'rpm' || targets === 'appimage')) {
748
+ arch = 'aarch64';
749
+ }
750
+ // The RPM format uses different separators and version number formats
751
+ if (targets === 'rpm') {
752
+ return `${name}-${version}-1.${arch}`;
753
+ }
754
+ return `${name}_${version}_${arch}`;
734
755
  }
735
756
  // Customize it, considering that there are all targets.
736
757
  async build(url) {
737
- const targetTypes = ['deb', 'appimage'];
758
+ const targetTypes = ['deb', 'appimage', 'rpm'];
738
759
  for (const target of targetTypes) {
739
- if (this.options.targets === target || this.options.targets === 'all') {
760
+ if (this.options.targets === target) {
740
761
  await this.buildAndCopy(url, target);
741
762
  }
742
763
  }
@@ -770,7 +791,6 @@ const DEFAULT_PAKE_OPTIONS = {
770
791
  height: 780,
771
792
  width: 1200,
772
793
  fullscreen: false,
773
- resizable: true,
774
794
  hideTitleBar: false,
775
795
  alwaysOnTop: false,
776
796
  appVersion: '1.0.0',
@@ -783,14 +803,17 @@ const DEFAULT_PAKE_OPTIONS = {
783
803
  targets: 'deb',
784
804
  useLocalFile: false,
785
805
  systemTrayIcon: '',
786
- proxyUrl: "",
806
+ proxyUrl: '',
787
807
  debug: false,
788
808
  inject: [],
789
809
  installerLanguage: 'en-US',
810
+ hideOnClose: true,
790
811
  };
791
812
 
792
813
  async function checkUpdateTips() {
793
- updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({ isGlobal: true });
814
+ updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 }).notify({
815
+ isGlobal: true,
816
+ });
794
817
  }
795
818
 
796
819
  async function handleIcon(options) {
@@ -815,7 +838,9 @@ async function handleIcon(options) {
815
838
  async function downloadIcon(iconUrl) {
816
839
  const spinner = getSpinner('Downloading icon...');
817
840
  try {
818
- const iconResponse = await axios.get(iconUrl, { responseType: 'arraybuffer' });
841
+ const iconResponse = await axios.get(iconUrl, {
842
+ responseType: 'arraybuffer',
843
+ });
819
844
  const iconData = await iconResponse.data;
820
845
  if (!iconData) {
821
846
  return null;
@@ -878,11 +903,12 @@ function appendProtocol(inputUrl) {
878
903
  // Normalizes the URL by ensuring it has a protocol and is valid.
879
904
  function normalizeUrl(urlToNormalize) {
880
905
  const urlWithProtocol = appendProtocol(urlToNormalize);
881
- if (isUrl(urlWithProtocol)) {
906
+ try {
907
+ new URL(urlWithProtocol);
882
908
  return urlWithProtocol;
883
909
  }
884
- else {
885
- throw new Error(`Your url "${urlWithProtocol}" is invalid`);
910
+ catch (err) {
911
+ throw new Error(`Your url "${urlWithProtocol}" is invalid: ${err.message}`);
886
912
  }
887
913
  }
888
914
 
@@ -892,8 +918,8 @@ function resolveAppName(name, platform) {
892
918
  }
893
919
  function isValidName(name, platform) {
894
920
  const platformRegexMapping = {
895
- linux: /^[a-z0-9]+(-[a-z0-9]+)*$/,
896
- default: /^[a-zA-Z0-9]+([-a-zA-Z0-9])*$/,
921
+ linux: /^[a-z0-9][a-z0-9-]*$/,
922
+ default: /^[a-zA-Z0-9][a-zA-Z0-9- ]*$/,
897
923
  };
898
924
  const reg = platformRegexMapping[platform] || platformRegexMapping.default;
899
925
  return !!name && reg.test(name);
@@ -909,9 +935,14 @@ async function handleOptions(options, url) {
909
935
  const namePrompt = await promptText(promptMessage, defaultName);
910
936
  name = namePrompt || defaultName;
911
937
  }
938
+ // Handle platform-specific name formatting
939
+ if (name && platform === 'linux') {
940
+ // Convert to lowercase and replace spaces with dashes for Linux
941
+ name = name.toLowerCase().replace(/\s+/g, '-');
942
+ }
912
943
  if (!isValidName(name, platform)) {
913
- 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.`;
914
- const DEFAULT_NAME_ERROR = `✕ Name should only include letters and numbers, and dashes (dashes must not at the beginning), and must contain at least one letter. Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead, we-read.`;
944
+ const LINUX_NAME_ERROR = `✕ Name should only include lowercase letters, numbers, and dashes (not leading dashes). Examples: com-123-xxx, 123pan, pan123, weread, we-read, 123.`;
945
+ const DEFAULT_NAME_ERROR = `✕ Name should only include letters, numbers, dashes, and spaces (not leading dashes and spaces). Examples: 123pan, 123Pan, Pan123, weread, WeRead, WERead, we-read, We Read, 123.`;
915
946
  const errorMsg = platform === 'linux' ? LINUX_NAME_ERROR : DEFAULT_NAME_ERROR;
916
947
  logger.error(errorMsg);
917
948
  if (isActions) {
@@ -958,9 +989,15 @@ ${green('| |_) / _` | |/ / _ \\')}
958
989
  ${green('| __/ (_| | < __/')} ${yellow('https://github.com/tw93/pake')}
959
990
  ${green('|_| \\__,_|_|\\_\\___| can turn any webpage into a desktop app with Rust.')}
960
991
  `;
961
- program.addHelpText('beforeAll', logo).usage(`[url] [options]`).showHelpAfterError();
992
+ program
993
+ .addHelpText('beforeAll', logo)
994
+ .usage(`[url] [options]`)
995
+ .showHelpAfterError();
962
996
  program
963
997
  .argument('[url]', 'The web URL you want to package', validateUrlInput)
998
+ // Refer to https://github.com/tj/commander.js#custom-option-processing, turn string array into a string connected with custom connectors.
999
+ // If the platform is Linux, use `-` as the connector, and convert all characters to lowercase.
1000
+ // For example, Google Translate will become google-translate.
964
1001
  .option('--name <string>', 'Application name')
965
1002
  .option('--icon <string>', 'Application icon', DEFAULT_PAKE_OPTIONS.icon)
966
1003
  .option('--width <number>', 'Window width', validateNumberInput, DEFAULT_PAKE_OPTIONS.width)
@@ -969,27 +1006,62 @@ program
969
1006
  .option('--fullscreen', 'Start in full screen', DEFAULT_PAKE_OPTIONS.fullscreen)
970
1007
  .option('--hide-title-bar', 'For Mac, hide title bar', DEFAULT_PAKE_OPTIONS.hideTitleBar)
971
1008
  .option('--multi-arch', 'For Mac, both Intel and M1', DEFAULT_PAKE_OPTIONS.multiArch)
972
- .option('--inject <url>', 'Injection of .js or .css files', DEFAULT_PAKE_OPTIONS.inject)
1009
+ .option('--inject <./style.css,./script.js,...>', 'Injection of .js or .css files', (val, previous) => {
1010
+ if (!val)
1011
+ return DEFAULT_PAKE_OPTIONS.inject;
1012
+ // Split by comma and trim whitespace, filter out empty strings
1013
+ const files = val
1014
+ .split(',')
1015
+ .map((item) => item.trim())
1016
+ .filter((item) => item.length > 0);
1017
+ // If previous values exist (from multiple --inject options), merge them
1018
+ return previous ? [...previous, ...files] : files;
1019
+ }, DEFAULT_PAKE_OPTIONS.inject)
973
1020
  .option('--debug', 'Debug build and more output', DEFAULT_PAKE_OPTIONS.debug)
974
- .addOption(new Option('--proxy-url <url>', 'Proxy URL for all network requests').default(DEFAULT_PAKE_OPTIONS.proxyUrl).hideHelp())
975
- .addOption(new Option('--user-agent <string>', 'Custom user agent').default(DEFAULT_PAKE_OPTIONS.userAgent).hideHelp())
976
- .addOption(new Option('--targets <string>', 'For Linux, option "deb" or "appimage"').default(DEFAULT_PAKE_OPTIONS.targets).hideHelp())
977
- .addOption(new Option('--app-version <string>', 'App version, the same as package.json version').default(DEFAULT_PAKE_OPTIONS.appVersion).hideHelp())
978
- .addOption(new Option('--always-on-top', 'Always on the top level').default(DEFAULT_PAKE_OPTIONS.alwaysOnTop).hideHelp())
979
- .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode').default(DEFAULT_PAKE_OPTIONS.darkMode).hideHelp())
980
- .addOption(new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts').default(DEFAULT_PAKE_OPTIONS.disabledWebShortcuts).hideHelp())
981
- .addOption(new Option('--activation-shortcut <string>', 'Shortcut key to active App').default(DEFAULT_PAKE_OPTIONS.activationShortcut).hideHelp())
982
- .addOption(new Option('--show-system-tray', 'Show system tray in app').default(DEFAULT_PAKE_OPTIONS.showSystemTray).hideHelp())
983
- .addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon').default(DEFAULT_PAKE_OPTIONS.systemTrayIcon).hideHelp())
984
- .addOption(new Option('--installer-language <string>', 'Installer language').default(DEFAULT_PAKE_OPTIONS.installerLanguage).hideHelp())
1021
+ .addOption(new Option('--proxy-url <url>', 'Proxy URL for all network requests (http://, https://, socks5://)')
1022
+ .default(DEFAULT_PAKE_OPTIONS.proxyUrl)
1023
+ .hideHelp())
1024
+ .addOption(new Option('--user-agent <string>', 'Custom user agent')
1025
+ .default(DEFAULT_PAKE_OPTIONS.userAgent)
1026
+ .hideHelp())
1027
+ .addOption(new Option('--targets <string>', 'For Linux, option "deb" or "appimage"')
1028
+ .default(DEFAULT_PAKE_OPTIONS.targets)
1029
+ .hideHelp())
1030
+ .addOption(new Option('--app-version <string>', 'App version, the same as package.json version')
1031
+ .default(DEFAULT_PAKE_OPTIONS.appVersion)
1032
+ .hideHelp())
1033
+ .addOption(new Option('--always-on-top', 'Always on the top level')
1034
+ .default(DEFAULT_PAKE_OPTIONS.alwaysOnTop)
1035
+ .hideHelp())
1036
+ .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode')
1037
+ .default(DEFAULT_PAKE_OPTIONS.darkMode)
1038
+ .hideHelp())
1039
+ .addOption(new Option('--disabled-web-shortcuts', 'Disabled webPage shortcuts')
1040
+ .default(DEFAULT_PAKE_OPTIONS.disabledWebShortcuts)
1041
+ .hideHelp())
1042
+ .addOption(new Option('--activation-shortcut <string>', 'Shortcut key to active App')
1043
+ .default(DEFAULT_PAKE_OPTIONS.activationShortcut)
1044
+ .hideHelp())
1045
+ .addOption(new Option('--show-system-tray', 'Show system tray in app')
1046
+ .default(DEFAULT_PAKE_OPTIONS.showSystemTray)
1047
+ .hideHelp())
1048
+ .addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon')
1049
+ .default(DEFAULT_PAKE_OPTIONS.systemTrayIcon)
1050
+ .hideHelp())
1051
+ .addOption(new Option('--hide-on-close', 'Hide window on close instead of exiting')
1052
+ .default(DEFAULT_PAKE_OPTIONS.hideOnClose)
1053
+ .hideHelp())
1054
+ .addOption(new Option('--installer-language <string>', 'Installer language')
1055
+ .default(DEFAULT_PAKE_OPTIONS.installerLanguage)
1056
+ .hideHelp())
985
1057
  .version(packageJson.version, '-v, --version', 'Output the current version')
986
1058
  .action(async (url, options) => {
987
1059
  await checkUpdateTips();
988
1060
  if (!url) {
989
- program.outputHelp(str => {
1061
+ program.outputHelp((str) => {
990
1062
  return str
991
1063
  .split('\n')
992
- .filter(line => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line))
1064
+ .filter((line) => !/((-h,|--help)|((-v|-V),|--version))\s+.+$/.test(line))
993
1065
  .join('\n');
994
1066
  });
995
1067
  process.exit(0);
package/dist/dev.js CHANGED
@@ -11,7 +11,7 @@ import ora from 'ora';
11
11
  import { fileTypeFromBuffer } from 'file-type';
12
12
  import * as psl from 'psl';
13
13
  import 'is-url';
14
- import shelljs from 'shelljs';
14
+ import { execa, execaSync } from 'execa';
15
15
  import dns from 'dns';
16
16
  import http from 'http';
17
17
  import { promisify } from 'util';
@@ -70,7 +70,8 @@ const logger = {
70
70
  const currentModulePath = fileURLToPath(import.meta.url);
71
71
  // Resolve the parent directory of the current module
72
72
  const npmDirectory = path.join(path.dirname(currentModulePath), '..');
73
- const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri');
73
+ const tauriConfigDirectory = path.join(npmDirectory, 'src-tauri', '.pake')
74
+ ;
74
75
 
75
76
  const { platform: platform$2 } = process;
76
77
  const IS_MAC = platform$2 === 'darwin';
@@ -373,17 +374,17 @@ let tauriConfig = {
373
374
  pake: pakeConf,
374
375
  };
375
376
 
376
- function shellExec(command) {
377
- return new Promise((resolve, reject) => {
378
- shelljs.exec(command, { async: true, silent: false, cwd: npmDirectory }, code => {
379
- if (code === 0) {
380
- resolve(0);
381
- }
382
- else {
383
- reject(new Error(`Error occurred while executing command "${command}". Exit code: ${code}`));
384
- }
377
+ async function shellExec(command) {
378
+ try {
379
+ const { exitCode } = await execa(command, {
380
+ cwd: npmDirectory,
381
+ stdio: 'inherit'
385
382
  });
386
- });
383
+ return exitCode;
384
+ }
385
+ catch (error) {
386
+ throw new Error(`Error occurred while executing command "${command}". Exit code: ${error.exitCode}`);
387
+ }
387
388
  }
388
389
 
389
390
  const resolve = promisify(dns.resolve);
@@ -450,7 +451,13 @@ async function installRust() {
450
451
  }
451
452
  }
452
453
  function checkRustInstalled() {
453
- return shelljs.exec('rustc --version', { silent: true }).code === 0;
454
+ try {
455
+ execaSync('rustc', ['--version']);
456
+ return true;
457
+ }
458
+ catch {
459
+ return false;
460
+ }
454
461
  }
455
462
 
456
463
  async function combineFiles(files, output) {
@@ -529,9 +536,9 @@ async function mergeConfig(url, options, tauriConf) {
529
536
  // Processing targets are currently only open to Linux.
530
537
  if (platform === 'linux') {
531
538
  delete tauriConf.bundle.linux.deb.files;
532
- const validTargets = ['all', 'deb', 'appimage', 'rpm'];
539
+ const validTargets = ['deb', 'appimage', 'rpm'];
533
540
  if (validTargets.includes(options.targets)) {
534
- tauriConf.bundle.targets = options.targets === 'all' ? ['deb', 'appimage', 'rpm'] : [options.targets];
541
+ tauriConf.bundle.targets = [options.targets];
535
542
  }
536
543
  else {
537
544
  logger.warn(`✼ The target must be one of ${validTargets.join(', ')}, the default 'deb' will be used.`);
@@ -639,6 +646,10 @@ async function mergeConfig(url, options, tauriConf) {
639
646
  await fsExtra.outputJSON(pakeConfigPath, tauriConf.pake, { spaces: 4 });
640
647
  let tauriConf2 = JSON.parse(JSON.stringify(tauriConf));
641
648
  delete tauriConf2.pake;
649
+ // delete tauriConf2.bundle;
650
+ {
651
+ tauriConf2.bundle = bundleConf.bundle;
652
+ }
642
653
  const configJsonPath = path.join(tauriConfigDirectory, 'tauri.conf.json');
643
654
  await fsExtra.outputJSON(configJsonPath, tauriConf2, { spaces: 4 });
644
655
  }
@@ -771,15 +782,23 @@ class LinuxBuilder extends BaseBuilder {
771
782
  super(options);
772
783
  }
773
784
  getFileName() {
774
- const { name } = this.options;
775
- const arch = process.arch === 'x64' ? 'amd64' : process.arch;
776
- return `${name}_${tauriConfig.version}_${arch}`;
785
+ const { name, targets } = this.options;
786
+ const version = tauriConfig.version;
787
+ let arch = process.arch === 'x64' ? 'amd64' : process.arch;
788
+ if (arch === 'arm64' && (targets === 'rpm' || targets === 'appimage')) {
789
+ arch = 'aarch64';
790
+ }
791
+ // The RPM format uses different separators and version number formats
792
+ if (targets === 'rpm') {
793
+ return `${name}-${version}-1.${arch}`;
794
+ }
795
+ return `${name}_${version}_${arch}`;
777
796
  }
778
797
  // Customize it, considering that there are all targets.
779
798
  async build(url) {
780
- const targetTypes = ['deb', 'appimage'];
799
+ const targetTypes = ['deb', 'appimage', 'rpm'];
781
800
  for (const target of targetTypes) {
782
- if (this.options.targets === target || this.options.targets === 'all') {
801
+ if (this.options.targets === target) {
783
802
  await this.buildAndCopy(url, target);
784
803
  }
785
804
  }