diff --git a/.changes/android-external-files-fix.md b/.changes/android-external-files-fix.md new file mode 100644 index 000000000..b6c2a1446 --- /dev/null +++ b/.changes/android-external-files-fix.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:bug +--- + +Fixed 500 error when accessing local video files in Android external storage directory via `convertFileSrc`. Added better error handling and logging for Android external storage access to help diagnose permission and accessibility issues. \ No newline at end of file diff --git a/.changes/change-pr-13253.md b/.changes/change-pr-13253.md new file mode 100644 index 000000000..e42a66072 --- /dev/null +++ b/.changes/change-pr-13253.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": patch:enhance +"tauri-cli": patch:enhance +--- + +Allow electron to run the CLI directly diff --git a/.changes/change-pr-14812.md b/.changes/change-pr-14812.md new file mode 100644 index 000000000..96c1f36c0 --- /dev/null +++ b/.changes/change-pr-14812.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:bug +--- + +fix(specta): don't use `#[specta(rename = ...)]` with `tauri::ipc::Channel` diff --git a/.changes/change-pr-14824.md b/.changes/change-pr-14824.md new file mode 100644 index 000000000..164991efa --- /dev/null +++ b/.changes/change-pr-14824.md @@ -0,0 +1,5 @@ +--- +'tauri-bundler': 'patch:enhance' +--- + +feat(nsis): add Norwegian language support for installer. \ No newline at end of file diff --git a/.changes/change-pr-14836.md b/.changes/change-pr-14836.md new file mode 100644 index 000000000..61215bed9 --- /dev/null +++ b/.changes/change-pr-14836.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": patch:changes +"tauri-cli": patch:changes +--- + +Continued refactors of tauri-cli, fix too weak atomics. diff --git a/.changes/fix-android-bundle-flag.md b/.changes/fix-android-bundle-flag.md new file mode 100644 index 000000000..1fc06e69e --- /dev/null +++ b/.changes/fix-android-bundle-flag.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + +Fix `android build`'s `--aab` and `--apk` flags requiring a value to be provided. diff --git a/.changes/fix-binary-patching.md b/.changes/fix-binary-patching.md new file mode 100644 index 000000000..0778d600f --- /dev/null +++ b/.changes/fix-binary-patching.md @@ -0,0 +1,8 @@ +--- +"tauri": minor:changes +"tauri-cli": minor:changes +"tauri-bundler": minor:changes +"@tauri-apps/cli": minor:changes +--- + +Change the way bundle type information is added to binary files. Instead of looking up the value of a variable we simply look for the default value. diff --git a/.changes/fix-empty-entitlements.md b/.changes/fix-empty-entitlements.md new file mode 100644 index 000000000..0bc9eea40 --- /dev/null +++ b/.changes/fix-empty-entitlements.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + +Fix empty associated-domains entitlements when domains are not configured for deep links. diff --git a/.changes/nsis-run-as-user.md b/.changes/nsis-run-as-user.md new file mode 100644 index 000000000..ca3d9f9f4 --- /dev/null +++ b/.changes/nsis-run-as-user.md @@ -0,0 +1,9 @@ +--- +"tauri-bundler": patch:bug +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + +Updated `nsis_tauri_utils` to 0.5.3: + +- Use an alternative method `CreateProcessWithTokenW` to run programs as user, this fixed a problem that the program launched with the previous method can't query its own handle diff --git a/.changes/only-watch-dependencies.md b/.changes/only-watch-dependencies.md new file mode 100644 index 000000000..e638cb591 --- /dev/null +++ b/.changes/only-watch-dependencies.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": patch:bug +"tauri-cli": patch:bug +--- + +Only watch dependent workspace members when running `tauri dev` instead of watching on all members diff --git a/.changes/webview-set-simple-fullscreen.md b/.changes/webview-set-simple-fullscreen.md new file mode 100644 index 000000000..ba0cdf8bf --- /dev/null +++ b/.changes/webview-set-simple-fullscreen.md @@ -0,0 +1,7 @@ +--- +'tauri': 'minor:feat' +--- + +Add `set_simple_fullscreen` method to `WebviewWindow`. + +This method was already available on the `Window` type and is now also available on `WebviewWindow` for consistency. On macOS, it toggles fullscreen mode without creating a new macOS Space. On other platforms, it falls back to regular fullscreen. diff --git a/.taurignore b/.taurignore deleted file mode 100644 index 6e49b1ea8..000000000 --- a/.taurignore +++ /dev/null @@ -1,16 +0,0 @@ -.changes -.devcontainer -.docker -.github -.scripts -.vscode -audits -bench -packages/api -packages/cli -crates/tauri-cli -crates/tauri-bundler -crates/tauri-driver -crates/tauri-macos-sign -crates/tauri-schema-generator -crates/tests diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index bac77c041..042a3dfb2 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -4,6 +4,8 @@ // SPDX-License-Identifier: MIT mod category; +#[cfg(any(target_os = "linux", target_os = "windows"))] +mod kmp; #[cfg(target_os = "linux")] mod linux; #[cfg(target_os = "macos")] @@ -15,29 +17,46 @@ mod windows; use tauri_utils::{display_path, platform::Target as TargetPlatform}; +#[cfg(any(target_os = "linux", target_os = "windows"))] +const BUNDLE_VAR_TOKEN: &[u8] = b"__TAURI_BUNDLE_TYPE_VAR_UNK"; /// Patch a binary with bundle type information +#[cfg(any(target_os = "linux", target_os = "windows"))] fn patch_binary(binary: &PathBuf, package_type: &PackageType) -> crate::Result<()> { - match package_type { - #[cfg(target_os = "linux")] - PackageType::AppImage | PackageType::Deb | PackageType::Rpm => { - log::info!( - "Patching binary {:?} for type {}", - binary, - package_type.short_name() - ); - linux::patch_binary(binary, package_type)?; - } - PackageType::Nsis | PackageType::WindowsMsi => { - log::info!( - "Patching binary {:?} for type {}", - binary, - package_type.short_name() - ); - windows::patch_binary(binary, package_type)?; - } - _ => (), - } + let mut file_data = std::fs::read(binary).expect("Could not read binary file."); + if let Some(bundle_var_index) = kmp::index_of(BUNDLE_VAR_TOKEN, &file_data) { + #[cfg(target_os = "linux")] + let bundle_type = match package_type { + crate::PackageType::Deb => b"__TAURI_BUNDLE_TYPE_VAR_DEB", + crate::PackageType::Rpm => b"__TAURI_BUNDLE_TYPE_VAR_RPM", + crate::PackageType::AppImage => b"__TAURI_BUNDLE_TYPE_VAR_APP", + _ => { + return Err(crate::Error::InvalidPackageType( + package_type.short_name().to_owned(), + "Linux".to_owned(), + )) + } + }; + #[cfg(target_os = "windows")] + let bundle_type = match package_type { + crate::PackageType::Nsis => b"__TAURI_BUNDLE_TYPE_VAR_NSS", + crate::PackageType::WindowsMsi => b"__TAURI_BUNDLE_TYPE_VAR_MSI", + _ => { + return Err(crate::Error::InvalidPackageType( + package_type.short_name().to_owned(), + "Windows".to_owned(), + )) + } + }; + + file_data[bundle_var_index..bundle_var_index + BUNDLE_VAR_TOKEN.len()] + .copy_from_slice(bundle_type); + + std::fs::write(binary, &file_data) + .map_err(|e| crate::Error::BinaryWriteError(e.to_string()))?; + } else { + return Err(crate::Error::MissingBundleTypeVar); + } Ok(()) } @@ -92,22 +111,17 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { .expect("Main binary missing in settings"); let main_binary_path = settings.binary_path(main_binary); - // When packaging multiple binary types, we make a copy of the unsigned main_binary so that we can - // restore it after each package_type step. This avoids two issues: + // We make a copy of the unsigned main_binary so that we can restore it after each package_type step. + // This allows us to patch the binary correctly and avoids two issues: // - modifying a signed binary without updating its PE checksum can break signature verification // - codesigning tools should handle calculating+updating this, we just need to ensure // (re)signing is performed after every `patch_binary()` operation // - signing an already-signed binary can result in multiple signatures, causing verification errors - let main_binary_reset_required = matches!(target_os, TargetPlatform::Windows) - && settings.windows().can_sign() - && package_types.len() > 1; - let mut unsigned_main_binary_copy = tempfile::tempfile()?; - if main_binary_reset_required { - let mut unsigned_main_binary = std::fs::File::open(&main_binary_path)?; - std::io::copy(&mut unsigned_main_binary, &mut unsigned_main_binary_copy)?; - } + // TODO: change this to work on a copy while preserving the main binary unchanged + let mut main_binary_copy = tempfile::tempfile()?; + let mut main_binary_orignal = std::fs::File::open(&main_binary_path)?; + std::io::copy(&mut main_binary_orignal, &mut main_binary_copy)?; - let mut main_binary_signed = false; let mut bundles = Vec::::new(); for package_type in &package_types { // bundle was already built! e.g. DMG already built .app @@ -115,22 +129,14 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { continue; } + #[cfg(any(target_os = "linux", target_os = "windows"))] if let Err(e) = patch_binary(&main_binary_path, package_type) { log::warn!("Failed to add bundler type to the binary: {e}. Updater plugin may not be able to update this package. This shouldn't normally happen, please report it to https://github.com/tauri-apps/tauri/issues"); } // sign main binary for every package type after patch if matches!(target_os, TargetPlatform::Windows) && settings.windows().can_sign() { - if main_binary_signed && main_binary_reset_required { - let mut signed_main_binary = std::fs::OpenOptions::new() - .write(true) - .truncate(true) - .open(&main_binary_path)?; - unsigned_main_binary_copy.seek(SeekFrom::Start(0))?; - std::io::copy(&mut unsigned_main_binary_copy, &mut signed_main_binary)?; - } windows::sign::try_sign(&main_binary_path, settings)?; - main_binary_signed = true; } let bundle_paths = match package_type { @@ -172,6 +178,14 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { package_type: package_type.to_owned(), bundle_paths, }); + + // Restore unsigned and unpatched binary + let mut modified_main_binary = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(&main_binary_path)?; + main_binary_copy.seek(SeekFrom::Start(0))?; + std::io::copy(&mut main_binary_copy, &mut modified_main_binary)?; } if let Some(updater) = settings.updater() { diff --git a/crates/tauri-bundler/src/bundle/kmp/mod.rs b/crates/tauri-bundler/src/bundle/kmp/mod.rs new file mode 100644 index 000000000..3e8489023 --- /dev/null +++ b/crates/tauri-bundler/src/bundle/kmp/mod.rs @@ -0,0 +1,61 @@ +// Copyright 2016-2019 Cargo-Bundle developers +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// Knuth–Morris–Pratt algorithm +// based on https://github.com/howeih/rust_kmp +#[cfg(any(target_os = "linux", target_os = "windows"))] +pub fn index_of(pattern: &[u8], target: &[u8]) -> Option { + let failure_function = find_failure_function(pattern); + + let mut t_i: usize = 0; + let mut p_i: usize = 0; + let target_len = target.len(); + let mut result_idx = None; + let pattern_len = pattern.len(); + + while (t_i < target_len) && (p_i < pattern_len) { + if target[t_i] == pattern[p_i] { + if result_idx.is_none() { + result_idx.replace(t_i); + } + t_i += 1; + p_i += 1; + if p_i >= pattern_len { + return result_idx; + } + } else { + if p_i == 0 { + p_i = 0; + t_i += 1; + } else { + p_i = failure_function[p_i - 1]; + } + result_idx = None; + } + } + None +} + +#[cfg(any(target_os = "linux", target_os = "windows"))] +fn find_failure_function(pattern: &[u8]) -> Vec { + let mut i = 1; + let mut j = 0; + let pattern_length = pattern.len(); + let end_i = pattern_length - 1; + let mut failure_function = vec![0usize; pattern_length]; + while i <= end_i { + if pattern[i] == pattern[j] { + failure_function[i] = j + 1; + i += 1; + j += 1; + } else if j == 0 { + failure_function[i] = 0; + i += 1; + } else { + j = failure_function[j - 1]; + } + } + failure_function +} diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs new file mode 100644 index 000000000..dccc3b5a2 --- /dev/null +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs @@ -0,0 +1,282 @@ +// Copyright 2016-2019 Cargo-Bundle developers +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{super::debian, write_and_make_executable}; +use crate::{ + bundle::settings::Arch, + error::{Context, ErrorExt}, + utils::{fs_utils, http_utils::download, CommandExt}, + Settings, +}; +use std::{ + fs, + path::{Path, PathBuf}, + process::Command, +}; + +/// Bundles the project. +/// Returns a vector of PathBuf that shows where the AppImage was created. +pub fn bundle_project(settings: &Settings) -> crate::Result> { + // generate the deb binary name + let appimage_arch: &str = match settings.binary_arch() { + Arch::X86_64 => "amd64", + Arch::X86 => "i386", + Arch::AArch64 => "aarch64", + Arch::Armhf => "armhf", + target => { + return Err(crate::Error::ArchError(format!( + "Unsupported architecture: {target:?}" + ))); + } + }; + + let tools_arch = if settings.binary_arch() == Arch::Armhf { + "armhf" + } else { + settings.target().split('-').next().unwrap() + }; + + let output_path = settings.project_out_directory().join("bundle/appimage"); + if output_path.exists() { + fs::remove_dir_all(&output_path)?; + } + + let tools_path = settings + .local_tools_directory() + .map(|d| d.join(".tauri")) + .unwrap_or_else(|| { + dirs::cache_dir().map_or_else(|| output_path.to_path_buf(), |p| p.join("tauri")) + }); + + fs::create_dir_all(&tools_path)?; + + let linuxdeploy_path = prepare_tools( + &tools_path, + tools_arch, + settings.log_level() != log::Level::Error, + )?; + + let package_dir = settings.project_out_directory().join("bundle/appimage_deb"); + + let main_binary = settings.main_binary()?; + let product_name = settings.product_name(); + + let mut settings = settings.clone(); + if main_binary.name().contains(' ') { + let main_binary_path = settings.binary_path(main_binary); + let project_out_directory = settings.project_out_directory(); + + let main_binary_name_kebab = heck::AsKebabCase(main_binary.name()).to_string(); + let new_path = project_out_directory.join(&main_binary_name_kebab); + fs::copy(main_binary_path, new_path)?; + + let main_binary = settings.main_binary_mut()?; + main_binary.set_name(main_binary_name_kebab); + } + + // generate deb_folder structure + let (data_dir, icons) = debian::generate_data(&settings, &package_dir) + .with_context(|| "Failed to build data folders and files")?; + fs_utils::copy_custom_files(&settings.appimage().files, &data_dir) + .with_context(|| "Failed to copy custom files")?; + + fs::create_dir_all(&output_path)?; + let app_dir_path = output_path.join(format!("{}.AppDir", settings.product_name())); + let appimage_filename = format!( + "{}_{}_{}.AppImage", + settings.product_name(), + settings.version_string(), + appimage_arch + ); + let appimage_path = output_path.join(&appimage_filename); + fs_utils::create_dir(&app_dir_path, true)?; + + fs::create_dir_all(&tools_path)?; + let larger_icon = icons + .iter() + .filter(|i| i.width == i.height) + .max_by_key(|i| i.width) + .expect("couldn't find a square icon to use as AppImage icon"); + let larger_icon_path = larger_icon + .path + .strip_prefix(package_dir.join("data")) + .unwrap() + .to_string_lossy() + .to_string(); + + log::info!(action = "Bundling"; "{} ({})", appimage_filename, appimage_path.display()); + + let app_dir_usr = app_dir_path.join("usr/"); + let app_dir_usr_bin = app_dir_usr.join("bin/"); + let app_dir_usr_lib = app_dir_usr.join("lib/"); + + fs_utils::copy_dir(&data_dir.join("usr/"), &app_dir_usr)?; + + // Using create_dir_all for a single dir so we don't get errors if the path already exists + fs::create_dir_all(&app_dir_usr_bin)?; + fs::create_dir_all(app_dir_usr_lib)?; + + // Copy bins and libs that linuxdeploy doesn't know about + + // we also check if the user may have provided their own copy already + // xdg-open will be handled by the `files` config instead + if settings.deep_link_protocols().is_some() && !app_dir_usr_bin.join("xdg-open").exists() { + fs::copy("/usr/bin/xdg-mime", app_dir_usr_bin.join("xdg-mime")) + .fs_context("xdg-mime binary not found", "/usr/bin/xdg-mime".to_string())?; + } + + // we also check if the user may have provided their own copy already + if settings.appimage().bundle_xdg_open && !app_dir_usr_bin.join("xdg-open").exists() { + fs::copy("/usr/bin/xdg-open", app_dir_usr_bin.join("xdg-open")) + .fs_context("xdg-open binary not found", "/usr/bin/xdg-open".to_string())?; + } + + let search_dirs = [ + match settings.binary_arch() { + Arch::X86_64 => "/usr/lib/x86_64-linux-gnu/", + Arch::X86 => "/usr/lib/i386-linux-gnu/", + Arch::AArch64 => "/usr/lib/aarch64-linux-gnu/", + Arch::Armhf => "/usr/lib/arm-linux-gnueabihf/", + _ => unreachable!(), + }, + "/usr/lib64", + "/usr/lib", + "/usr/libexec", + ]; + + for file in [ + "WebKitNetworkProcess", + "WebKitWebProcess", + "injected-bundle/libwebkit2gtkinjectedbundle.so", + ] { + for source in search_dirs.map(PathBuf::from) { + // TODO: Check if it's the same dir name on all systems + let source = source.join("webkit2gtk-4.1").join(file); + if source.exists() { + fs_utils::copy_file( + &source, + &app_dir_path.join(source.strip_prefix("/").unwrap()), + )?; + } + } + } + + fs::copy( + tools_path.join(format!("AppRun-{tools_arch}")), + app_dir_path.join("AppRun"), + )?; + fs::copy( + app_dir_path.join(larger_icon_path), + app_dir_path.join(format!("{product_name}.png")), + )?; + std::os::unix::fs::symlink( + app_dir_path.join(format!("{product_name}.png")), + app_dir_path.join(".DirIcon"), + )?; + std::os::unix::fs::symlink( + app_dir_path.join(format!("usr/share/applications/{product_name}.desktop")), + app_dir_path.join(format!("{product_name}.desktop")), + )?; + + let log_level = match settings.log_level() { + log::Level::Error => "3", + log::Level::Warn => "2", + log::Level::Info => "1", + _ => "0", + }; + + let mut cmd = Command::new(linuxdeploy_path); + cmd.env("OUTPUT", &appimage_path); + cmd.env("ARCH", tools_arch); + // Looks like the cli arg isn't enough for the updated AppImage output-plugin. + cmd.env("APPIMAGE_EXTRACT_AND_RUN", "1"); + cmd.args([ + "--appimage-extract-and-run", + "--verbosity", + log_level, + "--appdir", + &app_dir_path.display().to_string(), + "--plugin", + "gtk", + ]); + if settings.appimage().bundle_media_framework { + cmd.args(["--plugin", "gstreamer"]); + } + cmd.args(["--output", "appimage"]); + + // Linuxdeploy logs everything into stderr so we have to ignore the output ourselves here + if settings.log_level() == log::Level::Error { + log::debug!(action = "Running"; "Command `linuxdeploy {}`", cmd.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}"))); + if !cmd.output()?.status.success() { + return Err(crate::Error::GenericError( + "failed to run linuxdeploy".to_string(), + )); + } + } else { + cmd.output_ok()?; + } + + fs::remove_dir_all(&package_dir)?; + Ok(vec![appimage_path]) +} + +// returns the linuxdeploy path to keep linuxdeploy_arch contained +fn prepare_tools(tools_path: &Path, arch: &str, verbose: bool) -> crate::Result { + let apprun = tools_path.join(format!("AppRun-{arch}")); + if !apprun.exists() { + let data = download(&format!( + "https://github.com/tauri-apps/binary-releases/releases/download/apprun-old/AppRun-{arch}" + ))?; + write_and_make_executable(&apprun, data)?; + } + + let linuxdeploy_arch = if arch == "i686" { "i383" } else { arch }; + let linuxdeploy = tools_path.join(format!("linuxdeploy-{linuxdeploy_arch}.AppImage")); + if !linuxdeploy.exists() { + let data = download(&format!("https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-{linuxdeploy_arch}.AppImage"))?; + write_and_make_executable(&linuxdeploy, data)?; + } + + let gtk = tools_path.join("linuxdeploy-plugin-gtk.sh"); + if !gtk.exists() { + let data = download("https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh")?; + write_and_make_executable(>k, data)?; + } + + let gstreamer = tools_path.join("linuxdeploy-plugin-gstreamer.sh"); + if !gstreamer.exists() { + let data = download("https://raw.githubusercontent.com/tauri-apps/linuxdeploy-plugin-gstreamer/master/linuxdeploy-plugin-gstreamer.sh")?; + write_and_make_executable(&gstreamer, data)?; + } + + let appimage = tools_path.join("linuxdeploy-plugin-appimage.AppImage"); + if !appimage.exists() { + // This is optional, linuxdeploy will fall back to its built-in version if the download failed. + let data = download(&format!("https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-{arch}.AppImage")); + match data { + Ok(data) => write_and_make_executable(&appimage, data)?, + Err(err) => { + log::error!("Download of AppImage plugin failed. Using older built-in version instead."); + if verbose { + log::debug!("{err:?}"); + } + } + } + } + + // This should prevent linuxdeploy to be detected by appimage integration tools + let _ = Command::new("dd") + .args([ + "if=/dev/zero", + "bs=1", + "count=3", + "seek=8", + "conv=notrunc", + &format!("of={}", linuxdeploy.display()), + ]) + .output(); + + Ok(linuxdeploy) +} diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/mod.rs b/crates/tauri-bundler/src/bundle/linux/appimage/mod.rs index 29eb87bee..9e30f9cfd 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage/mod.rs +++ b/crates/tauri-bundler/src/bundle/linux/appimage/mod.rs @@ -1,287 +1,21 @@ -// Copyright 2016-2019 Cargo-Bundle developers // Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use super::debian; -use crate::{ - bundle::settings::Arch, - error::{Context, ErrorExt}, - utils::{fs_utils, http_utils::download, CommandExt}, - Settings, -}; use std::{ fs, path::{Path, PathBuf}, - process::Command, }; -/// Bundles the project. -/// Returns a vector of PathBuf that shows where the AppImage was created. +use crate::Settings; + +mod linuxdeploy; + pub fn bundle_project(settings: &Settings) -> crate::Result> { - // generate the deb binary name - let appimage_arch: &str = match settings.binary_arch() { - Arch::X86_64 => "amd64", - Arch::X86 => "i386", - Arch::AArch64 => "aarch64", - Arch::Armhf => "armhf", - target => { - return Err(crate::Error::ArchError(format!( - "Unsupported architecture: {target:?}" - ))); - } - }; - - let tools_arch = if settings.binary_arch() == Arch::Armhf { - "armhf" - } else { - settings.target().split('-').next().unwrap() - }; - - let output_path = settings.project_out_directory().join("bundle/appimage"); - if output_path.exists() { - fs::remove_dir_all(&output_path)?; - } - - let tools_path = settings - .local_tools_directory() - .map(|d| d.join(".tauri")) - .unwrap_or_else(|| { - dirs::cache_dir().map_or_else(|| output_path.to_path_buf(), |p| p.join("tauri")) - }); - - fs::create_dir_all(&tools_path)?; - - let linuxdeploy_path = prepare_tools( - &tools_path, - tools_arch, - settings.log_level() != log::Level::Error, - )?; - - let package_dir = settings.project_out_directory().join("bundle/appimage_deb"); - - let main_binary = settings.main_binary()?; - let product_name = settings.product_name(); - - let mut settings = settings.clone(); - if main_binary.name().contains(' ') { - let main_binary_path = settings.binary_path(main_binary); - let project_out_directory = settings.project_out_directory(); - - let main_binary_name_kebab = heck::AsKebabCase(main_binary.name()).to_string(); - let new_path = project_out_directory.join(&main_binary_name_kebab); - fs::copy(main_binary_path, new_path)?; - - let main_binary = settings.main_binary_mut()?; - main_binary.set_name(main_binary_name_kebab); - } - - // generate deb_folder structure - let (data_dir, icons) = debian::generate_data(&settings, &package_dir) - .with_context(|| "Failed to build data folders and files")?; - fs_utils::copy_custom_files(&settings.appimage().files, &data_dir) - .with_context(|| "Failed to copy custom files")?; - - fs::create_dir_all(&output_path)?; - let app_dir_path = output_path.join(format!("{}.AppDir", settings.product_name())); - let appimage_filename = format!( - "{}_{}_{}.AppImage", - settings.product_name(), - settings.version_string(), - appimage_arch - ); - let appimage_path = output_path.join(&appimage_filename); - fs_utils::create_dir(&app_dir_path, true)?; - - fs::create_dir_all(&tools_path)?; - let larger_icon = icons - .iter() - .filter(|i| i.width == i.height) - .max_by_key(|i| i.width) - .expect("couldn't find a square icon to use as AppImage icon"); - let larger_icon_path = larger_icon - .path - .strip_prefix(package_dir.join("data")) - .unwrap() - .to_string_lossy() - .to_string(); - - log::info!(action = "Bundling"; "{} ({})", appimage_filename, appimage_path.display()); - - let app_dir_usr = app_dir_path.join("usr/"); - let app_dir_usr_bin = app_dir_usr.join("bin/"); - let app_dir_usr_lib = app_dir_usr.join("lib/"); - - fs_utils::copy_dir(&data_dir.join("usr/"), &app_dir_usr)?; - - // Using create_dir_all for a single dir so we don't get errors if the path already exists - fs::create_dir_all(&app_dir_usr_bin)?; - fs::create_dir_all(app_dir_usr_lib)?; - - // Copy bins and libs that linuxdeploy doesn't know about - - // we also check if the user may have provided their own copy already - // xdg-open will be handled by the `files` config instead - if settings.deep_link_protocols().is_some() && !app_dir_usr_bin.join("xdg-open").exists() { - fs::copy("/usr/bin/xdg-mime", app_dir_usr_bin.join("xdg-mime")) - .fs_context("xdg-mime binary not found", "/usr/bin/xdg-mime".to_string())?; - } - - // we also check if the user may have provided their own copy already - if settings.appimage().bundle_xdg_open && !app_dir_usr_bin.join("xdg-open").exists() { - fs::copy("/usr/bin/xdg-open", app_dir_usr_bin.join("xdg-open")) - .fs_context("xdg-open binary not found", "/usr/bin/xdg-open".to_string())?; - } - - let search_dirs = [ - match settings.binary_arch() { - Arch::X86_64 => "/usr/lib/x86_64-linux-gnu/", - Arch::X86 => "/usr/lib/i386-linux-gnu/", - Arch::AArch64 => "/usr/lib/aarch64-linux-gnu/", - Arch::Armhf => "/usr/lib/arm-linux-gnueabihf/", - _ => unreachable!(), - }, - "/usr/lib64", - "/usr/lib", - "/usr/libexec", - ]; - - for file in [ - "WebKitNetworkProcess", - "WebKitWebProcess", - "injected-bundle/libwebkit2gtkinjectedbundle.so", - ] { - for source in search_dirs.map(PathBuf::from) { - // TODO: Check if it's the same dir name on all systems - let source = source.join("webkit2gtk-4.1").join(file); - if source.exists() { - fs_utils::copy_file( - &source, - &app_dir_path.join(source.strip_prefix("/").unwrap()), - )?; - } - } - } - - fs::copy( - tools_path.join(format!("AppRun-{tools_arch}")), - app_dir_path.join("AppRun"), - )?; - fs::copy( - app_dir_path.join(larger_icon_path), - app_dir_path.join(format!("{product_name}.png")), - )?; - std::os::unix::fs::symlink( - app_dir_path.join(format!("{product_name}.png")), - app_dir_path.join(".DirIcon"), - )?; - std::os::unix::fs::symlink( - app_dir_path.join(format!("usr/share/applications/{product_name}.desktop")), - app_dir_path.join(format!("{product_name}.desktop")), - )?; - - let log_level = match settings.log_level() { - log::Level::Error => "3", - log::Level::Warn => "2", - log::Level::Info => "1", - _ => "0", - }; - - let mut cmd = Command::new(linuxdeploy_path); - cmd.env("OUTPUT", &appimage_path); - cmd.env("ARCH", tools_arch); - // Looks like the cli arg isn't enough for the updated AppImage output-plugin. - cmd.env("APPIMAGE_EXTRACT_AND_RUN", "1"); - cmd.args([ - "--appimage-extract-and-run", - "--verbosity", - log_level, - "--appdir", - &app_dir_path.display().to_string(), - "--plugin", - "gtk", - ]); - if settings.appimage().bundle_media_framework { - cmd.args(["--plugin", "gstreamer"]); - } - cmd.args(["--output", "appimage"]); - - // Linuxdeploy logs everything into stderr so we have to ignore the output ourselves here - if settings.log_level() == log::Level::Error { - log::debug!(action = "Running"; "Command `linuxdeploy {}`", cmd.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}"))); - if !cmd.output()?.status.success() { - return Err(crate::Error::GenericError( - "failed to run linuxdeploy".to_string(), - )); - } - } else { - cmd.output_ok()?; - } - - fs::remove_dir_all(&package_dir)?; - Ok(vec![appimage_path]) + linuxdeploy::bundle_project(settings) } -// returns the linuxdeploy path to keep linuxdeploy_arch contained -fn prepare_tools(tools_path: &Path, arch: &str, verbose: bool) -> crate::Result { - let apprun = tools_path.join(format!("AppRun-{arch}")); - if !apprun.exists() { - let data = download(&format!( - "https://github.com/tauri-apps/binary-releases/releases/download/apprun-old/AppRun-{arch}" - ))?; - write_and_make_executable(&apprun, &data)?; - } - - let linuxdeploy_arch = if arch == "i686" { "i386" } else { arch }; - let linuxdeploy = tools_path.join(format!("linuxdeploy-{linuxdeploy_arch}.AppImage")); - if !linuxdeploy.exists() { - let data = download(&format!("https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-{linuxdeploy_arch}.AppImage"))?; - write_and_make_executable(&linuxdeploy, &data)?; - } - - let gtk = tools_path.join("linuxdeploy-plugin-gtk.sh"); - if !gtk.exists() { - let data = include_bytes!("./linuxdeploy-plugin-gtk.sh"); - write_and_make_executable(>k, data)?; - } - - let gstreamer = tools_path.join("linuxdeploy-plugin-gstreamer.sh"); - if !gstreamer.exists() { - let data = include_bytes!("./linuxdeploy-plugin-gstreamer.sh"); - write_and_make_executable(&gstreamer, data)?; - } - - let appimage = tools_path.join("linuxdeploy-plugin-appimage.AppImage"); - if !appimage.exists() { - // This is optional, linuxdeploy will fall back to its built-in version if the download failed. - let data = download(&format!("https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-{arch}.AppImage")); - match data { - Ok(data) => write_and_make_executable(&appimage, &data)?, - Err(err) => { - log::error!("Download of AppImage plugin failed. Using older built-in version instead."); - if verbose { - log::debug!("{err:?}"); - } - } - } - } - - // This should prevent linuxdeploy to be detected by appimage integration tools - let _ = Command::new("dd") - .args([ - "if=/dev/zero", - "bs=1", - "count=3", - "seek=8", - "conv=notrunc", - &format!("of={}", linuxdeploy.display()), - ]) - .output(); - - Ok(linuxdeploy) -} - -fn write_and_make_executable(path: &Path, data: &[u8]) -> std::io::Result<()> { +fn write_and_make_executable(path: &Path, data: Vec) -> std::io::Result<()> { use std::os::unix::fs::PermissionsExt; fs::write(path, data)?; diff --git a/crates/tauri-bundler/src/bundle/linux/mod.rs b/crates/tauri-bundler/src/bundle/linux/mod.rs index ba66a8d39..8459b0528 100644 --- a/crates/tauri-bundler/src/bundle/linux/mod.rs +++ b/crates/tauri-bundler/src/bundle/linux/mod.rs @@ -7,8 +7,3 @@ pub mod appimage; pub mod debian; pub mod freedesktop; pub mod rpm; - -mod util; - -#[cfg(target_os = "linux")] -pub use util::patch_binary; diff --git a/crates/tauri-bundler/src/bundle/linux/util.rs b/crates/tauri-bundler/src/bundle/linux/util.rs deleted file mode 100644 index be1256295..000000000 --- a/crates/tauri-bundler/src/bundle/linux/util.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019-2024 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -/// Change value of __TAURI_BUNDLE_TYPE static variable to mark which package type it was bundled in -#[cfg(target_os = "linux")] -pub fn patch_binary( - binary_path: &std::path::PathBuf, - package_type: &crate::PackageType, -) -> crate::Result<()> { - let mut file_data = std::fs::read(binary_path).expect("Could not read binary file."); - - let elf = match goblin::Object::parse(&file_data)? { - goblin::Object::Elf(elf) => elf, - _ => return Err(crate::Error::GenericError("Not an ELF file".to_owned())), - }; - - let offset = find_bundle_type_symbol(elf).ok_or(crate::Error::MissingBundleTypeVar)?; - let offset = offset as usize; - if offset + 3 <= file_data.len() { - let chars = &mut file_data[offset..offset + 3]; - match package_type { - crate::PackageType::Deb => chars.copy_from_slice(b"DEB"), - crate::PackageType::Rpm => chars.copy_from_slice(b"RPM"), - crate::PackageType::AppImage => chars.copy_from_slice(b"APP"), - _ => { - return Err(crate::Error::InvalidPackageType( - package_type.short_name().to_owned(), - "linux".to_owned(), - )) - } - } - - std::fs::write(binary_path, &file_data) - .map_err(|error| crate::Error::BinaryWriteError(error.to_string()))?; - } else { - return Err(crate::Error::BinaryOffsetOutOfRange); - } - - Ok(()) -} - -/// Find address of a symbol in relocations table -#[cfg(target_os = "linux")] -fn find_bundle_type_symbol(elf: goblin::elf::Elf<'_>) -> Option { - for sym in elf.syms.iter() { - if let Some(name) = elf.strtab.get_at(sym.st_name) { - if name == "__TAURI_BUNDLE_TYPE" { - for reloc in elf.dynrelas.iter() { - if reloc.r_offset == sym.st_value { - return Some(reloc.r_addend.unwrap()); - } - } - } - } - } - - None -} diff --git a/crates/tauri-bundler/src/bundle/windows/mod.rs b/crates/tauri-bundler/src/bundle/windows/mod.rs index 366e000e1..b92fb5f56 100644 --- a/crates/tauri-bundler/src/bundle/windows/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/mod.rs @@ -14,5 +14,3 @@ pub use util::{ NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME, WIX_UPDATER_OUTPUT_FOLDER_NAME, }; - -pub use util::patch_binary; diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/languages/Norwegian.nsh b/crates/tauri-bundler/src/bundle/windows/nsis/languages/Norwegian.nsh new file mode 100644 index 000000000..c999a2855 --- /dev/null +++ b/crates/tauri-bundler/src/bundle/windows/nsis/languages/Norwegian.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_NORWEGIAN} "Legg til/reinstaller komponenter" +LangString alreadyInstalled ${LANG_NORWEGIAN} "Allerede installert" +LangString alreadyInstalledLong ${LANG_NORWEGIAN} "${PRODUCTNAME} ${VERSION} er allerede installert. Velg operasjonen du vil utføre og klikk Neste for å fortsette." +LangString appRunning ${LANG_NORWEGIAN} "{{product_name}} kjører! Lukk den først og prøv igjen." +LangString appRunningOkKill ${LANG_NORWEGIAN} "{{product_name}} kjører!$\nKlikk OK for å avslutte den" +LangString chooseMaintenanceOption ${LANG_NORWEGIAN} "Velg vedlikeholdsoperasjonen som skal utføres." +LangString choowHowToInstall ${LANG_NORWEGIAN} "Velg hvordan du vil installere ${PRODUCTNAME}." +LangString createDesktop ${LANG_NORWEGIAN} "Opprett skrivebordssnarvei" +LangString dontUninstall ${LANG_NORWEGIAN} "Ikke avinstaller" +LangString dontUninstallDowngrade ${LANG_NORWEGIAN} "Ikke avinstaller (nedgradering uten avinstallasjon er deaktivert for denne installasjonen)" +LangString failedToKillApp ${LANG_NORWEGIAN} "Kunne ikke avslutte {{product_name}}. Lukk den først og prøv igjen" +LangString installingWebview2 ${LANG_NORWEGIAN} "Installerer WebView2..." +LangString newerVersionInstalled ${LANG_NORWEGIAN} "En nyere versjon av ${PRODUCTNAME} er allerede installert! Det anbefales ikke at du installerer en eldre versjon. Hvis du virkelig vil installere denne eldre versjonen, er det bedre å avinstallere den nåværende versjonen først. Velg operasjonen du vil utføre og klikk Neste for å fortsette." +LangString older ${LANG_NORWEGIAN} "eldre" +LangString olderOrUnknownVersionInstalled ${LANG_NORWEGIAN} "En $R4-versjon av ${PRODUCTNAME} er installert på systemet ditt. Det anbefales at du avinstallerer den nåværende versjonen før installasjon. Velg operasjonen du vil utføre og klikk Neste for å fortsette." +LangString silentDowngrades ${LANG_NORWEGIAN} "Nedgraderinger er deaktivert for denne installasjonen. Kan ikke fortsette med stille installasjon; bruk den grafiske installasjonen i stedet.$\n" +LangString unableToUninstall ${LANG_NORWEGIAN} "Kunne ikke avinstallere!" +LangString uninstallApp ${LANG_NORWEGIAN} "Avinstaller ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_NORWEGIAN} "Avinstaller før installasjon" +LangString unknown ${LANG_NORWEGIAN} "ukjent" +LangString webview2AbortError ${LANG_NORWEGIAN} "Kunne ikke installere WebView2! Appen kan ikke kjøre uten den. Prøv å starte installasjonen på nytt." +LangString webview2DownloadError ${LANG_NORWEGIAN} "Feil: Nedlasting av WebView2 mislyktes - $0" +LangString webview2DownloadSuccess ${LANG_NORWEGIAN} "WebView2-bootstrapper lastet ned" +LangString webview2Downloading ${LANG_NORWEGIAN} "Laster ned WebView2-bootstrapper..." +LangString webview2InstallError ${LANG_NORWEGIAN} "Feil: Installering av WebView2 mislyktes med avslutningskode $1" +LangString webview2InstallSuccess ${LANG_NORWEGIAN} "WebView2 ble installert" +LangString deleteAppData ${LANG_NORWEGIAN} "Slett programdata" diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index a67f59eda..21d15aa46 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -40,8 +40,8 @@ const NSIS_URL: &str = #[cfg(target_os = "windows")] const NSIS_SHA1: &str = "EF7FF767E5CBD9EDD22ADD3A32C9B8F4500BB10D"; const NSIS_TAURI_UTILS_URL: &str = - "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.5.2/nsis_tauri_utils.dll"; -const NSIS_TAURI_UTILS_SHA1: &str = "D0C502F45DF55C0465C9406088FF016C2E7E6817"; + "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.5.3/nsis_tauri_utils.dll"; +const NSIS_TAURI_UTILS_SHA1: &str = "75197FEE3C6A814FE035788D1C34EAD39349B860"; #[cfg(target_os = "windows")] const NSIS_REQUIRED_FILES: &[&str] = &[ @@ -872,6 +872,7 @@ fn get_lang_data(lang: &str) -> Option<(String, &[u8])> { "swedish" => include_bytes!("./languages/Swedish.nsh"), "portuguese" => include_bytes!("./languages/Portuguese.nsh"), "ukrainian" => include_bytes!("./languages/Ukrainian.nsh"), + "norwegian" => include_bytes!("./languages/Norwegian.nsh"), _ => return None, }; Some((path, content)) diff --git a/crates/tauri-bundler/src/bundle/windows/util.rs b/crates/tauri-bundler/src/bundle/windows/util.rs index 3685d0c06..55cfea3a9 100644 --- a/crates/tauri-bundler/src/bundle/windows/util.rs +++ b/crates/tauri-bundler/src/bundle/windows/util.rs @@ -77,75 +77,3 @@ pub fn os_bitness<'a>() -> Option<&'a str> { _ => None, } } - -pub fn patch_binary(binary_path: &PathBuf, package_type: &crate::PackageType) -> crate::Result<()> { - let mut file_data = std::fs::read(binary_path)?; - - let pe = match goblin::Object::parse(&file_data)? { - goblin::Object::PE(pe) => pe, - _ => { - return Err(crate::Error::BinaryParseError( - std::io::Error::new(std::io::ErrorKind::InvalidInput, "binary is not a PE file").into(), - )); - } - }; - - let tauri_bundle_section = pe - .sections - .iter() - .find(|s| s.name().unwrap_or_default() == ".taubndl") - .ok_or(crate::Error::MissingBundleTypeVar)?; - - let data_offset = tauri_bundle_section.pointer_to_raw_data as usize; - let pointer_size = if pe.is_64 { 8 } else { 4 }; - let ptr_bytes = file_data - .get(data_offset..data_offset + pointer_size) - .ok_or(crate::Error::BinaryOffsetOutOfRange)?; - // `try_into` is safe to `unwrap` here because we have already checked the slice's size through `get` - let ptr_value = if pe.is_64 { - u64::from_le_bytes(ptr_bytes.try_into().unwrap()) - } else { - u32::from_le_bytes(ptr_bytes.try_into().unwrap()).into() - }; - - let rdata_section = pe - .sections - .iter() - .find(|s| s.name().unwrap_or_default() == ".rdata") - .ok_or_else(|| { - crate::Error::BinaryParseError( - std::io::Error::new(std::io::ErrorKind::InvalidInput, ".rdata section not found").into(), - ) - })?; - - let rva = ptr_value.checked_sub(pe.image_base as u64).ok_or_else(|| { - crate::Error::BinaryParseError( - std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid RVA offset").into(), - ) - })?; - - // see "Relative virtual address (RVA)" for explanation of offset arithmetic here: - // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#general-concepts - let file_offset = rdata_section.pointer_to_raw_data as usize - + (rva as usize).saturating_sub(rdata_section.virtual_address as usize); - - // Overwrite the string at that offset - let string_bytes = file_data - .get_mut(file_offset..file_offset + 3) - .ok_or(crate::Error::BinaryOffsetOutOfRange)?; - match package_type { - crate::PackageType::Nsis => string_bytes.copy_from_slice(b"NSS"), - crate::PackageType::WindowsMsi => string_bytes.copy_from_slice(b"MSI"), - _ => { - return Err(crate::Error::InvalidPackageType( - package_type.short_name().to_owned(), - "windows".to_owned(), - )); - } - } - - std::fs::write(binary_path, &file_data) - .map_err(|e| crate::Error::BinaryWriteError(e.to_string()))?; - - Ok(()) -} diff --git a/crates/tauri-bundler/src/error.rs b/crates/tauri-bundler/src/error.rs index 518cb6ca9..40547a3ee 100644 --- a/crates/tauri-bundler/src/error.rs +++ b/crates/tauri-bundler/src/error.rs @@ -99,19 +99,13 @@ pub enum Error { #[error("Wrong package type {0} for platform {1}")] InvalidPackageType(String, String), /// Bundle type symbol missing in binary - #[cfg_attr( - target_os = "linux", - error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date and that symbol stripping is disabled (https://doc.rust-lang.org/cargo/reference/profiles.html#strip)") - )] - #[cfg_attr( - not(target_os = "linux"), - error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date") - )] + #[error("__TAURI_BUNDLE_TYPE variable not found in binary. Make sure tauri crate and tauri-cli are up to date")] MissingBundleTypeVar, /// Failed to write binary file changed #[error("Failed to write binary file changes: `{0}`")] BinaryWriteError(String), /// Invalid offset while patching binary file + #[deprecated] #[error("Invalid offset while patching binary file")] BinaryOffsetOutOfRange, /// Unsupported architecture. diff --git a/crates/tauri-cli/src/build.rs b/crates/tauri-cli/src/build.rs index 754b1793e..627fd763a 100644 --- a/crates/tauri-cli/src/build.rs +++ b/crates/tauri-cli/src/build.rs @@ -11,7 +11,7 @@ use crate::{ config::{get_config, ConfigMetadata, FrontendDist}, }, info::plugins::check_mismatched_packages, - interface::{rust::get_cargo_target_dir, AppInterface, Interface}, + interface::{rust::get_cargo_target_dir, AppInterface}, ConfigValue, Result, }; use clap::{ArgAction, Parser}; @@ -104,7 +104,7 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?; - setup(&interface, &mut options, &config, false, &dirs)?; + setup(&interface, &mut options, &config, &dirs, false)?; if let Some(minimum_system_version) = &config.bundle.macos.minimum_system_version { std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version); @@ -129,8 +129,8 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { &interface, &*app_settings, &config, - &out_dir, &dirs, + &out_dir, )?; } @@ -141,8 +141,8 @@ pub fn setup( interface: &AppInterface, options: &mut Options, config: &ConfigMetadata, - mobile: bool, dirs: &Dirs, + mobile: bool, ) -> Result<()> { // TODO: Maybe optimize this to run in parallel in the future // see https://github.com/tauri-apps/tauri/pull/13993#discussion_r2280697117 diff --git a/crates/tauri-cli/src/bundle.rs b/crates/tauri-cli/src/bundle.rs index 57e4a6f38..4d3637ab5 100644 --- a/crates/tauri-cli/src/bundle.rs +++ b/crates/tauri-cli/src/bundle.rs @@ -20,7 +20,7 @@ use crate::{ config::{get_config, ConfigMetadata}, updater_signature, }, - interface::{AppInterface, AppSettings, Interface}, + interface::{AppInterface, AppSettings}, ConfigValue, }; @@ -154,8 +154,8 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> { &interface, &*app_settings, &config, - &out_dir, &dirs, + &out_dir, ) } @@ -167,8 +167,8 @@ pub fn bundle( interface: &AppInterface, app_settings: &A, config: &ConfigMetadata, - out_dir: &Path, dirs: &Dirs, + out_dir: &Path, ) -> crate::Result<()> { let package_types: Vec = if let Some(bundles) = &options.bundles { bundles.iter().map(|bundle| bundle.0).collect::>() diff --git a/crates/tauri-cli/src/dev.rs b/crates/tauri-cli/src/dev.rs index 5bf62ef10..d175c4c18 100644 --- a/crates/tauri-cli/src/dev.rs +++ b/crates/tauri-cli/src/dev.rs @@ -10,7 +10,7 @@ use crate::{ config::{get_config, reload_config, BeforeDevCommand, ConfigMetadata, FrontendDist}, }, info::plugins::check_mismatched_packages, - interface::{AppInterface, ExitReason, Interface}, + interface::{AppInterface, ExitReason}, CommandExt, ConfigValue, Error, Result, }; @@ -25,13 +25,13 @@ use std::{ process::{exit, Command, Stdio}, sync::{ atomic::{AtomicBool, Ordering}, - Arc, Mutex, OnceLock, + OnceLock, }, }; mod builtin_dev_server; -static BEFORE_DEV: OnceLock>> = OnceLock::new(); +static BEFORE_DEV: OnceLock = OnceLock::new(); static KILL_BEFORE_DEV_FLAG: AtomicBool = AtomicBool::new(false); #[cfg(unix)] @@ -113,22 +113,20 @@ fn command_internal(mut options: Options, dirs: Dirs) -> Result<()> { .map(Target::from_triple) .unwrap_or_else(Target::current); - let mut cfg = get_config( + let mut config = get_config( target, &options.config.iter().map(|c| &c.0).collect::>(), dirs.tauri, )?; - let mut interface = AppInterface::new(&cfg, options.target.clone(), dirs.tauri)?; + let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?; - setup(&interface, &mut options, &mut cfg, &dirs)?; - - let config = Mutex::new(cfg); + setup(&interface, &mut options, &mut config, &dirs)?; let exit_on_panic = options.exit_on_panic; let no_watch = options.no_watch; interface.dev( - &config, + &mut config, options.into(), move |status, reason| on_app_exit(status, reason, exit_on_panic, no_watch), &dirs, @@ -207,21 +205,18 @@ pub fn setup( let child = SharedChild::spawn(&mut command) .unwrap_or_else(|_| panic!("failed to run `{before_dev}`")); - let child = Arc::new(child); - let child_ = child.clone(); + let child = BEFORE_DEV.get_or_init(move || child); std::thread::spawn(move || { - let status = child_ + let status = child .wait() .expect("failed to wait on \"beforeDevCommand\""); - if !(status.success() || KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed)) { + if !(status.success() || KILL_BEFORE_DEV_FLAG.load(Ordering::SeqCst)) { log::error!("The \"beforeDevCommand\" terminated with a non-zero status code."); exit(status.code().unwrap_or(1)); } }); - BEFORE_DEV.set(Mutex::new(child)).unwrap(); - let _ = ctrlc::set_handler(move || { kill_before_dev_process(); exit(130); @@ -338,11 +333,10 @@ pub fn on_app_exit(code: Option, reason: ExitReason, exit_on_panic: bool, n pub fn kill_before_dev_process() { if let Some(child) = BEFORE_DEV.get() { - let child = child.lock().unwrap(); - if KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed) { + if KILL_BEFORE_DEV_FLAG.load(Ordering::SeqCst) { return; } - KILL_BEFORE_DEV_FLAG.store(true, Ordering::Relaxed); + KILL_BEFORE_DEV_FLAG.store(true, Ordering::SeqCst); #[cfg(windows)] { let powershell_path = std::env::var("SYSTEMROOT").map_or_else( diff --git a/crates/tauri-cli/src/helpers/config.rs b/crates/tauri-cli/src/helpers/config.rs index 929f1fe57..f53d8c869 100644 --- a/crates/tauri-cli/src/helpers/config.rs +++ b/crates/tauri-cli/src/helpers/config.rs @@ -55,8 +55,7 @@ impl ConfigMetadata { for (ext, config) in &self.extensions { if let Some(identifier) = config .as_object() - .and_then(|bundle_config| bundle_config.get("identifier")) - .and_then(|id| id.as_str()) + .and_then(|bundle_config| bundle_config.get("identifier")?.as_str()) { if identifier == self.inner.identifier { return Some(ext.clone()); @@ -164,8 +163,7 @@ fn load_config( let original_identifier = config .as_object() - .and_then(|config| config.get("identifier")) - .and_then(|id| id.as_str()) + .and_then(|config| config.get("identifier")?.as_str()) .map(ToString::to_string); if let Some((platform_config, config_path)) = diff --git a/crates/tauri-cli/src/helpers/mod.rs b/crates/tauri-cli/src/helpers/mod.rs index 3d2a5f0e9..05ea00109 100644 --- a/crates/tauri-cli/src/helpers/mod.rs +++ b/crates/tauri-cli/src/helpers/mod.rs @@ -30,10 +30,7 @@ use tauri_utils::config::HookCommand; #[cfg(not(target_os = "windows"))] use crate::Error; -use crate::{ - interface::{AppInterface, Interface}, - CommandExt, -}; +use crate::{interface::AppInterface, CommandExt}; pub fn command_env(debug: bool) -> HashMap<&'static str, String> { let mut map = HashMap::new(); diff --git a/crates/tauri-cli/src/inspect.rs b/crates/tauri-cli/src/inspect.rs index de26dd984..1e2334965 100644 --- a/crates/tauri-cli/src/inspect.rs +++ b/crates/tauri-cli/src/inspect.rs @@ -6,7 +6,7 @@ use std::path::Path; use crate::Result; use clap::{Parser, Subcommand}; -use crate::interface::{AppInterface, AppSettings, Interface}; +use crate::interface::{AppInterface, AppSettings}; #[derive(Debug, Parser)] #[clap(about = "Inspect values used by Tauri")] diff --git a/crates/tauri-cli/src/interface/mod.rs b/crates/tauri-cli/src/interface/mod.rs index 8b797091d..683d29eba 100644 --- a/crates/tauri-cli/src/interface/mod.rs +++ b/crates/tauri-cli/src/interface/mod.rs @@ -5,24 +5,17 @@ pub mod rust; use std::{ - collections::HashMap, path::{Path, PathBuf}, process::ExitStatus, - sync::Arc, - sync::Mutex, }; -use crate::{ - error::Context, helpers::app_paths::Dirs, helpers::config::Config, - helpers::config::ConfigMetadata, -}; +use crate::{error::Context, helpers::config::Config}; use tauri_bundler::bundle::{PackageType, Settings, SettingsBuilder}; pub use rust::{MobileOptions, Options, Rust as AppInterface, WatcherOptions}; pub trait DevProcess { fn kill(&self) -> std::io::Result<()>; - fn try_wait(&self) -> std::io::Result>; #[allow(unused)] fn wait(&self) -> std::io::Result; #[allow(unused)] @@ -105,33 +98,3 @@ pub enum ExitReason { /// Regular exit. NormalExit, } - -pub trait Interface: Sized { - type AppSettings: AppSettings; - - fn new(config: &Config, target: Option, tauri_dir: &Path) -> crate::Result; - fn app_settings(&self) -> Arc; - fn env(&self) -> HashMap<&str, String>; - fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result; - fn dev, ExitReason) + Send + Sync + 'static>( - &mut self, - config: &Mutex, - options: Options, - on_exit: F, - dirs: &Dirs, - ) -> crate::Result<()>; - fn mobile_dev crate::Result>>( - &mut self, - config: &Mutex, - options: MobileOptions, - runner: R, - dirs: &Dirs, - ) -> crate::Result<()>; - fn watch crate::Result>>( - &mut self, - config: &Mutex, - options: WatcherOptions, - runner: R, - dirs: &Dirs, - ) -> crate::Result<()>; -} diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index 3c5f93efa..99220d257 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -7,6 +7,7 @@ use std::{ ffi::OsStr, fs::FileType, io::{BufRead, Write}, + iter::once, path::{Path, PathBuf}, process::Command, str::FromStr, @@ -15,7 +16,6 @@ use std::{ }; use dunce::canonicalize; -use glob::glob; use ignore::gitignore::{Gitignore, GitignoreBuilder}; use notify::RecursiveMode; use notify_debouncer_full::new_debouncer; @@ -27,7 +27,7 @@ use tauri_bundler::{ }; use tauri_utils::config::{parse::is_configuration_file, DeepLinkProtocol, RunnerConfig, Updater}; -use super::{AppSettings, DevProcess, ExitReason, Interface}; +use super::{AppSettings, DevProcess, ExitReason}; use crate::{ error::{Context, Error, ErrorExt}, helpers::{ @@ -134,10 +134,8 @@ pub struct Rust { main_binary_name: Option, } -impl Interface for Rust { - type AppSettings = RustAppSettings; - - fn new(config: &Config, target: Option, tauri_dir: &Path) -> crate::Result { +impl Rust { + pub fn new(config: &Config, target: Option, tauri_dir: &Path) -> crate::Result { let manifest = { let (tx, rx) = sync_channel(1); let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| { @@ -177,11 +175,11 @@ impl Interface for Rust { }) } - fn app_settings(&self) -> Arc { + pub fn app_settings(&self) -> Arc { self.app_settings.clone() } - fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result { + pub fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result { desktop::build( options, &self.app_settings, @@ -192,9 +190,9 @@ impl Interface for Rust { ) } - fn dev, ExitReason) + Send + Sync + 'static>( + pub fn dev, ExitReason) + Send + Sync + 'static>( &mut self, - config: &Mutex, + config: &mut ConfigMetadata, mut options: Options, on_exit: F, dirs: &Dirs, @@ -212,7 +210,7 @@ impl Interface for Rust { if options.no_watch { let (tx, rx) = sync_channel(1); - self.run_dev(options, run_args, move |status, reason| { + self.run_dev(options, &run_args, move |status, reason| { on_exit(status, reason); tx.send(()).unwrap(); })?; @@ -221,25 +219,28 @@ impl Interface for Rust { Ok(()) } else { let merge_configs = options.config.iter().map(|c| &c.0).collect::>(); - let run = Arc::new(|rust: &mut Rust| { - let on_exit = on_exit.clone(); - rust.run_dev(options.clone(), run_args.clone(), move |status, reason| { - on_exit(status, reason) - }) - }); self.run_dev_watcher( config, &options.additional_watch_folders, &merge_configs, - run, + |rust: &mut Rust, _config| { + let on_exit = on_exit.clone(); + rust + .run_dev(options.clone(), &run_args, move |status, reason| { + on_exit(status, reason) + }) + .map(|child| Box::new(child) as Box) + }, dirs, ) } } - fn mobile_dev crate::Result>>( + pub fn mobile_dev< + R: Fn(MobileOptions, &ConfigMetadata) -> crate::Result>, + >( &mut self, - config: &Mutex, + config: &mut ConfigMetadata, mut options: MobileOptions, runner: R, dirs: &Dirs, @@ -254,7 +255,7 @@ impl Interface for Rust { ); if options.no_watch { - runner(options)?; + runner(options, config)?; Ok(()) } else { self.watch( @@ -263,31 +264,30 @@ impl Interface for Rust { config: options.config.clone(), additional_watch_folders: options.additional_watch_folders.clone(), }, - move || runner(options.clone()), + move |config| runner(options.clone(), config), dirs, ) } } - fn watch crate::Result>>( + pub fn watch crate::Result>>( &mut self, - config: &Mutex, + config: &mut ConfigMetadata, options: WatcherOptions, runner: R, dirs: &Dirs, ) -> crate::Result<()> { let merge_configs = options.config.iter().map(|c| &c.0).collect::>(); - let run = Arc::new(|_rust: &mut Rust| runner()); self.run_dev_watcher( config, &options.additional_watch_folders, &merge_configs, - run, + |_rust: &mut Rust, config| runner(config), dirs, ) } - fn env(&self) -> HashMap<&str, String> { + pub fn env(&self) -> HashMap<&str, String> { let mut env = HashMap::new(); env.insert( "TAURI_ENV_TARGET_TRIPLE", @@ -363,7 +363,7 @@ fn build_ignore_matcher(dir: &Path) -> IgnoreMatcher { ignore_builder.add(path); - if let Ok(ignore_file) = std::env::var("TAURI_CLI_WATCHER_IGNORE_FILENAME") { + if let Some(ignore_file) = std::env::var_os("TAURI_CLI_WATCHER_IGNORE_FILENAME") { ignore_builder.add(dir.join(ignore_file)); } @@ -395,7 +395,7 @@ fn lookup(dir: &Path, mut f: F) { let mut builder = ignore::WalkBuilder::new(dir); builder.add_custom_ignore_filename(".taurignore"); let _ = builder.add_ignore(default_gitignore); - if let Ok(ignore_file) = std::env::var("TAURI_CLI_WATCHER_IGNORE_FILENAME") { + if let Some(ignore_file) = std::env::var_os("TAURI_CLI_WATCHER_IGNORE_FILENAME") { builder.add_ignore(ignore_file); } builder.require_git(false).ignore(false).max_depth(Some(1)); @@ -449,25 +449,15 @@ fn dev_options( } } -// Copied from https://github.com/rust-lang/cargo/blob/69255bb10de7f74511b5cef900a9d102247b6029/src/cargo/core/workspace.rs#L665 -fn expand_member_path(path: &Path) -> crate::Result> { - let path = path.to_str().context("path is not UTF-8 compatible")?; - let res = glob(path).with_context(|| format!("failed to expand glob pattern for {path}"))?; - let res = res - .map(|p| p.with_context(|| format!("failed to expand glob pattern for {path}"))) - .collect::, _>>()?; - Ok(res) -} - fn get_watch_folders( additional_watch_folders: &[PathBuf], tauri_dir: &Path, ) -> crate::Result> { - let workspace_path = get_workspace_dir(tauri_dir)?; - // We always want to watch the main tauri folder. let mut watch_folders = vec![tauri_dir.to_path_buf()]; + watch_folders.extend(get_in_workspace_dependency_paths(tauri_dir)?); + // Add the additional watch folders, resolving the path from the tauri path if it is relative watch_folders.extend(additional_watch_folders.iter().filter_map(|dir| { let path = if dir.is_absolute() { @@ -486,30 +476,6 @@ fn get_watch_folders( canonicalized })); - // We also try to watch workspace members, no matter if the tauri cargo project is the workspace root or a workspace member - let cargo_settings = CargoSettings::load(&workspace_path)?; - if let Some(members) = cargo_settings.workspace.and_then(|w| w.members) { - for p in members { - let p = workspace_path.join(p); - match expand_member_path(&p) { - // Sometimes expand_member_path returns an empty vec, for example if the path contains `[]` as in `C:/[abc]/project/`. - // Cargo won't complain unless theres a workspace.members config with glob patterns so we should support it too. - Ok(expanded_paths) => { - if expanded_paths.is_empty() { - watch_folders.push(p); - } else { - watch_folders.extend(expanded_paths); - } - } - Err(err) => { - // If this fails cargo itself should fail too. But we still try to keep going with the unexpanded path. - log::error!("Error watching {}: {}", p.display(), err); - watch_folders.push(p); - } - }; - } - } - Ok(watch_folders) } @@ -526,9 +492,9 @@ impl Rust { fn run_dev, ExitReason) + Send + Sync + 'static>( &mut self, options: Options, - run_args: Vec, + run_args: &[String], on_exit: F, - ) -> crate::Result> { + ) -> crate::Result { desktop::run_dev( options, run_args, @@ -536,26 +502,30 @@ impl Rust { self.config_features.clone(), on_exit, ) - .map(|c| Box::new(c) as Box) } - fn run_dev_watcher crate::Result>>( + fn run_dev_watcher< + F: Fn(&mut Rust, &ConfigMetadata) -> crate::Result>, + >( &mut self, - config: &Mutex, + config: &mut ConfigMetadata, additional_watch_folders: &[PathBuf], merge_configs: &[&serde_json::Value], - run: Arc, + run: F, dirs: &Dirs, ) -> crate::Result<()> { - let child = run(self)?; - - let process = Arc::new(Mutex::new(child)); + let mut child = run(self, config)?; let (tx, rx) = sync_channel(1); let watch_folders = get_watch_folders(additional_watch_folders, dirs.tauri)?; - let common_ancestor = common_path::common_path_all(watch_folders.iter().map(Path::new)) - .expect("watch_folders should not be empty"); + let common_ancestor = common_path::common_path_all( + watch_folders + .iter() + .map(Path::new) + .chain(once(self.app_settings.workspace_dir.as_path())), + ) + .expect("watch_folders should not be empty"); let ignore_matcher = build_ignore_matcher(&common_ancestor); let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| { @@ -593,9 +563,9 @@ impl Rust { if let Some(event_path) = event.paths.first() { if !ignore_matcher.is_ignore(event_path, event_path.is_dir()) { if is_configuration_file(self.app_settings.target_platform, event_path) - && reload_config(&mut config.lock().unwrap(), merge_configs, dirs.tauri).is_ok() + && reload_config(config, merge_configs, dirs.tauri).is_ok() { - let (manifest, modified) = rewrite_manifest(&config.lock().unwrap(), dirs.tauri)?; + let (manifest, modified) = rewrite_manifest(config, dirs.tauri)?; if modified { *self.app_settings.manifest.lock().unwrap() = manifest; // no need to run the watcher logic, the manifest was modified @@ -609,17 +579,12 @@ impl Rust { display_path(event_path.strip_prefix(dirs.frontend).unwrap_or(event_path)) ); - let mut p = process.lock().unwrap(); - p.kill().context("failed to kill app process")?; + child.kill().context("failed to kill app process")?; // wait for the process to exit // note that on mobile, kill() already waits for the process to exit (duct implementation) - loop { - if !matches!(p.try_wait(), Ok(None)) { - break; - } - } - *p = run(self)?; + let _ = child.wait(); + child = run(self, config)?; } } } @@ -690,7 +655,7 @@ pub struct TomlWorkspaceField { #[derive(Clone, Debug, Deserialize)] struct WorkspaceSettings { /// the workspace members. - members: Option>, + // members: Option>, package: Option, } @@ -777,6 +742,7 @@ pub struct RustAppSettings { cargo_config: CargoConfig, target_triple: String, target_platform: TargetPlatform, + workspace_dir: PathBuf, } #[derive(Deserialize)] @@ -1094,7 +1060,8 @@ impl RustAppSettings { } }; - let ws_package_settings = CargoSettings::load(&get_workspace_dir(tauri_dir)?) + let workspace_dir = get_workspace_dir(tauri_dir)?; + let ws_package_settings = CargoSettings::load(&workspace_dir) .context("failed to load Cargo settings from workspace root")? .workspace .and_then(|v| v.package); @@ -1189,6 +1156,7 @@ impl RustAppSettings { cargo_config, target_triple, target_platform, + workspace_dir, }) } @@ -1208,6 +1176,23 @@ impl RustAppSettings { pub(crate) struct CargoMetadata { pub(crate) target_directory: PathBuf, pub(crate) workspace_root: PathBuf, + workspace_members: Vec, + packages: Vec, +} + +#[derive(Deserialize)] +struct Package { + name: String, + id: String, + manifest_path: PathBuf, + dependencies: Vec, +} + +#[derive(Deserialize)] +struct Dependency { + name: String, + /// Local package + path: Option, } pub(crate) fn get_cargo_metadata(tauri_dir: &Path) -> crate::Result { @@ -1230,6 +1215,56 @@ pub(crate) fn get_cargo_metadata(tauri_dir: &Path) -> crate::Result crate::Result> { + let metadata = get_cargo_metadata(tauri_dir)?; + let tauri_project_manifest_path = tauri_dir.join("Cargo.toml"); + let tauri_project_package = metadata + .packages + .iter() + .find(|package| package.manifest_path == tauri_project_manifest_path) + .context("tauri project package doesn't exist in cargo metadata output `packages`")?; + + let workspace_packages = metadata + .workspace_members + .iter() + .map(|member_package_id| { + metadata + .packages + .iter() + .find(|package| package.id == *member_package_id) + .context("workspace member doesn't exist in cargo metadata output `packages`") + }) + .collect::>>()?; + + let mut found_dependency_paths = Vec::new(); + find_dependencies( + tauri_project_package, + &workspace_packages, + &mut found_dependency_paths, + ); + Ok(found_dependency_paths) +} + +fn find_dependencies( + package: &Package, + workspace_packages: &Vec<&Package>, + found_dependency_paths: &mut Vec, +) { + for dependency in &package.dependencies { + if let Some(path) = &dependency.path { + if let Some(package) = workspace_packages.iter().find(|workspace_package| { + workspace_package.name == dependency.name + && path.join("Cargo.toml") == workspace_package.manifest_path + && !found_dependency_paths.contains(path) + }) { + found_dependency_paths.push(path.to_owned()); + find_dependencies(package, workspace_packages, found_dependency_paths); + } + } + } +} + /// Get the cargo target directory based on the provided arguments. /// If "--target-dir" is specified in args, use it as the target directory (relative to current directory). /// Otherwise, use the target directory from cargo metadata. @@ -1339,7 +1374,7 @@ fn tauri_config_to_bundle_settings( if enabled_features.contains(&"tray-icon".into()) || enabled_features.contains(&"tauri/tray-icon".into()) { - let (tray_kind, path) = std::env::var("TAURI_LINUX_AYATANA_APPINDICATOR") + let (tray_kind, path) = std::env::var_os("TAURI_LINUX_AYATANA_APPINDICATOR") .map(|ayatana| { if ayatana == "true" || ayatana == "1" { ( @@ -1361,7 +1396,7 @@ fn tauri_config_to_bundle_settings( ) } }) - .unwrap_or_else(|_| pkgconfig_utils::get_appindicator_library_path()); + .unwrap_or_else(pkgconfig_utils::get_appindicator_library_path); match tray_kind { pkgconfig_utils::TrayKind::Ayatana => { depends_deb.push("libayatana-appindicator3-1".into()); @@ -1452,14 +1487,16 @@ fn tauri_config_to_bundle_settings( .map(tauri_bundler::bundle::Entitlements::Path) } else { let mut app_links_entitlements = plist::Dictionary::new(); - app_links_entitlements.insert( - "com.apple.developer.associated-domains".to_string(), - domains - .into_iter() - .map(|domain| format!("applinks:{domain}").into()) - .collect::>() - .into(), - ); + if !domains.is_empty() { + app_links_entitlements.insert( + "com.apple.developer.associated-domains".to_string(), + domains + .into_iter() + .map(|domain| format!("applinks:{domain}").into()) + .collect::>() + .into(), + ); + } let entitlements = if let Some(user_provided_entitlements) = config.macos.entitlements { crate::helpers::plist::merge_plist(vec![ PathBuf::from(user_provided_entitlements).into(), diff --git a/crates/tauri-cli/src/interface/rust/desktop.rs b/crates/tauri-cli/src/interface/rust/desktop.rs index 15cd503e6..ddde0a4f0 100644 --- a/crates/tauri-cli/src/interface/rust/desktop.rs +++ b/crates/tauri-cli/src/interface/rust/desktop.rs @@ -29,30 +29,26 @@ pub struct DevChild { impl DevProcess for DevChild { fn kill(&self) -> std::io::Result<()> { self.dev_child.kill()?; - self.manually_killed_app.store(true, Ordering::Relaxed); + self.manually_killed_app.store(true, Ordering::SeqCst); Ok(()) } - fn try_wait(&self) -> std::io::Result> { - self.dev_child.try_wait() - } - fn wait(&self) -> std::io::Result { self.dev_child.wait() } fn manually_killed_process(&self) -> bool { - self.manually_killed_app.load(Ordering::Relaxed) + self.manually_killed_app.load(Ordering::SeqCst) } } pub fn run_dev, ExitReason) + Send + Sync + 'static>( options: Options, - run_args: Vec, + run_args: &[String], available_targets: &mut Option>, config_features: Vec, on_exit: F, -) -> crate::Result { +) -> crate::Result { let mut dev_cmd = cargo_command(true, options, available_targets, config_features)?; let runner = dev_cmd.get_program().to_string_lossy().into_owned(); @@ -137,7 +133,7 @@ pub fn run_dev, ExitReason) + Send + Sync + 'static>( status.code(), if status.code() == Some(101) && is_cargo_compile_error { ExitReason::CompilationFailed - } else if manually_killed_app_.load(Ordering::Relaxed) { + } else if manually_killed_app_.load(Ordering::SeqCst) { ExitReason::TriggeredKill } else { ExitReason::NormalExit @@ -163,7 +159,7 @@ pub fn build( let out_dir = app_settings.out_dir(&options, tauri_dir)?; let bin_path = app_settings.app_binary_path(&options, tauri_dir)?; - if !std::env::var("STATIC_VCRUNTIME").is_ok_and(|v| v == "false") { + if !std::env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "false") { std::env::set_var("STATIC_VCRUNTIME", "true"); } diff --git a/crates/tauri-cli/src/interface/rust/manifest.rs b/crates/tauri-cli/src/interface/rust/manifest.rs index 58a5dd6c1..40d307c2b 100644 --- a/crates/tauri-cli/src/interface/rust/manifest.rs +++ b/crates/tauri-cli/src/interface/rust/manifest.rs @@ -351,10 +351,7 @@ mod tests { } else { None }; - if let Some(f) = item_table - .and_then(|t| t.get("features").cloned()) - .and_then(|f| f.as_array().cloned()) - { + if let Some(f) = item_table.and_then(|t| t.get("features")?.as_array().cloned()) { for feature in f.iter() { let feature = feature.as_str().expect("feature is not a string"); if !dep.all_cli_managed_features.contains(&feature) { diff --git a/crates/tauri-cli/src/mobile/android/android_studio_script.rs b/crates/tauri-cli/src/mobile/android/android_studio_script.rs index ce1d6ba8e..321b41041 100644 --- a/crates/tauri-cli/src/mobile/android/android_studio_script.rs +++ b/crates/tauri-cli/src/mobile/android/android_studio_script.rs @@ -6,7 +6,7 @@ use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_option use crate::{ error::{Context, ErrorExt}, helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config}, - interface::{AppInterface, Interface}, + interface::AppInterface, mobile::CliOptions, Error, Result, }; @@ -62,20 +62,17 @@ pub fn command(options: Options) -> Result<()> { )? }; - let (config, metadata) = { - let (config, metadata) = get_config( - &get_app( - MobileTarget::Android, - &tauri_config, - &AppInterface::new(&tauri_config, None, dirs.tauri)?, - dirs.tauri, - ), + let (config, metadata) = get_config( + &get_app( + MobileTarget::Android, &tauri_config, - &[], - &cli_options, - ); - (config, metadata) - }; + &AppInterface::new(&tauri_config, None, dirs.tauri)?, + dirs.tauri, + ), + &tauri_config, + &[], + &cli_options, + ); ensure_init( &tauri_config, diff --git a/crates/tauri-cli/src/mobile/android/build.rs b/crates/tauri-cli/src/mobile/android/build.rs index dee966a1f..8113ace54 100644 --- a/crates/tauri-cli/src/mobile/android/build.rs +++ b/crates/tauri-cli/src/mobile/android/build.rs @@ -14,7 +14,7 @@ use crate::{ config::{get_config as get_tauri_config, ConfigMetadata}, flock, }, - interface::{AppInterface, Interface, Options as InterfaceOptions}, + interface::{AppInterface, Options as InterfaceOptions}, mobile::{android::generate_tauri_properties, write_options, CliOptions, TargetDevice}, ConfigValue, Error, Result, }; @@ -28,7 +28,6 @@ use cargo_mobile2::{ use std::env::set_current_dir; use std::path::Path; -use std::sync::Mutex; #[derive(Debug, Clone, Parser)] #[clap( @@ -65,10 +64,12 @@ pub struct Options { pub split_per_abi: bool, /// Build APKs. #[clap(long)] - pub apk: Option, + pub apk: bool, /// Build AABs. #[clap(long)] - pub aab: Option, + pub aab: bool, + #[clap(skip)] + pub skip_bundle: bool, /// Open Android Studio #[clap(short, long)] pub open: bool, @@ -119,7 +120,7 @@ pub struct BuiltApplication { pub fn command(options: Options, noise_level: NoiseLevel) -> Result { let dirs = crate::helpers::app_paths::resolve_dirs(); - let tauri_config = Mutex::new(get_tauri_config( + let tauri_config = get_tauri_config( tauri_utils::platform::Target::Android, &options .config @@ -127,7 +128,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result>(), dirs.tauri, - )?); + )?; run(options, noise_level, &dirs, &tauri_config) } @@ -135,7 +136,7 @@ pub fn run( options: Options, noise_level: NoiseLevel, dirs: &Dirs, - tauri_config: &Mutex, + tauri_config: &ConfigMetadata, ) -> Result { delete_codegen_vars(); @@ -151,21 +152,17 @@ pub fn run( ) .unwrap(); build_options.target = Some(first_target.triple.into()); - let tauri_config = &tauri_config.lock().unwrap(); - let (interface, config, metadata) = { - let interface = AppInterface::new(tauri_config, build_options.target.clone(), dirs.tauri)?; - interface.build_options(&mut Vec::new(), &mut build_options.features, true); + let interface = AppInterface::new(tauri_config, build_options.target.clone(), dirs.tauri)?; + interface.build_options(&mut Vec::new(), &mut build_options.features, true); - let app = get_app(MobileTarget::Android, tauri_config, &interface, dirs.tauri); - let (config, metadata) = get_config( - &app, - tauri_config, - &build_options.features, - &Default::default(), - ); - (interface, config, metadata) - }; + let app = get_app(MobileTarget::Android, tauri_config, &interface, dirs.tauri); + let (config, metadata) = get_config( + &app, + tauri_config, + &build_options.features, + &Default::default(), + ); let profile = if options.debug { Profile::Debug @@ -188,7 +185,7 @@ pub fn run( generate_tauri_properties(&config, tauri_config, false)?; - crate::build::setup(&interface, &mut build_options, tauri_config, true, dirs)?; + crate::build::setup(&interface, &mut build_options, tauri_config, dirs, true)?; let installed_targets = crate::interface::rust::installation::installed_targets().unwrap_or_default(); @@ -244,10 +241,10 @@ fn run_build( noise_level: NoiseLevel, tauri_dir: &Path, ) -> Result { - if !(options.apk.is_some() || options.aab.is_some()) { + if !(options.skip_bundle || options.apk || options.aab) { // if the user didn't specify the format to build, we'll do both - options.apk = Some(true); - options.aab = Some(true); + options.apk = true; + options.aab = true; } let interface_options = InterfaceOptions { @@ -274,7 +271,7 @@ fn run_build( inject_resources(config, tauri_config)?; - let apk_outputs = if options.apk.unwrap_or_default() { + let apk_outputs = if options.apk { apk::build( config, env, @@ -288,7 +285,7 @@ fn run_build( Vec::new() }; - let aab_outputs = if options.aab.unwrap_or_default() { + let aab_outputs = if options.aab { aab::build( config, env, diff --git a/crates/tauri-cli/src/mobile/android/dev.rs b/crates/tauri-cli/src/mobile/android/dev.rs index bb4624980..7387eb831 100644 --- a/crates/tauri-cli/src/mobile/android/dev.rs +++ b/crates/tauri-cli/src/mobile/android/dev.rs @@ -14,7 +14,7 @@ use crate::{ config::{get_config as get_tauri_config, ConfigMetadata}, flock, }, - interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, + interface::{AppInterface, MobileOptions, Options as InterfaceOptions}, mobile::{ android::generate_tauri_properties, use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, TargetDevice, @@ -35,7 +35,6 @@ use cargo_mobile2::{ }; use url::Host; -use std::sync::Mutex; use std::{env::set_current_dir, net::Ipv4Addr, path::PathBuf}; #[derive(Debug, Clone, Parser)] @@ -184,18 +183,15 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result< .unwrap_or_else(|| Target::all().values().next().unwrap().triple.into()); dev_options.target = Some(target_triple); - let (interface, config, metadata) = { - let interface = AppInterface::new(&tauri_config, dev_options.target.clone(), dirs.tauri)?; + let interface = AppInterface::new(&tauri_config, dev_options.target.clone(), dirs.tauri)?; - let app = get_app(MobileTarget::Android, &tauri_config, &interface, dirs.tauri); - let (config, metadata) = get_config( - &app, - &tauri_config, - dev_options.features.as_ref(), - &Default::default(), - ); - (interface, config, metadata) - }; + let app = get_app(MobileTarget::Android, &tauri_config, &interface, dirs.tauri); + let (config, metadata) = get_config( + &app, + &tauri_config, + dev_options.features.as_ref(), + &Default::default(), + ); set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?; @@ -256,8 +252,6 @@ fn run_dev( crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, dirs)?; - let tauri_config = Mutex::new(tauri_config); - let interface_options = InterfaceOptions { debug: !dev_options.release_mode, target: dev_options.target.clone(), @@ -270,7 +264,7 @@ fn run_dev( configure_cargo(&mut env, config)?; - generate_tauri_properties(config, &tauri_config.lock().unwrap(), true)?; + generate_tauri_properties(config, &tauri_config, true)?; let installed_targets = crate::interface::rust::installation::installed_targets().unwrap_or_default(); @@ -306,7 +300,7 @@ fn run_dev( let open = options.open; interface.mobile_dev( - &tauri_config, + &mut tauri_config, MobileOptions { debug: !options.release_mode, features: options.features, @@ -315,7 +309,7 @@ fn run_dev( no_watch: options.no_watch, additional_watch_folders: options.additional_watch_folders, }, - |options| { + |options, tauri_config| { let cli_options = CliOptions { dev: true, features: options.features.clone(), @@ -329,9 +323,9 @@ fn run_dev( }), }; - let _handle = write_options(&tauri_config.lock().unwrap(), cli_options)?; + let _handle = write_options(tauri_config, cli_options)?; - inject_resources(config, &tauri_config.lock().unwrap())?; + inject_resources(config, tauri_config)?; if open { open_and_wait(config, &env) diff --git a/crates/tauri-cli/src/mobile/android/mod.rs b/crates/tauri-cli/src/mobile/android/mod.rs index 002ed73ac..8ea6490d0 100644 --- a/crates/tauri-cli/src/mobile/android/mod.rs +++ b/crates/tauri-cli/src/mobile/android/mod.rs @@ -104,7 +104,6 @@ enum Commands { } pub fn command(cli: Cli, verbosity: u8) -> Result<()> { - let dirs = crate::helpers::app_paths::resolve_dirs(); let noise_level = NoiseLevel::from_occurrences(verbosity as u64); match cli.command { Commands::Init(options) => init_command( @@ -113,7 +112,6 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> { false, options.skip_targets_install, options.config, - &dirs, )?, Commands::Dev(options) => dev::command(options, noise_level)?, Commands::Build(options) => build::command(options, noise_level).map(|_| ())?, diff --git a/crates/tauri-cli/src/mobile/android/run.rs b/crates/tauri-cli/src/mobile/android/run.rs index 986990ac3..c77596b03 100644 --- a/crates/tauri-cli/src/mobile/android/run.rs +++ b/crates/tauri-cli/src/mobile/android/run.rs @@ -9,12 +9,12 @@ use cargo_mobile2::{ }; use clap::{ArgAction, Parser}; use std::path::PathBuf; -use std::sync::Mutex; use super::{configure_cargo, device_prompt, env}; use crate::{ error::Context, - interface::{DevProcess, Interface, WatcherOptions}, + helpers::config::ConfigMetadata, + interface::{DevProcess, WatcherOptions}, mobile::{DevChild, TargetDevice}, ConfigValue, Result, }; @@ -79,7 +79,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }; let dirs = crate::helpers::app_paths::resolve_dirs(); - let cfg = crate::helpers::config::get_config( + let mut tauri_config = crate::helpers::config::get_config( tauri_utils::platform::Target::Android, &options .config @@ -88,7 +88,6 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { .collect::>(), dirs.tauri, )?; - let tauri_config = Mutex::new(cfg); let mut built_application = super::build::run( super::build::Options { debug: !options.release, @@ -102,8 +101,9 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { features: options.features, config: options.config.clone(), split_per_abi: true, - apk: Some(false), - aab: Some(false), + apk: false, + aab: false, + skip_bundle: false, open: options.open, ci: false, args: options.args, @@ -125,7 +125,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { if let Some(device) = device { let config = built_application.config.clone(); let release = options.release; - let runner = move || { + let runner = move |_tauri_config: &ConfigMetadata| { device .run( &config, @@ -150,10 +150,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }; if options.no_watch { - runner()?; + runner(&tauri_config)?; } else { built_application.interface.watch( - &tauri_config, + &mut tauri_config, WatcherOptions { config: options.config, additional_watch_folders: options.additional_watch_folders, diff --git a/crates/tauri-cli/src/mobile/init.rs b/crates/tauri-cli/src/mobile/init.rs index 0a7324970..7ace53b51 100644 --- a/crates/tauri-cli/src/mobile/init.rs +++ b/crates/tauri-cli/src/mobile/init.rs @@ -6,7 +6,7 @@ use super::{get_app, Target}; use crate::{ helpers::app_paths::Dirs, helpers::{config::get_config as get_tauri_config, template::JsonMap}, - interface::{AppInterface, Interface}, + interface::AppInterface, ConfigValue, Result, }; use cargo_mobile2::{ @@ -29,8 +29,8 @@ pub fn command( reinstall_deps: bool, skip_targets_install: bool, config: Vec, - dirs: &Dirs, ) -> Result<()> { + let dirs = crate::helpers::app_paths::resolve_dirs(); let wrapper = TextWrapper::default(); exec( @@ -45,14 +45,14 @@ pub fn command( Ok(()) } -pub fn exec( +fn exec( target: Target, wrapper: &TextWrapper, #[allow(unused_variables)] non_interactive: bool, #[allow(unused_variables)] reinstall_deps: bool, skip_targets_install: bool, config: Vec, - dirs: &Dirs, + dirs: Dirs, ) -> Result { let tauri_config = get_tauri_config( target.platform_target(), diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index dba74df4e..7e75ca462 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -16,7 +16,7 @@ use crate::{ flock, plist::merge_plist, }, - interface::{AppInterface, Interface, Options as InterfaceOptions}, + interface::{AppInterface, Options as InterfaceOptions}, mobile::{ios::ensure_ios_runtime_installed, write_options, CliOptions, TargetDevice}, ConfigValue, Error, Result, }; @@ -167,7 +167,12 @@ pub struct BuiltApplication { options_handle: OptionsHandle, } -pub fn command(options: Options, noise_level: NoiseLevel, dirs: &Dirs) -> Result { +pub fn command(options: Options, noise_level: NoiseLevel) -> Result { + let dirs = crate::helpers::app_paths::resolve_dirs(); + run(options, noise_level, &dirs) +} + +pub fn run(options: Options, noise_level: NoiseLevel, dirs: &Dirs) -> Result { let mut build_options: BuildOptions = options.clone().into(); build_options.target = Some( Target::all() @@ -189,20 +194,17 @@ pub fn command(options: Options, noise_level: NoiseLevel, dirs: &Dirs) -> Result &options.config.iter().map(|c| &c.0).collect::>(), dirs.tauri, )?; - let (interface, mut config) = { - let interface = AppInterface::new(&tauri_config, build_options.target.clone(), dirs.tauri)?; - interface.build_options(&mut Vec::new(), &mut build_options.features, true); + let interface = AppInterface::new(&tauri_config, build_options.target.clone(), dirs.tauri)?; + interface.build_options(&mut Vec::new(), &mut build_options.features, true); - let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); - let (config, _metadata) = get_config( - &app, - &tauri_config, - &build_options.features, - &Default::default(), - dirs.tauri, - )?; - (interface, config) - }; + let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); + let (mut config, _) = get_config( + &app, + &tauri_config, + &build_options.features, + &Default::default(), + dirs.tauri, + )?; set_current_dir(dirs.tauri).context("failed to set current directory")?; @@ -357,7 +359,7 @@ fn run_build( Profile::Release }; - crate::build::setup(interface, &mut build_options, &tauri_config, true, dirs)?; + crate::build::setup(interface, &mut build_options, &tauri_config, dirs, true)?; let app_settings = interface.app_settings(); let out_dir = app_settings.out_dir( diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index 6d9c8a697..0ef7fc083 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -15,7 +15,7 @@ use crate::{ flock, plist::merge_plist, }, - interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, + interface::{AppInterface, MobileOptions, Options as InterfaceOptions}, mobile::{ ios::ensure_ios_runtime_installed, use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, @@ -35,7 +35,6 @@ use cargo_mobile2::{ }; use url::Host; -use std::sync::Mutex; use std::{env::set_current_dir, net::Ipv4Addr, path::PathBuf}; const PHYSICAL_IPHONE_DEV_WARNING: &str = "To develop on physical phones you need the `--host` option (not required for Simulators). See the documentation for more information: https://v2.tauri.app/develop/#development-server"; @@ -189,20 +188,16 @@ fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result< &options.config.iter().map(|c| &c.0).collect::>(), dirs.tauri, )?; - let (interface, config) = { - let interface = AppInterface::new(&tauri_config, Some(target_triple), dirs.tauri)?; + let interface = AppInterface::new(&tauri_config, Some(target_triple), dirs.tauri)?; - let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); - let (config, _metadata) = get_config( - &app, - &tauri_config, - &dev_options.features, - &Default::default(), - dirs.tauri, - )?; - - (interface, config) - }; + let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); + let (config, _) = get_config( + &app, + &tauri_config, + &dev_options.features, + &Default::default(), + dirs.tauri, + )?; set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?; @@ -304,8 +299,6 @@ fn run_dev( crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, &dirs)?; - let tauri_config = Mutex::new(tauri_config); - let app_settings = interface.app_settings(); let out_dir = app_settings.out_dir( &InterfaceOptions { @@ -321,7 +314,7 @@ fn run_dev( let open = options.open; interface.mobile_dev( - &tauri_config, + &mut tauri_config, MobileOptions { debug: true, features: options.features, @@ -330,7 +323,7 @@ fn run_dev( no_watch: options.no_watch, additional_watch_folders: options.additional_watch_folders, }, - |options| { + |options, tauri_config| { let cli_options = CliOptions { dev: true, features: options.features.clone(), @@ -340,7 +333,7 @@ fn run_dev( config: dev_options.config.clone(), target_device: None, }; - let _handle = write_options(&tauri_config.lock().unwrap(), cli_options)?; + let _handle = write_options(tauri_config, cli_options)?; let open_xcode = || { if !set_host { diff --git a/crates/tauri-cli/src/mobile/ios/mod.rs b/crates/tauri-cli/src/mobile/ios/mod.rs index 0590e772a..6c0e0af87 100644 --- a/crates/tauri-cli/src/mobile/ios/mod.rs +++ b/crates/tauri-cli/src/mobile/ios/mod.rs @@ -102,7 +102,6 @@ enum Commands { pub fn command(cli: Cli, verbosity: u8) -> Result<()> { let noise_level = NoiseLevel::from_occurrences(verbosity as u64); - let dirs = crate::helpers::app_paths::resolve_dirs(); match cli.command { Commands::Init(options) => init_command( MobileTarget::Ios, @@ -110,10 +109,9 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> { options.reinstall_deps, options.skip_targets_install, options.config, - &dirs, )?, Commands::Dev(options) => dev::command(options, noise_level)?, - Commands::Build(options) => build::command(options, noise_level, &dirs).map(|_| ())?, + Commands::Build(options) => build::command(options, noise_level).map(|_| ())?, Commands::Run(options) => run::command(options, noise_level)?, Commands::XcodeScript(options) => xcode_script::command(options)?, } diff --git a/crates/tauri-cli/src/mobile/ios/run.rs b/crates/tauri-cli/src/mobile/ios/run.rs index 7d18cdb60..61e696ef9 100644 --- a/crates/tauri-cli/src/mobile/ios/run.rs +++ b/crates/tauri-cli/src/mobile/ios/run.rs @@ -3,7 +3,6 @@ // SPDX-License-Identifier: MIT use std::path::PathBuf; -use std::sync::Mutex; use cargo_mobile2::opts::{NoiseLevel, Profile}; use clap::{ArgAction, Parser}; @@ -11,8 +10,8 @@ use clap::{ArgAction, Parser}; use super::{device_prompt, env}; use crate::{ error::Context, - helpers::config::get_config as get_tauri_config, - interface::{DevProcess, Interface, WatcherOptions}, + helpers::config::{get_config as get_tauri_config, ConfigMetadata}, + interface::{DevProcess, WatcherOptions}, mobile::{DevChild, TargetDevice}, ConfigValue, Result, }; @@ -77,7 +76,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { let dirs = crate::helpers::app_paths::resolve_dirs(); - let mut built_application = super::build::command( + let mut built_application = super::build::run( super::build::Options { debug: !options.release, targets: Some(vec![]), /* skips IPA build since there's no target */ @@ -98,17 +97,16 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { &dirs, )?; - let cfg = get_tauri_config( + let mut tauri_config = get_tauri_config( tauri_utils::platform::Target::Ios, &options.config.iter().map(|c| &c.0).collect::>(), dirs.tauri, )?; - let tauri_config = Mutex::new(cfg); // options.open is handled by the build command // so all we need to do here is run the app on the selected device if let Some(device) = device { - let runner = move || { + let runner = move |_tauri_config: &ConfigMetadata| { device .run( &built_application.config, @@ -126,10 +124,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }; if options.no_watch { - runner()?; + runner(&tauri_config)?; } else { built_application.interface.watch( - &tauri_config, + &mut tauri_config, WatcherOptions { config: options.config, additional_watch_folders: options.additional_watch_folders, diff --git a/crates/tauri-cli/src/mobile/ios/xcode_script.rs b/crates/tauri-cli/src/mobile/ios/xcode_script.rs index 0b30ba2f4..05b182d7c 100644 --- a/crates/tauri-cli/src/mobile/ios/xcode_script.rs +++ b/crates/tauri-cli/src/mobile/ios/xcode_script.rs @@ -6,7 +6,7 @@ use super::{ensure_init, env, get_app, get_config, read_options, MobileTarget}; use crate::{ error::{Context, ErrorExt}, helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config}, - interface::{AppInterface, Interface, Options as InterfaceOptions}, + interface::{AppInterface, Options as InterfaceOptions}, mobile::ios::LIB_OUTPUT_FILE_NAME, Error, Result, }; @@ -95,40 +95,33 @@ pub fn command(options: Options) -> Result<()> { let macos = macos_from_platform(&options.platform); let mut tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[], dirs.tauri)?; - let cli_options = { - let cli_options = { read_options(&tauri_config) }; - if !cli_options.config.is_empty() { - // reload config with merges from the ios dev|build script - reload_tauri_config( - &mut tauri_config, - &cli_options - .config - .iter() - .map(|conf| &conf.0) - .collect::>(), - dirs.tauri, - )? - }; - - cli_options - }; - - let (config, metadata) = { - let cli_options = read_options(&tauri_config); - let (config, metadata) = get_config( - &get_app( - MobileTarget::Ios, - &tauri_config, - &AppInterface::new(&tauri_config, None, dirs.tauri)?, - dirs.tauri, - ), - &tauri_config, - &[], - &cli_options, + let cli_options = read_options(&tauri_config); + if !cli_options.config.is_empty() { + // reload config with merges from the ios dev|build script + reload_tauri_config( + &mut tauri_config, + &cli_options + .config + .iter() + .map(|conf| &conf.0) + .collect::>(), dirs.tauri, - )?; - (config, metadata) + )? }; + + let (config, metadata) = get_config( + &get_app( + MobileTarget::Ios, + &tauri_config, + &AppInterface::new(&tauri_config, None, dirs.tauri)?, + dirs.tauri, + ), + &tauri_config, + &[], + &cli_options, + dirs.tauri, + )?; + ensure_init( &tauri_config, config.app(), diff --git a/crates/tauri-cli/src/mobile/mod.rs b/crates/tauri-cli/src/mobile/mod.rs index 6b06e0cac..f7ab30357 100644 --- a/crates/tauri-cli/src/mobile/mod.rs +++ b/crates/tauri-cli/src/mobile/mod.rs @@ -5,7 +5,7 @@ use crate::{ error::{Context, ErrorExt}, helpers::config::{reload_config, Config as TauriConfig, ConfigMetadata}, - interface::{AppInterface, AppSettings, DevProcess, Interface, Options as InterfaceOptions}, + interface::{AppInterface, AppSettings, DevProcess, Options as InterfaceOptions}, ConfigValue, Error, Result, }; use heck::ToSnekCase; @@ -67,18 +67,9 @@ impl DevChild { impl DevProcess for DevChild { fn kill(&self) -> std::io::Result<()> { - self.manually_killed_process.store(true, Ordering::Relaxed); - match self.child.kill() { - Ok(_) => Ok(()), - Err(e) => { - self.manually_killed_process.store(false, Ordering::Relaxed); - Err(e) - } - } - } - - fn try_wait(&self) -> std::io::Result> { - self.child.try_wait().map(|res| res.map(|o| o.status)) + self.child.kill()?; + self.manually_killed_process.store(true, Ordering::SeqCst); + Ok(()) } fn wait(&self) -> std::io::Result { @@ -86,7 +77,7 @@ impl DevProcess for DevChild { } fn manually_killed_process(&self) -> bool { - self.manually_killed_process.load(Ordering::Relaxed) + self.manually_killed_process.load(Ordering::SeqCst) } } diff --git a/crates/tauri-schema-worker/package.json b/crates/tauri-schema-worker/package.json index 9b357db3f..d932ee878 100644 --- a/crates/tauri-schema-worker/package.json +++ b/crates/tauri-schema-worker/package.json @@ -8,6 +8,6 @@ "dev": "wrangler dev" }, "devDependencies": { - "wrangler": "^4.20.3" + "wrangler": "^4.59.1" } } diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index 56bfd277f..a16bc188c 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -3176,18 +3176,20 @@ impl<'d> serde::Deserialize<'d> for PackageVersion { })?; Ok(PackageVersion( Version::from_str(version) - .map_err(|_| DeError::custom("`package > version` must be a semver string"))? + .map_err(|_| { + DeError::custom("`tauri.conf.json > version` must be a semver string") + })? .to_string(), )) } else { Err(DeError::custom( - "`package > version` value is not a path to a JSON object", + "`tauri.conf.json > version` value is not a path to a JSON object", )) } } else { Ok(PackageVersion( Version::from_str(value) - .map_err(|_| DeError::custom("`package > version` must be a semver string"))? + .map_err(|_| DeError::custom("`tauri.conf.json > version` must be a semver string"))? .to_string(), )) } diff --git a/crates/tauri-utils/src/platform.rs b/crates/tauri-utils/src/platform.rs index 2ace45790..6eaaf3ffe 100644 --- a/crates/tauri-utils/src/platform.rs +++ b/crates/tauri-utils/src/platform.rs @@ -344,23 +344,20 @@ fn resource_dir_from>( // Variable holding the type of bundle the executable is stored in. This is modified by binary // patching during build #[used] -#[no_mangle] -#[cfg_attr(not(target_vendor = "apple"), link_section = ".taubndl")] -#[cfg_attr(target_vendor = "apple", link_section = "__DATA,taubndl")] // Marked as `mut` because it could get optimized away without it, // see https://github.com/tauri-apps/tauri/pull/13812 -static mut __TAURI_BUNDLE_TYPE: &str = "UNK"; +static mut __TAURI_BUNDLE_TYPE: &str = "__TAURI_BUNDLE_TYPE_VAR_UNK"; /// Get the type of the bundle current binary is packaged in. /// If the bundle type is unknown, it returns [`Option::None`]. pub fn bundle_type() -> Option { unsafe { match __TAURI_BUNDLE_TYPE { - "DEB" => Some(BundleType::Deb), - "RPM" => Some(BundleType::Rpm), - "APP" => Some(BundleType::AppImage), - "MSI" => Some(BundleType::Msi), - "NSS" => Some(BundleType::Nsis), + "__TAURI_BUNDLE_TYPE_VAR_DEB" => Some(BundleType::Deb), + "__TAURI_BUNDLE_TYPE_VAR_RPM" => Some(BundleType::Rpm), + "__TAURI_BUNDLE_TYPE_VAR_APP" => Some(BundleType::AppImage), + "__TAURI_BUNDLE_TYPE_VAR_MSI" => Some(BundleType::Msi), + "__TAURI_BUNDLE_TYPE_VAR_NSS" => Some(BundleType::Nsis), _ => { if cfg!(target_os = "macos") { Some(BundleType::App) diff --git a/crates/tauri/src/ipc/channel.rs b/crates/tauri/src/ipc/channel.rs index c33caf2a2..0b3eb6778 100644 --- a/crates/tauri/src/ipc/channel.rs +++ b/crates/tauri/src/ipc/channel.rs @@ -54,9 +54,9 @@ pub struct Channel { #[cfg(feature = "specta")] const _: () = { #[derive(specta::Type)] - #[specta(remote = super::Channel, rename = "TAURI_CHANNEL")] - #[allow(dead_code)] - struct Channel(std::marker::PhantomData); + #[specta(remote = super::Channel)] + #[allow(dead_code, non_camel_case_types)] + struct TAURI_CHANNEL(std::marker::PhantomData); }; impl Clone for Channel { diff --git a/crates/tauri/src/protocol/asset.rs b/crates/tauri/src/protocol/asset.rs index a5007d294..e7c713324 100644 --- a/crates/tauri/src/protocol/asset.rs +++ b/crates/tauri/src/protocol/asset.rs @@ -48,9 +48,29 @@ fn get_response( return resp.status(403).body(Vec::new().into()).map_err(Into::into); } - let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move { - let mut file = File::open(&path).await?; + // Separate block for easier error handling + let mut file = match crate::async_runtime::safe_block_on(File::open(path.clone())) { + Ok(file) => file, + Err(e) => { + #[cfg(target_os = "android")] + { + if path.starts_with("/storage/emulated/0/Android/data/") { + log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions.", path, e); + } + } + return if e.kind() == std::io::ErrorKind::NotFound { + log::error!("File does not exist at path: {}", path); + return resp.status(404).body(Vec::new().into()).map_err(Into::into); + } else if e.kind() == std::io::ErrorKind::PermissionDenied { + log::error!("Missing OS permission to access path \"{}\": {}", path, e); + return resp.status(403).body(Vec::new().into()).map_err(Into::into); + } else { + Err(e.into()) + }; + } + }; + let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move { // get file length let len = { let old_pos = file.stream_position().await?; diff --git a/crates/tauri/src/test/mod.rs b/crates/tauri/src/test/mod.rs index 6c1311bc3..9161f0979 100644 --- a/crates/tauri/src/test/mod.rs +++ b/crates/tauri/src/test/mod.rs @@ -243,6 +243,7 @@ pub fn assert_ipc_response< ); } +#[allow(clippy::needless_doctest_main)] /// Executes the given IPC message and get the return value. /// /// # Examples diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index 4df09182a..8842382bf 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -2312,4 +2312,25 @@ mod tests { crate::test_utils::assert_send::(); crate::test_utils::assert_sync::(); } + + #[cfg(target_os = "macos")] + #[test] + fn test_webview_window_has_set_simple_fullscreen_method() { + use crate::test::{mock_builder, mock_context, noop_assets}; + + // Create a mock app with proper context + let app = mock_builder().build(mock_context(noop_assets())).unwrap(); + + // Get or create a webview window + let webview_window = + crate::WebviewWindowBuilder::new(&app, "test", crate::WebviewUrl::default()) + .build() + .unwrap(); + + // This should compile if set_simple_fullscreen exists + let result = webview_window.set_simple_fullscreen(true); + + // We expect this to work without panicking + assert!(result.is_ok(), "set_simple_fullscreen should succeed"); + } } diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index 92b033b06..290730067 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -2057,6 +2057,20 @@ impl WebviewWindow { self.window.set_fullscreen(fullscreen) } + /// Toggles a fullscreen mode that doesn't require a new macOS space. + /// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen). + /// + /// This is how fullscreen used to work on macOS in versions before Lion. + /// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor. + /// + /// ## Platform-specific + /// + /// - **macOS:** Uses native simple fullscreen mode. + /// - **Other platforms:** Falls back to [`Self::set_fullscreen`]. + pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> { + self.window.set_simple_fullscreen(enable) + } + /// Bring the window to front and focus. pub fn set_focus(&self) -> crate::Result<()> { self.window.set_focus() diff --git a/crates/tauri/src/window/mod.rs b/crates/tauri/src/window/mod.rs index a67784cc3..47c95628b 100644 --- a/crates/tauri/src/window/mod.rs +++ b/crates/tauri/src/window/mod.rs @@ -1968,25 +1968,27 @@ tauri::Builder::default() .map_err(Into::into) } - /// Toggles a fullscreen mode that doesn’t require a new macOS space. Returns a boolean indicating whether the transition was successful (this won’t work if the window was already in the native fullscreen). + /// Toggles a fullscreen mode that doesn't require a new macOS space. + /// Returns a boolean indicating whether the transition was successful (this won't work if the window was already in the native fullscreen). /// - /// This is how fullscreen used to work on macOS in versions before Lion. And allows the user to have a fullscreen window without using another space or taking control over the entire monitor. - #[cfg(target_os = "macos")] + /// This is how fullscreen used to work on macOS in versions before Lion. + /// And allows the user to have a fullscreen window without using another space or taking control over the entire monitor. + /// + /// ## Platform-specific + /// + /// - **macOS:** Uses native simple fullscreen mode. + /// - **Other platforms:** Falls back to [`Self::set_fullscreen`]. pub fn set_simple_fullscreen(&self, enable: bool) -> crate::Result<()> { - self - .window - .dispatcher - .set_simple_fullscreen(enable) - .map_err(Into::into) - } - - /// On macOS, Toggles a fullscreen mode that doesn’t require a new macOS space. Returns a boolean indicating whether the transition was successful (this won’t work if the window was already in the native fullscreen). - /// This is how fullscreen used to work on macOS in versions before Lion. And allows the user to have a fullscreen window without using another space or taking control over the entire monitor. - /// - /// On other platforms, this is the same as [`Window#method.set_fullscreen`]. - #[cfg(not(target_os = "macos"))] - pub fn set_simple_fullscreen(&self, fullscreen: bool) -> crate::Result<()> { - self.set_fullscreen(fullscreen) + #[cfg(target_os = "macos")] + { + self + .window + .dispatcher + .set_simple_fullscreen(enable) + .map_err(Into::into) + } + #[cfg(not(target_os = "macos"))] + self.set_fullscreen(enable) } /// Bring the window to front and focus. diff --git a/packages/api/package.json b/packages/api/package.json index 6a08a7dd3..7c6899d72 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -55,7 +55,7 @@ "eslint-plugin-security": "3.0.1", "fast-glob": "3.3.3", "globals": "^17.0.0", - "rollup": "4.55.1", + "rollup": "4.55.2", "tslib": "^2.8.1", "typescript": "^5.8.3", "typescript-eslint": "^8.34.1" diff --git a/packages/cli/tauri.js b/packages/cli/tauri.js index d0460573b..452202cbb 100644 --- a/packages/cli/tauri.js +++ b/packages/cli/tauri.js @@ -20,7 +20,7 @@ if (globalThis.navigator?.userAgent?.includes('Deno')) { } // Even if started by a package manager, the binary will be NodeJS. // Some distribution still use "nodejs" as the binary name. -else if (binStem.match(/(nodejs|node|bun)\-?([0-9]*)*$/g)) { +else if (binStem.match(/(nodejs|node|bun|electron)\-?([0-9]*)*$/g)) { const managerStem = process.env.npm_execpath ? path.parse(process.env.npm_execpath).name.toLowerCase() : null diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0acf16256..b99d7cc26 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: crates/tauri-schema-worker: devDependencies: wrangler: - specifier: ^4.20.3 - version: 4.20.3 + specifier: ^4.59.1 + version: 4.59.1 examples/api: dependencies: @@ -63,10 +63,10 @@ importers: version: 9.29.0 '@rollup/plugin-terser': specifier: 0.4.4 - version: 0.4.4(rollup@4.55.1) + version: 0.4.4(rollup@4.55.2) '@rollup/plugin-typescript': specifier: 12.3.0 - version: 12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.8.3) + version: 12.3.0(rollup@4.55.2)(tslib@2.8.1)(typescript@5.8.3) '@types/eslint': specifier: ^9.6.1 version: 9.6.1 @@ -89,8 +89,8 @@ importers: specifier: ^17.0.0 version: 17.0.0 rollup: - specifier: 4.55.1 - version: 4.55.1 + specifier: 4.55.2 + version: 4.55.2 tslib: specifier: ^2.8.1 version: 2.8.1 @@ -105,7 +105,7 @@ importers: devDependencies: '@napi-rs/cli': specifier: ^3.4.1 - version: 3.4.1(@emnapi/runtime@1.7.1)(@types/node@24.10.0) + version: 3.4.1(@emnapi/runtime@1.8.1)(@types/node@24.10.0) '@types/node': specifier: ^24.0.0 version: 24.10.0 @@ -136,54 +136,54 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} - '@cloudflare/kv-asset-handler@0.4.0': - resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} + '@cloudflare/kv-asset-handler@0.4.1': + resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==} engines: {node: '>=18.0.0'} - '@cloudflare/unenv-preset@2.3.3': - resolution: {integrity: sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A==} + '@cloudflare/unenv-preset@2.9.0': + resolution: {integrity: sha512-99nEvuOTCGGGRNaIat8UVVXJ27aZK+U09SYDp0kVjQLwC9wyxcrQ28IqLwrQq2DjWLmBI1+UalGJzdPqYgPlRw==} peerDependencies: - unenv: 2.0.0-rc.17 - workerd: ^1.20250508.0 + unenv: 2.0.0-rc.24 + workerd: ^1.20251202.0 peerDependenciesMeta: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20250617.0': - resolution: {integrity: sha512-toG8JUKVLIks4oOJLe9FeuixE84pDpMZ32ip7mCpE7JaFc5BqGFvevk0YC/db3T71AQlialjRwioH3jS/dzItA==} + '@cloudflare/workerd-darwin-64@1.20260111.0': + resolution: {integrity: sha512-UGAjrGLev2/CMLZy7b+v1NIXA4Hupc/QJBFlJwMqldywMcJ/iEqvuUYYuVI2wZXuXeWkgmgFP87oFDQsg78YTQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20250617.0': - resolution: {integrity: sha512-JTX0exbC9/ZtMmQQA8tDZEZFMXZrxOpTUj2hHnsUkErWYkr5SSZH04RBhPg6dU4VL8bXuB5/eJAh7+P9cZAp7g==} + '@cloudflare/workerd-darwin-arm64@1.20260111.0': + resolution: {integrity: sha512-YFAZwidLCQVa6rKCCaiWrhA+eh87a7MUhyd9lat3KSbLBAGpYM+ORpyTXpi2Gjm3j6Mp1e/wtzcFTSeMIy2UqA==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20250617.0': - resolution: {integrity: sha512-8jkSoVRJ+1bOx3tuWlZCGaGCV2ew7/jFMl6V3CPXOoEtERUHsZBQLVkQIGKcmC/LKSj7f/mpyBUeu2EPTo2HEg==} + '@cloudflare/workerd-linux-64@1.20260111.0': + resolution: {integrity: sha512-zx1GW6FwfOBjCV7QUCRzGRkViUtn3Is/zaaVPmm57xyy9sjtInx6/SdeBr2Y45tx9AnOP1CnaOFFdmH1P7VIEg==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20250617.0': - resolution: {integrity: sha512-YAzcOyu897z5dQKFzme1oujGWMGEJCR7/Wrrm1nSP6dqutxFPTubRADM8BHn2CV3ij//vaPnAeLmZE3jVwOwig==} + '@cloudflare/workerd-linux-arm64@1.20260111.0': + resolution: {integrity: sha512-wFVKxNvCyjRaAcgiSnJNJAmIos3p3Vv6Uhf4pFUZ9JIxr69GNlLWlm9SdCPvtwNFAjzSoDaKzDwjj5xqpuCS6Q==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20250617.0': - resolution: {integrity: sha512-XWM/6sagDrO0CYDKhXhPjM23qusvIN1ju9ZEml6gOQs8tNOFnq6Cn6X9FAmnyapRFCGUSEC3HZYJAm7zwVKaMA==} + '@cloudflare/workerd-windows-64@1.20260111.0': + resolution: {integrity: sha512-zWgd77L7OI1BxgBbG+2gybDahIMgPX5iNo6e3LqcEz1Xm3KfiqgnDyMBcxeQ7xDrj7fHUGAlc//QnKvDchuUoQ==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -195,8 +195,8 @@ packages: '@emnapi/core@1.7.1': resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} @@ -210,150 +210,306 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.0': + resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.4': resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.0': + resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.4': resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.0': + resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.4': resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.0': + resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.4': resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.0': + resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.4': resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.0': + resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.4': resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.0': + resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.4': resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.0': + resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.4': resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.0': + resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.4': resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.0': + resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.4': resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.0': + resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.4': resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.0': + resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.4': resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.0': + resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.4': resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.0': + resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.4': resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.0': + resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.4': resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.0': + resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.4': resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.0': + resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.4': resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.0': + resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.4': resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.0': + resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.4': resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.0': + resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.4': resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.0': + resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.0': + resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.4': resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.0': + resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.4': resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.0': + resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.4': resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.0': + resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.4': resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.0': + resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.7.0': resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -396,10 +552,6 @@ packages: resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -432,107 +584,139 @@ packages: '@iconify/utils@2.3.0': resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1090,6 +1274,15 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + '@quansync/fs@0.1.3': resolution: {integrity: sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==} engines: {node: '>=20.0.0'} @@ -1125,131 +1318,138 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.55.1': - resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + '@rollup/rollup-android-arm-eabi@4.55.2': + resolution: {integrity: sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.55.1': - resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + '@rollup/rollup-android-arm64@4.55.2': + resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.55.1': - resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + '@rollup/rollup-darwin-arm64@4.55.2': + resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.55.1': - resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + '@rollup/rollup-darwin-x64@4.55.2': + resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.55.1': - resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + '@rollup/rollup-freebsd-arm64@4.55.2': + resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.55.1': - resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + '@rollup/rollup-freebsd-x64@4.55.2': + resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': - resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.55.2': + resolution: {integrity: sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.55.1': - resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + '@rollup/rollup-linux-arm-musleabihf@4.55.2': + resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.55.1': - resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + '@rollup/rollup-linux-arm64-gnu@4.55.2': + resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.55.1': - resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + '@rollup/rollup-linux-arm64-musl@4.55.2': + resolution: {integrity: sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.55.1': - resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + '@rollup/rollup-linux-loong64-gnu@4.55.2': + resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.55.1': - resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + '@rollup/rollup-linux-loong64-musl@4.55.2': + resolution: {integrity: sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.55.1': - resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + '@rollup/rollup-linux-ppc64-gnu@4.55.2': + resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.55.1': - resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + '@rollup/rollup-linux-ppc64-musl@4.55.2': + resolution: {integrity: sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.55.1': - resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + '@rollup/rollup-linux-riscv64-gnu@4.55.2': + resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.55.1': - resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + '@rollup/rollup-linux-riscv64-musl@4.55.2': + resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.55.1': - resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + '@rollup/rollup-linux-s390x-gnu@4.55.2': + resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.55.1': - resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + '@rollup/rollup-linux-x64-gnu@4.55.2': + resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.55.1': - resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + '@rollup/rollup-linux-x64-musl@4.55.2': + resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==} cpu: [x64] os: [linux] - '@rollup/rollup-openbsd-x64@4.55.1': - resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + '@rollup/rollup-openbsd-x64@4.55.2': + resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.55.1': - resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + '@rollup/rollup-openharmony-arm64@4.55.2': + resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.55.1': - resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + '@rollup/rollup-win32-arm64-msvc@4.55.2': + resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.55.1': - resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + '@rollup/rollup-win32-ia32-msvc@4.55.2': + resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.55.1': - resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + '@rollup/rollup-win32-x64-gnu@4.55.2': + resolution: {integrity: sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.55.1': - resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + '@rollup/rollup-win32-x64-msvc@4.55.2': + resolution: {integrity: sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==} cpu: [x64] os: [win32] + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.14': + resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -1541,9 +1741,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - as-table@1.0.55: - resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1616,13 +1813,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1639,9 +1829,9 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} cross-env@10.1.0: resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} @@ -1659,9 +1849,6 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - data-uri-to-buffer@2.0.2: - resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1684,8 +1871,8 @@ packages: destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} duplexer@0.1.2: @@ -1706,6 +1893,9 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -1717,6 +1907,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.0: + resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} + engines: {node: '>=18'} + hasBin: true + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1851,9 +2046,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - get-source@2.0.12: - resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1912,9 +2104,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -2009,8 +2198,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - miniflare@4.20250617.1: - resolution: {integrity: sha512-NjwKVzPGCAUgkCOJxHBwgV2Obu3g4/wAJE0JaA9whcYip4VAJwQ1fU9TMtoKLY91jD9ANR221+CqLyqxennjqg==} + miniflare@4.20260111.0: + resolution: {integrity: sha512-pUsbDlumPaTzliA+J9HMAM74nLR8wqpCQNOESximab51jAfvL7ZaP5Npzh4PWNV0Jfq28tlqazakuJcw6w5qlA==} engines: {node: '>=18.0.0'} hasBin: true @@ -2031,10 +2220,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mustache@4.2.0: - resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} - hasBin: true - mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -2057,9 +2242,6 @@ packages: ofetch@1.4.1: resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} - ohash@2.0.11: - resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2129,9 +2311,6 @@ packages: engines: {node: '>=14'} hasBin: true - printable-characters@1.0.42: - resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2166,8 +2345,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.55.1: - resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + rollup@4.55.2: + resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2183,16 +2362,16 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2210,9 +2389,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - sirv@3.0.1: resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} engines: {node: '>=18'} @@ -2234,9 +2410,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stacktracey@2.1.8: - resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} - std-env@3.9.0: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} @@ -2256,6 +2429,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2335,12 +2512,12 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@5.29.0: - resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} - engines: {node: '>=14.0'} + undici@7.14.0: + resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} + engines: {node: '>=20.18.1'} - unenv@2.0.0-rc.17: - resolution: {integrity: sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg==} + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} universal-user-agent@7.0.3: resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} @@ -2473,17 +2650,17 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workerd@1.20250617.0: - resolution: {integrity: sha512-Uv6p0PYUHp/W/aWfUPLkZVAoAjapisM27JJlwcX9wCPTfCfnuegGOxFMvvlYpmNaX4YCwEdLCwuNn3xkpSkuZw==} + workerd@1.20260111.0: + resolution: {integrity: sha512-ov6Pt4k6d/ALfJja/EIHohT9IrY/f6GAa0arWEPat2qekp78xHbVM7jSxNWAMbaE7ZmnQQIFEGD1ZhAWZmQKIg==} engines: {node: '>=16'} hasBin: true - wrangler@4.20.3: - resolution: {integrity: sha512-ugvmi43CFPbjeQFfhU7EqE1V0ek6ZFv80jzwHcPk/7jPFmOA4ahT5uUU1ga5ZP6vz6lUuG2bLnyl1T5qJah0cg==} - engines: {node: '>=18.0.0'} + wrangler@4.59.1: + resolution: {integrity: sha512-5DddGSNxHd6dOjREWTDQdovQlZ1Lh80NNRXZFQ4/CrK3fNyVIBj9tqCs9pmXMNrKQ/AnKNeYzEs/l1kr8rHhOg==} + engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20250617.0 + '@cloudflare/workers-types': ^4.20260111.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -2512,14 +2689,17 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - youch@3.3.4: - resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} - zod@3.22.3: - resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} snapshots: @@ -2539,38 +2719,38 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.5': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.6 - '@babel/types@7.28.5': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@cloudflare/kv-asset-handler@0.4.0': + '@cloudflare/kv-asset-handler@0.4.1': dependencies: mime: 3.0.0 - '@cloudflare/unenv-preset@2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250617.0)': + '@cloudflare/unenv-preset@2.9.0(unenv@2.0.0-rc.24)(workerd@1.20260111.0)': dependencies: - unenv: 2.0.0-rc.17 + unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20250617.0 + workerd: 1.20260111.0 - '@cloudflare/workerd-darwin-64@1.20250617.0': + '@cloudflare/workerd-darwin-64@1.20260111.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20250617.0': + '@cloudflare/workerd-darwin-arm64@1.20260111.0': optional: true - '@cloudflare/workerd-linux-64@1.20250617.0': + '@cloudflare/workerd-linux-64@1.20260111.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20250617.0': + '@cloudflare/workerd-linux-arm64@1.20260111.0': optional: true - '@cloudflare/workerd-windows-64@1.20250617.0': + '@cloudflare/workerd-windows-64@1.20260111.0': optional: true '@cspotcode/source-map-support@0.8.1': @@ -2583,7 +2763,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -2598,78 +2778,156 @@ snapshots: '@esbuild/aix-ppc64@0.25.4': optional: true + '@esbuild/aix-ppc64@0.27.0': + optional: true + '@esbuild/android-arm64@0.25.4': optional: true + '@esbuild/android-arm64@0.27.0': + optional: true + '@esbuild/android-arm@0.25.4': optional: true + '@esbuild/android-arm@0.27.0': + optional: true + '@esbuild/android-x64@0.25.4': optional: true + '@esbuild/android-x64@0.27.0': + optional: true + '@esbuild/darwin-arm64@0.25.4': optional: true + '@esbuild/darwin-arm64@0.27.0': + optional: true + '@esbuild/darwin-x64@0.25.4': optional: true + '@esbuild/darwin-x64@0.27.0': + optional: true + '@esbuild/freebsd-arm64@0.25.4': optional: true + '@esbuild/freebsd-arm64@0.27.0': + optional: true + '@esbuild/freebsd-x64@0.25.4': optional: true + '@esbuild/freebsd-x64@0.27.0': + optional: true + '@esbuild/linux-arm64@0.25.4': optional: true + '@esbuild/linux-arm64@0.27.0': + optional: true + '@esbuild/linux-arm@0.25.4': optional: true + '@esbuild/linux-arm@0.27.0': + optional: true + '@esbuild/linux-ia32@0.25.4': optional: true + '@esbuild/linux-ia32@0.27.0': + optional: true + '@esbuild/linux-loong64@0.25.4': optional: true + '@esbuild/linux-loong64@0.27.0': + optional: true + '@esbuild/linux-mips64el@0.25.4': optional: true + '@esbuild/linux-mips64el@0.27.0': + optional: true + '@esbuild/linux-ppc64@0.25.4': optional: true + '@esbuild/linux-ppc64@0.27.0': + optional: true + '@esbuild/linux-riscv64@0.25.4': optional: true + '@esbuild/linux-riscv64@0.27.0': + optional: true + '@esbuild/linux-s390x@0.25.4': optional: true + '@esbuild/linux-s390x@0.27.0': + optional: true + '@esbuild/linux-x64@0.25.4': optional: true + '@esbuild/linux-x64@0.27.0': + optional: true + '@esbuild/netbsd-arm64@0.25.4': optional: true + '@esbuild/netbsd-arm64@0.27.0': + optional: true + '@esbuild/netbsd-x64@0.25.4': optional: true + '@esbuild/netbsd-x64@0.27.0': + optional: true + '@esbuild/openbsd-arm64@0.25.4': optional: true + '@esbuild/openbsd-arm64@0.27.0': + optional: true + '@esbuild/openbsd-x64@0.25.4': optional: true + '@esbuild/openbsd-x64@0.27.0': + optional: true + + '@esbuild/openharmony-arm64@0.27.0': + optional: true + '@esbuild/sunos-x64@0.25.4': optional: true + '@esbuild/sunos-x64@0.27.0': + optional: true + '@esbuild/win32-arm64@0.25.4': optional: true + '@esbuild/win32-arm64@0.27.0': + optional: true + '@esbuild/win32-ia32@0.25.4': optional: true + '@esbuild/win32-ia32@0.27.0': + optional: true + '@esbuild/win32-x64@0.25.4': optional: true + '@esbuild/win32-x64@0.27.0': + optional: true + '@eslint-community/eslint-utils@4.7.0(eslint@9.29.0(jiti@2.4.2))': dependencies: eslint: 9.29.0(jiti@2.4.2) @@ -2718,8 +2976,6 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 - '@fastify/busboy@2.1.1': {} - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -2756,79 +3012,100 @@ snapshots: transitivePeerDependencies: - supports-color - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': {} + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.8.1 optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': optional: true '@inquirer/ansi@1.0.2': {} @@ -2980,7 +3257,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.1)(@types/node@24.10.0)': + '@napi-rs/cli@3.4.1(@emnapi/runtime@1.8.1)(@types/node@24.10.0)': dependencies: '@inquirer/prompts': 7.10.1(@types/node@24.10.0) '@napi-rs/cross-toolchain': 1.0.3 @@ -2992,10 +3269,10 @@ snapshots: emnapi: 1.7.1 es-toolkit: 1.42.0 js-yaml: 4.1.1 - semver: 7.7.2 + semver: 7.7.3 typanion: 3.14.0 optionalDependencies: - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.8.1 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' @@ -3164,7 +3441,7 @@ snapshots: '@napi-rs/wasm-runtime@1.0.7': dependencies: '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.8.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -3301,110 +3578,126 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + '@quansync/fs@0.1.3': dependencies: quansync: 0.2.10 - '@rollup/plugin-terser@0.4.4(rollup@4.55.1)': + '@rollup/plugin-terser@0.4.4(rollup@4.55.2)': dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 terser: 5.43.1 optionalDependencies: - rollup: 4.55.1 + rollup: 4.55.2 - '@rollup/plugin-typescript@12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.8.3)': + '@rollup/plugin-typescript@12.3.0(rollup@4.55.2)(tslib@2.8.1)(typescript@5.8.3)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.55.1) + '@rollup/pluginutils': 5.2.0(rollup@4.55.2) resolve: 1.22.10 typescript: 5.8.3 optionalDependencies: - rollup: 4.55.1 + rollup: 4.55.2 tslib: 2.8.1 - '@rollup/pluginutils@5.2.0(rollup@4.55.1)': + '@rollup/pluginutils@5.2.0(rollup@4.55.2)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.55.1 + rollup: 4.55.2 - '@rollup/rollup-android-arm-eabi@4.55.1': + '@rollup/rollup-android-arm-eabi@4.55.2': optional: true - '@rollup/rollup-android-arm64@4.55.1': + '@rollup/rollup-android-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-arm64@4.55.1': + '@rollup/rollup-darwin-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-x64@4.55.1': + '@rollup/rollup-darwin-x64@4.55.2': optional: true - '@rollup/rollup-freebsd-arm64@4.55.1': + '@rollup/rollup-freebsd-arm64@4.55.2': optional: true - '@rollup/rollup-freebsd-x64@4.55.1': + '@rollup/rollup-freebsd-x64@4.55.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + '@rollup/rollup-linux-arm-gnueabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.55.1': + '@rollup/rollup-linux-arm-musleabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.55.1': + '@rollup/rollup-linux-arm64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.55.1': + '@rollup/rollup-linux-arm64-musl@4.55.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.55.1': + '@rollup/rollup-linux-loong64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.55.1': + '@rollup/rollup-linux-loong64-musl@4.55.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.55.1': + '@rollup/rollup-linux-ppc64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.55.1': + '@rollup/rollup-linux-ppc64-musl@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.55.1': + '@rollup/rollup-linux-riscv64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.55.1': + '@rollup/rollup-linux-riscv64-musl@4.55.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.55.1': + '@rollup/rollup-linux-s390x-gnu@4.55.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.55.1': + '@rollup/rollup-linux-x64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-x64-musl@4.55.1': + '@rollup/rollup-linux-x64-musl@4.55.2': optional: true - '@rollup/rollup-openbsd-x64@4.55.1': + '@rollup/rollup-openbsd-x64@4.55.2': optional: true - '@rollup/rollup-openharmony-arm64@4.55.1': + '@rollup/rollup-openharmony-arm64@4.55.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.55.1': + '@rollup/rollup-win32-arm64-msvc@4.55.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.55.1': + '@rollup/rollup-win32-ia32-msvc@4.55.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.55.1': + '@rollup/rollup-win32-x64-gnu@4.55.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.55.1': + '@rollup/rollup-win32-x64-msvc@4.55.2': optional: true + '@sindresorhus/is@7.2.0': {} + + '@speed-highlight/core@1.2.14': {} + '@standard-schema/spec@1.0.0': {} '@sveltejs/acorn-typescript@1.0.5(acorn@8.15.0)': @@ -3527,7 +3820,7 @@ snapshots: fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.2 + semver: 7.7.3 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -3744,7 +4037,7 @@ snapshots: '@vue/compiler-core@3.5.17': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.28.6 '@vue/shared': 3.5.17 entities: 4.5.0 estree-walker: 2.0.2 @@ -3757,7 +4050,7 @@ snapshots: '@vue/compiler-sfc@3.5.17': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.28.6 '@vue/compiler-core': 3.5.17 '@vue/compiler-dom': 3.5.17 '@vue/compiler-ssr': 3.5.17 @@ -3828,10 +4121,6 @@ snapshots: aria-query@5.3.2: {} - as-table@1.0.55: - dependencies: - printable-characters: 1.0.42 - axobject-query@4.1.0: {} balanced-match@3.0.1: {} @@ -3891,16 +4180,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - colorette@2.0.20: {} commander@2.20.3: {} @@ -3911,7 +4190,7 @@ snapshots: consola@3.4.2: {} - cookie@0.7.2: {} + cookie@1.1.1: {} cross-env@10.1.0: dependencies: @@ -3931,8 +4210,6 @@ snapshots: csstype@3.2.3: {} - data-uri-to-buffer@2.0.2: {} - debug@4.4.3: dependencies: ms: 2.1.3 @@ -3945,7 +4222,7 @@ snapshots: destr@2.0.5: {} - detect-libc@2.0.4: {} + detect-libc@2.1.2: {} duplexer@0.1.2: {} @@ -3955,6 +4232,8 @@ snapshots: entities@4.5.0: {} + error-stack-parser-es@1.0.5: {} + es-module-lexer@1.7.0: {} es-toolkit@1.42.0: {} @@ -3987,6 +4266,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.4 '@esbuild/win32-x64': 0.25.4 + esbuild@0.27.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.0 + '@esbuild/android-arm': 0.27.0 + '@esbuild/android-arm64': 0.27.0 + '@esbuild/android-x64': 0.27.0 + '@esbuild/darwin-arm64': 0.27.0 + '@esbuild/darwin-x64': 0.27.0 + '@esbuild/freebsd-arm64': 0.27.0 + '@esbuild/freebsd-x64': 0.27.0 + '@esbuild/linux-arm': 0.27.0 + '@esbuild/linux-arm64': 0.27.0 + '@esbuild/linux-ia32': 0.27.0 + '@esbuild/linux-loong64': 0.27.0 + '@esbuild/linux-mips64el': 0.27.0 + '@esbuild/linux-ppc64': 0.27.0 + '@esbuild/linux-riscv64': 0.27.0 + '@esbuild/linux-s390x': 0.27.0 + '@esbuild/linux-x64': 0.27.0 + '@esbuild/netbsd-arm64': 0.27.0 + '@esbuild/netbsd-x64': 0.27.0 + '@esbuild/openbsd-arm64': 0.27.0 + '@esbuild/openbsd-x64': 0.27.0 + '@esbuild/openharmony-arm64': 0.27.0 + '@esbuild/sunos-x64': 0.27.0 + '@esbuild/win32-arm64': 0.27.0 + '@esbuild/win32-ia32': 0.27.0 + '@esbuild/win32-x64': 0.27.0 + escape-string-regexp@4.0.0: {} eslint-config-prettier@10.1.8(eslint@9.29.0(jiti@2.4.2)): @@ -4133,11 +4441,6 @@ snapshots: function-bind@1.1.2: {} - get-source@2.0.12: - dependencies: - data-uri-to-buffer: 2.0.2 - source-map: 0.6.1 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -4181,8 +4484,6 @@ snapshots: imurmurhash@0.1.4: {} - is-arrayish@0.3.2: {} - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -4261,20 +4562,20 @@ snapshots: mime@3.0.0: {} - miniflare@4.20250617.1: + miniflare@4.20260111.0: dependencies: '@cspotcode/source-map-support': 0.8.1 acorn: 8.14.0 acorn-walk: 8.3.2 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 - sharp: 0.33.5 + sharp: 0.34.5 stoppable: 1.1.0 - undici: 5.29.0 - workerd: 1.20250617.0 + undici: 7.14.0 + workerd: 1.20260111.0 ws: 8.18.0 - youch: 3.3.4 - zod: 3.22.3 + youch: 4.1.0-beta.10 + zod: 3.25.76 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -4298,8 +4599,6 @@ snapshots: ms@2.1.3: {} - mustache@4.2.0: {} - mute-stream@2.0.0: {} nanoid@3.3.11: {} @@ -4316,8 +4615,6 @@ snapshots: node-fetch-native: 1.6.6 ufo: 1.6.1 - ohash@2.0.11: {} - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -4381,8 +4678,6 @@ snapshots: prettier@3.6.2: {} - printable-characters@1.0.42: {} - punycode@2.3.1: {} quansync@0.2.10: {} @@ -4409,35 +4704,35 @@ snapshots: reusify@1.1.0: {} - rollup@4.55.1: + rollup@4.55.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.55.1 - '@rollup/rollup-android-arm64': 4.55.1 - '@rollup/rollup-darwin-arm64': 4.55.1 - '@rollup/rollup-darwin-x64': 4.55.1 - '@rollup/rollup-freebsd-arm64': 4.55.1 - '@rollup/rollup-freebsd-x64': 4.55.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 - '@rollup/rollup-linux-arm-musleabihf': 4.55.1 - '@rollup/rollup-linux-arm64-gnu': 4.55.1 - '@rollup/rollup-linux-arm64-musl': 4.55.1 - '@rollup/rollup-linux-loong64-gnu': 4.55.1 - '@rollup/rollup-linux-loong64-musl': 4.55.1 - '@rollup/rollup-linux-ppc64-gnu': 4.55.1 - '@rollup/rollup-linux-ppc64-musl': 4.55.1 - '@rollup/rollup-linux-riscv64-gnu': 4.55.1 - '@rollup/rollup-linux-riscv64-musl': 4.55.1 - '@rollup/rollup-linux-s390x-gnu': 4.55.1 - '@rollup/rollup-linux-x64-gnu': 4.55.1 - '@rollup/rollup-linux-x64-musl': 4.55.1 - '@rollup/rollup-openbsd-x64': 4.55.1 - '@rollup/rollup-openharmony-arm64': 4.55.1 - '@rollup/rollup-win32-arm64-msvc': 4.55.1 - '@rollup/rollup-win32-ia32-msvc': 4.55.1 - '@rollup/rollup-win32-x64-gnu': 4.55.1 - '@rollup/rollup-win32-x64-msvc': 4.55.1 + '@rollup/rollup-android-arm-eabi': 4.55.2 + '@rollup/rollup-android-arm64': 4.55.2 + '@rollup/rollup-darwin-arm64': 4.55.2 + '@rollup/rollup-darwin-x64': 4.55.2 + '@rollup/rollup-freebsd-arm64': 4.55.2 + '@rollup/rollup-freebsd-x64': 4.55.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.2 + '@rollup/rollup-linux-arm-musleabihf': 4.55.2 + '@rollup/rollup-linux-arm64-gnu': 4.55.2 + '@rollup/rollup-linux-arm64-musl': 4.55.2 + '@rollup/rollup-linux-loong64-gnu': 4.55.2 + '@rollup/rollup-linux-loong64-musl': 4.55.2 + '@rollup/rollup-linux-ppc64-gnu': 4.55.2 + '@rollup/rollup-linux-ppc64-musl': 4.55.2 + '@rollup/rollup-linux-riscv64-gnu': 4.55.2 + '@rollup/rollup-linux-riscv64-musl': 4.55.2 + '@rollup/rollup-linux-s390x-gnu': 4.55.2 + '@rollup/rollup-linux-x64-gnu': 4.55.2 + '@rollup/rollup-linux-x64-musl': 4.55.2 + '@rollup/rollup-openbsd-x64': 4.55.2 + '@rollup/rollup-openharmony-arm64': 4.55.2 + '@rollup/rollup-win32-arm64-msvc': 4.55.2 + '@rollup/rollup-win32-ia32-msvc': 4.55.2 + '@rollup/rollup-win32-x64-gnu': 4.55.2 + '@rollup/rollup-win32-x64-msvc': 4.55.2 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4452,37 +4747,42 @@ snapshots: safer-buffer@2.1.2: {} - semver@7.7.2: {} + semver@7.7.3: {} serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.2 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 shebang-command@2.0.0: dependencies: @@ -4494,10 +4794,6 @@ snapshots: signal-exit@4.1.0: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - sirv@3.0.1: dependencies: '@polka/url': 1.0.0-next.29 @@ -4517,11 +4813,6 @@ snapshots: stackback@0.0.2: {} - stacktracey@2.1.8: - dependencies: - as-table: 1.0.55 - get-source: 2.0.12 - std-env@3.9.0: {} stoppable@1.1.0: {} @@ -4538,6 +4829,8 @@ snapshots: strip-json-comments@3.1.1: {} + supports-color@10.2.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -4622,17 +4915,11 @@ snapshots: undici-types@7.16.0: {} - undici@5.29.0: - dependencies: - '@fastify/busboy': 2.1.1 + undici@7.14.0: {} - unenv@2.0.0-rc.17: + unenv@2.0.0-rc.24: dependencies: - defu: 6.1.4 - exsolve: 1.0.7 - ohash: 2.0.11 pathe: 2.0.3 - ufo: 1.6.1 universal-user-agent@7.0.3: {} @@ -4679,7 +4966,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.55.1 + rollup: 4.55.2 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.0 @@ -4754,24 +5041,24 @@ snapshots: word-wrap@1.2.5: {} - workerd@1.20250617.0: + workerd@1.20260111.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20250617.0 - '@cloudflare/workerd-darwin-arm64': 1.20250617.0 - '@cloudflare/workerd-linux-64': 1.20250617.0 - '@cloudflare/workerd-linux-arm64': 1.20250617.0 - '@cloudflare/workerd-windows-64': 1.20250617.0 + '@cloudflare/workerd-darwin-64': 1.20260111.0 + '@cloudflare/workerd-darwin-arm64': 1.20260111.0 + '@cloudflare/workerd-linux-64': 1.20260111.0 + '@cloudflare/workerd-linux-arm64': 1.20260111.0 + '@cloudflare/workerd-windows-64': 1.20260111.0 - wrangler@4.20.3: + wrangler@4.59.1: dependencies: - '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250617.0) + '@cloudflare/kv-asset-handler': 0.4.1 + '@cloudflare/unenv-preset': 2.9.0(unenv@2.0.0-rc.24)(workerd@1.20260111.0) blake3-wasm: 2.1.5 - esbuild: 0.25.4 - miniflare: 4.20250617.1 + esbuild: 0.27.0 + miniflare: 4.20260111.0 path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.17 - workerd: 1.20250617.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260111.0 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: @@ -4790,12 +5077,19 @@ snapshots: yoctocolors-cjs@2.1.3: {} - youch@3.3.4: + youch-core@0.3.3: dependencies: - cookie: 0.7.2 - mustache: 4.2.0 - stacktracey: 2.1.8 + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.14 + cookie: 1.1.1 + youch-core: 0.3.3 zimmerframe@1.1.2: {} - zod@3.22.3: {} + zod@3.25.76: {}