pake-cli 3.16.2 โ†’ 3.16.4

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
@@ -19,7 +19,7 @@ import * as psl from 'psl';
19
19
  import { InvalidArgumentError, program as program$1, Option } from 'commander';
20
20
 
21
21
  var name = "pake-cli";
22
- var version = "3.16.2";
22
+ var version = "3.16.4";
23
23
  var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚";
24
24
  var engines = {
25
25
  node: ">=20.9.0"
@@ -538,15 +538,8 @@ async function acquireBuildCache(targetDirectory) {
538
538
  async function enterBuildWorkspace() {
539
539
  const previousTarget = process.env.CARGO_TARGET_DIR;
540
540
  const targetDirectory = path.resolve(packageDirectory, previousTarget || 'src-tauri/target');
541
- const release = await acquireBuildCache(targetDirectory);
542
- let directory;
543
- try {
544
- directory = await createBuildWorkspace(packageDirectory);
545
- }
546
- catch (error) {
547
- await release();
548
- throw error;
549
- }
541
+ const directory = await createBuildWorkspace(packageDirectory);
542
+ let release;
550
543
  setBuildDirectory(directory);
551
544
  process.env.CARGO_TARGET_DIR = targetDirectory;
552
545
  const leave = async () => {
@@ -567,7 +560,7 @@ async function enterBuildWorkspace() {
567
560
  }
568
561
  finally {
569
562
  try {
570
- await release();
563
+ await release?.();
571
564
  }
572
565
  catch (error) {
573
566
  logger.warn(`Could not release the compilation cache lock: ${String(error)}`);
@@ -578,7 +571,11 @@ async function enterBuildWorkspace() {
578
571
  await leave();
579
572
  throwIfBuildCancelled();
580
573
  }
581
- return leave;
574
+ return Object.assign(leave, {
575
+ async lockCache() {
576
+ release = await acquireBuildCache(targetDirectory);
577
+ },
578
+ });
582
579
  }
583
580
 
584
581
  async function terminateBuildTree(pid) {
@@ -1663,9 +1660,14 @@ class BaseBuilder {
1663
1660
  await shellExec({ executable: packageManager, args });
1664
1661
  }
1665
1662
  async buildAndCopy(url, target, logSuccess = true) {
1666
- const { name = 'pake-app' } = this.options;
1663
+ await this.prepareBuild(url);
1664
+ await this.runBuildCommand(this.getBuildCommand(await detectPackageManager()), target);
1665
+ await this.copyBuildArtifacts(target, logSuccess);
1666
+ }
1667
+ async prepareBuild(url) {
1667
1668
  await mergeConfig(url, this.options, structuredClone(tauriConfig));
1668
- const packageManager = await detectPackageManager();
1669
+ }
1670
+ async runBuildCommand(buildCommand, target) {
1669
1671
  // Build app
1670
1672
  const buildSpinner = getSpinner('Building app...');
1671
1673
  buildSpinner.stop();
@@ -1684,7 +1686,6 @@ class BaseBuilder {
1684
1686
  if (isLinuxAppImage && !buildEnv.NO_STRIP && this.options.debug) {
1685
1687
  logger.warn('โš  AppImage strip step can fail on glibc 2.38+; Pake will auto-retry with NO_STRIP=1.');
1686
1688
  }
1687
- const buildCommand = this.getBuildCommand(packageManager);
1688
1689
  const buildTimeout = getBuildTimeout();
1689
1690
  try {
1690
1691
  await shellExec(buildCommand, buildTimeout, resolveExecEnv());
@@ -1711,6 +1712,9 @@ class BaseBuilder {
1711
1712
  throw retryError;
1712
1713
  }
1713
1714
  }
1715
+ }
1716
+ async copyBuildArtifacts(target, logSuccess = true) {
1717
+ const { name = 'pake-app' } = this.options;
1714
1718
  // With --no-bundle there is no installer to copy; surface the raw
1715
1719
  // executable the build produced instead.
1716
1720
  if (this.options.bundle === false) {
@@ -2083,6 +2087,7 @@ class LinuxBuilder extends BaseBuilder {
2083
2087
  constructor(options) {
2084
2088
  super(options);
2085
2089
  this.currentBuildType = '';
2090
+ this.compiled = false;
2086
2091
  const target = options.targets || 'deb';
2087
2092
  if (target.includes('-arm64')) {
2088
2093
  this.buildFormat = target.replace('-arm64', '');
@@ -2118,6 +2123,8 @@ class LinuxBuilder extends BaseBuilder {
2118
2123
  return `${name}_${version}_${arch}`;
2119
2124
  }
2120
2125
  async build(url) {
2126
+ this.compiled = false;
2127
+ this.currentBuildType = '';
2121
2128
  // --no-bundle: build the executable once with no per-format packaging loop.
2122
2129
  if (this.options.bundle === false) {
2123
2130
  await this.buildAndCopy(url, 'deb');
@@ -2128,6 +2135,13 @@ class LinuxBuilder extends BaseBuilder {
2128
2135
  throw new Error(`No valid Linux target in "${this.options.targets}". Valid targets: ${LINUX_TARGET_TYPES.join(', ')}.`);
2129
2136
  }
2130
2137
  const useTemporaryDebForZst = needsTemporaryDebForZst(targets);
2138
+ if (targets.length > 1) {
2139
+ await this.prepareBuild(url);
2140
+ const command = this.getBuildCommand(await detectPackageManager());
2141
+ command.args.push('--no-bundle');
2142
+ await this.runBuildCommand(command, 'compile');
2143
+ this.compiled = true;
2144
+ }
2131
2145
  // With a single explicit target, fail fast. With multiple targets (the
2132
2146
  // distro-aware default, or an explicit comma list) keep building the rest
2133
2147
  // when one fails, so a usable installer is still produced, e.g. AppImage
@@ -2293,7 +2307,24 @@ post_remove() {
2293
2307
  // Override buildAndCopy to ensure currentBuildType is synced if called directly, though the loop above handles it most of the time.
2294
2308
  async buildAndCopy(url, target, logSuccess = true) {
2295
2309
  this.currentBuildType = target;
2296
- await super.buildAndCopy(url, target, logSuccess);
2310
+ if (!this.compiled) {
2311
+ await super.buildAndCopy(url, target, logSuccess);
2312
+ return;
2313
+ }
2314
+ const packageManager = await detectPackageManager();
2315
+ const args = ['run', 'tauri'];
2316
+ if (packageManager === 'npm')
2317
+ args.push('--');
2318
+ args.push('bundle', '--config', path.join('src-tauri', '.pake', 'tauri.conf.json'));
2319
+ args.push('--bundles', target, '--features', this.getBuildFeatures().join(','));
2320
+ if (this.options.debug)
2321
+ args.push('--debug');
2322
+ if (this.options.debug || target === 'appimage' || process.env.PAKE_VERBOSE)
2323
+ args.push('--verbose');
2324
+ if (this.buildArch === 'arm64')
2325
+ args.push('--target', this.getTauriTarget('arm64', 'linux'));
2326
+ await this.runBuildCommand({ executable: packageManager, args }, target);
2327
+ await this.copyBuildArtifacts(target, logSuccess);
2297
2328
  }
2298
2329
  getBuildCommand(packageManager = 'pnpm') {
2299
2330
  const configPath = path.join('src-tauri', '.pake', 'tauri.conf.json');
@@ -3847,7 +3878,8 @@ program.action(async (urlArg, options) => {
3847
3878
  }
3848
3879
  endCancellation = beginBuildCancellation();
3849
3880
  phase = 'prepare';
3850
- leaveWorkspace = await enterBuildWorkspace();
3881
+ const workspace = await enterBuildWorkspace();
3882
+ leaveWorkspace = workspace;
3851
3883
  phase = 'input';
3852
3884
  const appOptions = await handleOptions(options, url);
3853
3885
  throwIfBuildCancelled();
@@ -3857,6 +3889,8 @@ program.action(async (urlArg, options) => {
3857
3889
  await builder.prepare();
3858
3890
  throwIfBuildCancelled();
3859
3891
  phase = 'build';
3892
+ await workspace.lockCache();
3893
+ throwIfBuildCancelled();
3860
3894
  await builder.build(url);
3861
3895
  throwIfBuildCancelled();
3862
3896
  await leaveWorkspace();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pake-cli",
3
- "version": "3.16.2",
3
+ "version": "3.16.4",
4
4
  "description": "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚",
5
5
  "engines": {
6
6
  "node": ">=20.9.0"
@@ -2564,7 +2564,7 @@ dependencies = [
2564
2564
 
2565
2565
  [[package]]
2566
2566
  name = "pake"
2567
- version = "3.16.2"
2567
+ version = "3.16.4"
2568
2568
  dependencies = [
2569
2569
  "block2",
2570
2570
  "dispatch",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pake"
3
- version = "3.16.2"
3
+ version = "3.16.4"
4
4
  description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with Rust."
5
5
  authors = ["Tw93"]
6
6
  license = "GPL-3.0-or-later"
@@ -405,6 +405,27 @@ fn build_window(
405
405
  ))
406
406
  })?;
407
407
 
408
+ let restored_url = if label == "pake"
409
+ && window_config.url_type == "web"
410
+ && !window_config.incognito
411
+ {
412
+ match app.path().app_data_dir() {
413
+ Ok(directory) => match crate::util::read_last_url(&directory.join("last-url.txt")) {
414
+ Ok(url) => url,
415
+ Err(error) => {
416
+ eprintln!("[Pake] Could not read the last URL: {error}");
417
+ None
418
+ }
419
+ },
420
+ Err(error) => {
421
+ eprintln!("[Pake] Could not locate the last URL: {error}");
422
+ None
423
+ }
424
+ }
425
+ } else {
426
+ None
427
+ };
428
+
408
429
  // On macOS both HTTP Basic auth and certificate bypass use the same
409
430
  // navigation-delegate proxy. Start on a neutral page so the proxy is in
410
431
  // place before the target can issue its first authentication challenge.
@@ -413,11 +434,15 @@ fn build_window(
413
434
  && window_config.url_type == "web"
414
435
  && (config.basic_auth || window_config.ignore_certificate_errors)
415
436
  {
416
- Url::parse(&window_config.url).ok()
437
+ restored_url
438
+ .clone()
439
+ .or_else(|| Url::parse(&window_config.url).ok())
417
440
  } else {
418
441
  None
419
442
  };
420
443
 
444
+ let url = restored_url.map(WebviewUrl::External).unwrap_or(url);
445
+
421
446
  // The delegate must be installed before the first TLS challenge. Start on
422
447
  // a neutral page, then navigate from the with_webview callback below.
423
448
  #[cfg(target_os = "macos")]
@@ -821,6 +846,20 @@ fn build_window(
821
846
  Ok(window)
822
847
  }
823
848
 
849
+ pub fn save_last_url(app: &AppHandle) {
850
+ let Some(window) = app.get_webview_window("pake") else {
851
+ return;
852
+ };
853
+ let result = (|| -> Result<(), Box<dyn std::error::Error>> {
854
+ let path = app.path().app_data_dir()?.join("last-url.txt");
855
+ crate::util::write_last_url(&path, &window.url()?)?;
856
+ Ok(())
857
+ })();
858
+ if let Err(error) = result {
859
+ eprintln!("[Pake] Could not save the last URL: {error}");
860
+ }
861
+ }
862
+
824
863
  #[cfg(all(test, target_os = "windows"))]
825
864
  mod proxy_arg_tests {
826
865
  use super::*;
@@ -32,8 +32,8 @@ use app::{
32
32
  },
33
33
  setup::{set_global_shortcut, set_system_tray},
34
34
  window::{
35
- open_additional_window_safe, reapply_window_icon, reveal_built_window, set_window,
36
- MultiWindowState,
35
+ open_additional_window_safe, reapply_window_icon, reveal_built_window, save_last_url,
36
+ set_window, MultiWindowState,
37
37
  },
38
38
  };
39
39
  use util::get_pake_config;
@@ -201,6 +201,8 @@ pub fn run_app() {
201
201
 
202
202
  let show_system_tray = pake_config.show_system_tray();
203
203
  let hide_on_close = pake_config.windows[0].hide_on_close;
204
+ let remember_url =
205
+ pake_config.windows[0].url_type == "web" && !pake_config.windows[0].incognito;
204
206
  let activation_shortcut = pake_config.windows[0].activation_shortcut.clone();
205
207
  let init_fullscreen = pake_config.windows[0].fullscreen;
206
208
  let start_to_tray = pake_config.windows[0].start_to_tray && show_system_tray; // Only valid when tray is enabled
@@ -357,6 +359,9 @@ pub fn run_app() {
357
359
  })
358
360
  .on_window_event(move |_window, _event| {
359
361
  if let tauri::WindowEvent::CloseRequested { api, .. } = _event {
362
+ if remember_url && _window.label() == "pake" {
363
+ save_last_url(_window.app_handle());
364
+ }
360
365
  if hide_on_close && _window.label() == "pake" {
361
366
  // User dismissed the window; do not let startup reveal reopen it.
362
367
  cancel_startup_reveal(&close_revealed);
@@ -395,6 +400,9 @@ pub fn run_app() {
395
400
  std::process::exit(1);
396
401
  })
397
402
  .run(move |_app, _event| {
403
+ if remember_url && matches!(&_event, tauri::RunEvent::Exit) {
404
+ save_last_url(_app);
405
+ }
398
406
  // Handle macOS dock icon click to reopen hidden window
399
407
  #[cfg(target_os = "macos")]
400
408
  if let tauri::RunEvent::Reopen {
@@ -48,6 +48,26 @@ pub fn get_data_dir(app: &AppHandle, package_name: String) -> std::io::Result<Pa
48
48
  Ok(data_dir)
49
49
  }
50
50
 
51
+ pub fn read_last_url(path: &Path) -> std::io::Result<Option<tauri::Url>> {
52
+ match std::fs::read_to_string(path) {
53
+ Ok(value) => Ok(tauri::Url::parse(&value)
54
+ .ok()
55
+ .filter(|url| matches!(url.scheme(), "http" | "https"))),
56
+ Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(None),
57
+ Err(error) => Err(error),
58
+ }
59
+ }
60
+
61
+ pub fn write_last_url(path: &Path, url: &tauri::Url) -> std::io::Result<()> {
62
+ if matches!(url.scheme(), "http" | "https") {
63
+ if let Some(parent) = path.parent() {
64
+ std::fs::create_dir_all(parent)?;
65
+ }
66
+ std::fs::write(path, url.as_str())?;
67
+ }
68
+ Ok(())
69
+ }
70
+
51
71
  /// Both native and IPC downloads use the trusted, packaged configuration.
52
72
  pub fn get_download_dir(app: &AppHandle) -> Result<PathBuf, String> {
53
73
  let state = app
@@ -257,6 +277,25 @@ mod tests {
257
277
  dir
258
278
  }
259
279
 
280
+ #[test]
281
+ fn last_url_round_trip_preserves_full_address() {
282
+ let path = temp_path("state/last-url.txt");
283
+ assert_eq!(read_last_url(&path).unwrap(), None);
284
+ for address in [
285
+ "https://acme.example/projects/42?view=board#activity",
286
+ "https://login.example/callback?code=example#result",
287
+ ] {
288
+ let url = tauri::Url::parse(address).unwrap();
289
+ write_last_url(&path, &url).unwrap();
290
+ assert_eq!(read_last_url(&path).unwrap(), Some(url));
291
+ }
292
+ write_last_url(&path, &tauri::Url::parse("about:blank").unwrap()).unwrap();
293
+ assert!(read_last_url(&path).unwrap().is_some());
294
+ std::fs::write(&path, "invalid URL").unwrap();
295
+ assert_eq!(read_last_url(&path).unwrap(), None);
296
+ fs::remove_dir_all(path.parent().unwrap().parent().unwrap()).unwrap();
297
+ }
298
+
260
299
  #[test]
261
300
  fn expand_download_dir_preserves_absolute_paths_without_home() {
262
301
  let absolute = temp_path("My Downloads");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "productName": "Weekly",
3
3
  "identifier": "com.pake.weekly",
4
- "version": "3.16.2",
4
+ "version": "3.16.4",
5
5
  "app": {
6
6
  "withGlobalTauri": true,
7
7
  "trayIcon": {